sat_minimize: improve logs and document Python bindings
* spot/priv/satcommon.cc, spot/priv/satcommon.hh: Make it possible to set the log file without setting the environment variable. Adjust print_log to take the input state and print it as a new column. * spot/twaalgos/dtbasat.cc, spot/twaalgos/dtwasat.cc: Adjust all calls to print_log. Fix log output for incremental approaches. Prefer purge_unreachable_states() over stats_reachable(). Do not call scc_filter() on colored automata. * spot/twaalgos/dtwasat.hh: Document the new "log" option. * NEWS: Mention the changes. * tests/python/satmin.ipynb: New file. * tests/Makefile.am: Add it. * doc/org/satmin.org, doc/org/tut.org: Link to it. * doc/org/satmin.org, bin/man/spot-x.x: Adjust description of CSV files. * bench/dtgbasat/gen.py, bench/dtgbasat/tabl.pl, bench/dtgbasat/tabl1.pl, bench/dtgbasat/tabl2.pl, bench/dtgbasat/tabl3.pl, bench/dtgbasat/tabl4.pl: Adjust for the new column. * spot/misc/satsolver.cc, spot/misc/satsolver.hh (stats): Make it const. * python/spot/__init__.py (sat_minimize): Add display_log and return_log options. * tests/python/ipnbdoctest.py: Adjust to not compare SAT-minimization logs as they contain timings.
This commit is contained in:
parent
5266010889
commit
c766f58d5d
21 changed files with 5076 additions and 177 deletions
|
|
@ -1,6 +1,6 @@
|
|||
// -*- coding: utf-8 -*-
|
||||
// Copyright (C) 2013, 2014, 2015, 2016, 2017 Laboratoire de Recherche et
|
||||
// Développement de l'Epita.
|
||||
// Copyright (C) 2013-2018 Laboratoire de Recherche et Développement
|
||||
// de l'Epita.
|
||||
//
|
||||
// This file is part of Spot, a model checking library.
|
||||
//
|
||||
|
|
@ -209,7 +209,7 @@ namespace spot
|
|||
return nvars_;
|
||||
}
|
||||
|
||||
std::pair<int, int> satsolver::stats()
|
||||
std::pair<int, int> satsolver::stats() const
|
||||
{
|
||||
return std::make_pair(get_nb_vars(), get_nb_clauses());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// -*- coding: utf-8 -*-
|
||||
// Copyright (C) 2013, 2017 Laboratoire de Recherche et Développement
|
||||
// de l'Epita.
|
||||
// Copyright (C) 2013, 2017, 2018 Laboratoire de Recherche et
|
||||
// Développement de l'Epita.
|
||||
//
|
||||
// This file is part of Spot, a model checking library.
|
||||
//
|
||||
|
|
@ -95,7 +95,7 @@ namespace spot
|
|||
int get_nb_vars() const;
|
||||
|
||||
/// \brief Returns std::pair<nvars, nclauses>;
|
||||
std::pair<int, int> stats();
|
||||
std::pair<int, int> stats() const;
|
||||
|
||||
/// \brief Add a comment.
|
||||
/// It should be used only in debug mode after providing a satsolver.
|
||||
|
|
|
|||
|
|
@ -142,50 +142,63 @@ namespace spot
|
|||
return buffer.str();
|
||||
}
|
||||
|
||||
static std::string satlog_filename;
|
||||
|
||||
void
|
||||
print_log(timer_map& t, int target_state_number,
|
||||
twa_graph_ptr& res, satsolver& solver)
|
||||
set_satlog_filename(const std::string& filename)
|
||||
{
|
||||
satlog_filename = filename;
|
||||
}
|
||||
|
||||
void
|
||||
print_log(timer_map& t,
|
||||
int input_state_number, int target_state_number,
|
||||
const twa_graph_ptr& res, const satsolver& solver)
|
||||
{
|
||||
// Always copy the environment variable into a static string,
|
||||
// so that we (1) look it up once, but (2) won't crash if the
|
||||
// environment is changed.
|
||||
static std::string log = []()
|
||||
static std::string envlog = []()
|
||||
{
|
||||
auto s = getenv("SPOT_SATLOG");
|
||||
return s ? s : "";
|
||||
}();
|
||||
if (!log.empty())
|
||||
const std::string log = satlog_filename.empty() ? envlog : satlog_filename;
|
||||
if (log.empty())
|
||||
return;
|
||||
|
||||
std::ofstream out(log, std::ios_base::ate | std::ios_base::app);
|
||||
out.exceptions(std::ifstream::failbit | std::ifstream::badbit);
|
||||
if (out.tellp() == 0)
|
||||
out <<
|
||||
("input.states,target.states,reachable.states,edges,transitions,"
|
||||
"variables,clauses,enc.user,enc.sys,sat.user,sat.sys,automaton\n");
|
||||
|
||||
const timer& te = t.timer("encode");
|
||||
const timer& ts = t.timer("solve");
|
||||
out << input_state_number << ',' << target_state_number << ',';
|
||||
if (res)
|
||||
{
|
||||
std::fstream out(log,
|
||||
std::ios_base::app | std::ios_base::out);
|
||||
out.exceptions(std::ifstream::failbit | std::ifstream::badbit);
|
||||
const timer& te = t.timer("encode");
|
||||
const timer& ts = t.timer("solve");
|
||||
out << target_state_number << ',';
|
||||
if (res)
|
||||
{
|
||||
twa_sub_statistics st = sub_stats_reachable(res);
|
||||
out << st.states << ',' << st.edges << ',' << st.transitions;
|
||||
}
|
||||
else
|
||||
{
|
||||
out << ",,";
|
||||
}
|
||||
std::pair<int, int> s = solver.stats(); // sat_stats
|
||||
out << ','
|
||||
<< s.first << ',' << s.second << ','
|
||||
<< te.utime() + te.cutime() << ','
|
||||
<< te.stime() + te.cstime() << ','
|
||||
<< ts.utime() + ts.cutime() << ','
|
||||
<< ts.stime() + ts.cstime() << ",\"";
|
||||
if (res)
|
||||
{
|
||||
std::ostringstream f;
|
||||
print_hoa(f, res, "l");
|
||||
escape_rfc4180(out, f.str());
|
||||
}
|
||||
out << "\"\n";
|
||||
twa_sub_statistics st = sub_stats_reachable(res);
|
||||
out << st.states << ',' << st.edges << ',' << st.transitions;
|
||||
}
|
||||
else
|
||||
{
|
||||
out << ",,";
|
||||
}
|
||||
std::pair<int, int> s = solver.stats();
|
||||
out << ',' << s.first << ',' << s.second << ','
|
||||
<< te.utime() + te.cutime() << ','
|
||||
<< te.stime() + te.cstime() << ','
|
||||
<< ts.utime() + ts.cutime() << ','
|
||||
<< ts.stime() + ts.cstime() << ',';
|
||||
if (res)
|
||||
{
|
||||
std::ostringstream f;
|
||||
print_hoa(f, res, "l");
|
||||
escape_rfc4180(out << '"', f.str()) << '"';
|
||||
}
|
||||
out << std::endl;
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// -*- coding: utf-8 -*-
|
||||
// Copyright (C) 2013, 2014, 2015 Laboratoire de Recherche et
|
||||
// Copyright (C) 2013-2016, 2018 Laboratoire de Recherche et
|
||||
// Développement de l'Epita.
|
||||
//
|
||||
// This file is part of Spot, a model checking library.
|
||||
|
|
@ -231,11 +231,17 @@ public:
|
|||
unsigned dst_ref);
|
||||
};
|
||||
|
||||
/// \brief Good old function that prints log is SPOT_SATLOG. It has been
|
||||
/// moved from spot/twaalgos/dt*asat.cc files.
|
||||
void
|
||||
print_log(timer_map& t, int target_state_number, twa_graph_ptr& res,
|
||||
satsolver& solver);
|
||||
/// \brief Give a filename to save the log of the SAT minimization.
|
||||
///
|
||||
/// This has priority over the SPOT_SATLOG environment variable.
|
||||
/// Pass en empty string to reset it.
|
||||
void set_satlog_filename(const std::string& filename);
|
||||
|
||||
/// \brief Prints a line in the SPOT_SATLOG file.
|
||||
void print_log(timer_map& t,
|
||||
int input_state_number,
|
||||
int target_state_number, const twa_graph_ptr& res,
|
||||
const satsolver& solver);
|
||||
|
||||
/// \brief Returns the number of distinct values containted in a vector.
|
||||
int
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@
|
|||
#include <spot/twaalgos/dtbasat.hh>
|
||||
#include <spot/twaalgos/langmap.hh>
|
||||
#include <spot/twaalgos/sccinfo.hh>
|
||||
#include <spot/twaalgos/stats.hh>
|
||||
|
||||
// If you set the SPOT_TMPKEEP environment variable the temporary
|
||||
// file used to communicate with the sat solver will be left in
|
||||
|
|
@ -708,6 +707,7 @@ namespace spot
|
|||
}
|
||||
#endif
|
||||
a->merge_edges();
|
||||
a->purge_unreachable_states();
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
|
@ -744,7 +744,8 @@ namespace spot
|
|||
if (!solution.second.empty())
|
||||
res = sat_build(solution.second, d, a, state_based);
|
||||
|
||||
print_log(t, target_state_number, res, solver); // If SPOT_SATLOG is set.
|
||||
print_log(t, a->num_states(),
|
||||
target_state_number, res, solver); // If SPOT_SATLOG is set.
|
||||
|
||||
trace << "dtba_sat_synthetize(...) = " << res << '\n';
|
||||
return res;
|
||||
|
|
@ -754,7 +755,6 @@ namespace spot
|
|||
dichotomy_dtba_research(int max,
|
||||
dict& d,
|
||||
satsolver& solver,
|
||||
timer_map& t1,
|
||||
const_twa_graph_ptr& prev,
|
||||
bool state_based)
|
||||
{
|
||||
|
|
@ -768,36 +768,47 @@ namespace spot
|
|||
target = (max + min) / 2;
|
||||
trace << "min:" << min << ", max:" << max << ", target:" << target
|
||||
<< '\n';
|
||||
|
||||
timer_map t1;
|
||||
t1.start("encode");
|
||||
solver.assume(d.nvars + target);
|
||||
t1.stop("encode");
|
||||
trace << "solver.assume(" << d.nvars + target << ")\n";
|
||||
|
||||
t1.start("solve");
|
||||
satsolver::solution_pair solution = solver.get_solution();
|
||||
t1.stop("solve");
|
||||
if (solution.second.empty())
|
||||
{
|
||||
trace << "UNSAT\n";
|
||||
max = target;
|
||||
print_log(t1, prev->num_states(), d.cand_size - target,
|
||||
nullptr, solver);
|
||||
}
|
||||
else
|
||||
{
|
||||
trace << "SAT\n";
|
||||
res = sat_build(solution.second, d, prev, state_based);
|
||||
min = d.cand_size - stats_reachable(res).states + 1;
|
||||
min = d.cand_size - res->num_states() + 1;
|
||||
print_log(t1, prev->num_states(), d.cand_size - target,
|
||||
res, solver);
|
||||
}
|
||||
}
|
||||
|
||||
trace << "End with max:" << max << ", min:" << min << '\n';
|
||||
if (!res)
|
||||
{
|
||||
trace << "All assumptions are UNSAT, let's try without...";
|
||||
trace << "All assumptions are UNSAT, let's try without...\n";
|
||||
timer_map t1;
|
||||
t1.start("encode");
|
||||
t1.stop("encode");
|
||||
t1.start("solve");
|
||||
t1.stop("solve");
|
||||
satsolver::solution_pair solution = solver.get_solution();
|
||||
trace << (solution.second.empty() ? "UNSAT!\n" : "SAT\n");
|
||||
res = solution.second.empty() ? nullptr :
|
||||
sat_build(solution.second, d, prev, state_based);
|
||||
print_log(t1, prev->num_states(), d.cand_size - target, res, solver);
|
||||
}
|
||||
|
||||
t1.stop("solve");
|
||||
print_log(t1, d.cand_size - target, res, solver); // SPOT_SATLOG.
|
||||
return res ? res : std::const_pointer_cast<spot::twa_graph>(prev);
|
||||
}
|
||||
|
||||
|
|
@ -816,8 +827,7 @@ namespace spot
|
|||
|
||||
const_twa_graph_ptr prev = a;
|
||||
dict d;
|
||||
d.cand_size = (max_states < 0) ?
|
||||
stats_reachable(prev).states - 1 : max_states;
|
||||
d.cand_size = (max_states < 0) ? prev->num_states() - 1 : max_states;
|
||||
if (d.cand_size == 0)
|
||||
return nullptr;
|
||||
|
||||
|
|
@ -829,7 +839,7 @@ namespace spot
|
|||
while (next && d.cand_size > 0)
|
||||
{
|
||||
// Warns the satsolver of the number of assumptions.
|
||||
int n_assumptions = (int) d.cand_size < sat_incr_steps ?
|
||||
int n_assumptions = (int) d.cand_size <= sat_incr_steps ?
|
||||
d.cand_size - 1 : sat_incr_steps;
|
||||
trace << "number of assumptions:" << n_assumptions << '\n';
|
||||
satsolver solver;
|
||||
|
|
@ -867,34 +877,36 @@ namespace spot
|
|||
solver.add({-assume_lit, assume_lit - 1, 0});
|
||||
}
|
||||
}
|
||||
t1.stop("encode");
|
||||
|
||||
t1.start("solve");
|
||||
if (n_assumptions)
|
||||
{
|
||||
trace << "solver.assume(" << d.nvars + n_assumptions << ")\n";
|
||||
solver.assume(d.nvars + n_assumptions);
|
||||
}
|
||||
t1.stop("encode");
|
||||
t1.start("solve");
|
||||
satsolver::solution_pair solution = solver.get_solution();
|
||||
t1.stop("solve");
|
||||
|
||||
if (solution.second.empty() && n_assumptions) // UNSAT
|
||||
{
|
||||
print_log(t1, prev->num_states(),
|
||||
d.cand_size - n_assumptions, nullptr, solver);
|
||||
trace << "UNSAT\n";
|
||||
return dichotomy_dtba_research(n_assumptions, d, solver, t1, prev,
|
||||
state_based);
|
||||
return dichotomy_dtba_research(n_assumptions, d, solver,
|
||||
prev, state_based);
|
||||
}
|
||||
|
||||
t1.stop("solve");
|
||||
trace << "SAT, restarting from zero\n";
|
||||
next = solution.second.empty() ? nullptr :
|
||||
sat_build(solution.second, d, prev, state_based);
|
||||
print_log(t1, d.cand_size - n_assumptions, next, solver); // SPOT_SATLOG.
|
||||
print_log(t1, prev->num_states(),
|
||||
d.cand_size - n_assumptions, next, solver);
|
||||
|
||||
if (next)
|
||||
{
|
||||
prev = next;
|
||||
d = dict();
|
||||
d.cand_size = stats_reachable(prev).states - 1;
|
||||
d.cand_size = prev->num_states() - 1;
|
||||
if (d.cand_size == 0)
|
||||
next = nullptr;
|
||||
}
|
||||
|
|
@ -912,8 +924,7 @@ namespace spot
|
|||
(": dtba_sat_minimize_incr() can only work with Büchi acceptance.");
|
||||
const_twa_graph_ptr prev = a;
|
||||
dict d;
|
||||
d.cand_size = (max_states < 0) ?
|
||||
stats_reachable(prev).states - 1 : max_states;
|
||||
d.cand_size = (max_states < 0) ? prev->num_states() - 1 : max_states;
|
||||
if (d.cand_size == 0)
|
||||
return nullptr;
|
||||
|
||||
|
|
@ -937,7 +948,7 @@ namespace spot
|
|||
t1.stop("solve");
|
||||
next = solution.second.empty() ? nullptr :
|
||||
sat_build(solution.second, d, prev, state_based);
|
||||
print_log(t1, d.cand_size, next, solver); // If SPOT_SATLOG is set.
|
||||
print_log(t1, prev->num_states(), d.cand_size, next, solver);
|
||||
|
||||
trace << "First iteration done\n";
|
||||
|
||||
|
|
@ -950,27 +961,27 @@ namespace spot
|
|||
for (int k = 0; next && d.cand_size > 0 && (naive || k < sat_incr_steps);
|
||||
++k)
|
||||
{
|
||||
t1.start("encode");
|
||||
prev = next;
|
||||
int reach_states = stats_reachable(prev).states;
|
||||
int reach_states = prev->num_states();
|
||||
cnf_comment("Next iteration: ", reach_states - 1, "\n");
|
||||
|
||||
trace << "Encoding the deletion of state " << reach_states - 1 << '\n';
|
||||
|
||||
timer_map t2;
|
||||
t2.start("encode");
|
||||
// Add new constraints.
|
||||
for (unsigned i = reach_states - 1; i < d.cand_size; ++i)
|
||||
for (unsigned l = 0; l < alpha_size; ++l)
|
||||
for (unsigned j = 0; j < orig_cand_size; ++j)
|
||||
solver.add({-d.transid(j, l, i), 0});
|
||||
|
||||
t2.stop("encode");
|
||||
d.cand_size = reach_states - 1;
|
||||
t1.stop("encode");
|
||||
t1.start("solve");
|
||||
t2.start("solve");
|
||||
satsolver::solution_pair solution = solver.get_solution();
|
||||
t1.stop("solve");
|
||||
t2.stop("solve");
|
||||
next = solution.second.empty() ? nullptr :
|
||||
sat_build(solution.second, d, prev, state_based);
|
||||
print_log(t1, d.cand_size, next, solver); // If SPOT_SATLOG is set.
|
||||
print_log(t2, prev->num_states(),
|
||||
d.cand_size, next, solver);
|
||||
}
|
||||
|
||||
if (next)
|
||||
|
|
@ -978,7 +989,7 @@ namespace spot
|
|||
trace << "Starting from scratch\n";
|
||||
prev = next;
|
||||
d = dict();
|
||||
d.cand_size = stats_reachable(prev).states - 1;
|
||||
d.cand_size = prev->num_states() - 1;
|
||||
if (d.cand_size == 0)
|
||||
next = nullptr;
|
||||
}
|
||||
|
|
@ -991,8 +1002,7 @@ namespace spot
|
|||
dtba_sat_minimize(const const_twa_graph_ptr& a,
|
||||
bool state_based, int max_states)
|
||||
{
|
||||
int n_states = (max_states < 0) ?
|
||||
stats_reachable(a).states : max_states + 1;
|
||||
int n_states = (max_states < 0) ? a->num_states() : max_states + 1;
|
||||
|
||||
twa_graph_ptr prev = nullptr;
|
||||
for (;;)
|
||||
|
|
@ -1002,7 +1012,7 @@ namespace spot
|
|||
if (!next)
|
||||
return prev;
|
||||
else
|
||||
n_states = stats_reachable(next).states;
|
||||
n_states = next->num_states();
|
||||
prev = next;
|
||||
}
|
||||
SPOT_UNREACHABLE();
|
||||
|
|
@ -1014,7 +1024,7 @@ namespace spot
|
|||
{
|
||||
trace << "Dichomoty\n";
|
||||
if (max_states < 0)
|
||||
max_states = stats_reachable(a).states - 1;
|
||||
max_states = a->num_states() - 1;
|
||||
int min_states = 1;
|
||||
if (langmap)
|
||||
{
|
||||
|
|
@ -1036,7 +1046,7 @@ namespace spot
|
|||
else
|
||||
{
|
||||
prev = next;
|
||||
max_states = stats_reachable(next).states - 1;
|
||||
max_states = next->num_states() - 1;
|
||||
}
|
||||
}
|
||||
return prev;
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@
|
|||
#include <spot/twaalgos/sbacc.hh>
|
||||
#include <spot/twaalgos/sccfilter.hh>
|
||||
#include <spot/twaalgos/sccinfo.hh>
|
||||
#include <spot/twaalgos/stats.hh>
|
||||
|
||||
// If you set the SPOT_TMPKEEP environment variable the temporary
|
||||
// file used to communicate with the sat solver will be left in
|
||||
|
|
@ -624,7 +623,7 @@ namespace spot
|
|||
{
|
||||
unsigned nacc = d.cand_nacc;
|
||||
cnf_comment("transitions belong to exactly one of the", nacc,
|
||||
"acceptance set\n");
|
||||
"acceptance sets\n");
|
||||
for (unsigned l = 0; l < alpha_size; ++l)
|
||||
for (unsigned q1 = 0; q1 < d.cand_size; ++q1)
|
||||
for (unsigned q2 = 0; q2 < d.cand_size; ++q2)
|
||||
|
|
@ -982,6 +981,7 @@ namespace spot
|
|||
#endif
|
||||
|
||||
a->merge_edges();
|
||||
a->purge_unreachable_states();
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
|
@ -1023,7 +1023,7 @@ namespace spot
|
|||
if (!solution.second.empty())
|
||||
res = sat_build(solution.second, d, a, state_based);
|
||||
|
||||
print_log(t, target_state_number, res, solver); // if SPOT_SATLOG is set.
|
||||
print_log(t, a->num_states(), target_state_number, res, solver);
|
||||
|
||||
trace << "dtwa_sat_synthetize(...) = " << res << '\n';
|
||||
return res;
|
||||
|
|
@ -1066,7 +1066,6 @@ namespace spot
|
|||
dichotomy_dtwa_research(int max,
|
||||
dict& d,
|
||||
satsolver& solver,
|
||||
timer_map& t1,
|
||||
const_twa_graph_ptr& prev,
|
||||
bool state_based)
|
||||
{
|
||||
|
|
@ -1081,35 +1080,46 @@ namespace spot
|
|||
trace << "min:" << min << ", max:" << max << ", target:" << target
|
||||
<< '\n';
|
||||
|
||||
timer_map t1;
|
||||
t1.start("encode");
|
||||
solver.assume(d.nvars + target);
|
||||
t1.stop("encode");
|
||||
trace << "solver.assume(" << d.nvars + target << ")\n";
|
||||
|
||||
t1.start("solve");
|
||||
satsolver::solution_pair solution = solver.get_solution();
|
||||
t1.stop("solve");
|
||||
if (solution.second.empty())
|
||||
{
|
||||
trace << "UNSAT\n";
|
||||
max = target;
|
||||
print_log(t1, prev->num_states(), d.cand_size - target,
|
||||
nullptr, solver);
|
||||
}
|
||||
else
|
||||
{
|
||||
trace << "SAT\n";
|
||||
res = sat_build(solution.second, d, prev, state_based);
|
||||
min = d.cand_size - stats_reachable(res).states + 1;
|
||||
min = d.cand_size - res->num_states() + 1;
|
||||
print_log(t1, prev->num_states(), d.cand_size - target,
|
||||
res, solver);
|
||||
}
|
||||
}
|
||||
|
||||
trace << "End with max:" << max << ", min:" << min << '\n';
|
||||
if (!res)
|
||||
{
|
||||
trace << "All assumptions are UNSAT, let's try without...";
|
||||
trace << "All assumptions are UNSAT, let's try without...\n";
|
||||
timer_map t1;
|
||||
t1.start("encode");
|
||||
t1.stop("encode");
|
||||
t1.start("solve");
|
||||
satsolver::solution_pair solution = solver.get_solution();
|
||||
t1.stop("solve");
|
||||
trace << (solution.second.empty() ? "UNSAT!\n" : "SAT\n");
|
||||
res = solution.second.empty() ? nullptr :
|
||||
sat_build(solution.second, d, prev, state_based);
|
||||
print_log(t1, prev->num_states(), d.cand_size - target, res, solver);
|
||||
}
|
||||
|
||||
t1.stop("solve");
|
||||
print_log(t1, d.cand_size - target , res, solver); // SPOT_SATLOG.
|
||||
return res ? res : std::const_pointer_cast<spot::twa_graph>(prev);
|
||||
}
|
||||
|
||||
|
|
@ -1128,8 +1138,7 @@ namespace spot
|
|||
|
||||
const_twa_graph_ptr prev = a;
|
||||
dict d(prev);
|
||||
d.cand_size = (max_states < 0) ?
|
||||
stats_reachable(prev).states - 1 : max_states;
|
||||
d.cand_size = (max_states < 0) ? prev->num_states() - 1 : max_states;
|
||||
d.cand_nacc = target_acc_number;
|
||||
d.cand_acc = target_acc;
|
||||
if (d.cand_size == 0)
|
||||
|
|
@ -1144,9 +1153,9 @@ namespace spot
|
|||
while (next && d.cand_size > 0)
|
||||
{
|
||||
// Warns the satsolver of the number of assumptions.
|
||||
int n_assumptions = (int) d.cand_size < sat_incr_steps ?
|
||||
int n_assumptions = (int) d.cand_size <= sat_incr_steps ?
|
||||
d.cand_size - 1 : sat_incr_steps;
|
||||
trace << "number of assumptions:" << n_assumptions << '\n';
|
||||
trace << "number of assumptions: " << n_assumptions << '\n';
|
||||
satsolver solver;
|
||||
solver.set_nassumptions_vars(n_assumptions);
|
||||
|
||||
|
|
@ -1182,35 +1191,39 @@ namespace spot
|
|||
solver.add({-assume_lit, assume_lit - 1, 0});
|
||||
}
|
||||
}
|
||||
t1.stop("encode");
|
||||
|
||||
t1.start("solve");
|
||||
if (n_assumptions)
|
||||
{
|
||||
trace << "solver.assume(" << d.nvars + n_assumptions << ")\n";
|
||||
solver.assume(d.nvars + n_assumptions);
|
||||
}
|
||||
t1.stop("encode");
|
||||
t1.start("solve");
|
||||
satsolver::solution_pair solution = solver.get_solution();
|
||||
t1.stop("solve");
|
||||
|
||||
if (solution.second.empty() && n_assumptions) // UNSAT
|
||||
{
|
||||
print_log(t1, prev->num_states(),
|
||||
d.cand_size - n_assumptions, nullptr, solver);
|
||||
trace << "UNSAT\n";
|
||||
twa_graph_ptr res = dichotomy_dtwa_research(n_assumptions, d, solver,
|
||||
t1, prev, state_based);
|
||||
prev, state_based);
|
||||
return res == a ? nullptr : res;
|
||||
}
|
||||
|
||||
t1.stop("solve");
|
||||
trace << "SAT, restarting from zero\n";
|
||||
next = solution.second.empty() ? nullptr :
|
||||
sat_build(solution.second, d, prev, state_based);
|
||||
print_log(t1, d.cand_size - n_assumptions, next, solver); // SPOT_SATLOG.
|
||||
print_log(t1, prev->num_states(),
|
||||
d.cand_size - n_assumptions, next, solver);
|
||||
|
||||
if (next)
|
||||
{
|
||||
prev = next;
|
||||
trace << "prev has " << prev->num_states() << '\n';
|
||||
d = dict(prev);
|
||||
d.cand_size = stats_reachable(prev).states - 1;
|
||||
d.cand_size = prev->num_states() - 1;
|
||||
d.cand_nacc = target_acc_number;
|
||||
d.cand_acc = target_acc;
|
||||
if (d.cand_size == 0)
|
||||
|
|
@ -1233,7 +1246,7 @@ namespace spot
|
|||
|
||||
dict d(prev);
|
||||
d.cand_size = (max_states < 0) ?
|
||||
stats_reachable(prev).states - 1 : max_states;
|
||||
prev->num_states() - 1 : max_states;
|
||||
d.cand_nacc = target_acc_number;
|
||||
d.cand_acc = target_acc;
|
||||
if (d.cand_size == 0)
|
||||
|
|
@ -1260,9 +1273,9 @@ namespace spot
|
|||
t1.stop("solve");
|
||||
next = solution.second.empty() ? nullptr :
|
||||
sat_build(solution.second, d, prev, state_based);
|
||||
print_log(t1, d.cand_size, next, solver); // If SPOT_SATLOG is set.
|
||||
print_log(t1, prev->num_states(), d.cand_size, next, solver);
|
||||
|
||||
trace << "First iteraton done\n";
|
||||
trace << "First iteration done\n";
|
||||
|
||||
// Compute the AP used.
|
||||
bdd ap = prev->ap_vars();
|
||||
|
|
@ -1273,27 +1286,25 @@ namespace spot
|
|||
for (int k = 0; next && d.cand_size > 0 && (naive || k < sat_incr_steps);
|
||||
++k)
|
||||
{
|
||||
t1.start("encode");
|
||||
prev = next;
|
||||
int reach_states = stats_reachable(prev).states;
|
||||
cnf_comment("Next iteration:", reach_states - 1, "\n");
|
||||
|
||||
int reach_states = prev->num_states();
|
||||
trace << "Encoding the deletion of state " << reach_states - 1 << '\n';
|
||||
|
||||
cnf_comment("Next iteration:", reach_states - 1, "\n");
|
||||
timer_map t2;
|
||||
t2.start("encode");
|
||||
// Add new constraints.
|
||||
for (unsigned i = reach_states - 1; i < d.cand_size; ++i)
|
||||
for (unsigned l = 0; l < alpha_size; ++l)
|
||||
for (unsigned j = 0; j < orig_cand_size; ++j)
|
||||
solver.add({-d.transid(j, l, i), 0});
|
||||
|
||||
t2.stop("encode");
|
||||
d.cand_size = reach_states - 1;
|
||||
t1.stop("encode");
|
||||
t1.start("solve");
|
||||
t2.start("solve");
|
||||
solution = solver.get_solution();
|
||||
t1.stop("solve");
|
||||
t2.stop("solve");
|
||||
next = solution.second.empty() ? nullptr :
|
||||
sat_build(solution.second, d, prev, state_based);
|
||||
print_log(t1, d.cand_size, next, solver); // If SPOT_SATLOG is set.
|
||||
print_log(t2, prev->num_states(), d.cand_size, next, solver);
|
||||
}
|
||||
|
||||
if (next)
|
||||
|
|
@ -1301,7 +1312,7 @@ namespace spot
|
|||
trace << "Starting from scratch\n";
|
||||
prev = next;
|
||||
d = dict(prev);
|
||||
d.cand_size = stats_reachable(prev).states - 1;
|
||||
d.cand_size = prev->num_states() - 1;
|
||||
d.cand_nacc = target_acc_number;
|
||||
d.cand_acc = target_acc;
|
||||
if (d.cand_size == 0)
|
||||
|
|
@ -1320,8 +1331,7 @@ namespace spot
|
|||
bool state_based, int max_states,
|
||||
bool colored)
|
||||
{
|
||||
int n_states = (max_states < 0) ?
|
||||
stats_reachable(a).states : max_states + 1;
|
||||
int n_states = (max_states < 0) ? a->num_states() : max_states + 1;
|
||||
|
||||
twa_graph_ptr prev = nullptr;
|
||||
for (;;)
|
||||
|
|
@ -1333,7 +1343,7 @@ namespace spot
|
|||
if (!next)
|
||||
return prev;
|
||||
else
|
||||
n_states = stats_reachable(next).states;
|
||||
n_states = next->num_states();
|
||||
prev = next;
|
||||
}
|
||||
SPOT_UNREACHABLE();
|
||||
|
|
@ -1348,7 +1358,7 @@ namespace spot
|
|||
{
|
||||
trace << "Dichotomy\n";
|
||||
if (max_states < 1)
|
||||
max_states = stats_reachable(a).states - 1;
|
||||
max_states = a->num_states() - 1;
|
||||
int min_states = 1;
|
||||
if (langmap)
|
||||
{
|
||||
|
|
@ -1373,7 +1383,7 @@ namespace spot
|
|||
else
|
||||
{
|
||||
prev = next;
|
||||
max_states = stats_reachable(next).states - 1;
|
||||
max_states = next->num_states() - 1;
|
||||
}
|
||||
}
|
||||
return prev;
|
||||
|
|
@ -1401,10 +1411,10 @@ namespace spot
|
|||
bool sat_langmap = om.get("sat-langmap", 0);
|
||||
int states = om.get("states", -1);
|
||||
int max_states = om.get("max-states", -1);
|
||||
auto accstr = om.get_str("acc");
|
||||
std::string accstr = om.get_str("acc");
|
||||
bool colored = om.get("colored", 0);
|
||||
int preproc = om.get("preproc", 3);
|
||||
|
||||
set_satlog_filename(om.get_str("log"));
|
||||
|
||||
// Set default sat-incr-steps value if not provided and used.
|
||||
if (sat_incr == 1 && !sat_incr_steps) // Assume
|
||||
|
|
@ -1551,7 +1561,7 @@ namespace spot
|
|||
|
||||
if (a)
|
||||
{
|
||||
if (state_based)
|
||||
if (state_based || colored)
|
||||
a = scc_filter_states(a);
|
||||
else
|
||||
a = scc_filter(a);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// -*- coding: utf-8 -*-
|
||||
// Copyright (C) 2013, 2014, 2015 Laboratoire de Recherche et
|
||||
// Copyright (C) 2013, 2014, 2015, 2018 Laboratoire de Recherche et
|
||||
// Développement de l'Epita.
|
||||
//
|
||||
// This file is part of Spot, a model checking library.
|
||||
|
|
@ -140,6 +140,7 @@ namespace spot
|
|||
/// fixed number of states before starting from scratch
|
||||
/// incr < 0 // use satsolver incrementally, never restart
|
||||
/// colored = 1 // build a colored TωA
|
||||
/// log = "filename"
|
||||
///
|
||||
SPOT_API twa_graph_ptr
|
||||
sat_minimize(twa_graph_ptr aut, const char* opt, bool state_based = false);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue