satmin: cleanup interfaces and minimization loops
* src/tgbaalgos/dtbasat.cc, src/tgbaalgos/dtbasat.hh: (dtba_sat_minimize): Split into... (dtba_sat_synthetize, dtba_sat_minimize): These. (dtba_sat_minimize_dichotomy): New function. * src/tgbaalgos/dtgbasat.cc, src/tgbaalgos/dtgbasat.hh (dtgba_sat_minimize, dtgba_sat_synthetize): Likewise. * src/tgbatest/ltl2tgba.cc: Adjust to new interface. * src/tgbaalgos/postproc.cc, src/tgbaalgos/postproc.hh: Cleanup option processing for SAT options. * src/tgbatest/satmin.test: Adjust. * src/bin/spot-x.cc, src/bin/man/spot-x.x, NEWS: Document.
This commit is contained in:
parent
b09ef5bea9
commit
fdb157bf94
11 changed files with 393 additions and 222 deletions
8
NEWS
8
NEWS
|
|
@ -58,6 +58,14 @@ New in spot 1.1.4a (not relased)
|
||||||
number of seconds spent building the output automaton (excluding
|
number of seconds spent building the output automaton (excluding
|
||||||
the time spent parsing the input).
|
the time spent parsing the input).
|
||||||
|
|
||||||
|
- ltl2tgba and dstar2tgba can use a SAT-solver to minimize
|
||||||
|
deterministic automata. Doing so is only needed on properties
|
||||||
|
that are stronger than obligations (for which our
|
||||||
|
WDBA-minimization procedure will return a minimimal
|
||||||
|
deterministic automaton more efficiently) and is disabled by
|
||||||
|
default. See the spot-x(7) man page for documentation about the
|
||||||
|
related options: sat-minimize, sat-states, sat-acc, state-based.
|
||||||
|
|
||||||
* All the parsers implemented in Spot now use the same type
|
* All the parsers implemented in Spot now use the same type
|
||||||
to store locations.
|
to store locations.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,39 @@
|
||||||
[NAME]
|
[NAME]
|
||||||
spot-x \- Common fine-tuning options.
|
spot-x \- Common fine-tuning options.
|
||||||
|
|
||||||
[SYNOPSIS]
|
[SYNOPSIS]
|
||||||
.B \-\-extra-options STRING
|
.B \-\-extra-options STRING
|
||||||
.br
|
.br
|
||||||
.B \-x STRING
|
.B \-x STRING
|
||||||
|
|
||||||
[DESCRIPTION]
|
[DESCRIPTION]
|
||||||
.\" Add any additional description here
|
.\" Add any additional description here
|
||||||
|
|
||||||
|
[ENVIRONMENT VARIABLES]
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fBSPOT_SATSOLVER\fR
|
||||||
|
If set, this variable should indicate how to call a SAT\-solver. This
|
||||||
|
is used by the sat\-minimize option described above. The default value
|
||||||
|
is \f(CW"glucose %I >%O"\fR. The escape sequences \f(CW%I\fR and \f(CW%O\fR
|
||||||
|
respectively denote the names of the input and output files. These
|
||||||
|
temporary files are created in the directory specified by \fBSPOT_TMPDIR\fR
|
||||||
|
or \fBTMPDIR\fR (see below).
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fBSPOT_TMPDIR\fR, \fBTMPDIR\fR
|
||||||
|
These variables control in which directory temporary files (e.g.,
|
||||||
|
those who contain the input and output when interfacing with
|
||||||
|
translators) are created. \fBTMPDIR\fR is only read if
|
||||||
|
\fBSPOT_TMPDIR\fR does not exist. If none of these environment
|
||||||
|
variables exist, or if their value is empty, files are created in the
|
||||||
|
current directory.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fBSPOT_TMPKEEP\fR
|
||||||
|
When this variable is defined, temporary files are not removed.
|
||||||
|
This is mostly useful for debugging.
|
||||||
|
|
||||||
[BIBLIOGRAPHY]
|
[BIBLIOGRAPHY]
|
||||||
.TP
|
.TP
|
||||||
1.
|
1.
|
||||||
|
|
@ -13,7 +41,10 @@ Christian Dax, Jochen Eisinger, Felix Klaedtke: Mechanizing the
|
||||||
Powerset Construction for Restricted Classes of
|
Powerset Construction for Restricted Classes of
|
||||||
ω-Automata. Proceedings of ATVA'07. LNCS 4762.
|
ω-Automata. Proceedings of ATVA'07. LNCS 4762.
|
||||||
|
|
||||||
Describes the WDBA-minimization algorithm implemented in Spot.
|
Describes the WDBA-minimization algorithm implemented in Spot. The
|
||||||
|
algorithm used for the tba-det options is also a generalization (to
|
||||||
|
TBA instead of BA) of what they describe in sections 3.2 and 3.3.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
2.
|
2.
|
||||||
Tomáš Babiak, Thomas Badie, Alexandre Duret-Lutz, Mojmír Křetínský,
|
Tomáš Babiak, Thomas Badie, Alexandre Duret-Lutz, Mojmír Křetínský,
|
||||||
|
|
@ -23,6 +54,14 @@ Improvements to LTL Translation. Proceedings of SPIN'13. LNCS 7976.
|
||||||
Describes the compositional suspension, the simulation-based
|
Describes the compositional suspension, the simulation-based
|
||||||
reductions, and the SCC-based simplifications.
|
reductions, and the SCC-based simplifications.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
3.
|
||||||
|
Rüdiger Ehlers: Minimising Deterministic Büchi Automata Precisely using
|
||||||
|
SAT Solving. Proceedings of SAT'10. LNCS 6175.
|
||||||
|
|
||||||
|
Our SAT-based minimization procedures are generalizations of this
|
||||||
|
paper to deal with TBA or TGBA.
|
||||||
|
|
||||||
[SEE ALSO]
|
[SEE ALSO]
|
||||||
.BR ltl2tgba (1)
|
.BR ltl2tgba (1)
|
||||||
.BR ltl2tgta (1)
|
.BR ltl2tgta (1)
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
|
||||||
// -*- coding: utf-8 -*-
|
// -*- coding: utf-8 -*-
|
||||||
// Copyright (C) 2013 Laboratoire de Recherche et Développement
|
// Copyright (C) 2013 Laboratoire de Recherche et Développement
|
||||||
// de l'Epita (LRDE).
|
// de l'Epita (LRDE).
|
||||||
|
|
@ -92,6 +93,37 @@ simulation. Set to 3 to iterate both direct and reverse simulations. \
|
||||||
The default is 3 in --high mode, and 0 otherwise.") },
|
The default is 3 in --high mode, and 0 otherwise.") },
|
||||||
{ DOC("wdba-minimize", "Set to 0 to disable WDBA-minimization. \
|
{ DOC("wdba-minimize", "Set to 0 to disable WDBA-minimization. \
|
||||||
Enabled by default.") },
|
Enabled by default.") },
|
||||||
|
{ DOC("tba-det", "Set to 1 to attempt a powerset determinization \
|
||||||
|
if the TGBA is not already deterministic. Doing so will degeneralize \
|
||||||
|
the automaton. This is disabled by default, unless sat-minimize is set.") },
|
||||||
|
{ DOC("sat-minimize",
|
||||||
|
"Set to 1 to enable SAT-based minimization of deterministic \
|
||||||
|
TGBA: it starts with the number of states of the input, and iteratively \
|
||||||
|
tries to find a deterministic TGBA with one less state. Set to 2 to perform \
|
||||||
|
a binary search instead. Disabled (0) by default. The sat solver to use \
|
||||||
|
can be set with the SPOT_SATSOLVER environment variable (see below). By \
|
||||||
|
default the procedure looks for a TGBA with the same number of acceptance \
|
||||||
|
set; this can be changed with the sat-acc option, or of course by using -B \
|
||||||
|
to construct a Büchi automaton. Enabling SAT-based minimization will \
|
||||||
|
also enable tba-det.") },
|
||||||
|
{ DOC("sat-states",
|
||||||
|
"When this is set to some positive integer, the SAT-based \
|
||||||
|
minimization will attempt to construct a TGBA with the given number of \
|
||||||
|
states. It may however return an automaton with less states if some of \
|
||||||
|
these are unreachable or useless. Setting sat-states automatically \
|
||||||
|
enables sat-minimize, but no iteration is performed. If no equivalent \
|
||||||
|
automaton could be constructed with the given number of states, the original \
|
||||||
|
automaton is returned.") },
|
||||||
|
{ DOC("sat-acc",
|
||||||
|
"When this is set to some positive integer, the SAT-based will \
|
||||||
|
attempt to construct a TGBA with the given number of acceptance sets. \
|
||||||
|
states. It may however return an automaton with less acceptance sets if \
|
||||||
|
some of these are useless. Setting sat-acc automatically \
|
||||||
|
sets sat-minimize to 1 if not set differently.") },
|
||||||
|
{ DOC("state-based",
|
||||||
|
"Set to 1 to instruct the SAT-minimization procedure to produce \
|
||||||
|
a TGBA where all outgoing transition of a state have the same acceptance \
|
||||||
|
sets. By default this is only enabled when option -B is used.") },
|
||||||
{ 0, 0, 0, 0, 0, 0 }
|
{ 0, 0, 0, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,8 +51,10 @@
|
||||||
#define DEBUG 0
|
#define DEBUG 0
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
#define dout out << "c "
|
#define dout out << "c "
|
||||||
|
#define trace std::cerr
|
||||||
#else
|
#else
|
||||||
#define dout while (0) out
|
#define dout while (0) std::cout
|
||||||
|
#define trace dout
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace spot
|
namespace spot
|
||||||
|
|
@ -317,8 +319,32 @@ namespace spot
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
debug_dict = ref->get_dict();
|
debug_dict = ref->get_dict();
|
||||||
|
dout << "ref_size: " << ref_size << "\n";
|
||||||
|
dout << "cand_size: " << d.cand_size << "\n";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// dout << "symmetry-breaking clauses\n";
|
||||||
|
// int k = 1;
|
||||||
|
// bdd all = bddtrue;
|
||||||
|
// while (all != bddfalse)
|
||||||
|
// {
|
||||||
|
// bdd s = bdd_satoneset(all, ap, bddfalse);
|
||||||
|
// all -= s;
|
||||||
|
// for (int q1 = 1; q1 < d.cand_size; ++q1)
|
||||||
|
// for (int q2 = q1 + 2; q2 <= d.cand_size; ++q2)
|
||||||
|
// if ((q1 - 1) * d.cand_size + q2 + 2 <= k)
|
||||||
|
// {
|
||||||
|
// transition t(q1, s, q2);
|
||||||
|
// int ti = d.transid[t];
|
||||||
|
// dout << "¬" << t << "\n";
|
||||||
|
// out << -ti << " 0\n";
|
||||||
|
// ++nclauses;
|
||||||
|
// }
|
||||||
|
// ++k;
|
||||||
|
// }
|
||||||
|
// if (!nclauses)
|
||||||
|
// dout << "(none)\n";
|
||||||
|
|
||||||
dout << "(1) the candidate automaton is complete\n";
|
dout << "(1) the candidate automaton is complete\n";
|
||||||
for (int q1 = 1; q1 <= d.cand_size; ++q1)
|
for (int q1 = 1; q1 <= d.cand_size; ++q1)
|
||||||
{
|
{
|
||||||
|
|
@ -712,86 +738,89 @@ namespace spot
|
||||||
}
|
}
|
||||||
|
|
||||||
tgba_explicit_number*
|
tgba_explicit_number*
|
||||||
dtba_sat_minimize(const tgba* a, int target_state_number,
|
dtba_sat_synthetize(const tgba* a, int target_state_number,
|
||||||
bool state_based)
|
bool state_based)
|
||||||
{
|
{
|
||||||
int ref_states =
|
trace << "dtba_sat_synthetize(..., states = " << target_state_number
|
||||||
target_state_number == -1
|
<< ", state_based = " << state_based << ")\n";
|
||||||
? stats_reachable(a).states - 1
|
std::string solution;
|
||||||
: target_state_number;
|
|
||||||
|
|
||||||
std::string current_solution;
|
|
||||||
std::string last_solution;
|
|
||||||
dict* last = 0;
|
|
||||||
dict* current = 0;
|
dict* current = 0;
|
||||||
temporary_file* cnf = 0;
|
temporary_file* cnf = 0;
|
||||||
temporary_file* out = 0;
|
temporary_file* out = 0;
|
||||||
|
|
||||||
do
|
current = new dict;
|
||||||
{
|
current->cand_size = target_state_number;
|
||||||
if (DEBUG && current)
|
|
||||||
{
|
|
||||||
xrename(out->name(), "dtba-sat.out");
|
|
||||||
xrename(cnf->name(), "dtba-sat.cnf");
|
|
||||||
}
|
|
||||||
delete out;
|
|
||||||
delete cnf;
|
|
||||||
std::swap(current_solution, last_solution);
|
|
||||||
delete last;
|
|
||||||
last = current;
|
|
||||||
current = new dict;
|
|
||||||
current->cand_size = ref_states--;
|
|
||||||
|
|
||||||
cnf = create_tmpfile("dtba-sat-", ".cnf");
|
cnf = create_tmpfile("dtba-sat-", ".cnf");
|
||||||
|
std::fstream cnfs(cnf->name(),
|
||||||
|
std::ios_base::trunc | std::ios_base::out);
|
||||||
|
dtba_to_sat(cnfs, a, *current, state_based);
|
||||||
|
cnfs.close();
|
||||||
|
|
||||||
std::fstream cnfs(cnf->name(),
|
out = create_tmpfile("dtba-sat-", ".out");
|
||||||
std::ios_base::trunc | std::ios_base::out);
|
satsolver(cnf, out);
|
||||||
dtba_to_sat(cnfs, a, *current, state_based);
|
|
||||||
cnfs.close();
|
|
||||||
|
|
||||||
out = create_tmpfile("dtba-sat-", ".out");
|
solution = get_solution(out->name());
|
||||||
satsolver(cnf, out);
|
|
||||||
current_solution = get_solution(out->name());
|
|
||||||
}
|
|
||||||
while (target_state_number == -1 && !current_solution.empty());
|
|
||||||
|
|
||||||
if (target_state_number != -1)
|
tgba_explicit_number* res = 0;
|
||||||
{
|
if (!solution.empty())
|
||||||
std::swap(current_solution, last_solution);
|
res = sat_build(solution, *current, a, state_based);
|
||||||
if (last_solution.empty())
|
|
||||||
{
|
|
||||||
last = 0;
|
|
||||||
delete current;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
last = current;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
delete current;
|
|
||||||
}
|
|
||||||
|
|
||||||
tgba_explicit_number* res;
|
delete current;
|
||||||
if (last == 0)
|
|
||||||
|
if (DEBUG)
|
||||||
{
|
{
|
||||||
res = 0;
|
xrename(out->name(), "dtba-sat.out");
|
||||||
if (DEBUG)
|
xrename(cnf->name(), "dtba-sat.cnf");
|
||||||
{
|
|
||||||
xrename(out->name(), "dtba-sat.out");
|
|
||||||
xrename(cnf->name(), "dtba-sat.cnf");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
res = sat_build(last_solution, *last, a, state_based);
|
|
||||||
delete last;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delete out;
|
delete out;
|
||||||
delete cnf;
|
delete cnf;
|
||||||
|
trace << "dtba_sat_synthetize(...) = " << res << "\n";
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tgba_explicit_number*
|
||||||
|
dtba_sat_minimize(const tgba* a, bool state_based)
|
||||||
|
{
|
||||||
|
int n_states = stats_reachable(a).states;
|
||||||
|
|
||||||
|
tgba_explicit_number* prev = 0;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
tgba_explicit_number* next =
|
||||||
|
dtba_sat_synthetize(prev ? prev : a, --n_states, state_based);
|
||||||
|
if (next == 0)
|
||||||
|
break;
|
||||||
|
delete prev;
|
||||||
|
prev = next;
|
||||||
|
}
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
tgba_explicit_number*
|
||||||
|
dtba_sat_minimize_dichotomy(const tgba* a, bool state_based)
|
||||||
|
{
|
||||||
|
int max_states = stats_reachable(a).states - 1;
|
||||||
|
int min_states = 1;
|
||||||
|
|
||||||
|
tgba_explicit_number* prev = 0;
|
||||||
|
while (min_states <= max_states)
|
||||||
|
{
|
||||||
|
int target = (max_states + min_states) / 2;
|
||||||
|
tgba_explicit_number* next =
|
||||||
|
dtba_sat_synthetize(prev ? prev : a, target, state_based);
|
||||||
|
if (next == 0)
|
||||||
|
{
|
||||||
|
min_states = target + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
delete prev;
|
||||||
|
prev = next;
|
||||||
|
max_states = target - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,32 +20,47 @@
|
||||||
#ifndef SPOT_TGBAALGOS_DTBASAT_HH
|
#ifndef SPOT_TGBAALGOS_DTBASAT_HH
|
||||||
# define SPOT_TGBAALGOS_DTBASAT_HH
|
# define SPOT_TGBAALGOS_DTBASAT_HH
|
||||||
|
|
||||||
#include <iosfwd>
|
|
||||||
#include "tgba/tgba.hh"
|
|
||||||
#include "tgba/tgbaexplicit.hh"
|
#include "tgba/tgbaexplicit.hh"
|
||||||
|
|
||||||
namespace spot
|
namespace spot
|
||||||
{
|
{
|
||||||
/// \brief Attempt to reduce a deterministic TBA with a SAT solver.
|
/// \brief Attempt to synthetize an equivalent deterministic TBA
|
||||||
|
/// with a SAT solver.
|
||||||
///
|
///
|
||||||
/// \param a the TGBA to reduce. It should have only one acceptance
|
/// \param a the input TGBA. It should have only one acceptance
|
||||||
/// set and be deterministic. I.e., it should be a deterministic TBA.
|
/// set and be deterministic. I.e., it should be a deterministic TBA.
|
||||||
///
|
///
|
||||||
/// \param target_state_number the expected number of states wanted
|
/// \param target_state_number the desired number of states wanted
|
||||||
/// in the resulting automaton. If \a target_state_number is left
|
/// in the resulting automaton. The result may have less than \a
|
||||||
/// to its default value of -1, this function will attempt to build
|
/// target_state_number reachable states.
|
||||||
/// the smallest possible deterministic TBA is can produce.
|
|
||||||
///
|
///
|
||||||
/// \param state_based set to true to force all outgoing transitions
|
/// \param state_based set to true to force all outgoing transitions
|
||||||
/// of a state to share the same acceptance condition, effectively
|
/// of a state to share the same acceptance condition, effectively
|
||||||
/// turning the TBA into a BA.
|
/// turning the TBA into a BA.
|
||||||
///
|
///
|
||||||
/// If no automaton with \a target_state_number states is found, or
|
/// If no equivalent deterministic TBA with \a target_state_number
|
||||||
/// (in case <code>target_state_number == -1</code>) if no smaller
|
/// states is found, a null pointer
|
||||||
/// automaton is found, then a null pointer is returned.
|
|
||||||
SPOT_API tgba_explicit_number*
|
SPOT_API tgba_explicit_number*
|
||||||
dtba_sat_minimize(const tgba* a, int target_state_number = -1,
|
dtba_sat_synthetize(const tgba* a, int target_state_number,
|
||||||
bool state_based = false);
|
bool state_based = false);
|
||||||
|
|
||||||
|
/// \brief Attempt to minimize a deterministic TBA with a SAT solver.
|
||||||
|
///
|
||||||
|
/// This calls dtba_sat_synthetize() in a loop, with a decreasing
|
||||||
|
/// number of states, and returns the last successfully built TBA.
|
||||||
|
///
|
||||||
|
/// If no smaller TBA exist, this returns a null pointer.
|
||||||
|
SPOT_API tgba_explicit_number*
|
||||||
|
dtba_sat_minimize(const tgba* a, bool state_based = false);
|
||||||
|
|
||||||
|
/// \brief Attempt to minimize a deterministic TBA with a SAT solver.
|
||||||
|
///
|
||||||
|
/// This calls dtba_sat_synthetize() in a loop, but attempting to
|
||||||
|
/// find the minimum number of states using a binary search.
|
||||||
|
//
|
||||||
|
/// If no smaller TBA exist, this returns a null pointer.
|
||||||
|
SPOT_API tgba_explicit_number*
|
||||||
|
dtba_sat_minimize_dichotomy(const tgba* a, bool state_based = false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // SPOT_TGBAALGOS_DTBASAT_HH
|
#endif // SPOT_TGBAALGOS_DTBASAT_HH
|
||||||
|
|
|
||||||
|
|
@ -52,16 +52,16 @@
|
||||||
#define DEBUG 0
|
#define DEBUG 0
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
#define dout out << "c "
|
#define dout out << "c "
|
||||||
|
#define trace std::cerr
|
||||||
#else
|
#else
|
||||||
#define dout while (0) out
|
#define dout while (0) std::cout
|
||||||
|
#define trace dout
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
namespace spot
|
namespace spot
|
||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
static bdd_dict* debug_dict = 0;
|
static bdd_dict* debug_dict = 0;
|
||||||
|
|
||||||
struct transition
|
struct transition
|
||||||
|
|
@ -477,9 +477,6 @@ namespace spot
|
||||||
sm.build_map();
|
sm.build_map();
|
||||||
bdd ap = sm.aprec_set_of(sm.initial());
|
bdd ap = sm.aprec_set_of(sm.initial());
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
debug_dict = ref->get_dict();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Number all the SAT variable we may need.
|
// Number all the SAT variable we may need.
|
||||||
{
|
{
|
||||||
|
|
@ -488,6 +485,12 @@ namespace spot
|
||||||
ref_size = f.size();
|
ref_size = f.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
debug_dict = ref->get_dict();
|
||||||
|
dout << "ref_size: " << ref_size << "\n";
|
||||||
|
dout << "cand_size: " << d.cand_size << "\n";
|
||||||
|
#endif
|
||||||
|
|
||||||
// empty automaton is impossible
|
// empty automaton is impossible
|
||||||
if (d.cand_size == 0)
|
if (d.cand_size == 0)
|
||||||
{
|
{
|
||||||
|
|
@ -937,87 +940,96 @@ namespace spot
|
||||||
}
|
}
|
||||||
|
|
||||||
tgba_explicit_number*
|
tgba_explicit_number*
|
||||||
dtgba_sat_minimize(const tgba* a, unsigned cand_nacc,
|
dtgba_sat_synthetize(const tgba* a, unsigned target_acc_number,
|
||||||
int target_state_number, bool state_based)
|
int target_state_number, bool state_based)
|
||||||
{
|
{
|
||||||
int ref_states =
|
trace << "dtgba_sat_synthetize(..., acc = " << target_acc_number
|
||||||
target_state_number == -1
|
<< ", states = " << target_state_number
|
||||||
? stats_reachable(a).states - 1
|
<< ", state_based = " << state_based << ")\n";
|
||||||
: target_state_number;
|
std::string solution;
|
||||||
|
|
||||||
std::string current_solution;
|
|
||||||
std::string last_solution;
|
|
||||||
dict* last = 0;
|
|
||||||
dict* current = 0;
|
dict* current = 0;
|
||||||
temporary_file* cnf = 0;
|
temporary_file* cnf = 0;
|
||||||
temporary_file* out = 0;
|
temporary_file* out = 0;
|
||||||
|
|
||||||
do
|
current = new dict(a);
|
||||||
{
|
current->cand_size = target_state_number;
|
||||||
if (DEBUG && current)
|
current->cand_nacc = target_acc_number;
|
||||||
{
|
|
||||||
xrename(out->name(), "dtgba-sat.out");
|
|
||||||
xrename(cnf->name(), "dtgba-sat.cnf");
|
|
||||||
}
|
|
||||||
delete out;
|
|
||||||
delete cnf;
|
|
||||||
std::swap(current_solution, last_solution);
|
|
||||||
delete last;
|
|
||||||
last = current;
|
|
||||||
current = new dict(a);
|
|
||||||
current->cand_size = ref_states--;
|
|
||||||
current->cand_nacc = cand_nacc;
|
|
||||||
|
|
||||||
cnf = create_tmpfile("dtgba-sat-", ".cnf");
|
cnf = create_tmpfile("dtgba-sat-", ".cnf");
|
||||||
|
std::fstream cnfs(cnf->name(),
|
||||||
|
std::ios_base::trunc | std::ios_base::out);
|
||||||
|
dtgba_to_sat(cnfs, a, *current, state_based);
|
||||||
|
cnfs.close();
|
||||||
|
|
||||||
std::fstream cnfs(cnf->name(),
|
out = create_tmpfile("dtgba-sat-", ".out");
|
||||||
std::ios_base::trunc | std::ios_base::out);
|
satsolver(cnf, out);
|
||||||
dtgba_to_sat(cnfs, a, *current, state_based);
|
|
||||||
cnfs.close();
|
|
||||||
|
|
||||||
out = create_tmpfile("dtgba-sat-", ".out");
|
solution = get_solution(out->name());
|
||||||
satsolver(cnf, out);
|
|
||||||
current_solution = get_solution(out->name());
|
|
||||||
}
|
|
||||||
while (target_state_number == -1 && !current_solution.empty());
|
|
||||||
|
|
||||||
if (target_state_number != -1)
|
tgba_explicit_number* res = 0;
|
||||||
{
|
if (!solution.empty())
|
||||||
std::swap(current_solution, last_solution);
|
res = sat_build(solution, *current, a, state_based);
|
||||||
if (last_solution.empty())
|
|
||||||
{
|
|
||||||
last = 0;
|
|
||||||
delete current;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
last = current;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
delete current;
|
|
||||||
}
|
|
||||||
|
|
||||||
tgba_explicit_number* res;
|
delete current;
|
||||||
if (last == 0)
|
|
||||||
|
if (DEBUG)
|
||||||
{
|
{
|
||||||
res = 0;
|
xrename(out->name(), "dtgba-sat.out");
|
||||||
if (DEBUG)
|
xrename(cnf->name(), "dtgba-sat.cnf");
|
||||||
{
|
|
||||||
xrename(out->name(), "dtgba-sat.out");
|
|
||||||
xrename(cnf->name(), "dtgba-sat.cnf");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
res = sat_build(last_solution, *last, a, state_based);
|
|
||||||
delete last;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delete out;
|
delete out;
|
||||||
delete cnf;
|
delete cnf;
|
||||||
|
trace << "dtgba_sat_synthetize(...) = " << res << "\n";
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tgba_explicit_number*
|
||||||
|
dtgba_sat_minimize(const tgba* a, unsigned target_acc_number,
|
||||||
|
bool state_based)
|
||||||
|
{
|
||||||
|
int n_states = stats_reachable(a).states;
|
||||||
|
|
||||||
|
tgba_explicit_number* prev = 0;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
tgba_explicit_number* next =
|
||||||
|
dtgba_sat_synthetize(prev ? prev : a, target_acc_number,
|
||||||
|
--n_states, state_based);
|
||||||
|
if (next == 0)
|
||||||
|
break;
|
||||||
|
delete prev;
|
||||||
|
prev = next;
|
||||||
|
}
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
tgba_explicit_number*
|
||||||
|
dtgba_sat_minimize_dichotomy(const tgba* a, unsigned target_acc_number,
|
||||||
|
bool state_based)
|
||||||
|
{
|
||||||
|
int max_states = stats_reachable(a).states - 1;
|
||||||
|
int min_states = 1;
|
||||||
|
|
||||||
|
tgba_explicit_number* prev = 0;
|
||||||
|
while (min_states <= max_states)
|
||||||
|
{
|
||||||
|
int target = (max_states + min_states) / 2;
|
||||||
|
tgba_explicit_number* next =
|
||||||
|
dtgba_sat_synthetize(prev ? prev : a, target_acc_number, target,
|
||||||
|
state_based);
|
||||||
|
if (next == 0)
|
||||||
|
{
|
||||||
|
min_states = target + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
delete prev;
|
||||||
|
prev = next;
|
||||||
|
max_states = target - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,36 +20,54 @@
|
||||||
#ifndef SPOT_TGBAALGOS_DTGBASAT_HH
|
#ifndef SPOT_TGBAALGOS_DTGBASAT_HH
|
||||||
# define SPOT_TGBAALGOS_DTGBASAT_HH
|
# define SPOT_TGBAALGOS_DTGBASAT_HH
|
||||||
|
|
||||||
#include <iosfwd>
|
|
||||||
#include "tgba/tgba.hh"
|
|
||||||
#include "tgba/tgbaexplicit.hh"
|
#include "tgba/tgbaexplicit.hh"
|
||||||
|
|
||||||
namespace spot
|
namespace spot
|
||||||
{
|
{
|
||||||
/// \brief Attempt to reduce a deterministic TGBA with a SAT solver.
|
/// \brief Attempt to synthetize am equivalent deterministic TGBA
|
||||||
|
/// with a SAT solver.
|
||||||
///
|
///
|
||||||
/// \param a the TGBA to reduce. It should have only one acceptance
|
/// \param a the input TGBA. It should be a deterministic TGBA.
|
||||||
/// set and be deterministic. I.e., it should be a deterministic TBA.
|
|
||||||
///
|
///
|
||||||
/// \param cand_nacc is the number of acceptance sets in the result.
|
/// \param target_acc_number is the number of acceptance sets wanted
|
||||||
|
/// in the result.
|
||||||
|
///
|
||||||
|
/// \param target_state_number is the desired number of states in
|
||||||
|
/// the result. The output may have less than \a
|
||||||
|
/// target_state_number reachable states.
|
||||||
///
|
///
|
||||||
/// \param state_based set to true to force all outgoing transitions
|
/// \param state_based set to true to force all outgoing transitions
|
||||||
/// of a state to share the same acceptance conditions, effectively
|
/// of a state to share the same acceptance conditions, effectively
|
||||||
/// turning the TGBA into a TBA.
|
/// turning the TGBA into a TBA.
|
||||||
///
|
///
|
||||||
/// \param target_state_number the expected number of states wanted
|
/// This functions attempts to find a TGBA with \a target_acc_number
|
||||||
/// in the resulting automaton. If \a target_state_number is left
|
|
||||||
/// to its default value of -1, this function will attempt to build
|
|
||||||
/// the smallest possible deterministic TGBA is can produce.
|
|
||||||
///
|
|
||||||
/// This functions attempts to find a TGBA with \a cand_nacc
|
|
||||||
/// acceptance sets and target_state_number states that is
|
/// acceptance sets and target_state_number states that is
|
||||||
/// equivalent to \a a. If no such TGBA is found, a null pointer is
|
/// equivalent to \a a. If no such TGBA is found, a null pointer is
|
||||||
/// returned.
|
/// returned.
|
||||||
SPOT_API tgba_explicit_number*
|
SPOT_API tgba_explicit_number*
|
||||||
dtgba_sat_minimize(const tgba* a, unsigned cand_nacc,
|
dtgba_sat_synthetize(const tgba* a, unsigned target_acc_number,
|
||||||
int target_state_number = -1,
|
int target_state_number,
|
||||||
|
bool state_based = false);
|
||||||
|
|
||||||
|
/// \brief Attempt to minimize a deterministic TGBA with a SAT solver.
|
||||||
|
///
|
||||||
|
/// This calls dtgba_sat_synthetize() in a loop, with a decreasing
|
||||||
|
/// number of states, and returns the last successfully built TGBA.
|
||||||
|
///
|
||||||
|
/// If no smaller TGBA exist, this returns a null pointer.
|
||||||
|
SPOT_API tgba_explicit_number*
|
||||||
|
dtgba_sat_minimize(const tgba* a, unsigned target_acc_number,
|
||||||
bool state_based = false);
|
bool state_based = false);
|
||||||
|
|
||||||
|
/// \brief Attempt to minimize a deterministic TGBA with a SAT solver.
|
||||||
|
///
|
||||||
|
/// This calls dtgba_sat_synthetize() in a loop, but attempting to
|
||||||
|
/// find the minimum number of states using a binary search.
|
||||||
|
//
|
||||||
|
/// If no smaller TBA exist, this returns a null pointer.
|
||||||
|
SPOT_API tgba_explicit_number*
|
||||||
|
dtgba_sat_minimize_dichotomy(const tgba* a, unsigned target_acc_number,
|
||||||
|
bool state_based = false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // SPOT_TGBAALGOS_DTGBASAT_HH
|
#endif // SPOT_TGBAALGOS_DTGBASAT_HH
|
||||||
|
|
|
||||||
|
|
@ -51,15 +51,24 @@ namespace spot
|
||||||
scc_filter_ = opt->get("scc-filter", -1);
|
scc_filter_ = opt->get("scc-filter", -1);
|
||||||
ba_simul_ = opt->get("ba-simul", -1);
|
ba_simul_ = opt->get("ba-simul", -1);
|
||||||
tba_determinisation_ = opt->get("tba-det", 0);
|
tba_determinisation_ = opt->get("tba-det", 0);
|
||||||
dtba_sat_minimize_ = opt->get("dtba-sat-minimize", -1);
|
sat_minimize_ = opt->get("sat-minimize", 0);
|
||||||
dtgba_sat_minimize_ = opt->get("dtgba-sat-minimize", -1);
|
sat_states_ = opt->get("sat-states", 0);
|
||||||
dtgba_sat_minimize_acc_ = opt->get("dtgba-sat-minimize-acc", -1);
|
sat_acc_ = opt->get("sat-acc", 0);
|
||||||
if (dtgba_sat_minimize_ >= 0 && dtgba_sat_minimize_acc_ == -1)
|
|
||||||
dtgba_sat_minimize_acc_ = 0;
|
|
||||||
if (dtgba_sat_minimize_ == -1 && dtgba_sat_minimize_acc_ >= 0)
|
|
||||||
dtgba_sat_minimize_ = 0;
|
|
||||||
state_based_ = opt->get("state-based", 0);
|
state_based_ = opt->get("state-based", 0);
|
||||||
wdba_minimize_ = opt->get("wdba-minimize", 1);
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -128,6 +137,8 @@ namespace spot
|
||||||
ba_simul_ = (level_ == High) ? 3 : 0;
|
ba_simul_ = (level_ == High) ? 3 : 0;
|
||||||
if (scc_filter_ < 0)
|
if (scc_filter_ < 0)
|
||||||
scc_filter_ = 1;
|
scc_filter_ = 1;
|
||||||
|
if (type_ == BA)
|
||||||
|
state_based_ = true;
|
||||||
|
|
||||||
// Remove useless SCCs.
|
// Remove useless SCCs.
|
||||||
if (type_ == Monitor)
|
if (type_ == Monitor)
|
||||||
|
|
@ -198,6 +209,7 @@ namespace spot
|
||||||
bool dba_is_minimal = false;
|
bool dba_is_minimal = false;
|
||||||
const tgba* dba = 0;
|
const tgba* dba = 0;
|
||||||
const tgba* sim = 0;
|
const tgba* sim = 0;
|
||||||
|
int original_acc = a->number_of_acceptance_conditions();
|
||||||
|
|
||||||
// (Small,Low) is the only configuration where we do not run
|
// (Small,Low) is the only configuration where we do not run
|
||||||
// WDBA-minimization.
|
// WDBA-minimization.
|
||||||
|
|
@ -287,56 +299,60 @@ namespace spot
|
||||||
// that case dba_is_wdba=true), or some deterministic automaton
|
// that case dba_is_wdba=true), or some deterministic automaton
|
||||||
// that is either the result of the simulation or of the
|
// that is either the result of the simulation or of the
|
||||||
// TBA-determinization (dba_is_wdba=false in both cases).
|
// TBA-determinization (dba_is_wdba=false in both cases).
|
||||||
|
if (sat_minimize_ && dba && !dba_is_wdba)
|
||||||
// Attempt SAT-minimization if requested.
|
|
||||||
if (dtba_sat_minimize_ >= 0 && dba && !dba_is_wdba)
|
|
||||||
{
|
{
|
||||||
// This only work on deterministic TBA, so degeneralize
|
unsigned target_acc;
|
||||||
// if needed.
|
if (type_ == BA)
|
||||||
const tgba* tmpd = 0;
|
target_acc = 1;
|
||||||
if (dba->number_of_acceptance_conditions() != 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 has always one.
|
||||||
|
target_acc = original_acc;
|
||||||
|
|
||||||
|
const tgba* in = 0;
|
||||||
|
const tgba* to_free = 0;
|
||||||
|
if (target_acc == 1)
|
||||||
{
|
{
|
||||||
// If we are seeking a minimal DBA with unknown number of
|
// If we are seeking a minimal DBA with unknown number of
|
||||||
// states, then we should start from the degeneralized,
|
// states, then we should start from the degeneralized,
|
||||||
// because the input TBA might be smaller.
|
// because the input TBA might be smaller.
|
||||||
if (state_based_ && dtba_sat_minimize_ == 0)
|
if (state_based_)
|
||||||
tmpd = degeneralize(dba);
|
to_free = in = degeneralize(dba);
|
||||||
|
else if (dba->number_of_acceptance_conditions() != 1)
|
||||||
|
to_free = in = new tgba_tba_proxy(dba);
|
||||||
else
|
else
|
||||||
tmpd = new tgba_tba_proxy(dba);
|
in = dba;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
in = dba;
|
||||||
}
|
}
|
||||||
|
|
||||||
const tgba* in = tmpd ? tmpd : dba;
|
|
||||||
|
|
||||||
const tgba* cmp = tgba_complete(in);
|
const tgba* cmp = tgba_complete(in);
|
||||||
const tgba* res = dtba_sat_minimize(cmp,
|
const tgba* res = 0;
|
||||||
dtba_sat_minimize_ == 0
|
if (target_acc == 1)
|
||||||
? -1 : dtba_sat_minimize_,
|
|
||||||
state_based_);
|
|
||||||
delete cmp;
|
|
||||||
delete tmpd;
|
|
||||||
if (res != 0)
|
|
||||||
{
|
{
|
||||||
delete dba;
|
if (sat_states_ != -1)
|
||||||
if (state_based_)
|
res = dtba_sat_synthetize(cmp, sat_states_, state_based_);
|
||||||
dba = scc_filter_states(res);
|
else if (sat_minimize_ == 1)
|
||||||
else
|
res = dtba_sat_minimize(cmp, state_based_);
|
||||||
dba = scc_filter(res, true);
|
else // sat_minimize_ == 2
|
||||||
delete res;
|
res = dtba_sat_minimize_dichotomy(cmp, state_based_);
|
||||||
dba_is_minimal = true;
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (sat_states_ != -1)
|
||||||
|
res = dtgba_sat_synthetize(cmp, target_acc, sat_states_,
|
||||||
|
state_based_);
|
||||||
|
else if (sat_minimize_ == 1)
|
||||||
|
res = dtgba_sat_minimize(cmp, target_acc, state_based_);
|
||||||
|
else // sat_minimize_ == 2
|
||||||
|
res = dtgba_sat_minimize_dichotomy(cmp, target_acc, state_based_);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if (dtgba_sat_minimize_ >= 0 && dba && !dba_is_wdba)
|
|
||||||
{
|
|
||||||
const tgba* cmp = tgba_complete(dba);
|
|
||||||
const tgba* res =
|
|
||||||
dtgba_sat_minimize(cmp,
|
|
||||||
dtgba_sat_minimize_acc_
|
|
||||||
? dtgba_sat_minimize_acc_
|
|
||||||
: dba->number_of_acceptance_conditions(),
|
|
||||||
dtgba_sat_minimize_ == 0
|
|
||||||
? -1 : dtgba_sat_minimize_,
|
|
||||||
state_based_);
|
|
||||||
delete cmp;
|
delete cmp;
|
||||||
|
delete to_free;
|
||||||
if (res != 0)
|
if (res != 0)
|
||||||
{
|
{
|
||||||
delete dba;
|
delete dba;
|
||||||
|
|
@ -353,10 +369,11 @@ namespace spot
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Degeneralize the dba resulting from tba-determinization or
|
||||||
// Degeneralize the dba resulting from tba-determinization
|
// sat-minimization (which is a TBA) if requested and needed.
|
||||||
// or sat-minimization (which is a TBA) if requested.
|
if (dba && !dba_is_wdba && type_ == BA
|
||||||
if (dba && !dba_is_wdba && type_ == BA)
|
&& !(dba_is_minimal && state_based_
|
||||||
|
&& dba->number_of_acceptance_conditions() == 1))
|
||||||
{
|
{
|
||||||
const tgba* d = degeneralize(dba);
|
const tgba* d = degeneralize(dba);
|
||||||
delete dba;
|
delete dba;
|
||||||
|
|
|
||||||
|
|
@ -106,9 +106,9 @@ namespace spot
|
||||||
int scc_filter_;
|
int scc_filter_;
|
||||||
int ba_simul_;
|
int ba_simul_;
|
||||||
bool tba_determinisation_;
|
bool tba_determinisation_;
|
||||||
int dtba_sat_minimize_;
|
int sat_minimize_;
|
||||||
int dtgba_sat_minimize_;
|
int sat_acc_;
|
||||||
int dtgba_sat_minimize_acc_;
|
int sat_states_;
|
||||||
bool state_based_;
|
bool state_based_;
|
||||||
bool wdba_minimize_;
|
bool wdba_minimize_;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1528,7 +1528,7 @@ main(int argc, char** argv)
|
||||||
if (opt_dtbasat >= 0)
|
if (opt_dtbasat >= 0)
|
||||||
{
|
{
|
||||||
tm.start("dtbasat");
|
tm.start("dtbasat");
|
||||||
satminimized = dtba_sat_minimize(a, opt_dtbasat);
|
satminimized = dtba_sat_synthetize(a, opt_dtbasat);
|
||||||
tm.stop("dtbasat");
|
tm.stop("dtbasat");
|
||||||
if (satminimized)
|
if (satminimized)
|
||||||
a = satminimized;
|
a = satminimized;
|
||||||
|
|
|
||||||
|
|
@ -89,8 +89,9 @@ $ltlcross -F formulas \
|
||||||
--timeout=60 \
|
--timeout=60 \
|
||||||
"$ltl2tgba --det --lbtt %f >%T" \
|
"$ltl2tgba --det --lbtt %f >%T" \
|
||||||
"$ltl2tgba --det --lbtt -x tba-det %f >%T" \
|
"$ltl2tgba --det --lbtt -x tba-det %f >%T" \
|
||||||
"$ltl2tgba --det --lbtt -x tba-det,dtba-sat-minimize=0 %f >%T" \
|
"$ltl2tgba --det --lbtt -x sat-acc=1 %f >%T" \
|
||||||
"$ltl2tgba --det --lbtt -x tba-det,dtgba-sat-minimize-acc=0 %f >%T" \
|
"$ltl2tgba --det --lbtt -x sat-acc=3 %f >%T" \
|
||||||
"$ltl2tgba --det --lbtt -x dtgba-sat-minimize-acc=0 %f >%T" \
|
"$ltl2tgba --det --lbtt -x sat-states=3 %f >%T" \
|
||||||
"$ltl2tgba --det --lbtt -x tba-det,dtgba-sat-minimize-acc=3 %f >%T" \
|
"$ltl2tgba --det --lbtt -x sat-minimize %f >%T" \
|
||||||
|
"$ltl2tgba --det --lbtt -x sat-minimize=2 %f >%T" \
|
||||||
--json=det.json
|
--json=det.json
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue