From 9dcfba2a8abf7eadd891ff9ea51df08c03e63522 Mon Sep 17 00:00:00 2001 From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz> Date: Sat, 20 Sep 2014 13:17:33 +0200 Subject: [PATCH] untested vpa determinisation --- adeterminize/src/vpa/VpaDeterminizer3.cpp | 229 ------------ adeterminize/src/vpa/VpaDeterminizer3.h | 113 ------ adeterminize2/src/adeterminize.cpp | 20 +- .../src/determinize/vpa/VPADeterminizer.cpp | 330 ++++++++++++++++++ .../src/determinize/vpa/VPADeterminizer.h | 31 ++ .../test-src/determinize/determinizeTest.cpp | 12 +- .../src/automaton/AutomatonFromXMLParser.cpp | 8 +- .../src/automaton/AutomatonToXMLComposer.cpp | 6 +- examples2/automaton/NIDPDA0.xml | 88 +++++ examples2/automaton/NIDPDA1.xml | 154 ++++++++ 10 files changed, 631 insertions(+), 360 deletions(-) delete mode 100644 adeterminize/src/vpa/VpaDeterminizer3.cpp delete mode 100644 adeterminize/src/vpa/VpaDeterminizer3.h create mode 100644 alib2algo/src/determinize/vpa/VPADeterminizer.cpp create mode 100644 alib2algo/src/determinize/vpa/VPADeterminizer.h create mode 100644 examples2/automaton/NIDPDA0.xml create mode 100644 examples2/automaton/NIDPDA1.xml diff --git a/adeterminize/src/vpa/VpaDeterminizer3.cpp b/adeterminize/src/vpa/VpaDeterminizer3.cpp deleted file mode 100644 index 3d6fa598fa..0000000000 --- a/adeterminize/src/vpa/VpaDeterminizer3.cpp +++ /dev/null @@ -1,229 +0,0 @@ -#include "VpaDeterminizer3.h" - -namespace determinization { -namespace vpa { - - -string VpaDeterminizer3::buildStateName(const SComponent& s) -{ - string name = "{"; - for (const auto& statesPair : s.statesPairs) { - if (&statesPair != &(*begin(s.statesPairs))) { - name += ", "; - } - name += "('" + statesPair.state1.getName() + "', '" + statesPair.state2.getName() + "')"; - } - name += "}"; - return name; -} - - -string VpaDeterminizer3::buildStackSymbolName(const SComponent& s, const Symbol& input) -{ - string name = "(" + this->buildStateName(s) + ")"; - name += ", " + input.getSymbol(); - try { - this->dvpa->addStackSymbol(name); - } catch (AutomatonException e) { - /* Stack symbol already exists */ - } - return name; -} - - -const State& VpaDeterminizer3::getOrCreateState(const SComponent& s) -{ - string stateName = this->buildStateName(s); - - map<string, StateData>::iterator statesIter = this->states.find(stateName); - if (statesIter != this->states.end()) { - return statesIter->second.state; - } - - State state(stateName); - StateData stateData(state, s); - StateData& insertedData = this->states.insert(pair<string, StateData>(stateName, stateData)).first->second; - this->dvpa->addState(state); - return insertedData.state; -} - - -const SComponent VpaDeterminizer3::getSComponentWithStatesIdentity(const set<State>& states) -{ - return VpaUtils::getSComponentWithStatesIdentity(states); -} - - -void VpaDeterminizer3::initDeterminization() -{ - this->states.clear(); - this->internalSymbols.clear(); - this->callSymbols.clear(); - this->returnSymbols.clear(); - Utils::copyInputAlphabet(*this->nvpa, *this->dvpa); - VpaUtils::divideInputAlphabet(*this->nvpa, this->internalSymbols, this->callSymbols, this->returnSymbols); - this->allSComponents = VpaUtils::generateAllSComponents(this->nvpa->getStates()); - this->dvpa->addStackSymbol(VpaUtils::BOTTOM_OF_STACK_SYMBOL); -} - - -VpaDeterminizer3::VpaDeterminizer3(PDA* nvpa) -{ - this->nvpa = nvpa; -} - - -Automaton* VpaDeterminizer3::determinize() -{ - this->dvpa = new PDA(); - this->initDeterminization(); - - const SComponent& initialS = this->getSComponentWithStatesIdentity(this->nvpa->getInitialStates()); - const State& initialState = this->getOrCreateState(initialS); - this->dvpa->addInitialState(initialState); - - while (true) { - StateData* unmarkedStateData = VpaUtils::getUnmarkedState(states); - if (unmarkedStateData == NULL) { - break; - } - - // Internal symbols - for (const auto& internalSymbol : internalSymbols) { - SComponent sPrimed; - SComponent& s = unmarkedStateData->s; - for (const auto& statesPair : s.statesPairs) { - const State& q = statesPair.state1; - const State& qDoublePrimed = statesPair.state2; - for (const auto& transition : this->nvpa->getTransitions()) { - if (transition.getFrom() == qDoublePrimed && transition.getInput() == internalSymbol) { - const State& qPrimed = transition.getTo(); - sPrimed.statesPairs.insert(StatesPair(q, qPrimed)); - } - } - } - if (sPrimed.statesPairs.size() > 0) { - const State& fromState = unmarkedStateData->state; - const State& toState = this->getOrCreateState(sPrimed); - const TransitionPDA transition(fromState, internalSymbol, toState); - this->dvpa->addTransition(transition); - } - } - - // Call symbols - for (const auto& callSymbol : callSymbols) { - RComponent rPrimed; - SComponent& s = unmarkedStateData->s; - for (const auto& statesPair : s.statesPairs) { - const State& q = statesPair.state2; - for (const auto& transition : this->nvpa->getTransitions()) { - if (transition.getFrom() == q && transition.getInput() == callSymbol) { - const State& qPrimed = transition.getTo(); - rPrimed.states.insert(qPrimed); - } - } - } - if (rPrimed.states.size() > 0) { - const SComponent& sPrimed = this->getSComponentWithStatesIdentity(rPrimed.states); - const State& fromState = unmarkedStateData->state; - const State& toState = this->getOrCreateState(sPrimed); - string stackSymbolName = this->buildStackSymbolName(s, callSymbol); - list<Symbol> pop = {}; - list<Symbol> push = {Symbol(stackSymbolName)}; - const TransitionPDA transition(fromState, callSymbol, toState, pop, push); - this->dvpa->addTransition(transition); - } - } - - // Return symbols - for (const auto& returnSymbol : returnSymbols) { - SComponent& s = unmarkedStateData->s; - - // Empty stack - list<Symbol> bottomOfStack = {VpaUtils::BOTTOM_OF_STACK_SYMBOL}; - SComponent sPrimed; - for (const auto& statesPair : s.statesPairs) { - const State& q = statesPair.state1; - const State& qDoublePrimed = statesPair.state2; - for (const auto& transition : this->nvpa->getTransitions()) { - if (transition.getFrom() == qDoublePrimed && transition.getInput() == returnSymbol && - transition.getPop() == bottomOfStack) { - const State& qPrimed = transition.getTo(); - sPrimed.statesPairs.insert(StatesPair(q, qPrimed)); - } - } - } - if (sPrimed.statesPairs.size() > 0) { - const State& fromState = unmarkedStateData->state; - const State& toState = this->getOrCreateState(sPrimed); - list<Symbol> pop = {VpaUtils::BOTTOM_OF_STACK_SYMBOL}; - list<Symbol> push = {}; - const TransitionPDA transition(fromState, returnSymbol, toState, pop, push); - this->dvpa->addTransition(transition); - } - - // Otherwise - for (const auto& callSymbol : callSymbols) { - set<StatesPair> update; - for (const auto& sPair : s.statesPairs) { - const State& q1 = sPair.state1; - const State& q2 = sPair.state2; - for (const auto& transitionPush : this->nvpa->getTransitions()) { - for (const auto& transitionPop : this->nvpa->getTransitions()) { - const State& q = transitionPush.getFrom(); - const State& qPrimed = transitionPop.getTo(); - if (transitionPush.getInput() == callSymbol && transitionPush.getTo() == q1 && - transitionPop.getInput() == returnSymbol && transitionPop.getFrom() == q2 && - transitionPush.getPush() == transitionPop.getPop()) { - update.insert(StatesPair(q, qPrimed)); - } - } - } - } - if (update.size() == 0) { - continue; - } - for (const auto& sPrimed : this->allSComponents) { - SComponent sDoublePrimed; - for (const auto& updateItem : update) { - const State& q3 = updateItem.state1; - const State& qPrimed = updateItem.state2; - for (const auto& sPrimedPair : sPrimed.statesPairs) { - if (sPrimedPair.state2 == q3) { - const State& q = sPrimedPair.state1; - sDoublePrimed.statesPairs.insert(StatesPair(q, qPrimed)); - } - } - } - if (sDoublePrimed.statesPairs.size() > 0) { - const State& fromState = unmarkedStateData->state; - const State& toState = this->getOrCreateState(sDoublePrimed); - string stackSymbolName = this->buildStackSymbolName(sPrimed, callSymbol); - list<Symbol> pop = {Symbol(stackSymbolName)}; - list<Symbol> push = {}; - const TransitionPDA transition(fromState, returnSymbol, toState, pop, push); - this->dvpa->addTransition(transition); - } - } - } - } - } - - // Final states - for (const auto& stateIter : states) { - const StateData& stateData = stateIter.second; - set<State> secondStates; - for (const auto& sPair : stateData.s.statesPairs) { - secondStates.insert(sPair.state2); - } - if (Utils::containFinalState(secondStates, *this->nvpa)) { - this->dvpa->addFinalState(stateData.state); - } - } - - return this->dvpa; -} - - -} -} diff --git a/adeterminize/src/vpa/VpaDeterminizer3.h b/adeterminize/src/vpa/VpaDeterminizer3.h deleted file mode 100644 index 38202fdd30..0000000000 --- a/adeterminize/src/vpa/VpaDeterminizer3.h +++ /dev/null @@ -1,113 +0,0 @@ -#ifndef VPADETERMINIZER3_H_ -#define VPADETERMINIZER3_H_ - -#include <string> -#include <set> -#include <map> -#include <vector> - -#include "automaton/PDA/PDA.h" -#include "automaton/Transition.h" -#include "automaton/exception/AutomatonException.h" -#include "alphabet/Symbol.h" - -#include "../common/Utils.h" -#include "../Determinizer.h" -#include "VpaUtils.h" -#include "VpaStructs.h" - -using namespace std; -using namespace automaton; -using namespace alphabet; - -namespace determinization { -namespace vpa { - -/** - * Class for running third version of determinization algorithm on vpa. - */ -class VpaDeterminizer3 : public Determinizer -{ - - private: - - /** Nondeterministic visibly pushdown automaton */ - PDA* nvpa; - - /** Deterministic visibly pushdown automaton */ - PDA* dvpa; - - /** Map of states of deterministic vpa, where key is the name of state and value is data about this state */ - map<string, StateData> states; - - /** Set of internal input symbols from nondeterministic automaton */ - set<Symbol> internalSymbols; - - /** Set of call input symbols from nondeterministic automaton */ - set<Symbol> callSymbols; - - /** Set of return input symbols from nondeterministic automaton */ - set<Symbol> returnSymbols; - - /** Vector with all possible S components of deterministic vpa */ - vector<SComponent> allSComponents; - - /** - * Returns name of state of deterministic vpa which is created from given S component. - * - * @param s S component of state - * @return name of state - */ - string buildStateName(const SComponent& s); - - /** - * Returns name of stack symbol of deterministic vpa which is created from given S component and input symbol. - * This method also ensures that this stack symbol is already added into deterministic vpa. - * - * @param s S component of stack symbol - * @param input input symbol - * @return name of stack symbol - */ - string buildStackSymbolName(const SComponent& s, const Symbol& input); - - /** - * Returns existing state from states map, if there is one with same name, or creates new one and adds it into - * states map and deterministic vpa. - * - * @param s S component of state - * @return state of deterministic vpa - */ - const State& getOrCreateState(const SComponent& s); - - /** - * Returns S component that contains pairs where states are same. - * - * @param states set of states from which to create pairs - * @return pairs where states are same - */ - const SComponent getSComponentWithStatesIdentity(const set<State>& states); - - /** - * Runs some initializiation stuff before determinization algorithm. - */ - void initDeterminization(); - - public: - - /** - * @param nvpa nondeterministic visibly pushdown automaton given for determinization - */ - VpaDeterminizer3(PDA* nvpa); - - /** - * Runs determinization algorithm on nondeterministic vpa given in constructor. - * - * @return deterministic visibly pushdown automaton - */ - Automaton* determinize(); - -}; - -} -} -#endif diff --git a/adeterminize2/src/adeterminize.cpp b/adeterminize2/src/adeterminize.cpp index 7f11fe1488..780b1ceb7a 100644 --- a/adeterminize2/src/adeterminize.cpp +++ b/adeterminize2/src/adeterminize.cpp @@ -11,7 +11,8 @@ #include "exception/AlibException.h" #include "determinize/nfa/NFADeterminizer.h" -//#include "idpda/IdpdaDeterminizer.h" +#include "determinize/idpda/IDPDADeterminizer.h" +#include "determinize/vpa/VPADeterminizer.h" //#include "vpa/VpaDeterminizer.h" //#include "vpa/VpaDeterminizer2.h" //#include "vpa/VpaDeterminizer3.h" @@ -113,14 +114,19 @@ int main(int argc, char** argv) { } else { throw exception::AlibException("Unsupported formalism"); } - } - -/* } else if (type == TYPE_IDPDA) { - return new idpda::IdpdaDeterminizer((PDA*) automaton); + } else if (type == TYPE_IDPDA) { + automaton::InputDrivenNPDA npda = alib::DataFactory::fromTokens<automaton::InputDrivenNPDA>(tokens); + automaton::DPDA dpda = determinize::IDPDADeterminizer::determinize(npda); + alib::DataFactory::toStdout(dpda); + return 0; } else if (type == TYPE_VPA) { - return getVpaDeterminizer(automaton, version); - + automaton::VisiblyPushdownNPDA npda = alib::DataFactory::fromTokens<automaton::VisiblyPushdownNPDA>(tokens); + automaton::VisiblyPushdownNPDA dpda = determinize::VPADeterminizer::determinize(npda); + alib::DataFactory::toStdout(dpda); + return 0; + } +/* } else if (type == TYPE_RHDPDA) { return getRhdpdaDeterminizer(automaton, version); }*/ diff --git a/alib2algo/src/determinize/vpa/VPADeterminizer.cpp b/alib2algo/src/determinize/vpa/VPADeterminizer.cpp new file mode 100644 index 0000000000..a676e490c9 --- /dev/null +++ b/alib2algo/src/determinize/vpa/VPADeterminizer.cpp @@ -0,0 +1,330 @@ +#include "VPADeterminizer.h" + +#include "automaton/common/State.h" +#include "alphabet/Symbol.h" +#include "alphabet/LabeledSymbol.h" +#include "label/Label.h" +#include "label/LabelSetLabel.h" +#include "label/LabelPairLabel.h" + +namespace determinize { + +label::Label VPADeterminizer::packToDVPAStateLabel(const std::set<std::pair<label::Label, label::Label>>& data) { + std::set<label::Label> res; + for(const auto& subData : data) { + res.insert(label::Label(label::LabelPairLabel(subData))); + } + return label::Label(label::LabelSetLabel(res)); +} + +std::set<std::pair<label::Label, label::Label>> VPADeterminizer::unpackFromDVPAStateLabel(const label::Label& data) { + std::set<std::pair<label::Label, label::Label>> res; + for (const auto& subData : static_cast<const label::LabelSetLabel&>(data.getData()).getData()) { + res.insert(static_cast<const label::LabelPairLabel&>(subData.getData()).getData()); + } + return res; +} + +label::Label VPADeterminizer::packToDVPAStackSymbolLabel(const std::pair<std::set<std::pair<label::Label, label::Label>>, label::Label>& data) { + std::set<label::Label> res; + for(const auto& subData : data.first) { + res.insert(label::Label(label::LabelPairLabel(subData))); + } + return label::Label(label::LabelPairLabel(std::make_pair(label::Label(label::LabelSetLabel(res)), data.second))); +} + +std::pair<std::set<std::pair<label::Label, label::Label>>, label::Label> VPADeterminizer::unpackFromDVPAStackSymbolLabel(const label::Label& data) { + std::set<std::pair<label::Label, label::Label>> res; + for (const auto& subData : static_cast<const label::LabelSetLabel&>(static_cast<const label::LabelPairLabel&>(data.getData()).getData().first.getData()).getData()) { + res.insert(static_cast<const label::LabelPairLabel&>(subData.getData()).getData()); + } + return std::make_pair(res, static_cast<const label::LabelPairLabel&>(data.getData()).getData().second); +} + +void addRetTransition(const automaton::State& from, const alphabet::Symbol& input, const alphabet::Symbol& dvpdaSymbol, const automaton::State& to, automaton::VisiblyPushdownNPDA& deterministic) { + deterministic.addState(from); + deterministic.addState(to); + deterministic.addStackSymbol(dvpdaSymbol); + + deterministic.addTransition(from, input, dvpdaSymbol, to); +} + +void retInitial(const automaton::State& state, const alphabet::Symbol& pdaSymbol, const alphabet::Symbol& input, const automaton::VisiblyPushdownNPDA& nondeterministic, automaton::VisiblyPushdownNPDA& deterministic) { + std::set<std::pair<label::Label, label::Label>> S = VPADeterminizer::unpackFromDVPAStateLabel(state.getName()); + + std::set<std::pair<label::Label, label::Label>> S1; + for(const auto& entry : S) { + const label::Label& q = entry.first; + const label::Label& q2 = entry.second; + + for(const auto& transition : nondeterministic.getReturnTransitions()) { + if(q2 != std::get<0>(transition.first).getName()) continue; + if(input != std::get<1>(transition.first)) continue; + if(nondeterministic.getBottomOfTheStackSymbol() != std::get<2>(transition.first)) continue; + + for(const auto& to : transition.second) { + const label::Label& q1 = to.getName(); + S1.insert(std::make_pair(q, q1)); + } + } + } + + addRetTransition(state, input, pdaSymbol, automaton::State(VPADeterminizer::packToDVPAStateLabel(S1)), deterministic); +} + +void ret(const automaton::State& state, const alphabet::Symbol& pdaSymbol, const alphabet::Symbol& input, const automaton::VisiblyPushdownNPDA& nondeterministic, automaton::VisiblyPushdownNPDA& deterministic) { + std::set<std::pair<label::Label, label::Label>> S = VPADeterminizer::unpackFromDVPAStateLabel(state.getName()); + std::pair<std::set<std::pair<label::Label, label::Label>>, label::Label> pdaSymbolUnpack = VPADeterminizer::unpackFromDVPAStackSymbolLabel(static_cast<const alphabet::LabeledSymbol&>(pdaSymbol.getData()).getLabel()); + const std::set<std::pair<label::Label, label::Label>>& S1 = pdaSymbolUnpack.first; + + std::set<std::pair<label::Label, label::Label>> update; + + for(const auto& transition : nondeterministic.getCallTransitions()) { + if(pdaSymbolUnpack.second != static_cast<const alphabet::LabeledSymbol&>(std::get<1>(transition.first).getData()).getLabel()) continue; + + const label::Label& q = std::get<0>(transition.first).getName(); + for(const auto& to : transition.second) { + const label::Label q1 = to.first.getName(); + const alphabet::Symbol& gamma = to.second; + + for(const auto& entry : S) { + if(q1 != entry.first) continue; + const label::Label& q2 = entry.second; + + for(const auto& transition2 : nondeterministic.getReturnTransitions()) { + if(q2 != std::get<0>(transition2.first).getName()) continue; + if(input != std::get<1>(transition2.first)) continue; + if(gamma != std::get<2>(transition2.first)) continue; + + for(const auto& to2 : transition2.second) { + const label::Label& qI = to2.getName(); + + update.insert(std::make_pair(q, qI)); + } + } + } + } + } + + std::set<std::pair<label::Label, label::Label>> S2; + for(const auto& entry : S1) { + const label::Label& q = entry.first; + const label::Label& q3 = entry.second; + for(const auto& entry2 : update) { + if(q3 != entry2.first) continue; + + const label::Label& qI = entry2.second; + + S2.insert(std::make_pair(q, qI)); + } + } + + addRetTransition(state, input, pdaSymbol, automaton::State(VPADeterminizer::packToDVPAStateLabel(S2)), deterministic); +} + +void addCallTransition(const automaton::State& from, const alphabet::Symbol& input, const automaton::State& to, const alphabet::Symbol& dvpdaSymbol, automaton::VisiblyPushdownNPDA& deterministic) { + deterministic.addState(from); + deterministic.addState(to); + deterministic.addStackSymbol(dvpdaSymbol); + + deterministic.addTransition(from, input, to, dvpdaSymbol); +} + +std::set<label::Label> retrieveDSubSet(const std::set<std::pair<label::Label, label::Label>>& localOperation) { + std::set<label::Label> id; + for(const auto& entry : localOperation) { + id.insert(entry.second); + } + return id; +} + +std::set<std::pair<label::Label, label::Label>> createIdentity(std::set<label::Label> states) { + std::set<std::pair<label::Label, label::Label>> id; + for(const label::Label& state : states) { + id.insert(std::make_pair(state, state)); + } + return id; +} + +void call(const automaton::State& state, const alphabet::Symbol& input, const automaton::VisiblyPushdownNPDA& nondeterministic, automaton::VisiblyPushdownNPDA& deterministic) { + std::set<std::pair<label::Label, label::Label>> S = VPADeterminizer::unpackFromDVPAStateLabel(state.getName()); + + std::set<label::Label> R = retrieveDSubSet(S); + std::set<label::Label> R1; + + for(const label::Label& q : R) { + for(const auto& transition : nondeterministic.getCallTransitions()) { + if(q != transition.first.first.getName()) continue; + if(input != transition.first.second) continue; + + for(const auto& to : transition.second) { + const label::Label& q1 = to.first.getName(); + + R1.insert(q1); + } + } + } + + const label::Label& inputLabel = static_cast<const alphabet::LabeledSymbol&>(input.getData()).getLabel(); + + addCallTransition(state, input, automaton::State(VPADeterminizer::packToDVPAStateLabel(createIdentity(R1))), alphabet::Symbol(alphabet::LabeledSymbol(VPADeterminizer::packToDVPAStackSymbolLabel(std::make_pair(S, inputLabel)))), deterministic); +} + +void addLocalTransition(const automaton::State& from, const alphabet::Symbol& input, const automaton::State& to, automaton::VisiblyPushdownNPDA& deterministic) { + deterministic.addState(from); + deterministic.addState(to); + + deterministic.addTransition(from, input, to); +} + +void local(const automaton::State& state, const alphabet::Symbol& input, const automaton::VisiblyPushdownNPDA& nondeterministic, automaton::VisiblyPushdownNPDA& deterministic) { + std::set<std::pair<label::Label, label::Label>> S = VPADeterminizer::unpackFromDVPAStateLabel(state.getName()); + std::set<std::pair<label::Label, label::Label>> S1; + + for(const auto& entry : S) { + label::Label q = entry.first; + label::Label q2 = entry.second; + for(const auto& transition : nondeterministic.getLocalTransitions()) { + if(q2 != transition.first.first.getName()) continue; + if(input != transition.first.second) continue; + + for(const auto& to : transition.second) { + label::Label q1 = to.getName(); + + S1.insert(std::make_pair(q, q1)); + } + } + } + + addLocalTransition(state, input, automaton::State(VPADeterminizer::packToDVPAStateLabel(S1)), deterministic); +} + +const automaton::State* existsDirtyState(const automaton::VisiblyPushdownNPDA& d) { + for(const automaton::State& state : d.getStates()) { + const label::Label& stateLabel = state.getName(); + + for(const auto& transition : d.getCallTransitions()) { + if(stateLabel != transition.first.first.getName()) continue; + + goto continue2; + } + return &state; + +continue2: while(false); + } + return NULL; +} + +std::set<label::Label> localClosure(std::set<label::Label> states, const automaton::VisiblyPushdownNPDA& d) { + std::set<label::Label> newStates; + + for(const label::Label& state : states) { + for(const auto& transition : d.getLocalTransitions()) { + if(!transition.second.count(automaton::State(state))) continue; + + newStates.insert(transition.first.first.getName()); + } + + for(const auto& transition : d.getReturnTransitions()) { + if(!transition.second.count(automaton::State(state))) continue; + + const alphabet::Symbol& popSymbol = std::get<2>(transition.first); + const label::Label& popSymbolLabel = static_cast<const alphabet::LabeledSymbol>(popSymbol.getData()).getLabel(); + const label::Label& statePart = static_cast<const label::LabelPairLabel&>(popSymbolLabel.getData()).getData().first; + newStates.insert(statePart); + } + } + if(states == newStates) return states; + return localClosure(newStates, d); +} + +std::pair<label::Label, alphabet::Symbol>* existsDirtyStateSymbol(const automaton::VisiblyPushdownNPDA& d) { + for(const automaton::State& state : d.getStates()) { + const label::Label& stateLabel = state.getName(); + + std::set<label::Label> lc = localClosure(std::set<label::Label> {stateLabel}, d); + std::set<alphabet::Symbol> topSymbols; + for(const label::Label& localState : lc) { + for(const auto& transition : d.getCallTransitions()) { + for(const auto& to : transition.second) { + if(localState != to.first.getName()) continue; + + topSymbols.insert(to.second); + } + } + + if(d.getInitialStates().count(localState)) { + topSymbols.insert(d.getBottomOfTheStackSymbol()); + } + } + + for(const auto& transition : d.getReturnTransitions()) { + if(stateLabel != std::get<0>(transition.first).getName()) continue; + + topSymbols.erase(std::get<2>(transition.first)); + } + + if(!topSymbols.empty()) return new std::pair<label::Label, alphabet::Symbol>(stateLabel, *topSymbols.begin()); + } + return NULL; +} + +std::set<label::Label> retrieveLabels(std::set<automaton::State> states) { + std::set<label::Label> labels; + for(const automaton::State& state : states) { + labels.insert(state.getName()); + } + return labels; +} + +automaton::VisiblyPushdownNPDA VPADeterminizer::determinize(const automaton::VisiblyPushdownNPDA& n) { + automaton::VisiblyPushdownNPDA d(n.getBottomOfTheStackSymbol()); + d.setCallInputSymbols(n.getCallInputAlphabet()); + d.setLocalInputSymbols(n.getLocalInputAlphabet()); + d.setReturnInputSymbols(n.getReturnInputAlphabet()); + + label::Label initialLabel = VPADeterminizer::packToDVPAStateLabel(createIdentity(retrieveLabels(n.getInitialStates()))); + d.addState(automaton::State(initialLabel)); + d.addInitialState(automaton::State(initialLabel)); + + for(;;) { + std::pair<label::Label, alphabet::Symbol>* stateSymbol = existsDirtyStateSymbol(d); + const automaton::State* state = existsDirtyState(d); + if(stateSymbol != NULL) { + for(alphabet::Symbol symbol : n.getReturnInputAlphabet()) { + if(stateSymbol->second == d.getBottomOfTheStackSymbol()) { + retInitial(stateSymbol->first, stateSymbol->second, symbol, n, d); + } else { + ret(stateSymbol->first, stateSymbol->second, symbol, n, d); + } + } + delete stateSymbol; //TODO remove this... + } else if(state != NULL) { + for(alphabet::Symbol symbol : n.getLocalInputAlphabet()) { + local(*state, symbol, n, d); + } + for(alphabet::Symbol symbol : n.getCallInputAlphabet()) { + call(*state, symbol, n, d); + } + } else { + break; + } + } + + std::set<label::Label> fin = retrieveLabels(n.getFinalStates()); + + for(automaton::State state : d.getStates()) { + std::set<label::Label> labels = retrieveDSubSet(VPADeterminizer::unpackFromDVPAStateLabel(state.getName())); + std::set<label::Label> finalLabels(fin); + + finalLabels.erase(labels.begin(), labels.end()); + + if(!finalLabels.empty()) { + d.addFinalState(state); + } + } + + return d; +} + +} diff --git a/alib2algo/src/determinize/vpa/VPADeterminizer.h b/alib2algo/src/determinize/vpa/VPADeterminizer.h new file mode 100644 index 0000000000..a3b7a62346 --- /dev/null +++ b/alib2algo/src/determinize/vpa/VPADeterminizer.h @@ -0,0 +1,31 @@ +#ifndef VPADETERMINIZER_H_ +#define VPADETERMINIZER_H_ + +#include "automaton/PDA/VisiblyPushdownNPDA.h" + +namespace determinize { + +/** + * Class for running basic determinization algorithm on vpa. + */ +class VPADeterminizer { +public: + static label::Label packToDVPAStateLabel(const std::set<std::pair<label::Label, label::Label>>& data); + + static std::set<std::pair<label::Label, label::Label>> unpackFromDVPAStateLabel(const label::Label& data); + + static label::Label packToDVPAStackSymbolLabel(const std::pair<std::set<std::pair<label::Label, label::Label>>, label::Label>& data); + + static std::pair<std::set<std::pair<label::Label, label::Label>>, label::Label> unpackFromDVPAStackSymbolLabel(const label::Label& data); + /** + * Runs determinization algorithm on nondeterministic vpa given in constructor. + * + * @return deterministic visibly pushdown automaton + */ + static automaton::VisiblyPushdownNPDA determinize(const automaton::VisiblyPushdownNPDA& nondeterministic); + +}; + +} /* namespace determinize */ + +#endif /* VPADETERMINIZER_h_ */ diff --git a/alib2algo/test-src/determinize/determinizeTest.cpp b/alib2algo/test-src/determinize/determinizeTest.cpp index 0e7891b6ef..6f7187a560 100644 --- a/alib2algo/test-src/determinize/determinizeTest.cpp +++ b/alib2algo/test-src/determinize/determinizeTest.cpp @@ -10,6 +10,8 @@ #include "determinize/nfa/NFADeterminizer.h" #include "determinize/idpda/IDPDADeterminizer.h" +#include "factory/DataFactory.hpp" + #define CPPUNIT_IMPLY(x, y) CPPUNIT_ASSERT(!(x) || (y)) CPPUNIT_TEST_SUITE_REGISTRATION( determinizeTest ); @@ -28,13 +30,13 @@ void determinizeTest::testDeterminizeNFA() { automaton.addState(automaton::State(3)); automaton.addInputSymbol(alphabet::symbolFrom("a")); automaton.addInputSymbol(alphabet::symbolFrom("b")); - + automaton.addTransition(automaton::State(1), alphabet::symbolFrom("a"), automaton::State(2)); automaton.addTransition(automaton::State(2), alphabet::symbolFrom("b"), automaton::State(1)); automaton.addInitialState(automaton::State(1)); automaton.addFinalState(automaton::State(3)); - + automaton::DFA determinized = determinize::NFADeterminizer::determinize(automaton); CPPUNIT_ASSERT(determinized.getStates().size() == 3); @@ -46,7 +48,7 @@ void determinizeTest::testDeterminizeIDPDA() { automaton.addInputSymbol(alphabet::symbolFrom("a")); automaton.addInputSymbol(alphabet::symbolFrom("b")); - + automaton.setPushdownStoreOperation(alphabet::symbolFrom("a"), std::vector<alphabet::Symbol>{}, std::vector<alphabet::Symbol> {}); automaton.setPushdownStoreOperation(alphabet::symbolFrom("b"), std::vector<alphabet::Symbol>{}, std::vector<alphabet::Symbol> {}); @@ -58,7 +60,9 @@ void determinizeTest::testDeterminizeIDPDA() { automaton.addInitialState(automaton::State(1)); automaton.addFinalState(automaton::State(3)); - + + alib::DataFactory::toStdout(automaton); + automaton::DPDA determinized = determinize::IDPDADeterminizer::determinize(automaton); CPPUNIT_ASSERT(determinized.getStates().size() == 3); diff --git a/alib2data/src/automaton/AutomatonFromXMLParser.cpp b/alib2data/src/automaton/AutomatonFromXMLParser.cpp index 052eb7def6..d781b89b51 100644 --- a/alib2data/src/automaton/AutomatonFromXMLParser.cpp +++ b/alib2data/src/automaton/AutomatonFromXMLParser.cpp @@ -48,10 +48,10 @@ Automaton AutomatonFromXMLParser::parseAutomaton(std::list<sax::Token>& input, c return Automaton(parseSinglePopDPDA(input)); } else if(isToken(input, sax::Token::TokenType::START_ELEMENT, "InputDrivenNPDA")) { if(!features.count(FEATURES::INPUT_DRIVEN_NPDA)) throw exception::AlibException(); - return Automaton(parseNPDA(input)); + return Automaton(parseInputDrivenNPDA(input)); } else if(isToken(input, sax::Token::TokenType::START_ELEMENT, "VisiblyPushdownNPDA")) { if(!features.count(FEATURES::VISIBLY_PUSHDOWN_NPDA)) throw exception::AlibException(); - return Automaton(parseSinglePopNPDA(input)); + return Automaton(parseVisiblyPushdownNPDA(input)); } else if(isToken(input, sax::Token::TokenType::START_ELEMENT, "NPDA")) { if(!features.count(FEATURES::NPDA)) throw exception::AlibException(); return Automaton(parseNPDA(input)); @@ -66,7 +66,7 @@ Automaton AutomatonFromXMLParser::parseAutomaton(std::list<sax::Token>& input, c } bool AutomatonFromXMLParser::first(std::list<sax::Token>& input) const { - if(isToken(input, sax::Token::TokenType::START_ELEMENT, "automaton") || isToken(input, sax::Token::TokenType::START_ELEMENT, "EpsilonNFA") || isToken(input, sax::Token::TokenType::START_ELEMENT, "NFA") || isToken(input, sax::Token::TokenType::START_ELEMENT, "DFA") || isToken(input, sax::Token::TokenType::START_ELEMENT, "CompactNFA") || isToken(input, sax::Token::TokenType::START_ELEMENT, "ExtendedNFA") || isToken(input, sax::Token::TokenType::START_ELEMENT, "DPDA") || isToken(input, sax::Token::TokenType::START_ELEMENT, "SinglePopDPDA") || isToken(input, sax::Token::TokenType::START_ELEMENT, "NPDA") || isToken(input, sax::Token::TokenType::START_ELEMENT, "SinglePopNPDA") || isToken(input, sax::Token::TokenType::START_ELEMENT, "OneTapeDTM")) { + if(isToken(input, sax::Token::TokenType::START_ELEMENT, "automaton") || isToken(input, sax::Token::TokenType::START_ELEMENT, "EpsilonNFA") || isToken(input, sax::Token::TokenType::START_ELEMENT, "NFA") || isToken(input, sax::Token::TokenType::START_ELEMENT, "DFA") || isToken(input, sax::Token::TokenType::START_ELEMENT, "CompactNFA") || isToken(input, sax::Token::TokenType::START_ELEMENT, "ExtendedNFA") || isToken(input, sax::Token::TokenType::START_ELEMENT, "DPDA") || isToken(input, sax::Token::TokenType::START_ELEMENT, "SinglePopDPDA") || isToken(input, sax::Token::TokenType::START_ELEMENT, "InputDrivenNPDA") || isToken(input, sax::Token::TokenType::START_ELEMENT, "VisiblyPushdownNPDA") || isToken(input, sax::Token::TokenType::START_ELEMENT, "NPDA") || isToken(input, sax::Token::TokenType::START_ELEMENT, "SinglePopNPDA") || isToken(input, sax::Token::TokenType::START_ELEMENT, "OneTapeDTM")) { return true; } else { return false; @@ -532,7 +532,7 @@ void AutomatonFromXMLParser::parseInputToPushdownStoreOperation(std::list<sax::T while (isTokenType(input, sax::Token::TokenType::START_ELEMENT)) { popToken(input, sax::Token::TokenType::START_ELEMENT, "operation"); - alphabet::Symbol inputSymbol = parseTransitionInputSymbol(input); + alphabet::Symbol inputSymbol(alib::api<alphabet::Symbol>::parse(input)); std::vector<alphabet::Symbol> pop = parseTransitionPop(input); std::vector<alphabet::Symbol> push = parseTransitionPush(input); diff --git a/alib2data/src/automaton/AutomatonToXMLComposer.cpp b/alib2data/src/automaton/AutomatonToXMLComposer.cpp index 941eaf6548..c30d83139e 100644 --- a/alib2data/src/automaton/AutomatonToXMLComposer.cpp +++ b/alib2data/src/automaton/AutomatonToXMLComposer.cpp @@ -118,7 +118,7 @@ void AutomatonToXMLComposer::composeBottomOfTheStackSymbol(std::list<sax::Token> void AutomatonToXMLComposer::composeInputToPushdownStoreOperation(std::list<sax::Token>& out, const automaton::InputDrivenNPDA& automaton) const { - out.push_back(sax::Token("inputToPushdownStoreOperation", sax::Token::TokenType::START_ELEMENT)); + out.push_back(sax::Token("inputToPushdownStoreOperations", sax::Token::TokenType::START_ELEMENT)); for(const auto& pushdownStoreOperation : automaton.getPushdownStoreOperations()) { out.push_back(sax::Token("operation", sax::Token::TokenType::START_ELEMENT)); @@ -129,7 +129,7 @@ void AutomatonToXMLComposer::composeInputToPushdownStoreOperation(std::list<sax: out.push_back(sax::Token("operation", sax::Token::TokenType::END_ELEMENT)); } - out.push_back(sax::Token("inputToPushdownStoreOperation", sax::Token::TokenType::END_ELEMENT)); + out.push_back(sax::Token("inputToPushdownStoreOperations", sax::Token::TokenType::END_ELEMENT)); } void AutomatonToXMLComposer::composeTransitions(std::list<sax::Token>& out, const UnknownAutomaton& automaton) const { @@ -644,8 +644,8 @@ std::list<sax::Token> AutomatonToXMLComposer::compose(const InputDrivenNPDA& aut composeInputAlphabet(out, automaton.getInputAlphabet()); composeStackAlphabet(out, automaton.getStackAlphabet()); composeInitialStates(out, automaton.getInitialStates()); - composeFinalStates(out, automaton.getFinalStates()); composeInitialStackSymbol(out, automaton.getInitialSymbol()); + composeFinalStates(out, automaton.getFinalStates()); composeInputToPushdownStoreOperation(out, automaton); composeTransitions(out, automaton); diff --git a/examples2/automaton/NIDPDA0.xml b/examples2/automaton/NIDPDA0.xml new file mode 100644 index 0000000000..941e5baeb0 --- /dev/null +++ b/examples2/automaton/NIDPDA0.xml @@ -0,0 +1,88 @@ +<InputDrivenNPDA> + <states> + <IntegerLabel>1</IntegerLabel> + <IntegerLabel>2</IntegerLabel> + <IntegerLabel>3</IntegerLabel> + </states> + <inputAlphabet> + <LabeledSymbol> + <StringLabel>a</StringLabel> + </LabeledSymbol> + <LabeledSymbol> + <StringLabel>b</StringLabel> + </LabeledSymbol> + </inputAlphabet> + <stackAlphabet> + <LabeledSymbol> + <CharacterLabel>S</CharacterLabel> + </LabeledSymbol> + </stackAlphabet> + <initialStates> + <IntegerLabel>1</IntegerLabel> + </initialStates> + <initialStackSymbol> + <LabeledSymbol> + <CharacterLabel>S</CharacterLabel> + </LabeledSymbol> + </initialStackSymbol> + <finalStates> + <IntegerLabel>3</IntegerLabel> + </finalStates> + <inputToPushdownStoreOperations> + <operation> + <LabeledSymbol> + <StringLabel>a</StringLabel> + </LabeledSymbol> + <pop/> + <push/> + </operation> + <operation> + <LabeledSymbol> + <StringLabel>b</StringLabel> + </LabeledSymbol> + <pop/> + <push/> + </operation> + </inputToPushdownStoreOperations> + <transitions> + <transition> + <from> + <IntegerLabel>1</IntegerLabel> + </from> + <input> + <LabeledSymbol> + <StringLabel>a</StringLabel> + </LabeledSymbol> + </input> + <to> + <IntegerLabel>2</IntegerLabel> + </to> + </transition> + <transition> + <from> + <IntegerLabel>2</IntegerLabel> + </from> + <input> + <LabeledSymbol> + <StringLabel>b</StringLabel> + </LabeledSymbol> + </input> + <to> + <IntegerLabel>1</IntegerLabel> + </to> + </transition> + <transition> + <from> + <IntegerLabel>2</IntegerLabel> + </from> + <input> + <LabeledSymbol> + <StringLabel>b</StringLabel> + </LabeledSymbol> + </input> + <to> + <IntegerLabel>3</IntegerLabel> + </to> + </transition> + </transitions> +</InputDrivenNPDA> diff --git a/examples2/automaton/NIDPDA1.xml b/examples2/automaton/NIDPDA1.xml new file mode 100644 index 0000000000..6be4da5419 --- /dev/null +++ b/examples2/automaton/NIDPDA1.xml @@ -0,0 +1,154 @@ +<InputDrivenNPDA> + <states> + <IntegerLabel>0</IntegerLabel> + <IntegerLabel>1</IntegerLabel> + <IntegerLabel>2</IntegerLabel> + <IntegerLabel>3</IntegerLabel> + </states> + <inputAlphabet> + <LabeledSymbol> + <StringLabel>a</StringLabel> + </LabeledSymbol> + <LabeledSymbol> + <StringLabel>b</StringLabel> + </LabeledSymbol> + <LabeledSymbol> + <StringLabel>c</StringLabel> + </LabeledSymbol> + <LabeledSymbol> + <StringLabel>d</StringLabel> + </LabeledSymbol> + </inputAlphabet> + <stackAlphabet> + <LabeledSymbol> + <StringLabel>a</StringLabel> + </LabeledSymbol> + <LabeledSymbol> + <StringLabel>b</StringLabel> + </LabeledSymbol> + </stackAlphabet> + <initialStates> + <IntegerLabel>0</IntegerLabel> + </initialStates> + <initialStackSymbol> + <LabeledSymbol> + <StringLabel>a</StringLabel> + </LabeledSymbol> + </initialStackSymbol> + <finalStates> + <IntegerLabel>3</IntegerLabel> + </finalStates> + <inputToPushdownStoreOperations> + <operation> + <LabeledSymbol> + <StringLabel>a</StringLabel> + </LabeledSymbol> + <pop/> + <push> + <LabeledSymbol> + <StringLabel>a</StringLabel> + </LabeledSymbol> + </push> + </operation> + <operation> + <LabeledSymbol> + <StringLabel>b</StringLabel> + </LabeledSymbol> + <pop/> + <push> + <LabeledSymbol> + <StringLabel>b</StringLabel> + </LabeledSymbol> + </push> + </operation> + <operation> + <LabeledSymbol> + <StringLabel>c</StringLabel> + </LabeledSymbol> + <pop> + <LabeledSymbol> + <StringLabel>b</StringLabel> + </LabeledSymbol> + </pop> + <push/> + </operation> + <operation> + <LabeledSymbol> + <StringLabel>d</StringLabel> + </LabeledSymbol> + <pop> + <LabeledSymbol> + <StringLabel>a</StringLabel> + </LabeledSymbol> + </pop> + <push/> + </operation> + </inputToPushdownStoreOperations> + <transitions> + <transition> + <from> + <IntegerLabel>0</IntegerLabel> + </from> + <input> + <LabeledSymbol> + <StringLabel>a</StringLabel> + </LabeledSymbol> + </input> + <to> + <IntegerLabel>1</IntegerLabel> + </to> + </transition> + <transition> + <from> + <IntegerLabel>1</IntegerLabel> + </from> + <input> + <LabeledSymbol> + <StringLabel>b</StringLabel> + </LabeledSymbol> + </input> + <to> + <IntegerLabel>1</IntegerLabel> + </to> + </transition> + <transition> + <from> + <IntegerLabel>1</IntegerLabel> + </from> + <input> + <LabeledSymbol> + <StringLabel>b</StringLabel> + </LabeledSymbol> + </input> + <to> + <IntegerLabel>2</IntegerLabel> + </to> + </transition> + <transition> + <from> + <IntegerLabel>2</IntegerLabel> + </from> + <input> + <LabeledSymbol> + <StringLabel>c</StringLabel> + </LabeledSymbol> + </input> + <to> + <IntegerLabel>2</IntegerLabel> + </to> + </transition> + <transition> + <from> + <IntegerLabel>2</IntegerLabel> + </from> + <input> + <LabeledSymbol> + <StringLabel>d</StringLabel> + </LabeledSymbol> + </input> + <to> + <IntegerLabel>3</IntegerLabel> + </to> + </transition> + </transitions> +</InputDrivenNPDA> -- GitLab