implement a FORQ-based inclusion check for SBAs

* spot/twaalgos/forq_contains.cc, spot/twaalgos/forq_contains.hh: New
files.
* spot/twaalgos/Makefile.am, python/spot/impl.i: Add them.
* tests/python/forq_contains.py: New file.
* tests/Makefile.am: Add it.
This commit is contained in:
Jonah Romero 2023-08-03 12:04:47 +02:00 committed by Alexandre Duret-Lutz
parent c2832cabfc
commit d1c5b2efdf
6 changed files with 1574 additions and 0 deletions

View file

@ -123,6 +123,7 @@
#include <spot/twaalgos/dot.hh> #include <spot/twaalgos/dot.hh>
#include <spot/twaalgos/dualize.hh> #include <spot/twaalgos/dualize.hh>
#include <spot/twaalgos/emptiness.hh> #include <spot/twaalgos/emptiness.hh>
#include <spot/twaalgos/forq_contains.hh>
#include <spot/twaalgos/gtec/gtec.hh> #include <spot/twaalgos/gtec/gtec.hh>
#include <spot/twaalgos/genem.hh> #include <spot/twaalgos/genem.hh>
#include <spot/twaalgos/lbtt.hh> #include <spot/twaalgos/lbtt.hh>
@ -702,6 +703,7 @@ def state_is_accepting(self, src) -> "bool":
%feature("flatnested") spot::twa_run::step; %feature("flatnested") spot::twa_run::step;
%include <spot/twaalgos/emptiness.hh> %include <spot/twaalgos/emptiness.hh>
%template(list_step) std::list<spot::twa_run::step>; %template(list_step) std::list<spot::twa_run::step>;
%include <spot/twaalgos/forq_contains.hh>
%include <spot/twaalgos/gtec/gtec.hh> %include <spot/twaalgos/gtec/gtec.hh>
%include <spot/twaalgos/genem.hh> %include <spot/twaalgos/genem.hh>
%include <spot/twaalgos/lbtt.hh> %include <spot/twaalgos/lbtt.hh>

View file

@ -51,6 +51,7 @@ twaalgos_HEADERS = \
dualize.hh \ dualize.hh \
emptiness.hh \ emptiness.hh \
emptiness_stats.hh \ emptiness_stats.hh \
forq_contains.hh \
game.hh \ game.hh \
genem.hh \ genem.hh \
gfguarantee.hh \ gfguarantee.hh \
@ -124,6 +125,7 @@ libtwaalgos_la_SOURCES = \
dtwasat.cc \ dtwasat.cc \
dualize.cc \ dualize.cc \
emptiness.cc \ emptiness.cc \
forq_contains.cc \
genem.cc \ genem.cc \
gfguarantee.cc \ gfguarantee.cc \
gv04.cc \ gv04.cc \

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,51 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2023 Laboratoire de Recherche et Développement
// de l'Epita. IMDEA Software Institute.
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#pragma once
#include <spot/twa/twagraph.hh>
#include <spot/twaalgos/word.hh>
namespace spot
{
/// \brief Returns a word accepted by \a left that is rejected by \a right,
/// or nullptr.
///
/// This implements the language containment algorithm from
/// \cite{doveriFORQBasedLanguageInclusion2022}
/// to check whether L(left)⊆L(right), in which case, it returns nullptr.
/// Otherwise, it returns a counterexample, i.e., a word that is accepted
/// by $L(left)\setminus L(right)$, hence the name of the function.
///
/// \pre Automata \a left and \a right should be
/// non-alternating state-based Büchi-automata.
SPOT_API twa_word_ptr difference_word_forq(
const_twa_graph_ptr left, spot::const_twa_graph_ptr right);
/// \brief Returns a boolean value indicating
/// whether \a left is included in the language of \a right.
///
/// This implements the language containment algorithm from
/// \cite{doveriFORQBasedLanguageInclusion2022}
/// to check whether L(left)⊆L(right).
///
/// \pre Automata \a left and \a right should be
/// non-alternating state-based Büchi-automata.
SPOT_API bool contains_forq(
const_twa_graph_ptr left, const_twa_graph_ptr right);
}

View file

@ -416,6 +416,7 @@ TESTS_python = \
python/dualize.py \ python/dualize.py \
python/ecfalse.py \ python/ecfalse.py \
python/except.py \ python/except.py \
python/forq_contains.py \
python/game.py \ python/game.py \
python/gen.py \ python/gen.py \
python/genem.py \ python/genem.py \

View file

@ -0,0 +1,327 @@
#!/usr/bin/python3
# -*- mode: python; coding: utf-8 -*-
# Copyright (C) 2017, 2020, 2022 Laboratoire de Recherche et
# Développement de l'EPITA.
#
# This file is part of Spot, a model checking library.
#
# Spot is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# Spot is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
# License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import spot
from unittest import TestCase
tc = TestCase()
def do_test(subset, superset, expected=True):
result = spot.contains_forq(subset, superset)
truth = spot.contains(superset, subset)
tc.assertTrue(truth == expected)
tc.assertTrue(result == truth)
def do_symmetric_test(subset, superset):
do_test(subset, superset, True)
do_test(superset, subset, False)
always_true = spot.automaton("""
HOA: v1
States: 1
Start: 0
acc-name: Buchi
Acceptance: 1 Inf(0)
AP: 2 "a" "b"
--BODY--
State: 0
[t] 0 {0}
--END--""")
one = spot.automaton("""
HOA: v1
States: 2
Start: 0
acc-name: Buchi
Acceptance: 1 Inf(0)
AP: 2 "a" "b"
--BODY--
State: 0
[0|1] 1
State: 1
[0] 1
[!0] 1 {0}
--END--""")
both = spot.automaton("""
HOA: v1
States: 1
Start: 0
acc-name: Buchi
Acceptance: 1 Inf(0)
AP: 2 "a" "b"
--BODY--
State: 0
[0] 0 {0}
[!0] 0 {0}
--END--""")
do_test(both, always_true)
do_test(always_true, both)
do_symmetric_test(one, always_true)
superset = spot.automaton("""
HOA: v1
States: 3
Start: 0
acc-name: Buchi
Acceptance: 1 Inf(0)
AP: 2 "a" "b"
--BODY--
State: 0
[!0|!1] 1
[0 & 1] 2
State: 1
[t] 1 {0}
State: 2
[t] 2 {0}
--END--""")
subset = spot.automaton("""
HOA: v1
States: 3
Start: 0
acc-name: Buchi
Acceptance: 1 Inf(0)
AP: 2 "a" "b"
--BODY--
State: 0
[!0] 1
[!0&1 | 0&!1] 2
State: 1
[t] 1 {0}
State: 2
[t] 2 {0}
--END--""")
do_symmetric_test(subset, superset)
subset = spot.automaton("""
HOA: v1
States: 1
Start: 0
AP: 1 "__ap832"
acc-name: Buchi
Acceptance: 1 Inf(0)
properties: trans-labels explicit-labels state-acc
--BODY--
State: 0 {0}
[!0] 0
--END--""")
superset = spot.automaton("""
HOA: v1
States: 1
Start: 0
AP: 1 "__ap832"
acc-name: Buchi
Acceptance: 1 Inf(0)
properties: trans-labels explicit-labels state-acc
--BODY--
State: 0 {0}
[0] 0
--END--""")
do_test(subset, superset, False)
do_test(superset, subset, False)
subset = spot.automaton("""
HOA: v1
States: 2
Start: 0
acc-name: Buchi
Acceptance: 1 Inf(0)
AP: 2 "a" "b"
--BODY--
State: 0
[!0|!1] 1
State: 1
[t] 1 {0}
--END--""")
superset = spot.automaton("""
HOA: v1
States: 3
Start: 0
acc-name: Buchi
Acceptance: 1 Inf(0)
AP: 2 "a" "b"
--BODY--
State: 0
[!0&1 | !0&!1] 1
[!0&1 | 0&!1] 2
State: 1
[t] 1 {0}
State: 2
[t] 2 {0}
--END--""")
# Equivlent Languages
do_test(subset, superset)
do_test(superset, subset)
superset = spot.automaton("""
HOA: v1
States: 20
Start: 0
AP: 4 "__ap876" "__ap877" "__ap878" "__ap879"
acc-name: Buchi
Acceptance: 1 Inf(0)
properties: trans-labels explicit-labels state-acc
--BODY--
State: 0
[0&!1&2&!3] 1
State: 1
[!0&!1&!2] 2
[!0&1&!2] 3
[!0&1&!2] 4
[!0&!1&!2&!3] 5
[!0&1&!2&!3] 6
State: 2
[!0&!1&!2] 2
[!0&!1&!2&!3] 5
[!0&1&!2&!3] 6
[!0&1&!2] 7
State: 3
[!0&!1&!2] 3
[0&!1&2&!3] 4
State: 4
[!0&!1&!2] 4
[!0&!2&!3] 6
[!0&1&!2] 7
State: 5
[!0&!2&3] 5
[!0&!2&!3] 6
State: 6
[!0&!1&!2&3] 5
[!0&!1&!2&!3 | !0&1&!2&3] 6
[!0&1&!2&!3] 8
State: 7
[!0&!2&!3] 6
[!0&!2] 7
[0&!1&2&!3] 9
State: 8
[!0&!2&3] 6
[!0&!2&!3] 8
[0&!1&2&!3] 10
State: 9
[!0&!2&!3] 6
[!0&!1&!2] 9
[!0&1&!2] 11
State: 10
[!0&!1&!2&!3] 12
[!0&1&!2&!3] 13
State: 11
[!0&!2&!3] 6
[!0&!2] 11
[0&!1&2&!3] 14
State: 12
[!0&!1&!2&!3] 12
[!0&1&!2&!3] 15
State: 13
[0&!1&2&!3] 12
[!0&!1&!2&!3] 13
[!0&1&!2&!3] 15
State: 14
[!0&!1&!2&!3] 6
[!0&1&!2&!3] 8
[!0&!1&!2] 9
[!0&1&!2] 16
State: 15
[!0&!2&!3] 15
[0&!1&2&!3] 17
State: 16
[!0&!1&!2&!3] 6
[!0&1&!2&!3] 8
[!0&!1&!2] 11
[0&!1&2&!3] 14
[!0&1&!2] 16
State: 17
[!0&!1&!2&!3] 17
[!0&1&!2&!3] 18
State: 18
[!0&!2&!3] 18
[0&!1&2&!3] 19
State: 19 {0}
[!0&!1&!2&!3] 17
[!0&1&!2&!3] 18
--END--""")
subset = spot.automaton("""
HOA: v1
States: 12
Start: 0
AP: 4 "__ap876" "__ap877" "__ap878" "__ap879"
acc-name: Buchi
Acceptance: 1 Inf(0)
properties: trans-labels explicit-labels state-acc
--BODY--
State: 0
[0&!1&2&!3] 1
State: 1
[!0&!1&!2&!3] 1
[!0&!1&!2&3] 2
[!0&1&!2&!3] 3
[!0&1&!2&3] 4
State: 2
[!0&!1&!2] 2
[!0&1&!2&3] 4
[!0&1&!2&!3] 5
State: 3
[!0&!2&!3] 3
[!0&!1&!2&3] 4
[!0&1&!2&3] 5
[0&!1&2&!3] 6
State: 4
[!0&!1&!2 | !0&!2&3] 4
[!0&1&!2&!3] 5
State: 5
[!0&!1&!2&3] 4
[!0&1&!2 | !0&!2&!3] 5
[0&!1&2&!3] 7
State: 6
[!0&!1&!2&3] 2
[!0&1&!2&!3] 3
[!0&1&!2&3] 5
[!0&!1&!2&!3] 8
[!0&!1&!2&!3] 9
[!0&1&!2&!3] 10
State: 7
[!0&!1&!2&!3] 1
[!0&!1&!2&3] 2
[!0&1&!2&!3] 3
[!0&1&!2&3] 4
[!0&1&!2&!3] 10
State: 8
[!0&!1&!2&!3] 8
[!0&1&!2&!3] 10
State: 9
[!0&!1&!2&3] 2
[!0&1&!2&!3] 3
[!0&1&!2&3] 5
[!0&!1&!2&!3] 9
State: 10
[!0&!2&!3] 10
[0&!1&2&!3] 11
State: 11 {0}
[!0&!1&!2&!3] 8
[!0&1&!2&!3] 10
--END--""")
do_symmetric_test(subset, superset)