Commit 2d1151e0 authored by martinez's avatar martinez
Browse files

* src/tgbaalgos/tarjan_on_fly.hh,

src/tgbaalgos/tarjan_on_fly.cc,
src/tgbaalgos/nesteddfs.hh,
src/tgbaalgos/nesteddfs.cc,
src/tgbaalgos/minimalce.hh,
src/tgbaalgos/minimalce.cc,
src/tgbaalgos/colordfs.hh,
src/tgbaalgos/colordfs.cc: four new algorithms for emptyness check.

src/tgbaalgos/gtec/ce.hh,
src/tgbaalgos/gtec/ce.cc: Adapt the counter exemple for the ce
object in minimalce.hh.

src/tgbatest/ltl2tgba.cc,
src/tgbatest/emptchk.test,
src/tgbaalgos/Makefile.am: Add files for emptyness-check.


* src/tgbaalgos/reductgba_sim_del.cc: Restrict to degeneralize automata.
* src/tgba/tgbareduc.hh: src/tgba/tgbareduc.cc: Merge transition
for scc reduce.
parent 3d2135c8
2004-08-23 Thomas Martinez <martinez@src.lip6.fr>
* src/tgbaalgos/tarjan_on_fly.hh,
src/tgbaalgos/tarjan_on_fly.cc,
src/tgbaalgos/nesteddfs.hh,
src/tgbaalgos/nesteddfs.cc,
src/tgbaalgos/minimalce.hh,
src/tgbaalgos/minimalce.cc,
src/tgbaalgos/colordfs.hh,
src/tgbaalgos/colordfs.cc: four new algorithms for emptyness check.
src/tgbaalgos/gtec/ce.hh,
src/tgbaalgos/gtec/ce.cc: Adapt the counter exemple for the ce
object in minimalce.hh.
src/tgbatest/ltl2tgba.cc,
src/tgbatest/emptchk.test,
src/tgbaalgos/Makefile.am: Add files for emptyness-check.
2004-08-23 Thomas Martinez <martinez@src.lip6.fr>
* src/tgbaalgos/reductgba_sim_del.cc: Restrict to degeneralize automata.
* src/tgba/tgbareduc.hh: src/tgba/tgbareduc.cc: Merge transition
for scc reduce.
2004-08-13 Alexandre Duret-Lutz <adl@src.lip6.fr>
* configure.ac, NEWS: Bump version to 0.0y.
......
......@@ -123,6 +123,8 @@ namespace spot
this->compute_scc();
this->prune_acc();
this->delete_scc();
this->merge_transitions();
}
std::string
......@@ -424,6 +426,12 @@ namespace spot
}
void
tgba_reduc::merge_state_delayed(const spot::state*,
const spot::state*)
{
}
/////////////////////////////////////////
/////////////////////////////////////////
......@@ -580,8 +588,6 @@ namespace spot
void
tgba_reduc::remove_acc(const spot::state* s)
{
//std::cout << "remove_acc" << std::endl;
tgba_explicit::state* s1;
seen_map::iterator sm = si_.find(s);
sm = si_.find(s);
......@@ -624,7 +630,6 @@ namespace spot
tgba_reduc::is_not_accepting(const spot::state* s,
int n)
{
//std::cout << "is not accepting" << std::endl;
bool b = false;
// First call of is_terminal //
......@@ -726,8 +731,6 @@ namespace spot
bool
tgba_reduc::is_terminal(const spot::state* s, int n)
{
// FIXME
// a SCC is terminal if there are no transition
// leaving the SCC AND she doesn't contain all
// the acceptance condition.
......
......@@ -117,6 +117,12 @@ namespace spot
void merge_state(const spot::state* s1,
const spot::state* s2);
/// Redirect all transition leading to s1 to s2.
/// Note that we can do the reverse because
/// s1 and s2 belong to a co-simulate relation.
void merge_state_delayed(const spot::state* s1,
const spot::state* s2);
/// Remove all the scc which are terminal and doesn't
/// contains all the acceptance conditions.
void delete_scc();
......
......@@ -27,33 +27,41 @@ AM_CXXFLAGS = $(WARNING_CXXFLAGS)
tgbaalgosdir = $(pkgincludedir)/tgbaalgos
tgbaalgos_HEADERS = \
colordfs.hh \
dotty.hh \
dupexp.hh \
lbtt.hh \
ltl2tgba_fm.hh \
ltl2tgba_lacim.hh \
magic.hh \
minimalce.hh \
nesteddfs.hh \
neverclaim.hh \
powerset.hh \
reachiter.hh \
save.hh \
stats.hh \
reductgba_sim.hh
reductgba_sim.hh \
tarjan_on_fly.hh
noinst_LTLIBRARIES = libtgbaalgos.la
libtgbaalgos_la_SOURCES = \
colordfs.cc \
dotty.cc \
dupexp.cc \
lbtt.cc \
ltl2tgba_fm.cc \
ltl2tgba_lacim.cc \
magic.cc \
minimalce.cc \
nesteddfs.cc \
neverclaim.cc \
powerset.cc \
reachiter.cc \
save.cc \
stats.cc \
reductgba_sim.cc \
reductgba_sim_del.cc
reductgba_sim_del.cc \
tarjan_on_fly.cc
libtgbaalgos_la_LIBADD = gtec/libgtec.la
// Copyright (C) 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
// dpartement Systmes Rpartis Coopratifs (SRC), Universit Pierre
// et Marie Curie.
//
// 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 2 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 Spot; see the file COPYING. If not, write to the Free
// Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
// 02111-1307, USA.
#include <iterator>
#include <cassert>
#include "colordfs.hh"
#include "tgba/bddprint.hh"
namespace spot
{
colordfs_search::colordfs_search(const tgba_tba_proxy* a)
: a(a), x(0), counter_(0)
{
}
colordfs_search::~colordfs_search()
{
hash_type::const_iterator s = h.begin();
while (s != h.end())
{
// Advance the iterator before deleting the "key" pointer.
const state* ptr = s->first;
++s;
delete ptr;
}
if (x)
delete x;
// Release all iterators on the stack.
while (!stack.empty())
{
delete stack.front().second;
stack.pop_front();
}
}
bool
colordfs_search::push(const state* s, color c)
{
tgba_succ_iterator* i = a->succ_iter(s);
i->first();
/*
hash_type::iterator hi = h.find(s);
if (hi != h.end())
if (hi->second.depth <= (int)stack.size())
//return false; // FIXME
return true;
*/
color_state cs = { c, true , stack.size() }; // FIXME
h[s] = cs;
stack.push_front(state_iter_pair(s, i));
// We build the counter example
bdd b = bddfalse;
if (!i->done()) // if the state is dead.
b = i->current_condition();
counter_->prefix.push_back(ce::state_ce(s->clone(), b));
return true;
}
void
colordfs_search::pop()
{
const state* s = stack.begin()->first;
tgba_succ_iterator* i = stack.begin()->second;
delete i;
//std::cout << "pop : " << a->format_state(s) << std::endl;
hash_type::iterator hi = h.find(s);
assert(hi != h.end());
hi->second.is_in_cp = false;
stack.pop_front();
//delete s;
// We build the counter example
delete counter_->prefix.back().first;
counter_->prefix.pop_back();
}
bool
colordfs_search::all_succ_black(const state* s)
{
bool return_value = true;
hash_type::iterator hi;
const state* s2;
tgba_succ_iterator* i = a->succ_iter(s);
int n = 0;
for (i->first(); !i->done(); i->next(), n++)
{
//std::cout << "iter : " << n << std::endl;
s2 = i->current_state();
//std::cout << a->format_state(s2) << std::endl;
hi = h.find(s2);
if (hi != h.end())
return_value &= (hi->second.c == black);
else
return_value = false;
delete s2;
}
delete i;
//std::cout << "End Loop" << std::endl;
hi = h.find(s);
assert(hi != h.end());
if (return_value)
hi->second.c = black;
return return_value;
}
ce::counter_example*
colordfs_search::check()
{
clock();
counter_ = new ce::counter_example(a);
const state* s = a->get_init_state();
if (dfs_blue(s))
counter_->build_cycle(x);
else
{
delete counter_;
counter_ = 0;
}
tps_ = clock();
return counter_;
}
bool
colordfs_search::dfs_blue(const state* s, bdd)
{
//std::cout << "dfs_blue : " << a->format_state(s) << std::endl;
if (!push(s, blue))
return false;
hash_type::iterator hi;
tgba_succ_iterator* i = a->succ_iter(s);
int n = 0;
for (i->first(); !i->done(); i->next(), n++)
{
const state* s2 = i->current_state();
//std::cout << "s2 : " << a->format_state(s2) << std::endl;
hi = h.find(s2);
if (a->state_is_accepting(s2) &&
(hi != h.end() && hi->second.is_in_cp))
{
ce::state_ce ce;
ce = ce::state_ce(s2, i->current_condition());
x = const_cast<state*>(s2);
delete i;
return true;// a counter example is found !!
}
else if (hi == h.end() || hi->second.c == white)
{
int res = dfs_blue(s2, i->current_acceptance_conditions());
if (res == 1)
{
delete i;
return true;
}
}
else
delete s2; // FIXME
}
delete i;
pop();
if (!all_succ_black(s) &&
a->state_is_accepting(s))
{
if (dfs_red(s))
return 1;
dfs_black(s);
}
return false;
}
bool
colordfs_search::dfs_red(const state* s)
{
//std::cout << "dfs_red : " << a->format_state(s) << std::endl;
if (!push(s, red))
return false;
hash_type::iterator hi;
tgba_succ_iterator* i = a->succ_iter(s);
int n = 0;
for (i->first(); !i->done(); i->next(), n++)
{
const state* s2 = i->current_state();
hi = h.find(s2);
if (hi != h.end() && hi->second.is_in_cp &&
(a->state_is_accepting(s2) ||
(hi->second.c == blue)))
{
//ce::state_ce ce;
//ce = ce::state_ce(s2->clone(), i->current_condition());
x = const_cast<state*>(s2);
delete i;
return true;// a counter example is found !!
}
if (hi != h.end() && hi->second.c == blue)
{
delete s2; // FIXME
if (dfs_red(hi->first))
{
delete i;
return true;
}
}
else
delete s2;
}
delete i;
//std::cout << "dfs_red : pop" << std::endl;
pop();
return false;
}
void
colordfs_search::dfs_black(const state* s)
{
//std::cout << "dfs_black" << a->format_state(s) << std::endl;
hash_type::iterator hi = h.find(s);
if (hi == h.end()) // impossible
{
color_state cs = { black, false, stack.size() };
h[s] = cs;
}
else
hi->second.c = black;
tgba_succ_iterator* i = a->succ_iter(s);
for (i->first(); !i->done(); i->next())
{
const state* s2 = i->current_state();
hi = h.find(s2);
if (hi == h.end())
{
color_state cs = { black, false, stack.size() };
h[s2] = cs;
dfs_black(s2);
}
else
{
delete s2;
if (hi->second.c != black)
dfs_black(hi->first);
}
}
delete i;
}
std::ostream&
colordfs_search::print_stat(std::ostream& os) const
{
int ce_size = 0;
if (counter_)
ce_size = counter_->size();
os << "Size of Counter Example : " << ce_size << std::endl
<< "States explored : " << h.size() << std::endl
<< "Computed time : " << tps_ << " microseconds" << std::endl;
return os;
}
}
// Copyright (C) 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
// et Marie Curie.
//
// 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 2 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 Spot; see the file COPYING. If not, write to the Free
// Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
// 02111-1307, USA.
#ifndef SPOT_TGBAALGOS_COLORDFS_HH
# define SPOT_TGBAALGOS_COLORDFS_HH
#include "misc/hash.hh"
#include <list>
#include <utility>
#include <ostream>
#include "tgba/tgbatba.hh"
#include "tgbaalgos/minimalce.hh"
namespace spot
{
class colordfs_search: public emptyness_search
{
public:
/// Initialize the Colordfs Search algorithm on the automaton \a a.
colordfs_search(const tgba_tba_proxy *a);
virtual ~colordfs_search();
/// \brief Perform a Color DFS Search.
///
/// \return a new accepting path if there exists one, NULL otherwise.
///
/// check() can be called several times until it return false,
/// to enumerate all accepting paths.
virtual ce::counter_example* check();
/// \brief Print Stat.
std::ostream& print_stat(std::ostream& os) const;
private:
// The names "stack", "h", and "x", are those used in the paper.
/// \brief Records the color of a state.
enum color
{
white = 0,
blue = 1,
red = 2,
black = 3
};
struct color_state
{
color c;
bool is_in_cp;
int depth;
};
typedef std::pair<const state*, tgba_succ_iterator*> state_iter_pair;
typedef std::list<state_iter_pair> stack_type;
stack_type stack; ///< Stack of visited states on the path.
typedef std::list<bdd> tstack_type;
/// \brief Stack of transitions.
///
/// This is an addition to the data from the paper.
tstack_type tstack;
typedef Sgi::hash_map<const state*, color_state,
state_ptr_hash, state_ptr_equal> hash_type;
hash_type h; ///< Map of visited states.
/// The three dfs as explain in
/// @InProceedings(GaMoZe04spin,
/// Author = "Gastin, P. and Moro, P. and Zeitoun, M.",
/// Title = "Minimization of counterexamples in {SPIN}",
/// BookTitle = "Proceedings of the 11th SPIN Workshop (SPIN'04)",
/// Editor = "Graf, S. and Mounier, L.",
/// Publisher = SPRINGER,
/// Series = LNCS,
/// Number = 2989,
/// Year = 2004,
/// Pages = "92-108")
bool dfs_blue(const state* s, bdd acc = bddfalse);
bool dfs_red(const state* s);
void dfs_black(const state* s);
/// Append a new state to the current path.
bool push(const state* s, color c);
/// Remove a state to the current path.
void pop();
/// Check if all successors of \a s are black and color
/// \a s in black if true.
bool all_succ_black(const state* s);
const tgba_tba_proxy* a; ///< The automata to check.
/// The state for which we are currently seeking an SCC.
const state* x;
ce::counter_example* counter_;
clock_t tps_;
};
}
#endif // SPOT_TGBAALGOS_COLORDFS_HH
......@@ -35,6 +35,8 @@ namespace spot
eccf)
: ecs_(ecs)
{
counter_ = new ce::counter_example(ecs->aut);
assert(!ecs_->root.empty());
assert(suffix.empty());
......@@ -76,6 +78,10 @@ namespace spot
assert(spi.first);
suffix.push_front(spi.first);
/////
counter_->prefix.push_front(ce::state_ce(spi.first->clone(), bddfalse));
////
// We build a path trough each SCC in the stack. For the
// first SCC, the starting state is the initial state of the
// automaton. The destination state is the closest state
......@@ -113,21 +119,35 @@ namespace spot
const state* h_dest = scc[k]->has_state(dest);
if (!h_dest)
{
// If we have found a state in the next SCC.
// If we have found a state in greater SCC which.
// Unwind the path and populate SUFFIX.
h_dest = scc[k+1]->has_state(dest);
if (h_dest)
{
state_sequence seq;
///
ce::l_state_ce seq_count;
///
seq.push_front(h_dest);
while (src->compare(start))
{
///
seq_count.push_front(ce::state_ce(src->clone(), bddfalse));
///
seq.push_front(src);
src = father[src];
}
// Append SEQ to SUFFIX.
suffix.splice(suffix.end(), seq);
///
counter_->prefix.splice(counter_->prefix.end(),
seq_count);
///
// Exit this BFS for this SCC.
while (!todo.empty())
{
......@@ -211,14 +231,27 @@ namespace spot
if (h_dest == to)
{
cycle_path p;
///
ce::l_state_ce p_counter;
p_counter.push_front(ce::state_ce(h_dest->clone(), cond));
///
p.push_front(state_proposition(h_dest, cond));
while (src != from)
{
const state_proposition& psi = father[src];
///
p_counter.push_front(ce::state_ce(src->clone(), psi.second));
///
p.push_front(state_proposition(src, psi.second));
src = psi.first;
}
period.splice(period.end(), p);
///