twaalgos/cobuchi: Add nsa_to_nca()

* NEWS: Update.
* spot/twaalgos/cobuchi.hh: Declare to_dca() and nsa_to_nca().
* spot/twaalgos/cobuchi.cc: Implement them.
* python/spot/impl.i: Include new file for python bindings.
* spot/twaalgos/Makefile.am: Add new file.
* bin/autfilt.cc: Add --dca command line option. This option does not
return a deterministic automaton yet, but it will.
* tests/core/dca.test: Add tests for Büchi automata.
* tests/python/dca.py: Add a python script that builds a nondet. Streett
automaton.
* tests/python/dca.test: Add tests for Streett automata.
* tests/Makefile.am: Add all tests.
This commit is contained in:
Alexandre GBAGUIDI AISSE 2017-06-17 19:33:26 +02:00
parent 37c1a19b39
commit cf18c06940
10 changed files with 678 additions and 1 deletions

View file

@ -33,6 +33,7 @@ twaalgos_HEADERS = \
bfssteps.hh \
canonicalize.hh \
cleanacc.hh \
cobuchi.hh \
complete.hh \
complement.hh \
compsusp.hh \
@ -95,6 +96,7 @@ libtwaalgos_la_SOURCES = \
bfssteps.cc \
canonicalize.cc \
cleanacc.cc \
cobuchi.cc \
complete.cc \
complement.cc \
compsusp.cc \

262
spot/twaalgos/cobuchi.cc Normal file
View file

@ -0,0 +1,262 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2017 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/>.
#include <spot/twaalgos/cobuchi.hh>
#include <spot/misc/bitvect.hh>
#include <spot/twaalgos/powerset.hh>
#include <spot/twaalgos/product.hh>
#include <spot/twaalgos/sccinfo.hh>
#include <spot/twaalgos/totgba.hh>
#include <stack>
#include <unordered_map>
namespace spot
{
namespace
{
typedef std::pair<unsigned, unsigned> pair_state_nca;
// Helper function that returns the called 'augmented subset construction'
// of the given automaton, i.e. the product of the automaton with its
// powerset construction.
//
// 'aut_power' is the automaton that will be used for the powerset
// construction and 'aut_prod' is the one that will be used for the
// product. They may be confusing in the sense that why the same automaton
// is not used for the product and the powerset construction. Actually,
// when dealing with an automaton A with Rabin acceptance, it is firstly
// converted into an automaton B with Streett-like acceptance. The powerset
// construction of B happens to be isomorphic with the powerset construction
// of A. Therefore, you would like to use A (which is smaller than B) for
// the powerset construction and B for the product.
static
twa_graph_ptr
aug_subset_cons(const const_twa_graph_ptr& aut_prod,
const const_twa_graph_ptr& aut_power,
bool named_states,
struct power_map& pmap)
{
twa_graph_ptr res = product(aut_prod, tgba_powerset(aut_power, pmap));
if (named_states)
{
const product_states* res_map = res->get_named_prop
<product_states>("product-states");
auto v = new std::vector<std::string>;
res->set_named_prop("state-names", v);
auto get_st_name =
[&](const pair_state_nca& x)
{
std::stringstream os;
os << x.first << ",{";
bool not_first = false;
for (auto& a : pmap.states_of(x.second))
{
if (not_first)
os << ',';
else
not_first = true;
os << a;
}
os << '}';
return os.str();
};
unsigned num_states = res->num_states();
for (unsigned i = 0; i < num_states; ++i)
v->emplace_back(get_st_name((*res_map)[i]));
}
return res;
}
class nsa_to_nca_converter final
{
protected:
struct power_map pmap_; // Sets of sts (powerset cons.).
const_twa_graph_ptr aut_; // The given automaton.
bool state_based_; // Is it state based?
std::vector<acc_cond::rs_pair> pairs_; // All pairs of the acc. cond.
unsigned nb_pairs_; // Nb pair in the acc. cond.
bool named_states_; // Name states for display?
twa_graph_ptr res_; // The augmented subset const.
product_states* res_map_; // States of the aug. sub. cons.
scc_info si_; // SCC information.
unsigned nb_states_; // Number of states.
unsigned was_rabin_; // Was it Rabin before Streett?
std::vector<unsigned>* orig_states_; // Match old Rabin st. from new.
unsigned orig_num_st_; // Rabin original nb states.
// Keep information of states that are wanted to be seen infinitely
// often (cf Header).
void save_inf_nca_st(unsigned s, acc_cond::mark_t m,
vect_nca_info* nca_info)
{
if (was_rabin_ && m)
{
for (unsigned p = 0; p < nb_pairs_; ++p)
if (pairs_[p].fin || m & pairs_[p].inf)
{
const pair_state_nca& st = (*res_map_)[s];
auto bv = make_bitvect(orig_num_st_);
for (unsigned state : pmap_.states_of(st.second))
bv->set(state);
assert(!was_rabin_
|| ((int)(*orig_states_)[st.first] >= 0));
unsigned state = was_rabin_ ? (*orig_states_)[st.first]
: st.first;
unsigned clause_nb = was_rabin_ ? p / 2 : p;
nca_info->push_back(new nca_st_info(clause_nb, state, bv));
}
}
else if (!was_rabin_)
{
const pair_state_nca& st = (*res_map_)[s];
auto bv = make_bitvect(aut_->num_states());
for (unsigned state : pmap_.states_of(st.second))
bv->set(state);
nca_info->push_back(new nca_st_info(0, st.first, bv));
}
}
// Helper function that marks states that we want to see finitely often
// and save some information about states that we want to see infinitely
// often (cf Header).
void set_marks_using(std::vector<bool>& nca_is_inf_state,
vect_nca_info* nca_info)
{
for (unsigned s = 0; s < nb_states_; ++s)
{
unsigned src_scc = si_.scc_of(s);
if (nca_is_inf_state[s])
{
acc_cond::mark_t m = 0u;
for (auto& e : res_->out(s))
{
if (nca_info && e.acc && (si_.scc_of(e.dst) == src_scc
|| state_based_))
m |= e.acc;
e.acc = 0u;
}
if (nca_info)
save_inf_nca_st(s, m, nca_info);
}
else
{
for (auto& e : res_->out(s))
{
if (si_.scc_of(e.dst) == src_scc || state_based_)
e.acc = acc_cond::mark_t({0});
else
e.acc = 0u;
}
}
}
}
public:
nsa_to_nca_converter(const const_twa_graph_ptr ref_prod,
const const_twa_graph_ptr ref_power,
std::vector<acc_cond::rs_pair>& pairs,
bool named_states = false,
bool was_rabin = false,
unsigned orig_num_st = 0)
: aut_(ref_prod),
state_based_((bool)aut_->prop_state_acc()),
pairs_(pairs),
nb_pairs_(pairs.size()),
named_states_(named_states),
res_(aug_subset_cons(ref_prod, ref_power, named_states_, pmap_)),
res_map_(res_->get_named_prop<product_states>("product-states")),
si_(scc_info(res_)),
nb_states_(res_->num_states()),
was_rabin_(was_rabin),
orig_num_st_(orig_num_st)
{
if (was_rabin)
orig_states_ = ref_prod->get_named_prop<std::vector<unsigned>>
("original-states");
}
~nsa_to_nca_converter()
{}
twa_graph_ptr run(vect_nca_info* nca_info)
{
std::vector<bool> nca_is_inf_state; // Accepting or rejecting sts.
nca_is_inf_state.resize(nb_states_, false);
// Iterate over all SCCs and check for accepting states. A state 's'
// is accepting if there is a cycle containing 's' that visits
// finitely often all acceptance sets marked as Fin or infinitely
// often acceptance sets marked by Inf.
unsigned nb_scc = si_.scc_count();
for (unsigned scc = 0; scc < nb_scc; ++scc)
for (unsigned st : si_.states_on_acc_cycle_of(scc))
nca_is_inf_state[st] = true;
set_marks_using(nca_is_inf_state, nca_info);
res_->prop_state_acc(state_based_);
res_->set_co_buchi();
res_->merge_edges();
return res_;
}
};
}
twa_graph_ptr
nsa_to_nca(const const_twa_graph_ptr& ref,
bool named_states,
vect_nca_info* nca_info)
{
twa_graph_ptr ref_tmp = ref->acc().is_parity() ? to_generalized_streett(ref)
: nullptr;
std::vector<acc_cond::rs_pair> pairs;
if (!(ref_tmp ? ref_tmp : ref)->acc().is_streett_like(pairs))
throw std::runtime_error("nsa_to_nca() only works with Streett-like or "
"Parity acceptance condition");
nsa_to_nca_converter nca_converter(ref_tmp ? ref_tmp : ref,
ref_tmp ? ref_tmp : ref,
pairs,
named_states,
false);
return nca_converter.run(nca_info);
}
twa_graph_ptr
to_dca(const const_twa_graph_ptr& aut, bool named_states)
{
std::vector<acc_cond::rs_pair> pairs;
if (aut->acc().is_streett_like(pairs) || aut->acc().is_parity())
return nsa_to_nca(aut, named_states);
else
throw std::runtime_error("to_dca() only works with Streett-like or Parity"
" acceptance condition");
}
}

91
spot/twaalgos/cobuchi.hh Normal file
View file

@ -0,0 +1,91 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2017 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/misc/bitvect.hh>
#include <spot/twa/fwd.hh>
#include <vector>
namespace spot
{
/// A vector of nca_st_info is given as argument to nsa_to_nca(). Each
/// nca_st_info has information about a state that must be seen infinitely
/// often. For a state 's' visited infinitely often by a run, the information
/// provided is:
/// - the clause number satisfied by the run (from left to right)
/// - the state number of 's'
/// - destinations of all outgoing edges of 's' (represented as a bitvect)
struct nca_st_info
{
unsigned clause_num;
unsigned state_num;
bitvect* all_dst;
nca_st_info(unsigned clause, unsigned st, bitvect* dst)
{
clause_num = clause;
state_num = st;
all_dst = dst;
}
~nca_st_info()
{
delete all_dst;
}
};
typedef std::vector<struct nca_st_info*> vect_nca_info;
/// \brief Converts a nondet Streett-like aut. to a nondet. co-Büchi aut.
///
/// This function works in top of the augmented subset construction algorithm
/// and is described in section 3.1 of:
/** \verbatim
@Article{boker.2009.lcs,
author = {Udi Boker and Orna Kupferman},
title = {Co-Büching Them All},
booktitle = {Foundations of Software Science and Computational
Structures - 14th International Conference, FOSSACS 2011}
year = {2011},
pages = {184--198},
url = {\url{www.cs.huji.ac.il/~ornak/publications/fossacs11b.pdf}}
}
\endverbatim */
/// This implementation is quite different from the described algorithm. It
/// is made to work with automaton with Street-like acceptance (including
/// Büchi).
///
/// \a aut The automaton to convert.
/// \a named_states name each state for easier debugging.
/// \a nca_info retrieve information about state visited infinitely often.
SPOT_API twa_graph_ptr
nsa_to_nca(const const_twa_graph_ptr& aut,
bool named_states = false,
vect_nca_info* nca_info = nullptr);
/// \brief Converts any ω-automata to det. co-buchi (when possible)
///
/// The resulting automaton will always recognize at least the same language.
/// Actually, it can recognize more if the original language can not be
/// expressed using a co-Büchi acceptance condition.
SPOT_API twa_graph_ptr
to_dca(const const_twa_graph_ptr& aut, bool named_states = false);
}