This is a huge patch, that took over a month to complete. The bit sets are currently restricted to what 'unsigned can store', but it should be easy to extend it to 'uint64_t' should we need it. * NEWS: Update. * src/tgba/acc.hh: New file. * src/tgbatest/acc.cc, src/tgbatest/acc.test: Test it. * src/tgba/tgbakvcomplement.cc, src/tgba/tgbakvcomplement.hh, src/tgba/tgbasgba.cc, src/tgba/tgbasgba.hh: Delete. The KV complementation is too slow to be used in practice, and I somehow broke it during the conversion to bitsets. The tgba->sgba conversion was only used for the KV complementation, and should be better redone on tgba_digraph_ptr should it be needed again. * src/bin/ltlcross.cc, src/dstarparse/dra2ba.cc, src/dstarparse/nsa2tgba.cc, src/graphtest/tgbagraph.cc, src/graphtest/tgbagraph.test, src/kripke/fairkripke.cc, src/kripke/fairkripke.hh, src/kripke/kripke.cc, src/kripke/kripke.hh, src/kripke/kripkeexplicit.cc, src/kripke/kripkeexplicit.hh, src/misc/hash.hh, src/neverparse/neverclaimparse.yy, src/priv/accmap.hh, src/ta/ta.cc, src/ta/ta.hh, src/ta/taexplicit.cc, src/ta/taexplicit.hh, src/ta/taproduct.cc, src/ta/taproduct.hh, src/ta/tgta.cc, src/ta/tgta.hh, src/ta/tgtaexplicit.cc, src/ta/tgtaexplicit.hh, src/ta/tgtaproduct.cc, src/ta/tgtaproduct.hh, src/taalgos/dotty.cc, src/taalgos/emptinessta.cc, src/taalgos/minimize.cc, src/taalgos/tgba2ta.cc, src/tgba/Makefile.am, src/tgba/fwd.hh, src/tgba/taatgba.cc, src/tgba/taatgba.hh, src/tgba/tgba.cc, src/tgba/tgba.hh, src/tgba/tgbagraph.cc, src/tgba/tgbagraph.hh, src/tgba/tgbamask.cc, src/tgba/tgbamask.hh, src/tgba/tgbaproduct.cc, src/tgba/tgbaproduct.hh, src/tgba/tgbaproxy.cc, src/tgba/tgbaproxy.hh, src/tgba/tgbasafracomplement.cc, src/tgba/tgbasafracomplement.hh, src/tgbaalgos/bfssteps.cc, src/tgbaalgos/complete.cc, src/tgbaalgos/compsusp.cc, src/tgbaalgos/degen.cc, src/tgbaalgos/dotty.cc, src/tgbaalgos/dtbasat.cc, src/tgbaalgos/dtgbacomp.cc, src/tgbaalgos/dtgbasat.cc, src/tgbaalgos/dupexp.cc, src/tgbaalgos/emptiness.cc, src/tgbaalgos/emptiness.hh, src/tgbaalgos/gtec/ce.cc, src/tgbaalgos/gtec/gtec.cc, src/tgbaalgos/gtec/gtec.hh, src/tgbaalgos/gtec/sccstack.cc, src/tgbaalgos/gtec/sccstack.hh, src/tgbaalgos/gv04.cc, src/tgbaalgos/hoaf.cc, src/tgbaalgos/isweakscc.cc, src/tgbaalgos/lbtt.cc, src/tgbaalgos/ltl2tgba_fm.cc, src/tgbaalgos/magic.cc, src/tgbaalgos/ndfs_result.hxx, src/tgbaalgos/neverclaim.cc, src/tgbaalgos/postproc.cc, src/tgbaalgos/powerset.cc, src/tgbaalgos/randomgraph.cc, src/tgbaalgos/randomgraph.hh, src/tgbaalgos/reducerun.cc, src/tgbaalgos/replayrun.cc, src/tgbaalgos/safety.cc, src/tgbaalgos/save.cc, src/tgbaalgos/scc.cc, src/tgbaalgos/scc.hh, src/tgbaalgos/sccfilter.cc, src/tgbaalgos/sccinfo.cc, src/tgbaalgos/sccinfo.hh, src/tgbaalgos/se05.cc, src/tgbaalgos/simulation.cc, src/tgbaalgos/simulation.hh, src/tgbaalgos/stats.cc, src/tgbaalgos/stripacc.cc, src/tgbaalgos/tau03.cc, src/tgbaalgos/tau03opt.cc, src/tgbaalgos/weight.cc, src/tgbaalgos/weight.hh, src/tgbaparse/tgbaparse.yy, src/tgbatest/Makefile.am, src/tgbatest/complementation.cc, src/tgbatest/complementation.test, src/tgbatest/degenlskip.test, src/tgbatest/det.test, src/tgbatest/dstar.test, src/tgbatest/emptchk.cc, src/tgbatest/explpro2.test, src/tgbatest/explpro3.test, src/tgbatest/explpro4.test, src/tgbatest/explprod.test, src/tgbatest/ltl2tgba.cc, src/tgbatest/ltl2tgba.test, src/tgbatest/maskacc.cc, src/tgbatest/maskacc.test, src/tgbatest/neverclaimread.test, src/tgbatest/randtgba.cc, src/tgbatest/readsave.test, src/tgbatest/sim.test, src/tgbatest/sim2.test, src/tgbatest/spotlbtt.test, src/tgbatest/tgbaread.test, src/tgbatest/tripprod.test, iface/dve2/dve2.cc: Adjust or use to the new acceptance interface.
390 lines
11 KiB
C++
390 lines
11 KiB
C++
// -*- coding: utf-8 -*-
|
|
// Copyright (C) 2012, 2013, 2014 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 "postproc.hh"
|
|
#include "minimize.hh"
|
|
#include "simulation.hh"
|
|
#include "sccfilter.hh"
|
|
#include "degen.hh"
|
|
#include "stripacc.hh"
|
|
#include <cstdlib>
|
|
#include "misc/optionmap.hh"
|
|
#include "priv/countstates.hh"
|
|
#include "powerset.hh"
|
|
#include "isdet.hh"
|
|
#include "dtbasat.hh"
|
|
#include "dtgbasat.hh"
|
|
#include "complete.hh"
|
|
|
|
namespace spot
|
|
{
|
|
|
|
postprocessor::postprocessor(const option_map* opt)
|
|
: type_(TGBA), pref_(Small), level_(High),
|
|
degen_reset_(true), degen_order_(false), degen_cache_(true),
|
|
degen_lskip_(true), simul_(-1), scc_filter_(-1), ba_simul_(-1),
|
|
tba_determinisation_(false), sat_minimize_(0), sat_acc_(0),
|
|
sat_states_(0), state_based_(false), wdba_minimize_(true)
|
|
{
|
|
if (opt)
|
|
{
|
|
degen_order_ = opt->get("degen-order", 0);
|
|
degen_reset_ = opt->get("degen-reset", 1);
|
|
degen_cache_ = opt->get("degen-lcache", 1);
|
|
degen_lskip_ = opt->get("degen-lskip", 1);
|
|
simul_ = opt->get("simul", -1);
|
|
simul_limit_ = opt->get("simul-limit", -1);
|
|
scc_filter_ = opt->get("scc-filter", -1);
|
|
ba_simul_ = opt->get("ba-simul", -1);
|
|
tba_determinisation_ = opt->get("tba-det", 0);
|
|
sat_minimize_ = opt->get("sat-minimize", 0);
|
|
sat_acc_ = opt->get("sat-acc", 0);
|
|
sat_states_ = opt->get("sat-states", 0);
|
|
state_based_ = opt->get("state-based", 0);
|
|
wdba_minimize_ = opt->get("wdba-minimize", 1);
|
|
|
|
if (sat_acc_ && sat_minimize_ == 0)
|
|
sat_minimize_ = 1; // 2?
|
|
if (sat_states_ && sat_minimize_ == 0)
|
|
sat_minimize_ = 1;
|
|
if (sat_minimize_)
|
|
{
|
|
tba_determinisation_ = 1;
|
|
if (sat_acc_ <= 0)
|
|
sat_acc_ = -1;
|
|
if (sat_states_ <= 0)
|
|
sat_states_ = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
tgba_digraph_ptr
|
|
postprocessor::do_simul(const tgba_digraph_ptr& a, int opt)
|
|
{
|
|
switch (opt)
|
|
{
|
|
case 0:
|
|
return a;
|
|
case 1:
|
|
return simulation(a);
|
|
case 2:
|
|
return cosimulation(a);
|
|
case 3:
|
|
default:
|
|
return iterated_simulations(a);
|
|
case 4:
|
|
return dont_care_simulation(a, simul_limit_);
|
|
case 5:
|
|
return dont_care_iterated_simulations(a, simul_limit_);
|
|
}
|
|
}
|
|
|
|
tgba_digraph_ptr
|
|
postprocessor::do_ba_simul(const tgba_digraph_ptr& a, int opt)
|
|
{
|
|
switch (opt)
|
|
{
|
|
case 0:
|
|
return a;
|
|
case 1:
|
|
return simulation_sba(a);
|
|
case 2:
|
|
return cosimulation_sba(a);
|
|
case 3:
|
|
default:
|
|
return iterated_simulations_sba(a);
|
|
}
|
|
}
|
|
|
|
|
|
tgba_digraph_ptr
|
|
postprocessor::do_degen(const tgba_digraph_ptr& a)
|
|
{
|
|
auto d = degeneralize(a,
|
|
degen_reset_, degen_order_,
|
|
degen_cache_, degen_lskip_);
|
|
if (ba_simul_ <= 0)
|
|
return d;
|
|
return do_ba_simul(d, ba_simul_);
|
|
}
|
|
|
|
#define PREF_ (pref_ & (Small | Deterministic))
|
|
#define COMP_ (pref_ & Complete)
|
|
|
|
tgba_digraph_ptr
|
|
postprocessor::run(tgba_digraph_ptr a, const ltl::formula* f)
|
|
{
|
|
if (type_ == TGBA && PREF_ == Any && level_ == Low)
|
|
return a;
|
|
|
|
if (simul_ < 0)
|
|
simul_ = (level_ == Low) ? 1 : 3;
|
|
if (ba_simul_ < 0)
|
|
ba_simul_ = (level_ == High) ? 3 : 0;
|
|
if (scc_filter_ < 0)
|
|
scc_filter_ = 1;
|
|
if (type_ == BA)
|
|
state_based_ = true;
|
|
|
|
int original_acc = a->acc().num_sets();
|
|
|
|
// Remove useless SCCs.
|
|
if (type_ == Monitor)
|
|
// Do not bother about acceptance conditions, they will be
|
|
// ignored.
|
|
a = scc_filter_states(a);
|
|
else if (scc_filter_ > 0)
|
|
a = scc_filter(a, scc_filter_ > 1);
|
|
|
|
if (type_ == Monitor)
|
|
{
|
|
if (PREF_ == Deterministic)
|
|
a = minimize_monitor(a);
|
|
else
|
|
strip_acceptance_here(a);
|
|
|
|
if (PREF_ == Any)
|
|
return a;
|
|
|
|
a = do_simul(a, simul_);
|
|
|
|
// For Small,High we return the smallest between the output of
|
|
// the simulation, and that of the deterministic minimization.
|
|
if (PREF_ == Small && level_ == High && simul_)
|
|
{
|
|
auto m = minimize_monitor(a);
|
|
if (m->num_states() < a->num_states())
|
|
a = m;
|
|
}
|
|
if (COMP_ == Complete)
|
|
a = tgba_complete(a);
|
|
return a;
|
|
}
|
|
|
|
if (PREF_ == Any)
|
|
{
|
|
if (type_ == BA)
|
|
a = do_degen(a);
|
|
return a;
|
|
}
|
|
|
|
bool dba_is_wdba = false;
|
|
bool dba_is_minimal = false;
|
|
tgba_digraph_ptr dba = 0;
|
|
tgba_digraph_ptr sim = 0;
|
|
|
|
// (Small,Low) is the only configuration where we do not run
|
|
// WDBA-minimization.
|
|
if ((PREF_ != Small || level_ != Low) && wdba_minimize_)
|
|
{
|
|
bool reject_bigger = (PREF_ == Small) && (level_ == Medium);
|
|
dba = minimize_obligation(a, f, 0, reject_bigger);
|
|
if (dba && dba->is_inherently_weak() && dba->is_deterministic())
|
|
dba_is_minimal = dba_is_wdba = true;
|
|
else
|
|
// Minimization failed.
|
|
dba = nullptr;
|
|
// The WDBA is a BA, so no degeneralization is required.
|
|
}
|
|
|
|
// Run a simulation when wdba failed (or was not run), or
|
|
// at hard levels if we want a small output.
|
|
if (!dba || (level_ == High && PREF_ == Small))
|
|
{
|
|
sim = do_simul(a, simul_);
|
|
// Degeneralize the result of the simulation if needed.
|
|
// No need to do that if tba_determinisation_ will be used.
|
|
if (type_ == BA && !tba_determinisation_)
|
|
sim = do_degen(sim);
|
|
}
|
|
|
|
// If WDBA failed, but the simulation returned a deterministic
|
|
// automaton, use it as dba.
|
|
assert(dba || sim);
|
|
if (!dba && is_deterministic(sim))
|
|
{
|
|
std::swap(sim, dba);
|
|
// We postponed degeneralization above i case we would need
|
|
// to perform TBA-determinisation, but now it is clear
|
|
// that we won't perform it. So do degeneralize.
|
|
if (tba_determinisation_ && type_ == BA)
|
|
{
|
|
dba = do_degen(dba);
|
|
assert(is_deterministic(dba));
|
|
}
|
|
}
|
|
|
|
// If we don't have a DBA, attempt tba-determinization if requested.
|
|
if (tba_determinisation_ && !dba)
|
|
{
|
|
tgba_digraph_ptr tmpd = nullptr;
|
|
if (PREF_ == Deterministic
|
|
&& f
|
|
&& f->is_syntactic_recurrence()
|
|
&& sim->acc().num_sets() > 1)
|
|
tmpd = degeneralize_tba(sim);
|
|
|
|
auto in = tmpd ? tmpd : sim;
|
|
|
|
// These thresholds are arbitrary.
|
|
//
|
|
// For producing Small automata, we assume that a
|
|
// deterministic automaton that is twice the size of the
|
|
// original will never get reduced to a smaller one. We also
|
|
// do not want more than 2^13 cycles in an SCC.
|
|
//
|
|
// For Deterministic automata, we accept automata that
|
|
// are 8 times bigger, with no more that 2^15 cycle per SCC.
|
|
// The cycle threshold is the most important limit here. You
|
|
// may up it if you want to try producing larger automata.
|
|
auto tmp =
|
|
tba_determinize_check(in,
|
|
(PREF_ == Small) ? 2 : 8,
|
|
1 << ((PREF_ == Small) ? 13 : 15),
|
|
f);
|
|
if (tmp && tmp != in)
|
|
{
|
|
// There is no point in running the reverse simulation on
|
|
// a deterministic automaton, since all prefixes are
|
|
// unique.
|
|
dba = simulation(tmp);
|
|
}
|
|
if (dba && PREF_ == Deterministic)
|
|
{
|
|
// disregard the result of the simulation.
|
|
sim = nullptr;
|
|
}
|
|
else
|
|
{
|
|
// degeneralize sim, because we did not do it earlier
|
|
if (type_ == BA)
|
|
sim = do_degen(sim);
|
|
}
|
|
}
|
|
|
|
// Now dba contains either the result of WDBA-minimization (in
|
|
// that case dba_is_wdba=true), or some deterministic automaton
|
|
// that is either the result of the simulation or of the
|
|
// TBA-determinization (dba_is_wdba=false in both cases). If the
|
|
// dba is a WDBA, we do not have to run SAT-minimization. A
|
|
// negative value in sat_minimize_ can for its use for debugging.
|
|
if (sat_minimize_ && dba && (!dba_is_wdba || sat_minimize_ < 0))
|
|
{
|
|
unsigned target_acc;
|
|
if (type_ == BA)
|
|
target_acc = 1;
|
|
else if (sat_acc_ != -1)
|
|
target_acc = sat_acc_;
|
|
else
|
|
// Take the number of acceptance conditions from the input
|
|
// automaton, not from dba, because dba often has been
|
|
// degeneralized to beform tba_determinize_check(). MAke
|
|
// sure it is at least 1.
|
|
target_acc = original_acc > 0 ? original_acc : 1;
|
|
|
|
const_tgba_digraph_ptr in = 0;
|
|
if (target_acc == 1)
|
|
{
|
|
// If we are seeking a minimal DBA with unknown number of
|
|
// states, then we should start from the degeneralized,
|
|
// because the input TBA might be smaller.
|
|
if (state_based_)
|
|
in = degeneralize(dba);
|
|
else if (dba->acc().num_sets() != 1)
|
|
in = degeneralize_tba(dba);
|
|
else
|
|
in = dba;
|
|
}
|
|
else
|
|
{
|
|
in = dba;
|
|
}
|
|
|
|
const_tgba_digraph_ptr res = tgba_complete(in);
|
|
if (target_acc == 1)
|
|
{
|
|
if (sat_states_ != -1)
|
|
res = dtba_sat_synthetize(res, sat_states_, state_based_);
|
|
else if (sat_minimize_ == 1 || sat_minimize_ == -1)
|
|
res = dtba_sat_minimize(res, state_based_);
|
|
else // sat_minimize_ == 2
|
|
res = dtba_sat_minimize_dichotomy(res, state_based_);
|
|
}
|
|
else
|
|
{
|
|
if (sat_states_ != -1)
|
|
res = dtgba_sat_synthetize(res, target_acc, sat_states_,
|
|
state_based_);
|
|
else if (sat_minimize_ == 1 || sat_minimize_ == -1)
|
|
res = dtgba_sat_minimize(res, target_acc, state_based_);
|
|
else // sat_minimize_ == 2
|
|
res = dtgba_sat_minimize_dichotomy(res, target_acc, state_based_);
|
|
}
|
|
|
|
if (res)
|
|
{
|
|
if (state_based_)
|
|
// FIXME: This does not simplify generalized acceptance
|
|
// conditions, but calling scc_filter() would break the
|
|
// BA-typeness of res by removing acceptance marks from
|
|
// out-of-SCC transitions.
|
|
dba = scc_filter_states(res);
|
|
else
|
|
dba = scc_filter(res, true);
|
|
dba_is_minimal = true;
|
|
}
|
|
}
|
|
|
|
// Degeneralize the dba resulting from tba-determinization or
|
|
// sat-minimization (which is a TBA) if requested and needed.
|
|
if (dba && !dba_is_wdba && type_ == BA
|
|
&& !(dba_is_minimal && state_based_ && dba->acc().num_sets() == 1))
|
|
dba = degeneralize(dba);
|
|
|
|
if (dba && sim)
|
|
{
|
|
if (dba->num_states() > sim->num_states())
|
|
dba = nullptr;
|
|
else
|
|
sim = nullptr;
|
|
}
|
|
|
|
|
|
if (type_ == TGBA && level_ == High && scc_filter_ != 0)
|
|
{
|
|
if (dba && !dba_is_minimal) // WDBA is already clean.
|
|
{
|
|
dba = scc_filter(dba, true);
|
|
assert(!sim);
|
|
}
|
|
else if (sim)
|
|
{
|
|
sim = scc_filter(sim, true);
|
|
assert(!dba);
|
|
}
|
|
}
|
|
|
|
sim = dba ? dba : sim;
|
|
|
|
if (COMP_ == Complete)
|
|
sim = tgba_complete(sim);
|
|
|
|
return sim;
|
|
}
|
|
}
|