2023-03-26 19:15:17 +08:00

274 lines
7.4 KiB
C

#include "analyze.h"
#include "backtrack.h"
#include "bump.h"
#include "deduce.h"
#include "inline.h"
#include "learn.h"
#include "minimize.h"
#include <inttypes.h>
#define INVALID_LEVEL UINT_MAX
static bool
one_literal_on_conflict_level(kissat *solver,
clause *conflict,
unsigned *conflict_level_ptr)
{
assert(conflict);
assert(conflict->size > 1);
unsigned conflict_level = INVALID_LEVEL;
unsigned literals_on_conflict_level = 0;
unsigned forced_lit = INVALID_LIT;
assigned *all_assigned = solver->assigned;
unsigned *lits = conflict->lits;
const unsigned conflict_size = conflict->size;
const unsigned *end_of_lits = lits + conflict_size;
for (const unsigned *p = lits; p != end_of_lits; p++)
{
const unsigned lit = *p;
assert(VALUE(lit) < 0);
const unsigned idx = IDX(lit);
const unsigned level = all_assigned[idx].level;
if (conflict_level == level)
{
if (++literals_on_conflict_level > 1 && level == solver->level)
break;
}
else if (conflict_level == INVALID_LEVEL || conflict_level < level)
{
forced_lit = lit;
conflict_level = level;
literals_on_conflict_level = 1;
}
}
assert(conflict_level != INVALID_LEVEL);
assert(literals_on_conflict_level);
LOG("found %u literals on conflict level %u",
literals_on_conflict_level, conflict_level);
*conflict_level_ptr = conflict_level;
if (!conflict_level)
{
solver->inconsistent = true;
LOG("learned empty clause from conflict at conflict level zero");
CHECK_AND_ADD_EMPTY();
ADD_EMPTY_TO_PROOF();
return false;
}
if (conflict_level < solver->level)
{
LOG("forced backtracking due to conflict level %u < level %u",
conflict_level, solver->level);
kissat_backtrack(solver, conflict_level);
}
if (conflict_size > 2)
{
for (unsigned i = 0; i < 2; i++)
{
const unsigned lit = lits[i];
const unsigned lit_idx = IDX(lit);
unsigned highest_position = i;
unsigned highest_literal = lit;
unsigned highest_level = all_assigned[lit_idx].level;
for (unsigned j = i + 1; j < conflict_size; j++)
{
const unsigned other = lits[j];
const unsigned other_idx = IDX(other);
const unsigned level = all_assigned[other_idx].level;
if (highest_level >= level)
continue;
highest_literal = other;
highest_position = j;
highest_level = level;
if (highest_level == conflict_level)
break;
}
if (highest_position == i)
continue;
reference ref = INVALID_REF;
if (highest_position > 1)
{
ref = kissat_reference_clause(solver, conflict);
kissat_unwatch_blocking(solver, lit, ref);
}
lits[highest_position] = lit;
lits[i] = highest_literal;
if (highest_position > 1)
kissat_watch_blocking(solver, lits[i], lits[!i], ref);
}
}
if (literals_on_conflict_level > 1)
return false;
assert(literals_on_conflict_level == 1);
assert(forced_lit != INVALID_LIT);
LOG("reusing conflict as driving clause of %s", LOGLIT(forced_lit));
kissat_backtrack(solver, solver->level - 1);
if (conflict_size == 2)
{
assert(conflict == &solver->conflict);
const unsigned other = lits[0] ^ lits[1] ^ forced_lit;
kissat_assign_binary(solver, conflict->redundant, forced_lit, other);
}
else
{
const reference ref = kissat_reference_clause(solver, conflict);
kissat_assign_reference(solver, forced_lit, ref, conflict);
}
return true;
}
static void
mark_literal_as_analyzed(kissat *solver, assigned *all_assigned,
unsigned lit, const char *type)
{
const unsigned idx = IDX(lit);
assigned *a = all_assigned + idx;
if (a->analyzed == ANALYZED)
return;
a->analyzed = ANALYZED;
LOG("marking %s literal %s as analyzed", type, LOGLIT(lit));
PUSH_STACK(solver->analyzed, idx);
(void)type;
}
static inline void
analyze_reason_side_literals(kissat *solver)
{
assert(!solver->probing);
if (!GET_OPTION(bumpreasons))
return;
assigned *all_assigned = solver->assigned;
for (all_stack(unsigned, lit, solver->clause.lits))
all_assigned[IDX(lit)].analyzed = ANALYZED;
word *arena = BEGIN_STACK(solver->arena);
for (all_stack(unsigned, lit, solver->clause.lits))
{
const unsigned idx = IDX(lit);
assigned *a = all_assigned + idx;
assert(a->level > 0);
assert(a->reason != UNIT);
if (a->reason == DECISION)
continue;
if (a->binary)
mark_literal_as_analyzed(solver, all_assigned, a->reason,
"reason side");
else
{
assert(a->reason < SIZE_STACK(solver->arena));
clause *c = (clause *)(arena + a->reason);
solver->dps_ticks++;
for (all_literals_in_clause(lit, c))
if (IDX(lit) != idx)
mark_literal_as_analyzed(solver, all_assigned, lit,
"reason side");
}
}
}
static void
reset_levels(kissat *solver)
{
LOG("reset %zu marked levels", SIZE_STACK(solver->levels));
frame *frames = BEGIN_STACK(solver->frames);
for (all_stack(unsigned, level, solver->levels))
{
assert(level < SIZE_STACK(solver->frames));
frame *f = frames + level;
assert(f->used > 0);
f->used = 0;
}
CLEAR_STACK(solver->levels);
}
static void
reset_markings(kissat *solver)
{
LOG("unmarking %zu analyzed variables", SIZE_STACK(solver->analyzed));
assigned *all_assigned = solver->assigned;
for (all_stack(unsigned, idx, solver->analyzed))
all_assigned[idx].analyzed = 0;
}
static void
reset_analyze(kissat *solver)
{
LOG("reset %zu analyzed variables", SIZE_STACK(solver->analyzed));
CLEAR_STACK(solver->analyzed);
LOG("reset %zu learned literals", SIZE_STACK(solver->clause.lits));
CLEAR_STACK(solver->clause.lits);
}
static void
update_trail_average(kissat *solver)
{
assert(!solver->probing);
const unsigned size = SIZE_STACK(solver->trail);
const unsigned assigned = size - solver->unflushed;
const unsigned active = solver->active;
const double filled = kissat_percent(assigned, active);
LOG("trail filled %.0f%% (size %u, unflushed %u, active %u)",
filled, size, solver->unflushed, active);
UPDATE(trail, filled);
}
int kissat_analyze(kissat *solver, clause *conflict)
{
assert(!solver->inconsistent);
START(analyze);
if (!solver->probing)
{
update_trail_average(solver);
UPDATE(level, solver->level);
}
int res;
do
{
LOGCLS(conflict, "analyzing conflict %" PRIu64, CONFLICTS);
unsigned conflict_level;
if (one_literal_on_conflict_level(solver, conflict, &conflict_level))
res = 1;
else if (!conflict_level)
res = -1;
else if ((conflict = kissat_deduce_first_uip_clause(solver, conflict)))
{
reset_markings(solver);
reset_analyze(solver);
reset_levels(solver);
res = 0;
}
else
{
kissat_minimize_clause(solver);
if (!solver->probing)
analyze_reason_side_literals(solver);
reset_markings(solver);
kissat_learn_clause(solver);
solver->nconflict++;
// MAB
if (!solver->probing && (!solver->stable || solver->heuristic == 0))
kissat_bump_variables(solver);
if (!solver->probing && solver->stable && (solver->heuristic == 1))
kissat_update_conflicted_chb(solver);
reset_analyze(solver);
reset_levels(solver);
res = 1;
}
} while (!res);
STOP(analyze);
return res > 0 ? 0 : 20;
}