Initial revision

This commit is contained in:
Alexandre Duret-Lutz 2004-07-07 16:40:50 +00:00
parent 478844dad8
commit cfdd81a919
10 changed files with 6728 additions and 0 deletions

98
lbtt/src/BuchiProduct.cc Normal file
View file

@ -0,0 +1,98 @@
/*
* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004
* Heikki Tauriainen <Heikki.Tauriainen@hut.fi>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "BuchiProduct.h"
namespace Graph
{
/******************************************************************************
*
* Static member definitions for class BuchiProduct.
*
*****************************************************************************/
map< ::Ltl::LtlFormula*, BuchiProduct::SatisfiabilityMapping,
less< ::Ltl::LtlFormula*>, ALLOC(BuchiProduct::SatisfiabilityMapping) >
BuchiProduct::sat_cache;
/******************************************************************************
*
* Function definitions for class BuchiProduct.
*
*****************************************************************************/
/* ========================================================================= */
bool BuchiProduct::synchronizable
(const Graph<GraphEdgeContainer>::Edge& transition_1,
const Graph<GraphEdgeContainer>::Edge& transition_2)
/* ----------------------------------------------------------------------------
*
* Description: Tests whether two transitions of two Büchi automata are
* synchronizable by checking whether the conjunction of their
* guard formulas is satisfiable.
*
* Arguments: transition_1, -- Constant references to the transitions.
* transition_2
*
* Returns: true iff the transitions are synchronizable. The result is
* also stored into `this->sat_cache' for later reference.
*
* ------------------------------------------------------------------------- */
{
using ::Ltl::LtlFormula;
using ::Ltl::And;
LtlFormula* guard_1 = &static_cast<const BuchiAutomaton::BuchiTransition&>
(transition_1).guard();
LtlFormula* guard_2 = &static_cast<const BuchiAutomaton::BuchiTransition&>
(transition_2).guard();
if (guard_2 > guard_1)
{
LtlFormula* swap_guard = guard_2;
guard_2 = guard_1;
guard_1 = swap_guard;
}
map<LtlFormula*, SatisfiabilityMapping, less<LtlFormula*>,
ALLOC(SatisfiabilityMapping) >::iterator
sat_cache_element = sat_cache.find(guard_1);
if (sat_cache_element == sat_cache.end())
sat_cache_element = sat_cache.insert
(make_pair(guard_1, SatisfiabilityMapping())).first;
else
{
SatisfiabilityMapping::const_iterator sat_result
= sat_cache_element->second.find(guard_2);
if (sat_result != sat_cache_element->second.end())
return sat_result->second;
}
LtlFormula* f = &And::construct(*guard_1, *guard_2);
const bool result = f->satisfiable();
LtlFormula::destruct(f);
sat_cache_element->second.insert(make_pair(guard_2, result));
return result;
}
}

512
lbtt/src/BuchiProduct.h Normal file
View file

@ -0,0 +1,512 @@
/*
* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004
* Heikki Tauriainen <Heikki.Tauriainen@hut.fi>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef BUCHIPRODUCT_H
#define BUCHIPRODUCT_H
#include <config.h>
#include <deque>
#include <iostream>
#include <map>
#include <string>
#include <vector>
#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<GraphEdgeContainer>& a1,
const Graph<GraphEdgeContainer>& 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<GraphEdgeContainer>::size_type /* intersection state */
state_id) const; /* identifier and states */
const BuchiAutomaton::BuchiState& secondComponent /* of the underlying */
(const Graph<GraphEdgeContainer>::size_type /* automata. */
state_id) const;
void mergeAcceptanceInformation /* Merges the acceptance */
(const Graph<GraphEdgeContainer>::Node& state1, /* sets associated with */
const Graph<GraphEdgeContainer>::Node& state2, /* a pair of states into */
BitArray& acceptance_sets) const; /* a collection of sets. */
void mergeAcceptanceInformation /* Merges the acceptance */
(const Graph<GraphEdgeContainer>::Edge& /* sets associated with */
transition1, /* a pair of */
const Graph<GraphEdgeContainer>::Edge& /* transitions into a */
transition2, /* collection of sets. */
BitArray& acceptance_sets) const;
void validateEdgeIterators /* Ensures that a pair */
(const Graph<GraphEdgeContainer>::Node& /* of transition */
state_1, /* iterators points to a */
const Graph<GraphEdgeContainer>::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<GraphEdgeContainer>::Node& /* transition iterators */
state_1, /* to make them point to */
const Graph<GraphEdgeContainer>::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<GraphEdgeContainer>::Edge& /* of transitions of two */
transition_1, /* Büchi automata is */
const Graph<GraphEdgeContainer>::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<GraphEdgeContainer>& a1, const Graph<GraphEdgeContainer>& a2) :
automaton_1(static_cast<const BuchiAutomaton&>(a1)),
automaton_2(static_cast<const BuchiAutomaton&>(a2)),
number_of_acceptance_sets(static_cast<const BuchiAutomaton&>(a1)
.numberOfAcceptanceSets()
+ static_cast<const BuchiAutomaton&>(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<GraphEdgeContainer> 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<GraphEdgeContainer>::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<GraphEdgeContainer>::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<GraphEdgeContainer>::Node& state1,
const Graph<GraphEdgeContainer>::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<const BuchiAutomaton::BuchiState&>(state1).acceptanceSets(),
static_cast<const BuchiAutomaton::BuchiState&>(state2).acceptanceSets(),
acceptance_sets);
}
/* ========================================================================= */
inline void BuchiProduct::mergeAcceptanceInformation
(const Graph<GraphEdgeContainer>::Edge& transition1,
const Graph<GraphEdgeContainer>::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<const BuchiAutomaton::BuchiTransition&>(transition1)
.acceptanceSets(),
static_cast<const BuchiAutomaton::BuchiTransition&>(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<GraphEdgeContainer>::Node& state_1,
const Graph<GraphEdgeContainer>::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<GraphEdgeContainer>::Node& state_1,
const Graph<GraphEdgeContainer>::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 */

187
lbtt/src/IntervalList.cc Normal file
View file

@ -0,0 +1,187 @@
/*
* Copyright (C) 2004
* Heikki Tauriainen <Heikki.Tauriainen@hut.fi>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "IntervalList.h"
#include "StringUtil.h"
/******************************************************************************
*
* Function definitions for class IntervalList.
*
*****************************************************************************/
/* ========================================================================= */
void IntervalList::merge(unsigned long int min, unsigned long int max)
/* ----------------------------------------------------------------------------
*
* Description: Merges a new interval with a list of intervals.
*
* Arguments: min, max -- Upper and lower bound of the new interval.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
if (min > max)
return;
list<Interval, ALLOC(Interval) >::iterator interval;
for (interval = intervals.begin();
interval != intervals.end() && interval->second + 1 < min;
++interval)
;
if (interval == intervals.end())
{
intervals.insert(interval, make_pair(min, max));
return;
}
if (interval->first <= min && max <= interval->second)
return;
if (max + 1 < interval->first)
{
intervals.insert(interval, make_pair(min, max));
return;
}
if (min < interval->first)
interval->first = min;
if (interval->second < max)
{
interval->second = max;
list<Interval, ALLOC(Interval) >::iterator interval2 = interval;
++interval2;
while (interval2 != intervals.end()
&& interval2->first <= interval->second + 1)
{
if (interval->second < interval2->second)
interval->second = interval2->second;
list<Interval, ALLOC(Interval) >::iterator interval_to_erase = interval2;
++interval2;
intervals.erase(interval_to_erase);
}
}
}
/* ========================================================================= */
void IntervalList::remove(unsigned long int min, unsigned long int max)
/* ----------------------------------------------------------------------------
*
* Description: Removes a closed interval from an interval list.
*
* Arguments: min, max -- Bounds for the interval to remove.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
if (min > max)
return;
list<Interval, ALLOC(Interval) >::iterator interval;
for (interval = intervals.begin();
interval != intervals.end() && interval->second < min;
++interval)
;
while (interval != intervals.end())
{
if (max < interval->first) /* min <= max < imin <= imax */
return;
if (interval->first < min)
{
if (max < interval->second) /* imin < min <= max < imax */
{
intervals.insert(interval, make_pair(interval->first, min - 1));
interval->first = max + 1;
return;
}
interval->second = min - 1; /* imin < min <= imax <= max */
++interval;
}
else if (max < interval->second) /* min <= imin <= max < imax */
{
interval->first = max + 1;
return;
}
else /* min <= imin <= imax <= max */
{
list<Interval, ALLOC(Interval) >::iterator interval_to_erase = interval;
++interval;
intervals.erase(interval_to_erase);
}
}
}
/* ========================================================================= */
bool IntervalList::covers(unsigned long int min, unsigned long int max) const
/* ----------------------------------------------------------------------------
*
* Description: Test whether an interval list covers a given interval.
*
* Arguments: min, max -- Upper and lower bound for the interval to test.
*
* Returns: True if the IntervalList covers the given interval.
*
* ------------------------------------------------------------------------- */
{
if (min > max)
return true; /* empty interval is always covered */
list<Interval, ALLOC(Interval) >::const_iterator interval;
for (interval = intervals.begin();
interval != intervals.end() && min > interval->second;
++interval)
;
if (interval == intervals.end())
return false;
return (min >= interval->first && max <= interval->second);
}
/* ========================================================================= */
string IntervalList::toString() const
/* ----------------------------------------------------------------------------
*
* Description: Converts the interval list to a string.
*
* Arguments: None.
*
* Returns: A string listing the intervals in the interval list.
*
* ------------------------------------------------------------------------- */
{
string s;
for (list<Interval, ALLOC(Interval) >::const_iterator
interval = intervals.begin();
interval != intervals.end();
++interval)
{
if (interval != intervals.begin())
s += ',';
s += StringUtil::toString(interval->first) + "..."
+ StringUtil::toString(interval->second);
}
return s;
}

499
lbtt/src/IntervalList.h Normal file
View file

@ -0,0 +1,499 @@
/*
* Copyright (C) 2004
* Heikki Tauriainen <Heikki.Tauriainen@hut.fi>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef INTERVALLIST_H
#define INTERVALLIST_H
#include <config.h>
#include <list>
#include <string>
#include <utility>
#include "LbttAlloc.h"
using namespace std;
/******************************************************************************
*
* The IntervalList class represents a list of disjoint closed intervals
* formed from pairs of unsigned long integers. The class supports merging
* a new interval with a list of intervals, removing an interval from a list
* of intervals and checking whether the interval list covers a given element
* (or a given interval). The elements of the intervals can also be accessed
* in increasing order via IntervalList::const_iterator.
*
*****************************************************************************/
class IntervalList
{
private:
typedef pair<unsigned long int,
unsigned long int>
Interval;
public:
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
class const_iterator /* A class for iterating */
{ /* over the elements of */
/* an IntervalList. */
public:
const_iterator(); /* Constructor. */
/* default copy constructor */
~const_iterator(); /* Destructor. */
/* default assignment operator */
bool operator==(const const_iterator& it) /* Comparison operators. */
const;
bool operator!=(const const_iterator& it)
const;
unsigned long int operator*() const; /* Dereference operator. */
unsigned long int operator++(); /* Prefix increment. */
unsigned long int operator++(int); /* Postfix increment. */
private:
const list<Interval, ALLOC(Interval) >* /* The interval list */
interval_list; /* associated with the */
/* iterator. */
list<Interval, ALLOC(Interval) > /* An iterator pointing */
::const_iterator interval; /* at the current */
/* interval list. */
unsigned long int element; /* Element currently
* pointed to by the
* iterator.
*/
friend class IntervalList;
};
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
IntervalList(); /* Constructor. */
~IntervalList(); /* Destructor. */
/* default copy constructor */
/* default assignment operator */
void merge(unsigned long int element); /* Merges a point interval
* with the list of
* intervals.
*/
void merge /* Merges a new interval */
(unsigned long int min, unsigned long int max); /* with the list of
* intervals.
*/
void remove(unsigned long int element); /* Removes an element from
* the list of intervals.
*/
void remove /* Removes an interval */
(unsigned long int min, unsigned long int max); /* from the list of
* intervals.
*/
bool covers(unsigned long int element) const; /* Tests whether the
* interval list covers an
* element.
*/
bool covers /* Tests whether the */
(unsigned long int min, unsigned long int max) /* interval list covers */
const; /* an interval. */
const_iterator begin() const; /* Returns an iterator to
* the beginning of the
* interval list.
*/
const_iterator end() const; /* Returns an iterator to
* the end of the interval
* list.
*/
typedef const_iterator iterator; /* The interval list
* cannot be modified with
* iterators.
*/
typedef list<Interval, ALLOC(Interval) > /* Size type. */
::size_type size_type;
size_type size() const; /* Tell the number of
* disjoint intervals in
* the interval list.
*/
size_type max_size() const; /* Tell the maximum
* allowable number of
* disjoint intervals in
* the interval list.
*/
bool empty() const; /* Tell whether the
* interval list is empty.
*/
void clear(); /* Makes the interval list
* empty.
*/
string toString() const; /* Converts the interval
* list to a string.
*/
private:
list<Interval, ALLOC(Interval) > intervals; /* List of intervals. */
friend class const_iterator;
};
/******************************************************************************
*
* Inline function definitions for class IntervalList.
*
*****************************************************************************/
/* ========================================================================= */
inline IntervalList::IntervalList()
/* ----------------------------------------------------------------------------
*
* Description: Constructor for class IntervalList. Creates an empty list of
* intervals.
*
* Arguments: None.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
}
/* ========================================================================= */
inline IntervalList::~IntervalList()
/* ----------------------------------------------------------------------------
*
* Description: Destructor for class IntervalList.
*
* Arguments: None.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
}
/* ========================================================================= */
inline void IntervalList::merge(unsigned long int element)
/* ----------------------------------------------------------------------------
*
* Description: Merges an element (a point interval) with an IntervalList.
*
* Arguments: element -- Element to merge.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
merge(element, element);
}
/* ========================================================================= */
inline bool IntervalList::covers(unsigned long int element) const
/* ----------------------------------------------------------------------------
*
* Description: Tests whether an interval list covers an element.
*
* Arguments: element -- Element to test.
*
* Returns: True if the IntervalList covers the element.
*
* ------------------------------------------------------------------------- */
{
return covers(element, element);
}
/* ========================================================================= */
inline IntervalList::size_type IntervalList::size() const
/* ----------------------------------------------------------------------------
*
* Description: Tells the number of disjoint intervals in an IntervalList.
*
* Arguments: None.
*
* Returns: Number of disjoint intervals in the IntervalList.
*
* ------------------------------------------------------------------------- */
{
return intervals.size();
}
/* ========================================================================= */
inline IntervalList::size_type IntervalList::max_size() const
/* ----------------------------------------------------------------------------
*
* Description: Tells the maximum allowable number of disjoint intervals in
* an IntervalList.
*
* Arguments: None.
*
* Returns: Maximum allowable number of disjoint intervals in the
* IntervalList.
*
* ------------------------------------------------------------------------- */
{
return intervals.max_size();
}
/* ========================================================================= */
inline bool IntervalList::empty() const
/* ----------------------------------------------------------------------------
*
* Description: Tells whether an IntervalList is empty.
*
* Arguments: None.
*
* Returns: True if the IntervalList is empty.
*
* ------------------------------------------------------------------------- */
{
return intervals.empty();
}
/* ========================================================================= */
inline void IntervalList::clear()
/* ----------------------------------------------------------------------------
*
* Description: Makes an IntervalList empty.
*
* Arguments: None.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
intervals.clear();
}
/* ========================================================================= */
inline IntervalList::const_iterator IntervalList::begin() const
/* ----------------------------------------------------------------------------
*
* Description: Returns an IntervalList::const_iterator pointing to the
* beginning of an IntervalList.
*
* Arguments: None.
*
* Returns: An IntervalList::const_iterator pointing to the beginning of
* the IntervalList.
*
* ------------------------------------------------------------------------- */
{
const_iterator it;
it.interval_list = &this->intervals;
it.interval = intervals.begin();
if (it.interval != intervals.end())
it.element = it.interval->first;
else
it.element = 0;
return it;
}
/* ========================================================================= */
inline IntervalList::const_iterator IntervalList::end() const
/* ----------------------------------------------------------------------------
*
* Description: Returns an IntervalList::const_iterator pointing to the end
* of an IntervalList.
*
* Arguments: None.
*
* Returns: An IntervalList::const_iterator pointing to the end of the
* IntervalList.
*
* ------------------------------------------------------------------------- */
{
const_iterator it;
it.interval_list = &this->intervals;
it.interval = intervals.end();
it.element = 0;
return it;
}
/******************************************************************************
*
* Inline function definitions for class IntervalList::const_iterator.
*
*****************************************************************************/
/* ========================================================================= */
inline IntervalList::const_iterator::const_iterator()
/* ----------------------------------------------------------------------------
*
* Description: Constructor for class IntervalList::const_iterator.
*
* Arguments: None.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
}
/* ========================================================================= */
inline IntervalList::const_iterator::~const_iterator()
/* ----------------------------------------------------------------------------
*
* Description: Destructor for class IntervalList::const_iterator.
*
* Arguments: None.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
}
/* ========================================================================= */
inline bool IntervalList::const_iterator::operator==
(const const_iterator& it) const
/* ----------------------------------------------------------------------------
*
* Description: Equality test for two IntervalList::const_iterators. Two
* IntervalList::const_iterators are equal if and only if they
* point to the same interval of an interval list and the same
* element in the interval.
*
* Argument: it -- A constant reference to another
* IntervalList::const_iterator.
*
* Returns: Result of the equality test (a truth value).
*
* ------------------------------------------------------------------------- */
{
return (interval_list == it.interval_list && interval == it.interval
&& element == it.element);
}
/* ========================================================================= */
inline bool IntervalList::const_iterator::operator!=
(const const_iterator& it) const
/* ----------------------------------------------------------------------------
*
* Description: Inequality test for two IntervalList::const_iterators. Two
* IntervalList::const_iterators are not equal if and only if
* they point to different intervals of an interval list or to
* different elements of the same interval in the list.
*
* Argument: it -- A constant reference to another
* IntervalList::const_iterator.
*
* Returns: Result of the inequality test (a truth value).
*
* ------------------------------------------------------------------------- */
{
return (interval_list != it.interval_list || interval != it.interval
|| element != it.element);
}
/* ========================================================================= */
inline unsigned long int IntervalList::const_iterator::operator*() const
/* ----------------------------------------------------------------------------
*
* Description: Dereferencing operator for IntervalList::const_iterator.
*
* Arguments: None.
*
* Returns: The element currently pointed to by the iterator.
*
* ------------------------------------------------------------------------- */
{
return element;
}
/* ========================================================================= */
inline unsigned long int IntervalList::const_iterator::operator++()
/* ----------------------------------------------------------------------------
*
* Description: Prefix increment operator for IntervalList::const_iterator.
*
* Arguments: None.
*
* Returns: The element following the "current" element in the interval
* list.
*
* ------------------------------------------------------------------------- */
{
if (element == interval->second)
{
++interval;
if (interval != interval_list->end())
element = interval->first;
else
element = 0;
}
else
++element;
return element;
}
/* ========================================================================= */
inline unsigned long int IntervalList::const_iterator::operator++(int)
/* ----------------------------------------------------------------------------
*
* Description: Postfix increment operator for IntervalList::const_iterator.
*
* Arguments: None.
*
* Returns: The "current" element in the interval list.
*
* ------------------------------------------------------------------------- */
{
unsigned long int current_element = element;
if (element == interval->second)
{
++interval;
if (interval != interval_list->end())
element = interval->first;
else
element = 0;
}
else
++element;
return current_element;
}
#endif /* INTERVALLIST_H */

610
lbtt/src/Ltl-parse.yy Normal file
View file

@ -0,0 +1,610 @@
/*
* Copyright (C) 2004
* Heikki Tauriainen <Heikki.Tauriainen@hut.fi>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
%{
#include <config.h>
#include <cctype>
#include <climits>
#include <cstring>
#include <istream>
#include <set>
#include "Exception.h"
#include "LbttAlloc.h"
#include "LtlFormula.h"
using namespace Ltl;
/******************************************************************************
*
* Variables and functions used for parsing an LTL formula.
*
*****************************************************************************/
static Exceptional_istream* estream; /* Pointer to input stream.
*/
static LtlFormula* result; /* This variable stores the
* result after a call to
* ltl_parse.
*/
static std::set<LtlFormula*, less<LtlFormula*>, /* Intermediate results. */
ALLOC(LtlFormula*) > /* (This set is used */
intermediate_results; /* for keeping track of
* the subformulas of a
* partially constructed
* formula in case the
* memory allocated for
* the subformulas needs
* to be freed because
* of a parse error.)
*/
static int ltl_lex(); /* The lexical scanner. */
/******************************************************************************
*
* Function for reporting parse errors.
*
*****************************************************************************/
static void ltl_error(const char*)
{
throw LtlFormula::ParseErrorException("error parsing LTL formula");
}
/******************************************************************************
*
* Function for updating the set of intermediate results.
*
*****************************************************************************/
inline LtlFormula* newFormula(LtlFormula& f)
{
intermediate_results.insert(&f);
return &f;
}
%}
%name-prefix="ltl_"
/******************************************************************************
*
* Declarations for terminal and nonterminal symbols used in the grammar rules
* below.
*
*****************************************************************************/
%union {
class LtlFormula* formula;
}
/* Uninterpreted symbols. */
%token LTLPARSE_LPAR LTLPARSE_RPAR LTLPARSE_FALSE LTLPARSE_TRUE
LTLPARSE_UNKNOWN
/* Atomic propositions. */
%token <formula> LTLPARSE_ATOM
/* Operators. */
%nonassoc LTLPARSE_UNTIL LTLPARSE_RELEASE LTLPARSE_WEAK_UNTIL
LTLPARSE_STRONG_RELEASE LTLPARSE_BEFORE
%left LTLPARSE_IMPLY LTLPARSE_EQUIV LTLPARSE_XOR
%left LTLPARSE_OR
%left LTLPARSE_AND
%nonassoc LTLPARSE_NOT LTLPARSE_NEXT LTLPARSE_FINALLY LTLPARSE_GLOBALLY
%nonassoc LTLPARSE_EQUALS
/* Compound formulas. */
%type <formula> formula atomic_formula unary_formula prefix_op_formula
binary_formula prefix_b_formula infix_b_formula
/******************************************************************************
*
* Grammar rule definitions.
*
*****************************************************************************/
%%
ltl_formula: formula
{ result = $1; }
;
formula: atomic_formula
{ $$ = $1; }
| unary_formula
{ $$ = $1; }
| binary_formula
{ $$ = $1; }
| LTLPARSE_LPAR formula LTLPARSE_RPAR
{ $$ = $2; }
;
atomic_formula: LTLPARSE_ATOM
{ $$ = $1; }
| LTLPARSE_ATOM LTLPARSE_EQUALS LTLPARSE_FALSE
{
intermediate_results.erase($1);
$$ = newFormula(Not::construct($1));
}
| LTLPARSE_ATOM LTLPARSE_EQUALS LTLPARSE_TRUE
{ $$ = $1; }
| LTLPARSE_FALSE
{ $$ = newFormula(False::construct()); }
| LTLPARSE_TRUE
{ $$ = newFormula(True::construct()); }
;
unary_formula: LTLPARSE_NOT formula
{
intermediate_results.erase($2);
$$ = newFormula(Not::construct($2));
}
| LTLPARSE_NEXT formula
{
intermediate_results.erase($2);
$$ = newFormula(Next::construct($2));
}
| LTLPARSE_FINALLY formula
{
intermediate_results.erase($2);
$$ = newFormula(Finally::construct($2));
}
| LTLPARSE_GLOBALLY formula
{
intermediate_results.erase($2);
$$ = newFormula(Globally::construct($2));
}
;
prefix_op_formula: atomic_formula
{ $$ = $1; }
| unary_formula
{ $$ = $1; }
| prefix_b_formula
{ $$ = $1; }
| LTLPARSE_LPAR formula LTLPARSE_RPAR
{ $$ = $2; }
;
binary_formula: prefix_b_formula
{ $$ = $1; }
| infix_b_formula
{ $$ = $1; }
;
prefix_b_formula: LTLPARSE_AND prefix_op_formula prefix_op_formula
{
intermediate_results.erase($2);
intermediate_results.erase($3);
$$ = newFormula(And::construct($2, $3));
}
| LTLPARSE_OR prefix_op_formula prefix_op_formula
{
intermediate_results.erase($2);
intermediate_results.erase($3);
$$ = newFormula(Or::construct($2, $3));
}
| LTLPARSE_IMPLY prefix_op_formula prefix_op_formula
{
intermediate_results.erase($2);
intermediate_results.erase($3);
$$ = newFormula(Imply::construct($2, $3));
}
| LTLPARSE_EQUIV prefix_op_formula prefix_op_formula
{
intermediate_results.erase($2);
intermediate_results.erase($3);
$$ = newFormula(Equiv::construct($2, $3));
}
| LTLPARSE_XOR prefix_op_formula prefix_op_formula
{
intermediate_results.erase($2);
intermediate_results.erase($3);
$$ = newFormula(Xor::construct($2, $3));
}
| LTLPARSE_UNTIL prefix_op_formula prefix_op_formula
{
intermediate_results.erase($2);
intermediate_results.erase($3);
$$ = newFormula(Until::construct($2, $3));
}
| LTLPARSE_RELEASE prefix_op_formula prefix_op_formula
{
intermediate_results.erase($2);
intermediate_results.erase($3);
$$ = newFormula(V::construct($2, $3));
}
| LTLPARSE_WEAK_UNTIL prefix_op_formula prefix_op_formula
{
intermediate_results.erase($2);
intermediate_results.erase($3);
$$ = newFormula(WeakUntil::construct($2, $3));
}
| LTLPARSE_STRONG_RELEASE prefix_op_formula
prefix_op_formula
{
intermediate_results.erase($2);
intermediate_results.erase($3);
$$ = newFormula(StrongRelease::construct($2, $3));
}
| LTLPARSE_BEFORE prefix_op_formula prefix_op_formula
{
intermediate_results.erase($2);
intermediate_results.erase($3);
$$ = newFormula(Before::construct($2, $3));
}
;
infix_b_formula: formula LTLPARSE_AND formula
{
intermediate_results.erase($1);
intermediate_results.erase($3);
$$ = newFormula(And::construct($1, $3));
}
| formula LTLPARSE_OR formula
{
intermediate_results.erase($1);
intermediate_results.erase($3);
$$ = newFormula(Or::construct($1, $3));
}
| formula LTLPARSE_IMPLY formula
{
intermediate_results.erase($1);
intermediate_results.erase($3);
$$ = newFormula(Imply::construct($1, $3));
}
| formula LTLPARSE_EQUIV formula
{
intermediate_results.erase($1);
intermediate_results.erase($3);
$$ = newFormula(Equiv::construct($1, $3));
}
| formula LTLPARSE_XOR formula
{
intermediate_results.erase($1);
intermediate_results.erase($3);
$$ = newFormula(Xor::construct($1, $3));
}
| formula LTLPARSE_UNTIL formula
{
intermediate_results.erase($1);
intermediate_results.erase($3);
$$ = newFormula(Until::construct($1, $3));
}
| formula LTLPARSE_RELEASE formula
{
intermediate_results.erase($1);
intermediate_results.erase($3);
$$ = newFormula(V::construct($1, $3));
}
| formula LTLPARSE_WEAK_UNTIL formula
{
intermediate_results.erase($1);
intermediate_results.erase($3);
$$ = newFormula(WeakUntil::construct($1, $3));
}
| formula LTLPARSE_STRONG_RELEASE formula
{
intermediate_results.erase($1);
intermediate_results.erase($3);
$$ = newFormula(StrongRelease::construct($1, $3));
}
| formula LTLPARSE_BEFORE formula
{
intermediate_results.erase($1);
intermediate_results.erase($3);
$$ = newFormula(Before::construct($1, $3));
}
;
%%
/******************************************************************************
*
* Helper function for reading lexical tokens from a stream.
*
*****************************************************************************/
static inline size_t matchCharactersFromStream
(istream& stream, char* chars)
{
size_t num_matched;
for (num_matched = 0; *chars != '\0' && stream.peek() == *chars; ++chars)
{
stream.ignore(1);
++num_matched;
}
return num_matched;
}
/******************************************************************************
*
* Main interface to the parser.
*
*****************************************************************************/
namespace Ltl
{
/* ========================================================================= */
LtlFormula* parseFormula(istream& stream)
/* ----------------------------------------------------------------------------
*
* Description: Parses an LTL formula from a stream. The formula should be
* in one of the formats used by the tools lbtt 1.0.x (both
* prefix and infix form), Spin/Temporal Massage Parlor/LTL2BA,
* LTL2AUT or Wring 1.1.0 (actually, the grammar is basically
* a combination of the grammars of the above tools with the
* exception that propositions should always be written in the
* form `pN' for some integer N; in principle, it is possible to
* use a mixed syntax for the formula). The input should be
* terminated with a newline.
*
* Argument: stream -- A reference to the input stream.
*
* Returns: A pointer to the formula. The function throws an
* LtlFormula::ParseErrorException if the syntax is incorrect,
* or an IOException in case of an end-of-file or another I/O
* error.
*
* ------------------------------------------------------------------------- */
{
Exceptional_istream es(&stream, ios::badbit | ios::failbit | ios::eofbit);
estream = &es;
intermediate_results.clear();
try
{
ltl_parse();
}
catch (...)
{
for (std::set<LtlFormula*, less<LtlFormula*>, ALLOC(LtlFormula*) >
::const_iterator f = intermediate_results.begin();
f != intermediate_results.end();
++f)
LtlFormula::destruct(*f);
throw;
}
return result;
}
}
/******************************************************************************
*
* The lexical scanner.
*
*****************************************************************************/
static int ltl_lex()
{
char c;
std::istream& stream = static_cast<istream&>(*estream);
do
{
estream->get(c);
}
while (isspace(c) && c != '\n');
switch (c)
{
case '\n' : return 0;
case '(' :
return (matchCharactersFromStream(stream, ")") == 1
? LTLPARSE_NEXT
: LTLPARSE_LPAR);
case ')' : return LTLPARSE_RPAR;
case 'f' :
switch (matchCharactersFromStream(stream, "alse"))
{
case 0 : case 4 :
return LTLPARSE_FALSE;
default:
break;
}
return LTLPARSE_UNKNOWN;
case '0' : return LTLPARSE_FALSE;
case 't' :
switch (matchCharactersFromStream(stream, "rue"))
{
case 0 : case 3 :
return LTLPARSE_TRUE;
default :
return LTLPARSE_UNKNOWN;
}
case 'T' :
return (matchCharactersFromStream(stream, "RUE") == 3
? LTLPARSE_TRUE
: LTLPARSE_UNKNOWN);
case '1' : return LTLPARSE_TRUE;
case '!' : case '~' : return LTLPARSE_NOT;
case '&' :
matchCharactersFromStream(stream, "&");
return LTLPARSE_AND;
case '/' :
return (matchCharactersFromStream(stream, "\\") == 1
? LTLPARSE_AND
: LTLPARSE_UNKNOWN);
case '*' : return LTLPARSE_AND;
case '|' :
matchCharactersFromStream(stream, "|");
return LTLPARSE_OR;
case '\\' :
return (matchCharactersFromStream(stream, "/") == 1
? LTLPARSE_OR
: LTLPARSE_UNKNOWN);
case '+' : return LTLPARSE_OR;
case '=' :
return (matchCharactersFromStream(stream, ">") == 1
? LTLPARSE_IMPLY
: LTLPARSE_EQUALS);
case '-' :
return (matchCharactersFromStream(stream, ">") == 1
? LTLPARSE_IMPLY
: LTLPARSE_UNKNOWN);
case 'i' : return LTLPARSE_IMPLY;
case '<' :
if (matchCharactersFromStream(stream, ">") == 1)
return LTLPARSE_FINALLY;
return (matchCharactersFromStream(stream, "->") == 2
|| matchCharactersFromStream(stream, "=>") == 2
? LTLPARSE_EQUIV
: LTLPARSE_UNKNOWN);
case 'e' : return LTLPARSE_EQUIV;
case 'x' :
return (matchCharactersFromStream(stream, "or") == 2
? LTLPARSE_XOR
: LTLPARSE_UNKNOWN);
case '^' : return LTLPARSE_XOR;
case 'X' : return LTLPARSE_NEXT;
case 'U' : return LTLPARSE_UNTIL;
case 'V' : case 'R' : return LTLPARSE_RELEASE;
case 'W' : return LTLPARSE_WEAK_UNTIL;
case 'M' : return LTLPARSE_STRONG_RELEASE;
case 'B' : return LTLPARSE_BEFORE;
case 'F' :
switch (matchCharactersFromStream(stream, "ALSE"))
{
case 0 :
return LTLPARSE_FINALLY;
case 4 :
return LTLPARSE_FALSE;
default :
return LTLPARSE_UNKNOWN;
}
case '[' :
return (matchCharactersFromStream(stream, "]") == 1
? LTLPARSE_GLOBALLY
: LTLPARSE_UNKNOWN);
case 'G' : return LTLPARSE_GLOBALLY;
case 'p' :
{
long int id = 0;
bool id_ok = false;
int ch = stream.peek();
while (ch >= '0' && ch <= '9')
{
id_ok = true;
estream->get(c);
if (LONG_MAX / 10 < id)
throw LtlFormula::ParseErrorException
("error parsing LTL formula (proposition identifier out of "
"range)");
id *= 10;
id += (c - '0');
ch = stream.peek();
}
if (id_ok)
{
ltl_lval.formula = newFormula(Atom::construct(id));
return LTLPARSE_ATOM;
}
return LTLPARSE_UNKNOWN;
}
default : return LTLPARSE_UNKNOWN;
}
}

2936
lbtt/src/Product.h Normal file

File diff suppressed because it is too large Load diff

1174
lbtt/src/SccCollection.h Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,430 @@
/*
* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004
* Heikki Tauriainen <Heikki.Tauriainen@hut.fi>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef STATESPACEPRODUCT_H
#define STATESPACEPRODUCT_H
#include <config.h>
#include "BitArray.h"
#include "BuchiAutomaton.h"
#include "EdgeContainer.h"
#include "Graph.h"
#include "StateSpace.h"
using namespace std;
namespace Graph
{
/******************************************************************************
*
* A class with operations for checking the product of a Büchi automaton and
* a state space for emptiness.
*
*****************************************************************************/
class StateSpaceProduct
{
public:
StateSpaceProduct /* Constructor. */
(const Graph<GraphEdgeContainer>& a,
const Graph<GraphEdgeContainer>& s);
/* default copy constructor */
~StateSpaceProduct(); /* Destructor. */
/* default assignment operator */
bool empty() const; /* Tells whether the
* product of a Büchi
* automaton and a state
* space is (trivially)
* empty.
*/
unsigned long int numberOfAcceptanceSets() const; /* Tells the number of
* acceptance sets in a
* Büchi automaton in its
* product with a state
* space.
*/
const BuchiAutomaton::BuchiState& firstComponent /* Mappings between a */
(const Graph<GraphEdgeContainer>::size_type /* product state */
state_id) const; /* identifier and */
const StateSpace::State& secondComponent /* states of the Büchi */
(const Graph<GraphEdgeContainer>::size_type /* automaton and the */
state_id) const; /* state space forming
* the product.
*/
void mergeAcceptanceInformation /* Merges the acceptance */
(const Graph<GraphEdgeContainer>::Node& state, /* sets associated with */
const Graph<GraphEdgeContainer>::Node&, /* a state in the Büchi */
BitArray& acceptance_sets) const; /* automaton into a
* collection of sets.
*/
void mergeAcceptanceInformation /* Merges the acceptance */
(const Graph<GraphEdgeContainer>::Edge& /* sets associated with */
buchi_transition, /* a transition in the */
const Graph<GraphEdgeContainer>::Edge&, /* Büchi automaton into */
BitArray& acceptance_sets) const; /* a collection of sets. */
void validateEdgeIterators /* Ensures that a pair */
(const Graph<GraphEdgeContainer>::Node& /* of transition */
buchi_state, /* iterators points to a */
const Graph<GraphEdgeContainer>::Node& /* transition beginning */
system_state, /* from a given state in */
GraphEdgeContainer::const_iterator& /* the product of a */
buchi_transition, /* Büchi automaton and */
GraphEdgeContainer::const_iterator& /* a state space. */
system_transition) const;
void incrementEdgeIterators /* Updates a pair of */
(const Graph<GraphEdgeContainer>::Node& /* transition iterators */
buchi_state, /* to make them point to */
const Graph<GraphEdgeContainer>::Node& /* the "next" transition */
system_state, /* starting from a given */
GraphEdgeContainer::const_iterator& /* state in the product */
buchi_transition, /* of a Büchi automaton */
GraphEdgeContainer::const_iterator& /* and a state space. */
system_transition) const;
private:
const BuchiAutomaton& buchi_automaton; /* Büchi automaton
* associated with the
* product.
*/
const StateSpace& statespace; /* State space associated
* with the product.
*/
};
/******************************************************************************
*
* Inline function definitions for class StateSpaceProduct.
*
*****************************************************************************/
/* ========================================================================= */
inline StateSpaceProduct::StateSpaceProduct
(const Graph<GraphEdgeContainer>& a, const Graph<GraphEdgeContainer>& s) :
buchi_automaton(static_cast<const BuchiAutomaton&>(a)),
statespace(static_cast<const StateSpace&>(s))
/* ----------------------------------------------------------------------------
*
* Description: Constructor for class StateSpaceProduct. Initializes a new
* object with operations for checking the emptiness of the
* product of a Büchi automaton and a state space.
*
* Arguments: a -- A constant reference to a Graph<GraphEdgeContainer>
* object, assumed to be a BuchiAutomaton.
* s -- A constant reference to a Graph<GraphEdgeContainer>
* object, assumed to be a StateSpace.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
}
/* ========================================================================= */
inline StateSpaceProduct::~StateSpaceProduct()
/* ----------------------------------------------------------------------------
*
* Description: Destructor for class StateSpaceProduct.
*
* Arguments: None.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
}
/* ========================================================================= */
inline bool StateSpaceProduct::empty() const
/* ----------------------------------------------------------------------------
*
* Description: Tells whether the product of `this->buchi_automaton' and
* `this->statespace' is (trivially) empty.
*
* Arguments: None.
*
* Returns: true iff either the Büchi automaton or the state space has
* no states.
*
* ------------------------------------------------------------------------- */
{
return (buchi_automaton.empty() || statespace.empty());
}
/* ========================================================================= */
inline unsigned long int StateSpaceProduct::numberOfAcceptanceSets() const
/* ----------------------------------------------------------------------------
*
* Description: Tells the number of acceptance sets in the Büchi automaton
* associated with a StateSpaceProduct object.
*
* Arguments: None.
*
* Returns: The number of acceptance sets in the automaton.
*
* ------------------------------------------------------------------------- */
{
return buchi_automaton.numberOfAcceptanceSets();
}
/* ========================================================================= */
inline const BuchiAutomaton::BuchiState& StateSpaceProduct::firstComponent
(const Graph<GraphEdgeContainer>::size_type state_id) const
/* ----------------------------------------------------------------------------
*
* Description: Function for accessing states in the Büchi automaton
* associated with a StateSpaceProduct object.
*
* Argument: state_id -- Identifier of a state in the automaton.
*
* Returns: A constant reference to a state in the automaton.
*
* ------------------------------------------------------------------------- */
{
return buchi_automaton[state_id];
}
/* ========================================================================= */
inline const StateSpace::State& StateSpaceProduct::secondComponent
(const Graph<GraphEdgeContainer>::size_type state_id) const
/* ----------------------------------------------------------------------------
*
* Description: Function for accessing states in the state space associated
* with a StateSpaceProduct object.
*
* Argument: state_id -- Identifier of a state in the state space.
*
* Returns: A constant reference to a state in the state space.
*
* ------------------------------------------------------------------------- */
{
return statespace[state_id];
}
/* ========================================================================= */
inline void StateSpaceProduct::mergeAcceptanceInformation
(const Graph<GraphEdgeContainer>::Node& state,
const Graph<GraphEdgeContainer>::Node&, BitArray& acceptance_sets) const
/* ----------------------------------------------------------------------------
*
* Description: Merges the acceptance sets associated with a state of a Büchi
* automaton into a collection of sets.
*
* Arguments: state -- A constant reference to a state in the
* automaton.
* acceptance_sets -- A reference to a BitArray for storing
* the result. The BitArray should have
* capacity for (at least)
* `this->buchi_automaton
* .numberOfAcceptanceSets()' bits.
* (The second argument is needed to allow the class
* StateSpaceProduct to be used for instantiating the Product
* template; see file Product.h.)
*
* Returns: Nothing. After the operation, `acceptance_sets[i] == true'
* holds if `state.acceptanceSets().test(i) == true' for all
* 0 <= i < `this->buchi_automaton.numberOfAcceptanceSets()'.
*
* ------------------------------------------------------------------------- */
{
acceptance_sets.bitwiseOr
(static_cast<const BuchiAutomaton::BuchiState&>(state).acceptanceSets(),
numberOfAcceptanceSets());
}
/* ========================================================================= */
inline void StateSpaceProduct::mergeAcceptanceInformation
(const Graph<GraphEdgeContainer>::Edge& buchi_transition,
const Graph<GraphEdgeContainer>::Edge&, BitArray& acceptance_sets) const
/* ----------------------------------------------------------------------------
*
* Description: Merges the acceptance sets associated with a transition of a
* Büchi automaton into a collection of sets.
*
* Arguments: transition -- A constant reference to a transition in
* the automaton.
* acceptance_sets -- A reference to a BitArray for storing
* the result. The BitArray should have
* capacity for (at least)
* `this->buchi_automaton
* .numberOfAcceptanceSets()' bits.
* (The second argument is needed to allow the class
* StateSpaceProduct to be used for instantiating the Product
* template; see file Product.h.)
*
* Returns: Nothing. After the operation, `acceptance_sets[i] == true'
* holds if `transition.acceptanceSets().test(i) == true' for
* all
* 0 <= i < `this->buchi_automaton.numberOfAcceptanceSets()'.
*
* ------------------------------------------------------------------------- */
{
acceptance_sets.bitwiseOr
(static_cast<const BuchiAutomaton::BuchiTransition&>(buchi_transition)
.acceptanceSets(),
numberOfAcceptanceSets());
}
/* ========================================================================= */
inline void StateSpaceProduct::validateEdgeIterators
(const Graph<GraphEdgeContainer>::Node& buchi_state,
const Graph<GraphEdgeContainer>::Node& system_state,
GraphEdgeContainer::const_iterator& buchi_transition,
GraphEdgeContainer::const_iterator& system_transition) const
/* ----------------------------------------------------------------------------
*
* Description: Checks whether a pair of transition iterators corresponds to
* a transition beginning from a state in the product of a Büchi
* automaton and a state space; if this is not the case, makes
* the iterators point to a valid transition beginning from the
* product state (or to the "end" of the collection of
* transitions beginning from the product state if no valid
* transition can be found by incrementing the iterators).
*
* Arguments: buchi_state, -- These variables determine the state
* system_state, in the product; `buchi_state' and
* `system_state' should be references to
* states in `this->buchi_automaton' and
* `this->statespace', respectively.
* buchi_transition, -- References to the transition
* system_transition iterators. It is assumed that
* `buchi_transition' and
* `system_transition' initially point to
* two transitions starting from
* `buchi_state' and `system_state',
* respectively.
*
* Returns: Nothing. Upon return, `buchi_transition' and
* `system_transition' will either equal
* `buchi_state.edges().end()' and `system_state.edges().end()',
* respectively, or they will point to a pair of transitions
* beginning from `buchi_state' and `system_state' such that
* this pair of transitions corresponds to a transition starting
* from the product state determined by `buchi_state' and
* `system_state'.
*
* ------------------------------------------------------------------------- */
{
const GraphEdgeContainer& buchi_transitions = buchi_state.edges();
const GraphEdgeContainer& system_transitions = system_state.edges();
if (buchi_transition == buchi_transitions.end())
{
system_transition = system_transitions.end();
return;
}
if (system_transition == system_transitions.end())
{
buchi_transition = buchi_transitions.end();
return;
}
while (!static_cast<const BuchiAutomaton::BuchiTransition*>
(*buchi_transition)->enabled
(static_cast<const StateSpace::State&>(system_state)
.positiveAtoms(),
statespace.numberOfPropositions()))
{
++buchi_transition;
if (buchi_transition == buchi_transitions.end())
{
system_transition = system_transitions.end();
return;
}
}
system_transition = system_transitions.begin();
}
/* ========================================================================= */
inline void StateSpaceProduct::incrementEdgeIterators
(const Graph<GraphEdgeContainer>::Node& buchi_state,
const Graph<GraphEdgeContainer>::Node& system_state,
GraphEdgeContainer::const_iterator& buchi_transition,
GraphEdgeContainer::const_iterator& system_transition) const
/* ----------------------------------------------------------------------------
*
* Description: Increments a pair of transition iterators to point to the
* "next" transition beginning from a state in the product of a
* Büchi automaton and a state space. If no "next" transition
* exists, makes the iterators point to the "end" of the
* collection of transitions beginning from the product state.
*
* Arguments: buchi_state, -- These variables determine the state
* system_state, in the product; `buchi_state' and
* `system_state' should be references to
* states in `this->buchi_automaton' and
* `this->statespace', respectively.
* buchi_transition, -- References to the transition
* system_transition iterators. It is assumed that
* `buchi_transition' and
* `system_transition' initially point to
* two transitions starting from
* `buchi_state' and `system_state',
* respectively.
*
* Returns: Nothing. Upon return, `buchi_transition' and
* `system_transition' will either equal
* `buchi_state.edges().end()' and `system_state.edges().end()',
* respectively, or they will point to a pair of transitions
* beginning from `buchi_state' and `system_state' such that
* this pair of transitions corresponds to a transition starting
* from the product state determined by `buchi_state' and
* `system_state'.
*
* ------------------------------------------------------------------------- */
{
const GraphEdgeContainer& buchi_transitions = buchi_state.edges();
const GraphEdgeContainer& system_transitions = system_state.edges();
++system_transition;
if (system_transition == system_transitions.end())
{
do
{
++buchi_transition;
if (buchi_transition == buchi_transitions.end())
return;
}
while (!static_cast<const BuchiAutomaton::BuchiTransition*>
(*buchi_transition)->enabled
(static_cast<const StateSpace::State&>(system_state)
.positiveAtoms(),
statespace.numberOfPropositions()));
system_transition = system_transitions.begin();
}
}
}
#endif /* !STATESPACEPRODUCT_H */

125
lbtt/src/TempFsysName.cc Normal file
View file

@ -0,0 +1,125 @@
/*
* Copyright (C) 2004
* Heikki Tauriainen <Heikki.Tauriainen@hut.fi>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <config.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sys/stat.h>
#include <sys/types.h>
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif /* HAVE_FCNTL_H */
#include <string>
#include "Exception.h"
#include "StringUtil.h"
#include "TempFsysName.h"
/******************************************************************************
*
* Number of generated temporary names.
*
*****************************************************************************/
unsigned long int TempFsysName::number_of_allocated_names = 0;
/******************************************************************************
*
* Function definitions for class TempFsysName.
*
*****************************************************************************/
/* ========================================================================= */
const char* TempFsysName::allocate
(const char* prefix, const NameType t, const bool literal)
/* ----------------------------------------------------------------------------
*
* Description: Associates a TempFsysName object with a temporary name. (As
* a side effect, the function actually creates an empty
* temporary file or a directory to reserve the name in the file
* system. The file or directory should never be removed
* explicitly; it is removed automatically when the TempFsysName
* object is destroyed or another call is made to
* `this->allocate'.)
*
* Arguments: prefix -- Pointer to a C-style string containing a prefix
* for the temporary name (empty by default). If
* `literal == true', `prefix' (if nonempty) is
* assumed to contain the full path for the
* temporary file or directory; otherwise the
* function will reserve a temporary name in the
* `P_tmpdir' directory. This name will consist
* of the value of `prefix' (if nonempty), followed
* by the current value of
* `TempFsysName::number_of_allocated_names' and
* the current process id, separated by dots.
* t -- Determines the type of the name (file or a
* directory).
* literal -- See above.
*
* Returns: A pointer to a constant C-style string containing the
* temporary name. The function throws an IOException if the
* name allocation or the file or directory creation fails.
*
* ------------------------------------------------------------------------- */
{
releaseName();
using ::StringUtil::toString;
string tempname;
try
{
if (!literal || strlen(prefix) == 0)
{
tempname = toString(P_tmpdir) + "/";
if (strlen(prefix))
tempname += string(prefix) + ".";
tempname += toString(number_of_allocated_names) + "."
+ toString(getpid());
++number_of_allocated_names;
}
else
tempname = prefix;
name = new char[tempname.length() + 1];
strcpy(name, tempname.c_str());
}
catch (const bad_alloc&)
{
name = 0;
throw IOException
("unable to allocate a temporary name in the file system");
}
type = t;
if (t == FILE)
{
int fd = open(name, O_RDWR | O_CREAT | O_EXCL, S_IREAD | S_IWRITE);
if (fd == -1)
throw IOException("unable to create a temporary file");
close(fd);
}
else if (mkdir(name, S_IRWXU) == -1)
throw IOException("unable to create a temporary directory");
return name;
}

157
lbtt/src/TempFsysName.h Normal file
View file

@ -0,0 +1,157 @@
/*
* Copyright (C) 2004
* Heikki Tauriainen <Heikki.Tauriainen@hut.fi>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef TEMPFSYSNAME_H
#define TEMPFSYSNAME_H
#include <config.h>
#include <cstdio>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif /* HAVE_UNISTD_H */
/******************************************************************************
*
* A class for temporary file system names.
*
*****************************************************************************/
class TempFsysName
{
public:
TempFsysName(); /* Constructor. */
~TempFsysName(); /* Destructor. */
enum NameType { FILE, DIRECTORY }; /* Types of temporary
* file system names.
*/
const char* allocate /* Allocates a name */
(const char* prefix = "", /* in the file system. */
const NameType t = FILE,
const bool literal = false);
const char* get() const; /* Tells the name. */
private:
TempFsysName(const TempFsysName&); /* Prevent copying and */
TempFsysName& operator=(const TempFsysName&); /* assignment of
* TempFsysName objects.
*/
void releaseName(); /* Frees a name in the file
* system.
*/
char* name; /* Temporary name. */
NameType type; /* Tells whether the name
* refers to a file or a
* directory.
*/
static unsigned long int /* Counter for the */
number_of_allocated_names; /* number of generated
* temporary names.
*/
};
/******************************************************************************
*
* Inline function definitions for class TempFsysName.
*
*****************************************************************************/
/* ========================================================================= */
inline TempFsysName::TempFsysName() : name(static_cast<char*>(0))
/* ----------------------------------------------------------------------------
*
* Description: Constructor for class TempFsysName.
*
* Arguments: None.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
}
/* ========================================================================= */
inline TempFsysName::~TempFsysName()
/* ----------------------------------------------------------------------------
*
* Description: Destructor for class TempFsysName.
*
* Arguments: None.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
releaseName();
}
/* ========================================================================= */
inline const char* TempFsysName::get() const
/* ----------------------------------------------------------------------------
*
* Description: Tells the name associated with the TempFsysName object.
*
* Arguments: None.
*
* Returns: A pointer to a constant C-style string containing the name
* associated with the TempFsysName object. If the TempFsysName
* object has not yet been (successfully) associated with a file
* using TempFsysName::allocate, this pointer has the value 0.
*
* ------------------------------------------------------------------------- */
{
return name;
}
/* ========================================================================= */
inline void TempFsysName::releaseName()
/* ----------------------------------------------------------------------------
*
* Description: Deallocates the memory reserved for `this->name' and frees
* the name also in the file system by removing the file or
* directory associated with the object. If the name
* is associated with a directory, the directory is assumed to
* be empty.
*
* Arguments: None.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
if (name == static_cast<char*>(0))
return;
if (type == FILE)
remove(name);
else
rmdir(name);
delete[] name;
name = 0;
}
#endif /* !TEMPFSYSNAME_H */