// Product automaton -*- c++ -*-

#ifndef PRODUCT_H_
# define PRODUCT_H_
# ifdef __GNUC__
#  pragma interface
# endif // __GNUC__

# include "typedefs.h"

# include <map>
# include <stack>
# include "s_list.h"
# include <assert.h>

/** @file Product.h
 * Product of reachability graph and the negation of property being verified
 */

/* Copyright © 1999-2002 Marko Mäkelä (msmakela@tcs.hut.fi).
   Copyright © 1999-2001 Timo Latvala (timo@tcs.hut.fi).

   This file is part of MARIA, a reachability analyzer and model checker
   for high-level Petri nets.

   MARIA 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, or (at your option)
   any later version.

   MARIA 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.

   The GNU General Public License is often shipped with GNU software, and
   is generally kept in a file called COPYING or LICENSE.  If you do not
   have a copy of the license, write to the Free Software Foundation,
   59 Temple Place, Suite 330, Boston, MA 02111 USA. */

/** Product automaton */
class Product
{
public:
  /** Product automaton state */
  class State
  {
  public:
    /** Default constructor */
    State (): rg (0), prop (0) {}
    /** Constructor
     * @param rg_	number of the reachability graph state
     * @param prop_	number of the property automaton state
     */
    State (card_t rg_, unsigned prop_) : rg (rg_), prop (prop_) {}
    /** Copy constructor */
    State (const class State& old) : rg (old.rg), prop (old.prop) {}
    /** Assignment operator */
    class State& operator= (const class State& old) {
      rg = old.rg, prop = old.prop; return *this;
    }
    /** Destructor */
    ~State () {}
    /** Equality comparison */
    bool operator== (const class State& other) const {
      return rg == other.rg && prop == other.prop;
    }
    /** Less-than comparison */
    bool operator< (const class State& other) const {
      return rg < other.rg || (rg == other.rg && prop < other.prop);
    }

    /** Get the hash value */
    size_t operator() () const;

    /** Reachability graph state number */
    card_t rg;
    /** Property automaton state number */
    unsigned prop;
  };
  /** Tarjan state */
  class Tarjan
  {
  public:
    /** Default constructor */
    Tarjan () : state (), depth (0), numSucc (0) {}
    /** Constructor
     * @param state_	product automaton state
     * @param depth_	search depth
     * @param numSucc_	number of enabled gates
     */
    Tarjan (const class State& state_,
	    unsigned depth_,
	    unsigned numSucc_) :
      state (state_), depth (depth_), numSucc (numSucc_) {}
    /** Copy constructor */
    Tarjan (const class Tarjan& old) :
      state (old.state), depth (old.depth), numSucc (old.numSucc) {}
    /** Assignment operator */
    class Tarjan& operator= (const class Tarjan& old) {
      state = old.state, depth = old.depth, numSucc = old.numSucc;
      return *this;
    }
    /** Destructor */
    ~Tarjan () {}

    /** product automaton state */
    class State state;
    /** search depth */
    unsigned depth;
    /** number of enabled gates */
    unsigned numSucc;
  };

  /** Stack of product automaton states */
  typedef slist<class State> StateStack;
  /** Stack of states of the strongly connected component algorithm */
  typedef slist<class Tarjan> TarjanStack;
  /** Map of product automaton states to nonzero search depths */
  typedef std::map<class State,unsigned> StateMap;

public:
  /** Constructor
   * @param reporter	interface to the reachability graph
   * @param prop	the property automaton
   */
  Product (class GraphReporter& reporter,
	   const class Property& prop) :
    myReporter (reporter), myProp (prop) {}
private:
  /** Copy constructor */
  Product (const class Product& old);
  /** Assignment operator */
  class Product& operator= (const class Product& old);
public:
  /** Destructor */
  ~Product () {}

  /** Check whether the property expressed by the property automaton holds,
   * calculating the product of the reachability graph and the automaton,
   * performing on-the-fly analysis
   * @param state	number of the state where to start the analysis
   * @return		the counterexample path, or NULL if the propery holds
   */
  card_t* analyze (card_t state) const;

private:
  /** The reachability graph */
  class GraphReporter& myReporter;
  /** The property automaton */
  const class Property& myProp;
};

#endif // PRODUCT_H_
