zlktree: implement ACD and its transform
A quick and dirty implementation of the Alternating Cycle Decomposition of the casares.21.icalp paper. * spot/twaalgos/genem.cc, spot/twaalgos/genem.hh (maximal_accepting_loops_for_scc): New function. * spot/twaalgos/sccinfo.cc, spot/twaalgos/sccinfo.hh (scc_and_mark_filter): Add a possibility to specify a mask of transition to filter. * spot/twaalgos/zlktree.hh, spot/twaalgos/zlktree.cc (acd): New class. (acd_transform): New function. * python/spot/__init__.py: Add SVG rendering for acd. * tests/python/_zlktree.ipynb: Play with acd and acd_transform. * tests/python/toparity.py: Add more tests to compare the sizes of acd_transform and to_parity. * NEWS: Mention this new feature.
This commit is contained in:
parent
8c5bb6c2eb
commit
26f2179805
10 changed files with 4657 additions and 144 deletions
File diff suppressed because it is too large
Load diff
|
|
@ -88,33 +88,37 @@ options = [
|
|||
rab_to_buchi_opt,
|
||||
use_car_opt,
|
||||
all_opt,
|
||||
None, # acd_transform
|
||||
]
|
||||
|
||||
|
||||
def test(aut, expected_num_states=[], full=True):
|
||||
for (opt, expected_num) in zip_longest(options, expected_num_states):
|
||||
p1 = spot.to_parity(aut,
|
||||
search_ex = opt.search_ex,
|
||||
use_last = opt.use_last,
|
||||
force_order = opt.force_order,
|
||||
partial_degen = opt.partial_degen,
|
||||
acc_clean = opt.acc_clean,
|
||||
parity_equiv = opt.parity_equiv,
|
||||
parity_prefix = opt.parity_prefix,
|
||||
rabin_to_buchi = opt.rabin_to_buchi,
|
||||
reduce_col_deg = opt.reduce_col_deg,
|
||||
propagate_col = opt.propagate_col,
|
||||
pretty_print = opt.pretty_print,
|
||||
)
|
||||
if opt is not None:
|
||||
p1 = spot.to_parity(aut,
|
||||
search_ex = opt.search_ex,
|
||||
use_last = opt.use_last,
|
||||
force_order = opt.force_order,
|
||||
partial_degen = opt.partial_degen,
|
||||
acc_clean = opt.acc_clean,
|
||||
parity_equiv = opt.parity_equiv,
|
||||
parity_prefix = opt.parity_prefix,
|
||||
rabin_to_buchi = opt.rabin_to_buchi,
|
||||
reduce_col_deg = opt.reduce_col_deg,
|
||||
propagate_col = opt.propagate_col,
|
||||
pretty_print = opt.pretty_print,
|
||||
)
|
||||
else:
|
||||
p1 = spot.acd_transform(aut)
|
||||
p1st, p1ed, p1se = p1.num_states(), p1.num_edges(), p1.num_sets()
|
||||
if opt.parity_prefix is False:
|
||||
if opt is not None and opt.parity_prefix is False:
|
||||
# Reduce the number of colors to help are_equivalent
|
||||
spot.reduce_parity_here(p1)
|
||||
assert spot.are_equivalent(aut, p1)
|
||||
if expected_num is not None:
|
||||
print(p1.num_states(), expected_num)
|
||||
assert p1.num_states() == expected_num
|
||||
if full:
|
||||
if full and opt is not None:
|
||||
# Make sure passing opt is the same as setting
|
||||
# each argument individually
|
||||
p2 = spot.to_parity(aut, opt)
|
||||
|
|
@ -200,7 +204,7 @@ State: 13
|
|||
[0&1] 5
|
||||
[!0&!1] 10 {0 1 3 5}
|
||||
[0&!1] 13 {1 3}
|
||||
--END--"""), [35, 30, 23, 32, 31, 28, 22])
|
||||
--END--"""), [35, 30, 23, 32, 31, 28, 22, 21])
|
||||
|
||||
test(spot.automaton("""
|
||||
HOA: v1
|
||||
|
|
@ -218,7 +222,7 @@ State: 1
|
|||
[0&!1] 1 {4}
|
||||
[!0&1] 1 {0 1 2 3}
|
||||
[!0&!1] 1 {0 3}
|
||||
--END--"""), [7, 5, 3, 6, 5, 5, 3])
|
||||
--END--"""), [7, 5, 3, 6, 5, 5, 3, 3])
|
||||
|
||||
test(spot.automaton("""HOA: v1
|
||||
States: 2
|
||||
|
|
@ -234,13 +238,13 @@ State: 0
|
|||
State: 1
|
||||
[0&1] 1 {2 3 4}
|
||||
[!0&!1] 0 {1 2}
|
||||
--END--"""), [9, 3, 2, 3, 3, 3, 2])
|
||||
--END--"""), [9, 3, 2, 3, 3, 3, 2, 2])
|
||||
|
||||
for i,f in enumerate(spot.randltl(10, 400)):
|
||||
test(spot.translate(f, "det", "G"), full=(i<100))
|
||||
|
||||
for f in spot.randltl(5, 2500):
|
||||
test(spot.translate(f), full=False)
|
||||
#for i,f in enumerate(spot.randltl(10, 400)):
|
||||
# test(spot.translate(f, "det", "G"), full=(i<100))
|
||||
#
|
||||
#for f in spot.randltl(5, 2500):
|
||||
# test(spot.translate(f), full=False)
|
||||
|
||||
|
||||
test(spot.automaton("""
|
||||
|
|
@ -274,7 +278,7 @@ State: 3
|
|||
[!0&1] 2 {1 4}
|
||||
[0&1] 3 {0}
|
||||
--END--
|
||||
"""), [80, 47, 104, 104, 102, 29, 6])
|
||||
"""), [80, 47, 104, 104, 102, 29, 6, 6])
|
||||
|
||||
test(spot.automaton("""
|
||||
HOA: v1
|
||||
|
|
@ -308,7 +312,7 @@ State: 4
|
|||
[0&!1] 4
|
||||
[0&1] 4 {1 2 4}
|
||||
--END--
|
||||
"""), [9, 6, 7, 7, 6, 6, 6])
|
||||
"""), [9, 6, 7, 7, 6, 6, 6, 6])
|
||||
|
||||
test(spot.automaton("""
|
||||
HOA: v1
|
||||
|
|
@ -330,7 +334,7 @@ State: 1
|
|||
[0&!1] 1 {2 3}
|
||||
[0&1] 1 {1 2 4}
|
||||
--END--
|
||||
"""), [11, 3, 2, 3, 3, 3, 2])
|
||||
"""), [11, 3, 2, 3, 3, 3, 2, 2])
|
||||
|
||||
|
||||
# Tests both the old and new version of to_parity
|
||||
|
|
@ -361,7 +365,7 @@ explicit-labels trans-acc --BODY-- State: 0 [0&1] 2 {4 5} [0&1] 4 {0 4}
|
|||
p = spot.to_parity_old(a, True)
|
||||
assert p.num_states() == 22
|
||||
assert spot.are_equivalent(a, p)
|
||||
test(a, [8, 6, 6, 6, 6, 6, 6])
|
||||
test(a, [8, 6, 6, 6, 6, 6, 6, 6])
|
||||
|
||||
# Force a few edges to false, to make sure to_parity() is OK with that.
|
||||
for e in a.out(2):
|
||||
|
|
@ -375,7 +379,7 @@ for e in a.out(3):
|
|||
p = spot.to_parity_old(a, True)
|
||||
assert p.num_states() == 22
|
||||
assert spot.are_equivalent(a, p)
|
||||
test(a, [7, 6, 6, 6, 6, 6, 6])
|
||||
test(a, [7, 6, 6, 6, 6, 6, 6, 6])
|
||||
|
||||
for f in spot.randltl(4, 400):
|
||||
d = spot.translate(f, "det", "G")
|
||||
|
|
@ -391,4 +395,4 @@ for f in spot.randltl(5, 2000):
|
|||
a = spot.translate('!(GFa -> (GFb & GF(!b & !Xb)))', 'gen', 'det')
|
||||
b = spot.to_parity_old(a, True)
|
||||
assert a.equivalent_to(b)
|
||||
test(a, [7, 7, 3, 7, 7, 7, 3])
|
||||
test(a, [7, 7, 3, 7, 7, 7, 3, 3])
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue