2933 lines
108 KiB
C++
2933 lines
108 KiB
C++
/*
|
|
* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
|
|
* Heikki Tauriainen <Heikki.Tauriainen@tkk.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 PRODUCT_H
|
|
#define PRODUCT_H
|
|
|
|
#include <config.h>
|
|
#include <deque>
|
|
#include <map>
|
|
#include <set>
|
|
#include <utility>
|
|
#include "LbttAlloc.h"
|
|
#include "BitArray.h"
|
|
#include "EdgeContainer.h"
|
|
#include "Exception.h"
|
|
#include "Graph.h"
|
|
#include "SccCollection.h"
|
|
|
|
using namespace std;
|
|
|
|
extern bool user_break;
|
|
|
|
namespace Graph
|
|
{
|
|
|
|
/******************************************************************************
|
|
*
|
|
* A template class for representing the product of two
|
|
* Graph<GraphEdgeContainer> objects (which, in lbtt, are always either two
|
|
* BuchiAutomaton objects, or a BuchiAutomaton and a StateSpace).
|
|
*
|
|
* The class provides functions for checking the products of these objects for
|
|
* emptiness (i.e., for two Büchi automata, whether the intersection of their
|
|
* languages is (non)empty; for a Büchi automaton and a state space, whether
|
|
* some infinite path in the state space is accepted by the automaton). The
|
|
* functions are as follows:
|
|
*
|
|
* * bool localEmptinessCheck
|
|
* (Graph<GraphEdgeContainer>::size_type,
|
|
* Graph<GraphEdgeContainer>::size_type)
|
|
* Checks whether the subproduct rooted at a product state
|
|
* determined by a pair of component state identifiers is not
|
|
* empty and returns true if this is the case.
|
|
*
|
|
* * pair<Graph<GraphEdgeContainer>::size_type, unsigned long int>
|
|
* globalEmptinessCheck
|
|
* (Graph<GraphEdgeContainer>::size_type state, Bitset&,
|
|
* unsigned long int emptiness_check_size)
|
|
* Checks a set of subproducts for emptiness and stores the
|
|
* results in a bit set that should have room for (at least)
|
|
* `emptiness_check_size' bits (this number is assumed to be less
|
|
* than the number of states in the second component of the
|
|
* product). The first parameter `state' identifies a state in
|
|
* the first component of the product. After the call, the i'th
|
|
* bit (for all 0 <= i < emptiness_check_size) in the bit set will
|
|
* then be 1 iff the subproduct rooted at the product state
|
|
* determined by the pair of state identifiers (state, i) is
|
|
* nonempty. The function returns a pair of numbers corresponding
|
|
* to the number of product states and transitions generated
|
|
* during the emptiness check.
|
|
*
|
|
* * void findWitness
|
|
* (Graph<GraphEdgeContainer>::size_type,
|
|
* Graph<GraphEdgeContainer>::size_type,
|
|
* Product<Operations>::Witness&)
|
|
* Checks whether the subproduct rooted at a product state
|
|
* determined by a pair of component state identifiers is not
|
|
* empty. If this is the case, the function constructs a
|
|
* certificate (a "witness") for the nonemptiness. For the
|
|
* product of two Büchi automata, the witness is an accepting
|
|
* execution from both automata on the same input; for the product
|
|
* of a Büchi automaton and a state space, the witness is a path
|
|
* in the state space that is accepted by the automaton.
|
|
*
|
|
* All of these functions construct the product "on the fly" with the help of
|
|
* operations provided by the class Operations used for instantiating the
|
|
* template. The public interface of this class must support the following
|
|
* operations:
|
|
*
|
|
* * Operations(const Graph<GraphEdgeContainer>&,
|
|
* const Graph<GraphEdgeContainer>&)
|
|
* Constructor that accepts references to the first and second
|
|
* component of the product (in this order) as parameters.
|
|
*
|
|
* * bool empty()
|
|
* A predicate which returns "true" iff either of the product
|
|
* components is (trivially) empty, i.e., iff either component has
|
|
* no states.
|
|
*
|
|
* * unsigned long int numberOfAcceptanceSets()
|
|
* Returns the number of acceptance sets associated with a state
|
|
* or a transition in the product.
|
|
*
|
|
* * const Graph<GraphEdgeContainer>::Node& firstComponent
|
|
* (Graph<GraphEdgeContainer>::size_type),
|
|
* const Graph<GraphEdgeContainer>::Node& secondComponent
|
|
* (Graph<GraphEdgeContainer>::size_type)
|
|
* Functions for accessing the states in the individual product
|
|
* components such that firstComponent(i) (secondComponent(i))
|
|
* returns a reference to the i'th state of the first (second)
|
|
* component in the product.
|
|
*
|
|
* * void mergeAcceptanceInformation
|
|
* (const Graph<GraphEdgeContainer>::Node&,
|
|
* const Graph<GraphEdgeContainer>::Node&,
|
|
* BitArray&)
|
|
* Updates the acceptance information of a product state
|
|
* (determined by a state of the first and the second component,
|
|
* respectively) into a BitArray that is guaranteed to have room
|
|
* for at least numberOfAcceptanceSets() bits. The function
|
|
* should not clear bits in the array.
|
|
*
|
|
* * void mergeAcceptanceInformation
|
|
* (const Graph<GraphEdgeContainer>::Edge&,
|
|
* const Graph<GraphEdgeContainer>::Edge&,
|
|
* BitArray&
|
|
* Updates the acceptance information of a product transition
|
|
* (corresponding to a pair of transitions of the first and second
|
|
* product component) into a BitArray (guaranteed to have room for
|
|
* at least numberOfAcceptanceSets() bits). The function should
|
|
* not clear bits in the array.
|
|
*
|
|
* * void validateEdgeIterators
|
|
* (const Graph<GraphEdgeContainer>::Node& node_1,
|
|
* const Graph<GraphEdgeContainer>::Node& node_2,
|
|
* GraphEdgeContainer::const_iterator iterator_1&,
|
|
* GraphEdgeContainer::const_iterator iterator_2&)
|
|
* Checks whether a pair of edges determined from a pair of
|
|
* iterators corresponds to an edge starting from a given state
|
|
* (node_1, node_2) in the product. If yes, the function should
|
|
* leave the iterators intact; otherwise the iterators should be
|
|
* updated such that they point to a pair of edges corresponding
|
|
* to an edge in the product (or to `node_1.edges().end()' and
|
|
* `node_2.edges().end()' if this is not possible).
|
|
* Calling the function with the iterators initialized to
|
|
* `node_1.edges().begin()' and `node_2.edges().begin()' should
|
|
* update the iterators such that repeated calls to
|
|
* `incrementEdgeIterators' (see below) result in an enumeration
|
|
* of all product edges beginning from the product state
|
|
* (node_1, node_2).
|
|
*
|
|
* * void incrementEdgeIterators
|
|
* (const Graph<GraphEdgeContainer>::Node& node_1,
|
|
* const Graph<GraphEdgeContainer>::Node& node_2,
|
|
* GraphEdgeContainer::const_iterator iterator_1&,
|
|
* GraphEdgeContainer::const_iterator iterator_2&)
|
|
* Updates a pair of edge iterators to point to the "next" edge
|
|
* starting from a given state (node_1, node_2) in the product
|
|
* (or to (node_1.edges().end(), node_2.edges().end()) if this is
|
|
* not possible).
|
|
*
|
|
* See the files BuchiProduct.h and StateSpaceProduct.h for examples of classes
|
|
* used for instantiating the template.
|
|
*
|
|
* Given a class suitable for instantiating the Product template, a product is
|
|
* built with the constructor
|
|
* Product<Operations>::Product
|
|
* (const Graph<GraphEdgeContainer>& graph_1,
|
|
* const Graph<GraphEdgeContainer>& graph_2).
|
|
* The product can be then analyzed by calling one of the emptiness checking
|
|
* functions described above.
|
|
*
|
|
* Note: All emptiness checking functions fail by throwing an exception of type
|
|
* Product<Operations>::SizeException if
|
|
* `graph_1.size() * graph_2.size()' exceeds the maximum integer
|
|
* representables using Graph<GraphEdgeContainer>::size_type. The
|
|
* implementation does not support such products.
|
|
*
|
|
* Note: Operations in the Product class are not re-entrant.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
template <class Operations>
|
|
class Product
|
|
{
|
|
public:
|
|
Product /* Constructor. */
|
|
(const Graph<GraphEdgeContainer>& g1,
|
|
const Graph<GraphEdgeContainer>& g2);
|
|
|
|
~Product(); /* Destructor. */
|
|
|
|
typedef typename Graph<GraphEdgeContainer> /* Type of product state */
|
|
::size_type size_type; /* identifiers. */
|
|
|
|
class ProductState; /* A class for accessing
|
|
* states in the product.
|
|
*/
|
|
|
|
const ProductState operator[] /* Indexing operator. */
|
|
(const size_type index) const;
|
|
|
|
size_type stateId /* Constructs a product */
|
|
(const size_type state_1, /* state identifier from */
|
|
const size_type state_2) const; /* the identifiers of
|
|
* the state components.
|
|
*/
|
|
|
|
const Graph<GraphEdgeContainer>::Node& /* Functions for */
|
|
firstComponent(const size_type state) const; /* accessing the */
|
|
const Graph<GraphEdgeContainer>::Node& /* components of a */
|
|
secondComponent(const size_type state) const; /* product state. */
|
|
|
|
bool empty() const; /* Tells whether the
|
|
* product is (trivially)
|
|
* empty.
|
|
*/
|
|
|
|
struct Witness /* Structure for */
|
|
{ /* representing witness */
|
|
pair<Graph<GraphEdgeContainer>::Path, /* paths for */
|
|
Graph<GraphEdgeContainer>::Path> /* the nonemptiness of */
|
|
prefix; /* the product. */
|
|
pair<Graph<GraphEdgeContainer>::Path,
|
|
Graph<GraphEdgeContainer>::Path>
|
|
cycle;
|
|
};
|
|
|
|
bool localEmptinessCheck /* Checks whether the */
|
|
(const typename Graph<GraphEdgeContainer> /* subproduct rooted at */
|
|
::size_type s1_id, /* a product state */
|
|
const typename Graph<GraphEdgeContainer> /* determined by a pair */
|
|
::size_type s2_id); /* of component state
|
|
* identifiers is empty.
|
|
*/
|
|
|
|
const pair<size_type, unsigned long int> /* Checks a set of */
|
|
globalEmptinessCheck /* subproducts for */
|
|
(const typename Graph<GraphEdgeContainer> /* emptiness (see */
|
|
::size_type state_id, /* above). */
|
|
Bitset& result,
|
|
const unsigned long int emptiness_check_size);
|
|
|
|
void findWitness
|
|
(const size_type s1_id, const size_type s2_id, /* Checks whether the */
|
|
Witness& witness); /* subproduct rooted at
|
|
* a product state
|
|
* determined by a pair
|
|
* of component state
|
|
* identifiers is empty.
|
|
* If this is the case,
|
|
* constructs also a
|
|
* witness for the
|
|
* nonemptiness.
|
|
*/
|
|
|
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
|
|
class ProductEdge; /* Classes for */
|
|
class ProductEdgePointer; /* representing
|
|
* transitions in the
|
|
* product and
|
|
* "pointer-like"
|
|
* objects to them.
|
|
*/
|
|
|
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
|
|
class ProductEdgeCollection /* A class that mimics
|
|
* a container for
|
|
* transitions starting
|
|
* from a product state.
|
|
* (The container does
|
|
* not actually store the
|
|
* transitions; instead,
|
|
* it provides functions
|
|
* for constructing
|
|
* iterators that can be
|
|
* used to generate the
|
|
* transitions.)
|
|
*/
|
|
{
|
|
public:
|
|
explicit ProductEdgeCollection /* Constructor. */
|
|
(const size_type state);
|
|
|
|
/* default copy constructor */
|
|
|
|
~ProductEdgeCollection(); /* Destructor. */
|
|
|
|
/* default assignment operator */
|
|
|
|
class const_iterator /* Iterator for generating
|
|
* the transitions starting
|
|
* from a product state.
|
|
*/
|
|
{
|
|
public:
|
|
const_iterator(); /* Default constructor. */
|
|
|
|
const_iterator
|
|
(const size_type state, /* Constructor. */
|
|
const GraphEdgeContainer::const_iterator&
|
|
e1,
|
|
const GraphEdgeContainer::const_iterator&
|
|
e2);
|
|
|
|
/* default copy constructor */
|
|
|
|
~const_iterator(); /* Destructor. */
|
|
|
|
/* default assignment operator */
|
|
|
|
bool operator==(const const_iterator& it) /* Equality test between */
|
|
const; /* iterators. */
|
|
|
|
bool operator!=(const const_iterator& it) /* Inequality test */
|
|
const; /* between iterators. */
|
|
|
|
const ProductEdgePointer operator*() const; /* Dereferencing */
|
|
const ProductEdge operator->() const; /* operators. */
|
|
|
|
const ProductEdgePointer operator++(); /* Prefix and postfix */
|
|
const ProductEdgePointer operator++(int); /* increment operators. */
|
|
|
|
private:
|
|
size_type product_state; /* Product state */
|
|
/* associated with the
|
|
* iterator.
|
|
*/
|
|
|
|
GraphEdgeContainer::const_iterator edge_1; /* Pair of iterators */
|
|
GraphEdgeContainer::const_iterator edge_2; /* from which product
|
|
* edges are determined.
|
|
*/
|
|
};
|
|
|
|
const const_iterator begin() const; /* Returns an iterator to
|
|
* the "beginning" of the
|
|
* list of transitions
|
|
* starting from the
|
|
* product state
|
|
* `this->product_state'.
|
|
*/
|
|
|
|
const const_iterator end() const; /* Returns an iterator to
|
|
* the "end" of the list of
|
|
* transitions starting
|
|
* from the product state
|
|
* `this->product_state'.
|
|
*/
|
|
|
|
private:
|
|
size_type product_state; /* Product state associated
|
|
* with the transition
|
|
* container.
|
|
*/
|
|
};
|
|
|
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
|
|
class SizeException : public Exception /* An exception class to */
|
|
/* be used in cases */
|
|
/* where `size_type' */
|
|
/* cannot hold values */
|
|
/* large enough to */
|
|
/* accommodate the */
|
|
/* largest identifier */
|
|
/* for a product state. */
|
|
{
|
|
public:
|
|
SizeException(); /* Constructor. */
|
|
|
|
/* default copy constructor */
|
|
|
|
~SizeException() throw(); /* Destructor. */
|
|
|
|
SizeException& operator= /* Assignment operator. */
|
|
(const SizeException& e);
|
|
|
|
/* `what' inherited from class Exception */
|
|
};
|
|
|
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
|
|
typedef ProductEdge Edge; /* Type definitions */
|
|
typedef ProductEdgeCollection EdgeContainerType; /* required for making */
|
|
/* Product<Operations> */
|
|
struct PathElement; /* suitable for */
|
|
typedef deque<PathElement> Path; /* instantiating the
|
|
* SccCollection
|
|
* template (see
|
|
* SccCollection.h).
|
|
*/
|
|
|
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
|
|
private:
|
|
Product(const Product&); /* Prevent copying and */
|
|
Product& operator=(const Product&); /* assignment of Product
|
|
* objects.
|
|
*/
|
|
|
|
class AcceptanceTracker; /* Callback operations */
|
|
class SimpleEmptinessChecker; /* used when searching */
|
|
class AcceptanceReachabilityTracker; /* the product for */
|
|
class AcceptingComponentFinder; /* strongly connected
|
|
* components.
|
|
*/
|
|
|
|
void addCycleSegment /* Helper function for */
|
|
(pair<Graph<GraphEdgeContainer>::Path, /* constructing a */
|
|
Graph<GraphEdgeContainer>::Path >& cycle, /* segment of the cycle */
|
|
size_type source_state_id, Edge transition, /* in a witness for the */
|
|
const size_type root_id, /* nonemptiness of the */
|
|
const map<size_type, PathElement>& /* product. */
|
|
predecessor) const;
|
|
|
|
Operations operations; /* Operations for
|
|
* building the product
|
|
* on the fly.
|
|
*/
|
|
|
|
bool too_large; /* Will be set to true
|
|
* if `size_type' cannot
|
|
* hold the maximum value
|
|
* that may be required for
|
|
* product state
|
|
* identifiers. Calling
|
|
* one of the emptiness
|
|
* checking operations on
|
|
* such a product results
|
|
* in a run-time exception.
|
|
*/
|
|
|
|
const size_type state_id_multiplier; /* Size of the "second"
|
|
* component of the
|
|
* product.
|
|
*/
|
|
|
|
static Product<Operations>* product; /* Pointer to the "current"
|
|
* product (i.e., the
|
|
* product for which one
|
|
* of the emptiness
|
|
* checking operations was
|
|
* last called) to allow
|
|
* accessing it from
|
|
* member classes.
|
|
*/
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* A template class for providing a Graph<>::Node-like interface to the states
|
|
* in a product (needed for accessing the transitions leaving from a state).
|
|
*
|
|
*****************************************************************************/
|
|
|
|
template <class Operations>
|
|
class Product<Operations>::ProductState
|
|
{
|
|
public:
|
|
ProductState(const size_type state); /* Constructor. */
|
|
|
|
/* default copy constructor */
|
|
|
|
~ProductState(); /* Destructor. */
|
|
|
|
/* default assignment operator */
|
|
|
|
const EdgeContainerType& edges() const; /* Returns an object for
|
|
* generating the
|
|
* transitions starting
|
|
* from the state.
|
|
*/
|
|
|
|
private:
|
|
EdgeContainerType outgoing_edges; /* Object for generating
|
|
* the transitions starting
|
|
* from the state.
|
|
*/
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* A template class for providing a Graph<>::Edge-like interface to the
|
|
* transitions in a product.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
template <class Operations>
|
|
class Product<Operations>::ProductEdge
|
|
{
|
|
public:
|
|
ProductEdge /* Constructor. */
|
|
(const GraphEdgeContainer::const_iterator& e1,
|
|
const GraphEdgeContainer::const_iterator& e2);
|
|
|
|
/* default copy constructor */
|
|
|
|
~ProductEdge(); /* Destructor. */
|
|
|
|
/* default assignment operator */
|
|
|
|
const Graph<GraphEdgeContainer>::Edge& /* Functions for */
|
|
firstComponent() const; /* accessing the */
|
|
const Graph<GraphEdgeContainer>::Edge& /* components of a */
|
|
secondComponent() const; /* product transition. */
|
|
|
|
size_type targetNode() const; /* Returns the target state
|
|
* of the transition.
|
|
*/
|
|
|
|
private:
|
|
GraphEdgeContainer::const_iterator edge_1; /* Components of the */
|
|
GraphEdgeContainer::const_iterator edge_2; /* transition. */
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* A template class for providing a constant pointer -like interface to
|
|
* ProductEdge objects.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
template <class Operations>
|
|
class Product<Operations>::ProductEdgePointer
|
|
{
|
|
public:
|
|
ProductEdgePointer /* Constructor. */
|
|
(const GraphEdgeContainer::const_iterator& e1,
|
|
const GraphEdgeContainer::const_iterator& e2);
|
|
|
|
/* default copy constructor */
|
|
|
|
~ProductEdgePointer(); /* Destructor. */
|
|
|
|
/* default assignment operator */
|
|
|
|
const ProductEdge& operator*() const; /* Dereferencing */
|
|
const ProductEdge* operator->() const; /* operators. */
|
|
|
|
private:
|
|
ProductEdge edge; /* The product transition.
|
|
*/
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* A template class for representing (product state, product transition) pairs
|
|
* in a path in the product.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
template <class Operations>
|
|
struct Product<Operations>::PathElement
|
|
{
|
|
PathElement(const size_type s, const Edge& t); /* Constructor. */
|
|
|
|
/* default copy constructor */
|
|
|
|
~PathElement(); /* Destructor. */
|
|
|
|
/* default assignment operator */
|
|
|
|
size_type state; /* Product state and */
|
|
Edge transition; /* transition. */
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* A template class for tracking acceptance information in strongly connected
|
|
* product components by (essentially) recording the information into roots of
|
|
* the components. This is done using the method described by Couvreur in
|
|
* [J.-M. Couvreur. On-the-fly verification of linear temporal logic.
|
|
* In Proceedings of the FM'99 World Congress on Formal Methods in the
|
|
* Development of Computing Systems, Volume I, LNCS 1708, pp. 253--271.
|
|
* Springer-Verlag, 1999].
|
|
*
|
|
*****************************************************************************/
|
|
|
|
template <class Operations>
|
|
class Product<Operations>::AcceptanceTracker :
|
|
public VisitorInterface<Product<Operations> >
|
|
{
|
|
public:
|
|
explicit AcceptanceTracker /* Constructor. */
|
|
(const unsigned long int num_accept_sets);
|
|
|
|
virtual ~AcceptanceTracker(); /* Destructor. */
|
|
|
|
/* `enter' inherited */
|
|
|
|
/* `backtrack' inherited */
|
|
|
|
/* `touch' inherited */
|
|
|
|
/* `leave' inherited */
|
|
|
|
virtual void addEdgeToComponent /* Adds the acceptance */
|
|
(const Edge& t, const size_type scc_id); /* sets associated with
|
|
* a product transition
|
|
* to a nontrivial
|
|
* strongly connected
|
|
* component of the
|
|
* product.
|
|
*/
|
|
|
|
virtual void addNodeToComponent /* Adds the acceptance */
|
|
(const size_type state_id, /* sets associated with */
|
|
const size_type scc_id); /* a product state to a */
|
|
/* nontrivial strongly
|
|
* connected component
|
|
* of the product.
|
|
*/
|
|
|
|
/* `beginComponent' inherited */
|
|
|
|
/* `insert' inherited */
|
|
|
|
virtual void endComponent /* Removes the */
|
|
(const size_type scc_id); /* association between a
|
|
* nontrivial strongly
|
|
* connected product
|
|
* component and a set
|
|
* of acceptance sets
|
|
* when the component is
|
|
* not needed any
|
|
* longer.
|
|
*/
|
|
|
|
protected:
|
|
typedef pair<size_type, BitArray*> /* Association between */
|
|
AcceptanceStackElement; /* a strongly connected
|
|
* component identifier
|
|
* and a collection of
|
|
* acceptance sets.
|
|
*/
|
|
|
|
typedef deque<AcceptanceStackElement> /* Stack formed from */
|
|
AcceptanceStack; /* the above
|
|
* associations.
|
|
*/
|
|
|
|
AcceptanceStack acceptance_stack; /* Stack for storing the
|
|
* dfs numbers of roots
|
|
* of strongly connected
|
|
* components and
|
|
* acceptance sets
|
|
* associated with them.
|
|
*/
|
|
|
|
BitArray* acceptance_sets; /* Used for manipulating
|
|
* the stack.
|
|
*/
|
|
|
|
const unsigned long int /* Number of acceptance */
|
|
number_of_acceptance_sets; /* sets in the product. */
|
|
|
|
private:
|
|
AcceptanceTracker(const AcceptanceTracker&); /* Prevent copying and */
|
|
AcceptanceTracker& operator= /* assignment of */
|
|
(const AcceptanceTracker&); /* AcceptanceTracker
|
|
* objects.
|
|
*/
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* A template class for checking a product for emptiness.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
template <class Operations>
|
|
class Product<Operations>::SimpleEmptinessChecker : public AcceptanceTracker
|
|
{
|
|
public:
|
|
explicit SimpleEmptinessChecker /* Constructor. */
|
|
(const unsigned long int num_accept_sets);
|
|
|
|
~SimpleEmptinessChecker(); /* Destructor. */
|
|
|
|
typedef int SccType; /* Dummy type definition
|
|
* required for supporting
|
|
* the expected class
|
|
* interface.
|
|
*/
|
|
|
|
const SccType& operator()() const; /* Dummy function required
|
|
* for supporting the
|
|
* expected class
|
|
* interface.
|
|
*/
|
|
|
|
/* `enter' inherited */
|
|
|
|
/* `backtrack' inherited */
|
|
|
|
/* `touch' inherited */
|
|
|
|
/* `leave' inherited */
|
|
|
|
void addEdgeToComponent /* Adds the acceptance */
|
|
(const Edge& t, const size_type scc_id); /* sets associated with
|
|
* a product transition
|
|
* to a nontrivial
|
|
* strongly connected
|
|
* component of the
|
|
* product and aborts
|
|
* the emptiness check
|
|
* if an accepting
|
|
* strongly connected
|
|
* component is
|
|
* detected.
|
|
*/
|
|
|
|
void addNodeToComponent /* Adds the acceptance */
|
|
(const size_type state, /* sets associated with */
|
|
const size_type scc_id); /* a product state to a
|
|
* nontrivial strongly
|
|
* connected component
|
|
* of the product and
|
|
* aborts the emptiness
|
|
* check if an accepting
|
|
* strongly connected
|
|
* component is
|
|
* detected.
|
|
*/
|
|
|
|
/* `beginComponent' inherited */
|
|
|
|
/* `insert' inherited */
|
|
|
|
/* `endComponent' inherited */
|
|
|
|
private:
|
|
SimpleEmptinessChecker /* Prevent copying and */
|
|
(const SimpleEmptinessChecker&); /* assignment of */
|
|
SimpleEmptinessChecker& /* SimpleEmptiness- */
|
|
operator=(const SimpleEmptinessChecker&); /* Checker objects. */
|
|
|
|
void abortIfNonempty() const; /* Aborts the search when
|
|
* an accepting strongly
|
|
* connected component is
|
|
* found.
|
|
*/
|
|
|
|
SccType dummy; /* Dummy variable needed
|
|
* for implementing the
|
|
* operator() function.
|
|
*/
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* A template class for tracking the reachability of accepting strongly
|
|
* connected components in a product.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
template <class Operations>
|
|
class Product<Operations>::AcceptanceReachabilityTracker
|
|
: public Product<Operations>::AcceptanceTracker
|
|
{
|
|
public:
|
|
explicit AcceptanceReachabilityTracker /* Constructor. */
|
|
(const unsigned long int num_accept_sets);
|
|
|
|
~AcceptanceReachabilityTracker(); /* Destructor. */
|
|
|
|
typedef int SccType; /* Dummy type definition
|
|
* required for supporting
|
|
* the expected class
|
|
* interface.
|
|
*/
|
|
|
|
const SccType& operator()() const; /* Dummy function required
|
|
* for supporting the
|
|
* expected class
|
|
* interface.
|
|
*/
|
|
|
|
void enter(const size_type); /* Function called when
|
|
* entering a new product
|
|
* state.
|
|
*/
|
|
|
|
void backtrack /* Function called when */
|
|
(const size_type source, const Edge&, /* backtracking from a */
|
|
const size_type target); /* product state. */
|
|
|
|
void touch /* Function called when */
|
|
(const size_type source, const Edge& edge, /* processing an edge */
|
|
const size_type target); /* with a target state
|
|
* that has already been
|
|
* visited during the
|
|
* search.
|
|
*/
|
|
|
|
/* `leave' inherited */
|
|
|
|
/* `addEdgeToComponent' inherited */
|
|
|
|
/* `addNodeToComponent' inherited */
|
|
|
|
void beginComponent /* Tests whether the */
|
|
(const size_type, const size_type state_id); /* strongly connected
|
|
* component about to
|
|
* be extracted from the
|
|
* product is an
|
|
* accepting component,
|
|
* or if it contains a
|
|
* state from which such
|
|
* a component is known
|
|
* to be reachable.
|
|
*/
|
|
|
|
void insert(const size_type state); /* Function used for
|
|
* updating accepting
|
|
* component reachability
|
|
* information while
|
|
* extracting states from
|
|
* a product component.
|
|
*/
|
|
|
|
/* `endComponent' inherited */
|
|
|
|
bool isMarked(const size_type state) const; /* Tests whether an
|
|
* accepting component is
|
|
* known to be reachable
|
|
* from a product state.
|
|
*/
|
|
|
|
size_type numberOfStates() const; /* Tells the number of
|
|
* product states explored
|
|
* during the search.
|
|
*/
|
|
|
|
unsigned long int numberOfTransitions() const; /* Tells the number of
|
|
* product transitions
|
|
* explored during the
|
|
* search.
|
|
*/
|
|
|
|
private:
|
|
AcceptanceReachabilityTracker /* Prevent copying and */
|
|
(const AcceptanceReachabilityTracker&); /* assignment of */
|
|
AcceptanceReachabilityTracker& /* AcceptanceSet- */
|
|
operator= /* ReachabilityTracker */
|
|
(const AcceptanceReachabilityTracker&); /* objects. */
|
|
|
|
void markState(const size_type state); /* Adds a product state to
|
|
* the set of states from
|
|
* which an accepting
|
|
* component is known to be
|
|
* reachable.
|
|
*/
|
|
|
|
set<size_type> reachability_info; /* Set of states from
|
|
* which an accepting
|
|
* component is known to
|
|
* be reachable in the
|
|
* product.
|
|
*/
|
|
|
|
size_type number_of_states; /* Number of states
|
|
* explored during the
|
|
* search.
|
|
*/
|
|
|
|
unsigned long int number_of_transitions; /* Number of transitions
|
|
* explored during the
|
|
* search.
|
|
*/
|
|
|
|
bool mark_scc; /* Used for determining
|
|
* whether to insert states
|
|
* into `this->
|
|
* reachability_info' while
|
|
* extracting a strongly
|
|
* connected component from
|
|
* the product.
|
|
*/
|
|
|
|
SccType dummy; /* Dummy variable needed
|
|
* for implementing the
|
|
* operator() function.
|
|
*/
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* A template class for finding accepting maximal strongly connected components
|
|
* in a product.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
template <class Operations>
|
|
class Product<Operations>::AcceptingComponentFinder :
|
|
public Product<Operations>::AcceptanceTracker
|
|
{
|
|
public:
|
|
explicit AcceptingComponentFinder /* Constructor. */
|
|
(const unsigned long int num_accept_sets);
|
|
|
|
~AcceptingComponentFinder(); /* Destructor. */
|
|
|
|
typedef set<size_type> SccType; /* Type definition for
|
|
* the set of product
|
|
* state identifiers in
|
|
* an accepting
|
|
* strongly connected
|
|
* component.
|
|
*/
|
|
|
|
const SccType& operator()() const; /* Returns the last
|
|
* accepting maximal
|
|
* strongly connected
|
|
* component found in the
|
|
* product.
|
|
*/
|
|
|
|
/* `enter' inherited */
|
|
|
|
/* `backtrack' inherited */
|
|
|
|
/* `touch' inherited */
|
|
|
|
/* `leave' inherited */
|
|
|
|
/* `addEdgeToComponent' inherited */
|
|
|
|
/* `addNodeToComponent' inherited */
|
|
|
|
void beginComponent /* Tests whether the */
|
|
(const size_type, const size_type); /* maximal strongly
|
|
* connected component
|
|
* that is about to be
|
|
* extracted from the
|
|
* product is an
|
|
* accepting component.
|
|
*/
|
|
|
|
void insert(const size_type state); /* Inserts a state to an
|
|
* accepting component.
|
|
*/
|
|
|
|
/* `endComponent' inherited */
|
|
|
|
private:
|
|
AcceptingComponentFinder /* Prevent copying and */
|
|
(const AcceptingComponentFinder&); /* assignment of */
|
|
AcceptingComponentFinder& /* AcceptingComponent- */
|
|
operator=(const AcceptingComponentFinder&); /* Finder objects. */
|
|
|
|
SccType scc; /* Set of product state
|
|
* identifiers forming the
|
|
* last accepting strongly
|
|
* connected component
|
|
* found in the product.
|
|
*/
|
|
|
|
bool construct_component; /* Used for determining
|
|
* whether the states
|
|
* extracted from a
|
|
* strongly connected
|
|
* component in the product
|
|
* should be inserted into
|
|
* `this->scc'.
|
|
*/
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* Inline function definitions for template class Product<Operations>.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline Product<Operations>::Product
|
|
(const Graph<GraphEdgeContainer>& g1, const Graph<GraphEdgeContainer>& g2)
|
|
: operations(g1, g2), state_id_multiplier(g2.size())
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Constructor for class Product<Operations>.
|
|
*
|
|
* Arguments: g1, g2 -- Constant references to the components of the
|
|
* product.
|
|
*
|
|
* Returns: Nothing. If `Product<Operations>::size_type' cannot hold
|
|
* values large enough to accommodate the largest identifier for
|
|
* a product state, `this->too_large' is set to true to cause
|
|
* all emptiness checking operations on the product to fail by
|
|
* throwing a Product<Operations>::SizeException.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
too_large = (!g2.empty() &&
|
|
g1.size() > (static_cast<size_type>(-1) / g2.size()));
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline Product<Operations>::~Product()
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Destructor for class Product<Operations>.
|
|
*
|
|
* Arguments: None.
|
|
*
|
|
* Returns: Nothing.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline const typename Product<Operations>::ProductState
|
|
Product<Operations>::operator[]
|
|
(const typename Product<Operations>::size_type index) const
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Indexing operator for class Product<Operations>.
|
|
*
|
|
* Argument: index -- Index of a state of the product.
|
|
*
|
|
* Returns: A ProductState object corresponding to the state with the
|
|
* given index.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
return ProductState(index);
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline typename Product<Operations>::size_type Product<Operations>
|
|
::stateId
|
|
(const size_type state_1, const size_type state_2) const
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Returns the product state identifier corresponding to
|
|
* identifiers of the state components.
|
|
*
|
|
* Arguments: state_1, state_2 -- Identifiers for the product state
|
|
* components.
|
|
*
|
|
* Returns: Identifier of the product state corresponding to the
|
|
* components.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
return (state_1 * state_id_multiplier) + state_2;
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline const Graph<GraphEdgeContainer>::Node&
|
|
Product<Operations>::firstComponent(const size_type state) const
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Function for accessing the "first" component state of a
|
|
* product state.
|
|
*
|
|
* Arguments: state -- Identifier of a product state.
|
|
*
|
|
* Returns: A constant reference to the state corresponding to the
|
|
* "first" component of the product state.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
return operations.firstComponent(state / state_id_multiplier);
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline const Graph<GraphEdgeContainer>::Node&
|
|
Product<Operations>::secondComponent(const size_type state) const
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Function for accessing the "second" component state of a
|
|
* product state.
|
|
*
|
|
* Arguments: state -- Identifier of a product state.
|
|
*
|
|
* Returns: A constant reference to the state corresponding to the
|
|
* "second" component of the product state.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
return operations.secondComponent(state % state_id_multiplier);
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline bool Product<Operations>::empty() const
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Tells whether the product is (trivially) empty, i.e., if
|
|
* either of its components has no states.
|
|
*
|
|
* Arguments: None.
|
|
*
|
|
* Returns: true iff the product is trivially empty.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
return operations.empty();
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* Function definitions for template class Product<Operations>.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
bool Product<Operations>::localEmptinessCheck
|
|
(const Graph<GraphEdgeContainer>::size_type s1_id,
|
|
const Graph<GraphEdgeContainer>::size_type s2_id)
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Checks whether the subproduct rooted at a product state
|
|
* determined by a pair of component state identifiers is not
|
|
* empty.
|
|
*
|
|
* Arguments: s1_id, s2_id -- Identifiers for the product state
|
|
* components.
|
|
*
|
|
* Returns: true iff the subproduct rooted at the product state
|
|
* determined by `s1_id' and `s2_id' is not empty. Throws a
|
|
* Product<Operations>::SizeException if the product is too
|
|
* large to handle.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
if (too_large)
|
|
throw SizeException();
|
|
|
|
if (empty())
|
|
return false;
|
|
|
|
product = this;
|
|
|
|
SimpleEmptinessChecker ec(operations.numberOfAcceptanceSets());
|
|
typedef SccCollection<Product<Operations>, SimpleEmptinessChecker>
|
|
ProductSccCollection;
|
|
|
|
ProductSccCollection sccs(*this, ec);
|
|
|
|
try
|
|
{
|
|
for (typename ProductSccCollection::iterator scc
|
|
= sccs.begin(stateId(s1_id, s2_id));
|
|
scc != sccs.end();
|
|
++scc)
|
|
{
|
|
if (::user_break)
|
|
throw UserBreakException();
|
|
}
|
|
}
|
|
catch (const int)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
const pair<Graph<GraphEdgeContainer>::size_type, unsigned long int>
|
|
Product<Operations>::globalEmptinessCheck
|
|
(const Graph<GraphEdgeContainer>::size_type state_id,
|
|
Bitset& result, const unsigned long int emptiness_check_size)
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Checks a set of subproducts of the product for emptiness.
|
|
*
|
|
* Arguments: state_id -- Identifier of a state in the first
|
|
* component of the product.
|
|
* result -- A reference to a Bitset for storing
|
|
* the result of the emptiness check.
|
|
* The set should have room for at
|
|
* least `emptiness_check_size' bits.
|
|
* emptiness_check_size -- Determines the scope of the
|
|
* emptiness check (see below).
|
|
*
|
|
* Returns: A pair giving the numbers of product states and transitions
|
|
* generated during the emptiness check. The result of the
|
|
* emptiness check itself is stored into `result' such that
|
|
* the i'th bit (for all 0 <= i < emptiness_check_size) in the
|
|
* bit set will be 1 iff the subproduct rooted at the product
|
|
* state determined by the pair of state identifiers
|
|
* (state_id, i) is nonempty.
|
|
*
|
|
* The function throws a Product<Operations>::SizeException if
|
|
* the product may be too large to handle.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
if (too_large)
|
|
throw SizeException();
|
|
|
|
result.clear();
|
|
|
|
if (empty())
|
|
return make_pair(0, 0);
|
|
|
|
product = this;
|
|
|
|
AcceptanceReachabilityTracker rt(operations.numberOfAcceptanceSets());
|
|
|
|
typedef SccCollection<Product<Operations>, AcceptanceReachabilityTracker>
|
|
ProductSccCollection;
|
|
|
|
ProductSccCollection sccs(*this, rt);
|
|
|
|
for (Graph<GraphEdgeContainer>::size_type state = 0;
|
|
state < emptiness_check_size;
|
|
++state)
|
|
{
|
|
for (typename ProductSccCollection::iterator scc
|
|
= sccs.begin(stateId(state_id, state));
|
|
scc != sccs.end();
|
|
++scc)
|
|
{
|
|
if (::user_break)
|
|
throw UserBreakException();
|
|
}
|
|
}
|
|
|
|
for (Graph<GraphEdgeContainer>::size_type state = 0;
|
|
state < emptiness_check_size;
|
|
++state)
|
|
{
|
|
if (rt.isMarked(stateId(state_id, state)))
|
|
result.setBit(state);
|
|
}
|
|
|
|
return make_pair(rt.numberOfStates(), rt.numberOfTransitions());
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
void Product<Operations>::findWitness
|
|
(const typename Graph<GraphEdgeContainer>::size_type s1_id,
|
|
const typename Graph<GraphEdgeContainer>::size_type s2_id,
|
|
typename Product<Operations>::Witness& witness)
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Checks whether the subproduct rooted at a product state
|
|
* determined by a pair of component state identifiers is not
|
|
* empty. If this is the case, constructs a witness for the
|
|
* nonemptiness.
|
|
*
|
|
* Arguments: s1_id, s2_id -- Identifiers for the product state
|
|
* components.
|
|
* witness -- A reference to an object for storing a
|
|
* witness if such a witness exists.
|
|
*
|
|
* Returns: Nothing. A witness was found iff
|
|
* `!witness.cycle.first.empty()
|
|
* && !witness.cycle.second.empty()' holds after the call.
|
|
*
|
|
* The function throws a Product<Operations>::SizeException if
|
|
* the product may be too large to handle.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
if (too_large)
|
|
throw SizeException();
|
|
|
|
witness.prefix.first.clear();
|
|
witness.prefix.second.clear();
|
|
witness.cycle.first.clear();
|
|
witness.cycle.second.clear();
|
|
|
|
if (empty())
|
|
return;
|
|
|
|
product = this;
|
|
const unsigned long int number_of_acceptance_sets
|
|
= operations.numberOfAcceptanceSets();
|
|
const size_type start_state = stateId(s1_id, s2_id);
|
|
|
|
AcceptingComponentFinder acf(number_of_acceptance_sets);
|
|
typedef SccCollection<Product<Operations>, AcceptingComponentFinder>
|
|
ProductSccCollection;
|
|
|
|
ProductSccCollection sccs(*this, acf);
|
|
|
|
for (typename ProductSccCollection::iterator scc = sccs.begin(start_state);
|
|
scc != sccs.end();
|
|
++scc)
|
|
{
|
|
if (::user_break)
|
|
throw UserBreakException();
|
|
|
|
if (!scc->empty())
|
|
{
|
|
/*
|
|
* The prefix of the witness consists of a path from the given product
|
|
* state to a state in an accepting strongly connected product
|
|
* component.
|
|
*/
|
|
|
|
Path path;
|
|
scc.getPath(path);
|
|
|
|
for (typename Path::const_iterator path_element = path.begin();
|
|
path_element != path.end();
|
|
++path_element)
|
|
{
|
|
witness.prefix.first.push_back
|
|
(Graph<GraphEdgeContainer>::PathElement
|
|
(path_element->state / state_id_multiplier,
|
|
path_element->transition.firstComponent()));
|
|
witness.prefix.second.push_back
|
|
(Graph<GraphEdgeContainer>::PathElement
|
|
(path_element->state % state_id_multiplier,
|
|
path_element->transition.secondComponent()));
|
|
}
|
|
|
|
/*
|
|
* Construct an accepting cycle by performing a breadth-first search
|
|
* in the MSCC.
|
|
*/
|
|
|
|
const size_type search_start_state
|
|
= path.empty() ? start_state : path.back().transition.targetNode();
|
|
|
|
BitArray collected_acceptance_sets(number_of_acceptance_sets);
|
|
collected_acceptance_sets.clear(number_of_acceptance_sets);
|
|
operations.mergeAcceptanceInformation
|
|
(firstComponent(search_start_state),
|
|
secondComponent(search_start_state), collected_acceptance_sets);
|
|
|
|
unsigned long int number_of_collected_acceptance_sets
|
|
= collected_acceptance_sets.count(number_of_acceptance_sets);
|
|
|
|
deque<size_type> search_queue;
|
|
set<size_type> visited;
|
|
map<size_type, PathElement> shortest_path_predecessor;
|
|
|
|
size_type bfs_root = search_start_state;
|
|
|
|
continue_bfs:
|
|
search_queue.clear();
|
|
search_queue.push_back(bfs_root);
|
|
visited.clear();
|
|
visited.insert(bfs_root);
|
|
shortest_path_predecessor.clear();
|
|
|
|
while (!search_queue.empty())
|
|
{
|
|
const EdgeContainerType transitions
|
|
= ProductState(search_queue.front()).edges();
|
|
|
|
for (typename EdgeContainerType::const_iterator transition
|
|
= transitions.begin();
|
|
transition != transitions.end();
|
|
++transition)
|
|
{
|
|
const size_type target = (*transition)->targetNode();
|
|
if (scc->find(target) == scc->end())
|
|
continue;
|
|
|
|
if (visited.find(target) == visited.end())
|
|
{
|
|
visited.insert(target);
|
|
shortest_path_predecessor.insert
|
|
(make_pair(target, PathElement(search_queue.front(),
|
|
**transition)));
|
|
search_queue.push_back(target);
|
|
|
|
if (number_of_collected_acceptance_sets
|
|
< number_of_acceptance_sets)
|
|
operations.mergeAcceptanceInformation
|
|
(firstComponent(target), secondComponent(target),
|
|
collected_acceptance_sets);
|
|
}
|
|
|
|
if (number_of_collected_acceptance_sets < number_of_acceptance_sets)
|
|
{
|
|
/*
|
|
* Test whether the current product transition or the target
|
|
* state of the transition covers new acceptance sets. If
|
|
* this is the case, construct the next segment of the cycle
|
|
* and begin a new breadth-first search in the target state of
|
|
* the transition.
|
|
*/
|
|
|
|
operations.mergeAcceptanceInformation
|
|
((*transition)->firstComponent(),
|
|
(*transition)->secondComponent(), collected_acceptance_sets);
|
|
|
|
const unsigned long int num
|
|
= collected_acceptance_sets.count(number_of_acceptance_sets);
|
|
if (num > number_of_collected_acceptance_sets)
|
|
{
|
|
number_of_collected_acceptance_sets = num;
|
|
|
|
addCycleSegment(witness.cycle, search_queue.front(),
|
|
**transition, bfs_root,
|
|
shortest_path_predecessor);
|
|
|
|
if (number_of_collected_acceptance_sets
|
|
== number_of_acceptance_sets
|
|
&& target == search_start_state)
|
|
return;
|
|
|
|
bfs_root = target;
|
|
goto continue_bfs;
|
|
}
|
|
}
|
|
else if (target == search_start_state)
|
|
{
|
|
/*
|
|
* If all acceptance sets have been collected and the current
|
|
* product transition points to the first state of the cycle,
|
|
* the cycle is complete.
|
|
*/
|
|
|
|
addCycleSegment(witness.cycle, search_queue.front(), **transition,
|
|
bfs_root, shortest_path_predecessor);
|
|
return;
|
|
}
|
|
}
|
|
|
|
search_queue.pop_front();
|
|
}
|
|
|
|
throw Exception
|
|
("Product::findWitness(...): internal error [cycle construction "
|
|
"failed]");
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
void Product<Operations>::addCycleSegment
|
|
(pair<Graph<GraphEdgeContainer>::Path, Graph<GraphEdgeContainer>::Path>&
|
|
cycle,
|
|
size_type source_state_id, Edge transition, const size_type root_id,
|
|
const map<size_type, PathElement>& predecessor) const
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Helper function for constructing a segment of an accepting
|
|
* cycle in the product.
|
|
*
|
|
* Arguments: cycle -- A reference to a pair of paths for
|
|
* storing the result.
|
|
* source_state_id -- Identifier of the last product state in
|
|
* the cycle segment.
|
|
* transition -- Last product transition in the cycle
|
|
* segment.
|
|
* root_id -- Identifier of the first product state in
|
|
* the cycle segment.
|
|
* predecessor -- Mapping between states and their
|
|
* predecessors in the cycle segment.
|
|
*
|
|
* Returns: Nothing. The segment of the cycle is appended to `cycle'.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
Graph<GraphEdgeContainer>::Path first_segment;
|
|
Graph<GraphEdgeContainer>::Path second_segment;
|
|
|
|
while (1)
|
|
{
|
|
first_segment.push_front
|
|
(Graph<GraphEdgeContainer>::PathElement
|
|
(source_state_id / state_id_multiplier, transition.firstComponent()));
|
|
second_segment.push_front
|
|
(Graph<GraphEdgeContainer>::PathElement
|
|
(source_state_id % state_id_multiplier,
|
|
transition.secondComponent()));
|
|
|
|
if (source_state_id == root_id)
|
|
{
|
|
cycle.first.insert(cycle.first.end(), first_segment.begin(),
|
|
first_segment.end());
|
|
cycle.second.insert(cycle.second.end(), second_segment.begin(),
|
|
second_segment.end());
|
|
return;
|
|
}
|
|
|
|
const PathElement& p = predecessor.find(source_state_id)->second;
|
|
source_state_id = p.state;
|
|
transition = p.transition;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* Inline function definitions for template class
|
|
* Product<Operations>::ProductState.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline Product<Operations>::ProductState::ProductState
|
|
(const size_type state) : outgoing_edges(state)
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Constructor for class Product<Operations>::ProductState.
|
|
*
|
|
* Argument: state -- Identifier of a product state.
|
|
*
|
|
* Returns: Nothing.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline Product<Operations>::ProductState::~ProductState()
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Destructor for class Product<Operations>::ProductState.
|
|
*
|
|
* Arguments: None.
|
|
*
|
|
* Returns: Nothing.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline const typename Product<Operations>::EdgeContainerType&
|
|
Product<Operations>::ProductState::edges() const
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Returns an object for generating the transitions starting
|
|
* from a product state.
|
|
*
|
|
* Arguments: None.
|
|
*
|
|
* Returns: A constant reference to an object that can be used for
|
|
* generating the transitions starting from the state.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
return outgoing_edges;
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* Inline function definitions for template class
|
|
* Product<Operations>::ProductEdge.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline Product<Operations>::ProductEdge::ProductEdge
|
|
(const GraphEdgeContainer::const_iterator& e1,
|
|
const GraphEdgeContainer::const_iterator& e2)
|
|
: edge_1(e1), edge_2(e2)
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Constructor for class Product<Operations>::ProductEdge.
|
|
*
|
|
* Arguments: e1, e2 -- Iterators pointing to the components of the
|
|
* product transition.
|
|
*
|
|
* Returns: Nothing.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline Product<Operations>::ProductEdge::~ProductEdge()
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Destructor for class Product<Operations>::ProductEdge.
|
|
*
|
|
* Arguments: None.
|
|
*
|
|
* Returns: Nothing.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline const Graph<GraphEdgeContainer>::Edge&
|
|
Product<Operations>::ProductEdge::firstComponent() const
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Function for accessing the "first" component of a product
|
|
* transition.
|
|
*
|
|
* Arguments: None.
|
|
*
|
|
* Returns: A constant reference to the "first" component of the
|
|
* transition.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
return **edge_1;
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline const Graph<GraphEdgeContainer>::Edge&
|
|
Product<Operations>::ProductEdge::secondComponent() const
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Function for accessing the "second" component of a product
|
|
* transition.
|
|
*
|
|
* Arguments: None.
|
|
*
|
|
* Returns: A constant reference to the "second" component of the
|
|
* transition.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
return **edge_2;
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline typename Product<Operations>::size_type
|
|
Product<Operations>::ProductEdge::targetNode() const
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Returns the target state of a product transition.
|
|
*
|
|
* Arguments: None.
|
|
*
|
|
* Returns: Identifier of the target state of the product transition.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
return product->stateId((*edge_1)->targetNode(), (*edge_2)->targetNode());
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* Inline function definitions for template class
|
|
* Product<Operations>::ProductEdgePointer.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline Product<Operations>::ProductEdgePointer::ProductEdgePointer
|
|
(const GraphEdgeContainer::const_iterator& e1,
|
|
const GraphEdgeContainer::const_iterator& e2)
|
|
: edge(e1, e2)
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Constructor for class
|
|
* Product<Operations>::ProductEdgePointer.
|
|
*
|
|
* Arguments: e1, e2 -- Iterators pointing to the components of the
|
|
* product transition.
|
|
*
|
|
* Returns: Nothing.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline Product<Operations>::ProductEdgePointer::~ProductEdgePointer()
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Destructor for class
|
|
* Product<Operations>::ProductEdgePointer.
|
|
*
|
|
* Arguments: None.
|
|
*
|
|
* Returns: Nothing.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline const typename Product<Operations>::ProductEdge&
|
|
Product<Operations>::ProductEdgePointer::operator*() const
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Dereferencing operator for class
|
|
* Product<Operations>::ProductEdgePointer.
|
|
*
|
|
* Arguments: None.
|
|
*
|
|
* Returns: A reference to the product transition associated with the
|
|
* object.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
return edge;
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline const typename Product<Operations>::ProductEdge*
|
|
Product<Operations>::ProductEdgePointer::operator->() const
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Dereferencing operator for class
|
|
* Product<Operations>::ProductEdgePointer.
|
|
*
|
|
* Arguments: None.
|
|
*
|
|
* Returns: A pointer to the product transition associated with the
|
|
* object.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
return &edge;
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* Inline function definitions for template class
|
|
* Product<Operations>::ProductEdgeCollection.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline Product<Operations>::ProductEdgeCollection::ProductEdgeCollection
|
|
(const size_type state) : product_state(state)
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Constructor for class
|
|
* Product<Operations>::ProductEdgeCollection.
|
|
*
|
|
* Argument: state -- Identifier of a product state. The
|
|
* ProductEdgeCollection object will mimic a
|
|
* container for the product transitions starting
|
|
* from this state.
|
|
*
|
|
* Returns: Nothing.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline Product<Operations>::ProductEdgeCollection::~ProductEdgeCollection()
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Destructor for class
|
|
* Product<Operations>::ProductEdgeCollection.
|
|
*
|
|
* Arguments: None.
|
|
*
|
|
* Returns: Nothing.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline const typename Product<Operations>::ProductEdgeCollection
|
|
::const_iterator
|
|
Product<Operations>::ProductEdgeCollection::begin() const
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Returns an iterator for generating the transitions starting
|
|
* from the product state identified by `this->product_state'.
|
|
*
|
|
* Arguments: None.
|
|
*
|
|
* Returns: Nothing.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
return const_iterator
|
|
(product_state,
|
|
product->firstComponent(product_state).edges().begin(),
|
|
product->secondComponent(product_state).edges().begin());
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline const typename Product<Operations>::ProductEdgeCollection
|
|
::const_iterator
|
|
Product<Operations>::ProductEdgeCollection::end() const
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Returns an iterator pointing to the "end" of the collection
|
|
* of transitions starting from the product state identified by
|
|
* `this->product_state'.
|
|
*
|
|
* Arguments: None.
|
|
*
|
|
* Returns: Nothing.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
return const_iterator
|
|
(product_state,
|
|
product->firstComponent(product_state).edges().end(),
|
|
product->secondComponent(product_state).edges().end());
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* Inline function definitions for template class
|
|
* Product<Operations>::ProductEdgeCollection::const_iterator.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline Product<Operations>::ProductEdgeCollection::const_iterator
|
|
::const_iterator() : product_state(0)
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Default constructor for class
|
|
* Product<Operations>::ProductEdgeCollection::const_iterator.
|
|
*
|
|
* Arguments: None.
|
|
*
|
|
* Returns: Nothing.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline Product<Operations>::ProductEdgeCollection::const_iterator
|
|
::const_iterator
|
|
(const size_type state,
|
|
const GraphEdgeContainer::const_iterator& e1,
|
|
const GraphEdgeContainer::const_iterator& e2) :
|
|
product_state(state), edge_1(e1), edge_2(e2)
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Constructor for class
|
|
* Product<Operations>::ProductEdgeCollection::const_iterator.
|
|
*
|
|
* Arguments: state -- Identifier of a product state to associate with
|
|
* the iterator.
|
|
* e1, e1 -- Constant references to a pair of iterators
|
|
* pointing to a pair of transitions starting from
|
|
* the component states of the product state. These
|
|
* iterators are used to determine where to start
|
|
* iterating over the product transitions.
|
|
*
|
|
* Returns: Nothing.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
product->operations.validateEdgeIterators
|
|
(product->firstComponent(product_state),
|
|
product->secondComponent(product_state),
|
|
edge_1, edge_2);
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline Product<Operations>::ProductEdgeCollection::const_iterator
|
|
::~const_iterator()
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Destructor for class
|
|
* Product<Operations>::ProductEdgeCollection::const_iterator.
|
|
*
|
|
* Arguments: None.
|
|
*
|
|
* Returns: Nothing.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline bool Product<Operations>::ProductEdgeCollection::const_iterator
|
|
::operator==
|
|
(const const_iterator& it) const
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Equality test between two
|
|
* Product<Operations>::ProductEdgeCollection::const_iterators.
|
|
*
|
|
* Argument: it -- A constant reference to an iterator to compare for
|
|
* equality. It is assumed that the iterators are
|
|
* associated with the same product state; the result of
|
|
* a comparison between iterators associated with
|
|
* different product states is undefined.
|
|
*
|
|
* Returns: true iff `it' and `*this' point to the same transition in the
|
|
* product.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
return (it.edge_1 == edge_1 && it.edge_2 == edge_2);
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline bool Product<Operations>::ProductEdgeCollection::const_iterator
|
|
::operator!=
|
|
(const const_iterator& it) const
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Inequality test between two
|
|
* Product<Operations>::ProductEdgeCollection::const_iterators.
|
|
*
|
|
* Argument: it -- A constant reference to an iterator to compare for
|
|
* equality. It is assumed that the iterators are
|
|
* associated with the same product state; the result of
|
|
* a comparison between iterators associated with
|
|
* different product states is undefined.
|
|
*
|
|
* Returns: true iff `it' and `*this' point to different transitions in
|
|
* the product.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
return (it.edge_1 != edge_1 || it.edge_2 != edge_2);
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline const typename Product<Operations>::ProductEdgePointer
|
|
Product<Operations>::ProductEdgeCollection::const_iterator::operator*() const
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Dereferencing operator for class
|
|
* Product<Operations>::ProductEdgeCollection::const_iterator.
|
|
*
|
|
* Arguments: None.
|
|
*
|
|
* Returns: An object of type Product<Operations>::ProductEdgePointer
|
|
* that allows access to the product transition pointed to by
|
|
* the iterator.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
return ProductEdgePointer(edge_1, edge_2);
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline const typename Product<Operations>::ProductEdge
|
|
Product<Operations>::ProductEdgeCollection::const_iterator::operator->() const
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Dereferencing operator for class
|
|
* Product<Operations>::ProductEdgeCollection::const_iterator.
|
|
*
|
|
* Arguments: None.
|
|
*
|
|
* Returns: A Product<Operations>::ProductEdge corresponding to the
|
|
* product transition pointed to by the iterator.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
return ProductEdge(edge_1, edge_2);
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline const typename Product<Operations>::ProductEdgePointer
|
|
Product<Operations>::ProductEdgeCollection::const_iterator::operator++()
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Prefix increment operator for class
|
|
* Product<Operations>::ProductEdgeCollection::const_iterator.
|
|
*
|
|
* Arguments: None.
|
|
*
|
|
* Returns: An object of type Product<Operations>::ProductEdgePointer
|
|
* that behaves like a pointer to the product transition
|
|
* obtained by advancing the iterator in the sequence of product
|
|
* transitions.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
product->operations.incrementEdgeIterators
|
|
(product->firstComponent(product_state),
|
|
product->secondComponent(product_state),
|
|
edge_1, edge_2);
|
|
return ProductEdgePointer(edge_1, edge_2);
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline const typename Product<Operations>::ProductEdgePointer
|
|
Product<Operations>::ProductEdgeCollection::const_iterator::operator++(int)
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Postfix increment operator for class
|
|
* Product<Operations>::ProductEdgeCollection::const_iterator.
|
|
*
|
|
* Arguments: None.
|
|
*
|
|
* Returns: An object of type Product<Operations>::ProductEdgePointer
|
|
* that behaves like a pointer to the product transition pointed
|
|
* to by the iterator before advancing it in the sequence of
|
|
* product transitions.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
const typename Product<Operations>::ProductEdgePointer edge(edge_1, edge_2);
|
|
product->operations.incrementEdgeIterators
|
|
(product->firstComponent(product_state),
|
|
product->secondComponent(product_state),
|
|
edge_1, edge_2);
|
|
return edge;
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* Inline function definitions for template class
|
|
* Product<Operations>::PathElement.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline Product<Operations>::PathElement::PathElement
|
|
(const size_type s, const Edge& t) : state(s), transition(t)
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Constructor for class Product<Operations>::PathElement.
|
|
*
|
|
* Arguments: s, t -- Product state and transition associated with the
|
|
* element.
|
|
*
|
|
* Returns: Nothing.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline Product<Operations>::PathElement::~PathElement()
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Destructor for class Product<Operations>::PathElement.
|
|
*
|
|
* Arguments: None.
|
|
*
|
|
* Returns: Nothing.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* Inline function definitions for template class
|
|
* Product<Operations>::SizeException.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline Product<Operations>::SizeException::SizeException() :
|
|
Exception("product may be too large")
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Constructor for class Product<Operations>::SizeException.
|
|
*
|
|
* Arguments: None.
|
|
*
|
|
* Returns: Nothing.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline Product<Operations>::SizeException::~SizeException() throw()
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Destructor for class Product<Operations>::SizeException.
|
|
*
|
|
* Arguments: None.
|
|
*
|
|
* Returns: Nothing.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline typename Product<Operations>::SizeException&
|
|
Product<Operations>::SizeException::operator=
|
|
(const typename Product<Operations>::SizeException& e)
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Assignment operator for class
|
|
* Product<Operations>::SizeException. Assigns the value of
|
|
* another Product<Operations>::SizeException to `this' one.
|
|
*
|
|
* Arguments: e -- A reference to a constant object of type
|
|
* Product<Operations>SizeException.
|
|
*
|
|
* Returns: A reference to the object whose value was changed.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
Exception::operator=(e);
|
|
return *this;
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* Inline function definitions for template class
|
|
* Product<Operations>::AcceptanceTracker.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline Product<Operations>::AcceptanceTracker::AcceptanceTracker
|
|
(const unsigned long int num_accept_sets)
|
|
: number_of_acceptance_sets(num_accept_sets)
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Constructor for class Product<Operations>::AcceptanceTracker.
|
|
*
|
|
* Arguments: num_accept_sets -- Number of acceptance sets in the
|
|
* product.
|
|
*
|
|
* Returns: Nothing.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
/* Initialize `acceptance_stack' with a sentinel element. */
|
|
acceptance_stack.push_front(make_pair(0, new BitArray(0)));
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline Product<Operations>::AcceptanceTracker::~AcceptanceTracker()
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Destructor for class Product<Operations>::AcceptanceTracker.
|
|
*
|
|
* Arguments: None.
|
|
*
|
|
* Returns: Nothing.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
for (AcceptanceStack::iterator a = acceptance_stack.begin();
|
|
a != acceptance_stack.end();
|
|
++a)
|
|
delete a->second;
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline void Product<Operations>::AcceptanceTracker::addEdgeToComponent
|
|
(const typename Product<Operations>::Edge& t,
|
|
const typename Product<Operations>::size_type scc_id)
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Adds the acceptance sets of the product transition `t'
|
|
* (inside a strongly connected product component) to the
|
|
* collection of acceptance sets associated with the strongly
|
|
* connected component identifier (a dfs number of a product
|
|
* state in Tarjan's algorithm). (The component is therefore
|
|
* nontrivial, because it contains a transition.) This is done
|
|
* as described by Couvreur
|
|
* [J.-M. Couvreur. On-the-fly verification of linear
|
|
* temporal logic. In Proceedings of the FM'99 World
|
|
* Congress on Formal Methods in the Development of
|
|
* Computing Systems, Volume I, LNCS 1708, pp. 253--271.
|
|
* Springer-Verlag, 1999]
|
|
* by first collapsing all elements in the top part of
|
|
* `this->acceptance_stack' (*) with strongly connected
|
|
* component identifiers greater than or equal to `scc_id' into
|
|
* a single element by taking the union of their acceptance sets
|
|
* and then merging the acceptance sets of the transition `t'
|
|
* with this element.
|
|
* After the call, the top element of `this->acceptance_stack'
|
|
* will have the scc id `scc_id', and `this->acceptance_sets'
|
|
* points to the acceptance sets associated with this stack
|
|
* element.
|
|
*
|
|
* (*) It is assumed that the contents of
|
|
* `this->acceptance_stack' form (from top to bottom) a sequence
|
|
* of elements (id1,a1), (id2,a2), (id3,a3), ..., where
|
|
* id1 > id2 > id3 > ... . The function maintains this
|
|
* invariant.
|
|
*
|
|
* Arguments: t -- A constant reference to the product transition.
|
|
* scc_id -- Identifier of the strongly connected component
|
|
* (assumed to be >= 1).
|
|
*
|
|
* Returns: Nothing.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
acceptance_sets = 0;
|
|
while (acceptance_stack.front().first >= scc_id)
|
|
{
|
|
if (acceptance_sets != 0)
|
|
{
|
|
acceptance_stack.front().second->bitwiseOr
|
|
(*acceptance_sets, number_of_acceptance_sets);
|
|
delete acceptance_sets;
|
|
}
|
|
acceptance_sets = acceptance_stack.front().second;
|
|
if (acceptance_stack.front().first == scc_id)
|
|
goto merge_sets;
|
|
|
|
acceptance_stack.pop_front();
|
|
}
|
|
|
|
if (acceptance_sets == 0)
|
|
{
|
|
acceptance_sets = new BitArray(number_of_acceptance_sets);
|
|
acceptance_sets->clear(number_of_acceptance_sets);
|
|
}
|
|
acceptance_stack.push_front(make_pair(scc_id, acceptance_sets));
|
|
merge_sets:
|
|
product->operations.mergeAcceptanceInformation
|
|
(t.firstComponent(), t.secondComponent(), *acceptance_sets);
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline void Product<Operations>::AcceptanceTracker::addNodeToComponent
|
|
(const typename Product<Operations>::size_type state_id,
|
|
const typename Product<Operations>::size_type scc_id)
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Adds the acceptance sets of the product state `state_id' to
|
|
* the collection of acceptance sets associated with a
|
|
* nontrivial strongly connected component identifier (a dfs
|
|
* number of a product state in Tarjan's algorithm).
|
|
*
|
|
* Arguments: state_id -- Identifier of the product state.
|
|
* scc_id -- Identifier of the strongly connected component
|
|
* (assumed to be >= 1).
|
|
*
|
|
* Returns: Nothing. Upon return, `this->acceptance_sets' either points
|
|
* to the acceptance sets associated with the topmost element of
|
|
* `this->acceptance_sets', or, if the component is a
|
|
* trivial strongly connected component,
|
|
* `this->acceptance_sets == 0'.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
/*
|
|
* When this function gets called, then depth-first search guarantees that
|
|
* the strongly connected component identifier of the topmost element (if
|
|
* such an element exists) of `this->acceptance_stack' is <= 'scc_id'.
|
|
* Furthermore, the strongly connected is nontrivial only if equality holds
|
|
* in the above test.
|
|
*/
|
|
|
|
if (acceptance_stack.front().first < scc_id)
|
|
{
|
|
acceptance_sets = 0;
|
|
return;
|
|
}
|
|
|
|
acceptance_sets = acceptance_stack.front().second;
|
|
product->operations.mergeAcceptanceInformation
|
|
(product->firstComponent(state_id), product->secondComponent(state_id),
|
|
*acceptance_sets);
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline void Product<Operations>::AcceptanceTracker::endComponent
|
|
(const typename Product<Operations>::size_type scc_id)
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Removes the association between a nontrivial strongly
|
|
* connected component identifier and a collection of acceptance
|
|
* sets when the component is not needed any longer. (This
|
|
* function gets called after extracting a maximal strongly
|
|
* connected component from the product. It is safe to remove
|
|
* the association at this point, because the search will not
|
|
* enter the component afterwards, nor can any state visited
|
|
* in the future belong to the strongly connected component
|
|
* identified by `scc_id'.)
|
|
*
|
|
* Argument: scc_id -- Identifier of the strongly connected component.
|
|
*
|
|
* Returns: Nothing.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
/*
|
|
* Because the depth-first search made a call to `addNodeToComponent' before
|
|
* extracting the component from the product, the topmost element (if any)
|
|
* of `this->acceptance_stack' is guaranteed to have scc id <= `scc_id' at
|
|
* this point.
|
|
*/
|
|
|
|
if (acceptance_stack.front().first == scc_id)
|
|
{
|
|
delete acceptance_stack.front().second;
|
|
acceptance_stack.pop_front();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* Inline function definitions for template class
|
|
* Product<Operations>::SimpleEmptinessChecker.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline Product<Operations>::SimpleEmptinessChecker::SimpleEmptinessChecker
|
|
(const unsigned long int num_accept_sets)
|
|
: AcceptanceTracker(num_accept_sets), dummy(0)
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Constructor for class
|
|
* Product<Operations>::SimpleEmptinessChecker.
|
|
*
|
|
* Arguments: num_accept_sets -- Number of acceptance sets in the
|
|
* product.
|
|
*
|
|
* Returns: Nothing.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline Product<Operations>::SimpleEmptinessChecker::~SimpleEmptinessChecker()
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Destructor for class
|
|
* Product<Operations>::SimpleEmptinessChecker.
|
|
*
|
|
* Arguments: None.
|
|
*
|
|
* Returns: Nothing.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline const typename Product<Operations>::SimpleEmptinessChecker::SccType&
|
|
Product<Operations>::SimpleEmptinessChecker::operator()() const
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Dummy function required for supporting the expected class
|
|
* interface.
|
|
*
|
|
* Arguments: None.
|
|
*
|
|
* Returns: A constant reference to `this->dummy'.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
return dummy;
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline void Product<Operations>::SimpleEmptinessChecker::addEdgeToComponent
|
|
(const typename Product<Operations>::Edge& t,
|
|
const typename Product<Operations>::size_type scc_id)
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Adds a transition to a nontrivial strongly connected product
|
|
* component and aborts the search if the addition of the
|
|
* transition in the component makes the component accepting.
|
|
*
|
|
* Arguments: t -- A constant reference to the product transition to
|
|
* be added to the component.
|
|
* scc_id -- Identifier of the strongly connected component.
|
|
*
|
|
* Returns: Nothing; aborts the search by throwing the constant 0 if the
|
|
* addition of the transition in the component makes the
|
|
* component accepting.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
AcceptanceTracker::addEdgeToComponent(t, scc_id);
|
|
/* `this->acceptance_sets' points to the acceptance sets associated with
|
|
* the nontrivial SCC `scc_id' at this point. */
|
|
abortIfNonempty();
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline void Product<Operations>::SimpleEmptinessChecker::addNodeToComponent
|
|
(const typename Product<Operations>::size_type state,
|
|
const typename Product<Operations>::size_type scc_id)
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Adds a state to a nontrivial strongly connected product
|
|
* component and aborts the search if the addition of the state
|
|
* in the component makes the component accepting.
|
|
*
|
|
* Arguments: state -- Identifier of a product state to be added to the
|
|
* component.
|
|
* scc_id -- Identifier of the strongly connected component.
|
|
*
|
|
* Returns: Nothing; aborts the search by throwing the constant 0 if the
|
|
* addition of the state in the component makes the component
|
|
* accepting.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
AcceptanceTracker::addNodeToComponent(state, scc_id);
|
|
/* If `this->acceptance_sets != 0', then `this->acceptance_sets' points to
|
|
* the acceptance sets associated with the nontrivial SCC `scc_id';
|
|
* otherwise the component `scc_id' is a trivial SCC. */
|
|
if (this->acceptance_sets != 0)
|
|
abortIfNonempty();
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline void Product<Operations>::SimpleEmptinessChecker::abortIfNonempty()
|
|
const
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Tests whether the strongly connected component with
|
|
* acceptance sets pointed to by `this->acceptance_sets' is an
|
|
* accepting component. This holds if all bits in the
|
|
* acceptance set bit vector pointed to by
|
|
* `this->acceptance_sets' are set to 1.
|
|
*
|
|
* Arguments: None.
|
|
*
|
|
* Returns: Nothing; throws the constant 0 if the component with
|
|
* acceptance sets pointed to by `this->acceptance_sets' is an
|
|
* accepting strongly connected component.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
if (this->acceptance_sets->count(this->number_of_acceptance_sets)
|
|
== this->number_of_acceptance_sets)
|
|
throw 0;
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* Inline function definitions for template class
|
|
* Product<Operations>::AcceptanceReachabilityTracker.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline Product<Operations>::AcceptanceReachabilityTracker
|
|
::AcceptanceReachabilityTracker
|
|
(const unsigned long int num_accept_sets) :
|
|
AcceptanceTracker(num_accept_sets), number_of_states(0),
|
|
number_of_transitions(0), mark_scc(false), dummy(0)
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Constructor for class
|
|
* Product<Operations>::AcceptanceReachabilityTracker.
|
|
*
|
|
* Arguments: num_accept_sets -- Number of acceptance sets in the
|
|
* product.
|
|
*
|
|
* Returns: Nothing.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline Product<Operations>::AcceptanceReachabilityTracker
|
|
::~AcceptanceReachabilityTracker()
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Destructor for class
|
|
* Product<Operations>::AcceptanceReachabilityTracker.
|
|
*
|
|
* Arguments: None.
|
|
*
|
|
* Returns: Nothing.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline
|
|
const typename Product<Operations>::AcceptanceReachabilityTracker::SccType&
|
|
Product<Operations>::AcceptanceReachabilityTracker::operator()() const
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Dummy function required for supporting the expected class
|
|
* interface.
|
|
*
|
|
* Arguments: None.
|
|
*
|
|
* Returns: A constant reference to `this->dummy'.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
return dummy;
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline void Product<Operations>::AcceptanceReachabilityTracker::enter
|
|
(const typename Product<Operations>::size_type)
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Function called when entering a new state in the product.
|
|
* Increments the number of product states that have been
|
|
* explored.
|
|
*
|
|
* Arguments: The single argument is required to support the expected class
|
|
* interface.
|
|
*
|
|
* Returns: Nothing.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
++number_of_states;
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline void Product<Operations>::AcceptanceReachabilityTracker::backtrack
|
|
(const typename Product<Operations>::size_type source,
|
|
const typename Product<Operations>::Edge&,
|
|
const typename Product<Operations>::size_type target)
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Function called when backtracking from a state in the
|
|
* product. Increments the number of product edges that have
|
|
* been explored. Additionally, if the state from which the
|
|
* search backtracks belongs to the set of states from which an
|
|
* accepting strongly connected component is known to be
|
|
* reachable in the product, adds also the state to which the
|
|
* search backtracks into this set of states.
|
|
*
|
|
* Arguments: (source, target) describe the endpoints of the product
|
|
* transition along which the backtrack occurs (i.e., `source'
|
|
* is the state _to_ which the search backtracks). The second
|
|
* argument is only needed to support the expected function call
|
|
* interface.
|
|
*
|
|
* Returns: Nothing.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
++number_of_transitions;
|
|
if (isMarked(target))
|
|
markState(source);
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline void Product<Operations>::AcceptanceReachabilityTracker::touch
|
|
(const typename Product<Operations>::size_type source,
|
|
const typename Product<Operations>::Edge& edge,
|
|
const typename Product<Operations>::size_type target)
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Function called when the search encounters an edge with a
|
|
* target node that has already been explored. Increments the
|
|
* number of explored product transitions and updates accepting
|
|
* strongly connected reachability information by calling
|
|
* `this->backtrack()'. (This function is needed for supporting
|
|
* the expected class interface.)
|
|
*
|
|
* Arguments: (source, edge, target) describe the product transition that
|
|
* "touches" the state `target'.
|
|
*
|
|
* Returns: Nothing.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
backtrack(source, edge, target);
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline void Product<Operations>::AcceptanceReachabilityTracker::beginComponent
|
|
(const typename Product<Operations>::size_type,
|
|
const typename Product<Operations>::size_type state_id)
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Tests whether the maximal strongly connected component that
|
|
* is about to be extracted from the product is an accepting
|
|
* component, or if the component contains a state from which
|
|
* such a component is known to be reachable. If either of
|
|
* these properties holds, `this->mark_scc' is set to true to
|
|
* cause all states referred to in subsequent calls to
|
|
* `this->insert' that occur before the next call to
|
|
* `this->endComponent' to be added into the set of states from
|
|
* which an accepting strongly connected component in the
|
|
* product is known to be reachable.
|
|
*
|
|
* A component is accepting iff `this->acceptance_sets' points
|
|
* to a bit vector in which all bits are set to 1.
|
|
*
|
|
* Arguments: state_id -- Identifier of a product state (in the
|
|
* component) that was encountered first during
|
|
* the search.
|
|
* The first argument is needed to support the expected function
|
|
* interface.
|
|
*
|
|
* Returns: Nothing.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
if (isMarked(state_id)) /* If the component itself is not accepting, but */
|
|
mark_scc = true; /* it contains a state from which such a component */
|
|
/* is reachable, then the fact that `state_id' is */
|
|
/* the first state of the component encountered */
|
|
/* during the search and the operation of the */
|
|
/* backtrack and touch functions guarantee that */
|
|
/* `isMarked(state_id) == true' holds at this */
|
|
/* point (the search is about to backtrack from */
|
|
/* this state when this function gets called). */
|
|
else /* test whether the component is an accepting component */
|
|
{
|
|
/*
|
|
* The dfs search guarantees (by having made a call to
|
|
* AcceptanceTracker::addNodeToComponent before calling this function) that
|
|
* `this->acceptance_sets' is either equal to 0 (in which case the
|
|
* component to be extracted is trivial), or it points to the acceptance
|
|
* sets associated with the component to be extracted.
|
|
*/
|
|
mark_scc = (this->acceptance_sets != 0
|
|
&& this->acceptance_sets->count
|
|
(this->number_of_acceptance_sets)
|
|
== this->number_of_acceptance_sets);
|
|
}
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline void Product<Operations>::AcceptanceReachabilityTracker::insert
|
|
(const typename Product<Operations>::size_type state)
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: If `this->mark_scc == true', inserts a product state
|
|
* identifier to the set of states from which an accepting
|
|
* strongly connected component is known to be reachable in the
|
|
* product. Discards the state otherwise.
|
|
*
|
|
* Argument: state -- Identifier of a product state.
|
|
*
|
|
* Returns: Nothing.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
if (mark_scc)
|
|
markState(state);
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline bool Product<Operations>::AcceptanceReachabilityTracker::isMarked
|
|
(const typename Product<Operations>::size_type state) const
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Tells whether an accepting strongly connected component is
|
|
* known to be reachable from a state in the product.
|
|
*
|
|
* Argument: state -- Identifier of the product state to test.
|
|
*
|
|
* Returns: true iff an accepting strongly connected component is known
|
|
* to be reachable from the product state.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
return (reachability_info.find(state) != reachability_info.end());
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline typename Product<Operations>::size_type
|
|
Product<Operations>::AcceptanceReachabilityTracker::numberOfStates() const
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Tells the number of product states explored during the
|
|
* search.
|
|
*
|
|
* Arguments: None.
|
|
*
|
|
* Returns: Number of product states explored.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
return number_of_states;
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline unsigned long int
|
|
Product<Operations>::AcceptanceReachabilityTracker::numberOfTransitions() const
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Tells the number of product transitions explored during the
|
|
* search.
|
|
*
|
|
* Arguments: None.
|
|
*
|
|
* Returns: Number of transitions explored.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
return number_of_transitions;
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline void Product<Operations>::AcceptanceReachabilityTracker::markState
|
|
(const typename Product<Operations>::size_type state)
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Adds a product state to the set of states from which an
|
|
* accepting strongly connected component is known to be
|
|
* reachable in the product.
|
|
*
|
|
* Argument: state -- Identifier of a product state.
|
|
*
|
|
* Returns: Nothing.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
reachability_info.insert(state);
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* Inline function definitions for template class
|
|
* Product<Operations>::AcceptingComponentFinder.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline Product<Operations>::AcceptingComponentFinder::AcceptingComponentFinder
|
|
(const unsigned long int num_accept_sets)
|
|
: AcceptanceTracker(num_accept_sets), construct_component(false)
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Constructor for class
|
|
* Product<Operations>::AcceptingComponentFinder.
|
|
*
|
|
* Arguments: num_accept_sets -- Number of acceptance sets in the
|
|
* product.
|
|
*
|
|
* Returns: Nothing.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline Product<Operations>::AcceptingComponentFinder
|
|
::~AcceptingComponentFinder()
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Destructor for class
|
|
* Product<Operations>::AcceptingComponentFinder.
|
|
*
|
|
* Arguments: None.
|
|
*
|
|
* Returns: Nothing.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline const typename Product<Operations>::AcceptingComponentFinder::SccType&
|
|
Product<Operations>::AcceptingComponentFinder::operator()() const
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Returns the latest accepting maximal strongly connected
|
|
* component found in the product.
|
|
*
|
|
* Arguments: None.
|
|
*
|
|
* Returns: A constant reference to a set of states containing the
|
|
* identifiers of product states forming an accepting maximal
|
|
* strongly connected component in the product. This set is
|
|
* empty if no such component has yet been found during the
|
|
* emptiness check.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
return scc;
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline void Product<Operations>::AcceptingComponentFinder::beginComponent
|
|
(const typename Product<Operations>::size_type,
|
|
const typename Product<Operations>::size_type)
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: Tests whether the maximal strongly connected component that
|
|
* is about to be extracted from the product is an accepting
|
|
* component. If this is the case, `this->construct_component'
|
|
* is set to true to cause all states referred to in subsequent
|
|
* calls to `this->insert' that occur before the next call to
|
|
* `this->endComponent' to be inserted into `this->scc'.
|
|
*
|
|
* A component is accepting iff `this->acceptance_sets' points
|
|
* to a bit vector in which all bits are set to 1.
|
|
*
|
|
* Arguments: The arguments are required to support the expected class
|
|
* interface.
|
|
*
|
|
* Returns: Nothing.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
scc.clear();
|
|
/*
|
|
* The dfs search guarantees (by having made a call to
|
|
* AcceptanceTracker::addNodeToComponent before calling this function) that
|
|
* `this->acceptance_sets' is either equal to 0 (in which case the component
|
|
* to be extracted is trivial), or it points to the acceptance sets
|
|
* associated with the component to be extracted.
|
|
*/
|
|
construct_component = (this->acceptance_sets != 0
|
|
&& this->acceptance_sets->count
|
|
(this->number_of_acceptance_sets)
|
|
== this->number_of_acceptance_sets);
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
template <class Operations>
|
|
inline void Product<Operations>::AcceptingComponentFinder::insert
|
|
(const typename Product<Operations>::size_type state)
|
|
/* ----------------------------------------------------------------------------
|
|
*
|
|
* Description: If `this->construct_component == true', inserts a product
|
|
* state identifier to the set of identifiers representing an
|
|
* accepting maximal strongly connected component. Discards the
|
|
* state otherwise.
|
|
*
|
|
* Argument: state -- Identifier of a product state.
|
|
*
|
|
* Returns: Nothing.
|
|
*
|
|
* ------------------------------------------------------------------------- */
|
|
{
|
|
if (construct_component)
|
|
scc.insert(state);
|
|
}
|
|
|
|
}
|
|
|
|
#endif /* !PRODUCT_H */
|