spot/lbtt/src/Graph.h.in
2004-02-16 12:09:29 +00:00

1859 lines
64 KiB
C

/*
* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004
* Heikki Tauriainen <Heikki.Tauriainen@hut.fi>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* 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 GRAPH_H
#define GRAPH_H
#include <config.h>
#include <deque>
#include <iostream>
#include <list>
#include <stack>
#include <set>
#ifdef HAVE_SLIST
@INCLUDE_SLIST_HEADER@
using SLIST_NAMESPACE::slist;
#endif /* HAVE_SLIST */
#include <utility>
#include <vector>
#include "LbttAlloc.h"
#include "BitArray.h"
#include "Exception.h"
using namespace std;
namespace Graph
{
/*
* Output formats for printing a graph, its edges or nodes. All output
* functions for these objects will accept a parameter `fmt' which can be
* either of these constants (and defaults to NORMAL).
* `NORMAL' corresponds to a plain text description of the printed object.
* `DOT' corresponds to the format recognized by the tool `dot' (a tool
* for displaying graphs graphically), so this format can be used
* for generating input files for the tool.
*/
enum GraphOutputFormat {NORMAL, DOT};
class BuchiAutomaton;
class StateSpace;
class ProductAutomaton;
/******************************************************************************
*
* A template base class for directed graphs. The template parameter specifies
* a class that will be used for storing the collection of edges beginning at
* the nodes of the graph. That is, each graph node will include a container
* (an object of the given class) storing all the edges beginning at the node.
*
* Different containers can be used to optimize the efficiency of different
* graph algorithms. For example, if the edges are often accessed randomly, a
* container which supports fast searching of any edge in the container may
* be useful: on the other hand, algorithms which only need to go through
* all the edges in some order will benefit from a more simple container since
* this container may consume less memory per container element.
*
* Definitions are provided for the following container classes:
* EdgeList -- Uses the STL `list' class (a doubly linked list) to store
* the edges.
* EdgeVector -- Uses the STL `vector' class to store the edges.
* EdgeSet -- Uses the STL `set' class to store the edges. Important
* note: This container will not allow multiple edges
* between a pair of nodes -- use EdgeMultiSet instead.
* EdgeMultiSet -- Uses the STL `multiset' class to store the edges.
*
* In addition, if using the SGI STL implementation, an additional container
* class `EdgeSlist' is available. This class is based on the `slist' (a
* singly linked list) container included in the SGI STL implementation.
*
* Any class used as a container (`EdgeContainer') must be able to hold
* objects of type Graph<EdgeContainer>::Edge* and must support the following
* interface:
*
* Default constructor which can be called without arguments.
*
* EdgeContainer::size_type
* Data type able to represent the maximum number of elements
* that can be stored in the container.
*
* EdgeContainer::size_type size()
* Returns the number of elements currently stored in the
* containers.
*
* bool empty()
* Tells whether the container is currently empty.
*
* void clear()
* Makes the container empty.
*
* EdgeContainer::iterator
* EdgeContainer::const_iterator
* Input iterators that can be used to traverse through the
* elements of the container. The iterators must support
* increment and dereferencing operations. However, support for
* changing the container elements through the iterator is not
* required.
*
* const_iterator EdgeContainer::begin()
* Returns a const_iterator pointing to the first element in the
* container.
*
* iterator EdgeContainer::begin()
* Returns an iterator pointing to the last element in the
* container.
*
* const_iterator EdgeContainer::end()
* Returns a const_iterator pointing to the end of the container.
*
* iterator EdgeContainer::end()
* Returns an iterator pointing to the end of the container.
*
* const_iterator find(const Graph<EdgeContainer>::Edge*)
* Finds an element of a given value in the container and returns
* a const_iterator pointing to it (or end() if the element is
* not found in the container).
*
* Very important note:
* In order for all the algorithms provided in this class to
* work correctly, searching an element in the container must
* be done by comparing the actual objects pointed to by the
* elements of the container, _not_ the pointers itself.
*
* The class Graph<EdgeContainer>::Edge already provides two
* classes for this purpose:
* 1. Graph<EdgeContainer>::Edge::ptr_less defines a `less
* than' relation between two pointers to
* Graph<EdgeContainer>::Edges
* 2. Graph<EdgeContainer>::Edge::ptr_equal defines an
* `equality' relation between two pointers to
* Graph<EdgeContainer>::Edges.
*
* See the comments on these classes (and the provided
* container class examples) for information on how to use
* them.
*
* iterator find(const Graph<EdgeContainer>::Edge*)
* Finds an element of a given value in the container and returns
* a iterator pointing to it (or end() if the element is not
* found in the container).
*
* insert(const Graph<EdgeContainer>::Edge*)
* Inserts an edge into the container.
*
* erase(iterator pos)
* Removes the element pointed by the iterator `pos' from the
* container.
*
*****************************************************************************/
template<class EdgeContainer>
class Graph
{
public:
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
class Edge; /* A class for representing
* edges between graph
* nodes.
*/
class Node; /* A class for representing
* graph nodes.
*/
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
protected:
vector<Node*, ALLOC(Node*) > nodes; /* Nodes of the graph.
* Derived classes can
* access this vector
* directly.
*/
public:
typedef typename /* Type definition for */
vector<Node*, ALLOC(Node*) >::size_type /* the size of the */
size_type; /* graph. The size can
* be no greater than
* the maximum size of
* the vector containing
* the graph nodes.
*/
typedef pair<size_type, size_type> StateIdPair; /* Type definition for a
* pair of state
* identifiers in a graph.
*/
explicit Graph /* Default constructor. */
(const size_type initial_number_of_nodes = 0);
Graph(const Graph& graph); /* Copy constructor. */
virtual ~Graph(); /* Destructor. */
Graph& operator=(const Graph& graph); /* Assignment operator. */
virtual Node& operator[](const size_type index) /* Indexing operator */
const; /* (for referencing the
* nodes of the graph).
* This function will
* not check whether the
* given index is in a
* valid range.
*/
virtual Node& node(const size_type index) const; /* Alternative way for
* referencing the graph
* nodes. This function
* also checks the range of
* the argument.
*/
size_type size() const; /* Returns the number of
* nodes in the graph.
*/
bool empty() const; /* Tests whether the graph
* is empty.
*/
virtual void clear(); /* Makes the graph empty.
*/
virtual size_type expand /* Inserts nodes to the */
(size_type node_count = 1); /* graph. */
virtual void connect /* Inserts an edge */
(const size_type father, /* between two nodes. */
const size_type child);
virtual void disconnect /* Removes an edge from */
(const size_type father, /* between two nodes. */
const size_type child);
virtual bool connected /* Tests whether two */
(const size_type father, /* nodes are connected */
const size_type child) const; /* with an edge. */
virtual pair<size_type, unsigned long int> /* Returns the number of */
stats() const; /* nodes and edges in
* the graph.
*/
virtual pair<size_type, unsigned long int> /* Returns the number of */
subgraphStats(const size_type index) const; /* nodes and edges in a
* connected subgraph of
* the graph.
*/
virtual void print /* Prints the contents */
(ostream& stream = cout, /* of the graph in */
const int indent = 0, /* various formats */
const GraphOutputFormat fmt = NORMAL) const; /* (determined by the
* `fmt' argument which
* can have the values
* NORMAL or DOT).
*/
};
/******************************************************************************
*
* A template class for representing the directed edges between graph nodes.
*
*****************************************************************************/
template<class EdgeContainer>
class Graph<EdgeContainer>::Edge
{
public:
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
class ptr_equal /* Class for a function */
{ /* object defining an */
public: /* equality relation */
bool operator() /* between pointers to */
(const Edge* edge_1, const Edge* edge_2) /* Edges. (Used with */
const; /* container */
}; /* algorithms.) */
class ptr_less /* Class for a function */
{ /* object defining a */
public: /* `less than' relation */
bool operator() /* between pointers to */
(const Edge* edge_1, const Edge* edge_2) /* Edges. (Used with */
const; /* container */
}; /* algorithms.) */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
Edge /* Constructor. */
(const Graph<EdgeContainer>::size_type target);
/* default copy constructor */
virtual ~Edge(); /* Destructor. */
/* default assignment operator */
Graph<EdgeContainer>::size_type targetNode() /* Returns the index of */
const; /* the target node of
* the directed edge.
*/
virtual void print /* Writes information */
(ostream& stream = cout, /* about the edge to a */
const int indent = 0, /* stream in various */
const GraphOutputFormat fmt = NORMAL) const; /* formats (determined
* by the `fmt'
* argument).
*/
friend class ptr_equal;
friend class ptr_less;
protected:
virtual bool operator==(const Edge& edge) const; /* Equality relation
* between two edges. Used
* for sorting Edges in an
* STL container.
*/
virtual bool operator<(const Edge& edge) const; /* `Less than' relation
* between two edges. Used
* for sorting Edges in an
* STL container.
*/
private:
Graph<EdgeContainer>::size_type target_node; /* Identifier of the edge's
* target node.
*/
};
/******************************************************************************
*
* A template class for representing graph nodes.
*
*****************************************************************************/
template<class EdgeContainer>
class Graph<EdgeContainer>::Node
{
public:
Node(); /* Constructor. */
Node(const Node& node); /* Copy constructor. */
virtual ~Node(); /* Destructor. */
Node& operator=(const Node& node); /* Assignment operator. */
const EdgeContainer& edges() const; /* Returns the container of
* edges beginning at the
* node.
*/
virtual void print /* Writes information */
(ostream& stream = cout, /* about the node to a */
const int indent = 0, /* stream in various */
const GraphOutputFormat fmt = NORMAL) const; /* formats (determined
* by the `fmt'
* argument).
*/
protected:
friend class Graph;
friend class BuchiAutomaton;
friend class StateSpace;
friend class ProductAutomaton;
EdgeContainer outgoing_edges; /* Container of edges
* beginning at the node.
*/
};
/******************************************************************************
*
* An exception class for reporting errors when indexing graph nodes.
*
*****************************************************************************/
class NodeIndexException : public Exception
{
public:
NodeIndexException(); /* Default constructor. */
/* default copy constructor */
~NodeIndexException() throw(); /* Destructor. */
NodeIndexException& operator= /* Assignment operator. */
(const NodeIndexException& e);
/* `what' inherited from class Exception */
};
/******************************************************************************
*
* An edge container class based on the basic STL container class `list', a
* doubly linked list.
*
*****************************************************************************/
class EdgeList : public list<Graph<EdgeList>::Edge*,
ALLOC(Graph<EdgeList>::Edge*) >
{
public:
EdgeList(); /* Constructor. */
/* default copy constructor */
~EdgeList(); /* Destructor. */
/* default assignment operator */
void insert(Graph<EdgeList>::Edge* edge); /* Inserts an element to
* the end of the list.
*/
list<Graph<EdgeList>::Edge*, /* Functions for finding */
ALLOC(Graph<EdgeList>::Edge*) > /* an element in the */
::const_iterator /* list. */
find(const Graph<EdgeList>::Edge* edge) const;
list<Graph<EdgeList>::Edge*,
ALLOC(Graph<EdgeList>::Edge*) >
::iterator
find(const Graph<EdgeList>::Edge* edge);
};
/******************************************************************************
*
* An edge container class based on the basic container class `slist'
* (available in SGI STL implementation), a singly linked list.
*
*****************************************************************************/
#ifdef HAVE_SLIST
class EdgeSlist : public slist<Graph<EdgeSlist>::Edge*,
ALLOC(Graph<EdgeSlist>::Edge*) >
{
public:
EdgeSlist(); /* Constructor. */
/* default copy constructor */
~EdgeSlist(); /* Destructor. */
/* default assignment operator */
void insert(Graph<EdgeSlist>::Edge* edge); /* Inserts an element to
* the beginning of the
* list.
*/
slist<Graph<EdgeSlist>::Edge*, /* Functions for finding */
ALLOC(Graph<EdgeSlist>::Edge*) > /* an element in the */
::const_iterator /* list. */
find(const Graph<EdgeSlist>::Edge* edge) const;
slist<Graph<EdgeSlist>::Edge*,
ALLOC(Graph<EdgeSlist>::Edge*) >
::iterator
find(const Graph<EdgeSlist>::Edge* edge);
};
#endif /* HAVE_SLIST */
/******************************************************************************
*
* An edge container class based on the basic STL container class `vector'.
*
*****************************************************************************/
class EdgeVector : public vector<Graph<EdgeVector>::Edge*,
ALLOC(Graph<EdgeVector>::Edge*) >
{
public:
EdgeVector(); /* Constructor. */
/* default copy constructor */
~EdgeVector(); /* Destructor. */
/* default assignment operator */
void insert(Graph<EdgeVector>::Edge* edge); /* Inserts an element to
* the vector of pointers
* to edges.
*/
vector<Graph<EdgeVector>::Edge*, /* Functions for finding */
ALLOC(Graph<EdgeVector>::Edge*) > /* an element in the */
::const_iterator /* container. */
find(const Graph<EdgeVector>::Edge* edge)
const;
vector<Graph<EdgeVector>::Edge*,
ALLOC(Graph<EdgeVector>::Edge*) >
::iterator
find(const Graph<EdgeVector>::Edge* edge);
};
/******************************************************************************
*
* An edge container class based on the basic STL container class `set'.
*
*****************************************************************************/
class EdgeSet : public set<Graph<EdgeSet>::Edge*,
Graph<EdgeSet>::Edge::ptr_less,
ALLOC(Graph<EdgeSet>::Edge*) >
{
};
/******************************************************************************
*
* An edge container class based on the basic STL container class `multiset'.
*
*****************************************************************************/
class EdgeMultiSet : public multiset<Graph<EdgeMultiSet>::Edge*,
Graph<EdgeMultiSet>::Edge::ptr_less,
ALLOC(Graph<EdgeMultiSet>::Edge*) >
{
};
/******************************************************************************
*
* Inline function definitions for template class Graph.
*
*****************************************************************************/
/* ========================================================================= */
template<class EdgeContainer>
inline Graph<EdgeContainer>::~Graph()
/* ----------------------------------------------------------------------------
*
* Description: Destructor for template class Graph<EdgeContainer>.
* Deallocates the memory reserved for the object.
*
* Arguments: None.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
clear();
}
/* ========================================================================= */
template<class EdgeContainer>
inline typename Graph<EdgeContainer>::Node& Graph<EdgeContainer>::operator[]
(const size_type index) const
/* ----------------------------------------------------------------------------
*
* Description: Indexing operator for template class Graph<EdgeContainer>.
* Can be used to access single nodes of the graph. This
* function does not perform any range checks on its argument.
*
* Argument: index -- Index of a node.
*
* Returns: A reference to a graph node.
*
* ------------------------------------------------------------------------- */
{
return *nodes[index];
}
/* ========================================================================= */
template<class EdgeContainer>
inline typename Graph<EdgeContainer>::size_type Graph<EdgeContainer>::size()
const
/* ----------------------------------------------------------------------------
*
* Description: Returns the number of nodes in the graph.
*
* Arguments: None.
*
* Returns: Number of nodes in the graph.
*
* ------------------------------------------------------------------------- */
{
return nodes.size();
}
/* ========================================================================= */
template<class EdgeContainer>
inline bool Graph<EdgeContainer>::empty() const
/* ----------------------------------------------------------------------------
*
* Description: Tests whether the graph is empty.
*
* Arguments: None.
*
* Returns: A truth value.
*
* ------------------------------------------------------------------------- */
{
return nodes.empty();
}
/* ========================================================================= */
template<class EdgeContainer>
inline ostream& operator<<(ostream& stream, const Graph<EdgeContainer>& graph)
/* ----------------------------------------------------------------------------
*
* Description: Defines an alternative way for printing a Graph by using the
* << operator.
*
* Arguments: stream -- A reference to an output stream.
* graph -- A reference to a constant graph to be printed.
*
* Returns: A reference to the output stream.
*
* ------------------------------------------------------------------------- */
{
graph.print(stream);
return stream;
}
/******************************************************************************
*
* Function definitions for template class Graph.
*
*****************************************************************************/
/* ========================================================================= */
template<class EdgeContainer>
Graph<EdgeContainer>::Graph(const size_type initial_number_of_nodes) :
nodes(initial_number_of_nodes)
/* ----------------------------------------------------------------------------
*
* Description: Constructor for template class Graph<EdgeContainer>.
* Initializes a new Graph<EdgeContainer> object with a given
* initial size (which can be extended later).
*
* Argument: initial_number_of_nodes -- Initial size of the graph.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
nodes.reserve(initial_number_of_nodes);
for (typename vector<Node*, ALLOC(Node*) >::iterator node = nodes.begin();
node != nodes.end();
++node)
*node = new Node();
}
/* ========================================================================= */
template<class EdgeContainer>
Graph<EdgeContainer>::Graph(const Graph<EdgeContainer>& graph)
/* ----------------------------------------------------------------------------
*
* Description: Copy constructor for template class Graph<EdgeContainer>.
* Initializes a copy of a Graph<EdgeContainer> object.
*
* Argument: graph -- A reference to a constant Graph<EdgeContainer>
* to be copied.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
nodes.reserve(graph.nodes.size());
for (typename vector<Node*, ALLOC(Node*) >::const_iterator
node = graph.nodes.begin();
node != graph.nodes.end(); ++node)
nodes.push_back(new Node(**node));
}
/* ========================================================================= */
template<class EdgeContainer>
Graph<EdgeContainer>& Graph<EdgeContainer>::operator=
(const Graph<EdgeContainer>& graph)
/* ----------------------------------------------------------------------------
*
* Description: Assignment operator for template class Graph<EdgeContainer>.
* Copies a Graph<EdgeContainer> object to another.
*
* Argument: graph -- A reference to the constant Graph<EdgeContainer>
* to be copied.
*
* Returns: A reference to the graph whose contents were changed.
*
* ------------------------------------------------------------------------- */
{
if (&graph != this)
{
clear();
nodes.reserve(graph.nodes.size());
for (typename vector<Node*, ALLOC(Node*) >::const_iterator
node = graph.nodes.begin();
node != graph.nodes.end();
++node)
nodes.push_back(new Node(**node));
}
return *this;
}
/* ========================================================================= */
template<class EdgeContainer>
typename Graph<EdgeContainer>::Node& Graph<EdgeContainer>::node
(const size_type index) const
/* ----------------------------------------------------------------------------
*
* Description: Function for accessing individual nodes of the graph. This
* function also performs a range check on its argument.
*
* Argument: index -- Index of the node.
*
* Returns: A reference to the node.
*
* ------------------------------------------------------------------------- */
{
if (index >= nodes.size())
throw NodeIndexException();
return *nodes[index];
}
/* ========================================================================= */
template<class EdgeContainer>
void Graph<EdgeContainer>::clear()
/* ----------------------------------------------------------------------------
*
* Description: Makes the graph empty.
*
* Arguments: None.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
for (typename vector<Node*, ALLOC(Node*) >::reverse_iterator
node = nodes.rbegin();
node != nodes.rend();
++node)
delete *node;
nodes.clear();
nodes.reserve(0);
}
/* ========================================================================= */
template<class EdgeContainer>
typename Graph<EdgeContainer>::size_type Graph<EdgeContainer>::expand
(size_type node_count)
/* ----------------------------------------------------------------------------
*
* Description: Inserts a given number of nodes to a graph.
*
* Arguments: node_count -- Number of nodes to be inserted.
*
* Returns: The index of the last inserted node.
*
* ------------------------------------------------------------------------- */
{
nodes.reserve(nodes.size() + node_count);
Node* new_node;
while (node_count > 0)
{
new_node = new Node();
try
{
nodes.push_back(new_node);
}
catch (...)
{
delete new_node;
throw;
}
node_count--;
}
return nodes.size() - 1;
}
/* ========================================================================= */
template<class EdgeContainer>
void Graph<EdgeContainer>::connect
(const size_type father, const size_type child)
/* ----------------------------------------------------------------------------
*
* Description: Inserts an edge between two nodes of the graph.
*
* Arguments: father -- Source node of the edge.
* child -- Target node of the edge.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
Edge* new_edge(new Edge(child));
try
{
nodes[father]->outgoing_edges.insert(new_edge);
}
catch (...)
{
delete new_edge;
throw;
}
}
/* ========================================================================= */
template<class EdgeContainer>
void Graph<EdgeContainer>::disconnect
(const size_type father, const size_type child)
/* ----------------------------------------------------------------------------
*
* Description: Removes an edge between two nodes of the graph.
*
* Arguments: father -- Source node of the edge.
* child -- Target node of the edge.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
Edge e(child);
/*
* Scan the set of the node's outgoing edges for an edge with the given
* target node and remove it if such an edge exists.
*/
typename EdgeContainer::iterator search_edge
= nodes[father]->outgoing_edges.find(&e);
if (search_edge != nodes[father]->outgoing_edges.end())
{
delete *search_edge;
nodes[father]->outgoing_edges.erase(search_edge);
}
}
/* ========================================================================= */
template<class EdgeContainer>
bool Graph<EdgeContainer>::connected
(const size_type father, const size_type child) const
/* ----------------------------------------------------------------------------
*
* Description: Tests whether there exists an edge from a given graph node
* to another one.
*
* Arguments: father -- Source node of the edge.
* child -- Target node of the edge.
*
* Returns: A truth value.
*
* ------------------------------------------------------------------------- */
{
Edge e(child);
return (nodes[father]->outgoing_edges.find(&e)
!= nodes[father]->outgoing_edges.end());
}
/* ========================================================================= */
template<class EdgeContainer>
pair<typename Graph<EdgeContainer>::size_type, unsigned long int>
Graph<EdgeContainer>::stats() const
/* ----------------------------------------------------------------------------
*
* Description: Returns the number of nodes and edges in a graph.
*
* Arguments: None.
*
* Returns: A pair consisting of the number of nodes and the number of
* transitions in the graph.
*
* ------------------------------------------------------------------------- */
{
pair<Graph<EdgeContainer>::size_type, unsigned long int> result;
result.first = nodes.size();
result.second = 0;
for (typename vector<Node*, ALLOC(Node*) >::const_iterator
node = nodes.begin();
node != nodes.end(); ++node)
result.second += (*node)->edges().size();
return result;
}
/* ========================================================================= */
template<class EdgeContainer>
pair<typename Graph<EdgeContainer>::size_type, unsigned long int>
Graph<EdgeContainer>::subgraphStats(const size_type index) const
/* ----------------------------------------------------------------------------
*
* Description: Computes the number of nodes and edges in some connected
* subgraph of the graph. The subgraph is computed by performing
* a depth-first traversal of a graph component starting from a
* given node (the `root' of the subgraph).
*
* Arguments: index -- Index of the node acting as the `root' of the
* subgraph.
*
* Returns: A pair consisting of the number of nodes and the number of
* transitions in the subgraph.
*
* ------------------------------------------------------------------------- */
{
if (empty())
return make_pair(0, 0);
const size_type s = nodes.size();
if (index >= s)
throw NodeIndexException();
stack<size_type, deque<size_type, ALLOC(size_type) > > unprocessed_nodes;
BitArray visited_nodes(s);
visited_nodes.clear(s);
unprocessed_nodes.push(index);
visited_nodes.setBit(index);
size_type current_node, child_node, number_of_subgraph_nodes = 0;
unsigned long int number_of_subgraph_edges = 0;
while (!unprocessed_nodes.empty())
{
current_node = unprocessed_nodes.top();
unprocessed_nodes.pop();
++number_of_subgraph_nodes;
number_of_subgraph_edges += nodes[current_node]->edges().size();
for (typename EdgeContainer::const_iterator
edge = nodes[current_node]->edges().begin();
edge != nodes[current_node]->edges().end();
++edge)
{
child_node = (*edge)->targetNode();
if (!visited_nodes.test(child_node))
{
unprocessed_nodes.push(child_node);
visited_nodes.setBit(child_node);
}
}
}
return make_pair(number_of_subgraph_nodes, number_of_subgraph_edges);
}
/* ========================================================================= */
template<class EdgeContainer>
void Graph<EdgeContainer>::print
(ostream& stream, const int indent, const GraphOutputFormat fmt) const
/* ----------------------------------------------------------------------------
*
* Description: Writes information about the graph to a stream.
*
* Arguments: stream -- A reference to an output stream.
* indent -- Number of spaces to leave to the left of output.
* fmt -- Determines the graph output format.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
Exceptional_ostream estream(&stream, ios::failbit | ios::badbit);
if (fmt == DOT)
estream << string(indent, ' ') + "digraph G {\n";
if (nodes.empty())
{
if (fmt == NORMAL)
estream << string(indent, ' ') + "The graph is empty.\n";
}
else
{
if (fmt == NORMAL)
{
pair<size_type, unsigned long int> statistics = stats();
estream << string(indent, ' ') + "The graph consists of\n"
+ string(indent + 4, ' ')
<< statistics.first
<< " states and\n" + string(indent + 4, ' ')
<< statistics.second
<< " transitions.\n";
}
size_type s = nodes.size();
for (size_type node = 0; node < s; ++node)
{
estream << string(indent, ' ');
if (fmt == NORMAL)
{
estream << "Node " << node << ":\n";
nodes[node]->print(stream, indent + 4, fmt);
}
else if (fmt == DOT)
{
typename EdgeContainer::const_iterator edge;
estream << " n" << node << " [shape=circle,label=\"" << node
<< "\",fontsize=12];\n";
for (edge = nodes[node]->edges().begin();
edge != nodes[node]->edges().end();
++edge)
{
estream << string(indent + 2, ' ') + 'n' << node;
(*edge)->print(stream, 0, fmt);
estream << ";\n";
}
}
}
}
if (fmt == DOT)
estream << string(indent, ' ') + "}\n";
estream.flush();
}
/******************************************************************************
*
* Inline function definitions for class Graph<EdgeContainer>::Edge.
*
*****************************************************************************/
/* ========================================================================= */
template<class EdgeContainer>
inline Graph<EdgeContainer>::Edge::Edge
(const Graph<EdgeContainer>::size_type target) : target_node(target)
/* ----------------------------------------------------------------------------
*
* Description: Constructor for template class Graph<EdgeContainer>::Edge.
* Creates a new edge and initializes its target node.
*
* Arguments: target -- Identifier of the edge's target node.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
}
/* ========================================================================= */
template<class EdgeContainer>
inline Graph<EdgeContainer>::Edge::~Edge()
/* ----------------------------------------------------------------------------
*
* Description: Destructor for template class Graph<EdgeContainer>::Edge.
*
* Arguments: None.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
}
/* ========================================================================= */
template<class EdgeContainer>
inline bool Graph<EdgeContainer>::Edge::operator==(const Edge& edge) const
/* ----------------------------------------------------------------------------
*
* Description: Equality relation for class Graph<EdgeContainer>::Edge. Two
* edges are `equal' if and only if their target nodes have the
* same identifier.
*
* Argument: edge -- A reference to a constant
* Graph<EdgeContainer>::Edge.
*
* Returns: Truth value according to the relationship between the two
* edges.
*
* ------------------------------------------------------------------------- */
{
return (target_node == edge.target_node);
}
/* ========================================================================= */
template<class EdgeContainer>
inline bool Graph<EdgeContainer>::Edge::operator<(const Edge& edge) const
/* ----------------------------------------------------------------------------
*
* Description: `Less than' relation for class Graph<EdgeContainer>::Edge. An
* edge is `less than' another if and only if the edge's target
* node has a smaller identifier than that of the other edge.
*
* Argument: edge -- A reference to a constant
* Graph<EdgeContainer>::Edge.
*
* Returns: Truth value according to the relationship between the two
* edges.
*
* ------------------------------------------------------------------------- */
{
return (target_node < edge.target_node);
}
/* ========================================================================= */
template<class EdgeContainer>
inline typename Graph<EdgeContainer>::size_type
Graph<EdgeContainer>::Edge::targetNode() const
/* ----------------------------------------------------------------------------
*
* Description: Returns the identifier of the edge's target node.
*
* Arguments: None.
*
* Returns: Identifier of the target node.
*
* ------------------------------------------------------------------------- */
{
return target_node;
}
/* ========================================================================= */
template<class EdgeContainer>
inline ostream& operator<<
(ostream& stream, const typename Graph<EdgeContainer>::Edge& edge)
/* ----------------------------------------------------------------------------
*
* Description: Defines an alternative way for printing a
* Graph<EdgeContainer>::Edge by using the << operator.
*
* Arguments: stream -- A reference to an output stream.
* edge -- A reference to a constant edge to be printed.
*
* Returns: A reference to the output stream.
*
* ------------------------------------------------------------------------- */
{
edge.print(stream);
return stream;
}
/******************************************************************************
*
* Function definitions for class Graph<EdgeContainer>::Edge.
*
*****************************************************************************/
/* ========================================================================= */
template<class EdgeContainer>
void Graph<EdgeContainer>::Edge::print
(ostream& stream, const int indent, const GraphOutputFormat fmt) const
/* ----------------------------------------------------------------------------
*
* Description: Writes information about the edge to a stream.
*
* Arguments: stream -- A reference to an output stream.
* indent -- Number of spaces to write before the edge
* description.
* fmt -- Determines the output format of the edge.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
Exceptional_ostream estream(&stream, ios::failbit | ios::badbit);
if (fmt == NORMAL)
estream << string(indent, ' ') << "Edge to node " << target_node << '\n';
else if (fmt == DOT)
estream << " -> n" << target_node;
estream.flush();
}
/******************************************************************************
*
* Inline function definitions for class Graph<EdgeContainer>::Edge::ptr_equal.
*
*****************************************************************************/
/* ========================================================================= */
template<class EdgeContainer>
inline bool Graph<EdgeContainer>::Edge::ptr_equal::operator()
(const Graph<EdgeContainer>::Edge* edge_1,
const Graph<EdgeContainer>::Edge* edge_2) const
/* ----------------------------------------------------------------------------
*
* Description: Function to test the `equality' of two pointers to
* Graph<EdgeContainer>::Edges, the other one of which is stored
* in the function object for whom this member function is
* called.
*
* Arguments: edge_1, edge_2 -- Two pointers to constant
* Graph<EdgeContainer>::Edges.
*
* Returns: A truth value according to the result of the equality test.
*
* ------------------------------------------------------------------------- */
{
return (*edge_1 == *edge_2);
}
/******************************************************************************
*
* Inline function definitions for class Graph<EdgeContainer>::Edge::ptr_less.
*
*****************************************************************************/
/* ========================================================================= */
template<class EdgeContainer>
inline bool Graph<EdgeContainer>::Edge::ptr_less::operator()
(const Graph<EdgeContainer>::Edge* edge_1,
const Graph<EdgeContainer>::Edge* edge_2) const
/* ----------------------------------------------------------------------------
*
* Description: Defines a `less than' relation between two pointers to
* Graph<EdgeContainer>::Edges by mapping the relation between
* the pointers to the relation between the objects itself.
* (Used for storing pointers to Edges into a container.)
*
* Arguments: edge_1, edge_2 -- Two pointers to constant
* Graph<EdgeContainer>::Edges.
*
* Returns: Truth value according to the relationship of the two edges
* involved.
*
* ------------------------------------------------------------------------- */
{
return (*edge_1 < *edge_2);
}
/******************************************************************************
*
* Inline function definitions for class Graph<EdgeContainer>::Node.
*
*****************************************************************************/
/* ========================================================================= */
template<class EdgeContainer>
inline Graph<EdgeContainer>::Node::Node()
/* ----------------------------------------------------------------------------
*
* Description: Constructor for class Graph<EdgeContainer>::Node. Creates a
* new node.
*
* Arguments: None.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
}
/* ========================================================================= */
template<class EdgeContainer>
inline const EdgeContainer& Graph<EdgeContainer>::Node::edges() const
/* ----------------------------------------------------------------------------
*
* Description: Returns the set of edges starting from the node.
*
* Arguments: None.
*
* Returns: A reference to the constant container of pointers to the
* edges starting from the node.
*
* ------------------------------------------------------------------------- */
{
return outgoing_edges;
}
/* ========================================================================= */
template<class EdgeContainer>
inline ostream& operator<<
(ostream& stream, const typename Graph<EdgeContainer>::Node& node)
/* ----------------------------------------------------------------------------
*
* Description: An alternative method for printing a
* Graph<EdgeContainer>::Node object by using the << operator.
*
* Arguments: stream -- A reference to an output stream.
* node -- Node to be printed.
*
* Returns: A reference to the output stream.
*
* ------------------------------------------------------------------------- */
{
node.print(stream);
return stream;
}
/******************************************************************************
*
* Function definitions for class Graph<EdgeContainer>::Node.
*
*****************************************************************************/
/* ========================================================================= */
template<class EdgeContainer>
Graph<EdgeContainer>::Node::Node(const Node& node)
/* ----------------------------------------------------------------------------
*
* Description: Copy constructor for Graph<EdgeContainer>::Node. Initializes
* a copy of a Node.
*
* Argument: node -- A reference to a constant node to be copied.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
typename EdgeContainer::const_iterator edge;
for (edge = node.outgoing_edges.begin(); edge != node.outgoing_edges.end();
++edge)
outgoing_edges.insert(new Edge(**edge));
}
/* ========================================================================= */
template<class EdgeContainer>
Graph<EdgeContainer>::Node::~Node()
/* ----------------------------------------------------------------------------
*
* Description: Destructor for Graph<EdgeContainer>::Node. Deallocates the
* memory reserved by the object.
*
* Arguments: None.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
typename EdgeContainer::iterator edge;
for (edge = outgoing_edges.begin(); edge != outgoing_edges.end(); ++edge)
delete *edge;
}
/* ========================================================================= */
template<class EdgeContainer>
typename Graph<EdgeContainer>::Node& Graph<EdgeContainer>::Node::operator=
(const Graph<EdgeContainer>::Node& node)
/* ----------------------------------------------------------------------------
*
* Description: Assignment operator for class Graph<EdgeContainer>::Node.
* Assigns a graph node a copy of another one.
*
* Argument: node -- A reference to the constant node to be copied.
*
* Returns: A reference to the graph node whose contents were changed.
*
* ------------------------------------------------------------------------- */
{
if (&node != this)
{
typename EdgeContainer::iterator edge;
for (edge = outgoing_edges.begin(); edge != outgoing_edges.end(); ++edge)
delete *edge;
outgoing_edges.clear();
for (edge = node.outgoing_edges.begin(); edge != node.outgoing_edges.end();
++edge)
outgoing_edges.insert(new Edge(**edge));
}
return *this;
}
/* ========================================================================= */
template<class EdgeContainer>
void Graph<EdgeContainer>::Node::print
(ostream& stream, const int indent, const GraphOutputFormat fmt) const
/* ----------------------------------------------------------------------------
*
* Description: Writes information about a graph node to a stream.
*
* Arguments: stream -- A reference to an output stream.
* indent -- Number of spaces to leave to the left of output.
* fmt -- Determines the node output format.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
if (fmt == DOT)
return;
Exceptional_ostream estream(&stream, ios::failbit | ios::badbit);
if (outgoing_edges.empty())
estream << string(indent, ' ') + "The node has no successors.\n";
else
{
typename EdgeContainer::const_iterator edge;
estream << string(indent, ' ') + "The node has "
<< outgoing_edges.size()
<< " successor nodes:\n";
for (edge = outgoing_edges.begin(); edge != outgoing_edges.end(); ++edge)
(*edge)->print(stream, indent + 4);
}
estream.flush();
}
/******************************************************************************
*
* Inline function definitions for class NodeIndexException.
*
*****************************************************************************/
/* ========================================================================= */
inline NodeIndexException::NodeIndexException() :
Exception("graph node index out of range")
/* ----------------------------------------------------------------------------
*
* Description: Constructor for class NodeIndexException. Creates a new
* exception object.
*
* Arguments: None.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
}
/* ========================================================================= */
inline NodeIndexException::~NodeIndexException() throw()
/* ----------------------------------------------------------------------------
*
* Description: Destructor for class NodeIndexException.
*
* Arguments: None.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
}
/* ========================================================================= */
inline NodeIndexException& NodeIndexException::operator=
(const NodeIndexException& e)
/* ----------------------------------------------------------------------------
*
* Description: Assignment operator for class NodeIndexException.
*
* Arguments: e -- A reference to another NodeIndexException.
*
* Returns: A reference to the assigned exception object.
*
* ------------------------------------------------------------------------- */
{
Exception::operator=(e);
return *this;
}
/******************************************************************************
*
* Inline function definitions for class EdgeList.
*
*****************************************************************************/
/* ========================================================================= */
inline EdgeList::EdgeList()
/* ----------------------------------------------------------------------------
*
* Description: Constructor for class EdgeList. Creates a new container based
* on doubly linked lists for storing graph edges.
*
* Arguments: None.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
}
/* ========================================================================= */
inline EdgeList::~EdgeList()
/* ----------------------------------------------------------------------------
*
* Description: Destructor for class EdgeList.
*
* Arguments: None.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
}
/* ========================================================================= */
inline void EdgeList::insert(Graph<EdgeList>::Edge* edge)
/* ----------------------------------------------------------------------------
*
* Description: Inserts a new edge to the end of the list.
*
* Argument: edge -- A pointer to a Graph<EdgeList>::Edge.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
push_back(edge);
}
/* ========================================================================= */
inline list<Graph<EdgeList>::Edge*, ALLOC(Graph<EdgeList>::Edge*) >
::const_iterator
EdgeList::find(const Graph<EdgeList>::Edge* edge) const
/* ----------------------------------------------------------------------------
*
* Description: Finds an edge in the EdgeList.
*
* Argument: edge -- Pointer to an edge to be searched in the list.
* Note that during the search, comparison is done
* between the actual values of the edges (not the
* pointers).
*
* Returns: A list<Graph<EdgeList>::Edge*, ALLOC>::const_iterator
* pointing to the edge in the list or
* list<Graph<EdgeList>::Edge*, ALLOC>::end() if the edge is
* not found in the list.
*
* ------------------------------------------------------------------------- */
{
Graph<EdgeList>::Edge::ptr_equal isEqual;
const_iterator e;
for (e = begin(); e != end() && !isEqual(edge, *e); ++e)
;
return e;
}
/* ========================================================================= */
inline list<Graph<EdgeList>::Edge*, ALLOC(Graph<EdgeList>::Edge*) >::iterator
EdgeList::find(const Graph<EdgeList>::Edge* edge)
/* ----------------------------------------------------------------------------
*
* Description: Finds an edge in the EdgeList.
*
* Argument: edge -- Pointer to an edge to be searched in the list.
* Note that during the search, comparison is done
* between the actual values of the edges (not the
* pointers).
*
* Returns: A list<Graph<EdgeList>::Edge*, ALLOC>::iterator pointing
* to the edge in the list or
* list<Graph<EdgeList>::Edge*, ALLOC>::end() if the edge is
* not found in the list.
*
* ------------------------------------------------------------------------- */
{
Graph<EdgeList>::Edge::ptr_equal isEqual;
iterator e;
for (e = begin(); e != end() && !isEqual(edge, *e); ++e)
;
return e;
}
/******************************************************************************
*
* Inline function definitions for class EdgeSlist.
*
*****************************************************************************/
#ifdef HAVE_SLIST
/* ========================================================================= */
inline EdgeSlist::EdgeSlist()
/* ----------------------------------------------------------------------------
*
* Description: Constructor for class EdgeList. Creates a new container based
* on singly linked lists for storing graph edges.
*
* Arguments: None.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
}
/* ========================================================================= */
inline EdgeSlist::~EdgeSlist()
/* ----------------------------------------------------------------------------
*
* Description: Destructor for class EdgeSlist.
*
* Arguments: None.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
}
/* ========================================================================= */
inline void EdgeSlist::insert(Graph<EdgeSlist>::Edge* edge)
/* ----------------------------------------------------------------------------
*
* Description: Inserts a new edge to the beginning of the list.
*
* Argument: edge -- A pointer to a Graph<EdgeList>::Edge.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
push_front(edge);
}
/* ========================================================================= */
inline slist<Graph<EdgeSlist>::Edge*, ALLOC(Graph<EdgeSlist>::Edge*) >
::const_iterator
EdgeSlist::find(const Graph<EdgeSlist>::Edge* edge) const
/* ----------------------------------------------------------------------------
*
* Description: Finds an edge in the EdgeSlist.
*
* Argument: edge -- Pointer to an edge to be searched in the list.
* Note that during the search, comparison is done
* between the actual values of the edges (not the
* pointers).
*
* Returns: A slist<Graph<EdgeSlist>::Edge*, ALLOC>::const_iterator
* pointing to the edge in the list or
* slist<Graph<EdgeSlist>::Edge*, ALLOC>::end() if the edge
* is not found in the list.
*
* ------------------------------------------------------------------------- */
{
Graph<EdgeSlist>::Edge::ptr_equal isEqual;
const_iterator e;
for (e = begin(); e != end() && !isEqual(edge, *e); ++e)
;
return e;
}
/* ========================================================================= */
inline slist<Graph<EdgeSlist>::Edge*, ALLOC(Graph<EdgeSlist>::Edge*) >
::iterator
EdgeSlist::find(const Graph<EdgeSlist>::Edge* edge)
/* ----------------------------------------------------------------------------
*
* Description: Finds an edge in the EdgeSlist.
*
* Argument: edge -- Pointer to an edge to be searched in the list.
* Note that during the search, comparison is done
* between the actual values of the edges (not the
* pointers).
*
* Returns: A slist<Graph<EdgeSlist>::Edge*, ALLOC>::iterator
* pointing to the edge in the list or
* slist<Graph<EdgeSlist>::Edge*, ALLOC>::end() if the edge
* is not found in the list.
*
* ------------------------------------------------------------------------- */
{
Graph<EdgeSlist>::Edge::ptr_equal isEqual;
iterator e;
for (e = begin(); e != end() && !isEqual(edge, *e); ++e)
;
return e;
}
#endif /* HAVE_SLIST */
/******************************************************************************
*
* Inline function definitions for class EdgeVector.
*
*****************************************************************************/
/* ========================================================================= */
inline EdgeVector::EdgeVector()
/* ----------------------------------------------------------------------------
*
* Description: Constructor for class EdgeVector. Creates a new container
* based on a vector for storing graph edges.
*
* Arguments: None.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
}
/* ========================================================================= */
inline EdgeVector::~EdgeVector()
/* ----------------------------------------------------------------------------
*
* Description: Destructor for class EdgeVector.
*
* Arguments: None.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
}
/* ========================================================================= */
inline void EdgeVector::insert(Graph<EdgeVector>::Edge* edge)
/* ----------------------------------------------------------------------------
*
* Description: Inserts an edge into the edge vector.
*
* Arguments: edge -- A pointer to a Graph<EdgeVector>::Edge.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
push_back(edge);
}
/* ========================================================================= */
inline vector<Graph<EdgeVector>::Edge*, ALLOC(Graph<EdgeVector>::Edge*) >
::const_iterator
EdgeVector::find(const Graph<EdgeVector>::Edge* edge) const
/* ----------------------------------------------------------------------------
*
* Description: Finds an edge in the EdgeVector.
*
* Argument: edge -- Pointer to an edge to be searched in the vector.
* Note that during the search, comparison is done
* between the actual values of the edges (not the
* pointers).
*
* Returns: A vector<Graph<EdgeVector>::Edge*, ALLOC>::const_iterator
* pointing to the edge in the container or
* vector<Graph<EdgeVector>::Edge*, ALLOC>::end() if the
* edge is not found in the container.
*
* ------------------------------------------------------------------------- */
{
Graph<EdgeVector>::Edge::ptr_equal isEqual;
const_iterator e;
for (e = begin(); e != end() && !isEqual(edge, *e); ++e)
;
return e;
}
/* ========================================================================= */
inline vector<Graph<EdgeVector>::Edge*, ALLOC(Graph<EdgeVector>::Edge*) >
::iterator
EdgeVector::find(const Graph<EdgeVector>::Edge* edge)
/* ----------------------------------------------------------------------------
*
* Description: Finds an edge in the EdgeVector.
*
* Argument: edge -- Pointer to an edge to be searched in the vector.
* Note that during the search, comparison is done
* between the actual values of the edges (not the
* pointers).
*
* Returns: A vector<Graph<EdgeVector>::Edge*, ALLOC>::iterator
* pointing to the edge in the container or
* vector<Graph<EdgeSlist>::Edge*, ALLOC>::end() if the edge
* is not found in the container.
*
* ------------------------------------------------------------------------- */
{
Graph<EdgeVector>::Edge::ptr_equal isEqual;
iterator e;
for (e = begin(); e != end() && !isEqual(edge, *e); ++e)
;
return e;
}
}
#endif /* !GRAPH_H */