Commit c766f58d authored by Alexandre Duret-Lutz's avatar Alexandre Duret-Lutz

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.
parent 52660108
Pipeline #1210 passed with stages
in 253 minutes and 48 seconds
...@@ -40,6 +40,15 @@ New in spot 2.5.2.dev (not yet released) ...@@ -40,6 +40,15 @@ New in spot 2.5.2.dev (not yet released)
example, the translation of GF(a <-> XXb) to transition-based example, the translation of GF(a <-> XXb) to transition-based
Büchi went from 9 to 5 states using that construction. Büchi went from 9 to 5 states using that construction.
- Slightly improved log output for the SAT-based minimization
functions. The CSV log files now include an additional column
with the size of the reference automaton, and they now have a
header line. These log files give more details and are more
accurate in the case of incremental SAT-solving. The python
bindings for sat_minimize() now have a display_log and return_log
options; there are demonstrated on the new
https://spot.lrde.epita.fr/ipynb/satmin.html page.
Bugs fixed: Bugs fixed:
- "autfilt --cobuchi --small/--det" would turn a transition-based - "autfilt --cobuchi --small/--det" would turn a transition-based
......
#!/usr/bin/env python3 #!/usr/bin/env python3
# Copyright (C) 2016, 2017 Laboratoire de Recherche et Développement de # Copyright (C) 2016-2018 Laboratoire de Recherche et Développement de
# l'Epita (LRDE). # l'Epita (LRDE).
# #
# This file is part of Spot, a model checking library. # This file is part of Spot, a model checking library.
...@@ -272,7 +272,7 @@ def get_last_successful(n, category, pattern): ...@@ -272,7 +272,7 @@ def get_last_successful(n, category, pattern):
+ '.satlog', 'r') + '.satlog', 'r')
log_csv = csv.reader(log) log_csv = csv.reader(log)
for line in log_csv: for line in log_csv:
min_val = line[1] min_val = line[2]
return '$\\le$' + min_val return '$\\le$' + min_val
except Exception: except Exception:
return '' return ''
......
...@@ -79,7 +79,7 @@ sub getlastsuccesful($$) ...@@ -79,7 +79,7 @@ sub getlastsuccesful($$)
while (my $line = <LOG>) while (my $line = <LOG>)
{ {
my @f = split(/,/, $line); my @f = split(/,/, $line);
$min = $f[1] if $f[1] ne ''; $min = $f[2] if $f[2] ne '';
} }
$min = ", \$\\le\$$min" if $min ne ""; $min = ", \$\\le\$$min" if $min ne "";
return $min; return $min;
......
...@@ -72,7 +72,7 @@ sub getlastsuccesful($$) ...@@ -72,7 +72,7 @@ sub getlastsuccesful($$)
while (my $line = <LOG>) while (my $line = <LOG>)
{ {
my @f = split(/,/, $line); my @f = split(/,/, $line);
$min = $f[1] if $f[1] ne ''; $min = $f[2] if $f[2] ne '';
} }
$min = ", \$\\le\$$min" if $min ne ""; $min = ", \$\\le\$$min" if $min ne "";
return $min; return $min;
......
...@@ -91,7 +91,7 @@ sub getlastsuccesful($$) ...@@ -91,7 +91,7 @@ sub getlastsuccesful($$)
while (my $line = <LOG>) while (my $line = <LOG>)
{ {
my @f = split(/,/, $line); my @f = split(/,/, $line);
$min = $f[1] if $f[1] ne ''; $min = $f[2] if $f[2] ne '';
} }
$min = ", \$\\le\$$min" if $min ne ""; $min = ", \$\\le\$$min" if $min ne "";
return $min; return $min;
......
...@@ -93,7 +93,7 @@ sub getlastsuccesful($$) ...@@ -93,7 +93,7 @@ sub getlastsuccesful($$)
while (my $line = <LOG>) while (my $line = <LOG>)
{ {
my @f = split(/,/, $line); my @f = split(/,/, $line);
$min = $f[1] if $f[1] ne ''; $min = $f[2] if $f[2] ne '';
} }
$min = ", \$\\le\$$min" if $min ne ""; $min = ", \$\\le\$$min" if $min ne "";
return $min; return $min;
......
...@@ -92,7 +92,7 @@ sub getlastsuccesful($$) ...@@ -92,7 +92,7 @@ sub getlastsuccesful($$)
while (my $line = <LOG>) while (my $line = <LOG>)
{ {
my @f = split(/,/, $line); my @f = split(/,/, $line);
$min = $f[1] if $f[1] ne ''; $min = $f[2] if $f[2] ne '';
} }
$min = ", \$\\le\$$min" if $min ne ""; $min = ", \$\\le\$$min" if $min ne "";
return $min; return $min;
......
...@@ -150,13 +150,14 @@ to the recurrence (or the persistence) class. ...@@ -150,13 +150,14 @@ to the recurrence (or the persistence) class.
\fBSPOT_SATLOG\fR \fBSPOT_SATLOG\fR
If set to a filename, the SAT-based minimization routines will append If set to a filename, the SAT-based minimization routines will append
statistics about each iteration to the named file. Each line lists statistics about each iteration to the named file. Each line lists
the following comma-separated values: requested number of states, the following comma-separated values: input number of states, target
number of reachable states in the output, number of edges in the number of states, number of reachable states in the output, number of
output, number of transitions in the output, number of variables in edges in the output, number of transitions in the output, number of
the SAT problem, number of clauses in the SAT problem, user time for variables in the SAT problem, number of clauses in the SAT problem,
encoding the SAT problem, system time for encoding the SAT problem, user time for encoding the SAT problem, system time for encoding the
user time for solving the SAT problem, system time for solving the SAT SAT problem, user time for solving the SAT problem, system time for
problem. solving the SAT problem, automaton produced at this step in HOA
format.
.TP .TP
\fBSPOT_SATSOLVER\fR \fBSPOT_SATSOLVER\fR
......
...@@ -29,7 +29,7 @@ Let us first state a few facts about this minimization procedure. ...@@ -29,7 +29,7 @@ Let us first state a few facts about this minimization procedure.
use state-based acceptance. (They simply restrict all the outgoing use state-based acceptance. (They simply restrict all the outgoing
transitions of a state to belong to the same acceptance sets.) transitions of a state to belong to the same acceptance sets.)
4) Spot is built using PicoSAT call_version()[:results raw]. 4) Spot is built using PicoSAT call_version()[:results raw].
This solver was chosen for its performances, simplicity of This solver was chosen for its performance, simplicity of
integration and license compatibility. However, it is integration and license compatibility. However, it is
still possible to use an external SAT solver (as described below). still possible to use an external SAT solver (as described below).
5) [[file:ltl2tgba.org][=ltl2tgba=]] and [[file:dstar2tgba.org][=dstar2tgba=]] will always try to output an automaton. 5) [[file:ltl2tgba.org][=ltl2tgba=]] and [[file:dstar2tgba.org][=dstar2tgba=]] will always try to output an automaton.
...@@ -730,48 +730,52 @@ export SPOT_SATLOG=stats.csv ...@@ -730,48 +730,52 @@ export SPOT_SATLOG=stats.csv
ltlfilt -f 'Ga R (F!b & (c U b))' -l | ltlfilt -f 'Ga R (F!b & (c U b))' -l |
ltl2dstar --ltl2nba=spin:ltl2tgba@-Ds - - | ltl2dstar --ltl2nba=spin:ltl2tgba@-Ds - - |
dstar2tgba -D -x sat-minimize,sat-acc=2 --stats='input(states=%S) output(states=%s, acc-sets=%a, det=%d)' dstar2tgba -D -x sat-minimize,sat-acc=2 --stats='input(states=%S) output(states=%s, acc-sets=%a, det=%d)'
echo ==== stats.csv ====
cat stats.csv cat stats.csv
#+END_SRC #+END_SRC
#+RESULTS: #+RESULTS:
: input(states=11) output(states=5, acc-sets=2, det=1) : input(states=11) output(states=5, acc-sets=2, det=1)
: 9,9,36,72,44064,9043076,616,18,258,24 : ==== stats.csv ====
: 8,7,29,56,19712,3493822,236,9,135,6 : input.states,target.states,reachable.states,edges,transitions,variables,clauses,enc.user,enc.sys,sat.user,sat.sys,automaton
: 6,6,25,48,10512,1362749,97,4,42,2 : 10,5,,,,13600,1543042,59,3,187,0,
: 5,,,,7200,784142,65,2,40,2 : 10,7,7,33,56,26656,4247441,162,7,775,0,"HOA: v1 States: 7 Start: 0 AP: 3 ""a"" ""b"" ""c"" acc-name: generalized-Buchi 2 Acceptance: 2 Inf(0)&Inf(1) properties: trans-labels explicit-labels trans-acc complete deterministic --BODY-- State: 0 [!0&!1&2] 0 {1} [!0&1] 0 {0} [!0&!1&!2] 1 {0} [0&!1&!2] 1 [0&!1&2] 2 {1} [0&1&!2] 4 [0&1&2] 4 {0} State: 1 [0&!1] 1 {0} [!0&!1&!2 | 0&1] 1 [!0&1 | !0&2] 3 {0} State: 2 [!0&!1&2] 0 {1} [!0&1] 0 {0 1} [!0&!1&!2] 1 [0&!1&2] 2 [0&!1&!2] 3 {1} [0&1] 5 {0 1} State: 3 [!1&!2] 3 [1 | 2] 3 {0} State: 4 [!0&!1&2] 0 {0 1} [!0&1] 0 {0} [!0&!1&!2] 1 [0&1] 4 {0} [0&!1&2] 5 {0} [0&!1&!2] 6 State: 5 [!0&1 | !0&2] 0 {0 1} [!0&!1&!2] 1 [0&1 | 0&2] 5 {0 1} [0&!1&!2] 6 {0} State: 6 [!0&!1&!2] 1 [!0&1&!2] 1 {0 1} [!0&1&2] 1 {1} [!0&!1&2] 3 {0 1} [0] 6 {0 1} --END--"
: 7,6,6,26,48,10512,1376507,50,0,269,0,"HOA: v1 States: 6 Start: 0 AP: 3 ""a"" ""b"" ""c"" acc-name: generalized-Buchi 2 Acceptance: 2 Inf(0)&Inf(1) properties: trans-labels explicit-labels trans-acc complete deterministic --BODY-- State: 0 [!0&!1&2] 0 {1} [!0&1] 0 {0} [!0&!1&!2] 1 [0&!1&!2] 1 {0 1} [0&!1&2] 2 {1} [0&1] 3 {0} State: 1 [t] 1 State: 2 [!0&!1&2] 0 {1} [!0&1] 0 {0} [!1&!2] 1 [0&!1&2] 2 {1} [0&1] 4 {1} State: 3 [!0&!1&2] 0 {1} [!0&1] 0 [!0&!1&!2] 1 [0&1] 3 [0&!1&2] 4 {1} [0&!1&!2] 5 {1} State: 4 [!0&!1&2 | !0&1&!2] 0 {0 1} [!0&1&2] 0 {0} [!0&!1&!2] 1 [0&1 | 0&2] 4 {0 1} [0&!1&!2] 5 State: 5 [!0&!1&!2] 1 [!0&1 | !0&2] 1 {0 1} [0] 5 {0 1} --END--"
The generated CSV file use the following columns: The generated CSV file use the following columns:
- the n passed to the SAT-based minimization algorithm - =input.states=: the number of states of the reference automaton at this step
- =target.states=: the n passed to the SAT-based minimization algorithm
(it means the input automaton had n+1 states) (it means the input automaton had n+1 states)
- number of reachable states in the output of - =reachable.states=: number of reachable states in the output of
the minimization. the minimization (with any luck this can be smaller than =target.states=)
- number of edges in the output - =edges=, =transitions=: number of edges or transitions in the output
- number of transitions - =variables=, =clauses=: size of the SAT problem
- number of variables in the SAT problem - =enc.user=, =enc.sys=: user and system time for encoding the SAT problem
- number of clauses in the SAT problem - =sat.user=, =sat.sys=: user and system time for solving the SAT problem
- user time for encoding the SAT problem - =automaton=: the automaton produced in HOA format.
- system time for encoding the SAT problem
- user time for solving the SAT problem Times are measured with the times() function, and expressed in ticks
- system time for solving the SAT problem (usually: 1/100 of seconds). The encoding of the automaton in the CSV
- automaton produced file follows RFC4180 in escaping double-quote by doubling them.
Times are measured with the times() function, and expressed In the above example, the DRA produced by =ltl2dstar= had 11 states.
in ticks (usually: 1/100 of seconds). In the first line of the =stats.csv= file, you can see the
minimization function had a 10-state input, which means that
In the above example, the input DRA had 11 =dstar2tgba= first reduced the 11-state (complete) DRA into a 10-state
states. In the first line of the =stats.csv= file, you can see the (complete) DBA before calling the SAT-based minimization. This first
minimization function searching for a 9 state DTBA and obtaining a line shows the SAT-based minimization for a (complete) 5-state DTGBA
8-state solution. (Since the minimization function searched for a and failing to find one. Then on the next line it looks for a 7-state
9-state DTBA, it means it received a 10-state complete DTBA, so the solution, finds one. Finally, it finds a (complete) 6-state solution,
processings performed before the minimization procedure managed to now using the 7-state version as reference automaton to further
convert the 11-state DRA into a 10-state DTBA.) Starting from the simplify the problem.
8-state solution, it looked for (and found) a 7-state solution, and
then a 6-state solution. The search for a 5-state complete DTBA The final output is reported with 5 states, because by default we
failed. The final output is reported with 5 states, because by output trim automata. If the =--complete= option had been given, the
default we output trim automata. If the =--complete= option had been useless sink state would have been kept and the output automaton would
given, the useless sink state would have been kept and the output have 6 states.
automaton would have 6 states.
#+BEGIN_SRC sh :results silent :exports results #+BEGIN_SRC sh :results silent :exports results
rm -f output.hoa output2.hoa rm -f output.hoa output2.hoa
#+END_SRC #+END_SRC
* Python interface
See the [[https://spot.lrde.epita.fr/ipynb/satmin.html][=satmin.ipynb=]] notebook.
...@@ -82,3 +82,4 @@ real notebooks instead. ...@@ -82,3 +82,4 @@ real notebooks instead.
- [[https://spot.lrde.epita.fr/ipynb/atva16-fig2b.html][=atva16-fig2b.ipynb=]] second example from our [[https://www.lrde.epita.fr/~adl/dl/adl/duret.16.atva2.pdf][ATVA'16 tool paper]]. - [[https://spot.lrde.epita.fr/ipynb/atva16-fig2b.html][=atva16-fig2b.ipynb=]] second example from our [[https://www.lrde.epita.fr/~adl/dl/adl/duret.16.atva2.pdf][ATVA'16 tool paper]].
- [[https://spot.lrde.epita.fr/ipynb/alternation.html][=alternation.ipynb=]] examples of alternating automata. - [[https://spot.lrde.epita.fr/ipynb/alternation.html][=alternation.ipynb=]] examples of alternating automata.
- [[https://spot.lrde.epita.fr/ipynb/stutter-inv.html][=stutter-inv.ipynb=]] working with stutter-invariant formulas properties. - [[https://spot.lrde.epita.fr/ipynb/stutter-inv.html][=stutter-inv.ipynb=]] working with stutter-invariant formulas properties.
- [[https://spot.lrde.epita.fr/ipynb/satmin.html][=satmin.ipynb=]] Python interface for [[file:satmin.org][SAT-based minimization of deterministic ω-automata]].
...@@ -33,7 +33,7 @@ from spot.aux import \ ...@@ -33,7 +33,7 @@ from spot.aux import \
import subprocess import subprocess
import os import os
import signal import signal
import tempfile
# The parrameters used by default when show() is called on an automaton. # The parrameters used by default when show() is called on an automaton.
_show_default = None _show_default = None
...@@ -927,7 +927,8 @@ for fun in ['remove_x', 'relabel', 'relabel_bse', ...@@ -927,7 +927,8 @@ for fun in ['remove_x', 'relabel', 'relabel_bse',
def sat_minimize(aut, acc=None, colored=False, def sat_minimize(aut, acc=None, colored=False,
state_based=False, states=0, state_based=False, states=0,
max_states=0, sat_naive=False, sat_langmap=False, max_states=0, sat_naive=False, sat_langmap=False,
sat_incr=0, sat_incr_steps=0): sat_incr=0, sat_incr_steps=0,
display_log=False, return_log=False):
args='' args=''
if acc is not None: if acc is not None:
if type(acc) is not str: if type(acc) is not str:
...@@ -950,9 +951,25 @@ def sat_minimize(aut, acc=None, colored=False, ...@@ -950,9 +951,25 @@ def sat_minimize(aut, acc=None, colored=False,
if sat_incr: if sat_incr:
args += ',sat-incr=' + str(sat_incr) args += ',sat-incr=' + str(sat_incr)
args += ',sat-incr-steps=' + str(sat_incr_steps) args += ',sat-incr-steps=' + str(sat_incr_steps)
from spot.impl import sat_minimize as sm from spot.impl import sat_minimize as sm
return sm(aut, args, state_based)
if display_log or return_log:
import pandas as pd
with tempfile.NamedTemporaryFile(dir='.', suffix='.satlog') as t:
args += ',log="{}"'.format(t.name)
aut = sm(aut, args, state_based)
dfrm = pd.read_csv(t.name, dtype=object)
if display_log:
# old versions of ipython do not import display by default
from IPython.display import display
del dfrm['automaton']
display(dfrm)
if return_log:
return aut, dfrm
else:
return aut
else:
return sm(aut, args, state_based)
def parse_word(word, dic=_bdd_dict): def parse_word(word, dic=_bdd_dict):
......
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2013, 2014, 2015, 2016, 2017 Laboratoire de Recherche et // Copyright (C) 2013-2018 Laboratoire de Recherche et Développement
// Développement de l'Epita. // de l'Epita.
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
// //
...@@ -209,7 +209,7 @@ namespace spot ...@@ -209,7 +209,7 @@ namespace spot
return nvars_; 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()); return std::make_pair(get_nb_vars(), get_nb_clauses());
} }
......
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2013, 2017 Laboratoire de Recherche et Développement // Copyright (C) 2013, 2017, 2018 Laboratoire de Recherche et
// de l'Epita. // Développement de l'Epita.
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
// //
...@@ -95,7 +95,7 @@ namespace spot ...@@ -95,7 +95,7 @@ namespace spot
int get_nb_vars() const; int get_nb_vars() const;
/// \brief Returns std::pair<nvars, nclauses>; /// \brief Returns std::pair<nvars, nclauses>;
std::pair<int, int> stats(); std::pair<int, int> stats() const;
/// \brief Add a comment. /// \brief Add a comment.
/// It should be used only in debug mode after providing a satsolver. /// It should be used only in debug mode after providing a satsolver.
......
...@@ -142,50 +142,63 @@ namespace spot ...@@ -142,50 +142,63 @@ namespace spot
return buffer.str(); return buffer.str();
} }
static std::string satlog_filename;
void
set_satlog_filename(const std::string& filename)
{
satlog_filename = filename;
}
void void
print_log(timer_map& t, int target_state_number, print_log(timer_map& t,
twa_graph_ptr& res, satsolver& solver) 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, // Always copy the environment variable into a static string,
// so that we (1) look it up once, but (2) won't crash if the // so that we (1) look it up once, but (2) won't crash if the
// environment is changed. // environment is changed.
static std::string log = []() static std::string envlog = []()
{ {
auto s = getenv("SPOT_SATLOG"); auto s = getenv("SPOT_SATLOG");
return s ? s : ""; 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)
{
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::fstream out(log, std::ostringstream f;
std::ios_base::app | std::ios_base::out); print_hoa(f, res, "l");
out.exceptions(std::ifstream::failbit | std::ifstream::badbit); escape_rfc4180(out << '"', f.str()) << '"';
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";
} }
out << std::endl;
} }
int int
......
// -*- coding: utf-8 -*- // -*- 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. // Développement de l'Epita.
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
...@@ -231,11 +231,17 @@ public: ...@@ -231,11 +231,17 @@ public:
unsigned dst_ref); unsigned dst_ref);
}; };
/// \brief Good old function that prints log is SPOT_SATLOG. It has been /// \brief Give a filename to save the log of the SAT minimization.
/// moved from spot/twaalgos/dt*asat.cc files. ///
void /// This has priority over the SPOT_SATLOG environment variable.
print_log(timer_map& t, int target_state_number, twa_graph_ptr& res, /// Pass en empty string to reset it.
satsolver& solver); 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. /// \brief Returns the number of distinct values containted in a vector.
int int
......
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
#include <spot/twaalgos/dtbasat.hh> #include <spot/twaalgos/dtbasat.hh>
#include <spot/twaalgos/langmap.hh> #include <spot/twaalgos/langmap.hh>
#include <spot/twaalgos/sccinfo.hh> #include <spot/twaalgos/sccinfo.hh>
#include <spot/twaalgos/stats.hh>
// If you set the SPOT_TMPKEEP environment variable the temporary // If you set the SPOT_TMPKEEP environment variable the temporary
// file used to communicate with the sat solver will be left in // file used to communicate with the sat solver will be left in
...@@ -708,6 +707,7 @@ namespace spot ...@@ -708,6 +707,7 @@ namespace spot
} }
#endif #endif
a->merge_edges(); a->merge_edges();
a->purge_unreachable_states();
return a; return a;
} }
} }
...@@ -744,7 +744,8 @@ namespace spot ...@@ -744,7 +744,8 @@ namespace spot
if (!solution.second.empty()) if (!solution.second.empty())
res = sat_build(solution.second, d, a, state_based); 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'; trace << "dtba_sat_synthetize(...) = " << res << '\n';
return res; return res;
...@@ -754,7 +755,6 @@ namespace spot ...@@ -754,7 +755,6 @@ namespace spot
dichotomy_dtba_research(int max, dichotomy_dtba_research(int max,
dict& d, dict& d,
satsolver& solver, satsolver& solver,
timer_map& t1,
const_twa_graph_ptr& prev, const_twa_graph_ptr& prev,
bool state_based) bool state_based)
{ {
...@@ -768,36 +768,47 @@ namespace spot ...@@ -768,36 +768,47 @@ namespace spot
target = (max + min) / 2; target = (max + min) / 2;
trace << "min:" << min << ", max:" << max << ", target:" << target trace << "min:" << min << ", max:" << max << ", target:" << target
<< '\n'; << '\n';
timer_map t1;
t1.start("encode");
solver.assume(d.nvars + target); solver.assume(d.nvars + target);
t1.stop("encode");
trace << "solver.assume(" << d.nvars + target << ")\n"; trace << "solver.assume(" << d.nvars + target << ")\n";
t1.start("solve");
satsolver::solution_pair solution = solver.get_solution(); satsolver::solution_pair solution = solver.get_solution();
t1.stop("solve");
if (solution.second.empty()) if (solution.second.empty())
{ {
trace << "UNSAT\n"; trace << "UNSAT\n";
max = target; max = target;
print_log(t1, prev->num_states(), d.cand_size - target,
nullptr, solver);
} }
else else
{ {
trace << "SAT\n"; trace << "SAT\n";
res = sat_build(solution.second, d, prev, state_based); 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'; trace << "End with max:" << max << ", min:" << min << '\n';
if (!res) 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(); satsolver::solution_pair solution = solver.get_solution();
trace << (solution.second.empty() ? "UNSAT!\n" : "SAT\n"); trace << (solution.second.empty() ? "UNSAT!\n" : "SAT\n");
res = solution.second.empty() ? nullptr : res = solution.second.empty() ? nullptr :
sat_build(solution.second, d, prev, state_based); 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.