Skip to content
Snippets Groups Projects
Unverified Commit 0fb7a684 authored by Tomáš Pecka's avatar Tomáš Pecka
Browse files

algo: Fix AutomataConcatenation when first automaton has a word of len 1

The algorithm, taken from BI-AAG course @ FIT CTU did not work
correctly when first automaton accepts a word of length 1.

There are two bugs. First, the set of final states was wrong. This was
the easy part to spot.
Second, we sometimes miss some transitions.

Consider these two automata:
 DFA a b
 ><A B -
  <B - -

 DFA a b
 ><C - -

The algorithm would result in this:
 DFA a   b
 ><S B   C
   A B|C -
   B -   -
  <C -   C

Which is of course wrong because the first automaton accepts "a + #E"
and the second one accepts a language of "b*". However, the result
doesn't accept words from neither "a" nor "ab*" which is in language
"(a+#E)b*".

The problem is that for every transition in the first automaton that
leads to a final state we create a new transition to an initial state of
the second automaton. This effectively says that "ok, we are done with
first automaton, we would accept. Let's continue from the initial state
of the second automaton".
Also, when we create a new initial state, we *only* copy transitions from
both initial states there. But if the word is of length 1 and is to be
accepted by the first automaton, we are missing this "transition to second
automaton".
In our example above, we need to add a transition (S, a) -> C and it's
fine.
parent 8faf1384
No related branches found
No related tags found
1 merge request!201Concat no eps
Pipeline #164170 passed with warnings
...@@ -80,13 +80,18 @@ automaton::NFA < typename AutomatonType::SymbolType, ext::pair < typename Automa ...@@ -80,13 +80,18 @@ automaton::NFA < typename AutomatonType::SymbolType, ext::pair < typename Automa
res.addState ( q01q02 ); res.addState ( q01q02 );
res.setInitialState ( 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 } ); 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 ( ) ) ) for ( const auto & t : second.getTransitionsFromState ( second.getInitialState ( ) ) )
res.addTransition ( q01q02, t.first.second, { t.second, SECOND } ); 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; return res;
......
...@@ -79,4 +79,41 @@ TEST_CASE ( "Automata Concatenation", "[unit][algo][automaton][transform]" ) { ...@@ -79,4 +79,41 @@ TEST_CASE ( "Automata Concatenation", "[unit][algo][automaton][transform]" ) {
CHECK(umdfa21 == umdfa); CHECK(umdfa21 == umdfa);
CHECK(umdfa22 == 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 );
}
} }
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
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment