From cf31335555c67beb5e1a025c848fa68865dde2b9 Mon Sep 17 00:00:00 2001 From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz> Date: Tue, 3 Dec 2019 19:18:56 +0100 Subject: [PATCH] Unordered DFTA and Unordered pattern matching with FTA --- .../exact/ExactPatternMatchingAutomaton.cpp | 4 + .../exact/ExactPatternMatchingAutomaton.h | 58 ++ .../exact/ExactSubtreeMatchingAutomaton.cpp | 2 + .../exact/ExactSubtreeMatchingAutomaton.h | 28 + .../src/automaton/determinize/Determinize.cpp | 14 + .../src/automaton/determinize/Determinize.h | 32 + .../determinize/DeterminizeNFTAPart.hxx | 70 ++ alib2algo/src/automaton/run/Occurrences.cpp | 7 + alib2algo/src/automaton/run/Occurrences.h | 23 + alib2algo/src/automaton/run/Run.h | 85 +++ alib2data/src/automaton/TA/UnorderedDFTA.cpp | 18 + alib2data/src/automaton/TA/UnorderedDFTA.h | 633 +++++++++++++++++ alib2data/src/automaton/TA/UnorderedNFTA.cpp | 21 + alib2data/src/automaton/TA/UnorderedNFTA.h | 661 ++++++++++++++++++ .../src/automaton/common/AutomatonNormalize.h | 13 + .../test-src/tests/arbologyTest.cpp | 35 + 16 files changed, 1704 insertions(+) create mode 100644 alib2data/src/automaton/TA/UnorderedDFTA.cpp create mode 100644 alib2data/src/automaton/TA/UnorderedDFTA.h create mode 100644 alib2data/src/automaton/TA/UnorderedNFTA.cpp create mode 100644 alib2data/src/automaton/TA/UnorderedNFTA.h diff --git a/alib2algo/src/arbology/exact/ExactPatternMatchingAutomaton.cpp b/alib2algo/src/arbology/exact/ExactPatternMatchingAutomaton.cpp index f2bcff82e3..3161fe9514 100644 --- a/alib2algo/src/arbology/exact/ExactPatternMatchingAutomaton.cpp +++ b/alib2algo/src/arbology/exact/ExactPatternMatchingAutomaton.cpp @@ -22,4 +22,8 @@ auto ExactPatternMatchingAutomatonRankedTree = registration::AbstractRegister < auto ExactPatternMatchingAutomatonRankedPattern = registration::AbstractRegister < arbology::exact::ExactPatternMatchingAutomaton, automaton::NFTA < DefaultSymbolType, unsigned >, const tree::RankedPattern < > & > ( arbology::exact::ExactPatternMatchingAutomaton::construct ); +auto ExactPatternMatchingAutomatonUnorderedRankedTree = registration::AbstractRegister < arbology::exact::ExactPatternMatchingAutomaton, automaton::UnorderedNFTA < DefaultSymbolType, unsigned >, const tree::UnorderedRankedTree < > & > ( arbology::exact::ExactPatternMatchingAutomaton::construct ); + +auto ExactPatternMatchingAutomatonUnorderedRankedPattern = registration::AbstractRegister < arbology::exact::ExactPatternMatchingAutomaton, automaton::UnorderedNFTA < DefaultSymbolType, unsigned >, const tree::UnorderedRankedPattern < > & > ( arbology::exact::ExactPatternMatchingAutomaton::construct ); + } /* namespace */ diff --git a/alib2algo/src/arbology/exact/ExactPatternMatchingAutomaton.h b/alib2algo/src/arbology/exact/ExactPatternMatchingAutomaton.h index 6b098de11b..0da09b3e75 100644 --- a/alib2algo/src/arbology/exact/ExactPatternMatchingAutomaton.h +++ b/alib2algo/src/arbology/exact/ExactPatternMatchingAutomaton.h @@ -14,6 +14,8 @@ #include <tree/ranked/RankedTree.h> #include <tree/ranked/RankedPattern.h> +#include <tree/ranked/UnorderedRankedTree.h> +#include <tree/ranked/UnorderedRankedPattern.h> #include <tree/ranked/PrefixRankedTree.h> #include <tree/ranked/PrefixRankedPattern.h> #include <tree/ranked/PrefixRankedBarTree.h> @@ -23,6 +25,7 @@ #include <automaton/PDA/VisiblyPushdownNPDA.h> #include <automaton/PDA/NPDA.h> #include <automaton/TA/NFTA.h> +#include <automaton/TA/UnorderedNFTA.h> #include <common/ranked_symbol.hpp> #include <alphabet/BottomOfTheStackSymbol.h> @@ -55,6 +58,12 @@ public: template < class SymbolType > static automaton::NFTA < SymbolType, unsigned > construct ( const tree::RankedPattern < SymbolType > & pattern ); + template < class SymbolType > + static automaton::UnorderedNFTA < SymbolType, unsigned > construct ( const tree::UnorderedRankedTree < SymbolType > & pattern ); + + template < class SymbolType > + static automaton::UnorderedNFTA < SymbolType, unsigned > construct ( const tree::UnorderedRankedPattern < SymbolType > & pattern ); + }; template < class SymbolType > @@ -261,6 +270,55 @@ automaton::NFTA < SymbolType, unsigned > ExactPatternMatchingAutomaton::construc return res; } +template < class SymbolType > +automaton::UnorderedNFTA < SymbolType, unsigned > ExactPatternMatchingAutomaton::construct ( const tree::UnorderedRankedTree < SymbolType > & pattern ) { + return ExactSubtreeMatchingAutomaton::construct ( pattern ); +} + +template < class SymbolType > +unsigned constructRecursivePattern ( const ext::tree < common::ranked_symbol < SymbolType > > & node, automaton::UnorderedNFTA < SymbolType, unsigned > & res, const common::ranked_symbol < SymbolType > & subtreeWildcard, unsigned & nextState ) { + if ( node.getData ( ) == subtreeWildcard ) { + unsigned state = nextState++; + res.addState ( state ); + + for ( const common::ranked_symbol < SymbolType > & symbol : res.getInputAlphabet ( ) ) { + ext::multiset < unsigned > states; + + for ( unsigned i = 0; i < ( unsigned ) symbol.getRank ( ); i++ ) + states.insert ( state ); + + res.addTransition ( symbol, states, state ); + } + + return state; + } else { + ext::multiset < unsigned > states; + + for ( const ext::tree < common::ranked_symbol < SymbolType > > & child : node.getChildren ( ) ) + states.insert ( constructRecursivePattern ( child, res, subtreeWildcard, nextState ) ); + + unsigned state = nextState++; + res.addState ( state ); + res.addTransition ( node.getData ( ), states, state ); + return state; + } +} + +template < class SymbolType > +automaton::UnorderedNFTA < SymbolType, unsigned > ExactPatternMatchingAutomaton::construct ( const tree::UnorderedRankedPattern < SymbolType > & pattern ) { + ext::set < common::ranked_symbol < SymbolType> > alphabet = pattern.getAlphabet ( ); + + alphabet.erase ( pattern.getSubtreeWildcard ( ) ); + + automaton::UnorderedNFTA < SymbolType, unsigned > res; + res.setInputAlphabet ( alphabet ); + + unsigned nextState = 0; + + res.addFinalState ( constructRecursivePattern ( pattern.getContent ( ), res, pattern.getSubtreeWildcard ( ), nextState ) ); + return res; +} + } /* namespace exact */ } /* namespace arbology */ diff --git a/alib2algo/src/arbology/exact/ExactSubtreeMatchingAutomaton.cpp b/alib2algo/src/arbology/exact/ExactSubtreeMatchingAutomaton.cpp index 74ea0b8b00..c8327fefbe 100644 --- a/alib2algo/src/arbology/exact/ExactSubtreeMatchingAutomaton.cpp +++ b/alib2algo/src/arbology/exact/ExactSubtreeMatchingAutomaton.cpp @@ -16,4 +16,6 @@ auto ExactSubtreeMatchingAutomatonPrefixRankedBarTree = registration::AbstractRe auto ExactSubtreeMatchingAutomatonRankedTree = registration::AbstractRegister < arbology::exact::ExactSubtreeMatchingAutomaton, automaton::NFTA < DefaultSymbolType, unsigned >, const tree::RankedTree < > & > ( arbology::exact::ExactSubtreeMatchingAutomaton::construct ); +auto ExactSubtreeMatchingAutomatonUnorderedRankedTree = registration::AbstractRegister < arbology::exact::ExactSubtreeMatchingAutomaton, automaton::UnorderedNFTA < DefaultSymbolType, unsigned >, const tree::UnorderedRankedTree < > & > ( arbology::exact::ExactSubtreeMatchingAutomaton::construct ); + } /* namespace */ diff --git a/alib2algo/src/arbology/exact/ExactSubtreeMatchingAutomaton.h b/alib2algo/src/arbology/exact/ExactSubtreeMatchingAutomaton.h index 5b6b53a225..0524631635 100644 --- a/alib2algo/src/arbology/exact/ExactSubtreeMatchingAutomaton.h +++ b/alib2algo/src/arbology/exact/ExactSubtreeMatchingAutomaton.h @@ -11,9 +11,11 @@ #include <tree/ranked/PrefixRankedBarTree.h> #include <tree/ranked/PrefixRankedTree.h> #include <tree/ranked/RankedTree.h> +#include <tree/ranked/UnorderedRankedTree.h> #include <automaton/PDA/InputDrivenNPDA.h> #include <automaton/TA/NFTA.h> +#include <automaton/TA/UnorderedNFTA.h> #include <alphabet/BottomOfTheStackSymbol.h> @@ -36,6 +38,9 @@ public: template < class SymbolType > static automaton::NFTA < SymbolType, unsigned > construct ( const tree::RankedTree < SymbolType > & pattern ); + template < class SymbolType > + static automaton::UnorderedNFTA < SymbolType, unsigned > construct ( const tree::UnorderedRankedTree < SymbolType > & pattern ); + }; template < class SymbolType > @@ -119,6 +124,29 @@ automaton::NFTA < SymbolType, unsigned > ExactSubtreeMatchingAutomaton::construc return res; } +template < class SymbolType > +unsigned constructRecursive ( const ext::tree < common::ranked_symbol < SymbolType > > & node, automaton::UnorderedNFTA < SymbolType, unsigned > & res, unsigned & nextState ) { + ext::multiset < unsigned > states; + + for ( const ext::tree < common::ranked_symbol < SymbolType > > & child : node.getChildren ( ) ) + states.insert ( constructRecursive ( child, res, nextState ) ); + + unsigned state = nextState++; + res.addState ( state ); + res.addTransition ( node.getData ( ), states, state ); + return state; +} + +template < class SymbolType > +automaton::UnorderedNFTA < SymbolType, unsigned > ExactSubtreeMatchingAutomaton::construct ( const tree::UnorderedRankedTree < SymbolType > & pattern ) { + automaton::UnorderedNFTA < SymbolType, unsigned > res; + + res.setInputAlphabet ( pattern.getAlphabet ( ) ); + unsigned nextState = 0; + res.addFinalState ( constructRecursive ( pattern.getContent ( ), res, nextState ) ); + return res; +} + } /* namespace exact */ } /* namespace arbology */ diff --git a/alib2algo/src/automaton/determinize/Determinize.cpp b/alib2algo/src/automaton/determinize/Determinize.cpp index b5b4185c61..6381a25f3f 100644 --- a/alib2algo/src/automaton/determinize/Determinize.cpp +++ b/alib2algo/src/automaton/determinize/Determinize.cpp @@ -16,6 +16,7 @@ #include <automaton/PDA/VisiblyPushdownDPDA.h> #include <automaton/TM/OneTapeDTM.h> #include <automaton/TA/DFTA.h> +#include <automaton/TA/UnorderedDFTA.h> #include <automaton/PDA/RealTimeHeightDeterministicNPDA.h> #include <registration/AlgoRegistration.hpp> @@ -40,6 +41,19 @@ auto DeterminizeMultiInitialStateNFA = registration::AbstractRegister < automato @param nfa nondeterministic finite automaton with multiple initial states\n\ @return deterministic finite automaton equivalent to @p nfa" ); +auto DeterminizeUnorderedDFTA = registration::AbstractRegister < automaton::determinize::Determinize, automaton::UnorderedDFTA < >, const automaton::UnorderedDFTA < > & > ( automaton::determinize::Determinize::determinize, "dfta" ).setDocumentation ( +"Determinization of deterministic finite tree automata.\n\ +Implemented as a no-op.\n\ +\n\ +@param dfta deterministic finite tree automaton\n\ +@return deterministic finite tree automaton equivalent to @p dfta" ); + +auto DeterminizeUnorderedNFTA = registration::AbstractRegister < automaton::determinize::Determinize, automaton::UnorderedDFTA < DefaultSymbolType, ext::set < DefaultSymbolType > >, const automaton::UnorderedNFTA < > & > ( automaton::determinize::Determinize::determinize, "nfta" ).setDocumentation ( +"Implementation of subset determinization for nondeterministic finite tree automata.\n\ +\n\ +@param nfta nondeterministic finite tree automaton\n\ +@return deterministic finite tree automaton equivalent to @p nfta" ); + auto DeterminizeDFTA = registration::AbstractRegister < automaton::determinize::Determinize, automaton::DFTA < >, const automaton::DFTA < > & > ( automaton::determinize::Determinize::determinize, "dfta" ).setDocumentation ( "Determinization of deterministic finite tree automata.\n\ Implemented as a no-op.\n\ diff --git a/alib2algo/src/automaton/determinize/Determinize.h b/alib2algo/src/automaton/determinize/Determinize.h index 6406acb071..b88e103672 100644 --- a/alib2algo/src/automaton/determinize/Determinize.h +++ b/alib2algo/src/automaton/determinize/Determinize.h @@ -37,6 +37,8 @@ #include <automaton/FSM/MultiInitialStateNFA.h> #include <automaton/TA/NFTA.h> #include <automaton/TA/DFTA.h> +#include <automaton/TA/UnorderedNFTA.h> +#include <automaton/TA/UnorderedDFTA.h> #include <automaton/transform/PDAToRHPDA.h> #include <automaton/transform/RHPDAToPDA.h> @@ -116,6 +118,31 @@ public: template < class SymbolType, class StateType > static automaton::DFTA < SymbolType, ext::set < StateType > > determinize ( const automaton::NFTA < SymbolType, StateType > & nfta ); + /** + * Determinization of deterministic finite tree automata. + * Implemented as a no-op. + * + * @tparam SymbolType Type for the input symbols. + * @tparam RankType Type for the rank (arity) in ranked alphabet. + * @tparam StateType Type for the states. + * @param dfta deterministic finite tree automaton + * @return deterministic finite tree automaton equivalent to @p dfta + */ + template < class SymbolType, class StateType > + static automaton::UnorderedDFTA < SymbolType, StateType > determinize ( const automaton::UnorderedDFTA < SymbolType, StateType > & automaton ); + + /** + * Implementation of subset determinization for nondeterministic finite tree automata. + * + * @tparam SymbolType Type for the input symbols. + * @tparam RankType Type for the rank (arity) in ranked alphabet. + * @tparam StateType Type for the states. + * @param nfta nondeterministic finite tree automaton + * @return deterministic finite tree automaton equivalent to @p nfta + */ + template < class SymbolType, class StateType > + static automaton::UnorderedDFTA < SymbolType, ext::set < StateType > > determinize ( const automaton::UnorderedNFTA < SymbolType, StateType > & nfta ); + /** * Determinization of deterministic input-driven pushdown automata. * Implemented as a no-op. @@ -252,6 +279,11 @@ automaton::DFTA < SymbolType, StateType > Determinize::determinize ( const autom return automaton; } +template < class SymbolType, class StateType > +automaton::UnorderedDFTA < SymbolType, StateType > Determinize::determinize ( const automaton::UnorderedDFTA < SymbolType, StateType > & automaton ) { + return automaton; +} + template < class InputSymbolType, class PushdownSymbolType, class StateType > automaton::InputDrivenDPDA < InputSymbolType, PushdownSymbolType, StateType > Determinize::determinize ( const automaton::InputDrivenDPDA < InputSymbolType, PushdownSymbolType, StateType > & automaton ) { return automaton; diff --git a/alib2algo/src/automaton/determinize/DeterminizeNFTAPart.hxx b/alib2algo/src/automaton/determinize/DeterminizeNFTAPart.hxx index 5853e929d0..b75caaf06c 100644 --- a/alib2algo/src/automaton/determinize/DeterminizeNFTAPart.hxx +++ b/alib2algo/src/automaton/determinize/DeterminizeNFTAPart.hxx @@ -82,6 +82,76 @@ automaton::DFTA < SymbolType, ext::set < StateType > > Determinize::determinize return res; } + +template < class SymbolType, class StateType > +void constructTransitions ( const common::ranked_symbol < SymbolType > & symbol, typename ext::multiset < StateType >::const_iterator state, typename ext::multiset < StateType >::const_iterator end, const StateType & rhs, const ext::multimap < StateType, ext::set < StateType > > & nftaStateToDftaStates, ext::multiset < ext::set < StateType > > & transitionLHS, ext::map < ext::pair < common::ranked_symbol < SymbolType >, ext::multiset < ext::set < StateType > > >, ext::set < StateType > > & resultTransition ) { + if ( state == end ) { + resultTransition [ ext::make_pair ( symbol, transitionLHS ) ].insert ( rhs ); + } else { + for ( const std::pair < const StateType, ext::set < StateType > > & dftaState : nftaStateToDftaStates.equal_range ( * state ) ) { + transitionLHS.insert ( dftaState.second ); + constructTransitions ( symbol, std::next ( state ), end, rhs, nftaStateToDftaStates, transitionLHS, resultTransition ); + transitionLHS.erase ( transitionLHS.find ( dftaState.second ) ); + } + } +} + +template < class SymbolType, class StateType > +automaton::UnorderedDFTA < SymbolType, ext::set < StateType > > Determinize::determinize ( const automaton::UnorderedNFTA < SymbolType, StateType > & nfta ) { + automaton::UnorderedDFTA < SymbolType, ext::set < StateType > > res; + + res.setInputAlphabet ( nfta.getInputAlphabet ( ) ); + + ext::multimap < StateType, ext::set < StateType > > nftaStateToDftaStates; // each dfta state must be inserted only once to each nfta d-subset state + + for ( const auto & symbol : nfta.getInputAlphabet ( ) ) { + if ( symbol.getRank ( ) != 0 ) + continue; + + ext::set < StateType > dftaState; + ext::multiset < StateType > source { }; + for ( const auto & transition : nfta.getTransitions ( ).equal_range ( ext::tie ( symbol, source ) ) ) + dftaState.insert ( transition.second ); + + for ( const auto & state : dftaState ) + nftaStateToDftaStates.insert ( state, dftaState ); + + res.addState ( dftaState ); + + res.addTransition ( symbol, ext::multiset < ext::set < StateType > > { }, dftaState ); + } + + bool added = true; + while ( added ) { + added = false; + + ext::map < ext::pair < common::ranked_symbol < SymbolType >, ext::multiset < ext::set < StateType > > >, ext::set < StateType > > transitions; + + for ( const auto & transition : nfta.getTransitions ( ) ) { + ext::multiset < ext::set < StateType > > transitionLHS; + constructTransitions ( transition.first.first, transition.first.second.begin ( ), transition.first.second.end ( ), transition.second, nftaStateToDftaStates, transitionLHS, transitions ); + } + + for ( const std::pair < const ext::pair < common::ranked_symbol < SymbolType >, ext::multiset < ext::set < StateType > > >, ext::set < StateType > > & transition : transitions ) { + if ( res.addState ( transition.second ) ) { + added = true; + + for ( const auto & state : transition.second ) + nftaStateToDftaStates.insert ( state, transition.second ); + } + res.addTransition ( transition.first.first, transition.first.second, transition.second ); + } + + } + + const ext::set < StateType > & finalLabels = nfta.getFinalStates(); + for ( const ext::set < StateType > & dfaState : res.getStates ( ) ) + if ( ! ext::excludes ( finalLabels.begin ( ), finalLabels.end ( ), dfaState.begin ( ), dfaState.end ( ) ) ) + res.addFinalState ( dfaState ); + + return res; +} + } /* namespace determinize */ } /* namespace automaton */ diff --git a/alib2algo/src/automaton/run/Occurrences.cpp b/alib2algo/src/automaton/run/Occurrences.cpp index 3fe9695c9c..c6a15993e2 100644 --- a/alib2algo/src/automaton/run/Occurrences.cpp +++ b/alib2algo/src/automaton/run/Occurrences.cpp @@ -24,6 +24,13 @@ auto OccurrencesDFTARankedTree = registration::AbstractRegister < automaton::run @param string the input of the automaton\n\ @return set of indexes to the string where the automaton passed a final state" ); +auto OccurrencesUnorderedDFTARankedTree = registration::AbstractRegister < automaton::run::Occurrences, ext::set < unsigned >, const automaton::UnorderedDFTA < > &, const tree::UnorderedRankedTree < > & > ( automaton::run::Occurrences::occurrences, "automaton", "tree" ).setDocumentation ( +"Automaton occurrences run implementation.\n\ +\n\ +@param automaton the runned automaton\n\ +@param string the input of the automaton\n\ +@return set of indexes to the string where the automaton passed a final state" ); + auto OccurrencesInputDrivenDPDALinearString = registration::AbstractRegister < automaton::run::Occurrences, ext::set < unsigned >, const automaton::InputDrivenDPDA < > &, const string::LinearString < > & > ( automaton::run::Occurrences::occurrences, "automaton", "string" ).setDocumentation ( "Automaton occurrences run implementation.\n\ \n\ diff --git a/alib2algo/src/automaton/run/Occurrences.h b/alib2algo/src/automaton/run/Occurrences.h index 166265c603..eda7144c6d 100644 --- a/alib2algo/src/automaton/run/Occurrences.h +++ b/alib2algo/src/automaton/run/Occurrences.h @@ -14,6 +14,7 @@ #include "Run.h" #include <automaton/FSM/DFA.h> #include <automaton/TA/DFTA.h> +#include <automaton/TA/UnorderedDFTA.h> #include <automaton/PDA/InputDrivenDPDA.h> #include <automaton/PDA/VisiblyPushdownDPDA.h> #include <automaton/PDA/RealTimeHeightDeterministicDPDA.h> @@ -60,6 +61,21 @@ public: template < class SymbolType, class StateType > static ext::set < unsigned > occurrences ( const automaton::DFTA < SymbolType, StateType > & automaton, const tree::RankedTree < SymbolType > & tree ); + /** + * \override + * + * \tparam SymbolType type of symbols of tree nodes and terminal symbols of the runned automaton + * \tparam RankType type of ranks of tree nodes and terminal symbols of the runned automaton + * \tparam StateType type of states of the runned automaton + * + * \param automaton the runned automaton + * \param string the input of the automaton + * + * \return set of indexes to the tree where the automaton passed a final state (as in the postorder traversal) + */ + template < class SymbolType, class StateType > + static ext::set < unsigned > occurrences ( const automaton::UnorderedDFTA < SymbolType, StateType > & automaton, const tree::UnorderedRankedTree < SymbolType > & tree ); + /** * \override * @@ -136,6 +152,13 @@ ext::set < unsigned > Occurrences::occurrences ( const automaton::DFTA < SymbolT return std::get < 2 > ( res ); } +template < class SymbolType, class StateType > +ext::set < unsigned > Occurrences::occurrences ( const automaton::UnorderedDFTA < SymbolType, StateType > & automaton, const tree::UnorderedRankedTree < SymbolType > & tree ) { + ext::tuple < bool, StateType, ext::set < unsigned > > res = Run::calculateState ( automaton, tree ); + + return std::get < 2 > ( res ); +} + template < class InputSymbolType, class PushdownStoreSymbolType, class StateType > ext::set < unsigned > Occurrences::occurrences ( const automaton::InputDrivenDPDA < InputSymbolType, PushdownStoreSymbolType, StateType > & automaton, const string::LinearString < InputSymbolType > & string ) { ext::tuple < bool, StateType, ext::set < unsigned >, ext::deque < PushdownStoreSymbolType > > res = Run::calculateState ( automaton, string ); diff --git a/alib2algo/src/automaton/run/Run.h b/alib2algo/src/automaton/run/Run.h index 4c6a05225a..1c51792b96 100644 --- a/alib2algo/src/automaton/run/Run.h +++ b/alib2algo/src/automaton/run/Run.h @@ -10,12 +10,14 @@ #include <string/LinearString.h> #include <tree/ranked/RankedTree.h> +#include <tree/ranked/UnorderedRankedTree.h> #include <automaton/FSM/DFA.h> #include <automaton/FSM/NFA.h> #include <automaton/FSM/EpsilonNFA.h> #include <automaton/TA/DFTA.h> #include <automaton/TA/NFTA.h> +#include <automaton/TA/UnorderedDFTA.h> #include <automaton/PDA/InputDrivenDPDA.h> #include <automaton/PDA/VisiblyPushdownDPDA.h> #include <automaton/PDA/RealTimeHeightDeterministicDPDA.h> @@ -59,6 +61,25 @@ class Run { template < class SymbolType, class StateType > static ext::pair < bool, StateType > calculateState ( const automaton::DFTA < SymbolType, StateType > & automaton, const ext::tree < common::ranked_symbol < SymbolType > > & node, ext::set < unsigned > & occ, unsigned & i ); + /** + * Recursive implementation of automaton run over a tree. + * + * \tparam SymbolType type of symbols of tree nodes and terminal symbols of the runned automaton + * \tparam RankType type of ranks of tree nodes and terminal symbols of the runned automaton + * \tparam StateType type of states of the runned automaton + * + * \param automaton the runned automaton + * \param string the input of the automaton + * \param occ the set of collected occurrences + * \param i the index to the tree following the postorder traversal + * + * \return pair of + * true if the automaton does not fail to find transitions, false otherwise + * state where the computation ended + */ + template < class SymbolType, class StateType > + static ext::pair < bool, StateType > calculateState ( const automaton::UnorderedDFTA < SymbolType, StateType > & automaton, const ext::tree < common::ranked_symbol < SymbolType > > & node, ext::set < unsigned > & occ, unsigned & i ); + /** * \override * @@ -161,6 +182,24 @@ public: template < class SymbolType, class StateType > static ext::tuple < bool, StateType, ext::set < unsigned > > calculateState ( const automaton::DFTA < SymbolType, StateType > & automaton, const tree::RankedTree < SymbolType > & tree ); + /** + * \override + * + * \tparam SymbolType type of symbols of tree nodes and terminal symbols of the runned automaton + * \tparam RankType type of ranks of tree nodes and terminal symbols of the runned automaton + * \tparam StateType type of states of the runned automaton + * + * \param automaton the runned automaton + * \param string the input of the automaton + * + * \return tuple of + * true if the automaton does not fail to find transitions, false otherwise + * state where the run stopped + * set of indexes to the tree where the automaton passed a final state (as in the postorder traversal) + */ + template < class SymbolType, class StateType > + static ext::tuple < bool, StateType, ext::set < unsigned > > calculateState ( const automaton::UnorderedDFTA < SymbolType, StateType > & automaton, const tree::UnorderedRankedTree < SymbolType > & tree ); + /** * \override * @@ -448,6 +487,52 @@ ext::tuple < bool, StateType, ext::set < unsigned > > Run::calculateState ( cons // ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +template < class SymbolType, class StateType > +ext::pair < bool, StateType > Run::calculateState ( const automaton::UnorderedDFTA < SymbolType, StateType > & automaton, const ext::tree < common::ranked_symbol < SymbolType > > & node, ext::set < unsigned > & occ, unsigned & i ) { + ext::multiset < StateType > states; + + unsigned tmp = i; + i++; + + bool sign = true; + + for ( const ext::tree < common::ranked_symbol < SymbolType > > & child : node.getChildren ( ) ) { + ext::pair < bool, StateType > res = calculateState ( automaton, child, occ, i ); + + if ( res.first == false ) + sign = false; + else + states.insert ( res.second ); + } + + if ( !sign ) return ext::make_pair ( false, label::FailStateLabel::instance < StateType > ( ) ); + + const auto & it = automaton.getTransitions ( ).find ( ext::make_pair ( node.getData ( ), states ) ); + + if ( it == automaton.getTransitions ( ).end ( ) ) return ext::make_pair ( false, label::FailStateLabel::instance < StateType > ( ) ); + + StateType state = it->second; + + if ( automaton.getFinalStates ( ).count ( state ) ) occ.insert ( tmp ); + + if ( common::GlobalData::verbose ) + common::Streams::log << state << std::endl; + + return ext::make_pair ( true, state ); +} + +template < class SymbolType, class StateType > +ext::tuple < bool, StateType, ext::set < unsigned > > Run::calculateState ( const automaton::UnorderedDFTA < SymbolType, StateType > & automaton, const tree::UnorderedRankedTree < SymbolType > & tree ) { + ext::set < unsigned > occ; + unsigned i = 0; + ext::pair < bool, StateType > res = calculateState ( automaton, tree.getContent ( ), occ, i ); + + return ext::make_tuple ( res.first, res.second, occ ); +} + +// ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + template < class SymbolType, class StateType > ext::pair < bool, ext::set < StateType > > Run::calculateStates ( const automaton::NFTA < SymbolType, StateType > & automaton, const ext::tree < common::ranked_symbol < SymbolType > > & node, ext::set < unsigned > & occ, unsigned & i ) { ext::vector < ext::set < StateType > > resStates; diff --git a/alib2data/src/automaton/TA/UnorderedDFTA.cpp b/alib2data/src/automaton/TA/UnorderedDFTA.cpp new file mode 100644 index 0000000000..6c08bc4848 --- /dev/null +++ b/alib2data/src/automaton/TA/UnorderedDFTA.cpp @@ -0,0 +1,18 @@ +/* + * UnorderedDFTA.cpp + * + * Created on: Apr 14, 2015 + * Author: Stepan Plachy + */ + +#include "UnorderedDFTA.h" + +#include <registration/ValuePrinterRegistration.hpp> + +template class automaton::UnorderedDFTA < >; + +namespace { + +auto valuePrinter = registration::ValuePrinterRegister < automaton::UnorderedDFTA < > > ( ); + +} /* namespace */ diff --git a/alib2data/src/automaton/TA/UnorderedDFTA.h b/alib2data/src/automaton/TA/UnorderedDFTA.h new file mode 100644 index 0000000000..8f5c50c24e --- /dev/null +++ b/alib2data/src/automaton/TA/UnorderedDFTA.h @@ -0,0 +1,633 @@ +/* + * UnorderedDFTA.h + * + * This file is part of Algorithms library toolkit. + * Copyright (C) 2017 Jan Travnicek (jan.travnicek@fit.cvut.cz) + + * Algorithms library toolkit is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * Algorithms library toolkit is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with Algorithms library toolkit. If not, see <http://www.gnu.org/licenses/>. + * + * Created on: Apr 14, 2015 + * Author: Stepan Plachy + */ + +#ifndef UNORDERED_DFTA_H_ +#define UNORDERED_DFTA_H_ + +#include <ostream> +#include <sstream> + +#include <alib/map> +#include <alib/set> +#include <alib/multiset> +#include <alib/compare> + +#include <core/components.hpp> +#include <common/ranked_symbol.hpp> + +#include <common/DefaultStateType.h> +#include <common/DefaultSymbolType.h> + +#include <automaton/AutomatonException.h> + +#include <core/normalize.hpp> +#include <alphabet/common/SymbolNormalize.h> +#include <automaton/common/AutomatonNormalize.h> + +namespace automaton { + +class InputAlphabet; +class States; +class FinalStates; + +/** + * \brief + * Nondeterministic finite tree automaton without epsilon transitions. Accepts regular tree languages. + + * \details + * Definition is classical definition of finite automata. + * A = (Q, T, \delta, F), + * Q (States) = nonempty finite set of states, + * T (TerminalAlphabet) = finite set of terminal ranked symbols - having this empty won't let automaton do much though, + * \delta = transition function of the form (A, B, C, ...) \times a -> X, where A, B, C, ..., X \in Q and a \in T, + * F (FinalStates) = set of final states + * + * Elements of the \delta mapping must meet following criteria. The size of the state list must equal the rank of the ranked symbol. + * + * Note that target state of a transition is required. + * This class is used to store minimal, total, ... variants of deterministic finite tree automata. + * + * Elements of the \delta mapping must meet following criteria. The size of the state list must equal the rank of the ranked symbol. + * + * \tparam SymbolTypeT used for the symbol part of the ranked symbol + * \tparam StateTypeT used to the states, and the initial state of the automaton. + */ +template < class SymbolTypeT = DefaultSymbolType, class StateTypeT = DefaultStateType > +class UnorderedDFTA final : public ext::CompareOperators < UnorderedDFTA < SymbolTypeT, StateTypeT > >, public core::Components < UnorderedDFTA < SymbolTypeT, StateTypeT >, ext::set < common::ranked_symbol < SymbolTypeT > >, component::Set, InputAlphabet, ext::set < StateTypeT >, component::Set, std::tuple < States, FinalStates > > { +public: + typedef SymbolTypeT SymbolType; + typedef StateTypeT StateType; + +private: + /** + * Transition function as mapping from a list of states times an input symbol on the left hand side to a state. + */ + ext::map < ext::pair < common::ranked_symbol < SymbolType >, ext::multiset < StateType > >, StateType > transitions; + +public: + /** + * \brief Creates a new instance of the automaton. + */ + explicit UnorderedDFTA ( ); + + /** + * \brief Creates a new instance of the automaton with a concrete set of states, input alphabet, and a set of final states. + * + * \param states the initial set of states of the automaton + * \param inputAlphabet the initial input alphabet + * \param finalStates the initial set of final states of the automaton + */ + explicit UnorderedDFTA ( ext::set < StateType > states, ext::set < common::ranked_symbol < SymbolType > > inputAlphabet, ext::set < StateType > finalStates ); + + /** + * Getter of states. + * + * \returns the states of the automaton + */ + const ext::set < StateType > & getStates ( ) const & { + return this->template accessComponent < States > ( ).get ( ); + } + + /** + * Getter of states. + * + * \returns the states of the automaton + */ + ext::set < StateType > && getStates ( ) && { + return std::move ( this->template accessComponent < States > ( ).get ( ) ); + } + + /** + * Adder of a state. + * + * \param state the new state to be added to a set of states + * + * \returns true if the state was indeed added + */ + bool addState ( StateType state ) { + return this->template accessComponent < States > ( ).add ( std::move ( state ) ); + } + + /** + * Setter of states. + * + * \param states completely new set of states + */ + void setStates ( ext::set < StateType > states ) { + this->template accessComponent < States > ( ).set ( std::move ( states ) ); + } + + /** + * Remover of a state. + * + * \param state a state to be removed from a set of states + * + * \returns true if the state was indeed removed + */ + void removeState ( const StateType & state ) { + this->template accessComponent < States > ( ).remove ( state ); + } + + /** + * Getter of final states. + * + * \returns the final states of the automaton + */ + const ext::set < StateType > & getFinalStates ( ) const & { + return this->template accessComponent < FinalStates > ( ).get ( ); + } + + /** + * Getter of final states. + * + * \returns the final states of the automaton + */ + ext::set < StateType > && getFinalStates ( ) && { + return std::move ( this->template accessComponent < FinalStates > ( ).get ( ) ); + } + + /** + * Adder of a final state. + * + * \param state the new state to be added to a set of final states + * + * \returns true if the state was indeed added + */ + bool addFinalState ( StateType state ) { + return this->template accessComponent < FinalStates > ( ).add ( std::move ( state ) ); + } + + /** + * Setter of final states. + * + * \param states completely new set of final states + */ + void setFinalStates ( ext::set < StateType > states ) { + this->template accessComponent < FinalStates > ( ).set ( std::move ( states ) ); + } + + /** + * Remover of a final state. + * + * \param state a state to be removed from a set of final states + * + * \returns true if the state was indeed removed + */ + void removeFinalState ( const StateType & state ) { + this->template accessComponent < FinalStates > ( ).remove ( state ); + } + + /** + * Getter of the input alphabet. + * + * \returns the input alphabet of the automaton + */ + const ext::set < common::ranked_symbol < SymbolType > > & getInputAlphabet ( ) const & { + return this->template accessComponent < InputAlphabet > ( ).get ( ); + } + + /** + * Getter of the input alphabet. + * + * \returns the input alphabet of the automaton + */ + ext::set < common::ranked_symbol < SymbolType > > && getInputAlphabet ( ) && { + return std::move ( this->template accessComponent < InputAlphabet > ( ).get ( ) ); + } + + /** + * Adder of a input symbol. + * + * \param symbol the new symbol to be added to an input alphabet + * + * \returns true if the symbol was indeed added + */ + bool addInputSymbol ( common::ranked_symbol < SymbolType > symbol ) { + return this->template accessComponent < InputAlphabet > ( ).add ( std::move ( symbol ) ); + } + + /** + * Adder of input symbols. + * + * \param symbols new symbols to be added to an input alphabet + */ + void addInputSymbols ( ext::set < common::ranked_symbol < SymbolType > > symbols ) { + this->template accessComponent < InputAlphabet > ( ).add ( std::move ( symbols ) ); + } + + /** + * Setter of input alphabet. + * + * \param symbols completely new input alphabet + */ + void setInputAlphabet ( ext::set < common::ranked_symbol < SymbolType > > symbols ) { + this->template accessComponent < InputAlphabet > ( ).set ( std::move ( symbols ) ); + } + + /** + * Remover of an input symbol. + * + * \param symbol a symbol to be removed from an input alphabet + * + * \returns true if the symbol was indeed removed + */ + void removeInputSymbol ( const common::ranked_symbol < SymbolType > & symbol ) { + this->template accessComponent < InputAlphabet > ( ).remove ( symbol ); + } + + /** + * \brief Add a transition to the automaton. + * + * \details The transition is in a form ( A, B, C, ... ) \times a -> X, where A, B, C, ..., X \in Q and a \in T + * + * \param children the source states (A, B, C, ...) + * \param current the input symbol (a) + * \param next the target state (B) + * + * \throws AutomatonException when transition contains state or symbol not present in the automaton components + * + * \returns true if the transition was indeed added + */ + bool addTransition ( common::ranked_symbol < SymbolType > symbol, ext::multiset < StateType > prevStates, StateType next ); + + /** + * \brief Removes a transition from the automaton. + * + * \details The transition is in a form ( A, B, C, ... ) \times a -> X, where A, B, C, ..., X \in Q and a \in T + * + * \param children the source states (A, B, C, ...) + * \param current the input symbol (a) + * \param next the target state (B) + * + * \returns true if the transition was indeed removed + */ + bool removeTransition ( const common::ranked_symbol < SymbolType > & symbol, const ext::multiset < StateType > & states, const StateType & next ); + + /** + * Get the transition function of the automaton in its natural form. + * + * \returns transition function of the automaton + */ + const ext::map < ext::pair < common::ranked_symbol < SymbolType >, ext::multiset < StateType > >, StateType > & getTransitions ( ) const & { + return transitions; + } + + /** + * Get the transition function of the automaton in its natural form. + * + * \returns transition function of the automaton + */ + ext::map < ext::pair < common::ranked_symbol < SymbolType >, ext::multiset < StateType > >, StateType > && getTransitions ( ) && { + return std::move ( transitions ); + } + + /** + * \returns transitions to state @p q + */ + ext::map < ext::pair < common::ranked_symbol < SymbolType >, ext::multiset < StateType > >, StateType > getTransitionsToState ( const StateType & q ) const { + ext::map < ext::pair < common::ranked_symbol < SymbolType >, ext::multiset < StateType > >, StateType > res; + + for ( const auto & transition : getTransitions ( ) ) { + if ( transition.second == q ) + res.insert ( std::make_pair ( transition.first, q ) ); + } + + return res; + } + + /** + * \returns transitions from state @p q + */ + ext::map < ext::pair < common::ranked_symbol < SymbolType >, ext::multiset < StateType > >, StateType > getTransitionsFromState ( const StateType & q ) const { + ext::map < ext::pair < common::ranked_symbol < SymbolType >, ext::multiset < StateType > >, StateType > res; + + for ( const auto & transition : getTransitions ( ) ) { + if ( std::find ( transition.first.second.begin ( ), transition.first.second.end ( ), q ) != transition.first.second.end ( ) ) + res.insert ( transition ); + } + + return res; + } + + /** + * The actual compare method + * + * \param other the other instance + * + * \returns the actual relation between two by type same automata instances + */ + int compare ( const UnorderedDFTA & other ) const; + + /** + * Print this object as raw representation to ostream. + * + * \param out ostream where to print + * \param instance object to print + * + * \returns modified output stream + */ + friend std::ostream & operator << ( std::ostream & out, const UnorderedDFTA & instance ) { + return out << "(UnorderedDFTA " + << " states = " << instance.getStates ( ) + << " inputAlphabet = " << instance.getInputAlphabet ( ) + << " finalStates = " << instance.getFinalStates ( ) + << " transitions = " << instance.getTransitions ( ) + << ")"; + } + + /** + * Casts this instance to as compact as possible string representation. + * + * \returns string representation of the object + */ + operator std::string ( ) const; +}; + +/** + * Trait to detect whether the type parameter T is or is not UnorderedDFTA. Derived from std::false_type. + * + * \tparam T the tested type parameter + */ +template < class T > +class isUnorderedDFTA_impl : public std::false_type {}; + +/** + * Trait to detect whether the type parameter T is or is not UnorderedDFTA. Derived from std::true_type. + * + * Specialisation for UnorderedDFTA. + * + * \tparam SymbolType used for the terminal alphabet of the automaton + * \tparam StateType used for the terminal alphabet of the automaton + */ +template < class SymbolType, class StateType > +class isUnorderedDFTA_impl < UnorderedDFTA < SymbolType, StateType > > : public std::true_type {}; + +/** + * Constexpr true if the type parameter T is UnorderedDFTA, false otherwise. + * + * \tparam T the tested type parameter + */ +template < class T > +constexpr bool isUnorderedDFTA = isUnorderedDFTA_impl < T > { }; + +template<class SymbolType, class StateType > +UnorderedDFTA < SymbolType, StateType >::UnorderedDFTA ( ext::set < StateType > states, ext::set < common::ranked_symbol < SymbolType > > inputAlphabet, ext::set < StateType > finalStates ) : core::Components < UnorderedDFTA, ext::set < common::ranked_symbol < SymbolType > >, component::Set, InputAlphabet, ext::set < StateType >, component::Set, std::tuple < States, FinalStates > > ( std::move ( inputAlphabet ), std::move ( states ), std::move ( finalStates ) ) { +} + +template<class SymbolType, class StateType > +UnorderedDFTA < SymbolType, StateType >::UnorderedDFTA() : UnorderedDFTA ( ext::set < StateType > { }, ext::set < common::ranked_symbol < SymbolType > > { }, ext::set < StateType > { } ) { +} + +template<class SymbolType, class StateType > +bool UnorderedDFTA < SymbolType, StateType >::addTransition ( common::ranked_symbol < SymbolType > symbol, ext::multiset<StateType> prevStates, StateType next) { + if ( prevStates.size() != ( size_t ) symbol.getRank() ) + throw AutomatonException("Number of states doesn't match rank of the symbol"); + + if (! getInputAlphabet().count(symbol)) + throw AutomatonException("Input symbol \"" + ext::to_string ( symbol ) + "\" doesn't exist."); + + if (! getStates().count(next)) + throw AutomatonException("State \"" + ext::to_string ( next ) + "\" doesn't exist."); + + for ( const StateType & it : prevStates) { + if (! getStates().count(it)) + throw AutomatonException("State \"" + ext::to_string ( it ) + "\" doesn't exist."); + } + + ext::pair<common::ranked_symbol < SymbolType >, ext::multiset<StateType> > key = ext::make_pair ( std::move ( symbol ), std::move ( prevStates ) ); + if ( transitions.find ( key ) != transitions.end ( ) ) { + if ( transitions.find ( key )->second == next ) + return false; + else + throw AutomatonException("Transition already exists"); + } + + transitions.insert ( std::move ( key ), std::move ( next ) ); + return true; +} + +template<class SymbolType, class StateType > +bool UnorderedDFTA < SymbolType, StateType >::removeTransition(const common::ranked_symbol < SymbolType > & symbol, const ext::multiset<StateType> & states, const StateType & next) { + ext::pair<common::ranked_symbol < SymbolType >, ext::multiset<StateType> > key = ext::make_pair(symbol, states); + + if ( transitions.find ( key ) == transitions.end ( ) ) + return false; + + if ( transitions.find ( key )->second != next ) + throw AutomatonException("Transition does not exist"); + + transitions.erase(key); + return true; +} + +template<class SymbolType, class StateType > +int UnorderedDFTA < SymbolType, StateType >::compare(const UnorderedDFTA& other) const { + auto first = ext::tie(getStates(), getInputAlphabet(), getFinalStates(), transitions); + auto second = ext::tie(other.getStates(), other.getInputAlphabet(), other.getFinalStates(), other.transitions); + + static ext::compare<decltype(first)> comp; + return comp(first, second); +} + +template<class SymbolType, class StateType > +UnorderedDFTA < SymbolType, StateType >::operator std::string ( ) const { + std::stringstream ss; + ss << *this; + return ss.str(); +} + +} /* namespace automaton */ + +namespace core { + +/** + * Helper class specifying constraints for the automaton's internal input alphabet component. + * + * \tparam SymbolType used for the symbol part of the ranked symbol + * \tparam StateType used for the terminal alphabet of the automaton. + */ +template<class SymbolType, class StateType > +class SetConstraint< automaton::UnorderedDFTA < SymbolType, StateType >, common::ranked_symbol < SymbolType >, automaton::InputAlphabet > { +public: + /** + * Returns true if the symbol is still used in some transition of the automaton. + * + * \param automaton the tested automaton + * \param symbol the tested symbol + * + * \returns true if the symbol is used, false othervise + */ + static bool used ( const automaton::UnorderedDFTA < SymbolType, StateType > & automaton, const common::ranked_symbol < SymbolType > & symbol ) { + for ( const std::pair<const ext::pair<common::ranked_symbol < SymbolType >, ext::multiset<StateType> >, StateType>& t : automaton.getTransitions()) + if (t.first.first == symbol) + return true; + + return false; + } + + /** + * Returns true as all symbols are possibly available to be elements of the input alphabet. + * + * \param automaton the tested automaton + * \param symbol the tested symbol + * + * \returns true + */ + static bool available ( const automaton::UnorderedDFTA < SymbolType, StateType > &, const common::ranked_symbol < SymbolType > & ) { + return true; + } + + /** + * All symbols are valid as input symbols. + * + * \param automaton the tested automaton + * \param symbol the tested symbol + */ + static void valid ( const automaton::UnorderedDFTA < SymbolType, StateType > &, const common::ranked_symbol < SymbolType > & ) { + } +}; + +/** + * Helper class specifying constraints for the automaton's internal states component. + * + * \tparam SymbolType used for the symbol part of the ranked symbol + * \tparam StateType used for the terminal alphabet of the automaton. + */ +template<class SymbolType, class StateType > +class SetConstraint< automaton::UnorderedDFTA < SymbolType, StateType >, StateType, automaton::States > { +public: + /** + * Returns true if the state is still used in some transition of the automaton. + * + * \param automaton the tested automaton + * \param state the tested state + * + * \returns true if the state is used, false othervise + */ + static bool used ( const automaton::UnorderedDFTA < SymbolType, StateType > & automaton, const StateType & state ) { + if ( automaton.getFinalStates ( ).count ( state ) ) + return true; + + for ( const std::pair<const ext::pair<common::ranked_symbol < SymbolType >, ext::multiset<StateType> >, StateType>& t : automaton.getTransitions()) + if(ext::contains(t.first.second.begin(), t.first.second.end(), state ) || t.second == state) + return true; + + return false; + } + + /** + * Returns true as all states are possibly available to be elements of the states. + * + * \param automaton the tested automaton + * \param state the tested state + * + * \returns true + */ + static bool available ( const automaton::UnorderedDFTA < SymbolType, StateType > &, const StateType & ) { + return true; + } + + /** + * All states are valid as a state of the automaton. + * + * \param automaton the tested automaton + * \param state the tested state + */ + static void valid ( const automaton::UnorderedDFTA < SymbolType, StateType > &, const StateType & ) { + } +}; + +/** + * Helper class specifying constraints for the automaton's internal final states component. + * + * \tparam SymbolType used for the symbol part of the ranked symbol + * \tparam StateType used for the terminal alphabet of the automaton. + */ +template<class SymbolType, class StateType > +class SetConstraint< automaton::UnorderedDFTA < SymbolType, StateType >, StateType, automaton::FinalStates > { +public: + /** + * Returns false. Final state is only a mark that the automaton itself does require further. + * + * \param automaton the tested automaton + * \param state the tested state + * + * \returns false + */ + static bool used ( const automaton::UnorderedDFTA < SymbolType, StateType > &, const StateType & ) { + return false; + } + + /** + * Determines whether the state is available in the automaton's states set. + * + * \param automaton the tested automaton + * \param state the tested state + * + * \returns true if the state is already in the set of states of the automaton + */ + static bool available ( const automaton::UnorderedDFTA < SymbolType, StateType > & automaton, const StateType & state ) { + return automaton.template accessComponent < automaton::States > ( ).get ( ).count ( state ); + } + + /** + * All states are valid as a final state of the automaton. + * + * \param automaton the tested automaton + * \param state the tested state + */ + static void valid ( const automaton::UnorderedDFTA < SymbolType, StateType > &, const StateType & ) { + } +}; + +/** + * Helper for normalisation of types specified by templates used as internal datatypes of symbols and states. + * + * \returns new instance of the automaton with default template parameters or unmodified instance if the template parameters were already the default ones + */ +template < class SymbolType, class StateType > +struct normalize < automaton::UnorderedDFTA < SymbolType, StateType > > { + static automaton::UnorderedDFTA < > eval ( automaton::UnorderedDFTA < SymbolType, StateType > && value ) { + ext::set < common::ranked_symbol < > > alphabet = alphabet::SymbolNormalize::normalizeRankedAlphabet ( std::move ( value ).getInputAlphabet ( ) ); + ext::set < DefaultStateType > states = automaton::AutomatonNormalize::normalizeStates ( std::move ( value ).getStates ( ) ); + ext::set < DefaultStateType > finalStates = automaton::AutomatonNormalize::normalizeStates ( std::move ( value ).getFinalStates ( ) ); + + automaton::UnorderedDFTA < > res ( std::move ( states ), std::move ( alphabet ), std::move ( finalStates ) ); + + for ( std::pair < ext::pair < common::ranked_symbol < SymbolType >, ext::multiset < StateType > >, StateType > && transition : ext::make_mover ( std::move ( value ).getTransitions ( ) ) ) { + common::ranked_symbol < DefaultSymbolType > input = alphabet::SymbolNormalize::normalizeRankedSymbol ( std::move ( transition.first.first ) ); + ext::multiset < DefaultStateType > from = automaton::AutomatonNormalize::normalizeStates ( std::move ( transition.first.second ) ); + DefaultStateType to = automaton::AutomatonNormalize::normalizeState ( std::move ( transition.second ) ); + + res.addTransition ( std::move ( input ), std::move ( from ), std::move ( to ) ); + } + + return res; + } +}; + +} /* namespace core */ + +extern template class automaton::UnorderedDFTA < >; + +#endif /* UNORDERED_DFTA_H_ */ diff --git a/alib2data/src/automaton/TA/UnorderedNFTA.cpp b/alib2data/src/automaton/TA/UnorderedNFTA.cpp new file mode 100644 index 0000000000..89509ec514 --- /dev/null +++ b/alib2data/src/automaton/TA/UnorderedNFTA.cpp @@ -0,0 +1,21 @@ +/* + * UnorderedNFTA.cpp + * + * Created on: Mar 21, 2015 + * Author: Stepan Plachy + */ + +#include "UnorderedNFTA.h" + +#include <registration/ValuePrinterRegistration.hpp> +#include <registration/CastRegistration.hpp> + +template class automaton::UnorderedNFTA < >; + +namespace { + +auto valuePrinter = registration::ValuePrinterRegister < automaton::UnorderedNFTA < > > ( ); + +auto NFTAFromDFTA = registration::CastRegister < automaton::UnorderedNFTA < >, automaton::UnorderedDFTA < > > ( ); + +} /* namespace */ diff --git a/alib2data/src/automaton/TA/UnorderedNFTA.h b/alib2data/src/automaton/TA/UnorderedNFTA.h new file mode 100644 index 0000000000..374028acf6 --- /dev/null +++ b/alib2data/src/automaton/TA/UnorderedNFTA.h @@ -0,0 +1,661 @@ +/* + * UnorderedNFTA.h + * + * This file is part of Algorithms library toolkit. + * Copyright (C) 2017 Jan Travnicek (jan.travnicek@fit.cvut.cz) + + * Algorithms library toolkit is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * Algorithms library toolkit is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with Algorithms library toolkit. If not, see <http://www.gnu.org/licenses/>. + * + * Created on: Mar 21, 2015 + * Author: Stepan Plachy + */ + +#ifndef UNORDERED_NFTA_H_ +#define UNORDERED_NFTA_H_ + +#include <ostream> +#include <sstream> + +#include <alib/multimap> +#include <alib/set> +#include <alib/multiset> +#include <alib/compare> + +#include <core/components.hpp> + +#include <core/normalize.hpp> + +#include <common/DefaultStateType.h> +#include <common/DefaultSymbolType.h> + +#include <automaton/AutomatonException.h> + +#include <core/normalize.hpp> +#include <alphabet/common/SymbolNormalize.h> +#include <automaton/common/AutomatonNormalize.h> + +#include "UnorderedDFTA.h" + +namespace automaton { + +class InputAlphabet; +class States; +class FinalStates; + +/** + * \brief + * Nondeterministic finite tree automaton without epsilon transitions. Accepts regular tree languages. + + * \details + * Definition is classical definition of finite automata. + * A = (Q, T, \delta, F), + * Q (States) = nonempty finite set of states, + * T (TerminalAlphabet) = finite set of terminal ranked symbols - having this empty won't let automaton do much though, + * \delta = transition function of the form (A, B, C, ...) \times a -> P(Q), where A, B, C, ... \in Q, a \in T, and P(Q) is a powerset of states, + * F (FinalStates) = set of final states + * + * Elements of the \delta multimapping must meet following criteria. The size of the state list must equal the rank of the ranked symbol. + * + * \tparam SymbolTypeT used for the symbol part of the ranked symbol + * \tparam StateTypeT used to the states, and the initial state of the automaton. + */ +template < class SymbolTypeT = DefaultSymbolType, class StateTypeT = DefaultStateType > +class UnorderedNFTA final : public ext::CompareOperators < UnorderedNFTA < SymbolTypeT, StateTypeT > >, public core::Components < UnorderedNFTA < SymbolTypeT, StateTypeT >, ext::set < common::ranked_symbol < SymbolTypeT > >, component::Set, InputAlphabet, ext::set < StateTypeT >, component::Set, std::tuple < States, FinalStates > > { +public: + typedef SymbolTypeT SymbolType; + typedef StateTypeT StateType; + +private: + /** + * Transition function as multimapping from a list of states times an input symbol on the left hand side to a set of states. + */ + ext::multimap < ext::pair < common::ranked_symbol < SymbolType >, ext::multiset < StateType > >, StateType > transitions; + +public: + /** + * \brief Creates a new instance of the automaton. + */ + explicit UnorderedNFTA ( ); + + /** + * \brief Creates a new instance of the automaton with a concrete set of states, input alphabet, and a set of final states. + * + * \param states the initial set of states of the automaton + * \param inputAlphabet the initial input alphabet + * \param finalStates the initial set of final states of the automaton + */ + explicit UnorderedNFTA ( ext::set < StateType > states, ext::set < common::ranked_symbol < SymbolType > > inputAlphabet, ext::set < StateType > finalStates ); + + /* + * \brief Creates a new instance of the automaton based on the Deterministic finite tree automaton. + * + * \param other the Deterministic finite tree automaton + */ + explicit UnorderedNFTA ( const UnorderedDFTA < SymbolType, StateType > & other ); + + /** + * Getter of states. + * + * \returns the states of the automaton + */ + const ext::set < StateType > & getStates ( ) const & { + return this->template accessComponent < States > ( ).get ( ); + } + + /** + * Getter of states. + * + * \returns the states of the automaton + */ + ext::set < StateType > && getStates ( ) && { + return std::move ( this->template accessComponent < States > ( ).get ( ) ); + } + + /** + * Adder of a state. + * + * \param state the new state to be added to a set of states + * + * \returns true if the state was indeed added + */ + bool addState ( StateType state ) { + return this->template accessComponent < States > ( ).add ( std::move ( state ) ); + } + + /** + * Setter of states. + * + * \param states completely new set of states + */ + void setStates ( ext::set < StateType > states ) { + this->template accessComponent < States > ( ).set ( std::move ( states ) ); + } + + /** + * Remover of a state. + * + * \param state a state to be removed from a set of states + * + * \returns true if the state was indeed removed + */ + void removeState ( const StateType & state ) { + this->template accessComponent < States > ( ).remove ( state ); + } + + /** + * Getter of final states. + * + * \returns the final states of the automaton + */ + const ext::set < StateType > & getFinalStates ( ) const & { + return this->template accessComponent < FinalStates > ( ).get ( ); + } + + /** + * Getter of final states. + * + * \returns the final states of the automaton + */ + ext::set < StateType > && getFinalStates ( ) && { + return std::move ( this->template accessComponent < FinalStates > ( ).get ( ) ); + } + + /** + * Adder of a final state. + * + * \param state the new state to be added to a set of final states + * + * \returns true if the state was indeed added + */ + bool addFinalState ( StateType state ) { + return this->template accessComponent < FinalStates > ( ).add ( std::move ( state ) ); + } + + /** + * Setter of final states. + * + * \param states completely new set of final states + */ + void setFinalStates ( ext::set < StateType > states ) { + this->template accessComponent < FinalStates > ( ).set ( std::move ( states ) ); + } + + /** + * Remover of a final state. + * + * \param state a state to be removed from a set of final states + * + * \returns true if the state was indeed removed + */ + void removeFinalState ( const StateType & state ) { + this->template accessComponent < FinalStates > ( ).remove ( state ); + } + + /** + * Getter of the input alphabet. + * + * \returns the input alphabet of the automaton + */ + const ext::set < common::ranked_symbol < SymbolType > > & getInputAlphabet ( ) const & { + return this->template accessComponent < InputAlphabet > ( ).get ( ); + } + + /** + * Getter of the input alphabet. + * + * \returns the input alphabet of the automaton + */ + ext::set < common::ranked_symbol < SymbolType > > && getInputAlphabet ( ) && { + return std::move ( this->template accessComponent < InputAlphabet > ( ).get ( ) ); + } + + /** + * Adder of a input symbol. + * + * \param symbol the new symbol to be added to an input alphabet + * + * \returns true if the symbol was indeed added + */ + bool addInputSymbol ( common::ranked_symbol < SymbolType > symbol ) { + return this->template accessComponent < InputAlphabet > ( ).add ( std::move ( symbol ) ); + } + + /** + * Adder of input symbols. + * + * \param symbols new symbols to be added to an input alphabet + */ + void addInputSymbols ( ext::set < common::ranked_symbol < SymbolType > > symbols ) { + this->template accessComponent < InputAlphabet > ( ).add ( std::move ( symbols ) ); + } + + /** + * Setter of input alphabet. + * + * \param symbols completely new input alphabet + */ + void setInputAlphabet ( ext::set < common::ranked_symbol < SymbolType > > symbols ) { + this->template accessComponent < InputAlphabet > ( ).set ( std::move ( symbols ) ); + } + + /** + * Remover of an input symbol. + * + * \param symbol a symbol to be removed from an input alphabet + * + * \returns true if the symbol was indeed removed + */ + void removeInputSymbol ( const common::ranked_symbol < SymbolType > & symbol ) { + this->template accessComponent < InputAlphabet > ( ).remove ( symbol ); + } + + /** + * \brief Add a transition to the automaton. + * + * \details The transition is in a form ( A, B, C, ... ) \times a -> X, where A, B, C, ..., X \in Q and a \in T + * + * \param children the source states (A, B, C, ...) + * \param current the input symbol (a) + * \param next the target state (B) + * + * \throws AutomatonException when transition contains state or symbol not present in the automaton components + * + * \returns true if the transition was indeed added + */ + bool addTransition ( common::ranked_symbol < SymbolType > symbol, ext::multiset < StateType > prevStates, StateType next ); + + /** + * \brief Removes a transition from the automaton. + * + * \details The transition is in a form ( A, B, C, ... ) \times a -> X, where A, B, C, ..., X \in Q and a \in T + * + * \param children the source states (A, B, C, ...) + * \param current the input symbol (a) + * \param next the target state (B) + * + * \returns true if the transition was indeed removed + */ + bool removeTransition ( const common::ranked_symbol < SymbolType > & symbol, const ext::multiset < StateType > & states, const StateType & next ); + + /** + * Get the transition function of the automaton in its natural form. + * + * \returns transition function of the automaton + */ + const ext::multimap < ext::pair < common::ranked_symbol < SymbolType >, ext::multiset < StateType > >, StateType > & getTransitions ( ) const & { + return transitions; + } + + /** + * Get the transition function of the automaton in its natural form. + * + * \returns transition function of the automaton + */ + ext::multimap < ext::pair < common::ranked_symbol < SymbolType >, ext::multiset < StateType > >, StateType > && getTransitions ( ) && { + return std::move ( transitions ); + } + + /** + * \returns transitions to state @p q + */ + ext::multimap < ext::pair < common::ranked_symbol < SymbolType >, ext::multiset < StateType > >, StateType > getTransitionsToState ( const StateType & q ) const { + ext::multimap < ext::pair < common::ranked_symbol < SymbolType >, ext::multiset < StateType > >, StateType > res; + + for ( const auto & transition : getTransitions ( ) ) + if ( transition.second == q ) + res.insert ( transition ); + + return res; + } + + /** + * \returns transitions from state @p q + */ + ext::multimap < ext::pair < common::ranked_symbol < SymbolType >, ext::multiset < StateType > >, StateType > getTransitionsFromState ( const StateType & q ) const { + ext::multimap < ext::pair < common::ranked_symbol < SymbolType >, ext::multiset < StateType > >, StateType > res; + + for ( const auto & transition : getTransitions ( ) ) { + if ( std::find ( transition.first.second.begin ( ), transition.first.second.end ( ), q ) != transition.first.second.end ( ) ) + res.insert ( transition ); + } + + return res; + } + + /** + * \brief Determines whether the automaton is deterministic. + * + * the automaton is deterministic if and only if: + * \li \c size of transition function \delta (from states, input symbol) \leq 1 + * + * \return true if the automaton is deterministic, false otherwise + */ + bool isDeterministic ( ) const; + + /** + * The actual compare method + * + * \param other the other instance + * + * \returns the actual relation between two by type same automata instances + */ + int compare ( const UnorderedNFTA & other ) const; + + /** + * Print this object as raw representation to ostream. + * + * \param out ostream where to print + * \param instance object to print + * + * \returns modified output stream + */ + friend std::ostream & operator << ( std::ostream & out, const UnorderedNFTA & instance ) { + return out << "(UnorderedNFTA " + << " states = " << instance.getStates ( ) + << " inputAlphabet = " << instance.getInputAlphabet ( ) + << " finalStates = " << instance.getFinalStates ( ) + << " transitions = " << instance.getTransitions ( ) + << ")"; + } + + /** + * Casts this instance to as compact as possible string representation. + * + * \returns string representation of the object + */ + operator std::string ( ) const; +}; + +/** + * Trait to detect whether the type parameter T is or is not UnorderedNFTA. Derived from std::false_type. + * + * \tparam T the tested type parameter + */ +template < class T > +class isUnorderedNFTA_impl : public std::false_type {}; + +/** + * Trait to detect whether the type parameter T is or is not DFA. Derived from std::true_type. + * + * Specialisation for UnorderedNFTA. + * + * \tparam SymbolType used for the terminal alphabet of the automaton + * \tparam StateType used for the terminal alphabet of the automaton + */ +template < class SymbolType, class StateType > +class isUnorderedNFTA_impl < UnorderedNFTA < SymbolType, StateType > > : public std::true_type {}; + +/** + * Constexpr true if the type parameter T is UnorderedNFTA, false otherwise. + * + * \tparam T the tested type parameter + */ +template < class T > +constexpr bool isUnorderedNFTA = isUnorderedNFTA_impl < T > { }; + +template < class SymbolType, class StateType > +UnorderedNFTA < SymbolType, StateType >::UnorderedNFTA ( ext::set < StateType > states, ext::set < common::ranked_symbol < SymbolType > > inputAlphabet, ext::set < StateType > finalStates ) : core::Components < UnorderedNFTA, ext::set < common::ranked_symbol < SymbolType > >, component::Set, InputAlphabet, ext::set < StateType >, component::Set, std::tuple < States, FinalStates > > ( std::move ( inputAlphabet ), std::move ( states ), std::move ( finalStates ) ) { +} + +template < class SymbolType, class StateType > +UnorderedNFTA < SymbolType, StateType >::UnorderedNFTA() : UnorderedNFTA ( ext::set < StateType > { }, ext::set < common::ranked_symbol < SymbolType > > { }, ext::set < StateType > { } ) { +} + +template < class SymbolType, class StateType > +UnorderedNFTA < SymbolType, StateType >::UnorderedNFTA(const UnorderedDFTA < SymbolType, StateType > & other) : UnorderedNFTA ( other.getStates(), other.getInputAlphabet(), other.getFinalStates() ) { + transitions.insert ( other.getTransitions ( ).begin ( ), other.getTransitions ( ).end ( ) ); +} + +template < class SymbolType, class StateType > +bool UnorderedNFTA < SymbolType, StateType >::addTransition ( common::ranked_symbol < SymbolType > symbol, ext::multiset<StateType> prevStates, StateType next) { + if (prevStates.size() != ( size_t ) symbol.getRank() ) + throw AutomatonException("Number of states doesn't match rank of the symbol"); + + if (! getInputAlphabet().count(symbol)) + throw AutomatonException("Input symbol \"" + ext::to_string ( symbol ) + "\" doesn't exist."); + + if (! getStates().count(next)) + throw AutomatonException("State \"" + ext::to_string ( next ) + "\" doesn't exist."); + + for (const StateType& it : prevStates) { + if (! getStates().count(it)) + throw AutomatonException("State \"" + ext::to_string ( it ) + "\" doesn't exist."); + } + + auto upper_bound = transitions.upper_bound ( ext::tie ( symbol, prevStates ) ); + auto lower_bound = transitions.lower_bound ( ext::tie ( symbol, prevStates ) ); + auto iter = std::lower_bound ( lower_bound, upper_bound, next, [ ] ( const auto & transition, const auto & target ) { return transition.second < target; } ); + if ( iter != upper_bound && next >= iter->second ) + return false; + + ext::pair < common::ranked_symbol < SymbolType >, ext::multiset < StateType > > key = ext::make_pair ( std::move ( symbol ), std::move ( prevStates ) ); + transitions.insert ( iter, std::make_pair ( std::move ( key ), std::move ( next ) ) ); + return true; +} + +template < class SymbolType, class StateType > +bool UnorderedNFTA < SymbolType, StateType >::removeTransition(const common::ranked_symbol < SymbolType > & symbol, const ext::multiset<StateType> & states, const StateType & next) { + auto upper_bound = transitions.upper_bound ( ext::tie ( symbol, states ) ); + auto lower_bound = transitions.lower_bound ( ext::tie ( symbol, states ) ); + auto iter = std::find_if ( lower_bound, upper_bound, [ & ] ( const auto & transition ) { return transition.second == next; } ); + if ( iter == upper_bound ) + return false; + + transitions.erase ( iter ); + return true; +} + +template < class SymbolType, class StateType > +bool UnorderedNFTA < SymbolType, StateType >::isDeterministic() const { + if ( transitions.empty ( ) ) + return true; + + for ( auto iter = transitions.begin ( ); std::next ( iter ) != transitions.end ( ); ++ iter ) + if ( iter->first == std::next ( iter )->first ) + return false; + + return true; +} + +template < class SymbolType, class StateType > +int UnorderedNFTA < SymbolType, StateType >::compare(const UnorderedNFTA& other) const { + auto first = ext::tie(getStates(), getInputAlphabet(), getFinalStates(), transitions); + auto second = ext::tie(other.getStates(), other.getInputAlphabet(), other.getFinalStates(), other.transitions); + + static ext::compare<decltype(first)> comp; + return comp(first, second); +} + +template < class SymbolType, class StateType > +UnorderedNFTA < SymbolType, StateType >::operator std::string ( ) const { + std::stringstream ss; + ss << *this; + return ss.str(); +} + +} /* namespace automaton */ + +namespace core { + +/** + * Helper class specifying constraints for the automaton's internal input alphabet component. + * + * \tparam SymbolType used for the symbol part of the ranked symbol + * \tparam StateType used for the terminal alphabet of the automaton. + */ +template < class SymbolType, class StateType > +class SetConstraint< automaton::UnorderedNFTA < SymbolType, StateType >, common::ranked_symbol < SymbolType >, automaton::InputAlphabet > { +public: + /** + * Returns true if the symbol is still used in some transition of the automaton. + * + * \param automaton the tested automaton + * \param symbol the tested symbol + * + * \returns true if the symbol is used, false othervise + */ + static bool used ( const automaton::UnorderedNFTA < SymbolType, StateType > & automaton, const common::ranked_symbol < SymbolType > & symbol ) { + for ( const std::pair<const ext::pair<common::ranked_symbol < SymbolType >, ext::multiset<StateType> >, StateType > & t : automaton.getTransitions()) + if (t.first.first == symbol) + return true; + + return false; + } + + /** + * Returns true as all symbols are possibly available to be elements of the input alphabet. + * + * \param automaton the tested automaton + * \param symbol the tested symbol + * + * \returns true + */ + static bool available ( const automaton::UnorderedNFTA < SymbolType, StateType > &, const common::ranked_symbol < SymbolType > & ) { + return true; + } + + /** + * All symbols are valid as input symbols. + * + * \param automaton the tested automaton + * \param symbol the tested symbol + */ + static void valid ( const automaton::UnorderedNFTA < SymbolType, StateType > &, const common::ranked_symbol < SymbolType > & ) { + } +}; + +/** + * Helper class specifying constraints for the automaton's internal states component. + * + * \tparam SymbolType used for the symbol part of the ranked symbol + * \tparam StateType used for the terminal alphabet of the automaton. + */ +template < class SymbolType, class StateType > +class SetConstraint< automaton::UnorderedNFTA < SymbolType, StateType >, StateType, automaton::States > { +public: + /** + * Returns true if the state is still used in some transition of the automaton. + * + * \param automaton the tested automaton + * \param state the tested state + * + * \returns true if the state is used, false othervise + */ + static bool used ( const automaton::UnorderedNFTA < SymbolType, StateType > & automaton, const StateType & state ) { + if ( automaton.getFinalStates ( ).count ( state ) ) + return true; + + for ( const std::pair<const ext::pair<common::ranked_symbol < SymbolType >, ext::multiset<StateType> >, StateType >& t : automaton.getTransitions()) + if(ext::contains(t.first.second.begin(), t.first.second.end(), state ) || t . second == state ) + return true; + + return false; + } + + /** + * Returns true as all states are possibly available to be elements of the states. + * + * \param automaton the tested automaton + * \param state the tested state + * + * \returns true + */ + static bool available ( const automaton::UnorderedNFTA < SymbolType, StateType > &, const StateType & ) { + return true; + } + + /** + * All states are valid as a state of the automaton. + * + * \param automaton the tested automaton + * \param state the tested state + */ + static void valid ( const automaton::UnorderedNFTA < SymbolType, StateType > &, const StateType & ) { + } +}; + +/** + * Helper class specifying constraints for the automaton's internal final states component. + * + * \tparam SymbolType used for the symbol part of the ranked symbol + * \tparam StateType used for the terminal alphabet of the automaton. + */ +template < class SymbolType, class StateType > +class SetConstraint< automaton::UnorderedNFTA < SymbolType, StateType >, StateType, automaton::FinalStates > { +public: + /** + * Returns false. Final state is only a mark that the automaton itself does require further. + * + * \param automaton the tested automaton + * \param state the tested state + * + * \returns false + */ + static bool used ( const automaton::UnorderedNFTA < SymbolType, StateType > &, const StateType & ) { + return false; + } + + /** + * Determines whether the state is available in the automaton's states set. + * + * \param automaton the tested automaton + * \param state the tested state + * + * \returns true if the state is already in the set of states of the automaton + */ + static bool available ( const automaton::UnorderedNFTA < SymbolType, StateType > & automaton, const StateType & state ) { + return automaton.template accessComponent < automaton::States > ( ).get ( ).count ( state ); + } + + /** + * All states are valid as a final state of the automaton. + * + * \param automaton the tested automaton + * \param state the tested state + */ + static void valid ( const automaton::UnorderedNFTA < SymbolType, StateType > &, const StateType & ) { + } +}; + +/** + * Helper for normalisation of types specified by templates used as internal datatypes of symbols and states. + * + * \returns new instance of the automaton with default template parameters or unmodified instance if the template parameters were already the default ones + */ +template < class SymbolType, class StateType > +struct normalize < automaton::UnorderedNFTA < SymbolType, StateType > > { + static automaton::UnorderedNFTA < > eval ( automaton::UnorderedNFTA < SymbolType, StateType > && value ) { + ext::set < common::ranked_symbol < > > alphabet = alphabet::SymbolNormalize::normalizeRankedAlphabet ( std::move ( value ).getInputAlphabet ( ) ); + ext::set < DefaultStateType > states = automaton::AutomatonNormalize::normalizeStates ( std::move ( value ).getStates ( ) ); + ext::set < DefaultStateType > finalStates = automaton::AutomatonNormalize::normalizeStates ( std::move ( value ).getFinalStates ( ) ); + + automaton::UnorderedNFTA < > res ( std::move ( states ), std::move ( alphabet ), std::move ( finalStates ) ); + + for ( std::pair < ext::pair < common::ranked_symbol < SymbolType >, ext::multiset < StateType > >, StateType > && transition : ext::make_mover ( std::move ( value ).getTransitions ( ) ) ) { + common::ranked_symbol < DefaultSymbolType > input = alphabet::SymbolNormalize::normalizeRankedSymbol ( std::move ( transition.first.first ) ); + ext::multiset < DefaultStateType > from = automaton::AutomatonNormalize::normalizeStates ( std::move ( transition.first.second ) ); + DefaultStateType to = automaton::AutomatonNormalize::normalizeState ( std::move ( transition.second ) ); + + res.addTransition ( std::move ( input ), std::move ( from ), std::move ( to ) ); + } + + return res; + } +}; + +} /* namespace core */ + +extern template class automaton::UnorderedNFTA < >; + +#endif /* UNORDERED_NFTA_H_ */ diff --git a/alib2data/src/automaton/common/AutomatonNormalize.h b/alib2data/src/automaton/common/AutomatonNormalize.h index dbb67ab12a..488b261146 100644 --- a/alib2data/src/automaton/common/AutomatonNormalize.h +++ b/alib2data/src/automaton/common/AutomatonNormalize.h @@ -11,6 +11,7 @@ #include <alib/deque> #include <alib/vector> #include <alib/set> +#include <alib/multiset> #include <alib/map> #include <regexp/unbounded/UnboundedRegExpStructure.h> @@ -27,6 +28,9 @@ namespace automaton { */ class AutomatonNormalize { public: + template < class StateType > + static ext::multiset < DefaultStateType > normalizeStates ( ext::multiset < StateType > && states ); + template < class StateType > static ext::set < DefaultStateType > normalizeStates ( ext::set < StateType > && states ); @@ -44,6 +48,15 @@ public: }; +template < class StateType > +ext::multiset < DefaultStateType > AutomatonNormalize::normalizeStates ( ext::multiset < StateType > && states ) { + ext::multiset < DefaultStateType > res; + for ( StateType && state : ext::make_mover ( states ) ) + res.insert ( normalizeState ( std::move ( state ) ) ); + + return res; +} + template < class StateType > ext::set < DefaultStateType > AutomatonNormalize::normalizeStates ( ext::set < StateType > && states ) { ext::set < DefaultStateType > res; diff --git a/alib2integrationtest/test-src/tests/arbologyTest.cpp b/alib2integrationtest/test-src/tests/arbologyTest.cpp index a87ce15945..43b200e68f 100644 --- a/alib2integrationtest/test-src/tests/arbologyTest.cpp +++ b/alib2integrationtest/test-src/tests/arbologyTest.cpp @@ -9,6 +9,8 @@ enum class EGenerateType { SUBTREE, NONLINEAR_PATTERN, NONLINEAR_PATTERN_SINGLE_VAR, + UNORDERED_PATTERN, + UNORDERED_SUBTREE, SUBJECT, }; @@ -25,6 +27,10 @@ std::ostream& operator << ( std::ostream& os, const EGenerateType& type ) { return ( os << "NONLINEAR_PATTERN_SINGLE_VAR"); case EGenerateType::SUBJECT: return ( os << "SUBJECT" ); + case EGenerateType::UNORDERED_PATTERN: + return ( os << "UNORDERED_PATTERN" ); + case EGenerateType::UNORDERED_SUBTREE: + return ( os << "UNORDERED_SUBTREE" ); default: return ( os << "Unhandled EGenerateType" ); } @@ -50,6 +56,10 @@ static std::string qGen ( const EGenerateType & type, int height, int nodes, int oss << "tree::generate::RandomRankedNonlinearPatternFactory"; } else if ( type == EGenerateType::NONLINEAR_PATTERN_SINGLE_VAR ) { oss << "tree::generate::RandomRankedNonlinearPatternFactory"; + } else if ( type == EGenerateType::UNORDERED_PATTERN ) { + oss << "(UnorderedRankedPattern) tree::generate::RandomRankedPatternFactory"; + } else if ( type == EGenerateType::UNORDERED_SUBTREE ) { + oss << "(UnorderedRankedTree) tree::generate::RandomRankedTreeFactory"; } oss << " (int)" << height; @@ -222,6 +232,31 @@ TEST_CASE ( "Arbology tests | pattern", "[integration]" ) { // -------------------------------------------------------------------------------------------------------------------- +TEST_CASE ( "Arbology tests | unordered pattern", "[integration]" ) { + auto definition = GENERATE ( as < std::tuple < std::string, std::string, size_t > > ( ), + std::make_tuple ( "Exact Pattern Matching Automaton (Pattern Tree)", + "automaton::run::Occurrences <(arbology::exact::ExactPatternMatchingAutomaton <(tree::GeneralAlphabet::add $pattern <(tree::GeneralAlphabet::get $subject)) | automaton::determinize::Determinize - ) $subject", 1000 ) ); + + auto exact = "arbology::exact::ExactPatternMatch $subject $pattern"; + auto pattern = EGenerateType::UNORDERED_PATTERN; + +/* SECTION ( "Test files" ) { + for ( const std::pair < std::string, std::string > files : pair_pattern_subject ( TestFiles::Get ( "/tree/aarbology.test[0-9]+.pattern.xml$" ), ".pattern.xml", ".subject.xml" ) ) { + CAPTURE ( std::get < 0 > ( definition ), std::get < 1 > ( definition ), files.first, files.second ); + runTest ( exact, std::get < 1 > ( definition ), files.first, files.second ); + } + }*/ + + SECTION ( "Random tests" ) { + for ( size_t i = 0; i < RANDOM_ITERATIONS; i++ ) { + CAPTURE ( std::get < 0 > ( definition ), std::get < 1 > ( definition ), pattern, std::get < 2 > ( definition ) ); + runRandom ( exact, std::get < 1 > ( definition ), pattern, std::get < 2 > ( definition ) ); + } + } +} + +// -------------------------------------------------------------------------------------------------------------------- + TEST_CASE ( "Arbology tests | pattern ends ", "[integration]" ) { auto definition = GENERATE ( as < std::tuple < std::string, std::string, size_t > > ( ), std::make_tuple ( "Exact Pattern Matching Using Compressed Bit Vectors (PrefixRanked)", -- GitLab