genem: fix removal of unsatisfied Fin(x) sets
Fixes #360. * spot/twa/acc.cc, spot/twa/acc.hh (force_inf): New method. * spot/twaalgos/genem.cc: Fix the emptiness check using force_inf. * tests/python/genem.py: Add test case and adjust the python version of the emptiness check.
This commit is contained in:
parent
9f81df2cd4
commit
469d2b4ef4
4 changed files with 88 additions and 3 deletions
|
|
@ -1481,6 +1481,51 @@ namespace spot
|
||||||
SPOT_UNREACHABLE();
|
SPOT_UNREACHABLE();
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static acc_cond::acc_code
|
||||||
|
force_inf_rec(const acc_cond::acc_word* pos, acc_cond::mark_t rem)
|
||||||
|
{
|
||||||
|
auto start = pos - pos->sub.size;
|
||||||
|
switch (pos->sub.op)
|
||||||
|
{
|
||||||
|
case acc_cond::acc_op::And:
|
||||||
|
{
|
||||||
|
--pos;
|
||||||
|
auto res = acc_cond::acc_code::t();
|
||||||
|
do
|
||||||
|
{
|
||||||
|
auto tmp = force_inf_rec(pos, rem) & std::move(res);
|
||||||
|
std::swap(tmp, res);
|
||||||
|
pos -= pos->sub.size + 1;
|
||||||
|
}
|
||||||
|
while (pos > start);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
case acc_cond::acc_op::Or:
|
||||||
|
{
|
||||||
|
--pos;
|
||||||
|
auto res = acc_cond::acc_code::f();
|
||||||
|
do
|
||||||
|
{
|
||||||
|
auto tmp = force_inf_rec(pos, rem) | std::move(res);
|
||||||
|
std::swap(tmp, res);
|
||||||
|
pos -= pos->sub.size + 1;
|
||||||
|
}
|
||||||
|
while (pos > start);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
case acc_cond::acc_op::Fin:
|
||||||
|
return acc_cond::acc_code::fin(pos[-1].mark - rem);
|
||||||
|
case acc_cond::acc_op::Inf:
|
||||||
|
return acc_cond::acc_code::inf(pos[-1].mark);
|
||||||
|
case acc_cond::acc_op::FinNeg:
|
||||||
|
case acc_cond::acc_op::InfNeg:
|
||||||
|
SPOT_UNREACHABLE();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
SPOT_UNREACHABLE();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
acc_cond::acc_code
|
acc_cond::acc_code
|
||||||
|
|
@ -1499,6 +1544,14 @@ namespace spot
|
||||||
return strip_rec(&back(), rem, missing, false);
|
return strip_rec(&back(), rem, missing, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
acc_cond::acc_code
|
||||||
|
acc_cond::acc_code::force_inf(mark_t rem) const
|
||||||
|
{
|
||||||
|
if (is_t() || is_f())
|
||||||
|
return *this;
|
||||||
|
return force_inf_rec(&back(), rem);
|
||||||
|
}
|
||||||
|
|
||||||
acc_cond::mark_t
|
acc_cond::mark_t
|
||||||
acc_cond::acc_code::used_sets() const
|
acc_cond::acc_code::used_sets() const
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -921,6 +921,8 @@ namespace spot
|
||||||
acc_code remove(acc_cond::mark_t rem, bool missing) const;
|
acc_code remove(acc_cond::mark_t rem, bool missing) const;
|
||||||
// Same as remove, but also shift numbers
|
// Same as remove, but also shift numbers
|
||||||
acc_code strip(acc_cond::mark_t rem, bool missing) const;
|
acc_code strip(acc_cond::mark_t rem, bool missing) const;
|
||||||
|
// for all x in m, this replaces Fin(x) by false.
|
||||||
|
acc_code force_inf(mark_t m) const;
|
||||||
|
|
||||||
// Return the set of sets appearing in the condition.
|
// Return the set of sets appearing in the condition.
|
||||||
acc_cond::mark_t used_sets() const;
|
acc_cond::mark_t used_sets() const;
|
||||||
|
|
@ -1388,6 +1390,12 @@ namespace spot
|
||||||
{ num_sets() - (all_sets() & rem).count(), code_.strip(rem, missing) };
|
{ num_sets() - (all_sets() & rem).count(), code_.strip(rem, missing) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For all x in m, this replaces Fin(x) by false.
|
||||||
|
acc_cond force_inf(mark_t m) const
|
||||||
|
{
|
||||||
|
return {num_sets(), code_.force_inf(m)};
|
||||||
|
}
|
||||||
|
|
||||||
// Restrict an acceptance condition to a subset of set numbers
|
// Restrict an acceptance condition to a subset of set numbers
|
||||||
// that are occurring at some point.
|
// that are occurring at some point.
|
||||||
acc_cond restrict_to(mark_t rem) const
|
acc_cond restrict_to(mark_t rem) const
|
||||||
|
|
|
||||||
|
|
@ -175,7 +175,7 @@ namespace spot
|
||||||
<deal_with_disjunct>))
|
<deal_with_disjunct>))
|
||||||
return false;
|
return false;
|
||||||
// Try to accept when Fin(fo) == false
|
// Try to accept when Fin(fo) == false
|
||||||
tmp.set(acc.remove({(unsigned) fo}, false));
|
tmp.set(acc.force_inf({(unsigned) fo}));
|
||||||
return generic_emptiness_check_for_scc_nocopy
|
return generic_emptiness_check_for_scc_nocopy
|
||||||
<deal_with_disjunct>(si, scc, tocut);
|
<deal_with_disjunct>(si, scc, tocut);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,30 @@ HOA: v1 States: 2 Acceptance: 6 (Fin(0)|Fin(1))&(Fin(2)|Fin(3))&
|
||||||
(Fin(4)|Fin(5)) Start: 0 AP: 0 --BODY-- State: 0 [t] 0 {0 2 3} [t]
|
(Fin(4)|Fin(5)) Start: 0 AP: 0 --BODY-- State: 0 [t] 0 {0 2 3} [t]
|
||||||
1 {1 4} State: 1 [t] 0 {2 5} [t] 1 {3 0 1} --END--""")
|
1 {1 4} State: 1 [t] 0 {2 5} [t] 1 {3 0 1} --END--""")
|
||||||
|
|
||||||
|
# From issue #360.
|
||||||
|
a360 = spot.automaton("""HOA: v1
|
||||||
|
States: 2
|
||||||
|
Start: 0
|
||||||
|
AP: 2 "a" "b"
|
||||||
|
Acceptance: 8 Fin(5) & (Inf(4) | (Fin(3) & (Inf(2) | (Fin(1) & Inf(0))))) &
|
||||||
|
(Inf(6) | Inf(7)) & (Fin(6)|Fin(7))
|
||||||
|
properties: trans-labels explicit-labels trans-acc complete
|
||||||
|
properties: deterministic
|
||||||
|
--BODY--
|
||||||
|
State: 0
|
||||||
|
[0&1] 0 {4 6 7}
|
||||||
|
[0&!1] 1 {0 6}
|
||||||
|
[!0&1] 0 {3 7}
|
||||||
|
[!0&!1] 0 {0}
|
||||||
|
State: 1
|
||||||
|
[0&1] 0 {4 6 7}
|
||||||
|
[0&!1] 1 {3 6}
|
||||||
|
[!0&1] 0 {4 7}
|
||||||
|
[!0&!1] 1 {0}
|
||||||
|
--END--""")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def generic_emptiness2_rec(aut):
|
def generic_emptiness2_rec(aut):
|
||||||
spot.cleanup_acceptance_here(aut, False)
|
spot.cleanup_acceptance_here(aut, False)
|
||||||
|
|
@ -143,7 +167,7 @@ def generic_emptiness2_rec(aut):
|
||||||
if not generic_emptiness2(part):
|
if not generic_emptiness2(part):
|
||||||
return False
|
return False
|
||||||
whole = si.split_on_sets(scc, [])[0]
|
whole = si.split_on_sets(scc, [])[0]
|
||||||
whole.set_acceptance(acc.remove([fo], False))
|
whole.set_acceptance(acc.force_inf([fo]))
|
||||||
if not generic_emptiness2(whole):
|
if not generic_emptiness2(whole):
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
@ -166,4 +190,4 @@ def run_bench(automata):
|
||||||
print(res)
|
print(res)
|
||||||
assert res in ('TTT', 'FFF')
|
assert res in ('TTT', 'FFF')
|
||||||
|
|
||||||
run_bench([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a11])
|
run_bench([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a11, a360])
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue