diff --git a/alib2algo/src/automaton/transform/AutomataConcatenation.h b/alib2algo/src/automaton/transform/AutomataConcatenation.h index 69717cea029b6891663b63117e65d484ed7932fa..7b19c9970dd941e569f7696f319f0005846ad1e1 100644 --- a/alib2algo/src/automaton/transform/AutomataConcatenation.h +++ b/alib2algo/src/automaton/transform/AutomataConcatenation.h @@ -80,13 +80,18 @@ automaton::NFA < typename AutomatonType::SymbolType, ext::pair < typename Automa res.addState ( q01q02 ); res.setInitialState ( q01q02 ); - for ( const auto & t : first.getTransitionsFromState ( first.getInitialState ( ) ) ) + for ( const auto & t : first.getTransitionsFromState ( first.getInitialState ( ) ) ) { res.addTransition ( q01q02, t.first.second, { t.second, FIRST } ); + if ( first.getFinalStates ( ).contains ( t.second ) ) + res.addTransition ( q01q02, t.first.second, { second.getInitialState ( ), SECOND } ); + } + for ( const auto & t : second.getTransitionsFromState ( second.getInitialState ( ) ) ) res.addTransition ( q01q02, t.first.second, { t.second, SECOND } ); - res.addFinalState ( q01q02 ); + if ( first.getFinalStates ( ).contains ( first.getInitialState() ) && second.getFinalStates().contains(second.getInitialState())) + res.addFinalState ( q01q02 ); } return res; diff --git a/alib2algo/test-src/automaton/transform/AutomataConcatenationTest.cpp b/alib2algo/test-src/automaton/transform/AutomataConcatenationTest.cpp index cfa92bb47ff239f1dc0d8ec4d1f7f3edb0dae705..9e24cb4bfc0afd1a1da5fcb9c8d4ad1f78d78686 100644 --- a/alib2algo/test-src/automaton/transform/AutomataConcatenationTest.cpp +++ b/alib2algo/test-src/automaton/transform/AutomataConcatenationTest.cpp @@ -79,4 +79,41 @@ TEST_CASE ( "Automata Concatenation", "[unit][algo][automaton][transform]" ) { CHECK(umdfa21 == umdfa); CHECK(umdfa22 == umdfa); } + + SECTION ( "No epsilon transitions, first automaton has a word of length 1" ) { + // Bug in AAG slides and our algorithm + + auto A = DefaultStateType ( "A" ); + auto B = DefaultStateType ( "B" ); + auto C = DefaultStateType ( "C" ); + auto a = DefaultSymbolType ( 'a' ); + auto b = DefaultSymbolType ( 'b' ); + auto init = std::make_pair ( label::InitialStateLabel::instance < DefaultStateType > ( ), 0 ); + + automaton::DFA < > m1 ( A ); + m1.setStates ( { A, B } ); + m1.setInputAlphabet ( { a, b } ); + m1.setFinalStates ( { A, B } ); + m1.addTransition ( A, a, B ); + + automaton::DFA < > m2 ( C ); + m2.setStates ( { C } ); + m2.setInputAlphabet ( { a, b } ); + m2.setFinalStates ( { C } ); + m2.addTransition ( C, b, C ); + + automaton::NFA < DefaultSymbolType, ext::pair < DefaultStateType, unsigned > > expected ( init ); + expected.setStates ( { init, { A, 1 }, { B, 1 }, { C, 2 } } ); + expected.setInputAlphabet ( { a, b } ); + expected.setFinalStates ( { init, { C, 2 } } ); + expected.addTransition ( init, a, { B, 1 } ); + expected.addTransition ( init, a, { C, 2 } ); + expected.addTransition ( init, b, { C, 2 } ); + expected.addTransition ( { A, 1 }, a, { B, 1 } ); + expected.addTransition ( { A, 1 }, a, { C, 2 } ); + expected.addTransition ( { C, 2 }, b, { C, 2 } ); + + + CHECK ( automaton::transform::AutomataConcatenation::concatenation ( m1, m2 ) == expected ); + } } diff --git a/tests/aql/AutomataConcatenation.aql b/tests/aql/AutomataConcatenation.aql new file mode 100644 index 0000000000000000000000000000000000000000..066ea23b55c0e706d7649285e380c0c8e59e76e8 --- /dev/null +++ b/tests/aql/AutomataConcatenation.aql @@ -0,0 +1,22 @@ +begin + declare auto $iter = 200; + while ( -- $iter ) do begin + execute automaton::generate::RandomAutomatonFactory 10 3 false 5 > $a1; + execute automaton::generate::RandomAutomatonFactory 10 3 false 5 > $a2; + + execute automaton::transform::AutomataConcatenation $a1 $a2 | automaton::determinize::Determinize - | automaton::simplify::Trim - | automaton::simplify::Minimize - | automaton::simplify::Normalize - > $r1; + execute automaton::transform::AutomataConcatenationEpsilonTransition $a1 $a2 | automaton::simplify::EpsilonRemoverIncoming - | automaton::determinize::Determinize - | automaton::simplify::Trim - | automaton::simplify::Minimize - | automaton::simplify::Normalize - > $r2; + + execute compare::AutomatonCompare $r1 $r2 > $res; + if ( $res != 1 ) then begin + print "Comparison returned non-OK value:"; + print $res; + print $a1 | string::Compose -; + print $a2 | string::Compose -; + print AutomataConcatenation $a1 $a2 | string::Compose -; + print $r1 | string::Compose -; + print $r2 | string::Compose -; + quit 1; + end + end +end