Commit f3e57901 authored by Alexandre Duret-Lutz's avatar Alexandre Duret-Lutz

simulation: improve merging of transiant-SCCs

* spot/twaalgos/simulation.cc: Code this.
* tests/core/det.test, tests/core/dra2dba.test,
tests/core/satmin.test, tests/core/sim3.test,
tests/python/decompose.ipynb, tests/python/dualize.py: Adjust test
cases.
* NEWS: Mention the optimization.
parent c9ddbd0a
Pipeline #10147 passed with stages
in 154 minutes and 55 seconds
...@@ -45,6 +45,9 @@ New in spot 2.7.5.dev (not yet released) ...@@ -45,6 +45,9 @@ New in spot 2.7.5.dev (not yet released)
'ltldo ltl2dstar -f 'GFa -> GFb' | autfilt --small' produces 1 'ltldo ltl2dstar -f 'GFa -> GFb' | autfilt --small' produces 1
state instead of 4.) state instead of 4.)
- simulation-based reductions hae learned another trick to better
merge states from transiant SCCs.
- acc_cond::top_disjuncts() and acc_cond::top_conjuncts() can be - acc_cond::top_disjuncts() and acc_cond::top_conjuncts() can be
used to split an acceptance condition on the top-level & or |. used to split an acceptance condition on the top-level & or |.
These methods also exist in acc_cond::acc_code. These methods also exist in acc_cond::acc_code.
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <utility> #include <utility>
#include <cmath> #include <cmath>
#include <limits> #include <limits>
#include <numeric>
#include <spot/twaalgos/simulation.hh> #include <spot/twaalgos/simulation.hh>
#include <spot/misc/minato.hh> #include <spot/misc/minato.hh>
#include <spot/twa/bddprint.hh> #include <spot/twa/bddprint.hh>
...@@ -493,7 +494,7 @@ namespace spot ...@@ -493,7 +494,7 @@ namespace spot
} }
} }
// Build the minimal resulting automaton. // Build the simplified automaton.
twa_graph_ptr build_result() twa_graph_ptr build_result()
{ {
twa_graph_ptr res = make_twa_graph(a_->get_dict()); twa_graph_ptr res = make_twa_graph(a_->get_dict());
...@@ -526,6 +527,9 @@ namespace spot ...@@ -526,6 +527,9 @@ namespace spot
(*record_implications_)[s] = relation_[cl]; (*record_implications_)[s] = relation_[cl];
} }
std::vector<bdd> signatures;
signatures.reserve(sorted_classes_.size());
// Acceptance of states. Only used if Sba && Cosimulation. // Acceptance of states. Only used if Sba && Cosimulation.
std::vector<acc_cond::mark_t> accst; std::vector<acc_cond::mark_t> accst;
if (Sba && Cosimulation) if (Sba && Cosimulation)
...@@ -538,6 +542,7 @@ namespace spot ...@@ -538,6 +542,7 @@ namespace spot
unsigned nb_minato = 0; unsigned nb_minato = 0;
auto all_inf = all_inf_; auto all_inf = all_inf_;
unsigned srcst = 0;
// For each class, we will create // For each class, we will create
// all the edges between the states. // all the edges between the states.
for (auto& p: sorted_classes_) for (auto& p: sorted_classes_)
...@@ -552,7 +557,11 @@ namespace spot ...@@ -552,7 +557,11 @@ namespace spot
if (Cosimulation) if (Cosimulation)
sig = bdd_compose(sig, bddfalse, bdd_var(bdd_initial)); sig = bdd_compose(sig, bddfalse, bdd_var(bdd_initial));
// Get all the variable in the signature. assert(gb->get_state(src.id()) == srcst);
assert(signatures.size() == srcst);
signatures.push_back(bdd_exist(sig, all_proms_));
// Get all the variables in the signature.
bdd sup_sig = bdd_support(sig); bdd sup_sig = bdd_support(sig);
// Get the variable in the signature which represents the // Get the variable in the signature which represents the
...@@ -607,7 +616,6 @@ namespace spot ...@@ -607,7 +616,6 @@ namespace spot
// acceptance conditions on the input automaton, // acceptance conditions on the input automaton,
// we must revert them to create a new edge. // we must revert them to create a new edge.
acc ^= all_inf; acc ^= all_inf;
if (Cosimulation) if (Cosimulation)
{ {
if (Sba) if (Sba)
...@@ -617,7 +625,7 @@ namespace spot ...@@ -617,7 +625,7 @@ namespace spot
// to all edges leaving src. As we // to all edges leaving src. As we
// can't do this here, store this in a table // can't do this here, store this in a table
// so we can fix it later. // so we can fix it later.
accst[gb->get_state(src.id())] = acc; accst[srcst] = acc;
acc = {}; acc = {};
} }
gb->new_edge(dst.id(), src.id(), cond, acc); gb->new_edge(dst.id(), src.id(), cond, acc);
...@@ -628,6 +636,7 @@ namespace spot ...@@ -628,6 +636,7 @@ namespace spot
} }
} }
} }
++srcst;
} }
res->set_init_state(gb->get_state(previous_class_ res->set_init_state(gb->get_state(previous_class_
...@@ -652,6 +661,41 @@ namespace spot ...@@ -652,6 +661,41 @@ namespace spot
} }
} }
// Attempt to merge trivial SCCs
if (!record_implications_ && res->num_states() > 1)
{
scc_info si(res, scc_info_options::NONE);
unsigned nscc = si.scc_count();
unsigned nstates = res->num_states();
std::vector<unsigned> redirect(nstates);
std::iota(redirect.begin(), redirect.end(), 0);
bool changed = false;
for (unsigned scc = 0; scc < nscc; ++scc)
if (si.is_trivial(scc))
{
unsigned s = si.one_state_of(scc);
bdd ref = signatures[s];
for (unsigned i = 0; i < nstates; ++i)
if (si.reachable_state(i)
&& signatures[i] == ref && !si.is_trivial(si.scc_of(i)))
{
changed = true;
redirect[s] = i;
break;
}
}
if (changed)
{
if (Cosimulation)
for (auto& e: res->edges())
e.src = redirect[e.src];
else
for (auto& e: res->edges())
e.dst = redirect[e.dst];
res->set_init_state(redirect[res->get_init_state_number()]);
}
}
// If we recorded implications for the determinization // If we recorded implications for the determinization
// procedure, we should not remove unreachable states, as that // procedure, we should not remove unreachable states, as that
// will invalidate the contents of the IMPLICATIONS vector. // will invalidate the contents of the IMPLICATIONS vector.
......
#!/bin/sh #!/bin/sh
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright (C) 2013-2018 Laboratoire de Recherche et Développement de # Copyright (C) 2013-2019 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.
...@@ -24,17 +24,17 @@ set -e ...@@ -24,17 +24,17 @@ set -e
cat >formulas <<'EOF' cat >formulas <<'EOF'
1,13,X((a M F((!b & !c) | (b & c))) W (G!c U b)) 1,13,X((a M F((!b & !c) | (b & c))) W (G!c U b))
1,5,X(((a & b) R (!a U !c)) R b) 1,5,X(((a & b) R (!a U !c)) R b)
1,9,XXG(Fa U Xb) 1,8,XXG(Fa U Xb)
1,5,(!a M !b) W F!c 1,5,(!a M !b) W F!c
1,3,(b & Fa & GFc) R a 1,3,(b & Fa & GFc) R a
1,2,(a R (b W a)) W G(!a M (b | c)) 1,2,(a R (b W a)) W G(!a M (b | c))
1,11,(Fa W b) R (!a | Fc) 1,11,(Fa W b) R (!a | Fc)
1,7,X(G(!a M !b) | G(a | G!a)) 1,6,X(G(!a M !b) | G(a | G!a))
1,2,Fa W Gb 1,2,Fa W Gb
1,3,Ga | GFb 1,2,Ga | GFb
1,9,G((G!a & ((!b & X!c) | (b & Xc))) | (Fa & ((!b & Xc) | (b & X!c)))) 1,9,G((G!a & ((!b & X!c) | (b & Xc))) | (Fa & ((!b & Xc) | (b & X!c))))
1,5,a M G(F!b | X!a) 1,5,a M G(F!b | X!a)
1,4,G!a R XFb 1,3,G!a R XFb
1,4,XF(!a | GFb) 1,4,XF(!a | GFb)
1,5,X(GF!a U a) 1,5,X(GF!a U a)
1,5,(a | G(a M !b)) W Fc 1,5,(a | G(a M !b)) W Fc
...@@ -43,14 +43,14 @@ cat >formulas <<'EOF' ...@@ -43,14 +43,14 @@ cat >formulas <<'EOF'
1,2,XG!a R Fb 1,2,XG!a R Fb
1,4,GFc | (a & Fb) 1,4,GFc | (a & Fb)
1,6,X(a R (Fb R F!b)) 1,6,X(a R (Fb R F!b))
1,2,G(Xa M Fa) 1,1,G(Xa M Fa)
1,4,X(Gb | GFa) 1,3,X(Gb | GFa)
1,9,X(Gc | XG((b & Ga) | (!b & F!a))) 1,9,X(Gc | XG((b & Ga) | (!b & F!a)))
1,2,Ga R Fb 1,2,Ga R Fb
1,3,G(a U (b | X((!a & !c) | (a & c)))) 1,3,G(a U (b | X((!a & !c) | (a & c))))
1,5,XG((G!a & F!b) | (Fa & (a | Gb))) 1,5,XG((G!a & F!b) | (Fa & (a | Gb)))
1,9,(a U X!a) | XG(!b & Fc) 1,7,(a U X!a) | XG(!b & Fc)
1,4,X(G!a | GFa) 1,3,X(G!a | GFa)
1,4,G(G!a | F!c | G!b) 1,4,G(G!a | F!c | G!b)
EOF EOF
......
...@@ -330,4 +330,5 @@ Acc-Sig: +2 ...@@ -330,4 +330,5 @@ Acc-Sig: +2
EOF EOF
autcross 'dstar2tgba -D' --language-preserved -F in.dra --csv=out.csv autcross 'dstar2tgba -D' --language-preserved -F in.dra --csv=out.csv
grep '3,18,107,144,1,2,0,0,0$' out.csv cat out.csv
grep '3,17,104,136,1,1,0,0,0$' out.csv
#!/bin/sh #!/bin/sh
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright (C) 2013, 2017, 2018 Laboratoire de Recherche et Développement # Copyright (C) 2013, 2017, 2018, 2019 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.
...@@ -949,7 +949,7 @@ cat >expected <<'EOF' ...@@ -949,7 +949,7 @@ cat >expected <<'EOF'
"!(((p0) R ((p1) W (p0))) W (G((!(p0)) M ((p1) | (p2)))))","16",4 "!(((p0) R ((p1) W (p0))) W (G((!(p0)) M ((p1) | (p2)))))","16",4
"!(((p0) R ((p1) W (p0))) W (G((!(p0)) M ((p1) | (p2)))))","17",4 "!(((p0) R ((p1) W (p0))) W (G((!(p0)) M ((p1) | (p2)))))","17",4
"X((G((!(p0)) M (!(p1)))) | (G((p0) | (G(!(p0))))))","1",5 "X((G((!(p0)) M (!(p1)))) | (G((p0) | (G(!(p0))))))","1",5
"X((G((!(p0)) M (!(p1)))) | (G((p0) | (G(!(p0))))))","2",7 "X((G((!(p0)) M (!(p1)))) | (G((p0) | (G(!(p0))))))","2",6
"X((G((!(p0)) M (!(p1)))) | (G((p0) | (G(!(p0))))))","3",6 "X((G((!(p0)) M (!(p1)))) | (G((p0) | (G(!(p0))))))","3",6
"X((G((!(p0)) M (!(p1)))) | (G((p0) | (G(!(p0))))))","4",6 "X((G((!(p0)) M (!(p1)))) | (G((p0) | (G(!(p0))))))","4",6
"X((G((!(p0)) M (!(p1)))) | (G((p0) | (G(!(p0))))))","6",6 "X((G((!(p0)) M (!(p1)))) | (G((p0) | (G(!(p0))))))","6",6
...@@ -1013,7 +1013,7 @@ cat >expected <<'EOF' ...@@ -1013,7 +1013,7 @@ cat >expected <<'EOF'
"!((F(p0)) W (G(p1)))","16",2 "!((F(p0)) W (G(p1)))","16",2
"!((F(p0)) W (G(p1)))","17",2 "!((F(p0)) W (G(p1)))","17",2
"(G(F(p1))) | (G(p0))","1",3 "(G(F(p1))) | (G(p0))","1",3
"(G(F(p1))) | (G(p0))","2",3 "(G(F(p1))) | (G(p0))","2",2
"(G(F(p1))) | (G(p0))","3",2 "(G(F(p1))) | (G(p0))","3",2
"(G(F(p1))) | (G(p0))","4",2 "(G(F(p1))) | (G(p0))","4",2
"(G(F(p1))) | (G(p0))","6",2 "(G(F(p1))) | (G(p0))","6",2
...@@ -1076,8 +1076,8 @@ cat >expected <<'EOF' ...@@ -1076,8 +1076,8 @@ cat >expected <<'EOF'
"!((p0) M (G((F(!(p1))) | (X(!(p0))))))","15",4 "!((p0) M (G((F(!(p1))) | (X(!(p0))))))","15",4
"!((p0) M (G((F(!(p1))) | (X(!(p0))))))","16",4 "!((p0) M (G((F(!(p1))) | (X(!(p0))))))","16",4
"!((p0) M (G((F(!(p1))) | (X(!(p0))))))","17",4 "!((p0) M (G((F(!(p1))) | (X(!(p0))))))","17",4
"(G(!(p0))) R (X(F(p1)))","1",4 "(G(!(p0))) R (X(F(p1)))","1",3
"(G(!(p0))) R (X(F(p1)))","2",4 "(G(!(p0))) R (X(F(p1)))","2",3
"(G(!(p0))) R (X(F(p1)))","3",3 "(G(!(p0))) R (X(F(p1)))","3",3
"(G(!(p0))) R (X(F(p1)))","4",3 "(G(!(p0))) R (X(F(p1)))","4",3
"(G(!(p0))) R (X(F(p1)))","6",3 "(G(!(p0))) R (X(F(p1)))","6",3
...@@ -1333,7 +1333,7 @@ cat >expected <<'EOF' ...@@ -1333,7 +1333,7 @@ cat >expected <<'EOF'
"!(X((p0) R ((F(p1)) R (F(!(p1))))))","16",3 "!(X((p0) R ((F(p1)) R (F(!(p1))))))","16",3
"!(X((p0) R ((F(p1)) R (F(!(p1))))))","17",3 "!(X((p0) R ((F(p1)) R (F(!(p1))))))","17",3
"G((X(p0)) M (F(p0)))","1",2 "G((X(p0)) M (F(p0)))","1",2
"G((X(p0)) M (F(p0)))","2",2 "G((X(p0)) M (F(p0)))","2",1
"G((X(p0)) M (F(p0)))","3",1 "G((X(p0)) M (F(p0)))","3",1
"G((X(p0)) M (F(p0)))","4",1 "G((X(p0)) M (F(p0)))","4",1
"G((X(p0)) M (F(p0)))","6",1 "G((X(p0)) M (F(p0)))","6",1
...@@ -1365,7 +1365,7 @@ cat >expected <<'EOF' ...@@ -1365,7 +1365,7 @@ cat >expected <<'EOF'
"!(G((X(p0)) M (F(p0))))","16",2 "!(G((X(p0)) M (F(p0))))","16",2
"!(G((X(p0)) M (F(p0))))","17",2 "!(G((X(p0)) M (F(p0))))","17",2
"X((G(F(p1))) | (G(p0)))","1",4 "X((G(F(p1))) | (G(p0)))","1",4
"X((G(F(p1))) | (G(p0)))","2",4 "X((G(F(p1))) | (G(p0)))","2",3
"X((G(F(p1))) | (G(p0)))","3",3 "X((G(F(p1))) | (G(p0)))","3",3
"X((G(F(p1))) | (G(p0)))","4",3 "X((G(F(p1))) | (G(p0)))","4",3
"X((G(F(p1))) | (G(p0)))","6",3 "X((G(F(p1))) | (G(p0)))","6",3
...@@ -1493,7 +1493,7 @@ cat >expected <<'EOF' ...@@ -1493,7 +1493,7 @@ cat >expected <<'EOF'
"!(X(G(((G(!(p0))) & (F(!(p1)))) | ((F(p0)) & ((p0) | (G(p1)))))))","16",7 "!(X(G(((G(!(p0))) & (F(!(p1)))) | ((F(p0)) & ((p0) | (G(p1)))))))","16",7
"!(X(G(((G(!(p0))) & (F(!(p1)))) | ((F(p0)) & ((p0) | (G(p1)))))))","17",7 "!(X(G(((G(!(p0))) & (F(!(p1)))) | ((F(p0)) & ((p0) | (G(p1)))))))","17",7
"X((G(F(p0))) | (G(!(p0))))","1",4 "X((G(F(p0))) | (G(!(p0))))","1",4
"X((G(F(p0))) | (G(!(p0))))","2",4 "X((G(F(p0))) | (G(!(p0))))","2",3
"X((G(F(p0))) | (G(!(p0))))","3",3 "X((G(F(p0))) | (G(!(p0))))","3",3
"X((G(F(p0))) | (G(!(p0))))","4",3 "X((G(F(p0))) | (G(!(p0))))","4",3
"X((G(F(p0))) | (G(!(p0))))","6",3 "X((G(F(p0))) | (G(!(p0))))","6",3
......
...@@ -47,7 +47,7 @@ State: 6 {0 3} ...@@ -47,7 +47,7 @@ State: 6 {0 3}
--END-- --END--
EOF EOF
test "`autfilt --small input --stats=%S,%s`" = 7,2 test "`autfilt --small input --stats=%S,%s`" = 7,1
autfilt -S --high --small input -H > out autfilt -S --high --small input -H > out
cat >expected <<EOF cat >expected <<EOF
......
This diff is collapsed.
#!/usr/bin/python3 #!/usr/bin/python3
# -*- mode: python; coding: utf-8 -*- # -*- mode: python; coding: utf-8 -*-
# Copyright (C) 2017, 2018 Laboratoire de Recherche et Développement de # Copyright (C) 2017-2019 Laboratoire de Recherche et Développement de
# l'EPITA. # l'EPITA.
# #
# This file is part of Spot, a model checking library. # This file is part of Spot, a model checking library.
...@@ -553,7 +553,7 @@ dual = spot.dualize(aut) ...@@ -553,7 +553,7 @@ dual = spot.dualize(aut)
h = dual.to_str('hoa') h = dual.to_str('hoa')
assert h == """HOA: v1 assert h == """HOA: v1
States: 6 States: 5
Start: 0 Start: 0
AP: 2 "a" "b" AP: 2 "a" "b"
acc-name: co-Buchi acc-name: co-Buchi
...@@ -561,27 +561,24 @@ Acceptance: 1 Fin(0) ...@@ -561,27 +561,24 @@ Acceptance: 1 Fin(0)
properties: trans-labels explicit-labels state-acc complete properties: trans-labels explicit-labels state-acc complete
properties: deterministic univ-branch properties: deterministic univ-branch
--BODY-- --BODY--
State: 0 State: 0 {0}
[0] 1 [0&1] 0
[!0] 1&2 [0&!1] 1
State: 1 {0} [!0&!1] 1&2
[0&1] 1 [!0&1] 0&2
[0&!1] 4 State: 1
[!0&!1] 2&4 [0&1] 0
[!0&1] 1&2 [0&!1] 1
[!0&!1] 1&2
[!0&1] 0&2
State: 2 State: 2
[!0&1] 3 [!0&1] 3
[0 | !1] 5 [0 | !1] 4
State: 3 {0} State: 3 {0}
[!0] 3 [!0] 3
[0] 5 [0] 4
State: 4 State: 4
[0&1] 1 [t] 4
[0&!1] 4
[!0&!1] 2&4
[!0&1] 1&2
State: 5
[t] 5
--END--""" --END--"""
opts = spot.option_map() opts = spot.option_map()
......
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