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.
634 lines
17 KiB
634 lines
17 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 RABINACCEPTANCE_H
|
|
#define RABINACCEPTANCE_H
|
|
|
|
/** @file
|
|
* Provides class RabinAcceptance.
|
|
*/
|
|
|
|
#include "common/BitSet.hpp"
|
|
#include "common/Exceptions.hpp"
|
|
#include <boost/iterator/filter_iterator.hpp>
|
|
#include <boost/iterator/counting_iterator.hpp>
|
|
|
|
#include <iostream>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
|
|
/**
|
|
* Class storing a Rabin acceptance condition.
|
|
* Contains a number k of pairs of BitSets (L_i,U_i), where the states
|
|
* in the acceptance sets L_i and U_i are set.
|
|
*/
|
|
class RabinAcceptance {
|
|
public:
|
|
/**
|
|
* Constructor
|
|
* @param number_of_initial_pairs The initial numbers of pairs to allocate
|
|
*/
|
|
RabinAcceptance(unsigned int number_of_initial_pairs=0) :
|
|
_is_compact(true) {
|
|
if (number_of_initial_pairs>0) {
|
|
newAcceptancePairs(number_of_initial_pairs);
|
|
}
|
|
}
|
|
|
|
/** Destructor */
|
|
~RabinAcceptance() {
|
|
// delete BitSets in the acceptance pairs
|
|
for (std::vector<BitSet*>::iterator it=_acceptance_L.begin();
|
|
it!=_acceptance_L.end();
|
|
++it) {
|
|
delete *it;
|
|
}
|
|
|
|
for (std::vector<BitSet*>::iterator it=_acceptance_U.begin();
|
|
it!=_acceptance_U.end();
|
|
++it) {
|
|
delete *it;
|
|
}
|
|
}
|
|
|
|
private:
|
|
RabinAcceptance(const RabinAcceptance& other); // not yet implemented
|
|
|
|
public:
|
|
|
|
|
|
// ---- The AcceptanceCondition Interface
|
|
|
|
/**
|
|
* Check if this RabinAcceptance is compact (part of interface AcceptanceCondition).
|
|
* @return true iff compact
|
|
*/
|
|
bool isCompact() const {
|
|
return _is_compact;
|
|
}
|
|
|
|
|
|
/**
|
|
* Make this RabinAcceptance compact (part of interface AcceptanceCondition).
|
|
*/
|
|
void makeCompact() {
|
|
if (isCompact()) {
|
|
return;
|
|
}
|
|
|
|
// Compress Acceptance-Pairs
|
|
unsigned pair_to=0;
|
|
for (unsigned int pair_from=0;
|
|
pair_from<_acceptance_L.size();
|
|
pair_from++) {
|
|
if (_acceptance_L[pair_from]!=0) {
|
|
if (pair_from==pair_to) {
|
|
// nothing to do
|
|
} else {
|
|
_acceptance_L[pair_to]=_acceptance_L[pair_from];
|
|
_acceptance_U[pair_to]=_acceptance_U[pair_from];
|
|
}
|
|
|
|
++pair_to;
|
|
}
|
|
}
|
|
|
|
unsigned int new_acceptance_count=pair_to;
|
|
|
|
_acceptance_L.resize(new_acceptance_count);
|
|
_acceptance_U.resize(new_acceptance_count);
|
|
|
|
_is_compact=true;
|
|
}
|
|
|
|
|
|
/** Update the acceptance condition upon renaming of states acording
|
|
* to the mapping (part of AcceptanceCondition interface).
|
|
* Assumes that states can only get a lower name.
|
|
* @param mapping vector with mapping a[i] -> j
|
|
*/
|
|
void moveStates(std::vector<unsigned int> mapping) {
|
|
if (!isCompact()) {
|
|
makeCompact();
|
|
}
|
|
|
|
for (unsigned int i=0;i<size();++i) {
|
|
move_acceptance_bits(*_acceptance_L[i], mapping);
|
|
move_acceptance_bits(*_acceptance_U[i], mapping);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Print the Acceptance-Pairs: header (part of interface AcceptanceCondition).
|
|
* @param out the output stream.
|
|
*/
|
|
void outputAcceptanceHeader(std::ostream& out) const {
|
|
out << "Acceptance-Pairs: "<< size() << std::endl;
|
|
}
|
|
|
|
/**
|
|
* Print the Acc-Sig: line for a state (part of interface AcceptanceCondition).
|
|
* @param out the output stream.
|
|
* @param state_index the state
|
|
*/
|
|
void outputAcceptanceForState(std::ostream& out, unsigned int state_index) const {
|
|
out << "Acc-Sig:";
|
|
for (unsigned int pair_index=0;pair_index<size();pair_index++) {
|
|
if (isStateInAcceptance_L(pair_index, state_index)) {
|
|
out << " +" << pair_index;
|
|
}
|
|
|
|
if (isStateInAcceptance_U(pair_index, state_index)) {
|
|
out << " -" << pair_index;
|
|
}
|
|
}
|
|
out << std::endl;
|
|
}
|
|
|
|
|
|
/**
|
|
* Add a state (part of interface AcceptanceCondition).
|
|
* @param state_index the index of the added state.
|
|
*/
|
|
void addState(unsigned int state_index) {
|
|
// TODO: Assert that state_index > highest set bit
|
|
;
|
|
}
|
|
|
|
/** The 3 different colors for RabinAcceptance */
|
|
enum RabinColor {RABIN_WHITE=0, RABIN_GREEN=1, RABIN_RED=2};
|
|
|
|
/** A class storing the acceptance signature for a state
|
|
* (for every acceptance pair one color).
|
|
*/
|
|
class RabinSignature {
|
|
public:
|
|
/** Constructor
|
|
* @param size the number of acceptance pairs
|
|
*/
|
|
RabinSignature(unsigned int size) : _size(size) {}
|
|
|
|
/** Constructor
|
|
* @param other another RabinSignature
|
|
*/
|
|
RabinSignature(const RabinSignature& other) :
|
|
_L(other._L), _U(other._U), _size(other._size) {}
|
|
|
|
/** Constructor
|
|
* @param L the L part of the acceptance signature.
|
|
* @param U the U part of the acceptance signature.
|
|
* @param size the number of acceptance pairs
|
|
*/
|
|
RabinSignature(const BitSet& L, const BitSet U, unsigned int size)
|
|
: _L(L), _U(U), _size(size) {}
|
|
|
|
/** Constructor for getting the acceptance signature for a Tree.
|
|
* @param tree the Tree, get acceptance signature from
|
|
* tree.generateAcceptance(*this).
|
|
*/
|
|
template <typename Tree>
|
|
RabinSignature(const Tree& tree) :_size(0) {
|
|
tree.generateAcceptance(*this);
|
|
}
|
|
|
|
/** Clear the acceptance signature */
|
|
void clear() {
|
|
_L.clear();
|
|
_U.clear();
|
|
}
|
|
|
|
/** Get the L part of this acceptance signature */
|
|
const BitSet& getL() const {return _L;}
|
|
/** Get the U part of this acceptance signature */
|
|
const BitSet& getU() const {return _U;}
|
|
|
|
/** Get the L part of this acceptance signature */
|
|
BitSet& getL() {return _L;}
|
|
/** Get the U part of this acceptance signature */
|
|
BitSet& getU() {return _U;}
|
|
|
|
/** Set index to value in the L part of this acceptance signature. */
|
|
void setL(unsigned int index, bool value=true) {
|
|
_L.set(index, value);
|
|
}
|
|
|
|
/** Set index to value. in the U part of this acceptance signature. */
|
|
void setU(unsigned int index, bool value=true) {
|
|
_U.set(index, value);
|
|
}
|
|
|
|
/** Set the L and U parts according to RabinColor c.
|
|
* @param i The pair index
|
|
* @param c the RabinColor
|
|
*/
|
|
void setColor(unsigned int i, RabinColor c) {
|
|
switch (c) {
|
|
case RABIN_RED:
|
|
_U.set(i, true);
|
|
_L.set(i, false);
|
|
break;
|
|
|
|
case RABIN_GREEN:
|
|
_U.set(i, false);
|
|
_L.set(i, true);
|
|
break;
|
|
|
|
case RABIN_WHITE:
|
|
_U.set(i, false);
|
|
_L.set(i, false);
|
|
break;
|
|
}
|
|
};
|
|
|
|
/** Get the RabinColor for a pair i */
|
|
RabinColor getColor(unsigned int i) const {
|
|
return _U.get(i) ? RABIN_RED : (_L.get(i) ? RABIN_GREEN : RABIN_WHITE);
|
|
}
|
|
|
|
/** Get string representation of this signature. */
|
|
std::string toString() const {
|
|
std::string a;
|
|
a="{";
|
|
for (unsigned int i=0;i<size();i++) {
|
|
switch (getColor(i)) {
|
|
case RABIN_RED:
|
|
a+='-'+boost::lexical_cast<std::string>(i);
|
|
break;
|
|
case RABIN_GREEN:
|
|
a+='+'+boost::lexical_cast<std::string>(i);
|
|
break;
|
|
case RABIN_WHITE:
|
|
break;
|
|
}
|
|
}
|
|
a+="}";
|
|
|
|
return a;
|
|
}
|
|
|
|
/** Compare to other signature for equality. */
|
|
bool operator==(const RabinSignature& other) const {
|
|
return ( _L==other.getL() ) && ( _U==other.getU() );
|
|
}
|
|
|
|
/** Compare less_than to other signature */
|
|
bool operator<(const RabinSignature& other) const {
|
|
if (_L<other.getL()) {
|
|
return true;
|
|
} else if (_L==other.getL()) {
|
|
return _U<other.getU();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/** Get the number of acceptance pairs */
|
|
unsigned int getSize() const {return _size;}
|
|
/** Get the number of acceptance pairs */
|
|
unsigned int size() const {return _size;}
|
|
|
|
/** Set the number of acceptance pairs */
|
|
void setSize(unsigned int size) {_size=size;}
|
|
|
|
/** Merge this acceptance signature with other signature,
|
|
* for each tuple element calculate the maximum of the
|
|
* colors according to the order
|
|
* RABIN_WHITE < RABIN_GREEN < RABIN_RED */
|
|
void maxMerge(const RabinSignature& other) {
|
|
for (unsigned int i=0;i<_size;i++) {
|
|
if (getColor(i) < other.getColor(i)) {
|
|
setColor(i, other.getColor(i));
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Calculate a hash value using HashFunction
|
|
* @param hashfunction the HashFunction
|
|
*/
|
|
template <class HashFunction>
|
|
void hashCode(HashFunction& hashfunction) {
|
|
_L.hashCode(hashfunction);
|
|
_U.hashCode(hashfunction);
|
|
}
|
|
|
|
|
|
private:
|
|
/** The L part */
|
|
BitSet _L;
|
|
/** The U part */
|
|
BitSet _U;
|
|
/** The number of acceptance pairs */
|
|
unsigned int _size;
|
|
};
|
|
|
|
/** The signature_type (part of AcceptanceCondition interface) */
|
|
typedef RabinSignature signature_type;
|
|
|
|
/** Accessor for the acceptance signature for a state
|
|
* (part of AcceptanceCondition interface)
|
|
*/
|
|
class AcceptanceForState {
|
|
private:
|
|
/** Reference to the underlying RabinAcceptance */
|
|
RabinAcceptance& _acceptance;
|
|
/** The state index for this accessor */
|
|
unsigned int _state_index;
|
|
|
|
public:
|
|
/** Constructor */
|
|
AcceptanceForState(RabinAcceptance& acceptance,
|
|
unsigned int state_index) :
|
|
_acceptance(acceptance), _state_index(state_index) {}
|
|
|
|
/** Add this state to L[pair_index] */
|
|
void addTo_L(unsigned int pair_index) {
|
|
_acceptance.getAcceptance_L(pair_index).set(_state_index);
|
|
_acceptance.getAcceptance_U(pair_index).set(_state_index, false);
|
|
}
|
|
|
|
/** Add this state to U[pair_index] */
|
|
void addTo_U(unsigned int pair_index) {
|
|
_acceptance.getAcceptance_U(pair_index).set(_state_index);
|
|
_acceptance.getAcceptance_L(pair_index).set(_state_index, false);
|
|
}
|
|
|
|
/** Is this state in L[pair_index] */
|
|
bool isIn_L(unsigned int pair_index) const {
|
|
return _acceptance.isStateInAcceptance_L(pair_index, _state_index);
|
|
}
|
|
|
|
/** Is this state in U[pair_index] */
|
|
bool isIn_U(unsigned int pair_index) const {
|
|
return _acceptance.isStateInAcceptance_U(pair_index, _state_index);
|
|
}
|
|
|
|
/** Set L and U for this state according to RabinSignature */
|
|
void setSignature(const RabinSignature& signature) {
|
|
for (unsigned int i=0;i<signature.size();i++) {
|
|
if (signature.getL().get(i)) {
|
|
addTo_L(i);
|
|
}
|
|
if (signature.getU().get(i)) {
|
|
addTo_U(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Get number of acceptance pairs */
|
|
unsigned int size() const {return _acceptance.size();}
|
|
|
|
/** Get the signature for this state */
|
|
RabinSignature getSignature() const {
|
|
return RabinSignature(_acceptance.getAcceptance_L_forState(_state_index),
|
|
_acceptance.getAcceptance_U_forState(_state_index),
|
|
_acceptance.size());
|
|
}
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// ---- Rabin/Streett acceptance specific
|
|
|
|
/**
|
|
* Creates a new acceptance pair.
|
|
* @return the index of the new acceptance pair.
|
|
*/
|
|
unsigned int newAcceptancePair() {
|
|
BitSet *l=new BitSet();
|
|
BitSet *u=new BitSet();
|
|
|
|
_acceptance_L.push_back(l);
|
|
_acceptance_U.push_back(u);
|
|
|
|
_acceptance_count++;
|
|
return _acceptance_L.size()-1;
|
|
}
|
|
|
|
|
|
/**
|
|
* Creates count new acceptance pairs.
|
|
* @return the index of the first new acceptance pair.
|
|
*/
|
|
unsigned int newAcceptancePairs(unsigned int count) {
|
|
unsigned int rv=_acceptance_L.size();
|
|
|
|
for (unsigned int i=0;i<count;i++) {
|
|
newAcceptancePair();
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
|
|
/**
|
|
* Delete an acceptance pair.
|
|
*/
|
|
void removeAcceptancePair(unsigned int pair_index) {
|
|
if (_acceptance_L[pair_index]!=0) {
|
|
_acceptance_count--;
|
|
}
|
|
|
|
delete _acceptance_L[pair_index];
|
|
delete _acceptance_U[pair_index];
|
|
|
|
_acceptance_L[pair_index]=0;
|
|
_acceptance_U[pair_index]=0;
|
|
|
|
_is_compact=false;
|
|
}
|
|
|
|
|
|
/**
|
|
* Get a reference to the BitSet representing L[pair_index],
|
|
* allowing changes to this set.
|
|
*/
|
|
BitSet& getAcceptance_L(unsigned int pair_index) {
|
|
return *_acceptance_L[pair_index];
|
|
}
|
|
|
|
/**
|
|
* Get a reference to the BitSet representing U[pair_index],
|
|
* allowing changes to this set.
|
|
*/
|
|
BitSet& getAcceptance_U(unsigned int pair_index) {
|
|
return *_acceptance_U[pair_index];
|
|
}
|
|
|
|
|
|
/**
|
|
* Get the L part of the acceptance signature for a state (changes to the
|
|
* BitSet do not affect the automaton).
|
|
*/
|
|
BitSet getAcceptance_L_forState(unsigned int state_index) const {
|
|
BitSet result;
|
|
getBitSetForState(state_index, _acceptance_L, &result);
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Get the U part of the acceptance signature for a state (changes to the
|
|
* BitSet do not affect the automaton).
|
|
*/
|
|
BitSet getAcceptance_U_forState(unsigned int state_index) const {
|
|
BitSet result;
|
|
getBitSetForState(state_index, _acceptance_U, &result);
|
|
|
|
return result;
|
|
}
|
|
|
|
/** Is a certain state in L[pair_index]? */
|
|
bool isStateInAcceptance_L(unsigned int pair_index,
|
|
unsigned int state_index) const {
|
|
return _acceptance_L[pair_index]->get(state_index);
|
|
}
|
|
|
|
/** Is a certain state in U[pair_index]? */
|
|
bool isStateInAcceptance_U(unsigned int pair_index,
|
|
unsigned int state_index) const {
|
|
return _acceptance_U[pair_index]->get(state_index);
|
|
}
|
|
|
|
/** Set L[pair_index] for this state to value. */
|
|
void stateIn_L(unsigned int pair_index,
|
|
unsigned int state_index,
|
|
bool value=true) {
|
|
getAcceptance_L(pair_index).set(state_index,value);
|
|
}
|
|
|
|
/** Set U[pair_index] for this state to value. */
|
|
void stateIn_U(unsigned int pair_index,
|
|
unsigned int state_index,
|
|
bool value=true) {
|
|
getAcceptance_U(pair_index).set(state_index,value);
|
|
}
|
|
|
|
/** Get the number of acceptance pairs.
|
|
* Requires the acceptance pairs to be compact. */
|
|
unsigned int size() const {
|
|
if (!isCompact()) {
|
|
throw Exception("Can't give acceptance pair count for uncompacted condition.");
|
|
}
|
|
return _acceptance_L.size();
|
|
}
|
|
|
|
|
|
private:
|
|
/** A vector of BitSet* */
|
|
typedef std::vector<BitSet*> BitSetVector;
|
|
|
|
/** Helper functor for acceptance_pair_iterator. */
|
|
struct acceptance_is_not_null{
|
|
BitSetVector& _acceptance_vector;
|
|
acceptance_is_not_null(BitSetVector& acceptance_vector) :
|
|
_acceptance_vector(acceptance_vector) {;};
|
|
|
|
bool operator()(int i) { return _acceptance_vector[i]!=0; };
|
|
};
|
|
|
|
public:
|
|
/** Type of an iterator over the index of acceptance pairs. */
|
|
typedef boost::filter_iterator<acceptance_is_not_null,
|
|
boost::counting_iterator<int> >
|
|
acceptance_pair_iterator;
|
|
|
|
/** Iterator pointing to the index of the first acceptance pair. */
|
|
acceptance_pair_iterator acceptance_pair_begin() {
|
|
return acceptance_pair_iterator(acceptance_is_not_null(_acceptance_L), boost::counting_iterator<int>(0), boost::counting_iterator<int>(_acceptance_L.size()));
|
|
};
|
|
|
|
/** Iterator pointing after the index of the last acceptance pair. */
|
|
acceptance_pair_iterator acceptance_pair_end() {
|
|
return acceptance_pair_iterator(acceptance_is_not_null(_acceptance_L), boost::counting_iterator<int>(_acceptance_L.size()), boost::counting_iterator<int>(_acceptance_L.size()));
|
|
};
|
|
|
|
|
|
private: //functions
|
|
/** Calculate the BitSet for a state from the acceptance pairs, store
|
|
* result in result.
|
|
* @param state_index the state
|
|
* @param acc the BitSetVector (either _L or _U)
|
|
* @param result the Bitset where the results are stored, has to be clear
|
|
* at the beginning!
|
|
*/
|
|
void getBitSetForState(unsigned int state_index,
|
|
const BitSetVector& acc,
|
|
BitSet* result) const {
|
|
|
|
for (unsigned int i=0;i<acc.size();i++) {
|
|
if (acc[i]!=0) {
|
|
if (acc[i]->get(state_index)) {
|
|
result->set(i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Move the bits set in acc to the places specified by mapping.
|
|
*/
|
|
void move_acceptance_bits(BitSet& acc,
|
|
std::vector<unsigned int> mapping) {
|
|
int i=acc.nextSetBit(0);
|
|
while (i!=-1) {
|
|
unsigned int j=mapping[i];
|
|
// :: j is always <= i
|
|
if (j>(unsigned int)i) {
|
|
THROW_EXCEPTION(Exception, "Wrong mapping in move_acceptance_bits");
|
|
}
|
|
|
|
if (((unsigned int)i) == j) {
|
|
// do nothing
|
|
} else {
|
|
// move bit from i->j
|
|
acc.set(j);
|
|
acc.clear(i);
|
|
}
|
|
i=acc.nextSetBit(i+1);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
private: // members
|
|
/** The number of acceptance pairs */
|
|
unsigned int _acceptance_count;
|
|
|
|
|
|
/** A vector of BitSet* representing the L part of the acceptance pairs. */
|
|
BitSetVector _acceptance_L;
|
|
/** A vector of BitSet* representing the U part of the acceptance pairs. */
|
|
BitSetVector _acceptance_U;
|
|
|
|
bool _is_compact;
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|