You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
379 lines
9.6 KiB
379 lines
9.6 KiB
/*
|
|
* This file is part of the program ltl2dstar (http://www.ltl2dstar.de/).
|
|
* Copyright (C) 2005-2007 Joachim Klein <j.klein@ltl2dstar.de>
|
|
*
|
|
* 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 <vector>
|
|
#include <string>
|
|
#include <boost/lexical_cast.hpp>
|
|
#include <cassert>
|
|
|
|
/**
|
|
* 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 <class DRA, class NBA>
|
|
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 <class DRA, class NBA>
|
|
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_state_t*> > nba_states;
|
|
|
|
nba_states.resize(dra.size());
|
|
for (unsigned int i=0;i<dra.size();i++) {
|
|
nba_states[i].resize(dra.acceptance().size()+1);
|
|
|
|
// basic level
|
|
nba_states[i][0]=nba.newState();
|
|
if (detailed_states) {
|
|
nba_states[i][0]->
|
|
setDescription(boost::lexical_cast<std::string>(i));
|
|
}
|
|
|
|
for (unsigned int j=0;j<dra.acceptance().size();j++) {
|
|
if (dra.acceptance().isStateInAcceptance_U(j,i)) {
|
|
;
|
|
} else {
|
|
nba_states[i][j+1]=nba.newState();
|
|
if (detailed_states) {
|
|
nba_states[i][j+1]->
|
|
setDescription(boost::lexical_cast<std::string>(i)+"_"+
|
|
boost::lexical_cast<std::string>(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;i<dra.size();i++) {
|
|
for (typename DRA::edge_iterator edge_it=dra[i]->edges().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;j<dra.acceptance().size();j++) {
|
|
if (dra.acceptance().isStateInAcceptance_L(j,i) &&
|
|
!dra.acceptance().isStateInAcceptance_U(j, dra_to_index)) {
|
|
nba_states[i][0]->addEdge(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<y) {return true;} \
|
|
else if (!(x==y)) {return false;}
|
|
|
|
/** Less-than operator */
|
|
bool operator<(const DSABuchiState& other) const {
|
|
CMP_LESS(_dsa_state_index, other._dsa_state_index);
|
|
CMP_LESS(_no_IJ, other._no_IJ);
|
|
CMP_LESS(_Iset, other._Iset);
|
|
CMP_LESS(_Jset, other._Jset);
|
|
|
|
return false;
|
|
}
|
|
|
|
/** return a hash value */
|
|
unsigned int hashCode() const {
|
|
StdHashFunction hash;
|
|
hash.hash(_dsa_state_index);
|
|
if (_no_IJ) {
|
|
hash.hash((unsigned char)'1');
|
|
} else {
|
|
_Iset.hashCode(hash);
|
|
_Jset.hashCode(hash);
|
|
}
|
|
|
|
return hash.value();
|
|
}
|
|
|
|
/** Helper hash_function */
|
|
struct hash_function {
|
|
size_t operator()(const DSABuchiState& state) const {
|
|
return state.hashCode();
|
|
}
|
|
};
|
|
};
|
|
|
|
|
|
/** Convert a DSA to an NBA.*/
|
|
template <class DRA, class NBA>
|
|
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<DSABuchiState, nba_state_t*> 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<DSABuchiState, nba_state_t*, DSABuchiState::hash_function> 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
|