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

dtgbacomp: Rewrite using tgba_digraph instead of tgba_explicit_number

* src/tgbaalgos/dtgbacomp.cc, src/tgbaalgos/dtgbacomp.hh: Rewrite.
Also prefer simple loops over reachiter.
* src/tgbatest/det.test: Adjust.
parent 0909c2fe
...@@ -19,124 +19,87 @@ ...@@ -19,124 +19,87 @@
#include "dtgbacomp.hh" #include "dtgbacomp.hh"
#include "ltlast/constant.hh" #include "ltlast/constant.hh"
#include "reachiter.hh" #include "dupexp.hh"
namespace spot namespace spot
{ {
tgba_digraph* dtgba_complement(const tgba* aut)
namespace
{ {
class dtgbacomp_iter: public tgba_reachable_iterator_depth_first_stack // Clone the original automaton.
{ tgba_digraph* res = tgba_dupexp_dfs(aut);
bdd orig_acc_;
bdd all_neg_;
bdd acc_;
bdd_dict* dict_;
tgba_explicit_number* out_;
int num_acc_;
typedef state_explicit_number::transition trans; auto dict = res->get_dict();
public:
dtgbacomp_iter(const tgba* a)
: tgba_reachable_iterator_depth_first_stack(a),
dict_(a->get_dict()),
out_(new tgba_explicit_number(dict_))
{
dict_->register_all_variables_of(a, out_);
orig_acc_ = a->all_acceptance_conditions();
all_neg_ = a->neg_acceptance_conditions();
num_acc_ = a->number_of_acceptance_conditions();
// Register one acceptance condition for the result. bdd oldaccs = aut->all_acceptance_conditions();
int accvar = dict_->register_acceptance_variable bdd oldnegs = aut->neg_acceptance_conditions();
(ltl::constant::true_instance(), out_);
acc_ = bdd_ithvar(accvar);
out_->set_acceptance_conditions(acc_);
}
tgba_explicit_number* // We will modify res in place, and the resulting
result() // automaton will only have one acceptance set.
{ dict->unregister_all_typed_variables(bdd_dict::acc, res);
return out_; bdd theacc =
} bdd_ithvar(dict->register_acceptance_variable
(ltl::constant::true_instance(), res));
res->set_acceptance_conditions(theacc);
void unsigned num_acc = aut->number_of_acceptance_conditions();
end() unsigned n = res->num_states();
{ // We will duplicate the automaton as many times as we have
out_->merge_transitions(); // acceptance sets, and we need one extra sink state.
// create a sink state if needed. res->new_states(num_acc * n + 1);
if (out_->has_state(0)) unsigned sink = res->num_states() - 1;
{ // The sink state has an accepting self-loop.
trans* t = out_->create_transition(0, 0); res->new_transition(sink, sink, bddtrue, theacc);
t->condition = bddtrue;
t->acceptance_conditions = acc_;
}
}
void process_state(const state*, int n, for (unsigned src = 0; src < n; ++src)
tgba_succ_iterator* i)
{ {
// add a transition to a sink state if the state is not complete. // Keep track of all conditions on transition leaving state
bdd all = bddtrue; // SRC, so we can complete it.
if (i->first()) bdd missingcond = bddtrue;
do for (auto& t: res->out(src))
all -= i->current_condition();
while (i->next());
if (all != bddfalse)
{ {
trans* t = out_->create_transition(n, 0); if (t.dst >= n) // Ignore transition we added.
t->condition = all; break;
} missingcond -= t.cond;
} bdd curacc = t.acc;
// The original transition must not accept anymore.
void t.acc = bddfalse;
process_link(const state*, int in, // Transition that were fully accepting are never cloned.
const state*, int out, if (curacc == oldaccs)
const tgba_succ_iterator* si) continue;
{ // Save t.cond and t.dst as the reference to t
assert(in > 0); // is invalided by calls to new_transition().
assert(out > 0); unsigned dst = t.dst;
bdd a = si->current_acceptance_conditions(); bdd cond = t.cond;
// We want all acceptance bdd variable to appear in curacc.
if (curacc == bddfalse)
curacc = oldnegs;
// Positive states represent a non-accepting copy of the // Iterate over all the acceptance conditions in 'curacc',
// original automaton. // an duplicate it each each clone for which it does not
trans* t1 = out_->create_transition(in, out); // belong to the acceptance set.
t1->condition = si->current_condition(); unsigned add = 0;
while (curacc != bddtrue)
// Negative states encode NUM_ACC_ copies of the automaton.
// In each copy transitions labeled by one of the acceptance
// set have been removed, and all the remaining transitions
// are now accepting.
// For each state S, we have NUM_ACC_ additional copies
// labeled S*-NUM_ACC, S*-NUM_ACC+1, ... S*-NUM_ACC+(NUM_ACC-1),
if (a != orig_acc_)
{
bool backlink = on_stack(out);
int add = 0;
if (a == bddfalse)
a = all_neg_;
// Iterate over all the acceptance conditions in 'a'.
bdd ac = a;
while (ac != bddtrue)
{ {
bdd h = bdd_high(ac); add += n;
bdd h = bdd_high(curacc);
if (h == bddfalse) if (h == bddfalse)
{ {
trans* t2 = out_->create_transition(in * -num_acc_ + add, // Clone the transition
out * -num_acc_ + add); res->new_transition(src + add, dst + add, cond, theacc);
t2->condition = si->current_condition(); assert(dst + add < sink);
t2->acceptance_conditions = acc_; // Using `t' is disallowed from now on as it is a
// reference to a transition that may have been
// reallocated.
if (backlink) // At least one transition per cycle should have a
{ // nondeterministic copy from the original clone.
// Since we are closing a cycle, add // We use state numbers to select it, as any cycle
// a non-deterministic transition from // is guaranteed to have at least one transition
// the original automaton to this copy. // with dst <= src. FIXME: Computing a feedback
trans* t3 = // arc set would be better.
out_->create_transition(in, out * -num_acc_ + add); if (dst <= src)
t3->condition = si->current_condition(); res->new_transition(src, dst + add, cond);
} curacc = bdd_low(curacc);
ac = bdd_low(ac);
} }
else else
{ {
...@@ -148,26 +111,21 @@ namespace spot ...@@ -148,26 +111,21 @@ namespace spot
// branch is false. In that case we take the HIGH // branch is false. In that case we take the HIGH
// branch to enumerate all the remaining negated // branch to enumerate all the remaining negated
// variables. // variables.
bdd tmp = bdd_low(ac); bdd tmp = bdd_low(curacc);
if (tmp != bddfalse) if (tmp != bddfalse)
ac = tmp; curacc = tmp;
else else
ac = h; curacc = h;
} }
++add;
} }
assert(add == num_acc_); assert(add == num_acc * n);
} }
// Complete the original automaton.
if (missingcond != bddfalse)
res->new_transition(src, sink, missingcond);
} }
res->merge_transitions();
}; // FIXME: Remove unreachable states.
return res;
} // anonymous
tgba_explicit_number* dtgba_complement(const tgba* aut)
{
dtgbacomp_iter dci(aut);
dci.run();
return dci.result();
} }
} }
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
#ifndef SPOT_TGBAALGOS_DTGBACOMP_HH #ifndef SPOT_TGBAALGOS_DTGBACOMP_HH
# define SPOT_TGBAALGOS_DTGBACOMP_HH # define SPOT_TGBAALGOS_DTGBACOMP_HH
#include "tgba/tgbaexplicit.hh" #include "tgba/tgbagraph.hh"
namespace spot namespace spot
{ {
...@@ -30,7 +30,7 @@ namespace spot ...@@ -30,7 +30,7 @@ namespace spot
/// to be complete. Acceptance can be transition-based, or /// to be complete. Acceptance can be transition-based, or
/// state-based. The resulting automaton is very unlikely to be /// state-based. The resulting automaton is very unlikely to be
/// deterministic. /// deterministic.
SPOT_API tgba_explicit_number* SPOT_API tgba_digraph*
dtgba_complement(const tgba* aut); dtgba_complement(const tgba* aut);
} }
......
#!/bin/sh #!/bin/sh
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright (C) 2013 Laboratoire de Recherche et Développement # Copyright (C) 2013, 2014 Laboratoire de Recherche et Développement
# de l'Epita (LRDE). # de l'Epita (LRDE).
# #
# This file is part of Spot, a model checking library. # This file is part of Spot, a model checking library.
...@@ -72,21 +72,22 @@ EOF ...@@ -72,21 +72,22 @@ EOF
# FIXME: we should improve this output # FIXME: we should improve this output
cat >ex.tgba <<'EOF' cat >ex.tgba <<'EOF'
acc = "1"; acc = "1";
"0", "1", "a",;
"0", "0", "!a",;
"0", "3", "!a",;
"1", "2", "a",; "1", "2", "a",;
"1", "1", "!a",; "1", "0", "!a",;
"1", "-1", "!a",; "1", "3", "!a",;
"2", "3", "a",; "3", "3", "!a", "1";
"2", "1", "!a",; "2", "2", "a",;
"2", "-1", "!a",; "2", "0", "!a",;
"-1", "-1", "!a", "1"; "2", "5", "a",;
"3", "3", "a",; "2", "3", "!a",;
"3", "-3", "a",; "5", "5", "a", "1";
"3", "1", "!a",; "5", "3", "!a", "1";
"3", "-1", "!a",;
"-3", "-3", "a", "1";
"-3", "-1", "!a", "1";
EOF EOF
run 0 ../ltl2tgba -b -DC -X in.tgba > out.tgba run 0 ../ltl2tgba -b -DC -X in.tgba > out.tgba
diff out.tgba ex.tgba diff out.tgba ex.tgba
...@@ -96,15 +97,15 @@ cat >ex.tgba <<EOF ...@@ -96,15 +97,15 @@ cat >ex.tgba <<EOF
digraph G { digraph G {
0 [label="", style=invis, height=0] 0 [label="", style=invis, height=0]
0 -> 1 0 -> 1
1 [label="1"] 1 [label="0"]
1 -> 2 [label="1\n"] 1 -> 2 [label="1\n"]
2 [label="2"] 2 [label="1"]
2 -> 2 [label="1\n"] 2 -> 2 [label="1\n"]
2 -> 3 [label="!a\n"] 2 -> 3 [label="!a\n"]
2 -> 4 [label="!b\n"] 2 -> 4 [label="!b\n"]
3 [label="-4"] 3 [label="3"]
3 -> 3 [label="!a\n{Acc[1]}"] 3 -> 3 [label="!a\n{Acc[1]}"]
4 [label="-3"] 4 [label="5"]
4 -> 4 [label="!b\n{Acc[1]}"] 4 -> 4 [label="!b\n{Acc[1]}"]
} }
EOF EOF
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment