/* * Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 * Heikki Tauriainen * * 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 BUCHIPRODUCT_H #define BUCHIPRODUCT_H #include #include #include #include #include #include #include "BitArray.h" #include "BuchiAutomaton.h" #include "EdgeContainer.h" #include "Graph.h" #include "LtlFormula.h" using namespace std; namespace Graph { /****************************************************************************** * * A class with operations for checking the intersection of two Büchi automata * (represented as two BuchiAutomaton objects) for emptiness. * *****************************************************************************/ class BuchiProduct { public: BuchiProduct /* Constructor. */ (const Graph& a1, const Graph& a2); /* default copy constructor */ ~BuchiProduct(); /* Destructor. */ /* default assignment operator */ bool empty() const; /* Tells whether the * intersection of the * Büchi automata * associated with the * product object is * (trivially) empty. */ unsigned long int numberOfAcceptanceSets() const; /* Tells the number of * acceptance sets in the * intersection of the * automata associated with * the object. */ const BuchiAutomaton::BuchiState& firstComponent /* Mappings between an */ (const Graph::size_type /* intersection state */ state_id) const; /* identifier and states */ const BuchiAutomaton::BuchiState& secondComponent /* of the underlying */ (const Graph::size_type /* automata. */ state_id) const; void mergeAcceptanceInformation /* Merges the acceptance */ (const Graph::Node& state1, /* sets associated with */ const Graph::Node& state2, /* a pair of states into */ BitArray& acceptance_sets) const; /* a collection of sets. */ void mergeAcceptanceInformation /* Merges the acceptance */ (const Graph::Edge& /* sets associated with */ transition1, /* a pair of */ const Graph::Edge& /* transitions into a */ transition2, /* collection of sets. */ BitArray& acceptance_sets) const; void validateEdgeIterators /* Ensures that a pair */ (const Graph::Node& /* of transition */ state_1, /* iterators points to a */ const Graph::Node& /* transition beginning */ state_2, /* from a given state in */ GraphEdgeContainer::const_iterator& /* the intersection of */ transition_1, /* two Büchi automata. */ GraphEdgeContainer::const_iterator& transition_2); void incrementEdgeIterators /* Updates a pair of */ (const Graph::Node& /* transition iterators */ state_1, /* to make them point to */ const Graph::Node& /* the "next" transition */ state_2, /* starting from a given */ GraphEdgeContainer::const_iterator& /* state in the */ transition_1, /* intersection of two */ GraphEdgeContainer::const_iterator& /* Büchi automata. */ transition_2); static void clearSatisfiabilityCache(); /* Clears information about * the satisfiability of * the guards of product * transitions. */ private: void mergeAcceptanceInformation /* Bitwise or between */ (const BitArray& sets1, const BitArray& sets2, /* two "component" */ BitArray& result) const; /* acceptance set * vectors and a result * vector. */ bool synchronizable /* Tests whether a pair */ (const Graph::Edge& /* of transitions of two */ transition_1, /* Büchi automata is */ const Graph::Edge& /* synchronizable. */ transition_2); const BuchiAutomaton& automaton_1; /* Automata associated */ const BuchiAutomaton& automaton_2; /* with the BuchiProduct */ /* object. */ const unsigned long int /* Number of acceptance */ number_of_acceptance_sets; /* sets in the * intersection of the * automata. */ typedef map< ::Ltl::LtlFormula*, bool, /* Type definition for */ less< ::Ltl::LtlFormula*>, /* storing information */ ALLOC(bool) > /* about the */ SatisfiabilityMapping; /* satisfiability of the * guards of product * transitions. */ static map< ::Ltl::LtlFormula*, /* Result cache for */ SatisfiabilityMapping, /* satisfiability tests. */ less< ::Ltl::LtlFormula*>, ALLOC(SatisfiabilityMapping) > sat_cache; }; /****************************************************************************** * * Inline function definitions for class BuchiProduct. * *****************************************************************************/ /* ========================================================================= */ inline BuchiProduct::BuchiProduct (const Graph& a1, const Graph& a2) : automaton_1(static_cast(a1)), automaton_2(static_cast(a2)), number_of_acceptance_sets(static_cast(a1) .numberOfAcceptanceSets() + static_cast(a2) .numberOfAcceptanceSets()) /* ---------------------------------------------------------------------------- * * Description: Constructor for class BuchiProduct. Initializes a new object * with operations for checking the emptiness of two Büchi * automata. * * Arguments: a1, a2 -- Constant references to two * Graph objects, assumed to be * BüchiAutomaton objects to which to apply the * operations. * * Returns: Nothing. * * ------------------------------------------------------------------------- */ { } /* ========================================================================= */ inline BuchiProduct::~BuchiProduct() /* ---------------------------------------------------------------------------- * * Description: Destructor for class BuchiProduct. * * Arguments: None. * * Returns: Nothing. * * ------------------------------------------------------------------------- */ { } /* ========================================================================= */ inline bool BuchiProduct::empty() const /* ---------------------------------------------------------------------------- * * Description: Tells whether the intersection of the Büchi automata * associated with a BuchiProduct object is (trivially) empty. * * Arguments: None. * * Returns: true iff either of the automata associated with the * BuchiProduct object is (trivially) empty (i.e., whether * either of the automata has no states). * * ------------------------------------------------------------------------- */ { return (automaton_1.empty() || automaton_2.empty()); } /* ========================================================================= */ inline unsigned long int BuchiProduct::numberOfAcceptanceSets() const /* ---------------------------------------------------------------------------- * * Description: Tells the number of acceptance sets in the intersection of * the two Büchi automata associated with a BuchiProduct object. * * Arguments: None. * * Returns: The number of acceptance sets in the intersection. * * ------------------------------------------------------------------------- */ { return number_of_acceptance_sets; } /* ========================================================================= */ inline const BuchiAutomaton::BuchiState& BuchiProduct::firstComponent (const Graph::size_type state_id) const /* ---------------------------------------------------------------------------- * * Description: Function for accessing states of the "first" component * automaton in the intersection of two Büchi automata. * * Argument: state_id -- Identifier of a state in the component * automaton. * * Returns: A constant reference to a state in the component automaton. * * ------------------------------------------------------------------------- */ { return automaton_1[state_id]; } /* ========================================================================= */ inline const BuchiAutomaton::BuchiState& BuchiProduct::secondComponent (const Graph::size_type state_id) const /* ---------------------------------------------------------------------------- * * Description: Function for accessing states of the "second" component * automaton in the intersection of two Büchi automata. * * Argument: state_id -- Identifier of a state in the component * automaton. * * Returns: A constant reference to a state in the component automaton. * * ------------------------------------------------------------------------- */ { return automaton_2[state_id]; } /* ========================================================================= */ inline void BuchiProduct::mergeAcceptanceInformation (const Graph::Node& state1, const Graph::Node& state2, BitArray& acceptance_sets) const /* ---------------------------------------------------------------------------- * * Description: Merges the acceptance sets associated with a pair of states * of two Büchi automata into a collection of sets. * * Arguments: state1, state2 -- Constant references to the states of the * automata. * acceptance_sets -- A reference to a BitArray for storing * the result. The BitArray is assumed to * have capacity for * `this->number_of_acceptance_sets' bits. * * Returns: Nothing. Let n=`this->automaton_1.numberOfAcceptanceSets()'; * after the operation, `acceptance_sets[i] = true' holds if * either * 0 <= i < n and * `state1.acceptanceSets().test(i) == true' * or 0 <= i - n < `this->automaton_2.numberOfAcceptanceSets()' * and `state2.acceptanceSets().test(i - n) == true'. * * ------------------------------------------------------------------------- */ { mergeAcceptanceInformation (static_cast(state1).acceptanceSets(), static_cast(state2).acceptanceSets(), acceptance_sets); } /* ========================================================================= */ inline void BuchiProduct::mergeAcceptanceInformation (const Graph::Edge& transition1, const Graph::Edge& transition2, BitArray& acceptance_sets) const /* ---------------------------------------------------------------------------- * * Description: Merges the acceptance sets associated with a pair of * transitions of two Büchi automata into a collection of * acceptance sets. * * Arguments: transition1, -- Constant references to the transitions * transition2 of the automata. * acceptance_sets -- A reference to a BitArray for storing * the result. The BitArray is assumed to * have capacity for * `this->number_of_acceptance_sets' bits. * * Returns: Nothing. Let n=`this->automaton_1.numberOfAcceptanceSets()'; * after the operation, `acceptance_sets[i] = true' holds if * either * 0 <= i < n and * `transition1.acceptanceSets().test(i) == true' * or 0 <= i - n < `this->automaton_2.numberOfAcceptanceSets()' * and `transition2.acceptanceSets().test(i - n) == true'. * * ------------------------------------------------------------------------- */ { mergeAcceptanceInformation (static_cast(transition1) .acceptanceSets(), static_cast(transition2) .acceptanceSets(), acceptance_sets); } /* ========================================================================= */ inline void BuchiProduct::mergeAcceptanceInformation (const BitArray& sets1, const BitArray& sets2, BitArray& result) const /* ---------------------------------------------------------------------------- * * Description: Bitwise or between two acceptance set vectors and a result * vector. * * Arguments: sets1, -- Constant references to two BitArrays having (at * sets2 least) capacities * `automaton_1.numberOfAcceptanceSets()' and * `automaton_2.numberOfAcceptanceSets()', * respectively. * result -- A BitArray for storing the result, assumed to * have room for at least * `this->number_of_acceptance_sets' bits. * * Returns: Nothing. Let n=`this->automaton_1.numberOfAcceptanceSets()'; * after the operation, `result[i] = true' holds if * either * 0 <= i < n and `sets1[i] == true' * or 0 <= i - n < `this->automaton_2.numberOfAcceptanceSets()' * and `sets2[i - n] == true'. * * ------------------------------------------------------------------------- */ { const unsigned long int shift = automaton_1.numberOfAcceptanceSets(); unsigned long int acceptance_set; for (acceptance_set = 0; acceptance_set < shift; ++acceptance_set) { if (sets1[acceptance_set]) result.setBit(acceptance_set); } for ( ; acceptance_set < number_of_acceptance_sets; ++acceptance_set) { if (sets2[acceptance_set - shift]) result.setBit(acceptance_set); } } /* ========================================================================= */ inline void BuchiProduct::validateEdgeIterators (const Graph::Node& state_1, const Graph::Node& state_2, GraphEdgeContainer::const_iterator& transition_1, GraphEdgeContainer::const_iterator& transition_2) /* ---------------------------------------------------------------------------- * * Description: Checks whether a pair of transition iterators corresponds to * a transition beginning from a state in the intersection of * two Büchi automata; if this is not the case, increments the * iterators to make them point to a valid transition beginning * from the state in the intersection (or to the "end" of the * collection of transitions beginning from the state if no * valid transition can be found by incrementing the iterators). * * Arguments: state_1, -- These variables determine the state in * state_2 the intersection automaton; `state_1' and * `state_2' should both be references to * BuchiAutomaton::BuchiState objects. * transition_1, -- References to the transition iterators. * transition_2 Initially, `transition_1' and * `transition_2' should point to two * transitions starting from `state_1' and * `state_2', respectively. * * Returns: Nothing. Upon return, `transition_1' and `transition_2' will * either equal `state_1.edges().end()' and * `state_2.edges().end()', respectively, or they will point to * a pair of transitions beginning from `state_1' and `state_2' * such that this pair of transitions corresponds to a * transition starting from the intersection state determined by * `state_1' and `state_2'. * * ------------------------------------------------------------------------- */ { const GraphEdgeContainer& transitions_1 = state_1.edges(); const GraphEdgeContainer& transitions_2 = state_2.edges(); if (transition_1 == transitions_1.end()) { transition_2 = transitions_2.end(); return; } if (transition_2 == transitions_2.end()) { transition_1 = transitions_1.end(); return; } if (!synchronizable(**transition_1, **transition_2)) incrementEdgeIterators(state_1, state_2, transition_1, transition_2); } /* ========================================================================= */ inline void BuchiProduct::incrementEdgeIterators (const Graph::Node& state_1, const Graph::Node& state_2, GraphEdgeContainer::const_iterator& transition_1, GraphEdgeContainer::const_iterator& transition_2) /* ---------------------------------------------------------------------------- * * Description: Increments a pair of transition iterators to point to the * "next" transition beginning from a state in the intersection * of two Büchi automata. If no "next" transition exists, makes * the iterators point to the "end" of the collection of * transitions beginning from the state. * * Arguments: state_1, -- These variables determine the state in * state_2 the intersection automaton; `state_1' and * `state_2' should both be references to * BuchiAutomaton::BuchiState objects. * transition_1, -- References to the transition iterators. * transition_2 Initially, `transition_1' and * `transition_2' should point to two * transitions starting from `state_1' and * `state_2', respectively. * * Returns: Nothing. Upon return, `transition_1' and `transition_2' will * either equal `state_1.edges().end()' and * `state_2.edges().end()', respectively, or they will point to * a pair of transitions beginning from `state_1' and `state_2' * such that this pair of transitions corresponds to a * transition starting from the intersection state determined by * `state_1' and `state_2'. * * ------------------------------------------------------------------------- */ { const GraphEdgeContainer& transitions_1 = state_1.edges(); const GraphEdgeContainer& transitions_2 = state_2.edges(); do { ++transition_2; if (transition_2 == transitions_2.end()) { ++transition_1; if (transition_1 == transitions_1.end()) return; transition_2 = transitions_2.begin(); } } while (!synchronizable(**transition_1, **transition_2)); } /* ========================================================================= */ inline void BuchiProduct::clearSatisfiabilityCache() /* ---------------------------------------------------------------------------- * * Description: Clears information about the satisfiability of the guard * formulas of product transitions. * * Arguments: None. * * Returns: Nothing. * * ------------------------------------------------------------------------- */ { sat_cache.clear(); } } #endif /* !BUCHIPRODUCT_H */