diff --git a/alib2algo/src/automaton/convert/ToRegExpStateElimination.cpp b/alib2algo/src/automaton/convert/ToRegExpStateElimination.cpp index b416f53ca86a457e9f18384136b3aaf2f5080e9f..8c6967b2ac9b327aae9a158b4af1f48b97378dd0 100644 --- a/alib2algo/src/automaton/convert/ToRegExpStateElimination.cpp +++ b/alib2algo/src/automaton/convert/ToRegExpStateElimination.cpp @@ -6,45 +6,12 @@ */ #include "ToRegExpStateElimination.h" - -#include <regexp/simplify/RegExpOptimize.h> -#include <regexp/transform/RegExpAlternate.h> -#include <regexp/transform/RegExpConcatenate.h> -#include <regexp/transform/RegExpIterate.h> - -#include <common/createUnique.hpp> - -#include <label/FinalStateLabel.h> #include <registration/AlgoRegistration.hpp> namespace automaton { namespace convert { -template<class T> -regexp::UnboundedRegExp < > ToRegExpStateElimination::convert(const T& automaton) { - if(automaton.getFinalStates().size() == 0) - return regexp::UnboundedRegExp < > (regexp::UnboundedRegExpStructure < DefaultSymbolType > (regexp::UnboundedRegExpEmpty < DefaultSymbolType > ())); - - // steps 1 + 2 - automaton::ExtendedNFA < > extendedAutomaton(automaton); - extendExtendedNFA(extendedAutomaton); - - // step 3 - Exterminate! - // select all states that are neither final nor initial - ext::set<DefaultStateType> statesToEliminate = extendedAutomaton.getStates(); - statesToEliminate.erase(extendedAutomaton.getInitialState()); - statesToEliminate.erase(*extendedAutomaton.getFinalStates().begin()); - - for(const auto& state : statesToEliminate) - extendedAutomaton = eliminateState(extendedAutomaton, state); - - // step 4 - regexp::UnboundedRegExpStructure < DefaultSymbolType > finalStateLoop = regexp::RegExpIterate::iterate ( transitionsToRegExp ( extendedAutomaton, *extendedAutomaton.getFinalStates().begin(), *extendedAutomaton.getFinalStates().begin())); - regexp::UnboundedRegExpStructure < DefaultSymbolType > initialToFinalState = regexp::RegExpConcatenate::concatenate ( transitionsToRegExp ( extendedAutomaton, extendedAutomaton.getInitialState(), *extendedAutomaton.getFinalStates().begin()),finalStateLoop ); - return regexp::UnboundedRegExp < > (regexp::simplify::RegExpOptimize::optimize(initialToFinalState)); -} - auto ToRegExpStateEliminationEpsilonNFA = registration::AbstractRegister < ToRegExpStateElimination, regexp::UnboundedRegExp < >, const automaton::EpsilonNFA < > & >(ToRegExpStateElimination::convert); auto ToRegExpStateEliminationMultiInitialStateNFA = registration::AbstractRegister < ToRegExpStateElimination, regexp::UnboundedRegExp < >, const automaton::MultiInitialStateNFA < > & >(ToRegExpStateElimination::convert); auto ToRegExpStateEliminationNFA = registration::AbstractRegister < ToRegExpStateElimination, regexp::UnboundedRegExp < >, const automaton::NFA < > & >(ToRegExpStateElimination::convert); @@ -52,65 +19,6 @@ auto ToRegExpStateEliminationDFA = registration::AbstractRegister < ToRegExpStat auto ToRegExpStateEliminationExtendedNFA = registration::AbstractRegister < ToRegExpStateElimination, regexp::UnboundedRegExp < >, const automaton::ExtendedNFA < > & >(ToRegExpStateElimination::convert); auto ToRegExpStateEliminationCompactNFA = registration::AbstractRegister < ToRegExpStateElimination, regexp::UnboundedRegExp < >, const automaton::CompactNFA < > & >(ToRegExpStateElimination::convert); -automaton::ExtendedNFA < > ToRegExpStateElimination::eliminateState(const automaton::ExtendedNFA < > & extendedAutomaton, const DefaultStateType& q) { - automaton::ExtendedNFA < > newAutomaton(extendedAutomaton.getInitialState()); // sure that q is neither initial nor final (follows from step 2 - extending ExtendedNFA) - newAutomaton.setStates(extendedAutomaton.getStates()); - newAutomaton.removeState(q); // preserve all states but q (the one to eliminate) - newAutomaton.setInputAlphabet(extendedAutomaton.getInputAlphabet()); - newAutomaton.setFinalStates(extendedAutomaton.getFinalStates()); - - for(const auto& p: newAutomaton.getStates()) { - for(const auto& r : newAutomaton.getStates()) { - regexp::UnboundedRegExpStructure < DefaultSymbolType > concat = transitionsToRegExp(extendedAutomaton, p, q); - concat = regexp::RegExpConcatenate::concatenate(concat, regexp::RegExpIterate::iterate(transitionsToRegExp(extendedAutomaton, q, q))); - concat = regexp::RegExpConcatenate::concatenate(concat, transitionsToRegExp(extendedAutomaton, q, r)); - - regexp::UnboundedRegExpStructure < DefaultSymbolType > alt = regexp::RegExpAlternate::alternate(concat, transitionsToRegExp(extendedAutomaton, p, r)); - - newAutomaton.addTransition(p, regexp::simplify::RegExpOptimize::optimize(alt), r); - } - } - - return newAutomaton; -} - -const regexp::UnboundedRegExpStructure < DefaultSymbolType > ToRegExpStateElimination::transitionsToRegExp(const automaton::ExtendedNFA < > & automaton, const DefaultStateType& from, const DefaultStateType& to) { - regexp::UnboundedRegExpStructure < DefaultSymbolType > ret(regexp::UnboundedRegExpEmpty < DefaultSymbolType > { }); - - for(const auto& transition: automaton.getTransitionsFromState(from)) - if(transition.second.count(to) > 0) - ret = regexp::RegExpAlternate::alternate(ret, transition.first.second); - - return regexp::simplify::RegExpOptimize::optimize(ret); -} - -void ToRegExpStateElimination::extendExtendedNFA(automaton::ExtendedNFA < > & automaton) { - const DefaultStateType& initState = automaton.getInitialState(); - if(automaton.getFinalStates().count(initState) > 0 || automaton.getTransitionsToState(initState).size() > 0 ) { - DefaultStateType q0 = common::createUnique(initState, automaton.getStates()); - automaton.addState(q0); - - regexp::UnboundedRegExpStructure < DefaultSymbolType > regexp { regexp::UnboundedRegExpEpsilon < DefaultSymbolType > () }; - automaton.addTransition(q0, regexp, initState); - - automaton.setInitialState(q0); - } - - if(automaton.getFinalStates().size() > 1) { - DefaultStateType f = common::createUnique(label::FinalStateLabel::instance < DefaultStateType > ( ), automaton.getStates()); - automaton.addState ( f ); - - for(const auto &state : automaton.getFinalStates() ) { - regexp::UnboundedRegExpStructure < DefaultSymbolType > regexp { regexp::UnboundedRegExpEpsilon < DefaultSymbolType > () }; - automaton.addTransition(state, regexp, f); - } - - ext::set < DefaultStateType > newFinalStates; - newFinalStates.insert ( f ); - automaton.setFinalStates ( newFinalStates ); - } -} - } /* namespace convert */ } /* namespace automaton */ diff --git a/alib2algo/src/automaton/convert/ToRegExpStateElimination.h b/alib2algo/src/automaton/convert/ToRegExpStateElimination.h index c16bd9e58fae22e89b1e013cd9a73590c0434b42..8ffc88a6ffb68eac8ff739b542570e3c24c0ac14 100644 --- a/alib2algo/src/automaton/convert/ToRegExpStateElimination.h +++ b/alib2algo/src/automaton/convert/ToRegExpStateElimination.h @@ -32,6 +32,17 @@ #include <automaton/FSM/EpsilonNFA.h> #include <automaton/FSM/ExtendedNFA.h> +#include <automaton/Automaton.h> + +#include <regexp/simplify/RegExpOptimize.h> +#include <regexp/transform/RegExpAlternate.h> +#include <regexp/transform/RegExpConcatenate.h> +#include <regexp/transform/RegExpIterate.h> + +#include <common/createUnique.hpp> + +#include <label/FinalStateLabel.h> + namespace automaton { namespace convert { @@ -45,38 +56,135 @@ public: /** * Performs conversion. * @tparam T type of the finite automaton + * @tparam SymbolType the type of input symbols of the accepted automaton + * @tparam StateType the type of states of the accepted automaton * @param automaton finite automaton to convert * @return unbounded regular expression equivalent to the original automaton */ - template<class T> - static regexp::UnboundedRegExp < > convert(const T& automaton); + template < class T, class SymbolType = typename automaton::SymbolTypeOfAutomaton < T >, class StateType = typename automaton::StateTypeOfAutomaton < T > > + static regexp::UnboundedRegExp < SymbolType > convert ( const T & automaton ); private: /** * Helper function to create new initial and final states in the automaton for the algorithm. + * @tparam SymbolType the type of input symbols of the accepted automaton + * @tparam StateType the type of states of the accepted automaton * @param automaton extended finite automaton */ - static void extendExtendedNFA(automaton::ExtendedNFA < > & automaton); + template < class SymbolType, class StateType > + static void extendExtendedNFA(automaton::ExtendedNFA < SymbolType, StateType > & automaton ); /** * Helper function to create a regexp from all transitions between states @p from and @p to. * It creates the alternation regexp of all such transitions. + * @tparam SymbolType the type of input symbols of the accepted automaton + * @tparam StateType the type of states of the accepted automaton * @param automaton automaton to select the transitions * @param from source state in @param automaton * @param to destination state in @param automaton * @return the regular expression node representing the transitions between states @p from and @p to */ - static const regexp::UnboundedRegExpStructure < DefaultSymbolType > transitionsToRegExp(const automaton::ExtendedNFA < > & automaton, const DefaultStateType& from, const DefaultStateType& to); + template < class SymbolType, class StateType > + static const regexp::UnboundedRegExpStructure < SymbolType > transitionsToRegExp ( const automaton::ExtendedNFA < SymbolType, StateType > & automaton, const StateType & from, const StateType & to ); /** * Helper function for the elimination of a single state according to the algorithm. + * @tparam SymbolType the type of input symbols of the accepted automaton + * @tparam StateType the type of states of the accepted automaton * @param extendedAutomaton automaton for the elimination * @param state state to eliminate * @return the @p extendedAutomaton after the elimination of a state @state. */ - static automaton::ExtendedNFA < > eliminateState(const automaton::ExtendedNFA < > & extendedAutomaton, const DefaultStateType& state); + template < class SymbolType, class StateType > + static automaton::ExtendedNFA < SymbolType, StateType > eliminateState ( const automaton::ExtendedNFA < SymbolType, StateType > & extendedAutomaton, const StateType & state ); }; +template < class T, class SymbolType, class StateType > +regexp::UnboundedRegExp < SymbolType > ToRegExpStateElimination::convert ( const T & automaton ) { + if ( automaton.getFinalStates ( ).size ( ) == 0 ) + return regexp::UnboundedRegExp < SymbolType > ( regexp::UnboundedRegExpStructure < DefaultSymbolType > ( regexp::UnboundedRegExpEmpty < DefaultSymbolType > ( ) ) ); + + // steps 1 + 2 + automaton::ExtendedNFA < SymbolType, StateType > extendedAutomaton ( automaton ); + extendExtendedNFA ( extendedAutomaton ); + + // step 3 - Exterminate! + // select all states that are neither final nor initial + ext::set < StateType > statesToEliminate = extendedAutomaton.getStates ( ); + statesToEliminate.erase ( extendedAutomaton.getInitialState ( ) ); + statesToEliminate.erase ( * extendedAutomaton.getFinalStates ( ).begin ( ) ); + + for ( const StateType & state : statesToEliminate ) + extendedAutomaton = eliminateState ( extendedAutomaton, state ); + + // step 4 + regexp::UnboundedRegExpStructure < SymbolType > finalStateLoop = regexp::RegExpIterate::iterate ( transitionsToRegExp ( extendedAutomaton, * extendedAutomaton.getFinalStates ( ).begin ( ), * extendedAutomaton.getFinalStates ( ).begin ( ) ) ); + regexp::UnboundedRegExpStructure < SymbolType > initialToFinalState = regexp::RegExpConcatenate::concatenate ( transitionsToRegExp ( extendedAutomaton, extendedAutomaton.getInitialState ( ), *extendedAutomaton.getFinalStates ( ).begin ( ) ),finalStateLoop ); + return regexp::UnboundedRegExp < SymbolType > ( regexp::simplify::RegExpOptimize::optimize ( initialToFinalState ) ); +} + +template < class SymbolType, class StateType > +automaton::ExtendedNFA < SymbolType, StateType > ToRegExpStateElimination::eliminateState ( const automaton::ExtendedNFA < SymbolType, StateType > & extendedAutomaton, const StateType & q ) { + automaton::ExtendedNFA < SymbolType, StateType > newAutomaton ( extendedAutomaton.getInitialState ( ) ); // sure that q is neither initial nor final (follows from step 2 - extending ExtendedNFA) + newAutomaton.setStates ( extendedAutomaton.getStates ( ) ); + newAutomaton.removeState ( q ); // preserve all states but q (the one to eliminate) + newAutomaton.setInputAlphabet ( extendedAutomaton.getInputAlphabet ( ) ); + newAutomaton.setFinalStates ( extendedAutomaton.getFinalStates ( ) ); + + for ( const StateType & p: newAutomaton.getStates ( ) ) { + for ( const StateType & r : newAutomaton.getStates ( ) ) { + regexp::UnboundedRegExpStructure < SymbolType > concat = transitionsToRegExp ( extendedAutomaton, p, q ); + concat = regexp::RegExpConcatenate::concatenate ( concat, regexp::RegExpIterate::iterate ( transitionsToRegExp ( extendedAutomaton, q, q ) ) ); + concat = regexp::RegExpConcatenate::concatenate ( concat, transitionsToRegExp ( extendedAutomaton, q, r ) ); + + regexp::UnboundedRegExpStructure < SymbolType > alt = regexp::RegExpAlternate::alternate ( concat, transitionsToRegExp ( extendedAutomaton, p, r ) ); + + newAutomaton.addTransition ( p, regexp::simplify::RegExpOptimize::optimize ( alt ), r ); + } + } + + return newAutomaton; +} + +template < class SymbolType, class StateType > +const regexp::UnboundedRegExpStructure < SymbolType > ToRegExpStateElimination::transitionsToRegExp ( const automaton::ExtendedNFA < SymbolType, StateType > & automaton, const StateType & from, const StateType & to ) { + regexp::UnboundedRegExpStructure < SymbolType > ret ( regexp::UnboundedRegExpEmpty < SymbolType > { } ); + + for ( const auto & transition: automaton.getTransitionsFromState ( from ) ) + if ( transition.second.count ( to ) > 0) + ret = regexp::RegExpAlternate::alternate ( ret, transition.first.second ); + + return regexp::simplify::RegExpOptimize::optimize ( ret ); +} + +template < class SymbolType, class StateType > +void ToRegExpStateElimination::extendExtendedNFA ( automaton::ExtendedNFA < SymbolType, StateType > & automaton ) { + const StateType & initState = automaton.getInitialState ( ); + if ( automaton.getFinalStates ( ).count ( initState ) > 0 || automaton.getTransitionsToState ( initState ).size ( ) > 0 ) { + StateType q0 = common::createUnique ( initState, automaton.getStates ( ) ); + automaton.addState ( q0 ); + + regexp::UnboundedRegExpStructure < DefaultSymbolType > regexp { regexp::UnboundedRegExpEpsilon < DefaultSymbolType > ( ) }; + automaton.addTransition ( q0, regexp, initState ); + + automaton.setInitialState ( q0 ); + } + + if ( automaton.getFinalStates ( ).size ( ) > 1 ) { + StateType f = common::createUnique ( label::FinalStateLabel::instance < StateType > ( ), automaton.getStates ( ) ); + automaton.addState ( f ); + + for ( const StateType & state : automaton.getFinalStates ( ) ) { + regexp::UnboundedRegExpStructure < SymbolType > regexp { regexp::UnboundedRegExpEpsilon < SymbolType > ( ) }; + automaton.addTransition ( state, regexp, f ); + } + + ext::set < StateType > newFinalStates; + newFinalStates.insert ( f ); + automaton.setFinalStates ( newFinalStates ); + } +} + } /* namespace convert */ } /* namespace automaton */