genem: Add yet another version of the algorithm
* spot/twa/acc.hh, spot/twa/acc.cc (fin_unit_one_split_improved): New function. * python/spot/impl.i: Add bindings for fin_unit_one_split_improved. * spot/twaalgos/genem.cc: Add the spot212 version. * tests/python/genem.py: Test it.
This commit is contained in:
parent
747ec8b1c5
commit
134da9209c
5 changed files with 112 additions and 24 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
// -*- coding: utf-8 -*-
|
// -*- coding: utf-8 -*-
|
||||||
// Copyright (C) 2009-2022 Laboratoire de Recherche et Développement
|
// Copyright (C) 2009-2023 Laboratoire de Recherche et Développement
|
||||||
// de l'Epita (LRDE).
|
// de l'Epita (LRDE).
|
||||||
// Copyright (C) 2003-2006 Laboratoire d'Informatique de Paris 6
|
// Copyright (C) 2003-2006 Laboratoire d'Informatique de Paris 6
|
||||||
// (LIP6), département Systèmes Répartis Coopératifs (SRC), Université
|
// (LIP6), département Systèmes Répartis Coopératifs (SRC), Université
|
||||||
|
|
@ -564,6 +564,16 @@ namespace std {
|
||||||
swig::from(std::get<2>(v)));
|
swig::from(std::get<2>(v)));
|
||||||
}
|
}
|
||||||
%}
|
%}
|
||||||
|
// Must occur before the twa declaration
|
||||||
|
%typemap(out) SWIGTYPE spot::acc_cond::fin_unit_one_split_improved %{
|
||||||
|
{
|
||||||
|
auto& v = static_cast<const std::tuple<int, spot::acc_cond, spot::acc_cond>>($1);
|
||||||
|
$result = PyTuple_Pack(3,
|
||||||
|
swig::from(std::get<0>(v)),
|
||||||
|
swig::from(std::get<1>(v)),
|
||||||
|
swig::from(std::get<2>(v)));
|
||||||
|
}
|
||||||
|
%}
|
||||||
|
|
||||||
%include <spot/twa/acc.hh>
|
%include <spot/twa/acc.hh>
|
||||||
%template(pair_bool_mark) std::pair<bool, spot::acc_cond::mark_t>;
|
%template(pair_bool_mark) std::pair<bool, spot::acc_cond::mark_t>;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// -*- coding: utf-8 -*-
|
// -*- coding: utf-8 -*-
|
||||||
// Copyright (C) 2015-2022 Laboratoire de Recherche et Développement
|
// Copyright (C) 2015-2023 Laboratoire de Recherche et Développement
|
||||||
// de l'Epita.
|
// de l'Epita.
|
||||||
//
|
//
|
||||||
// This file is part of Spot, a model checking library.
|
// This file is part of Spot, a model checking library.
|
||||||
|
|
@ -2707,8 +2707,9 @@ namespace spot
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check wheter pos looks like Fin(f) or Fin(f)&rest
|
// Check if pos contains Fin(f) in a substree
|
||||||
bool is_conj_fin(const acc_cond::acc_word* pos, acc_cond::mark_t f)
|
template<bool top_conjunct_only = false>
|
||||||
|
bool has_fin(const acc_cond::acc_word* pos, acc_cond::mark_t f)
|
||||||
{
|
{
|
||||||
auto sub = pos - pos->sub.size;
|
auto sub = pos - pos->sub.size;
|
||||||
do
|
do
|
||||||
|
|
@ -2719,7 +2720,10 @@ namespace spot
|
||||||
--pos;
|
--pos;
|
||||||
break;
|
break;
|
||||||
case acc_cond::acc_op::Or:
|
case acc_cond::acc_op::Or:
|
||||||
|
if constexpr (top_conjunct_only)
|
||||||
pos -= pos->sub.size + 1;
|
pos -= pos->sub.size + 1;
|
||||||
|
else
|
||||||
|
--pos;
|
||||||
break;
|
break;
|
||||||
case acc_cond::acc_op::Fin:
|
case acc_cond::acc_op::Fin:
|
||||||
if (pos[-1].mark & f)
|
if (pos[-1].mark & f)
|
||||||
|
|
@ -2736,6 +2740,12 @@ namespace spot
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check whether pos looks like Fin(f) or Fin(f)&rest
|
||||||
|
bool is_conj_fin(const acc_cond::acc_word* pos, acc_cond::mark_t f)
|
||||||
|
{
|
||||||
|
return has_fin<true>(pos, f);
|
||||||
|
}
|
||||||
|
|
||||||
acc_cond::acc_code extract_fin(const acc_cond::acc_word* pos,
|
acc_cond::acc_code extract_fin(const acc_cond::acc_word* pos,
|
||||||
acc_cond::mark_t f)
|
acc_cond::mark_t f)
|
||||||
{
|
{
|
||||||
|
|
@ -2772,6 +2782,7 @@ namespace spot
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<bool deeper_check = false>
|
||||||
std::pair<acc_cond::acc_code, acc_cond::acc_code>
|
std::pair<acc_cond::acc_code, acc_cond::acc_code>
|
||||||
split_top_fin(const acc_cond::acc_word* pos, acc_cond::mark_t f)
|
split_top_fin(const acc_cond::acc_word* pos, acc_cond::mark_t f)
|
||||||
{
|
{
|
||||||
|
|
@ -2798,6 +2809,17 @@ namespace spot
|
||||||
tmp |= std::move(left);
|
tmp |= std::move(left);
|
||||||
std::swap(tmp, left);
|
std::swap(tmp, left);
|
||||||
}
|
}
|
||||||
|
else if (deeper_check
|
||||||
|
&& has_top_fin(pos) == -1
|
||||||
|
&& has_fin(pos, f))
|
||||||
|
{
|
||||||
|
auto tmp = strip_rec(pos, f, true, false);
|
||||||
|
tmp |= std::move(left);
|
||||||
|
std::swap(tmp, left);
|
||||||
|
tmp = force_inf_rec(pos, f);
|
||||||
|
tmp |= std::move(right);
|
||||||
|
std::swap(tmp, right);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
acc_cond::acc_code tmp(pos);
|
acc_cond::acc_code tmp(pos);
|
||||||
|
|
@ -2851,6 +2873,27 @@ namespace spot
|
||||||
return {selected_fin, extract_fin(pos, fo_m), force_inf(fo_m)};
|
return {selected_fin, extract_fin(pos, fo_m), force_inf(fo_m)};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::tuple<int, acc_cond::acc_code, acc_cond::acc_code>
|
||||||
|
acc_cond::acc_code::fin_unit_one_split_improved() const
|
||||||
|
{
|
||||||
|
if (SPOT_UNLIKELY(is_t() || is_f()))
|
||||||
|
err:
|
||||||
|
throw std::runtime_error("fin_unit_one_split_improved(): no Fin");
|
||||||
|
const acc_cond::acc_word* pos = &back();
|
||||||
|
int selected_fin = has_top_fin(pos);
|
||||||
|
if (selected_fin >= 0)
|
||||||
|
{
|
||||||
|
auto [left, right] =
|
||||||
|
split_top_fin<true>(pos, {(unsigned) selected_fin});
|
||||||
|
return {selected_fin, std::move(left), std::move(right)};
|
||||||
|
}
|
||||||
|
selected_fin = fin_one();
|
||||||
|
if (selected_fin < 0)
|
||||||
|
goto err;
|
||||||
|
acc_cond::mark_t fo_m = {(unsigned) selected_fin};
|
||||||
|
return {selected_fin, extract_fin(pos, fo_m), force_inf(fo_m)};
|
||||||
|
}
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
bool
|
bool
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// -*- coding: utf-8 -*-
|
// -*- coding: utf-8 -*-
|
||||||
// Copyright (C) 2014-2022 Laboratoire de Recherche et Développement
|
// Copyright (C) 2014-2023 Laboratoire de Recherche et Développement
|
||||||
// de l'Epita.
|
// de l'Epita.
|
||||||
//
|
//
|
||||||
// This file is part of Spot, a model checking library.
|
// This file is part of Spot, a model checking library.
|
||||||
|
|
@ -1300,21 +1300,26 @@ namespace spot
|
||||||
/// \brief Split an acceptance condition, trying to select one
|
/// \brief Split an acceptance condition, trying to select one
|
||||||
/// unit-Fin.
|
/// unit-Fin.
|
||||||
///
|
///
|
||||||
/// If the condition is a disjunction and one of the disjunct as
|
/// If the condition is a disjunction and one of the disjunct has
|
||||||
/// has the shape `...&Fin(i)&...`, then this will return
|
/// the shape `...&Fin(i)&...`, then this will return (i, left,
|
||||||
/// (i, left, right), where left is all disjunct of this form, and
|
/// right), where left is all disjunct of this form (with Fin(i)
|
||||||
/// right are all the others.
|
/// replaced by true), and right are all the others.
|
||||||
///
|
///
|
||||||
/// If the input formula has the shape `...&Fin(i)&...` then left
|
/// If the input formula has the shape `...&Fin(i)&...` then left
|
||||||
/// is set to the entire formula, and right is empty.
|
/// is set to the entire formula (with Fin(i) replaced by true),
|
||||||
|
/// and right is empty.
|
||||||
///
|
///
|
||||||
/// If no disjunct has the right shape, then a random Fin(i) is
|
/// If no disjunct has the right shape, then a random Fin(i) is
|
||||||
/// searched in the formula, and the output (i, left, right).
|
/// searched in the formula, and the output (i, left, right).
|
||||||
/// is such that left contains all disjuncts containing Fin(i)
|
/// is such that left contains all disjuncts containing Fin(i)
|
||||||
/// (at any depth), and right contains the original formlula
|
/// (at any depth), and right contains the original formlula
|
||||||
/// where Fin(i) has been replaced by false.
|
/// where Fin(i) has been replaced by false.
|
||||||
|
/// @{
|
||||||
std::tuple<int, acc_cond::acc_code, acc_cond::acc_code>
|
std::tuple<int, acc_cond::acc_code, acc_cond::acc_code>
|
||||||
fin_unit_one_split() const;
|
fin_unit_one_split() const;
|
||||||
|
std::tuple<int, acc_cond::acc_code, acc_cond::acc_code>
|
||||||
|
fin_unit_one_split_improved() const;
|
||||||
|
/// @}
|
||||||
|
|
||||||
/// \brief Help closing accepting or rejecting cycle.
|
/// \brief Help closing accepting or rejecting cycle.
|
||||||
///
|
///
|
||||||
|
|
@ -2258,25 +2263,34 @@ namespace spot
|
||||||
/// \brief Split an acceptance condition, trying to select one
|
/// \brief Split an acceptance condition, trying to select one
|
||||||
/// unit-Fin.
|
/// unit-Fin.
|
||||||
///
|
///
|
||||||
/// If the condition is a disjunction and one of the disjunct as
|
/// If the condition is a disjunction and one of the disjunct has
|
||||||
/// has the shape `...&Fin(i)&...`, then this will return
|
/// the shape `...&Fin(i)&...`, then this will return (i, left,
|
||||||
/// (i, left, right), where left is all disjunct of this form, and
|
/// right), where left is all disjunct of this form (with Fin(i)
|
||||||
/// right are all the others.
|
/// replaced by true), and right are all the others.
|
||||||
///
|
///
|
||||||
/// If the input formula has the shape `...&Fin(i)&...` then left
|
/// If the input formula has the shape `...&Fin(i)&...` then left
|
||||||
/// is set to the entire formula, and right is empty.
|
/// is set to the entire formula (with Fin(i) replaced by true),
|
||||||
|
/// and right is empty.
|
||||||
///
|
///
|
||||||
/// If no disjunct has the right shape, then a random Fin(i) is
|
/// If no disjunct has the right shape, then a random Fin(i) is
|
||||||
/// searched in the formula, and the output (i, left, right).
|
/// searched in the formula, and the output (i, left, right).
|
||||||
/// is such that left contains all disjuncts containing Fin(i)
|
/// is such that left contains all disjuncts containing Fin(i)
|
||||||
/// (at any depth), and right contains the original formlula
|
/// (at any depth), and right contains the original formlula
|
||||||
/// where Fin(i) has been replaced by false.
|
/// where Fin(i) has been replaced by false.
|
||||||
|
/// @{
|
||||||
std::tuple<int, acc_cond, acc_cond>
|
std::tuple<int, acc_cond, acc_cond>
|
||||||
fin_unit_one_split() const
|
fin_unit_one_split() const
|
||||||
{
|
{
|
||||||
auto [f, l, r] = code_.fin_unit_one_split();
|
auto [f, l, r] = code_.fin_unit_one_split();
|
||||||
return {f, {num_sets(), std::move(l)}, {num_sets(), std::move(r)}};
|
return {f, {num_sets(), std::move(l)}, {num_sets(), std::move(r)}};
|
||||||
}
|
}
|
||||||
|
std::tuple<int, acc_cond, acc_cond>
|
||||||
|
fin_unit_one_split_improved() const
|
||||||
|
{
|
||||||
|
auto [f, l, r] = code_.fin_unit_one_split_improved();
|
||||||
|
return {f, {num_sets(), std::move(l)}, {num_sets(), std::move(r)}};
|
||||||
|
}
|
||||||
|
/// @}
|
||||||
|
|
||||||
/// \brief Return the top-level disjuncts.
|
/// \brief Return the top-level disjuncts.
|
||||||
///
|
///
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// -*- coding: utf-8 -*-
|
// -*- coding: utf-8 -*-
|
||||||
// Copyright (C) 2017-2022 Laboratoire de Recherche et Developpement
|
// Copyright (C) 2017-2023 Laboratoire de Recherche et Developpement
|
||||||
// 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.
|
||||||
|
|
@ -25,7 +25,7 @@ namespace spot
|
||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
enum genem_version_t { spot28, atva19, spot29, spot210, spot211 };
|
enum genem_version_t { spot28, atva19, spot29, spot210, spot211, spot212 };
|
||||||
static genem_version_t genem_version = spot29;
|
static genem_version_t genem_version = spot29;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -33,6 +33,8 @@ namespace spot
|
||||||
{
|
{
|
||||||
if (emversion == nullptr || !strcasecmp(emversion, "spot29"))
|
if (emversion == nullptr || !strcasecmp(emversion, "spot29"))
|
||||||
genem_version = spot29;
|
genem_version = spot29;
|
||||||
|
else if (!strcasecmp(emversion, "spot212"))
|
||||||
|
genem_version = spot212;
|
||||||
else if (!strcasecmp(emversion, "spot211"))
|
else if (!strcasecmp(emversion, "spot211"))
|
||||||
genem_version = spot211;
|
genem_version = spot211;
|
||||||
else if (!strcasecmp(emversion, "spot210"))
|
else if (!strcasecmp(emversion, "spot210"))
|
||||||
|
|
@ -44,7 +46,7 @@ namespace spot
|
||||||
else
|
else
|
||||||
throw std::invalid_argument("generic_emptiness_check version should be "
|
throw std::invalid_argument("generic_emptiness_check version should be "
|
||||||
"one of {spot28, atva19, spot29, spot210, "
|
"one of {spot28, atva19, spot29, spot210, "
|
||||||
"spot211}");
|
"spot211, spot212}");
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
|
|
@ -87,7 +89,9 @@ namespace spot
|
||||||
scc_split_check(const scc_info& si, unsigned scc, const acc_cond& acc,
|
scc_split_check(const scc_info& si, unsigned scc, const acc_cond& acc,
|
||||||
Extra extra, acc_cond::mark_t tocut)
|
Extra extra, acc_cond::mark_t tocut)
|
||||||
{
|
{
|
||||||
if (genem_version == spot211 || genem_version == spot210)
|
if (genem_version == spot211
|
||||||
|
|| genem_version == spot212
|
||||||
|
|| genem_version == spot210)
|
||||||
tocut |= acc.fin_unit();
|
tocut |= acc.fin_unit();
|
||||||
scc_and_mark_filter filt(si, scc, tocut);
|
scc_and_mark_filter filt(si, scc, tocut);
|
||||||
filt.override_acceptance(acc);
|
filt.override_acceptance(acc);
|
||||||
|
|
@ -144,6 +148,20 @@ namespace spot
|
||||||
}
|
}
|
||||||
while (!acc.is_f());
|
while (!acc.is_f());
|
||||||
}
|
}
|
||||||
|
else if (genem_version == spot212)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
auto [fo, fpart, rest] = acc.fin_unit_one_split_improved();
|
||||||
|
acc_cond::mark_t fo_m = {(unsigned) fo};
|
||||||
|
if (!scc_split_check<EarlyStop, Extra>
|
||||||
|
(si, scc, fpart, extra, fo_m))
|
||||||
|
if constexpr (EarlyStop)
|
||||||
|
return false;
|
||||||
|
acc = rest;
|
||||||
|
}
|
||||||
|
while (!acc.is_f());
|
||||||
|
}
|
||||||
else if (genem_version == spot29)
|
else if (genem_version == spot29)
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
# -*- mode: python; coding: utf-8 -*-
|
# -*- mode: python; coding: utf-8 -*-
|
||||||
# Copyright (C) 2018-2022 Laboratoire de Recherche et Développement de
|
# Copyright (C) 2018-2023 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.
|
||||||
|
|
@ -307,15 +307,18 @@ def run_bench(automata):
|
||||||
res3d = spot.generic_emptiness_check(aut)
|
res3d = spot.generic_emptiness_check(aut)
|
||||||
spot.generic_emptiness_check_select_version("spot211")
|
spot.generic_emptiness_check_select_version("spot211")
|
||||||
res3e = spot.generic_emptiness_check(aut)
|
res3e = spot.generic_emptiness_check(aut)
|
||||||
|
spot.generic_emptiness_check_select_version("spot212")
|
||||||
|
res3f = spot.generic_emptiness_check(aut)
|
||||||
spot.generic_emptiness_check_select_version("spot29")
|
spot.generic_emptiness_check_select_version("spot29")
|
||||||
res2 = spot.remove_fin(aut).is_empty()
|
res2 = spot.remove_fin(aut).is_empty()
|
||||||
res1 = generic_emptiness2(aut)
|
res1 = generic_emptiness2(aut)
|
||||||
res = (str(res1)[0] + str(res2)[0] + str(res3a)[0]
|
res = (str(res1)[0] + str(res2)[0] + str(res3a)[0]
|
||||||
+ str(res3b)[0] + str(res3c)[0] + str(res3d)[0]
|
+ str(res3b)[0] + str(res3c)[0] + str(res3d)[0]
|
||||||
+ str(res3e)[0] + str(res4)[0] + str(res5)[0])
|
+ str(res3e)[0] + str(res3f)[0] + str(res4)[0]
|
||||||
|
+ str(res5)[0])
|
||||||
print(res)
|
print(res)
|
||||||
tc.assertIn(res, ('TTTTTTTTT', 'FFFFFFFFF'))
|
tc.assertIn(res, ('TTTTTTTTTT', 'FFFFFFFFFF'))
|
||||||
if res == 'FFFFFFFFF':
|
if res == 'FFFFFFFFFF':
|
||||||
run3 = spot.generic_accepting_run(aut)
|
run3 = spot.generic_accepting_run(aut)
|
||||||
tc.assertTrue(run3.replay(spot.get_cout()))
|
tc.assertTrue(run3.replay(spot.get_cout()))
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue