Commit fcf6e251 authored by Thibaud Michaud's avatar Thibaud Michaud Committed by Alexandre Duret-Lutz
Browse files

Optimizing closure and sl.

* src/tgbaalgos/closure.cc, src/tgbaalgos/closure.hh: Using vectors
instead of sets and unordered maps, adding an overload to handle rvalue
references.
* src/tgbaalgos/stutterize.cc, src/tgbaalgos/stutterize.hh: Adding
an overload to handle rvalue references.
* bench/stutter/stutter_invariance_formulas.cc,
bench/stutter/stutter_invariance_randomgraph.cc: Automata are modified
in-place by is_stutter_invariant so they have to be copied before being
processed.
* src/tgbaalgos/stutter_invariance.cc,
src/tgbaalgos/stutter_invariance.hh: Use the in-place version of
closure and sl.
parent 5817a3c1
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "bin/common_output.hh" #include "bin/common_output.hh"
#include "tgbaalgos/translate.hh" #include "tgbaalgos/translate.hh"
#include "tgbaalgos/stutter_invariance.hh" #include "tgbaalgos/stutter_invariance.hh"
#include "tgbaalgos/dupexp.hh"
#include "ltlast/allnodes.hh" #include "ltlast/allnodes.hh"
#include "ltlvisit/apcollect.hh" #include "ltlvisit/apcollect.hh"
#include "ltlvisit/length.hh" #include "ltlvisit/length.hh"
...@@ -30,13 +31,6 @@ ...@@ -30,13 +31,6 @@
#include <argp.h> #include <argp.h>
#include "error.h" #include "error.h"
#include "tgbaalgos/closure.hh"
#include "tgbaalgos/stutterize.hh"
#include "tgbaalgos/dotty.hh"
#include "tgba/tgbaproduct.hh"
static unsigned n = 10;
const char argp_program_doc[] =""; const char argp_program_doc[] ="";
const struct argp_child children[] = const struct argp_child children[] =
...@@ -74,8 +68,9 @@ namespace ...@@ -74,8 +68,9 @@ namespace
const spot::ltl::formula* nf = const spot::ltl::formula* nf =
spot::ltl::unop::instance(spot::ltl::unop::Not, spot::ltl::unop::instance(spot::ltl::unop::Not,
f->clone()); f->clone());
spot::const_tgba_digraph_ptr a = trans.run(f); spot::tgba_digraph_ptr a = trans.run(f);
spot::const_tgba_digraph_ptr na = trans.run(nf); spot::tgba_digraph_ptr na = trans.run(nf);
unsigned num_states = a->num_states();
spot::ltl::atomic_prop_set* ap = spot::ltl::atomic_prop_collect(f); spot::ltl::atomic_prop_set* ap = spot::ltl::atomic_prop_collect(f);
bdd apdict = spot::ltl::atomic_prop_collect_as_bdd(f, a); bdd apdict = spot::ltl::atomic_prop_collect_as_bdd(f, a);
bool res; bool res;
...@@ -88,13 +83,16 @@ namespace ...@@ -88,13 +83,16 @@ namespace
setenv("SPOT_STUTTER_CHECK", algostr, true); setenv("SPOT_STUTTER_CHECK", algostr, true);
spot::stopwatch sw; spot::stopwatch sw;
auto dup_a = std::make_shared<spot::tgba_digraph>(a);
auto dup_na = std::make_shared<spot::tgba_digraph>(na);
sw.start(); sw.start();
for (unsigned i = 0; i < n; ++i) res = spot::is_stutter_invariant(std::move(dup_a),
res = spot::is_stutter_invariant(a, na, apdict); std::move(dup_na), apdict);
const double time = sw.stop(); const double time = sw.stop();
std::cout << formula << ", " << algo << ", " << ap->size() << ", " std::cout << formula << ", " << algo << ", " << ap->size() << ", "
<< a->num_states() << ", " << res << ", " << time << std::endl; << num_states << ", " << res << ", " << time * 1000000 << std::endl;
if (algo > '1') if (algo > '1')
assert(res == prev); assert(res == prev);
......
...@@ -75,18 +75,24 @@ main() ...@@ -75,18 +75,24 @@ main()
for (char algo = '1'; algo <= '8'; ++algo) for (char algo = '1'; algo <= '8'; ++algo)
{ {
// set SPOT_STUTTER_CHECK environment variable // Set SPOT_STUTTER_CHECK environment variable.
char algostr[2] = { 0 }; char algostr[2] = { 0 };
algostr[0] = algo; algostr[0] = algo;
setenv("SPOT_STUTTER_CHECK", algostr, true); setenv("SPOT_STUTTER_CHECK", algostr, true);
// Copy vec, because is_stutter_invariant modifies the
// automata.
std::vector<aut_pair_t> dup(vec);
spot::stopwatch sw; spot::stopwatch sw;
sw.start(); sw.start();
bool res; bool res;
for (auto& a: vec) for (auto& a: vec)
res = spot::is_stutter_invariant(a.first, a.second, apdict); res = spot::is_stutter_invariant(std::move(a.first),
std::move(a.second),
apdict);
const double time = sw.stop(); const double time = sw.stop();
vec = dup;
std::cout << algo << ", " << props_n << ", " << states_n std::cout << algo << ", " << props_n << ", " << states_n
<< ", " << res << ", " << time << std::endl; << ", " << res << ", " << time << std::endl;
} }
...@@ -95,6 +101,5 @@ main() ...@@ -95,6 +101,5 @@ main()
} }
} }
return 0; return 0;
} }
...@@ -21,101 +21,73 @@ ...@@ -21,101 +21,73 @@
#include <deque> #include <deque>
#include "closure.hh" #include "closure.hh"
#include "dupexp.hh" #include "dupexp.hh"
#include <algorithm>
namespace spot namespace spot
{ {
namespace
{
struct transition
{
unsigned dst;
acc_cond::mark_t acc;
transition(unsigned dst, acc_cond::mark_t acc) :
dst(dst), acc(acc)
{
}
};
struct transition_hash
{
size_t
operator()(const transition& t) const
{
return wang32_hash(t.dst) ^ wang32_hash(t.acc);
}
};
struct transition_equal
{
bool
operator()(const transition& left, const transition& right) const
{
return left.dst == right.dst
&& left.acc == right.acc;
}
};
typedef std::unordered_map<transition, unsigned, transition_hash,
transition_equal> tmap_t;
typedef std::set<unsigned> tset_t;
}
tgba_digraph_ptr tgba_digraph_ptr
closure(const const_tgba_digraph_ptr& a) closure(tgba_digraph_ptr&& a)
{ {
tgba_digraph_ptr res = tgba_dupexp_dfs(a); unsigned n = a->num_states();
unsigned n = res->num_states(); std::vector<unsigned> todo;
tset_t todo; std::vector<std::vector<unsigned> > dst2trans(n);
for (unsigned state = 0; state < n; ++state) for (unsigned state = 0; state < n; ++state)
{ {
tmap_t uniq; auto trans = a->out(state);
auto trans = res->out(state);
for (auto it = trans.begin(); it != trans.end(); ++it) for (auto it = trans.begin(); it != trans.end(); ++it)
{ {
todo.insert(it.trans()); todo.push_back(it.trans());
uniq.emplace(transition(it->dst, it->acc), it.trans()); dst2trans[it->dst].push_back(it.trans());
} }
while (!todo.empty()) while (!todo.empty())
{ {
unsigned t1 = *todo.begin(); auto t1 = a->trans_storage(todo.back());
todo.erase(t1); todo.pop_back();
tgba_graph_trans_data td = res->trans_data(t1);
unsigned dst = res->trans_storage(t1).dst;
for (auto& t2 : res->out(dst)) for (auto& t2 : a->out(t1.dst))
{ {
bdd cond = td.cond & t2.cond; bdd cond = t1.cond & t2.cond;
if (cond != bddfalse) if (cond != bddfalse)
{ {
acc_cond::mark_t acc = td.acc | t2.acc; bool need_new_trans = true;
transition jump(t2.dst, acc); acc_cond::mark_t acc = t1.acc | t2.acc;
unsigned i; for (auto& t: dst2trans[t2.dst])
auto u = uniq.find(jump);
if (u == uniq.end())
{ {
i = res->new_transition(state, t2.dst, cond, acc); auto& ts = a->trans_storage(t);
uniq.emplace(jump, i); if (acc == ts.acc)
todo.insert(i);
}
else
{ {
bdd old_cond = res->trans_data(u->second).cond; if (!bdd_implies(cond, ts.cond))
if (!bdd_implies(cond, old_cond))
{ {
res->trans_data(u->second).cond = cond | old_cond; ts.cond = ts.cond | cond;
todo.insert(u->second); if (std::find(todo.begin(), todo.end(), t)
== todo.end())
todo.push_back(t);
}
need_new_trans = false;
} }
} }
if (need_new_trans)
{
unsigned i =
a->new_transition(state, t2.dst, cond, acc);
dst2trans[t2.dst].push_back(i);
todo.push_back(i);
} }
} }
} }
uniq.clear();
} }
return res; for (auto& it: dst2trans)
it.clear();
}
return a;
}
tgba_digraph_ptr
closure(const const_tgba_digraph_ptr& a)
{
return closure(make_tgba_digraph(a));
} }
} }
...@@ -26,6 +26,11 @@ namespace spot ...@@ -26,6 +26,11 @@ namespace spot
{ {
SPOT_API tgba_digraph_ptr SPOT_API tgba_digraph_ptr
closure(const const_tgba_digraph_ptr&); closure(const const_tgba_digraph_ptr&);
#ifndef SWIG
SPOT_API tgba_digraph_ptr
closure(tgba_digraph_ptr&&);
#endif
} }
#endif #endif
...@@ -60,16 +60,16 @@ namespace spot ...@@ -60,16 +60,16 @@ namespace spot
} }
const ltl::formula* nf = ltl::unop::instance(ltl::unop::Not, f->clone()); const ltl::formula* nf = ltl::unop::instance(ltl::unop::Not, f->clone());
translator trans; translator trans;
auto aut_f = trans.run(f); tgba_digraph_ptr aut_f = trans.run(f);
auto aut_nf = trans.run(nf); tgba_digraph_ptr aut_nf = trans.run(nf);
bdd aps = atomic_prop_collect_as_bdd(f, aut_f); bdd aps = atomic_prop_collect_as_bdd(f, aut_f);
nf->destroy(); nf->destroy();
return is_stutter_invariant(aut_f, aut_nf, aps); return is_stutter_invariant(std::move(aut_f), std::move(aut_nf), aps);
} }
bool bool
is_stutter_invariant(const const_tgba_digraph_ptr& aut_f, is_stutter_invariant(tgba_digraph_ptr&& aut_f,
const const_tgba_digraph_ptr& aut_nf, bdd aps) tgba_digraph_ptr&& aut_nf, bdd aps)
{ {
const char* stutter_check = getenv("SPOT_STUTTER_CHECK"); const char* stutter_check = getenv("SPOT_STUTTER_CHECK");
char algo = stutter_check ? stutter_check[0] : '8'; char algo = stutter_check ? stutter_check[0] : '8';
...@@ -79,32 +79,38 @@ namespace spot ...@@ -79,32 +79,38 @@ namespace spot
// sl(aut_f) x sl(aut_nf) // sl(aut_f) x sl(aut_nf)
case '1': case '1':
{ {
return product(sl(aut_f, aps), sl(aut_nf, aps))->is_empty(); return product(sl(std::move(aut_f), aps),
sl(std::move(aut_nf), aps))->is_empty();
} }
// sl(cl(aut_f)) x aut_nf // sl(cl(aut_f)) x aut_nf
case '2': case '2':
{ {
return product(sl(closure(aut_f), aps), aut_nf)->is_empty(); return product(sl(closure(std::move(aut_f)), aps),
std::move(aut_nf))->is_empty();
} }
// (cl(sl(aut_f)) x aut_nf // (cl(sl(aut_f)) x aut_nf
case '3': case '3':
{ {
return product(closure(sl(aut_f, aps)), aut_nf)->is_empty(); return product(closure(sl(std::move(aut_f), aps)),
std::move(aut_nf))->is_empty();
} }
// sl2(aut_f) x sl2(aut_nf) // sl2(aut_f) x sl2(aut_nf)
case '4': case '4':
{ {
return product(sl2(aut_f, aps), sl2(aut_nf, aps))->is_empty(); return product(sl2(std::move(aut_f), aps),
sl2(std::move(aut_nf), aps))->is_empty();
} }
// sl2(cl(aut_f)) x aut_nf // sl2(cl(aut_f)) x aut_nf
case '5': case '5':
{ {
return product(sl2(closure(aut_f), aps), aut_nf)->is_empty(); return product(sl2(closure(std::move(aut_f)), aps),
std::move(aut_nf))->is_empty();
} }
// (cl(sl2(aut_f)) x aut_nf // (cl(sl2(aut_f)) x aut_nf
case '6': case '6':
{ {
return product(closure(sl2(aut_f, aps)), aut_nf)->is_empty(); return product(closure(sl2(std::move(aut_f), aps)),
std::move(aut_nf))->is_empty();
} }
// on-the-fly sl(aut_f) x sl(aut_nf) // on-the-fly sl(aut_f) x sl(aut_nf)
case '7': case '7':
...@@ -116,7 +122,8 @@ namespace spot ...@@ -116,7 +122,8 @@ namespace spot
// cl(aut_f) x cl(aut_nf) // cl(aut_f) x cl(aut_nf)
case '8': case '8':
{ {
return product(closure(aut_f), closure(aut_nf))->is_empty(); return product(closure(std::move(aut_f)),
closure(std::move(aut_nf)))->is_empty();
} }
default: default:
throw std::runtime_error("invalid value for SPOT_STUTTER_CHECK."); throw std::runtime_error("invalid value for SPOT_STUTTER_CHECK.");
......
...@@ -29,8 +29,8 @@ namespace spot ...@@ -29,8 +29,8 @@ namespace spot
is_stutter_invariant(const ltl::formula* f); is_stutter_invariant(const ltl::formula* f);
SPOT_API bool SPOT_API bool
is_stutter_invariant(const const_tgba_digraph_ptr& aut_f, is_stutter_invariant(tgba_digraph_ptr&& aut_f,
const const_tgba_digraph_ptr& aut_nf, bdd aps); tgba_digraph_ptr&& aut_nf, bdd aps);
} }
#endif #endif
...@@ -133,38 +133,45 @@ namespace spot ...@@ -133,38 +133,45 @@ namespace spot
} }
tgba_digraph_ptr tgba_digraph_ptr
sl2(const const_tgba_digraph_ptr& a, bdd atomic_propositions) sl2(tgba_digraph_ptr&& a, bdd atomic_propositions)
{ {
tgba_digraph_ptr res = tgba_dupexp_dfs(a); unsigned num_states = a->num_states();
unsigned num_states = res->num_states(); unsigned num_transitions = a->num_transitions();
for (unsigned state = 0; state < num_states; ++state) for (unsigned state = 0; state < num_states; ++state)
{ {
std::vector<unsigned> out; auto trans = a->out(state);
auto trans = res->out(state);
for (auto it = trans.begin(); it != trans.end(); ++it) for (auto it = trans.begin(); it != trans.end()
out.push_back(it.trans()); && it.trans() <= num_transitions; ++it)
for (auto it: out)
{ {
if (res->trans_storage(it).dst != state) if (it->dst != state)
{ {
bdd all = res->trans_storage(it).cond; bdd all = it->cond;
while (all != bddfalse) while (all != bddfalse)
{ {
unsigned dst = res->trans_storage(it).dst; unsigned dst = it->dst;
bdd one = bdd_satoneset(all, atomic_propositions, bddtrue); bdd one = bdd_satoneset(all, atomic_propositions, bddtrue);
unsigned tmp = res->new_state(); unsigned tmp = a->new_state();
res->new_transition(state, tmp, one, unsigned i = a->new_transition(state, tmp, one,
res->trans_storage(it).acc); it->acc);
res->new_transition(tmp, tmp, one, 0U); assert(i > num_transitions);
res->new_transition(tmp, dst, one, i = a->new_transition(tmp, tmp, one, 0U);
res->trans_storage(it).acc); assert(i > num_transitions);
i = a->new_transition(tmp, dst, one,
it->acc);
assert(i > num_transitions);
all -= one; all -= one;
} }
} }
} }
} }
res->merge_transitions(); a->merge_transitions();
return res; return a;
}
tgba_digraph_ptr
sl2(const const_tgba_digraph_ptr& a, bdd atomic_propositions)
{
return sl2(make_tgba_digraph(a), atomic_propositions);
} }
} }
...@@ -38,6 +38,11 @@ namespace spot ...@@ -38,6 +38,11 @@ namespace spot
SPOT_API tgba_digraph_ptr SPOT_API tgba_digraph_ptr
sl2(const const_tgba_digraph_ptr&, bdd); sl2(const const_tgba_digraph_ptr&, bdd);
#ifndef SWIG
SPOT_API tgba_digraph_ptr
sl2(tgba_digraph_ptr&&);
#endif
} }
#endif #endif
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment