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.
 
 
 
 

577 lines
15 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 DRAOPTIMIZATIONS_HPP
#define DRAOPTIMIZATIONS_HPP
/** @file
* Provides optimizations on complete DRAs, notably quotienting using bisimulation.
*/
#include "APSet.hpp"
#include "common/BitSet.hpp"
#include "common/BitSetIterator.hpp"
#include <algorithm>
#include <vector>
#include <cassert>
#include <iostream>
#include <sstream>
/**
* Provides optimizations on complete DRAs, notably quotienting using bisimulation.
*/
template <class DRA>
class DRAOptimizations {
public:
/** type of a color */
typedef unsigned int color_t;
/** type of vector state indizes */
typedef std::vector<unsigned int> state_vector;
private:
/** Helper class, storing a coloring of the states */
class Coloring {
private:
/** The number of colors */
unsigned int _nr_of_colors;
/** mapping state_id -> color */
std::vector<color_t> _coloring;
/** Keep detailed information of the equivalence classes? */
bool _detailed;
/**
* mapping from color
* -> the state ids which are colored alike
* only used when _detailed=true */
std::vector<BitSet> *_color2states;
/**
* mapping from color -> one representative state
*/
std::vector<unsigned int> _color2state;
public:
/**
* Constructor, get initial size of the coloring from DRA.
* @param dra the DRA
* @param detailed Keep detailed information on the equivalence classes?
*/
Coloring(DRA& dra, bool detailed=false)
: _nr_of_colors(0), _detailed(detailed) {
_coloring.resize(dra.size());
if (_detailed) {
_color2states=new std::vector<BitSet>();
} else {
_color2states=0;
}
}
/**
* Constructor, explicitly set initial size of the coloring
* @param size the initial size
* @param detailed Keep detailed information on the equivalence classes?
*/
Coloring(unsigned int size, bool detailed=false)
: _nr_of_colors(0), _detailed(detailed) {
_coloring.resize(size);
if (_detailed) {
_color2states=new std::vector<BitSet>();
} else {
_color2states=0;
}
}
/** Destructor */
~Coloring() {
delete _color2states;
}
/** Reset (clear) coloring. */
void reset() {_nr_of_colors=0;}
/** Get the flag 'detailed' */
bool getFlagDetailed() {return _detailed;}
/** Returns the size (number of states) of this coloring. */
unsigned int size() const {return _coloring.size();}
/**
* Create a new color
* @return the newly created color
*/
color_t newColor() {
_nr_of_colors++;
_color2state.resize(_nr_of_colors);
if (_detailed) {
_color2states->resize(_nr_of_colors);
}
return _nr_of_colors-1;
}
/** Return the current (last created) color */
color_t currentColor() const {
assert(_nr_of_colors>0);
return _nr_of_colors-1;
}
/** Return the number of colors */
unsigned int countColors() const {
return _nr_of_colors;
}
/** Set the color of a state */
void setColor(unsigned int state,
color_t color) {
assert(color<_nr_of_colors);
_coloring[state]=color;
_color2state[color]=state;
if (_detailed) {
(*_color2states)[color].set(state);
}
}
/** Get the color for a state */
unsigned int state2color(unsigned int state) const {
return _coloring[state];
}
/**
*Get one representative state for the equivalence class with the
* specified color.
*/
unsigned int color2state(color_t color) const {
assert(color<_nr_of_colors);
return _color2state[color];
}
/**
* Get the state indizes (in a BitSet) that have the specified color.
* Can only be called, when the 'detailed' flag is activated in the
* constructor.
*/
const BitSet& color2states(color_t color) const {
assert(color<_nr_of_colors);
assert(_detailed && _color2states!=0);
return (*_color2states)[color];
}
/** Print the coloring */
friend std::ostream& operator<<(std::ostream& out,
const Coloring& coloring) {
for (unsigned int i=0;i<coloring.size();i++) {
out << "color[" << i << "] = " << coloring.state2color(i) << std::endl;
}
return out;
}
private:
/** Dummy Copy constructor */
Coloring(const Coloring& other);
};
/**
* Functor, provides a 'less-than' Comparator
* for the states of the DRA, using the color of
* the states themself and the colors of the
* to-states of the edges.
*/
class ColoredStateComparator {
private:
/** The coloring */
const Coloring &_coloring;
/** The DRA */
DRA &_dra;
public:
/** Constructor */
ColoredStateComparator(const Coloring& coloring,
DRA& dra) :
_coloring(coloring), _dra(dra) {}
/**
* Compares two states 'less-than' using the
* coloring, uses the bisimulation
* equivalence relation to determine
* equality.
*/
bool operator()(unsigned int state_x,
unsigned int state_y) {
color_t cx=_coloring.state2color(state_x);
color_t cy=_coloring.state2color(state_y);
if (cx < cy) {
return true;
} else if (cx > cy) {
return false;
}
for (APSet::element_iterator label=
_dra.getAPSet().all_elements_begin();
label!=_dra.getAPSet().all_elements_end();
++label) {
typename DRA::state_type *to_x=
_dra[state_x]->edges().get(*label);
typename DRA::state_type *to_y=
_dra[state_y]->edges().get(*label);
color_t ctx=_coloring.state2color(to_x->getName());
color_t cty=_coloring.state2color(to_y->getName());
if (ctx < cty) {
return true;
} else if (ctx > cty) {
return false;
}
}
// we get here only if x and y are equal with this
// coloring -> return false
return false;
}
};
/**
* A container that stores (caches) the acceptance signatures of
* all the states in a DRA.
*/
class AcceptanceSignatureContainer {
public:
/** Type of an acceptance signature */
typedef std::pair<BitSet*, BitSet*> acceptance_signature_t;
/**
* Constructor, fills the container with the acceptance signatures of the states.
* @param dra the DRA
*/
AcceptanceSignatureContainer(DRA& dra) {
_acceptancesig_vector.resize(dra.size());
for (unsigned int i=0;
i<dra.size();
i++) {
BitSet b=dra.acceptance().getAcceptance_L_forState(i);
BitSet *bp=new BitSet(b);
_bitsets.push_back(bp);
_acceptancesig_vector[i].first=bp;
b=dra.acceptance().getAcceptance_U_forState(i);
bp=new BitSet(b);
_bitsets.push_back(bp);
_acceptancesig_vector[i].second=bp;
}
}
/** Destructor */
~AcceptanceSignatureContainer() {
for (std::vector<BitSet*>::iterator it=_bitsets.begin();
it!=_bitsets.end();
++it) {
delete *it;
}
}
/**
* Get the acceptance signature for state i.
* @param i the state index
*/
acceptance_signature_t get(unsigned int i) {
return _acceptancesig_vector[i];
}
private:
/** Type of a vector (state-id -> acceptance_signature) */
typedef std::vector<acceptance_signature_t> acceptancesig_vector_t;
/** Storage for the acceptance signatures */
acceptancesig_vector_t _acceptancesig_vector;
/**
* Vector to store the BitSet pointers that have to
* be cleaned up on destruction.
*/
std::vector<BitSet*> _bitsets;
};
/**
* Functor that compares two DRA states based on their
* acceptance signature.
*/
class AcceptanceSignatureComparator {
private:
/** The acceptance signature container */
AcceptanceSignatureContainer &_container;
public:
/** Constructor */
AcceptanceSignatureComparator(AcceptanceSignatureContainer& container) :
_container(container) {}
/**
* Compares (less-than) two DRAState indizes based on their
* acceptance signature.
*/
bool operator()(const unsigned int x,
const unsigned int y) {
typename AcceptanceSignatureContainer::acceptance_signature_t px, py;
px = _container.get(x);
py = _container.get(y);
if (*px.first < *py.first) {
return true;
} else if (*py.first < *px.first) {
return false;
}
if (*px.second < *py.second) {
return true;
}
// py.second >= px.second
return false;
}
};
public:
/**
* Perform quotienting using bisimulation
* @param dra the DRA to be optimized
* @param printColoring print colorings on std::cerr?
* @param detailedStates save detailed information on the interals in the state?
* @param printStats print statistics on std::cerr?
* @return shared_ptr to the quotiented DRA
*/
typename DRA::shared_ptr
optimizeBisimulation(DRA &dra,
bool printColoring=false,
bool detailedStates=false,
bool printStats=false) {
if (!dra.isCompact()) {dra.makeCompact();}
state_vector states(dra.size());
for (unsigned int i=0;i<dra.size();i++) {
states[i]=i;
}
AcceptanceSignatureContainer accsig_container(dra);
AcceptanceSignatureComparator accsig_comp(accsig_container);
Coloring *coloring=new Coloring(dra, detailedStates);
// generate initial coloring by running with the
// different acceptance signature
Coloring *new_coloring=generateColoring(states, *coloring, accsig_comp);
delete coloring;
coloring=new_coloring;
unsigned int old_size=dra.size();
unsigned int initial_partition=coloring->countColors();
unsigned int oldColors;
do {
oldColors=coloring->countColors();
ColoredStateComparator cnc(*coloring, dra);
Coloring* new_coloring=generateColoring(states, *coloring, cnc);
delete coloring;
coloring=new_coloring;
} while (oldColors != coloring->countColors());
if (printColoring) {
std::cerr << *coloring << std::endl;
}
typename DRA::shared_ptr dra_new=generateDRAfromColoring(dra,
*coloring,
detailedStates);
delete coloring;
unsigned int new_size=dra_new->size();
if (printStats) {
std::cerr << "Bisimulation: From (" << old_size << ") To (" << new_size << ") Initial: (" << initial_partition << ")" << std::endl;
}
return dra_new;
}
private:
/**
* Generate a new coloring based on the Comparator comp
* (one iteration of refinement)
* @param states A vector of the states
* @param coloring The current coloring
* @param comp the Comparator
* @return a pointer to a newly created Coloring, memory ownership
* passes to the caller
*/
template <class Comparator>
Coloring *generateColoring(state_vector &states,
Coloring &coloring,
Comparator &comp) {
std::sort(states.begin(), states.end(), comp);
Coloring* result=new Coloring(coloring.size(), coloring.getFlagDetailed());
if (states.size()==0) {return result;}
state_vector::reverse_iterator
current=states.rbegin(),
last=states.rbegin();
result->setColor(*current, result->newColor());
while (++current != states.rend()) {
// because states is sorted and we traverse
// from the end, either:
// *current < *last with comp(current,last)==true
// or *current == *last with !comp(current,last)
if (comp(*current, *last)) {
// -> we have to start a new color
result->setColor(*current, result->newColor());
} else {
// -> more of the same, we stay with this color
result->setColor(*current, result->currentColor());
}
last=current;
}
return result;
}
/**
* Generate a new DRA from a coloring
*/
typename DRA::shared_ptr
generateDRAfromColoring(DRA &oldDRA,
Coloring &coloring,
bool detailedStates) {
typename DRA::shared_ptr
newDRA((DRA*)oldDRA.createInstance(oldDRA.getAPSet_cp()));
newDRA->acceptance().newAcceptancePairs(oldDRA.acceptance().size());
for (unsigned int color=0;
color<coloring.countColors();
++color) {
newDRA->newState();
}
unsigned int old_start_state=oldDRA.getStartState()->getName();
unsigned int start_state_color=coloring.state2color(old_start_state);
newDRA->setStartState(newDRA->get(start_state_color));
const APSet &apset=newDRA->getAPSet();
for (unsigned int color=0;
color<coloring.countColors();
++color) {
typename DRA::state_type *new_state = newDRA->get(color);
unsigned int old_state_representative=coloring.color2state(color);
typename DRA::state_type *old_state =
oldDRA[old_state_representative];
if (detailedStates) {
const BitSet& old_states=coloring.color2states(color);
// create new description...
if (old_states.cardinality()==1) {
if (old_state->hasDescription()) {
new_state->setDescription(old_state->getDescription());
}
} else {
std::ostringstream s;
s << "<TABLE BORDER=\"1\" CELLBORDER=\"0\"><TR><TD>{</TD>";
bool first=true;
for (BitSetIterator it=BitSetIterator(old_states);
it!=BitSetIterator::end(old_states);
++it) {
if (first) {
first=false;
} else {
s << "<TD>,</TD>";
}
s << "<TD>";
if (!oldDRA[*it]->hasDescription()) {
s << *it;
} else {
s << oldDRA[*it]->getDescription();
}
s << "</TD>";
}
s << "<TD>}</TD></TR></TABLE>";
new_state->setDescription(s.str());
}
}
// Create appropriate acceptance conditions
unsigned int old_state_index=old_state->getName();
for (unsigned int i=0;
i<oldDRA.acceptance().size();
++i) {
if (oldDRA.acceptance().isStateInAcceptance_L(i, old_state_index)) {
new_state->acceptance().addTo_L(i);
}
if (oldDRA.acceptance().isStateInAcceptance_U(i, old_state_index)) {
new_state->acceptance().addTo_U(i);
}
}
for (APSet::element_iterator label=
apset.all_elements_begin();
label!=apset.all_elements_end();
++label) {
typename DRA::state_type *old_to=
old_state->edges().get(*label);
unsigned to_color=coloring.state2color(old_to->getName());
new_state->edges().addEdge(*label, newDRA->get(to_color));
}
}
return newDRA;
}
};
#endif