spot/lbtt/src/SccCollection.h
Alexandre Duret-Lutz d7b3d97422 Import of lbtt 1.1.0
2004-07-07 16:40:50 +00:00

1174 lines
43 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 SCCCOLLECTION_H
#define SCCCOLLECTION_H
#include <config.h>
#include <deque>
#include <map>
#include <set>
#include <utility>
#include <vector>
#include "EdgeContainer.h"
#include "LbttAlloc.h"
#include "Graph.h"
using namespace std;
namespace Graph
{
/******************************************************************************
*
* Interface for a "node visitor" object that provides implementations of
* callback functions to be used during a depth-first search for strongly
* connected components. The VisitorInterface class provides empty
* implementations for the operations; visitor objects can be defined by making
* them inherit the VisitorInterface and then overriding some (or all) of the
* interface functions.
*
* A "node visitor" object must always implement the following type definition
* and operation:
*
* SccType
* A type definition for storing data associated with a maximal strongly
* connected component. This data type should support copying and
* assignment; no other assumptions are made about the internals of this
* data type. It is intended that a node visitor object has a member of
* type SccType (which need not be public); this member can then be
* manipulated freely during the search for strongly connected
* components by giving implementations for the other interface
* functions listed below.
*
* const SccType& operator()()
* Function for accessing the data associated with a maximal strongly
* connected component. This function is called when dereferencing a
* strongly connected component iterator (see below).
*
* In addition, a node visitor can overload the default (empty) implementations
* for the following operations:
*
* void enter(typename GraphType::size_type node_id)
* This function is called whenever the search enters a new node of the
* graph, using the identifier of the node as a parameter.
*
* void backtrack
* (typename GraphType::size_type source_id,
* const typename GraphType::Edge& edge,
* typename GraphType::size_type target_id)
* This function is called when the search backtracks from a node with
* the identifier `target_id' to the node `source_id'. `edge' is a
* reference to the edge between graph nodes identified by `source_id'
* and `target_id'.
*
* void touch
* (typename GraphType::size_type source_id,
* const typename GraphType::Edge& edge,
* typename GraphType::size_type target_id)
* This function is called when the search (in node `source_id')
* encounters an edge (`edge') with a target node (with identifier
* `target_id') that has already been visited during the search.
*
* void leave(typename GraphType::size_type node_id)
* This function is called when the search leaves a node with the
* identifier `node_id'.
*
* void addEdgeToComponent
* (const typename GraphType::Edge& edge,
* typename GraphType::size_type component_id)
* This function is called when the search finds an edge belonging to a
* strongly connected component of the graph (i.e., an edge between two
* states in the component). The function is called with a constant
* reference to the edge and a strongly connected component identifier
* as parameters.
*
* void addNodeToComponent
* (typename GraphType::size_type node_id,
* typename GraphType::size_type component_id)
* This function is called when the search finds a state belonging to a
* strongly connected component of the graph.
*
* void beginComponent
* (typename GraphType::size_type component_id,
* typename GraphType::size_type component_root_id)
* This function is called when the SCC algorithm is about to extract a
* new maximal strongly connected component from the graph. Here,
* `component_id' corresponds to the identifier of the component, and
* `component_root_id' is the identifier of the node in the component
* which was first encountered during the search (the depth-first search
* is about to backtrack from this node).
*
* void insert(typename GraphType::size_type node_id)
* After a call to `beginComponent', the SCC search algorithm will call
* `insert' for each identifier of a node in the maximal strongly
* connected component.
*
* void endComponent(typename GraphType::size_type component_id)
* This function is called after the SCC algorithm has finished
* `insert''ing nodes into a maximal strongly connected component. The
* component identifier is given as a parameter.
*
*****************************************************************************/
template <class GraphType>
class VisitorInterface
{
public:
VisitorInterface(); /* Constructor. */
/* default copy constructor */
virtual ~VisitorInterface(); /* Destructor. */
/* default assignment operator */
virtual void enter /* Interface operations. */
(const typename GraphType::size_type);
virtual void backtrack
(const typename GraphType::size_type,
const typename GraphType::Edge&,
const typename GraphType::size_type);
virtual void touch
(const typename GraphType::size_type,
const typename GraphType::Edge&,
const typename GraphType::size_type);
virtual void leave
(const typename GraphType::size_type);
virtual void addEdgeToComponent
(const typename GraphType::Edge&,
const typename GraphType::size_type);
virtual void addNodeToComponent
(const typename GraphType::size_type,
const typename GraphType::size_type);
virtual void beginComponent
(const typename GraphType::size_type,
const typename GraphType::size_type);
virtual void insert
(const typename GraphType::size_type);
virtual void endComponent
(const typename GraphType::size_type);
};
/******************************************************************************
*
* A template class defining a node visitor for collecting the identifiers of
* nodes in a maximal strongly connected component into a set.
*
*****************************************************************************/
template <class GraphType>
class SccCollector : public VisitorInterface<GraphType>
{
public:
SccCollector(); /* Constructor. */
/* default copy constructor */
~SccCollector(); /* Destructor. */
/* default assignment operator */
typedef set<typename GraphType::size_type, /* Type definition for */
less<typename GraphType::size_type>, /* a set of node id's. */
ALLOC(typename GraphType::size_type) >
SccType;
const SccType& operator()() const; /* Returns the set of node
* identifiers in a
* maximal strongly
* connected component.
*/
/* `enter' inherited */
/* `backtrack' inherited */
/* `touch' inherited */
/* `leave' inherited */
/* `addEdgeToComponent' inherited */
/* `addNodeToComponent' inherited */
void beginComponent /* Function called */
(const typename GraphType::size_type, /* before inserting */
const typename GraphType::size_type); /* nodes in a component. */
void insert /* Function for */
(const typename GraphType::size_type node_id); /* inserting nodes into
* a component.
*/
/* `endComponent' inherited */
private:
SccType scc; /* A set of node
* identifiers representing
* a maximal strongly
* connected component.
*/
};
/******************************************************************************
*
* A template class for defining a "container" of maximal strongly connected
* components of a graph. The template should be instantiated with two classes
* GraphType and NodeVisitor, where the NodeVisitor type should support the
* interface required of a node visitor (see the above documentation of
* VisitorInterface), and GraphType (which defaults to
* Graph<GraphEdgeContainer>) should support the following type definitions and
* operations:
*
* size_type
* A type that can be used for identifying nodes (uniquely) in the
* graph. This type should have a constructor taking no parameters,
* and it should support copying, assignment, and comparison using the
* `less than' operator.
*
* EdgeContainerType
* A type that represents a container of objects behaving similarly to
* pointers to edges in the graph. This type is expected to have an
* STL-like container interface with `begin()' and `end()' operations
* and a const_iterator with a constructor having no parameters and
* copying and assignment operations.
*
* The objects in the container should behave similarly to pointers
* that can be dereferenced using the * and -> operators to get access
* to objects (the edges in the graph, e.g.,
* Graph<GraphEdgeContainer>::Edge) that support the operation
* size_type targetNode()
* that returns the identifier of an edge's target node in the graph.
*
* PathElement
* An object for representing (node_id, edge) pairs of the graph.
* The object should provide a constructor that can be called with two
* parameters: a parameter of type `size_type' and another parameter
* corresponding to the type obtained by dereferencing a pointer-like
* object stored in an object of type EdgeContainerType.
*
* Path
* A type that supports the `clear' operation (with no arguments) and
* the `push_front' operation with an argument of type PathElement.
*
* operator[](size_type node_id)
* This function should return an object that provides access to the
* edges starting from the graph node identified by `node_id' through
* the member function
* const EdgeContainerType& edges(),
* which returns the collection of (pointer-like objects to) edges
* beginning from the graph node with the identifier `node_id'.
*
* bool empty()
* This function should return true iff the graph contains no nodes.
*
* The NodeVisitor type defaults to SccCollector<GraphType>.
*
* The SccCollection class provides the following operations:
*
* SccCollection(const GraphType& g, NodeVisitor& node_visitor)
* Constructor that binds the SccCollection object to the graph `g'
* using the operations defined by `node_visitor' when visiting nodes
* of the graph during the search for strongly connected components.
*
* iterator begin(const typename GraphType::size_type initial_node_id)
* Returns an iterator to the strongly connected components of the
* graph. The function returns an iterator that points to the "first"
* maximal strongly connected component of the graph when starting the
* search for maximal strongly connected components from the node with
* the identifier `initial_node_id'.
*
* Note: If `initial_node_id' belongs to a strongly connected component
* of the graph which has alredy been visited by an iterator obtained
* by a previous call to `begin', the returned iterator is equal to
* `end()'. If this is not desired (i.e., if you wish to repeat the
* search for strongly connected components in a part of the graph,
* initialize a new SccCollection to the graph).
*
* iterator end()
* Returns an iterator pointing "past the end" of the collection of
* strongly connected components.
*
* The class `SccCollection::iterator' provides standard dereferencing and
* prefix and postfix increment operators. It also supports comparison for
* equality and inequality. See below for more detailed information.
*
*****************************************************************************/
template <class GraphType = Graph<GraphEdgeContainer>,
class NodeVisitor = SccCollector<GraphType> >
class SccCollection
{
public:
SccCollection /* Constructor. */
(const GraphType& g,
NodeVisitor& node_visitor);
~SccCollection(); /* Destructor. */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
typedef map<typename GraphType::size_type, /* Type definition for a */
typename GraphType::size_type, /* mapping between node */
less<typename GraphType::size_type>, /* identifiers and the */
ALLOC(typename GraphType::size_type) >/* order in which they */
DfsOrdering; /* were encountered in
* the search for
* strongly connected
* components.
*/
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
class iterator /* Iterator for */
{ /* accessing the maximal
* strongly connected
* components.
*/
public:
iterator(); /* Default constructor. */
/* default copy constructor */
~iterator(); /* Destructor. */
/* default assignment operator */
bool operator==(const iterator& it) const; /* Comparison functions. */
bool operator!=(const iterator& it) const;
const typename NodeVisitor::SccType& /* Dereferencing */
operator*() const; /* operators. */
const typename NodeVisitor::SccType*
operator->() const;
const typename NodeVisitor::SccType& /* Prefix and postfix */
operator++(); /* increment operators. */
const typename NodeVisitor::SccType
operator++(int);
void getPath(typename GraphType::Path& path); /* Function for accessing
* the path from the
* initial node of the
* search to a node in
* the most recently found
* strongly connected
* component.
*/
private:
iterator /* Constructor. */
(const GraphType& g,
NodeVisitor& node_visitor,
DfsOrdering& ordering);
void initialize /* Instructs the */
(const typename GraphType::size_type /* iterator to continue */
node_id); /* the search for
* strongly connected
* components from a
* given node.
*/
const GraphType& graph; /* Reference to the graph
* with which the iterator
* is associated.
*/
NodeVisitor& visitor; /* Reference to an object
* that provides
* implementations for the
* functions listed in the
* VisitorInterface class.
*/
DfsOrdering& dfs_ordering; /* Mapping between node
* identifiers and their
* dfs numbers.
*/
typename GraphType::size_type initial_node; /* Node from which the
* search was started.
*/
typename GraphType::size_type dfs_number; /* Number of graph nodes
* processed by the
* iterator.
*/
struct NodeStackElement /* Structure for */
{ /* storing information */
typename GraphType::size_type id; /* needed for */
typename GraphType::EdgeContainerType /* backtracking during */
::const_iterator edge; /* the search. */
typename GraphType::size_type lowlink;
};
deque<NodeStackElement, /* Depth-first search */
ALLOC(NodeStackElement) > /* backtracking stack. */
node_stack;
NodeStackElement* current_node; /* Pointer to the top
* element of the
* backtracking stack.
*/
deque<typename GraphType::size_type, /* Stack used for */
ALLOC(typename GraphType::size_type) > /* collecting the nodes */
scc_stack; /* in a strongly
* connected component,
* excluding the root
* nodes of the
* components.
*/
void computeNextScc(); /* Updates the iterator to
* point to the next
* strongly connected
* component.
*/
friend class SccCollection;
};
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
iterator begin /* Returns an iterator */
(const typename GraphType::size_type /* pointing to the */
node_id); /* "first" maximal
* strongly connected
* component reachable
* from a given node.
*/
const iterator& end() const; /* Returns an iterator
* pointing past the "end"
* of the maximal strongly
* connected components.
*/
private:
SccCollection(const SccCollection&); /* Prevent copying and */
SccCollection& operator=(const SccCollection&); /* assignment of
* SccCollection
* objects.
*/
const GraphType& graph; /* Reference to the graph
* associated with the
* container.
*/
NodeVisitor& visitor; /* Reference to an object
* that provides
* implementations for
* callback operations
* needed during the
* search for strongly
* connected components.
*/
const iterator end_iterator; /* Iterator pointing past
* the "end" of the
* collection of strongly
* connected components in
* the graph. This
* iterator is special by
* having both
* `initial_node' and
* `dfs_number' set to 0.
*/
DfsOrdering dfs_ordering; /* Mapping between node
* identifiers and their
* visiting order during
* the search for strongly
* connected components.
*/
};
/******************************************************************************
*
* Inline function definitions for template class VisitorInterface. This class
* provides default empty implementations for node visitor operations.
*
*****************************************************************************/
template <class GraphType>
inline VisitorInterface<GraphType>::VisitorInterface()
{
}
template <class GraphType>
inline VisitorInterface<GraphType>::~VisitorInterface()
{
}
template <class GraphType>
inline void VisitorInterface<GraphType>::enter
(const typename GraphType::size_type)
{
}
template <class GraphType>
inline void VisitorInterface<GraphType>::backtrack
(const typename GraphType::size_type, const typename GraphType::Edge&,
const typename GraphType::size_type)
{
}
template <class GraphType>
inline void VisitorInterface<GraphType>::touch
(const typename GraphType::size_type, const typename GraphType::Edge&,
const typename GraphType::size_type)
{
}
template <class GraphType>
inline void VisitorInterface<GraphType>::leave
(const typename GraphType::size_type)
{
}
template <class GraphType>
inline void VisitorInterface<GraphType>::addEdgeToComponent
(const typename GraphType::Edge&, const typename GraphType::size_type)
{
}
template <class GraphType>
inline void VisitorInterface<GraphType>::addNodeToComponent
(const typename GraphType::size_type, const typename GraphType::size_type)
{
}
template <class GraphType>
inline void VisitorInterface<GraphType>::beginComponent
(const typename GraphType::size_type, const typename GraphType::size_type)
{
}
template <class GraphType>
inline void VisitorInterface<GraphType>::insert
(const typename GraphType::size_type)
{
}
template <class GraphType>
inline void VisitorInterface<GraphType>::endComponent
(const typename GraphType::size_type)
{
}
/******************************************************************************
*
* Inline function definitions for template class SccCollector.
*
*****************************************************************************/
/* ========================================================================= */
template <class GraphType>
inline SccCollector<GraphType>::SccCollector()
/* ----------------------------------------------------------------------------
*
* Description: Constructor for class SccCollector.
*
* Arguments: None.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
}
/* ========================================================================= */
template <class GraphType>
inline SccCollector<GraphType>::~SccCollector()
/* ----------------------------------------------------------------------------
*
* Description: Destructor for class SccCollector.
*
* Arguments: None.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
}
/* ========================================================================= */
template <class GraphType>
inline const typename SccCollector<GraphType>::SccType&
SccCollector<GraphType>::operator()() const
/* ----------------------------------------------------------------------------
*
* Description: Returns the set of identifiers of nodes in the maximal
* strongly connected component.
*
* Arguments: None.
*
* Returns: A constant reference to the set of identifiers of nodes in
* the component.
*
* ------------------------------------------------------------------------- */
{
return scc;
}
/* ========================================================================= */
template <class GraphType>
inline void SccCollector<GraphType>::beginComponent
(const typename GraphType::size_type, const typename GraphType::size_type)
/* ----------------------------------------------------------------------------
*
* Description: Clears the set of node identifiers to make it empty before
* filling it with (identifiers of) nodes of a new maximal
* strongly connected component.
*
* Arguments: The arguments are needed to support the expected function
* calling interface.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
scc.clear();
}
/* ========================================================================= */
template <class GraphType>
inline void SccCollector<GraphType>::insert
(const typename GraphType::size_type node_id)
/* ----------------------------------------------------------------------------
*
* Description: Inserts an identifier into the set of node identifiers in a
* maximal strongly connected component.
*
* Arguments: node_id -- Node identifier.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
scc.insert(node_id);
}
/******************************************************************************
*
* Inline function definitions for template class SccCollection.
*
*****************************************************************************/
/* ========================================================================= */
template <class GraphType, class NodeVisitor>
inline SccCollection<GraphType, NodeVisitor>::SccCollection
(const GraphType& g, NodeVisitor& node_visitor) :
graph(g), visitor(node_visitor), end_iterator(g, node_visitor, dfs_ordering)
/* ----------------------------------------------------------------------------
*
* Description: Constructor for class SccCollection.
*
* Arguments: g -- A constant reference to an object of type
* GraphType. See above for the description
* of the interface that this object should
* support.
* node_visitor -- A reference to an object that provides
* node visiting operations. See the
* documentation of VisitorInterface for more
* information.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
}
/* ========================================================================= */
template <class GraphType, class NodeVisitor>
inline SccCollection<GraphType, NodeVisitor>::~SccCollection()
/* ----------------------------------------------------------------------------
*
* Description: Destructor for class SccCollection.
*
* Arguments: None.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
}
/* ========================================================================= */
template <class GraphType, class NodeVisitor>
inline typename SccCollection<GraphType, NodeVisitor>::iterator
SccCollection<GraphType, NodeVisitor>::begin
(const typename GraphType::size_type node_id)
/* ----------------------------------------------------------------------------
*
* Description: Returns an iterator pointing to the "first" strongly
* connected component reachable from a given node of
* `this->graph'.
*
* Argument: node_id -- Identifier of the node.
*
* Returns: An iterator pointing to the "first" strongly connected
* component reachable from the node, or an iterator equal to
* `this->end()' if the node with the identifier `node_id' has
* already been included in a strongly connected component
* returned by another iterator to the same collection of
* strongly connected components.
*
* ------------------------------------------------------------------------- */
{
iterator it(graph, visitor, dfs_ordering);
it.initialize(node_id);
return it;
}
/* ========================================================================= */
template <class GraphType, class NodeVisitor>
inline const typename SccCollection<GraphType, NodeVisitor>::iterator&
SccCollection<GraphType, NodeVisitor>::end() const
/* ----------------------------------------------------------------------------
*
* Description: Returns an iterator pointing past the "end" of the collection
* of strongly connected components in `this->graph'.
*
* Arguments: None.
*
* Returns: A constant reference to `this->end_iterator'.
*
* ------------------------------------------------------------------------- */
{
return end_iterator;
}
/******************************************************************************
*
* Inline function definitions for template class SccCollection::iterator.
*
*****************************************************************************/
/* ========================================================================= */
template <class GraphType, class NodeVisitor>
inline SccCollection<GraphType, NodeVisitor>::iterator::iterator
(const GraphType& g, NodeVisitor& node_visitor,
SccCollection<GraphType, NodeVisitor>::DfsOrdering& ordering) :
graph(g), visitor(node_visitor), dfs_ordering(ordering), initial_node(0),
dfs_number(0)
/* ----------------------------------------------------------------------------
*
* Description: Constructor for class
* SccCollection<GraphType, NodeVisitor>::iterator. Initializes
* a new iterator for scanning the maximal strongly connected
* components of a graph.
*
* Arguments: g -- The graph with which the iterator is to be
* associated.
* node_visitor -- A reference to a object that implements
* callback functions to be invoked during the
* search for strongly connected components.
* ordering -- A reference to a mapping between node
* identifiers and their dfs numbers.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
}
/* ========================================================================= */
template <class GraphType, class NodeVisitor>
inline SccCollection<GraphType, NodeVisitor>::iterator::~iterator()
/* ----------------------------------------------------------------------------
*
* Description: Destructor for class
* SccCollection<GraphType, NodeVisitor>::iterator.
*
* Arguments: None.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
}
/* ========================================================================= */
template <class GraphType, class NodeVisitor>
inline bool SccCollection<GraphType, NodeVisitor>::iterator::operator==
(const SccCollection<GraphType, NodeVisitor>::iterator& it) const
/* ----------------------------------------------------------------------------
*
* Description: Equality comparison between two SccCollection::iterators. Two
* iterators are equal iff they have the same initial state and
* they have visited the same amount of graph nodes.
*
* Argument: it -- A constant reference to an iterator.
*
* Returns: true iff the iterators are equal.
*
* ------------------------------------------------------------------------- */
{
return (it.initial_node == initial_node && it.dfs_number == dfs_number);
}
/* ========================================================================= */
template <class GraphType, class NodeVisitor>
inline bool SccCollection<GraphType, NodeVisitor>::iterator::operator!=
(const SccCollection<GraphType, NodeVisitor>::iterator& it) const
/* ----------------------------------------------------------------------------
*
* Description: Inequality comparison between two SccCollection::iterators.
* Two iterators are not equal iff they have different initial
* states or if they have visited different numbers of graph
* nodes.
*
* Argument: it -- A constant reference to an iterator.
*
* Returns: true iff the iterators are not equal.
*
* ------------------------------------------------------------------------- */
{
return (it.initial_node != initial_node || it.dfs_number != dfs_number);
}
/* ========================================================================= */
template <class GraphType, class NodeVisitor>
inline const typename NodeVisitor::SccType&
SccCollection<GraphType, NodeVisitor>::iterator::operator*() const
/* ----------------------------------------------------------------------------
*
* Description: Dereferencing operator for class
* SccCollection<GraphType, NodeVisitor>::iterator. Returns the
* data associated with the maximal strongly connected component
* currently pointed to by the iterator.
*
* Arguments: None.
*
* Returns: A constant reference to the data associated with the strongly
* connected component.
*
* ------------------------------------------------------------------------- */
{
return visitor();
}
/* ========================================================================= */
template <class GraphType, class NodeVisitor>
inline const typename NodeVisitor::SccType*
SccCollection<GraphType, NodeVisitor>::iterator::operator->() const
/* ----------------------------------------------------------------------------
*
* Description: Dereferencing operator for class
* SccCollection<GraphType, NodeVisitor>::iterator. Returns a
* pointer to the data associated with the maximal strongly
* connected component currently pointed to by the iterator.
*
* Arguments: None.
*
* Returns: A constant pointer to the data associated with the strongly
* connected component.
*
* ------------------------------------------------------------------------- */
{
return &visitor();
}
/* ========================================================================= */
template <class GraphType, class NodeVisitor>
inline const typename NodeVisitor::SccType&
SccCollection<GraphType, NodeVisitor>::iterator::operator++()
/* ----------------------------------------------------------------------------
*
* Description: Prefix increment operator for class
* SccCollection<GraphType, NodeVisitor>::iterator. Computes
* the next maximal strongly connected component of
* `this->graph' and then returns the data associated with it.
*
* Arguments: None.
*
* Returns: A reference to the data associated with the maximal strongly
* connected component found by incrementing the iterator.
*
* ------------------------------------------------------------------------- */
{
computeNextScc();
return visitor();
}
/* ========================================================================= */
template <class GraphType, class NodeVisitor>
inline const typename NodeVisitor::SccType
SccCollection<GraphType, NodeVisitor>::iterator::operator++(int)
/* ----------------------------------------------------------------------------
*
* Description: Postfix increment operator for class
* SccCollection<GraphType, NodeVisitor>::iterator. Computes
* the next strongly connected component of
* `this->graph', but returns the data associated with the
* strongly connected component that the iterator pointed to
* _before_ this operation.
*
* Arguments: None (the `int' is only required to distinguish this operator
* from the prefix increment operator).
*
* Returns: The data associated with the maximal strongly connected
* component pointed to by the iterator before incrementing it.
*
* ------------------------------------------------------------------------- */
{
const typename NodeVisitor::SccType old_scc = visitor();
computeNextScc();
return old_scc;
}
/******************************************************************************
*
* Function definitions for template class
* SccCollection<GraphType, NodeVisitor>.
*
*****************************************************************************/
/* ========================================================================= */
template <class GraphType, class NodeVisitor>
void SccCollection<GraphType, NodeVisitor>::iterator::getPath
(typename GraphType::Path& path)
/* ----------------------------------------------------------------------------
*
* Description: Constructs a path from the initial state of the search for
* the strongly connected components to a node in the most
* recently found maximal strongly connected graph component.
*
* Argument: path -- A reference to a GraphType::Path object for storing
* the (node_id, edge) pairs in the path.
*
* Returns: Nothing. Assuming that `path' is a standard STL container
* type object with the `push_front' operation, `*path.begin()'
* will correspond to the first element on the path after the
* call.
*
* ------------------------------------------------------------------------- */
{
path.clear();
/*
* When this function is called after extracting a maximal strongly connected
* component from the graph, `node_stack.front()' corresponds to the root
* node of the component. This node will not be included in the path
* (that is, the edge component of `path.back()' will point to this node
* when exiting from this function).
*/
typename deque<NodeStackElement, ALLOC(NodeStackElement) >::const_iterator
n = node_stack.begin();
if (n != node_stack.end())
{
for (++n; n != node_stack.end(); ++n)
{
const typename GraphType::PathElement element(n->id, **n->edge);
path.push_front(element);
}
}
}
/* ========================================================================= */
template <class GraphType, class NodeVisitor>
void SccCollection<GraphType, NodeVisitor>::iterator::initialize
(const typename GraphType::size_type node_id)
/* ----------------------------------------------------------------------------
*
* Description: Initializes a
* SccCollection<GraphType, NodeVisitor>::iterator for scanning
* the maximal strongly connected components of `this->graph'.
*
* Argument: node_id -- Identifier of a graph node from which to start
* the search for maximal strongly connected
* components.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
node_stack.clear();
scc_stack.clear();
/*
* If `node_id' is an identifier of a node that has not yet been visited,
* make the iterator point to the next strongly connected component of
* `this->graph'.
*/
if (!graph.empty() && dfs_ordering.find(node_id) == dfs_ordering.end())
{
initial_node = node_id;
visitor.enter(node_id);
dfs_ordering[node_id] = dfs_number = 1;
const NodeStackElement element
= { node_id, graph[node_id].edges().begin(), 1 };
node_stack.push_front(element);
current_node = &node_stack.front();
computeNextScc();
}
}
/* ========================================================================= */
template <class GraphType, class NodeVisitor>
void SccCollection<GraphType, NodeVisitor>::iterator::computeNextScc()
/* ----------------------------------------------------------------------------
*
* Description: Makes an SccCollection<GraphType, NodeVisitor>::iterator
* point to the "next" maximal strongly connected component of
* `this->graph', using an algorithm based on the depth-first
* search algorithm of Tarjan
* [R. J. Tarjan. Depth-first search and linear graph
* algorithms. SIAM Journal on Computing 1(2):146--160,
* 1972]
* for computing the maximal strongly connected components of
* the graph.
*
* The implementation includes the optimization in the first
* improved algorithm found in
* [E. Nuutila and E. Soisalon-Soininen. On finding the
* strongly connected components in a directed graph.
* Information Processing Letters 49(1):9--14, 1994].
*
* Arguments: None.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
if (current_node->lowlink == 0)
{
/* Backtrack from the root of an SCC that was extracted from the graph */
const typename GraphType::size_type child_node = current_node->id;
node_stack.pop_front();
if (node_stack.empty())
{
initial_node = dfs_number = 0;
return;
}
current_node = &node_stack.front();
visitor.backtrack(current_node->id, **current_node->edge, child_node);
++current_node->edge; /* prepare to process the next edge */
}
next_edge:
while (current_node->edge != graph[current_node->id].edges().end())
{
const typename GraphType::size_type child_node
= (*current_node->edge)->targetNode();
const typename DfsOrdering::const_iterator child_dfs_number_finder
= dfs_ordering.find(child_node);
if (child_dfs_number_finder == dfs_ordering.end()) /* child not visited */
{
++dfs_number;
dfs_ordering[child_node] = dfs_number;
visitor.enter(child_node);
const NodeStackElement element
= { child_node, graph[child_node].edges().begin(), dfs_number };
node_stack.push_front(element);
current_node = &node_stack.front();
goto next_edge;
}
visitor.touch(current_node->id, **current_node->edge, child_node);
if (child_dfs_number_finder->second != 0) /* child in the same SCC */
{
if (child_dfs_number_finder->second < current_node->lowlink)
current_node->lowlink = child_dfs_number_finder->second;
visitor.addEdgeToComponent(**current_node->edge, current_node->lowlink);
}
++current_node->edge;
}
visitor.addNodeToComponent(current_node->id, current_node->lowlink);
visitor.leave(current_node->id);
if (dfs_ordering.find(current_node->id)->second != current_node->lowlink)
{
scc_stack.push_front(current_node->id);
/* Backtrack from a node into a node in the same SCC */
const typename GraphType::size_type child_node = current_node->id;
const typename GraphType::size_type child_lowlink = current_node->lowlink;
node_stack.pop_front();
current_node = &node_stack.front();
if (current_node->lowlink > child_lowlink)
current_node->lowlink = child_lowlink;
visitor.backtrack(current_node->id, **current_node->edge, child_node);
visitor.addEdgeToComponent(**current_node->edge, current_node->lowlink);
++current_node->edge; /* prepare to process the next edge */
goto next_edge;
}
/*
* `current_node' is a root of a maximal strongly connected graph component.
* Extract the component from the graph.
*/
visitor.beginComponent(current_node->lowlink, current_node->id);
visitor.insert(current_node->id);
dfs_ordering.find(current_node->id)->second = 0;
while (!scc_stack.empty())
{
const typename GraphType::size_type node = scc_stack.front();
typename GraphType::size_type& node_dfs_number
= dfs_ordering.find(node)->second;
if (node_dfs_number > current_node->lowlink)
{
scc_stack.pop_front();
visitor.insert(node);
node_dfs_number = 0;
}
else
break;
}
visitor.endComponent(current_node->lowlink);
current_node->lowlink = 0;
}
}
#endif /* !SCCCOLLECTION_H */