mirror of https://github.com/YosysHQ/abc.git
kissat original
This commit is contained in:
parent
c25bf73466
commit
a7476c65d8
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef _application_h_INCLUDED
|
||||
#define _application_h_INCLUDED
|
||||
|
||||
struct kissat;
|
||||
|
||||
int kissat_application (struct kissat *, int argc, char **argv);
|
||||
|
||||
#endif
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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));
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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));
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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
|
||||
|
|
@ -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");
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef NOPTIONS
|
||||
#ifndef _config_h_INCLUDED
|
||||
#define _config_h_INCLUDED
|
||||
|
||||
void kissat_configuration_usage (void);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,9 @@
|
|||
#ifndef _congruence_h_INCLUDED
|
||||
#define _congruence_h_INCLUDED
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
struct kissat;
|
||||
bool kissat_congruence (struct kissat *);
|
||||
|
||||
#endif
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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 ();
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,9 @@
|
|||
#ifndef _factor_h_INCLUDED
|
||||
#define _factor_h_INCLUDED
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
struct kissat;
|
||||
void kissat_factor (struct kissat *);
|
||||
|
||||
#endif
|
||||
|
|
@ -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
|
||||
|
|
@ -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');
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef _fastel_h_INCLUDED
|
||||
|
||||
struct kissat;
|
||||
void kissat_fast_variable_elimination (struct kissat *);
|
||||
|
||||
#endif
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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]);
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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, ¬_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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
Loading…
Reference in New Issue