Moved IAR and the new version of to_parity in toparity.cc
* python/spot/__init__.py: Use keyword arguments in to_parity() * python/spot/impl.i: remove useless includes. * spot/twaalgos/car.cc, spot/twaalgos/car.hh, spot/twaalgos/rabin2parity.cc, spot/twaalgos/rabin2parity.hh, tests/Makefile.am, spot/twaalgos/Makefile.am: content moved to toparity. * spot/twaalgos/postproc.cc: Use the new version of to_parity in postprocessor::run. * spot/twaalgos/toparity.cc, spot/twaalgos/toparity.hh: Add the content of rabin2parity and car. * tests/python/car.py, tests/python/toparity.py: Moved all tests from car.py to toparity.py. * tests/python/except.py: Change iar() to iar_old().
This commit is contained in:
parent
dddc7920e4
commit
75990063f0
14 changed files with 2027 additions and 2105 deletions
|
|
@ -1290,3 +1290,30 @@ class scc_and_mark_filter:
|
||||||
|
|
||||||
def __exit__(self, exc_type, exc_value, traceback):
|
def __exit__(self, exc_type, exc_value, traceback):
|
||||||
self.restore_acceptance()
|
self.restore_acceptance()
|
||||||
|
|
||||||
|
|
||||||
|
def to_parity(aut, **kwargs):
|
||||||
|
option = car_option()
|
||||||
|
if "search_ex" in kwargs:
|
||||||
|
option.search_ex = kwargs.get("search_ex")
|
||||||
|
if "use_last" in kwargs:
|
||||||
|
option.use_last = kwargs.get("use_last")
|
||||||
|
if "force_order" in kwargs:
|
||||||
|
option.force_order = kwargs.get("force_order")
|
||||||
|
if "partial_degen" in kwargs:
|
||||||
|
option.partial_degen = kwargs.get("partial_degen")
|
||||||
|
if "acc_clean" in kwargs:
|
||||||
|
option.acc_clean = kwargs.get("acc_clean")
|
||||||
|
if "parity_equiv" in kwargs:
|
||||||
|
option.parity_equiv = kwargs.get("parity_equiv")
|
||||||
|
if "parity_prefix" in kwargs:
|
||||||
|
option.parity_prefix = kwargs.get("parity_prefix")
|
||||||
|
if "rabin_to_buchi" in kwargs:
|
||||||
|
option.rabin_to_buchi = kwargs.get("rabin_to_buchi")
|
||||||
|
if "reduce_col_deg" in kwargs:
|
||||||
|
option.reduce_col_deg = kwargs.get("reduce_col_deg")
|
||||||
|
if "propagate_col" in kwargs:
|
||||||
|
option.propagate_col = kwargs.get("propagate_col")
|
||||||
|
if "pretty_print" in kwargs:
|
||||||
|
option.pretty_print = kwargs.get("pretty_print")
|
||||||
|
return impl.to_parity(aut, option)
|
||||||
|
|
|
||||||
|
|
@ -160,9 +160,7 @@
|
||||||
#include <spot/twaalgos/relabel.hh>
|
#include <spot/twaalgos/relabel.hh>
|
||||||
#include <spot/twaalgos/word.hh>
|
#include <spot/twaalgos/word.hh>
|
||||||
#include <spot/twaalgos/are_isomorphic.hh>
|
#include <spot/twaalgos/are_isomorphic.hh>
|
||||||
#include <spot/twaalgos/rabin2parity.hh>
|
|
||||||
#include <spot/twaalgos/toparity.hh>
|
#include <spot/twaalgos/toparity.hh>
|
||||||
#include <spot/twaalgos/car.hh>
|
|
||||||
|
|
||||||
#include <spot/parseaut/public.hh>
|
#include <spot/parseaut/public.hh>
|
||||||
|
|
||||||
|
|
@ -682,9 +680,7 @@ def state_is_accepting(self, src) -> "bool":
|
||||||
%include <spot/twaalgos/word.hh>
|
%include <spot/twaalgos/word.hh>
|
||||||
%template(list_bdd) std::list<bdd>;
|
%template(list_bdd) std::list<bdd>;
|
||||||
%include <spot/twaalgos/are_isomorphic.hh>
|
%include <spot/twaalgos/are_isomorphic.hh>
|
||||||
%include <spot/twaalgos/rabin2parity.hh>
|
|
||||||
%include <spot/twaalgos/toparity.hh>
|
%include <spot/twaalgos/toparity.hh>
|
||||||
%include <spot/twaalgos/car.hh>
|
|
||||||
|
|
||||||
%pythonprepend spot::twa::dtwa_complement %{
|
%pythonprepend spot::twa::dtwa_complement %{
|
||||||
from warnings import warn
|
from warnings import warn
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,6 @@ twaalgos_HEADERS = \
|
||||||
isunamb.hh \
|
isunamb.hh \
|
||||||
isweakscc.hh \
|
isweakscc.hh \
|
||||||
langmap.hh \
|
langmap.hh \
|
||||||
car.hh \
|
|
||||||
lbtt.hh \
|
lbtt.hh \
|
||||||
ltl2taa.hh \
|
ltl2taa.hh \
|
||||||
ltl2tgba_fm.hh \
|
ltl2tgba_fm.hh \
|
||||||
|
|
@ -72,7 +71,6 @@ twaalgos_HEADERS = \
|
||||||
postproc.hh \
|
postproc.hh \
|
||||||
powerset.hh \
|
powerset.hh \
|
||||||
product.hh \
|
product.hh \
|
||||||
rabin2parity.hh \
|
|
||||||
randomgraph.hh \
|
randomgraph.hh \
|
||||||
randomize.hh \
|
randomize.hh \
|
||||||
reachiter.hh \
|
reachiter.hh \
|
||||||
|
|
@ -129,7 +127,6 @@ libtwaalgos_la_SOURCES = \
|
||||||
isunamb.cc \
|
isunamb.cc \
|
||||||
isweakscc.cc \
|
isweakscc.cc \
|
||||||
langmap.cc \
|
langmap.cc \
|
||||||
car.cc \
|
|
||||||
lbtt.cc \
|
lbtt.cc \
|
||||||
ltl2taa.cc \
|
ltl2taa.cc \
|
||||||
ltl2tgba_fm.cc \
|
ltl2tgba_fm.cc \
|
||||||
|
|
@ -143,7 +140,6 @@ libtwaalgos_la_SOURCES = \
|
||||||
postproc.cc \
|
postproc.cc \
|
||||||
powerset.cc \
|
powerset.cc \
|
||||||
product.cc \
|
product.cc \
|
||||||
rabin2parity.cc \
|
|
||||||
randomgraph.cc \
|
randomgraph.cc \
|
||||||
randomize.cc \
|
randomize.cc \
|
||||||
reachiter.cc \
|
reachiter.cc \
|
||||||
|
|
|
||||||
1291
spot/twaalgos/car.cc
1291
spot/twaalgos/car.cc
File diff suppressed because it is too large
Load diff
|
|
@ -1,69 +0,0 @@
|
||||||
// -*- coding: utf-8 -*-
|
|
||||||
// Copyright (C) 2012-2019 Laboratoire de Recherche
|
|
||||||
// et Développement de l'Epita (LRDE).
|
|
||||||
//
|
|
||||||
// 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>
|
|
||||||
|
|
||||||
namespace spot
|
|
||||||
{
|
|
||||||
struct car_option
|
|
||||||
{
|
|
||||||
bool search_ex = true;
|
|
||||||
bool use_last = true;
|
|
||||||
bool force_order = true;
|
|
||||||
bool partial_degen = true;
|
|
||||||
bool acc_clean = true;
|
|
||||||
bool parity_equiv = true;
|
|
||||||
bool parity_prefix = true;
|
|
||||||
bool rabin_to_buchi = true;
|
|
||||||
bool reduce_col_deg = false;
|
|
||||||
bool propagate_col = true;
|
|
||||||
bool pretty_print = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// \ingroup twa_acc_transform
|
|
||||||
/// \brief Take an automaton with any acceptance condition and return an
|
|
||||||
/// equivalent parity automaton.
|
|
||||||
///
|
|
||||||
/// The parity condition of the returned automaton is max even or
|
|
||||||
/// max odd.
|
|
||||||
/// If \a search_ex is true, when we move several elements, we
|
|
||||||
/// try to find an order such that the new permutation already exists.
|
|
||||||
/// If \a partial_degen is true, we apply a partial degeneralization to remove
|
|
||||||
// occurences of Fin | Fin and Inf & Inf.
|
|
||||||
/// If \a scc_acc_clean is true, we remove for each SCC the colors that don't
|
|
||||||
// appear.
|
|
||||||
/// If \a parity_equiv is true, we check if there exists a permutations of
|
|
||||||
// colors such that the acceptance
|
|
||||||
/// condition is a partity condition.
|
|
||||||
/// If \a use_last is true, we use the most recent state when looking for an
|
|
||||||
// existing state.
|
|
||||||
/// If \a pretty_print is true, we give a name to the states describing the
|
|
||||||
// state of the aut_ and the permutation.
|
|
||||||
|
|
||||||
SPOT_API twa_graph_ptr
|
|
||||||
remove_false_transitions(const twa_graph_ptr a);
|
|
||||||
|
|
||||||
SPOT_API twa_graph_ptr
|
|
||||||
to_parity(const twa_graph_ptr &aut, const car_option options = car_option());
|
|
||||||
|
|
||||||
} // namespace spot
|
|
||||||
|
|
@ -38,8 +38,8 @@
|
||||||
#include <spot/twaalgos/alternation.hh>
|
#include <spot/twaalgos/alternation.hh>
|
||||||
#include <spot/twaalgos/parity.hh>
|
#include <spot/twaalgos/parity.hh>
|
||||||
#include <spot/twaalgos/cobuchi.hh>
|
#include <spot/twaalgos/cobuchi.hh>
|
||||||
#include <spot/twaalgos/rabin2parity.hh>
|
|
||||||
#include <spot/twaalgos/cleanacc.hh>
|
#include <spot/twaalgos/cleanacc.hh>
|
||||||
|
#include <spot/twaalgos/toparity.hh>
|
||||||
|
|
||||||
namespace spot
|
namespace spot
|
||||||
{
|
{
|
||||||
|
|
@ -280,7 +280,7 @@ namespace spot
|
||||||
twa_graph_ptr b = nullptr;
|
twa_graph_ptr b = nullptr;
|
||||||
if (want_parity && is_deterministic(a) &&
|
if (want_parity && is_deterministic(a) &&
|
||||||
!a->acc().is_generalized_buchi())
|
!a->acc().is_generalized_buchi())
|
||||||
b = iar_maybe(a);
|
b = to_parity(a);
|
||||||
// possible only if a was deterministic and (Rabin-like or Streett-like)
|
// possible only if a was deterministic and (Rabin-like or Streett-like)
|
||||||
// and we want parity and a is not a TGBA
|
// and we want parity and a is not a TGBA
|
||||||
// NB: on a TGBA, degeneralization is better than IAR
|
// NB: on a TGBA, degeneralization is better than IAR
|
||||||
|
|
|
||||||
|
|
@ -1,361 +0,0 @@
|
||||||
// -*- coding: utf-8 -*-
|
|
||||||
// Copyright (C) 2017-2019 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/>.
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include <deque>
|
|
||||||
#include <spot/twaalgos/rabin2parity.hh>
|
|
||||||
#include <spot/twaalgos/sccinfo.hh>
|
|
||||||
|
|
||||||
namespace spot
|
|
||||||
{
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
|
|
||||||
using perm_t = std::vector<unsigned>;
|
|
||||||
struct iar_state
|
|
||||||
{
|
|
||||||
unsigned state;
|
|
||||||
perm_t perm;
|
|
||||||
|
|
||||||
bool
|
|
||||||
operator<(const iar_state& other) const
|
|
||||||
{
|
|
||||||
return state == other.state ? perm < other.perm : state < other.state;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<bool is_rabin>
|
|
||||||
class iar_generator
|
|
||||||
{
|
|
||||||
// helper functions: access fin and inf parts of the pairs
|
|
||||||
// these functions negate the Streett condition to see it as a Rabin one
|
|
||||||
const acc_cond::mark_t&
|
|
||||||
fin(unsigned k) const
|
|
||||||
{
|
|
||||||
if (is_rabin)
|
|
||||||
return pairs_[k].fin;
|
|
||||||
else
|
|
||||||
return pairs_[k].inf;
|
|
||||||
}
|
|
||||||
acc_cond::mark_t
|
|
||||||
inf(unsigned k) const
|
|
||||||
{
|
|
||||||
if (is_rabin)
|
|
||||||
return pairs_[k].inf;
|
|
||||||
else
|
|
||||||
return pairs_[k].fin;
|
|
||||||
}
|
|
||||||
public:
|
|
||||||
explicit iar_generator(const const_twa_graph_ptr& a,
|
|
||||||
const std::vector<acc_cond::rs_pair>& p,
|
|
||||||
const bool pretty_print)
|
|
||||||
: aut_(a)
|
|
||||||
, pairs_(p)
|
|
||||||
, scc_(scc_info(a))
|
|
||||||
, pretty_print_(pretty_print)
|
|
||||||
, state2pos_iar_states(aut_->num_states(), -1U)
|
|
||||||
{}
|
|
||||||
|
|
||||||
twa_graph_ptr
|
|
||||||
run()
|
|
||||||
{
|
|
||||||
res_ = make_twa_graph(aut_->get_dict());
|
|
||||||
res_->copy_ap_of(aut_);
|
|
||||||
|
|
||||||
build_iar_scc(scc_.initial());
|
|
||||||
|
|
||||||
{
|
|
||||||
// resulting automaton has acceptance condition: parity max odd
|
|
||||||
// for Rabin-like input and parity max even for Streett-like input.
|
|
||||||
// with priorities ranging from 0 to 2*(nb pairs)
|
|
||||||
// /!\ priorities are shifted by -1 compared to the original paper
|
|
||||||
unsigned sets = 2 * pairs_.size() + 1;
|
|
||||||
res_->set_acceptance(sets, acc_cond::acc_code::parity_max(is_rabin,
|
|
||||||
sets));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
unsigned s = iar2num.at(state2iar.at(aut_->get_init_state_number()));
|
|
||||||
res_->set_init_state(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
// there could be quite a number of unreachable states, prune them
|
|
||||||
res_->purge_unreachable_states();
|
|
||||||
|
|
||||||
if (pretty_print_)
|
|
||||||
{
|
|
||||||
unsigned nstates = res_->num_states();
|
|
||||||
auto names = new std::vector<std::string>(nstates);
|
|
||||||
for (auto e : res_->edges())
|
|
||||||
{
|
|
||||||
unsigned s = e.src;
|
|
||||||
iar_state iar = num2iar.at(s);
|
|
||||||
std::ostringstream st;
|
|
||||||
st << iar.state << ' ';
|
|
||||||
if (iar.perm.empty())
|
|
||||||
st << '[';
|
|
||||||
char sep = '[';
|
|
||||||
for (unsigned h: iar.perm)
|
|
||||||
{
|
|
||||||
st << sep << h;
|
|
||||||
sep = ',';
|
|
||||||
}
|
|
||||||
st << ']';
|
|
||||||
(*names)[s] = st.str();
|
|
||||||
}
|
|
||||||
res_->set_named_prop("state-names", names);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
build_iar_scc(unsigned scc_num)
|
|
||||||
{
|
|
||||||
// we are working on an SCC: the state we start from does not matter
|
|
||||||
unsigned init = scc_.one_state_of(scc_num);
|
|
||||||
|
|
||||||
std::deque<iar_state> todo;
|
|
||||||
auto get_state = [&](const iar_state& s)
|
|
||||||
{
|
|
||||||
auto it = iar2num.find(s);
|
|
||||||
if (it == iar2num.end())
|
|
||||||
{
|
|
||||||
unsigned nb = res_->new_state();
|
|
||||||
iar2num[s] = nb;
|
|
||||||
num2iar[nb] = s;
|
|
||||||
unsigned iar_pos = iar_states.size();
|
|
||||||
unsigned old_newest_pos = state2pos_iar_states[s.state];
|
|
||||||
state2pos_iar_states[s.state] = iar_pos;
|
|
||||||
iar_states.push_back(
|
|
||||||
std::pair<iar_state, unsigned>(s, old_newest_pos));
|
|
||||||
todo.push_back(s);
|
|
||||||
return nb;
|
|
||||||
}
|
|
||||||
return it->second;
|
|
||||||
};
|
|
||||||
|
|
||||||
auto get_other_scc = [this](unsigned state)
|
|
||||||
{
|
|
||||||
auto it = state2iar.find(state);
|
|
||||||
// recursively build the destination SCC if we detect that it has
|
|
||||||
// not been already built.
|
|
||||||
if (it == state2iar.end())
|
|
||||||
build_iar_scc(scc_.scc_of(state));
|
|
||||||
return iar2num.at(state2iar.at(state));
|
|
||||||
};
|
|
||||||
|
|
||||||
if (scc_.is_trivial(scc_num))
|
|
||||||
{
|
|
||||||
iar_state iar_s{init, perm_t()};
|
|
||||||
state2iar[init] = iar_s;
|
|
||||||
unsigned src_num = get_state(iar_s);
|
|
||||||
// Do not forget to connect to subsequent SCCs
|
|
||||||
for (const auto& e : aut_->out(init))
|
|
||||||
res_->new_edge(src_num, get_other_scc(e.dst), e.cond);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// determine the pairs that appear in the SCC
|
|
||||||
auto colors = scc_.acc_sets_of(scc_num);
|
|
||||||
std::set<unsigned> scc_pairs;
|
|
||||||
for (unsigned k = 0; k != pairs_.size(); ++k)
|
|
||||||
if (!inf(k) || (colors & (pairs_[k].fin | pairs_[k].inf)))
|
|
||||||
scc_pairs.insert(k);
|
|
||||||
|
|
||||||
perm_t p0;
|
|
||||||
for (unsigned k : scc_pairs)
|
|
||||||
p0.push_back(k);
|
|
||||||
|
|
||||||
iar_state s0{init, p0};
|
|
||||||
get_state(s0); // put s0 in todo
|
|
||||||
|
|
||||||
// the main loop
|
|
||||||
while (!todo.empty())
|
|
||||||
{
|
|
||||||
iar_state current = todo.front();
|
|
||||||
todo.pop_front();
|
|
||||||
|
|
||||||
unsigned src_num = get_state(current);
|
|
||||||
|
|
||||||
for (const auto& e : aut_->out(current.state))
|
|
||||||
{
|
|
||||||
// connect to the appropriate state
|
|
||||||
if (scc_.scc_of(e.dst) != scc_num)
|
|
||||||
res_->new_edge(src_num, get_other_scc(e.dst), e.cond);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// find the new permutation
|
|
||||||
perm_t new_perm = current.perm;
|
|
||||||
// Count pairs whose fin-part is seen on this transition
|
|
||||||
unsigned seen_nb = 0;
|
|
||||||
// consider the pairs for this SCC only
|
|
||||||
for (unsigned k : scc_pairs)
|
|
||||||
if (e.acc & fin(k))
|
|
||||||
{
|
|
||||||
++seen_nb;
|
|
||||||
auto it = std::find(new_perm.begin(),
|
|
||||||
new_perm.end(),
|
|
||||||
k);
|
|
||||||
// move the pair in front of the permutation
|
|
||||||
std::rotate(new_perm.begin(), it, it+1);
|
|
||||||
}
|
|
||||||
|
|
||||||
iar_state dst;
|
|
||||||
unsigned dst_num = -1U;
|
|
||||||
|
|
||||||
// Optimization: when several indices are seen in the
|
|
||||||
// transition, they move at the front of new_perm in any
|
|
||||||
// order. Check whether there already exists an iar_state
|
|
||||||
// that matches this condition.
|
|
||||||
|
|
||||||
auto iar_pos = state2pos_iar_states[e.dst];
|
|
||||||
while (iar_pos != -1U)
|
|
||||||
{
|
|
||||||
iar_state& tmp = iar_states[iar_pos].first;
|
|
||||||
iar_pos = iar_states[iar_pos].second;
|
|
||||||
if (std::equal(new_perm.begin() + seen_nb,
|
|
||||||
new_perm.end(),
|
|
||||||
tmp.perm.begin() + seen_nb))
|
|
||||||
{
|
|
||||||
dst = tmp;
|
|
||||||
dst_num = iar2num[dst];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// if such a state was not found, build it
|
|
||||||
if (dst_num == -1U)
|
|
||||||
{
|
|
||||||
dst = iar_state{e.dst, new_perm};
|
|
||||||
dst_num = get_state(dst);
|
|
||||||
}
|
|
||||||
|
|
||||||
// find the maximal index encountered by this transition
|
|
||||||
unsigned maxint = -1U;
|
|
||||||
for (int k = current.perm.size() - 1; k >= 0; --k)
|
|
||||||
{
|
|
||||||
unsigned pk = current.perm[k];
|
|
||||||
if (!inf(pk) ||
|
|
||||||
(e.acc & (pairs_[pk].fin | pairs_[pk].inf))) {
|
|
||||||
maxint = k;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
acc_cond::mark_t acc = {};
|
|
||||||
if (maxint == -1U)
|
|
||||||
acc = {0};
|
|
||||||
else if (e.acc & fin(current.perm[maxint]))
|
|
||||||
acc = {2*maxint+2};
|
|
||||||
else
|
|
||||||
acc = {2*maxint+1};
|
|
||||||
|
|
||||||
res_->new_edge(src_num, dst_num, e.cond, acc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optimization: find the bottom SCC of the sub-automaton we have just
|
|
||||||
// built. To that end, we have to ignore edges going out of scc_num.
|
|
||||||
auto leaving_edge = [&](unsigned d)
|
|
||||||
{
|
|
||||||
return scc_.scc_of(num2iar.at(d).state) != scc_num;
|
|
||||||
};
|
|
||||||
auto filter_edge = [](const twa_graph::edge_storage_t&,
|
|
||||||
unsigned dst,
|
|
||||||
void* filter_data)
|
|
||||||
{
|
|
||||||
decltype(leaving_edge)* data =
|
|
||||||
static_cast<decltype(leaving_edge)*>(filter_data);
|
|
||||||
|
|
||||||
if ((*data)(dst))
|
|
||||||
return scc_info::edge_filter_choice::ignore;
|
|
||||||
return scc_info::edge_filter_choice::keep;
|
|
||||||
};
|
|
||||||
scc_info sub_scc(res_, get_state(s0), filter_edge, &leaving_edge);
|
|
||||||
// SCCs are numbered in reverse topological order, so the bottom SCC has
|
|
||||||
// index 0.
|
|
||||||
const unsigned bscc = 0;
|
|
||||||
assert(sub_scc.succ(0).empty());
|
|
||||||
assert(
|
|
||||||
[&]()
|
|
||||||
{
|
|
||||||
for (unsigned s = 1; s != sub_scc.scc_count(); ++s)
|
|
||||||
if (sub_scc.succ(s).empty())
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
} ());
|
|
||||||
|
|
||||||
assert(sub_scc.states_of(bscc).size()
|
|
||||||
>= scc_.states_of(scc_num).size());
|
|
||||||
|
|
||||||
// update state2iar
|
|
||||||
for (unsigned scc_state : sub_scc.states_of(bscc))
|
|
||||||
{
|
|
||||||
iar_state& iar = num2iar.at(scc_state);
|
|
||||||
if (state2iar.find(iar.state) == state2iar.end())
|
|
||||||
state2iar[iar.state] = iar;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
const const_twa_graph_ptr& aut_;
|
|
||||||
const std::vector<acc_cond::rs_pair>& pairs_;
|
|
||||||
const scc_info scc_;
|
|
||||||
twa_graph_ptr res_;
|
|
||||||
bool pretty_print_;
|
|
||||||
|
|
||||||
// to be used when entering a new SCC
|
|
||||||
// maps a state of aut_ onto an iar_state with the appropriate perm
|
|
||||||
std::map<unsigned, iar_state> state2iar;
|
|
||||||
|
|
||||||
std::map<iar_state, unsigned> iar2num;
|
|
||||||
std::map<unsigned, iar_state> num2iar;
|
|
||||||
|
|
||||||
std::vector<unsigned> state2pos_iar_states;
|
|
||||||
std::vector<std::pair<iar_state, unsigned>> iar_states;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
twa_graph_ptr
|
|
||||||
iar_maybe(const const_twa_graph_ptr& aut, bool pretty_print)
|
|
||||||
{
|
|
||||||
std::vector<acc_cond::rs_pair> pairs;
|
|
||||||
if (!aut->acc().is_rabin_like(pairs))
|
|
||||||
if (!aut->acc().is_streett_like(pairs))
|
|
||||||
return nullptr;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
iar_generator<false> gen(aut, pairs, pretty_print);
|
|
||||||
return gen.run();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
iar_generator<true> gen(aut, pairs, pretty_print);
|
|
||||||
return gen.run();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
twa_graph_ptr
|
|
||||||
iar(const const_twa_graph_ptr& aut, bool pretty_print)
|
|
||||||
{
|
|
||||||
if (auto res = iar_maybe(aut, pretty_print))
|
|
||||||
return res;
|
|
||||||
throw std::runtime_error("iar() expects Rabin-like or Streett-like input");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
||||||
// -*- coding: utf-8 -*-
|
|
||||||
// Copyright (C) 2017-2018 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/>.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <spot/twa/twagraph.hh>
|
|
||||||
|
|
||||||
namespace spot
|
|
||||||
{
|
|
||||||
/// \ingroup twa_acc_transform
|
|
||||||
/// \brief Turn a Rabin-like or Streett-like automaton into a parity automaton
|
|
||||||
/// based on the index appearence record (IAR)
|
|
||||||
///
|
|
||||||
/// If the input automaton has n states and k pairs, the output automaton has
|
|
||||||
/// at most k!*n states and 2k+1 colors. If the input automaton is
|
|
||||||
/// deterministic, the output automaton is deterministic as well, which is the
|
|
||||||
/// intended use case for this function. If the input automaton is
|
|
||||||
/// non-deterministic, the result is still correct, but way larger than an
|
|
||||||
/// equivalent Büchi automaton.
|
|
||||||
/// If the input automaton is Rabin-like (resp. Streett-like), the output
|
|
||||||
/// automaton has max odd (resp. min even) acceptance condition.
|
|
||||||
/// Details on the algorithm can be found in:
|
|
||||||
/// https://arxiv.org/pdf/1701.05738.pdf (published at TACAS 2017)
|
|
||||||
///
|
|
||||||
/// Throws an std::runtime_error if the input is neither Rabin-like nor
|
|
||||||
/// Street-like.
|
|
||||||
SPOT_API
|
|
||||||
twa_graph_ptr
|
|
||||||
iar(const const_twa_graph_ptr& aut, bool pretty_print = false);
|
|
||||||
|
|
||||||
/// \ingroup twa_acc_transform
|
|
||||||
/// \brief Turn a Rabin-like or Streett-like automaton into a parity automaton
|
|
||||||
/// based on the index appearence record (IAR)
|
|
||||||
///
|
|
||||||
/// Returns nullptr if the input automaton is neither Rabin-like nor
|
|
||||||
/// Streett-like, and calls spot::iar() otherwise.
|
|
||||||
SPOT_API
|
|
||||||
twa_graph_ptr
|
|
||||||
iar_maybe(const const_twa_graph_ptr& aut, bool pretty_print = false);
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +1,6 @@
|
||||||
// -*- coding: utf-8 -*-
|
// -*- coding: utf-8 -*-
|
||||||
// Copyright (C) 2018 Laboratoire de Recherche et Développement
|
// Copyright (C) 2012-2020 Laboratoire de Recherche et Développement
|
||||||
// de l'Epita.
|
// de l'Epita (LRDE).
|
||||||
//
|
//
|
||||||
// This file is part of Spot, a model checking library.
|
// This file is part of Spot, a model checking library.
|
||||||
//
|
//
|
||||||
|
|
@ -23,11 +23,91 @@
|
||||||
|
|
||||||
namespace spot
|
namespace spot
|
||||||
{
|
{
|
||||||
|
// The version that combines CAR, IAR and multiple optimizations.
|
||||||
|
struct car_option
|
||||||
|
{
|
||||||
|
bool search_ex = true;
|
||||||
|
bool use_last = true;
|
||||||
|
bool force_order = true;
|
||||||
|
bool partial_degen = true;
|
||||||
|
bool acc_clean = true;
|
||||||
|
bool parity_equiv = true;
|
||||||
|
bool parity_prefix = true;
|
||||||
|
bool rabin_to_buchi = true;
|
||||||
|
bool reduce_col_deg = false;
|
||||||
|
bool propagate_col = true;
|
||||||
|
bool pretty_print = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// \ingroup twa_acc_transform
|
||||||
|
/// \brief Take an automaton with any acceptance condition and return an
|
||||||
|
/// equivalent parity automaton.
|
||||||
|
///
|
||||||
|
/// The parity condition of the returned automaton is max even or
|
||||||
|
/// max odd.
|
||||||
|
/// If \a search_ex is true, when we move several elements, we
|
||||||
|
/// try to find an order such that the new permutation already exists.
|
||||||
|
/// If \a partial_degen is true, we apply a partial degeneralization to remove
|
||||||
|
// occurences of Fin | Fin and Inf & Inf.
|
||||||
|
/// If \a scc_acc_clean is true, we remove for each SCC the colors that don't
|
||||||
|
// appear.
|
||||||
|
/// If \a parity_equiv is true, we check if there exists a permutations of
|
||||||
|
// colors such that the acceptance
|
||||||
|
/// condition is a partity condition.
|
||||||
|
/// If \a use_last is true, we use the most recent state when looking for an
|
||||||
|
// existing state.
|
||||||
|
/// If \a pretty_print is true, we give a name to the states describing the
|
||||||
|
// state of the aut_ and the permutation.
|
||||||
|
|
||||||
|
SPOT_API twa_graph_ptr
|
||||||
|
remove_false_transitions(const twa_graph_ptr a);
|
||||||
|
|
||||||
|
SPOT_API twa_graph_ptr
|
||||||
|
to_parity(const twa_graph_ptr &aut, const car_option options = car_option());
|
||||||
|
|
||||||
|
|
||||||
|
// Old version of CAR
|
||||||
|
|
||||||
/// \ingroup twa_acc_transform
|
/// \ingroup twa_acc_transform
|
||||||
/// \brief Take an automaton with any acceptance condition and return an
|
/// \brief Take an automaton with any acceptance condition and return an
|
||||||
/// equivalent parity automaton.
|
/// equivalent parity automaton.
|
||||||
///
|
///
|
||||||
/// The parity condition of the returned automaton is max even.
|
/// The parity condition of the returned automaton is max even.
|
||||||
SPOT_API twa_graph_ptr
|
SPOT_API twa_graph_ptr
|
||||||
to_parity(const const_twa_graph_ptr& aut, bool pretty_print=false);
|
to_parity_old(const const_twa_graph_ptr& aut, bool pretty_print=false);
|
||||||
}
|
|
||||||
|
// Old version of IAR
|
||||||
|
/// \ingroup twa_acc_transform
|
||||||
|
/// \brief Turn a Rabin-like or Streett-like automaton into a parity automaton
|
||||||
|
/// based on the index appearence record (IAR)
|
||||||
|
///
|
||||||
|
/// If the input automaton has n states and k pairs, the output automaton has
|
||||||
|
/// at most k!*n states and 2k+1 colors. If the input automaton is
|
||||||
|
/// deterministic, the output automaton is deterministic as well, which is the
|
||||||
|
/// intended use case for this function. If the input automaton is
|
||||||
|
/// non-deterministic, the result is still correct, but way larger than an
|
||||||
|
/// equivalent Büchi automaton.
|
||||||
|
/// If the input automaton is Rabin-like (resp. Streett-like), the output
|
||||||
|
/// automaton has max odd (resp. min even) acceptance condition.
|
||||||
|
/// Details on the algorithm can be found in:
|
||||||
|
/// https://arxiv.org/pdf/1701.05738.pdf (published at TACAS 2017)
|
||||||
|
///
|
||||||
|
/// Throws an std::runtime_error if the input is neither Rabin-like nor
|
||||||
|
/// Street-like.
|
||||||
|
SPOT_API
|
||||||
|
twa_graph_ptr
|
||||||
|
iar_old(const const_twa_graph_ptr& aut, bool pretty_print = false);
|
||||||
|
|
||||||
|
/// \ingroup twa_acc_transform
|
||||||
|
/// \brief Turn a Rabin-like or Streett-like automaton into a parity automaton
|
||||||
|
/// based on the index appearence record (IAR)
|
||||||
|
///
|
||||||
|
/// Returns nullptr if the input automaton is neither Rabin-like nor
|
||||||
|
/// Streett-like, and calls spot::iar() otherwise.
|
||||||
|
SPOT_API
|
||||||
|
twa_graph_ptr
|
||||||
|
iar_maybe_old(const const_twa_graph_ptr& aut, bool pretty_print = false);
|
||||||
|
|
||||||
|
} // namespace spot
|
||||||
|
|
@ -373,7 +373,6 @@ TESTS_python = \
|
||||||
python/bdditer.py \
|
python/bdditer.py \
|
||||||
python/bddnqueen.py \
|
python/bddnqueen.py \
|
||||||
python/bugdet.py \
|
python/bugdet.py \
|
||||||
python/car.py \
|
|
||||||
python/complement_semidet.py \
|
python/complement_semidet.py \
|
||||||
python/declenv.py \
|
python/declenv.py \
|
||||||
python/decompose_scc.py \
|
python/decompose_scc.py \
|
||||||
|
|
|
||||||
|
|
@ -1,304 +0,0 @@
|
||||||
#!/usr/bin/python3
|
|
||||||
# -*- mode: python; coding: utf-8 -*-
|
|
||||||
# Copyright (C) 2018, 2019 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
|
|
||||||
|
|
||||||
no_option = spot.car_option()
|
|
||||||
no_option.search_ex = False
|
|
||||||
no_option.use_last = False
|
|
||||||
no_option.force_order = False
|
|
||||||
no_option.partial_degen = False
|
|
||||||
no_option.acc_clean = False
|
|
||||||
no_option.parity_equiv = False
|
|
||||||
no_option.parity_prefix = False
|
|
||||||
no_option.rabin_to_buchi = False
|
|
||||||
no_option.propagate_col = False
|
|
||||||
|
|
||||||
acc_clean_search_opt = spot.car_option()
|
|
||||||
acc_clean_search_opt.force_order = False
|
|
||||||
acc_clean_search_opt.partial_degen = False
|
|
||||||
acc_clean_search_opt.parity_equiv = False
|
|
||||||
acc_clean_search_opt.parity_prefix = False
|
|
||||||
acc_clean_search_opt.rabin_to_buchi = False
|
|
||||||
acc_clean_search_opt.propagate_col = False
|
|
||||||
|
|
||||||
partial_degen_opt = spot.car_option()
|
|
||||||
partial_degen_opt.search_ex = False
|
|
||||||
partial_degen_opt.force_order = False
|
|
||||||
partial_degen_opt.parity_equiv = False
|
|
||||||
partial_degen_opt.parity_prefix = False
|
|
||||||
partial_degen_opt.rabin_to_buchi = False
|
|
||||||
partial_degen_opt.propagate_col = False
|
|
||||||
|
|
||||||
parity_equiv_opt = spot.car_option()
|
|
||||||
parity_equiv_opt.search_ex = False
|
|
||||||
parity_equiv_opt.use_last = False
|
|
||||||
parity_equiv_opt.force_order = False
|
|
||||||
parity_equiv_opt.partial_degen = False
|
|
||||||
parity_equiv_opt.parity_prefix = False
|
|
||||||
parity_equiv_opt.rabin_to_buchi = False
|
|
||||||
parity_equiv_opt.propagate_col = False
|
|
||||||
|
|
||||||
rab_to_buchi_opt = spot.car_option()
|
|
||||||
rab_to_buchi_opt.use_last = False
|
|
||||||
rab_to_buchi_opt.force_order = False
|
|
||||||
rab_to_buchi_opt.partial_degen = False
|
|
||||||
rab_to_buchi_opt.parity_equiv = False
|
|
||||||
rab_to_buchi_opt.parity_prefix = False
|
|
||||||
rab_to_buchi_opt.propagate_col = False
|
|
||||||
|
|
||||||
# Force to use CAR or IAR for each SCC
|
|
||||||
use_car_opt = spot.car_option()
|
|
||||||
use_car_opt.partial_degen = False
|
|
||||||
use_car_opt.parity_equiv = False
|
|
||||||
use_car_opt.parity_prefix = False
|
|
||||||
use_car_opt.rabin_to_buchi = False
|
|
||||||
use_car_opt.propagate_col = False
|
|
||||||
|
|
||||||
all_opt = spot.car_option()
|
|
||||||
all_opt.pretty_print = True
|
|
||||||
|
|
||||||
|
|
||||||
options = [
|
|
||||||
no_option,
|
|
||||||
acc_clean_search_opt,
|
|
||||||
partial_degen_opt,
|
|
||||||
parity_equiv_opt,
|
|
||||||
rab_to_buchi_opt,
|
|
||||||
use_car_opt,
|
|
||||||
spot.car_option(),
|
|
||||||
]
|
|
||||||
|
|
||||||
i = 1
|
|
||||||
|
|
||||||
def test(aut):
|
|
||||||
global i
|
|
||||||
for opt in options:
|
|
||||||
try:
|
|
||||||
p = spot.to_parity(aut, opt)
|
|
||||||
assert(spot.are_equivalent(aut, p))
|
|
||||||
except:
|
|
||||||
# Are equivalent can raise exception
|
|
||||||
assert(False)
|
|
||||||
|
|
||||||
|
|
||||||
test(spot.automaton("""HOA: v1
|
|
||||||
name: "(FGp0 & ((XFp0 & F!p1) | F(Gp1 & XG!p0))) | G(F!p0 & (XFp0 | F!p1) &
|
|
||||||
F(Gp1 | G!p0))"
|
|
||||||
States: 14
|
|
||||||
Start: 0
|
|
||||||
AP: 2 "p1" "p0"
|
|
||||||
Acceptance: 6 (Fin(0) & Fin(1)) | ((Fin(4)|Fin(5)) & (Inf(2)&Inf(3)))
|
|
||||||
properties: trans-labels explicit-labels trans-acc complete
|
|
||||||
properties: deterministic
|
|
||||||
--BODY--
|
|
||||||
State: 0
|
|
||||||
[!0] 1
|
|
||||||
[0] 2
|
|
||||||
State: 1
|
|
||||||
[!0&!1] 1 {0 1 2 3 5}
|
|
||||||
[0&!1] 3
|
|
||||||
[!0&1] 4
|
|
||||||
[0&1] 5
|
|
||||||
State: 2
|
|
||||||
[0&!1] 2 {1}
|
|
||||||
[!0&1] 4
|
|
||||||
[!0&!1] 6
|
|
||||||
[0&1] 7
|
|
||||||
State: 3
|
|
||||||
[0&!1] 3 {1 3}
|
|
||||||
[!0&1] 4
|
|
||||||
[!0&!1] 6 {0 1 2 3 5}
|
|
||||||
[0&1] 8
|
|
||||||
State: 4
|
|
||||||
[!0&!1] 4 {1 2 3 5}
|
|
||||||
[!0&1] 4 {2 4 5}
|
|
||||||
[0&!1] 5 {1 3}
|
|
||||||
[0&1] 5 {4}
|
|
||||||
State: 5
|
|
||||||
[!0&1] 4 {2 4 5}
|
|
||||||
[0&!1] 5 {1 3}
|
|
||||||
[0&1] 8 {2 4}
|
|
||||||
[!0&!1] 9 {1 2 3 5}
|
|
||||||
State: 6
|
|
||||||
[0&!1] 3 {1 3}
|
|
||||||
[!0&1] 4
|
|
||||||
[0&1] 5
|
|
||||||
[!0&!1] 10
|
|
||||||
State: 7
|
|
||||||
[!0&1] 4
|
|
||||||
[0&!1] 7 {1 3}
|
|
||||||
[!0&!1] 11
|
|
||||||
[0&1] 12 {0 4}
|
|
||||||
State: 8
|
|
||||||
[!0&1] 4 {2 4 5}
|
|
||||||
[0&1] 5 {4}
|
|
||||||
[0&!1] 8 {1 3}
|
|
||||||
[!0&!1] 11 {1 3 5}
|
|
||||||
State: 9
|
|
||||||
[!0&1] 4 {2 4 5}
|
|
||||||
[0&!1] 5 {1 3}
|
|
||||||
[0&1] 5 {4}
|
|
||||||
[!0&!1] 11 {1 3 5}
|
|
||||||
State: 10
|
|
||||||
[!0&1] 4
|
|
||||||
[0&1] 8
|
|
||||||
[!0&!1] 10 {0 1 2 3 5}
|
|
||||||
[0&!1] 13 {1 2 3}
|
|
||||||
State: 11
|
|
||||||
[!0&1] 4 {2 4 5}
|
|
||||||
[0&!1] 8 {1 2 3}
|
|
||||||
[0&1] 8 {2 4}
|
|
||||||
[!0&!1] 11 {1 2 3 5}
|
|
||||||
State: 12
|
|
||||||
[!0&1] 4
|
|
||||||
[0&1] 7 {0 2 4}
|
|
||||||
[!0&!1] 9
|
|
||||||
[0&!1] 12 {1 3}
|
|
||||||
State: 13
|
|
||||||
[!0&1] 4
|
|
||||||
[0&1] 5
|
|
||||||
[!0&!1] 10 {0 1 3 5}
|
|
||||||
[0&!1] 13 {1 3}
|
|
||||||
--END--"""))
|
|
||||||
|
|
||||||
test(spot.automaton("""
|
|
||||||
HOA: v1
|
|
||||||
States: 2
|
|
||||||
Start: 0
|
|
||||||
AP: 2 "p0" "p1"
|
|
||||||
Acceptance: 5 (Inf(0)&Inf(1)) | ((Fin(2)|Fin(3)) & Fin(4))
|
|
||||||
--BODY--
|
|
||||||
State: 0
|
|
||||||
[!0 & 1] 0 {2 3}
|
|
||||||
[!0 & !1] 0 {3}
|
|
||||||
[0] 1
|
|
||||||
State: 1
|
|
||||||
[0&1] 1 {1 2 4}
|
|
||||||
[0&!1] 1 {4}
|
|
||||||
[!0&1] 1 {0 1 2 3}
|
|
||||||
[!0&!1] 1 {0 3}
|
|
||||||
--END--"""))
|
|
||||||
|
|
||||||
test(spot.automaton("""
|
|
||||||
HOA: v1 States: 6 Start: 0 AP: 2 "p0" "p1" Acceptance: 6 Inf(5) |
|
|
||||||
Fin(2) | Inf(1) | (Inf(0) & Fin(3)) | Inf(4) properties: trans-labels
|
|
||||||
explicit-labels trans-acc --BODY-- State: 0 [0&1] 2 {4 5} [0&1] 4 {0 4}
|
|
||||||
[!0&!1] 3 {3 5} State: 1 [0&!1] 3 {1 5} [!0&!1] 5 {0 1} State: 2 [!0&!1]
|
|
||||||
0 {0 3} [0&!1] 1 {0} State: 3 [!0&1] 4 {1 2 3} [0&1] 3 {3 4 5} State:
|
|
||||||
4 [!0&!1] 1 {2 4} State: 5 [!0&1] 4 --END--
|
|
||||||
"""))
|
|
||||||
|
|
||||||
for f in spot.randltl(15, 2000):
|
|
||||||
test(spot.translate(f, "det", "G"))
|
|
||||||
|
|
||||||
for f in spot.randltl(5, 25000):
|
|
||||||
test(spot.translate(f))
|
|
||||||
|
|
||||||
test(spot.translate('!(GFa -> (GFb & GF(!b & !Xb)))', 'gen', 'det'))
|
|
||||||
|
|
||||||
test(spot.automaton("""
|
|
||||||
HOA: v1
|
|
||||||
States: 4
|
|
||||||
Start: 0
|
|
||||||
AP: 2 "p0" "p1"
|
|
||||||
Acceptance: 6
|
|
||||||
((Fin(1) | Inf(2)) & Inf(5)) | (Fin(0) & (Fin(1) | (Fin(3) & Inf(4))))
|
|
||||||
properties: trans-labels explicit-labels trans-acc complete
|
|
||||||
properties: deterministic
|
|
||||||
--BODY--
|
|
||||||
State: 0
|
|
||||||
[!0&!1] 0 {2}
|
|
||||||
[0&1] 1 {0 5}
|
|
||||||
[0&!1] 1 {0 2 5}
|
|
||||||
[!0&1] 2 {1}
|
|
||||||
State: 1
|
|
||||||
[0&1] 1 {0}
|
|
||||||
[!0&!1] 1 {2}
|
|
||||||
[0&!1] 1 {0 2}
|
|
||||||
[!0&1] 2 {1}
|
|
||||||
State: 2
|
|
||||||
[!0&!1] 0 {2 3}
|
|
||||||
[0&!1] 0 {0 2 3 5}
|
|
||||||
[!0&1] 2 {1 4}
|
|
||||||
[0&1] 3 {0 5}
|
|
||||||
State: 3
|
|
||||||
[!0&!1] 0 {2 3}
|
|
||||||
[0&!1] 0 {0 2 3 5}
|
|
||||||
[!0&1] 2 {1 4}
|
|
||||||
[0&1] 3 {0}
|
|
||||||
--END--
|
|
||||||
"""))
|
|
||||||
|
|
||||||
test(spot.automaton("""
|
|
||||||
HOA: v1
|
|
||||||
States: 5
|
|
||||||
Start: 0
|
|
||||||
AP: 2 "p1" "p0"
|
|
||||||
Acceptance: 5 (Fin(0) & Fin(1)) | (Fin(3) & (Inf(2)&Inf(4)))
|
|
||||||
properties: trans-labels explicit-labels trans-acc complete
|
|
||||||
properties: deterministic
|
|
||||||
--BODY--
|
|
||||||
State: 0
|
|
||||||
[!0] 1
|
|
||||||
[0] 2
|
|
||||||
State: 1
|
|
||||||
[!0&!1] 1 {0 1}
|
|
||||||
[!0&1] 3
|
|
||||||
[0] 4
|
|
||||||
State: 2
|
|
||||||
[!0&1] 1
|
|
||||||
[0&!1] 2
|
|
||||||
[0&1] 2 {0 1 2 4}
|
|
||||||
[!0&!1] 3
|
|
||||||
State: 3
|
|
||||||
[!0&1] 3 {1 2 3}
|
|
||||||
[!0&!1] 3 {4}
|
|
||||||
[0&!1] 4 {3}
|
|
||||||
[0&1] 4 {1 2 3}
|
|
||||||
State: 4
|
|
||||||
[!0&!1] 3 {3}
|
|
||||||
[!0&1] 3 {1 2 3}
|
|
||||||
[0&!1] 4
|
|
||||||
[0&1] 4 {1 2 4}
|
|
||||||
--END--
|
|
||||||
"""))
|
|
||||||
|
|
||||||
test(spot.automaton("""
|
|
||||||
HOA: v1
|
|
||||||
States: 2
|
|
||||||
Start: 0
|
|
||||||
AP: 2 "p1" "p0"
|
|
||||||
Acceptance: 5 (Fin(0) & (Fin(3)|Fin(4)) & (Inf(1)&Inf(2))) | Inf(3)
|
|
||||||
properties: trans-labels explicit-labels trans-acc complete
|
|
||||||
properties: deterministic stutter-invariant
|
|
||||||
--BODY--
|
|
||||||
State: 0
|
|
||||||
[0&!1] 0 {2 3}
|
|
||||||
[!0&!1] 0 {2 3 4}
|
|
||||||
[!0&1] 1
|
|
||||||
[0&1] 1 {2 4}
|
|
||||||
State: 1
|
|
||||||
[!0&!1] 0 {0 2 3 4}
|
|
||||||
[!0&1] 1 {1}
|
|
||||||
[0&!1] 1 {2 3}
|
|
||||||
[0&1] 1 {1 2 4}
|
|
||||||
--END--
|
|
||||||
"""))
|
|
||||||
|
|
@ -33,7 +33,7 @@ def report_missing_exception():
|
||||||
aut = spot.translate('GFa & GFb & GFc')
|
aut = spot.translate('GFa & GFb & GFc')
|
||||||
aut.set_acceptance(spot.acc_cond("parity min even 4"))
|
aut.set_acceptance(spot.acc_cond("parity min even 4"))
|
||||||
try:
|
try:
|
||||||
spot.iar(aut)
|
spot.iar_old(aut)
|
||||||
except RuntimeError as e:
|
except RuntimeError as e:
|
||||||
assert 'iar() expects Rabin-like or Streett-like input' in str(e)
|
assert 'iar() expects Rabin-like or Streett-like input' in str(e)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,304 @@
|
||||||
|
|
||||||
import spot
|
import spot
|
||||||
|
|
||||||
|
# Tests for the new version of to_parity
|
||||||
|
|
||||||
|
no_option = spot.car_option()
|
||||||
|
no_option.search_ex = False
|
||||||
|
no_option.use_last = False
|
||||||
|
no_option.force_order = False
|
||||||
|
no_option.partial_degen = False
|
||||||
|
no_option.acc_clean = False
|
||||||
|
no_option.parity_equiv = False
|
||||||
|
no_option.parity_prefix = False
|
||||||
|
no_option.rabin_to_buchi = False
|
||||||
|
no_option.propagate_col = False
|
||||||
|
|
||||||
|
acc_clean_search_opt = spot.car_option()
|
||||||
|
acc_clean_search_opt.force_order = False
|
||||||
|
acc_clean_search_opt.partial_degen = False
|
||||||
|
acc_clean_search_opt.parity_equiv = False
|
||||||
|
acc_clean_search_opt.parity_prefix = False
|
||||||
|
acc_clean_search_opt.rabin_to_buchi = False
|
||||||
|
acc_clean_search_opt.propagate_col = False
|
||||||
|
|
||||||
|
partial_degen_opt = spot.car_option()
|
||||||
|
partial_degen_opt.search_ex = False
|
||||||
|
partial_degen_opt.force_order = False
|
||||||
|
partial_degen_opt.parity_equiv = False
|
||||||
|
partial_degen_opt.parity_prefix = False
|
||||||
|
partial_degen_opt.rabin_to_buchi = False
|
||||||
|
partial_degen_opt.propagate_col = False
|
||||||
|
|
||||||
|
parity_equiv_opt = spot.car_option()
|
||||||
|
parity_equiv_opt.search_ex = False
|
||||||
|
parity_equiv_opt.use_last = False
|
||||||
|
parity_equiv_opt.force_order = False
|
||||||
|
parity_equiv_opt.partial_degen = False
|
||||||
|
parity_equiv_opt.parity_prefix = False
|
||||||
|
parity_equiv_opt.rabin_to_buchi = False
|
||||||
|
parity_equiv_opt.propagate_col = False
|
||||||
|
|
||||||
|
rab_to_buchi_opt = spot.car_option()
|
||||||
|
rab_to_buchi_opt.use_last = False
|
||||||
|
rab_to_buchi_opt.force_order = False
|
||||||
|
rab_to_buchi_opt.partial_degen = False
|
||||||
|
rab_to_buchi_opt.parity_equiv = False
|
||||||
|
rab_to_buchi_opt.parity_prefix = False
|
||||||
|
rab_to_buchi_opt.propagate_col = False
|
||||||
|
|
||||||
|
# Force to use CAR or IAR for each SCC
|
||||||
|
use_car_opt = spot.car_option()
|
||||||
|
use_car_opt.partial_degen = False
|
||||||
|
use_car_opt.parity_equiv = False
|
||||||
|
use_car_opt.parity_prefix = False
|
||||||
|
use_car_opt.rabin_to_buchi = False
|
||||||
|
use_car_opt.propagate_col = False
|
||||||
|
|
||||||
|
all_opt = spot.car_option()
|
||||||
|
all_opt.pretty_print = True
|
||||||
|
|
||||||
|
|
||||||
|
options = [
|
||||||
|
no_option,
|
||||||
|
acc_clean_search_opt,
|
||||||
|
partial_degen_opt,
|
||||||
|
parity_equiv_opt,
|
||||||
|
rab_to_buchi_opt,
|
||||||
|
use_car_opt,
|
||||||
|
all_opt,
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def test(aut):
|
||||||
|
global i
|
||||||
|
for opt in options:
|
||||||
|
try:
|
||||||
|
p = 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,
|
||||||
|
)
|
||||||
|
assert(spot.are_equivalent(aut, p))
|
||||||
|
except:
|
||||||
|
# are_equivalent can raise exception
|
||||||
|
assert(False)
|
||||||
|
|
||||||
|
|
||||||
|
test(spot.automaton("""HOA: v1
|
||||||
|
name: "(FGp0 & ((XFp0 & F!p1) | F(Gp1 & XG!p0))) | G(F!p0 & (XFp0 | F!p1) &
|
||||||
|
F(Gp1 | G!p0))"
|
||||||
|
States: 14
|
||||||
|
Start: 0
|
||||||
|
AP: 2 "p1" "p0"
|
||||||
|
Acceptance: 6 (Fin(0) & Fin(1)) | ((Fin(4)|Fin(5)) & (Inf(2)&Inf(3)))
|
||||||
|
properties: trans-labels explicit-labels trans-acc complete
|
||||||
|
properties: deterministic
|
||||||
|
--BODY--
|
||||||
|
State: 0
|
||||||
|
[!0] 1
|
||||||
|
[0] 2
|
||||||
|
State: 1
|
||||||
|
[!0&!1] 1 {0 1 2 3 5}
|
||||||
|
[0&!1] 3
|
||||||
|
[!0&1] 4
|
||||||
|
[0&1] 5
|
||||||
|
State: 2
|
||||||
|
[0&!1] 2 {1}
|
||||||
|
[!0&1] 4
|
||||||
|
[!0&!1] 6
|
||||||
|
[0&1] 7
|
||||||
|
State: 3
|
||||||
|
[0&!1] 3 {1 3}
|
||||||
|
[!0&1] 4
|
||||||
|
[!0&!1] 6 {0 1 2 3 5}
|
||||||
|
[0&1] 8
|
||||||
|
State: 4
|
||||||
|
[!0&!1] 4 {1 2 3 5}
|
||||||
|
[!0&1] 4 {2 4 5}
|
||||||
|
[0&!1] 5 {1 3}
|
||||||
|
[0&1] 5 {4}
|
||||||
|
State: 5
|
||||||
|
[!0&1] 4 {2 4 5}
|
||||||
|
[0&!1] 5 {1 3}
|
||||||
|
[0&1] 8 {2 4}
|
||||||
|
[!0&!1] 9 {1 2 3 5}
|
||||||
|
State: 6
|
||||||
|
[0&!1] 3 {1 3}
|
||||||
|
[!0&1] 4
|
||||||
|
[0&1] 5
|
||||||
|
[!0&!1] 10
|
||||||
|
State: 7
|
||||||
|
[!0&1] 4
|
||||||
|
[0&!1] 7 {1 3}
|
||||||
|
[!0&!1] 11
|
||||||
|
[0&1] 12 {0 4}
|
||||||
|
State: 8
|
||||||
|
[!0&1] 4 {2 4 5}
|
||||||
|
[0&1] 5 {4}
|
||||||
|
[0&!1] 8 {1 3}
|
||||||
|
[!0&!1] 11 {1 3 5}
|
||||||
|
State: 9
|
||||||
|
[!0&1] 4 {2 4 5}
|
||||||
|
[0&!1] 5 {1 3}
|
||||||
|
[0&1] 5 {4}
|
||||||
|
[!0&!1] 11 {1 3 5}
|
||||||
|
State: 10
|
||||||
|
[!0&1] 4
|
||||||
|
[0&1] 8
|
||||||
|
[!0&!1] 10 {0 1 2 3 5}
|
||||||
|
[0&!1] 13 {1 2 3}
|
||||||
|
State: 11
|
||||||
|
[!0&1] 4 {2 4 5}
|
||||||
|
[0&!1] 8 {1 2 3}
|
||||||
|
[0&1] 8 {2 4}
|
||||||
|
[!0&!1] 11 {1 2 3 5}
|
||||||
|
State: 12
|
||||||
|
[!0&1] 4
|
||||||
|
[0&1] 7 {0 2 4}
|
||||||
|
[!0&!1] 9
|
||||||
|
[0&!1] 12 {1 3}
|
||||||
|
State: 13
|
||||||
|
[!0&1] 4
|
||||||
|
[0&1] 5
|
||||||
|
[!0&!1] 10 {0 1 3 5}
|
||||||
|
[0&!1] 13 {1 3}
|
||||||
|
--END--"""))
|
||||||
|
|
||||||
|
test(spot.automaton("""
|
||||||
|
HOA: v1
|
||||||
|
States: 2
|
||||||
|
Start: 0
|
||||||
|
AP: 2 "p0" "p1"
|
||||||
|
Acceptance: 5 (Inf(0)&Inf(1)) | ((Fin(2)|Fin(3)) & Fin(4))
|
||||||
|
--BODY--
|
||||||
|
State: 0
|
||||||
|
[!0 & 1] 0 {2 3}
|
||||||
|
[!0 & !1] 0 {3}
|
||||||
|
[0] 1
|
||||||
|
State: 1
|
||||||
|
[0&1] 1 {1 2 4}
|
||||||
|
[0&!1] 1 {4}
|
||||||
|
[!0&1] 1 {0 1 2 3}
|
||||||
|
[!0&!1] 1 {0 3}
|
||||||
|
--END--"""))
|
||||||
|
|
||||||
|
test(spot.automaton("""
|
||||||
|
HOA: v1 States: 6 Start: 0 AP: 2 "p0" "p1" Acceptance: 6 Inf(5) |
|
||||||
|
Fin(2) | Inf(1) | (Inf(0) & Fin(3)) | Inf(4) properties: trans-labels
|
||||||
|
explicit-labels trans-acc --BODY-- State: 0 [0&1] 2 {4 5} [0&1] 4 {0 4}
|
||||||
|
[!0&!1] 3 {3 5} State: 1 [0&!1] 3 {1 5} [!0&!1] 5 {0 1} State: 2 [!0&!1]
|
||||||
|
0 {0 3} [0&!1] 1 {0} State: 3 [!0&1] 4 {1 2 3} [0&1] 3 {3 4 5} State:
|
||||||
|
4 [!0&!1] 1 {2 4} State: 5 [!0&1] 4 --END--
|
||||||
|
"""))
|
||||||
|
|
||||||
|
for f in spot.randltl(15, 2000):
|
||||||
|
test(spot.translate(f, "det", "G"))
|
||||||
|
|
||||||
|
for f in spot.randltl(5, 25000):
|
||||||
|
test(spot.translate(f))
|
||||||
|
|
||||||
|
test(spot.translate('!(GFa -> (GFb & GF(!b & !Xb)))', 'gen', 'det'))
|
||||||
|
|
||||||
|
test(spot.automaton("""
|
||||||
|
HOA: v1
|
||||||
|
States: 4
|
||||||
|
Start: 0
|
||||||
|
AP: 2 "p0" "p1"
|
||||||
|
Acceptance: 6
|
||||||
|
((Fin(1) | Inf(2)) & Inf(5)) | (Fin(0) & (Fin(1) | (Fin(3) & Inf(4))))
|
||||||
|
properties: trans-labels explicit-labels trans-acc complete
|
||||||
|
properties: deterministic
|
||||||
|
--BODY--
|
||||||
|
State: 0
|
||||||
|
[!0&!1] 0 {2}
|
||||||
|
[0&1] 1 {0 5}
|
||||||
|
[0&!1] 1 {0 2 5}
|
||||||
|
[!0&1] 2 {1}
|
||||||
|
State: 1
|
||||||
|
[0&1] 1 {0}
|
||||||
|
[!0&!1] 1 {2}
|
||||||
|
[0&!1] 1 {0 2}
|
||||||
|
[!0&1] 2 {1}
|
||||||
|
State: 2
|
||||||
|
[!0&!1] 0 {2 3}
|
||||||
|
[0&!1] 0 {0 2 3 5}
|
||||||
|
[!0&1] 2 {1 4}
|
||||||
|
[0&1] 3 {0 5}
|
||||||
|
State: 3
|
||||||
|
[!0&!1] 0 {2 3}
|
||||||
|
[0&!1] 0 {0 2 3 5}
|
||||||
|
[!0&1] 2 {1 4}
|
||||||
|
[0&1] 3 {0}
|
||||||
|
--END--
|
||||||
|
"""))
|
||||||
|
|
||||||
|
test(spot.automaton("""
|
||||||
|
HOA: v1
|
||||||
|
States: 5
|
||||||
|
Start: 0
|
||||||
|
AP: 2 "p1" "p0"
|
||||||
|
Acceptance: 5 (Fin(0) & Fin(1)) | (Fin(3) & (Inf(2)&Inf(4)))
|
||||||
|
properties: trans-labels explicit-labels trans-acc complete
|
||||||
|
properties: deterministic
|
||||||
|
--BODY--
|
||||||
|
State: 0
|
||||||
|
[!0] 1
|
||||||
|
[0] 2
|
||||||
|
State: 1
|
||||||
|
[!0&!1] 1 {0 1}
|
||||||
|
[!0&1] 3
|
||||||
|
[0] 4
|
||||||
|
State: 2
|
||||||
|
[!0&1] 1
|
||||||
|
[0&!1] 2
|
||||||
|
[0&1] 2 {0 1 2 4}
|
||||||
|
[!0&!1] 3
|
||||||
|
State: 3
|
||||||
|
[!0&1] 3 {1 2 3}
|
||||||
|
[!0&!1] 3 {4}
|
||||||
|
[0&!1] 4 {3}
|
||||||
|
[0&1] 4 {1 2 3}
|
||||||
|
State: 4
|
||||||
|
[!0&!1] 3 {3}
|
||||||
|
[!0&1] 3 {1 2 3}
|
||||||
|
[0&!1] 4
|
||||||
|
[0&1] 4 {1 2 4}
|
||||||
|
--END--
|
||||||
|
"""))
|
||||||
|
|
||||||
|
test(spot.automaton("""
|
||||||
|
HOA: v1
|
||||||
|
States: 2
|
||||||
|
Start: 0
|
||||||
|
AP: 2 "p1" "p0"
|
||||||
|
Acceptance: 5 (Fin(0) & (Fin(3)|Fin(4)) & (Inf(1)&Inf(2))) | Inf(3)
|
||||||
|
properties: trans-labels explicit-labels trans-acc complete
|
||||||
|
properties: deterministic stutter-invariant
|
||||||
|
--BODY--
|
||||||
|
State: 0
|
||||||
|
[0&!1] 0 {2 3}
|
||||||
|
[!0&!1] 0 {2 3 4}
|
||||||
|
[!0&1] 1
|
||||||
|
[0&1] 1 {2 4}
|
||||||
|
State: 1
|
||||||
|
[!0&!1] 0 {0 2 3 4}
|
||||||
|
[!0&1] 1 {1}
|
||||||
|
[0&!1] 1 {2 3}
|
||||||
|
[0&1] 1 {1 2 4}
|
||||||
|
--END--
|
||||||
|
"""))
|
||||||
|
|
||||||
|
|
||||||
|
# Tests for the old version of to_parity (CAR)
|
||||||
a = spot.automaton("""HOA: v1
|
a = spot.automaton("""HOA: v1
|
||||||
States: 1
|
States: 1
|
||||||
Start: 0
|
Start: 0
|
||||||
|
|
@ -32,7 +330,7 @@ State: 0
|
||||||
[!0&1] 0 {1}
|
[!0&1] 0 {1}
|
||||||
[!0&!1] 0
|
[!0&!1] 0
|
||||||
--END--""")
|
--END--""")
|
||||||
p = spot.to_parity(a)
|
p = spot.to_parity_old(a, True)
|
||||||
assert spot.are_equivalent(a, p)
|
assert spot.are_equivalent(a, p)
|
||||||
|
|
||||||
a = spot.automaton("""
|
a = spot.automaton("""
|
||||||
|
|
@ -43,21 +341,21 @@ explicit-labels trans-acc --BODY-- State: 0 [0&1] 2 {4 5} [0&1] 4 {0 4}
|
||||||
0 {0 3} [0&!1] 1 {0} State: 3 [!0&1] 4 {1 2 3} [0&1] 3 {3 4 5} State:
|
0 {0 3} [0&!1] 1 {0} State: 3 [!0&1] 4 {1 2 3} [0&1] 3 {3 4 5} State:
|
||||||
4 [!0&!1] 1 {2 4} State: 5 [!0&1] 4 --END--
|
4 [!0&!1] 1 {2 4} State: 5 [!0&1] 4 --END--
|
||||||
""")
|
""")
|
||||||
p = spot.to_parity(a)
|
p = spot.to_parity_old(a, True)
|
||||||
assert p.num_states() == 22
|
assert p.num_states() == 22
|
||||||
assert spot.are_equivalent(a, p)
|
assert spot.are_equivalent(a, p)
|
||||||
|
|
||||||
for f in spot.randltl(4, 400):
|
for f in spot.randltl(4, 400):
|
||||||
d = spot.translate(f, "det", "G")
|
d = spot.translate(f, "det", "G")
|
||||||
p = spot.to_parity(d)
|
p = spot.to_parity_old(d, True)
|
||||||
assert spot.are_equivalent(p, d)
|
assert spot.are_equivalent(p, d)
|
||||||
|
|
||||||
for f in spot.randltl(5, 2000):
|
for f in spot.randltl(5, 2000):
|
||||||
n = spot.translate(f)
|
n = spot.translate(f)
|
||||||
p = spot.to_parity(n)
|
p = spot.to_parity_old(n, True)
|
||||||
assert spot.are_equivalent(n, p)
|
assert spot.are_equivalent(n, p)
|
||||||
|
|
||||||
# Issue #390.
|
# Issue #390.
|
||||||
a = spot.translate('!(GFa -> (GFb & GF(!b & !Xb)))', 'gen', 'det')
|
a = spot.translate('!(GFa -> (GFb & GF(!b & !Xb)))', 'gen', 'det')
|
||||||
b = spot.to_parity(a)
|
b = spot.to_parity_old(a, True)
|
||||||
assert a.equivalent_to(b)
|
assert a.equivalent_to(b)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue