Commit 579c343e authored by Alexandre Duret-Lutz's avatar Alexandre Duret-Lutz
Browse files

* src/tgbaalgos/emptinesscheck.hh, src/tgbaalgos/emptinesscheck.cc:

Delete and split into ...
* src/tgbaalgos/gtec/ce.cc, src/tgbaalgos/gtec/ce.hh,
src/tgbaalgos/gtec/explscc.cc, src/tgbaalgos/gtec/explscc.hh,
src/tgbaalgos/gtec/gtec.cc, src/tgbaalgos/gtec/gtec.hh,
src/tgbaalgos/gtec/nsheap.cc, src/tgbaalgos/gtec/nsheap.hh,
src/tgbaalgos/gtec/sccstack.cc, src/tgbaalgos/gtec/sccstack.hh,
src/tgbaalgos/gtec/status.cc, src/tgbaalgos/gtec/status.hh: ...
these new files.
* src/tgbaalgos/gtec/Makefile.am: New file.
* src/tgbaalgos/Makefile.am (SUBDIRS, libtgbaalgos_la_LIBADD):
Recurse into gtec and link gtec/libgtec.la.
(tgbaalgos_HEADERS, libtgbaalgos_la_SOURCES): Remove emptinesscheck.hh
and emptinesscheck.cc.
* configure.ac: Output src/tgbalagos/gtec/Makefile.
* iface/gspn/ltlgspn.cc, src/tgbatest/ltl2tgba.cc: Update includes.
* README: Update tree description.
parent d8f5bf60
2004-04-14 Alexandre Duret-Lutz <adl@src.lip6.fr>
* src/tgbaalgos/emptinesscheck.hh, src/tgbaalgos/emptinesscheck.cc:
Delete and split into ...
* src/tgbaalgos/gtec/ce.cc, src/tgbaalgos/gtec/ce.hh,
src/tgbaalgos/gtec/explscc.cc, src/tgbaalgos/gtec/explscc.hh,
src/tgbaalgos/gtec/gtec.cc, src/tgbaalgos/gtec/gtec.hh,
src/tgbaalgos/gtec/nsheap.cc, src/tgbaalgos/gtec/nsheap.hh,
src/tgbaalgos/gtec/sccstack.cc, src/tgbaalgos/gtec/sccstack.hh,
src/tgbaalgos/gtec/status.cc, src/tgbaalgos/gtec/status.hh: ...
these new files.
* src/tgbaalgos/gtec/Makefile.am: New file.
* src/tgbaalgos/Makefile.am (SUBDIRS, libtgbaalgos_la_LIBADD):
Recurse into gtec and link gtec/libgtec.la.
(tgbaalgos_HEADERS, libtgbaalgos_la_SOURCES): Remove emptinesscheck.hh
and emptinesscheck.cc.
* configure.ac: Output src/tgbalagos/gtec/Makefile.
* iface/gspn/ltlgspn.cc, src/tgbatest/ltl2tgba.cc: Update includes.
* README: Update tree description.
2004-04-13 Alexandre Duret-Lutz <adl@src.lip6.fr>
* tgbaalgos/emptinesscheck.hh (numbered_state_heap_const_iterator,
* src/tgbaalgos/emptinesscheck.hh (numbered_state_heap_const_iterator,
numbered_state_heap, numbered_state_heap_hash_map): New classes.
* tgbaalgos/emptinesscheck.cc
* src/tgbaalgos/emptinesscheck.cc
(numbered_state_heap_hash_map_const_iterator): New class.
(numbered_state_heap_hash_map): Implement it.
......
......@@ -65,6 +65,7 @@ src/ Sources for libspot.
misc/ Miscellaneous support files.
tgba/ TGBA objects and cousins.
tgbaalgos/ Algorithms on TGBAs.
gtec/ Generalized Tarjan Emptiness-Check.
tgbaparse/ Parser for explicit TGBAs.
tgbatest/ Tests for tgba/, tgbaalgos/, and tgbaparse/.
doc/ Documentation for libspot.
......
......@@ -64,6 +64,7 @@ AC_CONFIG_FILES([
src/ltlvisit/Makefile
src/tgba/Makefile
src/tgbaalgos/Makefile
src/tgbaalgos/gtec/Makefile
src/tgbaparse/Makefile
src/tgbatest/Makefile
src/tgbatest/defs
......
......@@ -35,7 +35,8 @@
#include "tgbaalgos/ltl2tgba_lacim.hh"
#include "tgbaalgos/ltl2tgba_fm.hh"
#include "tgbaalgos/magic.hh"
#include "tgbaalgos/emptinesscheck.hh"
#include "tgbaalgos/gtec/gtec.hh"
#include "tgbaalgos/gtec/ce.hh"
void
......
......@@ -19,6 +19,8 @@
## Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
## 02111-1307, USA.
SUBDIRS = gtec
AM_CPPFLAGS = -I$(srcdir)/.. $(BUDDY_CPPFLAGS)
AM_CXXFLAGS = $(WARNING_CXXFLAGS)
......@@ -27,7 +29,6 @@ tgbaalgosdir = $(pkgincludedir)/tgbaalgos
tgbaalgos_HEADERS = \
dotty.hh \
dupexp.hh \
emptinesscheck.hh \
lbtt.hh \
ltl2tgba_fm.hh \
ltl2tgba_lacim.hh \
......@@ -41,7 +42,6 @@ noinst_LTLIBRARIES = libtgbaalgos.la
libtgbaalgos_la_SOURCES = \
dotty.cc \
dupexp.cc \
emptinesscheck.cc \
lbtt.cc \
ltl2tgba_fm.cc \
ltl2tgba_lacim.cc \
......@@ -50,3 +50,5 @@ libtgbaalgos_la_SOURCES = \
reachiter.cc \
save.cc \
stats.cc
libtgbaalgos_la_LIBADD = gtec/libgtec.la
.deps
.libs
*.lo
*.la
Makefile
Makefile.in
## 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.
AM_CPPFLAGS = -I$(srcdir)/../.. $(BUDDY_CPPFLAGS)
AM_CXXFLAGS = $(WARNING_CXXFLAGS)
gtecdir = $(pkgincludedir)/tgbaalgos/gtec
gtec_HEADERS = \
ce.hh \
explscc.hh \
gtec.hh \
nsheap.hh \
sccstack.hh \
status.hh
noinst_LTLIBRARIES = libgtec.la
libgtec_la_SOURCES = \
ce.cc \
explscc.cc \
gtec.cc \
nsheap.cc \
sccstack.cc \
status.cc
// 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.
#include "ce.hh"
#include "tgba/bddprint.hh"
#include <map>
namespace spot
{
namespace
{
typedef std::pair<const spot::state*, tgba_succ_iterator*> pair_state_iter;
}
counter_example::counter_example(const emptiness_check_status* ecs,
const explicit_connected_component_factory*
eccf)
: ecs_(ecs)
{
assert(!ecs_->root.empty());
assert(suffix.empty());
scc_stack::stack_type root = ecs_->root.s;
int comp_size = root.size();
// Transform the stack of connected component into an array.
explicit_connected_component** scc =
new (explicit_connected_component*)[comp_size];
for (int j = comp_size - 1; 0 <= j; --j)
{
scc[j] = eccf->build();
scc[j]->index = root.top().index;
scc[j]->condition = root.top().condition;
root.pop();
}
assert(root.empty());
// Build the set of states for all SCCs.
numbered_state_heap_const_iterator* i = ecs_->h.iterator();
for (i->first(); !i->done(); i->next())
{
int index = i->get_index();
// Skip states from dead SCCs.
if (index < 0)
continue;
assert(index != 0);
// Find the SCC this state belongs to.
int j;
for (j = 1; j < comp_size; ++j)
if (index < scc[j]->index)
break;
scc[j - 1]->insert(i->get_state());
}
delete i;
suffix.push_front(ecs_->h.filter(ecs_->aut->get_init_state()));
// 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
// from the next SCC. This destination state becomes the
// starting state when building a path though the next SCC.
for (int k = 0; k < comp_size - 1; ++k)
{
// FIFO for the breadth-first search.
// (we are looking for the closest state in the next SCC.)
std::deque<pair_state_iter> todo;
// Record the father of each state, while performing the BFS.
typedef std::map<const state*, const state*,
state_ptr_less_than> father_map;
father_map father;
// Initial state of the BFS.
const state* start = suffix.back();
{
tgba_succ_iterator* i = ecs_->aut->succ_iter(start);
todo.push_back(pair_state_iter(start, i));
}
while (!todo.empty())
{
const state* src = todo.front().first;
tgba_succ_iterator* i = todo.front().second;
todo.pop_front();
for (i->first(); !i->done(); i->next())
{
const state* dest = i->current_state();
// Are we leaving this SCC?
const state* h_dest = scc[k]->has_state(dest);
if (!h_dest)
{
// If we have found a state in the next SCC.
// Unwind the path and populate SUFFIX.
h_dest = scc[k+1]->has_state(dest);
if (h_dest)
{
state_sequence seq;
seq.push_front(h_dest);
while (src->compare(start))
{
seq.push_front(src);
src = father[src];
}
// Append SEQ to SUFFIX.
suffix.splice(suffix.end(), seq);
// Exit this BFS for this SCC.
while (!todo.empty())
{
delete todo.front().second;
todo.pop_front();
}
break;
}
// Restrict the BFS to state inside the SCC.
continue;
}
if (father.find(h_dest) == father.end())
{
todo.push_back
(pair_state_iter(h_dest, ecs_->aut->succ_iter(h_dest)));
father[h_dest] = src;
}
}
delete i;
}
}
accepting_path(scc[comp_size - 1], suffix.back(),
scc[comp_size - 1]->condition);
for (int j = comp_size - 1; 0 <= j; --j)
delete scc[j];
delete[] scc;
}
void
counter_example::complete_cycle(const explicit_connected_component* scc,
const state* from,
const state* to)
{
// If by change or period already ends on the state we have
// to reach back, we are done.
if (from == to
&& ! period.empty())
return;
// Records backlinks to parent state during the BFS.
// (This also stores the propositions of this link.)
std::map<const state*, state_proposition, state_ptr_less_than> father;
// BFS queue.
std::deque<pair_state_iter> todo;
// Initial state.
{
tgba_succ_iterator* i = ecs_->aut->succ_iter(from);
todo.push_back(pair_state_iter(from, i));
}
while (!todo.empty())
{
const state* src = todo.front().first;
tgba_succ_iterator* i = todo.front().second;
todo.pop_front();
for (i->first(); !i->done(); i->next())
{
const state* dest = i->current_state();
// Do not escape this SCC or visit a state already visited.
const state* h_dest = scc->has_state(dest);
if (!h_dest)
{
delete dest;
continue;
}
if (father.find(h_dest) != father.end())
continue;
bdd cond = i->current_condition();
// If we have reached our destination, unwind the path
// and populate PERIOD.
if (h_dest == to)
{
cycle_path p;
p.push_front(state_proposition(h_dest, cond));
while (src != from)
{
const state_proposition& psi = father[src];
p.push_front(state_proposition(src, psi.second));
src = psi.first;
}
period.splice(period.end(), p);
// Exit the BFS, but release all iterators first.
while (!todo.empty())
{
delete todo.front().second;
todo.pop_front();
}
break;
}
// Common case: record backlinks and continue BFS.
todo.push_back(pair_state_iter(h_dest,
ecs_->aut->succ_iter(h_dest)));
father[h_dest] = state_proposition(src, cond);
}
delete i;
}
}
namespace
{
struct triplet
{
const state* s; // Current state.
tgba_succ_iterator* iter; // Iterator to successor of the current state.
bdd acc; // All acceptance conditions traversed by
// the path so far.
triplet (const state* s, tgba_succ_iterator* iter, bdd acc)
: s(s), iter(iter), acc(acc)
{
}
};
}
void
counter_example::accepting_path(const explicit_connected_component* scc,
const state* start, bdd acc_to_traverse)
{
// State seen during the DFS.
typedef Sgi::hash_set<const state*,
state_ptr_hash, state_ptr_equal> set_type;
set_type seen;
// DFS stack.
std::stack<triplet> todo;
while (acc_to_traverse != bddfalse)
{
// Initial state.
{
tgba_succ_iterator* i = ecs_->aut->succ_iter(start);
i->first();
todo.push(triplet(start, i, bddfalse));
seen.insert(start);
}
// The path being explored currently.
cycle_path path;
// The best path seen so far.
cycle_path best_path;
// The acceptance conditions traversed by BEST_PATH.
bdd best_acc = bddfalse;
while (!todo.empty())
{
tgba_succ_iterator* iter = todo.top().iter;
const state* s = todo.top().s;
// Nothing more to explore, backtrack.
if (iter->done())
{
todo.pop();
delete iter;
seen.erase(s);
if (todo.size())
{
assert(path.size());
path.pop_back();
}
continue;
}
// We must not escape the current SCC.
const state* dest = iter->current_state();
const state* h_dest = scc->has_state(dest);
if (!h_dest)
{
delete dest;
iter->next();
continue;
}
bdd acc = iter->current_acceptance_conditions() | todo.top().acc;
path.push_back(state_proposition(h_dest,
iter->current_condition()));
// Advance iterator for next step.
iter->next();
if (seen.find(h_dest) == seen.end())
{
// A new state: continue the DFS.
tgba_succ_iterator* di = ecs_->aut->succ_iter(h_dest);
di->first();
todo.push(triplet(h_dest, di, acc));
seen.insert(h_dest);
continue;
}
// We have completed a full cycle.
// If we already have a best path, let see if the current
// one is better.
if (best_path.size())
{
// When comparing the merits of two paths, only the
// acceptance conditions we are trying the traverse
// are important.
bdd acc_restrict = acc & acc_to_traverse;
bdd best_acc_restrict = best_acc & acc_to_traverse;
// If the best path and the current one traverse the
// same acceptance conditions, we keep the shorter
// path. Otherwise, we keep the path which has the
// more acceptance conditions.
if (best_acc_restrict == acc_restrict)
{
if (best_path.size() <= path.size())
goto backtrack_path;
}
else
{
// `best_acc_restrict >> acc_restrict' is true
// when the set of acceptance conditions of
// best_acc_restrict is included in the set of
// acceptance conditions of acc_restrict.
//
// FIXME: It would be better to count the number
// of acceptance conditions.
if (bddtrue != (best_acc_restrict >> acc_restrict))
goto backtrack_path;
}
}
// The current path the best one.
best_path = path;
best_acc = acc;
backtrack_path:
// Continue exploration from parent to find better paths.
// (Do not pop PATH if ITER is done, because that will be
// done at the top of the loop, among other things.)
if (!iter->done())
path.pop_back();
}
// Append our best path to the period.
for (cycle_path::iterator it = best_path.begin();
it != best_path.end(); ++it)
period.push_back(*it);
// Prepare to find another path for the remaining acceptance
// conditions.
acc_to_traverse -= best_acc;
start = period.back().first;
}
// Complete the path so that it goes back to its beginning,
// forming a cycle.
complete_cycle(scc, start, suffix.back());
}
std::ostream&
counter_example::print_result(std::ostream& os, const tgba* restrict) const
{
os << "Prefix:" << std::endl;
const bdd_dict* d = ecs_->aut->get_dict();
for (state_sequence::const_iterator i_se = suffix.begin();
i_se != suffix.end(); ++i_se)
{
os << " ";
if (restrict)
{
const state* s = ecs_->aut->project_state(*i_se, restrict);
assert(s);
os << restrict->format_state(s) << std::endl;
delete s;
}
else
{
os << ecs_->aut->format_state(*i_se) << std::endl;
}
}
os << "Cycle:" <<std::endl;
for (cycle_path::const_iterator it = period.begin();
it != period.end(); ++it)
{
os << " | " << bdd_format_set(d, it->second) << std::endl;
os << " ";
if (restrict)
{
const state* s = ecs_->aut->project_state(it->first, restrict);
assert(s);
os << restrict->format_state(s) << std::endl;
delete s;
}
else
{
os << ecs_->aut->format_state(it->first) << std::endl;
}
}
return os;
}
void
counter_example::print_stats(std::ostream& os) const
{
ecs_->print_stats(os);
os << suffix.size() << " states in suffix" << std::endl;
os << period.size() << " states in period" << std::endl;
}
}
// 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_GTEC_CE_HH
# define SPOT_TGBAALGOS_GTEC_CE_HH
#include "status.hh"
#include "explscc.hh"
namespace spot
{
class counter_example
{
public:
counter_example(const emptiness_check_status* ecs,
const explicit_connected_component_factory*
eccf = connected_component_hash_set_factory::instance());
<