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.
 
 
 
 

410 lines
10 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 GRAPHALGORITHMS_HPP
#define GRAPHALGORITHMS_HPP
/** @file
* Provides algorithms to be used on graphs (automata), notably the calculation
* of Strongly Connected Components (SCCs).
*/
#include "common/BitSet.hpp"
#include "common/BitSetIterator.hpp"
#include <vector>
#include <stack>
#include <iostream>
#include <memory>
/**
* A class for storing information about the Strongly Connected Components (SCCs)
* of a graph
*/
class SCCs {
public:
/** Constructor */
SCCs() {};
/** Destructor */
~SCCs() {};
/** Get the states that are in SCC scc_index */
BitSet const& operator[](unsigned int scc_index) const {
return _sccs[scc_index];
}
/** Get the number of SCCs */
unsigned int countSCCs() const {return _sccs.size();}
/** Get the SCC index for state */
unsigned int state2scc(unsigned int state) {
return _state_to_scc[state];
}
/** Get a vector with a topological order of the states*/
std::vector<int> const& topologicalOrder() {
return _topological_order;
}
/** Get a set of SCCs that are successors of the SCC scc_index */
BitSet& successors(unsigned int scc_index) {
return _dag[scc_index];
}
/** Return true, if state_to is reachable from state_from */
bool stateIsReachable(unsigned int state_from,
unsigned int state_to) {
return isReachable(state2scc(state_from),
state2scc(state_to));
}
/** Return true, if SCC scc_to is reachable from SCC_fromom */
bool isReachable(unsigned int scc_from,
unsigned int scc_to) {
return _reachability[scc_from].get(scc_to);
}
/** Print the SCCs on the output stream */
friend std::ostream& operator<<(std::ostream& out,
const SCCs &scc) {
out << "SCC:" << std::endl;
for (unsigned int i=0;i<scc.countSCCs();i++) {
int scc_i=scc._topological_order[i];
out << scc_i << " : " << scc[scc_i] << std::endl;
}
return out;
}
/** Get a vector of BitSets with reachability information
* (state -> reachable_states)
*/
std::vector<BitSet> *getReachabilityForAllStates() {
std::vector<BitSet>* v=new std::vector<BitSet>;
v->resize(_state_to_scc.size());
for (unsigned int i=0;
i<_state_to_scc.size();
++i) {
unsigned int scc=state2scc(i);
BitSet& reachable_sccs=_reachability[scc];
BitSet reachable_states;
for (BitSetIterator it(reachable_sccs);
it!=BitSetIterator::end(reachable_sccs);
++it) {
// union with all states from the reachable scc
reachable_states.Union(_sccs[*it]);
}
(*v)[i]=reachable_states;
// std::cerr << "from "<<i<<": "<<reachable_states<<std::endl;
}
return v;
}
//private:
std::vector<BitSet> _sccs;
std::vector<unsigned int> _state_to_scc;
std::vector<BitSet> _dag;
std::vector<int> _topological_order;
std::vector<BitSet> _reachability;
// friend class GraphAlgorithms::SCC_DFS;
/** Add a new SCC */
unsigned int addSCC(BitSet& scc) {
_sccs.push_back(scc);
return _sccs.size()-1;
}
/** Set the SCC for a state */
void setState2SCC(unsigned int state, unsigned int scc) {
if (_state_to_scc.size() <= state) {
_state_to_scc.resize(state+1);
}
_state_to_scc[state]=scc;
}
};
/** Provide access for a given Graph to the successors
* for a state v, using the successors_begin and successors_end
* calls on the Graph::state_type* */
template <typename Graph>
class StdSuccessorAccess {
public:
typedef typename Graph::state_type::successor_iterator successor_iterator;
successor_iterator begin(Graph& graph, unsigned int v) {
return graph[v]->successors_begin();
}
successor_iterator end(Graph& graph, unsigned int v) {
return graph[v]->successors_end();
}
};
/**
* Perform graph algorithms
*/
template <typename Graph,
typename SuccessorAccess=StdSuccessorAccess<Graph> >
class GraphAlgorithms {
public:
/** Calculate the SCCs for Graph graph and save in result. */
static void calculateSCCs(Graph& graph,
SCCs& result,
bool disjoint=false,
SuccessorAccess successor_access=SuccessorAccess()) {
SCC_DFS::calculateSCCs(graph, result, disjoint, successor_access);
}
private:
/** Helper class to calculate the SCCs*/
class SCC_DFS {
public:
/** Calculate the SCCs for Graph graph and save in result. */
static void calculateSCCs(Graph& graph,
SCCs& result,
bool disjoint,
SuccessorAccess& successor_access) {
SCC_DFS scc_dfs(graph, result, successor_access);
scc_dfs.calculate(disjoint);
}
private:
/** Dummy constructor to restrict creation */
explicit SCC_DFS() {}
/** Constructor */
SCC_DFS(Graph& graph,
SCCs& result,
SuccessorAccess& successor_access) : _graph(graph), _result(result), _successor_access(successor_access) {};
/** A class for saving DFS state information */
class SCC_DFS_Data {
public:
unsigned int dfs_nr;
unsigned int root_index;
bool inComponent;
};
/** The graph */
Graph& _graph;
/** The SCCs */
SCCs& _result;
SuccessorAccess& _successor_access;
/** The current DFS number */
unsigned int current_dfs_nr;
/** The DFS stack */
std::stack<unsigned int> _stack;
/** The SCC_DFS_Data for every state (state index -> DFS_DATA) */
std::vector<std::shared_ptr<SCC_DFS_Data> > _dfs_data;
/** The current scc number */
unsigned int scc_nr;
/** Calculate the SCCs*/
void calculate(bool disjoint) {
current_dfs_nr=0;
_dfs_data.clear();
// Ensure there are as many entries as there are graph-states
_dfs_data.resize(_graph.size());
scc_nr=0;
typename Graph::state_type *start_state=_graph.getStartState();
if (start_state==0) {
return;
}
if (!disjoint) {
unsigned int start_idx=start_state->getName();
visit(start_idx);
} else {
// The Graph may be disjoint -> restart DFS on every not yet visited state
for (unsigned int v=0;
v<_graph.size();
++v) {
if (_dfs_data[v].get()==0) {
// not yet visited
visit(v);
}
}
}
calculateDAG();
}
/** Visit a state (perform DFS) */
void visit(unsigned int v) {
SCC_DFS_Data *sdd=new SCC_DFS_Data;
sdd->dfs_nr=current_dfs_nr++;
sdd->root_index=v;
sdd->inComponent=false;
_stack.push(v);
_dfs_data[v].reset(sdd);
for (typename SuccessorAccess::successor_iterator
succ_it=_successor_access.begin(_graph, v);
succ_it!=_successor_access.end(_graph, v);
++succ_it) {
unsigned int w=*succ_it;
if (_dfs_data[w].get()==0) {
// not yet visited
visit(w);
}
SCC_DFS_Data *sdd_w=_dfs_data[w].get();
if (sdd_w->inComponent==false) {
unsigned int dfs_nr_root_v=_dfs_data[sdd->root_index]->dfs_nr;
unsigned int dfs_nr_root_w=_dfs_data[sdd_w->root_index]->dfs_nr;
if (dfs_nr_root_v > dfs_nr_root_w) {
sdd->root_index=sdd_w->root_index;
}
}
}
if (sdd->root_index == v) {
BitSet set;
unsigned int w;
do {
w=_stack.top();
_stack.pop();
set.set(w);
_result.setState2SCC(w, scc_nr);
SCC_DFS_Data *sdd_w=_dfs_data[w].get();
sdd_w->inComponent=true;
} while (w!=v);
scc_nr=_result.addSCC(set)+1;
}
}
/** Calculate the Directed Acyclical Graph (DAG) */
void calculateDAG() {
_result._dag.clear();
_result._dag.resize(_result.countSCCs());
_result._reachability.resize(_result.countSCCs());
std::vector<signed int> in_degree(_result.countSCCs());
for (unsigned int scc=0;
scc<_result.countSCCs();
++scc) {
const BitSet& states_in_scc=_result[scc];
for (BitSetIterator it=BitSetIterator(states_in_scc);
it!=BitSetIterator::end(states_in_scc);
++it) {
unsigned int from_state=*it;
for (typename SuccessorAccess::successor_iterator
succ_it=_successor_access.begin(_graph, from_state);
succ_it!=_successor_access.end(_graph, from_state);
++succ_it) {
unsigned int to_state=*succ_it;
unsigned int to_scc=_result.state2scc(to_state);
if (to_scc!=scc) {
// Only successor in the DAG if not the same scc
if (!_result._dag[scc].get(to_scc)) {
// This SCC is a new successor, increment in_degree
in_degree[to_scc]++;
_result._dag[scc].set(to_scc);
}
}
// Reachability
_result._reachability[scc].set(to_scc);
}
}
}
bool progress = true;
int cnt = 0;
_result._topological_order.clear();
_result._topological_order.resize(_result.countSCCs());
std::vector<unsigned int> sort(_result.countSCCs());
while (progress) {
progress=false;
for (unsigned int scc=0;scc<_result.countSCCs();++scc) {
if (in_degree[scc]==0) {
sort[scc]=cnt++;
progress=true;
in_degree[scc]=-1;
for (BitSetIterator it_neighbors=
BitSetIterator(_result._dag[scc]);
it_neighbors!=BitSetIterator::end(_result._dag[scc]);
++it_neighbors) {
unsigned int scc_to=*it_neighbors;
in_degree[scc_to]--;
}
}
}
}
for (unsigned int i=0;i<_result.countSCCs();i++) {
_result._topological_order[sort[i]]=i;
}
// traverse SCCs in reverse topological order
for (unsigned int i=_result.countSCCs();
i>0;
--i) {
unsigned int cur_scc=_result._topological_order[i-1];
BitSet &reaches=_result._reachability[cur_scc];
for (BitSetIterator it_neighbors=
BitSetIterator(_result._dag[cur_scc]);
it_neighbors!=BitSetIterator::end(_result._dag[cur_scc]);
++it_neighbors) {
unsigned int scc_to=*it_neighbors;
reaches.Union(_result._reachability[scc_to]);
}
}
}
};
};
#endif