Store membership to acceptance sets using bitsets, not BDDs.

This is a huge patch, that took over a month to complete.  The bit sets
are currently restricted to what 'unsigned can store', but it should be
easy to extend it to 'uint64_t' should we need it.

* NEWS: Update.
* src/tgba/acc.hh: New file.
* src/tgbatest/acc.cc, src/tgbatest/acc.test: Test it.
* src/tgba/tgbakvcomplement.cc, src/tgba/tgbakvcomplement.hh,
src/tgba/tgbasgba.cc, src/tgba/tgbasgba.hh: Delete.  The KV
complementation is too slow to be used in practice, and I somehow broke
it during the conversion to bitsets.  The tgba->sgba conversion was only
used for the KV complementation, and should be better redone on
tgba_digraph_ptr should it be needed again.
* src/bin/ltlcross.cc, src/dstarparse/dra2ba.cc,
src/dstarparse/nsa2tgba.cc, src/graphtest/tgbagraph.cc,
src/graphtest/tgbagraph.test, src/kripke/fairkripke.cc,
src/kripke/fairkripke.hh, src/kripke/kripke.cc, src/kripke/kripke.hh,
src/kripke/kripkeexplicit.cc, src/kripke/kripkeexplicit.hh,
src/misc/hash.hh, src/neverparse/neverclaimparse.yy, src/priv/accmap.hh,
src/ta/ta.cc, src/ta/ta.hh, src/ta/taexplicit.cc, src/ta/taexplicit.hh,
src/ta/taproduct.cc, src/ta/taproduct.hh, src/ta/tgta.cc,
src/ta/tgta.hh, src/ta/tgtaexplicit.cc, src/ta/tgtaexplicit.hh,
src/ta/tgtaproduct.cc, src/ta/tgtaproduct.hh, src/taalgos/dotty.cc,
src/taalgos/emptinessta.cc, src/taalgos/minimize.cc,
src/taalgos/tgba2ta.cc, src/tgba/Makefile.am, src/tgba/fwd.hh,
src/tgba/taatgba.cc, src/tgba/taatgba.hh, src/tgba/tgba.cc,
src/tgba/tgba.hh, src/tgba/tgbagraph.cc, src/tgba/tgbagraph.hh,
src/tgba/tgbamask.cc, src/tgba/tgbamask.hh, src/tgba/tgbaproduct.cc,
src/tgba/tgbaproduct.hh, src/tgba/tgbaproxy.cc, src/tgba/tgbaproxy.hh,
src/tgba/tgbasafracomplement.cc, src/tgba/tgbasafracomplement.hh,
src/tgbaalgos/bfssteps.cc, src/tgbaalgos/complete.cc,
src/tgbaalgos/compsusp.cc, src/tgbaalgos/degen.cc,
src/tgbaalgos/dotty.cc, src/tgbaalgos/dtbasat.cc,
src/tgbaalgos/dtgbacomp.cc, src/tgbaalgos/dtgbasat.cc,
src/tgbaalgos/dupexp.cc, src/tgbaalgos/emptiness.cc,
src/tgbaalgos/emptiness.hh, src/tgbaalgos/gtec/ce.cc,
src/tgbaalgos/gtec/gtec.cc, src/tgbaalgos/gtec/gtec.hh,
src/tgbaalgos/gtec/sccstack.cc, src/tgbaalgos/gtec/sccstack.hh,
src/tgbaalgos/gv04.cc, src/tgbaalgos/hoaf.cc,
src/tgbaalgos/isweakscc.cc, src/tgbaalgos/lbtt.cc,
src/tgbaalgos/ltl2tgba_fm.cc, src/tgbaalgos/magic.cc,
src/tgbaalgos/ndfs_result.hxx, src/tgbaalgos/neverclaim.cc,
src/tgbaalgos/postproc.cc, src/tgbaalgos/powerset.cc,
src/tgbaalgos/randomgraph.cc, src/tgbaalgos/randomgraph.hh,
src/tgbaalgos/reducerun.cc, src/tgbaalgos/replayrun.cc,
src/tgbaalgos/safety.cc, src/tgbaalgos/save.cc, src/tgbaalgos/scc.cc,
src/tgbaalgos/scc.hh, src/tgbaalgos/sccfilter.cc,
src/tgbaalgos/sccinfo.cc, src/tgbaalgos/sccinfo.hh,
src/tgbaalgos/se05.cc, src/tgbaalgos/simulation.cc,
src/tgbaalgos/simulation.hh, src/tgbaalgos/stats.cc,
src/tgbaalgos/stripacc.cc, src/tgbaalgos/tau03.cc,
src/tgbaalgos/tau03opt.cc, src/tgbaalgos/weight.cc,
src/tgbaalgos/weight.hh, src/tgbaparse/tgbaparse.yy,
src/tgbatest/Makefile.am, src/tgbatest/complementation.cc,
src/tgbatest/complementation.test, src/tgbatest/degenlskip.test,
src/tgbatest/det.test, src/tgbatest/dstar.test, src/tgbatest/emptchk.cc,
src/tgbatest/explpro2.test, src/tgbatest/explpro3.test,
src/tgbatest/explpro4.test, src/tgbatest/explprod.test,
src/tgbatest/ltl2tgba.cc, src/tgbatest/ltl2tgba.test,
src/tgbatest/maskacc.cc, src/tgbatest/maskacc.test,
src/tgbatest/neverclaimread.test, src/tgbatest/randtgba.cc,
src/tgbatest/readsave.test, src/tgbatest/sim.test,
src/tgbatest/sim2.test, src/tgbatest/spotlbtt.test,
src/tgbatest/tgbaread.test, src/tgbatest/tripprod.test,
iface/dve2/dve2.cc: Adjust or use to the new acceptance interface.
This commit is contained in:
Alexandre Duret-Lutz 2014-09-29 18:17:34 +02:00
parent 37ece2b878
commit 2c764fb3c7
125 changed files with 1950 additions and 3254 deletions

View file

@ -80,7 +80,7 @@ namespace spot
continue;
bdd cond = i->current_condition();
bdd acc = i->current_acceptance_conditions();
acc_cond::mark_t acc = i->current_acceptance_conditions();
tgba_run::step s = { src, cond, acc };
if (match(s, dest))

View file

@ -26,8 +26,8 @@ namespace spot
{
unsigned n = aut->num_states();
unsigned sink = -1U;
bdd allacc = aut->all_acceptance_conditions();
if (allacc == bddfalse)
acc_cond::mark_t allacc = aut->acc().all_sets();
if (allacc == 0U)
{
// We cannot safely complete an automaton if it has no
// acceptance set as the added sink would become accepting.
@ -44,7 +44,7 @@ namespace spot
for (unsigned i = 0; i < n; ++i)
{
bool selfloop = true;
bdd accsum = bddfalse;
acc_cond::mark_t accsum = 0U;
for (auto& t: aut->out(i))
{
if (t.dst != i) // Not a self-loop
@ -66,7 +66,7 @@ namespace spot
for (unsigned i = 0; i < n; ++i)
{
bdd missingcond = bddtrue;
bdd acc = bddfalse;
acc_cond::mark_t acc = 0U;
for (auto& t: aut->out(i))
{
missingcond -= t.cond;

View file

@ -225,35 +225,11 @@ namespace spot
dict->register_all_variables_of(right, res);
dict->unregister_variable(bdd_var(v), res);
// The left and right automata might have acceptance marker in
// common.
// For the example, assume left has acceptance conditions A,B,C,D
// while right has acceptance condition C,D,E,F.
const acc_cond& la = left->acc();
const acc_cond& ra = right->acc();
res->set_acceptance_conditions(la.num_sets() + ra.num_sets());
// Negative acceptance variables...
// !A&!B&!C&!D
bdd lna = left->neg_acceptance_conditions();
// !C&!D&!E&!F
bdd rna = right->neg_acceptance_conditions();
// Missing acceptance variables...
// !E&!F
bdd lma = bdd_exist(rna, bdd_support(lna));
// !A&!B
bdd rma = bdd_exist(lna, bdd_support(rna));
// (A&!B&!C&!D + ... + !A&!B&!C&D) & !E&!F
bdd lac = left->all_acceptance_conditions() & lma;
// (C&!D&!E&!F + ... + !C&!D&!E&F) & !A&!B
bdd rac = right->all_acceptance_conditions() & rma;
bdd allacc = lac | rac;
res->set_acceptance_conditions(allacc);
// Acceptance condition to add to all transitions
// of the left automaton.
// !A&!B&!C&!D&E&!F | !A&!B&!C&!D&!E&F
bdd ladd = rac - lma;
bdd radd = lac - rma;
acc_cond::mark_t radd = ra.all_sets();
pair_map seen;
pair_queue todo;
@ -300,7 +276,7 @@ namespace spot
while (!ri || !ri->done())
{
bdd cond = lc;
bdd ra = allacc;
acc_cond::mark_t racc = radd;
if (ri)
{
cond = lc & ri->current_condition();
@ -311,7 +287,7 @@ namespace spot
continue;
}
d.second = ri->current_state();
ra = (ri->current_acceptance_conditions() & rma) | radd;
racc = ri->current_acceptance_conditions();
}
int dest;
@ -327,8 +303,10 @@ namespace spot
todo.push_back(d);
}
bdd la = (li->current_acceptance_conditions() & lma) | ladd;
res->new_transition(src, dest, bdd_exist(cond, v), ra & la);
acc_cond::mark_t a =
res->acc().join(la, li->current_acceptance_conditions(),
ra, racc);
res->new_transition(src, dest, bdd_exist(cond, v), a);
if (ri)
ri->next();

View file

@ -25,6 +25,7 @@
#include <deque>
#include <vector>
#include <algorithm>
#include <iterator>
#include "tgbaalgos/scc.hh"
#include "tgba/bddprint.hh"
@ -72,7 +73,7 @@ namespace spot
class outgoing_acc
{
const_tgba_ptr a_;
typedef std::pair<bdd, bdd> cache_entry;
typedef std::pair<acc_cond::mark_t, acc_cond::mark_t> cache_entry;
typedef std::unordered_map<const state*, cache_entry,
state_ptr_hash, state_ptr_equal> cache_t;
cache_t cache_;
@ -86,8 +87,8 @@ namespace spot
cache_t::const_iterator fill_cache(const state* s)
{
unsigned s1 = sm_ ? sm_->scc_of_state(s) : 0;
bdd common = a_->all_acceptance_conditions();
bdd union_ = bddfalse;
acc_cond::mark_t common = a_->acc().all_sets();
acc_cond::mark_t union_ = 0U;
for (auto it: a_->succ(s))
{
// Ignore transitions that leave the SCC of s.
@ -97,7 +98,7 @@ namespace spot
if (s2 != s1)
continue;
bdd set = it->current_acceptance_conditions();
acc_cond::mark_t set = it->current_acceptance_conditions();
common &= set;
union_ |= set;
}
@ -106,7 +107,7 @@ namespace spot
}
// Intersection of all outgoing acceptance sets
bdd common_acc(const state* s)
acc_cond::mark_t common_acc(const state* s)
{
cache_t::const_iterator i = cache_.find(s);
if (i == cache_.end())
@ -115,7 +116,7 @@ namespace spot
}
// Union of all outgoing acceptance sets
bdd union_acc(const state* s)
acc_cond::mark_t union_acc(const state* s)
{
cache_t::const_iterator i = cache_.find(s);
if (i == cache_.end())
@ -146,11 +147,10 @@ namespace spot
auto p = cache_.emplace(s, false);
if (p.second)
{
bdd all = a_->all_acceptance_conditions();
for (auto it: a_->succ(s))
{
// Look only for transitions that are accepting.
if (all != it->current_acceptance_conditions())
if (!a_->acc().accepting(it->current_acceptance_conditions()))
continue;
// Look only for self-loops.
const state* dest = uniq_(it->current_state());
@ -168,37 +168,23 @@ namespace spot
// Order of accepting sets (for one SCC)
class acc_order
{
std::vector<bdd> order_;
bdd found_;
std::vector<unsigned> order_;
acc_cond::mark_t found_;
public:
unsigned
next_level(bdd all, int slevel, bdd acc, bool skip_levels)
next_level(const acc_cond& acc, int slevel,
acc_cond::mark_t set, bool skip_levels)
{
bdd temp = acc;
if (all != found_)
{
// Check for new conditions in acc
if ((acc & found_) != acc)
{
bdd acc_t = acc;
while (acc_t != bddfalse)
{
bdd next = bdd_satone(acc_t);
acc_t -= next;
// Add new condition
if ((next & found_) != next)
{
order_.push_back(next);
found_ |= next;
}
}
}
}
// Update the order with any new set we discover
if (auto newsets = set - found_)
{
acc.fill_from(newsets, std::back_inserter(order_));
found_ |= newsets;
}
acc = temp;
unsigned next = slevel;
while (next < order_.size() && bdd_implies(order_[next], acc))
while (next < order_.size() && set.has(order_[next]))
{
++next;
if (!skip_levels)
@ -208,44 +194,41 @@ namespace spot
}
void
print(int scc, const bdd_dict_ptr dict)
print(int scc)
{
std::vector<bdd>::iterator i;
std::cout << "Order_" << scc << ":\t";
for (i = order_.begin(); i != order_.end(); i++)
{
bdd_print_acc(std::cout, dict, *i);
std::cout << ", ";
}
std::cout << std::endl;
for (auto i: order_)
std::cout << i << ", ";
std::cout << '\n';
}
};
// Accepting order for each SCC
class scc_orders
{
bdd all_;
const acc_cond& acc_;
std::map<int, acc_order> orders_;
bool skip_levels_;
public:
scc_orders(bdd all, bool skip_levels):
all_(all), skip_levels_(skip_levels)
scc_orders(const acc_cond& acc, bool skip_levels):
acc_(acc), skip_levels_(skip_levels)
{
}
unsigned
next_level(int scc, int slevel, bdd acc)
next_level(int scc, int slevel, acc_cond::mark_t set)
{
return orders_[scc].next_level(all_, slevel, acc, skip_levels_);
return orders_[scc].next_level(acc_, slevel, set, skip_levels_);
}
void
print(const bdd_dict_ptr dict)
print()
{
std::map<int, acc_order>::iterator i;
for (i = orders_.begin(); i != orders_.end(); i++)
i->second.print(i->first, dict);
i->second.print(i->first);
}
};
@ -273,26 +256,23 @@ namespace spot
// be used as a level in degen_state to indicate the next expected
// acceptance set. Level order.size() is a special level used to
// denote accepting states.
std::vector<bdd> order;
std::vector<unsigned> order;
{
// FIXME: revisit this comment once everything compiles again.
//
// The order is arbitrary, but it turns out that using push_back
// instead of push_front often gives better results because
// acceptance sets at the beginning if the cycle are more often
// used in the automaton. (This surprising fact is probably
// related to the order in which we declare the BDD variables
// during the translation.)
bdd all = a->all_acceptance_conditions();
while (all != bddfalse)
{
bdd next = bdd_satone(all);
all -= next;
order.push_back(next);
}
unsigned n = a->acc().num_sets();
for (unsigned i = n; i > 0; --i)
order.push_back(i - 1);
}
// Initialize scc_orders
bdd allacc = a->all_acceptance_conditions();
scc_orders orders(a->all_acceptance_conditions(), skip_levels);
scc_orders orders(a->acc(), skip_levels);
// Make sure we always use the same pointer for identical states
// from the input automaton.
@ -340,11 +320,12 @@ namespace spot
// start on the associated level.
if (s.second == 0)
{
bdd acc = outgoing.common_acc(s.first);
auto set = outgoing.common_acc(s.first);
if (use_cust_acc_orders)
s.second = orders.next_level(m.initial(), s.second, acc);
s.second = orders.next_level(m.initial(), s.second, set);
else
while (s.second < order.size() && bdd_implies(order[s.second], acc))
while (s.second < order.size()
&& set.has(order[s.second]))
{
++s.second;
if (!skip_levels)
@ -405,13 +386,13 @@ namespace spot
}
// The old level is slevel. What should be the new one?
bdd acc = i->current_acceptance_conditions();
bdd otheracc = outgoing.common_acc(d.first);
auto acc = i->current_acceptance_conditions();
auto otheracc = outgoing.common_acc(d.first);
if (want_sba && is_acc)
{
// Ignore the last expected acceptance set (the value of
// *prev below) if it is common to all other outgoing
// prev below) if it is common to all other outgoing
// transitions (of the current state) AND if it is not
// used by any outgoing transition of the destination
// state.
@ -447,12 +428,12 @@ namespace spot
if (!order.empty())
{
unsigned prev = order.size() - 1;
bdd common = outgoing.common_acc(s.first);
if (bdd_implies(order[prev], common))
auto common = outgoing.common_acc(s.first);
if (common.has(order[prev]))
{
bdd u = outgoing.union_acc(d.first);
if (!bdd_implies(order[prev], u))
acc -= order[prev];
auto u = outgoing.union_acc(d.first);
if (!u.has(order[prev]))
acc -= a->acc().mark(order[prev]);
}
}
}
@ -523,7 +504,7 @@ namespace spot
// are not skipping levels.
if (skip_levels || !is_acc)
while (next < order.size()
&& bdd_implies(order[next], acc))
&& acc.has(order[next]))
{
++next;
if (!skip_levels)
@ -545,7 +526,7 @@ namespace spot
{
d.second = 0; // Make it go to the first level.
// Skip levels as much as possible.
if (acc != allacc && !skip_levels)
if (!a->acc().accepting(acc) && !skip_levels)
{
if (use_cust_acc_orders)
{
@ -554,7 +535,7 @@ namespace spot
else
{
while (d.second < order.size() &&
bdd_implies(order[d.second], acc))
acc.has(order[d.second]))
++d.second;
}
}

View file

@ -73,9 +73,8 @@ namespace spot
else
{
si->first();
accepting = ((!si->done())
&& (si->current_acceptance_conditions() ==
aut_->all_acceptance_conditions()));
auto a = si->current_acceptance_conditions();
accepting = !si->done() && aut_->acc().accepting(a);
}
}
else
@ -96,10 +95,13 @@ namespace spot
{
std::string label =
bdd_format_formula(aut_->get_dict(),
si->current_condition())
+ "\n"
+ bdd_format_accset(aut_->get_dict(),
si->current_acceptance_conditions());
si->current_condition());
auto a = si->current_acceptance_conditions();
if (a)
{
label += "\n";
label += aut_->acc().format(a);
}
std::string s = aut_->transition_annotation(si);
if (!s.empty())

View file

@ -436,7 +436,7 @@ namespace spot
}
}
bdd all_acc = ref->all_acceptance_conditions();
const acc_cond& ra = ref->acc();
// construction of contraints (4,5) : all loops in the product
// where no accepting run is detected in the ref. automaton,
@ -477,7 +477,7 @@ namespace spot
if (sm.scc_of(dp) != q1p_scc)
continue;
if (tr.acc == all_acc)
if (ra.accepting(tr.acc))
continue;
for (unsigned q3 = 0; q3 < d.cand_size; ++q3)
{
@ -574,7 +574,7 @@ namespace spot
{
// We only care about the looping case if
// it is accepting in the reference.
if (tr.acc != all_acc)
if (!ra.accepting(tr.acc))
continue;
bdd all = tr.cond;
while (all != bddfalse)
@ -636,7 +636,7 @@ namespace spot
auto autdict = aut->get_dict();
auto a = make_tgba_digraph(autdict);
a->copy_ap_of(aut);
bdd acc = a->set_single_acceptance_set();
acc_cond::mark_t acc = a->set_single_acceptance_set();
a->new_states(satdict.cand_size);
unsigned last_aut_trans = -1U;

View file

@ -28,18 +28,20 @@ namespace spot
// Clone the original automaton.
tgba_digraph_ptr res = tgba_dupexp_dfs(aut);
bdd oldaccs = aut->all_acceptance_conditions();
bdd oldnegs = aut->neg_acceptance_conditions();
// Copy the old acceptance condition before we replace it.
acc_cond oldacc = aut->acc(); // Copy it!
// We will modify res in place, and the resulting
// automaton will only have one acceptance set.
// This changes aut->acc();
res->set_single_acceptance_set();
unsigned num_acc = aut->number_of_acceptance_conditions();
unsigned num_sets = oldacc.num_sets();
unsigned n = res->num_states();
// We will duplicate the automaton as many times as we have
// acceptance sets, and we need one extra sink state.
res->new_states(num_acc * n + 1);
res->new_states(num_sets * n + 1);
unsigned sink = res->num_states() - 1;
// The sink state has an accepting self-loop.
res->new_acc_transition(sink, sink, bddtrue);
@ -54,29 +56,26 @@ namespace spot
if (t.dst >= n) // Ignore transitions we added.
break;
missingcond -= t.cond;
bdd curacc = t.acc;
acc_cond::mark_t curacc = t.acc;
// The original transition must not accept anymore.
t.acc = bddfalse;
t.acc = 0U;
// Transition that were fully accepting are never cloned.
if (curacc == oldaccs)
if (oldacc.accepting(curacc))
continue;
// Save t.cond and t.dst as the reference to t
// is invalided by calls to new_transition().
unsigned dst = t.dst;
bdd cond = t.cond;
// We want all acceptance bdd variable to appear in curacc.
if (curacc == bddfalse)
curacc = oldnegs;
// Iterate over all the acceptance conditions in 'curacc',
// an duplicate it each each clone for which it does not
// an duplicate it for each clone for which it does not
// belong to the acceptance set.
unsigned add = 0;
while (curacc != bddtrue)
for (unsigned set = 0; set < num_sets; ++set)
{
add += n;
bdd h = bdd_high(curacc);
if (h == bddfalse)
if (!oldacc.has(curacc, set))
{
// Clone the transition
res->new_acc_transition(src + add, dst + add, cond);
@ -93,26 +92,9 @@ namespace spot
// arc set would be better.
if (dst <= src)
res->new_transition(src, dst + add, cond);
curacc = bdd_low(curacc);
}
else
{
// We know that only one variable can be positive
// on any branch, so since we have just seen such
// a variable, we want to go to explore its LOW
// branch for more positive variables. The only
// case where we will not do that is if the LOW
// branch is false. In that case we take the HIGH
// branch to enumerate all the remaining negated
// variables.
bdd tmp = bdd_low(curacc);
if (tmp != bddfalse)
curacc = tmp;
else
curacc = h;
}
}
assert(add == num_acc * n);
assert(add == num_sets * n);
}
// Complete the original automaton.
if (missingcond != bddfalse)
@ -134,21 +116,18 @@ namespace spot
true, // inherently_weak
true); // deterministic
bdd oldaccs = aut->all_acceptance_conditions();
bdd oldnegs = aut->neg_acceptance_conditions();
scc_info si(res);
// We will modify res in place, and the resulting
// automaton will only have one acceptance set.
bdd all_acc = res->set_single_acceptance_set();
acc_cond::mark_t all_acc = res->set_single_acceptance_set();
res->prop_state_based_acc();
unsigned sink = res->num_states();
for (unsigned src = 0; src < sink; ++src)
{
bdd acc = bddfalse;
acc_cond::mark_t acc = 0U;
unsigned scc = si.scc_of(src);
if (!si.is_accepting_scc(scc) && !si.is_trivial(scc))
acc = all_acc;

View file

@ -57,6 +57,8 @@ namespace spot
namespace
{
static bdd_dict_ptr debug_dict = 0;
static const acc_cond* debug_ref_acc = 0;
static const acc_cond* debug_cand_acc = 0;
struct transition
{
@ -120,10 +122,10 @@ namespace spot
{
unsigned src;
bdd cond;
bdd acc;
acc_cond::mark_t acc;
unsigned dst;
transition_acc(int src, bdd cond, bdd acc, int dst)
transition_acc(int src, bdd cond, acc_cond::mark_t acc, int dst)
: src(src), cond(cond), acc(acc), dst(dst)
{
}
@ -142,7 +144,7 @@ namespace spot
return true;
if (this->cond.id() > other.cond.id())
return false;
return this->acc.id() < other.acc.id();
return this->acc < other.acc;
}
bool operator==(const transition_acc& other) const
@ -150,7 +152,7 @@ namespace spot
return (this->src == other.src
&& this->dst == other.dst
&& this->cond.id() == other.cond.id()
&& this->acc.id() == other.acc.id());
&& this->acc == other.acc);
}
};
@ -160,19 +162,19 @@ namespace spot
unsigned src_ref;
unsigned dst_cand;
unsigned dst_ref;
bdd acc_cand;
bdd acc_ref;
acc_cond::mark_t acc_cand;
acc_cond::mark_t acc_ref;
path(unsigned src_cand, unsigned src_ref)
: src_cand(src_cand), src_ref(src_ref),
dst_cand(src_cand), dst_ref(src_ref),
acc_cand(bddfalse), acc_ref(bddfalse)
acc_cand(0U), acc_ref(0U)
{
}
path(unsigned src_cand, unsigned src_ref,
unsigned dst_cand, unsigned dst_ref,
bdd acc_cand, bdd acc_ref)
acc_cond::mark_t acc_cand, acc_cond::mark_t acc_ref)
: src_cand(src_cand), src_ref(src_ref),
dst_cand(dst_cand), dst_ref(dst_ref),
acc_cand(acc_cand), acc_ref(acc_ref)
@ -197,13 +199,13 @@ namespace spot
return true;
if (this->dst_ref > other.dst_ref)
return false;
if (this->acc_ref.id() < other.acc_ref.id())
if (this->acc_ref < other.acc_ref)
return true;
if (this->acc_ref.id() > other.acc_ref.id())
if (this->acc_ref > other.acc_ref)
return false;
if (this->acc_cand.id() < other.acc_cand.id())
if (this->acc_cand < other.acc_cand)
return true;
if (this->acc_cand.id() > other.acc_cand.id())
if (this->acc_cand > other.acc_cand)
return false;
return false;
@ -224,7 +226,7 @@ namespace spot
{
os << '<' << t.src << ','
<< bdd_format_formula(debug_dict, t.cond) << ','
<< bdd_format_accset(debug_dict, t.acc)
<< debug_cand_acc->format(t.acc)
<< ',' << t.dst << '>';
return os;
}
@ -236,15 +238,15 @@ namespace spot
<< p.src_ref << ','
<< p.dst_cand << ','
<< p.dst_ref << ", "
<< bdd_format_accset(debug_dict, p.acc_cand) << ", "
<< bdd_format_accset(debug_dict, p.acc_ref) << '>';
<< debug_cand_acc->format(p.acc_cand) << ", "
<< debug_ref_acc->format(p.acc_ref) << '>';
return os;
}
struct dict
{
dict(const const_tgba_ptr& a)
: aut(a)
: aut(a), cacc(a->get_dict())
{
}
@ -267,16 +269,15 @@ namespace spot
// int_map int_to_state;
unsigned cand_size;
unsigned int cand_nacc;
std::vector<bdd> cand_acc; // size cand_nacc
std::vector<acc_cond::mark_t> cand_acc; // size cand_nacc
std::vector<bdd> all_cand_acc;
std::vector<bdd> all_ref_acc;
bdd cand_all_acc;
bdd ref_all_acc;
std::vector<acc_cond::mark_t> all_cand_acc;
std::vector<acc_cond::mark_t> all_ref_acc;
std::vector<bool> is_weak_scc;
acc_cond cacc;
~dict()
{
aut->get_dict()->unregister_all_my_variables(this);
@ -288,48 +289,27 @@ namespace spot
dict& d, bdd ap, bool state_based, scc_info& sm)
{
bdd_dict_ptr bd = aut->get_dict();
ltl::default_environment& env = ltl::default_environment::instance();
d.cand_acc.resize(d.cand_nacc);
d.all_cand_acc.push_back(bddfalse);
bdd allneg = bddtrue;
d.cacc.add_sets(d.cand_nacc);
d.all_cand_acc.push_back(0U);
for (unsigned n = 0; n < d.cand_nacc; ++n)
{
std::ostringstream s;
s << n;
const ltl::formula* af = env.require(s.str());
int v = bd->register_acceptance_variable(af, &d);
af->destroy();
d.cand_acc[n] = bdd_ithvar(v);
allneg &= bdd_nithvar(v);
}
for (unsigned n = 0; n < d.cand_nacc; ++n)
{
bdd c = bdd_exist(allneg, d.cand_acc[n]) & d.cand_acc[n];
auto c = d.cacc.mark(n);
d.cand_acc[n] = c;
size_t s = d.all_cand_acc.size();
for (size_t i = 0; i < s; ++i)
d.all_cand_acc.push_back(d.all_cand_acc[i] | c);
}
d.cand_all_acc = bdd_support(allneg);
d.ref_all_acc = bdd_support(aut->all_acceptance_conditions());
bdd refall = d.ref_all_acc;
bdd refnegall = aut->neg_acceptance_conditions();
d.all_ref_acc.push_back(bddfalse);
while (refall != bddtrue)
d.all_ref_acc.push_back(0U);
unsigned ref_nacc = aut->acc().num_sets();
for (unsigned n = 0; n < ref_nacc; ++n)
{
bdd v = bdd_ithvar(bdd_var(refall));
bdd c = bdd_exist(refnegall, v) & v;
auto c = aut->acc().mark(n);
size_t s = d.all_ref_acc.size();
for (size_t i = 0; i < s; ++i)
d.all_ref_acc.push_back(d.all_ref_acc[i] | c);
refall = bdd_high(refall);
}
unsigned ref_size = aut->num_states();
@ -485,9 +465,12 @@ namespace spot
#if DEBUG
debug_dict = ref->get_dict();
debug_ref_acc = &ref->acc();
debug_cand_acc = &d.cacc;
dout << "ref_size: " << ref_size << '\n';
dout << "cand_size: " << d.cand_size << '\n';
#endif
auto& racc = ref->acc();
dout << "symmetry-breaking clauses\n";
int j = 0;
@ -586,8 +569,6 @@ namespace spot
}
}
bdd all_acc = ref->all_acceptance_conditions();
// construction of constraints (11,12,13)
for (unsigned q1p = 0; q1p < ref_size; ++q1p)
{
@ -630,7 +611,7 @@ namespace spot
for (unsigned q3 = 0; q3 < d.cand_size; ++q3)
{
bdd all = tr.cond;
bdd curacc = tr.acc;
acc_cond::mark_t curacc = tr.acc;
while (all != bddfalse)
{
bdd l = bdd_satoneset(all, ap, bddfalse);
@ -643,23 +624,22 @@ namespace spot
{
if ((!is_acc) ||
(!is_weak &&
(curacc |
d.all_ref_acc[fp]) != all_acc))
!racc.accepting
(curacc | d.all_ref_acc[fp])))
{
#if DEBUG
dout << "(11) " << p << ""
<< t << "δ → ¬(";
bdd all_ = d.all_cand_acc.back();
all_ -= d.all_cand_acc[f];
bool notfirst = false;
while (all_ != bddfalse)
acc_cond::mark_t all_ =
d.all_cand_acc.back() -
d.all_cand_acc[f];
for (auto m: d.cacc.sets(all_))
{
bdd one = bdd_satone(all_);
all_ -= one;
transition_acc ta(q2, l,
one, q1);
transition_acc
ta(q2, l,
d.cacc.mark(m), q1);
if (notfirst)
out << "";
else
@ -671,15 +651,14 @@ namespace spot
out << -pid << ' ' << -ti;
// 11
bdd all_f = d.all_cand_acc.back();
all_f -= d.all_cand_acc[f];
while (all_f != bddfalse)
acc_cond::mark_t all_f =
d.all_cand_acc.back() -
d.all_cand_acc[f];
for (auto m: d.cacc.sets(all_f))
{
bdd one = bdd_satone(all_f);
all_f -= one;
transition_acc ta(q2, l,
one, q1);
transition_acc
ta(q2, l,
d.cacc.mark(m), q1);
int tai = d.transaccid[ta];
assert(tai != 0);
out << ' ' << -tai;
@ -692,17 +671,15 @@ namespace spot
#if DEBUG
dout << "(12) " << p << ""
<< t << "δ → (";
bdd all_ = d.all_cand_acc.back();
all_ -= d.all_cand_acc[f];
bool notfirst = false;
while (all_ != bddfalse)
// 11
acc_cond::mark_t all_ =
d.cacc.comp(d.all_cand_acc[f]);
for (auto m: d.cacc.sets(all_))
{
bdd one = bdd_satone(all_);
all_ -= one;
transition_acc ta(q2, l,
one, q1);
transition_acc
ta(q2, l,
d.cacc.mark(m), q1);
if (notfirst)
out << "";
else
@ -712,15 +689,13 @@ namespace spot
out << ")\n";
#endif // DEBUG
// 12
bdd all_f = d.all_cand_acc.back();
all_f -= d.all_cand_acc[f];
while (all_f != bddfalse)
acc_cond::mark_t all_f =
d.cacc.comp(d.all_cand_acc[f]);
for (auto m: d.cacc.sets(all_f))
{
bdd one = bdd_satone(all_f);
all_f -= one;
transition_acc ta(q2, l,
one, q1);
transition_acc
ta(q2, l,
d.cacc.mark(m), q1);
int tai = d.transaccid[ta];
assert(tai != 0);
@ -735,10 +710,9 @@ namespace spot
size_t sf = d.all_cand_acc.size();
for (size_t f = 0; f < sf; ++f)
{
bdd f2 = p.acc_cand |
d.all_cand_acc[f];
bdd f2p = bddfalse;
acc_cond::mark_t f2 =
p.acc_cand | d.all_cand_acc[f];
acc_cond::mark_t f2p = 0U;
if (!is_weak)
f2p = p.acc_ref | curacc;
@ -751,47 +725,34 @@ namespace spot
dout << "(13) " << p << ""
<< t << "δ ";
bdd biga_ = d.all_cand_acc[f];
while (biga_ != bddfalse)
auto biga_ = d.all_cand_acc[f];
for (unsigned m = 0;
m < d.cand_nacc; ++m)
{
bdd a = bdd_satone(biga_);
biga_ -= a;
transition_acc ta(q2, l, a, q3);
out << "" << ta << "FC";
}
biga_ = d.all_cand_acc.back()
- d.all_cand_acc[f];
while (biga_ != bddfalse)
{
bdd a = bdd_satone(biga_);
biga_ -= a;
transition_acc ta(q2, l, a, q3);
out << " ∧ ¬" << ta << "FC";
transition_acc
ta(q2, l,
d.cacc.mark(m), q3);
int tai = d.transaccid[ta];
const char* not_ = "¬";
if (d.cacc.has(biga_, m))
not_ = "";
out << tai << ' ';
out << "" << not_
<< ta << "FC";
}
out << "" << p2 << '\n';
#endif
out << -pid << ' ' << -ti << ' ';
bdd biga = d.all_cand_acc[f];
while (biga != bddfalse)
auto biga = d.all_cand_acc[f];
for (unsigned m = 0;
m < d.cand_nacc; ++m)
{
bdd a = bdd_satone(biga);
biga -= a;
transition_acc ta(q2, l, a, q3);
int tai = d.transaccid[ta];
out << -tai << ' ';
}
biga = d.all_cand_acc.back()
- d.all_cand_acc[f];
while (biga != bddfalse)
{
bdd a = bdd_satone(biga);
biga -= a;
transition_acc ta(q2, l, a, q3);
transition_acc
ta(q2, l,
d.cacc.mark(m), q3);
int tai = d.transaccid[ta];
if (d.cacc.has(biga, m))
tai = -tai;
out << tai << ' ';
}
@ -818,7 +779,7 @@ namespace spot
auto autdict = aut->get_dict();
auto a = make_tgba_digraph(autdict);
a->copy_ap_of(aut);
a->set_acceptance_conditions(satdict.all_cand_acc.back());
a->set_acceptance_conditions(satdict.cand_nacc);
a->new_states(satdict.cand_size);
@ -835,7 +796,7 @@ namespace spot
#endif
dout << "--- transition variables ---\n";
std::map<int, bdd> state_acc;
std::map<int, acc_cond::mark_t> state_acc;
std::set<src_cond> seen_trans;
for (int v: solution)
{
@ -854,7 +815,7 @@ namespace spot
if (seen_trans.insert(src_cond(t->second.src,
t->second.cond)).second)
{
bdd acc = bddfalse;
acc_cond::mark_t acc = 0U;
if (state_based)
{
auto i = state_acc.find(t->second.src);
@ -887,11 +848,13 @@ namespace spot
ta->second.dst == last_sat_trans->dst)
{
assert(!state_based);
a->trans_data(last_aut_trans).acc |= ta->second.acc;
auto& v = a->trans_data(last_aut_trans).acc;
v |= ta->second.acc;
}
else if (state_based)
{
state_acc[ta->second.src] |= ta->second.acc;
auto& v = state_acc[ta->second.src];
v |= ta->second.acc;
}
}
}

View file

@ -60,9 +60,9 @@ namespace spot
const state*, int out,
const tgba_succ_iterator* si)
{
out_->new_transition(in - 1, out - 1,
si->current_condition(),
si->current_acceptance_conditions());
out_->new_transition
(in - 1, out - 1, si->current_condition(),
si->current_acceptance_conditions());
}
protected:

View file

@ -89,7 +89,7 @@ namespace spot
os << " | ";
bdd_print_formula(os, d, i->label);
os << '\t';
bdd_print_accset(os, d, i->acc);
os << a->acc().format(i->acc);
os << std::endl;
}
os << "Cycle:" << std::endl;
@ -100,7 +100,7 @@ namespace spot
os << " | ";
bdd_print_formula(os, d, i->label);
os << '\t';
bdd_print_accset(os, d, i->acc);
os << a->acc().format(i->acc);
os << '\n';
}
return os;
@ -302,7 +302,7 @@ namespace spot
unsigned src;
unsigned dst;
const tgba_run::steps* l;
bdd seen_acc = bddfalse;
acc_cond::mark_t seen_acc = 0U;
typedef std::unordered_map<const state*, unsigned,
state_ptr_hash, state_ptr_equal> state_map;
@ -323,7 +323,7 @@ namespace spot
{
// expected outgoing transition
bdd label = i->label;
bdd acc = i->acc;
acc_cond::mark_t acc = i->acc;
// compute the next expected state
const state* next;
@ -379,7 +379,7 @@ namespace spot
s->destroy();
assert(seen_acc == a->all_acceptance_conditions());
assert(a->acc().accepting(seen_acc));
return res;
}

View file

@ -269,7 +269,7 @@ namespace spot
struct step {
const state* s;
bdd label;
bdd acc;
acc_cond::mark_t acc;
};
typedef std::list<step> steps;

View file

@ -149,7 +149,7 @@ namespace spot
void
couvreur99_check_result::accepting_cycle()
{
bdd acc_to_traverse = ecs_->aut->all_acceptance_conditions();
acc_cond::mark_t acc_to_traverse = ecs_->aut->acc().all_sets();
// Compute an accepting cycle using successive BFS that are
// restarted from the point reached after we have discovered a
// transition with a new acceptance conditions.
@ -173,11 +173,11 @@ namespace spot
{
const couvreur99_check_status* ecs;
couvreur99_check_result* r;
bdd& acc_to_traverse;
acc_cond::mark_t& acc_to_traverse;
int scc_root;
scc_bfs(const couvreur99_check_status* ecs,
couvreur99_check_result* r, bdd& acc_to_traverse)
couvreur99_check_result* r, acc_cond::mark_t& acc_to_traverse)
: bfs_steps(ecs->aut), ecs(ecs), r(r),
acc_to_traverse(acc_to_traverse),
scc_root(ecs->root.top().index)
@ -202,9 +202,10 @@ namespace spot
virtual bool
match(tgba_run::step& st, const state* s)
{
bdd less_acc = acc_to_traverse - st.acc;
acc_cond::mark_t less_acc =
acc_to_traverse - st.acc;
if (less_acc != acc_to_traverse
|| (acc_to_traverse == bddfalse
|| (acc_to_traverse == 0U
&& s == ecs->cycle_seed))
{
acc_to_traverse = less_acc;
@ -218,7 +219,7 @@ namespace spot
substart = b.search(substart, run_->cycle);
assert(substart);
}
while (acc_to_traverse != bddfalse || substart != ecs_->cycle_seed);
while (acc_to_traverse != 0U || substart != ecs_->cycle_seed);
}
void

View file

@ -136,7 +136,7 @@ namespace spot
// * couvreur99_check::h, a hash of all visited nodes, with their order,
// (it is called "Hash" in Couvreur's paper)
// * arc, a stack of acceptance conditions between each of these SCC,
std::stack<bdd> arc;
std::stack<acc_cond::mark_t> arc;
// * num, the number of visited nodes. Used to set the order of each
// visited node,
int num = 1;
@ -152,7 +152,7 @@ namespace spot
state* init = ecs_->aut->get_init_state();
ecs_->h[init] = 1;
ecs_->root.push(1);
arc.push(bddfalse);
arc.push(0U);
tgba_succ_iterator* iter = ecs_->aut->succ_iter(init);
iter->first();
todo.emplace(init, iter);
@ -207,7 +207,7 @@ namespace spot
// Fetch the values (destination state, acceptance conditions
// of the arc) we are interested in...
const state* dest = succ->current_state();
bdd acc = succ->current_acceptance_conditions();
acc_cond::mark_t acc = succ->current_acceptance_conditions();
// ... and point the iterator to the next successor, for
// the next iteration.
succ->next();
@ -265,8 +265,7 @@ namespace spot
ecs_->root.top().condition |= acc;
ecs_->root.rem().splice(ecs_->root.rem().end(), rem);
if (ecs_->root.top().condition
== ecs_->aut->all_acceptance_conditions())
if (ecs_->aut->acc().accepting(ecs_->root.top().condition))
{
// We have found an accepting SCC.
// Release all iterators in TODO.
@ -521,7 +520,7 @@ namespace spot
// (called the "threshold").
int threshold = i->second;
std::list<const state*> rem;
bdd acc = succ.acc;
acc_cond::mark_t acc = succ.acc;
while (threshold < ecs_->root.top().index)
{
assert(!ecs_->root.empty());
@ -543,8 +542,7 @@ namespace spot
ecs_->root.rem().splice(ecs_->root.rem().end(), rem);
// Have we found all acceptance conditions?
if (ecs_->root.top().condition
== ecs_->aut->all_acceptance_conditions())
if (ecs_->aut->acc().accepting(ecs_->root.top().condition))
{
// Use this state to start the computation of an accepting
// cycle.

View file

@ -195,9 +195,9 @@ namespace spot
protected:
struct successor {
bdd acc;
acc_cond::mark_t acc;
const spot::state* s;
successor(bdd acc, const spot::state* s): acc(acc), s(s) {}
successor(acc_cond::mark_t acc, const spot::state* s): acc(acc), s(s) {}
};
// We use five main data in this algorithm:
@ -205,7 +205,7 @@ namespace spot
// * couvreur99_check::h, a hash of all visited nodes, with their order,
// (it is called "Hash" in Couvreur's paper)
// * arc, a stack of acceptance conditions between each of these SCC,
std::stack<bdd> arc;
std::stack<acc_cond::mark_t> arc;
// * num, the number of visited nodes. Used to set the order of each
// visited node,
int num;

View file

@ -27,7 +27,7 @@ namespace spot
scc_stack::connected_component::connected_component(int i)
{
index = i;
condition = bddfalse;
condition = 0U;
}
scc_stack::connected_component&

View file

@ -41,9 +41,9 @@ namespace spot
/// Index of the SCC.
int index;
/// The bdd condition is the union of all acceptance conditions of
/// transitions which connect the states of the connected component.
bdd condition;
/// The union of all acceptance marks of transitions the
/// connected component.
acc_cond::mark_t condition;
std::list<const state*> rem;
};

View file

@ -54,10 +54,6 @@ namespace spot
struct gv04: public emptiness_check, public ec_statistics
{
// The unique acceptance condition of the automaton \a a,
// or bddfalse if there is no.
bdd accepting;
// Map of visited states.
typedef std::unordered_map<const state*, size_t,
state_ptr_hash, state_ptr_equal> hash_type;
@ -72,9 +68,9 @@ namespace spot
bool violation; // Whether an accepting run was found.
gv04(const const_tgba_ptr& a, option_map o)
: emptiness_check(a, o), accepting(a->all_acceptance_conditions())
: emptiness_check(a, o)
{
assert(a->number_of_acceptance_conditions() <= 1);
assert(a->acc().num_sets() <= 1);
}
~gv04()
@ -125,7 +121,8 @@ namespace spot
else
{
const state* s_prime = iter->current_state();
bool acc = iter->current_acceptance_conditions() == accepting;
bool acc =
a_->acc().accepting(iter->current_acceptance_conditions());
inc_transitions();
trace << " Next successor: s_prime = "
@ -365,7 +362,7 @@ namespace spot
virtual bool
match(tgba_run::step& step, const state*)
{
return step.acc != bddfalse;
return step.acc != 0U;
}
};
@ -386,7 +383,7 @@ namespace spot
const state* bfs_start = data.stack[scc_root].s;
const state* bfs_end = bfs_start;
if (data.accepting != bddfalse)
if (a_->acc().num_sets() > 0)
{
first_bfs b1(this, scc_root);
bfs_start = b1.search(bfs_start, res->cycle);

View file

@ -44,10 +44,6 @@ namespace spot
typedef std::vector<int> vap_t;
vap_t vap;
// Assign a number to each acceptance condition.
typedef std::map<bdd, unsigned, bdd_less_than> acc_map;
acc_map acc;
// Map each state to a number.
typedef std::unordered_map<const state*, unsigned,
state_ptr_hash, state_ptr_equal> state_map;
@ -69,40 +65,27 @@ namespace spot
metadata(const const_tgba_ptr& aut)
: state_acc(true), is_complete(true), is_deterministic(true)
{
number_all_acc(aut);
number_all_states_and_fill_sup(aut);
number_all_ap();
}
void number_all_acc(const const_tgba_ptr& aut)
{
bdd all_acc = aut->all_acceptance_conditions();
unsigned count = 0;
while (all_acc != bddfalse)
{
bdd one = bdd_satone(all_acc);
all_acc -= one;
acc[one] = count++;
}
}
std::ostream&
emit_acc(std::ostream& os, bdd b)
emit_acc(std::ostream& os,
const const_tgba_ptr& aut,
acc_cond::mark_t b)
{
// FIXME: We could use a cache for this.
if (b == bddfalse)
if (b == 0U)
return os;
os << " {";
bool notfirst = false;
while (b != bddfalse)
for (auto v: aut->acc().sets(b))
{
bdd one = bdd_satone(b);
b -= one;
if (notfirst)
os << ' ';
else
notfirst = true;
os << acc[one];
os << v;
}
os << '}';
return os;
@ -124,7 +107,7 @@ namespace spot
{
auto src = todo.front();
todo.pop_front();
bdd prev = bddtrue;
acc_cond::mark_t prev = -1U;
bool st_acc = true;
bdd sum = bddfalse;
bdd available = bddtrue;
@ -153,8 +136,8 @@ namespace spot
}
if (st_acc)
{
bdd acc = i->current_acceptance_conditions();
if (prev != bddtrue && prev != acc)
acc_cond::mark_t acc = i->current_acceptance_conditions();
if (prev != -1U && prev != acc)
st_acc = false;
else
prev = acc;
@ -265,7 +248,7 @@ namespace spot
i != md.vap.end(); ++i)
escape_str(os << " \"", to_string(d->bdd_map[*i].f)) << '"';
os << nl;
unsigned num_acc = md.acc.size();
unsigned num_acc = aut->acc().num_sets();
if (num_acc == 0)
os << "acc-name: all";
else if (num_acc == 1)
@ -309,7 +292,7 @@ namespace spot
os << "State: " << i;
if (this_acc == Hoaf_Acceptance_States && !j->done())
md.emit_acc(os, j->current_acceptance_conditions());
md.emit_acc(os, aut, j->current_acceptance_conditions());
os << nl;
for (; !j->done(); j->next())
@ -317,7 +300,7 @@ namespace spot
const state* dst = j->current_state();
os << '[' << md.sup[j->current_condition()] << "] " << md.sm[dst];
if (this_acc == Hoaf_Acceptance_Transitions)
md.emit_acc(os, j->current_acceptance_conditions());
md.emit_acc(os, aut, j->current_acceptance_conditions());
os << nl;
dst->destroy();
}

View file

@ -40,7 +40,7 @@ namespace spot
cycle_found(const state* start)
{
dfs_stack::const_reverse_iterator i = dfs_.rbegin();
bdd acc = bddfalse;
acc_cond::mark_t acc = 0U;
for (;;)
{
acc |= i->succ->current_acceptance_conditions();
@ -51,7 +51,7 @@ namespace spot
// At least version 4.0 needs it.
assert(i != const_cast<const dfs_stack&>(dfs_).rend());
}
if (acc != aut_->all_acceptance_conditions())
if (!aut_->acc().accepting(acc))
{
// We have found an non-accepting cycle, so the SCC is not
// weak.
@ -83,9 +83,8 @@ namespace spot
// If no cycle is accepting, the SCC is weak.
if (!map.accepting(scc))
return true;
// If all transitions use all acceptance conditions, the SCC is weak.
return (map.useful_acc_of(scc)
== bdd_support(map.get_aut()->neg_acceptance_conditions()));
// If all transitions use the same acceptance set, the SCC is weak.
return map.useful_acc_of(scc).size() == 1;
}
bool
@ -128,8 +127,8 @@ namespace spot
is_terminal_scc(scc_map& map, unsigned scc)
{
// If all transitions use all acceptance conditions, the SCC is weak.
return ((map.useful_acc_of(scc) ==
bdd_support(map.get_aut()->neg_acceptance_conditions()))
return (map.accepting(scc)
&& map.useful_acc_of(scc).size() == 1
&& is_complete_scc(map, scc));
}
}

View file

@ -35,49 +35,12 @@ namespace spot
{
namespace
{
// At some point we'll need to print an acceptance set into LBTT's
// format. LBTT expects numbered acceptance sets, so first we'll
// number each acceptance condition, and later when we have to print
// them we'll just have to look up each of them.
class acceptance_cond_splitter
{
public:
acceptance_cond_splitter(bdd all_acc)
{
unsigned count = 0;
while (all_acc != bddfalse)
{
bdd acc = bdd_satone(all_acc);
all_acc -= acc;
sm[acc] = count++;
}
}
std::ostream&
split(std::ostream& os, bdd b)
{
while (b != bddfalse)
{
bdd acc = bdd_satone(b);
b -= acc;
os << sm[acc] << ' ';
}
return os;
}
private:
typedef std::map<bdd, unsigned, bdd_less_than> split_map;
split_map sm;
};
class lbtt_bfs : public tgba_reachable_iterator_breadth_first
{
public:
lbtt_bfs(const const_tgba_ptr& a, std::ostream& os, bool sba_format)
: tgba_reachable_iterator_breadth_first(a),
os_(os),
all_acc_conds_(a->all_acceptance_conditions()),
acs_(all_acc_conds_),
sba_format_(sba_format),
sba_(nullptr)
{
@ -104,7 +67,7 @@ namespace spot
// iterator.
tgba_succ_iterator* it = aut_->succ_iter(s);
bool accepting = it->first()
&& it->current_acceptance_conditions() == all_acc_conds_;
&& aut_->acc().accepting(it->current_acceptance_conditions());
aut_->release_iter(it);
return accepting;
}
@ -138,7 +101,8 @@ namespace spot
body_ << out - 1 << ' ';
if (!sba_format_)
{
acs_.split(body_, si->current_acceptance_conditions());
for (auto s: aut_->acc().sets(si->current_acceptance_conditions()))
body_ << s << ' ';
body_ << "-1 ";
}
const ltl::formula* f = bdd_to_formula(si->current_condition(),
@ -155,7 +119,7 @@ namespace spot
if (sba_format_)
os_ << '1';
else
os_ << aut_->number_of_acceptance_conditions() << 't';
os_ << aut_->acc().num_sets() << 't';
os_ << '\n' << body_.str() << "-1" << std::endl;
}
@ -163,7 +127,6 @@ namespace spot
std::ostream& os_;
std::ostringstream body_;
bdd all_acc_conds_;
acceptance_cond_splitter acs_;
bool sba_format_;
const_tgba_digraph_ptr sba_;
};
@ -196,7 +159,7 @@ namespace spot
break;
// Read the acceptance conditions.
bdd acc = bddfalse;
acc_cond::mark_t acc = 0U;
for (;;)
{
int acc_n = 0;
@ -254,7 +217,7 @@ namespace spot
aut->set_init_state(src_state);
// Read the acceptance conditions.
bdd acc = bddfalse;
acc_cond::mark_t acc = 0U;
for (;;)
{
int acc_n = 0;

View file

@ -141,7 +141,9 @@ namespace spot
{
public:
translate_dict(const bdd_dict_ptr& dict, ltl_simplifier* ls, bool exprop,
translate_dict(const bdd_dict_ptr& dict,
acc_cond& acc,
ltl_simplifier* ls, bool exprop,
bool single_acc)
: dict(dict),
ls(ls),
@ -150,7 +152,8 @@ namespace spot
next_set(bddtrue),
transdfa(*this),
exprop(exprop),
single_acc(single_acc)
single_acc(single_acc),
acc(acc)
{
}
@ -184,6 +187,9 @@ namespace spot
ratexp_to_dfa transdfa;
bool exprop;
bool single_acc;
acc_cond& acc;
// Map BDD variables to acceptance marks.
std::map<int, unsigned> bm;
enum translate_flags
{
@ -231,6 +237,7 @@ namespace spot
public:
int
register_proposition(const formula* f)
{
@ -239,6 +246,30 @@ namespace spot
return num;
}
acc_cond::mark_t
bdd_to_mark(bdd a)
{
bdd o = a;
if (a == bddtrue)
return 0U;
assert(a != bddfalse);
std::vector<unsigned> t;
do
{
int v = bdd_var(a);
bdd h = bdd_high(a);
a = bdd_low(a);
if (h != bddfalse)
{
t.push_back(bm[v]);
if (a == bddfalse)
a = h;
}
}
while (a != bddtrue);
return acc.marks(t.begin(), t.end());
}
int
register_a_variable(const formula* f)
{
@ -247,6 +278,10 @@ namespace spot
int num = dict->register_acceptance_variable
(ltl::constant::true_instance(), this);
a_set &= bdd_ithvar(num);
auto p = bm.emplace(num, 0U);
if (p.second)
p.first->second = acc.add_set();
return num;
}
// A promise of 'x', noted P(x) is pretty much like the F(x)
@ -297,6 +332,11 @@ namespace spot
int num = dict->register_acceptance_variable(g, this);
a_set &= bdd_ithvar(num);
g->destroy();
auto p = bm.emplace(num, 0U);
if (p.second)
p.first->second = acc.add_set();
return num;
}
else
@ -316,6 +356,11 @@ namespace spot
}
int num = dict->register_acceptance_variable(f, this);
a_set &= bdd_ithvar(num);
auto p = bm.emplace(num, 0U);
if (p.second)
p.first->second = acc.add_set();
return num;
}
@ -2105,7 +2150,10 @@ namespace spot
assert(dict == s->get_dict());
translate_dict d(dict, s, exprop, f->is_syntactic_persistence());
tgba_digraph_ptr a = make_tgba_digraph(dict);
auto namer = a->create_namer<const formula*, formula_ptr_hash>();
translate_dict d(dict, a->acc(), s, exprop, f->is_syntactic_persistence());
// Compute the set of all promises that can possibly occur
// inside the formula.
@ -2154,8 +2202,6 @@ namespace spot
bdd all_events = observable_events | unobservable_events;
tgba_digraph_ptr a = make_tgba_digraph(dict);
auto namer = a->create_namer<const formula*, formula_ptr_hash>();
// This is in case the initial state is equivalent to true...
if (symb_merge)
@ -2341,7 +2387,7 @@ namespace spot
formulae_to_translate.insert(truef);
namer->new_state(truef);
}
namer->new_transition(now, truef, cond_for_true, bddtrue);
namer->new_transition(now, truef, cond_for_true, 0U);
}
// Register other transitions.
for (i = dests.begin(); i != dests.end(); ++i)
@ -2365,7 +2411,7 @@ namespace spot
if (!reachable && !seen)
namer->new_state(dest);
reachable = true;
namer->new_transition(now, dest, cond, j.first);
namer->new_transition(now, dest, cond, d.bdd_to_mark(j.first));
}
if (reachable && !seen)
@ -2380,21 +2426,15 @@ namespace spot
delete namer;
dict->register_propositions(fc.used_vars(), a);
a->set_acceptance_conditions(d.a_set);
// Turn all promises into real acceptance conditions.
acc_compl ac(a->all_acceptance_conditions(),
a->neg_acceptance_conditions());
unsigned ns = a->num_states();
for (unsigned s = 0; s < ns; ++s)
for (auto& t: a->out(s))
t.acc = ac.reverse_complement(t.acc);
t.acc = a->acc().comp(t.acc);
if (!simplifier)
// This should not be deleted before we have registered all propositions.
delete s;
return a;
}

View file

@ -57,10 +57,9 @@ namespace spot
magic_search_(const const_tgba_ptr& a, size_t size,
option_map o = option_map())
: emptiness_check(a, o),
h(size),
all_cond(a->all_acceptance_conditions())
h(size)
{
assert(a->number_of_acceptance_conditions() <= 1);
assert(a->acc().num_sets() <= 1);
}
virtual ~magic_search_()
@ -98,7 +97,7 @@ namespace spot
const state* s0 = a_->get_init_state();
inc_states();
h.add_new_state(s0, BLUE);
push(st_blue, s0, bddfalse, bddfalse);
push(st_blue, s0, bddfalse, 0U);
if (dfs_blue())
return std::make_shared<magic_search_result>(t, options());
}
@ -151,7 +150,7 @@ namespace spot
private:
void push(stack_type& st, const state* s,
const bdd& label, const bdd& acc)
const bdd& label, acc_cond::mark_t acc)
{
inc_depth();
tgba_succ_iterator* i = a_->succ_iter(s);
@ -179,9 +178,6 @@ namespace spot
/// State targeted by the red dfs.
const state* target;
/// The unique acceptance condition of the automaton \a a.
bdd all_cond;
bool dfs_blue()
{
while (!st_blue.empty())
@ -194,7 +190,7 @@ namespace spot
trace << " Visit the successor: "
<< a_->format_state(s_prime) << std::endl;
bdd label = f.it->current_condition();
bdd acc = f.it->current_acceptance_conditions();
auto acc = f.it->current_acceptance_conditions();
// Go down the edge (f.s, <label, acc>, s_prime)
f.it->next();
inc_transitions();
@ -208,7 +204,7 @@ namespace spot
}
else
{
if (acc == all_cond && c.get_color() != RED)
if (a_->acc().accepting(acc) && c.get_color() != RED)
{
// the test 'c.get_color() != RED' is added to limit
// the number of runs reported by successive
@ -239,7 +235,7 @@ namespace spot
typename heap::color_ref c = h.get_color_ref(f_dest.s);
assert(!c.is_white());
if (!st_blue.empty() &&
f_dest.acc == all_cond && c.get_color() != RED)
a_->acc().accepting(f_dest.acc) && c.get_color() != RED)
{
// the test 'c.get_color() != RED' is added to limit
// the number of runs reported by successive
@ -281,7 +277,7 @@ namespace spot
trace << " Visit the successor: "
<< a_->format_state(s_prime) << std::endl;
bdd label = f.it->current_condition();
bdd acc = f.it->current_acceptance_conditions();
auto acc = f.it->current_acceptance_conditions();
// Go down the edge (f.s, <label, acc>, s_prime)
f.it->next();
inc_transitions();

View file

@ -46,7 +46,7 @@ namespace spot
{
struct stack_item
{
stack_item(const state* n, tgba_succ_iterator* i, bdd l, bdd a)
stack_item(const state* n, tgba_succ_iterator* i, bdd l, acc_cond::mark_t a)
: s(n), it(i), label(l), acc(a) {};
/// The visited state.
const state* s;
@ -57,7 +57,7 @@ namespace spot
bdd label;
/// The acceptance set of the transition traversed to reach \a s
/// (false for the first one).
bdd acc;
acc_cond::mark_t acc;
};
typedef std::list<stack_item> stack_type;
@ -112,7 +112,7 @@ namespace spot
assert(!stb.empty());
bdd covered_acc = bddfalse;
acc_cond::mark_t covered_acc = 0U;
accepting_transitions_list acc_trans;
const state* start;
@ -120,7 +120,7 @@ namespace spot
start = stb.front().s->clone();
if (!str.empty())
{
if (a_->number_of_acceptance_conditions() == 0)
if (a_->acc().num_sets() == 0)
{
// take arbitrarily the last transition on the red stack
stack_type::const_iterator i, j;
@ -164,7 +164,7 @@ namespace spot
assert(h_.has_been_visited(t.source));
assert(h_.has_been_visited(t.dest));
acc_trans.push_back(t);
covered_acc |= j->acc;
covered_acc |= j->acc;
}
i = j; ++j;
@ -184,7 +184,7 @@ namespace spot
}
}
if (a_->all_acceptance_conditions() != covered_acc)
if (!a_->acc().accepting(covered_acc))
{
bool b = dfs(start, acc_trans, covered_acc);
assert(b);
@ -222,7 +222,7 @@ namespace spot
struct transition {
const state* source;
bdd label;
bdd acc;
acc_cond::mark_t acc;
const state* dest;
};
typedef std::list<transition> accepting_transitions_list;
@ -253,7 +253,7 @@ namespace spot
}
bool dfs(const state* target, accepting_transitions_list& acc_trans,
bdd& covered_acc)
acc_cond::mark_t& covered_acc)
{
assert(h_.has_been_visited(target));
stack_type st1;
@ -264,7 +264,7 @@ namespace spot
seen.insert(start);
tgba_succ_iterator* i = a_->succ_iter(start);
i->first();
st1.emplace_front(start, i, bddfalse, bddfalse);
st1.emplace_front(start, i, bddfalse, 0U);
while (!st1.empty())
{
@ -277,7 +277,7 @@ namespace spot
ndfsr_trace << " Visit the successor: "
<< a_->format_state(s_prime) << std::endl;
bdd label = f.it->current_condition();
bdd acc = f.it->current_acceptance_conditions();
auto acc = f.it->current_acceptance_conditions();
f.it->next();
if (h_.has_been_visited(s_prime))
{
@ -308,7 +308,7 @@ namespace spot
assert(h_.has_been_visited(t.dest));
acc_trans.push_back(t);
covered_acc |= acc;
if (covered_acc == a_->all_acceptance_conditions())
if (a_->acc().accepting(covered_acc))
{
clean(a_, st1, seen, dead);
s_prime->destroy();
@ -337,7 +337,7 @@ namespace spot
stack_item f_dest(f);
a_->release_iter(st1.front().it);
st1.pop_front();
if (!st1.empty() && (f_dest.acc & covered_acc) != f_dest.acc)
if (!st1.empty() && ((f_dest.acc & covered_acc) != f_dest.acc))
{
ndfsr_trace << " a propagation is needed, start a search"
<< std::endl;
@ -349,8 +349,8 @@ namespace spot
assert(h_.has_been_visited(t.source));
assert(h_.has_been_visited(t.dest));
acc_trans.push_back(t);
covered_acc |= f_dest.acc;
if (covered_acc == a_->all_acceptance_conditions())
covered_acc |= f_dest.acc;
if (a_->acc().accepting(covered_acc))
{
clean(a_, st1, seen, dead);
return true;
@ -607,6 +607,7 @@ namespace spot
<< a_->format_state(begin) << std::endl;
transition tmp;
tmp.source = tmp.dest = 0; // Initialize to please GCC 4.0.1 (Darwin).
tmp.acc = 0U;
target.emplace(begin, tmp);
min_path<true> s(this, a_, target, h_);
const state* res = s.search(current.dest->clone(), run->cycle);
@ -621,6 +622,7 @@ namespace spot
m_source_trans target;
transition tmp;
tmp.source = tmp.dest = 0; // Initialize to please GCC 4.0.
tmp.acc = 0U;
// Register all states from the cycle as target of the BFS.
for (tgba_run::steps::const_iterator i = run->cycle.begin();

View file

@ -41,7 +41,7 @@ namespace spot
const ltl::formula* f, bool comments)
: tgba_reachable_iterator_breadth_first(a),
os_(os), f_(f), accept_all_(-1), fi_needed_(false),
comments_(comments), all_acc_conds_(a->all_acceptance_conditions()),
comments_(comments),
sba_(std::dynamic_pointer_cast<const tgba_digraph>(a))
{
assert(!sba_ || sba_->has_state_based_acc());
@ -87,8 +87,8 @@ namespace spot
// is not terribly efficient since we have to create the
// iterator.
tgba_succ_iterator* it = aut_->succ_iter(s);
bool accepting =
it->first() && it->current_acceptance_conditions() == all_acc_conds_;
bool accepting = it->first()
&& aut_->acc().accepting(it->current_acceptance_conditions());
aut_->release_iter(it);
return accepting;
}
@ -193,7 +193,6 @@ namespace spot
bool fi_needed_;
state* init_;
bool comments_;
bdd all_acc_conds_;
const_tgba_digraph_ptr sba_;
};
} // anonymous
@ -202,7 +201,7 @@ namespace spot
never_claim_reachable(std::ostream& os, const const_tgba_ptr& g,
const ltl::formula* f, bool comments)
{
assert(g->number_of_acceptance_conditions() <= 1);
assert(g->acc().num_sets() <= 1);
never_claim_bfs n(g, os, f, comments);
n.run();
return os;

View file

@ -142,7 +142,7 @@ namespace spot
if (type_ == BA)
state_based_ = true;
int original_acc = a->number_of_acceptance_conditions();
int original_acc = a->acc().num_sets();
// Remove useless SCCs.
if (type_ == Monitor)
@ -237,7 +237,7 @@ namespace spot
if (PREF_ == Deterministic
&& f
&& f->is_syntactic_recurrence()
&& sim->number_of_acceptance_conditions() > 1)
&& sim->acc().num_sets() > 1)
tmpd = degeneralize_tba(sim);
auto in = tmpd ? tmpd : sim;
@ -306,7 +306,7 @@ namespace spot
// because the input TBA might be smaller.
if (state_based_)
in = degeneralize(dba);
else if (dba->number_of_acceptance_conditions() != 1)
else if (dba->acc().num_sets() != 1)
in = degeneralize_tba(dba);
else
in = dba;
@ -354,8 +354,7 @@ namespace spot
// Degeneralize the dba resulting from tba-determinization or
// sat-minimization (which is a TBA) if requested and needed.
if (dba && !dba_is_wdba && type_ == BA
&& !(dba_is_minimal && state_based_
&& dba->number_of_acceptance_conditions() == 1))
&& !(dba_is_minimal && state_based_ && dba->acc().num_sets() == 1))
dba = degeneralize(dba);
if (dba && sim)

View file

@ -165,7 +165,7 @@ namespace spot
// print_set(std::cerr, *j) << '\n';
// }
bdd acc = aut_->all_acceptance_conditions();
auto acc = aut_->acc().all_sets();
for (auto i: all_)
i->acc = acc;
return threshold_ != 0 && cycles_left_ == 0;
@ -316,7 +316,7 @@ namespace spot
{
if (f == 0 && neg_aut == 0)
return 0;
if (aut->number_of_acceptance_conditions() > 1)
if (aut->acc().num_sets() > 1)
return 0;
auto det = tba_determinize(aut, threshold_states, threshold_cycles);

View file

@ -35,20 +35,12 @@ namespace spot
namespace
{
std::string
acc(int n)
{
std::stringstream s;
s << n;
return "a" + s.str();
}
void
random_labels(tgba_digraph_ptr aut,
unsigned src,
unsigned dest,
int* props, int props_n, float t,
const std::list<bdd>& accs, float a)
unsigned n_accs, float a)
{
int val = 0;
int size = 0;
@ -70,21 +62,18 @@ namespace spot
if (size > 0)
p &= bdd_ibuildcube(val, size, props);
bdd ac = bddfalse;
for (std::list<bdd>::const_iterator i = accs.begin();
i != accs.end(); ++i)
acc_cond::mark_t m = 0U;
for (unsigned i = 0U; i < n_accs; ++i)
if (drand() < a)
ac |= *i;
aut->new_transition(src, dest, p, ac);
m |= aut->acc().mark(i);
aut->new_transition(src, dest, p, m);
}
}
tgba_digraph_ptr
random_graph(int n, float d,
const ltl::atomic_prop_set* ap, const bdd_dict_ptr& dict,
int n_acc, float a, float t,
ltl::environment* env)
unsigned n_accs, float a, float t)
{
assert(n > 0);
auto res = make_tgba_digraph(dict);
@ -96,20 +85,7 @@ namespace spot
for (auto i: *ap)
props[pi++] = dict->register_proposition(i, res);
std::list<bdd> accs;
bdd allneg = bddtrue;
for (int i = 0; i < n_acc; ++i)
{
const ltl::formula* f = env->require(acc(i));
int v = dict->register_acceptance_variable(f, res);
f->destroy();
bdd b = bdd_nithvar(v);
allneg &= b;
accs.push_back(b);
}
res->set_acceptance_conditions(allneg);
for (auto& i: accs)
i = bdd_compose(allneg, i, bdd_var(i));
res->set_acceptance_conditions(n_accs);
// Using std::unordered_set instead of std::set for these sets is 3
// times slower (tested on a 50000 nodes example).
@ -162,7 +138,7 @@ namespace spot
std::advance(i, index);
// Link it from src.
random_labels(res, src, *i, props, props_n, t, accs, a);
random_labels(res, src, *i, props, props_n, t, n_accs, a);
nodes_to_process.insert(*i);
unreachable_nodes.erase(i);
break;
@ -178,7 +154,7 @@ namespace spot
state_randomizer[index] = state_randomizer[possibilities];
state_randomizer[possibilities] = x;
random_labels(res, src, x, props, props_n, t, accs, a);
random_labels(res, src, x, props, props_n, t, n_accs, a);
auto j = unreachable_nodes.find(x);
if (j != unreachable_nodes.end())

View file

@ -41,7 +41,7 @@ namespace spot
/// A density of 1 means all states will be connected to each other.
/// \param ap The list of atomic property that should label the transition.
/// \param dict The bdd_dict to used for this automata.
/// \param n_acc The number of acceptance sets to use.
/// \param n_accs The number of acceptance sets to use.
/// If this number is non null, then there is no guarantee
/// that the generated graph contains an accepting cycle (raise
/// the value of \a a to improve the chances).
@ -49,7 +49,6 @@ namespace spot
/// to an acceptance set.
/// \param t The probability (between 0.0 and 1.0) that an atomic proposition
/// is true.
/// \param env The environment in which to declare the acceptance conditions.
///
/// This algorithms is adapted from the one in Fig 6.2 page 48 of
/** \verbatim
@ -79,8 +78,7 @@ namespace spot
SPOT_API tgba_digraph_ptr
random_graph(int n, float d,
const ltl::atomic_prop_set* ap, const bdd_dict_ptr& dict,
int n_acc = 0, float a = 0.1, float t = 0.5,
ltl::environment* env = &ltl::default_environment::instance());
unsigned n_accs = 0, float a = 0.1, float t = 0.5);
}
#endif // SPOT_TGBAALGOS_RANDOMGRAPH_HH

View file

@ -102,9 +102,8 @@ namespace spot
const state* segment_next; // The state immediately after the segment.
// Start from the end of the original cycle, and rewind until all
// acceptance conditions have been seen.
bdd seen_acc = bddfalse;
bdd all_acc = a->all_acceptance_conditions();
// acceptance sets have been seen.
acc_cond::mark_t seen_acc = 0U;
tgba_run::steps::const_iterator seg = org->cycle.end();
do
{
@ -112,12 +111,12 @@ namespace spot
--seg;
seen_acc |= seg->acc;
}
while (seen_acc != all_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 conditions, cloning it in our result along the way.
seen_acc = bddfalse;
// acceptance sets, cloning it in our result along the way.
seen_acc = 0U;
do
{
assert(seg != org->cycle.end());
@ -128,7 +127,7 @@ namespace spot
++seg;
}
while (seen_acc != all_acc);
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

View file

@ -51,8 +51,7 @@ namespace spot
int serial = 1;
const tgba_run::steps* l;
std::string in;
bdd all_acc = bddfalse;
bdd expected_all_acc = a->all_acceptance_conditions();
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;
@ -116,7 +115,7 @@ namespace spot
// expected outgoing transition
bdd label = i->label;
bdd acc = i->acc;
acc_cond::mark_t acc = i->acc;
// compute the next expected state
const state* next;
@ -170,7 +169,7 @@ namespace spot
{
os << "ERROR: no transition with label="
<< bdd_format_formula(a->get_dict(), label)
<< " and acc=" << bdd_format_accset(a->get_dict(), acc)
<< " and acc=" << a->acc().format(acc)
<< " leaving state " << serial
<< " for state " << a->format_state(next) << '\n'
<< "The following transitions leave state " << serial
@ -185,9 +184,7 @@ namespace spot
<< bdd_format_formula(a->get_dict(),
j->current_condition())
<< " and acc="
<< (bdd_format_accset
(a->get_dict(),
j->current_acceptance_conditions()))
<< a->acc().format(j->current_acceptance_conditions())
<< " going to " << a->format_state(s2) << '\n';
s2->destroy();
}
@ -203,7 +200,7 @@ namespace spot
print_annotation(os, a, j);
os << " with label="
<< bdd_format_formula(a->get_dict(), label)
<< " and acc=" << bdd_format_accset(a->get_dict(), acc)
<< " and acc=" << a->acc().format(acc)
<< std::endl;
}
else
@ -212,7 +209,7 @@ namespace spot
print_annotation(os, a, j);
bdd_print_formula(os, a->get_dict(), label);
os << '\t';
bdd_print_accset(os, a->get_dict(), acc);
a->acc().format(acc);
os << std::endl;
}
a->release_iter(j);
@ -226,24 +223,24 @@ namespace spot
if (l == &run->cycle && i != l->begin())
{
all_acc |= acc;
if (!all_acc_seen && all_acc == expected_all_acc)
if (!all_acc_seen && a->acc().accepting(all_acc))
{
all_acc_seen = true;
if (debug)
os << "all acceptance conditions ("
<< bdd_format_accset(a->get_dict(), all_acc)
<< a->acc().format(all_acc)
<< ") have been seen\n";
}
}
}
s->destroy();
if (all_acc != expected_all_acc)
if (!a->acc().accepting(all_acc))
{
if (debug)
os << "ERROR: The cycle's acceptance conditions ("
<< bdd_format_accset(a->get_dict(), all_acc)
<< a->acc().format(all_acc)
<< ") do not\nmatch those of the automaton ("
<< bdd_format_accset(a->get_dict(), expected_all_acc)
<< a->acc().format(a->acc().all_sets())
<< ")\n";
return false;
}

View file

@ -76,8 +76,6 @@ namespace spot
todo.push_back(seen(aut->get_init_state()));
bdd all_acc = aut->all_acceptance_conditions();
bool all_accepting = true;
while (all_accepting && !todo.empty())
{
@ -86,8 +84,8 @@ namespace spot
for (auto it: aut->succ(s))
{
bdd acc = it->current_acceptance_conditions();
if (acc != all_acc)
auto acc = it->current_acceptance_conditions();
if (!aut->acc().accepting(acc))
{
all_accepting = false;
break;

View file

@ -43,8 +43,9 @@ namespace spot
void
start()
{
os_ << "acc =";
print_acc(aut_->all_acceptance_conditions()) << ";\n";
os_ << "acc = ";
aut_->acc().format_quoted(os_, aut_->acc().all_sets())
<< ";\n";
}
void
@ -61,7 +62,10 @@ namespace spot
os_ << "\", \"";
escape_str(os_, bdd_format_formula(d, si->current_condition()));
os_ << "\",";
print_acc(si->current_acceptance_conditions()) << ";\n";
if (si->current_acceptance_conditions())
aut_->acc().format_quoted(os_ << ' ',
si->current_acceptance_conditions());
os_ << ";\n";
dest->destroy();
}
while (si->next());
@ -69,28 +73,6 @@ namespace spot
private:
std::ostream& os_;
std::ostream&
print_acc(bdd acc)
{
const bdd_dict_ptr d = aut_->get_dict();
while (acc != bddfalse)
{
bdd cube = bdd_satone(acc);
acc -= cube;
const ltl::formula* f = d->oneacc_to_formula(cube);
std::string s = ltl::to_string(f);
if (is_atomic_prop(f) && s[0] == '"')
{
// Unquote atomic propositions.
s.erase(s.begin());
s.resize(s.size() - 1);
}
os_ << " \"";
escape_str(os_, s) << '"';
}
return os_;
}
};
}

View file

@ -86,7 +86,7 @@ namespace spot
{
if (scc_map_[n].trivial)
return false;
return acc_set_of(n) == aut_->all_acceptance_conditions();
return aut_->acc().accepting(acc_set_of(n));
}
const_tgba_ptr
@ -139,8 +139,6 @@ namespace spot
void
scc_map::build_map()
{
acceptance_convertor conv(aut_->neg_acceptance_conditions());
// Setup depth-first search from the initial state.
{
self_loops_ = 0;
@ -148,7 +146,7 @@ namespace spot
num_ = -1;
h_.emplace(init, num_);
root_.emplace_front(num_);
arc_acc_.push(bddfalse);
arc_acc_.push(0U);
arc_cond_.push(bddfalse);
tgba_succ_iterator* iter = aut_->succ_iter(init);
iter->first();
@ -209,7 +207,7 @@ namespace spot
const state* dest = succ->current_state();
if (!dest->compare(todo_.top().first))
++self_loops_;
bdd acc = succ->current_acceptance_conditions();
auto acc = succ->current_acceptance_conditions();
bdd cond = succ->current_condition();
root_.front().supp &= bdd_support(cond);
// ... and point the iterator to the next successor, for
@ -268,17 +266,18 @@ namespace spot
cond_set conds;
conds.insert(cond);
bdd supp = bddtrue;
bdd all = aut_->all_acceptance_conditions();
bdd useful = conv.as_full_product(acc);
std::set<acc_cond::mark_t> used_acc = { acc };
while (threshold > root_.front().index)
{
assert(!root_.empty());
assert(!arc_acc_.empty());
assert(arc_acc_.size() == arc_cond_.size());
acc |= root_.front().acc;
bdd lacc = arc_acc_.top();
auto lacc = arc_acc_.top();
acc |= lacc;
useful |= conv.as_full_product(lacc) | root_.front().useful_acc;
used_acc.insert(lacc);
used_acc.insert(root_.front().useful_acc.begin(),
root_.front().useful_acc.end());
states.splice(states.end(), root_.front().states);
succs.insert(root_.front().succ.begin(),
root_.front().succ.end());
@ -305,7 +304,8 @@ namespace spot
root_.front().supp &= supp;
// This SCC is no longer trivial.
root_.front().trivial = false;
root_.front().useful_acc |= useful;
assert(!used_acc.empty());
root_.front().useful_acc.insert(used_acc.begin(), used_acc.end());
}
// recursively update supp_rec
@ -339,7 +339,7 @@ namespace spot
}
bdd scc_map::acc_set_of(unsigned n) const
acc_cond::mark_t scc_map::acc_set_of(unsigned n) const
{
assert(scc_map_.size() > n);
return scc_map_[n].acc;
@ -367,7 +367,7 @@ namespace spot
return scc_map_.size();
}
bdd
const std::set<acc_cond::mark_t>&
scc_map::useful_acc_of(unsigned n) const
{
assert(scc_map_.size() > n);
@ -449,12 +449,14 @@ namespace spot
res.dead_paths = d.dead_paths[init];
res.useless_scc_map.reserve(res.scc_total);
res.useful_acc = bddfalse;
for (unsigned n = 0; n < res.scc_total; ++n)
{
res.useless_scc_map[n] = !d.acc_paths[n];
if (m.accepting(n))
res.useful_acc |= m.useful_acc_of(n);
{
auto& c = m.useful_acc_of(n);
res.useful_acc.insert(c.begin(), c.end());
}
}
return res;
}
@ -495,8 +497,7 @@ namespace spot
if (n > 1)
ostr << 's';
ostr << ")\\naccs=";
escape_str(ostr, bdd_format_accset(m.get_aut()->get_dict(),
m.acc_set_of(state)));
escape_str(ostr, m.get_aut()->acc().format(m.acc_set_of(state)));
ostr << "\\nconds=[";
for (scc_map::cond_set::const_iterator i = cs.begin();
i != cs.end(); ++i)
@ -514,8 +515,9 @@ namespace spot
escape_str(ostr, bdd_format_sat(m.get_aut()->get_dict(),
m.aprec_set_of(state)));
ostr << "]\\n useful=[";
escape_str(ostr, bdd_format_accset(m.get_aut()->get_dict(),
m.useful_acc_of(state))) << ']';
for (auto a: m.useful_acc_of(state))
m.get_aut()->acc().format(a);
ostr << ']';
}
out << " " << state << " [shape=box,"

View file

@ -61,7 +61,7 @@ namespace spot
/// The set of useful acceptance conditions (i.e. acceptance
/// conditions that are not always implied by other acceptance
/// conditions).
bdd useful_acc;
std::set<acc_cond::mark_t> useful_acc;
std::ostream& dump(std::ostream& out) const;
};
@ -144,13 +144,13 @@ namespace spot
/// \brief Return the set of acceptance conditions occurring in an SCC.
///
/// \pre This should only be called once build_map() has run.
bdd acc_set_of(unsigned n) const;
acc_cond::mark_t acc_set_of(unsigned n) const;
/// \brief Return the set of useful acceptance conditions of SCC \a n.
///
/// Useless acceptances conditions are always implied by other acceptances
/// conditions. This returns all the other acceptance conditions.
bdd useful_acc_of(unsigned n) const;
const std::set<acc_cond::mark_t>& useful_acc_of(unsigned n) const;
/// \brief Return the set of states of an SCC.
///
@ -183,14 +183,14 @@ namespace spot
struct scc
{
public:
scc(int index) : index(index), acc(bddfalse),
scc(int index) : index(index), acc(0U),
supp(bddtrue), supp_rec(bddfalse),
trivial(true), useful_acc(bddfalse) {};
trivial(true) {};
/// Index of the SCC.
int index;
/// The union of all acceptance conditions of transitions which
/// connect the states of the connected component.
bdd acc;
acc_cond::mark_t acc;
/// States of the component.
std::list<const state*> states;
/// Set of conditions used in the SCC.
@ -204,22 +204,13 @@ namespace spot
/// Trivial SCC have one state and no self-loops.
bool trivial;
/// \brief Set of acceptance combinations used in the SCC.
///
/// Note that the encoding used here differs from the
/// encoding used in automata.
/// If some transitions of the automaton are labeled by
/// Acc[a]&!Acc[b]&!Acc[c] | !Acc[a]&Acc[b]&!Acc[c]
/// an other transitions are labeled by
/// !Acc[a]&Acc[b]&!Acc[c] | !Acc[a]&!Acc[b]&Acc[c]
/// then useful_acc will contain
/// Acc[a]&Acc[b]&!Acc[c] | !Acc[a]&Acc[b]&Acc[c]
bdd useful_acc;
std::set<acc_cond::mark_t> useful_acc;
};
const_tgba_ptr aut_; // Automata to decompose.
typedef std::list<scc> stack_type;
stack_type root_; // Stack of SCC roots.
std::stack<bdd> arc_acc_; // A stack of acceptance conditions
std::stack<acc_cond::mark_t> arc_acc_; // A stack of acceptance conditions
// between each of these SCC.
std::stack<bdd> arc_cond_; // A stack of conditions
// between each of these SCC.

View file

@ -29,8 +29,7 @@ namespace spot
typedef std::map<int, unsigned> accremap_t;
typedef std::vector<accremap_t> remap_table_t;
typedef std::tuple<bool, bdd, bdd> filtered_trans;
typedef std::pair<bdd, bdd> acc_pair;
typedef std::tuple<bool, bdd, acc_cond::mark_t> filtered_trans;
// SCC filters are objects with two methods:
@ -53,13 +52,13 @@ namespace spot
return true;
}
acc_pair accsets(bdd all, bdd all_neg)
unsigned accsets(unsigned n)
{
return acc_pair(all, all_neg);
return n;
}
// Accept all transitions, unmodified
filtered_trans trans(unsigned, unsigned, bdd cond, bdd acc)
filtered_trans trans(unsigned, unsigned, bdd cond, acc_cond::mark_t acc)
{
return filtered_trans{true, cond, acc};
}
@ -101,7 +100,7 @@ namespace spot
}
filtered_trans trans(unsigned src, unsigned dst,
bdd cond, bdd acc)
bdd cond, acc_cond::mark_t acc)
{
bool keep;
std::tie(keep, cond, acc) =
@ -137,7 +136,7 @@ namespace spot
}
filtered_trans trans(unsigned src, unsigned dst,
bdd cond, bdd acc)
bdd cond, acc_cond::mark_t acc)
{
bool keep;
std::tie(keep, cond, acc) =
@ -149,7 +148,7 @@ namespace spot
// If the transition is between two SCCs, or in a
// non-accepting SCC. Remove the acceptance sets.
if (!this->si->is_accepting_scc(u) || u != this->si->scc_of(dst))
acc = bddfalse;
acc = 0U;
}
return filtered_trans(keep, cond, acc);
@ -168,14 +167,14 @@ namespace spot
}
filtered_trans trans(unsigned src, unsigned dst,
bdd cond, bdd acc)
bdd cond, acc_cond::mark_t acc)
{
bool keep;
std::tie(keep, cond, acc) =
this->next_filter::trans(src, dst, cond, acc);
if (!this->si->is_accepting_scc(this->si->scc_of(dst)))
acc = bddfalse;
acc = 0U;
return filtered_trans(keep, cond, acc);
}
};
@ -184,10 +183,8 @@ namespace spot
template <class next_filter = id_filter>
struct acc_filter_simplify: next_filter
{
std::vector<bdd> acc_;
typedef std::map<int, bdd> map_t;
typedef std::vector<map_t> remap_t;
remap_t remap_;
// Acceptance sets to strip in each SCC.
std::vector<acc_cond::mark_t> strip_;
template<typename... Args>
acc_filter_simplify(scc_info* si, Args&&... args)
@ -195,118 +192,27 @@ namespace spot
{
}
acc_pair accsets(bdd in_all, bdd in_all_neg)
unsigned accsets(unsigned n)
{
std::tie(in_all, in_all_neg) =
this->next_filter::accsets(in_all, in_all_neg);
unsigned scc_count = this->si->scc_count();
remap_table_t remap_table(scc_count);
std::vector<unsigned> max_table(scc_count);
std::vector<bdd> useful_table(scc_count);
std::vector<bdd> useless_table(scc_count);
unsigned max_num = 1;
const_tgba_digraph_ptr aut = this->si->get_aut();
std::vector<bdd> used_acc = this->si->used_acc();
auto& acc = this->si->get_aut()->acc();
assert(n == acc.num_sets());
(void) n;
auto used_acc = this->si->used_acc();
assert(used_acc.size() == scc_count);
strip_.resize(scc_count);
std::vector<unsigned> cnt(scc_count); // # of useful sets in each SCC
unsigned max = 0; // Max number of useful sets
for (unsigned n = 0; n < scc_count; ++n)
{
if (!this->si->is_accepting_scc(n))
continue;
bdd all = used_acc[n];
//std::cerr << "SCC #" << n << "; used = " << all << std::endl;
// Compute a set of useless acceptance sets.
// If the acceptance combinations occurring in
// the automata are { a, ab, abc, bd }, then
// ALL contains (a&!b&!c&!d)|(a&b&!c&!d)|(a&b&c&!d)|(!a&b&!c&d)
// and we want to find that 'a' and 'b' are useless because
// they always occur with 'c'.
// The way we check if 'a' is useless is to look whether ALL
// implications (x -> a) for some other acceptance set x.
//
// The two while() loops in the code perform the equivalent of
// for all a in allconds_a:
// for all x in allconds_x:
// check whether x -> a
// ...
//
// Initially allconds_a = allconds_x contains all acceptance
// sets. However when an acceptance set 'a' is determined to
// be useless, it can be removed from allconds_x from future
// iterations.
bdd allconds_a = bdd_support(in_all_neg);
bdd allconds_x = allconds_a;
bdd useless = bddtrue;
while (allconds_a != bddtrue)
{
// Speed-up the computation of implied acceptance sets by
// removing those that are always present. We detect
// those that appear as conjunction of positive variables
// at the start of ALL.
bdd prefix = bdd_satprefix(all);
if (prefix != bddtrue)
{
assert(prefix == bdd_support(prefix));
allconds_a = bdd_exist(allconds_a, prefix);
if (allconds_a != bddtrue)
{
useless &= prefix;
}
else
{
// Never erase all conditions: at least keep one.
useless &= bdd_high(prefix);
break;
}
allconds_x = bdd_exist(allconds_x, prefix);
}
// Pick an acceptance set 'a'.
bdd a = bdd_ithvar(bdd_var(allconds_a));
// For all acceptance sets 'x' that are not already
// useless...
bdd others = allconds_x;
while (others != bddtrue)
{
bdd x = bdd_ithvar(bdd_var(others));
// ... check whether 'x' always implies 'a'.
if (x != a && bdd_implies(all, x >> a))
{
// If so, 'a' is useless.
all = bdd_exist(all, a);
useless &= a;
allconds_x = bdd_exist(allconds_x, a);
break;
}
others = bdd_high(others);
}
allconds_a = bdd_high(allconds_a);
}
// We never remove ALL acceptance marks.
assert(in_all_neg == bddtrue || useless != bdd_support(in_all_neg));
useless_table[n] = useless;
bdd useful = bdd_exist(in_all_neg, useless);
//std::cerr << "SCC #" << n << "; useful = " << useful << std::endl;
// Go over all useful sets of acceptance marks, and give them
// a number.
unsigned num = 1;
// First compute the number of acceptance conditions used.
for (BDD c = useful.id(); c != 1; c = bdd_low(c))
++num;
max_table[n] = num;
if (num > max_num)
max_num = num;
useful_table[n] = useful;
strip_[n] = acc.useless(used_acc[n].begin(), used_acc[n].end());
cnt[n] = acc.num_sets() - strip_[n].count();
if (cnt[n] > max)
max = cnt[n];
}
// Now that we know about the max number of acceptance
// conditions, add extra acceptance conditions to those SCC
// that do not have enough.
@ -314,118 +220,30 @@ namespace spot
{
if (!this->si->is_accepting_scc(n))
continue;
//std::cerr << "SCC " << n << '\n';
bdd useful = useful_table[n];
int missing = max_num - max_table[n];
bdd useless = useless_table[n];
while (missing--)
{
//std::cerr << useful << " : " << useless << std::endl;
useful &= bdd_nithvar(bdd_var(useless));
useless = bdd_high(useless);
}
int num = max_num;
// Then number all of these acceptance conditions in the
// reverse order. This makes sure that the associated number
// varies in the same direction as the bdd variables, which in
// turn makes sure we preserve the acceptance condition
// ordering (which matters for degeneralization).
for (BDD c = useful.id(); c != 1; c = bdd_low(c))
remap_table[n].emplace(bdd_var(c), --num);
max_table[n] = max_num;
if (cnt[n] < max)
strip_[n].remove_some(max - cnt[n]);
}
acc_.resize(max_num);
acc_[0] = bddfalse;
bdd tmp = in_all;
assert(aut->number_of_acceptance_conditions() >= max_num - 1);
bdd all = bddfalse;
bdd all_neg = bddtrue;
if (tmp != bddfalse)
{
for (unsigned n = max_num - 1; n > 0; --n)
{
assert(tmp != bddfalse);
int v = bdd_var(tmp);
bdd vn = bdd_nithvar(v);
all = (all & vn) | (all_neg & bdd_ithvar(v));
all_neg &= vn;
tmp = bdd_low(tmp);
}
tmp = in_all;
for (unsigned n = max_num - 1; n > 0; --n)
{
int v = bdd_var(tmp);
acc_[n] = bdd_compose(all_neg, bdd_nithvar(v), v);
tmp = bdd_low(tmp);
}
}
else
{
assert(max_num == 1);
}
remap_.resize(scc_count);
bdd all_orig_neg = in_all_neg;
bdd all_sup = bdd_support(all_orig_neg);
for (unsigned n = 0; n < scc_count; ++n)
{
//std::cerr << "SCC #" << n << '\n';
if (!this->si->is_accepting_scc(n))
continue;
bdd all = used_acc[n];
while (all != bddfalse)
{
bdd one = bdd_satoneset(all, all_sup, bddtrue);
all -= one;
bdd res = bddfalse;
bdd resacc = bddfalse;
while (one != bddtrue)
{
if (bdd_high(one) == bddfalse)
{
one = bdd_low(one);
continue;
}
int vn = bdd_var(one);
bdd v = bdd_ithvar(vn);
resacc |= bdd_exist(all_orig_neg, v) & v;
res |= acc_[remap_table[n][vn]];
one = bdd_high(one);
}
int id = resacc.id();
//std::cerr << resacc << " -> " << res << '\n';
remap_[n][id] = res;
}
}
return acc_pair{all, all_neg};
return max;
}
filtered_trans trans(unsigned src, unsigned dst, bdd cond, bdd acc)
filtered_trans trans(unsigned src, unsigned dst, bdd cond,
acc_cond::mark_t acc)
{
bool keep;
std::tie(keep, cond, acc) =
this->next_filter::trans(src, dst, cond, acc);
if (keep && acc != bddfalse)
if (keep && acc)
{
unsigned u = this->si->scc_of(dst);
auto i = remap_[u].find(acc.id());
if (i != remap_[u].end())
acc = i->second;
if (!this->si->is_accepting_scc(u))
acc = 0U;
else
acc = bddfalse;
acc = this->si->get_aut()->acc().strip(acc, strip_[u]);
}
return filtered_trans{keep, cond, acc};
}
};
@ -456,11 +274,8 @@ namespace spot
else
inout.push_back(-1U);
{
bdd all = aut->all_acceptance_conditions();
bdd neg = aut->neg_acceptance_conditions();
filtered->set_acceptance_conditions(filter.accsets(all, neg).first);
}
filtered->
set_acceptance_conditions(filter.accsets(aut->acc().num_sets()));
filtered->new_states(out_n);
for (unsigned isrc = 0; isrc < in_n; ++isrc)
{
@ -474,7 +289,7 @@ namespace spot
continue;
bool want;
bdd cond;
bdd acc;
acc_cond::mark_t acc;
std::tie(want, cond, acc) =
filter.trans(isrc, t.dst, t.cond, t.acc);
if (want)

View file

@ -33,14 +33,14 @@ namespace spot
struct scc
{
public:
scc(int index, bdd in_cond, bdd in_acc):
scc(int index, bdd in_cond, acc_cond::mark_t in_acc):
index(index), in_cond(in_cond), in_acc(in_acc)
{
}
int index; // Index of the SCC
bdd in_cond; // Condition on incoming transition
bdd in_acc; // Acceptance sets on the incoming transition
acc_cond::mark_t in_acc; // Acceptance sets on the incoming transition
scc_info::scc_node node;
};
}
@ -50,7 +50,6 @@ namespace spot
{
unsigned n = aut->num_states();
sccof_.resize(n, -1U);
bdd all_acc = aut->all_acceptance_conditions();
typedef std::list<scc> stack_type;
stack_type root_; // Stack of SCC roots.
@ -81,7 +80,7 @@ namespace spot
unsigned init = aut->get_init_state_number();
num_ = -1;
h_[init] = num_;
root_.emplace_front(num_, bddfalse, bddfalse);
root_.emplace_front(num_, bddfalse, 0U);
todo_.emplace(init, aut->out(init).begin());
}
@ -117,12 +116,12 @@ namespace spot
h_[s] = num + 1;
}
bdd cond = root_.front().in_cond;
bdd acc = root_.front().node.acc;
auto acc = root_.front().node.acc;
bool triv = root_.front().node.trivial;
node_.emplace_back(acc, triv);
std::swap(node_.back().succ, root_.front().node.succ);
std::swap(node_.back().states, root_.front().node.states);
node_.back().accepting = acc == all_acc;
node_.back().accepting = aut->acc().accepting(acc);
root_.pop_front();
// Record the transition between the SCC being popped
// and the previous SCC.
@ -135,7 +134,7 @@ namespace spot
// We have a successor to look at.
// Fetch the values we are interested in...
unsigned dest = succ->dst;
bdd acc = succ->acc;
auto acc = succ->acc;
bdd cond = succ->cond;
++todo_.top().second;
@ -191,7 +190,8 @@ namespace spot
while (threshold > root_.front().index)
{
assert(!root_.empty());
acc |= root_.front().node.acc | root_.front().in_acc;
acc |= root_.front().node.acc;
acc |= root_.front().in_acc;
states.splice(states.end(), root_.front().node.states);
succs.insert(succs.end(),
@ -229,22 +229,22 @@ namespace spot
}
std::vector<bdd> scc_info::used_acc() const
std::vector<std::set<acc_cond::mark_t>> scc_info::used_acc() const
{
unsigned n = aut_->num_states();
std::vector<bdd> result(scc_count());
acceptance_convertor conv(aut_->neg_acceptance_conditions());
std::vector<std::set<acc_cond::mark_t>> result(scc_count());
for (unsigned src = 0; src < n; ++src)
{
unsigned src_scc = scc_of(src);
if (src_scc == -1U || !is_accepting_scc(src_scc))
continue;
auto& s = result[src_scc];
for (auto& t: aut_->out(src))
{
if (scc_of(t.dst) != src_scc)
continue;
result[src_scc] |= conv.as_full_product(t.acc);
s.insert(t.acc);
}
}
return result;
@ -255,9 +255,8 @@ namespace spot
unsigned n = scc_count();
std::vector<bool> result(scc_count());
auto acc = used_acc();
bdd all = bdd_support(aut_->neg_acceptance_conditions());
for (unsigned s = 0; s < n; ++s)
result[s] = !is_accepting_scc(s) || acc[s] == all;
result[s] = !is_accepting_scc(s) || acc[s].size() == 1;
return result;
}
@ -276,8 +275,6 @@ namespace spot
{
scc_info* m = sccinfo ? sccinfo : new scc_info(aut);
bdd all_acc = aut->all_acceptance_conditions();
out << "digraph G {\n i [label=\"\", style=invis, height=0]\n";
int start = m->scc_of(aut->get_init_state_number());
out << " i -> " << start << std::endl;
@ -293,7 +290,7 @@ namespace spot
q.pop();
out << " " << state << " [shape=box,"
<< (m->acc(state) == all_acc ? "style=bold," : "")
<< (aut->acc().accepting(m->acc(state)) ? "style=bold," : "")
<< "label=\"" << state;
{
size_t n = m->states_of(state).size();

View file

@ -45,17 +45,17 @@ namespace spot
struct scc_node
{
scc_node():
acc(bddfalse), trivial(true)
acc(0U), trivial(true)
{
}
scc_node(bdd acc, bool trivial):
scc_node(acc_cond::mark_t acc, bool trivial):
acc(acc), trivial(trivial)
{
}
scc_succs succ;
bdd acc;
acc_cond::mark_t acc;
std::list<unsigned> states; // States of the component
bool trivial:1;
bool accepting:1;
@ -114,7 +114,7 @@ namespace spot
return node(scc).trivial;
}
bdd acc(unsigned scc) const
acc_cond::mark_t acc(unsigned scc) const
{
return node(scc).acc;
}
@ -134,18 +134,9 @@ namespace spot
return reachable_state(st) && node(scc_of(st)).useful;
}
/// \brief Return the set of all used acceptance combinations, for
/// each accepting SCC.
///
/// If SCC #i use {a,b} and {c}, which
/// are normally respectively encoded as
/// Acc[a]&!Acc[b]&!Acc[c] | !Acc[a]&Acc[b]&!Acc[c]
/// and
/// !Acc[a]&!Acc[b]&Acc[c]
/// then the vector will contain
/// Acc[a]&Acc[b] | Acc[c]
/// at position #i.
std::vector<bdd> used_acc() const;
/// \brief Return the set of all used acceptance combinations, for
/// each accepting SCC.
std::vector<std::set<acc_cond::mark_t>> used_acc() const;
std::vector<bool> weak_sccs() const;

View file

@ -57,10 +57,9 @@ namespace spot
se05_search(const const_tgba_ptr a, size_t size,
option_map o = option_map())
: emptiness_check(a, o),
h(size),
all_cond(a->all_acceptance_conditions())
h(size)
{
assert(a->number_of_acceptance_conditions() <= 1);
assert(a->acc().num_sets() <= 1);
}
virtual ~se05_search()
@ -98,7 +97,7 @@ namespace spot
const state* s0 = a_->get_init_state();
inc_states();
h.add_new_state(s0, CYAN);
push(st_blue, s0, bddfalse, bddfalse);
push(st_blue, s0, bddfalse, 0U);
if (dfs_blue())
return std::make_shared<se05_result>(t, options());
}
@ -151,7 +150,7 @@ namespace spot
private:
void push(stack_type& st, const state* s,
const bdd& label, const bdd& acc)
const bdd& label, acc_cond::mark_t acc)
{
inc_depth();
tgba_succ_iterator* i = a_->succ_iter(s);
@ -176,9 +175,6 @@ namespace spot
/// by the last dfs visiting it.
heap h;
/// The unique acceptance condition of the automaton \a a.
bdd all_cond;
bool dfs_blue()
{
while (!st_blue.empty())
@ -191,7 +187,7 @@ namespace spot
trace << " Visit the successor: "
<< a_->format_state(s_prime) << std::endl;
bdd label = f.it->current_condition();
bdd acc = f.it->current_acceptance_conditions();
auto acc = f.it->current_acceptance_conditions();
// Go down the edge (f.s, <label, acc>, s_prime)
f.it->next();
inc_transitions();
@ -203,8 +199,9 @@ namespace spot
h.add_new_state(s_prime, CYAN);
push(st_blue, s_prime, label, acc);
}
else if (c.get_color() == CYAN && (acc == all_cond ||
(f.s->compare(s_prime) != 0 && f.acc == all_cond)))
else if (c.get_color() == CYAN && (a_->acc().accepting(acc) ||
(f.s->compare(s_prime) != 0
&& a_->acc().accepting(f.acc))))
{
trace << " It is cyan and acceptance condition "
<< "is reached, report cycle" << std::endl;
@ -212,7 +209,7 @@ namespace spot
push(st_red, s_prime, label, acc);
return true;
}
else if (acc == all_cond && c.get_color() != RED)
else if (a_->acc().accepting(acc) && c.get_color() != RED)
{
// the test 'c.get_color() != RED' is added to limit
// the number of runs reported by successive
@ -241,7 +238,7 @@ namespace spot
typename heap::color_ref c = h.get_color_ref(f_dest.s);
assert(!c.is_white());
if (!st_blue.empty() &&
f_dest.acc == all_cond && c.get_color() != RED)
a_->acc().accepting(f_dest.acc) && c.get_color() != RED)
{
// the test 'c.get_color() != RED' is added to limit
// the number of runs reported by successive
@ -281,7 +278,7 @@ namespace spot
trace << " Visit the successor: "
<< a_->format_state(s_prime) << std::endl;
bdd label = f.it->current_condition();
bdd acc = f.it->current_acceptance_conditions();
auto acc = f.it->current_acceptance_conditions();
// Go down the edge (f.s, <label, acc>, s_prime)
f.it->next();
inc_transitions();

View file

@ -215,7 +215,30 @@ namespace spot
protected:
// Shortcut used in update_po and go_to_next_it.
typedef std::map<bdd, bdd, bdd_less_than> map_bdd_bdd;
int acc_vars;
public:
bdd mark_to_bdd(acc_cond::mark_t m)
{
// FIXME: Use a cache.
bdd res = bddtrue;
for (auto n: a_->acc().sets(m))
res &= bdd_ithvar(acc_vars + n);
return res;
}
acc_cond::mark_t bdd_to_mark(const tgba_digraph_ptr& aut, bdd b)
{
// FIXME: Use a cache.
std::vector<unsigned> res;
while (b != bddtrue)
{
res.push_back(bdd_var(b) - acc_vars);
b = bdd_high(b);
}
return aut->acc().marks(res.begin(), res.end());
}
direct_simulation(const const_tgba_ptr& t,
const map_constraint* map_cst = 0)
: a_(0),
@ -234,9 +257,6 @@ namespace spot
old_a_ = a_;
acc_compl ac(a_->all_acceptance_conditions(),
a_->neg_acceptance_conditions());
// Replace all the acceptance conditions by their complements.
// (In the case of Cosimulation, we also flip the transitions.)
{
@ -253,7 +273,7 @@ namespace spot
{
for (auto& t: old_a_->out(s))
{
bdd acc;
acc_cond::mark_t acc;
if (Sba && Cosimulation)
{
// If the acceptance is interpreted as
@ -262,16 +282,16 @@ namespace spot
// the destination state on its incoming arcs
// (which now become outgoing arcs after
// transposition).
acc = bddfalse;
acc = 0U;
for (auto& td: old_a_->out(t.dst))
{
acc = ac.complement(td.acc);
acc = old_a_->acc().comp(td.acc);
break;
}
}
else
{
acc = ac.complement(t.acc);
acc = old_a_->acc().comp(t.acc);
}
if (Cosimulation)
a_->new_transition(t.dst, s, t.cond, acc);
@ -288,8 +308,13 @@ namespace spot
unsigned set_num = a_->get_dict()
->register_anonymous_variables(size_a_ + 1, this);
all_acceptance_conditions_ = a_->all_acceptance_conditions();
all_proms_ = bdd_support(all_acceptance_conditions_);
unsigned n_acc = a_->acc().num_sets();
acc_vars = a_->get_dict()
->register_anonymous_variables(n_acc, this);
all_proms_ = bddtrue;
for (unsigned v = acc_vars; v < acc_vars + n_acc; ++v)
all_proms_ &= bdd_ithvar(v);
bdd_initial = bdd_ithvar(set_num++);
bdd init = bdd_ithvar(set_num++);
@ -397,7 +422,7 @@ namespace spot
}
else
{
acc = t.acc;
acc = mark_to_bdd(t.acc);
}
// to_add is a conjunction of the acceptance condition,
@ -527,23 +552,14 @@ namespace spot
// Build the minimal resulting automaton.
tgba_digraph_ptr build_result()
{
// We have all the a_'s acceptances conditions
// complemented. So we need to complement it when adding a
// transition. We *must* keep the complemented because it
// is easy to know if an acceptance condition is maximal or
// not.
acc_compl reverser(all_acceptance_conditions_,
a_->neg_acceptance_conditions());
tgba_digraph_ptr res = make_tgba_digraph(a_->get_dict());
res->copy_ap_of(a_);
res->set_acceptance_conditions(all_acceptance_conditions_);
res->copy_acceptance_conditions_of(a_);
if (Sba)
res->prop_state_based_acc();
bdd sup_all_acc = bdd_support(all_acceptance_conditions_);
// Non atomic propositions variables (= acc and class)
bdd nonapvars = sup_all_acc & bdd_support(all_class_var_);
bdd nonapvars = all_proms_ & bdd_support(all_class_var_);
auto* gb = res->create_namer<int>();
@ -558,9 +574,9 @@ namespace spot
}
// Acceptance of states. Only used if Sba && Cosimulation.
std::vector<bdd> accst;
std::vector<acc_cond::mark_t> accst;
if (Sba && Cosimulation)
accst.resize(res->num_states(), bddfalse);
accst.resize(res->num_states(), 0U);
stat.states = bdd_lstate_.size();
stat.transitions = 0;
@ -626,7 +642,8 @@ namespace spot
all_class_var_);
// Keep only ones who are acceptance condition.
bdd acc = bdd_existcomp(cond_acc_dest, sup_all_acc);
auto acc = bdd_to_mark(res, bdd_existcomp(cond_acc_dest,
all_proms_));
// Keep the other!
bdd cond = bdd_existcomp(cond_acc_dest,
@ -635,7 +652,7 @@ namespace spot
// Because we have complemented all the acceptance
// conditions on the input automaton, we must
// revert them to create a new transition.
acc = reverser.reverse_complement(acc);
acc = res->acc().comp(acc);
if (Cosimulation)
{
@ -647,7 +664,7 @@ namespace spot
// can't do this here, store this in a table
// so we can fix it later.
accst[gb->get_state(src.id())] = acc;
acc = bddfalse;
acc = 0U;
}
gb->new_transition(dst.id(), src.id(), cond, acc);
}
@ -671,8 +688,8 @@ namespace spot
unsigned ns = res->num_states();
for (unsigned s = 0; s < ns; ++s)
{
bdd acc = accst[s];
if (acc == bddfalse)
acc_cond::mark_t acc = accst[s];
if (acc == 0U)
continue;
for (auto& t: res->out(s))
t.acc = acc;
@ -774,8 +791,6 @@ namespace spot
const map_constraint* map_cst_;
const_tgba_ptr original_;
bdd all_acceptance_conditions_;
};
// For now, we don't try to handle cosimulation.
@ -807,8 +822,7 @@ namespace spot
// simulation to run.
has_limit_ = false;
notap = (bdd_support(all_acceptance_conditions_)
& all_class_var_ & on_cycle_);
notap = bdd_support(all_proms_) & all_class_var_ & on_cycle_;
}
// This function computes the don't care signature of the state
@ -831,13 +845,14 @@ namespace spot
if (scc != scc_info_->scc_of(t.dst))
acc = !on_cycle_;
else if (sccacc)
acc = on_cycle_ & t.acc;
acc = on_cycle_ & mark_to_bdd(t.acc);
else
acc = on_cycle_ & all_proms_;
bdd to_add = acc & t.cond & relation_[cl];
res |= to_add;
}
return res;
}
@ -864,9 +879,6 @@ namespace spot
bool could_imply_aux(bdd f1, bdd g1, bdd left_class,
bdd right, bdd right_class)
{
(void) left_class;
(void) right_class;
bdd f2g2 = bdd_exist(right, on_cycle_);
bdd f2g2n = bdd_exist(f2g2, all_proms_);
@ -973,8 +985,7 @@ namespace spot
bdd b = bdd_exist(right, notap);
bdd add = bdd_exist(left & b, bdd_support(b));
if (add != bddfalse
&& bdd_exist(add, all_acceptance_conditions_) == bddtrue)
if (add != bddfalse && bdd_exist(add, all_proms_) == bddtrue)
{
assert(src_right != dst_right);
@ -988,8 +999,7 @@ namespace spot
bdd b = bdd_exist(left, notap);
bdd add = bdd_exist(right & b, bdd_support(b));
if (add != bddfalse
&& bdd_exist(add, all_acceptance_conditions_) == bddtrue)
if (add != bddfalse && bdd_exist(add, all_proms_) == bddtrue)
{
assert(src_left != dst_left);
@ -1003,8 +1013,7 @@ namespace spot
bdd b = bdd_exist(left, notap);
bdd add = bdd_exist(right & b, bdd_support(b));
if (add != bddfalse
&& bdd_exist(add, all_acceptance_conditions_) == bddtrue)
if (add != bddfalse && bdd_exist(add, all_proms_) == bddtrue)
{
assert(src_left != dst_left && src_right != dst_right);
// FIXME: cas pas compris.
@ -1174,6 +1183,9 @@ namespace spot
}
while (diff != bddtrue);
}
#ifndef NDEBUG
for (auto& i: class2state)
assert(previous_class_[i.second] == i.first);

View file

@ -145,6 +145,10 @@ namespace spot
/// @}
// FIXME: Remove: dont_care_*_simulation is broken since the move to
// bitset acceptance, has never been really used, and really useful
// (nor really well tested and understood), so we should remove it.
SPOT_API tgba_digraph_ptr
dont_care_simulation(const const_tgba_ptr& t, int limit = -1);

View file

@ -180,7 +180,7 @@ namespace spot
}
if (has('a'))
acc_ = aut->number_of_acceptance_conditions();
acc_ = aut->acc().num_sets();
if (has('c') || has('S'))
scc_ = scc_info(aut).scc_count();

View file

@ -27,7 +27,7 @@ namespace spot
unsigned n = a->num_states();
for (unsigned s = 0; s < n; ++s)
for (auto& t: a->out(s))
t.acc = bddfalse;
a->set_acceptance_conditions(bddfalse);
t.acc = 0U;
a->set_acceptance_conditions(0);
}
}

View file

@ -56,10 +56,9 @@ namespace spot
/// \brief Initialize the search algorithm on the automaton \a a
tau03_search(const const_tgba_ptr a, size_t size, option_map o)
: emptiness_check(a, o),
h(size),
all_cond(a->all_acceptance_conditions())
h(size)
{
assert(a->number_of_acceptance_conditions() > 0);
assert(a->acc().num_sets() > 0);
}
virtual ~tau03_search()
@ -91,7 +90,7 @@ namespace spot
const state* s0 = a_->get_init_state();
inc_states();
h.add_new_state(s0, BLUE);
push(st_blue, s0, bddfalse, bddfalse);
push(st_blue, s0, bddfalse, 0U);
auto t = std::static_pointer_cast<tau03_search>
(this->emptiness_check::shared_from_this());
if (dfs_blue())
@ -124,7 +123,7 @@ namespace spot
private:
void push(stack_type& st, const state* s,
const bdd& label, const bdd& acc)
const bdd& label, acc_cond::mark_t acc)
{
inc_depth();
tgba_succ_iterator* i = a_->succ_iter(s);
@ -149,9 +148,6 @@ namespace spot
/// by the last dfs visiting it.
heap h;
/// The unique acceptance condition of the automaton \a a.
bdd all_cond;
bool dfs_blue()
{
while (!st_blue.empty())
@ -164,7 +160,7 @@ namespace spot
trace << " Visit the successor: "
<< a_->format_state(s_prime) << std::endl;
bdd label = f.it->current_condition();
bdd acc = f.it->current_acceptance_conditions();
auto acc = f.it->current_acceptance_conditions();
// Go down the edge (f.s, <label, acc>, s_prime)
f.it->next();
inc_transitions();
@ -199,10 +195,10 @@ namespace spot
<< a_->format_state(f.s) << " to "
<< a_->format_state(s_prime) << std::endl;
bdd label = i->current_condition();
bdd acc = i->current_acceptance_conditions();
auto acc = i->current_acceptance_conditions();
typename heap::color_ref c_prime = h.get_color_ref(s_prime);
assert(!c_prime.is_white());
bdd acu = acc | c.get_acc();
auto acu = acc | c.get_acc();
if ((c_prime.get_acc() & acu) != acu)
{
trace << " a propagation is needed, go down"
@ -212,7 +208,7 @@ namespace spot
dfs_red(acu);
}
}
if (c.get_acc() == all_cond)
if (a_->acc().accepting(c.get_acc()))
{
trace << "DFS_BLUE propagation is successful, report a"
<< " cycle" << std::endl;
@ -230,7 +226,7 @@ namespace spot
return false;
}
void dfs_red(const bdd& acu)
void dfs_red(acc_cond::mark_t acu)
{
assert(!st_red.empty());
@ -244,7 +240,7 @@ namespace spot
trace << " Visit the successor: "
<< a_->format_state(s_prime) << std::endl;
bdd label = f.it->current_condition();
bdd acc = f.it->current_acceptance_conditions();
auto acc = f.it->current_acceptance_conditions();
// Go down the edge (f.s, <label, acc>, s_prime)
f.it->next();
inc_transitions();
@ -254,7 +250,7 @@ namespace spot
trace << " It is white, pop it" << std::endl;
s_prime->destroy();
}
else if ((c_prime.get_acc() & acu) != acu)
else if ((c_prime.get_acc() & acu) != acu)
{
trace << " It is blue and propagation "
<< "is needed, go down" << std::endl;
@ -286,7 +282,7 @@ namespace spot
class color_ref
{
public:
color_ref(color* c, bdd* a) :p(c), acc(a)
color_ref(color* c, acc_cond::mark_t* a) :p(c), acc(a)
{
}
color get_color() const
@ -298,15 +294,15 @@ namespace spot
assert(!is_white());
*p = c;
}
const bdd& get_acc() const
acc_cond::mark_t get_acc() const
{
assert(!is_white());
return *acc;
}
void cumulate_acc(const bdd& a)
void cumulate_acc(acc_cond::mark_t a)
{
assert(!is_white());
*acc |= a;
*acc |= a;
}
bool is_white() const
{
@ -314,7 +310,7 @@ namespace spot
}
private:
color *p;
bdd* acc;
acc_cond::mark_t* acc;
};
explicit_tau03_search_heap(size_t)
@ -349,7 +345,9 @@ namespace spot
void add_new_state(const state* s, color c)
{
assert(h.find(s) == h.end());
h.emplace(s, std::make_pair(c, bddfalse));
h.emplace(std::piecewise_construct,
std::forward_as_tuple(s),
std::forward_as_tuple(c, 0U));
}
void pop_notify(const state*) const
@ -369,7 +367,8 @@ namespace spot
}
private:
typedef std::unordered_map<const state*, std::pair<color, bdd>,
typedef std::unordered_map<const state*,
std::pair<color, acc_cond::mark_t>,
state_ptr_hash, state_ptr_equal> hash_type;
hash_type h;
};

View file

@ -67,24 +67,13 @@ namespace spot
/// \brief Initialize the search algorithm on the automaton \a a
tau03_opt_search(const const_tgba_ptr& a, size_t size, option_map o)
: emptiness_check(a, o),
current_weight(a->neg_acceptance_conditions()),
current_weight(a->acc()),
h(size),
all_acc(a->all_acceptance_conditions()),
use_condition_stack(o.get("condstack")),
use_ordering(use_condition_stack && o.get("ordering")),
use_weights(o.get("weights", 1)),
use_red_weights(use_weights && o.get("redweights", 1))
{
if (use_ordering)
{
bdd all_conds = all_acc;
while (all_conds != bddfalse)
{
bdd acc = bdd_satone(all_conds);
cond.push_back(acc);
all_conds -= acc;
}
}
}
virtual ~tau03_opt_search()
@ -116,7 +105,7 @@ namespace spot
const state* s0 = a_->get_init_state();
inc_states();
h.add_new_state(s0, CYAN, current_weight);
push(st_blue, s0, bddfalse, bddfalse);
push(st_blue, s0, bddfalse, 0U);
auto t = std::static_pointer_cast<tau03_opt_search>
(this->emptiness_check::shared_from_this());
if (dfs_blue())
@ -149,7 +138,7 @@ namespace spot
private:
void push(stack_type& st, const state* s,
const bdd& label, const bdd& acc)
const bdd& label, acc_cond::mark_t acc)
{
inc_depth();
tgba_succ_iterator* i = a_->succ_iter(s);
@ -164,14 +153,16 @@ namespace spot
st.pop_front();
}
bdd project_acc(bdd acc) const
acc_cond::mark_t project_acc(acc_cond::mark_t acc) const
{
bdd result = bddfalse;
for (std::vector<bdd>::const_iterator i = cond.begin();
i != cond.end() && (acc & *i) != bddfalse;
++i)
result |= *i;
return result;
if (!use_ordering)
return acc;
// FIXME: This should be improved.
std::vector<unsigned> res;
unsigned max = a_->acc().num_sets();
for (unsigned n = 0; n < max && a_->acc().has(acc, n); ++n)
res.push_back(n);
return a_->acc().marks(res.begin(), res.end());
}
/// \brief weight of the state on top of the blue stack.
@ -187,9 +178,6 @@ namespace spot
/// by the last dfs visiting it.
heap h;
/// The unique acceptance condition of the automaton \a a.
bdd all_acc;
/// Whether to use the "condition stack".
bool use_condition_stack;
/// Whether to use an ordering between the acceptance conditions.
@ -200,9 +188,6 @@ namespace spot
/// Whether to use weights in the red dfs.
bool use_red_weights;
/// Ordering of the acceptance conditions.
std::vector<bdd> cond;
bool dfs_blue()
{
while (!st_blue.empty())
@ -215,7 +200,7 @@ namespace spot
trace << " Visit the successor: "
<< a_->format_state(s_prime) << std::endl;
bdd label = f.it->current_condition();
bdd acc = f.it->current_acceptance_conditions();
auto acc = f.it->current_acceptance_conditions();
// Go down the edge (f.s, <label, acc>, s_prime)
f.it->next();
inc_transitions();
@ -224,7 +209,7 @@ namespace spot
{
trace << " It is white, go down" << std::endl;
if (use_weights)
current_weight += acc;
current_weight.add(a_->acc(), acc);
inc_states();
h.add_new_state(s_prime, CYAN, current_weight);
push(st_blue, s_prime, label, acc);
@ -234,22 +219,21 @@ namespace spot
typename heap::color_ref c = h.get_color_ref(f.s);
assert(!c.is_white());
if (c_prime.get_color() == CYAN
&& all_acc == ((current_weight - c_prime.get_weight())
| c.get_acc()
| acc
| c_prime.get_acc()))
&& a_->acc().accepting
(current_weight.diff(a_->acc(), c_prime. get_weight())
| c.get_acc() | acc | c_prime.get_acc()))
{
trace << " It is cyan and acceptance condition "
<< "is reached, report cycle" << std::endl;
c_prime.cumulate_acc(all_acc);
c_prime.cumulate_acc(a_->acc().all_sets());
push(st_red, s_prime, label, acc);
return true;
}
else
{
trace << " It is cyan or blue and";
bdd acu = acc | c.get_acc();
bdd acp = (use_ordering ? project_acc(acu) : acu);
auto acu = acc | c.get_acc();
auto acp = project_acc(acu);
if ((c_prime.get_acc() & acp) != acp)
{
trace << " a propagation is needed, "
@ -276,7 +260,7 @@ namespace spot
stack_item f_dest(f);
pop(st_blue);
if (use_weights)
current_weight -= f_dest.acc;
current_weight.sub(a_->acc(), f_dest.acc);
typename heap::color_ref c_prime = h.get_color_ref(f_dest.s);
assert(!c_prime.is_white());
c_prime.set_color(BLUE);
@ -285,8 +269,8 @@ namespace spot
typename heap::color_ref c =
h.get_color_ref(st_blue.front().s);
assert(!c.is_white());
bdd acu = f_dest.acc | c.get_acc();
bdd acp = (use_ordering ? project_acc(acu) : acu);
auto acu = f_dest.acc | c.get_acc();
auto acp = project_acc(acu);
if ((c_prime.get_acc() & acp) != acp)
{
trace << " The arc from "
@ -315,15 +299,15 @@ namespace spot
}
bool
dfs_red(bdd acu)
dfs_red(acc_cond::mark_t acu)
{
assert(!st_red.empty());
// These are useful only when USE_CONDITION_STACK is set.
typedef std::pair<bdd, unsigned> cond_level;
typedef std::pair<acc_cond::mark_t, unsigned> cond_level;
std::stack<cond_level> condition_stack;
unsigned depth = 1;
condition_stack.emplace(bddfalse, 0);
condition_stack.emplace(0U, 0);
while (!st_red.empty())
{
@ -335,7 +319,7 @@ namespace spot
trace << " Visit the successor: "
<< a_->format_state(s_prime) << std::endl;
bdd label = f.it->current_condition();
bdd acc = f.it->current_acceptance_conditions();
auto acc = f.it->current_acceptance_conditions();
// Go down the edge (f.s, <label, acc>, s_prime)
f.it->next();
inc_transitions();
@ -347,22 +331,23 @@ namespace spot
continue;
}
else if (c_prime.get_color() == CYAN &&
(all_acc == ((use_red_weights ?
(current_weight - c_prime.get_weight())
: bdd_false())
| c_prime.get_acc()
| acc
| acu)))
a_->acc().accepting
(acc | acu | c_prime.get_acc() |
(use_red_weights ?
current_weight.diff(a_->acc(),
c_prime.
get_weight())
: acc_cond::mark_t(0U))))
{
trace << " It is cyan and acceptance condition "
<< "is reached, report cycle" << std::endl;
c_prime.cumulate_acc(all_acc);
c_prime.cumulate_acc(a_->acc().all_sets());
push(st_red, s_prime, label, acc);
return true;
}
bdd acp;
acc_cond::mark_t acp;
if (use_ordering)
acp = project_acc(c_prime.get_acc() | acu | acc);
acp = project_acc(acu | acc | c_prime.get_acc());
else if (use_condition_stack)
acp = acu | acc;
else
@ -376,7 +361,7 @@ namespace spot
push(st_red, s_prime, label, acc);
if (use_condition_stack)
{
bdd old = acu;
auto old = acu;
acu |= acc;
condition_stack.emplace(acu - old, depth);
}
@ -412,20 +397,22 @@ namespace spot
class explicit_tau03_opt_search_heap
{
typedef std::unordered_map<const state*, std::pair<weight, bdd>,
typedef std::unordered_map<const state*, std::pair<weight,
acc_cond::mark_t>,
state_ptr_hash, state_ptr_equal> hcyan_type;
typedef std::unordered_map<const state*, std::pair<color, bdd>,
typedef std::unordered_map<const state*, std::pair<color,
acc_cond::mark_t>,
state_ptr_hash, state_ptr_equal> hash_type;
public:
class color_ref
{
public:
color_ref(hash_type* h, hcyan_type* hc, const state* s,
const weight* w, bdd* a)
const weight* w, acc_cond::mark_t* a)
: is_cyan(true), w(w), ph(h), phc(hc), ps(s), acc(a)
{
}
color_ref(color* c, bdd* a)
color_ref(color* c, acc_cond::mark_t* a)
: is_cyan(false), pc(c), acc(a)
{
}
@ -459,12 +446,12 @@ namespace spot
*pc=c;
}
}
const bdd& get_acc() const
acc_cond::mark_t get_acc() const
{
assert(!is_white());
return *acc;
}
void cumulate_acc(const bdd& a)
void cumulate_acc(acc_cond::mark_t a)
{
assert(!is_white());
*acc |= a;
@ -480,8 +467,8 @@ namespace spot
hcyan_type* phc; // point to the hash table hcyan
const state* ps; // point to the state in hcyan
color *pc; // point to the color of a state stored in main hash table
bdd* acc; // point to the acc set of a state stored in main hash table
// or hcyan
acc_cond::mark_t* acc; // point to the acc set of a state stored
// in main hash table or hcyan
};
explicit_tau03_opt_search_heap(size_t)
@ -540,7 +527,7 @@ namespace spot
(void)c;
hc.emplace(std::piecewise_construct,
std::forward_as_tuple(s),
std::forward_as_tuple(w, bddfalse));
std::forward_as_tuple(w, 0U));
}
void pop_notify(const state*) const

View file

@ -26,96 +26,41 @@
namespace spot
{
weight::weight_vector* weight::pm = 0;
weight::weight(const bdd& neg_all_cond) : neg_all_acc(neg_all_cond)
weight::weight(const acc_cond& acc):
m(acc.num_sets())
{
}
void weight::inc_weight_handler(char* varset, int size)
weight& weight::add(const acc_cond& acc, acc_cond::mark_t a)
{
for (int v = 0; v < size; ++v)
if (varset[v] > 0)
{
weight::weight_vector::iterator it = pm->find(v);
if (it == pm->end())
pm->emplace(v, 1);
else
++(it->second);
break;
}
}
weight& weight::operator+=(const bdd& acc)
{
pm = &m;
bdd_allsat(acc, inc_weight_handler);
for (auto s: acc.sets(a))
++m[s];
return *this;
}
void weight::dec_weight_handler(char* varset, int size)
weight& weight::sub(const acc_cond& acc, acc_cond::mark_t a)
{
for (int v = 0; v < size; ++v)
if (varset[v] > 0)
{
weight::weight_vector::iterator it = pm->find(v);
assert(it != pm->end() && it->second > 0);
if (it->second > 1)
--(it->second);
else
pm->erase(it);
break;
}
}
weight& weight::operator-=(const bdd& acc)
{
pm = &m;
bdd_allsat(acc, dec_weight_handler);
for (auto s: acc.sets(a))
if (m[s] > 0)
--m[s];
return *this;
}
bdd weight::operator-(const weight& w) const
acc_cond::mark_t weight::diff(const acc_cond& acc, const weight& w) const
{
weight_vector::const_iterator itw1 = m.begin(), itw2 = w.m.begin();
bdd res = bddfalse;
while (itw1 != m.end() && itw2 != w.m.end())
{
assert(itw1->first <= itw2->first);
if (itw1->first < itw2->first)
{
res |= bdd_exist(neg_all_acc, bdd_ithvar(itw1->first)) &
bdd_ithvar(itw1->first);
++itw1;
}
else
{
assert(itw1->second >= itw2->second);
if (itw1->second > itw2->second)
{
res |= bdd_exist(neg_all_acc, bdd_ithvar(itw1->first)) &
bdd_ithvar(itw1->first);
}
++itw1;
++itw2;
}
}
assert(itw2 == w.m.end());
while (itw1 != m.end())
{
res |= bdd_exist(neg_all_acc, bdd_ithvar(itw1->first)) &
bdd_ithvar(itw1->first);
++itw1;
}
return res;
unsigned max = acc.num_sets();
std::vector<unsigned> res;
for (unsigned n = 0; n < max; ++n)
if (m[n] > w.m[n])
res.push_back(n);
return acc.marks(res.begin(), res.end());
}
std::ostream& operator<<(std::ostream& os, const weight& w)
{
weight::weight_vector::const_iterator it;
for (it = w.m.begin(); it != w.m.end(); ++it)
os << '(' << it->first << ',' << it->second << ')';
unsigned s = w.m.size();
for (unsigned n = 0; n < s; ++n)
os << '(' << n << ',' << w.m[n] << ')';
return os;
}

View file

@ -1,4 +1,4 @@
// Copyright (C) 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
// Copyright (C) 2004, 2014 Laboratoire d'Informatique de Paris 6 (LIP6),
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
// et Marie Curie.
//
@ -23,6 +23,7 @@
#include <iosfwd>
#include <map>
#include <bdd.h>
#include "tgba/acc.hh"
namespace spot
{
@ -33,29 +34,23 @@ namespace spot
{
public:
/// Construct a empty vector (all counters set to zero).
///
/// \param neg_all_cond : negation of all the acceptance conditions of
/// the automaton (the bdd returned by tgba::neg_acceptance_conditions()).
weight(const bdd& neg_all_cond);
weight(const acc_cond& acc);
/// Increment by one the counters of each acceptance condition in \a acc.
weight& operator+=(const bdd& acc);
weight& add(const acc_cond& acc, acc_cond::mark_t a);
/// Decrement by one the counters of each acceptance condition in \a acc.
weight& operator-=(const bdd& acc);
weight& sub(const acc_cond& acc, acc_cond::mark_t a);
/// Return the set of each acceptance condition such that its counter is
/// strictly greatest than the corresponding counter in w.
///
/// \pre For each acceptance condition, its counter is greatest or equal to
/// the corresponding counter in w.
bdd operator-(const weight& w) const;
friend std::ostream& operator<<(std::ostream& os, const weight& w);
acc_cond::mark_t diff(const acc_cond& acc, const weight& w) const;
friend std::ostream& operator<<(std::ostream& os,
const weight& w);
private:
typedef std::map<int, int> weight_vector;
typedef std::vector<int> weight_vector;
weight_vector m;
bdd neg_all_acc;
static weight_vector* pm;
static void inc_weight_handler(char* varset, int size);
static void dec_weight_handler(char* varset, int size);
};
};