simulation: build tgba_digraph
* src/tgbaalgos/simulation.cc: Buid a tgba_digraph as the result of the simulation. * src/tgba/tgbagraph.hh (create_namer): New function. * src/tgbatest/basimul.test: Add an additional test case that caused a bug fixed in a previous patch. * src/tgbatest/sim.test: Adjust.
This commit is contained in:
parent
31bf8c2c1e
commit
e299a3d1bf
4 changed files with 70 additions and 77 deletions
|
|
@ -21,6 +21,7 @@
|
||||||
# define SPOT_TGBA_TGBAGRAPH_HH
|
# define SPOT_TGBA_TGBAGRAPH_HH
|
||||||
|
|
||||||
#include "graph/graph.hh"
|
#include "graph/graph.hh"
|
||||||
|
#include "graph/ngraph.hh"
|
||||||
#include "tgba/bdddict.hh"
|
#include "tgba/bdddict.hh"
|
||||||
#include "tgba/tgba.hh"
|
#include "tgba/tgba.hh"
|
||||||
#include "misc/bddop.hh"
|
#include "misc/bddop.hh"
|
||||||
|
|
@ -178,6 +179,15 @@ namespace spot
|
||||||
return g_;
|
return g_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename State_Name,
|
||||||
|
typename Name_Hash = std::hash<State_Name>,
|
||||||
|
typename Name_Equal = std::equal_to<State_Name>>
|
||||||
|
named_graph<graph_t, State_Name, Name_Hash, Name_Equal>*
|
||||||
|
create_namer()
|
||||||
|
{
|
||||||
|
return new named_graph<graph_t, State_Name, Name_Hash, Name_Equal>(g_);
|
||||||
|
}
|
||||||
|
|
||||||
const graph_t& get_graph() const
|
const graph_t& get_graph() const
|
||||||
{
|
{
|
||||||
return g_;
|
return g_;
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,6 @@
|
||||||
#include "tgbaalgos/sccfilter.hh"
|
#include "tgbaalgos/sccfilter.hh"
|
||||||
#include "tgbaalgos/scc.hh"
|
#include "tgbaalgos/scc.hh"
|
||||||
#include "tgbaalgos/dupexp.hh"
|
#include "tgbaalgos/dupexp.hh"
|
||||||
#include "tgbaalgos/dotty.hh"
|
|
||||||
|
|
||||||
// The way we developed this algorithm is the following: We take an
|
// The way we developed this algorithm is the following: We take an
|
||||||
// automaton, and reverse all these acceptance conditions. We reverse
|
// automaton, and reverse all these acceptance conditions. We reverse
|
||||||
|
|
@ -275,8 +274,6 @@ namespace spot
|
||||||
size_a_ = ns;
|
size_a_ = ns;
|
||||||
}
|
}
|
||||||
|
|
||||||
initial_state = a_->get_init_state();
|
|
||||||
|
|
||||||
// Now, we have to get the bdd which will represent the
|
// Now, we have to get the bdd which will represent the
|
||||||
// class. We register one bdd by state, because in the worst
|
// class. We register one bdd by state, because in the worst
|
||||||
// case, |Class| == |State|.
|
// case, |Class| == |State|.
|
||||||
|
|
@ -370,7 +367,7 @@ namespace spot
|
||||||
}
|
}
|
||||||
|
|
||||||
// The core loop of the algorithm.
|
// The core loop of the algorithm.
|
||||||
tgba* run()
|
tgba_digraph* run()
|
||||||
{
|
{
|
||||||
main_loop();
|
main_loop();
|
||||||
return build_result();
|
return build_result();
|
||||||
|
|
@ -540,17 +537,8 @@ namespace spot
|
||||||
|
|
||||||
|
|
||||||
// Build the minimal resulting automaton.
|
// Build the minimal resulting automaton.
|
||||||
tgba* build_result()
|
tgba_digraph* build_result()
|
||||||
{
|
{
|
||||||
// Now we need to create a state per partition. But the
|
|
||||||
// problem is that we don't know exactly the class. We know
|
|
||||||
// that it is a combination of the acceptance condition
|
|
||||||
// contained in all_class_var_. So we need to make a little
|
|
||||||
// workaround. We will create a map which will associate bdd
|
|
||||||
// and unsigned.
|
|
||||||
std::map<bdd, unsigned, bdd_less_than> bdd2state;
|
|
||||||
unsigned int current_max = 0;
|
|
||||||
|
|
||||||
// We have all the a_'s acceptances conditions
|
// We have all the a_'s acceptances conditions
|
||||||
// complemented. So we need to complement it when adding a
|
// complemented. So we need to complement it when adding a
|
||||||
// transition. We *must* keep the complemented because it
|
// transition. We *must* keep the complemented because it
|
||||||
|
|
@ -560,7 +548,7 @@ namespace spot
|
||||||
a_->neg_acceptance_conditions());
|
a_->neg_acceptance_conditions());
|
||||||
|
|
||||||
bdd_dict* d = a_->get_dict();
|
bdd_dict* d = a_->get_dict();
|
||||||
tgba_explicit_number* res = new tgba_explicit_number(d);
|
tgba_digraph* res = new tgba_digraph(d);
|
||||||
d->register_all_variables_of(a_, res);
|
d->register_all_variables_of(a_, res);
|
||||||
res->set_acceptance_conditions(all_acceptance_conditions_);
|
res->set_acceptance_conditions(all_acceptance_conditions_);
|
||||||
|
|
||||||
|
|
@ -568,23 +556,22 @@ namespace spot
|
||||||
// Non atomic propositions variables (= acc and class)
|
// Non atomic propositions variables (= acc and class)
|
||||||
bdd nonapvars = sup_all_acc & bdd_support(all_class_var_);
|
bdd nonapvars = sup_all_acc & bdd_support(all_class_var_);
|
||||||
|
|
||||||
|
auto* gb = res->create_namer<int>();
|
||||||
|
|
||||||
// Create one state per partition.
|
// Create one state per partition.
|
||||||
for (auto& p: bdd_lstate_)
|
for (auto& p: bdd_lstate_)
|
||||||
{
|
{
|
||||||
res->add_state(++current_max);
|
bdd cl = previous_class_[p.second.front()];
|
||||||
bdd part = previous_class_[p.second.front()];
|
// A state may be referred to either by
|
||||||
|
// its class, or by all the implied classes.
|
||||||
// The difference between the two next lines is:
|
auto s = gb->new_state(cl.id());
|
||||||
// the first says "if you see A", the second "if you
|
gb->alias_state(s, relation_[cl].id());
|
||||||
// see A and all the classes implied by it".
|
|
||||||
bdd2state[part] = current_max;
|
|
||||||
bdd2state[relation_[part]] = current_max;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Acceptance of states. Only used if Sba && Cosimulation.
|
// Acceptance of states. Only used if Sba && Cosimulation.
|
||||||
std::vector<bdd> accst;
|
std::vector<bdd> accst;
|
||||||
if (Sba && Cosimulation)
|
if (Sba && Cosimulation)
|
||||||
accst.resize(current_max + 1, bddfalse);
|
accst.resize(res->num_states(), bddfalse);
|
||||||
|
|
||||||
stat.states = bdd_lstate_.size();
|
stat.states = bdd_lstate_.size();
|
||||||
stat.transitions = 0;
|
stat.transitions = 0;
|
||||||
|
|
@ -592,11 +579,15 @@ namespace spot
|
||||||
unsigned nb_satoneset = 0;
|
unsigned nb_satoneset = 0;
|
||||||
unsigned nb_minato = 0;
|
unsigned nb_minato = 0;
|
||||||
|
|
||||||
// For each partition, we will create
|
// For each class, we will create
|
||||||
// all the transitions between the states.
|
// all the transitions between the states.
|
||||||
for (auto& p: bdd_lstate_)
|
for (auto& p: bdd_lstate_)
|
||||||
{
|
{
|
||||||
// Get the signature.
|
// All states in p.second have the same class, so just
|
||||||
|
// pick the class of the first one first one.
|
||||||
|
bdd src = previous_class_[p.second.front()];
|
||||||
|
|
||||||
|
// Get the signature to derive successors.
|
||||||
bdd sig = compute_sig(p.second.front());
|
bdd sig = compute_sig(p.second.front());
|
||||||
|
|
||||||
if (Cosimulation)
|
if (Cosimulation)
|
||||||
|
|
@ -642,7 +633,7 @@ namespace spot
|
||||||
|
|
||||||
// Take the transition, and keep only the variable which
|
// Take the transition, and keep only the variable which
|
||||||
// are used to represent the class.
|
// are used to represent the class.
|
||||||
bdd dest = bdd_existcomp(cond_acc_dest,
|
bdd dst = bdd_existcomp(cond_acc_dest,
|
||||||
all_class_var_);
|
all_class_var_);
|
||||||
|
|
||||||
// Keep only ones who are acceptance condition.
|
// Keep only ones who are acceptance condition.
|
||||||
|
|
@ -657,53 +648,48 @@ namespace spot
|
||||||
// revert them to create a new transition.
|
// revert them to create a new transition.
|
||||||
acc = reverser.reverse_complement(acc);
|
acc = reverser.reverse_complement(acc);
|
||||||
|
|
||||||
// Take the id of the source and destination. To
|
if (Cosimulation)
|
||||||
// know the source, we must take a random state in
|
{
|
||||||
// the list which is in the class we currently
|
gb->new_transition(dst.id(), src.id(),
|
||||||
// work on.
|
cond, Sba ? bddfalse : acc);
|
||||||
int src = bdd2state[previous_class_[p.second.front()]];
|
if (Sba)
|
||||||
int dst = bdd2state[dest];
|
// acc should be attached to src, or rather,
|
||||||
|
// in our transition-based representation)
|
||||||
if (Cosimulation)
|
// to all transitions leaving src. As we
|
||||||
std::swap(src, dst);
|
// can't do this here, store this in a table
|
||||||
|
// so we can fix it later.
|
||||||
// src or dst == 0 means "dest" or "prev..." isn't
|
accst[gb->get_state(src.id())] = acc;
|
||||||
// in the map. so it is a bug.
|
}
|
||||||
assert(src != 0);
|
|
||||||
assert(dst != 0);
|
|
||||||
|
|
||||||
// Create the transition, add the condition and the
|
|
||||||
// acceptance condition.
|
|
||||||
tgba_explicit_number::transition* t
|
|
||||||
= res->create_transition(src, dst);
|
|
||||||
t->condition = cond;
|
|
||||||
if (Sba && Cosimulation)
|
|
||||||
accst[dst] = acc;
|
|
||||||
else
|
else
|
||||||
t->acceptance_conditions = acc;
|
{
|
||||||
|
gb->new_transition(src.id(), dst.id(), cond, acc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
res->set_init_state(bdd2state[previous_class_[0]]);
|
res->set_init_state(gb->get_state(previous_class_
|
||||||
|
[a_->get_init_state_number()].id()));
|
||||||
|
|
||||||
res->merge_transitions();
|
res->merge_transitions(); // FIXME: is this really needed?
|
||||||
|
|
||||||
// Mark all accepting state in a second pass, when
|
// Mark all accepting state in a second pass, when
|
||||||
// dealing with SBA in cosimulation.
|
// dealing with SBA in cosimulation.
|
||||||
if (Sba && Cosimulation)
|
if (Sba && Cosimulation)
|
||||||
for (unsigned snum = current_max; snum > 0; --snum)
|
{
|
||||||
{
|
tgba_digraph::graph_t& g = res->get_graph();
|
||||||
const state* s = res->get_state(snum);
|
unsigned ns = res->num_states();
|
||||||
bdd acc = accst[snum];
|
for (unsigned s = 0; s < ns; ++s)
|
||||||
for (auto it: res->succ(s))
|
{
|
||||||
{
|
bdd acc = accst[s];
|
||||||
tgba_explicit_number::transition* t =
|
if (acc == bddfalse)
|
||||||
res->get_transition(it);
|
continue;
|
||||||
t->acceptance_conditions = acc;
|
for (auto& t: g.out(s))
|
||||||
}
|
t.acc = acc;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete gb;
|
||||||
res_is_deterministic = nb_minato == nb_satoneset;
|
res_is_deterministic = nb_minato == nb_satoneset;
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
|
@ -780,9 +766,6 @@ namespace spot
|
||||||
// The flag to say if the outgoing state is initial or not
|
// The flag to say if the outgoing state is initial or not
|
||||||
bdd bdd_initial;
|
bdd bdd_initial;
|
||||||
|
|
||||||
// Initial state of the automaton we are working on
|
|
||||||
state* initial_state;
|
|
||||||
|
|
||||||
bdd all_proms_;
|
bdd all_proms_;
|
||||||
|
|
||||||
automaton_size stat;
|
automaton_size stat;
|
||||||
|
|
@ -1120,7 +1103,7 @@ namespace spot
|
||||||
return min_size_;
|
return min_size_;
|
||||||
}
|
}
|
||||||
|
|
||||||
tgba* run()
|
tgba_digraph* run()
|
||||||
{
|
{
|
||||||
// Iterate the simulation until the end. We just don't return
|
// Iterate the simulation until the end. We just don't return
|
||||||
// an automaton. This allows us to get all the information
|
// an automaton. This allows us to get all the information
|
||||||
|
|
@ -1205,7 +1188,7 @@ namespace spot
|
||||||
assert(previous_class_[i.second] == i.first);
|
assert(previous_class_[i.second] == i.first);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
tgba* min = 0;
|
tgba_digraph* min = 0;
|
||||||
|
|
||||||
map_constraint cstr;
|
map_constraint cstr;
|
||||||
|
|
||||||
|
|
@ -1264,7 +1247,7 @@ namespace spot
|
||||||
// Compute recursively all the combinations.
|
// Compute recursively all the combinations.
|
||||||
void rec(constraint_list constraints,
|
void rec(constraint_list constraints,
|
||||||
map_constraint cstr,
|
map_constraint cstr,
|
||||||
tgba** min,
|
tgba_digraph** min,
|
||||||
int max_depth = std::numeric_limits<int>::max())
|
int max_depth = std::numeric_limits<int>::max())
|
||||||
{
|
{
|
||||||
assert(max_depth > 0);
|
assert(max_depth > 0);
|
||||||
|
|
@ -1282,7 +1265,7 @@ namespace spot
|
||||||
empty_seen_ = true;
|
empty_seen_ = true;
|
||||||
|
|
||||||
direct_simulation<false, false> dir_sim(original_, &cstr);
|
direct_simulation<false, false> dir_sim(original_, &cstr);
|
||||||
tgba* tmp = dir_sim.run();
|
tgba_digraph* tmp = dir_sim.run();
|
||||||
automaton_size cur_size = dir_sim.get_stat();
|
automaton_size cur_size = dir_sim.get_stat();
|
||||||
if (*min == 0 || min_size_ > cur_size)
|
if (*min == 0 || min_size_ > cur_size)
|
||||||
{
|
{
|
||||||
|
|
@ -1367,7 +1350,7 @@ namespace spot
|
||||||
{
|
{
|
||||||
prev = next;
|
prev = next;
|
||||||
direct_simulation<false, Sba> simul(res);
|
direct_simulation<false, Sba> simul(res);
|
||||||
tgba* after_simulation = simul.run();
|
tgba_digraph* after_simulation = simul.run();
|
||||||
|
|
||||||
if (res != t)
|
if (res != t)
|
||||||
delete res;
|
delete res;
|
||||||
|
|
@ -1379,9 +1362,8 @@ namespace spot
|
||||||
}
|
}
|
||||||
|
|
||||||
direct_simulation<true, Sba> cosimul(after_simulation);
|
direct_simulation<true, Sba> cosimul(after_simulation);
|
||||||
tgba* after_cosimulation = cosimul.run();
|
tgba_digraph* after_cosimulation = cosimul.run();
|
||||||
next = cosimul.get_stat();
|
next = cosimul.get_stat();
|
||||||
|
|
||||||
delete after_simulation;
|
delete after_simulation;
|
||||||
|
|
||||||
if (Sba)
|
if (Sba)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# Copyright (C) 2013 Laboratoire de Recherche et Développement de
|
# Copyright (C) 2013, 2014 Laboratoire de Recherche et Développement de
|
||||||
# l'Epita (LRDE).
|
# l'Epita (LRDE).
|
||||||
#
|
#
|
||||||
# This file is part of Spot, a model checking library.
|
# This file is part of Spot, a model checking library.
|
||||||
|
|
@ -59,6 +59,7 @@ ltl2tgba=../../bin/ltl2tgba
|
||||||
-f '((<> p5 V ((p0 U p1) <-> (p5 \/ p1))) -> ((<> p4 V p2) M p2))' \
|
-f '((<> p5 V ((p0 U p1) <-> (p5 \/ p1))) -> ((<> p4 V p2) M p2))' \
|
||||||
-f '!p2 & (Fp5 R (((p0 U p1) & (p5 | p1)) | (!p5 & (!p0 R !p1))))' \
|
-f '!p2 & (Fp5 R (((p0 U p1) & (p5 | p1)) | (!p5 & (!p0 R !p1))))' \
|
||||||
-f '! ((p0 /\ p4) <-> ! ((! p0 U (p0 W p4)) /\ (X p5 -> ([] p3 /\ p5))))' \
|
-f '! ((p0 /\ p4) <-> ! ((! p0 U (p0 W p4)) /\ (X p5 -> ([] p3 /\ p5))))' \
|
||||||
|
-f '(X <> (<> X p0 /\ X (p5 <-> p0)) W (p3 W p0))' \
|
||||||
"$ltl2tgba --ba --high --lbtt=t -x ba-simul=0 %f >%T" \
|
"$ltl2tgba --ba --high --lbtt=t -x ba-simul=0 %f >%T" \
|
||||||
"$ltl2tgba --ba --high --lbtt=t -x ba-simul=1 %f >%T" \
|
"$ltl2tgba --ba --high --lbtt=t -x ba-simul=1 %f >%T" \
|
||||||
"$ltl2tgba --ba --high --lbtt=t -x ba-simul=2 %f >%T" \
|
"$ltl2tgba --ba --high --lbtt=t -x ba-simul=2 %f >%T" \
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#! /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.
|
||||||
|
|
@ -35,8 +35,8 @@ run 0 ../ltl2tgba -X -RDCS -b in.tgba > out.tgba
|
||||||
|
|
||||||
cat >expected.tgba <<EOF
|
cat >expected.tgba <<EOF
|
||||||
acc = "1";
|
acc = "1";
|
||||||
"4", "3", "b",;
|
"3", "2", "b",;
|
||||||
"3", "3", "a", "1";
|
"2", "2", "a", "1";
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
diff out.tgba expected.tgba
|
diff out.tgba expected.tgba
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue