/* * This file is part of the program ltl2dstar (http://www.ltl2dstar.de/). * Copyright (C) 2005-2007 Joachim Klein * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef DRA2NBA_HPP #define DRA2NBA_HPP /** @file * Provides class DRA2NBA, which can convert a DRA/DSA to an equivalent * nondeterministic Büchi automaton. */ #include "DRA.hpp" #include "NBA.hpp" #include "common/hash_map.hpp" #include "common/HashFunction.hpp" #include #include #include #include /** * Converts a DRA/DSA to an equivalent nondeterministic Büchi automaton. */ class DRA2NBA { public: /** Generate an NBA that is equivalent to the DRA/DSA. * @param dra the DRA/DSA * @return a shared_ptr to an equivalent NBA */ template static typename NBA::shared_ptr dra2nba(DRA& dra) { APSet_cp ap_set=dra.getAPSet_cp();; typename NBA::shared_ptr nba_p(new NBA(ap_set)); if (dra.isStreett()) { convert_dsa2nba(dra, *nba_p); } else { convert_dra2nba(dra, *nba_p); } return nba_p; } private: /** * Perform the conversion from a DRA to an NBA. */ template static void convert_dra2nba(DRA& dra, NBA& nba, bool detailed_states=false) { typedef typename DRA::state_type dra_state_t; typedef typename NBA::state_type nba_state_t; assert(dra.isStreett() == false); if (!dra.isCompact()) { dra.makeCompact(); } std::vector< std::vector > nba_states; nba_states.resize(dra.size()); for (unsigned int i=0;i setDescription(boost::lexical_cast(i)); } for (unsigned int j=0;j setDescription(boost::lexical_cast(i)+"_"+ boost::lexical_cast(j)); } if (dra.acceptance().isStateInAcceptance_L(j,i)) { nba_states[i][j+1]->setFinal(true); } } } } assert(dra.getStartState()!=0); nba.setStartState(nba_states[dra.getIndexForState(dra.getStartState())][0]); for (unsigned int i=0;iedges().begin(); edge_it!=dra[i]->edges().end(); ++edge_it) { typename DRA::edge_type edge=*edge_it; unsigned int dra_to_index=dra.getIndexForState(edge.second); nba_states[i][0]->addEdge(edge.first, *nba_states[dra_to_index][0]); for (unsigned int j=0;jaddEdge(edge.first, *nba_states[dra_to_index][j+1]); } if (dra.acceptance().isStateInAcceptance_U(j,i) || dra.acceptance().isStateInAcceptance_U(j,dra_to_index)) { ; } else { nba_states[i][j+1]->addEdge(edge.first, *nba_states[dra_to_index][j+1]); } } } } } /** * Helper class, holds a state in the NBA generated for a Streett automaton. * Holds the index of the state in the DSA, * and two bitsets _Iset and _Jset which represent the acceptance pairs * that have not yet been satisfied. */ struct DSABuchiState { /** The index of the DSA state */ unsigned int _dsa_state_index; /** Bitsets representing I and J */ BitSet _Iset, _Jset; /** if true, no I/J exist (base copy of the DSA) */ bool _no_IJ; /** Constructor */ DSABuchiState(unsigned int dsa_state_index) : _dsa_state_index(dsa_state_index), _no_IJ(true) {} /** Constructor */ DSABuchiState(unsigned int dsa_state_index, BitSet I, BitSet J) : _dsa_state_index(dsa_state_index), _Iset(I), _Jset(J), _no_IJ(false) {} /** Equality */ bool operator==(const DSABuchiState& other) const { if (_dsa_state_index==other._dsa_state_index && _no_IJ==other._no_IJ && _Iset==other._Iset && _Jset==other._Jset) { return true; } return false; } #define CMP_LESS(x,y) if (x static void convert_dsa2nba(DRA& dsa, NBA& nba) { typedef typename DRA::state_type dsa_state_t; typedef typename NBA::state_type nba_state_t; assert(dsa.isStreett() == true); if (!dsa.isCompact()) { dsa.makeCompact(); } typedef std::pair unprocessed_pair; typedef std::stack< unprocessed_pair > unprocessed_vector; unprocessed_vector unprocessed; const APSet& ap_set=dsa.getAPSet(); /* Local helper class to keep track of the states in the NBA. */ class DSA2BuchiCalculator { public: /* The DSA */ DRA& _dsa; /* The NBA */ NBA& _nba; /* hash_map-type to store the DSABuchiStates and corresponding NBA_States */ typedef myHashMap state_map_t; /* Type of iterator over the hash_map */ typedef typename state_map_t::iterator state_map_iterator; /* Map for the states */ state_map_t new_states; /* Constructor */ DSA2BuchiCalculator(DRA& dsa, NBA& nba) : _dsa(dsa), _nba(nba) { } /* * Find an already existing DSABuchiState * @return a pointer to the DSABuchiState, NULL if it doesn't exist */ nba_state_t* findState(DSABuchiState& description) { state_map_iterator it; it = new_states.find(description); if (it!=new_states.end()) { return (*it).second; } else { return 0; } } /* * Create a new NBA state corresponding to the DSABuchiState */ nba_state_t* createState(DSABuchiState& description) { nba_state_t* state=_nba.newState(); new_states[description]=state; if (!description._no_IJ && description._Iset.isEmpty() && description._Jset.isEmpty()) { state->setFinal(true); } return state; } }; DSA2BuchiCalculator calc(dsa, nba); assert(dsa.getStartState()!=0); dsa_state_t *start_dsa=dsa.getStartState(); DSABuchiState start_dbn(start_dsa->getName()); nba_state_t *start=calc.createState(start_dbn); nba.setStartState(start); unprocessed.push(unprocessed_pair(start_dbn, start)); while (!unprocessed.empty()) { unprocessed_pair cur=unprocessed.top(); unprocessed.pop(); dsa_state_t* dsa_from=dsa[cur.first._dsa_state_index]; nba_state_t* nba_from=cur.second; for (typename APSet::element_iterator eit=ap_set.all_elements_begin(); eit!=ap_set.all_elements_end(); ++eit) { typename DRA::label_type label=*eit; dsa_state_t* dsa_to= dsa_from->edges().get(label); if (cur.first._no_IJ) { DSABuchiState p(dsa_to->getName()); DSABuchiState p00(dsa_to->getName(), BitSet(0), BitSet(0)); nba_state_t* nba_p=calc.findState(p); if (nba_p==0) { nba_p=calc.createState(p); unprocessed.push(unprocessed_pair(p, nba_p)); } nba_from->addEdge(label, *nba_p); nba_state_t* nba_p00=calc.findState(p00); if (nba_p00==0) { nba_p00=calc.createState(p00); unprocessed.push(unprocessed_pair(p00, nba_p00)); } nba_from->addEdge(label, *nba_p00); } else { BitSet I_=cur.first._Iset; I_.Union(dsa.acceptance().getAcceptance_L_forState(dsa_from->getName())); BitSet J_=cur.first._Jset; J_.Union(dsa.acceptance().getAcceptance_U_forState(dsa_from->getName())); BitSet subset=I_; subset.Minus(J_); if (subset.isEmpty()) { // I' - J' = 0 <=> I \subseteq J I_.clear(); J_.clear(); } DSABuchiState dbn_to(dsa_to->getName(), I_, J_); nba_state_t* nba_to=calc.findState(dbn_to); if (nba_to==0) { nba_to=calc.createState(dbn_to); unprocessed.push(unprocessed_pair(dbn_to, nba_to)); } nba_from->addEdge(label, *nba_to); } } } } }; #endif