kissat original

This commit is contained in:
MyskYko 2025-03-04 17:39:59 -08:00
parent c25bf73466
commit a7476c65d8
201 changed files with 37354 additions and 0 deletions

161
src/sat/kissat/allocate.c Normal file
View File

@ -0,0 +1,161 @@
#include "allocate.h"
#include "error.h"
#include "internal.h"
#include "logging.h"
#undef LOGPREFIX
#define LOGPREFIX "ALLOCATE"
#include <string.h>
#ifdef LOGGING
#include <inttypes.h>
#endif
static void inc_bytes (kissat *solver, size_t bytes) {
#ifdef METRICS
if (!solver)
return;
ADD (allocated_current, bytes);
LOG5 ("allocated_current = %s",
FORMAT_BYTES (solver->statistics.allocated_current));
if (solver->statistics.allocated_current >=
solver->statistics.allocated_max) {
solver->statistics.allocated_max = solver->statistics.allocated_current;
LOG5 ("allocated_max = %s",
FORMAT_BYTES (solver->statistics.allocated_max));
}
#else
(void) solver;
(void) bytes;
#endif
}
static void dec_bytes (kissat *solver, size_t bytes) {
#ifdef METRICS
if (!solver)
return;
SUB (allocated_current, bytes);
LOG5 ("allocated_current = %s",
FORMAT_BYTES (solver->statistics.allocated_current));
#else
(void) solver;
(void) bytes;
#endif
}
void *kissat_malloc (kissat *solver, size_t bytes) {
void *res;
if (!bytes)
return 0;
res = malloc (bytes);
LOG4 ("malloc (%zu) = %p", bytes, res);
if (!res)
kissat_fatal ("out-of-memory allocating %zu bytes", bytes);
inc_bytes (solver, bytes);
return res;
}
void kissat_free (kissat *solver, void *ptr, size_t bytes) {
if (ptr) {
LOG4 ("free (%p[%zu])", ptr, bytes);
dec_bytes (solver, bytes);
free (ptr);
} else
assert (!bytes);
}
char *kissat_strdup (kissat *solver, const char *str) {
char *res = kissat_malloc (solver, strlen (str) + 1);
return strcpy (res, str);
}
void kissat_freestr (struct kissat *solver, char *str) {
assert (str);
kissat_free (solver, str, strlen (str) + 1);
}
void *kissat_nalloc (kissat *solver, size_t n, size_t size) {
void *res;
if (!n || !size)
return 0;
if (MAX_SIZE_T / size < n)
kissat_fatal ("invalid 'kissat_nalloc (..., %zu, %zu)' call", n, size);
const size_t bytes = n * size;
res = malloc (bytes);
LOG4 ("nalloc (%zu, %zu) = %p", n, size, res);
if (!res)
kissat_fatal ("out-of-memory allocating "
"%zu = %zu x %zu bytes",
bytes, n, size);
inc_bytes (solver, bytes);
return res;
}
void *kissat_calloc (kissat *solver, size_t n, size_t size) {
void *res;
if (!n || !size)
return 0;
if (MAX_SIZE_T / size < n)
kissat_fatal ("invalid 'kissat_calloc (..., %zu, %zu)' call", n, size);
res = calloc (n, size);
LOG4 ("calloc (%zu, %zu) = %p", n, size, res);
const size_t bytes = n * size;
if (!res)
kissat_fatal ("out-of-memory allocating "
"%zu = %zu x %zu bytes",
bytes, n, size);
inc_bytes (solver, bytes);
return res;
}
void kissat_dealloc (kissat *solver, void *ptr, size_t n, size_t size) {
if (!n || !size)
return;
if (MAX_SIZE_T / size < n)
kissat_fatal ("invalid 'kissat_dealloc (..., %zu, %zu)' call", n, size);
const size_t bytes = n * size;
kissat_free (solver, ptr, bytes);
}
void *kissat_realloc (kissat *solver, void *p, size_t old_bytes,
size_t new_bytes) {
if (old_bytes == new_bytes)
return p;
if (!new_bytes) {
kissat_free (solver, p, old_bytes);
return 0;
}
dec_bytes (solver, old_bytes);
#ifdef LOGGING
if (GET_OPTION (log) > 3)
kissat_begin_logging (solver, LOGPREFIX, "realloc (%p[%zu, %zu) = ", p,
old_bytes, new_bytes);
#endif
void *res = realloc (p, new_bytes);
#ifdef LOGGING
if (GET_OPTION (log) > 3) {
printf ("%p", res);
kissat_end_logging ();
}
#endif
if (new_bytes && !res)
kissat_fatal ("out-of-memory reallocating from %zu to %zu bytes",
old_bytes, new_bytes);
inc_bytes (solver, new_bytes);
return res;
}
void *kissat_nrealloc (kissat *solver, void *p, size_t o, size_t n,
size_t size) {
if (!size) {
assert (!p);
assert (!o);
return 0;
}
const size_t max = MAX_SIZE_T / size;
if (max < o || max < n)
kissat_fatal ("invalid 'kissat_nrealloc (..., %zu, %zu, %zu)' call", o,
n, size);
return kissat_realloc (solver, p, o * size, n * size);
}

36
src/sat/kissat/allocate.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef _allocate_h_INCLUDED
#define _allocate_h_INCLUDED
#include <stdlib.h>
struct kissat;
void *kissat_malloc (struct kissat *, size_t bytes);
void kissat_free (struct kissat *, void *, size_t bytes);
char *kissat_strdup (struct kissat *, const char *);
void kissat_freestr (struct kissat *, char *);
void *kissat_calloc (struct kissat *, size_t n, size_t size);
void *kissat_nalloc (struct kissat *, size_t n, size_t size);
void kissat_dealloc (struct kissat *, void *ptr, size_t n, size_t size);
void *kissat_realloc (struct kissat *, void *, size_t old, size_t bytes);
void *kissat_nrealloc (struct kissat *, void *, size_t o, size_t n, size_t);
#define NALLOC(P, N) \
do { \
(P) = kissat_nalloc (solver, (N), sizeof *(P)); \
} while (0)
#define CALLOC(P, N) \
do { \
(P) = kissat_calloc (solver, (N), sizeof *(P)); \
} while (0)
#define DEALLOC(P, N) \
do { \
kissat_dealloc (solver, (P), (N), sizeof *(P)); \
} while (0)
#endif

579
src/sat/kissat/analyze.c Normal file
View File

@ -0,0 +1,579 @@
#include "analyze.h"
#include "backtrack.h"
#include "bump.h"
#include "deduce.h"
#include "inline.h"
#include "learn.h"
#include "minimize.h"
#include "print.h"
#include "rank.h"
#include "shrink.h"
#include "sort.h"
#include "tiers.h"
#include <inttypes.h>
static bool one_literal_on_conflict_level (kissat *solver, clause *conflict,
unsigned *conflict_level_ptr) {
assert (conflict);
assert (conflict->size > 1);
unsigned jump_level = INVALID_LEVEL;
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 *const 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 lit_level = all_assigned[idx].level;
if (conflict_level == INVALID_LEVEL || conflict_level < lit_level) {
literals_on_conflict_level = 1;
jump_level = conflict_level;
conflict_level = lit_level;
forced_lit = lit;
} else {
if (jump_level == INVALID_LEVEL || jump_level < lit_level)
jump_level = lit_level;
if (conflict_level == lit_level)
literals_on_conflict_level++;
}
if (literals_on_conflict_level > 1 && conflict_level == solver->level)
break;
}
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_after_conflict (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);
assert (jump_level != INVALID_LEVEL);
assert (jump_level < conflict_level);
LOG ("reusing conflict as driving clause of %s", LOGLIT (forced_lit));
unsigned new_level = kissat_determine_new_level (solver, jump_level);
kissat_backtrack_after_conflict (solver, new_level);
if (conflict_size == 2) {
assert (conflict == &solver->conflict);
const unsigned other = lits[0] ^ lits[1] ^ forced_lit;
kissat_assign_binary (solver, forced_lit, other);
} else {
const reference ref = kissat_reference_clause (solver, conflict);
kissat_assign_reference (solver, forced_lit, ref, conflict);
}
return true;
}
static inline void mark_reason_side_literal (kissat *solver,
assigned *all_assigned,
unsigned lit) {
const unsigned idx = IDX (lit);
const assigned *a = all_assigned + idx;
if (a->level && !a->analyzed)
kissat_push_analyzed (solver, all_assigned, idx);
}
static inline void analyze_reason_side_literal (kissat *solver,
size_t limit, ward *arena,
assigned *all_assigned,
unsigned lit) {
const unsigned idx = IDX (lit);
const assigned *a = all_assigned + idx;
assert (a->level);
assert (a->analyzed);
assert (a->reason != UNIT_REASON);
if (a->reason == DECISION_REASON)
return;
if (a->binary) {
const unsigned other = a->reason;
mark_reason_side_literal (solver, all_assigned, other);
} else {
const reference ref = a->reason;
assert (ref < SIZE_STACK (solver->arena));
clause *c = (clause *) (arena + ref);
const unsigned not_lit = NOT (lit);
INC (search_ticks);
for (all_literals_in_clause (other, c))
if (other != not_lit) {
assert (other != lit);
mark_reason_side_literal (solver, all_assigned, other);
if (SIZE_STACK (solver->analyzed) > limit)
break;
}
}
}
static void analyze_reason_side_literals (kissat *solver) {
if (!GET_OPTION (bump))
return;
if (!GET_OPTION (bumpreasons))
return;
if (solver->probing)
return;
if (DELAYING (bumpreasons))
return;
const double decision_rate = AVERAGE (decision_rate);
const int decision_rate_limit = GET_OPTION (bumpreasonsrate);
if (decision_rate >= decision_rate_limit) {
LOG ("decision rate %g >= limit %d", decision_rate,
decision_rate_limit);
return;
}
assigned *all_assigned = solver->assigned;
#ifndef NDEBUG
for (all_stack (unsigned, lit, solver->clause))
assert (all_assigned[IDX (lit)].analyzed);
#endif
LOG ("trying to bump reason side literals too");
const size_t saved = SIZE_STACK (solver->analyzed);
const size_t limit = GET_OPTION (bumpreasonslimit) * saved;
LOG ("analyzed already %zu literals thus limit %zu", saved, limit);
ward *arena = BEGIN_STACK (solver->arena);
for (all_stack (unsigned, lit, solver->clause)) {
analyze_reason_side_literal (solver, limit, arena, all_assigned, lit);
if (SIZE_STACK (solver->analyzed) > limit)
break;
}
if (SIZE_STACK (solver->analyzed) > limit) {
LOG ("too many additional reason side literals");
while (SIZE_STACK (solver->analyzed) > saved) {
const unsigned idx = POP_STACK (solver->analyzed);
struct assigned *a = all_assigned + idx;
LOG ("marking %s as not analyzed", LOGVAR (idx));
assert (a->analyzed);
a->analyzed = false;
}
BUMP_DELAY (bumpreasons);
} else
REDUCE_DELAY (bumpreasons);
}
#define RADIX_SORT_LEVELS_LIMIT 32
#define RANK_LEVEL(A) (A)
#define SMALLER_LEVEL(A, B) (RANK_LEVEL (A) < RANK_LEVEL (B))
static void sort_levels (kissat *solver) {
unsigneds *levels = &solver->levels;
size_t glue = SIZE_STACK (*levels);
if (glue < RADIX_SORT_LEVELS_LIMIT)
SORT_STACK (unsigned, *levels, SMALLER_LEVEL);
else
RADIX_STACK (unsigned, unsigned, *levels, RANK_LEVEL);
LOG ("sorted %zu levels", glue);
}
static void sort_deduced_clause (kissat *solver) {
sort_levels (solver);
#ifndef NDEBUG
const size_t size_frames = SIZE_STACK (solver->frames);
#endif
frame *frames = BEGIN_STACK (solver->frames);
unsigned pos = 1;
const unsigned *const begin_levels = BEGIN_STACK (solver->levels);
const unsigned *const end_levels = END_STACK (solver->levels);
unsigned const *p = end_levels;
while (p != begin_levels) {
const unsigned level = *--p;
assert (level < size_frames);
frame *f = frames + level;
const unsigned used = f->used;
#ifndef NDEBUG
f->saved = used;
#endif
assert (used > 0);
assert (UINT_MAX - used >= pos);
f->used = pos;
pos += used;
}
unsigneds *clause = &solver->clause;
const size_t size_clause = SIZE_STACK (*clause);
#ifndef NDEBUG
assert (pos == size_clause);
#endif
unsigned const *begin_clause = BEGIN_STACK (*clause);
const unsigned *const end_clause = END_STACK (*clause);
assert (begin_clause < end_clause);
unsigneds *shadow = &solver->shadow;
while (SIZE_STACK (*shadow) < size_clause)
PUSH_STACK (*shadow, INVALID_LIT);
const unsigned not_uip = *begin_clause++;
POKE_STACK (*shadow, 0, not_uip);
const assigned *const assigned = solver->assigned;
for (const unsigned *p = begin_clause; p != end_clause; p++) {
const unsigned lit = *p;
const unsigned idx = IDX (lit);
const struct assigned *a = assigned + idx;
const unsigned level = a->level;
assert (level < size_frames);
frame *f = frames + level;
const unsigned pos = f->used++;
POKE_STACK (*shadow, pos, lit);
}
assert (size_clause == SIZE_STACK (*shadow));
SWAP (unsigneds, *clause, *shadow);
pos = 1;
p = end_levels;
while (p != begin_levels) {
const unsigned level = *--p;
assert (level < size_frames);
frame *f = frames + level;
const unsigned end = f->used;
assert (pos < end);
f->used = end - pos;
assert (f->used == f->saved);
pos = end;
}
CLEAR_STACK (*shadow);
LOGTMP ("level sorted deduced");
#ifndef NDEBUG
unsigned prev_level = solver->level;
for (all_stack (unsigned, lit, solver->clause)) {
const unsigned idx = IDX (lit);
const unsigned lit_level = assigned[idx].level;
assert (prev_level >= lit_level);
prev_level = lit_level;
}
#endif
}
static void reset_levels (kissat *solver) {
LOG ("reset %zu marked levels", SIZE_STACK (solver->levels));
frame *frames = BEGIN_STACK (solver->frames);
#ifndef NDEBUG
const size_t size_frames = SIZE_STACK (solver->frames);
#endif
for (all_stack (unsigned, level, solver->levels)) {
assert (level < size_frames);
frame *f = frames + level;
assert (f->used > 0);
f->used = 0;
}
CLEAR_STACK (solver->levels);
}
void kissat_reset_only_analyzed_literals (kissat *solver) {
LOG ("reset %zu analyzed variables", SIZE_STACK (solver->analyzed));
assigned *assigned = solver->assigned;
for (all_stack (unsigned, idx, solver->analyzed)) {
assert (idx < VARS);
struct assigned *a = assigned + idx;
assert (!a->poisoned);
assert (!a->removable);
assert (!a->shrinkable);
a->analyzed = false;
}
CLEAR_STACK (solver->analyzed);
}
static void reset_removable (kissat *solver) {
LOG ("reset %zu removable variables", SIZE_STACK (solver->removable));
assigned *assigned = solver->assigned;
#ifndef NDEBUG
unsigned not_removable = 0;
#endif
for (all_stack (unsigned, idx, solver->removable)) {
assert (idx < VARS);
struct assigned *a = assigned + idx;
assert (a->removable || !not_removable++);
a->removable = false;
}
CLEAR_STACK (solver->removable);
}
static void reset_analysis_but_not_analyzed_literals (kissat *solver) {
reset_removable (solver);
reset_levels (solver);
LOG ("reset %zu learned literals", SIZE_STACK (solver->clause));
CLEAR_STACK (solver->clause);
}
static void update_trail_average (kissat *solver) {
assert (!solver->probing);
#if defined(LOGGING) || !defined(QUIET)
const unsigned size = SIZE_ARRAY (solver->trail);
const unsigned assigned = size - solver->unflushed;
const unsigned active = solver->active;
const double filled = kissat_percent (assigned, active);
#else
(void) solver;
#endif
LOG ("trail filled %.0f%% (size %u, unflushed %u, active %u)", filled,
size, solver->unflushed, active);
#ifndef QUIET
UPDATE_AVERAGE (trail, filled);
#endif
}
static void update_decision_rate_average (kissat *solver) {
assert (!solver->probing);
const uint64_t current = DECISIONS;
const uint64_t previous =
solver->averages[solver->stable].saved_decisions;
assert (previous <= current);
const uint64_t decisions = current - previous;
solver->averages[solver->stable].saved_decisions = current;
UPDATE_AVERAGE (decision_rate, decisions);
}
static void analyze_failed_literal (kissat *solver, clause *conflict) {
assert (solver->level == 1);
const unsigned failed = FRAME (1).decision;
LOGCLS (conflict, "analyzing failed literal %s conflict",
LOGLIT (failed));
unsigneds *units = &solver->clause;
assert (EMPTY_STACK (*units));
assert (EMPTY_STACK (solver->analyzed));
const unsigned not_failed = NOT (failed);
assigned *all_assigned = solver->assigned;
#ifndef NDEBUG
const value *const values = solver->values;
#endif
unsigned const *t = END_ARRAY (solver->trail);
unsigned unresolved = 0;
unsigned unit = INVALID_LIT;
for (all_literals_in_clause (lit, conflict)) {
assert (lit != failed);
if (lit == not_failed) {
LOG ("negation %s of failed literal %s occurs in conflict",
LOGLIT (not_failed), LOGLIT (failed));
goto DONE;
}
assert (values[lit] < 0);
const unsigned idx = IDX (lit);
assigned *a = all_assigned + idx;
if (!a->level)
continue;
assert (a->level == 1);
LOG ("analyzing conflict literal %s", LOGLIT (lit));
kissat_push_analyzed (solver, all_assigned, idx);
unresolved++;
}
for (;;) {
unsigned lit;
assigned *a;
do {
assert (t > BEGIN_ARRAY (solver->trail));
lit = *--t;
assert (values[lit] > 0);
const unsigned idx = IDX (lit);
a = all_assigned + idx;
} while (!a->analyzed);
if (unresolved == 1) {
unit = NOT (lit);
LOG ("learning additional unit %s", LOGLIT (unit));
PUSH_STACK (*units, unit);
}
if (a->binary) {
const unsigned other = a->reason;
LOGBINARY (lit, other, "resolving %s reason", LOGLIT (lit));
assert (other != failed);
assert (other != unit);
assert (values[other] < 0);
if (other == not_failed) {
LOG ("negation %s of failed literal %s in reason",
LOGLIT (not_failed), LOGLIT (failed));
goto DONE;
}
const unsigned idx = IDX (other);
assigned *b = all_assigned + idx;
assert (b->level == 1);
if (!b->analyzed) {
LOG ("analyzing reason literal %s", LOGLIT (other));
kissat_push_analyzed (solver, all_assigned, idx);
unresolved++;
}
} else {
assert (a->reason != UNIT_REASON);
assert (a->reason != DECISION_REASON);
const reference ref = a->reason;
LOGREF (ref, "resolving %s reason", LOGLIT (lit));
clause *reason = kissat_dereference_clause (solver, ref);
for (all_literals_in_clause (other, reason)) {
assert (other != NOT (lit));
assert (other != failed);
if (other == lit)
continue;
if (other == unit)
continue;
if (other == not_failed) {
LOG ("negation %s of failed literal %s occurs in reason",
LOGLIT (not_failed), LOGLIT (failed));
goto DONE;
}
assert (values[other] < 0);
const unsigned idx = IDX (other);
assigned *b = all_assigned + idx;
if (!b->level)
continue;
assert (b->level == 1);
if (b->analyzed)
continue;
LOG ("analyzing reason literal %s", LOGLIT (other));
kissat_push_analyzed (solver, all_assigned, idx);
unresolved++;
}
}
assert (unresolved > 0);
unresolved--;
LOG ("after resolving %s there are %u unresolved literals",
LOGLIT (lit), unresolved);
}
DONE:
LOG ("learning negated failed literal %s", LOGLIT (not_failed));
PUSH_STACK (*units, not_failed);
if (!solver->probing)
kissat_update_learned (solver, 0, 1);
LOG ("failed literal %s produced %zu units", LOGLIT (failed),
SIZE_STACK (*units));
kissat_backtrack_without_updating_phases (solver, 0);
for (all_stack (unsigned, lit, *units))
kissat_learned_unit (solver, lit);
CLEAR_STACK (*units);
if (!solver->probing) {
solver->iterating = true;
INC (iterations);
}
}
static void update_tier_limits (kissat *solver) {
INC (retiered);
kissat_compute_and_set_tier_limits (solver);
if (solver->limits.glue.interval < (1u << 16))
solver->limits.glue.interval *= 2;
solver->limits.glue.conflicts = CONFLICTS + solver->limits.glue.interval;
}
int kissat_analyze (kissat *solver, clause *conflict) {
if (solver->inconsistent) {
assert (!solver->level);
return 20;
}
START (analyze);
if (!solver->probing) {
update_trail_average (solver);
update_decision_rate_average (solver);
#ifndef QUIET
UPDATE_AVERAGE (level, solver->level);
#endif
}
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_level == 1) {
analyze_failed_literal (solver, conflict);
res = 1;
} else if ((conflict =
kissat_deduce_first_uip_clause (solver, conflict))) {
reset_analysis_but_not_analyzed_literals (solver);
INC (conflicts);
if (CONFLICTS > solver->limits.glue.conflicts)
update_tier_limits (solver);
res = 0; // And continue with new conflict analysis.
} else {
if (GET_OPTION (minimize)) {
sort_deduced_clause (solver);
kissat_minimize_clause (solver);
if (GET_OPTION (shrink))
kissat_shrink_clause (solver);
}
analyze_reason_side_literals (solver);
kissat_learn_clause (solver);
reset_analysis_but_not_analyzed_literals (solver);
res = 1;
}
if (!EMPTY_STACK (solver->analyzed)) {
if (!solver->probing && GET_OPTION (bump))
kissat_bump_analyzed (solver);
kissat_reset_only_analyzed_literals (solver);
}
} while (!res);
STOP (analyze);
return res > 0 ? 0 : 20;
}

12
src/sat/kissat/analyze.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef _analyze_h_INCLUDED
#define _analyze_h_INCLUDED
#include <stdbool.h>
struct clause;
struct kissat;
int kissat_analyze (struct kissat *, struct clause *);
void kissat_reset_only_analyzed_literals (struct kissat *);
#endif

88
src/sat/kissat/ands.c Normal file
View File

@ -0,0 +1,88 @@
#include "ands.h"
#include "eliminate.h"
#include "gates.h"
#include "inline.h"
bool kissat_find_and_gate (kissat *solver, unsigned lit,
unsigned negative) {
if (!GET_OPTION (ands))
return false;
size_t marked = kissat_mark_binaries (solver, lit);
if (!marked)
return false;
if (marked < 2) {
kissat_unmark_binaries (solver, lit);
return false;
}
unsigned not_lit = NOT (lit);
watches *not_watches = &WATCHES (not_lit);
ward *const arena = BEGIN_STACK (solver->arena);
value *marks = solver->marks;
const value *const values = solver->values;
clause *base = 0;
for (all_binary_large_watches (watch, *not_watches)) {
if (watch.type.binary)
continue;
const reference ref = watch.large.ref;
assert (ref < SIZE_STACK (solver->arena));
clause *c = (clause *) (arena + ref);
assert (!c->garbage);
base = c;
for (all_literals_in_clause (other, c)) {
if (other == not_lit)
continue;
const value value = values[other];
if (value > 0) {
kissat_eliminate_clause (solver, c, INVALID_LIT);
base = 0;
break;
}
if (value < 0)
continue;
const unsigned not_other = NOT (other);
signed char mark = marks[not_other];
if (mark)
continue;
base = 0;
break;
}
if (base)
break;
}
if (!base) {
kissat_unmark_binaries (solver, lit);
return false;
}
LOGCLS (base, "found and gate %s base clause", LOGLIT (not_lit));
for (all_literals_in_clause (other, base)) {
if (other == not_lit)
continue;
if (values[other])
continue;
const unsigned not_other = NOT (other);
assert (marks[not_other]);
marks[not_other] = 0;
}
watch tmp = kissat_binary_watch (0);
watches *watches = &WATCHES (lit);
for (all_binary_large_watches (watch, *watches)) {
if (!watch.type.binary)
continue;
const unsigned other = watch.binary.lit;
assert (!solver->values[other]);
if (marks[other]) {
marks[other] = 0;
continue;
}
tmp.binary.lit = other;
PUSH_STACK (solver->gates[negative], tmp);
}
tmp = kissat_large_watch (kissat_reference_clause (solver, base));
PUSH_STACK (solver->gates[!negative], tmp);
solver->gate_eliminated = GATE_ELIMINATED (ands);
INC (ands_extracted);
return true;
}

11
src/sat/kissat/ands.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef _ands_h_INCLUDED
#define _ands_h_INCLUDED
#include <stdbool.h>
struct kissat;
bool kissat_find_and_gate (struct kissat *, unsigned lit,
unsigned negative);
#endif

View File

@ -0,0 +1,8 @@
#ifndef _application_h_INCLUDED
#define _application_h_INCLUDED
struct kissat;
int kissat_application (struct kissat *, int argc, char **argv);
#endif

108
src/sat/kissat/arena.c Normal file
View File

@ -0,0 +1,108 @@
#include "error.h"
#include "internal.h"
#include "logging.h"
#include "print.h"
static void report_resized (kissat *solver, const char *mode,
arena before) {
#ifndef QUIET
ward *const old_begin = BEGIN_STACK (before);
ward *const new_begin = BEGIN_STACK (solver->arena);
const bool moved = (new_begin != old_begin);
const uint64_t capacity = CAPACITY_STACK (solver->arena);
const uint64_t bytes = capacity * sizeof (ward);
kissat_phase (solver, "arena", GET (arena_resized),
"%s to %s %d-byte-words %s (%s)", mode,
FORMAT_COUNT (capacity), (int) sizeof (ward),
FORMAT_BYTES (bytes), (moved ? "moved" : "in place"));
#else
(void) solver;
(void) mode;
(void) before;
#endif
}
reference kissat_allocate_clause (kissat *solver, size_t size) {
assert (size <= UINT_MAX);
const size_t res = SIZE_STACK (solver->arena);
assert (res <= MAX_REF);
const size_t bytes = kissat_bytes_of_clause (size);
assert (kissat_aligned_word (bytes));
const size_t needed = bytes / sizeof (ward);
assert (needed <= UINT_MAX);
size_t capacity = CAPACITY_STACK (solver->arena);
assert (kissat_is_power_of_two (MAX_ARENA));
assert (capacity <= MAX_ARENA);
size_t available = capacity - res;
if (needed > available) {
const arena before = solver->arena;
do {
assert (kissat_is_zero_or_power_of_two (capacity));
if (capacity == MAX_ARENA)
kissat_fatal ("maximum arena capacity "
"of 2^%u %zu-byte-words %s exhausted"
#ifdef COMPACT
" (consider a configuration without '--compact')"
#endif
,
LD_MAX_ARENA, sizeof (ward),
FORMAT_BYTES (MAX_ARENA * sizeof (ward)));
kissat_stack_enlarge (solver, (chars *) &solver->arena,
sizeof (ward));
capacity = CAPACITY_STACK (solver->arena);
available = capacity - res;
} while (needed > available);
INC (arena_resized);
INC (arena_enlarged);
report_resized (solver, "enlarged", before);
assert (capacity <= MAX_ARENA);
}
solver->arena.end += needed;
LOG ("allocated clause[%zu] of size %zu bytes %s", res, size,
FORMAT_BYTES (bytes));
return (reference) res;
}
void kissat_shrink_arena (kissat *solver) {
const arena before = solver->arena;
const size_t capacity = CAPACITY_STACK (before);
const size_t size = SIZE_STACK (before);
#ifndef QUIET
const size_t capacity_bytes = capacity * sizeof (ward);
kissat_phase (solver, "arena", GET (arena_resized),
"capacity of %s %d-byte-words %s", FORMAT_COUNT (capacity),
(int) sizeof (ward), FORMAT_BYTES (capacity_bytes));
const size_t size_bytes = size * sizeof (ward);
kissat_phase (solver, "arena", GET (arena_resized),
"filled %.0f%% with %s %d-byte-words %s",
kissat_percent (size, capacity), FORMAT_COUNT (size),
(int) sizeof (ward), FORMAT_BYTES (size_bytes));
#endif
if (size > capacity / 4) {
kissat_phase (solver, "arena", GET (arena_resized),
"not shrinking since more than 25%% filled");
return;
}
INC (arena_resized);
INC (arena_shrunken);
SHRINK_STACK (solver->arena);
report_resized (solver, "shrunken", before);
}
#if !defined(NDEBUG) || defined(LOGGING)
bool kissat_clause_in_arena (const kissat *solver, const clause *c) {
if (!kissat_aligned_pointer (c))
return false;
const char *p = (char *) c;
const char *begin = (char *) BEGIN_STACK (solver->arena);
const char *end = (char *) END_STACK (solver->arena);
if (p < begin)
return false;
const size_t bytes = kissat_bytes_of_clause (c->size);
if (end < p + bytes)
return false;
return true;
}
#endif

46
src/sat/kissat/arena.h Normal file
View File

@ -0,0 +1,46 @@
#ifndef _arena_h_INCLUDED
#define _arena_h_INCLUDED
#include "reference.h"
#include "stack.h"
#include "utilities.h"
#ifdef COMPACT
typedef word ward;
#else
typedef w2rd ward;
#endif
#define LD_MAX_ARENA_32 (29 - (unsigned) sizeof (ward) / 4)
#define LD_MAX_ARENA ((sizeof (word) == 4) ? LD_MAX_ARENA_32 : LD_MAX_REF)
#define MAX_ARENA ((size_t) 1 << LD_MAX_ARENA)
// clang-format off
typedef STACK (ward) arena;
// clang-format on
struct clause;
struct kissat;
reference kissat_allocate_clause (struct kissat *, size_t size);
void kissat_shrink_arena (struct kissat *);
#if !defined(NDEBUG) || defined(LOGGING)
bool kissat_clause_in_arena (const struct kissat *, const struct clause *);
#endif
static inline word kissat_align_ward (word w) {
#ifdef COMPACT
return kissat_align_word (w);
#else
return kissat_align_w2rd (w);
#endif
}
#endif

58
src/sat/kissat/array.h Normal file
View File

@ -0,0 +1,58 @@
#ifndef _array_h_INCLUDED
#define _array_h_INCLUDED
#include "allocate.h"
#include "stack.h"
#define ARRAY(TYPE) \
struct { \
TYPE *begin; \
TYPE *end; \
}
#define ALLOCATE_ARRAY(A, N) \
do { \
const size_t TMP_N = (N); \
(A).begin = (A).end = \
kissat_nalloc (solver, TMP_N, sizeof *(A).begin); \
} while (0)
#define EMPTY_ARRAY EMPTY_STACK
#define SIZE_ARRAY SIZE_STACK
#define PUSH_ARRAY(A, E) \
do { \
*(A).end++ = (E); \
} while (0)
#define REALLOCATE_ARRAY(A, O, N) \
do { \
const size_t SIZE = SIZE_ARRAY (A); \
(A).begin = \
kissat_nrealloc (solver, (A).begin, (O), (N), sizeof *(A).begin); \
(A).end = (A).begin + SIZE; \
} while (0)
#define RELEASE_ARRAY(A, N) \
do { \
const size_t TMP_NIZE = (N); \
DEALLOC ((A).begin, TMP_NIZE); \
} while (0)
#define CLEAR_ARRAY CLEAR_STACK
#define TOP_ARRAY TOP_STACK
#define PEEK_ARRAY PEEK_STACK
#define POKE_ARRAY POKE_STACK
#define POP_ARRAY POP_STACK
#define BEGIN_ARRAY BEGIN_STACK
#define END_ARRAY END_STACK
#define RESIZE_ARRAY RESIZE_STACK
#define SET_END_OF_ARRAY SET_END_OF_STACK
// clang-format off
typedef ARRAY (unsigned) unsigned_array;
// clang-format on
#endif

59
src/sat/kissat/assign.c Normal file
View File

@ -0,0 +1,59 @@
#include "assign.h"
#include "inline.h"
#include "inlineassign.h"
#include "logging.h"
#include <limits.h>
void kissat_assign_unit (kissat *solver, unsigned lit, const char *reason) {
kissat_assign (solver, solver->probing, 0, false, lit, UNIT_REASON);
LOGUNARY (lit, "assign %s %s", LOGLIT (lit), reason);
#ifndef LOGGING
(void) reason;
#endif
}
void kissat_learned_unit (kissat *solver, unsigned lit) {
kissat_assign_unit (solver, lit, "learned reason");
CHECK_AND_ADD_UNIT (lit);
ADD_UNIT_TO_PROOF (lit);
}
void kissat_original_unit (kissat *solver, unsigned lit) {
kissat_assign_unit (solver, lit, "original reason");
}
void kissat_assign_decision (kissat *solver, unsigned lit) {
kissat_assign (solver, solver->probing, solver->level, false, lit,
DECISION_REASON);
LOG ("assign %s decision", LOGLIT (lit));
}
void kissat_assign_binary (kissat *solver, unsigned lit, unsigned other) {
assert (VALUE (other) < 0);
assigned *assigned = solver->assigned;
const unsigned other_idx = IDX (other);
struct assigned *a = assigned + other_idx;
unsigned level = a->level;
if (GET_OPTION (jumpreasons) && level && a->binary) {
LOGBINARY (lit, other, "jumping %s reason", LOGLIT (lit));
INC (jumped_reasons);
other = a->reason;
}
kissat_assign (solver, solver->probing, a->level, true, lit, other);
LOGBINARY (lit, other, "assign %s reason", LOGLIT (lit));
}
void kissat_assign_reference (kissat *solver, unsigned lit, reference ref,
clause *reason) {
assert (reason == kissat_dereference_clause (solver, ref));
assigned *assigned = solver->assigned;
value *values = solver->values;
const unsigned level =
kissat_assignment_level (solver, values, assigned, lit, reason);
assert (level <= solver->level);
assert (ref != DECISION_REASON);
assert (ref != UNIT_REASON);
kissat_assign (solver, solver->probing, level, false, lit, ref);
LOGREF (ref, "assign %s reason", LOGLIT (lit));
}

55
src/sat/kissat/assign.h Normal file
View File

@ -0,0 +1,55 @@
#ifndef _assign_h_INCLUDED
#define _assign_h_INCLUDED
#include <stdbool.h>
#define DECISION_REASON UINT_MAX
#define UNIT_REASON (DECISION_REASON - 1)
#define INVALID_LEVEL UINT_MAX
#define INVALID_TRAIL UINT_MAX
typedef struct assigned assigned;
struct clause;
struct assigned {
unsigned level;
unsigned trail;
bool analyzed : 1;
bool binary : 1;
bool poisoned : 1;
bool removable : 1;
bool shrinkable : 1;
unsigned reason;
};
#define ASSIGNED(LIT) \
(assert (VALID_INTERNAL_LITERAL (LIT)), solver->assigned + IDX (LIT))
#define LEVEL(LIT) (ASSIGNED (LIT)->level)
#define TRAIL(LIT) (ASSIGNED (LIT)->trail)
#define REASON(LIT) (ASSIGNED (LIT)->reason)
#ifndef FAST_ASSIGN
#include "reference.h"
struct kissat;
struct clause;
void kissat_assign_unit (struct kissat *, unsigned lit, const char *);
void kissat_learned_unit (struct kissat *, unsigned lit);
void kissat_original_unit (struct kissat *, unsigned lit);
void kissat_assign_decision (struct kissat *, unsigned lit);
void kissat_assign_binary (struct kissat *, unsigned, unsigned);
void kissat_assign_reference (struct kissat *, unsigned lit, reference,
struct clause *);
#endif
#endif

View File

@ -0,0 +1,10 @@
#ifndef _attribute_h_INCLUDED
#define _attribute_h_INCLUDED
#define ATTRIBUTE_FORMAT(FORMAT_POSITION, VARIADIC_ARGUMENT_POSITION) \
__attribute__ (( \
format (printf, FORMAT_POSITION, VARIADIC_ARGUMENT_POSITION)))
#define ATTRIBUTE_ALWAYS_INLINE __attribute__ ((always_inline))
#endif

17
src/sat/kissat/averages.c Normal file
View File

@ -0,0 +1,17 @@
#include "internal.h"
void kissat_init_averages (kissat *solver, averages *averages) {
if (averages->initialized)
return;
#define INIT_EMA(EMA, WINDOW) \
kissat_init_smooth (solver, &averages->EMA, WINDOW, #EMA)
#ifndef QUIET
INIT_EMA (level, GET_OPTION (emaslow));
INIT_EMA (size, GET_OPTION (emaslow));
INIT_EMA (trail, GET_OPTION (emaslow));
#endif
INIT_EMA (fast_glue, GET_OPTION (emafast));
INIT_EMA (slow_glue, GET_OPTION (emaslow));
INIT_EMA (decision_rate, GET_OPTION (emaslow));
averages->initialized = true;
}

33
src/sat/kissat/averages.h Normal file
View File

@ -0,0 +1,33 @@
#ifndef _averages_h_INCLUDED
#define _averages_h_INCLUDED
#include "smooth.h"
#include <stdbool.h>
typedef struct averages averages;
struct averages {
bool initialized;
smooth fast_glue, slow_glue;
#ifndef QUIET
smooth level, size, trail;
#endif
smooth decision_rate;
uint64_t saved_decisions;
};
struct kissat;
void kissat_init_averages (struct kissat *, averages *);
#define AVERAGES (solver->averages[solver->stable])
#define EMA(NAME) (AVERAGES.NAME)
#define AVERAGE(NAME) (EMA (NAME).value)
#define UPDATE_AVERAGE(NAME, VALUE) \
kissat_update_smooth (solver, &EMA (NAME), VALUE)
#endif

598
src/sat/kissat/backbone.c Normal file
View File

@ -0,0 +1,598 @@
#include "backbone.h"
#include "allocate.h"
#include "analyze.h"
#include "backtrack.h"
#include "decide.h"
#include "inline.h"
#include "internal.h"
#include "logging.h"
#include "print.h"
#include "proprobe.h"
#include "report.h"
#include "terminate.h"
#include "trail.h"
#include "utilities.h"
static void schedule_backbone_candidates (kissat *solver,
unsigneds *candidates) {
flags *flags = solver->flags;
unsigned not_rescheduled = 0;
for (all_variables (idx)) {
const struct flags *f = flags + idx;
if (!f->active)
continue;
const unsigned lit = LIT (idx);
if (f->backbone0) {
PUSH_STACK (*candidates, lit);
LOG ("rescheduling backbone literal candidate %s", LOGLIT (lit));
} else
not_rescheduled++;
if (f->backbone1) {
const unsigned not_lit = NOT (lit);
PUSH_STACK (*candidates, not_lit);
LOG ("rescheduling backbone literal candidate %s", LOGLIT (not_lit));
} else
not_rescheduled++;
}
#ifndef QUIET
const size_t rescheduled = SIZE_STACK (*candidates);
const unsigned active_literals = 2u * solver->active;
kissat_very_verbose (
solver, "rescheduled %zu backbone candidate literals %.0f%%",
rescheduled, kissat_percent (rescheduled, active_literals));
#endif
if (not_rescheduled) {
for (all_variables (idx)) {
struct flags *f = flags + idx;
if (!f->active)
continue;
const unsigned lit = LIT (idx);
if (!f->backbone0) {
LOG ("scheduling backbone literal candidate %s", LOGLIT (lit));
PUSH_STACK (*candidates, lit);
}
if (!f->backbone1) {
const unsigned not_lit = NOT (lit);
LOG ("scheduling backbone literal candidate %s", LOGLIT (not_lit));
PUSH_STACK (*candidates, not_lit);
}
}
}
#ifndef QUIET
const size_t total = SIZE_STACK (*candidates);
kissat_very_verbose (solver,
"scheduled %zu backbone candidate literals %.0f%%"
" in total",
total, kissat_percent (total, active_literals));
#endif
}
static void keep_backbone_candidates (kissat *solver,
unsigneds *candidates) {
flags *flags = solver->flags;
size_t prioritized = 0;
size_t remain = 0;
for (all_stack (unsigned, lit, *candidates)) {
const unsigned idx = IDX (lit);
const struct flags *f = flags + idx;
if (!f->active)
continue;
remain++;
if (NEGATED (lit))
prioritized += f->backbone1;
else
prioritized += f->backbone0;
}
assert (prioritized <= remain);
if (!remain) {
kissat_very_verbose (solver, "no backbone candidates remain");
#ifndef NDEBUG
for (all_variables (idx)) {
const struct flags *f = flags + idx;
if (!f->active)
continue;
assert (!f->backbone0);
assert (!f->backbone1);
}
#endif
return;
}
#ifndef QUIET
const size_t active_literals = 2u * solver->active;
#endif
if (prioritized == remain)
kissat_very_verbose (solver,
"keeping all remaining %zu backbone "
"candidates %.0f%% prioritized (all were)",
remain, kissat_percent (remain, active_literals));
else if (!prioritized) {
for (all_stack (unsigned, lit, *candidates)) {
const unsigned idx = IDX (lit);
struct flags *f = flags + idx;
if (!f->active)
continue;
if (NEGATED (lit)) {
assert (!f->backbone1);
f->backbone1 = true;
} else {
assert (!f->backbone0);
f->backbone0 = true;
}
}
kissat_very_verbose (solver,
"keeping all remaining %zu backbone "
"candidates %.0f%% prioritized (none was)",
remain, kissat_percent (remain, active_literals));
} else {
kissat_very_verbose (solver,
"keeping %zu backbone candidates %.0f%% "
"prioritized (%.0f%% of remaining %zu)",
prioritized,
kissat_percent (prioritized, active_literals),
kissat_percent (prioritized, remain), remain);
}
}
static inline void backbone_assign (kissat *solver, unsigned_array *trail,
value *values, assigned *assigned,
unsigned lit, unsigned reason) {
const unsigned not_lit = NOT (lit);
assert (!values[lit]);
assert (!values[not_lit]);
values[lit] = 1;
values[not_lit] = -1;
PUSH_ARRAY (*trail, lit);
const unsigned idx = IDX (lit);
struct assigned *a = assigned + idx;
a->reason = reason;
a->level = solver->level;
}
static inline clause *
backbone_propagate_literal (kissat *solver, const bool stop_early,
const watches *const all_watches,
unsigned_array *trail, value *values,
assigned *assigned, unsigned lit) {
LOG ("backbone propagating %s", LOGLIT (lit));
assert (VALID_INTERNAL_LITERAL (lit));
assert (values[lit] > 0);
const unsigned not_lit = NOT (lit);
assert (values[not_lit] < 0);
assert (not_lit < LITS);
const watches *const watches = all_watches + not_lit;
const watch *const begin_watches = BEGIN_CONST_WATCHES (*watches);
const watch *const end_watches = END_CONST_WATCHES (*watches);
const watch *p = begin_watches;
while (p != end_watches) {
const watch watch = *p++;
if (watch.type.binary) {
const unsigned other = watch.binary.lit;
assert (VALID_INTERNAL_LITERAL (other));
const value value = values[other];
if (value > 0)
continue;
if (value < 0)
return kissat_binary_conflict (solver, not_lit, other);
assert (!value);
backbone_assign (solver, trail, values, assigned, other, lit);
LOG ("backbone assign %s reason binary clause %s %s", LOGLIT (other),
LOGLIT (other), LOGLIT (not_lit));
} else {
if (stop_early) {
#ifndef NDEBUG
for (const union watch *q = p + 1; q != end_watches; q++) {
const union watch watch = *q++;
assert (!watch.type.binary);
}
#endif
break;
}
p++;
}
}
const size_t touched = p - begin_watches;
solver->ticks += 1 + kissat_cache_lines (touched, sizeof (watch));
return 0;
}
static inline clause *backbone_propagate (kissat *solver,
unsigned_array *trail,
value *values,
assigned *assigned) {
const bool stop_early =
solver->large_clauses_watched_after_binary_clauses;
clause *conflict = 0;
solver->ticks = 0;
const watches *const watches = solver->watches;
unsigned *propagate = solver->propagate;
while (!conflict && propagate != END_ARRAY (*trail))
conflict = backbone_propagate_literal (
solver, stop_early, watches, trail, values, assigned, *propagate++);
assert (solver->propagate <= propagate);
const unsigned propagated = propagate - solver->propagate;
solver->propagate = propagate;
ADD (backbone_propagations, propagated);
ADD (probing_propagations, propagated);
ADD (propagations, propagated);
const uint64_t ticks = solver->ticks;
ADD (backbone_ticks, ticks);
ADD (probing_ticks, ticks);
ADD (ticks, ticks);
return conflict;
}
static inline void backbone_backtrack (kissat *solver,
unsigned_array *trail, value *values,
unsigned *saved,
unsigned decision_level) {
assert (decision_level <= solver->level);
unsigned *end_trail = END_ARRAY (*trail);
assert (saved != end_trail);
LOG ("backbone backtracking to trail level %zu and decision level %u",
(size_t) (saved - BEGIN_ARRAY (*trail)), decision_level);
while (saved != end_trail) {
const unsigned lit = *--end_trail;
const unsigned not_lit = NOT (lit);
LOG ("backbone unassign %s", LOGLIT (lit));
assert (values[lit] > 0);
assert (values[not_lit] < 0);
values[lit] = values[not_lit] = 0;
}
SET_END_OF_ARRAY (solver->trail, saved);
solver->level = decision_level;
solver->propagate = saved;
}
static unsigned backbone_analyze (kissat *solver, clause *conflict) {
assert (conflict);
LOGCLS (conflict, "backbone analyzing");
assert (conflict->size == 2);
assigned *const assigned = solver->assigned;
kissat_push_analyzed (solver, assigned, IDX (conflict->lits[0]));
kissat_push_analyzed (solver, assigned, IDX (conflict->lits[1]));
const unsigned *t = END_ARRAY (solver->trail);
for (;;) {
assert (t > BEGIN_ARRAY (solver->trail));
unsigned lit = *--t;
const unsigned lit_idx = IDX (lit);
const struct assigned *a = assigned + lit_idx;
if (!a->analyzed)
continue;
LOG ("backbone analyzing %s", LOGLIT (lit));
const unsigned reason = a->reason;
assert (reason != UNIT_REASON);
assert (reason != DECISION_REASON);
const unsigned reason_idx = IDX (reason);
const struct assigned *b = assigned + reason_idx;
if (!b->analyzed) {
LOG ("reason %s of %s not yet analyzed", LOGLIT (reason),
LOGLIT (lit));
kissat_push_analyzed (solver, assigned, reason_idx);
} else {
LOG ("backbone UIP %s", LOGLIT (reason));
kissat_reset_only_analyzed_literals (solver);
return reason;
}
}
}
#ifndef NDEBUG
static void
check_large_clauses_watched_after_binary_clauses (kissat *solver) {
for (all_literals (lit)) {
bool large = false;
for (all_binary_blocking_watches (watch, WATCHES (lit)))
if (watch.type.binary)
assert (!large);
else
large = true;
}
}
#endif
static unsigned compute_backbone (kissat *solver) {
#ifndef NDEBUG
if (solver->large_clauses_watched_after_binary_clauses)
check_large_clauses_watched_after_binary_clauses (solver);
#endif
size_t failed = 0;
unsigneds units;
unsigneds candidates;
INIT_STACK (candidates);
INIT_STACK (units);
schedule_backbone_candidates (solver, &candidates);
#ifndef QUIET
const size_t scheduled = SIZE_STACK (candidates);
#endif
#if defined(METRICS) && (!defined(QUIET) || !defined(NDEBUG))
const uint64_t implied_before = solver->statistics.backbone_implied;
#endif
unsigned_array *trail = &solver->trail;
value *values = solver->values;
flags *flags = solver->flags;
assigned *assigned = solver->assigned;
assert (kissat_propagated (solver));
assert (kissat_trail_flushed (solver));
unsigned inconsistent = INVALID_LIT;
SET_EFFORT_LIMIT (ticks_limit, backbone, backbone_ticks);
size_t round_limit = GET_OPTION (backbonerounds);
assert (solver->statistics.backbone_computations);
round_limit *= solver->statistics.backbone_computations;
const size_t max_rounds = GET_OPTION (backbonemaxrounds);
if (round_limit > max_rounds)
round_limit = max_rounds;
size_t round = 0;
for (;;) {
if (round >= round_limit) {
kissat_very_verbose (solver, "backbone round limit %zu hit", round);
break;
}
const uint64_t ticks = solver->statistics.backbone_ticks;
if (ticks > ticks_limit) {
kissat_very_verbose (solver,
"backbone ticks limit %" PRIu64 " hit "
"after %" PRIu64 " ticks",
ticks_limit, ticks);
break;
}
size_t previous = failed;
assert (!solver->inconsistent);
if (TERMINATED (backbone_terminated_1))
break;
round++;
INC (backbone_rounds);
LOG ("starting backbone round %zu", round);
unsigned *const begin_candidates = BEGIN_STACK (candidates);
assert (!solver->level);
#if !defined(QUIET) && defined(METRICS)
size_t decisions = 0;
uint64_t propagated = solver->statistics.backbone_propagations;
#endif
unsigned active_before = solver->active;
{
unsigned *q = begin_candidates;
const unsigned *p = begin_candidates;
const unsigned *const end_candidates = END_STACK (candidates);
while (p != end_candidates) {
assert (!solver->inconsistent);
const unsigned probe = *q++ = *p++;
const value value = values[probe];
if (value > 0) {
q--;
LOG ("removing satisfied backbone probe %s", LOGLIT (probe));
const unsigned idx = IDX (probe);
struct flags *f = flags + idx;
if (NEGATED (probe))
f->backbone1 = false;
else
f->backbone0 = false;
continue;
}
if (value < 0) {
const unsigned idx = IDX (probe);
struct assigned *a = assigned + idx;
if (a->level)
LOG ("skipping falsified backbone probe %s", LOGLIT (probe));
else {
LOG ("removing root-level falsified backbone probe %s",
LOGLIT (probe));
q--;
}
continue;
}
if (solver->statistics.backbone_ticks > ticks_limit)
break;
if (TERMINATED (backbone_terminated_2))
break;
const unsigned level = solver->level;
unsigned *const saved = END_ARRAY (*trail);
assert (level != UINT_MAX);
#if !defined(QUIET) && defined(METRICS)
decisions++;
#endif
solver->level = level + 1;
INC (backbone_probes);
backbone_assign (solver, trail, values, assigned, probe,
DECISION_REASON);
LOG ("backbone assume %s", LOGLIT (probe));
clause *conflict =
backbone_propagate (solver, trail, values, assigned);
if (!conflict) {
LOG ("propagating backbone probe %s successful", LOGLIT (probe));
continue;
}
failed++;
INC (backbone_units);
q--;
LOG ("propagating backbone probe %s failed", LOGLIT (probe));
unsigned uip = backbone_analyze (solver, conflict);
unsigned not_uip = NOT (uip);
backbone_backtrack (solver, trail, values, saved, level);
PUSH_STACK (units, not_uip);
backbone_assign (solver, trail, values, assigned, not_uip,
UNIT_REASON);
LOG ("backbone forced assign %s", LOGLIT (not_uip));
assert (failed == SIZE_STACK (units));
conflict = backbone_propagate (solver, trail, values, assigned);
if (conflict) {
LOG ("propagating backbone forced %s failed", LOGLIT (not_uip));
inconsistent = not_uip;
break;
}
LOG ("propagating backbone forced %s successful", LOGLIT (not_uip));
}
#ifndef QUIET
size_t remain = end_candidates - p;
if (remain)
kissat_extremely_verbose (solver,
"backbone round %zu aborted with "
"%zu candidates %.0f%% remaining",
round, remain,
kissat_percent (remain, scheduled));
else
kissat_extremely_verbose (solver,
"backbone round %zu completed with "
"all %zu scheduled candidates tried",
round, scheduled);
#endif
while (p != end_candidates)
*q++ = *p++;
SET_END_OF_STACK (candidates, q);
}
if (inconsistent == INVALID_LIT) {
LOG ("flushing satisfied probe candidates");
unsigned *q = begin_candidates;
const unsigned *p = begin_candidates;
const unsigned *const end_candidates = END_STACK (candidates);
while (p != end_candidates) {
const unsigned probe = *q++ = *p++;
const value value = values[probe];
if (value > 0) {
q--;
LOG ("removing satisfied backbone probe %s", LOGLIT (probe));
const unsigned idx = IDX (probe);
struct flags *f = flags + idx;
if (NEGATED (probe))
f->backbone1 = false;
else
f->backbone0 = false;
continue;
}
if (value < 0) {
LOG ("keeping falsified probe %s", LOGLIT (probe));
continue;
}
assert (!value);
LOG ("keeping unassigned probe %s", LOGLIT (probe));
}
LOG ("flushed %zu probe candidates",
(size_t) (q - BEGIN_STACK (candidates)));
SET_END_OF_STACK (candidates, q);
}
if (!EMPTY_ARRAY (*trail))
backbone_backtrack (solver, trail, values, BEGIN_ARRAY (*trail), 0);
if (inconsistent == INVALID_LIT && previous < failed) {
for (size_t i = previous; i < failed; i++) {
const unsigned unit = PEEK_STACK (units, i);
LOG ("assigning backbone unit %s", LOGLIT (unit));
kissat_learned_unit (solver, unit);
}
if (kissat_probing_propagate (solver, 0, true))
break;
}
assert (solver->active <= active_before);
unsigned implied = active_before - solver->active;
assert (failed <= failed);
ADD (backbone_implied, implied);
#ifndef QUIET
#ifdef METRICS
propagated = solver->statistics.backbone_propagations - propagated;
kissat_very_verbose (solver,
"backbone round %zu with %zu decisions "
"(%.2f propagations per decision)",
round, decisions,
kissat_average (propagated, decisions));
#endif
size_t left = SIZE_STACK (candidates);
kissat_very_verbose (solver,
"backbone round %zu produced %zu failed literals"
" %u implied (%zu candidates left %.0f%%)",
round, failed - previous, implied, left,
kissat_percent (left, scheduled));
#endif
if (inconsistent != INVALID_LIT)
break;
if (EMPTY_STACK (candidates))
break;
}
if (inconsistent != INVALID_LIT && !solver->inconsistent) {
LOG ("assuming forced unit %s", LOGLIT (inconsistent));
kissat_learned_unit (solver, inconsistent);
(void) kissat_probing_propagate (solver, 0, true);
assert (solver->inconsistent);
}
RELEASE_STACK (units);
if (solver->inconsistent)
kissat_phase (solver, "backbone", GET (backbone_computations),
"inconsistent binary clauses");
else {
keep_backbone_candidates (solver, &candidates);
#if defined(METRICS) && (!defined(QUIET) || !defined(NDEBUG))
assert (implied_before <= solver->statistics.backbone_implied);
#endif
#if defined(METRICS) && !defined(QUIET)
const uint64_t total_implied =
solver->statistics.backbone_implied - implied_before;
kissat_phase (solver, "backbone", GET (backbone_computations),
"found %zu backbone literals %" PRIu64
" implied in %zu rounds",
failed, total_implied, round);
#endif
}
RELEASE_STACK (candidates);
return failed;
}
void kissat_binary_clauses_backbone (kissat *solver) {
if (solver->inconsistent)
return;
if (!GET_OPTION (backbone))
return;
if (TERMINATED (backbone_terminated_3))
return;
assert (solver->watching);
assert (solver->probing);
assert (!solver->level);
START (backbone);
INC (backbone_computations);
#if !defined(NDEBUG) || defined(METRICS)
assert (!solver->backbone_computing);
solver->backbone_computing = true;
#endif
#ifndef QUIET
const unsigned failed =
#endif
compute_backbone (solver);
REPORT (!failed, 'b');
#if !defined(NDEBUG) || defined(METRICS)
assert (solver->backbone_computing);
solver->backbone_computing = false;
#endif
STOP (backbone);
}

View File

@ -0,0 +1,9 @@
#ifndef _backbone_h_INCLUDED
#define _backbone_h_INCLUDED
#include <stdbool.h>
struct kissat;
void kissat_binary_clauses_backbone (struct kissat *);
#endif

177
src/sat/kissat/backtrack.c Normal file
View File

@ -0,0 +1,177 @@
#include "backtrack.h"
#include "analyze.h"
#include "inline.h"
#include "inlineheap.h"
#include "inlinequeue.h"
#include "print.h"
#include "proprobe.h"
#include "propsearch.h"
#include "trail.h"
static inline void unassign (kissat *solver, value *values, unsigned lit) {
LOG ("unassign %s", LOGLIT (lit));
assert (values[lit] > 0);
const unsigned not_lit = NOT (lit);
values[lit] = values[not_lit] = 0;
assert (solver->unassigned < VARS);
solver->unassigned++;
}
static inline void add_unassigned_variable_back_to_queue (kissat *solver,
links *links,
unsigned lit) {
assert (!solver->stable);
const unsigned idx = IDX (lit);
if (links[idx].stamp > solver->queue.search.stamp)
kissat_update_queue (solver, links, idx);
}
static inline void add_unassigned_variable_back_to_heap (kissat *solver,
heap *scores,
unsigned lit) {
assert (solver->stable);
const unsigned idx = IDX (lit);
if (!kissat_heap_contains (scores, idx))
kissat_push_heap (solver, scores, idx);
}
static void kissat_update_target_and_best_phases (kissat *solver) {
if (solver->probing)
return;
if (!solver->stable)
return;
const unsigned assigned = kissat_assigned (solver);
#ifdef LOGGING
LOG ("updating target and best phases");
LOG ("currently %u variables assigned", assigned);
#endif
if (solver->target_assigned < assigned) {
kissat_extremely_verbose (solver,
"updating target assigned "
"trail height from %u to %u",
solver->target_assigned, assigned);
solver->target_assigned = assigned;
kissat_save_target_phases (solver);
INC (target_saved);
}
if (solver->best_assigned < assigned) {
kissat_extremely_verbose (solver,
"updating best assigned "
"trail height from %u to %u",
solver->best_assigned, assigned);
solver->best_assigned = assigned;
kissat_save_best_phases (solver);
INC (best_saved);
}
}
void kissat_backtrack_without_updating_phases (kissat *solver,
unsigned new_level) {
assert (solver->level >= new_level);
if (solver->level == new_level)
return;
LOG ("backtracking to decision level %u", new_level);
frame *new_frame = &FRAME (new_level + 1);
SET_END_OF_STACK (solver->frames, new_frame);
value *values = solver->values;
unsigned *trail = BEGIN_ARRAY (solver->trail);
unsigned *new_end = trail + new_frame->trail;
assigned *assigned = solver->assigned;
unsigned *old_end = END_ARRAY (solver->trail);
unsigned unassigned = 0, reassigned = 0;
unsigned *q = new_end;
if (solver->stable) {
heap *scores = SCORES;
for (const unsigned *p = q; p != old_end; p++) {
const unsigned lit = *p;
const unsigned idx = IDX (lit);
assert (idx < VARS);
struct assigned *a = assigned + idx;
const unsigned level = a->level;
if (level <= new_level) {
const unsigned new_trail = q - trail;
assert (new_trail <= a->trail);
a->trail = new_trail;
*q++ = lit;
LOG ("reassign %s", LOGLIT (lit));
reassigned++;
} else {
unassign (solver, values, lit);
add_unassigned_variable_back_to_heap (solver, scores, lit);
unassigned++;
}
}
} else {
links *links = solver->links;
for (const unsigned *p = q; p != old_end; p++) {
const unsigned lit = *p;
const unsigned idx = IDX (lit);
assert (idx < VARS);
struct assigned *a = assigned + idx;
const unsigned level = a->level;
if (level <= new_level) {
const unsigned new_trail = q - trail;
assert (new_trail <= a->trail);
a->trail = new_trail;
*q++ = lit;
LOG ("reassign %s", LOGLIT (lit));
reassigned++;
} else {
unassign (solver, values, lit);
add_unassigned_variable_back_to_queue (solver, links, lit);
unassigned++;
}
}
}
SET_END_OF_ARRAY (solver->trail, q);
solver->level = new_level;
LOG ("unassigned %u literals", unassigned);
LOG ("reassigned %u literals", reassigned);
(void) unassigned, (void) reassigned;
assert (new_end <= END_ARRAY (solver->trail));
LOG ("propagation will resume at trail position %zu",
(size_t) (new_end - trail));
solver->propagate = new_end;
assert (!solver->extended);
}
void kissat_backtrack_in_consistent_state (kissat *solver,
unsigned new_level) {
kissat_update_target_and_best_phases (solver);
kissat_backtrack_without_updating_phases (solver, new_level);
}
void kissat_backtrack_after_conflict (kissat *solver, unsigned new_level) {
if (solver->level)
kissat_backtrack_without_updating_phases (solver, solver->level - 1);
kissat_update_target_and_best_phases (solver);
kissat_backtrack_without_updating_phases (solver, new_level);
}
void kissat_backtrack_propagate_and_flush_trail (kissat *solver) {
if (solver->level) {
assert (solver->watching);
kissat_backtrack_in_consistent_state (solver, 0);
#ifndef NDEBUG
clause *conflict =
#endif
solver->probing ? kissat_probing_propagate (solver, 0, true)
: kissat_search_propagate (solver);
assert (!conflict);
}
assert (kissat_propagated (solver));
assert (kissat_trail_flushed (solver));
}

View File

@ -0,0 +1,11 @@
#ifndef _backtrack_h_INCLUDED
#define _backtrack_h_INCLUDED
struct kissat;
void kissat_backtrack_without_updating_phases (struct kissat *, unsigned);
void kissat_backtrack_in_consistent_state (struct kissat *, unsigned);
void kissat_backtrack_after_conflict (struct kissat *, unsigned);
void kissat_backtrack_propagate_and_flush_trail (struct kissat *);
#endif

81
src/sat/kissat/build.c Normal file
View File

@ -0,0 +1,81 @@
#include "build.h"
#include "colors.h"
#include "kissat.h"
#include "print.h"
#include <stdio.h>
const char *kissat_signature (void) { return "kissat-" VERSION; }
const char *kissat_id (void) { return ID; }
const char *kissat_compiler (void) { return COMPILER; }
static const char *copyright_lines[] = {
"Copyright (c) 2021-2024 Armin Biere University of Freiburg",
"Copyright (c) 2019-2021 Armin Biere Johannes Kepler University Linz",
0};
const char **kissat_copyright (void) { return copyright_lines; }
const char *kissat_version (void) { return VERSION; }
#define PREFIX(COLORS) \
do { \
if (prefix) \
fputs (prefix, stdout); \
COLOR (COLORS); \
} while (0)
#define NL() \
do { \
fputs ("\n", stdout); \
COLOR (NORMAL); \
} while (0)
void kissat_build (const char *prefix) {
TERMINAL (stdout, 1);
if (!prefix)
connected_to_terminal = false;
PREFIX (MAGENTA);
if (ID)
printf ("Version %s %s", VERSION, ID);
else
printf ("Version %s", VERSION);
NL ();
PREFIX (MAGENTA);
printf ("%s", COMPILER);
NL ();
PREFIX (MAGENTA);
printf ("%s", BUILD);
NL ();
}
void kissat_banner (const char *prefix, const char *name) {
TERMINAL (stdout, 1);
if (!prefix)
connected_to_terminal = false;
PREFIX (BOLD MAGENTA);
printf ("%s", name);
NL ();
PREFIX (BOLD MAGENTA);
NL ();
for (const char **p = kissat_copyright (), *line; (line = *p); p++) {
PREFIX (BOLD MAGENTA);
fputs (line, stdout);
NL ();
}
if (prefix) {
PREFIX ("");
NL ();
}
kissat_build (prefix);
}

120
src/sat/kissat/bump.c Normal file
View File

@ -0,0 +1,120 @@
#include "bump.h"
#include "analyze.h"
#include "inlineheap.h"
#include "inlinequeue.h"
#include "inlinevector.h"
#include "internal.h"
#include "logging.h"
#include "print.h"
#include "rank.h"
#include "sort.h"
#define RANK(A) ((A).rank)
#define SMALLER(A, B) (RANK (A) < RANK (B))
#define RADIX_SORT_BUMP_LIMIT 32
static void sort_bump (kissat *solver) {
const size_t size = SIZE_STACK (solver->analyzed);
if (size < RADIX_SORT_BUMP_LIMIT) {
LOG ("quick sorting %zu analyzed variables", size);
SORT_STACK (datarank, solver->ranks, SMALLER);
} else {
LOG ("radix sorting %zu analyzed variables", size);
RADIX_STACK (datarank, unsigned, solver->ranks, RANK);
}
}
void kissat_rescale_scores (kissat *solver) {
INC (rescaled);
heap *scores = &solver->scores;
const double max_score = kissat_max_score_on_heap (scores);
kissat_phase (solver, "rescale", GET (rescaled),
"maximum score %g increment %g", max_score, solver->scinc);
const double rescale = MAX (max_score, solver->scinc);
assert (rescale > 0);
const double factor = 1.0 / rescale;
kissat_rescale_heap (solver, scores, factor);
solver->scinc *= factor;
kissat_phase (solver, "rescale", GET (rescaled), "rescaled by factor %g",
factor);
}
void kissat_bump_score_increment (kissat *solver) {
const double old_scinc = solver->scinc;
const double decay = GET_OPTION (decay) * 1e-3;
assert (0 <= decay), assert (decay <= 0.5);
const double factor = 1.0 / (1.0 - decay);
const double new_scinc = old_scinc * factor;
LOG ("new score increment %g = %g * %g", new_scinc, factor, old_scinc);
solver->scinc = new_scinc;
if (new_scinc > MAX_SCORE)
kissat_rescale_scores (solver);
}
static inline void bump_analyzed_variable_score (kissat *solver,
unsigned idx) {
heap *scores = &solver->scores;
const double old_score = kissat_get_heap_score (scores, idx);
const double inc = solver->scinc;
const double new_score = old_score + inc;
LOG ("new score[%u] = %g = %g + %g", idx, new_score, old_score, inc);
kissat_update_heap (solver, scores, idx, new_score);
if (new_score > MAX_SCORE)
kissat_rescale_scores (solver);
}
void kissat_bump_variable (kissat *solver, unsigned idx) {
bump_analyzed_variable_score (solver, idx);
}
static void bump_analyzed_variable_scores (kissat *solver) {
flags *flags = solver->flags;
for (all_stack (unsigned, idx, solver->analyzed))
if (flags[idx].active)
bump_analyzed_variable_score (solver, idx);
kissat_bump_score_increment (solver);
}
static void move_analyzed_variables_to_front_of_queue (kissat *solver) {
assert (EMPTY_STACK (solver->ranks));
const links *const links = solver->links;
for (all_stack (unsigned, idx, solver->analyzed)) {
// clang-format off
const datarank rank = { .data = idx, .rank = links[idx].stamp };
// clang-format on
PUSH_STACK (solver->ranks, rank);
}
sort_bump (solver);
flags *flags = solver->flags;
unsigned idx;
for (all_stack (datarank, rank, solver->ranks))
if (flags[idx = rank.data].active)
kissat_move_to_front (solver, idx);
CLEAR_STACK (solver->ranks);
}
void kissat_bump_analyzed (kissat *solver) {
START (bump);
const size_t bumped = SIZE_STACK (solver->analyzed);
if (!solver->stable)
move_analyzed_variables_to_front_of_queue (solver);
else
bump_analyzed_variable_scores (solver);
ADD (literals_bumped, bumped);
STOP (bump);
}
void kissat_update_scores (kissat *solver) {
assert (solver->stable);
heap *scores = SCORES;
for (all_variables (idx))
if (ACTIVE (idx) && !kissat_heap_contains (scores, idx))
kissat_push_heap (solver, scores, idx);
}

16
src/sat/kissat/bump.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef _bump_h_INCLUDED
#define _bump_h_INCLUDED
#include <stdbool.h>
struct kissat;
void kissat_bump_analyzed (struct kissat *);
void kissat_update_scores (struct kissat *);
void kissat_rescale_scores (struct kissat *);
void kissat_bump_variable (struct kissat *, unsigned idx);
void kissat_bump_score_increment (struct kissat *);
#define MAX_SCORE 1e150
#endif

1033
src/sat/kissat/check.c Normal file

File diff suppressed because it is too large Load Diff

175
src/sat/kissat/check.h Normal file
View File

@ -0,0 +1,175 @@
#ifndef _check_h_INCLUDED
#define _check_h_INCLUDED
#ifndef NDEBUG
#include <stdbool.h>
#include <stdlib.h>
struct kissat;
void kissat_check_satisfying_assignment (struct kissat *);
typedef struct checker checker;
struct clause;
void kissat_init_checker (struct kissat *);
void kissat_release_checker (struct kissat *);
#ifndef QUIET
void kissat_print_checker_statistics (struct kissat *, bool verbose);
#endif
void kissat_add_unchecked_external (struct kissat *, size_t, const int *);
void kissat_check_and_add_binary (struct kissat *, unsigned, unsigned);
void kissat_check_and_add_clause (struct kissat *, struct clause *c);
void kissat_check_and_add_empty (struct kissat *);
void kissat_check_and_add_internal (struct kissat *, size_t,
const unsigned *);
void kissat_check_and_add_unit (struct kissat *, unsigned);
void kissat_check_shrink_clause (struct kissat *, struct clause *,
unsigned remove, unsigned keep);
void kissat_remove_checker_binary (struct kissat *, unsigned, unsigned);
void kissat_remove_checker_clause (struct kissat *, struct clause *c);
void kissat_remove_checker_external (struct kissat *, size_t, const int *);
void kissat_remove_checker_internal (struct kissat *, size_t,
const unsigned *);
#define ADD_UNCHECKED_EXTERNAL(SIZE, LITS) \
do { \
if (GET_OPTION (check) > 1) \
kissat_add_unchecked_external (solver, (SIZE), (LITS)); \
} while (0)
#define CHECK_AND_ADD_BINARY(A, B) \
do { \
if (GET_OPTION (check) > 1) \
kissat_check_and_add_binary (solver, (A), (B)); \
} while (0)
#define CHECK_AND_ADD_TERNARY(A, B, C) \
do { \
if (GET_OPTION (check) > 1) { \
unsigned CLAUSE[3] = {(A), (B), (C)}; \
kissat_check_and_add_internal (solver, 3, CLAUSE); \
} \
} while (0)
#define CHECK_AND_ADD_CLAUSE(CLAUSE) \
do { \
if (GET_OPTION (check) > 1) \
kissat_check_and_add_clause (solver, (CLAUSE)); \
} while (0)
#define CHECK_AND_ADD_EMPTY() \
do { \
if (GET_OPTION (check) > 1) \
kissat_check_and_add_empty (solver); \
} while (0)
#define CHECK_AND_ADD_LITS(SIZE, LITS) \
do { \
if (GET_OPTION (check) > 1) \
kissat_check_and_add_internal (solver, (SIZE), (LITS)); \
} while (0)
#define CHECK_AND_ADD_STACK(S) \
CHECK_AND_ADD_LITS (SIZE_STACK (S), BEGIN_STACK (S))
#define CHECK_AND_ADD_UNIT(A) \
do { \
if (GET_OPTION (check) > 1) \
kissat_check_and_add_unit (solver, (A)); \
} while (0)
#define CHECK_SHRINK_CLAUSE(C, REMOVE, KEEP) \
do { \
if (GET_OPTION (check) > 1) \
kissat_check_shrink_clause (solver, (C), (REMOVE), (KEEP)); \
} while (0)
#define REMOVE_CHECKER_BINARY(A, B) \
do { \
if (GET_OPTION (check) > 1) \
kissat_remove_checker_binary (solver, (A), (B)); \
} while (0)
#define REMOVE_CHECKER_TERNARY(A, B, C) \
do { \
if (GET_OPTION (check) > 1) { \
unsigned CLAUSE[3] = {(A), (B), (C)}; \
kissat_remove_checker_internal (solver, 3, CLAUSE); \
} \
} while (0)
#define REMOVE_CHECKER_CLAUSE(CLAUSE) \
do { \
if (GET_OPTION (check) > 1) \
kissat_remove_checker_clause (solver, (CLAUSE)); \
} while (0)
#define REMOVE_CHECKER_LITS(SIZE, LITS) \
do { \
if (GET_OPTION (check) > 1) \
kissat_remove_checker_internal (solver, (SIZE), (LITS)); \
} while (0)
#define REMOVE_CHECKER_STACK(S) \
do { \
if (GET_OPTION (check) > 1) \
kissat_remove_checker_internal (solver, SIZE_STACK (S), \
BEGIN_STACK (S)); \
} while (0)
#else
#define ADD_UNCHECKED_EXTERNAL(...) \
do { \
} while (0)
#define CHECK_AND_ADD_BINARY(...) \
do { \
} while (0)
#define CHECK_AND_ADD_TERNARY(...) \
do { \
} while (0)
#define CHECK_AND_ADD_CLAUSE(...) \
do { \
} while (0)
#define CHECK_AND_ADD_EMPTY(...) \
do { \
} while (0)
#define CHECK_AND_ADD_LITS(...) \
do { \
} while (0)
#define CHECK_AND_ADD_STACK(...) \
do { \
} while (0)
#define CHECK_AND_ADD_UNIT(...) \
do { \
} while (0)
#define CHECK_SHRINK_CLAUSE(...) \
do { \
} while (0)
#define REMOVE_CHECKER_BINARY(...) \
do { \
} while (0)
#define REMOVE_CHECKER_TERNARY(...) \
do { \
} while (0)
#define REMOVE_CHECKER_CLAUSE(...) \
do { \
} while (0)
#define REMOVE_CHECKER_LITS(...) \
do { \
} while (0)
#define REMOVE_CHECKER_STACK(...) \
do { \
} while (0)
#endif
#endif

28
src/sat/kissat/classify.c Normal file
View File

@ -0,0 +1,28 @@
#include "classify.h"
#include "internal.h"
#include "print.h"
void kissat_classify (struct kissat *solver) {
statistics *s = &solver->statistics;
uint64_t clauses = s->clauses_binary + s->clauses_irredundant;
unsigned small_clauses_limit = GET_OPTION (smallclauses);
if (clauses <= small_clauses_limit) {
solver->classification.small = true;
solver->classification.bigbig = false;
} else {
solver->classification.small = false;
unsigned bigbigfraction = GET_OPTION (bigbigfraction);
double percent = bigbigfraction / 1000.0;
double actual = kissat_percent (s->clauses_binary, clauses);
if (actual >= percent)
solver->classification.bigbig = true;
else
solver->classification.bigbig = false;
}
kissat_very_verbose (
solver, "formula classified as having a %s total number of clauses",
solver->classification.small ? "small" : "large");
kissat_very_verbose (
solver, "formula classified to have a %s binary clauses fraction",
solver->classification.bigbig ? "large" : "small");
}

17
src/sat/kissat/classify.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef _classify_h_INCLUDED
#define _classify_h_INCLUDED
#include <stdbool.h>
struct kissat;
struct classification {
bool small;
bool bigbig;
};
typedef struct classification classification;
void kissat_classify (struct kissat *);
#endif

187
src/sat/kissat/clause.c Normal file
View File

@ -0,0 +1,187 @@
#include "allocate.h"
#include "collect.h"
#include "inline.h"
#include <string.h>
static void inc_clause (kissat *solver, bool original, bool redundant,
bool binary) {
if (binary)
INC (clauses_binary);
else if (redundant)
INC (clauses_redundant);
else
INC (clauses_irredundant);
INC (clauses_added);
if (original)
INC (clauses_original);
}
static void dec_clause (kissat *solver, bool redundant, bool binary) {
if (binary)
DEC (clauses_binary);
else if (redundant)
DEC (clauses_redundant);
else
DEC (clauses_irredundant);
}
static void init_clause (clause *res, bool redundant, unsigned glue,
unsigned size) {
assert (size <= UINT_MAX);
assert (redundant || !glue);
glue = MIN (MAX_GLUE, glue);
res->glue = glue;
res->garbage = false;
res->quotient = false;
res->reason = false;
res->redundant = redundant;
res->shrunken = false;
res->subsume = false;
res->swept = false;
res->vivify = false;
res->used = 0;
res->searched = 2;
res->size = size;
}
void kissat_connect_referenced (kissat *solver, reference ref) {
watches *all_watches = solver->watches;
clause *c = kissat_dereference_clause (solver, ref);
kissat_inlined_connect_clause (solver, all_watches, c, ref);
}
void kissat_connect_clause (kissat *solver, clause *c) {
watches *all_watches = solver->watches;
const reference ref = kissat_reference_clause (solver, c);
kissat_inlined_connect_clause (solver, all_watches, c, ref);
}
static reference new_binary_clause (kissat *solver, bool original,
bool watch, unsigned first,
unsigned second) {
assert (first != second);
assert (first != NOT (second));
if (watch)
kissat_watch_binary (solver, first, second);
kissat_mark_added_literal (solver, first);
kissat_mark_added_literal (solver, second);
inc_clause (solver, original, false, true);
if (!original) {
CHECK_AND_ADD_BINARY (first, second);
ADD_BINARY_TO_PROOF (first, second);
}
return INVALID_REF;
}
static reference new_large_clause (kissat *solver, bool original,
bool redundant, unsigned glue,
unsigned size, unsigned *lits) {
assert (size > 2);
reference res = kissat_allocate_clause (solver, size);
clause *c = kissat_unchecked_dereference_clause (solver, res);
init_clause (c, redundant, glue, size);
memcpy (c->lits, lits, size * sizeof (unsigned));
LOGREF (res, "new");
if (solver->watching)
kissat_watch_reference (solver, lits[0], lits[1], res);
else
kissat_connect_clause (solver, c);
if (redundant) {
if (solver->first_reducible == INVALID_REF)
solver->first_reducible = res;
} else {
kissat_mark_added_literals (solver, size, lits);
solver->last_irredundant = res;
}
inc_clause (solver, original, redundant, false);
if (!original) {
CHECK_AND_ADD_CLAUSE (c);
ADD_CLAUSE_TO_PROOF (c);
}
return res;
}
static reference new_clause (kissat *solver, bool original, bool redundant,
unsigned glue, unsigned size, unsigned *lits) {
reference res;
if (size == 2)
res = new_binary_clause (solver, original, true, lits[0], lits[1]);
else
res = new_large_clause (solver, original, redundant, glue, size, lits);
kissat_defrag_watches_if_needed (solver);
return res;
}
void kissat_new_binary_clause (kissat *solver, unsigned first,
unsigned second) {
(void) new_binary_clause (solver, false, true, first, second);
}
void kissat_new_unwatched_binary_clause (kissat *solver, unsigned first,
unsigned second) {
(void) new_binary_clause (solver, false, false, first, second);
}
reference kissat_new_original_clause (kissat *solver) {
const unsigned size = SIZE_STACK (solver->clause);
unsigned *lits = BEGIN_STACK (solver->clause);
kissat_sort_literals (solver, size, lits);
reference res = new_clause (solver, true, false, 0, size, lits);
return res;
}
reference kissat_new_irredundant_clause (kissat *solver) {
const unsigned size = SIZE_STACK (solver->clause);
unsigned *lits = BEGIN_STACK (solver->clause);
return new_clause (solver, false, false, 0, size, lits);
}
reference kissat_new_redundant_clause (kissat *solver, unsigned glue) {
const unsigned size = SIZE_STACK (solver->clause);
unsigned *lits = BEGIN_STACK (solver->clause);
return new_clause (solver, false, true, glue, size, lits);
}
static void mark_clause_as_garbage (kissat *solver, clause *c) {
assert (!c->garbage);
LOGCLS (c, "garbage");
if (!c->redundant)
kissat_mark_removed_literals (solver, c->size, c->lits);
REMOVE_CHECKER_CLAUSE (c);
DELETE_CLAUSE_FROM_PROOF (c);
assert (c->size > 2);
dec_clause (solver, c->redundant, false);
c->garbage = true;
}
void kissat_mark_clause_as_garbage (kissat *solver, clause *c) {
assert (!c->garbage);
mark_clause_as_garbage (solver, c);
size_t bytes = kissat_actual_bytes_of_clause (c);
ADD (arena_garbage, bytes);
}
clause *kissat_delete_clause (kissat *solver, clause *c) {
LOGCLS (c, "delete");
assert (c->size > 2);
assert (c->garbage);
size_t bytes = kissat_actual_bytes_of_clause (c);
SUB (arena_garbage, bytes);
INC (clauses_deleted);
return (clause *) ((char *) c + bytes);
}
void kissat_delete_binary (kissat *solver, unsigned a, unsigned b) {
LOGBINARY (a, b, "delete");
kissat_mark_removed_literal (solver, a);
kissat_mark_removed_literal (solver, b);
REMOVE_CHECKER_BINARY (a, b);
DELETE_BINARY_FROM_PROOF (a, b);
dec_clause (solver, false, true);
INC (clauses_deleted);
}

90
src/sat/kissat/clause.h Normal file
View File

@ -0,0 +1,90 @@
#ifndef _clause_h_INCLUDED
#define _clause_h_INCLUDED
#include "arena.h"
#include "literal.h"
#include "reference.h"
#include "utilities.h"
#include <stdbool.h>
typedef struct clause clause;
#define LD_MAX_GLUE 19
#define LD_MAX_USED 5
#define MAX_GLUE ((1u << LD_MAX_GLUE) - 1)
#define MAX_USED ((1u << LD_MAX_USED) - 1)
struct clause {
unsigned glue : LD_MAX_GLUE;
bool garbage : 1;
bool quotient : 1;
bool reason : 1;
bool redundant : 1;
bool shrunken : 1;
bool subsume : 1;
bool swept : 1;
bool vivify : 1;
unsigned used : LD_MAX_USED;
unsigned searched;
unsigned size;
unsigned lits[3];
};
#define SIZE_OF_CLAUSE_HEADER ((size_t) & ((clause *) 0)->searched)
#define BEGIN_LITS(C) ((C)->lits)
#define END_LITS(C) (BEGIN_LITS (C) + (C)->size)
#define all_literals_in_clause(LIT, C) \
unsigned LIT, \
*LIT##_PTR = BEGIN_LITS (C), *const LIT##_END = END_LITS (C); \
LIT##_PTR != LIT##_END && ((LIT = *LIT##_PTR), true); \
++LIT##_PTR
static inline size_t kissat_bytes_of_clause (unsigned size) {
const size_t res = sizeof (clause) + (size - 3) * sizeof (unsigned);
return kissat_align_ward (res);
}
static inline size_t kissat_actual_bytes_of_clause (clause *c) {
unsigned const *p = END_LITS (c);
if (c->shrunken)
while (*p++ != INVALID_LIT)
;
return kissat_align_ward ((char *) p - (char *) c);
}
static inline clause *kissat_next_clause (clause *c) {
word bytes = kissat_actual_bytes_of_clause (c);
return (clause *) ((char *) c + bytes);
}
struct kissat;
void kissat_new_binary_clause (struct kissat *, unsigned, unsigned);
void kissat_new_unwatched_binary_clause (struct kissat *, unsigned,
unsigned);
reference kissat_new_original_clause (struct kissat *);
reference kissat_new_irredundant_clause (struct kissat *);
reference kissat_new_redundant_clause (struct kissat *, unsigned glue);
#ifndef INLINE_SORT
void kissat_sort_literals (struct kissat *, unsigned size, unsigned *lits);
#endif
void kissat_connect_clause (struct kissat *, clause *);
void kissat_connect_referenced (struct kissat *solver, reference);
clause *kissat_delete_clause (struct kissat *, clause *);
void kissat_delete_binary (struct kissat *, unsigned, unsigned);
void kissat_mark_clause_as_garbage (struct kissat *, clause *);
#endif

738
src/sat/kissat/collect.c Normal file
View File

@ -0,0 +1,738 @@
#define INLINE_SORT
#include "collect.h"
#include "allocate.h"
#include "colors.h"
#include "compact.h"
#include "inline.h"
#include "print.h"
#include "report.h"
#include "sort.c"
#include "trail.h"
#include <inttypes.h>
#include <string.h>
static void flush_watched_clauses_by_literal (kissat *solver, unsigned lit,
bool compact,
reference start) {
assert (start != INVALID_REF);
const value *const values = solver->values;
const assigned *const all_assigned = solver->assigned;
const value lit_value = values[lit];
const assigned *const lit_assigned = all_assigned + IDX (lit);
const value lit_fixed =
(lit_value && !lit_assigned->level) ? lit_value : 0;
const unsigned mlit = kissat_map_literal (solver, lit, true);
watches *lit_watches = &WATCHES (lit);
watch *begin = BEGIN_WATCHES (*lit_watches), *q = begin;
const watch *const end_of_watches = END_WATCHES (*lit_watches), *p = q;
while (p != end_of_watches) {
watch head = *p++;
if (head.type.binary) {
const unsigned other = head.binary.lit;
const unsigned other_idx = IDX (other);
const value other_value = values[other];
const value other_fixed =
(other_value && !all_assigned[other_idx].level) ? other_value : 0;
const unsigned mother = kissat_map_literal (solver, other, compact);
if (lit_fixed > 0 || other_fixed > 0 || mother == INVALID_LIT) {
if (lit < other)
kissat_delete_binary (solver, lit, other);
} else {
assert (!lit_fixed);
assert (!other_fixed);
{
head.binary.lit = mother;
*q++ = head;
#ifdef LOGGING
if (lit < other) {
LOGBINARY (lit, other, "SRC");
LOGBINARY (mlit, mother, "DST");
}
#endif
}
}
} else {
assert (solver->watching);
const watch tail = *p++;
if (!lit_fixed) {
const reference ref = tail.large.ref;
if (ref < start) {
*q++ = head;
*q++ = tail;
}
}
}
}
assert (!lit_fixed || q == begin);
SET_END_OF_WATCHES (*lit_watches, q);
#ifdef LOGGING
const size_t size_lit_watches = SIZE_WATCHES (*lit_watches);
LOG ("keeping %zu watches[%u]", size_lit_watches, lit);
#endif
if (!compact)
return;
if (mlit == INVALID_LIT)
return;
watches *mlit_watches = &WATCHES (mlit);
#if defined(LOGGING) || !defined(NDEBUG)
const size_t size_mlit_watches = SIZE_WATCHES (*mlit_watches);
#endif
if (lit_fixed)
assert (!size_mlit_watches);
else if (mlit < lit) {
assert (mlit != INVALID_LIT);
assert (mlit < lit);
*mlit_watches = *lit_watches;
LOG ("copied watches[%u] = watches[%u] (size %zu)", mlit, lit,
size_mlit_watches);
memset (lit_watches, 0, sizeof *lit_watches);
} else
assert (mlit == lit);
}
static void flush_all_watched_clauses (kissat *solver, bool compact,
reference start) {
assert (solver->watching);
LOG ("starting to flush watches at clause[%" REFERENCE_FORMAT "]", start);
for (all_variables (idx)) {
const unsigned lit = LIT (idx);
flush_watched_clauses_by_literal (solver, lit, compact, start);
const unsigned not_lit = NOT (lit);
flush_watched_clauses_by_literal (solver, not_lit, compact, start);
}
}
static void update_large_reason (kissat *solver, assigned *assigned,
unsigned forced, clause *dst) {
assert (dst->reason);
assert (forced != INVALID_LIT);
reference dst_ref = kissat_reference_clause (solver, dst);
const unsigned forced_idx = IDX (forced);
struct assigned *a = assigned + forced_idx;
assert (!a->binary);
if (a->reason != dst_ref) {
LOG ("reason reference %u of %s updated to %u", a->reason,
LOGLIT (forced), dst_ref);
a->reason = dst_ref;
}
dst->reason = false;
}
static unsigned get_forced (const value *values, clause *dst) {
assert (dst->reason);
unsigned forced = INVALID_LIT;
for (all_literals_in_clause (lit, dst)) {
const value value = values[lit];
if (value <= 0)
continue;
forced = lit;
break;
}
assert (forced != INVALID_LIT);
return forced;
}
static void get_forced_and_update_large_reason (kissat *solver,
assigned *assigned,
const value *const values,
clause *dst) {
const unsigned forced = get_forced (values, dst);
update_large_reason (solver, assigned, forced, dst);
}
static void update_first_reducible (kissat *solver, const clause *end,
clause *first_reducible) {
if (first_reducible >= end) {
LOG ("first reducible after end of arena");
solver->first_reducible = INVALID_REF;
} else if (first_reducible) {
LOGCLS (first_reducible, "updating first reducible clause to");
solver->first_reducible =
kissat_reference_clause (solver, first_reducible);
} else {
LOG ("first reducible clause becomes invalid");
solver->first_reducible = INVALID_REF;
}
}
static void update_last_irredundant (kissat *solver, const clause *end,
clause *last_irredundant) {
if (!last_irredundant) {
LOG ("no more large irredundant clauses left");
solver->last_irredundant = INVALID_REF;
} else if (end <= last_irredundant) {
LOG ("last irredundant clause after end of arena");
solver->last_irredundant = INVALID_REF;
} else {
LOGCLS (last_irredundant, "updating last irredundant clause to");
reference ref = kissat_reference_clause (solver, last_irredundant);
solver->last_irredundant = ref;
}
}
void kissat_update_first_reducible (kissat *solver, clause *reducible) {
assert (reducible);
assert (!reducible->garbage);
assert (reducible->redundant);
if (solver->first_reducible != INVALID_REF) {
reference ref = kissat_reference_clause (solver, reducible);
if (ref >= solver->first_reducible) {
LOG ("no need to update larger first reducible");
return;
}
}
clause *end = (clause *) END_STACK (solver->arena);
update_first_reducible (solver, end, reducible);
}
void kissat_update_last_irredundant (kissat *solver, clause *irredundant) {
assert (irredundant);
assert (!irredundant->garbage);
assert (!irredundant->redundant);
if (solver->last_irredundant != INVALID_REF) {
reference ref = kissat_reference_clause (solver, irredundant);
if (ref <= solver->last_irredundant) {
LOG ("no need to update smaller last irredundant");
return;
}
}
clause *end = (clause *) END_STACK (solver->arena);
update_last_irredundant (solver, end, irredundant);
}
static void move_redundant_clauses_to_the_end (kissat *solver,
reference ref) {
INC (moved);
assert (ref != INVALID_REF);
#ifndef NDEBUG
const size_t size = SIZE_STACK (solver->arena);
assert ((size_t) ref <= size);
#endif
clause *begin = (clause *) (BEGIN_STACK (solver->arena) + ref);
clause *end = (clause *) END_STACK (solver->arena);
size_t bytes_redundant = (char *) end - (char *) begin;
kissat_phase (solver, "move", GET (moved),
"moving redundant clauses of %s to the end",
FORMAT_BYTES (bytes_redundant));
kissat_mark_reason_clauses (solver, ref);
clause *redundant = (clause *) kissat_malloc (solver, bytes_redundant);
clause *p = begin, *q = begin, *r = redundant;
const value *const values = solver->values;
assigned *assigned = solver->assigned;
clause *last_irredundant = kissat_last_irredundant_clause (solver);
while (p != end) {
assert (!p->shrunken);
size_t bytes = kissat_bytes_of_clause (p->size);
if (p->redundant) {
memcpy (r, p, bytes);
r = (clause *) (bytes + (char *) r);
} else {
LOGCLS (p, "old DST");
memmove (q, p, bytes);
LOGCLS (q, "new DST");
last_irredundant = q;
if (q->reason)
get_forced_and_update_large_reason (solver, assigned, values, q);
q = (clause *) (bytes + (char *) q);
}
p = (clause *) (bytes + (char *) p);
}
r = redundant;
clause *first_reducible = 0;
while (q != end) {
size_t bytes = kissat_bytes_of_clause (r->size);
memcpy (q, r, bytes);
LOGCLS (q, "new DST");
if (q->reason)
get_forced_and_update_large_reason (solver, assigned, values, q);
assert (q->redundant);
if (!first_reducible)
first_reducible = q;
r = (clause *) (bytes + (char *) r);
q = (clause *) (bytes + (char *) q);
}
assert ((char *) r <= (char *) redundant + bytes_redundant);
kissat_free (solver, redundant, bytes_redundant);
assert (!first_reducible || first_reducible < q);
update_first_reducible (solver, q, first_reducible);
update_last_irredundant (solver, q, last_irredundant);
kissat_reset_last_learned (solver);
}
static reference sparse_sweep_garbage_clauses (kissat *solver, bool compact,
reference start) {
assert (solver->watching);
LOG ("sparse garbage collection starting at clause[%" REFERENCE_FORMAT
"]",
start);
#ifdef CHECKING_OR_PROVING
const bool checking_or_proving = kissat_checking_or_proving (solver);
#endif
assert (EMPTY_STACK (solver->added));
assert (EMPTY_STACK (solver->removed));
const value *const values = solver->values;
assigned *assigned = solver->assigned;
#ifndef QUIET
size_t flushed_garbage_clauses = 0;
size_t flushed_satisfied_clauses = 0;
#endif
size_t flushed = 0;
clause *begin = (clause *) BEGIN_STACK (solver->arena);
const clause *const end = (clause *) END_STACK (solver->arena);
clause *first, *src, *dst;
if (start)
first = kissat_dereference_clause (solver, start);
else
first = begin;
src = dst = first;
clause *first_redundant = 0;
clause *first_reducible = 0;
clause *last_irredundant;
if (start)
last_irredundant = kissat_last_irredundant_clause (solver);
else
last_irredundant = 0;
#ifdef LOGGING
size_t redundant_bytes = 0;
#endif
for (clause *next; src != end; src = next) {
if (src->garbage) {
next = kissat_delete_clause (solver, src);
#ifndef QUIET
flushed_garbage_clauses++;
#endif
if (last_irredundant == src) {
if (first == begin)
last_irredundant = 0;
else
last_irredundant = first;
}
continue;
}
assert (src->size > 1);
LOGCLS (src, "SRC");
next = kissat_next_clause (src);
#if !defined(NDEBUG) || defined(CHECKING_OR_PROVING)
const unsigned old_size = src->size;
#endif
assert (SIZE_OF_CLAUSE_HEADER == sizeof (unsigned));
*(unsigned *) dst = *(unsigned *) src;
unsigned *q = dst->lits;
unsigned mfirst = INVALID_LIT;
unsigned msecond = INVALID_LIT;
unsigned forced = INVALID_LIT;
unsigned other = INVALID_LIT;
unsigned non_false = 0;
bool satisfied = false;
for (all_literals_in_clause (lit, src)) {
#ifdef CHECKING_OR_PROVING
if (checking_or_proving)
PUSH_STACK (solver->removed, lit);
#endif
if (satisfied)
continue;
const value tmp = values[lit];
const unsigned idx = IDX (lit);
const unsigned level = tmp ? assigned[idx].level : INVALID_LEVEL;
if (tmp < 0 && !level)
flushed++;
else if (tmp > 0 && !level) {
assert (!satisfied);
assert (!dst->reason);
LOG ("SRC satisfied by %s", LOGLIT (lit));
satisfied = true;
} else {
const unsigned mlit = kissat_map_literal (solver, lit, compact);
if (tmp > 0) {
assert (level);
forced = non_false++ ? INVALID_LIT : lit;
} else if (tmp < 0)
other = lit;
if (mfirst == INVALID_LIT)
mfirst = mlit;
else if (msecond == INVALID_LIT)
msecond = mlit;
*q++ = mlit;
#ifdef CHECKING_OR_PROVING
if (checking_or_proving)
PUSH_STACK (solver->added, lit);
#endif
}
}
if (satisfied) {
if (dst->redundant)
DEC (clauses_redundant);
else
DEC (clauses_irredundant);
#ifndef QUIET
flushed_satisfied_clauses++;
#endif
#ifdef CHECKING_OR_PROVING
if (checking_or_proving) {
REMOVE_CHECKER_STACK (solver->removed);
DELETE_STACK_FROM_PROOF (solver->removed);
CLEAR_STACK (solver->added);
CLEAR_STACK (solver->removed);
}
#endif
if (last_irredundant == src) {
if (first == begin)
last_irredundant = 0;
else
last_irredundant = first;
}
continue;
}
const unsigned new_size = q - dst->lits;
assert (new_size <= old_size);
assert (1 < new_size);
if (new_size == 2) {
assert (mfirst != INVALID_LIT);
assert (msecond != INVALID_LIT);
statistics *statistics = &solver->statistics;
assert (statistics->clauses_binary < UINT64_MAX);
statistics->clauses_binary++;
bool redundant = dst->redundant;
if (redundant) {
assert (statistics->clauses_redundant > 0);
statistics->clauses_redundant--;
redundant = false;
} else {
assert (statistics->clauses_irredundant > 0);
statistics->clauses_irredundant--;
}
LOGBINARY (mfirst, msecond, "DST");
kissat_watch_binary (solver, mfirst, msecond);
if (dst->reason) {
assert (non_false == 1);
assert (other != INVALID_LIT);
assert (forced != INVALID_LIT);
const unsigned forced_idx = IDX (forced);
struct assigned *a = assigned + forced_idx;
assert (!a->binary);
LOGBINARY (mfirst, msecond,
"reason clause[%u] of %s updated to binary reason",
a->reason, LOGLIT (forced));
a->binary = true;
a->reason = other;
}
if (!redundant && last_irredundant == src) {
if (first == begin)
last_irredundant = 0;
else
last_irredundant = first;
}
} else {
assert (2 < new_size);
dst->size = new_size;
dst->shrunken = false;
dst->searched = 2;
LOGCLS (dst, "DST");
if (dst->reason)
update_large_reason (solver, assigned, forced, dst);
clause *next_dst = kissat_next_clause (dst);
if (dst->redundant) {
if (!first_reducible)
first_reducible = dst;
#ifdef LOGGING
redundant_bytes += (char *) next_dst - (char *) dst;
#endif
if (!first_redundant)
first_redundant = dst;
} else
last_irredundant = dst;
dst = next_dst;
}
#ifdef CHECKING_OR_PROVING
if (!checking_or_proving)
continue;
if (new_size != old_size) {
assert (1 < new_size);
assert (new_size < old_size);
CHECK_AND_ADD_STACK (solver->added);
ADD_STACK_TO_PROOF (solver->added);
REMOVE_CHECKER_STACK (solver->removed);
DELETE_STACK_FROM_PROOF (solver->removed);
}
CLEAR_STACK (solver->added);
CLEAR_STACK (solver->removed);
#endif
}
update_first_reducible (solver, dst, first_reducible);
update_last_irredundant (solver, dst, last_irredundant);
kissat_reset_last_learned (solver);
if (first_redundant)
LOGCLS (first_redundant, "determined first redundant clause as");
#if !defined(QUIET) || defined(METRICS)
size_t bytes = (char *) END_STACK (solver->arena) - (char *) dst;
#endif
#ifndef QUIET
if (flushed)
kissat_phase (solver, "collect", GET (garbage_collections),
"flushed %zu falsified literals in large clauses",
flushed);
size_t flushed_clauses =
flushed_satisfied_clauses + flushed_garbage_clauses;
if (flushed_satisfied_clauses)
kissat_phase (
solver, "collect", GET (garbage_collections),
"flushed %zu satisfied large clauses %.0f%%",
flushed_satisfied_clauses,
kissat_percent (flushed_satisfied_clauses, flushed_clauses));
if (flushed_garbage_clauses)
kissat_phase (
solver, "collect", GET (garbage_collections),
"flushed %zu large garbage clauses %.0f%%", flushed_garbage_clauses,
kissat_percent (flushed_garbage_clauses, flushed_clauses));
kissat_phase (solver, "collect", GET (garbage_collections),
"collected %s in total", FORMAT_BYTES (bytes));
#endif
ADD (flushed, flushed);
#ifdef METRICS
ADD (allocated_collected, bytes);
#endif
reference res = INVALID_REF;
if (first_redundant && last_irredundant &&
first_redundant < last_irredundant) {
#ifdef LOGGING
size_t move_bytes = (char *) dst - (char *) first_redundant;
LOG ("redundant bytes %s (%.0f%%) out of %s moving bytes",
FORMAT_BYTES (redundant_bytes),
kissat_percent (redundant_bytes, move_bytes),
FORMAT_BYTES (move_bytes));
#endif
assert (first_redundant < dst);
res = kissat_reference_clause (solver, first_redundant);
assert (res != INVALID_REF);
}
SET_END_OF_STACK (solver->arena, (ward *) dst);
kissat_shrink_arena (solver);
#ifdef METRICS
if (solver->statistics.arena_garbage)
kissat_very_verbose (solver, "still %s garbage left in arena",
FORMAT_BYTES (solver->statistics.arena_garbage));
else
kissat_very_verbose (solver, "all garbage clauses in arena collected");
#endif
return res;
}
static void rewatch_clauses (kissat *solver, reference start) {
LOG ("rewatching clause[%" REFERENCE_FORMAT "] and following clauses",
start);
assert (solver->watching);
const value *const values = solver->values;
const assigned *const assigned = solver->assigned;
watches *watches = solver->watches;
ward *const arena = BEGIN_STACK (solver->arena);
clause *end = (clause *) END_STACK (solver->arena);
clause *c = (clause *) (BEGIN_STACK (solver->arena) + start);
assert (c <= end);
for (clause *next; c != end; c = next) {
next = kissat_next_clause (c);
unsigned *lits = c->lits;
kissat_sort_literals (solver, values, assigned, c->size, lits);
c->searched = 2;
const reference ref = (ward *) c - arena;
const unsigned l0 = lits[0];
const unsigned l1 = lits[1];
kissat_push_blocking_watch (solver, watches + l0, l1, ref);
kissat_push_blocking_watch (solver, watches + l1, l0, ref);
}
}
void kissat_sparse_collect (kissat *solver, bool compact, reference start) {
assert (solver->watching);
START (collect);
INC (garbage_collections);
INC (sparse_gcs);
REPORT (1, 'G');
unsigned vars, mfixed;
if (compact)
vars = kissat_compact_literals (solver, &mfixed);
else {
vars = solver->vars;
mfixed = INVALID_LIT;
}
flush_all_watched_clauses (solver, compact, start);
reference move = sparse_sweep_garbage_clauses (solver, compact, start);
if (compact)
kissat_finalize_compacting (solver, vars, mfixed);
if (move != INVALID_REF)
move_redundant_clauses_to_the_end (solver, move);
rewatch_clauses (solver, start);
REPORT (1, 'C');
kissat_check_statistics (solver);
STOP (collect);
}
bool kissat_compacting (kissat *solver) {
if (!GET_OPTION (compact))
return false;
unsigned inactive = solver->vars - solver->active;
unsigned limit = GET_OPTION (compactlim) / 1e2 * solver->vars;
bool compact = (inactive > limit);
LOG ("%u inactive variables %.0f%% <= limit %u %.0f%%", inactive,
kissat_percent (inactive, solver->vars), limit,
kissat_percent (limit, solver->vars));
return compact;
}
void kissat_initial_sparse_collect (kissat *solver) {
assert (!solver->level);
assert (!solver->inconsistent);
assert (solver->watching);
assert (kissat_trail_flushed (solver));
if (solver->statistics.units) {
bool compact = GET_OPTION (compact);
kissat_sparse_collect (solver, compact, 0);
}
REPORT (0, '.');
}
static void dense_sweep_garbage_clauses (kissat *solver) {
assert (!solver->level);
assert (!solver->watching);
LOG ("dense garbage collection");
#ifndef QUIET
size_t flushed_garbage_clauses = 0;
#endif
clause *first_reducible = 0;
clause *last_irredundant = 0;
clause *begin = (clause *) BEGIN_STACK (solver->arena);
const clause *const end = (clause *) END_STACK (solver->arena);
clause *src = begin;
clause *dst = src;
for (clause *next; src != end; src = next) {
if (src->garbage) {
next = kissat_delete_clause (solver, src);
#ifndef QUIET
flushed_garbage_clauses++;
#endif
continue;
}
assert (src->size > 1);
LOGCLS (src, "SRC");
next = kissat_next_clause (src);
assert (SIZE_OF_CLAUSE_HEADER == sizeof (unsigned));
*(unsigned *) dst = *(unsigned *) src;
dst->searched = src->searched;
dst->size = src->size;
dst->shrunken = false;
memmove (dst->lits, src->lits, src->size * sizeof (unsigned));
LOGCLS (dst, "DST");
if (!dst->redundant)
last_irredundant = dst;
else if (!first_reducible)
first_reducible = dst;
dst = kissat_next_clause (dst);
}
update_first_reducible (solver, dst, first_reducible);
update_last_irredundant (solver, dst, last_irredundant);
kissat_reset_last_learned (solver);
#if !defined(QUIET) || defined(METRICS)
size_t bytes = (char *) END_STACK (solver->arena) - (char *) dst;
#endif
kissat_phase (solver, "collect", GET (garbage_collections),
"flushed %zu large garbage clauses",
flushed_garbage_clauses);
kissat_phase (solver, "collect", GET (garbage_collections),
"collected %s in total", FORMAT_BYTES (bytes));
#ifdef METRICS
ADD (allocated_collected, bytes);
#endif
SET_END_OF_STACK (solver->arena, (ward *) dst);
kissat_shrink_arena (solver);
#ifdef METRICS
if (solver->statistics.arena_garbage)
kissat_very_verbose (solver, "still %s garbage left in arena",
FORMAT_BYTES (solver->statistics.arena_garbage));
else
kissat_very_verbose (solver, "all garbage clauses in arena collected");
#endif
}
void kissat_dense_collect (kissat *solver) {
assert (!solver->watching);
assert (!solver->level);
START (collect);
INC (garbage_collections);
INC (dense_garbage_collections);
REPORT (1, 'G');
dense_sweep_garbage_clauses (solver);
REPORT (1, 'C');
STOP (collect);
}

33
src/sat/kissat/collect.h Normal file
View File

@ -0,0 +1,33 @@
#ifndef _collect_h_INCLUDED
#define _collect_h_INCLUDED
#include "internal.h"
bool kissat_compacting (kissat *);
void kissat_dense_collect (kissat *);
void kissat_sparse_collect (kissat *, bool compact, reference start);
void kissat_initial_sparse_collect (kissat *);
static inline void kissat_defrag_watches (kissat *solver) {
kissat_defrag_vectors (solver, LITS, solver->watches);
}
static inline void kissat_defrag_watches_if_needed (kissat *solver) {
const size_t size = SIZE_STACK (solver->vectors.stack);
const size_t size_limit = GET_OPTION (defragsize);
if (size <= size_limit)
return;
const size_t usable = solver->vectors.usable;
const size_t usable_limit = (size * GET_OPTION (defraglim)) / 100;
if (usable <= usable_limit)
return;
INC (vectors_defrags_needed);
kissat_defrag_watches (solver);
}
void kissat_update_last_irredundant (kissat *, clause *last_irredundant);
void kissat_update_first_reducible (kissat *, clause *first_reducible);
#endif

19
src/sat/kissat/colors.c Normal file
View File

@ -0,0 +1,19 @@
#include "colors.h"
#include <unistd.h>
int kissat_is_terminal[3] = {0, -1, -1};
int kissat_initialize_terminal (int fd) {
assert (fd == 1 || fd == 2);
assert (kissat_is_terminal[fd] < 0);
return kissat_is_terminal[fd] = isatty (fd);
}
void kissat_force_colors (void) {
kissat_is_terminal[1] = kissat_is_terminal[2] = 1;
}
void kissat_force_no_colors (void) {
kissat_is_terminal[1] = kissat_is_terminal[2] = 0;
}

68
src/sat/kissat/colors.h Normal file
View File

@ -0,0 +1,68 @@
#ifndef _colors_h_INCLUDED
#define _colors_h_INCLUDED
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include "keatures.h"
#define BLUE "\033[34m"
#define BOLD "\033[1m"
#define CYAN "\033[36m"
#define GREEN "\033[32m"
#define MAGENTA "\033[35m"
#define NORMAL "\033[0m"
#define RED "\033[31m"
#define WHITE "\037[34m"
#define YELLOW "\033[33m"
#define LIGHT_GRAY "\033[1;37m"
#define DARK_GRAY "\033[0;37m"
#ifdef KISSAT_HAS_FILENO
#define assert_if_has_fileno assert
#else
#define assert_if_has_fileno(...) \
do { \
} while (0)
#endif
#define TERMINAL(F, I) \
assert_if_has_fileno (fileno (F) == \
I); /* 'fileno' only in POSIX not C99 */ \
assert ((I == 1 && F == stdout) || (I == 2 && F == stderr)); \
bool connected_to_terminal = kissat_connected_to_terminal (I); \
FILE *terminal_file = F
#define COLOR(CODE) \
do { \
if (!connected_to_terminal) \
break; \
fputs (CODE, terminal_file); \
} while (0)
extern int kissat_is_terminal[3];
int kissat_initialize_terminal (int fd);
void kissat_force_colors (void);
void kissat_force_no_colors (void);
static inline bool kissat_connected_to_terminal (int fd) {
assert (fd == 1 || fd == 2);
int res = kissat_is_terminal[fd];
if (res < 0)
res = kissat_initialize_terminal (fd);
assert (res == 0 || res == 1);
return res;
}
static inline const char *kissat_bold_green_color_code (int fd) {
return kissat_connected_to_terminal (fd) ? BOLD GREEN : "";
}
static inline const char *kissat_normal_color_code (int fd) {
return kissat_connected_to_terminal (fd) ? NORMAL : "";
}
#endif

376
src/sat/kissat/compact.c Normal file
View File

@ -0,0 +1,376 @@
#include "compact.h"
#include "inline.h"
#include "inlineheap.h"
#include "print.h"
#include "resize.h"
#include <string.h>
static void reimport_literal (kissat *solver, unsigned eidx,
unsigned mlit) {
import *import = &PEEK_STACK (solver->import, eidx);
assert (import->imported);
assert (!import->eliminated);
LOG ("reimporting external variable %u as internal literal %u (was %u)",
eidx, mlit, import->lit);
import->lit = mlit;
}
unsigned kissat_compact_literals (kissat *solver, unsigned *mfixed_ptr) {
INC (compacted);
#if !defined(QUIET) || !defined(NDEBUG)
const unsigned active = solver->active;
#ifndef QUIET
const unsigned inactive = solver->vars - active;
kissat_phase (solver, "compact", GET (compacted),
"compacting garbage collection "
"(%u inactive variables %.2f%%)",
inactive, kissat_percent (inactive, solver->vars));
#endif
#endif
#ifdef LOGGING
assert (!solver->compacting);
solver->compacting = true;
#endif
unsigned mfixed = INVALID_LIT;
unsigned vars = 0;
for (all_variables (iidx)) {
const flags *const flags = FLAGS (iidx);
if (flags->eliminated)
continue;
const unsigned ilit = LIT (iidx);
unsigned mlit;
if (flags->fixed) {
const value value = kissat_fixed (solver, ilit);
assert (value);
if (mfixed == INVALID_LIT) {
mlit = mfixed = LIT (vars);
LOG2 ("first fixed %u mapped to %u assigned to %d", ilit, mfixed,
value);
if (value < 0)
mfixed = NOT (mfixed);
LOG2 ("all other fixed mapped to %u", mfixed);
vars++;
} else if (value < 0) {
mlit = NOT (mfixed);
LOG2 ("negatively fixed %u mapped to %u", ilit, mlit);
} else {
mlit = mfixed;
LOG2 ("positively fixed %u mapped to %u", ilit, mlit);
}
} else if (flags->active) {
assert (flags->active);
mlit = LIT (vars);
LOG2 ("remapping %u to %u", ilit, mlit);
vars++;
} else {
const int elit = PEEK_STACK (solver->export, iidx);
if (elit) {
const unsigned eidx = ABS (elit);
import *import = &PEEK_STACK (solver->import, eidx);
assert (import->imported);
assert (!import->eliminated);
import->imported = false;
LOG2 ("external variable %d not imported anymore", eidx);
POKE_STACK (solver->export, iidx, 0);
} else
LOG2 ("skipping inactive %u", ilit);
continue;
}
assert (mlit <= ilit);
assert (mlit != NOT (ilit));
if (mlit == ilit)
continue;
const int elit = PEEK_STACK (solver->export, iidx);
const unsigned eidx = ABS (elit);
if (elit < 0)
mlit = NOT (mlit);
reimport_literal (solver, eidx, mlit);
}
*mfixed_ptr = mfixed;
LOG ("compacting to %u variables %.2f%% from %u", vars,
kissat_percent (vars, solver->vars), solver->vars);
assert (vars == active || vars == active + 1);
return vars;
}
static void compact_literal (kissat *solver, unsigned dst_lit,
unsigned src_lit) {
assert (dst_lit < src_lit);
assert (dst_lit != NOT (src_lit));
const unsigned dst_idx = IDX (dst_lit);
const unsigned src_idx = IDX (src_lit);
assert (dst_idx != src_idx);
LOG ("mapping old internal literal %u to %u", src_lit, dst_lit);
solver->assigned[dst_idx] = solver->assigned[src_idx];
solver->flags[dst_idx] = solver->flags[src_idx];
solver->phases.best[dst_idx] = solver->phases.best[src_idx];
solver->phases.saved[dst_idx] = solver->phases.saved[src_idx];
solver->phases.target[dst_idx] = solver->phases.target[src_idx];
const unsigned not_src_lit = NOT (src_lit);
const unsigned not_dst_lit = NOT (dst_lit);
solver->values[dst_lit] = solver->values[src_lit];
solver->values[not_dst_lit] = solver->values[not_src_lit];
}
static unsigned map_idx (kissat *solver, unsigned iidx) {
int elit = PEEK_STACK (solver->export, iidx);
if (!elit)
return INVALID_IDX;
assert (elit);
const unsigned eidx = ABS (elit);
assert (eidx);
import *import = &PEEK_STACK (solver->import, eidx);
assert (import->imported);
if (import->eliminated)
return INVALID_IDX;
const unsigned mlit = import->lit;
const unsigned midx = IDX (mlit);
assert (midx <= iidx);
return midx;
}
static void compact_queue (kissat *solver) {
LOG ("compacting queue");
links *links = solver->links, *l;
unsigned *p = &solver->queue.first, prev = DISCONNECT;
solver->queue.stamp = 0;
for (unsigned idx; !DISCONNECTED (idx = *p); p = &l->next) {
const unsigned midx = map_idx (solver, idx);
assert (midx != INVALID_IDX);
l = links + idx;
l->prev = prev;
l->stamp = ++solver->queue.stamp;
if (idx == solver->queue.search.idx) {
solver->queue.search.idx = midx;
solver->queue.search.stamp = l->stamp;
}
*p = prev = midx;
}
solver->queue.last = prev;
*p = DISCONNECT;
for (all_variables (idx)) {
const unsigned midx = map_idx (solver, idx);
if (midx == INVALID_IDX)
continue;
links[midx] = links[idx];
}
}
static void compact_stack (kissat *solver, unsigneds *stack) {
unsigned *q = BEGIN_STACK (*stack);
const unsigned *const end = END_STACK (*stack);
for (const unsigned *p = q; p != end; p++) {
const unsigned idx = *p;
const unsigned midx = map_idx (solver, idx);
if (midx == INVALID_IDX)
continue;
*q++ = midx;
}
SET_END_OF_STACK (*stack, q);
SHRINK_STACK (*stack);
}
static void compact_scores (kissat *solver, heap *old_scores,
unsigned vars) {
LOG ("compacting scores");
heap new_scores;
memset (&new_scores, 0, sizeof new_scores);
kissat_resize_heap (solver, &new_scores, vars);
if (old_scores->tainted) {
LOG ("copying scores of tainted old scores heap");
for (all_variables (idx)) {
const unsigned midx = map_idx (solver, idx);
if (midx == INVALID_IDX)
continue;
const double score = kissat_get_heap_score (old_scores, idx);
kissat_update_heap (solver, &new_scores, midx, score);
}
} else
LOG ("no need to copy scores of old untainted scores heap");
LOG ("now pushing mapped literals onto new heap");
for (all_stack (unsigned, idx, old_scores->stack)) {
const unsigned midx = map_idx (solver, idx);
if (midx == INVALID_IDX)
continue;
kissat_push_heap (solver, &new_scores, midx);
}
kissat_release_heap (solver, old_scores);
*old_scores = new_scores;
}
static void compact_trail (kissat *solver) {
LOG ("compacting trail");
const size_t size = SIZE_ARRAY (solver->trail);
for (size_t i = 0; i < size; i++) {
const unsigned ilit = PEEK_ARRAY (solver->trail, i);
const unsigned mlit = kissat_map_literal (solver, ilit, true);
assert (mlit != INVALID_LIT);
POKE_ARRAY (solver->trail, i, mlit);
const unsigned idx = IDX (ilit);
assigned *a = solver->assigned + idx;
if (!a->binary)
continue;
const unsigned other = a->reason;
assert (VALID_INTERNAL_LITERAL (other));
const unsigned mother = kissat_map_literal (solver, other, true);
assert (mother != INVALID_LIT);
a->reason = mother;
}
}
static void compact_frames (kissat *solver) {
LOG ("compacting frames");
const size_t size = SIZE_STACK (solver->frames);
for (size_t level = 1; level < size; level++) {
frame *frame = &FRAME (level);
const unsigned ilit = frame->decision;
const unsigned mlit = kissat_map_literal (solver, ilit, true);
assert (mlit != INVALID_LIT);
frame->decision = mlit;
}
}
static void compact_export (kissat *solver, unsigned vars) {
LOG ("compacting export");
const size_t size = SIZE_STACK (solver->export);
assert (size <= UINT_MAX);
assert (size == solver->vars);
for (unsigned iidx = 0; iidx < size; iidx++) {
const unsigned elit = PEEK_STACK (solver->export, iidx);
if (!elit)
continue;
const unsigned midx = map_idx (solver, iidx);
if (midx == INVALID_IDX)
continue;
POKE_STACK (solver->export, midx, elit);
}
RESIZE_STACK (solver->export, vars);
SHRINK_STACK (solver->export);
#ifndef NDEBUG
assert (SIZE_STACK (solver->export) == vars);
for (unsigned iidx = 0; iidx < vars; iidx++) {
const int elit = PEEK_STACK (solver->export, iidx);
assert (VALID_EXTERNAL_LITERAL (elit));
const unsigned eidx = ABS (elit);
const import *const import = &PEEK_STACK (solver->import, eidx);
assert (import->imported);
if (import->eliminated)
continue;
unsigned mlit = import->lit;
if (elit < 0)
mlit = NOT (mlit);
const unsigned ilit = LIT (iidx);
assert (mlit == ilit);
}
#endif
}
static void compact_units (kissat *solver, unsigned mfixed) {
LOG ("compacting units (first fixed %u)", mfixed);
assert (kissat_fixed (solver, mfixed) > 0);
for (all_stack (int, elit, solver->units)) {
const unsigned eidx = ABS (elit);
const unsigned mlit = elit < 0 ? NOT (mfixed) : mfixed;
const import *const import = &PEEK_STACK (solver->import, eidx);
assert (import->imported);
assert (!import->eliminated);
const unsigned ilit = import->lit;
if (mlit != ilit)
reimport_literal (solver, eidx, mlit);
}
}
static void compact_best_and_target_values (kissat *solver, unsigned vars) {
const value *const best = solver->phases.best;
const value *const target = solver->phases.target;
const flags *const flags = solver->flags;
unsigned best_assigned = 0;
unsigned target_assigned = 0;
for (unsigned idx = 0; idx < vars; idx++) {
if (!flags[idx].active)
continue;
if (target[idx])
target_assigned++;
if (best[idx])
best_assigned++;
}
if (solver->target_assigned != target_assigned) {
LOG ("compacting target assigned from %u to %u",
solver->target_assigned, target_assigned);
solver->target_assigned = target_assigned;
}
if (solver->best_assigned != best_assigned) {
LOG ("compacting best assigned from %u to %u", solver->best_assigned,
best_assigned);
solver->best_assigned = best_assigned;
}
}
void kissat_finalize_compacting (kissat *solver, unsigned vars,
unsigned mfixed) {
LOG ("finalizing compacting");
assert (vars <= solver->vars);
#ifdef LOGGING
assert (solver->compacting);
#endif
if (vars == solver->vars) {
#ifdef LOGGING
solver->compacting = false;
LOG ("number of variables does not change");
#endif
return;
}
unsigned reduced = solver->vars - vars;
LOG ("compacted number of variables from %u to %u", solver->vars, vars);
bool first = true;
for (all_variables (iidx)) {
flags *flags = FLAGS (iidx);
if (flags->fixed && first)
first = false;
else if (!flags->active)
POKE_STACK (solver->export, iidx, 0);
}
compact_trail (solver);
for (all_variables (iidx)) {
const unsigned ilit = LIT (iidx);
const unsigned mlit = kissat_map_literal (solver, ilit, true);
if (mlit != INVALID_LIT && ilit != mlit)
compact_literal (solver, mlit, ilit);
}
if (mfixed != INVALID_LIT)
compact_units (solver, mfixed);
memset (solver->assigned + vars, 0, reduced * sizeof (assigned));
memset (solver->flags + vars, 0, reduced * sizeof (flags));
memset (solver->values + 2 * vars, 0, 2 * reduced * sizeof (value));
memset (solver->watches + 2 * vars, 0, 2 * reduced * sizeof (watches));
compact_queue (solver);
compact_stack (solver, &solver->sweep_schedule);
compact_scores (solver, SCORES, vars);
compact_frames (solver);
compact_export (solver, vars);
compact_best_and_target_values (solver, vars);
solver->vars = vars;
#ifdef LOGGING
solver->compacting = false;
#endif
kissat_decrease_size (solver);
}

9
src/sat/kissat/compact.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef _compact_h_INCLUDED
#define _compact_h_INCLUDED
struct kissat;
unsigned kissat_compact_literals (struct kissat *, unsigned *mfixed_ptr);
void kissat_finalize_compacting (struct kissat *, unsigned vars,
unsigned mfixed);
#endif

83
src/sat/kissat/config.c Normal file
View File

@ -0,0 +1,83 @@
#ifndef NOPTIONS
#include "config.h"
#include "kissat.h"
#include "options.h"
#include <stdio.h>
#include <string.h>
int kissat_has_configuration (const char *name) {
if (!strcmp (name, "basic"))
return 1;
if (!strcmp (name, "default"))
return 1;
if (!strcmp (name, "plain"))
return 1;
if (!strcmp (name, "sat"))
return 1;
if (!strcmp (name, "unsat"))
return 1;
return 0;
}
void kissat_configuration_usage (void) {
#define FMT " --%-8s %s"
printf (FMT "\n", "basic",
"basic CDCL solving "
"('--plain' but no restarts, minimize, reduce)");
printf (FMT "\n", "default", "default configuration");
printf (FMT "\n", "plain",
"plain CDCL solving without advanced techniques");
printf (FMT " ('--target=%d --restartint=%d')\n", "sat",
"target satisfiable instances", (int) TARGET_SAT,
(int) RESTARTINT_SAT);
printf (FMT " ('--stable=%d')\n", "unsat",
"target unsatisfiable instances", (int) STABLE_UNSAT);
}
static void set_plain_options (kissat *solver) {
kissat_set_option (solver, "bumpreasons", 0);
kissat_set_option (solver, "chrono", 0);
kissat_set_option (solver, "compact", 0);
kissat_set_option (solver, "eagersubsume", 0);
kissat_set_option (solver, "jumpreasons", 0);
kissat_set_option (solver, "otfs", 0);
kissat_set_option (solver, "preprocess", 0);
kissat_set_option (solver, "reorder", 0);
kissat_set_option (solver, "rephase", 0);
kissat_set_option (solver, "restartreusetrail", 0);
kissat_set_option (solver, "simplify", 0);
kissat_set_option (solver, "stable", 2);
kissat_set_option (solver, "tumble", 0);
}
int kissat_set_configuration (kissat *solver, const char *name) {
if (!strcmp (name, "basic")) {
set_plain_options (solver);
kissat_set_option (solver, "restart", 0);
kissat_set_option (solver, "reduce", 0);
kissat_set_option (solver, "minimize", 0);
return 1;
}
if (!strcmp (name, "default"))
return 1;
if (!strcmp (name, "plain")) {
set_plain_options (solver);
return 1;
}
if (!strcmp (name, "sat")) {
kissat_set_option (solver, "target", TARGET_SAT);
kissat_set_option (solver, "restartint", RESTARTINT_SAT);
return 1;
}
if (!strcmp (name, "unsat")) {
kissat_set_option (solver, "stable", STABLE_UNSAT);
return 1;
}
return 0;
}
#else
int kissat_config_dummy_to_avoid_warning;
#endif

8
src/sat/kissat/config.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef NOPTIONS
#ifndef _config_h_INCLUDED
#define _config_h_INCLUDED
void kissat_configuration_usage (void);
#endif
#endif

4635
src/sat/kissat/congruence.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,9 @@
#ifndef _congruence_h_INCLUDED
#define _congruence_h_INCLUDED
#include <stdbool.h>
struct kissat;
bool kissat_congruence (struct kissat *);
#endif

28
src/sat/kissat/cover.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef _cover_h_INCLUDED
#define _cover_h_INCLUDED
#include <stdio.h>
#include <stdlib.h>
#define COVER(COND) \
((COND) ? \
\
(fflush (stdout), \
fprintf (stderr, "%s:%ld: %s: Coverage goal `%s' reached.\n", \
__FILE__, (long) __LINE__, __func__, #COND), \
abort (), (void) 0) \
: (void) 0)
#ifdef COVERAGE
#define FLUSH_COVERAGE() \
do { \
void __gcov_dump (void); \
__gcov_dump (); \
} while (0)
#else
#define FLUSH_COVERAGE() \
do { \
} while (0)
#endif
#endif

244
src/sat/kissat/decide.c Normal file
View File

@ -0,0 +1,244 @@
#include "decide.h"
#include "inlineframes.h"
#include "inlineheap.h"
#include "inlinequeue.h"
#include "print.h"
#include <inttypes.h>
static unsigned last_enqueued_unassigned_variable (kissat *solver) {
assert (solver->unassigned);
const links *const links = solver->links;
const value *const values = solver->values;
unsigned res = solver->queue.search.idx;
if (values[LIT (res)]) {
do {
res = links[res].prev;
assert (!DISCONNECTED (res));
} while (values[LIT (res)]);
kissat_update_queue (solver, links, res);
}
#ifdef LOGGING
const unsigned stamp = links[res].stamp;
LOG ("last enqueued unassigned %s stamp %u", LOGVAR (res), stamp);
#endif
#ifdef CHECK_QUEUE
for (unsigned i = links[res].next; !DISCONNECTED (i); i = links[i].next)
assert (VALUE (LIT (i)));
#endif
return res;
}
static unsigned largest_score_unassigned_variable (kissat *solver) {
heap *scores = SCORES;
unsigned res = kissat_max_heap (scores);
const value *const values = solver->values;
while (values[LIT (res)]) {
kissat_pop_max_heap (solver, scores);
res = kissat_max_heap (scores);
}
#if defined(LOGGING) || defined(CHECK_HEAP)
const double score = kissat_get_heap_score (scores, res);
#endif
LOG ("largest score unassigned %s score %g", LOGVAR (res), score);
#ifdef CHECK_HEAP
for (all_variables (idx)) {
if (!ACTIVE (idx))
continue;
if (VALUE (LIT (idx)))
continue;
const double idx_score = kissat_get_heap_score (scores, idx);
assert (score >= idx_score);
}
#endif
return res;
}
void kissat_start_random_sequence (kissat *solver) {
if (!GET_OPTION (randec))
return;
if (solver->stable && !GET_OPTION (randecstable))
return;
if (!solver->stable && !GET_OPTION (randecfocused))
return;
if (solver->randec)
kissat_very_verbose (solver,
"continuing random decision sequence "
"at %s conflicts",
FORMAT_COUNT (CONFLICTS));
else {
INC (random_sequences);
const uint64_t count = solver->statistics.random_sequences;
const unsigned length = GET_OPTION (randeclength) * LOGN (count);
kissat_very_verbose (solver,
"starting random decision sequence "
"at %s conflicts for %s conflicts",
FORMAT_COUNT (CONFLICTS), FORMAT_COUNT (length));
solver->randec = length;
UPDATE_CONFLICT_LIMIT (randec, random_sequences, LOGN, false);
}
}
static unsigned next_random_decision (kissat *solver) {
if (!VARS)
return INVALID_IDX;
if (solver->warming)
return INVALID_IDX;
if (!GET_OPTION (randec))
return INVALID_IDX;
if (solver->stable && !GET_OPTION (randecstable))
return INVALID_IDX;
if (!solver->stable && !GET_OPTION (randecfocused))
return INVALID_IDX;
if (!solver->randec) {
assert (solver->level);
if (solver->level > 1)
return INVALID_IDX;
uint64_t conflicts = CONFLICTS;
limits *limits = &solver->limits;
if (conflicts < limits->randec.conflicts)
return INVALID_IDX;
kissat_start_random_sequence (solver);
}
for (;;) {
unsigned idx = kissat_next_random32 (&solver->random) % VARS;
if (!ACTIVE (idx))
continue;
unsigned lit = LIT (idx);
if (solver->values[lit])
continue;
return idx;
}
}
unsigned kissat_next_decision_variable (kissat *solver) {
#ifdef LOGGING
const char *type = 0;
#endif
unsigned res = next_random_decision (solver);
if (res == INVALID_IDX) {
if (solver->stable) {
#ifdef LOGGING
type = "maximum score";
#endif
res = largest_score_unassigned_variable (solver);
INC (score_decisions);
} else {
#ifdef LOGGING
type = "dequeued";
#endif
res = last_enqueued_unassigned_variable (solver);
INC (queue_decisions);
}
} else {
#ifdef LOGGING
type = "random";
#endif
INC (random_decisions);
}
LOG ("next %s decision %s", type, LOGVAR (res));
return res;
}
int kissat_decide_phase (kissat *solver, unsigned idx) {
bool force = GET_OPTION (forcephase);
value *target;
if (force)
target = 0;
else if (!GET_OPTION (target))
target = 0;
else if (solver->stable || GET_OPTION (target) > 1)
target = solver->phases.target + idx;
else
target = 0;
value *saved;
if (force)
saved = 0;
else if (GET_OPTION (phasesaving))
saved = solver->phases.saved + idx;
else
saved = 0;
value res = 0;
if (!solver->stable) {
switch ((solver->statistics.switched >> 1) & 7) {
case 1:
res = INITIAL_PHASE;
break;
case 3:
res = -INITIAL_PHASE;
break;
}
}
if (!res && target && (res = *target)) {
LOG ("%s uses target decision phase %d", LOGVAR (idx), (int) res);
INC (target_decisions);
}
if (!res && saved && (res = *saved)) {
LOG ("%s uses saved decision phase %d", LOGVAR (idx), (int) res);
INC (saved_decisions);
}
if (!res) {
res = INITIAL_PHASE;
LOG ("%s uses initial decision phase %d", LOGVAR (idx), (int) res);
INC (initial_decisions);
}
assert (res);
return res < 0 ? -1 : 1;
}
void kissat_decide (kissat *solver) {
START (decide);
assert (solver->unassigned);
if (solver->warming)
INC (warming_decisions);
else {
INC (decisions);
if (solver->stable)
INC (stable_decisions);
else
INC (focused_decisions);
}
solver->level++;
assert (solver->level != INVALID_LEVEL);
const unsigned idx = kissat_next_decision_variable (solver);
const value value = kissat_decide_phase (solver, idx);
unsigned lit = LIT (idx);
if (value < 0)
lit = NOT (lit);
kissat_push_frame (solver, lit);
assert (solver->level < SIZE_STACK (solver->frames));
LOG ("decide literal %s", LOGLIT (lit));
kissat_assign_decision (solver, lit);
STOP (decide);
}
void kissat_internal_assume (kissat *solver, unsigned lit) {
assert (solver->unassigned);
assert (!VALUE (lit));
solver->level++;
assert (solver->level != INVALID_LEVEL);
kissat_push_frame (solver, lit);
assert (solver->level < SIZE_STACK (solver->frames));
LOG ("assuming literal %s", LOGLIT (lit));
kissat_assign_decision (solver, lit);
}

14
src/sat/kissat/decide.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef _decide_h_INCLUDED
#define _decide_h_INCLUDED
struct kissat;
void kissat_decide (struct kissat *);
void kissat_start_random_sequence (struct kissat *);
void kissat_internal_assume (struct kissat *, unsigned lit);
unsigned kissat_next_decision_variable (struct kissat *);
int kissat_decide_phase (struct kissat *, unsigned idx);
#define INITIAL_PHASE (GET_OPTION (phase) ? 1 : -1)
#endif

168
src/sat/kissat/deduce.c Normal file
View File

@ -0,0 +1,168 @@
#include "deduce.h"
#include "inline.h"
#include "promote.h"
#include "strengthen.h"
static inline void recompute_and_promote (kissat *solver, clause *c) {
assert (c->redundant);
const unsigned old_glue = c->glue;
const unsigned new_glue = kissat_recompute_glue (solver, c, old_glue);
if (new_glue < old_glue)
kissat_promote_clause (solver, c, new_glue);
}
static inline void mark_clause_as_used (kissat *solver, clause *c) {
if (!c->redundant)
return;
INC (clauses_used);
c->used = MAX_USED;
LOGCLS (c, "using");
recompute_and_promote (solver, c);
unsigned glue = MIN (c->glue, MAX_GLUE_USED);
solver->statistics.used[solver->stable].glue[glue]++;
if (solver->stable)
INC (clauses_used_stable);
else
INC (clauses_used_focused);
}
bool kissat_recompute_and_promote (kissat *solver, clause *c) {
assert (c->redundant);
const unsigned old_glue = c->glue;
const unsigned new_glue = kissat_recompute_glue (solver, c, old_glue);
if (new_glue >= old_glue)
return false;
kissat_promote_clause (solver, c, new_glue);
return true;
}
static inline bool analyze_literal (kissat *solver, assigned *all_assigned,
frame *frames, unsigned lit) {
assert (VALUE (lit) < 0);
const unsigned idx = IDX (lit);
assigned *a = all_assigned + idx;
const unsigned level = a->level;
if (!level)
return false;
solver->antecedent_size++;
if (a->analyzed)
return false;
LOG ("analyzing literal %s", LOGLIT (lit));
kissat_push_analyzed (solver, all_assigned, idx);
assert (level <= solver->level);
#if defined(LOGGING) || !defined(NDEBUG)
PUSH_STACK (solver->resolvent, lit);
#endif
solver->resolvent_size++;
if (level == solver->level)
return true;
assert (a->analyzed);
PUSH_STACK (solver->clause, lit);
LOG ("learned literal %s", LOGLIT (lit));
frame *f = frames + level;
if (f->used++)
return false;
LOG ("pulling in decision level %u", level);
PUSH_STACK (solver->levels, level);
return false;
}
clause *kissat_deduce_first_uip_clause (kissat *solver, clause *conflict) {
START (deduce);
assert (EMPTY_STACK (solver->analyzed));
assert (EMPTY_STACK (solver->levels));
assert (EMPTY_STACK (solver->clause));
#if defined(LOGGING) || !defined(NDEBUG)
CLEAR_STACK (solver->resolvent);
#endif
if (conflict->size > 2)
mark_clause_as_used (solver, conflict);
PUSH_STACK (solver->clause, INVALID_LIT);
solver->antecedent_size = 0;
solver->resolvent_size = 0;
unsigned unresolved_on_current_level = 0, conflict_size = 0;
assigned *all_assigned = solver->assigned;
frame *frames = BEGIN_STACK (solver->frames);
for (all_literals_in_clause (lit, conflict)) {
assert (VALUE (lit) < 0);
if (LEVEL (lit))
conflict_size++;
if (analyze_literal (solver, all_assigned, frames, lit))
unresolved_on_current_level++;
}
assert (unresolved_on_current_level > 1);
LOG ("starting with %u unresolved literals on current decision level",
unresolved_on_current_level);
assert (solver->antecedent_size == solver->resolvent_size);
LOGRES2 ("initial");
const bool otfs = GET_OPTION (otfs);
unsigned const *t = END_ARRAY (solver->trail);
unsigned uip = INVALID_LIT;
unsigned resolved = 0;
assigned *a = 0;
for (;;) {
do {
assert (t > BEGIN_ARRAY (solver->trail));
uip = *--t;
a = ASSIGNED (uip);
} while (!a->analyzed || a->level != solver->level);
if (unresolved_on_current_level == 1)
break;
assert (a->reason != DECISION_REASON);
assert (a->level == solver->level);
solver->antecedent_size = 1;
resolved++;
if (a->binary) {
const unsigned other = a->reason;
LOGBINARY (uip, other, "resolving %s reason", LOGLIT (uip));
if (analyze_literal (solver, all_assigned, frames, other))
unresolved_on_current_level++;
} else {
const reference ref = a->reason;
LOGREF (ref, "resolving %s reason", LOGLIT (uip));
clause *reason = kissat_dereference_clause (solver, ref);
for (all_literals_in_clause (lit, reason))
if (lit != uip &&
analyze_literal (solver, all_assigned, frames, lit))
unresolved_on_current_level++;
mark_clause_as_used (solver, reason);
}
assert (unresolved_on_current_level > 0);
unresolved_on_current_level--;
LOG ("after resolving %s there are %u literals left "
"on current decision level",
LOGLIT (uip), unresolved_on_current_level);
assert (solver->resolvent_size > 0);
solver->resolvent_size--;
#if defined(LOGGING) || !defined(NDEBUG)
LOG2 ("actual antecedent size %u", solver->antecedent_size);
REMOVE_STACK (unsigned, solver->resolvent, NOT (uip));
assert (SIZE_STACK (solver->resolvent) == solver->resolvent_size);
LOGRES2 ("new");
#endif
if (otfs && solver->antecedent_size > 2 &&
solver->resolvent_size < solver->antecedent_size) {
assert (!a->binary);
assert (solver->antecedent_size && solver->resolvent_size + 1);
clause *reason = kissat_dereference_clause (solver, a->reason);
assert (!reason->garbage);
clause *res = kissat_on_the_fly_strengthen (solver, reason, uip);
if (resolved == 1 && solver->resolvent_size < conflict_size) {
assert (!conflict->garbage);
assert (conflict_size > 2);
kissat_on_the_fly_subsume (solver, res, conflict);
}
STOP (deduce);
return res;
}
}
assert (uip != INVALID_LIT);
LOG ("first unique implication point %s (1st UIP)", LOGLIT (uip));
assert (PEEK_STACK (solver->clause, 0) == INVALID_LIT);
POKE_STACK (solver->clause, 0, NOT (uip));
LOGTMP ("deduced not yet minimized 1st UIP");
if (!solver->probing)
ADD (literals_deduced, SIZE_STACK (solver->clause));
STOP (deduce);
return 0;
}

14
src/sat/kissat/deduce.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef _deduce_h_INCLUDED
#define _deduce_h_INCLUDED
#include <stdbool.h>
struct clause;
struct kissat;
struct clause *kissat_deduce_first_uip_clause (struct kissat *,
struct clause *);
bool kissat_recompute_and_promote (struct kissat *, struct clause *);
#endif

230
src/sat/kissat/definition.c Normal file
View File

@ -0,0 +1,230 @@
#include "definition.h"
#include "allocate.h"
#include "gates.h"
#include "inline.h"
#include "kitten.h"
#include "print.h"
typedef struct definition_extractor definition_extractor;
struct definition_extractor {
unsigned lit;
kissat *solver;
watches *watches[2];
};
static void traverse_definition_core (void *state, unsigned id) {
definition_extractor *extractor = state;
kissat *solver = extractor->solver;
watch watch;
watches *watches0 = extractor->watches[0];
watches *watches1 = extractor->watches[1];
const size_t size_watches0 = SIZE_WATCHES (*watches0);
assert (size_watches0 <= UINT_MAX);
unsigned sign;
if (id < size_watches0) {
watch = BEGIN_WATCHES (*watches0)[id];
LOGWATCH (extractor->lit, watch, "gate[0]");
sign = 0;
} else {
unsigned tmp = id - size_watches0;
#ifndef NDEBUG
const size_t size_watches1 = SIZE_WATCHES (*watches1);
assert (size_watches1 <= UINT_MAX);
assert (tmp < size_watches1);
#endif
watch = BEGIN_WATCHES (*watches1)[tmp];
LOGWATCH (NOT (extractor->lit), watch, "gate[1]");
sign = 1;
}
PUSH_STACK (solver->gates[sign], watch);
}
#if !defined(NDEBUG) || !defined(NPROOFS)
typedef struct lemma_extractor lemma_extractor;
struct lemma_extractor {
kissat *solver;
unsigned lemmas;
unsigned unit;
};
static void traverse_one_sided_core_lemma (void *state, bool learned,
size_t size,
const unsigned *lits) {
if (!learned)
return;
lemma_extractor *extractor = state;
kissat *solver = extractor->solver;
const unsigned unit = extractor->unit;
unsigneds *added = &solver->added;
assert (extractor->lemmas || EMPTY_STACK (*added));
if (size) {
PUSH_STACK (*added, size + 1);
const size_t offset = SIZE_STACK (*added);
PUSH_STACK (*added, unit);
const unsigned *end = lits + size;
for (const unsigned *p = lits; p != end; p++)
PUSH_STACK (*added, *p);
unsigned *extended = &PEEK_STACK (*added, offset);
assert (offset + size + 1 == SIZE_STACK (*added));
CHECK_AND_ADD_LITS (size + 1, extended);
ADD_LITS_TO_PROOF (size + 1, extended);
} else {
kissat_learned_unit (solver, unit);
const unsigned *end = END_STACK (*added);
unsigned *begin = BEGIN_STACK (*added);
for (unsigned *p = begin, size; p != end; p += size) {
size = *p++;
assert (p + size <= end);
REMOVE_CHECKER_LITS (size, p);
DELETE_LITS_FROM_PROOF (size, p);
}
CLEAR_STACK (*added);
}
extractor->lemmas++;
}
#endif
bool kissat_find_definition (kissat *solver, unsigned lit) {
if (!GET_OPTION (definitions))
return false;
START (definition);
struct kitten *kitten = solver->kitten;
assert (kitten);
kitten_clear (kitten);
const unsigned not_lit = NOT (lit);
definition_extractor extractor;
extractor.lit = lit;
extractor.solver = solver;
extractor.watches[0] = &WATCHES (lit);
extractor.watches[1] = &WATCHES (not_lit);
kitten_track_antecedents (kitten);
unsigned exported = 0;
#if !defined(QUIET) || !defined(NDEBUG)
size_t occs[2] = {0, 0};
#endif
for (unsigned sign = 0; sign < 2; sign++) {
const unsigned except = sign ? not_lit : lit;
for (all_binary_large_watches (watch, *extractor.watches[sign])) {
if (watch.type.binary) {
const unsigned other = watch.binary.lit;
kitten_clause_with_id_and_exception (kitten, exported, 1, &other,
INVALID_LIT);
} else {
const reference ref = watch.large.ref;
clause *c = kissat_dereference_clause (solver, ref);
kitten_clause_with_id_and_exception (kitten, exported, c->size,
c->lits, except);
}
#if !defined(QUIET) || !defined(NDEBUG)
occs[sign]++;
#endif
exported++;
}
}
bool res = false;
LOG ("exported %u = %zu + %zu environment clauses to sub-solver",
exported, occs[0], occs[1]);
INC (definitions_checked);
const size_t limit = GET_OPTION (definitionticks);
kitten_set_ticks_limit (kitten, limit);
int status = kitten_solve (kitten);
if (status == 20) {
LOG ("sub-solver result UNSAT shows definition exists");
uint64_t learned;
unsigned reduced = kitten_compute_clausal_core (kitten, &learned);
LOG ("1st sub-solver core of size %u original clauses out of %u",
reduced, exported);
for (int i = 2; i <= GET_OPTION (definitioncores); i++) {
kitten_shrink_to_clausal_core (kitten);
kitten_shuffle_clauses (kitten);
kitten_set_ticks_limit (kitten, 10 * limit);
int tmp = kitten_solve (kitten);
assert (!tmp || tmp == 20);
if (!tmp) {
LOG ("aborting core extraction");
goto ABORT;
}
#ifndef NDEBUG
unsigned previous = reduced;
#endif
reduced = kitten_compute_clausal_core (kitten, &learned);
LOG ("%s sub-solver core of size %u original clauses out of %u",
FORMAT_ORDINAL (i), reduced, exported);
assert (reduced <= previous);
#if defined(QUIET) && defined(NDEBUG)
(void) reduced;
#endif
}
INC (definitions_extracted);
kitten_traverse_core_ids (kitten, &extractor, traverse_definition_core);
size_t size[2];
size[0] = SIZE_STACK (solver->gates[0]);
size[1] = SIZE_STACK (solver->gates[1]);
#if !defined(QUIET) || !defined(NDEBUG)
assert (reduced == size[0] + size[1]);
#ifdef METRICS
kissat_extremely_verbose (
solver,
"definition extracted[%" PRIu64 "] "
"size %u = %zu + %zu clauses %.0f%% "
"of %u = %zu + %zu (checked %" PRIu64 ")",
solver->statistics.definitions_extracted, reduced, size[0], size[1],
kissat_percent (reduced, exported), exported, occs[0], occs[1],
solver->statistics.definitions_checked);
#else
kissat_extremely_verbose (solver,
"definition extracted with core "
"size %u = %zu + %zu clauses %.0f%% "
"of %u = %zu + %zu",
reduced, size[0], size[1],
kissat_percent (reduced, exported), exported,
occs[0], occs[1]);
#endif
#endif
unsigned unit = INVALID_LIT;
if (!size[0]) {
unit = not_lit;
assert (size[1]);
} else if (!size[1])
unit = lit;
if (unit != INVALID_LIT) {
INC (definition_units);
kissat_extremely_verbose (solver, "one sided core "
"definition extraction yields "
"failed literal");
#if !defined(NDEBUG) || !defined(NPROOFS)
if (false
#ifndef NDEBUG
|| GET_OPTION (check) > 1
#endif
#ifndef NPROOFS
|| solver->proof
#endif
) {
lemma_extractor extractor;
extractor.solver = solver;
extractor.unit = unit;
extractor.lemmas = 0;
kitten_traverse_core_clauses (kitten, &extractor,
traverse_one_sided_core_lemma);
} else
#endif
kissat_learned_unit (solver, unit);
}
solver->gate_eliminated = GATE_ELIMINATED (definitions);
solver->resolve_gate = true;
res = true;
} else {
ABORT:
LOG ("sub-solver failed to show that definition exists");
}
CLEAR_STACK (solver->analyzed);
STOP (definition);
return res;
}

View File

@ -0,0 +1,10 @@
#ifndef _definition_h_INCLUDED
#define _definition_h_INCLUDED
#include <stdbool.h>
struct kissat;
bool kissat_find_definition (struct kissat *, unsigned lit);
#endif

235
src/sat/kissat/dense.c Normal file
View File

@ -0,0 +1,235 @@
#define INLINE_SORT
#include "dense.h"
#include "inline.h"
#include "proprobe.h"
#include "propsearch.h"
#include "trail.h"
#include "sort.c"
#include <string.h>
static void flush_large_watches (kissat *solver, litpairs *irredundant) {
assert (!solver->level);
assert (solver->watching);
#ifndef LOGGING
LOG ("flushing large watches");
if (irredundant)
LOG ("flushing and saving irredundant binary clauses too");
else
LOG ("keep watching irredundant binary clauses");
#endif
const value *const values = solver->values;
mark *const marks = solver->marks;
#ifndef NDEBUG
for (all_literals (lit))
assert (!marks[lit]);
#endif
size_t flushed = 0, collected = 0;
#ifdef LOGGING
size_t deduplicated = 0;
#endif
watches *all_watches = solver->watches;
unsigneds *marked = &solver->analyzed;
for (all_literals (lit)) {
const value lit_value = values[lit];
watches *watches = all_watches + lit;
watch *begin = BEGIN_WATCHES (*watches), *q = begin;
const watch *const end_watches = END_WATCHES (*watches), *p = q;
assert (EMPTY_STACK (*marked));
while (p != end_watches) {
const watch watch = *p++;
if (watch.type.binary) {
const unsigned other = watch.binary.lit;
const value other_value = values[other];
if (!lit_value && !other_value) {
const mark mark = marks[other];
if (mark) {
if (lit < other) {
kissat_delete_binary (solver, lit, other);
#ifdef LOGGING
deduplicated++;
#endif
}
} else {
marks[other] = 1;
PUSH_STACK (*marked, other);
if (irredundant) {
const unsigned other = watch.binary.lit;
if (lit < other) {
const litpair litpair = {.lits = {lit, other}};
PUSH_STACK (*irredundant, litpair);
}
} else
*q++ = watch;
}
} else {
assert (lit_value > 0 || other_value > 0);
if (lit < other) {
kissat_delete_binary (solver, lit, other);
collected++;
}
}
} else {
flushed++;
p++;
}
}
if (irredundant)
memset (watches, 0, sizeof *watches);
else
SET_END_OF_WATCHES (*watches, q);
for (all_stack (unsigned, other, *marked))
marks[other] = 0;
CLEAR_ARRAY (*marked);
}
assert (EMPTY_STACK (*marked));
LOG ("flushed %zu large watches", flushed);
LOG ("removed %zu duplicated binary clauses", deduplicated);
LOG ("collected %zu satisfied binary clauses", collected);
if (irredundant) {
LOG ("saved %zu irredundant binary clauses", SIZE_STACK (*irredundant));
kissat_release_vectors (solver);
}
(void) collected;
(void) flushed;
}
void kissat_enter_dense_mode (kissat *solver, litpairs *irredundant) {
assert (!solver->level);
assert (solver->watching);
assert (kissat_propagated (solver));
LOG ("entering dense mode with full occurrence lists");
if (irredundant)
flush_large_watches (solver, irredundant);
else
kissat_flush_large_watches (solver);
LOG ("switched to full occurrence lists");
solver->watching = false;
}
static void resume_watching_irredundant_binaries (kissat *solver,
litpairs *binaries) {
assert (binaries);
#ifdef LOGGING
size_t resumed_watching = 0;
#endif
watches *all_watches = solver->watches;
for (all_stack (litpair, litpair, *binaries)) {
const unsigned first = litpair.lits[0];
const unsigned second = litpair.lits[1];
assert (!ELIMINATED (IDX (first)));
assert (!ELIMINATED (IDX (second)));
watches *first_watches = all_watches + first;
watch first_watch = kissat_binary_watch (second);
PUSH_WATCHES (*first_watches, first_watch);
watches *second_watches = all_watches + second;
watch second_watch = kissat_binary_watch (first);
PUSH_WATCHES (*second_watches, second_watch);
#ifdef LOGGING
resumed_watching++;
#endif
}
LOG ("resumed watching %zu binary clauses", resumed_watching);
}
static void
resume_watching_large_clauses_after_elimination (kissat *solver) {
#ifdef LOGGING
size_t resumed_watching_redundant = 0;
size_t resumed_watching_irredundant = 0;
#endif
const flags *const flags = solver->flags;
watches *watches = solver->watches;
const value *const values = solver->values;
const assigned *const assigned = solver->assigned;
ward *const arena = BEGIN_STACK (solver->arena);
for (all_clauses (c)) {
if (c->garbage)
continue;
bool collect = false;
for (all_literals_in_clause (lit, c)) {
if (values[lit] > 0) {
LOGCLS (c, "%s satisfied", LOGLIT (lit));
collect = true;
break;
}
const unsigned idx = IDX (lit);
if (flags[idx].eliminated) {
LOGCLS (c, "containing eliminated %s", LOGLIT (lit));
collect = true;
break;
}
}
if (collect) {
kissat_mark_clause_as_garbage (solver, c);
continue;
}
assert (c->size > 2);
unsigned *lits = c->lits;
kissat_sort_literals (solver, values, assigned, c->size, lits);
c->searched = 2;
const reference ref = (ward *) c - arena;
const unsigned l0 = lits[0];
const unsigned l1 = lits[1];
kissat_push_blocking_watch (solver, watches + l0, l1, ref);
kissat_push_blocking_watch (solver, watches + l1, l0, ref);
#ifdef LOGGING
if (c->redundant)
resumed_watching_redundant++;
else
resumed_watching_irredundant++;
#endif
}
LOG ("resumed watching %zu irredundant and %zu redundant large clauses",
resumed_watching_irredundant, resumed_watching_redundant);
}
void kissat_resume_sparse_mode (kissat *solver, bool flush_eliminated,
litpairs *irredundant) {
assert (!solver->level);
assert (!solver->watching);
if (solver->inconsistent)
return;
LOG ("resuming sparse mode watching clauses");
kissat_flush_large_connected (solver);
LOG ("switched to watching clauses");
solver->watching = true;
if (irredundant) {
LOG ("resuming watching %zu irredundant binaries",
SIZE_STACK (*irredundant));
resume_watching_irredundant_binaries (solver, irredundant);
}
if (flush_eliminated)
resume_watching_large_clauses_after_elimination (solver);
else
kissat_watch_large_clauses (solver);
LOG ("forcing to propagate units on all clauses");
kissat_reset_propagate (solver);
clause *conflict;
if (solver->probing)
conflict = kissat_probing_propagate (solver, 0, true);
else
conflict = kissat_search_propagate (solver);
#ifndef NDEBUG
if (conflict)
assert (solver->inconsistent);
else
assert (kissat_trail_flushed (solver));
#else
(void) conflict;
#endif
}

12
src/sat/kissat/dense.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef _dense_h_INCLUDED
#define _dense_h_INCLUDED
#include "watch.h"
void kissat_enter_dense_mode (struct kissat *,
litpairs *saved_irredundant_binary_clauses);
void kissat_resume_sparse_mode (struct kissat *, bool flush_eliminated,
litpairs *);
#endif

293
src/sat/kissat/dump.c Normal file
View File

@ -0,0 +1,293 @@
#ifndef NDEBUG
#include "inline.h"
#include <inttypes.h>
static void dump_literal (kissat *solver, unsigned ilit) {
const int elit = kissat_export_literal (solver, ilit);
printf ("%u(%d)", ilit, elit);
const int value = VALUE (ilit);
if (value) {
const unsigned ilit_level = LEVEL (ilit);
printf ("@%u=%d", ilit_level, value);
}
}
static void dump_binary (kissat *solver, unsigned a, unsigned b) {
printf ("binary clause ");
dump_literal (solver, a);
fputc (' ', stdout);
dump_literal (solver, b);
fputc ('\n', stdout);
}
static void dump_clause (kissat *solver, clause *c) {
if (c->redundant)
printf ("redundant glue %u", c->glue);
else
printf ("irredundant");
const reference ref = kissat_reference_clause (solver, c);
if (c->garbage)
printf (" garbage");
printf (" clause[%u]", ref);
for (all_literals_in_clause (lit, c)) {
fputc (' ', stdout);
dump_literal (solver, lit);
}
fputc ('\n', stdout);
}
static void dump_ref (kissat *solver, reference ref) {
clause *c = kissat_dereference_clause (solver, ref);
dump_clause (solver, c);
}
static void dump_trail (kissat *solver) {
unsigned prev = 0;
for (unsigned level = 0; level <= solver->level; level++) {
frame *frame = &FRAME (level);
unsigned next;
if (level < solver->level)
next = frame[1].trail;
else
next = SIZE_ARRAY (solver->trail);
if (next == prev)
printf ("frame[%u] has no assignments\n", level);
else {
printf ("frame[%u] has %u assignments\n", level, next - prev);
if (prev < next)
printf ("block[%u] = trail[%u..%u]\n", level, prev, next - 1);
}
for (unsigned i = prev; i < next; i++) {
printf ("trail[%u] ", i);
const unsigned lit = PEEK_ARRAY (solver->trail, i);
dump_literal (solver, lit);
const unsigned lit_level = LEVEL (lit);
assert (lit_level <= level);
if (lit_level < level)
printf (" out-of-order");
assigned *a = ASSIGNED (lit);
if (!lit_level) {
printf (" UNIT\n");
assert (!a->binary);
assert (a->reason == UNIT_REASON);
} else {
fputc (' ', stdout);
if (a->binary) {
const unsigned other = a->reason;
dump_binary (solver, lit, other);
} else if (a->reason == DECISION_REASON)
printf ("DECISION\n");
else {
assert (a->reason != UNIT_REASON);
const reference ref = a->reason;
dump_ref (solver, ref);
}
}
}
prev = next;
}
}
static void dump_values (kissat *solver) {
for (unsigned idx = 0; idx < VARS; idx++) {
unsigned lit = LIT (idx);
int value = solver->values[lit];
printf ("val[%u] = ", lit);
if (!value)
printf ("unassigned\n");
else
printf ("%d\n", value);
}
}
static void dump_queue (kissat *solver) {
const queue *const queue = &solver->queue;
printf ("queue: first %u, last %u, stamp %u, search %u (stamp %u)\n",
queue->first, queue->last, queue->stamp, queue->search.idx,
queue->search.stamp);
const links *const links = solver->links;
for (unsigned idx = queue->first; !DISCONNECTED (idx);
idx = links[idx].next) {
const struct links *l = links + idx;
printf ("%u ( prev %u, next %u, stamp %u )\n", idx, l->prev, l->next,
l->stamp);
}
}
static void dump_scores (kissat *solver) {
heap *heap = SCORES;
printf ("scores.vars = %u\n", heap->vars);
printf ("scores.size = %u\n", heap->size);
for (unsigned i = 0; i < SIZE_STACK (heap->stack); i++)
printf ("scores.stack[%u] = %u\n", i, PEEK_STACK (heap->stack, i));
for (unsigned i = 0; i < heap->vars; i++)
printf ("scores.score[%u] = %g\n", i, heap->score[i]);
for (unsigned i = 0; i < heap->vars; i++)
printf ("scores.pos[%u] = %u\n", i, heap->pos[i]);
}
static void dump_export (kissat *solver) {
const unsigned size = SIZE_STACK (solver->export);
for (unsigned idx = 0; idx < size; idx++)
printf ("export[%u] = %u\n", LIT (idx),
PEEK_STACK (solver->export, idx));
}
void dump_map (kissat *solver) {
const unsigned size = SIZE_STACK (solver->export);
unsigned first = INVALID_LIT;
for (unsigned idx = 0; idx < size; idx++) {
const unsigned ilit = LIT (idx);
const int elit = PEEK_STACK (solver->export, idx);
printf ("map[%u] -> %d", ilit, elit);
if (elit) {
const unsigned eidx = ABS (elit);
const import *const import = &PEEK_STACK (solver->import, eidx);
if (import->eliminated)
printf (" -> eliminated[%u]", import->lit);
else {
unsigned mlit = import->lit;
if (elit < 0)
mlit = NOT (mlit);
printf (" -> %u", mlit);
}
}
if (!LEVEL (ilit) && VALUE (ilit)) {
if (first == INVALID_LIT) {
first = ilit;
printf (" #");
} else
printf (" *");
}
fputc ('\n', stdout);
}
}
static void dump_import (kissat *solver) {
const unsigned size = SIZE_STACK (solver->import);
for (unsigned idx = 1; idx < size; idx++) {
import *import = &PEEK_STACK (solver->import, idx);
printf ("import[%u] = ", idx);
if (!import->imported)
printf ("undefined\n");
else if (import->eliminated) {
unsigned pos = import->lit;
printf ("eliminated[%u]", pos);
if (pos < SIZE_STACK (solver->eliminated)) {
int value = PEEK_STACK (solver->eliminated, pos);
if (value)
printf (" (assigned to %d)", value);
}
fputc ('\n', stdout);
} else
printf ("%u\n", import->lit);
}
}
static void dump_etrail (kissat *solver) {
for (unsigned i = 0; i < SIZE_STACK (solver->etrail); i++)
printf ("etrail[%u] = %d\n", i, (int) PEEK_STACK (solver->etrail, i));
}
static void dump_extend (kissat *solver) {
const extension *const begin = BEGIN_STACK (solver->extend);
const extension *const end = END_STACK (solver->extend);
for (const extension *p = begin, *q; p != end; p = q) {
assert (p->blocking);
printf ("extend[%zu] %d", (size_t) (p - begin), p->lit);
if (!p[1].blocking)
fputs (" :", stdout);
for (q = p + 1; q != end && !q->blocking; q++)
printf (" %d", q->lit);
fputc ('\n', stdout);
}
}
static void dump_binaries (kissat *solver) {
for (all_literals (lit)) {
if (solver->watching) {
for (all_binary_blocking_watches (watch, WATCHES (lit))) {
if (!watch.type.binary)
continue;
const unsigned other = watch.binary.lit;
if (lit > other)
continue;
dump_binary (solver, lit, other);
}
} else {
for (all_binary_large_watches (watch, WATCHES (lit))) {
if (!watch.type.binary)
continue;
const unsigned other = watch.binary.lit;
if (lit > other)
continue;
dump_binary (solver, lit, other);
}
}
}
}
static void dump_clauses (kissat *solver) {
for (all_clauses (c))
dump_clause (solver, c);
}
void kissat_dump_vectors (kissat *solver) {
vectors *vectors = &solver->vectors;
unsigneds *stack = &vectors->stack;
printf ("vectors.size = %zu\n", SIZE_STACK (*stack));
printf ("vectors.capacity = %zu\n", CAPACITY_STACK (*stack));
printf ("vectors.usable = %zu\n", vectors->usable);
const unsigned *const begin = BEGIN_STACK (*stack);
const unsigned *const end = END_STACK (*stack);
if (begin == end)
return;
fputc ('-', stdout);
for (const unsigned *p = begin + 1; p != end; p++)
if (*p == INVALID_LIT)
fputs (" -", stdout);
else
printf (" %u", *p);
fputc ('\n', stdout);
}
int kissat_dump (kissat *solver) {
if (!solver)
return 0;
printf ("vars = %u\n", solver->vars);
printf ("size = %u\n", solver->size);
printf ("level = %u\n", solver->level);
printf ("active = %u\n", solver->active);
printf ("assigned = %u\n", kissat_assigned (solver));
printf ("unassigned = %u\n", solver->unassigned);
dump_import (solver);
dump_export (solver);
#ifdef LOGGING
if (solver->compacting)
dump_map (solver);
#endif
dump_etrail (solver);
dump_extend (solver);
dump_trail (solver);
printf ("stable = %u\n", (unsigned) solver->stable);
if (solver->stable)
dump_scores (solver);
else
dump_queue (solver);
dump_values (solver);
printf ("binary = %" PRIu64 "\n", solver->statistics.clauses_binary);
printf ("irredundant = %" PRIu64 "\n",
solver->statistics.clauses_irredundant);
printf ("redundant = %" PRIu64 "\n",
solver->statistics.clauses_redundant);
dump_binaries (solver);
dump_clauses (solver);
dump_extend (solver);
return 0;
}
#else
int kissat_dump_dummy_to_avoid_warning;
#endif

603
src/sat/kissat/eliminate.c Normal file
View File

@ -0,0 +1,603 @@
#include "eliminate.h"
#include "allocate.h"
#include "backtrack.h"
#include "collect.h"
#include "dense.h"
#include "forward.h"
#include "inline.h"
#include "inlineheap.h"
#include "kitten.h"
#include "print.h"
#include "propdense.h"
#include "report.h"
#include "resolve.h"
#include "terminate.h"
#include "trail.h"
#include "weaken.h"
#include <inttypes.h>
#include <math.h>
bool kissat_eliminating (kissat *solver) {
if (!solver->enabled.eliminate)
return false;
statistics *statistics = &solver->statistics;
if (!statistics->clauses_irredundant)
return false;
const uint64_t conflicts = statistics->conflicts;
if (solver->last.conflicts.reduce == conflicts)
return false;
limits *limits = &solver->limits;
if (limits->eliminate.conflicts > conflicts)
return false;
if (limits->eliminate.variables.eliminate <
statistics->variables_eliminate)
return true;
if (limits->eliminate.variables.subsume < statistics->variables_subsume)
return true;
return false;
}
static inline double variable_score (kissat *solver, unsigned idx) {
const unsigned lit = LIT (idx);
const unsigned not_lit = NOT (lit);
size_t occlim = GET_OPTION (eliminateocclim);
size_t pos = SIZE_WATCHES (WATCHES (lit));
size_t neg = SIZE_WATCHES (WATCHES (not_lit));
if (pos > occlim)
pos = occlim;
if (neg > occlim)
neg = occlim;
double prod = pos * neg;
double sum = pos + neg;
double occlim2 = occlim * (double) occlim;
assert (prod <= occlim2);
double score = prod - sum;
assert (score <= occlim2);
double relevancy;
if (solver->stable)
relevancy = kissat_get_heap_score (&solver->scores, idx);
else
relevancy = LINK (idx).stamp;
double res = relevancy + score - occlim2;
LOG ("variable score of %s computed as "
"%g = %g + (%zu*%zu - %zu - %zu) - %g"
" = %g + %g - %g",
LOGVAR (idx), res, relevancy, pos, neg, pos, neg, occlim2, relevancy,
score, occlim2);
return res;
}
static inline void update_variable_score (kissat *solver, heap *schedule,
unsigned idx) {
assert (schedule->size);
assert (schedule == &solver->schedule);
double new_score = variable_score (solver, idx);
LOG ("new score %g for variable %s", new_score, LOGVAR (idx));
kissat_update_heap (solver, schedule, idx, -new_score);
}
void kissat_update_variable_score (kissat *solver, unsigned idx) {
update_variable_score (solver, &solver->schedule, idx);
}
static inline void update_after_adding_stack (kissat *solver,
unsigneds *stack) {
assert (!solver->probing);
heap *schedule = &solver->schedule;
if (!schedule->size)
return;
for (all_stack (unsigned, lit, *stack))
update_variable_score (solver, schedule, IDX (lit));
}
static inline void update_after_removing_variable (kissat *solver,
unsigned idx) {
heap *schedule = &solver->schedule;
if (!schedule->size)
return;
assert (!solver->probing);
flags *f = solver->flags + idx;
if (f->fixed)
return;
assert (!f->eliminated);
update_variable_score (solver, schedule, idx);
if (!kissat_heap_contains (schedule, idx))
kissat_push_heap (solver, schedule, idx);
}
static inline void update_after_removing_clause (kissat *solver, clause *c,
unsigned except) {
if (!solver->schedule.size)
return;
assert (c->garbage);
for (all_literals_in_clause (lit, c))
if (lit != except)
update_after_removing_variable (solver, IDX (lit));
}
void kissat_eliminate_binary (kissat *solver, unsigned lit,
unsigned other) {
kissat_disconnect_binary (solver, other, lit);
kissat_delete_binary (solver, lit, other);
update_after_removing_variable (solver, IDX (other));
}
void kissat_eliminate_clause (kissat *solver, clause *c, unsigned lit) {
kissat_mark_clause_as_garbage (solver, c);
update_after_removing_clause (solver, c, lit);
}
static unsigned schedule_variables (kissat *solver) {
LOG ("initializing variable schedule");
assert (!solver->schedule.size);
kissat_resize_heap (solver, &solver->schedule, solver->vars);
flags *all_flags = solver->flags;
size_t scheduled = 0;
for (all_variables (idx)) {
flags *flags = all_flags + idx;
if (!flags->active)
continue;
if (!flags->eliminate)
continue;
LOG ("scheduling %s", LOGVAR (idx));
scheduled++;
update_after_removing_variable (solver, idx);
}
assert (scheduled == kissat_size_heap (&solver->schedule));
#ifndef QUIET
size_t active = solver->active;
kissat_phase (solver, "eliminate", GET (eliminations),
"scheduled %zu variables %.0f%%", scheduled,
kissat_percent (scheduled, active));
#endif
return scheduled;
}
void kissat_flush_units_while_connected (kissat *solver) {
const unsigned *propagate = solver->propagate;
const unsigned *end_trail = END_ARRAY (solver->trail);
assert (propagate <= end_trail);
const size_t units = end_trail - propagate;
if (!units)
return;
#ifdef LOGGING
LOG ("propagating and flushing %zu units", units);
#endif
if (!kissat_dense_propagate (solver))
return;
LOG ("marking and flushing unit satisfied clauses");
end_trail = END_ARRAY (solver->trail);
while (propagate != end_trail) {
const unsigned unit = *propagate++;
watches *unit_watches = &WATCHES (unit);
watch *begin = BEGIN_WATCHES (*unit_watches), *q = begin;
const watch *const end = END_WATCHES (*unit_watches), *p = q;
if (begin == end)
continue;
LOG ("marking %s satisfied clauses as garbage", LOGLIT (unit));
while (p != end) {
const watch watch = *q++ = *p++;
if (watch.type.binary) {
const unsigned other = watch.binary.lit;
if (!solver->values[other])
update_after_removing_variable (solver, IDX (other));
} else {
const reference ref = watch.large.ref;
clause *c = kissat_dereference_clause (solver, ref);
if (!c->garbage)
kissat_eliminate_clause (solver, c, unit);
assert (c->garbage);
q--;
}
}
assert (q <= end);
size_t flushed = end - q;
if (!flushed)
continue;
LOG ("flushing %zu references satisfied by %s", flushed, LOGLIT (unit));
SET_END_OF_WATCHES (*unit_watches, q);
}
}
static void connect_resolvents (kissat *solver) {
const value *const values = solver->values;
assert (EMPTY_STACK (solver->clause));
bool satisfied = false;
#ifdef LOGGING
uint64_t added = 0;
#endif
for (all_stack (unsigned, other, solver->resolvents)) {
if (other == INVALID_LIT) {
if (satisfied)
satisfied = false;
else {
LOGTMP ("temporary resolvent");
const size_t size = SIZE_STACK (solver->clause);
if (!size) {
assert (!solver->inconsistent);
LOG ("resolved empty clause");
CHECK_AND_ADD_EMPTY ();
ADD_EMPTY_TO_PROOF ();
solver->inconsistent = true;
break;
} else if (size == 1) {
const unsigned unit = PEEK_STACK (solver->clause, 0);
LOG ("resolved unit clause %s", LOGLIT (unit));
kissat_learned_unit (solver, unit);
} else {
assert (size > 1);
(void) kissat_new_irredundant_clause (solver);
update_after_adding_stack (solver, &solver->clause);
#ifdef LOGGING
added++;
#endif
}
}
CLEAR_STACK (solver->clause);
} else if (!satisfied) {
const value value = values[other];
if (value > 0) {
LOGTMP ("now %s satisfied resolvent", LOGLIT (other));
satisfied = true;
} else if (value < 0)
LOG2 ("dropping now falsified literal %s", LOGLIT (other));
else
PUSH_STACK (solver->clause, other);
}
}
LOG ("added %" PRIu64 " new clauses", added);
CLEAR_STACK (solver->resolvents);
}
static void weaken_clauses (kissat *solver, unsigned lit) {
const unsigned not_lit = NOT (lit);
const value *const values = solver->values;
assert (!values[lit]);
watches *pos_watches = &WATCHES (lit);
for (all_binary_large_watches (watch, *pos_watches)) {
if (watch.type.binary) {
const unsigned other = watch.binary.lit;
const value value = values[other];
if (value <= 0)
kissat_weaken_binary (solver, lit, other);
kissat_eliminate_binary (solver, lit, other);
} else {
const reference ref = watch.large.ref;
clause *c = kissat_dereference_clause (solver, ref);
if (c->garbage)
continue;
bool satisfied = false;
for (all_literals_in_clause (other, c)) {
const value value = values[other];
if (value <= 0)
continue;
satisfied = true;
break;
}
if (!satisfied)
kissat_weaken_clause (solver, lit, c);
LOGCLS (c, "removing %s", LOGLIT (lit));
kissat_eliminate_clause (solver, c, lit);
}
}
RELEASE_WATCHES (*pos_watches);
watches *neg_watches = &WATCHES (not_lit);
bool optimize = !GET_OPTION (incremental);
for (all_binary_large_watches (watch, *neg_watches)) {
if (watch.type.binary) {
const unsigned other = watch.binary.lit;
const value value = values[other];
if (!optimize && value <= 0)
kissat_weaken_binary (solver, not_lit, other);
kissat_eliminate_binary (solver, not_lit, other);
} else {
const reference ref = watch.large.ref;
clause *d = kissat_dereference_clause (solver, ref);
if (d->garbage)
continue;
bool satisfied = false;
for (all_literals_in_clause (other, d)) {
const value value = values[other];
if (value <= 0)
continue;
satisfied = true;
break;
}
if (!optimize && !satisfied)
kissat_weaken_clause (solver, not_lit, d);
LOGCLS (d, "removing %s", LOGLIT (not_lit));
kissat_eliminate_clause (solver, d, not_lit);
}
}
if (optimize && !EMPTY_WATCHES (*neg_watches))
kissat_weaken_unit (solver, not_lit);
RELEASE_WATCHES (*neg_watches);
kissat_flush_units_while_connected (solver);
}
static void try_to_eliminate_all_variables_again (kissat *solver) {
LOG ("trying to elimination all variables again");
flags *all_flags = solver->flags;
for (all_variables (idx)) {
flags *flags = all_flags + idx;
flags->eliminate = true;
}
solver->limits.eliminate.variables.eliminate = 0;
}
static void set_next_elimination_bound (kissat *solver, bool complete) {
const unsigned max_bound = GET_OPTION (eliminatebound);
const unsigned current_bound =
solver->bounds.eliminate.additional_clauses;
assert (current_bound <= max_bound);
if (complete) {
if (current_bound == max_bound) {
kissat_phase (solver, "eliminate", GET (eliminations),
"completed maximum elimination bound %u",
current_bound);
limits *limits = &solver->limits;
statistics *statistics = &solver->statistics;
limits->eliminate.variables.eliminate =
statistics->variables_eliminate;
limits->eliminate.variables.subsume = statistics->variables_subsume;
#ifndef QUIET
bool first = !solver->bounds.eliminate.max_bound_completed++;
REPORT (!first, first ? '!' : ':');
#endif
} else {
const unsigned next_bound =
!current_bound ? 1 : MIN (2 * current_bound, max_bound);
kissat_phase (solver, "eliminate", GET (eliminations),
"completed elimination bound %u next %u", current_bound,
next_bound);
solver->bounds.eliminate.additional_clauses = next_bound;
try_to_eliminate_all_variables_again (solver);
REPORT (0, '^');
}
} else
kissat_phase (solver, "eliminate", GET (eliminations),
"incomplete elimination bound %u", current_bound);
}
static bool can_eliminate_variable (kissat *solver, unsigned idx) {
flags *flags = FLAGS (idx);
if (!flags->active)
return false;
if (!flags->eliminate)
return false;
return true;
}
static bool eliminate_variable (kissat *solver, unsigned idx) {
LOG ("next elimination candidate %s", LOGVAR (idx));
#ifdef LOGGING
if (GET_OPTION (log))
(void) variable_score (solver, idx);
#endif
assert (!solver->inconsistent);
assert (can_eliminate_variable (solver, idx));
LOG ("marking %s as not removed", LOGVAR (idx));
FLAGS (idx)->eliminate = false;
unsigned lit;
if (!kissat_generate_resolvents (solver, idx, &lit))
return false;
connect_resolvents (solver);
if (!solver->inconsistent)
weaken_clauses (solver, lit);
INC (eliminated);
kissat_mark_eliminated_variable (solver, idx);
if (solver->gate_eliminated) {
INC (gates_eliminated);
#ifdef METRICS
assert (*solver->gate_eliminated < UINT64_MAX);
*solver->gate_eliminated += 1;
#endif
}
return true;
}
static void eliminate_variables (kissat *solver) {
kissat_very_verbose (solver,
"trying to eliminate variables with bound %u",
solver->bounds.eliminate.additional_clauses);
assert (!solver->inconsistent);
#ifndef QUIET
unsigned before = solver->active;
unsigned eliminated = 0;
uint64_t tried = 0;
#endif
unsigned last_round_eliminated = 0;
SET_EFFORT_LIMIT (resolution_limit, eliminate, eliminate_resolutions);
bool complete;
int round = 0;
const bool forward = GET_OPTION (forward);
for (;;) {
round++;
LOG ("starting new elimination round %d", round);
if (forward) {
unsigned *propagate = solver->propagate;
complete = kissat_forward_subsume_during_elimination (solver);
if (solver->inconsistent)
break;
kissat_flush_large_connected (solver);
kissat_connect_irredundant_large_clauses (solver);
solver->propagate = propagate;
kissat_flush_units_while_connected (solver);
if (solver->inconsistent)
break;
} else {
kissat_connect_irredundant_large_clauses (solver);
complete = true;
}
#ifndef QUIET
const unsigned last_round_scheduled =
#endif
schedule_variables (solver);
kissat_very_verbose (
solver,
"scheduled %u variables %.0f%% to eliminate "
"in round %d",
last_round_scheduled,
kissat_percent (last_round_scheduled, solver->active), round);
unsigned last_round_eliminated = 0;
while (!solver->inconsistent &&
!kissat_empty_heap (&solver->schedule)) {
if (TERMINATED (eliminate_terminated_1)) {
complete = false;
break;
}
unsigned idx = kissat_pop_max_heap (solver, &solver->schedule);
if (!can_eliminate_variable (solver, idx))
continue;
statistics *s = &solver->statistics;
if (s->eliminate_resolutions > resolution_limit) {
kissat_extremely_verbose (
solver,
"eliminate round %u hits "
"resolution limit %" PRIu64 " at %" PRIu64 " resolutions",
round, resolution_limit, s->eliminate_resolutions);
complete = false;
break;
}
#ifndef QUIET
tried++;
#endif
if (eliminate_variable (solver, idx))
last_round_eliminated++;
if (solver->inconsistent)
break;
kissat_flush_units_while_connected (solver);
}
if (last_round_eliminated) {
complete = false;
#ifndef QUIET
eliminated += last_round_eliminated;
#endif
}
if (!solver->inconsistent) {
kissat_flush_large_connected (solver);
kissat_dense_collect (solver);
}
kissat_phase (
solver, "eliminate", GET (eliminations),
"eliminated %u variables %.0f%% in round %u", last_round_eliminated,
kissat_percent (last_round_eliminated, last_round_scheduled),
round);
REPORT (!last_round_eliminated, 'e');
if (solver->inconsistent)
break;
kissat_release_heap (solver, &solver->schedule);
if (complete)
break;
if (round == GET_OPTION (eliminaterounds))
break;
if (solver->statistics.eliminate_resolutions > resolution_limit)
break;
if (TERMINATED (eliminate_terminated_2))
break;
}
const unsigned remain = kissat_size_heap (&solver->schedule);
kissat_release_heap (solver, &solver->schedule);
#ifndef QUIET
kissat_very_verbose (solver,
"eliminated %u variables %.0f%% of %" PRIu64 " tried"
" (%u remain %.0f%%)",
eliminated, kissat_percent (eliminated, tried),
tried, remain,
kissat_percent (remain, solver->active));
kissat_phase (solver, "eliminate", GET (eliminations),
"eliminated %u variables %.0f%% out of %u in %d rounds",
eliminated, kissat_percent (eliminated, before), before,
round);
#endif
if (!solver->inconsistent) {
const bool complete = !remain && !last_round_eliminated;
set_next_elimination_bound (solver, complete);
if (!complete) {
const flags *end = solver->flags + VARS;
#ifndef QUIET
unsigned dropped = 0;
#endif
for (struct flags *f = solver->flags; f != end; f++)
if (f->eliminate) {
f->eliminate = false;
#ifndef QUIET
dropped++;
#endif
}
kissat_very_verbose (solver, "dropping %u eliminate candidates",
dropped);
}
}
}
static void init_map_and_kitten (kissat *solver) {
if (!GET_OPTION (definitions))
return;
assert (!solver->kitten);
solver->kitten = kitten_embedded (solver);
}
static void reset_map_and_kitten (kissat *solver) {
if (solver->kitten) {
kitten_release (solver->kitten);
solver->kitten = 0;
}
}
static void eliminate (kissat *solver) {
kissat_backtrack_propagate_and_flush_trail (solver);
assert (!solver->inconsistent);
STOP_SEARCH_AND_START_SIMPLIFIER (eliminate);
kissat_phase (solver, "eliminate", GET (eliminations),
"elimination limit of %" PRIu64 " conflicts hit",
solver->limits.eliminate.conflicts);
init_map_and_kitten (solver);
kissat_enter_dense_mode (solver, 0);
eliminate_variables (solver);
kissat_resume_sparse_mode (solver, true, 0);
reset_map_and_kitten (solver);
kissat_check_statistics (solver);
STOP_SIMPLIFIER_AND_RESUME_SEARCH (eliminate);
}
int kissat_eliminate (kissat *solver) {
assert (!solver->inconsistent);
INC (eliminations);
eliminate (solver);
kissat_classify (solver);
UPDATE_CONFLICT_LIMIT (eliminate, eliminations, NLOG2N, true);
solver->last.ticks.eliminate = solver->statistics.search_ticks;
return solver->inconsistent ? 20 : 0;
}

View File

@ -0,0 +1,19 @@
#ifndef _eliminate_hpp_INCLUDED
#define _eliminate_hpp_INCLUDED
#include <stdbool.h>
struct kissat;
struct clause;
struct heap;
void kissat_flush_units_while_connected (struct kissat *);
bool kissat_eliminating (struct kissat *);
int kissat_eliminate (struct kissat *);
void kissat_eliminate_binary (struct kissat *, unsigned, unsigned);
void kissat_eliminate_clause (struct kissat *, struct clause *, unsigned);
void kissat_update_variable_score (struct kissat *, unsigned idx);
#endif

View File

@ -0,0 +1,37 @@
#include "gates.h"
#include "inlinevector.h"
#include "logging.h"
bool kissat_find_equivalence_gate (kissat *solver, unsigned lit) {
if (!GET_OPTION (equivalences))
return false;
if (!kissat_mark_binaries (solver, lit))
return false;
value *marks = solver->marks;
unsigned not_lit = NOT (lit);
watches *watches = &WATCHES (not_lit);
unsigned replace = INVALID_LIT;
for (all_binary_large_watches (watch, *watches)) {
if (!watch.type.binary)
continue;
const unsigned other = watch.binary.lit;
const unsigned not_other = NOT (other);
if (!marks[not_other])
continue;
replace = other;
break;
}
kissat_unmark_binaries (solver, lit);
if (replace == INVALID_LIT)
return false;
LOG ("found equivalence gate %s = %s", LOGLIT (lit), LOGLIT (replace));
const watch watch1 = kissat_binary_watch (replace);
PUSH_STACK (solver->gates[1], watch1);
const watch watch0 = kissat_binary_watch (NOT (replace));
PUSH_STACK (solver->gates[0], watch0);
solver->gate_eliminated = GATE_ELIMINATED (equivalences);
INC (equivalences_extracted);
return true;
}

View File

@ -0,0 +1,10 @@
#ifndef _equivs_h_INCLUDED
#define _equivs_h_INCLUDED
#include <stdbool.h>
struct kissat;
bool kissat_find_equivalence_gate (struct kissat *, unsigned lit);
#endif

62
src/sat/kissat/error.c Normal file
View File

@ -0,0 +1,62 @@
#include "error.h"
#include "colors.h"
#include "cover.h"
#include <stdarg.h>
#include <stdlib.h>
static void (*kissat_abort_function) (void);
void kissat_call_function_instead_of_abort (void (*f) (void)) {
kissat_abort_function = f;
}
// clang-format off
void
kissat_abort (void)
{
if (kissat_abort_function)
{ FLUSH_COVERAGE (); kissat_abort_function (); } // Keep all in this line.
else
{ FLUSH_COVERAGE (); abort (); } // Keep all in this line.
}
// clang-format on
static void typed_error_message_start (const char *type) {
fflush (stdout);
TERMINAL (stderr, 2);
COLOR (BOLD);
fputs ("kissat: ", stderr);
COLOR (RED);
fputs (type, stderr);
fputs (": ", stderr);
COLOR (NORMAL);
}
void kissat_fatal_message_start (void) {
typed_error_message_start ("fatal error");
}
static void vprint_error (const char *type, const char *fmt, va_list *ap) {
typed_error_message_start (type);
vfprintf (stderr, fmt, *ap);
fputc ('\n', stderr);
fflush (stderr);
}
void kissat_error (const char *fmt, ...) {
va_list ap;
va_start (ap, fmt);
vprint_error ("error", fmt, &ap);
va_end (ap);
}
void kissat_fatal (const char *fmt, ...) {
va_list ap;
va_start (ap, fmt);
vprint_error ("fatal error", fmt, &ap);
va_end (ap);
kissat_abort ();
}

18
src/sat/kissat/error.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef _error_h_INCLUDED
#define _error_h_INCLUDED
#include "attribute.h"
// clang-format off
void kissat_error (const char *fmt, ...) ATTRIBUTE_FORMAT (1, 2);
void kissat_fatal (const char *fmt, ...) ATTRIBUTE_FORMAT (1, 2);
void kissat_fatal_message_start (void);
void kissat_call_function_instead_of_abort (void (*)(void));
void kissat_abort (void);
// clang-format on
#endif

181
src/sat/kissat/extend.c Normal file
View File

@ -0,0 +1,181 @@
#include "colors.h"
#include "inline.h"
static void undo_eliminated_assignment (kissat *solver) {
size_t size_etrail = SIZE_STACK (solver->etrail);
#ifdef LOGGING
size_t size_eliminated = SIZE_STACK (solver->eliminated);
#endif
if (!size_etrail) {
LOG ("all %zu eliminated variables are unassigned", size_eliminated);
return;
}
LOG ("unassigning %zu eliminated variables %.0f%%", size_etrail,
kissat_percent (size_etrail, size_eliminated));
value *values = BEGIN_STACK (solver->eliminated);
while (!EMPTY_STACK (solver->etrail)) {
const unsigned pos = POP_STACK (solver->etrail);
assert (pos < SIZE_STACK (solver->eliminated));
assert (values[pos]);
LOG2 ("unassigned eliminated[%u] external variable", pos);
values[pos] = 0;
}
}
static void extend_assign (kissat *solver, value *values, int lit) {
assert (lit);
assert (lit != INT_MIN);
const unsigned idx = ABS (lit);
import *import = &PEEK_STACK (solver->import, idx);
assert (import->eliminated);
assert (import->imported);
const unsigned pos = import->lit;
assert (pos < SIZE_STACK (solver->eliminated));
const value value = lit < 0 ? -1 : 1;
values[pos] = value;
assert (kissat_value (solver, lit) == lit);
LOG ("assigned eliminated[%u] external literal %d", pos, value * idx);
PUSH_STACK (solver->etrail, pos);
}
void kissat_extend (kissat *solver) {
assert (!EMPTY_STACK (solver->extend));
assert (!solver->extended);
START (extend);
solver->extended = true;
undo_eliminated_assignment (solver);
LOG ("extending solution with reconstruction stack of size %zu",
SIZE_STACK (solver->extend));
value *evalues = BEGIN_STACK (solver->eliminated);
value *ivalues = solver->values;
const import *const imports = BEGIN_STACK (solver->import);
const extension *const begin = BEGIN_STACK (solver->extend);
extension const *p = END_STACK (solver->extend);
#ifdef LOGGING
size_t assigned = 0;
size_t flipped = 0;
#endif
while (p != begin) {
unsigned pos = UINT_MAX;
bool satisfied = false;
int eliminated = 0;
int blocking = 0;
size_t size = 0;
#ifndef LOGGING
(void) size;
#endif
do {
size++;
assert (begin < p);
const extension ext = *--p;
const int elit = ext.lit;
if (ext.blocking)
blocking = elit;
if (satisfied)
continue;
assert (elit != INT_MIN);
const unsigned eidx = ABS (elit);
assert (eidx < SIZE_STACK (solver->import));
const import *const import = imports + eidx;
assert (import->imported);
if (import->eliminated) {
const unsigned tmp = import->lit;
assert (tmp < SIZE_STACK (solver->eliminated));
value value = evalues[tmp];
if (elit < 0)
value = -value;
if (value > 0) {
LOG2 ("previously assigned eliminated literal %d "
"satisfies clause",
elit);
satisfied = true;
} else if (!value && (!eliminated || pos < tmp)) {
#ifdef LOGGING
if (eliminated)
LOG2 ("earlier unassigned eliminated literal %d", elit);
else
LOG2 ("found unassigned eliminated literal %d", elit);
#endif
eliminated = elit;
pos = tmp;
}
} else {
const unsigned ilit = import->lit;
value value = ivalues[ilit];
assert (value);
if (elit < 0)
value = -value;
if (value > 0) {
LOG2 ("internal literal %s satisfies clause", LOGLIT (ilit));
satisfied = true;
}
}
} while (!blocking);
if (satisfied) {
LOGEXT2 (size, p, "satisfied");
continue;
}
if (eliminated && eliminated != blocking) {
LOGEXT2 (size, p,
"assigning eliminated unassigned external literal %d "
"to satisfy size %zu witness labelled clause at",
eliminated, size);
extend_assign (solver, evalues, eliminated);
#ifdef LOGGING
assigned++;
#endif
continue;
}
#ifdef LOGGING
const unsigned blocking_idx = ABS (blocking);
assert (blocking_idx < SIZE_STACK (solver->import));
assert (imports[blocking_idx].eliminated);
const unsigned blocking_pos = imports[blocking_idx].lit;
assert (blocking_pos < SIZE_STACK (solver->eliminated));
const value blocking_value = evalues[blocking_pos];
LOGEXT2 (size, p,
"%s blocking external literal %d "
"to satisfy size %zu witness labelled clause at",
blocking_value ? "flipping" : "assigning", blocking, size);
if (blocking_value)
flipped++;
else
assigned++;
#endif
extend_assign (solver, evalues, blocking);
}
#ifdef LOGGING
size_t total = SIZE_STACK (solver->eliminated);
LOG ("assigned %zu external variables %.0f%% out of %zu eliminated",
assigned, kissat_percent (assigned, total), total);
LOG ("flipped %zu external variables %.0f%% out of %zu assigned", flipped,
kissat_percent (flipped, assigned), assigned);
LOG ("extended assignment complete");
#endif
STOP (extend);
}

30
src/sat/kissat/extend.h Normal file
View File

@ -0,0 +1,30 @@
#ifndef _extend_h_INCLUDED
#define _extend_h_INCLUDED
#include "stack.h"
#include "utilities.h"
typedef struct extension extension;
struct extension {
signed int lit : 31;
bool blocking : 1;
};
// clang-format off
typedef STACK (extension) extensions;
// clang-format on
static inline extension kissat_extension (bool blocking, int lit) {
assert (ABS (lit) < (1 << 30));
extension res;
res.blocking = blocking;
res.lit = lit;
return res;
}
struct kissat;
void kissat_extend (struct kissat *solver);
#endif

1136
src/sat/kissat/factor.c Normal file

File diff suppressed because it is too large Load Diff

9
src/sat/kissat/factor.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef _factor_h_INCLUDED
#define _factor_h_INCLUDED
#include <stdbool.h>
struct kissat;
void kissat_factor (struct kissat *);
#endif

View File

@ -0,0 +1,41 @@
#ifndef _fastassign_h_INCLUDED
#define _fastassign_h_INCLUDED
#define FAST_ASSIGN
#include "inline.h"
#include "inlineassign.h"
static inline void kissat_fast_binary_assign (
kissat *solver, const bool probing, const unsigned level, value *values,
assigned *assigned, unsigned lit, unsigned other) {
if (GET_OPTION (jumpreasons) && level && solver->classification.bigbig) {
unsigned other_idx = IDX (other);
struct assigned *a = assigned + other_idx;
if (a->binary) {
LOGBINARY (lit, other, "jumping %s reason", LOGLIT (lit));
INC (jumped_reasons);
other = a->reason;
}
}
kissat_fast_assign (solver, probing, level, values, assigned, true, lit,
other);
LOGBINARY (lit, other, "assign %s reason", LOGLIT (lit));
}
static inline void
kissat_fast_assign_reference (kissat *solver, value *values,
assigned *assigned, unsigned lit,
reference ref, clause *reason) {
assert (reason == kissat_dereference_clause (solver, ref));
const unsigned level =
kissat_assignment_level (solver, values, assigned, lit, reason);
assert (level <= solver->level);
assert (ref != DECISION_REASON);
assert (ref != UNIT_REASON);
kissat_fast_assign (solver, solver->probing, level, values, assigned,
false, lit, ref);
LOGREF (ref, "assign %s reason", LOGLIT (lit));
}
#endif

934
src/sat/kissat/fastel.c Normal file
View File

@ -0,0 +1,934 @@
#include "fastel.h"
#include "dense.h"
#include "eliminate.h"
#include "inline.h"
#include "internal.h"
#include "print.h"
#include "rank.h"
#include "report.h"
#include "terminate.h"
#include "weaken.h"
static bool fast_forward_subsumed (kissat *solver, clause *c) {
assert (!c->garbage);
assert (!c->redundant);
unsigned max_occurring = INVALID_LIT;
size_t max_occurrence = 0;
watches *all_watches = solver->watches;
mark *marks = solver->marks;
value *values = solver->values;
for (all_literals_in_clause (other, c)) {
const unsigned other_idx = IDX (other);
if (!ACTIVE (other_idx))
continue;
watches *other_watches = all_watches + other;
size_t other_occurrence = SIZE_WATCHES (*other_watches);
if (other_occurrence <= max_occurrence)
continue;
max_occurrence = other_occurrence;
max_occurring = other;
marks[other] = 1;
}
bool subsumed = false;
const size_t fasteloccs = GET_OPTION (fasteloccs);
for (all_literals_in_clause (other, c)) {
if (other == max_occurring)
continue;
const unsigned other_idx = IDX (other);
if (!ACTIVE (other_idx))
continue;
watches *other_watches = all_watches + other;
const size_t size_other_watches = SIZE_WATCHES (*other_watches);
if (size_other_watches > fasteloccs)
continue;
for (all_binary_large_watches (watch, *other_watches)) {
if (watch.type.binary) {
const unsigned other2 = watch.type.lit;
if (marks[other2]) {
LOGBINARY (other, other2, "subsuming");
subsumed = true;
break;
}
} else {
const reference d_ref = watch.large.ref;
clause *d = kissat_dereference_clause (solver, d_ref);
if (d == c)
continue;
if (d->garbage)
continue;
if (d->size > c->size)
continue;
assert (!d->redundant);
subsumed = true;
for (all_literals_in_clause (other2, d)) {
if (values[other2] < 0)
continue;
if (!marks[other2]) {
subsumed = false;
break;
}
}
if (subsumed)
LOGCLS (d, "subsuming");
}
}
if (subsumed)
break;
}
for (all_literals_in_clause (other, c))
marks[other] = 0;
if (subsumed) {
LOGCLS (c, "subsumed");
kissat_mark_clause_as_garbage (solver, c);
INC (subsumed);
INC (fast_subsumed);
}
return subsumed;
}
static size_t flush_occurrences (kissat *solver, unsigned lit) {
const size_t fasteloccs = GET_OPTION (fasteloccs);
const size_t fastelclslim = GET_OPTION (fastelclslim);
const size_t fastelsub = GET_OPTION (fastelsub);
const value *const values = solver->values;
const flags *const all_flags = solver->flags;
watches *watches = &WATCHES (lit);
watch *begin = BEGIN_WATCHES (*watches);
watch *end = END_WATCHES (*watches);
watch *q = begin, *p = q;
size_t res = 0;
while (p != end) {
const watch watch = *q++ = *p++;
if (watch.type.binary) {
const unsigned other = watch.binary.lit;
if (values[other] > 0)
continue;
const unsigned other_idx = IDX (other);
const flags *other_flags = all_flags + other_idx;
if (other_flags->eliminated) {
q--;
continue;
}
} else {
const reference ref = watch.large.ref;
clause *c = kissat_dereference_clause (solver, ref);
if (c->garbage) {
q--;
continue;
}
if (c->size > fastelclslim) {
res = fasteloccs + 1;
break;
}
for (all_literals_in_clause (other, c)) {
value other_value = values[other];
if (other_value > 0) {
LOGCLS (c, "%s satisfied", LOGLIT (other));
kissat_mark_clause_as_garbage (solver, c);
q--;
continue;
}
}
if (fastelsub && fast_forward_subsumed (solver, c)) {
q--;
continue;
}
}
if (++res > fasteloccs)
break;
}
if (q < p) {
while (p != end)
*q++ = *p++;
SET_END_OF_WATCHES (*watches, q);
}
return res;
}
static void do_fast_resolve_binary_binary (kissat *solver, unsigned pivot,
unsigned clit, unsigned dlit) {
assert (!FLAGS (IDX (clit))->eliminated);
assert (!FLAGS (IDX (dlit))->eliminated);
if (clit == NOT (dlit)) {
LOG ("resolvent tautological");
return;
}
value *values = solver->values;
value cval = values[clit];
if (cval > 0) {
LOG ("1st antecedent satisfied");
return;
}
value dval = values[dlit];
if (dval > 0) {
LOG ("2nd antecedent satisfied");
return;
}
if (cval < 0 && dval < 0) {
assert (!solver->inconsistent);
solver->inconsistent = true;
LOG ("resolved empty clause");
CHECK_AND_ADD_EMPTY ();
ADD_EMPTY_TO_PROOF ();
return;
}
if (cval < 0) {
LOG ("resolved unit clause %s", LOGLIT (dlit));
INC (eliminate_units);
kissat_learned_unit (solver, dlit);
return;
}
if (dval < 0) {
LOG ("resolved unit clause %s", LOGLIT (clit));
INC (eliminate_units);
kissat_learned_unit (solver, clit);
return;
}
if (clit == dlit) {
LOG ("resolved unit clause %s", LOGLIT (clit));
INC (eliminate_units);
kissat_learned_unit (solver, clit);
return;
}
assert (!cval);
assert (!dval);
unsigneds *clause = &solver->clause;
assert (EMPTY_STACK (*clause));
PUSH_STACK (*clause, clit);
PUSH_STACK (*clause, dlit);
LOGTMP ("%s resolvent", LOGVAR (pivot));
#ifndef LOGGING
(void) pivot;
#endif
kissat_new_irredundant_clause (solver);
CLEAR_STACK (*clause);
}
static void do_fast_resolve_binary_large (kissat *solver, unsigned pivot,
unsigned lit, clause *c) {
assert (!FLAGS (IDX (lit))->eliminated);
if (c->garbage)
return;
assert (!c->redundant);
value *values = solver->values;
value lit_val = values[lit];
if (lit_val > 0) {
LOG ("binary clause antecedent satisfied");
return;
}
unsigneds *clause = &solver->clause;
assert (EMPTY_STACK (*clause));
if (!lit_val)
PUSH_STACK (*clause, lit);
bool satisfied = false, tautological = false;
const unsigned not_lit = NOT (lit);
for (all_literals_in_clause (other, c)) {
const unsigned idx_other = IDX (other);
if (idx_other == pivot)
continue;
if (other == lit)
continue;
if (other == not_lit) {
LOG ("resolvent tautological");
tautological = true;
break;
}
value other_val = values[other];
if (other_val < 0)
continue;
if (other_val > 0) {
LOG ("large clause antecedent satisfied");
kissat_mark_clause_as_garbage (solver, c);
satisfied = true;
break;
}
PUSH_STACK (*clause, other);
}
if (satisfied || tautological) {
CLEAR_STACK (*clause);
return;
}
size_t size = SIZE_STACK (*clause);
if (!size) {
assert (!solver->inconsistent);
solver->inconsistent = true;
LOG ("resolved empty clause");
CHECK_AND_ADD_EMPTY ();
ADD_EMPTY_TO_PROOF ();
return;
}
if (size == 1) {
const unsigned unit = PEEK_STACK (*clause, 0);
CLEAR_STACK (*clause);
LOG ("resolved unit clause %s", LOGLIT (unit));
INC (eliminate_units);
kissat_learned_unit (solver, unit);
return;
}
LOGTMP ("%s resolvent", LOGVAR (pivot));
kissat_new_irredundant_clause (solver);
CLEAR_STACK (*clause);
}
static void do_fast_resolve_large_large (kissat *solver, unsigned pivot,
clause *c, clause *d) {
if (c->garbage)
return;
if (d->garbage)
return;
assert (!c->redundant);
assert (!d->redundant);
value *values = solver->values;
mark *marks = solver->marks;
unsigneds *clause = &solver->clause;
assert (EMPTY_STACK (*clause));
bool satisfied = false, tautological = false;
for (all_literals_in_clause (other, c)) {
const unsigned idx_other = IDX (other);
if (idx_other == pivot)
continue;
value other_val = values[other];
if (other_val < 0)
continue;
if (other_val > 0) {
LOG ("1st antecedent satisfied");
satisfied = true;
break;
}
PUSH_STACK (*clause, other);
marks[other] = 1;
}
if (satisfied || tautological) {
for (all_stack (unsigned, other, *clause))
marks[other] = 0;
CLEAR_STACK (*clause);
return;
}
size_t marked = SIZE_STACK (*clause);
for (all_literals_in_clause (other, d)) {
const unsigned idx_other = IDX (other);
if (idx_other == pivot)
continue;
value other_val = values[other];
if (other_val < 0)
continue;
if (other_val > 0) {
LOG ("2nd antecedent satisfied");
satisfied = true;
break;
}
mark mark_other = marks[other];
if (mark_other)
continue;
const unsigned not_other = NOT (other);
mark mark_not_other = marks[not_other];
if (mark_not_other) {
LOG ("tautological resolvent");
tautological = true;
break;
}
PUSH_STACK (*clause, other);
}
if (satisfied || tautological) {
for (all_stack (unsigned, other, *clause))
marks[other] = 0;
CLEAR_STACK (*clause);
return;
}
size_t size = SIZE_STACK (*clause);
if (!size) {
assert (!solver->inconsistent);
solver->inconsistent = true;
LOG ("resolved empty clause");
CHECK_AND_ADD_EMPTY ();
ADD_EMPTY_TO_PROOF ();
return;
}
if (size == 1) {
const unsigned unit = PEEK_STACK (*clause, 0);
CLEAR_STACK (*clause);
marks[unit] = 0;
LOG ("resolved unit clause %s", LOGLIT (unit));
INC (eliminate_units);
kissat_learned_unit (solver, unit);
return;
}
LOGTMP ("%s resolvent", LOGVAR (pivot));
kissat_new_irredundant_clause (solver);
RESIZE_STACK (*clause, marked);
for (all_stack (unsigned, other, *clause))
marks[other] = 0;
CLEAR_STACK (*clause);
}
static void do_fast_resolve (kissat *solver, unsigned pivot, watch cwatch,
watch dwatch) {
assert (!solver->inconsistent);
LOGWATCH (LIT (pivot), cwatch, "1st fast %s elimination antecedent",
LOGVAR (pivot));
LOGWATCH (NOT (LIT (pivot)), dwatch, "1st fast %s elimination antecedent",
LOGVAR (pivot));
const unsigned clit = cwatch.binary.lit;
const unsigned dlit = dwatch.binary.lit;
const reference cref = cwatch.large.ref;
const reference dref = dwatch.large.ref;
const bool cbin = cwatch.type.binary;
const bool dbin = dwatch.type.binary;
clause *c = cbin ? 0 : kissat_dereference_clause (solver, cref);
clause *d = dbin ? 0 : kissat_dereference_clause (solver, dref);
if (cbin && dbin)
do_fast_resolve_binary_binary (solver, pivot, clit, dlit);
else if (cbin && !dbin)
do_fast_resolve_binary_large (solver, pivot, clit, d);
else if (!cbin && dbin)
do_fast_resolve_binary_large (solver, pivot, dlit, c);
else {
assert (!cbin), assert (!dbin);
do_fast_resolve_large_large (solver, pivot, c, d);
}
}
static void fast_delete_and_weaken_clauses (kissat *solver, unsigned lit) {
watches *all_watches = solver->watches;
watches *lit_watches = all_watches + lit;
value *values = solver->values;
for (all_binary_large_watches (watch, *lit_watches)) {
if (watch.type.binary) {
const unsigned other = watch.binary.lit;
const value value = values[other];
if (value <= 0)
kissat_weaken_binary (solver, lit, other);
kissat_delete_binary (solver, lit, other);
} else {
const reference ref = watch.large.ref;
clause *c = kissat_dereference_clause (solver, ref);
if (!c->garbage) {
bool satisfied = false;
for (all_literals_in_clause (other, c))
if (values[other] > 0) {
satisfied = true;
break;
}
if (!satisfied)
kissat_weaken_clause (solver, lit, c);
kissat_mark_clause_as_garbage (solver, c);
}
}
}
RELEASE_WATCHES (*lit_watches);
}
static void do_fast_eliminate (kissat *solver, unsigned pivot) {
LOG ("fast variable elimination of %s", LOGVAR (pivot));
const unsigned lit = LIT (pivot);
const unsigned not_lit = NOT (lit);
watches *all_watches = solver->watches;
watches *lit_watches = all_watches + lit;
watches *not_lit_watches = all_watches + not_lit;
LOG ("occurs %zu positively", SIZE_WATCHES (*lit_watches));
LOG ("occurs %zu negatively", SIZE_WATCHES (*not_lit_watches));
watch *begin_lit_watches = BEGIN_WATCHES (*lit_watches);
watch *begin_not_lit_watches = BEGIN_WATCHES (*not_lit_watches);
watch *end_lit_watches = END_WATCHES (*lit_watches);
watch *end_not_lit_watches = END_WATCHES (*not_lit_watches);
for (watch *p = begin_lit_watches; p < end_lit_watches; p++)
for (watch *q = begin_not_lit_watches; q < end_not_lit_watches; q++) {
do_fast_resolve (solver, pivot, *p, *q);
if (solver->inconsistent)
return;
watches *new_all_watches = solver->watches;
const size_t i = p - begin_lit_watches;
const size_t j = q - begin_not_lit_watches;
all_watches = new_all_watches;
lit_watches = all_watches + lit;
not_lit_watches = all_watches + not_lit;
begin_lit_watches = BEGIN_WATCHES (*lit_watches);
begin_not_lit_watches = BEGIN_WATCHES (*not_lit_watches);
end_lit_watches = END_WATCHES (*lit_watches);
end_not_lit_watches = END_WATCHES (*not_lit_watches);
p = begin_lit_watches + i;
q = begin_not_lit_watches + j;
}
assert (!solver->inconsistent);
INC (eliminated);
INC (fast_eliminated);
kissat_mark_eliminated_variable (solver, pivot);
fast_delete_and_weaken_clauses (solver, lit);
fast_delete_and_weaken_clauses (solver, not_lit);
}
static bool can_fast_resolve_binary_binary (kissat *solver, unsigned clit,
unsigned dlit) {
assert (!FLAGS (IDX (clit))->eliminated);
assert (!FLAGS (IDX (dlit))->eliminated);
if (clit == NOT (dlit))
return false;
value *values = solver->values;
value cval = values[clit];
if (cval > 0)
return false;
value dval = values[dlit];
if (dval > 0)
return false;
if (cval < 0 && dval < 0) {
assert (!solver->inconsistent);
solver->inconsistent = true;
LOG ("resolved empty clause");
CHECK_AND_ADD_EMPTY ();
ADD_EMPTY_TO_PROOF ();
return false;
}
if (cval < 0) {
LOG ("resolved unit clause %s", LOGLIT (dlit));
INC (eliminate_units);
kissat_learned_unit (solver, dlit);
return false;
}
if (dval < 0) {
LOG ("resolved unit clause %s", LOGLIT (clit));
INC (eliminate_units);
kissat_learned_unit (solver, clit);
return false;
}
if (clit == dlit) {
LOG ("resolved unit clause %s", LOGLIT (clit));
INC (eliminate_units);
kissat_learned_unit (solver, clit);
return false;
}
assert (!cval);
assert (!dval);
return true;
}
static bool can_fast_resolve_binary_large (kissat *solver, unsigned pivot,
unsigned lit, clause *c) {
assert (!FLAGS (IDX (lit))->eliminated);
if (c->garbage)
return false;
assert (!c->redundant);
value *values = solver->values;
value lit_val = values[lit];
if (lit_val > 0)
return false;
const unsigned not_lit = NOT (lit);
bool found_lit = false;
for (all_literals_in_clause (other, c)) {
if (other == lit)
found_lit = true;
if (other == not_lit)
return false;
value other_val = values[other];
if (other_val > 0) {
LOG ("large clause antecedent satisfied");
kissat_mark_clause_as_garbage (solver, c);
return false;
}
}
if (found_lit) {
unsigneds *clause = &solver->clause;
assert (EMPTY_STACK (*clause));
for (all_literals_in_clause (other, c)) {
const unsigned idx = IDX (other);
if (idx == pivot)
continue;
value value = values[other];
if (value < 0)
continue;
assert (!value);
PUSH_STACK (*clause, other);
}
LOGTMP ("self-subsuming resolvent");
INC (strengthened);
INC (fast_strengthened);
const size_t size = SIZE_STACK (*clause);
const reference ref = kissat_reference_clause (solver, c);
if (!size) {
assert (!solver->inconsistent);
solver->inconsistent = true;
LOG ("resolved empty clause");
CHECK_AND_ADD_EMPTY ();
ADD_EMPTY_TO_PROOF ();
} else if (size == 1) {
const unsigned unit = PEEK_STACK (*clause, 0);
LOG ("resolved %s unit clause", LOGLIT (unit));
INC (eliminate_units);
kissat_learned_unit (solver, unit);
} else
kissat_new_irredundant_clause (solver);
CLEAR_STACK (*clause);
c = kissat_dereference_clause (solver, ref);
LOGCLS (c, "self-subsuming antecedent");
kissat_mark_clause_as_garbage (solver, c);
return false;
}
return true;
}
static bool can_fast_resolve_large_large (kissat *solver, unsigned pivot,
clause *c, clause *d) {
if (c->garbage)
return false;
if (d->garbage)
return false;
assert (!c->redundant);
assert (!d->redundant);
value *values = solver->values;
mark *marks = solver->marks;
bool satisfied = false;
unsigneds *clause = &solver->clause;
assert (EMPTY_STACK (*clause));
for (all_literals_in_clause (other, c)) {
const unsigned idx_other = IDX (other);
if (idx_other == pivot)
continue;
value other_val = values[other];
if (other_val < 0)
continue;
if (other_val > 0) {
satisfied = true;
LOGCLS (c, "%s satisfied", LOGLIT (other));
kissat_mark_clause_as_garbage (solver, c);
break;
}
assert (!marks[other]);
marks[other] = 1;
PUSH_STACK (*clause, other);
}
bool tautological = false;
if (!satisfied) {
for (all_literals_in_clause (other, d)) {
const unsigned idx_other = IDX (other);
if (idx_other == pivot)
continue;
value other_val = values[other];
if (other_val < 0)
continue;
if (other_val > 0) {
satisfied = true;
LOGCLS (d, "%s satisfied", LOGLIT (other));
kissat_mark_clause_as_garbage (solver, d);
break;
}
const unsigned not_other = NOT (other);
const mark mark_not_other = marks[not_other];
if (mark_not_other) {
tautological = true;
break;
}
const mark other_mark = marks[other];
if (other_mark)
continue;
PUSH_STACK (*clause, other);
}
}
for (all_literals_in_clause (other, c))
marks[other] = 0;
bool strengthened = false;
if (!satisfied && !tautological) {
const size_t size = SIZE_STACK (*clause);
if (!size) {
assert (!solver->inconsistent);
solver->inconsistent = true;
LOG ("resolved empty clause");
CHECK_AND_ADD_EMPTY ();
ADD_EMPTY_TO_PROOF ();
strengthened = true;
} else if (size == 1) {
const unsigned unit = PEEK_STACK (*clause, 0);
LOG ("resolved %s unit clause", LOGLIT (unit));
INC (eliminate_units);
kissat_learned_unit (solver, unit);
strengthened = true;
} else {
bool c_subsumed = false, d_subsumed = false;
bool marked = false;
if (size < c->size) {
marked = true;
for (all_stack (unsigned, other, *clause))
marks[other] = 1;
size_t count = 0;
for (all_literals_in_clause (other, c))
if (marks[other])
count++;
c_subsumed = (count >= size);
}
if (size < d->size) {
if (!marked) {
marked = true;
for (all_stack (unsigned, other, *clause))
marks[other] = 1;
}
size_t count = 0;
for (all_literals_in_clause (other, d))
if (marks[other])
count++;
d_subsumed = (count >= size);
}
if (marked) {
for (all_stack (unsigned, other, *clause))
marks[other] = 0;
}
if (c_subsumed || d_subsumed) {
LOGTMP ("self-subsuming resolvent");
INC (strengthened);
INC (fast_strengthened);
const reference c_ref = kissat_reference_clause (solver, c);
const reference d_ref = kissat_reference_clause (solver, d);
kissat_new_irredundant_clause (solver);
strengthened = true;
if (c_subsumed) {
c = kissat_dereference_clause (solver, c_ref);
LOGCLS (c, "self-subsuming antecedent");
kissat_mark_clause_as_garbage (solver, c);
}
if (d_subsumed) {
d = kissat_dereference_clause (solver, d_ref);
LOGCLS (d, "self-subsuming antecedent");
kissat_mark_clause_as_garbage (solver, d);
}
if (c_subsumed && d_subsumed)
INC (fast_subsumed);
}
}
}
CLEAR_STACK (*clause);
return !satisfied && !tautological && !strengthened;
}
static bool can_fast_resolve (kissat *solver, unsigned pivot, watch cwatch,
watch dwatch) {
assert (!solver->inconsistent);
const unsigned clit = cwatch.binary.lit;
const unsigned dlit = dwatch.binary.lit;
const reference cref = cwatch.large.ref;
const reference dref = dwatch.large.ref;
const bool cbin = cwatch.type.binary;
const bool dbin = dwatch.type.binary;
clause *c = cbin ? 0 : kissat_dereference_clause (solver, cref);
clause *d = dbin ? 0 : kissat_dereference_clause (solver, dref);
if (cbin && dbin)
return can_fast_resolve_binary_binary (solver, clit, dlit);
if (cbin && !dbin)
return can_fast_resolve_binary_large (solver, pivot, clit, d);
if (!cbin && dbin)
return can_fast_resolve_binary_large (solver, pivot, dlit, c);
assert (!cbin), assert (!dbin);
return can_fast_resolve_large_large (solver, pivot, c, d);
}
static bool resolvents_limited (kissat *solver, unsigned pivot,
size_t limit) {
const unsigned lit = LIT (pivot);
const unsigned not_lit = NOT (lit);
watches *all_watches = solver->watches;
watches *lit_watches = all_watches + lit;
watches *not_lit_watches = all_watches + not_lit;
watch *begin_lit_watches = BEGIN_WATCHES (*lit_watches);
watch *begin_not_lit_watches = BEGIN_WATCHES (*not_lit_watches);
watch *end_lit_watches = END_WATCHES (*lit_watches);
watch *end_not_lit_watches = END_WATCHES (*not_lit_watches);
size_t resolved = 0;
for (watch *p = begin_lit_watches; p < end_lit_watches; p++)
for (watch *q = begin_not_lit_watches; q < end_not_lit_watches; q++) {
if (can_fast_resolve (solver, pivot, *p, *q) && ++resolved > limit)
return false;
if (solver->inconsistent)
return false;
watches *new_all_watches = solver->watches;
const size_t i = p - begin_lit_watches;
const size_t j = q - begin_not_lit_watches;
all_watches = new_all_watches;
lit_watches = all_watches + lit;
not_lit_watches = all_watches + not_lit;
begin_lit_watches = BEGIN_WATCHES (*lit_watches);
begin_not_lit_watches = BEGIN_WATCHES (*not_lit_watches);
end_lit_watches = END_WATCHES (*lit_watches);
end_not_lit_watches = END_WATCHES (*not_lit_watches);
p = begin_lit_watches + i;
q = begin_not_lit_watches + j;
}
return true;
}
static bool try_to_fast_eliminate (kissat *solver, unsigned pivot) {
assert (!solver->inconsistent);
if (!ACTIVE (pivot))
return false;
const unsigned lit = LIT (pivot);
const unsigned not_lit = NOT (lit);
const size_t fasteloccs = GET_OPTION (fasteloccs);
const size_t pos = flush_occurrences (solver, lit);
if (pos > fasteloccs)
return false;
const size_t neg = flush_occurrences (solver, not_lit);
if (neg > fasteloccs)
return false;
const size_t sum = pos + neg;
const size_t product = pos * neg;
if (sum > fasteloccs)
return false;
const size_t fastelim = GET_OPTION (fastelim);
if (product <= fastelim) {
do_fast_eliminate (solver, pivot);
return true;
}
if (resolvents_limited (solver, pivot, fastelim)) {
do_fast_eliminate (solver, pivot);
return true;
}
return false;
}
static void flush_eliminated_binary_clauses_of_literal (kissat *solver,
unsigned lit) {
flags *all_flags = solver->flags;
watches *watches = &WATCHES (lit);
watch *begin = BEGIN_WATCHES (*watches);
watch *end = END_WATCHES (*watches);
watch *q = begin, *p = q;
while (p != end) {
watch watch = *q++ = *p++;
if (!watch.type.binary)
continue;
const unsigned other = watch.binary.lit;
const unsigned other_idx = IDX (other);
flags *other_flags = all_flags + other_idx;
if (other_flags->eliminated)
q--;
}
SET_END_OF_WATCHES (*watches, q);
}
static void flush_eliminated_binary_clauses (kissat *solver) {
for (all_variables (idx)) {
const unsigned lit = LIT (idx);
const unsigned not_lit = NOT (lit);
flush_eliminated_binary_clauses_of_literal (solver, lit);
flush_eliminated_binary_clauses_of_literal (solver, not_lit);
}
}
struct candidate {
unsigned pivot;
unsigned score;
};
typedef struct candidate candidate;
typedef STACK (candidate) candidates;
#define RANK_CANDIDATE(CANDIDATE) ((CANDIDATE).score)
void kissat_fast_variable_elimination (kissat *solver) {
if (solver->inconsistent)
return;
if (!GET_OPTION (fastel))
return;
#ifndef QUIET
const unsigned variables_before = solver->active;
#endif
assert (!solver->level);
START (fastel);
kissat_enter_dense_mode (solver, 0);
kissat_connect_irredundant_large_clauses (solver);
const unsigned fastelrounds = GET_OPTION (fastelrounds);
const size_t fasteloccs = GET_OPTION (fasteloccs);
#ifndef QUIET
unsigned eliminated = 0;
#endif
unsigned round = 0;
candidates candidates;
INIT_STACK (candidates);
bool done = false;
do {
if (round++ >= fastelrounds)
break;
kissat_extremely_verbose (
solver, "gathering candidates for fast elimination round %u",
round);
assert (EMPTY_STACK (candidates));
flags *all_flags = solver->flags;
for (all_variables (pivot)) {
flags *pivot_flags = all_flags + pivot;
if (!pivot_flags->active)
continue;
if (!pivot_flags->eliminate)
continue;
const unsigned lit = LIT (pivot);
const size_t pos = flush_occurrences (solver, lit);
if (pos > fasteloccs)
continue;
const unsigned not_lit = LIT (pivot);
const size_t neg = flush_occurrences (solver, not_lit);
if (neg > fasteloccs)
continue;
const unsigned score = pos + neg;
if (score > fasteloccs)
continue;
candidate candidate = {pivot, score};
PUSH_STACK (candidates, candidate);
}
#ifndef QUIET
const size_t size_candidates = SIZE_STACK (candidates);
const size_t active_variables = solver->active;
kissat_extremely_verbose (
solver, "gathered %zu candidates %.0f%% in elimination round %u",
size_candidates, kissat_percent (size_candidates, active_variables),
round);
#endif
RADIX_STACK (candidate, unsigned, candidates, RANK_CANDIDATE);
unsigned eliminated_this_round = 0;
for (all_stack (candidate, candidate, candidates)) {
const unsigned pivot = candidate.pivot;
flags *pivot_flags = all_flags + pivot;
if (!pivot_flags->active)
continue;
if (!pivot_flags->eliminate)
continue;
if (TERMINATED (fastel_terminated_1)) {
done = true;
break;
}
if (try_to_fast_eliminate (solver, pivot))
eliminated_this_round++;
if (solver->inconsistent) {
done = true;
break;
}
pivot_flags->eliminate = false;
kissat_flush_units_while_connected (solver);
if (solver->inconsistent) {
done = true;
break;
}
}
CLEAR_STACK (candidates);
#ifndef QUIET
eliminated += eliminated_this_round;
kissat_very_verbose (
solver, "fast eliminated %u of %zu candidates %.0f%% in round %u",
eliminated_this_round, size_candidates,
kissat_percent (eliminated_this_round, size_candidates), round);
#endif
if (!eliminated_this_round)
done = true;
} while (!done);
RELEASE_STACK (candidates);
for (all_variables (idx))
FLAGS (idx)->eliminate = true;
flush_eliminated_binary_clauses (solver);
kissat_resume_sparse_mode (solver, true, 0);
#ifndef QUIET
const unsigned original_variables = solver->statistics.variables_original;
const unsigned variables_after = solver->active;
kissat_verbose (
solver,
"[fastel] "
"fast elimination of %u variables %.0f%% (%u remain %.0f%%)",
eliminated, kissat_percent (eliminated, variables_before),
variables_after,
kissat_percent (variables_after, original_variables));
#endif
STOP (fastel);
REPORT (!eliminated, 'e');
}

6
src/sat/kissat/fastel.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef _fastel_h_INCLUDED
struct kissat;
void kissat_fast_variable_elimination (struct kissat *);
#endif

97
src/sat/kissat/fifo.h Normal file
View File

@ -0,0 +1,97 @@
#ifndef _fifo_h_INCLUDED
#define _fifo_h_INCLUDED
#include "stack.h"
#include <string.h>
#define FIFO(TYPE) \
struct { \
TYPE *begin; \
TYPE *end; \
TYPE *start; \
TYPE *limit; \
TYPE *allocated; \
}
#define BEGIN_FIFO(F) ((F).begin)
#define END_FIFO(F) ((F).end)
#define START_FIFO(F) ((F).start)
#define LIMIT_FIFO(F) ((F).limit)
#define ALLOCATED_FIFO(F) ((F).allocated)
#define INIT_FIFO(F) memset (&(F), 0, sizeof (F))
#define EMPTY_FIFO(F) (END_FIFO (F) == BEGIN_FIFO (F))
#define FULL_FIFO(F) (END_FIFO (F) == ALLOCATED_FIFO (F))
#define SIZE_FIFO(F) (END_FIFO (F) - BEGIN_FIFO (F))
#define MOVABLE_FIFO(F) (BEGIN_FIFO (F) == LIMIT_FIFO (F))
#define CAPACITY_FIFO(F) (ALLOCATED_FIFO (F) - START_FIFO (F))
#define ENLARGE_FIFO(F) \
do { \
size_t OLD_BEGIN_OFFSET = BEGIN_FIFO (F) - START_FIFO (F); \
size_t OLD_END_OFFSET = END_FIFO (F) - START_FIFO (F); \
size_t OLD_CAPACITY = CAPACITY_FIFO (F); \
size_t NEW_CAPACITY = OLD_CAPACITY ? 2 * OLD_CAPACITY : 2; \
size_t OLD_BYTES = OLD_CAPACITY * sizeof *BEGIN_FIFO (F); \
size_t NEW_BYTES = NEW_CAPACITY * sizeof *BEGIN_FIFO (F); \
START_FIFO (F) = \
kissat_realloc (solver, START_FIFO (F), OLD_BYTES, NEW_BYTES); \
ALLOCATED_FIFO (F) = START_FIFO (F) + NEW_CAPACITY; \
LIMIT_FIFO (F) = START_FIFO (F) + NEW_CAPACITY / 2; \
BEGIN_FIFO (F) = START_FIFO (F) + OLD_BEGIN_OFFSET; \
END_FIFO (F) = START_FIFO (F) + OLD_END_OFFSET; \
assert (BEGIN_FIFO (F) < LIMIT_FIFO (F)); \
} while (0)
#define MOVE_FIFO(F) \
do { \
size_t SIZE = SIZE_FIFO (F); \
size_t BYTES = SIZE * sizeof *BEGIN_FIFO (F); \
memmove (START_FIFO (F), BEGIN_FIFO (F), BYTES); \
BEGIN_FIFO (F) = START_FIFO (F); \
END_FIFO (F) = BEGIN_FIFO (F) + SIZE; \
} while (0)
#define ENQUEUE_FIFO(F, E) \
do { \
if (FULL_FIFO (F)) \
ENLARGE_FIFO (F); \
*END_FIFO (F)++ = (E); \
} while (0)
#define DEQUEUE_FIFO(F, E) \
do { \
assert (!EMPTY_FIFO (F)); \
(E) = *BEGIN_FIFO (F)++; \
if (MOVABLE_FIFO (F)) \
MOVE_FIFO (F); \
} while (0)
#define POP_FIFO(F) (assert (!EMPTY_FIFO (F)), *--END_FIFO (F))
#define RELEASE_FIFO(F) \
do { \
size_t CAPACITY = CAPACITY_FIFO (F); \
size_t BYTES = CAPACITY * sizeof *BEGIN_FIFO (F); \
kissat_free (solver, START_FIFO (F), BYTES); \
INIT_FIFO (F); \
} while (0)
#define CLEAR_FIFO(F) \
do { \
BEGIN_FIFO (F) = END_FIFO (F) = START_FIFO (F); \
} while (0)
struct unsigned_fifo {
unsigned *begin, *end;
unsigned *start, *limit, *allocated;
};
typedef struct unsigned_fifo unsigned_fifo;
#define all_fifo all_stack
#endif

310
src/sat/kissat/file.c Normal file
View File

@ -0,0 +1,310 @@
#include "file.h"
#include "keatures.h"
#include "utilities.h"
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
bool kissat_file_exists (const char *path) {
if (!path)
return false;
struct stat buf;
if (stat (path, &buf))
return false;
return true;
}
bool kissat_file_readable (const char *path) {
if (!path)
return false;
struct stat buf;
if (stat (path, &buf))
return false;
if (access (path, R_OK))
return false;
return true;
}
bool kissat_file_writable (const char *path) {
int res;
if (!path)
res = 1;
else if (!strcmp (path, "/dev/null"))
res = 0;
else {
if (!*path)
res = 2;
else {
struct stat buf;
const char *p = strrchr (path, '/');
if (!p) {
if (stat (path, &buf)) {
if (errno == ENOENT)
res = 0;
else
res = -2;
} else if (S_ISDIR (buf.st_mode))
res = 3;
else if (access (path, W_OK))
res = 4;
else
res = 0;
} else if (!p[1])
res = 5;
else {
const size_t len = p - path;
char *dirname = malloc (len + 1);
if (dirname) {
strncpy (dirname, path, len);
dirname[len] = 0;
if (stat (dirname, &buf))
res = 6;
else if (!S_ISDIR (buf.st_mode))
res = 7;
else if (access (dirname, W_OK))
res = 8;
else if (stat (path, &buf)) {
if (errno == ENOENT)
res = 0;
else
res = -3;
} else if (access (path, W_OK))
res = 9;
else
res = 0;
free (dirname);
} else
res = 10;
}
}
}
return !res;
}
size_t kissat_file_size (const char *path) {
struct stat buf;
if (stat (path, &buf))
return 0;
return (size_t) buf.st_size;
}
bool kissat_find_executable (const char *name) {
const size_t name_len = strlen (name);
const char *environment = getenv ("PATH");
if (!environment)
return false;
const size_t dirs_len = strlen (environment);
char *dirs = malloc (dirs_len + 1);
if (!dirs)
return false;
strcpy (dirs, environment);
bool res = false;
const char *end = dirs + dirs_len + 1;
for (char *dir = dirs, *q; !res && dir != end; dir = q) {
for (q = dir; *q && *q != ':'; q++)
assert (q + 1 < end);
*q++ = 0;
const size_t path_len = (q - dir) + name_len;
char *path = malloc (path_len + 1);
if (!path) {
free (dirs);
return false;
}
sprintf (path, "%s/%s", dir, name);
assert (strlen (path) == path_len);
res = kissat_file_readable (path);
free (path);
}
free (dirs);
return res;
}
static int bz2sig[] = {0x42, 0x5A, 0x68, EOF};
static int gzsig[] = {0x1F, 0x8B, EOF};
static int lzmasig[] = {0x5D, 0x00, 0x00, 0x80, 0x00, EOF};
static int sig7z[] = {0x37, 0x7A, 0xBC, 0xAF, 0x27, 0x1C, EOF};
static int xzsig[] = {0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, EOF};
static int Zsig[] = {0x1F, 0x9D, 0x90, EOF};
static bool match_signature (const char *path, const int *sig) {
assert (path);
FILE *tmp = fopen (path, "r");
if (!tmp)
return false;
bool res = true;
for (const int *p = sig; res && (*p != EOF); p++)
res = (getc (tmp) == *p);
fclose (tmp);
return res;
}
#ifdef KISSAT_HAS_COMPRESSION
static FILE *open_pipe (const char *fmt, const char *path,
const char *mode) {
size_t name_len = 0;
while (fmt[name_len] && fmt[name_len] != ' ')
name_len++;
char *name = malloc (name_len + 1);
if (!name)
return 0;
strncpy (name, fmt, name_len);
name[name_len] = 0;
bool found = kissat_find_executable (name);
free (name);
if (!found)
return 0;
char *cmd = malloc (strlen (fmt) + strlen (path));
if (!cmd)
return 0;
sprintf (cmd, fmt, path);
FILE *res = popen (cmd, mode);
free (cmd);
return res;
}
static FILE *read_pipe (const char *fmt, const int *sig, const char *path) {
if (!kissat_file_readable (path))
return 0;
if (sig && !match_signature (path, sig))
return 0;
return open_pipe (fmt, path, "r");
}
#ifndef SAFE
static FILE *write_pipe (const char *fmt, const char *path) {
return open_pipe (fmt, path, "w");
}
#endif
#endif
void kissat_read_already_open_file (file *file, FILE *f, const char *path) {
file->file = f;
file->close = false;
file->reading = true;
file->compressed = false;
file->path = path;
file->bytes = 0;
}
void kissat_write_already_open_file (file *file, FILE *f,
const char *path) {
file->file = f;
file->close = false;
file->reading = false;
file->compressed = false;
file->path = path;
file->bytes = 0;
}
#ifndef KISSAT_HAS_COMPRESSION
bool kissat_looks_like_a_compressed_file (const char *path) {
#define RETURN_TRUE_IF_COMPRESSED(SUFFIX, SIGNATURE) \
if (kissat_has_suffix (path, SUFFIX) && \
match_signature (path, SIGNATURE)) \
return true
RETURN_TRUE_IF_COMPRESSED (".bz2", bz2sig);
RETURN_TRUE_IF_COMPRESSED (".gz", gzsig);
RETURN_TRUE_IF_COMPRESSED (".lzma", lzmasig);
RETURN_TRUE_IF_COMPRESSED (".7z", sig7z);
RETURN_TRUE_IF_COMPRESSED (".xz", xzsig);
RETURN_TRUE_IF_COMPRESSED (".Z", Zsig);
return false;
}
#endif
bool kissat_open_to_read_file (file *file, const char *path) {
#ifdef KISSAT_HAS_COMPRESSION
#define READ_PIPE(SUFFIX, CMD, SIG) \
do { \
if (kissat_has_suffix (path, SUFFIX)) { \
file->file = read_pipe (CMD, SIG, path); \
if (!file->file) \
break; \
file->close = true; \
file->reading = true; \
file->compressed = true; \
file->path = path; \
file->bytes = 0; \
return true; \
} \
} while (0)
READ_PIPE (".bz2", "bzip2 -c -d %s", bz2sig);
READ_PIPE (".gz", "gzip -c -d %s", gzsig);
READ_PIPE (".lzma", "lzma -c -d %s", lzmasig);
READ_PIPE (".7z", "7z x -so %s 2>/dev/null", sig7z);
READ_PIPE (".xz", "xz -c -d %s", xzsig);
READ_PIPE (".Z", "gzip -c -d %s", Zsig);
#endif
file->file = fopen (path, "r");
if (!file->file)
return false;
file->close = true;
file->reading = true;
file->compressed = false;
file->path = path;
file->bytes = 0;
return true;
}
bool kissat_open_to_write_file (file *file, const char *path) {
#if defined(KISSAT_HAS_COMPRESSION) && !defined(SAFE)
#define WRITE_PIPE(SUFFIX, CMD) \
do { \
if (kissat_has_suffix (path, SUFFIX)) { \
if (SUFFIX[1] == '7' && kissat_file_readable (path) && \
unlink (path)) \
return false; \
file->file = write_pipe (CMD, path); \
if (!file->file) \
return false; \
file->close = true; \
file->reading = false; \
file->compressed = true; \
file->path = path; \
file->bytes = 0; \
return true; \
} \
} while (0)
WRITE_PIPE (".bz2", "bzip2 -c > %s");
WRITE_PIPE (".gz", "gzip -c > %s");
WRITE_PIPE (".lzma", "lzma -c > %s");
WRITE_PIPE (".7z", "7z a -si %s 2>/dev/null");
WRITE_PIPE (".xz", "xz -c > %s");
#endif
file->file = fopen (path, "w");
if (!file->file)
return false;
file->close = true;
file->reading = false;
file->compressed = false;
file->path = path;
file->bytes = 0;
return true;
}
void kissat_close_file (file *file) {
assert (file);
assert (file->file);
#ifdef KISSAT_HAS_COMPRESSION
if (file->close && file->compressed)
pclose (file->file);
#else
assert (!file->compressed);
#endif
if (file->close && !file->compressed)
fclose (file->file);
file->file = 0;
}

124
src/sat/kissat/file.h Normal file
View File

@ -0,0 +1,124 @@
#ifndef _file_h_INCLUDED
#define _file_h_INCLUDED
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "attribute.h"
#include "keatures.h"
bool kissat_file_exists (const char *path);
bool kissat_file_readable (const char *path);
bool kissat_file_writable (const char *path);
size_t kissat_file_size (const char *path);
bool kissat_find_executable (const char *name);
typedef struct file file;
struct file {
FILE *file;
bool close;
bool reading;
bool compressed;
const char *path;
uint64_t bytes;
};
void kissat_read_already_open_file (file *, FILE *, const char *path);
void kissat_write_already_open_file (file *, FILE *, const char *path);
bool kissat_open_to_read_file (file *, const char *path);
bool kissat_open_to_write_file (file *, const char *path);
void kissat_close_file (file *);
#ifndef KISSAT_HAS_COMPRESSION
bool kissat_looks_like_a_compressed_file (const char *path);
#endif
// clang-format off
static inline size_t
kissat_read (file *, void *, size_t) ATTRIBUTE_ALWAYS_INLINE;
static inline size_t
kissat_write (file *, void *, size_t) ATTRIBUTE_ALWAYS_INLINE;
static inline int kissat_getc (file *) ATTRIBUTE_ALWAYS_INLINE;
static inline int kissat_putc (file *, int) ATTRIBUTE_ALWAYS_INLINE;
static inline void kissat_flush (file *) ATTRIBUTE_ALWAYS_INLINE;
// clang-format on
static inline size_t kissat_read (file *file, void *ptr, size_t bytes) {
assert (file);
assert (file->file);
assert (file->reading);
#ifdef KISSAT_HAS_UNLOCKEDIO
size_t res = fread_unlocked (ptr, 1, bytes, file->file);
#else
size_t res = fread (ptr, 1, bytes, file->file);
#endif
file->bytes += res;
return res;
}
static inline size_t kissat_write (file *file, void *ptr, size_t bytes) {
assert (file);
assert (file->file);
assert (!file->reading);
#ifdef KISSAT_HAS_UNLOCKEDIO
size_t res = fwrite_unlocked (ptr, 1, bytes, file->file);
#else
size_t res = fwrite (ptr, 1, bytes, file->file);
#endif
file->bytes += res;
return res;
}
static inline int kissat_getc (file *file) {
assert (file);
assert (file->file);
assert (file->reading);
#ifdef KISSAT_HAS_UNLOCKEDIO
int res = getc_unlocked (file->file);
#else
int res = getc (file->file);
#endif
if (res != EOF)
file->bytes++;
return res;
}
static inline int kissat_putc (file *file, int ch) {
assert (file);
assert (file->file);
assert (!file->reading);
#ifdef KISSAT_HAS_UNLOCKEDIO
int res = putc_unlocked (ch, file->file);
#else
int res = putc (ch, file->file);
#endif
if (res != EOF)
file->bytes++;
return ch;
}
static inline void kissat_flush (file *file) {
assert (file);
assert (file->file);
assert (!file->reading);
#ifdef KISSAT_HAS_UNLOCKEDIO
fflush_unlocked (file->file);
#else
fflush (file->file);
#endif
}
#endif

115
src/sat/kissat/flags.c Normal file
View File

@ -0,0 +1,115 @@
#include "inline.h"
#include "inlineheap.h"
#include "inlinequeue.h"
static inline void activate_literal (kissat *solver, unsigned lit) {
const unsigned idx = IDX (lit);
flags *f = FLAGS (idx);
if (f->active)
return;
lit = STRIP (lit);
LOG ("activating %s", LOGVAR (idx));
f->active = true;
assert (!f->fixed);
assert (!f->eliminated);
solver->active++;
INC (variables_activated);
kissat_enqueue (solver, idx);
const double score = 1.0 - 1.0 / solver->statistics.variables_activated;
kissat_update_heap (solver, &solver->scores, idx, score);
if (solver->stable) {
const unsigned lit = LIT (idx);
if (!VALUE (lit))
kissat_push_heap (solver, &solver->scores, idx);
}
assert (solver->unassigned < UINT_MAX);
solver->unassigned++;
kissat_mark_removed_literal (solver, lit);
kissat_mark_added_literal (solver, lit);
assert (!VALUE (lit));
assert (!VALUE (NOT (lit)));
assert (!SAVED (idx));
assert (!TARGET (idx));
assert (!BEST (idx));
}
static inline void deactivate_variable (kissat *solver, flags *f,
unsigned idx) {
assert (solver->flags + idx == f);
LOG ("deactivating %s", LOGVAR (idx));
assert (f->active);
assert (f->eliminated || f->fixed);
f->active = false;
assert (solver->active > 0);
solver->active--;
kissat_dequeue (solver, idx);
if (kissat_heap_contains (SCORES, idx))
kissat_pop_heap (solver, SCORES, idx);
}
void kissat_activate_literal (kissat *solver, unsigned lit) {
activate_literal (solver, lit);
}
void kissat_activate_literals (kissat *solver, unsigned size,
unsigned *lits) {
for (unsigned i = 0; i < size; i++)
activate_literal (solver, lits[i]);
}
void kissat_mark_fixed_literal (kissat *solver, unsigned lit) {
assert (VALUE (lit) > 0);
const unsigned idx = IDX (lit);
LOG ("marking internal %s as fixed", LOGVAR (idx));
flags *f = FLAGS (idx);
assert (f->active);
assert (!f->eliminated);
assert (!f->fixed);
f->fixed = true;
deactivate_variable (solver, f, idx);
INC (units);
int elit = kissat_export_literal (solver, lit);
assert (elit);
PUSH_STACK (solver->units, elit);
LOG ("pushed external unit literal %d (internal %u)", elit, lit);
}
void kissat_mark_eliminated_variable (kissat *solver, unsigned idx) {
const unsigned lit = LIT (idx);
assert (!VALUE (lit));
LOG ("marking internal %s as eliminated", LOGVAR (idx));
flags *f = FLAGS (idx);
assert (f->active);
assert (!f->eliminated);
assert (!f->fixed);
f->eliminated = true;
deactivate_variable (solver, f, idx);
int elit = kissat_export_literal (solver, lit);
assert (elit);
assert (elit != INT_MIN);
unsigned eidx = ABS (elit);
import *import = &PEEK_STACK (solver->import, eidx);
assert (!import->eliminated);
assert (import->imported);
assert (STRIP (import->lit) == STRIP (lit));
size_t pos = SIZE_STACK (solver->eliminated);
assert (pos < (1u << 30));
import->lit = pos;
import->eliminated = true;
PUSH_STACK (solver->eliminated, (value) 0);
LOG ("marked external variable %u as eliminated", eidx);
assert (solver->unassigned > 0);
solver->unassigned--;
}
void kissat_mark_removed_literals (kissat *solver, unsigned size,
unsigned *lits) {
for (unsigned i = 0; i < size; i++)
kissat_mark_removed_literal (solver, lits[i]);
}
void kissat_mark_added_literals (kissat *solver, unsigned size,
unsigned *lits) {
for (unsigned i = 0; i < size; i++)
kissat_mark_added_literal (solver, lits[i]);
}

37
src/sat/kissat/flags.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef _flags_h_INCLUDED
#define _flags_h_INCLUDED
#include <stdbool.h>
typedef struct flags flags;
struct flags {
bool active : 1;
bool backbone0 : 1;
bool backbone1 : 1;
bool eliminate : 1;
bool eliminated : 1;
unsigned factor : 2;
bool fixed : 1;
bool subsume : 1;
bool sweep : 1;
bool transitive : 1;
};
#define FLAGS(IDX) (assert ((IDX) < VARS), (solver->flags + (IDX)))
#define ACTIVE(IDX) (FLAGS (IDX)->active)
#define ELIMINATED(IDX) (FLAGS (IDX)->eliminated)
struct kissat;
void kissat_activate_literal (struct kissat *, unsigned);
void kissat_activate_literals (struct kissat *, unsigned, unsigned *);
void kissat_mark_eliminated_variable (struct kissat *, unsigned idx);
void kissat_mark_fixed_literal (struct kissat *, unsigned lit);
void kissat_mark_added_literals (struct kissat *, unsigned, unsigned *);
void kissat_mark_removed_literals (struct kissat *, unsigned, unsigned *);
#endif

145
src/sat/kissat/format.c Normal file
View File

@ -0,0 +1,145 @@
#include "format.h"
#include <assert.h>
#include <inttypes.h>
#include <limits.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
char *kissat_next_format_string (format *format) {
assert (format->pos < NUM_FORMAT_STRINGS);
char *res = format->str[format->pos++];
if (format->pos == NUM_FORMAT_STRINGS)
format->pos = 0;
return res;
}
static void format_count (char *res, uint64_t w) {
if (w >= 128 && kissat_is_power_of_two (w)) {
unsigned l;
for (l = 0; ((uint64_t) 1 << l) != w; l++)
assert (l + 1 < 8 * sizeof (word));
sprintf (res, "2^%u", l);
} else if (w >= 1000 && !(w % 1000)) {
unsigned l;
for (l = 0; !(w % 10); l++)
w /= 10;
sprintf (res, "%" PRIu64 "e%u", w, l);
} else
sprintf (res, "%" PRIu64, w);
}
const char *kissat_format_count (format *format, uint64_t w) {
char *res = kissat_next_format_string (format);
format_count (res, w);
return res;
}
const char *kissat_format_value (format *format, bool boolean, int value) {
if (boolean && value)
return "true";
if (boolean && !value)
return "false";
if (value == INT_MAX)
return "INT_MAX";
if (value == INT_MIN)
return "INT_MIN";
char *res = kissat_next_format_string (format);
if (value < 0) {
*res = '-';
format_count (res + 1, ABS (value));
} else
format_count (res, value);
return res;
}
const char *kissat_format_bytes (format *format, uint64_t bytes) {
char *res = kissat_next_format_string (format);
if (bytes < (1u << 10))
sprintf (res, "%" PRIu64 " bytes", bytes);
else if (bytes < (1u << 20))
sprintf (res, "%" PRIu64 " bytes (%" PRIu64 " KB)", bytes,
(bytes + (1 << 9)) >> 10);
else if (bytes < (1u << 30))
sprintf (res, "%" PRIu64 " bytes (%" PRIu64 " MB)", bytes,
(bytes + (1u << 19)) >> 20);
else
sprintf (res, "%" PRIu64 " bytes (%" PRIu64 " GB)", bytes,
(bytes + (1u << 29)) >> 30);
return res;
}
const char *kissat_format_time (format *format, double seconds) {
if (!seconds)
return "0s";
char *res = kissat_next_format_string (format);
uint64_t rounded = round (seconds);
uint64_t minutes = rounded / 60;
rounded %= 60;
uint64_t hours = minutes / 60;
minutes %= 60;
uint64_t days = hours / 24;
hours %= 24;
char *tmp = res;
if (days) {
sprintf (res, "%" PRIu64 "d", days);
tmp += strlen (res);
}
if (hours) {
if (tmp != res)
*tmp++ = ' ';
sprintf (tmp, "%" PRIu64 "h", hours);
tmp += strlen (tmp);
}
if (minutes) {
if (tmp != res)
*tmp++ = ' ';
sprintf (tmp, "%" PRIu64 "m", minutes);
tmp += strlen (tmp);
}
if (rounded) {
if (tmp != res)
*tmp++ = ' ';
sprintf (tmp, "%" PRIu64 "s", rounded);
}
return res;
}
const char *kissat_format_signs (format *format, unsigned size,
word signs) {
char *res = kissat_next_format_string (format);
assert (size + 1 < FORMAT_STRING_SIZE);
char *p = res;
word bit = 1;
for (unsigned i = 0; i < size; i++, bit <<= 1)
*p++ = (bit & signs) ? '1' : '0';
*p = 0;
return res;
}
const char *kissat_format_ordinal (format *format, uint64_t ordinal) {
char const *suffix;
unsigned mod100 = ordinal % 100;
if (10 <= mod100 && mod100 <= 19)
suffix = "th";
else {
switch (mod100 % 10) {
case 1:
suffix = "st";
break;
case 2:
suffix = "nd";
break;
case 3:
suffix = "rd";
break;
default:
suffix = "th";
break;
}
}
char *res = kissat_next_format_string (format);
sprintf (res, "%" PRIu64 "%s", ordinal, suffix);
return res;
}

42
src/sat/kissat/format.h Normal file
View File

@ -0,0 +1,42 @@
#ifndef _format_h_INCLUDED
#define _format_h_INCLUDED
#include "utilities.h"
#include <stdbool.h>
#include <stdint.h>
#define NUM_FORMAT_STRINGS 16
#define FORMAT_STRING_SIZE 128
typedef struct format format;
struct format {
unsigned pos;
char str[NUM_FORMAT_STRINGS][FORMAT_STRING_SIZE];
};
char *kissat_next_format_string (format *);
char const *kissat_format_bytes (format *, uint64_t bytes);
char const *kissat_format_count (format *, uint64_t);
char const *kissat_format_ordinal (format *, uint64_t);
char const *kissat_format_signs (format *, unsigned size, word);
char const *kissat_format_time (format *, double seconds);
char const *kissat_format_value (format *, bool boolean, int value);
#define FORMAT_BYTES(BYTES) kissat_format_bytes (&solver->format, BYTES)
#define FORMAT_COUNT(WORD) kissat_format_count (&solver->format, WORD)
#define FORMAT_ORDINAL(WORD) kissat_format_ordinal (&solver->format, WORD)
#define FORMAT_SIGNS(SIZE, SIGNS) \
kissat_format_signs (&solver->format, SIZE, SIGNS)
#define FORMAT_TIME(SECONDS) kissat_format_time (&solver->format, SECONDS)
#define FORMAT_VALUE(BOOLEAN, VALUE) \
kissat_format_value (&solver->format, BOOLEAN, VALUE)
#endif

691
src/sat/kissat/forward.c Normal file
View File

@ -0,0 +1,691 @@
#include "forward.h"
#include "allocate.h"
#include "eliminate.h"
#include "inline.h"
#include "print.h"
#include "rank.h"
#include "report.h"
#include "sort.h"
#include "terminate.h"
#include <inttypes.h>
static size_t remove_duplicated_binaries_with_literal (kissat *solver,
unsigned lit) {
watches *watches = &WATCHES (lit);
value *marks = solver->marks;
flags *flags = solver->flags;
watch *begin = BEGIN_WATCHES (*watches), *q = begin;
const watch *const end = END_WATCHES (*watches), *p = q;
while (p != end) {
const watch watch = *q++ = *p++;
assert (watch.type.binary);
const unsigned other = watch.binary.lit;
struct flags *f = flags + IDX (other);
if (!f->active)
continue;
if (!f->subsume)
continue;
const value marked = marks[other];
if (marked) {
q--;
if (lit < other) {
kissat_delete_binary (solver, lit, other);
INC (duplicated);
}
} else {
const unsigned not_other = NOT (other);
if (marks[not_other]) {
LOGBINARY (lit, other,
"duplicate hyper unary resolution on %s "
"first antecedent",
LOGLIT (other));
LOGBINARY (lit, not_other,
"duplicate hyper unary resolution on %s "
"second antecedent",
LOGLIT (not_other));
PUSH_STACK (solver->delayed, lit);
}
marks[other] = 1;
}
}
for (const watch *r = begin; r != q; r++)
marks[r->binary.lit] = 0;
if (q == end)
return 0;
size_t removed = end - q;
SET_END_OF_WATCHES (*watches, q);
LOG ("removed %zu watches with literal %s", removed, LOGLIT (lit));
return removed;
}
static void remove_all_duplicated_binary_clauses (kissat *solver) {
LOG ("removing all duplicated irredundant binary clauses");
#if !defined(QUIET) || !defined(NDEBUG)
size_t removed = 0;
#endif
assert (EMPTY_STACK (solver->delayed));
const flags *const all_flags = solver->flags;
for (all_variables (idx)) {
const flags *const flags = all_flags + idx;
if (!flags->active)
continue;
if (!flags->subsume)
continue;
const unsigned int lit = LIT (idx);
const unsigned int not_lit = NOT (lit);
#if !defined(QUIET) || !defined(NDEBUG)
removed +=
#endif
remove_duplicated_binaries_with_literal (solver, lit);
#if !defined(QUIET) || !defined(NDEBUG)
removed +=
#endif
remove_duplicated_binaries_with_literal (solver, not_lit);
}
assert (!(removed & 1));
size_t units = SIZE_STACK (solver->delayed);
if (units) {
LOG ("found %zu hyper unary resolved units", units);
const value *const values = solver->values;
for (all_stack (unsigned, unit, solver->delayed)) {
const value value = values[unit];
if (value > 0) {
LOG ("skipping satisfied resolved unit %s", LOGLIT (unit));
continue;
}
if (value < 0) {
LOG ("found falsified resolved unit %s", LOGLIT (unit));
CHECK_AND_ADD_EMPTY ();
ADD_EMPTY_TO_PROOF ();
solver->inconsistent = true;
break;
}
LOG ("new resolved unit clause %s", LOGLIT (unit));
kissat_learned_unit (solver, unit);
}
CLEAR_STACK (solver->delayed);
if (!solver->inconsistent)
kissat_flush_units_while_connected (solver);
}
REPORT (!removed && !units, '2');
}
static void find_forward_subsumption_candidates (kissat *solver,
references *candidates) {
const unsigned clslim = GET_OPTION (subsumeclslim);
const value *const values = solver->values;
const flags *const flags = solver->flags;
clause *last_irredundant = kissat_last_irredundant_clause (solver);
for (all_clauses (c)) {
if (last_irredundant && c > last_irredundant)
break;
if (c->garbage)
continue;
c->subsume = false;
if (c->redundant)
continue;
if (c->size > clslim)
continue;
assert (c->size > 2);
unsigned subsume = 0;
for (all_literals_in_clause (lit, c)) {
const unsigned idx = IDX (lit);
const struct flags *f = flags + idx;
if (f->subsume)
subsume++;
if (values[lit] > 0) {
LOGCLS (c, "satisfied by %s", LOGLIT (lit));
kissat_mark_clause_as_garbage (solver, c);
assert (c->garbage);
break;
}
}
if (c->garbage)
continue;
if (subsume < 2)
continue;
const unsigned ref = kissat_reference_clause (solver, c);
PUSH_STACK (*candidates, ref);
}
}
static inline unsigned
get_size_of_reference (kissat *solver, ward *const arena, reference ref) {
assert (ref < SIZE_STACK (solver->arena));
const clause *const c = (clause *) (arena + ref);
(void) solver;
return c->size;
}
#define GET_SIZE_OF_REFERENCE(REF) \
get_size_of_reference (solver, arena, (REF))
static void sort_forward_subsumption_candidates (kissat *solver,
references *candidates) {
reference *references = BEGIN_STACK (*candidates);
size_t size = SIZE_STACK (*candidates);
ward *const arena = BEGIN_STACK (solver->arena);
RADIX_SORT (reference, unsigned, size, references, GET_SIZE_OF_REFERENCE);
}
static inline bool forward_literal (kissat *solver, unsigned lit,
bool binaries, unsigned *remove,
unsigned limit) {
watches *watches = &WATCHES (lit);
const size_t size_watches = SIZE_WATCHES (*watches);
if (!size_watches)
return false;
if (size_watches > limit)
return false;
watch *begin = BEGIN_WATCHES (*watches), *q = begin;
const watch *const end = END_WATCHES (*watches), *p = q;
uint64_t steps = 1 + kissat_cache_lines (size_watches, sizeof (watch));
uint64_t checks = 0;
const value *const values = solver->values;
const value *const marks = solver->marks;
ward *const arena = BEGIN_STACK (solver->arena);
bool subsume = false;
while (p != end) {
const watch watch = *q++ = *p++;
if (watch.type.binary) {
if (!binaries)
continue;
const unsigned other = watch.binary.lit;
if (marks[other]) {
LOGBINARY (lit, other, "forward subsuming");
subsume = true;
break;
} else {
const unsigned not_other = NOT (other);
if (marks[not_other]) {
LOGBINARY (lit, other, "forward %s strengthener", LOGLIT (other));
assert (!subsume);
*remove = not_other;
break;
}
}
} else {
const reference ref = watch.large.ref;
assert (ref < SIZE_STACK (solver->arena));
clause *d = (clause *) (arena + ref);
steps++;
if (d->garbage) {
q--;
continue;
}
checks++;
subsume = true;
unsigned candidate = INVALID_LIT;
for (all_literals_in_clause (other, d)) {
if (marks[other])
continue;
const value value = values[other];
if (value < 0)
continue;
if (value > 0) {
LOGCLS (d, "satisfied by %s", LOGLIT (other));
kissat_mark_clause_as_garbage (solver, d);
assert (d->garbage);
candidate = INVALID_LIT;
subsume = false;
break;
}
if (!subsume) {
assert (candidate != INVALID_LIT);
candidate = INVALID_LIT;
break;
}
subsume = false;
const unsigned not_other = NOT (other);
if (!marks[not_other]) {
assert (candidate == INVALID_LIT);
break;
}
candidate = not_other;
}
if (d->garbage) {
assert (!subsume);
q--;
break;
}
if (subsume) {
LOGCLS (d, "forward subsuming");
assert (subsume);
break;
}
if (candidate != INVALID_LIT) {
LOGCLS (d, "forward %s strengthener", LOGLIT (candidate));
*remove = candidate;
}
}
}
if (p != q) {
while (p != end)
*q++ = *p++;
SET_END_OF_WATCHES (*watches, q);
}
ADD (subsumption_checks, checks);
ADD (forward_checks, checks);
ADD (forward_steps, steps);
return subsume;
}
static inline bool forward_marked_clause (kissat *solver, clause *c,
unsigned *remove) {
const unsigned limit = GET_OPTION (subsumeocclim);
const flags *const flags = solver->flags;
INC (forward_steps);
for (all_literals_in_clause (lit, c)) {
const unsigned idx = IDX (lit);
if (!flags[idx].active)
continue;
assert (!VALUE (lit));
if (forward_literal (solver, lit, true, remove, limit))
return true;
if (forward_literal (solver, NOT (lit), false, remove, limit))
return true;
}
return false;
}
static bool forward_subsumed_clause (kissat *solver, clause *c,
bool *strengthened,
unsigneds *new_binaries) {
assert (!c->garbage);
LOGCLS2 (c, "trying to forward subsume");
value *marks = solver->marks;
const value *const values = solver->values;
unsigned non_false = 0, unit = INVALID_LIT;
for (all_literals_in_clause (lit, c)) {
const value value = values[lit];
if (value < 0)
continue;
if (value > 0) {
LOGCLS (c, "satisfied by %s", LOGLIT (lit));
kissat_mark_clause_as_garbage (solver, c);
assert (c->garbage);
break;
}
marks[lit] = 1;
if (non_false++)
unit ^= lit;
else
unit = lit;
}
if (c->garbage || non_false <= 1)
for (all_literals_in_clause (lit, c))
marks[lit] = 0;
if (c->garbage)
return false;
if (!non_false) {
LOGCLS (c, "found falsified clause");
CHECK_AND_ADD_EMPTY ();
ADD_EMPTY_TO_PROOF ();
solver->inconsistent = true;
return false;
}
if (non_false == 1) {
assert (VALID_INTERNAL_LITERAL (unit));
LOG ("new remaining non-false literal unit clause %s", LOGLIT (unit));
kissat_learned_unit (solver, unit);
kissat_mark_clause_as_garbage (solver, c);
kissat_flush_units_while_connected (solver);
return false;
}
unsigned remove = INVALID_LIT;
const bool subsume = forward_marked_clause (solver, c, &remove);
for (all_literals_in_clause (lit, c))
marks[lit] = 0;
if (subsume) {
LOGCLS (c, "forward subsumed");
kissat_mark_clause_as_garbage (solver, c);
INC (subsumed);
INC (forward_subsumed);
} else if (remove != INVALID_LIT) {
*strengthened = true;
INC (strengthened);
INC (forward_strengthened);
LOGCLS (c, "forward strengthening by removing %s in", LOGLIT (remove));
if (non_false == 2) {
unit ^= remove;
assert (VALID_INTERNAL_LITERAL (unit));
LOG ("forward strengthened unit clause %s", LOGLIT (unit));
kissat_learned_unit (solver, unit);
kissat_mark_clause_as_garbage (solver, c);
kissat_flush_units_while_connected (solver);
LOGCLS (c, "%s satisfied", LOGLIT (unit));
} else {
SHRINK_CLAUSE_IN_PROOF (c, remove, INVALID_LIT);
CHECK_SHRINK_CLAUSE (c, remove, INVALID_LIT);
kissat_mark_removed_literal (solver, remove);
if (non_false > 3) {
unsigned *lits = c->lits;
unsigned new_size = 0;
for (unsigned i = 0; i < c->size; i++) {
const unsigned lit = lits[i];
if (remove == lit)
continue;
const value value = values[lit];
if (value < 0)
continue;
assert (!value);
lits[new_size++] = lit;
kissat_mark_added_literal (solver, lit);
}
assert (new_size == non_false - 1);
assert (new_size > 2);
if (!c->shrunken) {
c->shrunken = true;
lits[c->size - 1] = INVALID_LIT;
}
c->size = new_size;
c->searched = 2;
c->subsume = true;
LOGCLS (c, "forward strengthened");
} else {
assert (non_false == 3);
LOGCLS (c, "garbage");
assert (!c->garbage);
const size_t bytes = kissat_actual_bytes_of_clause (c);
ADD (arena_garbage, bytes);
c->garbage = true;
unsigned first = INVALID_LIT, second = INVALID_LIT;
for (all_literals_in_clause (lit, c)) {
if (lit == remove)
continue;
const value value = values[lit];
if (value < 0)
continue;
assert (!value);
if (first == INVALID_LIT)
first = lit;
else {
assert (second == INVALID_LIT);
second = lit;
}
kissat_mark_added_literal (solver, lit);
}
assert (first != INVALID_LIT);
assert (second != INVALID_LIT);
LOGBINARY (first, second, "forward strengthened");
kissat_watch_other (solver, first, second);
kissat_watch_other (solver, second, first);
assert (new_binaries);
assert (solver->statistics.clauses_irredundant);
solver->statistics.clauses_irredundant--;
assert (solver->statistics.clauses_binary < UINT64_MAX);
solver->statistics.clauses_binary++;
PUSH_STACK (*new_binaries, first);
PUSH_STACK (*new_binaries, second);
}
}
}
return subsume;
}
static void connect_subsuming (kissat *solver, unsigned occlim, clause *c) {
assert (!c->garbage);
unsigned min_lit = INVALID_LIT;
size_t min_occs = MAX_SIZE_T;
const flags *const all_flags = solver->flags;
bool subsume = true;
for (all_literals_in_clause (lit, c)) {
const unsigned idx = IDX (lit);
const flags *const flags = all_flags + idx;
if (!flags->active)
continue;
if (!flags->subsume) {
subsume = false;
break;
}
watches *watches = &WATCHES (lit);
const size_t occs = SIZE_WATCHES (*watches);
if (min_lit != INVALID_LIT && occs > min_occs)
continue;
min_lit = lit;
min_occs = occs;
}
if (!subsume)
return;
if (min_occs > occlim)
return;
LOG ("connecting %s with %zu occurrences", LOGLIT (min_lit), min_occs);
const reference ref = kissat_reference_clause (solver, c);
kissat_connect_literal (solver, min_lit, ref);
}
static bool forward_subsume_all_clauses (kissat *solver) {
references candidates;
INIT_STACK (candidates);
find_forward_subsumption_candidates (solver, &candidates);
#ifndef QUIET
size_t scheduled = SIZE_STACK (candidates);
kissat_phase (
solver, "forward", GET (forward_subsumptions),
"scheduled %zu irredundant clauses %.0f%%", scheduled,
kissat_percent (scheduled, solver->statistics.clauses_irredundant));
#endif
sort_forward_subsumption_candidates (solver, &candidates);
const reference *const end_of_candidates = END_STACK (candidates);
reference *p = BEGIN_STACK (candidates);
#ifndef QUIET
size_t subsumed = 0;
size_t strengthened = 0;
size_t checked = 0;
#endif
const unsigned occlim = GET_OPTION (subsumeocclim);
unsigneds new_binaries;
INIT_STACK (new_binaries);
{
SET_EFFORT_LIMIT (steps_limit, forward, forward_steps);
ward *arena = BEGIN_STACK (solver->arena);
while (p != end_of_candidates) {
if (solver->statistics.forward_steps > steps_limit)
break;
if (TERMINATED (forward_terminated_1))
break;
reference ref = *p++;
clause *c = (clause *) (arena + ref);
assert (kissat_clause_in_arena (solver, c));
assert (!c->garbage);
#ifndef QUIET
checked++;
#endif
bool not_subsumed_but_strengthened = false;
if (forward_subsumed_clause (
solver, c, &not_subsumed_but_strengthened, &new_binaries)) {
#ifndef QUIET
subsumed++;
#endif
} else if (not_subsumed_but_strengthened) {
#ifndef QUIET
strengthened++;
#endif
}
if (solver->inconsistent)
break;
if (!c->garbage)
connect_subsuming (solver, occlim, c);
}
}
#ifndef QUIET
if (subsumed)
kissat_phase (solver, "forward", GET (forward_subsumptions),
"subsumed %zu clauses %.2f%% of %zu checked %.0f%%",
subsumed, kissat_percent (subsumed, checked), checked,
kissat_percent (checked, scheduled));
if (strengthened)
kissat_phase (solver, "forward", GET (forward_subsumptions),
"strengthened %zu clauses %.2f%% of %zu checked %.0f%%",
strengthened, kissat_percent (strengthened, checked),
checked, kissat_percent (checked, scheduled));
if (!subsumed && !strengthened)
kissat_phase (solver, "forward", GET (forward_subsumptions),
"no clause subsumed nor strengthened "
"out of %zu checked %.0f%%",
checked, kissat_percent (checked, scheduled));
#endif
struct flags *flags = solver->flags;
for (all_variables (idx))
flags[idx].subsume = false;
ward *arena = BEGIN_STACK (solver->arena);
unsigned reactivated = 0;
#ifndef QUIET
size_t remain = 0;
#endif
for (reference *q = BEGIN_STACK (candidates); q != end_of_candidates;
q++) {
const reference ref = *q;
clause *c = (clause *) (arena + ref);
assert (kissat_clause_in_arena (solver, c));
if (c->garbage)
continue;
if (q < p && !c->subsume)
continue;
#ifndef QUIET
remain++;
#endif
for (all_literals_in_clause (lit, c)) {
const unsigned idx = IDX (lit);
struct flags *f = flags + idx;
if (f->subsume)
continue;
LOGCLS (c,
"reactivating subsume flag of %s "
"in remaining or strengthened",
LOGVAR (idx));
f->subsume = true;
assert (reactivated < UINT_MAX);
reactivated++;
}
}
while (!EMPTY_STACK (new_binaries)) {
unsigned lits[2];
lits[1] = POP_STACK (new_binaries);
lits[0] = POP_STACK (new_binaries);
for (unsigned i = 0; i < 2; i++) {
const unsigned lit = lits[i];
const unsigned idx = IDX (lit);
struct flags *f = flags + idx;
if (f->subsume)
continue;
LOGBINARY (lits[0], lits[1],
"reactivating subsume flag of %s "
"in strengthened binary clause",
LOGVAR (idx));
f->subsume = true;
assert (reactivated < UINT_MAX);
reactivated++;
}
}
RELEASE_STACK (new_binaries);
kissat_very_verbose (solver,
"marked %u variables %.0f%% to be reconsidered "
"in next forward subsumption",
reactivated,
kissat_percent (reactivated, solver->active));
#ifndef QUIET
if (remain)
kissat_phase (solver, "forward", GET (forward_subsumptions),
"%zu unchecked clauses remain %.0f%%", remain,
kissat_percent (remain, scheduled));
else
kissat_phase (solver, "forward", GET (forward_subsumptions),
"all %zu scheduled clauses checked", scheduled);
#endif
RELEASE_STACK (candidates);
REPORT (!subsumed, 's');
bool completed;
if (solver->inconsistent)
completed = true;
else if (reactivated)
completed = false;
else
completed = true;
#ifndef QUIET
kissat_very_verbose (solver, "forward subsumption considered %scomplete",
completed ? "" : "in");
#endif
return completed;
}
bool kissat_forward_subsume_during_elimination (kissat *solver) {
START (subsume);
START (forward);
assert (GET_OPTION (forward));
INC (forward_subsumptions);
assert (!solver->watching);
remove_all_duplicated_binary_clauses (solver);
bool complete = true;
if (!solver->inconsistent)
complete = forward_subsume_all_clauses (solver);
STOP (forward);
STOP (subsume);
return complete;
}

10
src/sat/kissat/forward.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef _forward_h_INCLUDED
#define _forward_h_INCLUDED
#include <stdbool.h>
struct kissat;
bool kissat_forward_subsume_during_elimination (struct kissat *);
#endif

32
src/sat/kissat/frames.h Normal file
View File

@ -0,0 +1,32 @@
#ifndef _frames_h_INCLUDED
#define _frames_h_INCLUDED
#include "literal.h"
#include "stack.h"
#include <stdbool.h>
typedef struct frame frame;
typedef struct slice slice;
struct frame {
bool promote;
unsigned decision;
unsigned trail;
unsigned used;
#ifndef NDEBUG
unsigned saved;
#endif
};
// clang-format off
typedef STACK (frame) frames;
// clang-format on
struct kissat;
#define FRAME(LEVEL) (PEEK_STACK (solver->frames, (LEVEL)))
#endif

104
src/sat/kissat/gates.c Normal file
View File

@ -0,0 +1,104 @@
#include "gates.h"
#include "ands.h"
#include "definition.h"
#include "eliminate.h"
#include "equivalences.h"
#include "ifthenelse.h"
#include "inline.h"
size_t kissat_mark_binaries (kissat *solver, unsigned lit) {
value *marks = solver->marks;
size_t res = 0;
watches *watches = &WATCHES (lit);
for (all_binary_large_watches (watch, *watches)) {
if (!watch.type.binary)
continue;
const unsigned other = watch.binary.lit;
assert (!solver->values[other]);
if (marks[other])
continue;
marks[other] = 1;
res++;
}
return res;
}
void kissat_unmark_binaries (kissat *solver, unsigned lit) {
value *marks = solver->marks;
watches *watches = &WATCHES (lit);
for (all_binary_large_watches (watch, *watches))
if (watch.type.binary)
marks[watch.binary.lit] = 0;
}
bool kissat_find_gates (kissat *solver, unsigned lit) {
solver->gate_eliminated = 0;
solver->resolve_gate = false;
if (!GET_OPTION (extract))
return false;
INC (gates_checked);
const unsigned not_lit = NOT (lit);
if (EMPTY_WATCHES (WATCHES (not_lit)))
return false;
bool res = false;
if (kissat_find_equivalence_gate (solver, lit))
res = true;
else if (kissat_find_and_gate (solver, lit, 0))
res = true;
else if (kissat_find_and_gate (solver, not_lit, 1))
res = true;
else if (kissat_find_if_then_else_gate (solver, lit, 0))
res = true;
else if (kissat_find_if_then_else_gate (solver, not_lit, 1))
res = true;
else if (kissat_find_definition (solver, lit))
res = true;
if (res)
INC (gates_extracted);
return res;
}
static void get_antecedents (kissat *solver, unsigned lit,
unsigned negative) {
assert (!solver->watching);
assert (!negative || negative == 1);
statches *gates = solver->gates + negative;
watches *watches = &WATCHES (lit);
statches *antecedents = solver->antecedents + negative;
assert (EMPTY_STACK (*antecedents));
const watch *const begin_gates = BEGIN_STACK (*gates);
const watch *const end_gates = END_STACK (*gates);
watch const *g = begin_gates;
const watch *const begin_watches = BEGIN_WATCHES (*watches);
const watch *const end_watches = END_WATCHES (*watches);
watch const *w = begin_watches;
while (w != end_watches) {
const watch watch = *w++;
if (g != end_gates && g->raw == watch.raw)
g++;
else
PUSH_STACK (*antecedents, watch);
}
assert (g == end_gates);
#ifdef LOGGING
size_t size_gates = SIZE_STACK (*gates);
size_t size_antecedents = SIZE_STACK (*antecedents);
size_t size_watches = SIZE_WATCHES (*watches);
LOG ("got %zu antecedent %.0f%% and %zu gate clauses %.0f%% "
"out of %zu watches of literal %s",
size_antecedents, kissat_percent (size_antecedents, size_watches),
size_gates, kissat_percent (size_gates, size_watches), size_watches,
LOGLIT (lit));
#endif
}
void kissat_get_antecedents (kissat *solver, unsigned lit) {
get_antecedents (solver, lit, 0);
get_antecedents (solver, NOT (lit), 1);
}

22
src/sat/kissat/gates.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef _gates_h_INCLUDED
#define _gates_h_INCLUDED
#include <stdbool.h>
#include <stdlib.h>
struct kissat;
struct clause;
bool kissat_find_gates (struct kissat *, unsigned lit);
void kissat_get_antecedents (struct kissat *, unsigned lit);
size_t kissat_mark_binaries (struct kissat *, unsigned lit);
void kissat_unmark_binaries (struct kissat *, unsigned lit);
#ifndef METRICS
#define GATE_ELIMINATED(...) true
#else
#define GATE_ELIMINATED(NAME) (&solver->statistics.NAME##_eliminated)
#endif
#endif

43
src/sat/kissat/handle.h Normal file
View File

@ -0,0 +1,43 @@
#ifndef _handle_h_INCLUDED
#define _handle_h_INCLUDED
#include <signal.h>
void kissat_init_signal_handler (void (*handler) (int));
void kissat_reset_signal_handler (void);
void kissat_init_alarm (void (*handler) (void));
void kissat_reset_alarm (void);
#ifdef __MINGW32__
#define SIGNAL_SIGBUS
#else
#define SIGNAL_SIGBUS SIGNAL (SIGBUS)
#endif
#define SIGNALS \
SIGNAL (SIGABRT) \
SIGNAL_SIGBUS \
SIGNAL (SIGINT) \
SIGNAL (SIGSEGV) \
SIGNAL (SIGTERM)
// clang-format off
static inline const char *
kissat_signal_name (int sig)
{
#define SIGNAL(SIG) \
if (sig == SIG) return #SIG;
SIGNALS
#undef SIGNAL
#ifndef __MINGW32__
if (sig == SIGALRM)
return "SIGALRM";
#endif
return "SIGUNKNOWN";
}
// clang-format on
#endif

108
src/sat/kissat/heap.c Normal file
View File

@ -0,0 +1,108 @@
#include "allocate.h"
#include "inlineheap.h"
#include "internal.h"
#include "logging.h"
#include <string.h>
void kissat_release_heap (kissat *solver, heap *heap) {
RELEASE_STACK (heap->stack);
DEALLOC (heap->pos, heap->size);
DEALLOC (heap->score, heap->size);
memset (heap, 0, sizeof *heap);
}
#ifndef NDEBUG
void kissat_check_heap (heap *heap) {
const unsigned *const stack = BEGIN_STACK (heap->stack);
const unsigned end = SIZE_STACK (heap->stack);
const unsigned *const pos = heap->pos;
const double *const score = heap->score;
for (unsigned i = 0; i < end; i++) {
const unsigned idx = stack[i];
const unsigned idx_pos = pos[idx];
assert (idx_pos == i);
unsigned child_pos = HEAP_CHILD (idx_pos);
unsigned parent_pos = HEAP_PARENT (child_pos);
assert (parent_pos == idx_pos);
if (child_pos < end) {
unsigned child = stack[child_pos];
assert (score[idx] >= score[child]);
if (++child_pos < end) {
parent_pos = HEAP_PARENT (child_pos);
assert (parent_pos == idx_pos);
child = stack[child_pos];
assert (score[idx] >= score[child]);
}
}
}
}
#endif
void kissat_resize_heap (kissat *solver, heap *heap, unsigned new_size) {
const unsigned old_size = heap->size;
if (old_size >= new_size)
return;
LOG ("resizing %s heap from %u to %u",
(heap->tainted ? "tainted" : "untainted"), old_size, new_size);
heap->pos = kissat_nrealloc (solver, heap->pos, old_size, new_size,
sizeof (unsigned));
if (heap->tainted) {
heap->score = kissat_nrealloc (solver, heap->score, old_size, new_size,
sizeof (double));
} else {
if (old_size)
DEALLOC (heap->score, old_size);
heap->score = kissat_calloc (solver, new_size, sizeof (double));
}
heap->size = new_size;
#ifdef CHECK_HEAP
kissat_check_heap (heap);
#endif
}
void kissat_rescale_heap (kissat *solver, heap *heap, double factor) {
LOG ("rescaling scores on heap with factor %g", factor);
double *score = heap->score;
for (unsigned i = 0; i < heap->vars; i++)
score[i] *= factor;
#ifndef NDEBUG
kissat_check_heap (heap);
#endif
#ifndef LOGGING
(void) solver;
#endif
}
void kissat_enlarge_heap (kissat *solver, heap *heap, unsigned new_vars) {
const unsigned old_vars = heap->vars;
assert (old_vars < new_vars);
assert (new_vars <= heap->size);
const size_t delta = new_vars - heap->vars;
memset (heap->pos + old_vars, 0xff, delta * sizeof (unsigned));
heap->vars = new_vars;
if (heap->tainted)
memset (heap->score + old_vars, 0, delta * sizeof (double));
LOG ("enlarged heap from %u to %u", old_vars, new_vars);
#ifndef LOGGING
(void) solver;
#endif
}
#ifndef NDEBUG
static void dump_heap (heap *heap) {
for (unsigned i = 0; i < SIZE_STACK (heap->stack); i++)
printf ("heap.stack[%u] = %u\n", i, PEEK_STACK (heap->stack, i));
for (unsigned i = 0; i < heap->vars; i++)
printf ("heap.pos[%u] = %u\n", i, heap->pos[i]);
for (unsigned i = 0; i < heap->vars; i++)
printf ("heap.score[%u] = %g\n", i, heap->score[i]);
}
void kissat_dump_heap (heap *heap) { dump_heap (heap); }
#endif

85
src/sat/kissat/heap.h Normal file
View File

@ -0,0 +1,85 @@
#ifndef _heap_h_INCLUDED
#define _heap_h_INCLUDED
#include "stack.h"
#include "utilities.h"
#include <assert.h>
#include <limits.h>
#include <stdbool.h>
#define DISCONTAIN UINT_MAX
#define DISCONTAINED(IDX) ((int) (IDX) < 0)
typedef struct heap heap;
struct heap {
bool tainted;
unsigned vars;
unsigned size;
unsigneds stack;
double *score;
unsigned *pos;
};
struct kissat;
void kissat_resize_heap (struct kissat *, heap *, unsigned size);
void kissat_release_heap (struct kissat *, heap *);
static inline bool kissat_heap_contains (heap *heap, unsigned idx) {
return idx < heap->vars && !DISCONTAINED (heap->pos[idx]);
}
static inline unsigned kissat_get_heap_pos (const heap *heap,
unsigned idx) {
return idx < heap->vars ? heap->pos[idx] : DISCONTAIN;
}
static inline double kissat_get_heap_score (const heap *heap,
unsigned idx) {
return idx < heap->vars ? heap->score[idx] : 0.0;
}
static inline bool kissat_empty_heap (heap *heap) {
return EMPTY_STACK (heap->stack);
}
static inline size_t kissat_size_heap (heap *heap) {
return SIZE_STACK (heap->stack);
}
static inline unsigned kissat_max_heap (heap *heap) {
assert (!kissat_empty_heap (heap));
return PEEK_STACK (heap->stack, 0);
}
void kissat_rescale_heap (struct kissat *, heap *heap, double factor);
void kissat_enlarge_heap (struct kissat *, heap *, unsigned new_vars);
static inline double kissat_max_score_on_heap (heap *heap) {
if (!heap->tainted)
return 0;
assert (heap->vars);
const double *const score = heap->score;
const double *const end = score + heap->vars;
double res = score[0];
for (const double *p = score + 1; p != end; p++)
res = MAX (res, *p);
return res;
}
#ifndef NDEBUG
void kissat_dump_heap (heap *);
#endif
#ifndef NDEBUG
void kissat_check_heap (heap *);
#else
#define kissat_check_heap(...) \
do { \
} while (0)
#endif
#endif

174
src/sat/kissat/ifthenelse.c Normal file
View File

@ -0,0 +1,174 @@
#include "ifthenelse.h"
#include "eliminate.h"
#include "gates.h"
#include "inline.h"
static bool get_ternary_clause (kissat *solver, reference ref, unsigned *p,
unsigned *q, unsigned *r) {
clause *clause = kissat_dereference_clause (solver, ref);
if (clause->garbage)
return false;
const value *const values = solver->values;
unsigned a = INVALID_LIT, b = INVALID_LIT, c = INVALID_LIT;
unsigned found = 0;
for (all_literals_in_clause (other, clause)) {
const value value = values[other];
if (value > 0) {
kissat_eliminate_clause (solver, clause, INVALID_LIT);
return false;
}
if (value < 0)
continue;
if (++found == 1)
a = other;
else if (found == 2)
b = other;
else if (found == 3)
c = other;
else
return false;
}
if (found != 3)
return false;
assert (a != INVALID_LIT);
assert (b != INVALID_LIT);
assert (c != INVALID_LIT);
*p = a;
*q = b;
*r = c;
return true;
}
static bool match_ternary_ref (kissat *solver, reference ref, unsigned a,
unsigned b, unsigned c) {
clause *clause = kissat_dereference_clause (solver, ref);
if (clause->garbage)
return false;
const value *const values = solver->values;
unsigned found = 0;
for (all_literals_in_clause (other, clause)) {
const value value = values[other];
if (value > 0) {
kissat_eliminate_clause (solver, clause, INVALID_LIT);
return false;
}
if (value < 0)
continue;
if (a != other && b != other && c != other)
return false;
found++;
}
if (found == 3)
return true;
solver->resolve_gate = true;
return true;
}
static bool match_ternary_watch (kissat *solver, watch watch, unsigned a,
unsigned b, unsigned c) {
if (watch.type.binary) {
const unsigned other = watch.binary.lit;
if (other != b && other != c)
return false;
solver->resolve_gate = true;
return true;
} else {
const reference ref = watch.large.ref;
return match_ternary_ref (solver, ref, a, b, c);
}
}
static inline const watch *find_ternary_clause (kissat *solver,
uint64_t *steps, unsigned a,
unsigned b, unsigned c) {
watches *watches = &WATCHES (a);
const watch *const begin = BEGIN_WATCHES (*watches);
const watch *const end = END_WATCHES (*watches);
for (const watch *p = begin; p != end; p++) {
*steps += 1;
if (match_ternary_watch (solver, *p, a, b, c))
return p;
}
return 0;
}
bool kissat_find_if_then_else_gate (kissat *solver, unsigned lit,
unsigned negative) {
if (!GET_OPTION (ifthenelse))
return false;
watches *watches = &WATCHES (lit);
const watch *const begin = BEGIN_WATCHES (*watches);
const watch *const end = END_WATCHES (*watches);
if (begin == end)
return false;
uint64_t large_clauses = 0;
for (const watch *p = begin; p != end; p++)
if (!p->type.binary)
large_clauses++;
const uint64_t limit = GET_OPTION (eliminateocclim);
if (large_clauses * large_clauses > limit)
return false;
const watch *const last = end - 1;
uint64_t steps = 0;
for (const watch *p1 = begin; steps < limit && p1 != last; p1++) {
watch w1 = *p1;
if (w1.type.binary)
continue;
unsigned a1, b1, c1;
if (!get_ternary_clause (solver, p1->large.ref, &a1, &b1, &c1))
continue;
if (b1 == lit)
SWAP (unsigned, a1, b1);
if (c1 == lit)
SWAP (unsigned, a1, c1);
assert (a1 == lit);
for (const watch *p2 = p1 + 1; steps < limit && p2 != end; p2++) {
watch w2 = *p2;
if (w2.type.binary)
continue;
unsigned a2, b2, c2;
if (!get_ternary_clause (solver, p2->large.ref, &a2, &b2, &c2))
continue;
if (b2 == lit)
SWAP (unsigned, a2, b2);
if (c2 == lit)
SWAP (unsigned, a2, c2);
assert (a2 == lit);
if (STRIP (b1) == STRIP (c2))
SWAP (unsigned, b2, c2);
if (STRIP (c1) == STRIP (c2))
continue;
const unsigned not_b2 = NOT (b2);
if (b1 != not_b2)
continue;
solver->resolve_gate = false;
const unsigned not_lit = NOT (lit);
const unsigned not_c1 = NOT (c1);
const watch *const p3 =
find_ternary_clause (solver, &steps, not_lit, b1, not_c1);
if (!p3)
continue;
const unsigned not_c2 = NOT (c2);
const watch *const p4 =
find_ternary_clause (solver, &steps, not_lit, b2, not_c2);
if (!p4)
continue;
watch w3 = p3 < p4 ? *p3 : *p4;
watch w4 = p3 < p4 ? *p4 : *p3;
LOGWATCH (lit, w1, "1st if-then-else");
LOGWATCH (lit, w2, "2nd if-then-else");
LOGWATCH (not_lit, w3, "3rd if-then-else");
LOGWATCH (not_lit, w4, "4th if-then-else");
LOG ("found if-then-else gate %s = (%s ? %s : %s)", LOGLIT (lit),
LOGLIT (NOT (b1)), LOGLIT (not_c1), LOGLIT (not_c2));
solver->gate_eliminated = GATE_ELIMINATED (if_then_else);
PUSH_STACK (solver->gates[negative], w1);
PUSH_STACK (solver->gates[negative], w2);
PUSH_STACK (solver->gates[!negative], w3);
PUSH_STACK (solver->gates[!negative], w4);
INC (if_then_else_extracted);
return true;
}
}
return false;
}

View File

@ -0,0 +1,11 @@
#ifndef _ifthenelse_h_INCLUDED
#define _ifthenelse_h_INCLUDED
#include <stdbool.h>
struct kissat;
bool kissat_find_if_then_else_gate (struct kissat *, unsigned lit,
unsigned negative);
#endif

100
src/sat/kissat/import.c Normal file
View File

@ -0,0 +1,100 @@
#include "internal.h"
#include "logging.h"
#include "resize.h"
static void adjust_imports_for_external_literal (kissat *solver,
unsigned eidx) {
while (eidx >= SIZE_STACK (solver->import)) {
struct import import;
import.lit = 0;
import.extension = false;
import.imported = false;
import.eliminated = false;
PUSH_STACK (solver->import, import);
}
}
static void adjust_exports_for_external_literal (kissat *solver,
unsigned eidx,
bool extension) {
struct import *import = &PEEK_STACK (solver->import, eidx);
unsigned iidx = solver->vars;
kissat_enlarge_variables (solver, iidx + 1);
unsigned ilit = 2 * iidx;
import->extension = extension;
import->imported = true;
if (extension)
INC (variables_extension);
else
INC (variables_original);
assert (!import->eliminated);
import->lit = ilit;
LOG ("importing %s external variable %u as internal literal %u",
extension ? "extension" : "original", eidx, ilit);
while (iidx >= SIZE_STACK (solver->export))
PUSH_STACK (solver->export, 0);
POKE_STACK (solver->export, iidx, (int) eidx);
LOG ("exporting internal variable %u as external literal %u", iidx, eidx);
}
static inline unsigned import_literal (kissat *solver, int elit,
bool extension) {
const unsigned eidx = ABS (elit);
adjust_imports_for_external_literal (solver, eidx);
struct import *import = &PEEK_STACK (solver->import, eidx);
if (import->eliminated)
return INVALID_LIT;
unsigned ilit;
if (!import->imported)
adjust_exports_for_external_literal (solver, eidx, extension);
assert (import->imported);
ilit = import->lit;
if (elit < 0)
ilit = NOT (ilit);
assert (VALID_INTERNAL_LITERAL (ilit));
return ilit;
}
unsigned kissat_import_literal (kissat *solver, int elit) {
assert (VALID_EXTERNAL_LITERAL (elit));
if (GET_OPTION (tumble))
return import_literal (solver, elit, false);
const unsigned eidx = ABS (elit);
assert (SIZE_STACK (solver->import) <= UINT_MAX);
unsigned other = SIZE_STACK (solver->import);
if (eidx < other)
return import_literal (solver, elit, false);
if (!other)
adjust_imports_for_external_literal (solver, other++);
unsigned ilit = 0;
do {
assert (VALID_EXTERNAL_LITERAL ((int) other));
ilit = import_literal (solver, other, false);
} while (other++ < eidx);
if (elit < 0)
ilit = NOT (ilit);
return ilit;
}
unsigned kissat_fresh_literal (kissat *solver) {
size_t imported = SIZE_STACK (solver->import);
assert (imported <= EXTERNAL_MAX_VAR);
if (imported == EXTERNAL_MAX_VAR) {
LOG ("can not get another external variable");
return INVALID_LIT;
}
assert (imported <= (unsigned) INT_MAX);
int eidx = (int) imported;
unsigned res = import_literal (solver, eidx, true);
#ifndef NDEBUG
struct import *import = &PEEK_STACK (solver->import, imported);
assert (import->imported);
assert (import->extension);
#endif
INC (fresh);
kissat_activate_literal (solver, res);
return res;
}

9
src/sat/kissat/import.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef _import_h_INLCUDED
#define _import_h_INLCUDED
struct kissat;
unsigned kissat_import_literal (struct kissat *solver, int lit);
unsigned kissat_fresh_literal (struct kissat *solver);
#endif

328
src/sat/kissat/inline.h Normal file
View File

@ -0,0 +1,328 @@
#ifndef _inline_h_INCLUDED
#define _inline_h_INCLUDED
#include "inlinevector.h"
#include "logging.h"
#ifdef METRICS
static inline size_t kissat_allocated (kissat *solver) {
return solver->statistics.allocated_current;
}
#endif
static inline bool kissat_propagated (kissat *solver) {
assert (BEGIN_ARRAY (solver->trail) <= solver->propagate);
assert (solver->propagate <= END_ARRAY (solver->trail));
return solver->propagate == END_ARRAY (solver->trail);
}
static inline bool kissat_trail_flushed (kissat *solver) {
return !solver->unflushed && EMPTY_ARRAY (solver->trail);
}
static inline void kissat_reset_propagate (kissat *solver) {
solver->propagate = BEGIN_ARRAY (solver->trail);
}
static inline value kissat_fixed (kissat *solver, unsigned lit) {
assert (lit < LITS);
const value res = solver->values[lit];
if (!res)
return 0;
if (LEVEL (lit))
return 0;
return res;
}
static inline void kissat_mark_removed_literal (kissat *solver,
unsigned lit) {
const unsigned idx = IDX (lit);
flags *flags = FLAGS (idx);
if (flags->fixed)
return;
if (!flags->eliminate) {
LOG ("marking %s to be eliminated", LOGVAR (idx));
flags->eliminate = true;
INC (variables_eliminate);
}
}
static inline void kissat_mark_added_literal (kissat *solver,
unsigned lit) {
const unsigned idx = IDX (lit);
flags *flags = FLAGS (idx);
if (!flags->subsume) {
LOG ("marking %s to forward subsume", LOGVAR (idx));
flags->subsume = true;
INC (variables_subsume);
}
const unsigned bit = 1u << NEGATED (lit);
if (!(flags->factor & bit)) {
flags->factor |= bit;
LOG ("marking literal %s to factor", LOGLIT (lit));
INC (literals_factor);
}
}
static inline void
kissat_push_large_watch (kissat *solver, watches *watches, reference ref) {
const watch watch = kissat_large_watch (ref);
PUSH_WATCHES (*watches, watch);
}
static inline void kissat_push_binary_watch (kissat *solver,
watches *watches,
unsigned other) {
const watch watch = kissat_binary_watch (other);
PUSH_WATCHES (*watches, watch);
}
static inline void kissat_push_blocking_watch (kissat *solver,
watches *watches,
unsigned blocking,
reference ref) {
assert (solver->watching);
const watch head = kissat_blocking_watch (blocking);
PUSH_WATCHES (*watches, head);
const watch tail = kissat_large_watch (ref);
PUSH_WATCHES (*watches, tail);
}
static inline void kissat_watch_other (kissat *solver, unsigned lit,
unsigned other) {
LOGBINARY (lit, other, "watching %s blocking %s in", LOGLIT (lit),
LOGLIT (other));
watches *watches = &WATCHES (lit);
kissat_push_binary_watch (solver, watches, other);
}
static inline void kissat_watch_binary (kissat *solver, unsigned a,
unsigned b) {
kissat_watch_other (solver, a, b);
kissat_watch_other (solver, b, a);
}
static inline void kissat_watch_blocking (kissat *solver, unsigned lit,
unsigned blocking,
reference ref) {
assert (solver->watching);
LOGREF3 (ref, "watching %s blocking %s in", LOGLIT (lit),
LOGLIT (blocking));
watches *watches = &WATCHES (lit);
kissat_push_blocking_watch (solver, watches, blocking, ref);
}
static inline void kissat_unwatch_blocking (kissat *solver, unsigned lit,
reference ref) {
assert (solver->watching);
LOGREF3 (ref, "unwatching %s in", LOGLIT (lit));
watches *watches = &WATCHES (lit);
kissat_remove_blocking_watch (solver, watches, ref);
}
static inline void kissat_disconnect_binary (kissat *solver, unsigned lit,
unsigned other) {
assert (!solver->watching);
watches *watches = &WATCHES (lit);
const watch watch = kissat_binary_watch (other);
REMOVE_WATCHES (*watches, watch);
}
static inline void
kissat_disconnect_reference (kissat *solver, unsigned lit, reference ref) {
assert (!solver->watching);
LOGREF3 (ref, "disconnecting %s in", LOGLIT (lit));
const watch watch = kissat_large_watch (ref);
watches *watches = &WATCHES (lit);
REMOVE_WATCHES (*watches, watch);
}
static inline void kissat_watch_reference (kissat *solver, unsigned a,
unsigned b, reference ref) {
assert (solver->watching);
kissat_watch_blocking (solver, a, b, ref);
kissat_watch_blocking (solver, b, a, ref);
}
static inline void kissat_connect_literal (kissat *solver, unsigned lit,
reference ref) {
assert (!solver->watching);
LOGREF3 (ref, "connecting %s in", LOGLIT (lit));
watches *watches = &WATCHES (lit);
kissat_push_large_watch (solver, watches, ref);
}
static inline clause *kissat_unchecked_dereference_clause (kissat *solver,
reference ref) {
return (clause *) &PEEK_STACK (solver->arena, ref);
}
static inline clause *kissat_dereference_clause (kissat *solver,
reference ref) {
clause *res = kissat_unchecked_dereference_clause (solver, ref);
assert (kissat_clause_in_arena (solver, res));
return res;
}
static inline reference kissat_reference_clause (kissat *solver,
const clause *c) {
assert (kissat_clause_in_arena (solver, c));
return (ward *) c - BEGIN_STACK (solver->arena);
}
static inline void kissat_inlined_connect_clause (kissat *solver,
watches *all_watches,
clause *c,
reference ref) {
assert (!solver->watching);
assert (ref == kissat_reference_clause (solver, c));
assert (c == kissat_dereference_clause (solver, ref));
for (all_literals_in_clause (lit, c)) {
assert (!solver->watching);
LOGREF3 (ref, "connecting %s in", LOGLIT (lit));
assert (lit < LITS);
watches *lit_watches = all_watches + lit;
kissat_push_large_watch (solver, lit_watches, ref);
}
}
static inline void kissat_watch_clause (kissat *solver, clause *c) {
assert (c->searched < c->size);
const reference ref = kissat_reference_clause (solver, c);
kissat_watch_reference (solver, c->lits[0], c->lits[1], ref);
}
static inline int kissat_export_literal (kissat *solver, unsigned ilit) {
const unsigned iidx = IDX (ilit);
assert (iidx < (unsigned) INT_MAX);
int elit = PEEK_STACK (solver->export, iidx);
if (!elit)
return 0;
if (NEGATED (ilit))
elit = -elit;
assert (VALID_EXTERNAL_LITERAL (elit));
return elit;
}
static inline unsigned kissat_map_literal (kissat *solver, unsigned ilit,
bool map) {
if (!map)
return ilit;
int elit = kissat_export_literal (solver, ilit);
if (!elit)
return INVALID_LIT;
const unsigned eidx = ABS (elit);
const import *const import = &PEEK_STACK (solver->import, eidx);
if (import->eliminated)
return INVALID_LIT;
unsigned mlit = import->lit;
if (elit < 0)
mlit = NOT (mlit);
return mlit;
}
static inline clause *kissat_last_irredundant_clause (kissat *solver) {
return (solver->last_irredundant == INVALID_REF)
? 0
: kissat_dereference_clause (solver, solver->last_irredundant);
}
static inline clause *kissat_binary_conflict (kissat *solver, unsigned a,
unsigned b) {
LOGBINARY (a, b, "conflicting");
clause *res = &solver->conflict;
res->size = 2;
unsigned *lits = res->lits;
lits[0] = a;
lits[1] = b;
return res;
}
static inline void kissat_push_analyzed (kissat *solver, assigned *assigned,
unsigned idx) {
assert (idx < VARS);
struct assigned *a = assigned + idx;
assert (!a->analyzed);
a->analyzed = true;
PUSH_STACK (solver->analyzed, idx);
LOG2 ("%s analyzed", LOGVAR (idx));
}
static inline bool kissat_analyzed (kissat *solver) {
return !EMPTY_STACK (solver->analyzed);
}
static inline void
kissat_push_removable (kissat *solver, assigned *assigned, unsigned idx) {
assert (idx < VARS);
struct assigned *a = assigned + idx;
assert (!a->removable);
a->removable = true;
PUSH_STACK (solver->removable, idx);
LOG2 ("%s removable", LOGVAR (idx));
}
static inline void kissat_push_poisoned (kissat *solver, assigned *assigned,
unsigned idx) {
assert (idx < VARS);
struct assigned *a = assigned + idx;
assert (!a->poisoned);
a->poisoned = true;
PUSH_STACK (solver->poisoned, idx);
LOG2 ("%s poisoned", LOGVAR (idx));
}
static inline void
kissat_push_shrinkable (kissat *solver, assigned *assigned, unsigned idx) {
assert (idx < VARS);
struct assigned *a = assigned + idx;
assert (!a->shrinkable);
a->shrinkable = true;
PUSH_STACK (solver->shrinkable, idx);
LOG2 ("%s shrinkable", LOGVAR (idx));
}
static inline int kissat_checking (kissat *solver) {
#ifndef NDEBUG
#ifdef NOPTIONS
(void) solver;
#endif
return GET_OPTION (check);
#else
(void) solver;
return 0;
#endif
}
static inline bool kissat_logging (kissat *solver) {
#ifdef LOGGING
#ifdef NOPTIONS
(void) solver;
#endif
return GET_OPTION (log) > 0;
#else
(void) solver;
return false;
#endif
}
static inline bool kissat_proving (kissat *solver) {
#ifdef NPROOFS
(void) solver;
return false;
#else
return solver->proof != 0;
#endif
}
static inline bool kissat_checking_or_proving (kissat *solver) {
return kissat_checking (solver) || kissat_proving (solver);
}
#if !defined(NDEBUG) || !defined(NPROOFS)
#define CHECKING_OR_PROVING
#endif
#endif

View File

@ -0,0 +1,100 @@
#ifndef _inlineassign_h_INLCUDED
#define _inlineassign_h_INLCUDED
#ifdef FAST_ASSIGN
#define kissat_assign kissat_fast_assign
#endif
static inline void kissat_assign (kissat *solver, const bool probing,
const unsigned level,
#ifdef FAST_ASSIGN
value *values, assigned *assigned,
#endif
bool binary, unsigned lit,
unsigned reason) {
const unsigned not_lit = NOT (lit);
watches watches = WATCHES (not_lit);
if (!kissat_empty_vector (&watches)) {
watch *w = BEGIN_WATCHES (watches);
__builtin_prefetch (w, 0, 1);
}
#ifndef FAST_ASSIGN
value *values = solver->values;
#endif
assert (!values[lit]);
assert (!values[not_lit]);
values[lit] = 1;
values[not_lit] = -1;
assert (solver->unassigned > 0);
solver->unassigned--;
if (!level) {
kissat_mark_fixed_literal (solver, lit);
assert (solver->unflushed < UINT_MAX);
solver->unflushed++;
if (reason != UNIT_REASON) {
CHECK_AND_ADD_UNIT (lit);
ADD_UNIT_TO_PROOF (lit);
reason = UNIT_REASON;
binary = false;
}
}
const size_t trail = SIZE_ARRAY (solver->trail);
PUSH_ARRAY (solver->trail, lit);
const unsigned idx = IDX (lit);
#if !defined(PROBING_PROPAGATION)
if (!probing) {
const bool negated = NEGATED (lit);
const value new_value = BOOL_TO_VALUE (negated);
value *saved = &SAVED (idx);
*saved = new_value;
}
#endif
struct assigned b;
b.level = level;
b.trail = trail;
b.analyzed = false;
b.binary = binary;
b.poisoned = false;
b.reason = reason;
b.removable = false;
b.shrinkable = false;
#ifndef FAST_ASSIGN
assigned *assigned = solver->assigned;
#endif
struct assigned *a = assigned + idx;
*a = b;
}
static inline unsigned
kissat_assignment_level (kissat *solver, value *values, assigned *assigned,
unsigned lit, clause *reason) {
unsigned res = 0;
for (all_literals_in_clause (other, reason)) {
if (other == lit)
continue;
assert (values[other] < 0), (void) values;
const unsigned other_idx = IDX (other);
struct assigned *a = assigned + other_idx;
const unsigned level = a->level;
if (res < level)
res = level;
}
#ifdef NDEBUG
(void) solver;
#endif
return res;
}
#endif

View File

@ -0,0 +1,18 @@
#ifndef _inlineframes_h_INCLUDEDd
#define _inlineframes_h_INCLUDEDd
#include "allocate.h"
#include "internal.h"
static inline void kissat_push_frame (kissat *solver, unsigned decision) {
assert (!solver->level || decision != UINT_MAX);
const size_t trail = SIZE_ARRAY (solver->trail);
frame frame;
frame.decision = decision;
frame.promote = false;
frame.trail = trail;
frame.used = 0;
PUSH_STACK (solver->frames, frame);
}
#endif

176
src/sat/kissat/inlineheap.h Normal file
View File

@ -0,0 +1,176 @@
#ifndef _inlineheap_h_INCLUDED
#define _inlineheap_h_INCLUDED
#include "allocate.h"
#include "internal.h"
#include "logging.h"
#define HEAP_CHILD(POS) (assert ((POS) < (1u << 31)), (2 * (POS) + 1))
#define HEAP_PARENT(POS) (assert ((POS) > 0), (((POS) - 1) / 2))
static inline void kissat_bubble_up (kissat *solver, heap *heap,
unsigned idx) {
unsigned *stack = BEGIN_STACK (heap->stack);
unsigned *pos = heap->pos;
unsigned idx_pos = pos[idx];
const double *const score = heap->score;
const double idx_score = score[idx];
while (idx_pos) {
const unsigned parent_pos = HEAP_PARENT (idx_pos);
const unsigned parent = stack[parent_pos];
if (score[parent] >= idx_score)
break;
LOG ("heap bubble up: %u@%u = %g swapped with %u@%u = %g", parent,
parent_pos, score[parent], idx, idx_pos, idx_score);
stack[idx_pos] = parent;
pos[parent] = idx_pos;
idx_pos = parent_pos;
}
stack[idx_pos] = idx;
pos[idx] = idx_pos;
#ifndef LOGGING
(void) solver;
#endif
}
static inline void kissat_bubble_down (kissat *solver, heap *heap,
unsigned idx) {
unsigned *stack = BEGIN_STACK (heap->stack);
const unsigned end = SIZE_STACK (heap->stack);
unsigned *pos = heap->pos;
unsigned idx_pos = pos[idx];
const double *const score = heap->score;
const double idx_score = score[idx];
for (;;) {
unsigned child_pos = HEAP_CHILD (idx_pos);
if (child_pos >= end)
break;
unsigned child = stack[child_pos];
double child_score = score[child];
const unsigned sibling_pos = child_pos + 1;
if (sibling_pos < end) {
const unsigned sibling = stack[sibling_pos];
const double sibling_score = score[sibling];
if (sibling_score > child_score) {
child = sibling;
child_pos = sibling_pos;
child_score = sibling_score;
}
}
if (child_score <= idx_score)
break;
LOG ("heap bubble down: %u@%u = %g swapped with %u@%u = %g", child,
child_pos, score[child], idx, idx_pos, idx_score);
stack[idx_pos] = child;
pos[child] = idx_pos;
idx_pos = child_pos;
}
stack[idx_pos] = idx;
pos[idx] = idx_pos;
#ifndef LOGGING
(void) solver;
#endif
}
#define HEAP_IMPORT(IDX) \
do { \
assert ((IDX) < UINT_MAX - 1); \
if (heap->vars <= (IDX)) \
kissat_enlarge_heap (solver, heap, (IDX) + 1); \
} while (0)
#define CHECK_HEAP_IMPORTED(IDX)
static inline void kissat_push_heap (kissat *solver, heap *heap,
unsigned idx) {
LOG ("push heap %u", idx);
assert (!kissat_heap_contains (heap, idx));
HEAP_IMPORT (idx);
heap->pos[idx] = SIZE_STACK (heap->stack);
PUSH_STACK (heap->stack, idx);
kissat_bubble_up (solver, heap, idx);
}
static inline void kissat_pop_heap (kissat *solver, heap *heap,
unsigned idx) {
LOG ("pop heap %u", idx);
assert (kissat_heap_contains (heap, idx));
const unsigned last = POP_STACK (heap->stack);
heap->pos[last] = DISCONTAIN;
if (last == idx)
return;
const unsigned idx_pos = heap->pos[idx];
heap->pos[idx] = DISCONTAIN;
POKE_STACK (heap->stack, idx_pos, last);
heap->pos[last] = idx_pos;
kissat_bubble_up (solver, heap, last);
kissat_bubble_down (solver, heap, last);
#ifdef CHECK_HEAP
kissat_check_heap (heap);
#endif
}
static inline unsigned kissat_pop_max_heap (kissat *solver, heap *heap) {
assert (!EMPTY_STACK (heap->stack));
unsigneds *stack = &heap->stack;
unsigned *const begin = BEGIN_STACK (*stack);
const unsigned idx = *begin;
assert (!heap->pos[idx]);
LOG ("pop max heap %u", idx);
const unsigned last = POP_STACK (*stack);
unsigned *const pos = heap->pos;
pos[last] = DISCONTAIN;
if (last == idx)
return idx;
pos[idx] = DISCONTAIN;
*begin = last;
pos[last] = 0;
kissat_bubble_down (solver, heap, last);
#ifdef CHECK_HEAP
kissat_check_heap (heap);
#endif
return idx;
}
static inline void kissat_adjust_heap (kissat *solver, heap *heap,
unsigned idx) {
const unsigned new_vars = idx + 1;
const unsigned old_vars = heap->vars;
if (new_vars <= old_vars)
return;
const unsigned old_size = heap->size;
if (idx >= old_size) {
size_t new_size = old_size ? 2 * old_size : 1;
while (idx >= new_size)
new_size *= 2;
assert (new_size < DISCONTAIN);
kissat_resize_heap (solver, heap, new_size);
}
kissat_enlarge_heap (solver, heap, idx + 1);
}
static inline void kissat_update_heap (kissat *solver, heap *heap,
unsigned idx, double new_score) {
const double old_score = kissat_get_heap_score (heap, idx);
if (old_score == new_score)
return;
HEAP_IMPORT (idx);
LOG ("update heap %u score from %g to %g", idx, old_score, new_score);
heap->score[idx] = new_score;
if (!heap->tainted) {
heap->tainted = true;
LOG ("tainted heap");
}
if (!kissat_heap_contains (heap, idx))
return;
if (new_score > old_score)
kissat_bubble_up (solver, heap, idx);
else
kissat_bubble_down (solver, heap, idx);
#ifdef CHECK_HEAP
kissat_check_heap (heap);
#endif
}
#endif

View File

@ -0,0 +1,117 @@
#ifndef _inlinequeue_h_INCLUDED
#define _inlinequeue_h_INCLUDED
#include "internal.h"
#include "logging.h"
static inline void kissat_update_queue (kissat *solver, const links *links,
unsigned idx) {
assert (!DISCONNECTED (idx));
const unsigned stamp = links[idx].stamp;
LOG ("queue updated to %s stamped %u", LOGVAR (idx), stamp);
solver->queue.search.idx = idx;
solver->queue.search.stamp = stamp;
}
static inline void kissat_enqueue_links (kissat *solver, unsigned i,
links *links, queue *queue) {
struct links *p = links + i;
assert (DISCONNECTED (p->prev));
assert (DISCONNECTED (p->next));
const unsigned j = p->prev = queue->last;
queue->last = i;
if (DISCONNECTED (j))
queue->first = i;
else {
struct links *l = links + j;
assert (DISCONNECTED (l->next));
l->next = i;
}
if (queue->stamp == UINT_MAX) {
kissat_reassign_queue_stamps (solver);
assert (p->stamp == queue->stamp);
} else
p->stamp = ++queue->stamp;
}
static inline void kissat_dequeue_links (unsigned i, links *links,
queue *queue) {
struct links *l = links + i;
const unsigned j = l->prev, k = l->next;
l->prev = l->next = DISCONNECT;
if (DISCONNECTED (j)) {
assert (queue->first == i);
queue->first = k;
} else {
struct links *p = links + j;
assert (p->next == i);
p->next = k;
}
if (DISCONNECTED (k)) {
assert (queue->last == i);
queue->last = j;
} else {
struct links *n = links + k;
assert (n->prev == i);
n->prev = j;
}
}
static inline void kissat_enqueue (kissat *solver, unsigned idx) {
assert (idx < solver->vars);
links *links = solver->links, *l = links + idx;
l->prev = l->next = DISCONNECT;
kissat_enqueue_links (solver, idx, links, &solver->queue);
LOG ("enqueued %s stamped %u", LOGVAR (idx), l->stamp);
if (!VALUE (LIT (idx)))
kissat_update_queue (solver, links, idx);
kissat_check_queue (solver);
}
static inline void kissat_dequeue (kissat *solver, unsigned idx) {
assert (idx < solver->vars);
LOG ("dequeued %s", LOGVAR (idx));
links *links = solver->links;
if (solver->queue.search.idx == idx) {
struct links *l = links + idx;
unsigned search = l->next;
if (search == DISCONNECT)
search = l->prev;
if (search == DISCONNECT) {
solver->queue.search.idx = DISCONNECT;
solver->queue.search.stamp = 0;
} else
kissat_update_queue (solver, links, search);
}
kissat_dequeue_links (idx, links, &solver->queue);
kissat_check_queue (solver);
}
static inline void kissat_move_to_front (kissat *solver, unsigned idx) {
queue *queue = &solver->queue;
links *links = solver->links;
if (idx == queue->last) {
assert (DISCONNECTED (links[idx].next));
return;
}
assert (idx < solver->vars);
const value tmp = VALUE (LIT (idx));
if (tmp && queue->search.idx == idx) {
unsigned prev = links[idx].prev;
if (!DISCONNECTED (prev))
kissat_update_queue (solver, links, prev);
else {
unsigned next = links[idx].next;
assert (!DISCONNECTED (next));
kissat_update_queue (solver, links, next);
}
}
kissat_dequeue_links (idx, links, queue);
kissat_enqueue_links (solver, idx, links, queue);
LOG ("moved-to-front %s stamped %u", LOGVAR (idx), LINK (idx).stamp);
if (!tmp)
kissat_update_queue (solver, links, idx);
kissat_check_queue (solver);
}
#endif

View File

@ -0,0 +1,193 @@
#ifndef _inlinevector_h_INCLUDED
#define _inlinevector_h_INCLUDED
#include "internal.h"
static inline unsigned *kissat_begin_vector (kissat *solver,
vector *vector) {
#ifdef COMPACT
return BEGIN_STACK (solver->vectors.stack) + vector->offset;
#else
(void) solver;
return vector->begin;
#endif
}
static inline unsigned *kissat_end_vector (kissat *solver, vector *vector) {
#ifdef COMPACT
return kissat_begin_vector (solver, vector) + vector->size;
#else
(void) solver;
return vector->end;
#endif
}
static inline const unsigned *
kissat_begin_const_vector (kissat *solver, const vector *vector) {
#ifdef COMPACT
return BEGIN_STACK (solver->vectors.stack) + vector->offset;
#else
(void) solver;
return vector->begin;
#endif
}
static inline const unsigned *
kissat_end_const_vector (kissat *solver, const vector *vector) {
#ifdef COMPACT
return kissat_begin_const_vector (solver, vector) + vector->size;
#else
(void) solver;
return vector->end;
#endif
}
#if defined(LOGGING) || defined(TEST_VECTOR)
static inline size_t kissat_offset_vector (kissat *solver, vector *vector) {
#ifdef COMPACT
(void) solver;
return vector->offset;
#else
unsigned *begin_vector = vector->begin;
unsigned *begin_stack = BEGIN_STACK (solver->vectors.stack);
return begin_vector ? begin_vector - begin_stack : 0;
#endif
}
#endif
static inline size_t kissat_size_vector (const vector *vector) {
#ifdef COMPACT
return vector->size;
#else
return vector->end - vector->begin;
#endif
}
static inline bool kissat_empty_vector (vector *vector) {
#ifdef COMPACT
return !vector->size;
#else
return vector->end == vector->begin;
#endif
}
static inline void kissat_inc_usable (kissat *solver) {
assert (MAX_SECTOR > solver->vectors.usable);
solver->vectors.usable++;
}
static inline void kissat_add_usable (kissat *solver, size_t inc) {
assert (MAX_SECTOR - inc >= solver->vectors.usable);
solver->vectors.usable += inc;
}
static inline unsigned *kissat_last_vector_pointer (kissat *solver,
vector *vector) {
assert (!kissat_empty_vector (vector));
#ifdef COMPACT
assert (vector->size);
unsigned *begin = kissat_begin_vector (solver, vector);
return begin + vector->size - 1;
#else
(void) solver;
return vector->end - 1;
#endif
}
#ifdef TEST_VECTOR
static inline void kissat_pop_vector (kissat *solver, vector *vector) {
assert (!kissat_empty_vector (vector));
#ifdef COMPACT
unsigned *p = kissat_last_vector_pointer (solver, vector);
vector->size--;
*p = INVALID_VECTOR_ELEMENT;
#else
*--vector->end = INVALID_VECTOR_ELEMENT;
(void) solver;
#endif
kissat_inc_usable (solver);
}
#endif
static inline void kissat_release_vector (kissat *solver, vector *vector) {
kissat_resize_vector (solver, vector, 0);
}
static inline void kissat_dec_usable (kissat *solver) {
assert (solver->vectors.usable > 0);
solver->vectors.usable--;
}
static inline void kissat_push_vectors (kissat *solver, vector *vector,
unsigned e) {
unsigneds *stack = &solver->vectors.stack;
assert (e != INVALID_VECTOR_ELEMENT);
if (
#ifdef COMPACT
!vector->size && !vector->offset
#else
!vector->begin
#endif
) {
if (EMPTY_STACK (*stack))
PUSH_STACK (*stack, 0);
if (FULL_STACK (*stack)) {
unsigned *end = kissat_enlarge_vector (solver, vector);
assert (*end == INVALID_VECTOR_ELEMENT);
*end = e;
kissat_dec_usable (solver);
} else {
#ifdef COMPACT
assert ((uint64_t) SIZE_STACK (*stack) < MAX_VECTORS);
vector->offset = SIZE_STACK (*stack);
assert (vector->offset);
*stack->end++ = e;
#else
assert (stack->end < stack->allocated);
*(vector->begin = stack->end++) = e;
#endif
}
#if !defined(COMPACT)
vector->end = vector->begin;
#endif
} else {
unsigned *end = kissat_end_vector (solver, vector);
if (end == END_STACK (*stack)) {
if (FULL_STACK (*stack)) {
end = kissat_enlarge_vector (solver, vector);
assert (*end == INVALID_VECTOR_ELEMENT);
*end = e;
kissat_dec_usable (solver);
} else
*stack->end++ = e;
} else {
if (*end != INVALID_VECTOR_ELEMENT)
end = kissat_enlarge_vector (solver, vector);
assert (*end == INVALID_VECTOR_ELEMENT);
*end = e;
kissat_dec_usable (solver);
}
}
#ifndef COMPACT
vector->end++;
#else
vector->size++;
#endif
kissat_check_vectors (solver);
}
#ifdef TEST_VECTOR
#define all_vector(E, V) \
unsigned E, *E##_PTR = kissat_begin_vector (solver, &V), \
*const E##_END = kissat_end_vector (solver, &V); \
E##_PTR != E##_END && (E = *E##_PTR, true); \
E##_PTR++
#endif
#endif

520
src/sat/kissat/internal.c Normal file
View File

@ -0,0 +1,520 @@
#include "allocate.h"
#include "backtrack.h"
#include "error.h"
#include "import.h"
#include "inline.h"
#include "inlineframes.h"
#include "print.h"
#include "propsearch.h"
#include "require.h"
#include "resize.h"
#include "resources.h"
#include "search.h"
#include <assert.h>
#include <inttypes.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
void kissat_reset_last_learned (kissat *solver) {
for (really_all_last_learned (p))
*p = INVALID_REF;
}
kissat *kissat_init (void) {
kissat *solver = kissat_calloc (0, 1, sizeof *solver);
#ifndef NOPTIONS
kissat_init_options (&solver->options);
#else
kissat_init_options ();
#endif
#ifndef QUIET
kissat_init_profiles (&solver->profiles);
#endif
START (total);
kissat_init_queue (solver);
assert (INTERNAL_MAX_LIT < UINT_MAX);
kissat_push_frame (solver, UINT_MAX);
solver->watching = true;
solver->conflict.size = 2;
solver->scinc = 1.0;
solver->first_reducible = INVALID_REF;
solver->last_irredundant = INVALID_REF;
kissat_reset_last_learned (solver);
#ifndef NDEBUG
kissat_init_checker (solver);
#endif
solver->prefix = kissat_strdup (solver, "c ");
return solver;
}
void kissat_set_prefix (kissat *solver, const char *prefix) {
kissat_freestr (solver, solver->prefix);
solver->prefix = kissat_strdup (solver, prefix);
}
#define DEALLOC_GENERIC(NAME, ELEMENTS_PER_BLOCK) \
do { \
const size_t block_size = ELEMENTS_PER_BLOCK * sizeof *solver->NAME; \
kissat_dealloc (solver, solver->NAME, solver->size, block_size); \
solver->NAME = 0; \
} while (0)
#define DEALLOC_VARIABLE_INDEXED(NAME) DEALLOC_GENERIC (NAME, 1)
#define DEALLOC_LITERAL_INDEXED(NAME) DEALLOC_GENERIC (NAME, 2)
#define RELEASE_LITERAL_INDEXED_STACKS(NAME, ACCESS) \
do { \
for (all_stack (unsigned, IDX_RILIS, solver->active)) { \
const unsigned LIT_RILIS = LIT (IDX_RILIS); \
const unsigned NOT_LIT_RILIS = NOT (LIT_RILIS); \
RELEASE_STACK (ACCESS (LIT_RILIS)); \
RELEASE_STACK (ACCESS (NOT_LIT_RILIS)); \
} \
DEALLOC_LITERAL_INDEXED (NAME); \
} while (0)
void kissat_release (kissat *solver) {
kissat_require_initialized (solver);
kissat_release_heap (solver, SCORES);
kissat_release_heap (solver, &solver->schedule);
kissat_release_vectors (solver);
kissat_release_phases (solver);
RELEASE_STACK (solver->export);
RELEASE_STACK (solver->import);
DEALLOC_VARIABLE_INDEXED (assigned);
DEALLOC_VARIABLE_INDEXED (flags);
DEALLOC_VARIABLE_INDEXED (links);
DEALLOC_LITERAL_INDEXED (marks);
DEALLOC_LITERAL_INDEXED (values);
DEALLOC_LITERAL_INDEXED (watches);
RELEASE_STACK (solver->import);
RELEASE_STACK (solver->eliminated);
RELEASE_STACK (solver->extend);
RELEASE_STACK (solver->witness);
RELEASE_STACK (solver->etrail);
RELEASE_STACK (solver->delayed);
RELEASE_STACK (solver->clause);
RELEASE_STACK (solver->shadow);
#if defined(LOGGING) || !defined(NDEBUG)
RELEASE_STACK (solver->resolvent);
#endif
RELEASE_STACK (solver->arena);
RELEASE_STACK (solver->units);
RELEASE_STACK (solver->frames);
RELEASE_STACK (solver->sorter);
RELEASE_ARRAY (solver->trail, solver->size);
RELEASE_STACK (solver->analyzed);
RELEASE_STACK (solver->levels);
RELEASE_STACK (solver->minimize);
RELEASE_STACK (solver->poisoned);
RELEASE_STACK (solver->promote);
RELEASE_STACK (solver->removable);
RELEASE_STACK (solver->shrinkable);
RELEASE_STACK (solver->xorted[0]);
RELEASE_STACK (solver->xorted[1]);
RELEASE_STACK (solver->sweep_schedule);
RELEASE_STACK (solver->ranks);
RELEASE_STACK (solver->antecedents[0]);
RELEASE_STACK (solver->antecedents[1]);
RELEASE_STACK (solver->gates[0]);
RELEASE_STACK (solver->gates[1]);
RELEASE_STACK (solver->resolvents);
#if !defined(NDEBUG) || !defined(NPROOFS)
RELEASE_STACK (solver->added);
RELEASE_STACK (solver->removed);
#endif
#if !defined(NDEBUG) || !defined(NPROOFS) || defined(LOGGING)
RELEASE_STACK (solver->original);
#endif
#ifndef QUIET
RELEASE_STACK (solver->profiles.stack);
#endif
kissat_freestr (solver, solver->prefix);
#ifndef NDEBUG
kissat_release_checker (solver);
#endif
#if !defined(NDEBUG) && defined(METRICS)
uint64_t leaked = solver->statistics.allocated_current;
if (leaked)
if (!getenv ("LEAK"))
kissat_fatal ("internally leaking %" PRIu64 " bytes", leaked);
#endif
kissat_free (0, solver, sizeof *solver);
}
void kissat_reserve (kissat *solver, int max_var) {
kissat_require_initialized (solver);
kissat_require (0 <= max_var, "negative maximum variable argument '%d'",
max_var);
kissat_require (max_var <= EXTERNAL_MAX_VAR,
"invalid maximum variable argument '%d'", max_var);
kissat_increase_size (solver, (unsigned) max_var);
if (!GET_OPTION (tumble)) {
for (int idx = 1; idx <= max_var; idx++)
(void) kissat_import_literal (solver, idx);
for (unsigned idx = 0; idx != (unsigned) max_var; idx++)
kissat_activate_literal (solver, LIT (idx));
}
}
int kissat_get_option (kissat *solver, const char *name) {
kissat_require_initialized (solver);
kissat_require (name, "name zero pointer");
#ifndef NOPTIONS
return kissat_options_get (&solver->options, name);
#else
(void) solver;
return kissat_options_get (name);
#endif
}
int kissat_set_option (kissat *solver, const char *name, int new_value) {
#ifndef NOPTIONS
kissat_require_initialized (solver);
kissat_require (name, "name zero pointer");
#ifndef NOPTIONS
return kissat_options_set (&solver->options, name, new_value);
#else
return kissat_options_set (name, new_value);
#endif
#else
(void) solver, (void) new_value;
return kissat_options_get (name);
#endif
}
void kissat_set_decision_limit (kissat *solver, unsigned limit) {
kissat_require_initialized (solver);
limits *limits = &solver->limits;
limited *limited = &solver->limited;
statistics *statistics = &solver->statistics;
limited->decisions = true;
assert (UINT64_MAX - limit >= statistics->decisions);
limits->decisions = statistics->decisions + limit;
LOG ("set decision limit to %" PRIu64 " after %u decisions",
limits->decisions, limit);
}
void kissat_set_conflict_limit (kissat *solver, unsigned limit) {
kissat_require_initialized (solver);
limits *limits = &solver->limits;
limited *limited = &solver->limited;
statistics *statistics = &solver->statistics;
limited->conflicts = true;
assert (UINT64_MAX - limit >= statistics->conflicts);
limits->conflicts = statistics->conflicts + limit;
LOG ("set conflict limit to %" PRIu64 " after %u conflicts",
limits->conflicts, limit);
}
void kissat_print_statistics (kissat *solver) {
#ifndef QUIET
kissat_require_initialized (solver);
const int verbosity = kissat_verbosity (solver);
if (verbosity < 0)
return;
if (GET_OPTION (profile)) {
kissat_section (solver, "profiling");
kissat_profiles_print (solver);
}
const bool complete = GET_OPTION (statistics);
kissat_section (solver, "statistics");
const bool verbose = (complete || verbosity > 0);
kissat_statistics_print (solver, verbose);
#ifndef NPROOFS
if (solver->proof) {
kissat_section (solver, "proof");
kissat_print_proof_statistics (solver, verbose);
}
#endif
#ifndef NDEBUG
if (GET_OPTION (check) > 1) {
kissat_section (solver, "checker");
kissat_print_checker_statistics (solver, verbose);
}
#endif
kissat_section (solver, "glue usage");
kissat_print_glue_usage (solver);
kissat_section (solver, "resources");
kissat_print_resources (solver);
#endif
(void) solver;
}
void kissat_add (kissat *solver, int elit) {
kissat_require_initialized (solver);
kissat_require (!GET (searches), "incremental solving not supported");
#if !defined(NDEBUG) || !defined(NPROOFS) || defined(LOGGING)
const int checking = kissat_checking (solver);
const bool logging = kissat_logging (solver);
const bool proving = kissat_proving (solver);
#endif
if (elit) {
kissat_require_valid_external_internal (elit);
#if !defined(NDEBUG) || !defined(NPROOFS) || defined(LOGGING)
if (checking || logging || proving)
PUSH_STACK (solver->original, elit);
#endif
unsigned ilit = kissat_import_literal (solver, elit);
const mark mark = MARK (ilit);
if (!mark) {
const value value = kissat_fixed (solver, ilit);
if (value > 0) {
if (!solver->clause_satisfied) {
LOG ("adding root level satisfied literal %u(%d)@0=1", ilit,
elit);
solver->clause_satisfied = true;
}
} else if (value < 0) {
LOG ("adding root level falsified literal %u(%d)@0=-1", ilit, elit);
if (!solver->clause_shrink) {
solver->clause_shrink = true;
LOG ("thus original clause needs shrinking");
}
} else {
MARK (ilit) = 1;
MARK (NOT (ilit)) = -1;
assert (SIZE_STACK (solver->clause) < UINT_MAX);
PUSH_STACK (solver->clause, ilit);
}
} else if (mark < 0) {
assert (mark < 0);
if (!solver->clause_trivial) {
LOG ("adding dual literal %u(%d) and %u(%d)", NOT (ilit), -elit,
ilit, elit);
solver->clause_trivial = true;
}
} else {
assert (mark > 0);
LOG ("adding duplicated literal %u(%d)", ilit, elit);
if (!solver->clause_shrink) {
solver->clause_shrink = true;
LOG ("thus original clause needs shrinking");
}
}
} else {
#if !defined(NDEBUG) || !defined(NPROOFS) || defined(LOGGING)
const size_t offset = solver->offset_of_last_original_clause;
size_t esize = SIZE_STACK (solver->original) - offset;
int *elits = BEGIN_STACK (solver->original) + offset;
assert (esize <= UINT_MAX);
#endif
ADD_UNCHECKED_EXTERNAL (esize, elits);
const size_t isize = SIZE_STACK (solver->clause);
unsigned *ilits = BEGIN_STACK (solver->clause);
assert (isize < (unsigned) INT_MAX);
if (solver->inconsistent)
LOG ("inconsistent thus skipping original clause");
else if (solver->clause_satisfied)
LOG ("skipping satisfied original clause");
else if (solver->clause_trivial)
LOG ("skipping trivial original clause");
else {
kissat_activate_literals (solver, isize, ilits);
if (!isize) {
if (solver->clause_shrink)
LOG ("all original clause literals root level falsified");
else
LOG ("found empty original clause");
if (!solver->inconsistent) {
LOG ("thus solver becomes inconsistent");
solver->inconsistent = true;
CHECK_AND_ADD_EMPTY ();
ADD_EMPTY_TO_PROOF ();
}
} else if (isize == 1) {
unsigned unit = TOP_STACK (solver->clause);
if (solver->clause_shrink)
LOGUNARY (unit, "original clause shrinks to");
else
LOGUNARY (unit, "found original");
kissat_original_unit (solver, unit);
COVER (solver->level);
if (!solver->level)
(void) kissat_search_propagate (solver);
} else {
reference res = kissat_new_original_clause (solver);
const unsigned a = ilits[0];
const unsigned b = ilits[1];
const value u = VALUE (a);
const value v = VALUE (b);
const unsigned k = u ? LEVEL (a) : UINT_MAX;
const unsigned l = v ? LEVEL (b) : UINT_MAX;
bool assign = false;
if (!u && v < 0) {
LOG ("original clause immediately forcing");
assign = true;
} else if (u < 0 && k == l) {
LOG ("both watches falsified at level @%u", k);
assert (v < 0);
assert (k > 0);
kissat_backtrack_without_updating_phases (solver, k - 1);
} else if (u < 0) {
LOG ("watches falsified at levels @%u and @%u", k, l);
assert (v < 0);
assert (k > l);
assert (l > 0);
assign = true;
} else if (u > 0 && v < 0) {
LOG ("first watch satisfied at level @%u "
"second falsified at level @%u",
k, l);
assert (k <= l);
} else if (!u && v > 0) {
LOG ("first watch unassigned "
"second falsified at level @%u",
l);
assign = true;
} else {
assert (!u);
assert (!v);
}
if (assign) {
assert (solver->level > 0);
if (isize == 2) {
assert (res == INVALID_REF);
kissat_assign_binary (solver, a, b);
} else {
assert (res != INVALID_REF);
clause *c = kissat_dereference_clause (solver, res);
kissat_assign_reference (solver, a, res, c);
}
}
}
}
#if !defined(NDEBUG) || !defined(NPROOFS)
if (solver->clause_satisfied || solver->clause_trivial) {
#ifndef NDEBUG
if (checking > 1)
kissat_remove_checker_external (solver, esize, elits);
#endif
#ifndef NPROOFS
if (proving) {
if (esize == 1)
LOG ("skipping deleting unit from proof");
else
kissat_delete_external_from_proof (solver, esize, elits);
}
#endif
} else if (!solver->inconsistent && solver->clause_shrink) {
#ifndef NDEBUG
if (checking > 1) {
kissat_check_and_add_internal (solver, isize, ilits);
kissat_remove_checker_external (solver, esize, elits);
}
#endif
#ifndef NPROOFS
if (proving) {
kissat_add_lits_to_proof (solver, isize, ilits);
kissat_delete_external_from_proof (solver, esize, elits);
}
#endif
}
#endif
#if !defined(NDEBUG) || !defined(NPROOFS) || defined(LOGGING)
if (checking) {
LOGINTS (esize, elits, "saved original");
PUSH_STACK (solver->original, 0);
solver->offset_of_last_original_clause =
SIZE_STACK (solver->original);
} else if (logging || proving) {
LOGINTS (esize, elits, "reset original");
CLEAR_STACK (solver->original);
solver->offset_of_last_original_clause = 0;
}
#endif
for (all_stack (unsigned, lit, solver->clause))
MARK (lit) = MARK (NOT (lit)) = 0;
CLEAR_STACK (solver->clause);
solver->clause_satisfied = false;
solver->clause_trivial = false;
solver->clause_shrink = false;
}
}
int kissat_solve (kissat *solver) {
kissat_require_initialized (solver);
kissat_require (EMPTY_STACK (solver->clause),
"incomplete clause (terminating zero not added)");
kissat_require (!GET (searches), "incremental solving not supported");
return kissat_search (solver);
}
void kissat_terminate (kissat *solver) {
kissat_require_initialized (solver);
solver->termination.flagged = ~(unsigned) 0;
assert (solver->termination.flagged);
}
void kissat_set_terminate (kissat *solver, void *state,
int (*terminate) (void *)) {
solver->termination.terminate = 0;
solver->termination.state = state;
solver->termination.terminate = terminate;
}
int kissat_value (kissat *solver, int elit) {
kissat_require_initialized (solver);
kissat_require_valid_external_internal (elit);
const unsigned eidx = ABS (elit);
if (eidx >= SIZE_STACK (solver->import))
return 0;
const import *const import = &PEEK_STACK (solver->import, eidx);
if (!import->imported)
return 0;
value tmp;
if (import->eliminated) {
if (!solver->extended && !EMPTY_STACK (solver->extend))
kissat_extend (solver);
const unsigned eliminated = import->lit;
tmp = PEEK_STACK (solver->eliminated, eliminated);
} else {
const unsigned ilit = import->lit;
tmp = VALUE (ilit);
}
if (!tmp)
return 0;
if (elit < 0)
tmp = -tmp;
return tmp < 0 ? -elit : elit;
}

295
src/sat/kissat/internal.h Normal file
View File

@ -0,0 +1,295 @@
#ifndef _internal_h_INCLUDED
#define _internal_h_INCLUDED
#include "arena.h"
#include "array.h"
#include "assign.h"
#include "averages.h"
#include "check.h"
#include "classify.h"
#include "clause.h"
#include "cover.h"
#include "extend.h"
#include "flags.h"
#include "format.h"
#include "frames.h"
#include "heap.h"
#include "kimits.h"
#include "kissat.h"
#include "literal.h"
#include "mode.h"
#include "options.h"
#include "phases.h"
#include "profile.h"
#include "proof.h"
#include "queue.h"
#include "random.h"
#include "reluctant.h"
#include "rephase.h"
#include "smooth.h"
#include "stack.h"
#include "statistics.h"
#include "value.h"
#include "vector.h"
#include "watch.h"
typedef struct datarank datarank;
struct datarank {
unsigned data;
unsigned rank;
};
typedef struct import import;
struct import {
unsigned lit;
bool extension;
bool imported;
bool eliminated;
};
typedef struct termination termination;
struct termination {
#ifdef COVERAGE
volatile uint64_t flagged;
#else
volatile bool flagged;
#endif
volatile void *state;
int (*volatile terminate) (void *);
};
// clang-format off
typedef STACK (value) eliminated;
typedef STACK (import) imports;
typedef STACK (datarank) dataranks;
typedef STACK (watch) statches;
typedef STACK (watch *) patches;
// clang-format on
struct kitten;
struct kissat {
#if !defined(NDEBUG) || defined(METRICS)
bool backbone_computing;
#endif
#ifdef LOGGING
bool compacting;
#endif
bool extended;
bool inconsistent;
bool iterating;
bool preprocessing;
bool probing;
#ifndef QUIET
bool sectioned;
#endif
bool stable;
#if !defined(NDEBUG) || defined(METRICS)
bool transitive_reducing;
bool vivifying;
#endif
bool warming;
bool watching;
bool large_clauses_watched_after_binary_clauses;
termination termination;
unsigned vars;
unsigned size;
unsigned active;
unsigned randec;
ints export;
ints units;
imports import;
extensions extend;
unsigneds witness;
assigned *assigned;
flags *flags;
mark *marks;
value *values;
phases phases;
eliminated eliminated;
unsigneds etrail;
links *links;
queue queue;
heap scores;
double scinc;
heap schedule;
double scoreshift;
unsigned level;
frames frames;
unsigned_array trail;
unsigned *propagate;
unsigned best_assigned;
unsigned target_assigned;
unsigned unflushed;
unsigned unassigned;
unsigneds delayed;
#if defined(LOGGING) || !defined(NDEBUG)
unsigneds resolvent;
#endif
unsigned resolvent_size;
unsigned antecedent_size;
dataranks ranks;
unsigneds analyzed;
unsigneds levels;
unsigneds minimize;
unsigneds poisoned;
unsigneds promote;
unsigneds removable;
unsigneds shrinkable;
clause conflict;
bool clause_satisfied;
bool clause_shrink;
bool clause_trivial;
unsigneds clause;
unsigneds shadow;
arena arena;
vectors vectors;
reference first_reducible;
reference last_irredundant;
watches *watches;
reference last_learned[4];
sizes sorter;
generator random;
averages averages[2];
unsigned tier1[2], tier2[2];
reluctant reluctant;
bounds bounds;
classification classification;
delays delays;
enabled enabled;
limited limited;
limits limits;
remember last;
unsigned walked;
mode mode;
uint64_t ticks;
format format;
char *prefix;
statches antecedents[2];
statches gates[2];
patches xorted[2];
unsigneds resolvents;
bool resolve_gate;
struct kitten *kitten;
#ifdef METRICS
uint64_t *gate_eliminated;
#else
bool gate_eliminated;
#endif
bool sweep_incomplete;
unsigneds sweep_schedule;
#if !defined(NDEBUG) || !defined(NPROOFS)
unsigneds added;
unsigneds removed;
#endif
#if !defined(NDEBUG) || !defined(NPROOFS) || defined(LOGGING)
ints original;
size_t offset_of_last_original_clause;
#endif
#ifndef QUIET
profiles profiles;
#endif
#ifndef NOPTIONS
options options;
#endif
#ifndef NDEBUG
checker *checker;
#endif
#ifndef NPROOFS
proof *proof;
#endif
statistics statistics;
};
#define VARS (solver->vars)
#define LITS (2 * solver->vars)
#if 0
#define TIEDX (GET_OPTION (focusedtiers) ? 0 : solver->stable)
#define TIER1 (solver->tier1[TIEDX])
#define TIER2 (solver->tier2[TIEDX])
#else
#define TIER1 (solver->tier1[0])
#define TIER2 (solver->tier2[1])
#endif
#define SCORES (&solver->scores)
static inline unsigned kissat_assigned (kissat *solver) {
assert (VARS >= solver->unassigned);
return VARS - solver->unassigned;
}
#define all_variables(IDX) \
unsigned IDX = 0, IDX##_END = solver->vars; \
IDX != IDX##_END; \
++IDX
#define all_literals(LIT) \
unsigned LIT = 0, LIT##_END = LITS; \
LIT != LIT##_END; \
++LIT
#define all_clauses(C) \
clause *C = (clause *) BEGIN_STACK (solver->arena), \
*const C##_END = (clause *) END_STACK (solver->arena), *C##_NEXT; \
C != C##_END && (C##_NEXT = kissat_next_clause (C), true); \
C = C##_NEXT
#define capacity_last_learned \
(sizeof solver->last_learned / sizeof *solver->last_learned)
#define real_end_last_learned (solver->last_learned + capacity_last_learned)
#define really_all_last_learned(REF_PTR) \
reference *REF_PTR = solver->last_learned, \
*REF_PTR##_END = real_end_last_learned; \
REF_PTR != REF_PTR##_END; \
REF_PTR++
void kissat_reset_last_learned (kissat *solver);
#endif

18
src/sat/kissat/keatures.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef _keatures_h_INCLUDED
#define _keatures_h_INCLUDED
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#define KISSAT_IS_BIG_ENDIAN
#endif
#if defined(_POSIX_C_SOURCE) || defined(__APPLE__)
#define KISSAT_HAS_COMPRESSION
#define KISSAT_HAS_COLORS
#define KISSAT_HAS_FILENO
#endif
#if defined(_POSIX_C_SOURCE)
#define KISSAT_HAS_UNLOCKEDIO
#endif
#endif

194
src/sat/kissat/kimits.c Normal file
View File

@ -0,0 +1,194 @@
#include "internal.h"
#include "logging.h"
#include "mode.h"
#include "print.h"
#include "reduce.h"
#include "rephase.h"
#include "resources.h"
#include "restart.h"
#include <inttypes.h>
#include <math.h>
double kissat_logn (uint64_t count) {
assert (count > 0);
const double res = log10 (count + 9);
assert (res >= 1);
return res;
}
double kissat_sqrt (uint64_t count) {
assert (count > 0);
const double res = sqrt (count);
assert (res >= 1);
return res;
}
double kissat_nlogpown (uint64_t count, unsigned exponent) {
assert (count > 0);
const double tmp = log10 (count + 9);
double factor = 1;
while (exponent--)
factor *= tmp;
assert (factor >= 1);
const double res = count * factor;
assert (res >= 1);
return res;
}
uint64_t kissat_scale_delta (kissat *solver, const char *pretty,
uint64_t delta) {
const uint64_t C = BINIRR_CLAUSES;
double f = kissat_logn (C + 1) - 5;
const double ff = f * f;
assert (ff >= 0);
const double fff = 4.5 * ff + 25;
uint64_t scaled = fff * delta;
assert (delta <= scaled);
// clang-format off
kissat_very_verbose (solver,
"scaled %s delta %" PRIu64
" = %g * %" PRIu64
" = (4.5 (log10(%" PRIu64 ") - 5)^2 + 25) * %" PRIu64,
pretty, scaled, fff, delta, C, delta);
// clang-format on
(void) pretty;
return scaled;
}
static void init_enabled (kissat *solver) {
bool probe;
if (!GET_OPTION (simplify))
probe = false;
else if (!GET_OPTION (probe))
probe = false;
else if (GET_OPTION (substitute))
probe = true;
else if (GET_OPTION (sweep))
probe = true;
else if (GET_OPTION (vivify))
probe = true;
else
probe = false;
kissat_very_verbose (solver, "probing %sabled", probe ? "en" : "dis");
solver->enabled.probe = probe;
bool eliminate;
if (!GET_OPTION (simplify))
eliminate = false;
else if (!GET_OPTION (eliminate))
eliminate = false;
else
eliminate = true;
kissat_very_verbose (solver, "eliminate %sabled",
eliminate ? "en" : "dis");
solver->enabled.eliminate = eliminate;
}
#define INIT_CONFLICT_LIMIT(NAME, SCALE) \
do { \
const uint64_t DELTA = GET_OPTION (NAME##init); \
const uint64_t SCALED = \
!(SCALE) ? DELTA : kissat_scale_delta (solver, #NAME, DELTA); \
limits->NAME.conflicts = CONFLICTS + SCALED; \
kissat_very_verbose (solver, \
"initial " #NAME " limit of %s conflicts", \
FORMAT_COUNT (limits->NAME.conflicts)); \
} while (0)
void kissat_init_limits (kissat *solver) {
assert (solver->statistics.searches == 1);
init_enabled (solver);
limits *limits = &solver->limits;
if (GET_OPTION (randec))
INIT_CONFLICT_LIMIT (randec, false);
if (GET_OPTION (reduce))
INIT_CONFLICT_LIMIT (reduce, false);
if (GET_OPTION (reorder))
INIT_CONFLICT_LIMIT (reorder, false);
if (GET_OPTION (rephase))
INIT_CONFLICT_LIMIT (rephase, false);
if (!solver->stable)
kissat_update_focused_restart_limit (solver);
kissat_init_mode_limit (solver);
if (solver->enabled.eliminate) {
INIT_CONFLICT_LIMIT (eliminate, true);
solver->bounds.eliminate.max_bound_completed = 0;
solver->bounds.eliminate.additional_clauses = 0;
kissat_very_verbose (solver, "reset elimination bound to zero");
}
if (solver->enabled.probe)
INIT_CONFLICT_LIMIT (probe, true);
}
#ifndef QUIET
static const char *delay_description (kissat *solver, delay *delay) {
delays *delays = &solver->delays;
if (delay == &delays->bumpreasons)
return "bumping reason side literals";
else if (delay == &delays->congruence)
return "congruence closure";
else if (delay == &delays->sweep)
return "sweeping";
else {
assert (delay == &delays->vivifyirr);
return "vivifying irredundant clauses";
}
}
#endif
#define VERY_VERBOSE_IF_NOT_BUMPREASONS(...) \
VERY_VERBOSE_OR_LOG (delay == &solver->delays.bumpreasons, __VA_ARGS__)
void kissat_reduce_delay (kissat *solver, delay *delay) {
if (!delay->current)
return;
delay->current /= 2;
VERY_VERBOSE_IF_NOT_BUMPREASONS (
solver, "%s delay interval decreased to %u",
delay_description (solver, delay), delay->current);
delay->count = delay->current;
#ifdef QUIET
(void) solver;
#endif
}
void kissat_bump_delay (kissat *solver, delay *delay) {
delay->current += delay->current < UINT_MAX;
VERY_VERBOSE_IF_NOT_BUMPREASONS (
solver, "%s delay interval increased to %u",
delay_description (solver, delay), delay->current);
delay->count = delay->current;
#ifdef QUIET
(void) solver;
#endif
}
bool kissat_delaying (kissat *solver, delay *delay) {
if (delay->count) {
delay->count--;
VERY_VERBOSE_IF_NOT_BUMPREASONS (
solver, "%s still delayed (%u more times)",
delay_description (solver, delay), delay->current);
return true;
} else {
VERY_VERBOSE_IF_NOT_BUMPREASONS (solver, "%s not delayed",
delay_description (solver, delay));
return false;
}
#ifdef QUIET
(void) solver;
#endif
}

185
src/sat/kissat/kimits.h Normal file
View File

@ -0,0 +1,185 @@
#ifndef _limits_h_INCLUDED
#define _limits_h_INCLUDED
#include <stdbool.h>
#include <stdint.h>
typedef struct bounds bounds;
typedef struct changes changes;
typedef struct delays delays;
typedef struct delay delay;
typedef struct remember remember;
typedef struct enabled enabled;
typedef struct limited limited;
typedef struct limits limits;
struct bounds {
struct {
uint64_t max_bound_completed;
unsigned additional_clauses;
} eliminate;
};
struct limits {
uint64_t conflicts;
uint64_t decisions;
uint64_t reports;
struct {
uint64_t count;
uint64_t ticks;
uint64_t conflicts;
} mode;
struct {
struct {
uint64_t eliminate;
uint64_t subsume;
} variables;
uint64_t conflicts;
} eliminate;
struct {
uint64_t marked;
} factor;
struct {
uint64_t conflicts;
} probe, randec, reduce, reorder, rephase, restart;
struct {
uint64_t conflicts;
uint64_t interval;
} glue;
};
struct limited {
bool conflicts;
bool decisions;
};
struct enabled {
bool eliminate;
bool focus;
bool mode;
bool probe;
};
struct delay {
unsigned count;
unsigned current;
};
struct delays {
delay bumpreasons;
delay congruence;
delay sweep;
delay vivifyirr;
};
struct remember {
struct {
uint64_t eliminate;
uint64_t probe;
} ticks;
struct {
uint64_t reduce;
} conflicts;
};
struct kissat;
changes kissat_changes (struct kissat *);
bool kissat_changed (changes before, changes after);
void kissat_init_limits (struct kissat *);
uint64_t kissat_scale_delta (struct kissat *, const char *, uint64_t);
double kissat_nlogpown (uint64_t, unsigned);
double kissat_sqrt (uint64_t);
double kissat_logn (uint64_t);
#define LOGN(COUNT) kissat_logn (COUNT)
#define LINEAR(COUNT) (COUNT)
#define NLOGN(COUNT) kissat_nlogpown (COUNT, 1)
#define NLOG2N(COUNT) kissat_nlogpown (COUNT, 2)
#define NLOG3N(COUNT) kissat_nlogpown (COUNT, 3)
#define SQRT(COUNT) kissat_sqrt (COUNT)
#define UPDATE_CONFLICT_LIMIT(NAME, COUNT, SCALE_COUNT_FUNCTION, \
SCALE_DELTA) \
do { \
if (solver->inconsistent) \
break; \
const struct statistics *statistics = &solver->statistics; \
assert (statistics->COUNT > 0); \
struct limits *limits = &solver->limits; \
uint64_t DELTA = GET_OPTION (NAME##int); \
const double SCALING = SCALE_COUNT_FUNCTION (statistics->COUNT); \
assert (SCALING >= 1); \
DELTA *= SCALING; \
const uint64_t SCALED = \
!(SCALE_DELTA) ? DELTA \
: kissat_scale_delta (solver, #NAME, DELTA); \
limits->NAME.conflicts = CONFLICTS + SCALED; \
kissat_phase ( \
solver, #NAME, GET (COUNT), "new limit of %s after %s conflicts", \
FORMAT_COUNT (limits->NAME.conflicts), FORMAT_COUNT (SCALED)); \
} while (0)
#include <inttypes.h>
#define SET_EFFORT_LIMIT(LIMIT, NAME, START) \
uint64_t LIMIT; \
do { \
const uint64_t OLD_LIMIT = solver->statistics.START; \
const uint64_t TICKS = solver->statistics.search_ticks; \
const uint64_t LAST = solver->probing ? solver->last.ticks.probe \
: solver->last.ticks.eliminate; \
uint64_t REFERENCE = TICKS - LAST; \
const uint64_t MINEFFORT = 1e6 * GET_OPTION (mineffort); \
if (REFERENCE < MINEFFORT) { \
REFERENCE = MINEFFORT; \
kissat_extremely_verbose ( \
solver, #NAME " effort reference %s set to 'mineffort'", \
FORMAT_COUNT (REFERENCE)); \
} else { \
kissat_extremely_verbose ( \
solver, #NAME " effort reference %s = %s - %s 'search_ticks'", \
FORMAT_COUNT (REFERENCE), FORMAT_COUNT (TICKS), \
FORMAT_COUNT (LAST)); \
} \
const double EFFORT = (double) GET_OPTION (NAME##effort) * 1e-3; \
const uint64_t DELTA = EFFORT * REFERENCE; \
\
kissat_extremely_verbose ( \
solver, #NAME " effort delta %s = %g * %s '" #START "'", \
FORMAT_COUNT (DELTA), EFFORT, FORMAT_COUNT (REFERENCE)); \
\
const uint64_t NEW_LIMIT = OLD_LIMIT + DELTA; \
kissat_very_verbose (solver, \
#NAME " effort limit %s = %s + %s '" #START "'", \
FORMAT_COUNT (NEW_LIMIT), \
FORMAT_COUNT (OLD_LIMIT), FORMAT_COUNT (DELTA)); \
\
LIMIT = NEW_LIMIT; \
\
} while (0)
struct kissat;
bool kissat_delaying (struct kissat *, delay *);
void kissat_bump_delay (struct kissat *, delay *);
void kissat_reduce_delay (struct kissat *, delay *);
#define DELAYING(NAME) kissat_delaying (solver, &solver->delays.NAME)
#define BUMP_DELAY(NAME) kissat_bump_delay (solver, &solver->delays.NAME)
#define REDUCE_DELAY(NAME) \
kissat_reduce_delay (solver, &solver->delays.NAME)
#endif

44
src/sat/kissat/kissat.h Normal file
View File

@ -0,0 +1,44 @@
#ifndef _kissat_h_INCLUDED
#define _kissat_h_INCLUDED
typedef struct kissat kissat;
// Default (partial) IPASIR interface.
const char *kissat_signature (void);
kissat *kissat_init (void);
void kissat_add (kissat *solver, int lit);
int kissat_solve (kissat *solver);
int kissat_value (kissat *solver, int lit);
void kissat_release (kissat *solver);
void kissat_set_terminate (kissat *solver, void *state,
int (*terminate) (void *state));
// Additional API functions.
void kissat_terminate (kissat *solver);
void kissat_reserve (kissat *solver, int max_var);
const char *kissat_id (void);
const char *kissat_version (void);
const char *kissat_compiler (void);
const char **kissat_copyright (void);
void kissat_build (const char *line_prefix);
void kissat_banner (const char *line_prefix, const char *name_of_app);
int kissat_get_option (kissat *solver, const char *name);
int kissat_set_option (kissat *solver, const char *name, int new_value);
void kissat_set_prefix (kissat *solver, const char *prefix);
int kissat_has_configuration (const char *name);
int kissat_set_configuration (kissat *solver, const char *name);
void kissat_set_conflict_limit (kissat *solver, unsigned);
void kissat_set_decision_limit (kissat *solver, unsigned);
void kissat_print_statistics (kissat *solver);
#endif

2794
src/sat/kissat/kitten.c Normal file

File diff suppressed because it is too large Load Diff

54
src/sat/kissat/kitten.h Normal file
View File

@ -0,0 +1,54 @@
#ifndef _kitten_h_INCLUDED
#define _kitten_h_INCLUDED
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
typedef struct kitten kitten;
kitten *kitten_init (void);
void kitten_clear (kitten *);
void kitten_release (kitten *);
void kitten_track_antecedents (kitten *);
void kitten_shuffle_clauses (kitten *);
void kitten_flip_phases (kitten *);
void kitten_randomize_phases (kitten *);
void kitten_assume (kitten *, unsigned lit);
void kitten_clause (kitten *, size_t size, unsigned *);
void kitten_unit (kitten *, unsigned);
void kitten_binary (kitten *, unsigned, unsigned);
void kitten_clause_with_id_and_exception (kitten *, unsigned id,
size_t size, const unsigned *,
unsigned except);
void kitten_no_ticks_limit (kitten *);
void kitten_set_ticks_limit (kitten *, uint64_t);
int kitten_solve (kitten *);
int kitten_status (kitten *);
signed char kitten_value (kitten *, unsigned);
signed char kitten_fixed (kitten *, unsigned);
bool kitten_failed (kitten *, unsigned);
bool kitten_flip_literal (kitten *, unsigned);
unsigned kitten_compute_clausal_core (kitten *, uint64_t *learned);
void kitten_shrink_to_clausal_core (kitten *);
void kitten_traverse_core_ids (kitten *, void *state,
void (*traverse) (void *state, unsigned id));
void kitten_traverse_core_clauses (kitten *, void *state,
void (*traverse) (void *state,
bool learned, size_t,
const unsigned *));
struct kissat;
kitten *kitten_embedded (struct kissat *);
#endif

45
src/sat/kissat/krite.c Normal file
View File

@ -0,0 +1,45 @@
#include "krite.h"
#include "inline.h"
#include "internal.h"
#include "watch.h"
#include <inttypes.h>
void kissat_write_dimacs (kissat *solver, FILE *file) {
size_t imported = SIZE_STACK (solver->import);
if (imported)
imported--;
fprintf (file, "p cnf %zu %" PRIu64 "\n", imported, BINIRR_CLAUSES);
assert (solver->watching);
if (solver->watching) {
for (all_literals (ilit))
for (all_binary_blocking_watches (watch, WATCHES (ilit)))
if (watch.type.binary) {
const unsigned iother = watch.binary.lit;
if (iother < ilit)
continue;
const int elit = kissat_export_literal (solver, ilit);
const int eother = kissat_export_literal (solver, iother);
fprintf (file, "%d %d 0\n", elit, eother);
}
} else {
for (all_literals (ilit))
for (all_binary_large_watches (watch, WATCHES (ilit)))
if (watch.type.binary) {
const unsigned iother = watch.binary.lit;
if (iother < ilit)
continue;
const int elit = kissat_export_literal (solver, ilit);
const int eother = kissat_export_literal (solver, iother);
fprintf (file, "%d %d 0\n", elit, eother);
}
}
for (all_clauses (c))
if (!c->garbage && !c->redundant) {
for (all_literals_in_clause (ilit, c)) {
const int elit = kissat_export_literal (solver, ilit);
fprintf (file, "%d ", elit);
}
fputs ("0\n", file);
}
}

9
src/sat/kissat/krite.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef _krite_h_INCLUDED
#define _krite_h_INCLUDED
#include <stdio.h>
struct kissat;
void kissat_write_dimacs (struct kissat *, FILE *);
#endif

210
src/sat/kissat/learn.c Normal file
View File

@ -0,0 +1,210 @@
#include "learn.h"
#include "backtrack.h"
#include "inline.h"
#include "reluctant.h"
#include <inttypes.h>
static unsigned backjump_limit (struct kissat *solver) {
#ifdef NOPTIONS
(void) solver;
#endif
return GET_OPTION (chrono) ? (unsigned) GET_OPTION (chronolevels)
: UINT_MAX;
}
unsigned kissat_determine_new_level (kissat *solver, unsigned jump) {
assert (solver->level);
const unsigned back = solver->level - 1;
assert (jump <= back);
const unsigned delta = back - jump;
const unsigned limit = backjump_limit (solver);
unsigned res;
if (!delta) {
res = jump;
LOG ("using identical backtrack and jump level %u", res);
} else if (delta > limit) {
res = back;
LOG ("backjumping over %u levels (%u - %u) considered inefficient",
delta, back, jump);
LOG ("backtracking chronologically to backtrack level %u", res);
INC (chronological);
} else {
res = jump;
LOG ("backjumping over %u levels (%u - %u) considered efficient", delta,
back, jump);
LOG ("backjumping non-chronologically to jump level %u", res);
}
return res;
}
static void learn_unit (kissat *solver, unsigned not_uip) {
assert (not_uip == PEEK_STACK (solver->clause, 0));
LOG ("learned unit clause %s triggers iteration", LOGLIT (not_uip));
const unsigned new_level = kissat_determine_new_level (solver, 0);
kissat_backtrack_after_conflict (solver, new_level);
kissat_learned_unit (solver, not_uip);
if (!solver->probing) {
solver->iterating = true;
INC (iterations);
}
}
static void learn_binary (kissat *solver, unsigned not_uip) {
const unsigned other = PEEK_STACK (solver->clause, 1);
const unsigned jump_level = LEVEL (other);
const unsigned new_level =
kissat_determine_new_level (solver, jump_level);
kissat_backtrack_after_conflict (solver, new_level);
#ifndef NDEBUG
const reference ref =
#endif
kissat_new_redundant_clause (solver, 1);
assert (ref == INVALID_REF);
kissat_assign_binary (solver, not_uip, other);
}
static void insert_last_learned (kissat *solver, reference ref) {
const reference *const end =
solver->last_learned + GET_OPTION (eagersubsume);
reference prev = ref;
for (reference *p = solver->last_learned; p != end; p++) {
reference tmp = *p;
*p = prev;
prev = tmp;
}
}
static reference learn_reference (kissat *solver, unsigned not_uip,
unsigned glue) {
assert (solver->level > 1);
assert (SIZE_STACK (solver->clause) > 2);
unsigned *lits = BEGIN_STACK (solver->clause);
assert (lits[0] == not_uip);
unsigned *q = lits + 1;
unsigned jump_lit = *q;
unsigned jump_level = LEVEL (jump_lit);
const unsigned *const end = END_STACK (solver->clause);
const unsigned backtrack_level = solver->level - 1;
assigned *all_assigned = solver->assigned;
for (unsigned *p = lits + 2; p != end; p++) {
const unsigned lit = *p;
const unsigned idx = IDX (lit);
const unsigned level = all_assigned[idx].level;
if (jump_level >= level)
continue;
jump_level = level;
jump_lit = lit;
q = p;
if (level == backtrack_level)
break;
}
*q = lits[1];
lits[1] = jump_lit;
const reference ref = kissat_new_redundant_clause (solver, glue);
assert (ref != INVALID_REF);
clause *c = kissat_dereference_clause (solver, ref);
c->used = MAX_USED;
const unsigned new_level =
kissat_determine_new_level (solver, jump_level);
kissat_backtrack_after_conflict (solver, new_level);
kissat_assign_reference (solver, not_uip, ref, c);
return ref;
}
void kissat_update_learned (kissat *solver, unsigned glue, unsigned size) {
assert (!solver->probing);
INC (clauses_learned);
LOG ("learned[%" PRIu64 "] clause glue %u size %u", GET (clauses_learned),
glue, size);
if (solver->stable)
kissat_tick_reluctant (&solver->reluctant);
ADD (literals_learned, size);
#ifndef QUIET
UPDATE_AVERAGE (size, size);
#endif
UPDATE_AVERAGE (fast_glue, glue);
UPDATE_AVERAGE (slow_glue, glue);
}
static void flush_last_learned (kissat *solver) {
reference *q = solver->last_learned;
const reference *const end = q + GET_OPTION (eagersubsume), *p = q;
while (p != end) {
reference ref = *p++;
if (ref != INVALID_REF)
*q++ = ref;
}
while (q != end)
*q++ = INVALID_REF;
}
static void eagerly_subsume_last_learned (kissat *solver) {
value *marks = solver->marks;
for (all_stack (unsigned, lit, solver->clause)) {
assert (!marks[lit]);
marks[lit] = 1;
}
unsigned clause_size = SIZE_STACK (solver->clause);
unsigned subsumed = 0;
reference *p = solver->last_learned;
const reference *const end = p + GET_OPTION (eagersubsume);
while (p != end) {
reference ref = *p++;
if (ref == INVALID_REF)
continue;
clause *c = kissat_dereference_clause (solver, ref);
if (c->garbage)
continue;
if (!c->redundant)
continue;
unsigned c_size = c->size;
if (c_size <= clause_size)
continue;
LOGCLS2 (c, "trying to eagerly subsume");
unsigned needed = clause_size;
unsigned remain = c_size;
for (all_literals_in_clause (lit, c)) {
if (marks[lit] && !--needed)
break;
else if (--remain < needed)
break;
}
if (needed)
continue;
LOGCLS (c, "eagerly subsumed");
kissat_mark_clause_as_garbage (solver, c);
p[-1] = INVALID_REF;
subsumed++;
INC (eagerly_subsumed);
}
for (all_stack (unsigned, lit, solver->clause))
marks[lit] = 0;
if (subsumed)
flush_last_learned (solver);
}
void kissat_learn_clause (kissat *solver) {
const unsigned not_uip = PEEK_STACK (solver->clause, 0);
const unsigned size = SIZE_STACK (solver->clause);
const size_t glue = SIZE_STACK (solver->levels);
assert (glue <= UINT_MAX);
if (!solver->probing)
kissat_update_learned (solver, glue, size);
assert (size > 0);
reference ref = INVALID_REF;
if (size == 1)
learn_unit (solver, not_uip);
else if (size == 2)
learn_binary (solver, not_uip);
else
ref = learn_reference (solver, not_uip, glue);
if (GET_OPTION (eagersubsume)) {
eagerly_subsume_last_learned (solver);
if (ref != INVALID_REF)
insert_last_learned (solver, ref);
}
}

10
src/sat/kissat/learn.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef _learn_h_INCLUDED
#define _learn_h_INCLUDED
struct kissat;
void kissat_learn_clause (struct kissat *);
void kissat_update_learned (struct kissat *, unsigned glue, unsigned size);
unsigned kissat_determine_new_level (struct kissat *, unsigned jump);
#endif

36
src/sat/kissat/literal.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef _literal_h_INCLUDED
#define _literal_h_INCLUDED
#include <limits.h>
#define LD_MAX_VAR 30u
#define LD_MAX_LIT (1 + LD_MAX_VAR)
#define EXTERNAL_MAX_VAR ((1 << LD_MAX_VAR) - 1)
#define INTERNAL_MAX_VAR ((1u << LD_MAX_VAR) - 2)
#define INTERNAL_MAX_LIT (2 * INTERNAL_MAX_VAR + 1)
#define ILLEGAL_LIT ((1u << LD_MAX_LIT) - 1)
#define INVALID_IDX UINT_MAX
#define INVALID_LIT UINT_MAX
#define VALID_INTERNAL_INDEX(IDX) ((IDX) < VARS)
#define VALID_INTERNAL_LITERAL(LIT) ((LIT) < LITS)
#define VALID_EXTERNAL_LITERAL(LIT) \
((LIT) && ((LIT) != INT_MIN) && ABS (LIT) <= EXTERNAL_MAX_VAR)
#define IDX(LIT) \
(assert (VALID_INTERNAL_LITERAL (LIT)), (((unsigned) (LIT)) >> 1))
#define LIT(IDX) (assert (VALID_INTERNAL_INDEX (IDX)), ((IDX) << 1))
#define NOT(LIT) (assert (VALID_INTERNAL_LITERAL (LIT)), ((LIT) ^ 1u))
#define NEGATED(LIT) (assert (VALID_INTERNAL_LITERAL (LIT)), ((LIT) & 1u))
#define STRIP(LIT) (assert (VALID_INTERNAL_LITERAL (LIT)), ((LIT) & ~1u))
#endif

456
src/sat/kissat/logging.c Normal file
View File

@ -0,0 +1,456 @@
#if defined(LOGGING) && !defined(QUIET)
#include "colors.h"
#include "inline.h"
#include <stdarg.h>
#include <string.h>
static void begin_logging (kissat *solver, const char *prefix,
const char *fmt, va_list *ap) {
TERMINAL (stdout, 1);
assert (GET_OPTION (log));
fputs (solver->prefix, stdout);
COLOR (MAGENTA);
printf ("%s %u ", prefix, solver->level);
vprintf (fmt, *ap);
}
static void end_logging (void) {
TERMINAL (stdout, 1);
fputc ('\n', stdout);
COLOR (NORMAL);
fflush (stdout);
}
void kissat_begin_logging (kissat *solver, const char *prefix,
const char *fmt, ...) {
va_list ap;
va_start (ap, fmt);
begin_logging (solver, prefix, fmt, &ap);
va_end (ap);
}
void kissat_end_logging (void) { end_logging (); }
void kissat_log_msg (kissat *solver, const char *prefix, const char *fmt,
...) {
va_list ap;
va_start (ap, fmt);
begin_logging (solver, prefix, fmt, &ap);
va_end (ap);
end_logging ();
}
static void append_sprintf (char *str, const char *fmt, ...) {
va_list ap;
va_start (ap, fmt);
const size_t len = strlen (str);
vsprintf (str + len, fmt, ap);
va_end (ap);
}
const char *kissat_log_repr (kissat *solver, unsigned lit,
const unsigned *repr) {
assert (solver);
char *res = kissat_next_format_string (&solver->format);
sprintf (res, "%u", lit);
if (!solver->compacting && GET_OPTION (log) > 1)
append_sprintf (res, "(%d)", kissat_export_literal (solver, lit));
if (repr && repr[lit] != lit) {
strcat (res, "[");
unsigned repr_lit = repr[lit];
append_sprintf (res, "%u", repr_lit);
if (!solver->compacting && GET_OPTION (log) > 1)
append_sprintf (res, "(%d)",
kissat_export_literal (solver, repr_lit));
strcat (res, "]");
}
if (!solver->compacting && GET_OPTION (log) > 1 && solver->values) {
const value value = VALUE (lit);
if (value) {
append_sprintf (res, "=%d", value);
if (solver->assigned)
append_sprintf (res, "@%u", LEVEL (lit));
}
}
assert (strlen (res) < FORMAT_STRING_SIZE);
return res;
}
const char *kissat_log_lit (kissat *solver, unsigned lit) {
return kissat_log_repr (solver, lit, 0);
}
const char *kissat_log_var (kissat *solver, unsigned idx) {
assert (solver);
char *res = kissat_next_format_string (&solver->format);
const unsigned lit = LIT (idx);
sprintf (res, "variable %u (literal %s)", idx, LOGLIT (lit));
assert (strlen (res) < FORMAT_STRING_SIZE);
return res;
}
static void log_lits (kissat *solver, size_t size, const unsigned *lits,
const unsigned *counts) {
for (size_t i = 0; i < size; i++) {
const unsigned lit = lits[i];
fputc (' ', stdout);
fputs (LOGLIT (lit), stdout);
if (counts)
printf ("#%u", counts[lit]);
}
}
static void log_reprs (kissat *solver, size_t size, const unsigned *lits,
const unsigned *repr) {
for (size_t i = 0; i < size; i++) {
const unsigned lit = lits[i];
fputc (' ', stdout);
fputs (LOGREPR (lit, repr), stdout);
}
}
void kissat_log_lits (kissat *solver, const char *prefix, size_t size,
const unsigned *const lits, const char *fmt, ...) {
va_list ap;
va_start (ap, fmt);
begin_logging (solver, prefix, fmt, &ap);
va_end (ap);
printf (" size %zu clause", size);
log_lits (solver, size, lits, 0);
end_logging ();
}
void kissat_log_litset (kissat *solver, const char *prefix, size_t size,
const unsigned *const lits, const char *fmt, ...) {
va_list ap;
va_start (ap, fmt);
begin_logging (solver, prefix, fmt, &ap);
va_end (ap);
printf (" size %zu literal set {", size);
log_lits (solver, size, lits, 0);
fputs (" }", stdout);
end_logging ();
}
void kissat_log_litpart (kissat *solver, const char *prefix, size_t size,
const unsigned *const lits, const char *fmt, ...) {
va_list ap;
va_start (ap, fmt);
begin_logging (solver, prefix, fmt, &ap);
va_end (ap);
size_t classes = 0;
for (size_t i = 0; i < size; i++)
if (lits[i] == INVALID_LIT)
classes++;
printf (" %zu literals %zu classes literal partition [", size - classes,
classes);
for (size_t i = 0; i < size; i++) {
const unsigned lit = lits[i];
if (lit == INVALID_LIT) {
if (i + 1 != size)
fputs (" |", stdout);
} else {
fputc (' ', stdout);
fputs (LOGLIT (lit), stdout);
}
}
fputs (" ]", stdout);
end_logging ();
}
void kissat_log_counted_ref_lits (kissat *solver, const char *prefix,
reference ref, size_t size,
const unsigned *const lits,
const unsigned *const counts,
const char *fmt, ...) {
va_list ap;
va_start (ap, fmt);
begin_logging (solver, prefix, fmt, &ap);
va_end (ap);
printf (" size %zu clause", size);
printf ("[%u]", ref);
log_lits (solver, size, lits, counts);
end_logging ();
}
void kissat_log_counted_lits (kissat *solver, const char *prefix,
size_t size, const unsigned *const lits,
const unsigned *const counts, const char *fmt,
...) {
va_list ap;
va_start (ap, fmt);
begin_logging (solver, prefix, fmt, &ap);
va_end (ap);
printf (" size %zu literals", size);
log_lits (solver, size, lits, counts);
end_logging ();
}
void kissat_log_resolvent (kissat *solver, const char *prefix,
const char *fmt, ...) {
va_list ap;
va_start (ap, fmt);
begin_logging (solver, prefix, fmt, &ap);
va_end (ap);
const size_t size = SIZE_STACK (solver->resolvent);
printf (" size %zu resolvent", size);
const unsigned *const lits = BEGIN_STACK (solver->resolvent);
log_lits (solver, size, lits, 0);
end_logging ();
}
void kissat_log_ints (kissat *solver, const char *prefix, size_t size,
const int *const lits, const char *fmt, ...) {
va_list ap;
va_start (ap, fmt);
begin_logging (solver, prefix, fmt, &ap);
va_end (ap);
printf (" size %zu external literals clause", size);
for (size_t i = 0; i < size; i++)
printf (" %d", lits[i]);
end_logging ();
}
void kissat_log_unsigneds (kissat *solver, const char *prefix, size_t size,
const unsigned *const lits, const char *fmt,
...) {
va_list ap;
va_start (ap, fmt);
begin_logging (solver, prefix, fmt, &ap);
va_end (ap);
printf (" size %zu clause", size);
for (size_t i = 0; i < size; i++)
printf (" %u", lits[i]);
end_logging ();
}
static void log_gate (kissat *solver, size_t id, const char *type,
const char *op, const char *empty_rhs_constant,
const unsigned *repr, unsigned lhs, size_t size,
const unsigned *rhs) {
printf (" arity %zu %s gate", size, type);
if (id != INVALID_GATE_ID)
printf ("[%zu]", id);
fputc (' ', stdout);
if (lhs == INVALID_LIT)
fputs ("<LHS>", stdout);
else
fputs (LOGREPR (lhs, repr), stdout);
if (size)
for (size_t i = 0; i < size; i++) {
fputc (' ', stdout);
fputs (i ? op : ":=", stdout);
fputc (' ', stdout);
fputs (LOGREPR (rhs[i], repr), stdout);
}
else {
fputs (" := ", stdout);
fputs (empty_rhs_constant, stdout);
}
}
void kissat_log_and_gate (kissat *solver, const char *prefix, size_t id,
unsigned *repr, unsigned lhs, size_t size,
const unsigned *rhs, const char *fmt, ...) {
va_list ap;
va_start (ap, fmt);
begin_logging (solver, prefix, fmt, &ap);
va_end (ap);
log_gate (solver, id, "AND", "&", "<true>", repr, lhs, size, rhs);
end_logging ();
}
void kissat_log_xor_gate (kissat *solver, const char *prefix, size_t id,
unsigned *repr, unsigned lhs, size_t size,
const unsigned *rhs, const char *fmt, ...) {
va_list ap;
va_start (ap, fmt);
begin_logging (solver, prefix, fmt, &ap);
va_end (ap);
log_gate (solver, id, "XOR", "^", "<false>", repr, lhs, size, rhs);
end_logging ();
}
void kissat_log_ite_gate (kissat *solver, const char *prefix, size_t id,
unsigned *repr, unsigned lhs, unsigned cond,
unsigned then_lit, unsigned else_lit,
const char *fmt, ...) {
va_list ap;
va_start (ap, fmt);
begin_logging (solver, prefix, fmt, &ap);
va_end (ap);
printf (" ITE gate");
if (id != INVALID_GATE_ID)
printf ("[%zu]", id);
fputc (' ', stdout);
if (lhs == INVALID_LIT)
fputs ("<LHS>", stdout);
else
fputs (LOGREPR (lhs, repr), stdout);
fputs (" := ", stdout);
fputs (LOGREPR (cond, repr), stdout);
fputs (" ? ", stdout);
fputs (LOGREPR (then_lit, repr), stdout);
fputs (" : ", stdout);
fputs (LOGREPR (else_lit, repr), stdout);
end_logging ();
}
void kissat_log_extensions (kissat *solver, const char *prefix, size_t size,
const extension *const exts, const char *fmt,
...) {
assert (size > 0);
va_list ap;
va_start (ap, fmt);
begin_logging (solver, prefix, fmt, &ap);
va_end (ap);
const extension *const begin = BEGIN_STACK (solver->extend);
const size_t pos = exts - begin;
printf (" extend[%zu]", pos);
printf (" %d", exts[0].lit);
if (size > 1)
fputs (" :", stdout);
for (size_t i = 1; i < size; i++)
printf (" %d", exts[i].lit);
end_logging ();
}
static void log_clause (kissat *solver, const clause *c) {
fputc (' ', stdout);
if (c == &solver->conflict) {
fputs ("static ", stdout);
fputs (c->redundant ? "redundant" : "irredundant", stdout);
fputs (" binary conflict clause", stdout);
} else {
if (c->redundant)
printf ("redundant glue %u", c->glue);
else
fputs ("irredundant", stdout);
printf (" size %u", c->size);
if (c->reason)
fputs (" reason", stdout);
if (c->garbage)
fputs (" garbage", stdout);
fputs (" clause", stdout);
if (kissat_clause_in_arena (solver, c)) {
reference ref = kissat_reference_clause (solver, c);
printf ("[%u]", ref);
}
}
}
void kissat_log_clause (kissat *solver, const char *prefix, const clause *c,
const char *fmt, ...) {
va_list ap;
va_start (ap, fmt);
begin_logging (solver, prefix, fmt, &ap);
va_end (ap);
log_clause (solver, c);
log_lits (solver, c->size, c->lits, 0);
end_logging ();
}
void kissat_log_counted_clause (kissat *solver, const char *prefix,
const clause *c, const unsigned *counts,
const char *fmt, ...) {
va_list ap;
va_start (ap, fmt);
begin_logging (solver, prefix, fmt, &ap);
va_end (ap);
log_clause (solver, c);
log_lits (solver, c->size, c->lits, counts);
end_logging ();
}
void kissat_log_repr_clause (kissat *solver, const char *prefix,
const clause *c, const unsigned *repr,
const char *fmt, ...) {
va_list ap;
va_start (ap, fmt);
begin_logging (solver, prefix, fmt, &ap);
va_end (ap);
log_clause (solver, c);
log_reprs (solver, c->size, c->lits, repr);
end_logging ();
}
static void log_binary (kissat *solver, unsigned a, unsigned b) {
printf (" binary clause %s %s", LOGLIT (a), LOGLIT (b));
}
void kissat_log_binary (kissat *solver, const char *prefix, unsigned a,
unsigned b, const char *fmt, ...) {
va_list ap;
va_start (ap, fmt);
begin_logging (solver, prefix, fmt, &ap);
va_end (ap);
log_binary (solver, a, b);
end_logging ();
}
void kissat_log_unary (kissat *solver, const char *prefix, unsigned a,
const char *fmt, ...) {
va_list ap;
va_start (ap, fmt);
begin_logging (solver, prefix, fmt, &ap);
va_end (ap);
printf (" unary clause %s", LOGLIT (a));
end_logging ();
}
static void log_ref (kissat *solver, reference ref) {
clause *c = kissat_dereference_clause (solver, ref);
log_clause (solver, c);
log_lits (solver, c->size, c->lits, 0);
}
void kissat_log_ref (kissat *solver, const char *prefix, reference ref,
const char *fmt, ...) {
va_list ap;
va_start (ap, fmt);
begin_logging (solver, prefix, fmt, &ap);
va_end (ap);
log_ref (solver, ref);
end_logging ();
}
void kissat_log_watch (kissat *solver, const char *prefix, unsigned lit,
watch watch, const char *fmt, ...) {
va_list ap;
va_start (ap, fmt);
begin_logging (solver, prefix, fmt, &ap);
va_end (ap);
if (watch.type.binary)
log_binary (solver, lit, watch.binary.lit);
else
log_ref (solver, watch.large.ref);
end_logging ();
}
void kissat_log_xor (kissat *solver, const char *prefix, unsigned lit,
unsigned size, const unsigned *lits, const char *fmt,
...) {
va_list ap;
va_start (ap, fmt);
begin_logging (solver, prefix, fmt, &ap);
va_end (ap);
printf (" size %u XOR gate ", size);
fputs (kissat_log_lit (solver, lit), stdout);
printf (" =");
for (unsigned i = 0; i < size; i++) {
if (i)
fputs (" ^ ", stdout);
else
fputc (' ', stdout);
fputs (kissat_log_lit (solver, lits[i]), stdout);
}
end_logging ();
}
#else
int kissat_log_dummy_to_avoid_pedantic_warning;
#endif

Some files were not shown because too many files have changed in this diff Show More