rename src/ as spot/ and use include <spot/...>

* NEWS: Mention the change.
* src/: Rename as ...
* spot/: ... this, adjust all headers to include <spot/...> instead of
"...", and adjust all Makefile.am to search headers from the top-level
directory.
* HACKING: Add conventions about #include.
* spot/sanity/style.test: Add a few more grep to catch cases
that do not follow these conventions.
* .gitignore, Makefile.am, README, bench/stutter/Makefile.am,
bench/stutter/stutter_invariance_formulas.cc,
bench/stutter/stutter_invariance_randomgraph.cc, configure.ac,
debian/rules, doc/Doxyfile.in, doc/Makefile.am,
doc/org/.dir-locals.el.in, doc/org/g++wrap.in, doc/org/init.el.in,
doc/org/tut01.org, doc/org/tut02.org, doc/org/tut03.org,
doc/org/tut10.org, doc/org/tut20.org, doc/org/tut21.org,
doc/org/tut22.org, doc/org/tut30.org, iface/ltsmin/Makefile.am,
iface/ltsmin/kripke.test, iface/ltsmin/ltsmin.cc,
iface/ltsmin/ltsmin.hh, iface/ltsmin/modelcheck.cc,
wrap/python/Makefile.am, wrap/python/ajax/spotcgi.in,
wrap/python/spot_impl.i, wrap/python/tests/ltl2tgba.py,
wrap/python/tests/randgen.py, wrap/python/tests/run.in: Adjust.
This commit is contained in:
Alexandre Duret-Lutz 2015-12-04 19:42:23 +01:00
parent 1fddfe60ec
commit f120dd3206
529 changed files with 1308 additions and 1262 deletions

39
spot/ta/Makefile.am Normal file
View file

@ -0,0 +1,39 @@
## -*- coding: utf-8 -*-
## Copyright (C) 2010, 2012, 2013, 2015 Laboratoire de Recherche et
## Développement de l'Epita (LRDE).
##
## This file is part of Spot, a model checking library.
##
## Spot 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 3 of the License, or
## (at your option) any later version.
##
## Spot 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, see <http://www.gnu.org/licenses/>.
AM_CPPFLAGS = -I$(top_builddir) -I$(top_srcdir) $(BUDDY_CPPFLAGS)
AM_CXXFLAGS = $(WARNING_CXXFLAGS)
tadir = $(pkgincludedir)/ta
ta_HEADERS = \
ta.hh \
taexplicit.hh \
taproduct.hh \
tgta.hh \
tgtaexplicit.hh \
tgtaproduct.hh
noinst_LTLIBRARIES = libta.la
libta_la_SOURCES = \
ta.cc \
taproduct.cc \
tgtaexplicit.cc \
taexplicit.cc \
tgtaproduct.cc

77
spot/ta/ta.cc Normal file
View file

@ -0,0 +1,77 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2010, 2011, 2014 Laboratoire de Recherche et
// Developpement de l Epita (LRDE).
//
// This file is part of Spot, a model checking library.
//
// Spot 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 3 of the License, or
// (at your option) any later version.
//
// Spot 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, see <http://www.gnu.org/licenses/>.
#include <spot/ta/ta.hh>
namespace spot
{
scc_stack_ta::connected_component::connected_component(int i)
{
index = i;
is_accepting = false;
condition = 0U;
}
scc_stack_ta::connected_component&
scc_stack_ta::top()
{
return s.front();
}
const scc_stack_ta::connected_component&
scc_stack_ta::top() const
{
return s.front();
}
void
scc_stack_ta::pop()
{
// assert(rem().empty());
s.pop_front();
}
void
scc_stack_ta::push(int index)
{
s.emplace_front(index);
}
std::list<const state*>&
scc_stack_ta::rem()
{
return top().rem;
}
size_t
scc_stack_ta::size() const
{
return s.size();
}
bool
scc_stack_ta::empty() const
{
return s.empty();
}
}

296
spot/ta/ta.hh Normal file
View file

@ -0,0 +1,296 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2010, 2012, 2013, 2014, 2015 Laboratoire de Recherche et
// Developpement de l Epita (LRDE).
//
// This file is part of Spot, a model checking library.
//
// Spot 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 3 of the License, or
// (at your option) any later version.
//
// Spot 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, see <http://www.gnu.org/licenses/>.
#pragma once
#include <set>
#include <cassert>
#include <spot/misc/bddlt.hh>
#include <spot/twa/twa.hh>
namespace spot
{
// Forward declarations. See below.
class ta_succ_iterator;
/// \defgroup ta TA (Testing Automata)
///
/// This type and its cousins are listed \ref ta_essentials "here".
/// This is an abstract interface. Its implementations are \ref
/// ta_representation "concrete representations". The
/// algorithms that work on spot::ta are \ref tgba_algorithms
/// "listed separately".
/// \addtogroup ta_essentials Essential TA types
/// \ingroup ta
/// \ingroup ta_essentials
/// \brief A Testing Automaton.
///
/// The Testing Automata (TA) were introduced by
/// Henri Hansen, Wojciech Penczek and Antti Valmari
/// in "Stuttering-insensitive automata for on-the-fly detection of livelock
/// properties" In Proc. of FMICSÕ02, vol. 66(2) of Electronic Notes in
/// Theoretical Computer Science.Elsevier.
///
/// While a TGBA automaton observes the value of the atomic propositions, the
/// basic idea of TA is to detect the changes in these values; if a valuation
/// does not change between two consecutive valuations of an execution,
/// the TA stay in the same state. A TA transition \c (s,k,d) is labeled by a
/// "changeset" \c k: i.e. the set of atomic propositions that change between
/// states \c s and \c d, if the changeset is empty then the transition is
/// called stuttering transition.
/// To detect execution that ends by stuttering in the same TA state, a
/// new kind of acceptance states is introduced: "livelock-acceptance states"
/// (in addition to the standard Buchi-acceptance states).
///
/// Browsing such automaton can be achieved using two functions:
/// \c get_initial_states_set or \c get_artificial_initial_state, and \c
/// succ_iter. The former returns the initial state(s) while the latter lists
/// the successor states of any state (filtred by "changeset").
///
/// Note that although this is a transition-based automata,
/// we never represent transitions! Transition informations are
/// obtained by querying the iterator over the successors of
/// a state.
class SPOT_API ta
{
protected:
acc_cond acc_;
bdd_dict_ptr dict_;
public:
ta(const bdd_dict_ptr& d)
: dict_(d)
{
}
virtual
~ta()
{
}
typedef std::set<state*, state_ptr_less_than> states_set_t;
typedef std::set<const state*, state_ptr_less_than> const_states_set_t;
/// \brief Get the initial states set of the automaton.
virtual const_states_set_t
get_initial_states_set() const = 0;
/// \brief Get the artificial initial state set of the automaton.
/// Return 0 if this artificial state is not implemented
/// (in this case, use \c get_initial_states_set)
/// The aim of adding this state is to have an unique initial state. This
/// artificial initial state have one transition to each real initial state,
/// and this transition is labeled by the corresponding initial condition.
/// (For more details, see the paper cited above)
virtual const spot::state*
get_artificial_initial_state() const
{
return nullptr;
}
/// \brief Get an iterator over the successors of \a state.
///
/// The iterator has been allocated with \c new. It is the
/// responsability of the caller to \c delete it when no
/// longer needed.
///
virtual ta_succ_iterator*
succ_iter(const spot::state* state) const = 0;
/// \brief Get an iterator over the successors of \a state
/// filtred by the changeset on transitions
///
/// The iterator has been allocated with \c new. It is the
/// responsability of the caller to \c delete it when no
/// longer needed.
///
virtual ta_succ_iterator*
succ_iter(const spot::state* state, bdd changeset) const = 0;
/// \brief Get the dictionary associated to the automaton.
///
/// State are represented as BDDs. The dictionary allows
/// to map BDD variables back to formulae, and vice versa.
/// This is useful when dealing with several automata (which
/// may use the same BDD variable for different formula),
/// or simply when printing.
bdd_dict_ptr
get_dict() const
{
return dict_;
}
/// \brief Format the state as a string for printing.
///
/// This formating is the responsability of the automata
/// that owns the state.
virtual std::string
format_state(const spot::state* s) const = 0;
/// \brief Return true if \a s is a Buchi-accepting state, otherwise false
virtual bool
is_accepting_state(const spot::state* s) const = 0;
/// \brief Return true if \a s is a livelock-accepting state
/// , otherwise false
virtual bool
is_livelock_accepting_state(const spot::state* s) const = 0;
/// \brief Return true if \a s is an initial state, otherwise false
virtual bool
is_initial_state(const spot::state* s) const = 0;
/// \brief Return a BDD condition that represents the valuation
/// of atomic propositions in the state \a s
virtual bdd
get_state_condition(const spot::state* s) const = 0;
/// \brief Release a state \a s
virtual void
free_state(const spot::state* s) const = 0;
const acc_cond& acc() const
{
return acc_;
}
acc_cond& acc()
{
return acc_;
}
};
typedef std::shared_ptr<ta> ta_ptr;
typedef std::shared_ptr<const ta> const_ta_ptr;
/// \ingroup ta_essentials
/// \brief Iterate over the successors of a state.
///
/// This class provides the basic functionalities required to
/// iterate over the successors of a state, as well as querying
/// transition labels. Because transitions are never explicitely
/// encoded, labels (conditions and acceptance conditions) can only
/// be queried while iterating over the successors.
class ta_succ_iterator : public twa_succ_iterator
{
public:
virtual
~ta_succ_iterator()
{
}
virtual bool first() = 0;
virtual bool next() = 0;
virtual bool done() const = 0;
virtual const state* dst() const = 0;
/// \brief Get the changeset on the transition leading to current successor.
///
/// This is a boolean function of atomic propositions.
virtual bdd cond() const = 0;
acc_cond::mark_t acc() const = 0;
};
#ifndef SWIG
// A stack of Strongly-Connected Components
class scc_stack_ta
{
public:
struct connected_component
{
public:
connected_component(int index = -1);
/// Index of the SCC.
int index;
bool is_accepting;
/// The bdd condition is the union of all acceptance conditions of
/// transitions which connect the states of the connected component.
acc_cond::mark_t condition;
std::list<const state*> rem;
};
/// Stack a new SCC with index \a index.
void
push(int index);
/// Access the top SCC.
connected_component&
top();
/// Access the top SCC.
const connected_component&
top() const;
/// Pop the top SCC.
void
pop();
/// How many SCC are in stack.
size_t
size() const;
/// The \c rem member of the top SCC.
std::list<const state*>&
rem();
/// Is the stack empty?
bool
empty() const;
typedef std::list<connected_component> stack_type;
stack_type s;
};
#endif // !SWIG
/// \addtogroup ta_representation TA representations
/// \ingroup ta
/// \addtogroup ta_algorithms TA algorithms
/// \ingroup ta
/// \addtogroup ta_io Input/Output of TA
/// \ingroup ta_algorithms
/// \addtogroup tgba_ta Transforming TGBA into TA
/// \ingroup ta_algorithms
/// \addtogroup ta_generic Algorithm patterns
/// \ingroup ta_algorithms
/// \addtogroup ta_reduction TA simplifications
/// \ingroup ta_algorithms
/// \addtogroup ta_misc Miscellaneous algorithms on TA
/// \ingroup ta_algorithms
}

543
spot/ta/taexplicit.cc Normal file
View file

@ -0,0 +1,543 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015 Laboratoire de
// Recherche et Développement de l'Epita (LRDE).
//
// This file is part of Spot, a model checking library.
//
// Spot 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 3 of the License, or
// (at your option) any later version.
//
// Spot 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, see <http://www.gnu.org/licenses/>.
//#define TRACE
#include <iostream>
#ifdef TRACE
#define trace std::clog
#else
#define trace while (0) std::clog
#endif
#include <spot/ta/taexplicit.hh>
#include <spot/twa/formula2bdd.hh>
#include <cassert>
#include <spot/twa/bddprint.hh>
namespace spot
{
////////////////////////////////////////
// ta_explicit_succ_iterator
ta_explicit_succ_iterator::ta_explicit_succ_iterator(
const state_ta_explicit* s)
{
transitions_ = s->get_transitions();
}
ta_explicit_succ_iterator::ta_explicit_succ_iterator(
const state_ta_explicit* s, bdd condition)
{
transitions_ = s->get_transitions(condition);
}
bool
ta_explicit_succ_iterator::first()
{
if (!transitions_)
return false;
i_ = transitions_->begin();
return i_ != transitions_->end();
}
bool
ta_explicit_succ_iterator::next()
{
++i_;
return i_ != transitions_->end();
}
bool
ta_explicit_succ_iterator::done() const
{
return !transitions_ || i_ == transitions_->end();
}
const state*
ta_explicit_succ_iterator::dst() const
{
trace
<< "***ta_explicit_succ_iterator::dst() if(done()) =***"
<< done() << std::endl;
assert(!done());
trace
<< "***ta_explicit_succ_iterator::dst() (*i_)->condition =***"
<< (*i_)->condition << std::endl;
return (*i_)->dest;
}
bdd
ta_explicit_succ_iterator::cond() const
{
assert(!done());
return (*i_)->condition;
}
acc_cond::mark_t
ta_explicit_succ_iterator::acc() const
{
assert(!done());
return (*i_)->acceptance_conditions;
}
////////////////////////////////////////
// state_ta_explicit
state_ta_explicit::transitions*
state_ta_explicit::get_transitions() const
{
return transitions_;
}
// return transitions filtred by condition
state_ta_explicit::transitions*
state_ta_explicit::get_transitions(bdd condition) const
{
std::unordered_map<int, transitions*, std::hash<int> >::const_iterator i =
transitions_by_condition.find(condition.id());
if (i == transitions_by_condition.end())
return nullptr;
else
return i->second;
}
void
state_ta_explicit::add_transition(state_ta_explicit::transition* t,
bool add_at_beginning)
{
if (!transitions_)
transitions_ = new transitions;
transitions* trans_by_condition = get_transitions(t->condition);
if (!trans_by_condition)
{
trans_by_condition = new transitions;
transitions_by_condition[(t->condition).id()] = trans_by_condition;
}
state_ta_explicit::transitions::iterator it_trans;
bool transition_found = false;
for (it_trans = trans_by_condition->begin(); (it_trans
!= trans_by_condition->end() && !transition_found); ++it_trans)
{
transition_found = ((*it_trans)->dest == t->dest);
if (transition_found)
{
(*it_trans)->acceptance_conditions |= t->acceptance_conditions;
}
}
if (!transition_found)
{
if (add_at_beginning)
{
trans_by_condition->push_front(t);
transitions_->push_front(t);
}
else
{
trans_by_condition->push_back(t);
transitions_->push_back(t);
}
}
else
{
delete t;
}
}
const state*
state_ta_explicit::get_tgba_state() const
{
return tgba_state_;
}
const bdd
state_ta_explicit::get_tgba_condition() const
{
return tgba_condition_;
}
bool
state_ta_explicit::is_accepting_state() const
{
return is_accepting_state_;
}
bool
state_ta_explicit::is_initial_state() const
{
return is_initial_state_;
}
void
state_ta_explicit::set_accepting_state(bool is_accepting_state)
{
is_accepting_state_ = is_accepting_state;
}
bool
state_ta_explicit::is_livelock_accepting_state() const
{
return is_livelock_accepting_state_;
}
void
state_ta_explicit::set_livelock_accepting_state(
bool is_livelock_accepting_state)
{
is_livelock_accepting_state_ = is_livelock_accepting_state;
}
void
state_ta_explicit::set_initial_state(bool is_initial_state)
{
is_initial_state_ = is_initial_state;
}
bool
state_ta_explicit::is_hole_state() const
{
state_ta_explicit::transitions* trans = get_transitions();
return !trans || trans->empty();
}
int
state_ta_explicit::compare(const spot::state* other) const
{
const state_ta_explicit* o = down_cast<const state_ta_explicit*>(other);
assert(o);
int compare_value = tgba_state_->compare(o->tgba_state_);
if (compare_value)
return compare_value;
compare_value = tgba_condition_.id() - o->tgba_condition_.id();
// if (compare_value != 0)
// return compare_value;
//
// //unique artificial_livelock_accepting_state
// if (o->is_the_artificial_livelock_accepting_state())
// return is_the_artificial_livelock_accepting_state();
return compare_value;
}
size_t
state_ta_explicit::hash() const
{
//return wang32_hash(tgba_state_->hash());
return wang32_hash(tgba_state_->hash()) ^ wang32_hash(tgba_condition_.id());
}
state_ta_explicit*
state_ta_explicit::clone() const
{
return new state_ta_explicit(*this);
}
void
state_ta_explicit::delete_stuttering_and_hole_successors()
{
state_ta_explicit::transitions* trans = get_transitions();
state_ta_explicit::transitions::iterator it_trans;
if (trans)
for (it_trans = trans->begin(); it_trans != trans->end();)
{
auto dest = (*it_trans)->dest;
bool is_stuttering_transition = (get_tgba_condition()
== (dest)->get_tgba_condition());
bool dest_is_livelock_accepting =
dest->is_livelock_accepting_state();
//Before deleting stuttering transitions, propaged back livelock
//and initial state's properties
if (is_stuttering_transition)
{
if (!is_livelock_accepting_state() && dest_is_livelock_accepting)
{
set_livelock_accepting_state(true);
stuttering_reachable_livelock
= dest->stuttering_reachable_livelock;
}
if (dest->is_initial_state())
set_initial_state(true);
}
//remove hole successors states
state_ta_explicit::transitions* dest_trans =
(dest)->get_transitions();
bool dest_trans_empty = !dest_trans || dest_trans->empty();
if (is_stuttering_transition || (dest_trans_empty
&& (!dest_is_livelock_accepting)))
{
get_transitions((*it_trans)->condition)->remove(*it_trans);
delete *it_trans;
it_trans = trans->erase(it_trans);
}
else
{
++it_trans;
}
}
}
void
state_ta_explicit::free_transitions()
{
state_ta_explicit::transitions* trans = transitions_;
// We don't destroy the transitions in the state's destructor because
// they are not cloned.
if (trans)
for (auto& t: *trans)
delete t;
delete trans;
std::unordered_map<int, transitions*, std::hash<int> >::iterator i =
transitions_by_condition.begin();
while (i != transitions_by_condition.end())
{
delete i->second;
++i;
}
transitions_ = nullptr;
}
////////////////////////////////////////
// ta_explicit
ta_explicit::ta_explicit(const const_twa_ptr& tgba,
unsigned n_acc,
state_ta_explicit* artificial_initial_state):
ta(tgba->get_dict()),
tgba_(tgba),
artificial_initial_state_(artificial_initial_state)
{
get_dict()->register_all_variables_of(&tgba_, this);
acc().add_sets(n_acc);
acc().set_generalized_buchi();
if (artificial_initial_state)
{
auto is = add_state(artificial_initial_state);
assert(is == artificial_initial_state);
(void)is;
}
}
ta_explicit::~ta_explicit()
{
ta::states_set_t::iterator it;
for (it = states_set_.begin(); it != states_set_.end(); ++it)
{
auto* s = const_cast<state_ta_explicit*>
(down_cast<const state_ta_explicit*>(*it));
s->free_transitions();
s->get_tgba_state()->destroy();
delete s;
}
get_dict()->unregister_all_my_variables(this);
}
state_ta_explicit*
ta_explicit::add_state(state_ta_explicit* s)
{
std::pair<ta::states_set_t::iterator, bool> add_state_to_ta =
states_set_.insert(s);
return down_cast<state_ta_explicit*>(*add_state_to_ta.first);
}
void
ta_explicit::add_to_initial_states_set(state* state, bdd condition)
{
state_ta_explicit* s = down_cast<state_ta_explicit*>(state);
s->set_initial_state(true);
if (condition == bddfalse)
condition = get_state_condition(s);
auto add_state = initial_states_set_.insert(s);
if (get_artificial_initial_state())
if (add_state.second)
{
auto i =
down_cast<state_ta_explicit*>(get_artificial_initial_state());
create_transition(i, condition, 0U, s);
}
}
void
ta_explicit::delete_stuttering_and_hole_successors(const spot::state* s)
{
auto state =
const_cast<state_ta_explicit*>(down_cast<const state_ta_explicit*>(s));
assert(state);
state->delete_stuttering_and_hole_successors();
if (state->is_initial_state())
add_to_initial_states_set(state);
}
void
ta_explicit::create_transition(state_ta_explicit* source, bdd condition,
acc_cond::mark_t acceptance_conditions,
const state_ta_explicit* dest,
bool add_at_beginning)
{
state_ta_explicit::transition* t = new state_ta_explicit::transition;
t->dest = dest;
t->condition = condition;
t->acceptance_conditions = acceptance_conditions;
source->add_transition(t, add_at_beginning);
}
ta::const_states_set_t
ta_explicit::get_initial_states_set() const
{
return initial_states_set_;
}
bdd
ta_explicit::get_state_condition(const spot::state* initial_state) const
{
const state_ta_explicit* sta =
down_cast<const state_ta_explicit*>(initial_state);
assert(sta);
return sta->get_tgba_condition();
}
bool
ta_explicit::is_accepting_state(const spot::state* s) const
{
const state_ta_explicit* sta = down_cast<const state_ta_explicit*>(s);
assert(sta);
return sta->is_accepting_state();
}
bool
ta_explicit::is_initial_state(const spot::state* s) const
{
const state_ta_explicit* sta = down_cast<const state_ta_explicit*>(s);
assert(sta);
return sta->is_initial_state();
}
bool
ta_explicit::is_livelock_accepting_state(const spot::state* s) const
{
const state_ta_explicit* sta = down_cast<const state_ta_explicit*>(s);
assert(sta);
return sta->is_livelock_accepting_state();
}
ta_succ_iterator*
ta_explicit::succ_iter(const spot::state* state) const
{
const state_ta_explicit* s = down_cast<const state_ta_explicit*>(state);
assert(s);
return new ta_explicit_succ_iterator(s);
}
ta_succ_iterator*
ta_explicit::succ_iter(const spot::state* state, bdd condition) const
{
const state_ta_explicit* s = down_cast<const state_ta_explicit*>(state);
assert(s);
return new ta_explicit_succ_iterator(s, condition);
}
bdd_dict_ptr
ta_explicit::get_dict() const
{
return tgba_->get_dict();
}
const_twa_ptr
ta_explicit::get_tgba() const
{
return tgba_;
}
std::string
ta_explicit::format_state(const spot::state* s) const
{
const state_ta_explicit* sta = down_cast<const state_ta_explicit*>(s);
assert(sta);
if (sta->get_tgba_condition() == bddtrue)
return tgba_->format_state(sta->get_tgba_state());
return tgba_->format_state(sta->get_tgba_state()) + "\n"
+ bdd_format_formula(get_dict(), sta->get_tgba_condition());
}
void
ta_explicit::delete_stuttering_transitions()
{
ta::states_set_t::iterator it;
for (it = states_set_.begin(); it != states_set_.end(); ++it)
{
const state_ta_explicit* source =
static_cast<const state_ta_explicit*>(*it);
state_ta_explicit::transitions* trans = source->get_transitions();
state_ta_explicit::transitions::iterator it_trans;
if (trans)
for (it_trans = trans->begin(); it_trans != trans->end();)
{
if (source->get_tgba_condition()
== ((*it_trans)->dest)->get_tgba_condition())
{
delete *it_trans;
it_trans = trans->erase(it_trans);
}
else
{
++it_trans;
}
}
}
}
void
ta_explicit::free_state(const spot::state*) const
{
}
}

261
spot/ta/taexplicit.hh Normal file
View file

@ -0,0 +1,261 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015 Laboratoire de
// Recherche et Développement de l'Epita (LRDE).
//
// This file is part of Spot, a model checking library.
//
// Spot 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 3 of the License, or
// (at your option) any later version.
//
// Spot 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, see <http://www.gnu.org/licenses/>.
#pragma once
#include <spot/misc/hash.hh>
#include <list>
#include <spot/twa/twa.hh>
#include <set>
#include <spot/tl/formula.hh>
#include <cassert>
#include <spot/misc/bddlt.hh>
#include <spot/ta/ta.hh>
namespace spot
{
// Forward declarations. See below.
class state_ta_explicit;
class ta_explicit_succ_iterator;
class ta_explicit;
/// Explicit representation of a spot::ta.
/// \ingroup ta_representation
class SPOT_API ta_explicit : public ta
{
public:
ta_explicit(const const_twa_ptr& tgba,
unsigned n_acc,
state_ta_explicit* artificial_initial_state = nullptr);
const_twa_ptr
get_tgba() const;
state_ta_explicit*
add_state(state_ta_explicit* s);
void
add_to_initial_states_set(state* s, bdd condition = bddfalse);
void
create_transition(state_ta_explicit* source, bdd condition,
acc_cond::mark_t acceptance_conditions,
const state_ta_explicit* dest,
bool add_at_beginning = false);
void
delete_stuttering_transitions();
// ta interface
virtual
~ta_explicit();
virtual const_states_set_t
get_initial_states_set() const;
virtual ta_succ_iterator*
succ_iter(const spot::state* s) const;
virtual ta_succ_iterator*
succ_iter(const spot::state* s, bdd condition) const;
virtual bdd_dict_ptr
get_dict() const;
virtual std::string
format_state(const spot::state* s) const;
virtual bool
is_accepting_state(const spot::state* s) const;
virtual bool
is_livelock_accepting_state(const spot::state* s) const;
virtual bool
is_initial_state(const spot::state* s) const;
virtual bdd
get_state_condition(const spot::state* s) const;
virtual void
free_state(const spot::state* s) const;
spot::state*
get_artificial_initial_state() const
{
return (spot::state*) artificial_initial_state_;
}
void
set_artificial_initial_state(state_ta_explicit* s)
{
artificial_initial_state_ = s;
}
virtual void
delete_stuttering_and_hole_successors(const spot::state* s);
ta::states_set_t
get_states_set()
{
return states_set_;
}
private:
// Disallow copy.
ta_explicit(const ta_explicit& other) = delete;
ta_explicit& operator=(const ta_explicit& other) = delete;
const_twa_ptr tgba_;
state_ta_explicit* artificial_initial_state_;
ta::states_set_t states_set_;
ta::const_states_set_t initial_states_set_;
};
/// states used by spot::ta_explicit.
/// \ingroup ta_representation
class SPOT_API state_ta_explicit : public spot::state
{
#ifndef SWIG
public:
/// Explicit transitions.
struct transition
{
bdd condition;
acc_cond::mark_t acceptance_conditions;
const state_ta_explicit* dest;
};
typedef std::list<transition*> transitions;
state_ta_explicit(const state* tgba_state, const bdd tgba_condition,
bool is_initial_state = false,
bool is_accepting_state = false,
bool is_livelock_accepting_state = false,
transitions* trans = nullptr) :
tgba_state_(tgba_state), tgba_condition_(tgba_condition),
is_initial_state_(is_initial_state), is_accepting_state_(
is_accepting_state), is_livelock_accepting_state_(
is_livelock_accepting_state), transitions_(trans)
{
}
virtual int
compare(const spot::state* other) const;
virtual size_t
hash() const;
virtual state_ta_explicit*
clone() const;
virtual void
destroy() const
{
}
virtual
~state_ta_explicit()
{
}
transitions*
get_transitions() const;
// return transitions filtred by condition
transitions*
get_transitions(bdd condition) const;
void
add_transition(transition* t, bool add_at_beginning = false);
const state*
get_tgba_state() const;
const bdd
get_tgba_condition() const;
bool
is_accepting_state() const;
void
set_accepting_state(bool is_accepting_state);
bool
is_livelock_accepting_state() const;
void
set_livelock_accepting_state(bool is_livelock_accepting_state);
bool
is_initial_state() const;
void
set_initial_state(bool is_initial_state);
/// \brief Return true if the state has no successors
bool
is_hole_state() const;
/// \brief Remove stuttering transitions
/// and transitions leading to states having no successors
void
delete_stuttering_and_hole_successors();
void
free_transitions();
state_ta_explicit* stuttering_reachable_livelock;
private:
const state* tgba_state_;
const bdd tgba_condition_;
bool is_initial_state_;
bool is_accepting_state_;
bool is_livelock_accepting_state_;
transitions* transitions_;
std::unordered_map<int, transitions*, std::hash<int>>
transitions_by_condition;
#endif // !SWIG
};
/// Successor iterators used by spot::ta_explicit.
class SPOT_API ta_explicit_succ_iterator : public ta_succ_iterator
{
public:
ta_explicit_succ_iterator(const state_ta_explicit* s);
ta_explicit_succ_iterator(const state_ta_explicit* s, bdd condition);
virtual bool first();
virtual bool next();
virtual bool done() const;
virtual const state* dst() const;
virtual bdd cond() const;
virtual acc_cond::mark_t acc() const;
private:
state_ta_explicit::transitions* transitions_;
state_ta_explicit::transitions::const_iterator i_;
};
typedef std::shared_ptr<ta_explicit> ta_explicit_ptr;
typedef std::shared_ptr<const ta_explicit> const_ta_explicit_ptr;
inline ta_explicit_ptr
make_ta_explicit(const const_twa_ptr& tgba,
unsigned n_acc,
state_ta_explicit* artificial_initial_state = nullptr)
{
return std::make_shared<ta_explicit>(tgba, n_acc, artificial_initial_state);
}
}

454
spot/ta/taproduct.cc Normal file
View file

@ -0,0 +1,454 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2011, 2012, 2014, 2015 Laboratoire de Recherche et
// Développement de l'Epita (LRDE).
//
//
// This file is part of Spot, a model checking library.
//
// Spot 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 3 of the License, or
// (at your option) any later version.
//
// Spot 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, see <http://www.gnu.org/licenses/>.
#include <spot/ta/taproduct.hh>
#include <cassert>
#include <spot/misc/hashfunc.hh>
namespace spot
{
////////////////////////////////////////////////////////////
// state_ta_product
state_ta_product::state_ta_product(const state_ta_product& o) :
state(), ta_state_(o.get_ta_state()), kripke_state_(
o.get_kripke_state()->clone())
{
}
state_ta_product::~state_ta_product()
{
//see ta_product::free_state() method
kripke_state_->destroy();
}
int
state_ta_product::compare(const state* other) const
{
const state_ta_product* o = down_cast<const state_ta_product*> (other);
assert(o);
int res = ta_state_->compare(o->get_ta_state());
if (res != 0)
return res;
return kripke_state_->compare(o->get_kripke_state());
}
size_t
state_ta_product::hash() const
{
// We assume that size_t is 32-bit wide.
return wang32_hash(ta_state_->hash()) ^ wang32_hash(kripke_state_->hash());
}
state_ta_product*
state_ta_product::clone() const
{
return new state_ta_product(*this);
}
////////////////////////////////////////////////////////////
// ta_succ_iterator_product
ta_succ_iterator_product::ta_succ_iterator_product(const state_ta_product* s,
const ta* t,
const kripke* k)
: source_(s), ta_(t), kripke_(k)
{
kripke_source_condition = kripke_->state_condition(s->get_kripke_state());
kripke_succ_it_ = kripke_->succ_iter(s->get_kripke_state());
kripke_current_dest_state = nullptr;
ta_succ_it_ = nullptr;
current_state_ = nullptr;
}
ta_succ_iterator_product::~ta_succ_iterator_product()
{
delete current_state_;
current_state_ = nullptr;
delete ta_succ_it_;
delete kripke_succ_it_;
if (kripke_current_dest_state)
kripke_current_dest_state->destroy();
}
void
ta_succ_iterator_product::step_()
{
if (!ta_succ_it_->done())
ta_succ_it_->next();
if (ta_succ_it_->done())
{
delete ta_succ_it_;
ta_succ_it_ = nullptr;
next_kripke_dest();
}
}
void
ta_succ_iterator_product::next_kripke_dest()
{
if (!kripke_succ_it_)
return;
if (!kripke_current_dest_state)
{
kripke_succ_it_->first();
}
else
{
kripke_current_dest_state->destroy();
kripke_current_dest_state = nullptr;
kripke_succ_it_->next();
}
// If one of the two successor sets is empty initially, we reset
// kripke_succ_it_, so that done() can detect this situation easily. (We
// choose to reset kripke_succ_it_ because this variable is already used by
// done().)
if (kripke_succ_it_->done())
{
delete kripke_succ_it_;
kripke_succ_it_ = nullptr;
return;
}
kripke_current_dest_state = kripke_succ_it_->dst();
bdd kripke_current_dest_condition = kripke_->state_condition(
kripke_current_dest_state);
is_stuttering_transition_ = (kripke_source_condition
== kripke_current_dest_condition);
if (is_stuttering_transition_)
{
current_condition_ = bddfalse;
}
else
{
current_condition_ = bdd_setxor(kripke_source_condition,
kripke_current_dest_condition);
ta_succ_it_ = ta_->succ_iter(source_->get_ta_state(),
current_condition_);
ta_succ_it_->first();
}
}
bool
ta_succ_iterator_product::first()
{
next_kripke_dest();
if (!done())
return next_non_stuttering_();
return false;
}
bool
ta_succ_iterator_product::next()
{
delete current_state_;
current_state_ = nullptr;
if (is_stuttering_transition())
{
next_kripke_dest();
}
else
step_();
if (!done())
return next_non_stuttering_();
return false;
}
bool
ta_succ_iterator_product::next_non_stuttering_()
{
while (!done())
{
if (is_stuttering_transition_)
{
//if stuttering transition, the TA automata stays in the same state
current_state_ = new state_ta_product(source_->get_ta_state(),
kripke_current_dest_state->clone());
current_acceptance_conditions_ = 0U;
return true;
}
if (!ta_succ_it_->done())
{
current_state_ = new state_ta_product(ta_succ_it_->dst(),
kripke_current_dest_state->clone());
current_acceptance_conditions_
= ta_succ_it_->acc();
return true;
}
step_();
}
return false;
}
bool
ta_succ_iterator_product::done() const
{
return !kripke_succ_it_ || kripke_succ_it_->done();
}
state_ta_product*
ta_succ_iterator_product::dst() const
{
return current_state_->clone();
}
bool
ta_succ_iterator_product::is_stuttering_transition() const
{
return is_stuttering_transition_;
}
bdd
ta_succ_iterator_product::cond() const
{
return current_condition_;
}
acc_cond::mark_t
ta_succ_iterator_product::acc() const
{
return current_acceptance_conditions_;
}
////////////////////////////////////////////////////////////
// ta_product
ta_product::ta_product(const const_ta_ptr& testing_automata,
const const_kripke_ptr& kripke_structure):
ta(testing_automata->get_dict()),
dict_(testing_automata->get_dict()),
ta_(testing_automata),
kripke_(kripke_structure)
{
assert(dict_ == kripke_structure->get_dict());
dict_->register_all_variables_of(ta_, this);
dict_->register_all_variables_of(kripke_, this);
}
ta_product::~ta_product()
{
dict_->unregister_all_my_variables(this);
}
ta::const_states_set_t
ta_product::get_initial_states_set() const
{
//build initial states set
ta::const_states_set_t ta_init_states_set;
ta::const_states_set_t::const_iterator it;
ta::const_states_set_t initial_states_set;
const state* kripke_init = kripke_->get_init_state();
bdd kripke_init_condition = kripke_->state_condition(kripke_init);
const spot::state* artificial_initial_state =
ta_->get_artificial_initial_state();
if (artificial_initial_state)
{
ta_succ_iterator* ta_init_it_ = ta_->succ_iter(
artificial_initial_state, kripke_init_condition);
for (ta_init_it_->first(); !ta_init_it_->done(); ta_init_it_->next())
{
ta_init_states_set.insert(ta_init_it_->dst());
}
delete ta_init_it_;
}
else
{
ta_init_states_set = ta_->get_initial_states_set();
}
for (auto s: ta_init_states_set)
if (artificial_initial_state ||
(kripke_init_condition == ta_->get_state_condition(s)))
initial_states_set.insert(new state_ta_product(s,
kripke_init->clone()));
kripke_init->destroy();
return initial_states_set;
}
ta_succ_iterator_product*
ta_product::succ_iter(const state* s) const
{
const state_ta_product* stp = down_cast<const state_ta_product*> (s);
assert(s);
return new ta_succ_iterator_product(stp, ta_.get(), kripke_.get());
}
ta_succ_iterator_product*
ta_product::succ_iter(const spot::state* s, bdd changeset) const
{
const state_ta_product* stp = down_cast<const state_ta_product*> (s);
assert(s);
return new ta_succ_iterator_product_by_changeset(stp,
ta_.get(), kripke_.get(),
changeset);
}
bdd_dict_ptr
ta_product::get_dict() const
{
return dict_;
}
std::string
ta_product::format_state(const state* state) const
{
const state_ta_product* s = down_cast<const state_ta_product*> (state);
assert(s);
return kripke_->format_state(s->get_kripke_state()) + " * \n"
+ ta_->format_state(s->get_ta_state());
}
bool
ta_product::is_accepting_state(const spot::state* s) const
{
const state_ta_product* stp = down_cast<const state_ta_product*> (s);
assert(stp);
return ta_->is_accepting_state(stp->get_ta_state());
}
bool
ta_product::is_livelock_accepting_state(const spot::state* s) const
{
const state_ta_product* stp = down_cast<const state_ta_product*> (s);
assert(stp);
return ta_->is_livelock_accepting_state(stp->get_ta_state());
}
bool
ta_product::is_initial_state(const spot::state* s) const
{
const state_ta_product* stp = down_cast<const state_ta_product*> (s);
assert(stp);
const state* ta_s = stp->get_ta_state();
const state* kr_s = stp->get_kripke_state();
return (ta_->is_initial_state(ta_s))
&& ((kripke_->get_init_state())->compare(kr_s) == 0)
&& ((kripke_->state_condition(kr_s))
== (ta_->get_state_condition(ta_s)));
}
bool
ta_product::is_hole_state_in_ta_component(const spot::state* s) const
{
const state_ta_product* stp = down_cast<const state_ta_product*> (s);
ta_succ_iterator* ta_succ_iter = get_ta()->succ_iter(stp->get_ta_state());
bool is_hole_state = ta_succ_iter->done();
delete ta_succ_iter;
return is_hole_state;
}
bdd
ta_product::get_state_condition(const spot::state* s) const
{
const state_ta_product* stp = down_cast<const state_ta_product*> (s);
assert(stp);
const state* ta_s = stp->get_ta_state();
return ta_->get_state_condition(ta_s);
}
void
ta_product::free_state(const spot::state* s) const
{
const state_ta_product* stp = down_cast<const state_ta_product*> (s);
assert(stp);
ta_->free_state(stp->get_ta_state());
delete stp;
}
ta_succ_iterator_product_by_changeset::
ta_succ_iterator_product_by_changeset(const state_ta_product* s, const ta* t,
const kripke* k, bdd changeset)
: ta_succ_iterator_product(s, t, k)
{
current_condition_ = changeset;
}
void
ta_succ_iterator_product_by_changeset::next_kripke_dest()
{
if (!kripke_succ_it_)
return;
if (!kripke_current_dest_state)
{
kripke_succ_it_->first();
}
else
{
kripke_current_dest_state->destroy();
kripke_current_dest_state = nullptr;
kripke_succ_it_->next();
}
// If one of the two successor sets is empty initially, we reset
// kripke_succ_it_, so that done() can detect this situation easily. (We
// choose to reset kripke_succ_it_ because this variable is already used by
// done().)
if (kripke_succ_it_->done())
{
delete kripke_succ_it_;
kripke_succ_it_ = nullptr;
return;
}
kripke_current_dest_state = kripke_succ_it_->dst();
bdd kripke_current_dest_condition = kripke_->state_condition(
kripke_current_dest_state);
if (current_condition_ != bdd_setxor(kripke_source_condition,
kripke_current_dest_condition))
next_kripke_dest();
is_stuttering_transition_ = (kripke_source_condition
== kripke_current_dest_condition);
if (!is_stuttering_transition_)
{
ta_succ_it_ = ta_->succ_iter(source_->get_ta_state(),
current_condition_);
ta_succ_it_->first();
}
}
}

221
spot/ta/taproduct.hh Normal file
View file

@ -0,0 +1,221 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2011, 2012, 2013, 2014 Laboratoire de Recherche et
// Développement de l'Epita (LRDE).
//
// This file is part of Spot, a model checking library.
//
// Spot 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 3 of the License, or
// (at your option) any later version.
//
// Spot 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, see <http://www.gnu.org/licenses/>.
#pragma once
#include <spot/ta/ta.hh>
#include <spot/kripke/kripke.hh>
namespace spot
{
/// \ingroup ta_emptiness_check
/// \brief A state for spot::ta_product.
///
/// This state is in fact a pair of state: the state from the TA
/// automaton and that of Kripke structure.
class SPOT_API state_ta_product : public state
{
public:
/// \brief Constructor
/// \param ta_state The state from the ta automaton.
/// \param kripke_state The state from Kripke structure.
state_ta_product(const state* ta_state, const state* kripke_state) :
ta_state_(ta_state), kripke_state_(kripke_state)
{
}
/// Copy constructor
state_ta_product(const state_ta_product& o);
virtual
~state_ta_product();
const state*
get_ta_state() const
{
return ta_state_;
}
const state*
get_kripke_state() const
{
return kripke_state_;
}
virtual int
compare(const state* other) const;
virtual size_t
hash() const;
virtual state_ta_product*
clone() const;
private:
const state* ta_state_; ///< State from the ta automaton.
const state* kripke_state_; ///< State from the kripke structure.
};
/// \brief Iterate over the successors of a product computed on the fly.
class SPOT_API ta_succ_iterator_product : public ta_succ_iterator
{
public:
ta_succ_iterator_product(const state_ta_product* s, const ta* t,
const kripke* k);
virtual
~ta_succ_iterator_product();
// iteration
bool first();
bool next();
bool done() const;
// inspection
state_ta_product*
dst() const;
bdd
cond() const;
acc_cond::mark_t
acc() const;
/// \brief Return true if the changeset of the current transition is empty
bool
is_stuttering_transition() const;
protected:
//@{
/// Internal routines to advance to the next successor.
void step_();
bool next_non_stuttering_();
/// \brief Move to the next successor in the kripke structure
void
next_kripke_dest();
//@}
protected:
const state_ta_product* source_;
const ta* ta_;
const kripke* kripke_;
ta_succ_iterator* ta_succ_it_;
twa_succ_iterator* kripke_succ_it_;
const state_ta_product* current_state_;
bdd current_condition_;
acc_cond::mark_t current_acceptance_conditions_;
bool is_stuttering_transition_;
bdd kripke_source_condition;
const state* kripke_current_dest_state;
};
/// \ingroup ta_emptiness_check
/// \brief A lazy product between a Testing automaton and a Kripke structure.
/// (States are computed on the fly.)
class SPOT_API ta_product: public ta
{
public:
/// \brief Constructor.
/// \param testing_automaton The TA component in the product.
/// \param kripke_structure The Kripke component in the product.
ta_product(const const_ta_ptr& testing_automaton,
const const_kripke_ptr& kripke_structure);
virtual
~ta_product();
virtual ta::const_states_set_t
get_initial_states_set() const;
virtual ta_succ_iterator_product*
succ_iter(const spot::state* s) const;
virtual ta_succ_iterator_product*
succ_iter(const spot::state* s, bdd changeset) const;
virtual bdd_dict_ptr
get_dict() const;
virtual std::string
format_state(const spot::state* s) const;
virtual bool
is_accepting_state(const spot::state* s) const;
virtual bool
is_livelock_accepting_state(const spot::state* s) const;
virtual bool
is_initial_state(const spot::state* s) const;
/// \brief Return true if the state \a s has no succeseurs
/// in the TA automaton (the TA component of the product automaton)
virtual bool
is_hole_state_in_ta_component(const spot::state* s) const;
virtual bdd
get_state_condition(const spot::state* s) const;
virtual void
free_state(const spot::state* s) const;
const const_ta_ptr&
get_ta() const
{
return ta_;
}
const const_kripke_ptr&
get_kripke() const
{
return kripke_;
}
private:
bdd_dict_ptr dict_;
const_ta_ptr ta_;
const_kripke_ptr kripke_;
// Disallow copy.
ta_product(const ta_product&) = delete;
ta_product& operator=(const ta_product&) = delete;
};
typedef std::shared_ptr<ta_product> ta_product_ptr;
typedef std::shared_ptr<const ta_product> const_ta_product_ptr;
inline ta_product_ptr product(const const_ta_ptr& testing_automaton,
const const_kripke_ptr& kripke_structure)
{
return std::make_shared<ta_product>(testing_automaton, kripke_structure);
}
class SPOT_API ta_succ_iterator_product_by_changeset :
public ta_succ_iterator_product
{
public:
ta_succ_iterator_product_by_changeset(const state_ta_product* s,
const ta* t, const kripke* k,
bdd changeset);
/// \brief Move to the next successor in the Kripke structure
void next_kripke_dest();
};
}

87
spot/ta/tgta.hh Normal file
View file

@ -0,0 +1,87 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015 Laboratoire de
// Recherche et Développement de l'Epita (LRDE).
//
// This file is part of Spot, a model checking library.
//
// Spot 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 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANta_explicitBILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more deta_explicitils.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#pragma once
#include <spot/twa/twa.hh>
namespace spot
{
/// \ingroup ta_essentials
/// \brief A Transition-based Generalized Testing Automaton (TGTA).
///
/// Transition-based Generalized Testing Automaton (TGTA) is a new
/// kind of automaton that combines features from both TA and TGBA.
/// From TA, we take the idea of labeling transitions with
/// changesets, however we remove the use of livelock-acceptance
/// (because it may require a two-pass emptiness check), and the
/// implicit stuttering. From TGBA, we inherit the use of
/// transition-based generalized acceptance conditions. The
/// resulting Chimera, which we call "Transition-based Generalized
/// Testing Automaton" (TGTA), accepts only stuttering-insensitive
/// languages like TA, and inherits advantages from both TA and
/// TGBA: it has a simple one-pass emptiness-check procedure (the
/// same as algorithm the one for TGBA), and can benefit from
/// reductions based on the stuttering of the properties pretty much
/// like a TA. Livelock acceptance states, which are no longer
/// supported are emulated using states with a Büchi accepting
/// self-loop labeled by empty changeset.
///
/// Browsing such automaton can be achieved using two functions:
/// \c get_initial_state and \c
/// succ_iter. The former returns the initial state(s) while the latter lists
/// the successor states of any state. A second implementation of \c succ_iter
/// returns only the successors reached through a changeset passed as
/// a parameter.
///
/// Note that although this is a transition-based automata,
/// we never represent transitions! Transition informations are
/// obtained by querying the iterator over the successors of
/// a state.
class SPOT_API tgta : public twa
{
protected:
tgta(const bdd_dict_ptr& d)
: twa(d)
{
}
public:
virtual ~tgta()
{
}
/// \brief Get an iterator over the successors of \a state
/// filtred by the value of the changeset on transitions between the
/// \a state and his successors
///
/// The iterator has been allocated with \c new. It is the
/// responsability of the caller to \c delete it when no
/// longer needed.
///
virtual twa_succ_iterator*
succ_iter_by_changeset(const spot::state* s, bdd change_set) const =0;
};
typedef std::shared_ptr<tgta> tgta_ptr;
typedef std::shared_ptr<const tgta> const_tgta_ptr;
}

73
spot/ta/tgtaexplicit.cc Normal file
View file

@ -0,0 +1,73 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2010, 2011, 2012, 2014, 2015 Laboratoire de Recherche
// et Developpement de l'Epita (LRDE).
//
// This file is part of Spot, a model checking library.
//
// Spot 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 3 of the License, or
// (at your option) any later version.
//
// Spot 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, see <http://www.gnu.org/licenses/>.
#include <spot/ta/tgtaexplicit.hh>
#include <spot/twa/formula2bdd.hh>
#include <spot/twa/bddprint.hh>
namespace spot
{
tgta_explicit::tgta_explicit(const const_twa_ptr& tgba,
unsigned n_acc,
state_ta_explicit* artificial_initial_state) :
tgta(tgba->get_dict()),
ta_(make_ta_explicit(tgba, n_acc, artificial_initial_state))
{
}
state*
tgta_explicit::get_init_state() const
{
return ta_->get_artificial_initial_state();
}
twa_succ_iterator*
tgta_explicit::succ_iter(const spot::state* state) const
{
return ta_->succ_iter(state);
}
bdd
tgta_explicit::compute_support_conditions(const spot::state* in) const
{
const state_ta_explicit* s = down_cast<const state_ta_explicit*>(in);
assert(s);
return ta_->get_tgba()->support_conditions(s->get_tgba_state());
}
bdd_dict_ptr
tgta_explicit::get_dict() const
{
return ta_->get_dict();
}
std::string
tgta_explicit::format_state(const spot::state* s) const
{
return ta_->format_state(s);
}
spot::twa_succ_iterator*
tgta_explicit::succ_iter_by_changeset(const spot::state* s, bdd chngset) const
{
return ta_->succ_iter(s, chngset);
}
}

76
spot/ta/tgtaexplicit.hh Normal file
View file

@ -0,0 +1,76 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015 Laboratoire de
// Recherche et Développement de l'Epita (LRDE).
//
// This file is part of Spot, a model checking library.
//
// Spot 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 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANta_explicitBILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more deta_explicitils.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#pragma once
#include <spot/misc/hash.hh>
#include <list>
#include <spot/twa/twa.hh>
#include <set>
#include <spot/tl/formula.hh>
#include <cassert>
#include <spot/misc/bddlt.hh>
#include <spot/ta/taexplicit.hh>
#include <spot/ta/tgta.hh>
namespace spot
{
/// Explicit representation of a spot::tgta.
/// \ingroup ta_representation
class SPOT_API tgta_explicit : public tgta
{
public:
tgta_explicit(const const_twa_ptr& tgba,
unsigned n_acc,
state_ta_explicit* artificial_initial_state);
// tgba interface
virtual spot::state* get_init_state() const;
virtual twa_succ_iterator*
succ_iter(const spot::state* local_state) const;
virtual bdd_dict_ptr
get_dict() const;
const_ta_explicit_ptr get_ta() const { return ta_; }
ta_explicit_ptr get_ta() { return ta_; }
virtual std::string format_state(const spot::state* s) const;
virtual twa_succ_iterator*
succ_iter_by_changeset(const spot::state* s, bdd change_set) const;
protected:
virtual bdd compute_support_conditions(const spot::state* state) const;
ta_explicit_ptr ta_;
};
typedef std::shared_ptr<tgta_explicit> tgta_explicit_ptr;
typedef std::shared_ptr<const tgta_explicit> const_tgta_explicit_ptr;
inline tgta_explicit_ptr
make_tgta_explicit(const const_twa_ptr& tgba, unsigned n_acc,
state_ta_explicit* artificial_initial_state = nullptr)
{
return std::make_shared<tgta_explicit>(tgba, n_acc,
artificial_initial_state);
}
}

253
spot/ta/tgtaproduct.cc Normal file
View file

@ -0,0 +1,253 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2012, 2014, 2015 Laboratoire de Recherche et
// Développement de l Epita (LRDE).
//
// This file is part of Spot, a model checking library.
//
// Spot 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 3 of the License, or
// (at your option) any later version.
//
// Spot 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, see <http://www.gnu.org/licenses/>.
//#define TRACE
#include <iostream>
#ifdef TRACE
#define trace std::clog
#else
#define trace while (0) std::clog
#endif
#include <spot/ta/tgtaproduct.hh>
#include <string>
#include <cassert>
#include <spot/misc/hashfunc.hh>
#include <spot/kripke/kripke.hh>
namespace spot
{
////////////////////////////////////////////////////////////
// tgta_succ_iterator_product
////////////////////////////////////////////////////////////
// tgta_product
tgta_product::tgta_product(const const_kripke_ptr& left,
const const_tgta_ptr& right):
twa_product(left, right)
{
}
const state*
tgta_product::get_init_state() const
{
fixed_size_pool* p = const_cast<fixed_size_pool*> (&pool_);
return new (p->allocate()) state_product(left_->get_init_state(),
right_->get_init_state(), p);
}
twa_succ_iterator*
tgta_product::succ_iter(const state* state) const
{
const state_product* s = down_cast<const state_product*> (state);
assert(s);
fixed_size_pool* p = const_cast<fixed_size_pool*> (&pool_);
auto l = std::static_pointer_cast<const kripke>(left_);
auto r = std::static_pointer_cast<const tgta>(right_);
return new tgta_succ_iterator_product(s, l, r, p);
}
////////////////////////////////////////////////////////////
// tgbtgta_succ_iterator_product
tgta_succ_iterator_product::tgta_succ_iterator_product(
const state_product* s,
const const_kripke_ptr& k, const const_tgta_ptr& t,
fixed_size_pool* pool)
: source_(s), tgta_(t), kripke_(k), pool_(pool)
{
const state* tgta_init_state = tgta_->get_init_state();
if ((s->right())->compare(tgta_init_state) == 0)
source_ = nullptr;
if (!source_)
{
kripke_succ_it_ = nullptr;
kripke_current_dest_state = kripke_->get_init_state();
current_condition_
= kripke_->state_condition(kripke_current_dest_state);
tgta_succ_it_ = tgta_->succ_iter_by_changeset(
tgta_init_state, current_condition_);
tgta_succ_it_->first();
trace
<< "*** tgta_succ_it_->done() = ***" << tgta_succ_it_->done()
<< std::endl;
}
else
{
kripke_source_condition = kripke_->state_condition(s->left());
kripke_succ_it_ = kripke_->succ_iter(s->left());
kripke_current_dest_state = nullptr;
tgta_succ_it_ = nullptr;
}
tgta_init_state->destroy();
current_state_ = nullptr;
}
tgta_succ_iterator_product::~tgta_succ_iterator_product()
{
// ta_->free_state(current_state_);
if (current_state_)
current_state_->destroy();
current_state_ = nullptr;
delete tgta_succ_it_;
delete kripke_succ_it_;
if (kripke_current_dest_state)
kripke_current_dest_state->destroy();
}
void
tgta_succ_iterator_product::step_()
{
if (!tgta_succ_it_->done())
tgta_succ_it_->next();
if (tgta_succ_it_->done())
{
delete tgta_succ_it_;
tgta_succ_it_ = nullptr;
next_kripke_dest();
}
}
void
tgta_succ_iterator_product::next_kripke_dest()
{
if (!kripke_succ_it_)
return;
if (!kripke_current_dest_state)
{
kripke_succ_it_->first();
}
else
{
kripke_current_dest_state->destroy();
kripke_current_dest_state = nullptr;
kripke_succ_it_->next();
}
// If one of the two successor sets is empty initially, we reset
// kripke_succ_it_, so that done() can detect this situation
// easily. (We choose to reset kripke_succ_it_ because this
// variable is already used by done().)
if (kripke_succ_it_->done())
{
delete kripke_succ_it_;
kripke_succ_it_ = nullptr;
return;
}
kripke_current_dest_state = kripke_succ_it_->dst();
bdd kripke_current_dest_condition = kripke_->state_condition(
kripke_current_dest_state);
current_condition_ = bdd_setxor(kripke_source_condition,
kripke_current_dest_condition);
tgta_succ_it_ = tgta_->succ_iter_by_changeset(source_->right(),
current_condition_);
tgta_succ_it_->first();
}
bool
tgta_succ_iterator_product::first()
{
next_kripke_dest();
trace << "*** first() .... if(done()) = ***" << done() << std::endl;
return find_next_succ_();
}
bool
tgta_succ_iterator_product::next()
{
current_state_->destroy();
current_state_ = nullptr;
step_();
trace << "*** next() .... if(done()) = ***" << done() << std::endl;
return find_next_succ_();
}
bool
tgta_succ_iterator_product::find_next_succ_()
{
while (!done())
{
if (!tgta_succ_it_->done())
{
current_state_ = new (pool_->allocate()) state_product(
kripke_current_dest_state->clone(),
tgta_succ_it_->dst(), pool_);
current_acceptance_conditions_
= tgta_succ_it_->acc();
return true;
}
step_();
}
return false;
}
bool
tgta_succ_iterator_product::done() const
{
if (!source_)
{
return !tgta_succ_it_ || tgta_succ_it_->done();
}
else
{
return !kripke_succ_it_ || kripke_succ_it_->done();
}
}
state_product*
tgta_succ_iterator_product::dst() const
{
trace
<< "*** dst() .... if(done()) = ***" << done() << std::endl;
return current_state_->clone();
}
bdd
tgta_succ_iterator_product::cond() const
{
return current_condition_;
}
acc_cond::mark_t
tgta_succ_iterator_product::acc() const
{
return current_acceptance_conditions_;
}
}

101
spot/ta/tgtaproduct.hh Normal file
View file

@ -0,0 +1,101 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2011, 2012, 2013, 2014 Laboratoire de Recherche et
// Développement de l'Epita (LRDE).
//
// This file is part of Spot, a model checking library.
//
// Spot 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 3 of the License, or
// (at your option) any later version.
//
// Spot 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, see <http://www.gnu.org/licenses/>.
#pragma once
#include <spot/twa/twa.hh>
#include <spot/twa/twaproduct.hh>
#include <spot/misc/fixpool.hh>
#include <spot/kripke/kripke.hh>
#include <spot/ta/tgta.hh>
namespace spot
{
/// \brief A lazy product. (States are computed on the fly.)
class SPOT_API tgta_product : public twa_product
{
public:
tgta_product(const const_kripke_ptr& left,
const const_tgta_ptr& right);
virtual const state* get_init_state() const;
virtual twa_succ_iterator*
succ_iter(const state* local_state) const;
};
inline twa_ptr product(const const_kripke_ptr& left,
const const_tgta_ptr& right)
{
return std::make_shared<tgta_product>(left, right);
}
/// \brief Iterate over the successors of a product computed on the fly.
class SPOT_API tgta_succ_iterator_product : public twa_succ_iterator
{
public:
tgta_succ_iterator_product(const state_product* s,
const const_kripke_ptr& k,
const const_tgta_ptr& tgta,
fixed_size_pool* pool);
virtual
~tgta_succ_iterator_product();
// iteration
bool first();
bool next();
bool done() const;
// inspection
state_product*
dst() const;
bdd
cond() const;
acc_cond::mark_t
acc() const;
private:
//@{
/// Internal routines to advance to the next successor.
void
step_();
bool find_next_succ_();
void
next_kripke_dest();
//@}
protected:
const state_product* source_;
const_tgta_ptr tgta_;
const_kripke_ptr kripke_;
fixed_size_pool* pool_;
twa_succ_iterator* tgta_succ_it_;
twa_succ_iterator* kripke_succ_it_;
state_product* current_state_;
bdd current_condition_;
acc_cond::mark_t current_acceptance_conditions_;
bdd kripke_source_condition;
const state* kripke_current_dest_state;
};
}