#include "internal.hpp"
namespace CaDiCaL {
void Internal::transred () {
if (!opts.transred)
return;
if (unsat)
return;
if (terminated_asynchronously ())
return;
if (!stats.current.redundant && !stats.current.irredundant)
return;
assert (opts.transred);
assert (!level);
START_SIMPLIFIER (transred, TRANSRED);
stats.transreds++;
int64_t limit = stats.propagations.search;
limit -= last.transred.propagations;
limit *= 1e-3 * opts.transredeffort;
if (limit < opts.transredmineff)
limit = opts.transredmineff;
if (limit > opts.transredmaxeff)
limit = opts.transredmaxeff;
PHASE ("transred", stats.transreds,
"transitive reduction limit of %" PRId64 " propagations", limit);
const auto end = clauses.end ();
auto i = clauses.begin ();
for (; i != end; i++) {
Clause *c = *i;
if (c->garbage)
continue;
if (c->size != 2)
continue;
if (c->redundant && c->hyper)
continue;
if (!c->transred)
break;
}
if (i == end) {
PHASE ("transred", stats.transreds,
"rescheduling all clauses since no clauses to check left");
for (i = clauses.begin (); i != end; i++) {
Clause *c = *i;
if (c->transred)
c->transred = false;
}
i = clauses.begin ();
}
sort_watches ();
vector<int> work;
int64_t propagations = 0, units = 0, removed = 0;
while (!unsat && i != end && !terminated_asynchronously () &&
propagations < limit) {
Clause *c = *i++;
if (c->garbage)
continue;
if (c->size != 2)
continue;
if (c->redundant && c->hyper)
continue;
if (c->transred)
continue; c->transred = true;
LOG (c, "checking transitive reduction of");
int src = -c->literals[0];
int dst = c->literals[1];
if (val (src) || val (dst))
continue;
if (watches (-src).size () < watches (dst).size ()) {
int tmp = dst;
dst = -src;
src = -tmp;
}
LOG ("searching path from %d to %d", src, dst);
const bool irredundant = !c->redundant;
assert (work.empty ());
mark (src);
work.push_back (src);
LOG ("transred assign %d", src);
bool transitive = false; bool failed = false;
size_t j = 0;
assert (lrat_chain.empty ());
assert (mini_chain.empty ());
vector<int> parents;
while (!transitive && !failed && j < work.size ()) {
const int lit = work[j++];
assert (marked (lit) > 0);
LOG ("transred propagating %d", lit);
propagations++;
const Watches &ws = watches (-lit);
const const_watch_iterator eow = ws.end ();
const_watch_iterator k;
for (k = ws.begin (); !transitive && !failed && k != eow; k++) {
const Watch &w = *k;
if (!w.binary ())
break; Clause *d = w.clause;
if (d == c)
continue;
if (irredundant && d->redundant)
continue;
if (d->garbage)
continue;
const int other = w.blit;
if (other == dst)
transitive = true; else {
const int tmp = marked (other);
if (tmp > 0)
continue;
else if (tmp < 0) {
if (lrat) {
parents.push_back (lit);
mini_chain.push_back (d->id);
work.push_back (other);
}
LOG ("found both %d and %d reachable", -other, other);
failed = true;
} else {
if (lrat) {
parents.push_back (lit);
mini_chain.push_back (d->id);
}
mark (other);
work.push_back (other);
LOG ("transred assign %d", other);
}
}
}
}
int failed_lit = work.back ();
int next_pos = 0;
int next_neg = 0;
while (!work.empty ()) {
const int lit = work.back ();
work.pop_back ();
if (lrat && failed && !work.empty ()) {
assert (!parents.empty () && !mini_chain.empty ());
LOG ("transred LRAT current lit %d next pos %d next neg %d", lit,
next_pos, next_neg);
if (lit == failed_lit || lit == next_pos) {
lrat_chain.push_back (mini_chain.back ());
next_pos = parents.back ();
} else if (lit == -failed_lit || lit == next_neg) {
lrat_chain.push_back (mini_chain.back ());
next_neg = parents.back ();
}
parents.pop_back ();
mini_chain.pop_back ();
}
unmark (lit);
}
mini_chain.clear ();
assert (mini_chain.empty ());
if (lrat && failed) {
reverse (lrat_chain.begin (), lrat_chain.end ());
}
if (transitive) {
removed++;
stats.transitive++;
LOG (c, "transitive redundant");
mark_garbage (c);
} else if (failed) {
units++;
LOG ("found failed literal %d during transitive reduction", src);
stats.failed++;
stats.transredunits++;
assign_unit (-src);
if (!propagate ()) {
VERBOSE (1, "propagating new unit results in conflict");
learn_empty_clause ();
}
}
lrat_chain.clear ();
}
last.transred.propagations = stats.propagations.search;
stats.propagations.transred += propagations;
erase_vector (work);
PHASE ("transred", stats.transreds,
"removed %" PRId64 " transitive clauses, found %" PRId64 " units",
removed, units);
STOP_SIMPLIFIER (transred, TRANSRED);
report ('t', !opts.reportall && !(removed + units));
}
}