Commit 484c56c6 authored by Alexandre Duret-Lutz's avatar Alexandre Duret-Lutz
Browse files

sat: skip reference transitions that are out of any cycle

* src/tgbaalgos/dtbasat.cc, src/tgbaalgos/dtgbasat.cc: Greatly reduce
the number of clauses and variable by removing any path variable that
reference a reference transition that is not in a SCC.
parent e9f60df8
...@@ -217,10 +217,12 @@ namespace spot ...@@ -217,10 +217,12 @@ namespace spot
int size_; int size_;
bdd ap_; bdd ap_;
bool state_based_; bool state_based_;
scc_map& sm_;
public: public:
filler_dfs(const tgba* aut, dict& d, bdd ap, bool state_based) filler_dfs(const tgba* aut, dict& d, bdd ap, bool state_based,
scc_map& sm)
: tgba_reachable_iterator_depth_first(aut), d(d), ap_(ap), : tgba_reachable_iterator_depth_first(aut), d(d), ap_(ap),
state_based_(state_based) state_based_(state_based), sm_(sm)
{ {
d.nvars = 0; d.nvars = 0;
} }
...@@ -237,29 +239,33 @@ namespace spot ...@@ -237,29 +239,33 @@ namespace spot
if (d.cand_size == -1) if (d.cand_size == -1)
d.cand_size = size_ - 1; d.cand_size = size_ - 1;
int seen_size = seen.size(); for (dict::state_map::const_iterator i2 = seen.begin();
for (int i = 1; i <= seen_size; ++i) i2 != seen.end(); ++i2)
{ {
int i = i2->second;
d.int_to_state[i] = i2->first;
unsigned i_scc = sm_.scc_of_state(i2->first);
for (int j = 1; j <= d.cand_size; ++j) for (int j = 1; j <= d.cand_size; ++j)
{ {
d.prodid[state_pair(j, i)] = ++d.nvars; d.prodid[state_pair(j, i)] = ++d.nvars;
for (int k = 1; k <= seen_size; ++k) for (dict::state_map::const_iterator k2 = seen.begin();
for (int l = 1; l <= d.cand_size; ++l) k2 != seen.end(); ++k2)
{
int k = k2->second;
if (sm_.scc_of_state(k2->first) != i_scc)
continue;
for (int l = 1; l <= d.cand_size; ++l)
{ {
path p(j, i, l, k); path p(j, i, l, k);
d.pathid_ref[p] = ++d.nvars; d.pathid_ref[p] = ++d.nvars;
d.pathid_cand[p] = ++d.nvars; d.pathid_cand[p] = ++d.nvars;
} }
}
} }
} }
for (dict::state_map::const_iterator i = seen.begin();
i != seen.end(); ++i)
{
d.int_to_state[i->second] = i->first;
}
std::swap(d.state_to_int, seen); std::swap(d.state_to_int, seen);
for (int i = 1; i <= d.cand_size; ++i) for (int i = 1; i <= d.cand_size; ++i)
...@@ -314,7 +320,7 @@ namespace spot ...@@ -314,7 +320,7 @@ namespace spot
// Number all the SAT variable we may need. // Number all the SAT variable we may need.
{ {
filler_dfs f(ref, d, ap, state_based); filler_dfs f(ref, d, ap, state_based, sm);
f.run(); f.run();
ref_size = f.size(); ref_size = f.size();
} }
...@@ -450,158 +456,185 @@ namespace spot ...@@ -450,158 +456,185 @@ namespace spot
// construction of contraints (4,5) : all loops in the product // construction of contraints (4,5) : all loops in the product
// where no accepting run is detected in the ref. automaton, // where no accepting run is detected in the ref. automaton,
// must also be marked as not accepting in the cand. automaton // must also be marked as not accepting in the cand. automaton
for (int q1 = 1; q1 <= d.cand_size; ++q1) for (int q1p = 1; q1p <= ref_size; ++q1p)
for (int q1p = 1; q1p <= ref_size; ++q1p) {
{ unsigned q1p_scc = sm.scc_of_state(d.int_to_state[q1p]);
for (int q2 = 1; q2 <= d.cand_size; ++q2) for (int q2p = 1; q2p <= ref_size; ++q2p)
for (int q2p = 1; q2p <= ref_size; ++q2p) {
{ // We are only interested in transition that can form a
path p1(q1, q1p, q2, q2p); // cycle, so they must belong to the same SCC.
if (sm.scc_of_state(d.int_to_state[q2p]) != q1p_scc)
dout << "(4&5) matching paths from reference based on " continue;
<< p1 << "\n"; for (int q1 = 1; q1 <= d.cand_size; ++q1)
for (int q2 = 1; q2 <= d.cand_size; ++q2)
int pid1 = d.pathid_ref[p1]; {
path p1(q1, q1p, q2, q2p);
tgba_succ_iterator* it = ref->succ_iter(d.int_to_state[q2p]);
for (it->first(); !it->done(); it->next()) dout << "(4&5) matching paths from reference based on "
{ << p1 << "\n";
const state* dps = it->current_state();
int dp = d.state_to_int[dps]; int pid1 = d.pathid_ref[p1];
dps->destroy();
if (it->current_acceptance_conditions() == all_acc) tgba_succ_iterator* it =
continue; ref->succ_iter(d.int_to_state[q2p]);
for (int q3 = 1; q3 <= d.cand_size; ++q3) for (it->first(); !it->done(); it->next())
{ {
if (dp == q1p && q3 == q1) // (4) looping const state* dps = it->current_state();
{ // Skip destinations not in the SCC.
bdd all = it->current_condition(); if (sm.scc_of_state(dps) != q1p_scc)
while (all != bddfalse) {
{ dps->destroy();
bdd s = bdd_satoneset(all, ap, bddfalse); continue;
all -= s; }
int dp = d.state_to_int[dps];
transition t(q2, s, q1); dps->destroy();
int ti = d.transid[t];
int ta = d.transacc[t]; if (it->current_acceptance_conditions() == all_acc)
continue;
dout << p1 << "R ∧ " << t << "δ → ¬" << t for (int q3 = 1; q3 <= d.cand_size; ++q3)
<< "F\n"; {
out << -pid1 << " " << -ti << " " if (dp == q1p && q3 == q1) // (4) looping
<< -ta << " 0\n"; {
++nclauses; bdd all = it->current_condition();
} while (all != bddfalse)
{
bdd s = bdd_satoneset(all, ap, bddfalse);
} all -= s;
else // (5) not looping
{ transition t(q2, s, q1);
path p2 = path(q1, q1p, q3, dp); int ti = d.transid[t];
int pid2 = d.pathid_ref[p2]; int ta = d.transacc[t];
if (pid1 == pid2) dout << p1 << "R ∧ " << t << "δ → ¬" << t
continue; << "F\n";
out << -pid1 << " " << -ti << " "
bdd all = it->current_condition(); << -ta << " 0\n";
while (all != bddfalse) ++nclauses;
{ }
bdd s = bdd_satoneset(all, ap, bddfalse);
all -= s;
}
transition t(q2, s, q3); else // (5) not looping
int ti = d.transid[t]; {
path p2 = path(q1, q1p, q3, dp);
dout << p1 << "R ∧ " << t << "δ → " << p2 int pid2 = d.pathid_ref[p2];
<< "R\n";
out << -pid1 << " " << -ti << " " if (pid1 == pid2)
<< pid2 << " 0\n"; continue;
++nclauses;
} bdd all = it->current_condition();
} while (all != bddfalse)
} {
} bdd s = bdd_satoneset(all, ap, bddfalse);
delete it; all -= s;
}
} transition t(q2, s, q3);
int ti = d.transid[t];
dout << p1 << "R ∧ " << t << "δ → " << p2
<< "R\n";
out << -pid1 << " " << -ti << " "
<< pid2 << " 0\n";
++nclauses;
}
}
}
}
delete it;
}
}
}
// construction of contraints (6,7): all loops in the product // construction of contraints (6,7): all loops in the product
// where accepting run is detected in the ref. automaton, must // where accepting run is detected in the ref. automaton, must
// also be marked as accepting in the candidate. // also be marked as accepting in the candidate.
for (int q1 = 1; q1 <= d.cand_size; ++q1) for (int q1p = 1; q1p <= ref_size; ++q1p)
for (int q1p = 1; q1p <= ref_size; ++q1p) {
{ unsigned q1p_scc = sm.scc_of_state(d.int_to_state[q1p]);
for (int q2 = 1; q2 <= d.cand_size; ++q2) for (int q2p = 1; q2p <= ref_size; ++q2p)
for (int q2p = 1; q2p <= ref_size; ++q2p) {
{ // We are only interested in transition that can form a
path p1(q1, q1p, q2, q2p); // cycle, so they must belong to the same SCC.
dout << "(6&7) matching paths from candidate based on " if (sm.scc_of_state(d.int_to_state[q2p]) != q1p_scc)
<< p1 << "\n"; continue;
int pid1 = d.pathid_cand[p1]; for (int q1 = 1; q1 <= d.cand_size; ++q1)
for (int q2 = 1; q2 <= d.cand_size; ++q2)
tgba_succ_iterator* it = ref->succ_iter(d.int_to_state[q2p]); {
for (it->first(); !it->done(); it->next()) path p1(q1, q1p, q2, q2p);
{ dout << "(6&7) matching paths from candidate based on "
const state* dps = it->current_state(); << p1 << "\n";
int dp = d.state_to_int[dps]; int pid1 = d.pathid_cand[p1];
dps->destroy();
for (int q3 = 1; q3 <= d.cand_size; q3++) tgba_succ_iterator* it =
{ ref->succ_iter(d.int_to_state[q2p]);
if (dp == q1p && q3 == q1) // (6) looping for (it->first(); !it->done(); it->next())
{ {
// We only care about the looping case if const state* dps = it->current_state();
// it is accepting in the reference. // Skip destinations not in the SCC.
if (it->current_acceptance_conditions() if (sm.scc_of_state(dps) != q1p_scc)
!= all_acc) {
continue; dps->destroy();
bdd all = it->current_condition(); continue;
while (all != bddfalse) }
{ int dp = d.state_to_int[dps];
bdd s = bdd_satoneset(all, ap, bddfalse); dps->destroy();
all -= s; for (int q3 = 1; q3 <= d.cand_size; q3++)
{
transition t(q2, s, q1); if (dp == q1p && q3 == q1) // (6) looping
int ti = d.transid[t]; {
int ta = d.transacc[t]; // We only care about the looping case if
// it is accepting in the reference.
dout << p1 << "C ∧ " << t << "δ → " << t if (it->current_acceptance_conditions()
<< "F\n"; != all_acc)
out << -pid1 << " " << -ti << " " << ta continue;
<< " 0\n"; bdd all = it->current_condition();
++nclauses; while (all != bddfalse)
} {
} bdd s = bdd_satoneset(all, ap, bddfalse);
else // (7) no loop all -= s;
{
path p2 = path(q1, q1p, q3, dp); transition t(q2, s, q1);
int pid2 = d.pathid_cand[p2]; int ti = d.transid[t];
int ta = d.transacc[t];
if (pid1 == pid2)
continue; dout << p1 << "C ∧ " << t << "δ → " << t
<< "F\n";
bdd all = it->current_condition(); out << -pid1 << " " << -ti << " " << ta
while (all != bddfalse) << " 0\n";
{ ++nclauses;
bdd s = bdd_satoneset(all, ap, bddfalse); }
all -= s; }
else // (7) no loop
transition t(q2, s, q3); {
int ti = d.transid[t]; path p2 = path(q1, q1p, q3, dp);
int ta = d.transacc[t]; int pid2 = d.pathid_cand[p2];
dout << p1 << "C ∧ " << t << "δ ∧ ¬" if (pid1 == pid2)
<< t << "F → " << p2 << "C\n"; continue;
out << -pid1 << " " << -ti << " " bdd all = it->current_condition();
<< ta << " " << pid2 << " 0\n"; while (all != bddfalse)
++nclauses; {
} bdd s = bdd_satoneset(all, ap, bddfalse);
} all -= s;
}
} transition t(q2, s, q3);
delete it; int ti = d.transid[t];
} int ta = d.transacc[t];
}
dout << p1 << "C ∧ " << t << "δ ∧ ¬"
<< t << "F → " << p2 << "C\n";
out << -pid1 << " " << -ti << " "
<< ta << " " << pid2 << " 0\n";
++nclauses;
}
}
}
}
delete it;
}
}
}
out.seekp(0); out.seekp(0);
out << "p cnf " << d.nvars << " " << nclauses; out << "p cnf " << d.nvars << " " << nclauses;
} }
......
...@@ -298,10 +298,12 @@ namespace spot ...@@ -298,10 +298,12 @@ namespace spot
int size_; int size_;
bdd ap_; bdd ap_;
bool state_based_; bool state_based_;
scc_map& sm_;
public: public:
filler_dfs(const tgba* aut, dict& d, bdd ap, bool state_based) filler_dfs(const tgba* aut, dict& d, bdd ap, bool state_based,
scc_map& sm)
: tgba_reachable_iterator_depth_first(aut), d(d), ap_(ap), : tgba_reachable_iterator_depth_first(aut), d(d), ap_(ap),
state_based_(state_based) state_based_(state_based), sm_(sm)
{ {
d.nvars = 0; d.nvars = 0;
...@@ -363,38 +365,42 @@ namespace spot ...@@ -363,38 +365,42 @@ namespace spot
if (d.cand_size == -1) if (d.cand_size == -1)
d.cand_size = size_ - 1; d.cand_size = size_ - 1;
int seen_size = seen.size(); for (dict::state_map::const_iterator i2 = seen.begin();
for (int i = 1; i <= seen_size; ++i) i2 != seen.end(); ++i2)
{ {
int i = i2->second;
d.int_to_state[i] = i2->first;
unsigned i_scc = sm_.scc_of_state(i2->first);
for (int j = 1; j <= d.cand_size; ++j) for (int j = 1; j <= d.cand_size; ++j)
{ {
d.prodid[state_pair(j, i)] = ++d.nvars; d.prodid[state_pair(j, i)] = ++d.nvars;
for (dict::state_map::const_iterator k2 = seen.begin();
for (int k = 1; k <= seen_size; ++k) k2 != seen.end(); ++k2)
for (int l = 1; l <= d.cand_size; ++l) {
{ int k = k2->second;
size_t sf = d.all_cand_acc.size(); if (sm_.scc_of_state(k2->first) != i_scc)
for (size_t f = 0; f < sf; ++f) continue;
{ for (int l = 1; l <= d.cand_size; ++l)
size_t sfp = d.all_ref_acc.size(); {
for (size_t fp = 0; fp < sfp; ++fp) size_t sf = d.all_cand_acc.size();
{ for (size_t f = 0; f < sf; ++f)
path p(j, i, l, k, {
d.all_cand_acc[f], size_t sfp = d.all_ref_acc.size();
d.all_ref_acc[fp]); for (size_t fp = 0; fp < sfp; ++fp)
d.pathid[p] = ++d.nvars; {
} path p(j, i, l, k,
d.all_cand_acc[f],
} d.all_ref_acc[fp]);
} d.pathid[p] = ++d.nvars;
}
}
}
}
} }
} }
for (dict::state_map::const_iterator i = seen.begin();
i != seen.end(); ++i)
d.int_to_state[i->second] = i->first;
std::swap(d.state_to_int, seen); std::swap(d.state_to_int, seen);
if (!state_based_) if (!state_based_)
...@@ -491,7 +497,7 @@ namespace spot ...@@ -491,7 +497,7 @@ namespace spot
// Number all the SAT variable we may need. // Number all the SAT variable we may need.
{ {
filler_dfs f(ref, d, ap, state_based); filler_dfs f(ref, d, ap, state_based, sm);
f.run(); f.run();
ref_size = f.size(); ref_size = f.size();
} }
...@@ -623,211 +629,223 @@ namespace spot ...@@ -623,211 +629,223 @@ namespace spot
bdd all_acc = ref->all_acceptance_conditions(); bdd all_acc = ref->all_acceptance_conditions();
// construction of constraints (11,12,13) // construction of constraints (11,12,13)
for (int q1 = 1; q1 <= d.cand_size; ++q1) for (int q1p = 1; q1p <= ref_size; ++q1p)
for (int q1p = 1; q1p <= ref_size; ++q1p) {
for (int q2 = 1; q2 <= d.cand_size; ++q2) unsigned q1p_scc = sm.scc_of_state(d.int_to_state[q1p]);
for (int q2p = 1; q2p <= ref_size; ++q2p) for (int q2p = 1; q2p <= ref_size; ++q2p)
{ {
size_t sf = d.all_cand_acc.size(); // We are only interested in transition that can form a
size_t sfp = d.all_ref_acc.size(); // cycle, so they must belong to the same SCC.
for (size_t f = 0; f < sf; ++f) if (sm.scc_of_state(d.int_to_state[q2p]) != q1p_scc)
for (size_t fp = 0; fp < sfp; ++fp) continue;
{ for (int q1 = 1; q1 <= d.cand_size; ++q1)
path p(q1, q1p, q2, q2p, for (int q2 = 1; q2 <= d.cand_size; ++q2)
d.all_cand_acc[f], d.all_ref_acc[fp]); {
size_t sf = d.all_cand_acc.size();
dout << "(11&12&13) paths from " << p << "\n"; size_t sfp = d.all_ref_acc.size();
for (size_t f = 0; f < sf; ++f)
for (size_t fp = 0; fp < sfp; ++fp)
{
path p(q1, q1p, q2, q2p,
d.all_cand_acc[f], d.all_ref_acc[fp]);
int pid = d.pathid[p]; dout << "(11&12&13) paths from " << p << "\n";
tgba_succ_iterator* it = int pid = d.pathid[p];
ref->succ_iter(d.int_to_state[q2p]);
for (it->first(); !it->done(); it->next()) tgba_succ_iterator* it =
{ ref->succ_iter(d.int_to_state[q2p]);
const state* dps = it->current_state();
int dp = d.state_to_int[dps];
dps->destroy();
for (int q3 = 1; q3 <= d.cand_size; ++q3) for (it->first(); !it->done(); it->next())
{ {
bdd all = it->current_condition(); const state* dps = it->current_state();
bdd curacc = it->current_acceptance_conditions(); // Skip destinations not in the SCC.
if (sm.scc_of_state(dps) != q1p_scc)
while (all != bddfalse)
{ {
bdd l = bdd_satoneset(all, ap, bddfalse); dps->destroy();
all -= l; continue;
}
int dp = d.state_to_int[dps];
dps->destroy();
transition t(q2, l, q3); for (int q3 = 1; q3 <= d.cand_size; ++q3)
int ti = d.transid[t]; {
bdd all = it->current_condition();
bdd curacc =
it->current_acceptance_conditions();
if (dp == q1p && q3 == q1) // (11,12) loop while (all != bddfalse)