Merge pull request #378 from MyskYko/kissat

Kissat
This commit is contained in:
alanminko 2025-03-05 21:57:10 +07:00 committed by GitHub
commit e7cd9a3b66
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
211 changed files with 39273 additions and 1 deletions

View File

@ -28,7 +28,7 @@ MODULES := \
src/opt/cut src/opt/fxu src/opt/fxch src/opt/rwr src/opt/mfs src/opt/sim \
src/opt/ret src/opt/fret src/opt/res src/opt/lpk src/opt/nwk src/opt/rwt src/opt/rar \
src/opt/cgt src/opt/csw src/opt/dar src/opt/dau src/opt/dsc src/opt/sfm src/opt/sbd \
src/sat/bsat src/sat/xsat src/sat/satoko src/sat/csat src/sat/msat src/sat/psat src/sat/cnf src/sat/bmc src/sat/glucose src/sat/glucose2 \
src/sat/bsat src/sat/xsat src/sat/satoko src/sat/csat src/sat/msat src/sat/psat src/sat/cnf src/sat/bmc src/sat/glucose src/sat/glucose2 src/sat/kissat \
src/bool/bdc src/bool/deco src/bool/dec src/bool/kit src/bool/lucky \
src/bool/rsb src/bool/rpo \
src/proof/pdr src/proof/abs src/proof/live src/proof/ssc src/proof/int \

View File

@ -2518,6 +2518,374 @@ SOURCE=.\src\sat\glucose2\Vec.h
SOURCE=.\src\sat\glucose2\XAlloc.h
# End Source File
# End Group
# Begin Group "kissat"
# PROP Default_Filter ""
# Begin Source File
SOURCE=.\src\sat\kissat\allocate.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\analyze.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\ands.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\arena.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\assign.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\averages.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\backbone.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\backtrack.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\build.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\bump.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\check.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\classify.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\clause.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\collect.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\colors.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\compact.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\config.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\congruence.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\decide.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\deduce.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\definition.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\dense.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\dump.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\eliminate.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\equivalences.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\error.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\extend.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\factor.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\fastel.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\file.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\flags.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\format.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\forward.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\gates.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\heap.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\ifthenelse.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\import.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\internal.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\kimits.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\kissatSolver.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\kissatTest.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\kitten.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\kptions.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\krite.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\kucky.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\learn.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\logging.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\minimize.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\mode.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\phases.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\preprocess.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\print.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\probe.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\profile.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\promote.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\proof.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\propbeyond.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\propdense.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\propinitially.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\proprobe.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\propsearch.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\queue.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\reduce.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\reluctant.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\reorder.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\rephase.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\report.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\resize.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\resolve.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\resources.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\restart.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\search.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\shrink.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\smooth.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\sort.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\stack.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\statistics.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\strengthen.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\substitute.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\sweep.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\terminate.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\tiers.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\trail.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\transitive.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\utilities.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\vector.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\vivify.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\walk.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\warmup.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\watch.c
# End Source File
# Begin Source File
SOURCE=.\src\sat\kissat\weaken.c
# End Source File
# End Group
# End Group
# Begin Group "opt"

View File

@ -56001,6 +56001,11 @@ int Abc_CommandAbc9Test( Abc_Frame_t * pAbc, int argc, char ** argv )
goto usage;
}
}
extern void kissat_solver_test();
kissat_solver_test();
return 0;
if ( pAbc->pGia == NULL )
{
Abc_Print( -1, "Abc_CommandAbc9Test(): There is no AIG.\n" );

20
src/sat/kissat/LICENSE Normal file
View File

@ -0,0 +1,20 @@
Copyright (c) 2021-2024 Armin Biere, University of Freiburg, Germany
Copyright (c) 2019-2021 Armin Biere, Johannes Kepler University Linz, Austria
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

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

@ -0,0 +1,165 @@
#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
ABC_NAMESPACE_IMPL_START
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
KISSAT_assert (!bytes);
}
char *kissat_strdup (kissat *solver, const char *str) {
char *res = (char*)kissat_malloc (solver, strlen (str) + 1);
return strcpy (res, str);
}
void kissat_freestr (struct kissat *solver, char *str) {
KISSAT_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) {
KISSAT_assert (!p);
KISSAT_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);
}
ABC_NAMESPACE_IMPL_END

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

@ -0,0 +1,41 @@
#ifndef _allocate_h_INCLUDED
#define _allocate_h_INCLUDED
#include <stdlib.h>
#include "global.h"
ABC_NAMESPACE_HEADER_START
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(T, P, N) \
do { \
(P) = (T*) kissat_nalloc (solver, (N), sizeof *(P)); \
} while (0)
#define CALLOC(T, P, N) \
do { \
(P) = (T*) kissat_calloc (solver, (N), sizeof *(P)); \
} while (0)
#define DEALLOC(P, N) \
do { \
kissat_dealloc (solver, (P), (N), sizeof *(P)); \
} while (0)
ABC_NAMESPACE_HEADER_END
#endif

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

@ -0,0 +1,583 @@
#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>
ABC_NAMESPACE_IMPL_START
static bool one_literal_on_conflict_level (kissat *solver, clause *conflict,
unsigned *conflict_level_ptr) {
KISSAT_assert (conflict);
KISSAT_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;
KISSAT_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;
}
KISSAT_assert (conflict_level != INVALID_LEVEL);
KISSAT_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;
KISSAT_assert (literals_on_conflict_level == 1);
KISSAT_assert (forced_lit != INVALID_LIT);
KISSAT_assert (jump_level != INVALID_LEVEL);
KISSAT_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) {
KISSAT_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;
KISSAT_assert (a->level);
KISSAT_assert (a->analyzed);
KISSAT_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;
KISSAT_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) {
KISSAT_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 KISSAT_NDEBUG
for (all_stack (unsigned, lit, solver->clause))
KISSAT_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));
KISSAT_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 KISSAT_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;
KISSAT_assert (level < size_frames);
frame *f = frames + level;
const unsigned used = f->used;
#ifndef KISSAT_NDEBUG
f->saved = used;
#endif
KISSAT_assert (used > 0);
KISSAT_assert (UINT_MAX - used >= pos);
f->used = pos;
pos += used;
}
unsigneds *clause = &solver->clause;
const size_t size_clause = SIZE_STACK (*clause);
#ifndef KISSAT_NDEBUG
KISSAT_assert (pos == size_clause);
#endif
unsigned const *begin_clause = BEGIN_STACK (*clause);
const unsigned *const end_clause = END_STACK (*clause);
KISSAT_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;
KISSAT_assert (level < size_frames);
frame *f = frames + level;
const unsigned pos = f->used++;
POKE_STACK (*shadow, pos, lit);
}
KISSAT_assert (size_clause == SIZE_STACK (*shadow));
SWAP (unsigneds, *clause, *shadow);
pos = 1;
p = end_levels;
while (p != begin_levels) {
const unsigned level = *--p;
KISSAT_assert (level < size_frames);
frame *f = frames + level;
const unsigned end = f->used;
KISSAT_assert (pos < end);
f->used = end - pos;
KISSAT_assert (f->used == f->saved);
pos = end;
}
CLEAR_STACK (*shadow);
LOGTMP ("level sorted deduced");
#ifndef KISSAT_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;
KISSAT_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 KISSAT_NDEBUG
const size_t size_frames = SIZE_STACK (solver->frames);
#endif
for (all_stack (unsigned, level, solver->levels)) {
KISSAT_assert (level < size_frames);
frame *f = frames + level;
KISSAT_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)) {
KISSAT_assert (idx < VARS);
struct assigned *a = assigned + idx;
KISSAT_assert (!a->poisoned);
KISSAT_assert (!a->removable);
KISSAT_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 KISSAT_NDEBUG
unsigned not_removable = 0;
#endif
for (all_stack (unsigned, idx, solver->removable)) {
KISSAT_assert (idx < VARS);
struct assigned *a = assigned + idx;
KISSAT_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) {
KISSAT_assert (!solver->probing);
#if defined(LOGGING) || !defined(KISSAT_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 KISSAT_QUIET
UPDATE_AVERAGE (trail, filled);
#endif
}
static void update_decision_rate_average (kissat *solver) {
KISSAT_assert (!solver->probing);
const uint64_t current = DECISIONS;
const uint64_t previous =
solver->averages[solver->stable].saved_decisions;
KISSAT_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) {
KISSAT_assert (solver->level == 1);
const unsigned failed = FRAME (1).decision;
LOGCLS (conflict, "analyzing failed literal %s conflict",
LOGLIT (failed));
unsigneds *units = &solver->clause;
KISSAT_assert (EMPTY_STACK (*units));
KISSAT_assert (EMPTY_STACK (solver->analyzed));
const unsigned not_failed = NOT (failed);
assigned *all_assigned = solver->assigned;
#ifndef KISSAT_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)) {
KISSAT_assert (lit != failed);
if (lit == not_failed) {
LOG ("negation %s of failed literal %s occurs in conflict",
LOGLIT (not_failed), LOGLIT (failed));
goto DONE;
}
KISSAT_assert (values[lit] < 0);
const unsigned idx = IDX (lit);
assigned *a = all_assigned + idx;
if (!a->level)
continue;
KISSAT_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 {
KISSAT_assert (t > BEGIN_ARRAY (solver->trail));
lit = *--t;
KISSAT_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));
KISSAT_assert (other != failed);
KISSAT_assert (other != unit);
KISSAT_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;
KISSAT_assert (b->level == 1);
if (!b->analyzed) {
LOG ("analyzing reason literal %s", LOGLIT (other));
kissat_push_analyzed (solver, all_assigned, idx);
unresolved++;
}
} else {
KISSAT_assert (a->reason != UNIT_REASON);
KISSAT_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)) {
KISSAT_assert (other != NOT (lit));
KISSAT_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;
}
KISSAT_assert (values[other] < 0);
const unsigned idx = IDX (other);
assigned *b = all_assigned + idx;
if (!b->level)
continue;
KISSAT_assert (b->level == 1);
if (b->analyzed)
continue;
LOG ("analyzing reason literal %s", LOGLIT (other));
kissat_push_analyzed (solver, all_assigned, idx);
unresolved++;
}
}
KISSAT_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) {
KISSAT_assert (!solver->level);
return 20;
}
START (analyze);
if (!solver->probing) {
update_trail_average (solver);
update_decision_rate_average (solver);
#ifndef KISSAT_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;
}
ABC_NAMESPACE_IMPL_END

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

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

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

@ -0,0 +1,92 @@
#include "ands.h"
#include "eliminate.h"
#include "gates.h"
#include "inline.h"
ABC_NAMESPACE_IMPL_START
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;
KISSAT_assert (ref < SIZE_STACK (solver->arena));
clause *c = (clause *) (arena + ref);
KISSAT_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);
KISSAT_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;
KISSAT_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;
}
ABC_NAMESPACE_IMPL_END

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

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

View File

@ -0,0 +1,13 @@
#ifndef _application_h_INCLUDED
#define _application_h_INCLUDED
#include "global.h"
ABC_NAMESPACE_HEADER_START
struct kissat;
int kissat_application (struct kissat *, int argc, char **argv);
ABC_NAMESPACE_HEADER_END
#endif

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

@ -0,0 +1,112 @@
#include "error.h"
#include "internal.h"
#include "logging.h"
#include "print.h"
ABC_NAMESPACE_IMPL_START
static void report_resized (kissat *solver, const char *mode,
arena before) {
#ifndef KISSAT_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) {
KISSAT_assert (size <= UINT_MAX);
const size_t res = SIZE_STACK (solver->arena);
KISSAT_assert (res <= MAX_REF);
const size_t bytes = kissat_bytes_of_clause (size);
KISSAT_assert (kissat_aligned_word (bytes));
const size_t needed = bytes / sizeof (ward);
KISSAT_assert (needed <= UINT_MAX);
size_t capacity = CAPACITY_STACK (solver->arena);
KISSAT_assert (kissat_is_power_of_two (MAX_ARENA));
KISSAT_assert (capacity <= MAX_ARENA);
size_t available = capacity - res;
if (needed > available) {
const arena before = solver->arena;
do {
KISSAT_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 KISSAT_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);
KISSAT_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 KISSAT_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(KISSAT_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
ABC_NAMESPACE_IMPL_END

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

@ -0,0 +1,51 @@
#ifndef _arena_h_INCLUDED
#define _arena_h_INCLUDED
#include "reference.h"
#include "stack.h"
#include "utilities.h"
#include "global.h"
ABC_NAMESPACE_HEADER_START
#ifdef KISSAT_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(KISSAT_NDEBUG) || defined(LOGGING)
bool kissat_clause_in_arena (const struct kissat *, const struct clause *);
#endif
static inline word kissat_align_ward (word w) {
#ifdef KISSAT_COMPACT
return kissat_align_word (w);
#else
return kissat_align_w2rd (w);
#endif
}
ABC_NAMESPACE_HEADER_END
#endif

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

@ -0,0 +1,63 @@
#ifndef _array_h_INCLUDED
#define _array_h_INCLUDED
#include "allocate.h"
#include "stack.h"
#include "global.h"
ABC_NAMESPACE_HEADER_START
#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(T, A, O, N) \
do { \
const size_t SIZE = SIZE_ARRAY (A); \
(A).begin = \
(T*) 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
ABC_NAMESPACE_HEADER_END
#endif

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

@ -0,0 +1,63 @@
#include "assign.h"
#include "inline.h"
#include "inlineassign.h"
#include "logging.h"
#include <limits.h>
ABC_NAMESPACE_IMPL_START
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) {
KISSAT_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) {
KISSAT_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);
KISSAT_assert (level <= solver->level);
KISSAT_assert (ref != DECISION_REASON);
KISSAT_assert (ref != UNIT_REASON);
kissat_assign (solver, solver->probing, level, false, lit, ref);
LOGREF (ref, "assign %s reason", LOGLIT (lit));
}
ABC_NAMESPACE_IMPL_END

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

@ -0,0 +1,64 @@
#ifndef _assign_h_INCLUDED
#define _assign_h_INCLUDED
#include <stdbool.h>
#include "global.h"
ABC_NAMESPACE_HEADER_START
#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) \
(KISSAT_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
ABC_NAMESPACE_HEADER_END
#include "reference.h"
ABC_NAMESPACE_HEADER_START
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
ABC_NAMESPACE_HEADER_END
#endif

View File

@ -0,0 +1,19 @@
#ifndef _attribute_h_INCLUDED
#define _attribute_h_INCLUDED
#include "global.h"
ABC_NAMESPACE_HEADER_START
/* #define ATTRIBUTE_FORMAT(FORMAT_POSITION, VARIADIC_ARGUMENT_POSITION) \ */
/* __attribute__ (( \ */
/* format (printf, FORMAT_POSITION, VARIADIC_ARGUMENT_POSITION))) */
#define ATTRIBUTE_FORMAT(FORMAT_POSITION, VARIADIC_ARGUMENT_POSITION)
/* #define ATTRIBUTE_ALWAYS_INLINE __attribute__ ((always_inline)) */
#define ATTRIBUTE_ALWAYS_INLINE
ABC_NAMESPACE_HEADER_END
#endif

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

@ -0,0 +1,21 @@
#include "internal.h"
ABC_NAMESPACE_IMPL_START
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 KISSAT_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;
}
ABC_NAMESPACE_IMPL_END

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

@ -0,0 +1,38 @@
#ifndef _averages_h_INCLUDED
#define _averages_h_INCLUDED
#include "smooth.h"
#include <stdbool.h>
#include "global.h"
ABC_NAMESPACE_HEADER_START
typedef struct averages averages;
struct averages {
bool initialized;
smooth fast_glue, slow_glue;
#ifndef KISSAT_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)
ABC_NAMESPACE_HEADER_END
#endif

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

@ -0,0 +1,602 @@
#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"
ABC_NAMESPACE_IMPL_START
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 KISSAT_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 KISSAT_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;
}
KISSAT_assert (prioritized <= remain);
if (!remain) {
kissat_very_verbose (solver, "no backbone candidates remain");
#ifndef KISSAT_NDEBUG
for (all_variables (idx)) {
const struct flags *f = flags + idx;
if (!f->active)
continue;
KISSAT_assert (!f->backbone0);
KISSAT_assert (!f->backbone1);
}
#endif
return;
}
#ifndef KISSAT_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)) {
KISSAT_assert (!f->backbone1);
f->backbone1 = true;
} else {
KISSAT_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);
KISSAT_assert (!values[lit]);
KISSAT_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));
KISSAT_assert (VALID_INTERNAL_LITERAL (lit));
KISSAT_assert (values[lit] > 0);
const unsigned not_lit = NOT (lit);
KISSAT_assert (values[not_lit] < 0);
KISSAT_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;
KISSAT_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);
KISSAT_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 KISSAT_NDEBUG
for (const union watch *q = p + 1; q != end_watches; q++) {
const union watch watch = *q++;
KISSAT_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++);
KISSAT_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) {
KISSAT_assert (decision_level <= solver->level);
unsigned *end_trail = END_ARRAY (*trail);
KISSAT_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));
KISSAT_assert (values[lit] > 0);
KISSAT_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) {
KISSAT_assert (conflict);
LOGCLS (conflict, "backbone analyzing");
KISSAT_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 (;;) {
KISSAT_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;
KISSAT_assert (reason != UNIT_REASON);
KISSAT_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 KISSAT_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)
KISSAT_assert (!large);
else
large = true;
}
}
#endif
static unsigned compute_backbone (kissat *solver) {
#ifndef KISSAT_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 KISSAT_QUIET
const size_t scheduled = SIZE_STACK (candidates);
#endif
#if defined(METRICS) && (!defined(KISSAT_QUIET) || !defined(KISSAT_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;
KISSAT_assert (kissat_propagated (solver));
KISSAT_assert (kissat_trail_flushed (solver));
unsigned inconsistent = INVALID_LIT;
SET_EFFORT_LIMIT (ticks_limit, backbone, backbone_ticks);
size_t round_limit = GET_OPTION (backbonerounds);
KISSAT_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;
KISSAT_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);
KISSAT_assert (!solver->level);
#if !defined(KISSAT_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) {
KISSAT_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);
KISSAT_assert (level != UINT_MAX);
#if !defined(KISSAT_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));
KISSAT_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 KISSAT_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;
}
KISSAT_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;
}
KISSAT_assert (solver->active <= active_before);
unsigned implied = active_before - solver->active;
KISSAT_assert (failed <= failed);
ADD (backbone_implied, implied);
#ifndef KISSAT_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);
KISSAT_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(KISSAT_QUIET) || !defined(KISSAT_NDEBUG))
KISSAT_assert (implied_before <= solver->statistics_.backbone_implied);
#endif
#if defined(METRICS) && !defined(KISSAT_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;
KISSAT_assert (solver->watching);
KISSAT_assert (solver->probing);
KISSAT_assert (!solver->level);
START (backbone);
INC (backbone_computations);
#if !defined(KISSAT_NDEBUG) || defined(METRICS)
KISSAT_assert (!solver->backbone_computing);
solver->backbone_computing = true;
#endif
#ifndef KISSAT_QUIET
const unsigned failed =
#endif
compute_backbone (solver);
REPORT (!failed, 'b');
#if !defined(KISSAT_NDEBUG) || defined(METRICS)
KISSAT_assert (solver->backbone_computing);
solver->backbone_computing = false;
#endif
STOP (backbone);
}
ABC_NAMESPACE_IMPL_END

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

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

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

@ -0,0 +1,181 @@
#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"
ABC_NAMESPACE_IMPL_START
static inline void unassign (kissat *solver, value *values, unsigned lit) {
LOG ("unassign %s", LOGLIT (lit));
KISSAT_assert (values[lit] > 0);
const unsigned not_lit = NOT (lit);
values[lit] = values[not_lit] = 0;
KISSAT_assert (solver->unassigned < VARS);
solver->unassigned++;
}
static inline void add_unassigned_variable_back_to_queue (kissat *solver,
links *links,
unsigned lit) {
KISSAT_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) {
KISSAT_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) {
KISSAT_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);
KISSAT_assert (idx < VARS);
struct assigned *a = assigned + idx;
const unsigned level = a->level;
if (level <= new_level) {
const unsigned new_trail = q - trail;
KISSAT_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);
KISSAT_assert (idx < VARS);
struct assigned *a = assigned + idx;
const unsigned level = a->level;
if (level <= new_level) {
const unsigned new_trail = q - trail;
KISSAT_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;
KISSAT_assert (new_end <= END_ARRAY (solver->trail));
LOG ("propagation will resume at trail position %zu",
(size_t) (new_end - trail));
solver->propagate = new_end;
KISSAT_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) {
KISSAT_assert (solver->watching);
kissat_backtrack_in_consistent_state (solver, 0);
#ifndef KISSAT_NDEBUG
clause *conflict =
#endif
solver->probing ? kissat_probing_propagate (solver, 0, true)
: kissat_search_propagate (solver);
KISSAT_assert (!conflict);
}
KISSAT_assert (kissat_propagated (solver));
KISSAT_assert (kissat_trail_flushed (solver));
}
ABC_NAMESPACE_IMPL_END

View File

@ -0,0 +1,16 @@
#ifndef _backtrack_h_INCLUDED
#define _backtrack_h_INCLUDED
#include "global.h"
ABC_NAMESPACE_HEADER_START
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 *);
ABC_NAMESPACE_HEADER_END
#endif

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

@ -0,0 +1,85 @@
#include "build.h"
#include "colors.h"
#include "kissat.h"
#include "print.h"
#include <stdio.h>
ABC_NAMESPACE_IMPL_START
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);
}
ABC_NAMESPACE_IMPL_END

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

@ -0,0 +1,10 @@
#include "global.h"
ABC_NAMESPACE_HEADER_START
#define VERSION ""
#define COMPILER ""
#define ID ""
#define BUILD ""
#define DIR ""
ABC_NAMESPACE_HEADER_END

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

@ -0,0 +1,124 @@
#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"
ABC_NAMESPACE_IMPL_START
#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);
KISSAT_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;
KISSAT_assert (0 <= decay), KISSAT_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) {
KISSAT_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) {
KISSAT_assert (solver->stable);
heap *scores = SCORES;
for (all_variables (idx))
if (ACTIVE (idx) && !kissat_heap_contains (scores, idx))
kissat_push_heap (solver, scores, idx);
}
ABC_NAMESPACE_IMPL_END

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

@ -0,0 +1,21 @@
#ifndef _bump_h_INCLUDED
#define _bump_h_INCLUDED
#include <stdbool.h>
#include "global.h"
ABC_NAMESPACE_HEADER_START
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
ABC_NAMESPACE_HEADER_END
#endif

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

File diff suppressed because it is too large Load Diff

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

@ -0,0 +1,181 @@
#ifndef _check_h_INCLUDED
#define _check_h_INCLUDED
#include <stdbool.h>
#include <stdlib.h>
#include "global.h"
ABC_NAMESPACE_HEADER_START
#ifndef KISSAT_NDEBUG
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 KISSAT_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
ABC_NAMESPACE_HEADER_END
#endif

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

@ -0,0 +1,32 @@
#include "classify.h"
#include "internal.h"
#include "print.h"
ABC_NAMESPACE_IMPL_START
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");
}
ABC_NAMESPACE_IMPL_END

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

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

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

@ -0,0 +1,191 @@
#include "allocate.h"
#include "collect.h"
#include "inline.h"
#include <string.h>
ABC_NAMESPACE_IMPL_START
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) {
KISSAT_assert (size <= UINT_MAX);
KISSAT_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) {
KISSAT_assert (first != second);
KISSAT_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) {
KISSAT_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) {
KISSAT_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);
KISSAT_assert (c->size > 2);
dec_clause (solver, c->redundant, false);
c->garbage = true;
}
void kissat_mark_clause_as_garbage (kissat *solver, clause *c) {
KISSAT_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");
KISSAT_assert (c->size > 2);
KISSAT_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);
}
ABC_NAMESPACE_IMPL_END

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

@ -0,0 +1,95 @@
#ifndef _clause_h_INCLUDED
#define _clause_h_INCLUDED
#include "arena.h"
#include "literal.h"
#include "reference.h"
#include "utilities.h"
#include <stdbool.h>
#include "global.h"
ABC_NAMESPACE_HEADER_START
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 *);
ABC_NAMESPACE_HEADER_END
#endif

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

@ -0,0 +1,742 @@
#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>
ABC_NAMESPACE_IMPL_START
static void flush_watched_clauses_by_literal (kissat *solver, unsigned lit,
bool compact,
reference start) {
KISSAT_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 {
KISSAT_assert (!lit_fixed);
KISSAT_assert (!other_fixed);
{
head.binary.lit = mother;
*q++ = head;
#ifdef LOGGING
if (lit < other) {
LOGBINARY (lit, other, "SRC");
LOGBINARY (mlit, mother, "DST");
}
#endif
}
}
} else {
KISSAT_assert (solver->watching);
const watch tail = *p++;
if (!lit_fixed) {
const reference ref = tail.large.ref;
if (ref < start) {
*q++ = head;
*q++ = tail;
}
}
}
}
KISSAT_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(KISSAT_NDEBUG)
const size_t size_mlit_watches = SIZE_WATCHES (*mlit_watches);
#endif
if (lit_fixed)
KISSAT_assert (!size_mlit_watches);
else if (mlit < lit) {
KISSAT_assert (mlit != INVALID_LIT);
KISSAT_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
KISSAT_assert (mlit == lit);
}
static void flush_all_watched_clauses (kissat *solver, bool compact,
reference start) {
KISSAT_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) {
KISSAT_assert (dst->reason);
KISSAT_assert (forced != INVALID_LIT);
reference dst_ref = kissat_reference_clause (solver, dst);
const unsigned forced_idx = IDX (forced);
struct assigned *a = assigned + forced_idx;
KISSAT_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) {
KISSAT_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;
}
KISSAT_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) {
KISSAT_assert (reducible);
KISSAT_assert (!reducible->garbage);
KISSAT_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) {
KISSAT_assert (irredundant);
KISSAT_assert (!irredundant->garbage);
KISSAT_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);
KISSAT_assert (ref != INVALID_REF);
#ifndef KISSAT_NDEBUG
const size_t size = SIZE_STACK (solver->arena);
KISSAT_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) {
KISSAT_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);
KISSAT_assert (q->redundant);
if (!first_reducible)
first_reducible = q;
r = (clause *) (bytes + (char *) r);
q = (clause *) (bytes + (char *) q);
}
KISSAT_assert ((char *) r <= (char *) redundant + bytes_redundant);
kissat_free (solver, redundant, bytes_redundant);
KISSAT_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) {
KISSAT_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
KISSAT_assert (EMPTY_STACK (solver->added));
KISSAT_assert (EMPTY_STACK (solver->removed));
const value *const values = solver->values;
assigned *assigned = solver->assigned;
#ifndef KISSAT_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 KISSAT_QUIET
flushed_garbage_clauses++;
#endif
if (last_irredundant == src) {
if (first == begin)
last_irredundant = 0;
else
last_irredundant = first;
}
continue;
}
KISSAT_assert (src->size > 1);
LOGCLS (src, "SRC");
next = kissat_next_clause (src);
#if !defined(KISSAT_NDEBUG) || defined(CHECKING_OR_PROVING)
const unsigned old_size = src->size;
#endif
KISSAT_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) {
KISSAT_assert (!satisfied);
KISSAT_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) {
KISSAT_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 KISSAT_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;
KISSAT_assert (new_size <= old_size);
KISSAT_assert (1 < new_size);
if (new_size == 2) {
KISSAT_assert (mfirst != INVALID_LIT);
KISSAT_assert (msecond != INVALID_LIT);
statistics *statistics = &solver->statistics_;
KISSAT_assert (statistics->clauses_binary < UINT64_MAX);
statistics->clauses_binary++;
bool redundant = dst->redundant;
if (redundant) {
KISSAT_assert (statistics->clauses_redundant > 0);
statistics->clauses_redundant--;
redundant = false;
} else {
KISSAT_assert (statistics->clauses_irredundant > 0);
statistics->clauses_irredundant--;
}
LOGBINARY (mfirst, msecond, "DST");
kissat_watch_binary (solver, mfirst, msecond);
if (dst->reason) {
KISSAT_assert (non_false == 1);
KISSAT_assert (other != INVALID_LIT);
KISSAT_assert (forced != INVALID_LIT);
const unsigned forced_idx = IDX (forced);
struct assigned *a = assigned + forced_idx;
KISSAT_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 {
KISSAT_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) {
KISSAT_assert (1 < new_size);
KISSAT_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(KISSAT_QUIET) || defined(METRICS)
size_t bytes = (char *) END_STACK (solver->arena) - (char *) dst;
#endif
#ifndef KISSAT_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
KISSAT_assert (first_redundant < dst);
res = kissat_reference_clause (solver, first_redundant);
KISSAT_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);
KISSAT_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);
KISSAT_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) {
KISSAT_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) {
KISSAT_assert (!solver->level);
KISSAT_assert (!solver->inconsistent);
KISSAT_assert (solver->watching);
KISSAT_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) {
KISSAT_assert (!solver->level);
KISSAT_assert (!solver->watching);
LOG ("dense garbage collection");
#ifndef KISSAT_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 KISSAT_QUIET
flushed_garbage_clauses++;
#endif
continue;
}
KISSAT_assert (src->size > 1);
LOGCLS (src, "SRC");
next = kissat_next_clause (src);
KISSAT_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(KISSAT_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) {
KISSAT_assert (!solver->watching);
KISSAT_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);
}
ABC_NAMESPACE_IMPL_END

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

@ -0,0 +1,38 @@
#ifndef _collect_h_INCLUDED
#define _collect_h_INCLUDED
#include "internal.h"
#include "global.h"
ABC_NAMESPACE_HEADER_START
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);
ABC_NAMESPACE_HEADER_END
#endif

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

@ -0,0 +1,27 @@
#include "colors.h"
#ifdef WIN32
#define isatty _isatty
#else
#include <unistd.h>
#endif
ABC_NAMESPACE_IMPL_START
int kissat_is_terminal[3] = {0, -1, -1};
int kissat_initialize_terminal (int fd) {
KISSAT_assert (fd == 1 || fd == 2);
KISSAT_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;
}
ABC_NAMESPACE_IMPL_END

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

@ -0,0 +1,73 @@
#ifndef _colors_h_INCLUDED
#define _colors_h_INCLUDED
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include "keatures.h"
#include "global.h"
ABC_NAMESPACE_HEADER_START
#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 KISSAT_assert_if_has_fileno KISSAT_assert
#else
#define KISSAT_assert_if_has_fileno(...) \
do { \
} while (0)
#endif
#define TERMINAL(F, I) \
KISSAT_assert_if_has_fileno (fileno (F) == \
I); /* 'fileno' only in POSIX not C99 */ \
KISSAT_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) {
KISSAT_assert (fd == 1 || fd == 2);
int res = kissat_is_terminal[fd];
if (res < 0)
res = kissat_initialize_terminal (fd);
KISSAT_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 : "";
}
ABC_NAMESPACE_HEADER_END
#endif

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

@ -0,0 +1,380 @@
#include "compact.h"
#include "inline.h"
#include "inlineheap.h"
#include "print.h"
#include "resize.h"
#include <string.h>
ABC_NAMESPACE_IMPL_START
static void reimport_literal (kissat *solver, unsigned eidx,
unsigned mlit) {
import *import = &PEEK_STACK (solver->import, eidx);
KISSAT_assert (import->imported);
KISSAT_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(KISSAT_QUIET) || !defined(KISSAT_NDEBUG)
const unsigned active = solver->active;
#ifndef KISSAT_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
KISSAT_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);
KISSAT_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) {
KISSAT_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);
KISSAT_assert (import->imported);
KISSAT_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;
}
KISSAT_assert (mlit <= ilit);
KISSAT_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);
KISSAT_assert (vars == active || vars == active + 1);
return vars;
}
static void compact_literal (kissat *solver, unsigned dst_lit,
unsigned src_lit) {
KISSAT_assert (dst_lit < src_lit);
KISSAT_assert (dst_lit != NOT (src_lit));
const unsigned dst_idx = IDX (dst_lit);
const unsigned src_idx = IDX (src_lit);
KISSAT_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;
KISSAT_assert (elit);
const unsigned eidx = ABS (elit);
KISSAT_assert (eidx);
import *import = &PEEK_STACK (solver->import, eidx);
KISSAT_assert (import->imported);
if (import->eliminated)
return INVALID_IDX;
const unsigned mlit = import->lit;
const unsigned midx = IDX (mlit);
KISSAT_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);
KISSAT_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);
KISSAT_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;
KISSAT_assert (VALID_INTERNAL_LITERAL (other));
const unsigned mother = kissat_map_literal (solver, other, true);
KISSAT_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);
KISSAT_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_);
KISSAT_assert (size <= UINT_MAX);
KISSAT_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 KISSAT_NDEBUG
KISSAT_assert (SIZE_STACK (solver->export_) == vars);
for (unsigned iidx = 0; iidx < vars; iidx++) {
const int elit = PEEK_STACK (solver->export_, iidx);
KISSAT_assert (VALID_EXTERNAL_LITERAL (elit));
const unsigned eidx = ABS (elit);
const import *const import = &PEEK_STACK (solver->import, eidx);
KISSAT_assert (import->imported);
if (import->eliminated)
continue;
unsigned mlit = import->lit;
if (elit < 0)
mlit = NOT (mlit);
const unsigned ilit = LIT (iidx);
KISSAT_assert (mlit == ilit);
}
#endif
}
static void compact_units (kissat *solver, unsigned mfixed) {
LOG ("compacting units (first fixed %u)", mfixed);
KISSAT_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);
KISSAT_assert (import->imported);
KISSAT_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");
KISSAT_assert (vars <= solver->vars);
#ifdef LOGGING
KISSAT_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);
}
ABC_NAMESPACE_IMPL_END

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

@ -0,0 +1,14 @@
#ifndef _compact_h_INCLUDED
#define _compact_h_INCLUDED
#include "global.h"
ABC_NAMESPACE_HEADER_START
struct kissat;
unsigned kissat_compact_literals (struct kissat *, unsigned *mfixed_ptr);
void kissat_finalize_compacting (struct kissat *, unsigned vars,
unsigned mfixed);
ABC_NAMESPACE_HEADER_END
#endif

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

@ -0,0 +1,85 @@
#include "global.h"
#ifndef KISSAT_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

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

@ -0,0 +1,14 @@
#ifndef _config_h_INCLUDED
#define _config_h_INCLUDED
#include "global.h"
ABC_NAMESPACE_HEADER_START
#ifndef KISSAT_NOPTIONS
void kissat_configuration_usage (void);
#endif
ABC_NAMESPACE_HEADER_END
#endif

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

File diff suppressed because it is too large Load Diff

View File

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

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

@ -0,0 +1,33 @@
#ifndef _cover_h_INCLUDED
#define _cover_h_INCLUDED
#include <stdio.h>
#include <stdlib.h>
#include "global.h"
ABC_NAMESPACE_HEADER_START
#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
ABC_NAMESPACE_HEADER_END
#endif

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

@ -0,0 +1,248 @@
#include "decide.h"
#include "inlineframes.h"
#include "inlineheap.h"
#include "inlinequeue.h"
#include "print.h"
#include <inttypes.h>
ABC_NAMESPACE_IMPL_START
static unsigned last_enqueued_unassigned_variable (kissat *solver) {
KISSAT_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;
KISSAT_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)
KISSAT_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);
KISSAT_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) {
KISSAT_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);
}
KISSAT_assert (res);
return res < 0 ? -1 : 1;
}
void kissat_decide (kissat *solver) {
START (decide);
KISSAT_assert (solver->unassigned);
if (solver->warming)
INC (warming_decisions);
else {
INC (decisions);
if (solver->stable)
INC (stable_decisions);
else
INC (focused_decisions);
}
solver->level++;
KISSAT_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);
KISSAT_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) {
KISSAT_assert (solver->unassigned);
KISSAT_assert (!VALUE (lit));
solver->level++;
KISSAT_assert (solver->level != INVALID_LEVEL);
kissat_push_frame (solver, lit);
KISSAT_assert (solver->level < SIZE_STACK (solver->frames));
LOG ("assuming literal %s", LOGLIT (lit));
kissat_assign_decision (solver, lit);
}
ABC_NAMESPACE_IMPL_END

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

@ -0,0 +1,19 @@
#ifndef _decide_h_INCLUDED
#define _decide_h_INCLUDED
#include "global.h"
ABC_NAMESPACE_HEADER_START
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)
ABC_NAMESPACE_HEADER_END
#endif

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

@ -0,0 +1,172 @@
#include "deduce.h"
#include "inline.h"
#include "promote.h"
#include "strengthen.h"
ABC_NAMESPACE_IMPL_START
static inline void recompute_and_promote (kissat *solver, clause *c) {
KISSAT_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) {
KISSAT_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) {
KISSAT_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);
KISSAT_assert (level <= solver->level);
#if defined(LOGGING) || !defined(KISSAT_NDEBUG)
PUSH_STACK (solver->resolvent, lit);
#endif
solver->resolvent_size++;
if (level == solver->level)
return true;
KISSAT_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);
KISSAT_assert (EMPTY_STACK (solver->analyzed));
KISSAT_assert (EMPTY_STACK (solver->levels));
KISSAT_assert (EMPTY_STACK (solver->clause));
#if defined(LOGGING) || !defined(KISSAT_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)) {
KISSAT_assert (VALUE (lit) < 0);
if (LEVEL (lit))
conflict_size++;
if (analyze_literal (solver, all_assigned, frames, lit))
unresolved_on_current_level++;
}
KISSAT_assert (unresolved_on_current_level > 1);
LOG ("starting with %u unresolved literals on current decision level",
unresolved_on_current_level);
KISSAT_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 {
KISSAT_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;
KISSAT_assert (a->reason != DECISION_REASON);
KISSAT_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);
}
KISSAT_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);
KISSAT_assert (solver->resolvent_size > 0);
solver->resolvent_size--;
#if defined(LOGGING) || !defined(KISSAT_NDEBUG)
LOG2 ("actual antecedent size %u", solver->antecedent_size);
REMOVE_STACK (unsigned, solver->resolvent, NOT (uip));
KISSAT_assert (SIZE_STACK (solver->resolvent) == solver->resolvent_size);
LOGRES2 ("new");
#endif
if (otfs && solver->antecedent_size > 2 &&
solver->resolvent_size < solver->antecedent_size) {
KISSAT_assert (!a->binary);
KISSAT_assert (solver->antecedent_size && solver->resolvent_size + 1);
clause *reason = kissat_dereference_clause (solver, a->reason);
KISSAT_assert (!reason->garbage);
clause *res = kissat_on_the_fly_strengthen (solver, reason, uip);
if (resolved == 1 && solver->resolvent_size < conflict_size) {
KISSAT_assert (!conflict->garbage);
KISSAT_assert (conflict_size > 2);
kissat_on_the_fly_subsume (solver, res, conflict);
}
STOP (deduce);
return res;
}
}
KISSAT_assert (uip != INVALID_LIT);
LOG ("first unique implication point %s (1st UIP)", LOGLIT (uip));
KISSAT_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;
}
ABC_NAMESPACE_IMPL_END

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

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

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

@ -0,0 +1,234 @@
#include "definition.h"
#include "allocate.h"
#include "gates.h"
#include "inline.h"
#include "kitten.h"
#include "print.h"
ABC_NAMESPACE_IMPL_START
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 = (definition_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);
KISSAT_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 KISSAT_NDEBUG
const size_t size_watches1 = SIZE_WATCHES (*watches1);
KISSAT_assert (size_watches1 <= UINT_MAX);
KISSAT_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(KISSAT_NDEBUG) || !defined(KISSAT_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;
KISSAT_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);
KISSAT_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++;
KISSAT_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;
KISSAT_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(KISSAT_QUIET) || !defined(KISSAT_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(KISSAT_QUIET) || !defined(KISSAT_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);
KISSAT_assert (!tmp || tmp == 20);
if (!tmp) {
LOG ("aborting core extraction");
goto ABORT;
}
#ifndef KISSAT_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);
KISSAT_assert (reduced <= previous);
#if defined(KISSAT_QUIET) && defined(KISSAT_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(KISSAT_QUIET) || !defined(KISSAT_NDEBUG)
KISSAT_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;
KISSAT_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(KISSAT_NDEBUG) || !defined(KISSAT_NPROOFS)
if (false
#ifndef KISSAT_NDEBUG
|| GET_OPTION (check) > 1
#endif
#ifndef KISSAT_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;
}
ABC_NAMESPACE_IMPL_END

View File

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

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

@ -0,0 +1,239 @@
#define INLINE_SORT
#include "dense.h"
#include "inline.h"
#include "proprobe.h"
#include "propsearch.h"
#include "trail.h"
#include "sort.c"
#include <string.h>
ABC_NAMESPACE_IMPL_START
static void flush_large_watches (kissat *solver, litpairs *irredundant) {
KISSAT_assert (!solver->level);
KISSAT_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 KISSAT_NDEBUG
for (all_literals (lit))
KISSAT_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;
KISSAT_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 {
KISSAT_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);
}
KISSAT_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) {
KISSAT_assert (!solver->level);
KISSAT_assert (solver->watching);
KISSAT_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) {
KISSAT_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];
KISSAT_assert (!ELIMINATED (IDX (first)));
KISSAT_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;
}
KISSAT_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) {
KISSAT_assert (!solver->level);
KISSAT_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 KISSAT_NDEBUG
if (conflict)
KISSAT_assert (solver->inconsistent);
else
KISSAT_assert (kissat_trail_flushed (solver));
#else
(void) conflict;
#endif
}
ABC_NAMESPACE_IMPL_END

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

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

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

@ -0,0 +1,295 @@
#include "global.h"
#ifndef KISSAT_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);
KISSAT_assert (lit_level <= level);
if (lit_level < level)
printf (" out-of-order");
assigned *a = ASSIGNED (lit);
if (!lit_level) {
printf (" UNIT\n");
KISSAT_assert (!a->binary);
KISSAT_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 {
KISSAT_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) {
KISSAT_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

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

@ -0,0 +1,607 @@
#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>
ABC_NAMESPACE_IMPL_START
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;
KISSAT_assert (prod <= occlim2);
double score = prod - sum;
KISSAT_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) {
KISSAT_assert (schedule->size);
KISSAT_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) {
KISSAT_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;
KISSAT_assert (!solver->probing);
flags *f = solver->flags + idx;
if (f->fixed)
return;
KISSAT_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;
KISSAT_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");
KISSAT_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);
}
KISSAT_assert (scheduled == kissat_size_heap (&solver->schedule));
#ifndef KISSAT_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);
KISSAT_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);
KISSAT_assert (c->garbage);
q--;
}
}
KISSAT_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;
KISSAT_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) {
KISSAT_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 {
KISSAT_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;
KISSAT_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;
KISSAT_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 KISSAT_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
KISSAT_assert (!solver->inconsistent);
KISSAT_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
KISSAT_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);
KISSAT_assert (!solver->inconsistent);
#ifndef KISSAT_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 KISSAT_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 KISSAT_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 KISSAT_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 KISSAT_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 KISSAT_QUIET
unsigned dropped = 0;
#endif
for (struct flags *f = solver->flags; f != end; f++)
if (f->eliminate) {
f->eliminate = false;
#ifndef KISSAT_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;
KISSAT_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);
KISSAT_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) {
KISSAT_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;
}
ABC_NAMESPACE_IMPL_END

View File

@ -0,0 +1,24 @@
#ifndef _eliminate_hpp_INCLUDED
#define _eliminate_hpp_INCLUDED
#include <stdbool.h>
#include "global.h"
ABC_NAMESPACE_HEADER_START
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);
ABC_NAMESPACE_HEADER_END
#endif

View File

@ -0,0 +1,41 @@
#include "gates.h"
#include "inlinevector.h"
#include "logging.h"
ABC_NAMESPACE_IMPL_START
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;
}
ABC_NAMESPACE_IMPL_END

View File

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

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

@ -0,0 +1,66 @@
#include "error.h"
#include "colors.h"
#include "cover.h"
#include <stdarg.h>
#include <stdlib.h>
ABC_NAMESPACE_IMPL_START
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 ();
}
ABC_NAMESPACE_IMPL_END

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

@ -0,0 +1,23 @@
#ifndef _error_h_INCLUDED
#define _error_h_INCLUDED
#include "attribute.h"
#include "global.h"
ABC_NAMESPACE_HEADER_START
// 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
ABC_NAMESPACE_HEADER_END
#endif

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

@ -0,0 +1,185 @@
#include "colors.h"
#include "inline.h"
ABC_NAMESPACE_IMPL_START
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);
KISSAT_assert (pos < SIZE_STACK (solver->eliminated));
KISSAT_assert (values[pos]);
LOG2 ("unassigned eliminated[%u] external variable", pos);
values[pos] = 0;
}
}
static void extend_assign (kissat *solver, value *values, int lit) {
KISSAT_assert (lit);
KISSAT_assert (lit != INT_MIN);
const unsigned idx = ABS (lit);
import *import = &PEEK_STACK (solver->import, idx);
KISSAT_assert (import->eliminated);
KISSAT_assert (import->imported);
const unsigned pos = import->lit;
KISSAT_assert (pos < SIZE_STACK (solver->eliminated));
const value value = lit < 0 ? -1 : 1;
values[pos] = value;
KISSAT_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) {
KISSAT_assert (!EMPTY_STACK (solver->extend));
KISSAT_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++;
KISSAT_assert (begin < p);
const extension ext = *--p;
const int elit = ext.lit;
if (ext.blocking)
blocking = elit;
if (satisfied)
continue;
KISSAT_assert (elit != INT_MIN);
const unsigned eidx = ABS (elit);
KISSAT_assert (eidx < SIZE_STACK (solver->import));
const import *const import = imports + eidx;
KISSAT_assert (import->imported);
if (import->eliminated) {
const unsigned tmp = import->lit;
KISSAT_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];
KISSAT_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);
KISSAT_assert (blocking_idx < SIZE_STACK (solver->import));
KISSAT_assert (imports[blocking_idx].eliminated);
const unsigned blocking_pos = imports[blocking_idx].lit;
KISSAT_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);
}
ABC_NAMESPACE_IMPL_END

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

@ -0,0 +1,35 @@
#ifndef _extend_h_INCLUDED
#define _extend_h_INCLUDED
#include "stack.h"
#include "utilities.h"
#include "global.h"
ABC_NAMESPACE_HEADER_START
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) {
KISSAT_assert (ABS (lit) < (1 << 30));
extension res;
res.blocking = blocking;
res.lit = lit;
return res;
}
struct kissat;
void kissat_extend (struct kissat *solver);
ABC_NAMESPACE_HEADER_END
#endif

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

File diff suppressed because it is too large Load Diff

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

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

View File

@ -0,0 +1,46 @@
#ifndef _fastassign_h_INCLUDED
#define _fastassign_h_INCLUDED
#define FAST_ASSIGN
#include "inline.h"
#include "inlineassign.h"
#include "global.h"
ABC_NAMESPACE_HEADER_START
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) {
KISSAT_assert (reason == kissat_dereference_clause (solver, ref));
const unsigned level =
kissat_assignment_level (solver, values, assigned, lit, reason);
KISSAT_assert (level <= solver->level);
KISSAT_assert (ref != DECISION_REASON);
KISSAT_assert (ref != UNIT_REASON);
kissat_fast_assign (solver, solver->probing, level, values, assigned,
false, lit, ref);
LOGREF (ref, "assign %s reason", LOGLIT (lit));
}
ABC_NAMESPACE_HEADER_END
#endif

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

@ -0,0 +1,938 @@
#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"
ABC_NAMESPACE_IMPL_START
static bool fast_forward_subsumed (kissat *solver, clause *c) {
KISSAT_assert (!c->garbage);
KISSAT_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;
KISSAT_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) {
KISSAT_assert (!FLAGS (IDX (clit))->eliminated);
KISSAT_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) {
KISSAT_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;
}
KISSAT_assert (!cval);
KISSAT_assert (!dval);
unsigneds *clause = &solver->clause;
KISSAT_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) {
KISSAT_assert (!FLAGS (IDX (lit))->eliminated);
if (c->garbage)
return;
KISSAT_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;
KISSAT_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) {
KISSAT_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;
KISSAT_assert (!c->redundant);
KISSAT_assert (!d->redundant);
value *values = solver->values;
mark *marks = solver->marks;
unsigneds *clause = &solver->clause;
KISSAT_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) {
KISSAT_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) {
KISSAT_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 {
KISSAT_assert (!cbin), KISSAT_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;
}
KISSAT_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) {
KISSAT_assert (!FLAGS (IDX (clit))->eliminated);
KISSAT_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) {
KISSAT_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;
}
KISSAT_assert (!cval);
KISSAT_assert (!dval);
return true;
}
static bool can_fast_resolve_binary_large (kissat *solver, unsigned pivot,
unsigned lit, clause *c) {
KISSAT_assert (!FLAGS (IDX (lit))->eliminated);
if (c->garbage)
return false;
KISSAT_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;
KISSAT_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;
KISSAT_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) {
KISSAT_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;
KISSAT_assert (!c->redundant);
KISSAT_assert (!d->redundant);
value *values = solver->values;
mark *marks = solver->marks;
bool satisfied = false;
unsigneds *clause = &solver->clause;
KISSAT_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;
}
KISSAT_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) {
KISSAT_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) {
KISSAT_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);
KISSAT_assert (!cbin), KISSAT_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) {
KISSAT_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 KISSAT_QUIET
const unsigned variables_before = solver->active;
#endif
KISSAT_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 KISSAT_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);
KISSAT_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 KISSAT_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 KISSAT_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 KISSAT_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');
}
ABC_NAMESPACE_IMPL_END

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

@ -0,0 +1,11 @@
#ifndef _fastel_h_INCLUDED
#include "global.h"
ABC_NAMESPACE_HEADER_START
struct kissat;
void kissat_fast_variable_elimination (struct kissat *);
ABC_NAMESPACE_HEADER_END
#endif

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

@ -0,0 +1,102 @@
#ifndef _fifo_h_INCLUDED
#define _fifo_h_INCLUDED
#include "stack.h"
#include <string.h>
#include "global.h"
ABC_NAMESPACE_HEADER_START
#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(T, 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) = \
(T*) 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; \
KISSAT_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(T, F, E) \
do { \
if (FULL_FIFO (F)) \
ENLARGE_FIFO (T, F); \
*END_FIFO (F)++ = (E); \
} while (0)
#define DEQUEUE_FIFO(F, E) \
do { \
KISSAT_assert (!EMPTY_FIFO (F)); \
(E) = *BEGIN_FIFO (F)++; \
if (MOVABLE_FIFO (F)) \
MOVE_FIFO (F); \
} while (0)
#define POP_FIFO(F) (KISSAT_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
ABC_NAMESPACE_HEADER_END
#endif

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

@ -0,0 +1,322 @@
#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>
#ifdef WIN32
#define unlink _unlink
#define access _access
#define R_OK 4
#define W_OK 2
#else
#include <unistd.h>
#endif
ABC_NAMESPACE_IMPL_START
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 = (char*)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 = (char*)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++)
KISSAT_assert (q + 1 < end);
*q++ = 0;
const size_t path_len = (q - dir) + name_len;
char *path = (char*)malloc (path_len + 1);
if (!path) {
free (dirs);
return false;
}
sprintf (path, "%s/%s", dir, name);
KISSAT_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) {
KISSAT_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 = (char*)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 = (char*)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) {
KISSAT_assert (file);
KISSAT_assert (file->file);
#ifdef KISSAT_HAS_COMPRESSION
if (file->close && file->compressed)
pclose (file->file);
#else
KISSAT_assert (!file->compressed);
#endif
if (file->close && !file->compressed)
fclose (file->file);
file->file = 0;
}
ABC_NAMESPACE_IMPL_END

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

@ -0,0 +1,129 @@
#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"
#include "global.h"
ABC_NAMESPACE_HEADER_START
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) {
KISSAT_assert (file);
KISSAT_assert (file->file);
KISSAT_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) {
KISSAT_assert (file);
KISSAT_assert (file->file);
KISSAT_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) {
KISSAT_assert (file);
KISSAT_assert (file->file);
KISSAT_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) {
KISSAT_assert (file);
KISSAT_assert (file->file);
KISSAT_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) {
KISSAT_assert (file);
KISSAT_assert (file->file);
KISSAT_assert (!file->reading);
#ifdef KISSAT_HAS_UNLOCKEDIO
fflush_unlocked (file->file);
#else
fflush (file->file);
#endif
}
ABC_NAMESPACE_HEADER_END
#endif

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

@ -0,0 +1,119 @@
#include "inline.h"
#include "inlineheap.h"
#include "inlinequeue.h"
ABC_NAMESPACE_IMPL_START
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;
KISSAT_assert (!f->fixed);
KISSAT_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);
}
KISSAT_assert (solver->unassigned < UINT_MAX);
solver->unassigned++;
kissat_mark_removed_literal (solver, lit);
kissat_mark_added_literal (solver, lit);
KISSAT_assert (!VALUE (lit));
KISSAT_assert (!VALUE (NOT (lit)));
KISSAT_assert (!SAVED (idx));
KISSAT_assert (!TARGET (idx));
KISSAT_assert (!BEST (idx));
}
static inline void deactivate_variable (kissat *solver, flags *f,
unsigned idx) {
KISSAT_assert (solver->flags + idx == f);
LOG ("deactivating %s", LOGVAR (idx));
KISSAT_assert (f->active);
KISSAT_assert (f->eliminated || f->fixed);
f->active = false;
KISSAT_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) {
KISSAT_assert (VALUE (lit) > 0);
const unsigned idx = IDX (lit);
LOG ("marking internal %s as fixed", LOGVAR (idx));
flags *f = FLAGS (idx);
KISSAT_assert (f->active);
KISSAT_assert (!f->eliminated);
KISSAT_assert (!f->fixed);
f->fixed = true;
deactivate_variable (solver, f, idx);
INC (units);
int elit = kissat_export_literal (solver, lit);
KISSAT_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);
KISSAT_assert (!VALUE (lit));
LOG ("marking internal %s as eliminated", LOGVAR (idx));
flags *f = FLAGS (idx);
KISSAT_assert (f->active);
KISSAT_assert (!f->eliminated);
KISSAT_assert (!f->fixed);
f->eliminated = true;
deactivate_variable (solver, f, idx);
int elit = kissat_export_literal (solver, lit);
KISSAT_assert (elit);
KISSAT_assert (elit != INT_MIN);
unsigned eidx = ABS (elit);
import *import = &PEEK_STACK (solver->import, eidx);
KISSAT_assert (!import->eliminated);
KISSAT_assert (import->imported);
KISSAT_assert (STRIP (import->lit) == STRIP (lit));
size_t pos = SIZE_STACK (solver->eliminated);
KISSAT_assert (pos < (1u << 30));
import->lit = pos;
import->eliminated = true;
PUSH_STACK (solver->eliminated, (value) 0);
LOG ("marked external variable %u as eliminated", eidx);
KISSAT_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]);
}
ABC_NAMESPACE_IMPL_END

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

@ -0,0 +1,42 @@
#ifndef _flags_h_INCLUDED
#define _flags_h_INCLUDED
#include <stdbool.h>
#include "global.h"
ABC_NAMESPACE_HEADER_START
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) (KISSAT_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 *);
ABC_NAMESPACE_HEADER_END
#endif

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

@ -0,0 +1,149 @@
#include "format.h"
#include <assert.h>
#include <inttypes.h>
#include <limits.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
ABC_NAMESPACE_IMPL_START
char *kissat_next_format_string (kormat *format) {
KISSAT_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++)
KISSAT_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 (kormat *format, uint64_t w) {
char *res = kissat_next_format_string (format);
format_count (res, w);
return res;
}
const char *kissat_format_value (kormat *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 (kormat *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 (kormat *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 (kormat *format, unsigned size,
word signs) {
char *res = kissat_next_format_string (format);
KISSAT_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 (kormat *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;
}
ABC_NAMESPACE_IMPL_END

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

@ -0,0 +1,47 @@
#ifndef _format_h_INCLUDED
#define _format_h_INCLUDED
#include "utilities.h"
#include <stdbool.h>
#include <stdint.h>
#include "global.h"
ABC_NAMESPACE_HEADER_START
#define NUM_FORMAT_STRINGS 16
#define FORMAT_STRING_SIZE 128
typedef struct kormat kormat;
struct kormat {
unsigned pos;
char str[NUM_FORMAT_STRINGS][FORMAT_STRING_SIZE];
};
char *kissat_next_format_string (kormat *);
char const *kissat_format_bytes (kormat *, uint64_t bytes);
char const *kissat_format_count (kormat *, uint64_t);
char const *kissat_format_ordinal (kormat *, uint64_t);
char const *kissat_format_signs (kormat *, unsigned size, word);
char const *kissat_format_time (kormat *, double seconds);
char const *kissat_format_value (kormat *, 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)
ABC_NAMESPACE_HEADER_END
#endif

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

@ -0,0 +1,695 @@
#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>
ABC_NAMESPACE_IMPL_START
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++;
KISSAT_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(KISSAT_QUIET) || !defined(KISSAT_NDEBUG)
size_t removed = 0;
#endif
KISSAT_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(KISSAT_QUIET) || !defined(KISSAT_NDEBUG)
removed +=
#endif
remove_duplicated_binaries_with_literal (solver, lit);
#if !defined(KISSAT_QUIET) || !defined(KISSAT_NDEBUG)
removed +=
#endif
remove_duplicated_binaries_with_literal (solver, not_lit);
}
KISSAT_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;
KISSAT_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);
KISSAT_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) {
KISSAT_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));
KISSAT_assert (!subsume);
*remove = not_other;
break;
}
}
} else {
const reference ref = watch.large.ref;
KISSAT_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);
KISSAT_assert (d->garbage);
candidate = INVALID_LIT;
subsume = false;
break;
}
if (!subsume) {
KISSAT_assert (candidate != INVALID_LIT);
candidate = INVALID_LIT;
break;
}
subsume = false;
const unsigned not_other = NOT (other);
if (!marks[not_other]) {
KISSAT_assert (candidate == INVALID_LIT);
break;
}
candidate = not_other;
}
if (d->garbage) {
KISSAT_assert (!subsume);
q--;
break;
}
if (subsume) {
LOGCLS (d, "forward subsuming");
KISSAT_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;
KISSAT_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) {
KISSAT_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);
KISSAT_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) {
KISSAT_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;
KISSAT_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;
KISSAT_assert (!value);
lits[new_size++] = lit;
kissat_mark_added_literal (solver, lit);
}
KISSAT_assert (new_size == non_false - 1);
KISSAT_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 {
KISSAT_assert (non_false == 3);
LOGCLS (c, "garbage");
KISSAT_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;
KISSAT_assert (!value);
if (first == INVALID_LIT)
first = lit;
else {
KISSAT_assert (second == INVALID_LIT);
second = lit;
}
kissat_mark_added_literal (solver, lit);
}
KISSAT_assert (first != INVALID_LIT);
KISSAT_assert (second != INVALID_LIT);
LOGBINARY (first, second, "forward strengthened");
kissat_watch_other (solver, first, second);
kissat_watch_other (solver, second, first);
KISSAT_assert (new_binaries);
KISSAT_assert (solver->statistics_.clauses_irredundant);
solver->statistics_.clauses_irredundant--;
KISSAT_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) {
KISSAT_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 KISSAT_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 KISSAT_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);
KISSAT_assert (kissat_clause_in_arena (solver, c));
KISSAT_assert (!c->garbage);
#ifndef KISSAT_QUIET
checked++;
#endif
bool not_subsumed_but_strengthened = false;
if (forward_subsumed_clause (
solver, c, &not_subsumed_but_strengthened, &new_binaries)) {
#ifndef KISSAT_QUIET
subsumed++;
#endif
} else if (not_subsumed_but_strengthened) {
#ifndef KISSAT_QUIET
strengthened++;
#endif
}
if (solver->inconsistent)
break;
if (!c->garbage)
connect_subsuming (solver, occlim, c);
}
}
#ifndef KISSAT_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 KISSAT_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);
KISSAT_assert (kissat_clause_in_arena (solver, c));
if (c->garbage)
continue;
if (q < p && !c->subsume)
continue;
#ifndef KISSAT_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;
KISSAT_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;
KISSAT_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 KISSAT_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 KISSAT_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);
KISSAT_assert (GET_OPTION (forward));
INC (forward_subsumptions);
KISSAT_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;
}
ABC_NAMESPACE_IMPL_END

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

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

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

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

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

@ -0,0 +1,108 @@
#include "gates.h"
#include "ands.h"
#include "definition.h"
#include "eliminate.h"
#include "equivalences.h"
#include "ifthenelse.h"
#include "inline.h"
ABC_NAMESPACE_IMPL_START
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;
KISSAT_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) {
KISSAT_assert (!solver->watching);
KISSAT_assert (!negative || negative == 1);
statches *gates = solver->gates + negative;
watches *watches = &WATCHES (lit);
statches *antecedents = solver->antecedents + negative;
KISSAT_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);
}
KISSAT_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);
}
ABC_NAMESPACE_IMPL_END

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

@ -0,0 +1,27 @@
#ifndef _gates_h_INCLUDED
#define _gates_h_INCLUDED
#include <stdbool.h>
#include <stdlib.h>
#include "global.h"
ABC_NAMESPACE_HEADER_START
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
ABC_NAMESPACE_HEADER_END
#endif

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

@ -0,0 +1,14 @@
#ifndef ABC_SAT_KISSAT_GLOBAL_H_
#define ABC_SAT_KISSAT_GLOBAL_H_
#define KISSAT_COMPACT
#define KISSAT_NDEBUG
#define KISSAT_NOPTIONS
#define KISSAT_NPROOFS
#define KISSAT_QUIET
#define KISSAT_assert(ignore) ((void)0)
#include "misc/util/abc_global.h"
#endif

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

@ -0,0 +1,48 @@
#ifndef _handle_h_INCLUDED
#define _handle_h_INCLUDED
#include <signal.h>
#include "global.h"
ABC_NAMESPACE_HEADER_START
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
ABC_NAMESPACE_HEADER_END
#endif

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

@ -0,0 +1,112 @@
#include "allocate.h"
#include "inlineheap.h"
#include "internal.h"
#include "logging.h"
#include <string.h>
ABC_NAMESPACE_IMPL_START
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 KISSAT_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];
KISSAT_assert (idx_pos == i);
unsigned child_pos = HEAP_CHILD (idx_pos);
unsigned parent_pos = HEAP_PARENT (child_pos);
KISSAT_assert (parent_pos == idx_pos);
if (child_pos < end) {
unsigned child = stack[child_pos];
KISSAT_assert (score[idx] >= score[child]);
if (++child_pos < end) {
parent_pos = HEAP_PARENT (child_pos);
KISSAT_assert (parent_pos == idx_pos);
child = stack[child_pos];
KISSAT_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 = (unsigned*)kissat_nrealloc (solver, heap->pos, old_size, new_size,
sizeof (unsigned));
if (heap->tainted) {
heap->score = (double*)kissat_nrealloc (solver, heap->score, old_size, new_size,
sizeof (double));
} else {
if (old_size)
DEALLOC (heap->score, old_size);
heap->score = (double*)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 KISSAT_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;
KISSAT_assert (old_vars < new_vars);
KISSAT_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 KISSAT_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
ABC_NAMESPACE_IMPL_END

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

@ -0,0 +1,90 @@
#ifndef _heap_h_INCLUDED
#define _heap_h_INCLUDED
#include "stack.h"
#include "utilities.h"
#include <assert.h>
#include <limits.h>
#include <stdbool.h>
#include "global.h"
ABC_NAMESPACE_HEADER_START
#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) {
KISSAT_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;
KISSAT_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 KISSAT_NDEBUG
void kissat_dump_heap (heap *);
#endif
#ifndef KISSAT_NDEBUG
void kissat_check_heap (heap *);
#else
#define kissat_check_heap(...) \
do { \
} while (0)
#endif
ABC_NAMESPACE_HEADER_END
#endif

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

@ -0,0 +1,178 @@
#include "ifthenelse.h"
#include "eliminate.h"
#include "gates.h"
#include "inline.h"
ABC_NAMESPACE_IMPL_START
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;
KISSAT_assert (a != INVALID_LIT);
KISSAT_assert (b != INVALID_LIT);
KISSAT_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);
KISSAT_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);
KISSAT_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;
}
ABC_NAMESPACE_IMPL_END

View File

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

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

@ -0,0 +1,104 @@
#include "internal.h"
#include "logging.h"
#include "resize.h"
ABC_NAMESPACE_IMPL_START
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);
KISSAT_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);
KISSAT_assert (import->imported);
ilit = import->lit;
if (elit < 0)
ilit = NOT (ilit);
KISSAT_assert (VALID_INTERNAL_LITERAL (ilit));
return ilit;
}
unsigned kissat_import_literal (kissat *solver, int elit) {
KISSAT_assert (VALID_EXTERNAL_LITERAL (elit));
if (GET_OPTION (tumble))
return import_literal (solver, elit, false);
const unsigned eidx = ABS (elit);
KISSAT_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 {
KISSAT_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);
KISSAT_assert (imported <= EXTERNAL_MAX_VAR);
if (imported == EXTERNAL_MAX_VAR) {
LOG ("can not get another external variable");
return INVALID_LIT;
}
KISSAT_assert (imported <= (unsigned) INT_MAX);
int eidx = (int) imported;
unsigned res = import_literal (solver, eidx, true);
#ifndef KISSAT_NDEBUG
struct import *import = &PEEK_STACK (solver->import, imported);
KISSAT_assert (import->imported);
KISSAT_assert (import->extension);
#endif
INC (fresh);
kissat_activate_literal (solver, res);
return res;
}
ABC_NAMESPACE_IMPL_END

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

@ -0,0 +1,14 @@
#ifndef _import_h_INLCUDED
#define _import_h_INLCUDED
#include "global.h"
ABC_NAMESPACE_HEADER_START
struct kissat;
unsigned kissat_import_literal (struct kissat *solver, int lit);
unsigned kissat_fresh_literal (struct kissat *solver);
ABC_NAMESPACE_HEADER_END
#endif

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

@ -0,0 +1,333 @@
#ifndef _inline_h_INCLUDED
#define _inline_h_INCLUDED
#include "inlinevector.h"
#include "logging.h"
#include "global.h"
ABC_NAMESPACE_HEADER_START
#ifdef METRICS
static inline size_t kissat_allocated (kissat *solver) {
return solver->statistics.allocated_current;
}
#endif
static inline bool kissat_propagated (kissat *solver) {
KISSAT_assert (BEGIN_ARRAY (solver->trail) <= solver->propagate);
KISSAT_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) {
KISSAT_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) {
KISSAT_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) {
KISSAT_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) {
KISSAT_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) {
KISSAT_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) {
KISSAT_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) {
KISSAT_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) {
KISSAT_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);
KISSAT_assert (kissat_clause_in_arena (solver, res));
return res;
}
static inline reference kissat_reference_clause (kissat *solver,
const clause *c) {
KISSAT_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) {
KISSAT_assert (!solver->watching);
KISSAT_assert (ref == kissat_reference_clause (solver, c));
KISSAT_assert (c == kissat_dereference_clause (solver, ref));
for (all_literals_in_clause (lit, c)) {
KISSAT_assert (!solver->watching);
LOGREF3 (ref, "connecting %s in", LOGLIT (lit));
KISSAT_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) {
KISSAT_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);
KISSAT_assert (iidx < (unsigned) INT_MAX);
int elit = PEEK_STACK (solver->export_, iidx);
if (!elit)
return 0;
if (NEGATED (ilit))
elit = -elit;
KISSAT_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) {
KISSAT_assert (idx < VARS);
struct assigned *a = assigned + idx;
KISSAT_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) {
KISSAT_assert (idx < VARS);
struct assigned *a = assigned + idx;
KISSAT_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) {
KISSAT_assert (idx < VARS);
struct assigned *a = assigned + idx;
KISSAT_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) {
KISSAT_assert (idx < VARS);
struct assigned *a = assigned + idx;
KISSAT_assert (!a->shrinkable);
a->shrinkable = true;
PUSH_STACK (solver->shrinkable, idx);
LOG2 ("%s shrinkable", LOGVAR (idx));
}
static inline int kissat_checking (kissat *solver) {
#ifndef KISSAT_NDEBUG
#ifdef KISSAT_NOPTIONS
(void) solver;
#endif
return GET_OPTION (check);
#else
(void) solver;
return 0;
#endif
}
static inline bool kissat_logging (kissat *solver) {
#ifdef LOGGING
#ifdef KISSAT_NOPTIONS
(void) solver;
#endif
return GET_OPTION (log) > 0;
#else
(void) solver;
return false;
#endif
}
static inline bool kissat_proving (kissat *solver) {
#ifdef KISSAT_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(KISSAT_NDEBUG) || !defined(KISSAT_NPROOFS)
#define CHECKING_OR_PROVING
#endif
ABC_NAMESPACE_HEADER_END
#endif

View File

@ -0,0 +1,107 @@
#ifndef _inlineassign_h_INLCUDED
#define _inlineassign_h_INLCUDED
#include "global.h"
ABC_NAMESPACE_HEADER_START
#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);
#ifndef WIN32
__builtin_prefetch (w, 0, 1);
#endif
}
#ifndef FAST_ASSIGN
value *values = solver->values;
#endif
KISSAT_assert (!values[lit]);
KISSAT_assert (!values[not_lit]);
values[lit] = 1;
values[not_lit] = -1;
KISSAT_assert (solver->unassigned > 0);
solver->unassigned--;
if (!level) {
kissat_mark_fixed_literal (solver, lit);
KISSAT_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;
KISSAT_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 KISSAT_NDEBUG
(void) solver;
#endif
return res;
}
ABC_NAMESPACE_HEADER_END
#endif

View File

@ -0,0 +1,23 @@
#ifndef _inlineframes_h_INCLUDEDd
#define _inlineframes_h_INCLUDEDd
#include "allocate.h"
#include "internal.h"
#include "global.h"
ABC_NAMESPACE_HEADER_START
static inline void kissat_push_frame (kissat *solver, unsigned decision) {
KISSAT_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);
}
ABC_NAMESPACE_HEADER_END
#endif

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

@ -0,0 +1,181 @@
#ifndef _inlineheap_h_INCLUDED
#define _inlineheap_h_INCLUDED
#include "allocate.h"
#include "internal.h"
#include "logging.h"
#include "global.h"
ABC_NAMESPACE_HEADER_START
#define HEAP_CHILD(POS) (KISSAT_assert ((POS) < (1u << 31)), (2 * (POS) + 1))
#define HEAP_PARENT(POS) (KISSAT_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 { \
KISSAT_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);
KISSAT_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);
KISSAT_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) {
KISSAT_assert (!EMPTY_STACK (heap->stack));
unsigneds *stack = &heap->stack;
unsigned *const begin = BEGIN_STACK (*stack);
const unsigned idx = *begin;
KISSAT_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;
KISSAT_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
}
ABC_NAMESPACE_HEADER_END
#endif

View File

@ -0,0 +1,122 @@
#ifndef _inlinequeue_h_INCLUDED
#define _inlinequeue_h_INCLUDED
#include "internal.h"
#include "logging.h"
#include "global.h"
ABC_NAMESPACE_HEADER_START
static inline void kissat_update_queue (kissat *solver, const links *links,
unsigned idx) {
KISSAT_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;
KISSAT_assert (DISCONNECTED (p->prev));
KISSAT_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;
KISSAT_assert (DISCONNECTED (l->next));
l->next = i;
}
if (queue->stamp == UINT_MAX) {
kissat_reassign_queue_stamps (solver);
KISSAT_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)) {
KISSAT_assert (queue->first == i);
queue->first = k;
} else {
struct links *p = links + j;
KISSAT_assert (p->next == i);
p->next = k;
}
if (DISCONNECTED (k)) {
KISSAT_assert (queue->last == i);
queue->last = j;
} else {
struct links *n = links + k;
KISSAT_assert (n->prev == i);
n->prev = j;
}
}
static inline void kissat_enqueue (kissat *solver, unsigned idx) {
KISSAT_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) {
KISSAT_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) {
KISSAT_assert (DISCONNECTED (links[idx].next));
return;
}
KISSAT_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;
KISSAT_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);
}
ABC_NAMESPACE_HEADER_END
#endif

View File

@ -0,0 +1,198 @@
#ifndef _inlinevector_h_INCLUDED
#define _inlinevector_h_INCLUDED
#include "internal.h"
#include "global.h"
ABC_NAMESPACE_HEADER_START
static inline unsigned *kissat_begin_vector (kissat *solver,
vector *vector) {
#ifdef KISSAT_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 KISSAT_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 KISSAT_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 KISSAT_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 KISSAT_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 KISSAT_COMPACT
return vector->size;
#else
return vector->end - vector->begin;
#endif
}
static inline bool kissat_empty_vector (vector *vector) {
#ifdef KISSAT_COMPACT
return !vector->size;
#else
return vector->end == vector->begin;
#endif
}
static inline void kissat_inc_usable (kissat *solver) {
KISSAT_assert (MAX_SECTOR > solver->vectors.usable);
solver->vectors.usable++;
}
static inline void kissat_add_usable (kissat *solver, size_t inc) {
KISSAT_assert (MAX_SECTOR - inc >= solver->vectors.usable);
solver->vectors.usable += inc;
}
static inline unsigned *kissat_last_vector_pointer (kissat *solver,
vector *vector) {
KISSAT_assert (!kissat_empty_vector (vector));
#ifdef KISSAT_COMPACT
KISSAT_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) {
KISSAT_assert (!kissat_empty_vector (vector));
#ifdef KISSAT_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) {
KISSAT_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;
KISSAT_assert (e != INVALID_VECTOR_ELEMENT);
if (
#ifdef KISSAT_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);
KISSAT_assert (*end == INVALID_VECTOR_ELEMENT);
*end = e;
kissat_dec_usable (solver);
} else {
#ifdef KISSAT_COMPACT
KISSAT_assert ((uint64_t) SIZE_STACK (*stack) < MAX_VECTORS);
vector->offset = SIZE_STACK (*stack);
KISSAT_assert (vector->offset);
*stack->end++ = e;
#else
KISSAT_assert (stack->end < stack->allocated);
*(vector->begin = stack->end++) = e;
#endif
}
#if !defined(KISSAT_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);
KISSAT_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);
KISSAT_assert (*end == INVALID_VECTOR_ELEMENT);
*end = e;
kissat_dec_usable (solver);
}
}
#ifndef KISSAT_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
ABC_NAMESPACE_HEADER_END
#endif

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

@ -0,0 +1,528 @@
#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>
ABC_NAMESPACE_IMPL_START
void kissat_reset_last_learned (kissat *solver) {
for (really_all_last_learned (p))
*p = INVALID_REF;
}
kissat *kissat_init (void) {
kissat *solver = (kissat*)kissat_calloc (0, 1, sizeof *solver);
#ifndef KISSAT_NOPTIONS
kissat_init_options (&solver->options);
#else
kissat_init_options ();
#endif
#ifndef KISSAT_QUIET
kissat_init_profiles (&solver->profiles);
#endif
START (total);
kissat_init_queue (solver);
KISSAT_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 KISSAT_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(KISSAT_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(KISSAT_NDEBUG) || !defined(KISSAT_NPROOFS)
RELEASE_STACK (solver->added);
RELEASE_STACK (solver->removed);
#endif
#if !defined(KISSAT_NDEBUG) || !defined(KISSAT_NPROOFS) || defined(LOGGING)
RELEASE_STACK (solver->original);
#endif
#ifndef KISSAT_QUIET
RELEASE_STACK (solver->profiles.stack);
#endif
kissat_freestr (solver, solver->prefix);
#ifndef KISSAT_NDEBUG
kissat_release_checker (solver);
#endif
#if !defined(KISSAT_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 KISSAT_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 KISSAT_NOPTIONS
kissat_require_initialized (solver);
kissat_require (name, "name zero pointer");
#ifndef KISSAT_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;
KISSAT_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;
KISSAT_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 KISSAT_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 KISSAT_NPROOFS
if (solver->proof) {
kissat_section (solver, "proof");
kissat_print_proof_statistics (solver, verbose);
}
#endif
#ifndef KISSAT_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(KISSAT_NDEBUG) || !defined(KISSAT_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(KISSAT_NDEBUG) || !defined(KISSAT_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;
KISSAT_assert (SIZE_STACK (solver->clause) < UINT_MAX);
PUSH_STACK (solver->clause, ilit);
}
} else if (mark < 0) {
KISSAT_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 {
KISSAT_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(KISSAT_NDEBUG) || !defined(KISSAT_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;
KISSAT_assert (esize <= UINT_MAX);
#endif
ADD_UNCHECKED_EXTERNAL (esize, elits);
const size_t isize = SIZE_STACK (solver->clause);
unsigned *ilits = BEGIN_STACK (solver->clause);
KISSAT_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);
KISSAT_assert (v < 0);
KISSAT_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);
KISSAT_assert (v < 0);
KISSAT_assert (k > l);
KISSAT_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);
KISSAT_assert (k <= l);
} else if (!u && v > 0) {
LOG ("first watch unassigned "
"second falsified at level @%u",
l);
assign = true;
} else {
KISSAT_assert (!u);
KISSAT_assert (!v);
}
if (assign) {
KISSAT_assert (solver->level > 0);
if (isize == 2) {
KISSAT_assert (res == INVALID_REF);
kissat_assign_binary (solver, a, b);
} else {
KISSAT_assert (res != INVALID_REF);
clause *c = kissat_dereference_clause (solver, res);
kissat_assign_reference (solver, a, res, c);
}
}
}
}
#if !defined(KISSAT_NDEBUG) || !defined(KISSAT_NPROOFS)
if (solver->clause_satisfied || solver->clause_trivial) {
#ifndef KISSAT_NDEBUG
if (checking > 1)
kissat_remove_checker_external (solver, esize, elits);
#endif
#ifndef KISSAT_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 KISSAT_NDEBUG
if (checking > 1) {
kissat_check_and_add_internal (solver, isize, ilits);
kissat_remove_checker_external (solver, esize, elits);
}
#endif
#ifndef KISSAT_NPROOFS
if (proving) {
kissat_add_lits_to_proof (solver, isize, ilits);
kissat_delete_external_from_proof (solver, esize, elits);
}
#endif
}
#endif
#if !defined(KISSAT_NDEBUG) || !defined(KISSAT_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;
KISSAT_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;
}
int kissat_is_inconsistent(kissat *solver) {
return solver->inconsistent;
}
ABC_NAMESPACE_IMPL_END

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

@ -0,0 +1,300 @@
#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"
#include "global.h"
ABC_NAMESPACE_HEADER_START
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(KISSAT_NDEBUG) || defined(METRICS)
bool backbone_computing;
#endif
#ifdef LOGGING
bool compacting;
#endif
bool extended;
bool inconsistent;
bool iterating;
bool preprocessing;
bool probing;
#ifndef KISSAT_QUIET
bool sectioned;
#endif
bool stable;
#if !defined(KISSAT_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(KISSAT_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;
kormat 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(KISSAT_NDEBUG) || !defined(KISSAT_NPROOFS)
unsigneds added;
unsigneds removed;
#endif
#if !defined(KISSAT_NDEBUG) || !defined(KISSAT_NPROOFS) || defined(LOGGING)
ints original;
size_t offset_of_last_original_clause;
#endif
#ifndef KISSAT_QUIET
profiles profiles;
#endif
#ifndef KISSAT_NOPTIONS
options options;
#endif
#ifndef KISSAT_NDEBUG
checker *checker;
#endif
#ifndef KISSAT_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) {
KISSAT_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);
ABC_NAMESPACE_HEADER_END
#endif

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

@ -0,0 +1,23 @@
#ifndef _keatures_h_INCLUDED
#define _keatures_h_INCLUDED
#include "global.h"
ABC_NAMESPACE_HEADER_START
#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
ABC_NAMESPACE_HEADER_END
#endif

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

@ -0,0 +1,198 @@
#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>
ABC_NAMESPACE_IMPL_START
double kissat_logn (uint64_t count) {
KISSAT_assert (count > 0);
const double res = log10 (count + 9);
KISSAT_assert (res >= 1);
return res;
}
double kissat_sqrt (uint64_t count) {
KISSAT_assert (count > 0);
const double res = sqrt (count);
KISSAT_assert (res >= 1);
return res;
}
double kissat_nlogpown (uint64_t count, unsigned exponent) {
KISSAT_assert (count > 0);
const double tmp = log10 (count + 9);
double factor = 1;
while (exponent--)
factor *= tmp;
KISSAT_assert (factor >= 1);
const double res = count * factor;
KISSAT_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;
KISSAT_assert (ff >= 0);
const double fff = 4.5 * ff + 25;
uint64_t scaled = fff * delta;
KISSAT_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) {
KISSAT_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 KISSAT_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 {
KISSAT_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 KISSAT_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 KISSAT_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 KISSAT_QUIET
(void) solver;
#endif
}
ABC_NAMESPACE_IMPL_END

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

@ -0,0 +1,190 @@
#ifndef _limits_h_INCLUDED
#define _limits_h_INCLUDED
#include <stdbool.h>
#include <stdint.h>
#include "global.h"
ABC_NAMESPACE_HEADER_START
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_; \
KISSAT_assert (statistics->COUNT > 0); \
struct limits *limits = &solver->limits; \
uint64_t DELTA = GET_OPTION (NAME##int); \
const double SCALING = SCALE_COUNT_FUNCTION (statistics->COUNT); \
KISSAT_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)
ABC_NAMESPACE_HEADER_END
#endif

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

@ -0,0 +1,52 @@
#ifndef _kissat_h_INCLUDED
#define _kissat_h_INCLUDED
#include "global.h"
ABC_NAMESPACE_HEADER_START
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);
// Extra API functions.
int kissat_is_inconsistent(kissat *solver);
ABC_NAMESPACE_HEADER_END
#endif

View File

@ -0,0 +1,198 @@
/**CFile****************************************************************
FileName [kissatSolver.c]
SystemName [ABC: Logic synthesis and verification system.]
PackageName []
Synopsis []
Author [Alan Mishchenko]
Affiliation [UC Berkeley]
Date [Ver. 1.0. Started - June 20, 2005.]
Revision [$Id: kissatSolver.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
***********************************************************************/
#include "kissat.h"
#include "kissatSolver.h"
ABC_NAMESPACE_IMPL_START
////////////////////////////////////////////////////////////////////////
/// DECLARATIONS ///
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
/// FUNCTION DEFINITIONS ///
////////////////////////////////////////////////////////////////////////
/**Function*************************************************************
Synopsis [allocate solver]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
kissat_solver* kissat_solver_new(void) {
kissat_solver* s = (kissat_solver*)malloc(sizeof(kissat_solver));
s->p = (void*)kissat_init();
s->nVars = 0;
return s;
}
/**Function*************************************************************
Synopsis [delete solver]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void kissat_solver_delete(kissat_solver* s) {
kissat_release((kissat*)s->p);
free(s);
}
/**Function*************************************************************
Synopsis [add clause]
Description [kissat takes x and -x as a literal for a variable x > 0,
where 0 is an indicator of the end of a clause.
since variables start from 0 in abc, a variable v is
translated into v + 1 in kissat.]
SideEffects []
SeeAlso []
***********************************************************************/
int kissat_solver_addclause(kissat_solver* s, int* begin, int* end) {
for(;begin != end; begin++) {
if(*begin & 1) {
kissat_add((kissat*)s->p, -(1 + ((*begin) >> 1)));
} else {
kissat_add((kissat*)s->p, 1 + ((*begin) >> 1) );
}
}
kissat_add((kissat*)s->p, 0);
return !kissat_is_inconsistent((kissat*)s->p);
}
/**Function*************************************************************
Synopsis [solve with resource limits]
Description [assumptions and inspection limits are not supported.]
SideEffects []
SeeAlso []
***********************************************************************/
int kissat_solver_solve(kissat_solver* s, int* begin, int* end, ABC_INT64_T nConfLimit, ABC_INT64_T nInsLimit, ABC_INT64_T nConfLimitGlobal, ABC_INT64_T nInsLimitGlobal) {
// assumptions are not supported
assert(begin == end);
// inspection limits are not supported
assert(nInsLimit == 0);
assert(nInsLimitGlobal == 0);
// set conflict limits
if(nConfLimit)
kissat_set_conflict_limit((kissat*)s->p, nConfLimit);
if(nConfLimitGlobal && (nConfLimit == 0 || nConfLimit > nConfLimitGlobal))
kissat_set_conflict_limit((kissat*)s->p, nConfLimitGlobal);
// solve
int res = kissat_solve((kissat*)s->p);
// translate this kissat return value into a corresponding ABC status value
switch(res) {
case 0: // UNDETERMINED
return 0;
case 10: // SATISFIABLE
return 1;
case 20: // UNSATISFIABLE
return -1;
default:
assert(0);
}
return 0;
}
/**Function*************************************************************
Synopsis [get number of variables]
Description [emulated using "nVars".]
SideEffects []
SeeAlso []
***********************************************************************/
int kissat_solver_nvars(kissat_solver* s) {
return s->nVars;
}
/**Function*************************************************************
Synopsis [add new variable]
Description [emulated using "nVars".]
SideEffects []
SeeAlso []
***********************************************************************/
int kissat_solver_addvar(kissat_solver* s) {
return s->nVars++;
}
/**Function*************************************************************
Synopsis [set number of variables]
Description [not only emulate with "nVars" but also reserve memory.]
SideEffects []
SeeAlso []
***********************************************************************/
void kissat_solver_setnvars(kissat_solver* s,int n) {
s->nVars = n;
kissat_reserve((kissat*)s->p, n);
}
/**Function*************************************************************
Synopsis [get value of variable]
Description [kissat returns x (true) or -x (false) for a variable x.
note a variable v was translated into v + 1 in kissat.]
SideEffects []
SeeAlso []
***********************************************************************/
int kissat_solver_get_var_value(kissat_solver* s, int v) {
return kissat_value((kissat*)s->p, v + 1) > 0;
}
////////////////////////////////////////////////////////////////////////
/// END OF FILE ///
////////////////////////////////////////////////////////////////////////
ABC_NAMESPACE_IMPL_END

View File

@ -0,0 +1,71 @@
/**CFile****************************************************************
FileName [kissatSolver.h]
SystemName [ABC: Logic synthesis and verification system.]
PackageName []
Synopsis []
Author [Alan Mishchenko]
Affiliation [UC Berkeley]
Date [Ver. 1.0. Started - June 20, 2005.]
Revision [$Id: kissatSolver.h,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
***********************************************************************/
#ifndef ABC_SAT_KISSAT_SOLVER_H_
#define ABC_SAT_KISSAT_SOLVER_H_
////////////////////////////////////////////////////////////////////////
/// INCLUDES ///
////////////////////////////////////////////////////////////////////////
#include "aig/gia/gia.h"
////////////////////////////////////////////////////////////////////////
/// PARAMETERS ///
////////////////////////////////////////////////////////////////////////
ABC_NAMESPACE_HEADER_START
////////////////////////////////////////////////////////////////////////
/// BASIC TYPES ///
////////////////////////////////////////////////////////////////////////
typedef struct kissat_solver_ kissat_solver;
struct kissat_solver_
{
void* p;
int nVars;
};
////////////////////////////////////////////////////////////////////////
/// MACRO DEFINITIONS ///
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
/// FUNCTION DECLARATIONS ///
////////////////////////////////////////////////////////////////////////
extern kissat_solver* kissat_solver_new(void);
extern void kissat_solver_delete(kissat_solver* s);
extern int kissat_solver_addclause(kissat_solver* s, int* begin, int* end);
extern int kissat_solver_solve(kissat_solver* s, int* begin, int* end, ABC_INT64_T nConfLimit, ABC_INT64_T nInsLimit, ABC_INT64_T nConfLimitGlobal, ABC_INT64_T nInsLimitGlobal);
extern int kissat_solver_nvars(kissat_solver* s);
extern int kissat_solver_addvar(kissat_solver* s);
extern void kissat_solver_setnvars(kissat_solver* s,int n);
extern int kissat_solver_get_var_value(kissat_solver* s, int v);
ABC_NAMESPACE_HEADER_END
#endif
////////////////////////////////////////////////////////////////////////
/// END OF FILE ///
////////////////////////////////////////////////////////////////////////

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