Commit 99c967f0 authored by Alexandre Duret-Lutz's avatar Alexandre Duret-Lutz
Browse files

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.
parent 63917def
......@@ -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.
* 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
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_sub_statistics::sub_transitions -> twa_sub_statistics::transitions
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:
......
......@@ -23,7 +23,6 @@
#include "tl/parse.hh"
#include "twaalgos/translate.hh"
#include "twaalgos/emptiness.hh"
#include "twaalgos/reducerun.hh"
#include "twaalgos/postproc.hh"
#include "twa/twaproduct.hh"
#include "misc/timer.hh"
......@@ -336,11 +335,10 @@ checked_main(int argc, char **argv)
else
{
tm.start("reducing accepting run");
run = spot::reduce_run(res->automaton(), run);
run = run->reduce();
tm.stop("reducing accepting run");
tm.start("printing accepting run");
spot::print_twa_run(std::cout, product, run);
std::cout << run;
tm.stop("printing accepting run");
}
}
......
......@@ -29,7 +29,6 @@
#include "twaalgos/stats.hh"
#include "twaalgos/sccinfo.hh"
#include "twaalgos/gtec/gtec.hh"
#include "twaalgos/reducerun.hh"
#include "twaalgos/word.hh"
#include "twaalgos/isdet.hh"
#include "common_file.hh"
......@@ -179,8 +178,7 @@ public:
{
auto run = res->accepting_run();
assert(run);
run = reduce_run(run);
spot::tgba_word w(run);
spot::tgba_word w(run->reduce());
w.simplify();
std::ostringstream out;
w.print(out, aut->get_dict());
......
......@@ -52,7 +52,6 @@
#include "twaalgos/randomgraph.hh"
#include "twaalgos/sccinfo.hh"
#include "twaalgos/isweakscc.hh"
#include "twaalgos/reducerun.hh"
#include "twaalgos/word.hh"
#include "twaalgos/complement.hh"
#include "twaalgos/cleanacc.hh"
......@@ -703,10 +702,9 @@ namespace
auto run = res->accepting_run();
if (run)
{
run = reduce_run(run);
std::cerr << "; both automata accept the infinite word\n"
<< " ";
spot::tgba_word w(run);
spot::tgba_word w(run->reduce());
w.simplify();
w.print(example(), prod->get_dict()) << '\n';
}
......
......@@ -161,8 +161,7 @@ main(int argc, char** argv)
std::cout << ce_found << " counterexample found\n";
if (auto run = res->accepting_run())
{
auto ar = spot::twa_run_to_tgba(a, run);
spot::print_dot(std::cout, ar);
spot::print_dot(std::cout, run->as_twa());
}
std::cout << '\n';
if (runs == 0)
......
......@@ -38,13 +38,11 @@
#include "twaalgos/hoa.hh"
#include "twaalgos/degen.hh"
#include "twa/twaproduct.hh"
#include "twaalgos/reducerun.hh"
#include "parseaut/public.hh"
#include "twaalgos/copy.hh"
#include "twaalgos/minimize.hh"
#include "taalgos/minimize.hh"
#include "twaalgos/neverclaim.hh"
#include "twaalgos/replayrun.hh"
#include "twaalgos/sccfilter.hh"
#include "twaalgos/safety.hh"
#include "twaalgos/gtec/gtec.hh"
......@@ -1580,13 +1578,13 @@ checked_main(int argc, char** argv)
if (opt_reduce)
{
tm.start("reducing accepting run");
run = spot::reduce_run(run);
run = run->reduce();
tm.stop("reducing accepting run");
}
if (accepting_run_replay)
{
tm.start("replaying acc. run");
if (!spot::replay_twa_run(std::cout, run, true))
if (!run->replay(std::cout, true))
exit_code = 1;
tm.stop("replaying acc. run");
}
......@@ -1594,14 +1592,9 @@ checked_main(int argc, char** argv)
{
tm.start("printing accepting run");
if (graph_run_tgba_opt)
{
auto ar = spot::twa_run_to_tgba(a, run);
spot::print_dot(std::cout, ar);
}
spot::print_dot(std::cout, run->as_twa());
else
{
std::cout << run;
}
std::cout << run;
tm.stop("printing accepting run");
}
}
......
......@@ -51,8 +51,6 @@
#include "twaalgos/emptiness.hh"
#include "twaalgos/emptiness_stats.hh"
#include "twaalgos/reducerun.hh"
#include "twaalgos/replayrun.hh"
struct ec_algo
{
......@@ -1026,7 +1024,7 @@ main(int argc, char** argv)
{
tm_ar.stop(algo);
std::ostringstream s;
if (!spot::replay_twa_run(s, run))
if (!run->replay(s))
{
if (!opt_paper)
std::cout << ", but could not replay "
......@@ -1047,8 +1045,8 @@ main(int argc, char** argv)
if (opt_reduce)
{
auto redrun = spot::reduce_run(run);
if (!spot::replay_twa_run(s, redrun))
auto redrun = run->reduce();
if (!redrun->replay(s))
{
if (!opt_paper)
std::cout
......
......@@ -62,11 +62,9 @@ twaalgos_HEADERS = \
randomgraph.hh \
randomize.hh \
reachiter.hh \
reducerun.hh \
relabel.hh \
remfin.hh \
remprop.hh \
replayrun.hh \
safety.hh \
sbacc.hh \
sccfilter.hh \
......@@ -119,10 +117,8 @@ libtwaalgos_la_SOURCES = \
randomgraph.cc \
randomize.cc \
reachiter.cc \
reducerun.cc \
remfin.cc \
remprop.cc \
replayrun.cc \
relabel.cc \
safety.cc \
sbacc.cc \
......
......@@ -22,79 +22,19 @@
#include <sstream>
#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 "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
{
// 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
//////////////////////////////////////////////////////////////////////
......@@ -276,18 +216,459 @@ namespace spot
return nullptr;
}
// twa_run_to_tgba
// 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;
}
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))
{