twa_run: swallow reduce_run, replay_twa_run, twa_run_to_tgba
These now become twa_run::reduce, twa_run::replay, and twa_run::as_twa. * src/twaalgos/reducerun.cc, src/twaalgos/reducerun.hh, src/twaalgos/replayrun.cc, src/twaalgos/replayrun.hh: Delete. * src/twaalgos/Makefile.am: Adjust. * src/twaalgos/emptiness.cc, src/twaalgos/emptiness.hh: Move the above functions here, as method of twa_run. * src/bin/common_aoutput.hh, src/bin/ltlcross.cc, src/tests/emptchk.cc, src/tests/ikwiad.cc, src/tests/randtgba.cc, wrap/python/ajax/spotcgi.in, iface/ltsmin/modelcheck.cc: Adjust. * NEWS: List the renamings.
This commit is contained in:
parent
63917def2d
commit
99c967f021
15 changed files with 508 additions and 664 deletions
6
NEWS
6
NEWS
|
|
@ -44,7 +44,7 @@ New in spot 1.99.4a (not yet released)
|
||||||
looks like a subversion of v1 and no parse error was detected.
|
looks like a subversion of v1 and no parse error was detected.
|
||||||
|
|
||||||
* The way to pass option to the automaton parser has been changed to
|
* The way to pass option to the automaton parser has been changed to
|
||||||
make it easier to introduct new options. One such new option is
|
make it easier to introduce new options. One such new option is
|
||||||
"trust_hoa": when true (the default) supported properties declared
|
"trust_hoa": when true (the default) supported properties declared
|
||||||
in HOA files are trusted even if they cannot be easily be verified.
|
in HOA files are trusted even if they cannot be easily be verified.
|
||||||
|
|
||||||
|
|
@ -53,6 +53,10 @@ New in spot 1.99.4a (not yet released)
|
||||||
tgba_statistics::transitions -> twa_statistics::edges
|
tgba_statistics::transitions -> twa_statistics::edges
|
||||||
tgba_sub_statistics::sub_transitions -> twa_sub_statistics::transitions
|
tgba_sub_statistics::sub_transitions -> twa_sub_statistics::transitions
|
||||||
tgba_run -> twa_run
|
tgba_run -> twa_run
|
||||||
|
reduce_run -> twa_run::reduce
|
||||||
|
replay_twa_run -> twa_run::replay
|
||||||
|
print_twa_run -> operator<<
|
||||||
|
twa_run_to_tgba -> twa_run::as_twa
|
||||||
|
|
||||||
Python:
|
Python:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@
|
||||||
#include "tl/parse.hh"
|
#include "tl/parse.hh"
|
||||||
#include "twaalgos/translate.hh"
|
#include "twaalgos/translate.hh"
|
||||||
#include "twaalgos/emptiness.hh"
|
#include "twaalgos/emptiness.hh"
|
||||||
#include "twaalgos/reducerun.hh"
|
|
||||||
#include "twaalgos/postproc.hh"
|
#include "twaalgos/postproc.hh"
|
||||||
#include "twa/twaproduct.hh"
|
#include "twa/twaproduct.hh"
|
||||||
#include "misc/timer.hh"
|
#include "misc/timer.hh"
|
||||||
|
|
@ -336,11 +335,10 @@ checked_main(int argc, char **argv)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tm.start("reducing accepting run");
|
tm.start("reducing accepting run");
|
||||||
run = spot::reduce_run(res->automaton(), run);
|
run = run->reduce();
|
||||||
tm.stop("reducing accepting run");
|
tm.stop("reducing accepting run");
|
||||||
|
|
||||||
tm.start("printing accepting run");
|
tm.start("printing accepting run");
|
||||||
spot::print_twa_run(std::cout, product, run);
|
std::cout << run;
|
||||||
tm.stop("printing accepting run");
|
tm.stop("printing accepting run");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,6 @@
|
||||||
#include "twaalgos/stats.hh"
|
#include "twaalgos/stats.hh"
|
||||||
#include "twaalgos/sccinfo.hh"
|
#include "twaalgos/sccinfo.hh"
|
||||||
#include "twaalgos/gtec/gtec.hh"
|
#include "twaalgos/gtec/gtec.hh"
|
||||||
#include "twaalgos/reducerun.hh"
|
|
||||||
#include "twaalgos/word.hh"
|
#include "twaalgos/word.hh"
|
||||||
#include "twaalgos/isdet.hh"
|
#include "twaalgos/isdet.hh"
|
||||||
#include "common_file.hh"
|
#include "common_file.hh"
|
||||||
|
|
@ -179,8 +178,7 @@ public:
|
||||||
{
|
{
|
||||||
auto run = res->accepting_run();
|
auto run = res->accepting_run();
|
||||||
assert(run);
|
assert(run);
|
||||||
run = reduce_run(run);
|
spot::tgba_word w(run->reduce());
|
||||||
spot::tgba_word w(run);
|
|
||||||
w.simplify();
|
w.simplify();
|
||||||
std::ostringstream out;
|
std::ostringstream out;
|
||||||
w.print(out, aut->get_dict());
|
w.print(out, aut->get_dict());
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,6 @@
|
||||||
#include "twaalgos/randomgraph.hh"
|
#include "twaalgos/randomgraph.hh"
|
||||||
#include "twaalgos/sccinfo.hh"
|
#include "twaalgos/sccinfo.hh"
|
||||||
#include "twaalgos/isweakscc.hh"
|
#include "twaalgos/isweakscc.hh"
|
||||||
#include "twaalgos/reducerun.hh"
|
|
||||||
#include "twaalgos/word.hh"
|
#include "twaalgos/word.hh"
|
||||||
#include "twaalgos/complement.hh"
|
#include "twaalgos/complement.hh"
|
||||||
#include "twaalgos/cleanacc.hh"
|
#include "twaalgos/cleanacc.hh"
|
||||||
|
|
@ -703,10 +702,9 @@ namespace
|
||||||
auto run = res->accepting_run();
|
auto run = res->accepting_run();
|
||||||
if (run)
|
if (run)
|
||||||
{
|
{
|
||||||
run = reduce_run(run);
|
|
||||||
std::cerr << "; both automata accept the infinite word\n"
|
std::cerr << "; both automata accept the infinite word\n"
|
||||||
<< " ";
|
<< " ";
|
||||||
spot::tgba_word w(run);
|
spot::tgba_word w(run->reduce());
|
||||||
w.simplify();
|
w.simplify();
|
||||||
w.print(example(), prod->get_dict()) << '\n';
|
w.print(example(), prod->get_dict()) << '\n';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -161,8 +161,7 @@ main(int argc, char** argv)
|
||||||
std::cout << ce_found << " counterexample found\n";
|
std::cout << ce_found << " counterexample found\n";
|
||||||
if (auto run = res->accepting_run())
|
if (auto run = res->accepting_run())
|
||||||
{
|
{
|
||||||
auto ar = spot::twa_run_to_tgba(a, run);
|
spot::print_dot(std::cout, run->as_twa());
|
||||||
spot::print_dot(std::cout, ar);
|
|
||||||
}
|
}
|
||||||
std::cout << '\n';
|
std::cout << '\n';
|
||||||
if (runs == 0)
|
if (runs == 0)
|
||||||
|
|
|
||||||
|
|
@ -38,13 +38,11 @@
|
||||||
#include "twaalgos/hoa.hh"
|
#include "twaalgos/hoa.hh"
|
||||||
#include "twaalgos/degen.hh"
|
#include "twaalgos/degen.hh"
|
||||||
#include "twa/twaproduct.hh"
|
#include "twa/twaproduct.hh"
|
||||||
#include "twaalgos/reducerun.hh"
|
|
||||||
#include "parseaut/public.hh"
|
#include "parseaut/public.hh"
|
||||||
#include "twaalgos/copy.hh"
|
#include "twaalgos/copy.hh"
|
||||||
#include "twaalgos/minimize.hh"
|
#include "twaalgos/minimize.hh"
|
||||||
#include "taalgos/minimize.hh"
|
#include "taalgos/minimize.hh"
|
||||||
#include "twaalgos/neverclaim.hh"
|
#include "twaalgos/neverclaim.hh"
|
||||||
#include "twaalgos/replayrun.hh"
|
|
||||||
#include "twaalgos/sccfilter.hh"
|
#include "twaalgos/sccfilter.hh"
|
||||||
#include "twaalgos/safety.hh"
|
#include "twaalgos/safety.hh"
|
||||||
#include "twaalgos/gtec/gtec.hh"
|
#include "twaalgos/gtec/gtec.hh"
|
||||||
|
|
@ -1580,13 +1578,13 @@ checked_main(int argc, char** argv)
|
||||||
if (opt_reduce)
|
if (opt_reduce)
|
||||||
{
|
{
|
||||||
tm.start("reducing accepting run");
|
tm.start("reducing accepting run");
|
||||||
run = spot::reduce_run(run);
|
run = run->reduce();
|
||||||
tm.stop("reducing accepting run");
|
tm.stop("reducing accepting run");
|
||||||
}
|
}
|
||||||
if (accepting_run_replay)
|
if (accepting_run_replay)
|
||||||
{
|
{
|
||||||
tm.start("replaying acc. run");
|
tm.start("replaying acc. run");
|
||||||
if (!spot::replay_twa_run(std::cout, run, true))
|
if (!run->replay(std::cout, true))
|
||||||
exit_code = 1;
|
exit_code = 1;
|
||||||
tm.stop("replaying acc. run");
|
tm.stop("replaying acc. run");
|
||||||
}
|
}
|
||||||
|
|
@ -1594,14 +1592,9 @@ checked_main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
tm.start("printing accepting run");
|
tm.start("printing accepting run");
|
||||||
if (graph_run_tgba_opt)
|
if (graph_run_tgba_opt)
|
||||||
{
|
spot::print_dot(std::cout, run->as_twa());
|
||||||
auto ar = spot::twa_run_to_tgba(a, run);
|
|
||||||
spot::print_dot(std::cout, ar);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
std::cout << run;
|
std::cout << run;
|
||||||
}
|
|
||||||
tm.stop("printing accepting run");
|
tm.stop("printing accepting run");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,8 +51,6 @@
|
||||||
|
|
||||||
#include "twaalgos/emptiness.hh"
|
#include "twaalgos/emptiness.hh"
|
||||||
#include "twaalgos/emptiness_stats.hh"
|
#include "twaalgos/emptiness_stats.hh"
|
||||||
#include "twaalgos/reducerun.hh"
|
|
||||||
#include "twaalgos/replayrun.hh"
|
|
||||||
|
|
||||||
struct ec_algo
|
struct ec_algo
|
||||||
{
|
{
|
||||||
|
|
@ -1026,7 +1024,7 @@ main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
tm_ar.stop(algo);
|
tm_ar.stop(algo);
|
||||||
std::ostringstream s;
|
std::ostringstream s;
|
||||||
if (!spot::replay_twa_run(s, run))
|
if (!run->replay(s))
|
||||||
{
|
{
|
||||||
if (!opt_paper)
|
if (!opt_paper)
|
||||||
std::cout << ", but could not replay "
|
std::cout << ", but could not replay "
|
||||||
|
|
@ -1047,8 +1045,8 @@ main(int argc, char** argv)
|
||||||
|
|
||||||
if (opt_reduce)
|
if (opt_reduce)
|
||||||
{
|
{
|
||||||
auto redrun = spot::reduce_run(run);
|
auto redrun = run->reduce();
|
||||||
if (!spot::replay_twa_run(s, redrun))
|
if (!redrun->replay(s))
|
||||||
{
|
{
|
||||||
if (!opt_paper)
|
if (!opt_paper)
|
||||||
std::cout
|
std::cout
|
||||||
|
|
|
||||||
|
|
@ -62,11 +62,9 @@ twaalgos_HEADERS = \
|
||||||
randomgraph.hh \
|
randomgraph.hh \
|
||||||
randomize.hh \
|
randomize.hh \
|
||||||
reachiter.hh \
|
reachiter.hh \
|
||||||
reducerun.hh \
|
|
||||||
relabel.hh \
|
relabel.hh \
|
||||||
remfin.hh \
|
remfin.hh \
|
||||||
remprop.hh \
|
remprop.hh \
|
||||||
replayrun.hh \
|
|
||||||
safety.hh \
|
safety.hh \
|
||||||
sbacc.hh \
|
sbacc.hh \
|
||||||
sccfilter.hh \
|
sccfilter.hh \
|
||||||
|
|
@ -119,10 +117,8 @@ libtwaalgos_la_SOURCES = \
|
||||||
randomgraph.cc \
|
randomgraph.cc \
|
||||||
randomize.cc \
|
randomize.cc \
|
||||||
reachiter.cc \
|
reachiter.cc \
|
||||||
reducerun.cc \
|
|
||||||
remfin.cc \
|
remfin.cc \
|
||||||
remprop.cc \
|
remprop.cc \
|
||||||
replayrun.cc \
|
|
||||||
relabel.cc \
|
relabel.cc \
|
||||||
safety.cc \
|
safety.cc \
|
||||||
sbacc.cc \
|
sbacc.cc \
|
||||||
|
|
|
||||||
|
|
@ -22,79 +22,19 @@
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include "emptiness.hh"
|
#include "emptiness.hh"
|
||||||
#include "twa/twa.hh"
|
#include "bfssteps.hh"
|
||||||
|
#include "gtec/gtec.hh"
|
||||||
|
#include "gv04.hh"
|
||||||
|
#include "magic.hh"
|
||||||
|
#include "misc/hash.hh"
|
||||||
|
#include "se05.hh"
|
||||||
|
#include "tau03.hh"
|
||||||
|
#include "tau03opt.hh"
|
||||||
#include "twa/bddprint.hh"
|
#include "twa/bddprint.hh"
|
||||||
#include "twaalgos/gtec/gtec.hh"
|
|
||||||
#include "twaalgos/gv04.hh"
|
|
||||||
#include "twaalgos/magic.hh"
|
|
||||||
#include "twaalgos/se05.hh"
|
|
||||||
#include "twaalgos/tau03.hh"
|
|
||||||
#include "twaalgos/tau03opt.hh"
|
|
||||||
|
|
||||||
namespace spot
|
namespace spot
|
||||||
{
|
{
|
||||||
|
|
||||||
// twa_run
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
twa_run::~twa_run()
|
|
||||||
{
|
|
||||||
for (auto i : prefix)
|
|
||||||
i.s->destroy();
|
|
||||||
for (auto i : cycle)
|
|
||||||
i.s->destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
twa_run::twa_run(const twa_run& run)
|
|
||||||
{
|
|
||||||
aut = run.aut;
|
|
||||||
for (step s : run.prefix)
|
|
||||||
{
|
|
||||||
s.s = s.s->clone();
|
|
||||||
prefix.push_back(s);
|
|
||||||
}
|
|
||||||
for (step s : run.cycle)
|
|
||||||
{
|
|
||||||
s.s = s.s->clone();
|
|
||||||
cycle.push_back(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
twa_run&
|
|
||||||
twa_run::operator=(const twa_run& run)
|
|
||||||
{
|
|
||||||
if (&run != this)
|
|
||||||
{
|
|
||||||
this->~twa_run();
|
|
||||||
new(this) twa_run(run);
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ostream&
|
|
||||||
operator<<(std::ostream& os, const twa_run_ptr& run)
|
|
||||||
{
|
|
||||||
auto& a = run->aut;
|
|
||||||
bdd_dict_ptr d = a->get_dict();
|
|
||||||
|
|
||||||
auto pstep = [&](const twa_run::step& st)
|
|
||||||
{
|
|
||||||
os << " " << a->format_state(st.s) << "\n | ";
|
|
||||||
bdd_print_formula(os, d, st.label);
|
|
||||||
if (st.acc)
|
|
||||||
os << '\t' << st.acc;
|
|
||||||
os << '\n';
|
|
||||||
};
|
|
||||||
|
|
||||||
os << "Prefix:" << std::endl;
|
|
||||||
for (auto& s: run->prefix)
|
|
||||||
pstep(s);
|
|
||||||
os << "Cycle:" << std::endl;
|
|
||||||
for (auto& s: run->cycle)
|
|
||||||
pstep(s);
|
|
||||||
return os;
|
|
||||||
}
|
|
||||||
|
|
||||||
// emptiness_check_result
|
// emptiness_check_result
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
@ -276,18 +216,459 @@ namespace spot
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// twa_run_to_tgba
|
// twa_run
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
twa_graph_ptr
|
twa_run::~twa_run()
|
||||||
twa_run_to_tgba(const const_twa_ptr& a, const const_twa_run_ptr& run)
|
|
||||||
{
|
{
|
||||||
auto d = a->get_dict();
|
for (auto i : prefix)
|
||||||
auto res = make_twa_graph(d);
|
i.s->destroy();
|
||||||
res->copy_ap_of(a);
|
for (auto i : cycle)
|
||||||
res->copy_acceptance_of(a);
|
i.s->destroy();
|
||||||
|
}
|
||||||
|
|
||||||
const state* s = a->get_init_state();
|
twa_run::twa_run(const twa_run& run)
|
||||||
|
{
|
||||||
|
aut = run.aut;
|
||||||
|
for (step s : run.prefix)
|
||||||
|
{
|
||||||
|
s.s = s.s->clone();
|
||||||
|
prefix.push_back(s);
|
||||||
|
}
|
||||||
|
for (step s : run.cycle)
|
||||||
|
{
|
||||||
|
s.s = s.s->clone();
|
||||||
|
cycle.push_back(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
twa_run&
|
||||||
|
twa_run::operator=(const twa_run& run)
|
||||||
|
{
|
||||||
|
if (&run != this)
|
||||||
|
{
|
||||||
|
this->~twa_run();
|
||||||
|
new(this) twa_run(run);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream&
|
||||||
|
operator<<(std::ostream& os, const twa_run_ptr& run)
|
||||||
|
{
|
||||||
|
auto& a = run->aut;
|
||||||
|
bdd_dict_ptr d = a->get_dict();
|
||||||
|
|
||||||
|
auto pstep = [&](const twa_run::step& st)
|
||||||
|
{
|
||||||
|
os << " " << a->format_state(st.s) << "\n | ";
|
||||||
|
bdd_print_formula(os, d, st.label);
|
||||||
|
if (st.acc)
|
||||||
|
os << '\t' << st.acc;
|
||||||
|
os << '\n';
|
||||||
|
};
|
||||||
|
|
||||||
|
os << "Prefix:" << std::endl;
|
||||||
|
for (auto& s: run->prefix)
|
||||||
|
pstep(s);
|
||||||
|
os << "Cycle:" << std::endl;
|
||||||
|
for (auto& s: run->cycle)
|
||||||
|
pstep(s);
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
class shortest_path: public bfs_steps
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
shortest_path(const const_twa_ptr& a)
|
||||||
|
: bfs_steps(a), target(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~shortest_path()
|
||||||
|
{
|
||||||
|
state_set::const_iterator i = seen.begin();
|
||||||
|
while (i != seen.end())
|
||||||
|
{
|
||||||
|
const state* ptr = *i;
|
||||||
|
++i;
|
||||||
|
ptr->destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
set_target(const state_set* t)
|
||||||
|
{
|
||||||
|
target = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
const state*
|
||||||
|
search(const state* start, twa_run::steps& l)
|
||||||
|
{
|
||||||
|
return this->bfs_steps::search(filter(start), l);
|
||||||
|
}
|
||||||
|
|
||||||
|
const state*
|
||||||
|
filter(const state* s)
|
||||||
|
{
|
||||||
|
state_set::const_iterator i = seen.find(s);
|
||||||
|
if (i == seen.end())
|
||||||
|
seen.insert(s);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
s->destroy();
|
||||||
|
s = *i;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
match(twa_run::step&, const state* dest)
|
||||||
|
{
|
||||||
|
return target->find(dest) != target->end();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
state_set seen;
|
||||||
|
const state_set* target;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
twa_run_ptr twa_run::reduce() const
|
||||||
|
{
|
||||||
|
auto& a = aut;
|
||||||
|
auto res = std::make_shared<twa_run>(a);
|
||||||
|
state_set ss;
|
||||||
|
shortest_path shpath(a);
|
||||||
|
shpath.set_target(&ss);
|
||||||
|
|
||||||
|
// We want to find a short segment of the original cycle that
|
||||||
|
// contains all acceptance conditions.
|
||||||
|
|
||||||
|
const state* segment_start; // The initial state of the segment.
|
||||||
|
const state* segment_next; // The state immediately after the segment.
|
||||||
|
|
||||||
|
// Start from the end of the original cycle, and rewind until all
|
||||||
|
// acceptance sets have been seen.
|
||||||
|
acc_cond::mark_t seen_acc = 0U;
|
||||||
|
twa_run::steps::const_iterator seg = cycle.end();
|
||||||
|
do
|
||||||
|
{
|
||||||
|
assert(seg != cycle.begin());
|
||||||
|
--seg;
|
||||||
|
seen_acc |= seg->acc;
|
||||||
|
}
|
||||||
|
while (!a->acc().accepting(seen_acc));
|
||||||
|
segment_start = seg->s;
|
||||||
|
|
||||||
|
// Now go forward and ends the segment as soon as we have seen all
|
||||||
|
// acceptance sets, cloning it in our result along the way.
|
||||||
|
seen_acc = 0U;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
assert(seg != cycle.end());
|
||||||
|
seen_acc |= seg->acc;
|
||||||
|
|
||||||
|
twa_run::step st = { seg->s->clone(), seg->label, seg->acc };
|
||||||
|
res->cycle.push_back(st);
|
||||||
|
|
||||||
|
++seg;
|
||||||
|
}
|
||||||
|
while (!a->acc().accepting(seen_acc));
|
||||||
|
segment_next = seg == cycle.end() ? cycle.front().s : seg->s;
|
||||||
|
|
||||||
|
// Close this cycle if needed, that is, compute a cycle going
|
||||||
|
// from the state following the segment to its starting state.
|
||||||
|
if (segment_start != segment_next)
|
||||||
|
{
|
||||||
|
ss.insert(segment_start);
|
||||||
|
const state* s = shpath.search(segment_next->clone(), res->cycle);
|
||||||
|
ss.clear();
|
||||||
|
assert(s->compare(segment_start) == 0);
|
||||||
|
(void)s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the prefix: it's the shortest path from the initial
|
||||||
|
// state of the automata to any state of the cycle.
|
||||||
|
|
||||||
|
// Register all states from the cycle as target of the BFS.
|
||||||
|
for (twa_run::steps::const_iterator i = res->cycle.begin();
|
||||||
|
i != res->cycle.end(); ++i)
|
||||||
|
ss.insert(i->s);
|
||||||
|
|
||||||
|
const state* prefix_start = a->get_init_state();
|
||||||
|
// There are two cases: either the initial state is already on
|
||||||
|
// the cycle, or it is not. If it is, we will have to rotate
|
||||||
|
// the cycle so it begins on this position. Otherwise we will shift
|
||||||
|
// the cycle so it begins on the state that follows the prefix.
|
||||||
|
// cycle_entry_point is that state.
|
||||||
|
const state* cycle_entry_point;
|
||||||
|
state_set::const_iterator ps = ss.find(prefix_start);
|
||||||
|
if (ps != ss.end())
|
||||||
|
{
|
||||||
|
// The initial state is on the cycle.
|
||||||
|
prefix_start->destroy();
|
||||||
|
cycle_entry_point = *ps;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// This initial state is outside the cycle. Compute the prefix.
|
||||||
|
cycle_entry_point = shpath.search(prefix_start, res->prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Locate cycle_entry_point on the cycle.
|
||||||
|
twa_run::steps::iterator cycle_ep_it;
|
||||||
|
for (cycle_ep_it = res->cycle.begin();
|
||||||
|
cycle_ep_it != res->cycle.end()
|
||||||
|
&& cycle_entry_point->compare(cycle_ep_it->s); ++cycle_ep_it)
|
||||||
|
continue;
|
||||||
|
assert(cycle_ep_it != res->cycle.end());
|
||||||
|
|
||||||
|
// Now shift the cycle so it starts on cycle_entry_point.
|
||||||
|
res->cycle.splice(res->cycle.end(), res->cycle,
|
||||||
|
res->cycle.begin(), cycle_ep_it);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
static void
|
||||||
|
print_annotation(std::ostream& os,
|
||||||
|
const const_twa_ptr& a,
|
||||||
|
const twa_succ_iterator* i)
|
||||||
|
{
|
||||||
|
std::string s = a->transition_annotation(i);
|
||||||
|
if (s == "")
|
||||||
|
return;
|
||||||
|
os << ' ' << s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool twa_run::replay(std::ostream& os, bool debug) const
|
||||||
|
{
|
||||||
|
const state* s = aut->get_init_state();
|
||||||
|
int serial = 1;
|
||||||
|
const twa_run::steps* l;
|
||||||
|
std::string in;
|
||||||
|
acc_cond::mark_t all_acc = 0U;
|
||||||
|
bool all_acc_seen = false;
|
||||||
|
typedef std::unordered_map<const state*, std::set<int>,
|
||||||
|
state_ptr_hash, state_ptr_equal> state_map;
|
||||||
|
state_map seen;
|
||||||
|
|
||||||
|
if (prefix.empty())
|
||||||
|
{
|
||||||
|
l = &cycle;
|
||||||
|
in = "cycle";
|
||||||
|
if (!debug)
|
||||||
|
os << "No prefix.\nCycle:\n";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
l = &prefix;
|
||||||
|
in = "prefix";
|
||||||
|
if (!debug)
|
||||||
|
os << "Prefix:\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
twa_run::steps::const_iterator i = l->begin();
|
||||||
|
|
||||||
|
if (s->compare(i->s))
|
||||||
|
{
|
||||||
|
if (debug)
|
||||||
|
os << "ERROR: First state of run (in " << in << "): "
|
||||||
|
<< aut->format_state(i->s)
|
||||||
|
<< "\ndoes not match initial state of automata: "
|
||||||
|
<< aut->format_state(s) << '\n';
|
||||||
|
s->destroy();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; i != l->end(); ++serial)
|
||||||
|
{
|
||||||
|
if (debug)
|
||||||
|
{
|
||||||
|
// Keep track of the serial associated to each state so we
|
||||||
|
// can note duplicate states and make the replay easier to read.
|
||||||
|
state_map::iterator o = seen.find(s);
|
||||||
|
std::ostringstream msg;
|
||||||
|
if (o != seen.end())
|
||||||
|
{
|
||||||
|
for (auto d: o->second)
|
||||||
|
msg << " == " << d;
|
||||||
|
o->second.insert(serial);
|
||||||
|
s->destroy();
|
||||||
|
s = o->first;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
seen[s].insert(serial);
|
||||||
|
}
|
||||||
|
os << "state " << serial << " in " << in << msg.str() << ": ";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
os << " ";
|
||||||
|
}
|
||||||
|
os << aut->format_state(s) << '\n';
|
||||||
|
|
||||||
|
// expected outgoing transition
|
||||||
|
bdd label = i->label;
|
||||||
|
acc_cond::mark_t acc = i->acc;
|
||||||
|
|
||||||
|
// compute the next expected state
|
||||||
|
const state* next;
|
||||||
|
++i;
|
||||||
|
if (i != l->end())
|
||||||
|
{
|
||||||
|
next = i->s;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (l == &prefix)
|
||||||
|
{
|
||||||
|
l = &cycle;
|
||||||
|
in = "cycle";
|
||||||
|
i = l->begin();
|
||||||
|
if (!debug)
|
||||||
|
os << "Cycle:\n";
|
||||||
|
}
|
||||||
|
next = l->begin()->s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// browse the actual outgoing transitions
|
||||||
|
twa_succ_iterator* j = aut->succ_iter(s);
|
||||||
|
// When not debugging, S is not used as key in SEEN, so we can
|
||||||
|
// destroy it right now.
|
||||||
|
if (!debug)
|
||||||
|
s->destroy();
|
||||||
|
if (j->first())
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (j->current_condition() != label
|
||||||
|
|| j->current_acceptance_conditions() != acc)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const state* s2 = j->current_state();
|
||||||
|
if (s2->compare(next))
|
||||||
|
{
|
||||||
|
s2->destroy();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
s = s2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (j->next());
|
||||||
|
if (j->done())
|
||||||
|
{
|
||||||
|
if (debug)
|
||||||
|
{
|
||||||
|
os << "ERROR: no transition with label="
|
||||||
|
<< bdd_format_formula(aut->get_dict(), label)
|
||||||
|
<< " and acc=" << aut->acc().format(acc)
|
||||||
|
<< " leaving state " << serial
|
||||||
|
<< " for state " << aut->format_state(next) << '\n'
|
||||||
|
<< "The following transitions leave state " << serial
|
||||||
|
<< ":\n";
|
||||||
|
if (j->first())
|
||||||
|
do
|
||||||
|
{
|
||||||
|
const state* s2 = j->current_state();
|
||||||
|
os << " *";
|
||||||
|
print_annotation(os, aut, j);
|
||||||
|
os << " label="
|
||||||
|
<< bdd_format_formula(aut->get_dict(),
|
||||||
|
j->current_condition())
|
||||||
|
<< " and acc="
|
||||||
|
<< (aut->acc().format
|
||||||
|
(j->current_acceptance_conditions()))
|
||||||
|
<< " going to " << aut->format_state(s2) << '\n';
|
||||||
|
s2->destroy();
|
||||||
|
}
|
||||||
|
while (j->next());
|
||||||
|
}
|
||||||
|
aut->release_iter(j);
|
||||||
|
s->destroy();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (debug)
|
||||||
|
{
|
||||||
|
os << "transition";
|
||||||
|
print_annotation(os, aut, j);
|
||||||
|
os << " with label="
|
||||||
|
<< bdd_format_formula(aut->get_dict(), label)
|
||||||
|
<< " and acc=" << aut->acc().format(acc)
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
os << " | ";
|
||||||
|
print_annotation(os, aut, j);
|
||||||
|
bdd_print_formula(os, aut->get_dict(), label);
|
||||||
|
os << '\t';
|
||||||
|
aut->acc().format(acc);
|
||||||
|
os << std::endl;
|
||||||
|
}
|
||||||
|
aut->release_iter(j);
|
||||||
|
|
||||||
|
// Sum acceptance conditions.
|
||||||
|
//
|
||||||
|
// (Beware l and i designate the next step to consider.
|
||||||
|
// Therefore if i is at the beginning of the cycle, `acc'
|
||||||
|
// contains the acceptance conditions of the last transition
|
||||||
|
// in the prefix; we should not account it.)
|
||||||
|
if (l == &cycle && i != l->begin())
|
||||||
|
{
|
||||||
|
all_acc |= acc;
|
||||||
|
if (!all_acc_seen && aut->acc().accepting(all_acc))
|
||||||
|
{
|
||||||
|
all_acc_seen = true;
|
||||||
|
if (debug)
|
||||||
|
os << "all acceptance conditions ("
|
||||||
|
<< aut->acc().format(all_acc)
|
||||||
|
<< ") have been seen\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s->destroy();
|
||||||
|
if (!aut->acc().accepting(all_acc))
|
||||||
|
{
|
||||||
|
if (debug)
|
||||||
|
os << "ERROR: The cycle's acceptance conditions ("
|
||||||
|
<< aut->acc().format(all_acc)
|
||||||
|
<< ") do not\nmatch those of the automaton ("
|
||||||
|
<< aut->acc().format(aut->acc().all_sets())
|
||||||
|
<< ")\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
state_map::const_iterator o = seen.begin();
|
||||||
|
while (o != seen.end())
|
||||||
|
{
|
||||||
|
// Advance the iterator before deleting the "key" pointer.
|
||||||
|
const state* ptr = o->first;
|
||||||
|
++o;
|
||||||
|
ptr->destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
twa_graph_ptr
|
||||||
|
twa_run::as_twa() const
|
||||||
|
{
|
||||||
|
auto d = aut->get_dict();
|
||||||
|
auto res = make_twa_graph(d);
|
||||||
|
res->copy_ap_of(aut);
|
||||||
|
res->copy_acceptance_of(aut);
|
||||||
|
|
||||||
|
const state* s = aut->get_init_state();
|
||||||
unsigned src;
|
unsigned src;
|
||||||
unsigned dst;
|
unsigned dst;
|
||||||
const twa_run::steps* l;
|
const twa_run::steps* l;
|
||||||
|
|
@ -297,10 +678,10 @@ namespace spot
|
||||||
state_ptr_hash, state_ptr_equal> state_map;
|
state_ptr_hash, state_ptr_equal> state_map;
|
||||||
state_map seen;
|
state_map seen;
|
||||||
|
|
||||||
if (run->prefix.empty())
|
if (prefix.empty())
|
||||||
l = &run->cycle;
|
l = &cycle;
|
||||||
else
|
else
|
||||||
l = &run->prefix;
|
l = &prefix;
|
||||||
|
|
||||||
twa_run::steps::const_iterator i = l->begin();
|
twa_run::steps::const_iterator i = l->begin();
|
||||||
|
|
||||||
|
|
@ -323,9 +704,9 @@ namespace spot
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (l == &run->prefix)
|
if (l == &prefix)
|
||||||
{
|
{
|
||||||
l = &run->cycle;
|
l = &cycle;
|
||||||
i = l->begin();
|
i = l->begin();
|
||||||
}
|
}
|
||||||
next = l->begin()->s;
|
next = l->begin()->s;
|
||||||
|
|
@ -334,7 +715,7 @@ namespace spot
|
||||||
// browse the actual outgoing transitions and
|
// browse the actual outgoing transitions and
|
||||||
// look for next;
|
// look for next;
|
||||||
const state* the_next = nullptr;
|
const state* the_next = nullptr;
|
||||||
for (auto j: a->succ(s))
|
for (auto j: aut->succ(s))
|
||||||
{
|
{
|
||||||
if (j->current_condition() != label
|
if (j->current_condition() != label
|
||||||
|| j->current_acceptance_conditions() != acc)
|
|| j->current_acceptance_conditions() != acc)
|
||||||
|
|
@ -362,13 +743,13 @@ namespace spot
|
||||||
src = dst;
|
src = dst;
|
||||||
|
|
||||||
// Sum acceptance conditions.
|
// Sum acceptance conditions.
|
||||||
if (l == &run->cycle && i != l->begin())
|
if (l == &cycle && i != l->begin())
|
||||||
seen_acc |= acc;
|
seen_acc |= acc;
|
||||||
}
|
}
|
||||||
|
|
||||||
s->destroy();
|
s->destroy();
|
||||||
|
|
||||||
assert(a->acc().accepting(seen_acc));
|
assert(aut->acc().accepting(seen_acc));
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -292,6 +292,31 @@ namespace spot
|
||||||
twa_run(const twa_run& run);
|
twa_run(const twa_run& run);
|
||||||
twa_run& operator=(const twa_run& run);
|
twa_run& operator=(const twa_run& run);
|
||||||
|
|
||||||
|
/// \brief Reduce an accepting run.
|
||||||
|
///
|
||||||
|
/// Return a run which is still accepting for <code>aut</code>,
|
||||||
|
/// but is no longer than this one.
|
||||||
|
twa_run_ptr reduce() const;
|
||||||
|
|
||||||
|
/// \brief Replay a run.
|
||||||
|
///
|
||||||
|
/// This is similar to <code>os << run;</code>, except that the
|
||||||
|
/// run is actually replayed on the automaton while it is printed.
|
||||||
|
/// Doing so makes it possible to display transition annotations
|
||||||
|
/// (returned by spot::twa::transition_annotation()). The output
|
||||||
|
/// will stop if the run cannot be completed.
|
||||||
|
///
|
||||||
|
/// \param os the stream on which the replay should be traced
|
||||||
|
/// \param debug if set the output will be more verbose and extra
|
||||||
|
/// debugging informations will be output on failure
|
||||||
|
/// \return true iff the run could be completed
|
||||||
|
bool replay(std::ostream& os, bool debug = false) const;
|
||||||
|
|
||||||
|
/// \brief Return a twa_graph_ptr corresponding to \a run
|
||||||
|
///
|
||||||
|
/// Identical states are merged.
|
||||||
|
twa_graph_ptr as_twa() const;
|
||||||
|
|
||||||
/// \brief Display a twa_run.
|
/// \brief Display a twa_run.
|
||||||
///
|
///
|
||||||
/// Output the prefix and cycle parts of the twa_run \a run on \a os.
|
/// Output the prefix and cycle parts of the twa_run \a run on \a os.
|
||||||
|
|
@ -309,15 +334,6 @@ namespace spot
|
||||||
SPOT_API
|
SPOT_API
|
||||||
friend std::ostream& operator<<(std::ostream& os, const twa_run_ptr& run);
|
friend std::ostream& operator<<(std::ostream& os, const twa_run_ptr& run);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/// \brief Return an explicit_tgba corresponding to \a run (i.e. comparable
|
|
||||||
/// states are merged).
|
|
||||||
///
|
|
||||||
/// \pre \a run must correspond to an actual run of the automaton \a a.
|
|
||||||
SPOT_API twa_graph_ptr
|
|
||||||
twa_run_to_tgba(const const_twa_ptr& a, const const_twa_run_ptr& run);
|
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
/// \addtogroup emptiness_check_stats Emptiness-check statistics
|
/// \addtogroup emptiness_check_stats Emptiness-check statistics
|
||||||
|
|
|
||||||
|
|
@ -1,187 +0,0 @@
|
||||||
// -*- coding: utf-8 -*-
|
|
||||||
// Copyright (C) 2011, 2013, 2014, 2015 Laboratoire de Recherche et
|
|
||||||
// Développement de l'Epita (LRDE).
|
|
||||||
// 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 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 "misc/hash.hh"
|
|
||||||
#include "emptiness.hh"
|
|
||||||
#include "twa/twa.hh"
|
|
||||||
#include "bfssteps.hh"
|
|
||||||
#include "reducerun.hh"
|
|
||||||
|
|
||||||
namespace spot
|
|
||||||
{
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
class shortest_path: public bfs_steps
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
shortest_path(const const_twa_ptr& a)
|
|
||||||
: bfs_steps(a), target(nullptr)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
~shortest_path()
|
|
||||||
{
|
|
||||||
state_set::const_iterator i = seen.begin();
|
|
||||||
while (i != seen.end())
|
|
||||||
{
|
|
||||||
const state* ptr = *i;
|
|
||||||
++i;
|
|
||||||
ptr->destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
set_target(const state_set* t)
|
|
||||||
{
|
|
||||||
target = t;
|
|
||||||
}
|
|
||||||
|
|
||||||
const state*
|
|
||||||
search(const state* start, twa_run::steps& l)
|
|
||||||
{
|
|
||||||
return this->bfs_steps::search(filter(start), l);
|
|
||||||
}
|
|
||||||
|
|
||||||
const state*
|
|
||||||
filter(const state* s)
|
|
||||||
{
|
|
||||||
state_set::const_iterator i = seen.find(s);
|
|
||||||
if (i == seen.end())
|
|
||||||
seen.insert(s);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
s->destroy();
|
|
||||||
s = *i;
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
match(twa_run::step&, const state* dest)
|
|
||||||
{
|
|
||||||
return target->find(dest) != target->end();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
state_set seen;
|
|
||||||
const state_set* target;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
twa_run_ptr
|
|
||||||
reduce_run(const const_twa_run_ptr& org)
|
|
||||||
{
|
|
||||||
auto& a = org->aut;
|
|
||||||
auto res = std::make_shared<twa_run>(a);
|
|
||||||
state_set ss;
|
|
||||||
shortest_path shpath(a);
|
|
||||||
shpath.set_target(&ss);
|
|
||||||
|
|
||||||
// We want to find a short segment of the original cycle that
|
|
||||||
// contains all acceptance conditions.
|
|
||||||
|
|
||||||
const state* segment_start; // The initial state of the segment.
|
|
||||||
const state* segment_next; // The state immediately after the segment.
|
|
||||||
|
|
||||||
// Start from the end of the original cycle, and rewind until all
|
|
||||||
// acceptance sets have been seen.
|
|
||||||
acc_cond::mark_t seen_acc = 0U;
|
|
||||||
twa_run::steps::const_iterator seg = org->cycle.end();
|
|
||||||
do
|
|
||||||
{
|
|
||||||
assert(seg != org->cycle.begin());
|
|
||||||
--seg;
|
|
||||||
seen_acc |= seg->acc;
|
|
||||||
}
|
|
||||||
while (!a->acc().accepting(seen_acc));
|
|
||||||
segment_start = seg->s;
|
|
||||||
|
|
||||||
// Now go forward and ends the segment as soon as we have seen all
|
|
||||||
// acceptance sets, cloning it in our result along the way.
|
|
||||||
seen_acc = 0U;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
assert(seg != org->cycle.end());
|
|
||||||
seen_acc |= seg->acc;
|
|
||||||
|
|
||||||
twa_run::step st = { seg->s->clone(), seg->label, seg->acc };
|
|
||||||
res->cycle.push_back(st);
|
|
||||||
|
|
||||||
++seg;
|
|
||||||
}
|
|
||||||
while (!a->acc().accepting(seen_acc));
|
|
||||||
segment_next = seg == org->cycle.end() ? org->cycle.front().s : seg->s;
|
|
||||||
|
|
||||||
// Close this cycle if needed, that is, compute a cycle going
|
|
||||||
// from the state following the segment to its starting state.
|
|
||||||
if (segment_start != segment_next)
|
|
||||||
{
|
|
||||||
ss.insert(segment_start);
|
|
||||||
const state* s = shpath.search(segment_next->clone(), res->cycle);
|
|
||||||
ss.clear();
|
|
||||||
assert(s->compare(segment_start) == 0);
|
|
||||||
(void)s;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compute the prefix: it's the shortest path from the initial
|
|
||||||
// state of the automata to any state of the cycle.
|
|
||||||
|
|
||||||
// Register all states from the cycle as target of the BFS.
|
|
||||||
for (twa_run::steps::const_iterator i = res->cycle.begin();
|
|
||||||
i != res->cycle.end(); ++i)
|
|
||||||
ss.insert(i->s);
|
|
||||||
|
|
||||||
const state* prefix_start = a->get_init_state();
|
|
||||||
// There are two cases: either the initial state is already on
|
|
||||||
// the cycle, or it is not. If it is, we will have to rotate
|
|
||||||
// the cycle so it begins on this position. Otherwise we will shift
|
|
||||||
// the cycle so it begins on the state that follows the prefix.
|
|
||||||
// cycle_entry_point is that state.
|
|
||||||
const state* cycle_entry_point;
|
|
||||||
state_set::const_iterator ps = ss.find(prefix_start);
|
|
||||||
if (ps != ss.end())
|
|
||||||
{
|
|
||||||
// The initial state is on the cycle.
|
|
||||||
prefix_start->destroy();
|
|
||||||
cycle_entry_point = *ps;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// This initial state is outside the cycle. Compute the prefix.
|
|
||||||
cycle_entry_point = shpath.search(prefix_start, res->prefix);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Locate cycle_entry_point on the cycle.
|
|
||||||
twa_run::steps::iterator cycle_ep_it;
|
|
||||||
for (cycle_ep_it = res->cycle.begin();
|
|
||||||
cycle_ep_it != res->cycle.end()
|
|
||||||
&& cycle_entry_point->compare(cycle_ep_it->s); ++cycle_ep_it)
|
|
||||||
continue;
|
|
||||||
assert(cycle_ep_it != res->cycle.end());
|
|
||||||
|
|
||||||
// Now shift the cycle so it starts on cycle_entry_point.
|
|
||||||
res->cycle.splice(res->cycle.end(), res->cycle,
|
|
||||||
res->cycle.begin(), cycle_ep_it);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,38 +0,0 @@
|
||||||
// -*- coding: utf-8 -*-
|
|
||||||
// Copyright (C) 2010, 2013, 2014, 2015 Laboratoire de Recherche et
|
|
||||||
// Développement de l'Epita.
|
|
||||||
// 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 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 "misc/common.hh"
|
|
||||||
#include "twa/fwd.hh"
|
|
||||||
#include "twaalgos/emptiness.hh"
|
|
||||||
|
|
||||||
namespace spot
|
|
||||||
{
|
|
||||||
/// \ingroup twa_run
|
|
||||||
/// \brief Reduce an accepting run.
|
|
||||||
///
|
|
||||||
/// Return a run which is still accepting for <code>org->aut</code>,
|
|
||||||
/// but is no longer than \a org.
|
|
||||||
SPOT_API twa_run_ptr
|
|
||||||
reduce_run(const const_twa_run_ptr& org);
|
|
||||||
}
|
|
||||||
|
|
@ -1,260 +0,0 @@
|
||||||
// -*- coding: utf-8 -*-
|
|
||||||
// Copyright (C) 2011, 2013, 2014, 2015 Laboratoire de Recherche et
|
|
||||||
// Développement de l'Epita (LRDE).
|
|
||||||
// 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 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 "misc/hash.hh"
|
|
||||||
#include "replayrun.hh"
|
|
||||||
#include "twa/twa.hh"
|
|
||||||
#include "emptiness.hh"
|
|
||||||
#include "twa/bddprint.hh"
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
namespace spot
|
|
||||||
{
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
void
|
|
||||||
print_annotation(std::ostream& os,
|
|
||||||
const const_twa_ptr& a,
|
|
||||||
const twa_succ_iterator* i)
|
|
||||||
{
|
|
||||||
std::string s = a->transition_annotation(i);
|
|
||||||
if (s == "")
|
|
||||||
return;
|
|
||||||
os << ' ' << s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
replay_twa_run(std::ostream& os,
|
|
||||||
const const_twa_run_ptr& run, bool debug)
|
|
||||||
{
|
|
||||||
auto& a = run->aut;
|
|
||||||
const state* s = a->get_init_state();
|
|
||||||
int serial = 1;
|
|
||||||
const twa_run::steps* l;
|
|
||||||
std::string in;
|
|
||||||
acc_cond::mark_t all_acc = 0U;
|
|
||||||
bool all_acc_seen = false;
|
|
||||||
typedef std::unordered_map<const state*, std::set<int>,
|
|
||||||
state_ptr_hash, state_ptr_equal> state_map;
|
|
||||||
state_map seen;
|
|
||||||
|
|
||||||
if (run->prefix.empty())
|
|
||||||
{
|
|
||||||
l = &run->cycle;
|
|
||||||
in = "cycle";
|
|
||||||
if (!debug)
|
|
||||||
os << "No prefix.\nCycle:\n";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
l = &run->prefix;
|
|
||||||
in = "prefix";
|
|
||||||
if (!debug)
|
|
||||||
os << "Prefix:\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
twa_run::steps::const_iterator i = l->begin();
|
|
||||||
|
|
||||||
if (s->compare(i->s))
|
|
||||||
{
|
|
||||||
if (debug)
|
|
||||||
os << "ERROR: First state of run (in " << in << "): "
|
|
||||||
<< a->format_state(i->s)
|
|
||||||
<< "\ndoes not match initial state of automata: "
|
|
||||||
<< a->format_state(s) << '\n';
|
|
||||||
s->destroy();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (; i != l->end(); ++serial)
|
|
||||||
{
|
|
||||||
if (debug)
|
|
||||||
{
|
|
||||||
// Keep track of the serial associated to each state so we
|
|
||||||
// can note duplicate states and make the replay easier to read.
|
|
||||||
state_map::iterator o = seen.find(s);
|
|
||||||
std::ostringstream msg;
|
|
||||||
if (o != seen.end())
|
|
||||||
{
|
|
||||||
for (auto d: o->second)
|
|
||||||
msg << " == " << d;
|
|
||||||
o->second.insert(serial);
|
|
||||||
s->destroy();
|
|
||||||
s = o->first;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
seen[s].insert(serial);
|
|
||||||
}
|
|
||||||
os << "state " << serial << " in " << in << msg.str() << ": ";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
os << " ";
|
|
||||||
}
|
|
||||||
os << a->format_state(s) << '\n';
|
|
||||||
|
|
||||||
// expected outgoing transition
|
|
||||||
bdd label = i->label;
|
|
||||||
acc_cond::mark_t acc = i->acc;
|
|
||||||
|
|
||||||
// compute the next expected state
|
|
||||||
const state* next;
|
|
||||||
++i;
|
|
||||||
if (i != l->end())
|
|
||||||
{
|
|
||||||
next = i->s;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (l == &run->prefix)
|
|
||||||
{
|
|
||||||
l = &run->cycle;
|
|
||||||
in = "cycle";
|
|
||||||
i = l->begin();
|
|
||||||
if (!debug)
|
|
||||||
os << "Cycle:\n";
|
|
||||||
}
|
|
||||||
next = l->begin()->s;
|
|
||||||
}
|
|
||||||
|
|
||||||
// browse the actual outgoing transitions
|
|
||||||
twa_succ_iterator* j = a->succ_iter(s);
|
|
||||||
// When not debugging, S is not used as key in SEEN, so we can
|
|
||||||
// destroy it right now.
|
|
||||||
if (!debug)
|
|
||||||
s->destroy();
|
|
||||||
if (j->first())
|
|
||||||
do
|
|
||||||
{
|
|
||||||
if (j->current_condition() != label
|
|
||||||
|| j->current_acceptance_conditions() != acc)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const state* s2 = j->current_state();
|
|
||||||
if (s2->compare(next))
|
|
||||||
{
|
|
||||||
s2->destroy();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
s = s2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while (j->next());
|
|
||||||
if (j->done())
|
|
||||||
{
|
|
||||||
if (debug)
|
|
||||||
{
|
|
||||||
os << "ERROR: no transition with label="
|
|
||||||
<< bdd_format_formula(a->get_dict(), label)
|
|
||||||
<< " and acc=" << a->acc().format(acc)
|
|
||||||
<< " leaving state " << serial
|
|
||||||
<< " for state " << a->format_state(next) << '\n'
|
|
||||||
<< "The following transitions leave state " << serial
|
|
||||||
<< ":\n";
|
|
||||||
if (j->first())
|
|
||||||
do
|
|
||||||
{
|
|
||||||
const state* s2 = j->current_state();
|
|
||||||
os << " *";
|
|
||||||
print_annotation(os, a, j);
|
|
||||||
os << " label="
|
|
||||||
<< bdd_format_formula(a->get_dict(),
|
|
||||||
j->current_condition())
|
|
||||||
<< " and acc="
|
|
||||||
<< a->acc().format(j->current_acceptance_conditions())
|
|
||||||
<< " going to " << a->format_state(s2) << '\n';
|
|
||||||
s2->destroy();
|
|
||||||
}
|
|
||||||
while (j->next());
|
|
||||||
}
|
|
||||||
a->release_iter(j);
|
|
||||||
s->destroy();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (debug)
|
|
||||||
{
|
|
||||||
os << "transition";
|
|
||||||
print_annotation(os, a, j);
|
|
||||||
os << " with label="
|
|
||||||
<< bdd_format_formula(a->get_dict(), label)
|
|
||||||
<< " and acc=" << a->acc().format(acc)
|
|
||||||
<< std::endl;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
os << " | ";
|
|
||||||
print_annotation(os, a, j);
|
|
||||||
bdd_print_formula(os, a->get_dict(), label);
|
|
||||||
os << '\t';
|
|
||||||
a->acc().format(acc);
|
|
||||||
os << std::endl;
|
|
||||||
}
|
|
||||||
a->release_iter(j);
|
|
||||||
|
|
||||||
// Sum acceptance conditions.
|
|
||||||
//
|
|
||||||
// (Beware l and i designate the next step to consider.
|
|
||||||
// Therefore if i is at the beginning of the cycle, `acc'
|
|
||||||
// contains the acceptance conditions of the last transition
|
|
||||||
// in the prefix; we should not account it.)
|
|
||||||
if (l == &run->cycle && i != l->begin())
|
|
||||||
{
|
|
||||||
all_acc |= acc;
|
|
||||||
if (!all_acc_seen && a->acc().accepting(all_acc))
|
|
||||||
{
|
|
||||||
all_acc_seen = true;
|
|
||||||
if (debug)
|
|
||||||
os << "all acceptance conditions ("
|
|
||||||
<< a->acc().format(all_acc)
|
|
||||||
<< ") have been seen\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s->destroy();
|
|
||||||
if (!a->acc().accepting(all_acc))
|
|
||||||
{
|
|
||||||
if (debug)
|
|
||||||
os << "ERROR: The cycle's acceptance conditions ("
|
|
||||||
<< a->acc().format(all_acc)
|
|
||||||
<< ") do not\nmatch those of the automaton ("
|
|
||||||
<< a->acc().format(a->acc().all_sets())
|
|
||||||
<< ")\n";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
state_map::const_iterator o = seen.begin();
|
|
||||||
while (o != seen.end())
|
|
||||||
{
|
|
||||||
// Advance the iterator before deleting the "key" pointer.
|
|
||||||
const state* ptr = o->first;
|
|
||||||
++o;
|
|
||||||
ptr->destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,52 +0,0 @@
|
||||||
// -*- coding: utf-8 -*-
|
|
||||||
// Copyright (C) 2013, 2014, 2015 Laboratoire de Recherche et Developpement
|
|
||||||
// de l'Epita (LRDE).
|
|
||||||
// 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 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 "misc/common.hh"
|
|
||||||
#include <iosfwd>
|
|
||||||
#include "twa/fwd.hh"
|
|
||||||
#include "twaalgos/emptiness.hh"
|
|
||||||
|
|
||||||
namespace spot
|
|
||||||
{
|
|
||||||
struct twa_run;
|
|
||||||
|
|
||||||
/// \ingroup twa_run
|
|
||||||
/// \brief Replay a twa_run on a tgba.
|
|
||||||
///
|
|
||||||
/// This is similar to <code>os << run;</code>, except that the run is
|
|
||||||
/// actually replayed on the automaton while it is printed. Doing
|
|
||||||
/// so makes it possible to display transition annotations (returned
|
|
||||||
/// by spot::twa::transition_annotation()). The output will stop
|
|
||||||
/// if the run cannot be completed.
|
|
||||||
///
|
|
||||||
/// \param run the run to replay
|
|
||||||
/// \param os the stream on which the replay should be traced
|
|
||||||
/// \param debug if set the output will be more verbose and extra
|
|
||||||
/// debugging informations will be output on failure
|
|
||||||
/// \return true iff the run could be completed
|
|
||||||
SPOT_API bool
|
|
||||||
replay_twa_run(std::ostream& os,
|
|
||||||
const const_twa_run_ptr& run,
|
|
||||||
bool debug = false);
|
|
||||||
}
|
|
||||||
|
|
@ -843,7 +843,7 @@ if output_type == 'r':
|
||||||
unbufprint('<div class="accrun">%s</div>' %
|
unbufprint('<div class="accrun">%s</div>' %
|
||||||
cgi.escape(str(ec_run)))
|
cgi.escape(str(ec_run)))
|
||||||
if draw_acc_run:
|
if draw_acc_run:
|
||||||
render_automaton(spot.twa_run_to_tgba(ec_a, ec_run), False)
|
render_automaton(ec_run.as_twa(), False)
|
||||||
del ec_run
|
del ec_run
|
||||||
del ec_res
|
del ec_res
|
||||||
unbufprint('</div>')
|
unbufprint('</div>')
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue