postproc: add support for -x dpa-simul and simul-trans-pruning

Also have simul-max default to 4096 instead of 512, because it's
really simul-trans-pruning that is very slow and need to be limited.

* spot/twaalgos/postproc.cc, spot/twaalgos/postproc.hh,
spot/twaalgos/simulation.cc, spot/twaalgos/simulation.hh,
spot/twaalgos/determinize.cc, spot/twaalgos/determinize.hh:
Implement the above options.
* bin/spot-x.cc, NEWS: Document them.
* tests/core/ltlsynt.test, tests/core/minusx.test,
tests/core/sim3.test: Add some test cases.
This commit is contained in:
Alexandre Duret-Lutz 2021-04-29 17:24:26 +02:00
parent fca6513604
commit d32f19f5d0
11 changed files with 210 additions and 101 deletions

View file

@ -811,7 +811,8 @@ namespace spot
tgba_determinize(const const_twa_graph_ptr& a,
bool pretty_print, bool use_scc,
bool use_simulation, bool use_stutter,
const output_aborter* aborter)
const output_aborter* aborter,
int trans_pruning)
{
if (!a->is_existential())
throw std::runtime_error
@ -829,7 +830,7 @@ namespace spot
if (use_simulation)
{
aut_tmp = spot::scc_filter(aut_tmp);
auto aut2 = simulation(aut_tmp, &implications);
auto aut2 = simulation(aut_tmp, &implications, trans_pruning);
if (pretty_print)
aut2->copy_state_names_from(aut_tmp);
aut_tmp = aut2;

View file

@ -77,11 +77,16 @@ namespace spot
/// \param aborter abort the construction if the constructed
/// automaton would be too large. Return nullptr
/// in this case.
///
/// \param trans_pruning when \a use_simulation is true, \a trans_pruning
/// is passed to the simulation-based reduction to limit
/// the effect of transition pruning.
SPOT_API twa_graph_ptr
tgba_determinize(const const_twa_graph_ptr& aut,
bool pretty_print = false,
bool use_scc = true,
bool use_simulation = true,
bool use_stutter = true,
const output_aborter* aborter = nullptr);
const output_aborter* aborter = nullptr,
int trans_pruning = -1);
}

View file

@ -75,6 +75,7 @@ namespace spot
det_max_edges_ = opt->get("det-max-edges", -1);
simul_ = opt->get("simul", -1);
simul_method_ = opt->get("simul-method", -1);
dpa_simul_ = opt->get("dpa-simul", -1);
scc_filter_ = opt->get("scc-filter", -1);
ba_simul_ = opt->get("ba-simul", -1);
tba_determinisation_ = opt->get("tba-det", 0);
@ -86,8 +87,9 @@ namespace spot
state_based_ = opt->get("state-based", 0);
wdba_minimize_ = opt->get("wdba-minimize", -1);
gen_reduce_parity_ = opt->get("gen-reduce-parity", 1);
simul_max_ = opt->get("simul-max", 512);
simul_max_ = opt->get("simul-max", 4096);
wdba_det_max_ = opt->get("wdba-det-max", 4096);
simul_trans_pruning_ = opt->get("simul-trans-pruning", 512);
if (sat_acc_ && sat_minimize_ == 0)
sat_minimize_ = 1; // Dicho.
@ -113,11 +115,10 @@ namespace spot
twa_graph_ptr
postprocessor::do_simul(const twa_graph_ptr& a, int opt) const
{
if (simul_max_ > 0 && static_cast<unsigned>(simul_max_) < a->num_states())
return a;
if (opt == 0)
return a;
if (simul_max_ > 0 && static_cast<unsigned>(simul_max_) < a->num_states())
return a;
static unsigned sim = [&]()
{
@ -131,18 +132,18 @@ namespace spot
if (sim == 2)
opt += 3;
// FIXME: simulation-based reduction how have work-arounds for
// FIXME: simulation-based reduction now have work-arounds for
// non-separated sets, so we can probably try them.
if (!has_separate_sets(a))
return a;
switch (opt)
{
case 1:
return simulation(a);
return simulation(a, simul_trans_pruning_);
case 2:
return cosimulation(a);
return cosimulation(a, simul_trans_pruning_);
case 3:
return iterated_simulations(a);
return iterated_simulations(a, simul_trans_pruning_);
case 4:
return reduce_direct_sim(a);
case 5:
@ -150,7 +151,7 @@ namespace spot
case 6:
return reduce_iterated(a);
default:
return iterated_simulations(a);
return iterated_simulations(a, simul_trans_pruning_);
}
}
@ -166,12 +167,12 @@ namespace spot
case 0:
return a;
case 1:
return simulation_sba(a);
return simulation_sba(a, simul_trans_pruning_);
case 2:
return cosimulation_sba(a);
return cosimulation_sba(a, simul_trans_pruning_);
case 3:
default:
return iterated_simulations_sba(a);
return iterated_simulations_sba(a, simul_trans_pruning_);
}
}
@ -266,6 +267,8 @@ namespace spot
simul_ = (level_ == Low) ? 1 : 3;
if (ba_simul_ < 0)
ba_simul_ = (level_ == High) ? 3 : 0;
if (dpa_simul_ < 0)
dpa_simul_ = (level_ != Low) ? 1 : 0;
if (scc_filter_ < 0)
scc_filter_ = 1;
if (type_ == BA)
@ -551,14 +554,13 @@ namespace spot
det_simul = false;
dba = tgba_determinize(tba,
false, det_scc_, det_simul, det_stutter_,
aborter);
aborter, simul_trans_pruning_);
// Setting det-max-states or det-max-edges may cause tgba_determinize
// to fail.
if (dba)
{
dba = simplify_acc(dba);
if (level_ != Low)
dba = simulation(dba);
dba = do_simul(simplify_acc(dba), dpa_simul_);
sim = nullptr;
}
}

View file

@ -1,5 +1,5 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2012-2020 Laboratoire de Recherche et Développement
// Copyright (C) 2012-2021 Laboratoire de Recherche et Développement
// de l'Epita (LRDE).
//
// This file is part of Spot, a model checking library.
@ -253,6 +253,8 @@ namespace spot
int det_max_edges_ = -1;
int simul_ = -1;
int simul_method_ = -1;
int simul_trans_pruning_ = 512;
int dpa_simul_ = -1;
int scc_filter_ = -1;
int ba_simul_ = -1;
bool tba_determinisation_ = false;
@ -264,7 +266,7 @@ namespace spot
int gen_reduce_parity_ = 1;
bool state_based_ = false;
int wdba_minimize_ = -1;
int simul_max_ = 512;
int simul_max_ = 4096;
int wdba_det_max_ = 4096;
};
/// @}

View file

@ -154,10 +154,12 @@ namespace spot
}
direct_simulation(const const_twa_graph_ptr& in,
int trans_pruning,
std::vector<bdd>* implications = nullptr)
: po_size_(0),
all_class_var_(bddtrue),
original_(in),
trans_pruning_(trans_pruning),
record_implications_(implications)
{
if (!has_separate_sets(in))
@ -467,13 +469,18 @@ namespace spot
}
// Update the partial order.
//
// Do not compute implication between classes if we have more
// classes than trans_pruning_, or if the automaton is
// deterministic (in which case want_implications_ was
// initialized to false). The number of classes should only
// augment, so if we exceed trans_pruning_, it's safe to
// disable want_implications_ for good.
// This loop follows the pattern given by the paper.
// foreach class do
// | foreach class do
// | | update po if needed
// | od
// od
if (want_implications_
&& trans_pruning_ >= 0
&& static_cast<unsigned>(trans_pruning_) < sz)
want_implications_ = false;
for (unsigned n = 0; n < sz; ++n)
{
@ -773,7 +780,7 @@ namespace spot
if (!need_another_pass)
return res;
direct_simulation<Cosimulation, Sba> sim(res);
direct_simulation<Cosimulation, Sba> sim(res, trans_pruning_);
return sim.run();
}
@ -861,16 +868,16 @@ namespace spot
automaton_size stat;
const const_twa_graph_ptr original_;
int trans_pruning_;
std::vector<bdd>* record_implications_;
};
template<typename Fun, typename Aut>
twa_graph_ptr
wrap_simul(Fun f, const Aut& a)
wrap_simul(Fun f, const Aut& a, int trans_pruning)
{
if (has_separate_sets(a))
return f(a);
return f(a, trans_pruning);
// If the input has acceptance sets common to Fin and Inf,
// separate them before doing the simulation, and merge them
// back afterwards. Doing will temporarily introduce more sets
@ -879,62 +886,63 @@ namespace spot
// automata sharing Fin/Inf sets.
auto b = make_twa_graph(a, twa::prop_set::all());
separate_sets_here(b);
return simplify_acceptance_here(f(b));
return simplify_acceptance_here(f(b, trans_pruning));
}
} // End namespace anonymous.
twa_graph_ptr
simulation(const const_twa_graph_ptr& t)
simulation(const const_twa_graph_ptr& t, int trans_pruning)
{
return wrap_simul([](const const_twa_graph_ptr& t) {
direct_simulation<false, false> simul(t);
return simul.run();
}, t);
return wrap_simul([](const const_twa_graph_ptr& t, int trans_pruning) {
direct_simulation<false, false> simul(t, trans_pruning);
return simul.run();
}, t, trans_pruning);
}
twa_graph_ptr
simulation(const const_twa_graph_ptr& t,
std::vector<bdd>* implications)
std::vector<bdd>* implications, int trans_pruning)
{
return wrap_simul([implications](const const_twa_graph_ptr& t) {
direct_simulation<false, false> simul(t, implications);
return simul.run();
}, t);
return wrap_simul([implications](const const_twa_graph_ptr& t,
int trans_pruning) {
direct_simulation<false, false> simul(t, trans_pruning, implications);
return simul.run();
}, t, trans_pruning);
}
twa_graph_ptr
simulation_sba(const const_twa_graph_ptr& t)
simulation_sba(const const_twa_graph_ptr& t, int trans_pruning)
{
return wrap_simul([](const const_twa_graph_ptr& t) {
direct_simulation<false, true> simul(t);
return simul.run();
}, t);
return wrap_simul([](const const_twa_graph_ptr& t, int trans_pruning) {
direct_simulation<false, true> simul(t, trans_pruning);
return simul.run();
}, t, trans_pruning);
}
twa_graph_ptr
cosimulation(const const_twa_graph_ptr& t)
cosimulation(const const_twa_graph_ptr& t, int trans_pruning)
{
return wrap_simul([](const const_twa_graph_ptr& t) {
direct_simulation<true, false> simul(t);
return simul.run();
}, t);
return wrap_simul([](const const_twa_graph_ptr& t, int trans_pruning) {
direct_simulation<true, false> simul(t, trans_pruning);
return simul.run();
}, t, trans_pruning);
}
twa_graph_ptr
cosimulation_sba(const const_twa_graph_ptr& t)
cosimulation_sba(const const_twa_graph_ptr& t, int trans_pruning)
{
return wrap_simul([](const const_twa_graph_ptr& t) {
direct_simulation<true, true> simul(t);
return simul.run();
}, t);
return wrap_simul([](const const_twa_graph_ptr& t, int trans_pruning) {
direct_simulation<true, true> simul(t, trans_pruning);
return simul.run();
}, t, trans_pruning);
}
template<bool Sba>
twa_graph_ptr
iterated_simulations_(const const_twa_graph_ptr& t)
iterated_simulations_(const const_twa_graph_ptr& t, int trans_pruning)
{
twa_graph_ptr res = nullptr;
automaton_size prev;
@ -943,12 +951,12 @@ namespace spot
do
{
prev = next;
direct_simulation<false, Sba> simul(res ? res : t);
direct_simulation<false, Sba> simul(res ? res : t, trans_pruning);
res = simul.run();
if (res->prop_universal())
break;
direct_simulation<true, Sba> cosimul(res);
direct_simulation<true, Sba> cosimul(res, trans_pruning);
res = cosimul.run();
if (Sba)
@ -963,15 +971,15 @@ namespace spot
}
twa_graph_ptr
iterated_simulations(const const_twa_graph_ptr& t)
iterated_simulations(const const_twa_graph_ptr& t, int trans_pruning)
{
return wrap_simul(iterated_simulations_<false>, t);
return wrap_simul(iterated_simulations_<false>, t, trans_pruning);
}
twa_graph_ptr
iterated_simulations_sba(const const_twa_graph_ptr& t)
iterated_simulations_sba(const const_twa_graph_ptr& t, int trans_pruning)
{
return wrap_simul(iterated_simulations_<true>, t);
return wrap_simul(iterated_simulations_<true>, t, trans_pruning);
}
template <bool Cosimulation, bool Sba>

View file

@ -1,5 +1,5 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2012-2015, 2017, 2019 Laboratoire de Recherche et
// Copyright (C) 2012-2015, 2017, 2019, 2021 Laboratoire de Recherche et
// Développement de l'Epita (LRDE).
//
// This file is part of Spot, a model checking library.
@ -36,7 +36,8 @@ namespace spot
/// described in \cite babiak.13.spin .
///
/// Our reconstruction of the quotient automaton based on this
/// suffix-inclusion relation will also improve determinism.
/// suffix-inclusion relation will also improve determinism thanks
/// to a kind of transition-pruning.
///
/// We recommend to call scc_filter() to first simplify the
/// automaton that should be reduced by simulation.
@ -47,22 +48,33 @@ namespace spot
/// acceptance conditions than necessary, and running scc_filter()
/// again afterwards will remove these superfluous conditions.
///
/// The resulting automaton has a named property "simulated-states", that is a
/// vector mapping each state of the input to a state of the output. Note that
/// some input states may be mapped to -1, as a by-product of improved
/// determinism. Typically, if the language of q1 is included in the language
/// of q2, only a transition to q2 will be built.
///
/// The resulting automaton has a named property "simulated-states",
/// that is a vector mapping each state of the input to a state of
/// the output. Note that some input states may be mapped to -1, as
/// a by-product of transition prunning.
///
/// \param automaton the automaton to simulate.
///
/// \param trans_pruning Transition pruning requires a quadratic
/// number of BDD implication checks between all equivalence
/// classes, so it can be costly on large automata. If \a
/// trans_pruning is set to a non-negative integer, only
/// (non-deterministic) automata with more states than trans_pruning
/// will be simplified.
///
/// \return a new automaton which is at worst a copy of the received
/// one
SPOT_API twa_graph_ptr
simulation(const const_twa_graph_ptr& automaton);
simulation(const const_twa_graph_ptr& automaton,
int trans_pruning = -1);
SPOT_API twa_graph_ptr
simulation(const const_twa_graph_ptr& automaton,
std::vector<bdd>* implications);
std::vector<bdd>* implications,
int trans_pruning = -1);
SPOT_API twa_graph_ptr
simulation_sba(const const_twa_graph_ptr& automaton);
simulation_sba(const const_twa_graph_ptr& automaton,
int trans_pruning = -1);
/// @}
/// @{
@ -73,7 +85,8 @@ namespace spot
/// state can be merged into the latter. \cite babiak.13.spin .
///
/// Our reconstruction of the quotient automaton based on this
/// prefix-inclusion relation will also improve codeterminism.
/// prefix-inclusion relation will also improve codeterminism
/// thanks to a kind of transition pruning.
///
/// We recommend to call scc_filter() to first simplify the
/// automaton that should be reduced by cosimulation.
@ -93,12 +106,22 @@ namespace spot
/// codeterminism.)
///
/// \param automaton the automaton to simulate.
///
/// \param trans_pruning Transition pruning requires a quadratic
/// number of BDD implication checks between all equivalence
/// classes, so it can be costly on large automata. If \a
/// trans_pruning is set to a non-negative integer, only
/// (non-deterministic) automata with more states than trans_pruning
/// will be simplified.
///
/// \return a new automaton which is at worst a copy of the received
/// one
SPOT_API twa_graph_ptr
cosimulation(const const_twa_graph_ptr& automaton);
cosimulation(const const_twa_graph_ptr& automaton,
int trans_pruning = -1);
SPOT_API twa_graph_ptr
cosimulation_sba(const const_twa_graph_ptr& automaton);
cosimulation_sba(const const_twa_graph_ptr& automaton,
int trans_pruning = -1);
/// @}
/// @{
@ -117,9 +140,11 @@ namespace spot
/// \return a new automaton which is at worst a copy of the received
/// one
SPOT_API twa_graph_ptr
iterated_simulations(const const_twa_graph_ptr& automaton);
iterated_simulations(const const_twa_graph_ptr& automaton,
int trans_pruning = -1);
SPOT_API twa_graph_ptr
iterated_simulations_sba(const const_twa_graph_ptr& automaton);
iterated_simulations_sba(const const_twa_graph_ptr& automaton,
int trans_pruning = -1);
/// @}
/// @{