182 lines
4.5 KiB
C
182 lines
4.5 KiB
C
#include "inline.h"
|
|
#include "minimize.h"
|
|
|
|
static bool minimize_literal (kissat *, assigned *, unsigned lit, int depth);
|
|
|
|
static inline bool
|
|
minimize_reference (kissat * solver, assigned * assigned,
|
|
reference ref, unsigned lit, int depth)
|
|
{
|
|
const unsigned not_lit = NOT (lit);
|
|
clause *c = kissat_dereference_clause (solver, ref);
|
|
solver->dps_ticks++;
|
|
for (all_literals_in_clause (other, c))
|
|
if (other != not_lit &&
|
|
!minimize_literal (solver, assigned, other, depth))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
static inline bool
|
|
minimize_binary (kissat * solver, assigned * assigned,
|
|
unsigned lit, int depth)
|
|
{
|
|
const size_t saved = SIZE_STACK (solver->minimize);
|
|
bool res;
|
|
for (unsigned next = lit;;)
|
|
{
|
|
const unsigned next_idx = IDX (next);
|
|
struct assigned *a = assigned + next_idx;
|
|
if (a->analyzed == REMOVABLE)
|
|
{
|
|
res = true;
|
|
break;
|
|
}
|
|
if (a->reason == DECISION || a->analyzed == POISONED)
|
|
{
|
|
res = false;
|
|
break;
|
|
}
|
|
PUSH_STACK (solver->minimize, next_idx);
|
|
if (!a->binary)
|
|
{
|
|
res = minimize_reference (solver, assigned,
|
|
a->reason, next, depth + 1);
|
|
break;
|
|
}
|
|
next = a->reason;
|
|
}
|
|
unsigned *begin = BEGIN_STACK (solver->minimize) + saved;
|
|
const unsigned *end = END_STACK (solver->minimize);
|
|
assert (begin <= end);
|
|
if (res)
|
|
{
|
|
for (const unsigned *p = begin; p != end; p++)
|
|
{
|
|
const unsigned other_idx = *p;
|
|
LOG ("removable variable %u", other_idx);
|
|
PUSH_STACK (solver->removable, other_idx);
|
|
struct assigned *a = assigned + other_idx;
|
|
a->analyzed = REMOVABLE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (const unsigned *p = begin; p != end; p++)
|
|
{
|
|
const unsigned other_idx = *p;
|
|
LOG ("poisoned variable %u", other_idx);
|
|
PUSH_STACK (solver->poisoned, other_idx);
|
|
struct assigned *a = assigned + other_idx;
|
|
a->analyzed = POISONED;
|
|
}
|
|
}
|
|
SET_END_OF_STACK (solver->minimize, begin);
|
|
return res;
|
|
}
|
|
|
|
static bool
|
|
minimize_literal (kissat * solver, assigned * assigned,
|
|
unsigned lit, int depth)
|
|
{
|
|
assert (VALUE (lit) < 0);
|
|
if (depth >= GET_OPTION (minimizedepth))
|
|
return false;
|
|
const unsigned idx = IDX (lit);
|
|
struct assigned *a = assigned + idx;
|
|
if (!a->level)
|
|
return true;
|
|
if (a->analyzed == REMOVABLE && depth)
|
|
return true;
|
|
assert (a->reason != UNIT);
|
|
if (a->reason == DECISION)
|
|
return false;
|
|
if (a->analyzed == POISONED)
|
|
return false;
|
|
frame *frame = &FRAME (a->level);
|
|
if (frame->used <= 1)
|
|
return false;
|
|
bool res = true;
|
|
if (a->binary)
|
|
res = minimize_binary (solver, assigned, a->reason, depth);
|
|
else
|
|
res = minimize_reference (solver, assigned, a->reason, lit, depth + 1);
|
|
if (!depth)
|
|
assert (a->analyzed == REMOVABLE);
|
|
else if (res)
|
|
{
|
|
LOG ("removable variable %u", idx);
|
|
PUSH_STACK (solver->removable, idx);
|
|
a->analyzed = REMOVABLE;
|
|
}
|
|
else
|
|
{
|
|
LOG ("poisoned variable %u", idx);
|
|
PUSH_STACK (solver->poisoned, idx);
|
|
a->analyzed = POISONED;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
static void
|
|
reset_minimize (kissat * solver)
|
|
{
|
|
LOG ("unmarking %zu poisoned variables", SIZE_STACK (solver->poisoned));
|
|
for (all_stack (unsigned, idx, solver->poisoned))
|
|
solver->assigned[idx].analyzed = 0;
|
|
|
|
LOG ("reset %zu poisoned variables", SIZE_STACK (solver->poisoned));
|
|
CLEAR_STACK (solver->poisoned);
|
|
|
|
LOG ("unmarking %zu removable variables", SIZE_STACK (solver->removable));
|
|
for (all_stack (unsigned, idx, solver->removable))
|
|
solver->assigned[idx].analyzed = 0;
|
|
|
|
LOG ("reset %zu removable variables", SIZE_STACK (solver->removable));
|
|
CLEAR_STACK (solver->removable);
|
|
}
|
|
|
|
void
|
|
kissat_minimize_clause (kissat * solver)
|
|
{
|
|
START (minimize);
|
|
|
|
assert (EMPTY_STACK (solver->minimize));
|
|
assert (EMPTY_STACK (solver->removable));
|
|
assert (EMPTY_STACK (solver->poisoned));
|
|
assert (!EMPTY_STACK (solver->clause.lits));
|
|
|
|
unsigned *lits = BEGIN_STACK (solver->clause.lits);
|
|
const unsigned *end = END_STACK (solver->clause.lits);
|
|
unsigned *q = lits + 1;
|
|
|
|
unsigned minimized = 0;
|
|
|
|
assigned *assigned = solver->assigned;
|
|
|
|
for (const unsigned *p = q; p != end; p++)
|
|
{
|
|
const unsigned lit = *p;
|
|
if (minimize_literal (solver, assigned, lit, 0))
|
|
{
|
|
LOG ("minimized literal %s", LOGLIT (lit));
|
|
minimized++;
|
|
}
|
|
else
|
|
{
|
|
LOG ("keeping literal %s", LOGLIT (lit));
|
|
*q++ = lit;
|
|
}
|
|
}
|
|
SET_END_OF_STACK (solver->clause.lits, q);
|
|
LOG ("clause minimization removed %u literals", minimized);
|
|
|
|
if (!solver->probing)
|
|
ADD (minimized, minimized);
|
|
|
|
LOGTMP ("minimized learned");
|
|
|
|
reset_minimize (solver);
|
|
STOP (minimize);
|
|
}
|