From a7476c65d8d79cd1e128cbed8af4ebd83cb9853b Mon Sep 17 00:00:00 2001 From: MyskYko Date: Tue, 4 Mar 2025 17:39:59 -0800 Subject: [PATCH 1/3] kissat original --- src/sat/kissat/allocate.c | 161 ++ src/sat/kissat/allocate.h | 36 + src/sat/kissat/analyze.c | 579 ++++ src/sat/kissat/analyze.h | 12 + src/sat/kissat/ands.c | 88 + src/sat/kissat/ands.h | 11 + src/sat/kissat/application.h | 8 + src/sat/kissat/arena.c | 108 + src/sat/kissat/arena.h | 46 + src/sat/kissat/array.h | 58 + src/sat/kissat/assign.c | 59 + src/sat/kissat/assign.h | 55 + src/sat/kissat/attribute.h | 10 + src/sat/kissat/averages.c | 17 + src/sat/kissat/averages.h | 33 + src/sat/kissat/backbone.c | 598 ++++ src/sat/kissat/backbone.h | 9 + src/sat/kissat/backtrack.c | 177 ++ src/sat/kissat/backtrack.h | 11 + src/sat/kissat/build.c | 81 + src/sat/kissat/bump.c | 120 + src/sat/kissat/bump.h | 16 + src/sat/kissat/check.c | 1033 +++++++ src/sat/kissat/check.h | 175 ++ src/sat/kissat/classify.c | 28 + src/sat/kissat/classify.h | 17 + src/sat/kissat/clause.c | 187 ++ src/sat/kissat/clause.h | 90 + src/sat/kissat/collect.c | 738 +++++ src/sat/kissat/collect.h | 33 + src/sat/kissat/colors.c | 19 + src/sat/kissat/colors.h | 68 + src/sat/kissat/compact.c | 376 +++ src/sat/kissat/compact.h | 9 + src/sat/kissat/config.c | 83 + src/sat/kissat/config.h | 8 + src/sat/kissat/congruence.c | 4635 ++++++++++++++++++++++++++++++++ src/sat/kissat/congruence.h | 9 + src/sat/kissat/cover.h | 28 + src/sat/kissat/decide.c | 244 ++ src/sat/kissat/decide.h | 14 + src/sat/kissat/deduce.c | 168 ++ src/sat/kissat/deduce.h | 14 + src/sat/kissat/definition.c | 230 ++ src/sat/kissat/definition.h | 10 + src/sat/kissat/dense.c | 235 ++ src/sat/kissat/dense.h | 12 + src/sat/kissat/dump.c | 293 ++ src/sat/kissat/eliminate.c | 603 +++++ src/sat/kissat/eliminate.h | 19 + src/sat/kissat/equivalences.c | 37 + src/sat/kissat/equivalences.h | 10 + src/sat/kissat/error.c | 62 + src/sat/kissat/error.h | 18 + src/sat/kissat/extend.c | 181 ++ src/sat/kissat/extend.h | 30 + src/sat/kissat/factor.c | 1136 ++++++++ src/sat/kissat/factor.h | 9 + src/sat/kissat/fastassign.h | 41 + src/sat/kissat/fastel.c | 934 +++++++ src/sat/kissat/fastel.h | 6 + src/sat/kissat/fifo.h | 97 + src/sat/kissat/file.c | 310 +++ src/sat/kissat/file.h | 124 + src/sat/kissat/flags.c | 115 + src/sat/kissat/flags.h | 37 + src/sat/kissat/format.c | 145 + src/sat/kissat/format.h | 42 + src/sat/kissat/forward.c | 691 +++++ src/sat/kissat/forward.h | 10 + src/sat/kissat/frames.h | 32 + src/sat/kissat/gates.c | 104 + src/sat/kissat/gates.h | 22 + src/sat/kissat/handle.h | 43 + src/sat/kissat/heap.c | 108 + src/sat/kissat/heap.h | 85 + src/sat/kissat/ifthenelse.c | 174 ++ src/sat/kissat/ifthenelse.h | 11 + src/sat/kissat/import.c | 100 + src/sat/kissat/import.h | 9 + src/sat/kissat/inline.h | 328 +++ src/sat/kissat/inlineassign.h | 100 + src/sat/kissat/inlineframes.h | 18 + src/sat/kissat/inlineheap.h | 176 ++ src/sat/kissat/inlinequeue.h | 117 + src/sat/kissat/inlinevector.h | 193 ++ src/sat/kissat/internal.c | 520 ++++ src/sat/kissat/internal.h | 295 ++ src/sat/kissat/keatures.h | 18 + src/sat/kissat/kimits.c | 194 ++ src/sat/kissat/kimits.h | 185 ++ src/sat/kissat/kissat.h | 44 + src/sat/kissat/kitten.c | 2794 +++++++++++++++++++ src/sat/kissat/kitten.h | 54 + src/sat/kissat/krite.c | 45 + src/sat/kissat/krite.h | 9 + src/sat/kissat/learn.c | 210 ++ src/sat/kissat/learn.h | 10 + src/sat/kissat/literal.h | 36 + src/sat/kissat/logging.c | 456 ++++ src/sat/kissat/logging.h | 464 ++++ src/sat/kissat/lucky.c | 393 +++ src/sat/kissat/lucky.h | 7 + src/sat/kissat/minimize.c | 211 ++ src/sat/kissat/minimize.h | 14 + src/sat/kissat/mode.c | 215 ++ src/sat/kissat/mode.h | 24 + src/sat/kissat/options.c | 396 +++ src/sat/kissat/options.h | 299 ++ src/sat/kissat/parse.h | 19 + src/sat/kissat/phases.c | 68 + src/sat/kissat/phases.h | 32 + src/sat/kissat/preprocess.c | 178 ++ src/sat/kissat/preprocess.h | 10 + src/sat/kissat/print.c | 172 ++ src/sat/kissat/print.h | 65 + src/sat/kissat/probe.c | 104 + src/sat/kissat/probe.h | 12 + src/sat/kissat/profile.c | 148 + src/sat/kissat/profile.h | 143 + src/sat/kissat/promote.c | 42 + src/sat/kissat/promote.h | 33 + src/sat/kissat/proof.c | 408 +++ src/sat/kissat/proof.h | 164 ++ src/sat/kissat/propbeyond.c | 48 + src/sat/kissat/propbeyond.h | 9 + src/sat/kissat/propdense.c | 108 + src/sat/kissat/propdense.h | 11 + src/sat/kissat/propinitially.c | 56 + src/sat/kissat/propinitially.h | 10 + src/sat/kissat/proplit.h | 204 ++ src/sat/kissat/proprobe.c | 59 + src/sat/kissat/proprobe.h | 12 + src/sat/kissat/propsearch.c | 71 + src/sat/kissat/propsearch.h | 9 + src/sat/kissat/queue.c | 55 + src/sat/kissat/queue.h | 38 + src/sat/kissat/random.h | 44 + src/sat/kissat/rank.h | 140 + src/sat/kissat/reduce.c | 198 ++ src/sat/kissat/reduce.h | 11 + src/sat/kissat/reference.h | 19 + src/sat/kissat/reluctant.c | 67 + src/sat/kissat/reluctant.h | 33 + src/sat/kissat/reorder.c | 217 ++ src/sat/kissat/reorder.h | 11 + src/sat/kissat/rephase.c | 137 + src/sat/kissat/rephase.h | 11 + src/sat/kissat/report.c | 159 ++ src/sat/kissat/report.h | 22 + src/sat/kissat/require.h | 30 + src/sat/kissat/resize.c | 137 + src/sat/kissat/resize.h | 10 + src/sat/kissat/resolve.c | 370 +++ src/sat/kissat/resolve.h | 11 + src/sat/kissat/resources.c | 104 + src/sat/kissat/resources.h | 23 + src/sat/kissat/restart.c | 131 + src/sat/kissat/restart.h | 13 + src/sat/kissat/search.c | 229 ++ src/sat/kissat/search.h | 8 + src/sat/kissat/shrink.c | 395 +++ src/sat/kissat/shrink.h | 8 + src/sat/kissat/smooth.c | 73 + src/sat/kissat/smooth.h | 22 + src/sat/kissat/sort.c | 98 + src/sat/kissat/sort.h | 154 ++ src/sat/kissat/stack.c | 51 + src/sat/kissat/stack.h | 140 + src/sat/kissat/statistics.c | 414 +++ src/sat/kissat/statistics.h | 467 ++++ src/sat/kissat/strengthen.c | 187 ++ src/sat/kissat/strengthen.h | 17 + src/sat/kissat/substitute.c | 617 +++++ src/sat/kissat/substitute.h | 10 + src/sat/kissat/sweep.c | 1724 ++++++++++++ src/sat/kissat/sweep.h | 9 + src/sat/kissat/terminate.c | 15 + src/sat/kissat/terminate.h | 86 + src/sat/kissat/tiers.c | 161 ++ src/sat/kissat/tiers.h | 12 + src/sat/kissat/trail.c | 92 + src/sat/kissat/trail.h | 16 + src/sat/kissat/transitive.c | 389 +++ src/sat/kissat/transitive.h | 8 + src/sat/kissat/utilities.c | 16 + src/sat/kissat/utilities.h | 136 + src/sat/kissat/value.h | 13 + src/sat/kissat/vector.c | 320 +++ src/sat/kissat/vector.h | 55 + src/sat/kissat/vivify.c | 1480 ++++++++++ src/sat/kissat/vivify.h | 8 + src/sat/kissat/walk.c | 966 +++++++ src/sat/kissat/walk.h | 11 + src/sat/kissat/warmup.c | 54 + src/sat/kissat/warmup.h | 8 + src/sat/kissat/watch.c | 223 ++ src/sat/kissat/watch.h | 176 ++ src/sat/kissat/weaken.c | 60 + src/sat/kissat/weaken.h | 11 + src/sat/kissat/witness.h | 10 + 201 files changed, 37354 insertions(+) create mode 100644 src/sat/kissat/allocate.c create mode 100644 src/sat/kissat/allocate.h create mode 100644 src/sat/kissat/analyze.c create mode 100644 src/sat/kissat/analyze.h create mode 100644 src/sat/kissat/ands.c create mode 100644 src/sat/kissat/ands.h create mode 100644 src/sat/kissat/application.h create mode 100644 src/sat/kissat/arena.c create mode 100644 src/sat/kissat/arena.h create mode 100644 src/sat/kissat/array.h create mode 100644 src/sat/kissat/assign.c create mode 100644 src/sat/kissat/assign.h create mode 100644 src/sat/kissat/attribute.h create mode 100644 src/sat/kissat/averages.c create mode 100644 src/sat/kissat/averages.h create mode 100644 src/sat/kissat/backbone.c create mode 100644 src/sat/kissat/backbone.h create mode 100644 src/sat/kissat/backtrack.c create mode 100644 src/sat/kissat/backtrack.h create mode 100644 src/sat/kissat/build.c create mode 100644 src/sat/kissat/bump.c create mode 100644 src/sat/kissat/bump.h create mode 100644 src/sat/kissat/check.c create mode 100644 src/sat/kissat/check.h create mode 100644 src/sat/kissat/classify.c create mode 100644 src/sat/kissat/classify.h create mode 100644 src/sat/kissat/clause.c create mode 100644 src/sat/kissat/clause.h create mode 100644 src/sat/kissat/collect.c create mode 100644 src/sat/kissat/collect.h create mode 100644 src/sat/kissat/colors.c create mode 100644 src/sat/kissat/colors.h create mode 100644 src/sat/kissat/compact.c create mode 100644 src/sat/kissat/compact.h create mode 100644 src/sat/kissat/config.c create mode 100644 src/sat/kissat/config.h create mode 100644 src/sat/kissat/congruence.c create mode 100644 src/sat/kissat/congruence.h create mode 100644 src/sat/kissat/cover.h create mode 100644 src/sat/kissat/decide.c create mode 100644 src/sat/kissat/decide.h create mode 100644 src/sat/kissat/deduce.c create mode 100644 src/sat/kissat/deduce.h create mode 100644 src/sat/kissat/definition.c create mode 100644 src/sat/kissat/definition.h create mode 100644 src/sat/kissat/dense.c create mode 100644 src/sat/kissat/dense.h create mode 100644 src/sat/kissat/dump.c create mode 100644 src/sat/kissat/eliminate.c create mode 100644 src/sat/kissat/eliminate.h create mode 100644 src/sat/kissat/equivalences.c create mode 100644 src/sat/kissat/equivalences.h create mode 100644 src/sat/kissat/error.c create mode 100644 src/sat/kissat/error.h create mode 100644 src/sat/kissat/extend.c create mode 100644 src/sat/kissat/extend.h create mode 100644 src/sat/kissat/factor.c create mode 100644 src/sat/kissat/factor.h create mode 100644 src/sat/kissat/fastassign.h create mode 100644 src/sat/kissat/fastel.c create mode 100644 src/sat/kissat/fastel.h create mode 100644 src/sat/kissat/fifo.h create mode 100644 src/sat/kissat/file.c create mode 100644 src/sat/kissat/file.h create mode 100644 src/sat/kissat/flags.c create mode 100644 src/sat/kissat/flags.h create mode 100644 src/sat/kissat/format.c create mode 100644 src/sat/kissat/format.h create mode 100644 src/sat/kissat/forward.c create mode 100644 src/sat/kissat/forward.h create mode 100644 src/sat/kissat/frames.h create mode 100644 src/sat/kissat/gates.c create mode 100644 src/sat/kissat/gates.h create mode 100644 src/sat/kissat/handle.h create mode 100644 src/sat/kissat/heap.c create mode 100644 src/sat/kissat/heap.h create mode 100644 src/sat/kissat/ifthenelse.c create mode 100644 src/sat/kissat/ifthenelse.h create mode 100644 src/sat/kissat/import.c create mode 100644 src/sat/kissat/import.h create mode 100644 src/sat/kissat/inline.h create mode 100644 src/sat/kissat/inlineassign.h create mode 100644 src/sat/kissat/inlineframes.h create mode 100644 src/sat/kissat/inlineheap.h create mode 100644 src/sat/kissat/inlinequeue.h create mode 100644 src/sat/kissat/inlinevector.h create mode 100644 src/sat/kissat/internal.c create mode 100644 src/sat/kissat/internal.h create mode 100644 src/sat/kissat/keatures.h create mode 100644 src/sat/kissat/kimits.c create mode 100644 src/sat/kissat/kimits.h create mode 100644 src/sat/kissat/kissat.h create mode 100644 src/sat/kissat/kitten.c create mode 100644 src/sat/kissat/kitten.h create mode 100644 src/sat/kissat/krite.c create mode 100644 src/sat/kissat/krite.h create mode 100644 src/sat/kissat/learn.c create mode 100644 src/sat/kissat/learn.h create mode 100644 src/sat/kissat/literal.h create mode 100644 src/sat/kissat/logging.c create mode 100644 src/sat/kissat/logging.h create mode 100644 src/sat/kissat/lucky.c create mode 100644 src/sat/kissat/lucky.h create mode 100644 src/sat/kissat/minimize.c create mode 100644 src/sat/kissat/minimize.h create mode 100644 src/sat/kissat/mode.c create mode 100644 src/sat/kissat/mode.h create mode 100644 src/sat/kissat/options.c create mode 100644 src/sat/kissat/options.h create mode 100644 src/sat/kissat/parse.h create mode 100644 src/sat/kissat/phases.c create mode 100644 src/sat/kissat/phases.h create mode 100644 src/sat/kissat/preprocess.c create mode 100644 src/sat/kissat/preprocess.h create mode 100644 src/sat/kissat/print.c create mode 100644 src/sat/kissat/print.h create mode 100644 src/sat/kissat/probe.c create mode 100644 src/sat/kissat/probe.h create mode 100644 src/sat/kissat/profile.c create mode 100644 src/sat/kissat/profile.h create mode 100644 src/sat/kissat/promote.c create mode 100644 src/sat/kissat/promote.h create mode 100644 src/sat/kissat/proof.c create mode 100644 src/sat/kissat/proof.h create mode 100644 src/sat/kissat/propbeyond.c create mode 100644 src/sat/kissat/propbeyond.h create mode 100644 src/sat/kissat/propdense.c create mode 100644 src/sat/kissat/propdense.h create mode 100644 src/sat/kissat/propinitially.c create mode 100644 src/sat/kissat/propinitially.h create mode 100644 src/sat/kissat/proplit.h create mode 100644 src/sat/kissat/proprobe.c create mode 100644 src/sat/kissat/proprobe.h create mode 100644 src/sat/kissat/propsearch.c create mode 100644 src/sat/kissat/propsearch.h create mode 100644 src/sat/kissat/queue.c create mode 100644 src/sat/kissat/queue.h create mode 100644 src/sat/kissat/random.h create mode 100644 src/sat/kissat/rank.h create mode 100644 src/sat/kissat/reduce.c create mode 100644 src/sat/kissat/reduce.h create mode 100644 src/sat/kissat/reference.h create mode 100644 src/sat/kissat/reluctant.c create mode 100644 src/sat/kissat/reluctant.h create mode 100644 src/sat/kissat/reorder.c create mode 100644 src/sat/kissat/reorder.h create mode 100644 src/sat/kissat/rephase.c create mode 100644 src/sat/kissat/rephase.h create mode 100644 src/sat/kissat/report.c create mode 100644 src/sat/kissat/report.h create mode 100644 src/sat/kissat/require.h create mode 100644 src/sat/kissat/resize.c create mode 100644 src/sat/kissat/resize.h create mode 100644 src/sat/kissat/resolve.c create mode 100644 src/sat/kissat/resolve.h create mode 100644 src/sat/kissat/resources.c create mode 100644 src/sat/kissat/resources.h create mode 100644 src/sat/kissat/restart.c create mode 100644 src/sat/kissat/restart.h create mode 100644 src/sat/kissat/search.c create mode 100644 src/sat/kissat/search.h create mode 100644 src/sat/kissat/shrink.c create mode 100644 src/sat/kissat/shrink.h create mode 100644 src/sat/kissat/smooth.c create mode 100644 src/sat/kissat/smooth.h create mode 100644 src/sat/kissat/sort.c create mode 100644 src/sat/kissat/sort.h create mode 100644 src/sat/kissat/stack.c create mode 100644 src/sat/kissat/stack.h create mode 100644 src/sat/kissat/statistics.c create mode 100644 src/sat/kissat/statistics.h create mode 100644 src/sat/kissat/strengthen.c create mode 100644 src/sat/kissat/strengthen.h create mode 100644 src/sat/kissat/substitute.c create mode 100644 src/sat/kissat/substitute.h create mode 100644 src/sat/kissat/sweep.c create mode 100644 src/sat/kissat/sweep.h create mode 100644 src/sat/kissat/terminate.c create mode 100644 src/sat/kissat/terminate.h create mode 100644 src/sat/kissat/tiers.c create mode 100644 src/sat/kissat/tiers.h create mode 100644 src/sat/kissat/trail.c create mode 100644 src/sat/kissat/trail.h create mode 100644 src/sat/kissat/transitive.c create mode 100644 src/sat/kissat/transitive.h create mode 100644 src/sat/kissat/utilities.c create mode 100644 src/sat/kissat/utilities.h create mode 100644 src/sat/kissat/value.h create mode 100644 src/sat/kissat/vector.c create mode 100644 src/sat/kissat/vector.h create mode 100644 src/sat/kissat/vivify.c create mode 100644 src/sat/kissat/vivify.h create mode 100644 src/sat/kissat/walk.c create mode 100644 src/sat/kissat/walk.h create mode 100644 src/sat/kissat/warmup.c create mode 100644 src/sat/kissat/warmup.h create mode 100644 src/sat/kissat/watch.c create mode 100644 src/sat/kissat/watch.h create mode 100644 src/sat/kissat/weaken.c create mode 100644 src/sat/kissat/weaken.h create mode 100644 src/sat/kissat/witness.h diff --git a/src/sat/kissat/allocate.c b/src/sat/kissat/allocate.c new file mode 100644 index 000000000..68bb68a88 --- /dev/null +++ b/src/sat/kissat/allocate.c @@ -0,0 +1,161 @@ +#include "allocate.h" +#include "error.h" +#include "internal.h" +#include "logging.h" + +#undef LOGPREFIX +#define LOGPREFIX "ALLOCATE" + +#include + +#ifdef LOGGING +#include +#endif + +static void inc_bytes (kissat *solver, size_t bytes) { +#ifdef METRICS + if (!solver) + return; + ADD (allocated_current, bytes); + LOG5 ("allocated_current = %s", + FORMAT_BYTES (solver->statistics.allocated_current)); + if (solver->statistics.allocated_current >= + solver->statistics.allocated_max) { + solver->statistics.allocated_max = solver->statistics.allocated_current; + LOG5 ("allocated_max = %s", + FORMAT_BYTES (solver->statistics.allocated_max)); + } +#else + (void) solver; + (void) bytes; +#endif +} + +static void dec_bytes (kissat *solver, size_t bytes) { +#ifdef METRICS + if (!solver) + return; + SUB (allocated_current, bytes); + LOG5 ("allocated_current = %s", + FORMAT_BYTES (solver->statistics.allocated_current)); +#else + (void) solver; + (void) bytes; +#endif +} + +void *kissat_malloc (kissat *solver, size_t bytes) { + void *res; + if (!bytes) + return 0; + res = malloc (bytes); + LOG4 ("malloc (%zu) = %p", bytes, res); + if (!res) + kissat_fatal ("out-of-memory allocating %zu bytes", bytes); + inc_bytes (solver, bytes); + return res; +} + +void kissat_free (kissat *solver, void *ptr, size_t bytes) { + if (ptr) { + LOG4 ("free (%p[%zu])", ptr, bytes); + dec_bytes (solver, bytes); + free (ptr); + } else + assert (!bytes); +} + +char *kissat_strdup (kissat *solver, const char *str) { + char *res = kissat_malloc (solver, strlen (str) + 1); + return strcpy (res, str); +} + +void kissat_freestr (struct kissat *solver, char *str) { + assert (str); + kissat_free (solver, str, strlen (str) + 1); +} + +void *kissat_nalloc (kissat *solver, size_t n, size_t size) { + void *res; + if (!n || !size) + return 0; + if (MAX_SIZE_T / size < n) + kissat_fatal ("invalid 'kissat_nalloc (..., %zu, %zu)' call", n, size); + const size_t bytes = n * size; + res = malloc (bytes); + LOG4 ("nalloc (%zu, %zu) = %p", n, size, res); + if (!res) + kissat_fatal ("out-of-memory allocating " + "%zu = %zu x %zu bytes", + bytes, n, size); + inc_bytes (solver, bytes); + return res; +} + +void *kissat_calloc (kissat *solver, size_t n, size_t size) { + void *res; + if (!n || !size) + return 0; + if (MAX_SIZE_T / size < n) + kissat_fatal ("invalid 'kissat_calloc (..., %zu, %zu)' call", n, size); + res = calloc (n, size); + LOG4 ("calloc (%zu, %zu) = %p", n, size, res); + const size_t bytes = n * size; + if (!res) + kissat_fatal ("out-of-memory allocating " + "%zu = %zu x %zu bytes", + bytes, n, size); + inc_bytes (solver, bytes); + return res; +} + +void kissat_dealloc (kissat *solver, void *ptr, size_t n, size_t size) { + if (!n || !size) + return; + if (MAX_SIZE_T / size < n) + kissat_fatal ("invalid 'kissat_dealloc (..., %zu, %zu)' call", n, size); + const size_t bytes = n * size; + kissat_free (solver, ptr, bytes); +} + +void *kissat_realloc (kissat *solver, void *p, size_t old_bytes, + size_t new_bytes) { + if (old_bytes == new_bytes) + return p; + if (!new_bytes) { + kissat_free (solver, p, old_bytes); + return 0; + } + dec_bytes (solver, old_bytes); +#ifdef LOGGING + if (GET_OPTION (log) > 3) + kissat_begin_logging (solver, LOGPREFIX, "realloc (%p[%zu, %zu) = ", p, + old_bytes, new_bytes); +#endif + void *res = realloc (p, new_bytes); +#ifdef LOGGING + if (GET_OPTION (log) > 3) { + printf ("%p", res); + kissat_end_logging (); + } +#endif + if (new_bytes && !res) + kissat_fatal ("out-of-memory reallocating from %zu to %zu bytes", + old_bytes, new_bytes); + inc_bytes (solver, new_bytes); + return res; +} + +void *kissat_nrealloc (kissat *solver, void *p, size_t o, size_t n, + size_t size) { + if (!size) { + assert (!p); + assert (!o); + return 0; + } + const size_t max = MAX_SIZE_T / size; + if (max < o || max < n) + kissat_fatal ("invalid 'kissat_nrealloc (..., %zu, %zu, %zu)' call", o, + n, size); + return kissat_realloc (solver, p, o * size, n * size); +} diff --git a/src/sat/kissat/allocate.h b/src/sat/kissat/allocate.h new file mode 100644 index 000000000..db24fd5f8 --- /dev/null +++ b/src/sat/kissat/allocate.h @@ -0,0 +1,36 @@ +#ifndef _allocate_h_INCLUDED +#define _allocate_h_INCLUDED + +#include + +struct kissat; + +void *kissat_malloc (struct kissat *, size_t bytes); +void kissat_free (struct kissat *, void *, size_t bytes); + +char *kissat_strdup (struct kissat *, const char *); +void kissat_freestr (struct kissat *, char *); + +void *kissat_calloc (struct kissat *, size_t n, size_t size); +void *kissat_nalloc (struct kissat *, size_t n, size_t size); +void kissat_dealloc (struct kissat *, void *ptr, size_t n, size_t size); + +void *kissat_realloc (struct kissat *, void *, size_t old, size_t bytes); +void *kissat_nrealloc (struct kissat *, void *, size_t o, size_t n, size_t); + +#define NALLOC(P, N) \ + do { \ + (P) = kissat_nalloc (solver, (N), sizeof *(P)); \ + } while (0) + +#define CALLOC(P, N) \ + do { \ + (P) = kissat_calloc (solver, (N), sizeof *(P)); \ + } while (0) + +#define DEALLOC(P, N) \ + do { \ + kissat_dealloc (solver, (P), (N), sizeof *(P)); \ + } while (0) + +#endif diff --git a/src/sat/kissat/analyze.c b/src/sat/kissat/analyze.c new file mode 100644 index 000000000..d21b0a74b --- /dev/null +++ b/src/sat/kissat/analyze.c @@ -0,0 +1,579 @@ +#include "analyze.h" +#include "backtrack.h" +#include "bump.h" +#include "deduce.h" +#include "inline.h" +#include "learn.h" +#include "minimize.h" +#include "print.h" +#include "rank.h" +#include "shrink.h" +#include "sort.h" +#include "tiers.h" + +#include + +static bool one_literal_on_conflict_level (kissat *solver, clause *conflict, + unsigned *conflict_level_ptr) { + assert (conflict); + assert (conflict->size > 1); + + unsigned jump_level = INVALID_LEVEL; + unsigned conflict_level = INVALID_LEVEL; + unsigned literals_on_conflict_level = 0; + unsigned forced_lit = INVALID_LIT; + + assigned *all_assigned = solver->assigned; + + unsigned *lits = conflict->lits; + const unsigned conflict_size = conflict->size; + const unsigned *const end_of_lits = lits + conflict_size; + + for (const unsigned *p = lits; p != end_of_lits; p++) { + const unsigned lit = *p; + assert (VALUE (lit) < 0); + const unsigned idx = IDX (lit); + const unsigned lit_level = all_assigned[idx].level; + if (conflict_level == INVALID_LEVEL || conflict_level < lit_level) { + literals_on_conflict_level = 1; + jump_level = conflict_level; + conflict_level = lit_level; + forced_lit = lit; + } else { + if (jump_level == INVALID_LEVEL || jump_level < lit_level) + jump_level = lit_level; + if (conflict_level == lit_level) + literals_on_conflict_level++; + } + if (literals_on_conflict_level > 1 && conflict_level == solver->level) + break; + } + assert (conflict_level != INVALID_LEVEL); + assert (literals_on_conflict_level); + + LOG ("found %u literals on conflict level %u", literals_on_conflict_level, + conflict_level); + *conflict_level_ptr = conflict_level; + + if (!conflict_level) { + solver->inconsistent = true; + LOG ("learned empty clause from conflict at conflict level zero"); + CHECK_AND_ADD_EMPTY (); + ADD_EMPTY_TO_PROOF (); + return false; + } + + if (conflict_level < solver->level) { + LOG ("forced backtracking due to conflict level %u < level %u", + conflict_level, solver->level); + kissat_backtrack_after_conflict (solver, conflict_level); + } + + if (conflict_size > 2) { + for (unsigned i = 0; i < 2; i++) { + const unsigned lit = lits[i]; + const unsigned lit_idx = IDX (lit); + unsigned highest_position = i; + unsigned highest_literal = lit; + unsigned highest_level = all_assigned[lit_idx].level; + for (unsigned j = i + 1; j < conflict_size; j++) { + const unsigned other = lits[j]; + const unsigned other_idx = IDX (other); + const unsigned level = all_assigned[other_idx].level; + if (highest_level >= level) + continue; + highest_literal = other; + highest_position = j; + highest_level = level; + if (highest_level == conflict_level) + break; + } + if (highest_position == i) + continue; + reference ref = INVALID_REF; + if (highest_position > 1) { + ref = kissat_reference_clause (solver, conflict); + kissat_unwatch_blocking (solver, lit, ref); + } + lits[highest_position] = lit; + lits[i] = highest_literal; + if (highest_position > 1) + kissat_watch_blocking (solver, lits[i], lits[!i], ref); + } + } + + if (literals_on_conflict_level > 1) + return false; + + assert (literals_on_conflict_level == 1); + assert (forced_lit != INVALID_LIT); + assert (jump_level != INVALID_LEVEL); + assert (jump_level < conflict_level); + + LOG ("reusing conflict as driving clause of %s", LOGLIT (forced_lit)); + + unsigned new_level = kissat_determine_new_level (solver, jump_level); + kissat_backtrack_after_conflict (solver, new_level); + + if (conflict_size == 2) { + assert (conflict == &solver->conflict); + const unsigned other = lits[0] ^ lits[1] ^ forced_lit; + kissat_assign_binary (solver, forced_lit, other); + } else { + const reference ref = kissat_reference_clause (solver, conflict); + kissat_assign_reference (solver, forced_lit, ref, conflict); + } + + return true; +} + +static inline void mark_reason_side_literal (kissat *solver, + assigned *all_assigned, + unsigned lit) { + const unsigned idx = IDX (lit); + const assigned *a = all_assigned + idx; + if (a->level && !a->analyzed) + kissat_push_analyzed (solver, all_assigned, idx); +} + +static inline void analyze_reason_side_literal (kissat *solver, + size_t limit, ward *arena, + assigned *all_assigned, + unsigned lit) { + const unsigned idx = IDX (lit); + const assigned *a = all_assigned + idx; + assert (a->level); + assert (a->analyzed); + assert (a->reason != UNIT_REASON); + if (a->reason == DECISION_REASON) + return; + if (a->binary) { + const unsigned other = a->reason; + mark_reason_side_literal (solver, all_assigned, other); + } else { + const reference ref = a->reason; + assert (ref < SIZE_STACK (solver->arena)); + clause *c = (clause *) (arena + ref); + const unsigned not_lit = NOT (lit); + INC (search_ticks); + for (all_literals_in_clause (other, c)) + if (other != not_lit) { + assert (other != lit); + mark_reason_side_literal (solver, all_assigned, other); + if (SIZE_STACK (solver->analyzed) > limit) + break; + } + } +} + +static void analyze_reason_side_literals (kissat *solver) { + if (!GET_OPTION (bump)) + return; + if (!GET_OPTION (bumpreasons)) + return; + if (solver->probing) + return; + if (DELAYING (bumpreasons)) + return; + const double decision_rate = AVERAGE (decision_rate); + const int decision_rate_limit = GET_OPTION (bumpreasonsrate); + if (decision_rate >= decision_rate_limit) { + LOG ("decision rate %g >= limit %d", decision_rate, + decision_rate_limit); + return; + } + assigned *all_assigned = solver->assigned; +#ifndef NDEBUG + for (all_stack (unsigned, lit, solver->clause)) + assert (all_assigned[IDX (lit)].analyzed); +#endif + LOG ("trying to bump reason side literals too"); + const size_t saved = SIZE_STACK (solver->analyzed); + const size_t limit = GET_OPTION (bumpreasonslimit) * saved; + LOG ("analyzed already %zu literals thus limit %zu", saved, limit); + ward *arena = BEGIN_STACK (solver->arena); + for (all_stack (unsigned, lit, solver->clause)) { + analyze_reason_side_literal (solver, limit, arena, all_assigned, lit); + if (SIZE_STACK (solver->analyzed) > limit) + break; + } + if (SIZE_STACK (solver->analyzed) > limit) { + LOG ("too many additional reason side literals"); + while (SIZE_STACK (solver->analyzed) > saved) { + const unsigned idx = POP_STACK (solver->analyzed); + struct assigned *a = all_assigned + idx; + LOG ("marking %s as not analyzed", LOGVAR (idx)); + assert (a->analyzed); + a->analyzed = false; + } + BUMP_DELAY (bumpreasons); + } else + REDUCE_DELAY (bumpreasons); +} + +#define RADIX_SORT_LEVELS_LIMIT 32 + +#define RANK_LEVEL(A) (A) +#define SMALLER_LEVEL(A, B) (RANK_LEVEL (A) < RANK_LEVEL (B)) + +static void sort_levels (kissat *solver) { + unsigneds *levels = &solver->levels; + size_t glue = SIZE_STACK (*levels); + if (glue < RADIX_SORT_LEVELS_LIMIT) + SORT_STACK (unsigned, *levels, SMALLER_LEVEL); + else + RADIX_STACK (unsigned, unsigned, *levels, RANK_LEVEL); + LOG ("sorted %zu levels", glue); +} + +static void sort_deduced_clause (kissat *solver) { + sort_levels (solver); +#ifndef NDEBUG + const size_t size_frames = SIZE_STACK (solver->frames); +#endif + frame *frames = BEGIN_STACK (solver->frames); + unsigned pos = 1; + const unsigned *const begin_levels = BEGIN_STACK (solver->levels); + const unsigned *const end_levels = END_STACK (solver->levels); + unsigned const *p = end_levels; + while (p != begin_levels) { + const unsigned level = *--p; + assert (level < size_frames); + frame *f = frames + level; + const unsigned used = f->used; +#ifndef NDEBUG + f->saved = used; +#endif + assert (used > 0); + assert (UINT_MAX - used >= pos); + f->used = pos; + pos += used; + } + unsigneds *clause = &solver->clause; + const size_t size_clause = SIZE_STACK (*clause); +#ifndef NDEBUG + assert (pos == size_clause); +#endif + unsigned const *begin_clause = BEGIN_STACK (*clause); + const unsigned *const end_clause = END_STACK (*clause); + assert (begin_clause < end_clause); + + unsigneds *shadow = &solver->shadow; + while (SIZE_STACK (*shadow) < size_clause) + PUSH_STACK (*shadow, INVALID_LIT); + + const unsigned not_uip = *begin_clause++; + POKE_STACK (*shadow, 0, not_uip); + + const assigned *const assigned = solver->assigned; + + for (const unsigned *p = begin_clause; p != end_clause; p++) { + const unsigned lit = *p; + const unsigned idx = IDX (lit); + const struct assigned *a = assigned + idx; + const unsigned level = a->level; + assert (level < size_frames); + frame *f = frames + level; + const unsigned pos = f->used++; + POKE_STACK (*shadow, pos, lit); + } + + assert (size_clause == SIZE_STACK (*shadow)); + SWAP (unsigneds, *clause, *shadow); + + pos = 1; + p = end_levels; + while (p != begin_levels) { + const unsigned level = *--p; + assert (level < size_frames); + frame *f = frames + level; + const unsigned end = f->used; + assert (pos < end); + f->used = end - pos; + assert (f->used == f->saved); + pos = end; + } + + CLEAR_STACK (*shadow); + LOGTMP ("level sorted deduced"); + +#ifndef NDEBUG + unsigned prev_level = solver->level; + for (all_stack (unsigned, lit, solver->clause)) { + const unsigned idx = IDX (lit); + const unsigned lit_level = assigned[idx].level; + assert (prev_level >= lit_level); + prev_level = lit_level; + } +#endif +} + +static void reset_levels (kissat *solver) { + LOG ("reset %zu marked levels", SIZE_STACK (solver->levels)); + frame *frames = BEGIN_STACK (solver->frames); +#ifndef NDEBUG + const size_t size_frames = SIZE_STACK (solver->frames); +#endif + for (all_stack (unsigned, level, solver->levels)) { + assert (level < size_frames); + frame *f = frames + level; + assert (f->used > 0); + f->used = 0; + } + CLEAR_STACK (solver->levels); +} + +void kissat_reset_only_analyzed_literals (kissat *solver) { + LOG ("reset %zu analyzed variables", SIZE_STACK (solver->analyzed)); + assigned *assigned = solver->assigned; + for (all_stack (unsigned, idx, solver->analyzed)) { + assert (idx < VARS); + struct assigned *a = assigned + idx; + assert (!a->poisoned); + assert (!a->removable); + assert (!a->shrinkable); + a->analyzed = false; + } + CLEAR_STACK (solver->analyzed); +} + +static void reset_removable (kissat *solver) { + LOG ("reset %zu removable variables", SIZE_STACK (solver->removable)); + assigned *assigned = solver->assigned; +#ifndef NDEBUG + unsigned not_removable = 0; +#endif + for (all_stack (unsigned, idx, solver->removable)) { + assert (idx < VARS); + struct assigned *a = assigned + idx; + assert (a->removable || !not_removable++); + a->removable = false; + } + CLEAR_STACK (solver->removable); +} + +static void reset_analysis_but_not_analyzed_literals (kissat *solver) { + reset_removable (solver); + reset_levels (solver); + LOG ("reset %zu learned literals", SIZE_STACK (solver->clause)); + CLEAR_STACK (solver->clause); +} + +static void update_trail_average (kissat *solver) { + assert (!solver->probing); +#if defined(LOGGING) || !defined(QUIET) + const unsigned size = SIZE_ARRAY (solver->trail); + const unsigned assigned = size - solver->unflushed; + const unsigned active = solver->active; + const double filled = kissat_percent (assigned, active); +#else + (void) solver; +#endif + LOG ("trail filled %.0f%% (size %u, unflushed %u, active %u)", filled, + size, solver->unflushed, active); +#ifndef QUIET + UPDATE_AVERAGE (trail, filled); +#endif +} + +static void update_decision_rate_average (kissat *solver) { + assert (!solver->probing); + const uint64_t current = DECISIONS; + const uint64_t previous = + solver->averages[solver->stable].saved_decisions; + assert (previous <= current); + const uint64_t decisions = current - previous; + solver->averages[solver->stable].saved_decisions = current; + UPDATE_AVERAGE (decision_rate, decisions); +} + +static void analyze_failed_literal (kissat *solver, clause *conflict) { + assert (solver->level == 1); + const unsigned failed = FRAME (1).decision; + + LOGCLS (conflict, "analyzing failed literal %s conflict", + LOGLIT (failed)); + + unsigneds *units = &solver->clause; + assert (EMPTY_STACK (*units)); + assert (EMPTY_STACK (solver->analyzed)); + + const unsigned not_failed = NOT (failed); + assigned *all_assigned = solver->assigned; +#ifndef NDEBUG + const value *const values = solver->values; +#endif + unsigned const *t = END_ARRAY (solver->trail); + unsigned unresolved = 0; + unsigned unit = INVALID_LIT; + + for (all_literals_in_clause (lit, conflict)) { + assert (lit != failed); + if (lit == not_failed) { + LOG ("negation %s of failed literal %s occurs in conflict", + LOGLIT (not_failed), LOGLIT (failed)); + goto DONE; + } + assert (values[lit] < 0); + const unsigned idx = IDX (lit); + assigned *a = all_assigned + idx; + if (!a->level) + continue; + assert (a->level == 1); + LOG ("analyzing conflict literal %s", LOGLIT (lit)); + kissat_push_analyzed (solver, all_assigned, idx); + unresolved++; + } + + for (;;) { + unsigned lit; + assigned *a; + do { + assert (t > BEGIN_ARRAY (solver->trail)); + lit = *--t; + assert (values[lit] > 0); + const unsigned idx = IDX (lit); + a = all_assigned + idx; + } while (!a->analyzed); + if (unresolved == 1) { + unit = NOT (lit); + LOG ("learning additional unit %s", LOGLIT (unit)); + PUSH_STACK (*units, unit); + } + if (a->binary) { + const unsigned other = a->reason; + LOGBINARY (lit, other, "resolving %s reason", LOGLIT (lit)); + assert (other != failed); + assert (other != unit); + assert (values[other] < 0); + if (other == not_failed) { + LOG ("negation %s of failed literal %s in reason", + LOGLIT (not_failed), LOGLIT (failed)); + goto DONE; + } + const unsigned idx = IDX (other); + assigned *b = all_assigned + idx; + assert (b->level == 1); + if (!b->analyzed) { + LOG ("analyzing reason literal %s", LOGLIT (other)); + kissat_push_analyzed (solver, all_assigned, idx); + unresolved++; + } + } else { + assert (a->reason != UNIT_REASON); + assert (a->reason != DECISION_REASON); + const reference ref = a->reason; + LOGREF (ref, "resolving %s reason", LOGLIT (lit)); + clause *reason = kissat_dereference_clause (solver, ref); + for (all_literals_in_clause (other, reason)) { + assert (other != NOT (lit)); + assert (other != failed); + if (other == lit) + continue; + if (other == unit) + continue; + if (other == not_failed) { + LOG ("negation %s of failed literal %s occurs in reason", + LOGLIT (not_failed), LOGLIT (failed)); + goto DONE; + } + assert (values[other] < 0); + const unsigned idx = IDX (other); + assigned *b = all_assigned + idx; + if (!b->level) + continue; + assert (b->level == 1); + if (b->analyzed) + continue; + LOG ("analyzing reason literal %s", LOGLIT (other)); + kissat_push_analyzed (solver, all_assigned, idx); + unresolved++; + } + } + assert (unresolved > 0); + unresolved--; + LOG ("after resolving %s there are %u unresolved literals", + LOGLIT (lit), unresolved); + } +DONE: + LOG ("learning negated failed literal %s", LOGLIT (not_failed)); + PUSH_STACK (*units, not_failed); + + if (!solver->probing) + kissat_update_learned (solver, 0, 1); + + LOG ("failed literal %s produced %zu units", LOGLIT (failed), + SIZE_STACK (*units)); + + kissat_backtrack_without_updating_phases (solver, 0); + + for (all_stack (unsigned, lit, *units)) + kissat_learned_unit (solver, lit); + CLEAR_STACK (*units); + if (!solver->probing) { + solver->iterating = true; + INC (iterations); + } +} + +static void update_tier_limits (kissat *solver) { + INC (retiered); + kissat_compute_and_set_tier_limits (solver); + if (solver->limits.glue.interval < (1u << 16)) + solver->limits.glue.interval *= 2; + solver->limits.glue.conflicts = CONFLICTS + solver->limits.glue.interval; +} + +int kissat_analyze (kissat *solver, clause *conflict) { + if (solver->inconsistent) { + assert (!solver->level); + return 20; + } + + START (analyze); + if (!solver->probing) { + update_trail_average (solver); + update_decision_rate_average (solver); +#ifndef QUIET + UPDATE_AVERAGE (level, solver->level); +#endif + } + int res; + do { + LOGCLS (conflict, "analyzing conflict %" PRIu64, CONFLICTS); + unsigned conflict_level; + if (one_literal_on_conflict_level (solver, conflict, &conflict_level)) + res = 1; + else if (!conflict_level) + res = -1; + else if (conflict_level == 1) { + analyze_failed_literal (solver, conflict); + res = 1; + } else if ((conflict = + kissat_deduce_first_uip_clause (solver, conflict))) { + reset_analysis_but_not_analyzed_literals (solver); + INC (conflicts); + if (CONFLICTS > solver->limits.glue.conflicts) + update_tier_limits (solver); + res = 0; // And continue with new conflict analysis. + } else { + if (GET_OPTION (minimize)) { + sort_deduced_clause (solver); + kissat_minimize_clause (solver); + if (GET_OPTION (shrink)) + kissat_shrink_clause (solver); + } + analyze_reason_side_literals (solver); + kissat_learn_clause (solver); + reset_analysis_but_not_analyzed_literals (solver); + res = 1; + } + if (!EMPTY_STACK (solver->analyzed)) { + if (!solver->probing && GET_OPTION (bump)) + kissat_bump_analyzed (solver); + kissat_reset_only_analyzed_literals (solver); + } + } while (!res); + STOP (analyze); + return res > 0 ? 0 : 20; +} diff --git a/src/sat/kissat/analyze.h b/src/sat/kissat/analyze.h new file mode 100644 index 000000000..be4393c76 --- /dev/null +++ b/src/sat/kissat/analyze.h @@ -0,0 +1,12 @@ +#ifndef _analyze_h_INCLUDED +#define _analyze_h_INCLUDED + +#include + +struct clause; +struct kissat; + +int kissat_analyze (struct kissat *, struct clause *); +void kissat_reset_only_analyzed_literals (struct kissat *); + +#endif diff --git a/src/sat/kissat/ands.c b/src/sat/kissat/ands.c new file mode 100644 index 000000000..51bff792a --- /dev/null +++ b/src/sat/kissat/ands.c @@ -0,0 +1,88 @@ +#include "ands.h" +#include "eliminate.h" +#include "gates.h" +#include "inline.h" + +bool kissat_find_and_gate (kissat *solver, unsigned lit, + unsigned negative) { + if (!GET_OPTION (ands)) + return false; + size_t marked = kissat_mark_binaries (solver, lit); + if (!marked) + return false; + if (marked < 2) { + kissat_unmark_binaries (solver, lit); + return false; + } + + unsigned not_lit = NOT (lit); + watches *not_watches = &WATCHES (not_lit); + + ward *const arena = BEGIN_STACK (solver->arena); + value *marks = solver->marks; + const value *const values = solver->values; + + clause *base = 0; + for (all_binary_large_watches (watch, *not_watches)) { + if (watch.type.binary) + continue; + const reference ref = watch.large.ref; + assert (ref < SIZE_STACK (solver->arena)); + clause *c = (clause *) (arena + ref); + assert (!c->garbage); + base = c; + for (all_literals_in_clause (other, c)) { + if (other == not_lit) + continue; + const value value = values[other]; + if (value > 0) { + kissat_eliminate_clause (solver, c, INVALID_LIT); + base = 0; + break; + } + if (value < 0) + continue; + const unsigned not_other = NOT (other); + signed char mark = marks[not_other]; + if (mark) + continue; + base = 0; + break; + } + if (base) + break; + } + if (!base) { + kissat_unmark_binaries (solver, lit); + return false; + } + LOGCLS (base, "found and gate %s base clause", LOGLIT (not_lit)); + for (all_literals_in_clause (other, base)) { + if (other == not_lit) + continue; + if (values[other]) + continue; + const unsigned not_other = NOT (other); + assert (marks[not_other]); + marks[not_other] = 0; + } + watch tmp = kissat_binary_watch (0); + watches *watches = &WATCHES (lit); + for (all_binary_large_watches (watch, *watches)) { + if (!watch.type.binary) + continue; + const unsigned other = watch.binary.lit; + assert (!solver->values[other]); + if (marks[other]) { + marks[other] = 0; + continue; + } + tmp.binary.lit = other; + PUSH_STACK (solver->gates[negative], tmp); + } + tmp = kissat_large_watch (kissat_reference_clause (solver, base)); + PUSH_STACK (solver->gates[!negative], tmp); + solver->gate_eliminated = GATE_ELIMINATED (ands); + INC (ands_extracted); + return true; +} diff --git a/src/sat/kissat/ands.h b/src/sat/kissat/ands.h new file mode 100644 index 000000000..606c41d6e --- /dev/null +++ b/src/sat/kissat/ands.h @@ -0,0 +1,11 @@ +#ifndef _ands_h_INCLUDED +#define _ands_h_INCLUDED + +#include + +struct kissat; + +bool kissat_find_and_gate (struct kissat *, unsigned lit, + unsigned negative); + +#endif diff --git a/src/sat/kissat/application.h b/src/sat/kissat/application.h new file mode 100644 index 000000000..f4a5b12f7 --- /dev/null +++ b/src/sat/kissat/application.h @@ -0,0 +1,8 @@ +#ifndef _application_h_INCLUDED +#define _application_h_INCLUDED + +struct kissat; + +int kissat_application (struct kissat *, int argc, char **argv); + +#endif diff --git a/src/sat/kissat/arena.c b/src/sat/kissat/arena.c new file mode 100644 index 000000000..7296d2605 --- /dev/null +++ b/src/sat/kissat/arena.c @@ -0,0 +1,108 @@ +#include "error.h" +#include "internal.h" +#include "logging.h" +#include "print.h" + +static void report_resized (kissat *solver, const char *mode, + arena before) { +#ifndef QUIET + ward *const old_begin = BEGIN_STACK (before); + ward *const new_begin = BEGIN_STACK (solver->arena); + const bool moved = (new_begin != old_begin); + const uint64_t capacity = CAPACITY_STACK (solver->arena); + const uint64_t bytes = capacity * sizeof (ward); + kissat_phase (solver, "arena", GET (arena_resized), + "%s to %s %d-byte-words %s (%s)", mode, + FORMAT_COUNT (capacity), (int) sizeof (ward), + FORMAT_BYTES (bytes), (moved ? "moved" : "in place")); +#else + (void) solver; + (void) mode; + (void) before; +#endif +} + +reference kissat_allocate_clause (kissat *solver, size_t size) { + assert (size <= UINT_MAX); + const size_t res = SIZE_STACK (solver->arena); + assert (res <= MAX_REF); + const size_t bytes = kissat_bytes_of_clause (size); + assert (kissat_aligned_word (bytes)); + const size_t needed = bytes / sizeof (ward); + assert (needed <= UINT_MAX); + size_t capacity = CAPACITY_STACK (solver->arena); + assert (kissat_is_power_of_two (MAX_ARENA)); + assert (capacity <= MAX_ARENA); + size_t available = capacity - res; + if (needed > available) { + const arena before = solver->arena; + do { + assert (kissat_is_zero_or_power_of_two (capacity)); + if (capacity == MAX_ARENA) + kissat_fatal ("maximum arena capacity " + "of 2^%u %zu-byte-words %s exhausted" +#ifdef COMPACT + " (consider a configuration without '--compact')" +#endif + , + LD_MAX_ARENA, sizeof (ward), + FORMAT_BYTES (MAX_ARENA * sizeof (ward))); + kissat_stack_enlarge (solver, (chars *) &solver->arena, + sizeof (ward)); + capacity = CAPACITY_STACK (solver->arena); + available = capacity - res; + } while (needed > available); + INC (arena_resized); + INC (arena_enlarged); + report_resized (solver, "enlarged", before); + assert (capacity <= MAX_ARENA); + } + solver->arena.end += needed; + LOG ("allocated clause[%zu] of size %zu bytes %s", res, size, + FORMAT_BYTES (bytes)); + return (reference) res; +} + +void kissat_shrink_arena (kissat *solver) { + const arena before = solver->arena; + const size_t capacity = CAPACITY_STACK (before); + const size_t size = SIZE_STACK (before); +#ifndef QUIET + const size_t capacity_bytes = capacity * sizeof (ward); + kissat_phase (solver, "arena", GET (arena_resized), + "capacity of %s %d-byte-words %s", FORMAT_COUNT (capacity), + (int) sizeof (ward), FORMAT_BYTES (capacity_bytes)); + const size_t size_bytes = size * sizeof (ward); + kissat_phase (solver, "arena", GET (arena_resized), + "filled %.0f%% with %s %d-byte-words %s", + kissat_percent (size, capacity), FORMAT_COUNT (size), + (int) sizeof (ward), FORMAT_BYTES (size_bytes)); +#endif + if (size > capacity / 4) { + kissat_phase (solver, "arena", GET (arena_resized), + "not shrinking since more than 25%% filled"); + return; + } + INC (arena_resized); + INC (arena_shrunken); + SHRINK_STACK (solver->arena); + report_resized (solver, "shrunken", before); +} + +#if !defined(NDEBUG) || defined(LOGGING) + +bool kissat_clause_in_arena (const kissat *solver, const clause *c) { + if (!kissat_aligned_pointer (c)) + return false; + const char *p = (char *) c; + const char *begin = (char *) BEGIN_STACK (solver->arena); + const char *end = (char *) END_STACK (solver->arena); + if (p < begin) + return false; + const size_t bytes = kissat_bytes_of_clause (c->size); + if (end < p + bytes) + return false; + return true; +} + +#endif diff --git a/src/sat/kissat/arena.h b/src/sat/kissat/arena.h new file mode 100644 index 000000000..da83c7e39 --- /dev/null +++ b/src/sat/kissat/arena.h @@ -0,0 +1,46 @@ +#ifndef _arena_h_INCLUDED +#define _arena_h_INCLUDED + +#include "reference.h" +#include "stack.h" +#include "utilities.h" + +#ifdef COMPACT +typedef word ward; +#else +typedef w2rd ward; +#endif + +#define LD_MAX_ARENA_32 (29 - (unsigned) sizeof (ward) / 4) + +#define LD_MAX_ARENA ((sizeof (word) == 4) ? LD_MAX_ARENA_32 : LD_MAX_REF) + +#define MAX_ARENA ((size_t) 1 << LD_MAX_ARENA) + +// clang-format off + +typedef STACK (ward) arena; + +// clang-format on + +struct clause; +struct kissat; + +reference kissat_allocate_clause (struct kissat *, size_t size); +void kissat_shrink_arena (struct kissat *); + +#if !defined(NDEBUG) || defined(LOGGING) + +bool kissat_clause_in_arena (const struct kissat *, const struct clause *); + +#endif + +static inline word kissat_align_ward (word w) { +#ifdef COMPACT + return kissat_align_word (w); +#else + return kissat_align_w2rd (w); +#endif +} + +#endif diff --git a/src/sat/kissat/array.h b/src/sat/kissat/array.h new file mode 100644 index 000000000..3ae23f90b --- /dev/null +++ b/src/sat/kissat/array.h @@ -0,0 +1,58 @@ +#ifndef _array_h_INCLUDED +#define _array_h_INCLUDED + +#include "allocate.h" +#include "stack.h" + +#define ARRAY(TYPE) \ + struct { \ + TYPE *begin; \ + TYPE *end; \ + } + +#define ALLOCATE_ARRAY(A, N) \ + do { \ + const size_t TMP_N = (N); \ + (A).begin = (A).end = \ + kissat_nalloc (solver, TMP_N, sizeof *(A).begin); \ + } while (0) + +#define EMPTY_ARRAY EMPTY_STACK +#define SIZE_ARRAY SIZE_STACK + +#define PUSH_ARRAY(A, E) \ + do { \ + *(A).end++ = (E); \ + } while (0) + +#define REALLOCATE_ARRAY(A, O, N) \ + do { \ + const size_t SIZE = SIZE_ARRAY (A); \ + (A).begin = \ + kissat_nrealloc (solver, (A).begin, (O), (N), sizeof *(A).begin); \ + (A).end = (A).begin + SIZE; \ + } while (0) + +#define RELEASE_ARRAY(A, N) \ + do { \ + const size_t TMP_NIZE = (N); \ + DEALLOC ((A).begin, TMP_NIZE); \ + } while (0) + +#define CLEAR_ARRAY CLEAR_STACK +#define TOP_ARRAY TOP_STACK +#define PEEK_ARRAY PEEK_STACK +#define POKE_ARRAY POKE_STACK +#define POP_ARRAY POP_STACK +#define BEGIN_ARRAY BEGIN_STACK +#define END_ARRAY END_STACK +#define RESIZE_ARRAY RESIZE_STACK +#define SET_END_OF_ARRAY SET_END_OF_STACK + +// clang-format off + +typedef ARRAY (unsigned) unsigned_array; + +// clang-format on + +#endif diff --git a/src/sat/kissat/assign.c b/src/sat/kissat/assign.c new file mode 100644 index 000000000..6a34f3529 --- /dev/null +++ b/src/sat/kissat/assign.c @@ -0,0 +1,59 @@ +#include "assign.h" +#include "inline.h" +#include "inlineassign.h" +#include "logging.h" + +#include + +void kissat_assign_unit (kissat *solver, unsigned lit, const char *reason) { + kissat_assign (solver, solver->probing, 0, false, lit, UNIT_REASON); + LOGUNARY (lit, "assign %s %s", LOGLIT (lit), reason); +#ifndef LOGGING + (void) reason; +#endif +} + +void kissat_learned_unit (kissat *solver, unsigned lit) { + kissat_assign_unit (solver, lit, "learned reason"); + CHECK_AND_ADD_UNIT (lit); + ADD_UNIT_TO_PROOF (lit); +} + +void kissat_original_unit (kissat *solver, unsigned lit) { + kissat_assign_unit (solver, lit, "original reason"); +} + +void kissat_assign_decision (kissat *solver, unsigned lit) { + kissat_assign (solver, solver->probing, solver->level, false, lit, + DECISION_REASON); + LOG ("assign %s decision", LOGLIT (lit)); +} + +void kissat_assign_binary (kissat *solver, unsigned lit, unsigned other) { + assert (VALUE (other) < 0); + assigned *assigned = solver->assigned; + const unsigned other_idx = IDX (other); + struct assigned *a = assigned + other_idx; + unsigned level = a->level; + if (GET_OPTION (jumpreasons) && level && a->binary) { + LOGBINARY (lit, other, "jumping %s reason", LOGLIT (lit)); + INC (jumped_reasons); + other = a->reason; + } + kissat_assign (solver, solver->probing, a->level, true, lit, other); + LOGBINARY (lit, other, "assign %s reason", LOGLIT (lit)); +} + +void kissat_assign_reference (kissat *solver, unsigned lit, reference ref, + clause *reason) { + assert (reason == kissat_dereference_clause (solver, ref)); + assigned *assigned = solver->assigned; + value *values = solver->values; + const unsigned level = + kissat_assignment_level (solver, values, assigned, lit, reason); + assert (level <= solver->level); + assert (ref != DECISION_REASON); + assert (ref != UNIT_REASON); + kissat_assign (solver, solver->probing, level, false, lit, ref); + LOGREF (ref, "assign %s reason", LOGLIT (lit)); +} diff --git a/src/sat/kissat/assign.h b/src/sat/kissat/assign.h new file mode 100644 index 000000000..64ac2027d --- /dev/null +++ b/src/sat/kissat/assign.h @@ -0,0 +1,55 @@ +#ifndef _assign_h_INCLUDED +#define _assign_h_INCLUDED + +#include + +#define DECISION_REASON UINT_MAX +#define UNIT_REASON (DECISION_REASON - 1) + +#define INVALID_LEVEL UINT_MAX +#define INVALID_TRAIL UINT_MAX + +typedef struct assigned assigned; +struct clause; + +struct assigned { + unsigned level; + unsigned trail; + + bool analyzed : 1; + bool binary : 1; + bool poisoned : 1; + bool removable : 1; + bool shrinkable : 1; + + unsigned reason; +}; + +#define ASSIGNED(LIT) \ + (assert (VALID_INTERNAL_LITERAL (LIT)), solver->assigned + IDX (LIT)) + +#define LEVEL(LIT) (ASSIGNED (LIT)->level) +#define TRAIL(LIT) (ASSIGNED (LIT)->trail) +#define REASON(LIT) (ASSIGNED (LIT)->reason) + +#ifndef FAST_ASSIGN + +#include "reference.h" + +struct kissat; +struct clause; + +void kissat_assign_unit (struct kissat *, unsigned lit, const char *); +void kissat_learned_unit (struct kissat *, unsigned lit); +void kissat_original_unit (struct kissat *, unsigned lit); + +void kissat_assign_decision (struct kissat *, unsigned lit); + +void kissat_assign_binary (struct kissat *, unsigned, unsigned); + +void kissat_assign_reference (struct kissat *, unsigned lit, reference, + struct clause *); + +#endif + +#endif diff --git a/src/sat/kissat/attribute.h b/src/sat/kissat/attribute.h new file mode 100644 index 000000000..9ec5f40ab --- /dev/null +++ b/src/sat/kissat/attribute.h @@ -0,0 +1,10 @@ +#ifndef _attribute_h_INCLUDED +#define _attribute_h_INCLUDED + +#define ATTRIBUTE_FORMAT(FORMAT_POSITION, VARIADIC_ARGUMENT_POSITION) \ + __attribute__ (( \ + format (printf, FORMAT_POSITION, VARIADIC_ARGUMENT_POSITION))) + +#define ATTRIBUTE_ALWAYS_INLINE __attribute__ ((always_inline)) + +#endif diff --git a/src/sat/kissat/averages.c b/src/sat/kissat/averages.c new file mode 100644 index 000000000..03c96a73f --- /dev/null +++ b/src/sat/kissat/averages.c @@ -0,0 +1,17 @@ +#include "internal.h" + +void kissat_init_averages (kissat *solver, averages *averages) { + if (averages->initialized) + return; +#define INIT_EMA(EMA, WINDOW) \ + kissat_init_smooth (solver, &averages->EMA, WINDOW, #EMA) +#ifndef QUIET + INIT_EMA (level, GET_OPTION (emaslow)); + INIT_EMA (size, GET_OPTION (emaslow)); + INIT_EMA (trail, GET_OPTION (emaslow)); +#endif + INIT_EMA (fast_glue, GET_OPTION (emafast)); + INIT_EMA (slow_glue, GET_OPTION (emaslow)); + INIT_EMA (decision_rate, GET_OPTION (emaslow)); + averages->initialized = true; +} diff --git a/src/sat/kissat/averages.h b/src/sat/kissat/averages.h new file mode 100644 index 000000000..d8cd03045 --- /dev/null +++ b/src/sat/kissat/averages.h @@ -0,0 +1,33 @@ +#ifndef _averages_h_INCLUDED +#define _averages_h_INCLUDED + +#include "smooth.h" + +#include + +typedef struct averages averages; + +struct averages { + bool initialized; + smooth fast_glue, slow_glue; +#ifndef QUIET + smooth level, size, trail; +#endif + smooth decision_rate; + uint64_t saved_decisions; +}; + +struct kissat; + +void kissat_init_averages (struct kissat *, averages *); + +#define AVERAGES (solver->averages[solver->stable]) + +#define EMA(NAME) (AVERAGES.NAME) + +#define AVERAGE(NAME) (EMA (NAME).value) + +#define UPDATE_AVERAGE(NAME, VALUE) \ + kissat_update_smooth (solver, &EMA (NAME), VALUE) + +#endif diff --git a/src/sat/kissat/backbone.c b/src/sat/kissat/backbone.c new file mode 100644 index 000000000..6a774efce --- /dev/null +++ b/src/sat/kissat/backbone.c @@ -0,0 +1,598 @@ +#include "backbone.h" +#include "allocate.h" +#include "analyze.h" +#include "backtrack.h" +#include "decide.h" +#include "inline.h" +#include "internal.h" +#include "logging.h" +#include "print.h" +#include "proprobe.h" +#include "report.h" +#include "terminate.h" +#include "trail.h" +#include "utilities.h" + +static void schedule_backbone_candidates (kissat *solver, + unsigneds *candidates) { + flags *flags = solver->flags; + unsigned not_rescheduled = 0; + for (all_variables (idx)) { + const struct flags *f = flags + idx; + if (!f->active) + continue; + const unsigned lit = LIT (idx); + if (f->backbone0) { + PUSH_STACK (*candidates, lit); + LOG ("rescheduling backbone literal candidate %s", LOGLIT (lit)); + } else + not_rescheduled++; + if (f->backbone1) { + const unsigned not_lit = NOT (lit); + PUSH_STACK (*candidates, not_lit); + LOG ("rescheduling backbone literal candidate %s", LOGLIT (not_lit)); + } else + not_rescheduled++; + } +#ifndef QUIET + const size_t rescheduled = SIZE_STACK (*candidates); + const unsigned active_literals = 2u * solver->active; + kissat_very_verbose ( + solver, "rescheduled %zu backbone candidate literals %.0f%%", + rescheduled, kissat_percent (rescheduled, active_literals)); +#endif + if (not_rescheduled) { + for (all_variables (idx)) { + struct flags *f = flags + idx; + if (!f->active) + continue; + const unsigned lit = LIT (idx); + if (!f->backbone0) { + LOG ("scheduling backbone literal candidate %s", LOGLIT (lit)); + PUSH_STACK (*candidates, lit); + } + if (!f->backbone1) { + const unsigned not_lit = NOT (lit); + LOG ("scheduling backbone literal candidate %s", LOGLIT (not_lit)); + PUSH_STACK (*candidates, not_lit); + } + } + } +#ifndef QUIET + const size_t total = SIZE_STACK (*candidates); + kissat_very_verbose (solver, + "scheduled %zu backbone candidate literals %.0f%%" + " in total", + total, kissat_percent (total, active_literals)); +#endif +} + +static void keep_backbone_candidates (kissat *solver, + unsigneds *candidates) { + flags *flags = solver->flags; + size_t prioritized = 0; + size_t remain = 0; + for (all_stack (unsigned, lit, *candidates)) { + const unsigned idx = IDX (lit); + const struct flags *f = flags + idx; + if (!f->active) + continue; + remain++; + if (NEGATED (lit)) + prioritized += f->backbone1; + else + prioritized += f->backbone0; + } + assert (prioritized <= remain); + if (!remain) { + kissat_very_verbose (solver, "no backbone candidates remain"); +#ifndef NDEBUG + for (all_variables (idx)) { + const struct flags *f = flags + idx; + if (!f->active) + continue; + assert (!f->backbone0); + assert (!f->backbone1); + } +#endif + return; + } +#ifndef QUIET + const size_t active_literals = 2u * solver->active; +#endif + if (prioritized == remain) + kissat_very_verbose (solver, + "keeping all remaining %zu backbone " + "candidates %.0f%% prioritized (all were)", + remain, kissat_percent (remain, active_literals)); + else if (!prioritized) { + for (all_stack (unsigned, lit, *candidates)) { + const unsigned idx = IDX (lit); + struct flags *f = flags + idx; + if (!f->active) + continue; + if (NEGATED (lit)) { + assert (!f->backbone1); + f->backbone1 = true; + } else { + assert (!f->backbone0); + f->backbone0 = true; + } + } + kissat_very_verbose (solver, + "keeping all remaining %zu backbone " + "candidates %.0f%% prioritized (none was)", + remain, kissat_percent (remain, active_literals)); + } else { + kissat_very_verbose (solver, + "keeping %zu backbone candidates %.0f%% " + "prioritized (%.0f%% of remaining %zu)", + prioritized, + kissat_percent (prioritized, active_literals), + kissat_percent (prioritized, remain), remain); + } +} + +static inline void backbone_assign (kissat *solver, unsigned_array *trail, + value *values, assigned *assigned, + unsigned lit, unsigned reason) { + const unsigned not_lit = NOT (lit); + assert (!values[lit]); + assert (!values[not_lit]); + values[lit] = 1; + values[not_lit] = -1; + PUSH_ARRAY (*trail, lit); + const unsigned idx = IDX (lit); + struct assigned *a = assigned + idx; + a->reason = reason; + a->level = solver->level; +} + +static inline clause * +backbone_propagate_literal (kissat *solver, const bool stop_early, + const watches *const all_watches, + unsigned_array *trail, value *values, + assigned *assigned, unsigned lit) { + LOG ("backbone propagating %s", LOGLIT (lit)); + assert (VALID_INTERNAL_LITERAL (lit)); + assert (values[lit] > 0); + + const unsigned not_lit = NOT (lit); + assert (values[not_lit] < 0); + + assert (not_lit < LITS); + const watches *const watches = all_watches + not_lit; + + const watch *const begin_watches = BEGIN_CONST_WATCHES (*watches); + const watch *const end_watches = END_CONST_WATCHES (*watches); + const watch *p = begin_watches; + + while (p != end_watches) { + const watch watch = *p++; + if (watch.type.binary) { + const unsigned other = watch.binary.lit; + assert (VALID_INTERNAL_LITERAL (other)); + const value value = values[other]; + if (value > 0) + continue; + if (value < 0) + return kissat_binary_conflict (solver, not_lit, other); + assert (!value); + backbone_assign (solver, trail, values, assigned, other, lit); + LOG ("backbone assign %s reason binary clause %s %s", LOGLIT (other), + LOGLIT (other), LOGLIT (not_lit)); + } else { + if (stop_early) { +#ifndef NDEBUG + for (const union watch *q = p + 1; q != end_watches; q++) { + const union watch watch = *q++; + assert (!watch.type.binary); + } +#endif + break; + } + + p++; + } + } + + const size_t touched = p - begin_watches; + solver->ticks += 1 + kissat_cache_lines (touched, sizeof (watch)); + + return 0; +} + +static inline clause *backbone_propagate (kissat *solver, + unsigned_array *trail, + value *values, + assigned *assigned) { + const bool stop_early = + solver->large_clauses_watched_after_binary_clauses; + + clause *conflict = 0; + solver->ticks = 0; + + const watches *const watches = solver->watches; + unsigned *propagate = solver->propagate; + + while (!conflict && propagate != END_ARRAY (*trail)) + conflict = backbone_propagate_literal ( + solver, stop_early, watches, trail, values, assigned, *propagate++); + + assert (solver->propagate <= propagate); + const unsigned propagated = propagate - solver->propagate; + solver->propagate = propagate; + + ADD (backbone_propagations, propagated); + ADD (probing_propagations, propagated); + ADD (propagations, propagated); + + const uint64_t ticks = solver->ticks; + + ADD (backbone_ticks, ticks); + ADD (probing_ticks, ticks); + ADD (ticks, ticks); + + return conflict; +} + +static inline void backbone_backtrack (kissat *solver, + unsigned_array *trail, value *values, + unsigned *saved, + unsigned decision_level) { + assert (decision_level <= solver->level); + unsigned *end_trail = END_ARRAY (*trail); + assert (saved != end_trail); + LOG ("backbone backtracking to trail level %zu and decision level %u", + (size_t) (saved - BEGIN_ARRAY (*trail)), decision_level); + while (saved != end_trail) { + const unsigned lit = *--end_trail; + const unsigned not_lit = NOT (lit); + LOG ("backbone unassign %s", LOGLIT (lit)); + assert (values[lit] > 0); + assert (values[not_lit] < 0); + values[lit] = values[not_lit] = 0; + } + SET_END_OF_ARRAY (solver->trail, saved); + solver->level = decision_level; + solver->propagate = saved; +} + +static unsigned backbone_analyze (kissat *solver, clause *conflict) { + assert (conflict); + LOGCLS (conflict, "backbone analyzing"); + assert (conflict->size == 2); + + assigned *const assigned = solver->assigned; + + kissat_push_analyzed (solver, assigned, IDX (conflict->lits[0])); + kissat_push_analyzed (solver, assigned, IDX (conflict->lits[1])); + + const unsigned *t = END_ARRAY (solver->trail); + + for (;;) { + assert (t > BEGIN_ARRAY (solver->trail)); + + unsigned lit = *--t; + + const unsigned lit_idx = IDX (lit); + const struct assigned *a = assigned + lit_idx; + if (!a->analyzed) + continue; + + LOG ("backbone analyzing %s", LOGLIT (lit)); + const unsigned reason = a->reason; + assert (reason != UNIT_REASON); + assert (reason != DECISION_REASON); + const unsigned reason_idx = IDX (reason); + const struct assigned *b = assigned + reason_idx; + if (!b->analyzed) { + LOG ("reason %s of %s not yet analyzed", LOGLIT (reason), + LOGLIT (lit)); + kissat_push_analyzed (solver, assigned, reason_idx); + } else { + LOG ("backbone UIP %s", LOGLIT (reason)); + kissat_reset_only_analyzed_literals (solver); + return reason; + } + } +} + +#ifndef NDEBUG + +static void +check_large_clauses_watched_after_binary_clauses (kissat *solver) { + for (all_literals (lit)) { + bool large = false; + for (all_binary_blocking_watches (watch, WATCHES (lit))) + if (watch.type.binary) + assert (!large); + else + large = true; + } +} + +#endif + +static unsigned compute_backbone (kissat *solver) { +#ifndef NDEBUG + if (solver->large_clauses_watched_after_binary_clauses) + check_large_clauses_watched_after_binary_clauses (solver); +#endif + size_t failed = 0; + unsigneds units; + unsigneds candidates; + INIT_STACK (candidates); + INIT_STACK (units); + schedule_backbone_candidates (solver, &candidates); +#ifndef QUIET + const size_t scheduled = SIZE_STACK (candidates); +#endif +#if defined(METRICS) && (!defined(QUIET) || !defined(NDEBUG)) + const uint64_t implied_before = solver->statistics.backbone_implied; +#endif + unsigned_array *trail = &solver->trail; + value *values = solver->values; + flags *flags = solver->flags; + assigned *assigned = solver->assigned; + + assert (kissat_propagated (solver)); + assert (kissat_trail_flushed (solver)); + + unsigned inconsistent = INVALID_LIT; + + SET_EFFORT_LIMIT (ticks_limit, backbone, backbone_ticks); + size_t round_limit = GET_OPTION (backbonerounds); + assert (solver->statistics.backbone_computations); + round_limit *= solver->statistics.backbone_computations; + const size_t max_rounds = GET_OPTION (backbonemaxrounds); + if (round_limit > max_rounds) + round_limit = max_rounds; + + size_t round = 0; + + for (;;) { + if (round >= round_limit) { + kissat_very_verbose (solver, "backbone round limit %zu hit", round); + break; + } + const uint64_t ticks = solver->statistics.backbone_ticks; + if (ticks > ticks_limit) { + kissat_very_verbose (solver, + "backbone ticks limit %" PRIu64 " hit " + "after %" PRIu64 " ticks", + ticks_limit, ticks); + break; + } + size_t previous = failed; + assert (!solver->inconsistent); + if (TERMINATED (backbone_terminated_1)) + break; + round++; + INC (backbone_rounds); + LOG ("starting backbone round %zu", round); + unsigned *const begin_candidates = BEGIN_STACK (candidates); + assert (!solver->level); +#if !defined(QUIET) && defined(METRICS) + size_t decisions = 0; + uint64_t propagated = solver->statistics.backbone_propagations; +#endif + unsigned active_before = solver->active; + { + unsigned *q = begin_candidates; + const unsigned *p = begin_candidates; + const unsigned *const end_candidates = END_STACK (candidates); + while (p != end_candidates) { + assert (!solver->inconsistent); + const unsigned probe = *q++ = *p++; + const value value = values[probe]; + if (value > 0) { + q--; + LOG ("removing satisfied backbone probe %s", LOGLIT (probe)); + const unsigned idx = IDX (probe); + struct flags *f = flags + idx; + if (NEGATED (probe)) + f->backbone1 = false; + else + f->backbone0 = false; + continue; + } + if (value < 0) { + const unsigned idx = IDX (probe); + struct assigned *a = assigned + idx; + if (a->level) + LOG ("skipping falsified backbone probe %s", LOGLIT (probe)); + else { + LOG ("removing root-level falsified backbone probe %s", + LOGLIT (probe)); + q--; + } + continue; + } + if (solver->statistics.backbone_ticks > ticks_limit) + break; + if (TERMINATED (backbone_terminated_2)) + break; + const unsigned level = solver->level; + unsigned *const saved = END_ARRAY (*trail); + assert (level != UINT_MAX); +#if !defined(QUIET) && defined(METRICS) + decisions++; +#endif + solver->level = level + 1; + INC (backbone_probes); + backbone_assign (solver, trail, values, assigned, probe, + DECISION_REASON); + LOG ("backbone assume %s", LOGLIT (probe)); + clause *conflict = + backbone_propagate (solver, trail, values, assigned); + if (!conflict) { + LOG ("propagating backbone probe %s successful", LOGLIT (probe)); + continue; + } + + failed++; + INC (backbone_units); + q--; + + LOG ("propagating backbone probe %s failed", LOGLIT (probe)); + unsigned uip = backbone_analyze (solver, conflict); + unsigned not_uip = NOT (uip); + backbone_backtrack (solver, trail, values, saved, level); + + PUSH_STACK (units, not_uip); + backbone_assign (solver, trail, values, assigned, not_uip, + UNIT_REASON); + LOG ("backbone forced assign %s", LOGLIT (not_uip)); + assert (failed == SIZE_STACK (units)); + + conflict = backbone_propagate (solver, trail, values, assigned); + if (conflict) { + LOG ("propagating backbone forced %s failed", LOGLIT (not_uip)); + inconsistent = not_uip; + break; + } + + LOG ("propagating backbone forced %s successful", LOGLIT (not_uip)); + } +#ifndef QUIET + size_t remain = end_candidates - p; + if (remain) + kissat_extremely_verbose (solver, + "backbone round %zu aborted with " + "%zu candidates %.0f%% remaining", + round, remain, + kissat_percent (remain, scheduled)); + else + kissat_extremely_verbose (solver, + "backbone round %zu completed with " + "all %zu scheduled candidates tried", + round, scheduled); +#endif + while (p != end_candidates) + *q++ = *p++; + + SET_END_OF_STACK (candidates, q); + } + if (inconsistent == INVALID_LIT) { + LOG ("flushing satisfied probe candidates"); + unsigned *q = begin_candidates; + const unsigned *p = begin_candidates; + const unsigned *const end_candidates = END_STACK (candidates); + while (p != end_candidates) { + const unsigned probe = *q++ = *p++; + const value value = values[probe]; + if (value > 0) { + q--; + LOG ("removing satisfied backbone probe %s", LOGLIT (probe)); + const unsigned idx = IDX (probe); + struct flags *f = flags + idx; + if (NEGATED (probe)) + f->backbone1 = false; + else + f->backbone0 = false; + continue; + } + if (value < 0) { + LOG ("keeping falsified probe %s", LOGLIT (probe)); + continue; + } + assert (!value); + LOG ("keeping unassigned probe %s", LOGLIT (probe)); + } + LOG ("flushed %zu probe candidates", + (size_t) (q - BEGIN_STACK (candidates))); + SET_END_OF_STACK (candidates, q); + } + if (!EMPTY_ARRAY (*trail)) + backbone_backtrack (solver, trail, values, BEGIN_ARRAY (*trail), 0); + if (inconsistent == INVALID_LIT && previous < failed) { + for (size_t i = previous; i < failed; i++) { + const unsigned unit = PEEK_STACK (units, i); + LOG ("assigning backbone unit %s", LOGLIT (unit)); + kissat_learned_unit (solver, unit); + } + if (kissat_probing_propagate (solver, 0, true)) + break; + } + assert (solver->active <= active_before); + unsigned implied = active_before - solver->active; + assert (failed <= failed); + ADD (backbone_implied, implied); +#ifndef QUIET +#ifdef METRICS + propagated = solver->statistics.backbone_propagations - propagated; + kissat_very_verbose (solver, + "backbone round %zu with %zu decisions " + "(%.2f propagations per decision)", + round, decisions, + kissat_average (propagated, decisions)); +#endif + size_t left = SIZE_STACK (candidates); + kissat_very_verbose (solver, + "backbone round %zu produced %zu failed literals" + " %u implied (%zu candidates left %.0f%%)", + round, failed - previous, implied, left, + kissat_percent (left, scheduled)); +#endif + if (inconsistent != INVALID_LIT) + break; + if (EMPTY_STACK (candidates)) + break; + } + + if (inconsistent != INVALID_LIT && !solver->inconsistent) { + LOG ("assuming forced unit %s", LOGLIT (inconsistent)); + kissat_learned_unit (solver, inconsistent); + (void) kissat_probing_propagate (solver, 0, true); + assert (solver->inconsistent); + } + RELEASE_STACK (units); + if (solver->inconsistent) + kissat_phase (solver, "backbone", GET (backbone_computations), + "inconsistent binary clauses"); + else { + keep_backbone_candidates (solver, &candidates); +#if defined(METRICS) && (!defined(QUIET) || !defined(NDEBUG)) + assert (implied_before <= solver->statistics.backbone_implied); +#endif +#if defined(METRICS) && !defined(QUIET) + const uint64_t total_implied = + solver->statistics.backbone_implied - implied_before; + kissat_phase (solver, "backbone", GET (backbone_computations), + "found %zu backbone literals %" PRIu64 + " implied in %zu rounds", + failed, total_implied, round); +#endif + } + RELEASE_STACK (candidates); + return failed; +} + +void kissat_binary_clauses_backbone (kissat *solver) { + if (solver->inconsistent) + return; + if (!GET_OPTION (backbone)) + return; + if (TERMINATED (backbone_terminated_3)) + return; + assert (solver->watching); + assert (solver->probing); + assert (!solver->level); + START (backbone); + INC (backbone_computations); +#if !defined(NDEBUG) || defined(METRICS) + assert (!solver->backbone_computing); + solver->backbone_computing = true; +#endif +#ifndef QUIET + const unsigned failed = +#endif + compute_backbone (solver); + REPORT (!failed, 'b'); +#if !defined(NDEBUG) || defined(METRICS) + assert (solver->backbone_computing); + solver->backbone_computing = false; +#endif + STOP (backbone); +} diff --git a/src/sat/kissat/backbone.h b/src/sat/kissat/backbone.h new file mode 100644 index 000000000..0ddf87c99 --- /dev/null +++ b/src/sat/kissat/backbone.h @@ -0,0 +1,9 @@ +#ifndef _backbone_h_INCLUDED +#define _backbone_h_INCLUDED + +#include + +struct kissat; +void kissat_binary_clauses_backbone (struct kissat *); + +#endif diff --git a/src/sat/kissat/backtrack.c b/src/sat/kissat/backtrack.c new file mode 100644 index 000000000..09ba8df70 --- /dev/null +++ b/src/sat/kissat/backtrack.c @@ -0,0 +1,177 @@ +#include "backtrack.h" +#include "analyze.h" +#include "inline.h" +#include "inlineheap.h" +#include "inlinequeue.h" +#include "print.h" +#include "proprobe.h" +#include "propsearch.h" +#include "trail.h" + +static inline void unassign (kissat *solver, value *values, unsigned lit) { + LOG ("unassign %s", LOGLIT (lit)); + assert (values[lit] > 0); + const unsigned not_lit = NOT (lit); + values[lit] = values[not_lit] = 0; + assert (solver->unassigned < VARS); + solver->unassigned++; +} + +static inline void add_unassigned_variable_back_to_queue (kissat *solver, + links *links, + unsigned lit) { + assert (!solver->stable); + const unsigned idx = IDX (lit); + if (links[idx].stamp > solver->queue.search.stamp) + kissat_update_queue (solver, links, idx); +} + +static inline void add_unassigned_variable_back_to_heap (kissat *solver, + heap *scores, + unsigned lit) { + assert (solver->stable); + const unsigned idx = IDX (lit); + if (!kissat_heap_contains (scores, idx)) + kissat_push_heap (solver, scores, idx); +} + +static void kissat_update_target_and_best_phases (kissat *solver) { + if (solver->probing) + return; + + if (!solver->stable) + return; + + const unsigned assigned = kissat_assigned (solver); +#ifdef LOGGING + LOG ("updating target and best phases"); + LOG ("currently %u variables assigned", assigned); +#endif + + if (solver->target_assigned < assigned) { + kissat_extremely_verbose (solver, + "updating target assigned " + "trail height from %u to %u", + solver->target_assigned, assigned); + solver->target_assigned = assigned; + kissat_save_target_phases (solver); + INC (target_saved); + } + + if (solver->best_assigned < assigned) { + kissat_extremely_verbose (solver, + "updating best assigned " + "trail height from %u to %u", + solver->best_assigned, assigned); + solver->best_assigned = assigned; + kissat_save_best_phases (solver); + INC (best_saved); + } +} + +void kissat_backtrack_without_updating_phases (kissat *solver, + unsigned new_level) { + assert (solver->level >= new_level); + if (solver->level == new_level) + return; + + LOG ("backtracking to decision level %u", new_level); + + frame *new_frame = &FRAME (new_level + 1); + SET_END_OF_STACK (solver->frames, new_frame); + + value *values = solver->values; + unsigned *trail = BEGIN_ARRAY (solver->trail); + unsigned *new_end = trail + new_frame->trail; + assigned *assigned = solver->assigned; + + unsigned *old_end = END_ARRAY (solver->trail); + unsigned unassigned = 0, reassigned = 0; + + unsigned *q = new_end; + if (solver->stable) { + heap *scores = SCORES; + for (const unsigned *p = q; p != old_end; p++) { + const unsigned lit = *p; + const unsigned idx = IDX (lit); + assert (idx < VARS); + struct assigned *a = assigned + idx; + const unsigned level = a->level; + if (level <= new_level) { + const unsigned new_trail = q - trail; + assert (new_trail <= a->trail); + a->trail = new_trail; + *q++ = lit; + LOG ("reassign %s", LOGLIT (lit)); + reassigned++; + } else { + unassign (solver, values, lit); + add_unassigned_variable_back_to_heap (solver, scores, lit); + unassigned++; + } + } + } else { + links *links = solver->links; + for (const unsigned *p = q; p != old_end; p++) { + const unsigned lit = *p; + const unsigned idx = IDX (lit); + assert (idx < VARS); + struct assigned *a = assigned + idx; + const unsigned level = a->level; + if (level <= new_level) { + const unsigned new_trail = q - trail; + assert (new_trail <= a->trail); + a->trail = new_trail; + *q++ = lit; + LOG ("reassign %s", LOGLIT (lit)); + reassigned++; + } else { + unassign (solver, values, lit); + add_unassigned_variable_back_to_queue (solver, links, lit); + unassigned++; + } + } + } + SET_END_OF_ARRAY (solver->trail, q); + + solver->level = new_level; + LOG ("unassigned %u literals", unassigned); + LOG ("reassigned %u literals", reassigned); + (void) unassigned, (void) reassigned; + + assert (new_end <= END_ARRAY (solver->trail)); + LOG ("propagation will resume at trail position %zu", + (size_t) (new_end - trail)); + solver->propagate = new_end; + + assert (!solver->extended); +} + +void kissat_backtrack_in_consistent_state (kissat *solver, + unsigned new_level) { + kissat_update_target_and_best_phases (solver); + kissat_backtrack_without_updating_phases (solver, new_level); +} + +void kissat_backtrack_after_conflict (kissat *solver, unsigned new_level) { + if (solver->level) + kissat_backtrack_without_updating_phases (solver, solver->level - 1); + kissat_update_target_and_best_phases (solver); + kissat_backtrack_without_updating_phases (solver, new_level); +} + +void kissat_backtrack_propagate_and_flush_trail (kissat *solver) { + if (solver->level) { + assert (solver->watching); + kissat_backtrack_in_consistent_state (solver, 0); +#ifndef NDEBUG + clause *conflict = +#endif + solver->probing ? kissat_probing_propagate (solver, 0, true) + : kissat_search_propagate (solver); + assert (!conflict); + } + + assert (kissat_propagated (solver)); + assert (kissat_trail_flushed (solver)); +} diff --git a/src/sat/kissat/backtrack.h b/src/sat/kissat/backtrack.h new file mode 100644 index 000000000..7a9b93bf7 --- /dev/null +++ b/src/sat/kissat/backtrack.h @@ -0,0 +1,11 @@ +#ifndef _backtrack_h_INCLUDED +#define _backtrack_h_INCLUDED + +struct kissat; + +void kissat_backtrack_without_updating_phases (struct kissat *, unsigned); +void kissat_backtrack_in_consistent_state (struct kissat *, unsigned); +void kissat_backtrack_after_conflict (struct kissat *, unsigned); +void kissat_backtrack_propagate_and_flush_trail (struct kissat *); + +#endif diff --git a/src/sat/kissat/build.c b/src/sat/kissat/build.c new file mode 100644 index 000000000..0426854a2 --- /dev/null +++ b/src/sat/kissat/build.c @@ -0,0 +1,81 @@ +#include "build.h" +#include "colors.h" +#include "kissat.h" +#include "print.h" + +#include + +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); +} diff --git a/src/sat/kissat/bump.c b/src/sat/kissat/bump.c new file mode 100644 index 000000000..5771db4ac --- /dev/null +++ b/src/sat/kissat/bump.c @@ -0,0 +1,120 @@ +#include "bump.h" +#include "analyze.h" +#include "inlineheap.h" +#include "inlinequeue.h" +#include "inlinevector.h" +#include "internal.h" +#include "logging.h" +#include "print.h" +#include "rank.h" +#include "sort.h" + +#define RANK(A) ((A).rank) +#define SMALLER(A, B) (RANK (A) < RANK (B)) + +#define RADIX_SORT_BUMP_LIMIT 32 + +static void sort_bump (kissat *solver) { + const size_t size = SIZE_STACK (solver->analyzed); + if (size < RADIX_SORT_BUMP_LIMIT) { + LOG ("quick sorting %zu analyzed variables", size); + SORT_STACK (datarank, solver->ranks, SMALLER); + } else { + LOG ("radix sorting %zu analyzed variables", size); + RADIX_STACK (datarank, unsigned, solver->ranks, RANK); + } +} + +void kissat_rescale_scores (kissat *solver) { + INC (rescaled); + heap *scores = &solver->scores; + const double max_score = kissat_max_score_on_heap (scores); + kissat_phase (solver, "rescale", GET (rescaled), + "maximum score %g increment %g", max_score, solver->scinc); + const double rescale = MAX (max_score, solver->scinc); + assert (rescale > 0); + const double factor = 1.0 / rescale; + kissat_rescale_heap (solver, scores, factor); + solver->scinc *= factor; + kissat_phase (solver, "rescale", GET (rescaled), "rescaled by factor %g", + factor); +} + +void kissat_bump_score_increment (kissat *solver) { + const double old_scinc = solver->scinc; + const double decay = GET_OPTION (decay) * 1e-3; + assert (0 <= decay), assert (decay <= 0.5); + const double factor = 1.0 / (1.0 - decay); + const double new_scinc = old_scinc * factor; + LOG ("new score increment %g = %g * %g", new_scinc, factor, old_scinc); + solver->scinc = new_scinc; + if (new_scinc > MAX_SCORE) + kissat_rescale_scores (solver); +} + +static inline void bump_analyzed_variable_score (kissat *solver, + unsigned idx) { + heap *scores = &solver->scores; + const double old_score = kissat_get_heap_score (scores, idx); + const double inc = solver->scinc; + const double new_score = old_score + inc; + LOG ("new score[%u] = %g = %g + %g", idx, new_score, old_score, inc); + kissat_update_heap (solver, scores, idx, new_score); + if (new_score > MAX_SCORE) + kissat_rescale_scores (solver); +} + +void kissat_bump_variable (kissat *solver, unsigned idx) { + bump_analyzed_variable_score (solver, idx); +} + +static void bump_analyzed_variable_scores (kissat *solver) { + flags *flags = solver->flags; + + for (all_stack (unsigned, idx, solver->analyzed)) + if (flags[idx].active) + bump_analyzed_variable_score (solver, idx); + + kissat_bump_score_increment (solver); +} + +static void move_analyzed_variables_to_front_of_queue (kissat *solver) { + assert (EMPTY_STACK (solver->ranks)); + const links *const links = solver->links; + for (all_stack (unsigned, idx, solver->analyzed)) { + // clang-format off + const datarank rank = { .data = idx, .rank = links[idx].stamp }; + // clang-format on + PUSH_STACK (solver->ranks, rank); + } + + sort_bump (solver); + + flags *flags = solver->flags; + unsigned idx; + + for (all_stack (datarank, rank, solver->ranks)) + if (flags[idx = rank.data].active) + kissat_move_to_front (solver, idx); + + CLEAR_STACK (solver->ranks); +} + +void kissat_bump_analyzed (kissat *solver) { + START (bump); + const size_t bumped = SIZE_STACK (solver->analyzed); + if (!solver->stable) + move_analyzed_variables_to_front_of_queue (solver); + else + bump_analyzed_variable_scores (solver); + ADD (literals_bumped, bumped); + STOP (bump); +} + +void kissat_update_scores (kissat *solver) { + assert (solver->stable); + heap *scores = SCORES; + for (all_variables (idx)) + if (ACTIVE (idx) && !kissat_heap_contains (scores, idx)) + kissat_push_heap (solver, scores, idx); +} diff --git a/src/sat/kissat/bump.h b/src/sat/kissat/bump.h new file mode 100644 index 000000000..55d541562 --- /dev/null +++ b/src/sat/kissat/bump.h @@ -0,0 +1,16 @@ +#ifndef _bump_h_INCLUDED +#define _bump_h_INCLUDED + +#include + +struct kissat; + +void kissat_bump_analyzed (struct kissat *); +void kissat_update_scores (struct kissat *); +void kissat_rescale_scores (struct kissat *); +void kissat_bump_variable (struct kissat *, unsigned idx); +void kissat_bump_score_increment (struct kissat *); + +#define MAX_SCORE 1e150 + +#endif diff --git a/src/sat/kissat/check.c b/src/sat/kissat/check.c new file mode 100644 index 000000000..0245a0866 --- /dev/null +++ b/src/sat/kissat/check.c @@ -0,0 +1,1033 @@ +#ifndef NDEBUG + +#include "check.h" +#include "error.h" +#include "internal.h" +#include "literal.h" +#include "logging.h" +#include "print.h" + +#include +#include +#include + +#undef LOGPREFIX +#define LOGPREFIX "CHECK" + +void kissat_check_satisfying_assignment (kissat *solver) { + LOG ("checking satisfying assignment"); + const int *const begin = BEGIN_STACK (solver->original); + const int *const end = END_STACK (solver->original); +#ifdef LOGGING + size_t count = 0; +#endif + for (const int *p = begin, *q; p != end; p = q + 1) { + bool satisfied = false; + int lit, other; + for (q = p; (lit = *q); q++) + if (!satisfied && kissat_value (solver, lit) == lit) + satisfied = true; +#ifdef LOGGING + count++; +#endif + if (satisfied) + continue; + for (q = p; (lit = *q); q++) + for (const int *r = q + 1; (other = *r); r++) + if (lit == -other) + satisfied = true; + if (satisfied) + continue; + kissat_fatal_message_start (); + fputs ("unsatisfied clause:\n", stderr); + for (q = p; (lit = *q); q++) + fprintf (stderr, "%d ", lit); + fputs ("0\n", stderr); + fflush (stderr); + kissat_abort (); + } + LOG ("assignment satisfies all %zu original clauses", count); +} + +#include "allocate.h" +#include "inline.h" +#include "sort.h" + +typedef struct hash hash; +typedef struct bucket bucket; + +// clang-format off + +typedef STACK (bucket*) buckets; + +// clang-format on + +struct bucket { + bucket *next; + unsigned size; + unsigned hash; + unsigned lits[]; +}; + +struct checker { + bool inconsistent; + + unsigned vars; + unsigned size; + + unsigned buckets; + unsigned hashed; + + bucket **table; + + buckets *watches; + bool *marks; + bool *large; + bool *used; + signed char *values; + + bool marked; + unsigneds imported; + + unsigneds trail; + unsigned propagated; + + unsigned nonces[32]; + + uint64_t added; + uint64_t blocked; + uint64_t checked; + uint64_t collisions; + uint64_t decisions; + uint64_t propagations; + uint64_t pure; + uint64_t removed; + uint64_t satisfied; + uint64_t searches; + uint64_t unchecked; +}; + +#define LOGIMPORTED3(...) \ + LOGUNSIGNEDS3 (SIZE_STACK (checker->imported), \ + BEGIN_STACK (checker->imported), __VA_ARGS__) + +#define LOGLINE3(...) \ + LOGUNSIGNEDS3 (bucket->size, bucket->lits, __VA_ARGS__) + +#define MAX_NONCES (sizeof checker->nonces / sizeof *checker->nonces) + +static inline bool less_unsigned (unsigned a, unsigned b) { return a < b; } + +static void sort_line (kissat *solver, checker *checker) { + SORT_STACK (unsigned, checker->imported, less_unsigned); + LOGIMPORTED3 ("sorted checker"); +} + +static unsigned hash_line (checker *checker) { + unsigned res = 0, pos = 0; + for (all_stack (unsigned, lit, checker->imported)) { + res += checker->nonces[pos++] * lit; + if (pos == MAX_NONCES) + pos = 0; + } + return res; +} + +static size_t bytes_line (unsigned size) { + return sizeof (bucket) + size * sizeof (unsigned); +} + +static void init_nonces (kissat *solver, checker *checker) { + generator random = 42; + for (unsigned i = 0; i < MAX_NONCES; i++) + checker->nonces[i] = 1 | kissat_next_random32 (&random); + LOG3 ("initialized %zu checker nonces", MAX_NONCES); +#ifndef LOGGING + (void) solver; +#endif +} + +void kissat_init_checker (kissat *solver) { + LOG ("initializing internal proof checker"); + checker *checker = kissat_calloc (solver, 1, sizeof (struct checker)); + solver->checker = checker; + init_nonces (solver, checker); +} + +static void release_hash (kissat *solver, checker *checker) { + for (unsigned h = 0; h < checker->hashed; h++) { + for (bucket *bucket = checker->table[h], *next; bucket; bucket = next) { + next = bucket->next; + kissat_free (solver, bucket, bytes_line (bucket->size)); + } + } + kissat_dealloc (solver, checker->table, checker->hashed, + sizeof (bucket *)); +} + +static void release_watches (kissat *solver, checker *checker) { + const unsigned lits = 2 * checker->vars; + for (unsigned i = 0; i < lits; i++) + RELEASE_STACK (checker->watches[i]); + kissat_dealloc (solver, checker->watches, 2 * checker->size, + sizeof (buckets)); +} + +void kissat_release_checker (kissat *solver) { + LOG ("releasing internal proof checker"); + checker *checker = solver->checker; + release_hash (solver, checker); + RELEASE_STACK (checker->imported); + RELEASE_STACK (checker->trail); + kissat_free (solver, checker->marks, 2 * checker->size * sizeof (bool)); + kissat_free (solver, checker->used, 2 * checker->size * sizeof (bool)); + kissat_free (solver, checker->large, 2 * checker->size * sizeof (bool)); + kissat_free (solver, checker->values, 2 * checker->size); + release_watches (solver, checker); + kissat_free (solver, checker, sizeof (struct checker)); +} + +#ifndef QUIET + +#include + +#define PERCENT_ADDED(NAME) kissat_percent (checker->NAME, checker->added) +#define PERCENT_CHECKED(NAME) \ + kissat_percent (checker->NAME, checker->checked) + +void kissat_print_checker_statistics (kissat *solver, bool verbose) { + checker *checker = solver->checker; + PRINT_STAT ("checker_added", checker->added, 100, "%", ""); + if (verbose) + PRINT_STAT ("checker_blocked", checker->blocked, + PERCENT_CHECKED (blocked), "%", "checked"); + PRINT_STAT ("checker_checked", checker->checked, PERCENT_ADDED (checked), + "%", "added"); + if (verbose) { + PRINT_STAT ("checker_collisions", checker->collisions, + kissat_percent (checker->collisions, checker->searches), + "%", "per search"); + PRINT_STAT ("checker_decisions", checker->decisions, + kissat_average (checker->decisions, checker->checked), "", + "per check"); + PRINT_STAT ("checker_propagations", checker->propagations, + kissat_average (checker->propagations, checker->checked), + "", "per check"); + PRINT_STAT ("checker_pure", checker->pure, PERCENT_CHECKED (pure), "%", + "checked"); + } + PRINT_STAT ("checker_removed", checker->removed, PERCENT_ADDED (removed), + "%", "added"); + if (verbose) { + PRINT_STAT ("checker_satisfied", checker->satisfied, + PERCENT_CHECKED (satisfied), "%", "checked"); + PRINT_STAT ("checker_unchecked", checker->unchecked, + PERCENT_ADDED (unchecked), "%", "added"); + } +} + +#endif + +#define MAX_VARS (1u << 29) +#define MAX_SIZE (1u << 30) + +static unsigned reduce_hash (unsigned hash, unsigned mod) { + if (mod < 2) + return 0; + assert (mod); + unsigned res = hash; + for (unsigned shift = 16, mask = 0xffff; res >= mod; + mask >>= (shift >>= 1)) + res = (res >> shift) & mask; + assert (res < mod); + return res; +} + +static void resize_hash (kissat *solver, checker *checker) { + const unsigned old_hashed = checker->hashed; + assert (old_hashed < MAX_SIZE); + const unsigned new_hashed = old_hashed ? 2 * old_hashed : 1; + bucket **table = kissat_calloc (solver, new_hashed, sizeof (bucket *)); + bucket **old_table = checker->table; + for (unsigned i = 0; i < old_hashed; i++) { + for (bucket *bucket = old_table[i], *next; bucket; bucket = next) { + next = bucket->next; + const unsigned reduced = reduce_hash (bucket->hash, new_hashed); + bucket->next = table[reduced]; + table[reduced] = bucket; + } + } + kissat_dealloc (solver, checker->table, old_hashed, sizeof (bucket *)); + checker->hashed = new_hashed; + checker->table = table; +} + +static bucket *new_line (kissat *solver, checker *checker, unsigned size, + unsigned hash) { + bucket *res = kissat_malloc (solver, bytes_line (size)); + res->next = 0; + res->size = size; + res->hash = hash; + memcpy (res->lits, BEGIN_STACK (checker->imported), + size * sizeof *res->lits); + return res; +} + +#define CHECKER_LITS (2 * (checker)->vars) +#define VALID_CHECKER_LIT(LIT) ((LIT) < CHECKER_LITS) + +static bucket decision_line; +static bucket unit_line; + +static void checker_assign (kissat *solver, checker *checker, unsigned lit, + bucket *bucket) { +#ifdef LOGGING + if (bucket == &decision_line) + LOG3 ("checker assign %u (decision)", lit); + else if (bucket == &unit_line) + LOG3 ("checker assign %u (unit)", lit); + else + LOGLINE3 ("checker assign %u reason", lit); +#else + (void) bucket; +#endif + assert (VALID_CHECKER_LIT (lit)); + const unsigned not_lit = lit ^ 1; + signed char *values = checker->values; + assert (!values[lit]); + assert (!values[not_lit]); + values[lit] = 1; + values[not_lit] = -1; + PUSH_STACK (checker->trail, lit); +} + +static buckets *checker_watches (checker *checker, unsigned lit) { + assert (VALID_CHECKER_LIT (lit)); + return checker->watches + lit; +} + +static void watch_checker_literal (kissat *solver, checker *checker, + bucket *bucket, unsigned lit) { + LOGLINE3 ("checker watches %u in", lit); + buckets *buckets = checker_watches (checker, lit); + PUSH_STACK (*buckets, bucket); +} + +static void unwatch_checker_literal (kissat *solver, checker *checker, + bucket *bucket, unsigned lit) { + LOGLINE3 ("checker unwatches %u in", lit); + buckets *buckets = checker_watches (checker, lit); + REMOVE_STACK (struct bucket *, *buckets, bucket); +#ifndef LOGGING + (void) solver; +#endif +} + +static void unwatch_line (kissat *solver, checker *checker, + bucket *bucket) { + assert (bucket->size > 1); + const unsigned *const lits = bucket->lits; + unwatch_checker_literal (solver, checker, bucket, lits[0]); + unwatch_checker_literal (solver, checker, bucket, lits[1]); +} + +static bool satisfied_or_trivial_imported (kissat *solver, + checker *checker) { + const unsigned *const lits = BEGIN_STACK (checker->imported); + const unsigned *const end_of_lits = END_STACK (checker->imported); + const signed char *values = checker->values; + bool *marks = checker->marks; + unsigned const *p; + bool res = false; + for (p = lits; !res && p != end_of_lits; p++) { + const unsigned lit = *p; + if (marks[lit]) + continue; + marks[lit] = true; + const unsigned not_lit = lit ^ 1; + if (marks[not_lit]) { + LOGIMPORTED3 ("trivial by %u and %u imported checker", not_lit, lit); + res = true; + } else if (values[lit] > 0) { + LOGIMPORTED3 ("satisfied by %u imported checker", lit); + res = true; + } + } + for (const unsigned *q = lits; q != p; q++) + marks[*q] = 0; +#ifndef LOGGING + (void) solver; +#endif + return res; +} + +static void mark_line (checker *checker) { + bool *marks = checker->marks; + for (all_stack (unsigned, lit, checker->imported)) + marks[lit] = 1; + checker->marked = true; +} + +static void unmark_line (checker *checker) { + bool *marks = checker->marks; + for (all_stack (unsigned, lit, checker->imported)) + marks[lit] = 0; + checker->marked = false; +} + +static bool simplify_imported (kissat *solver, checker *checker) { + if (checker->inconsistent) { + LOG3 ("skipping addition since checker already inconsistent"); + return true; + } + unsigned non_false = 0; +#ifdef LOGGING + unsigned num_false = 0; +#endif + const unsigned *const end_of_lits = END_STACK (checker->imported); + unsigned *lits = BEGIN_STACK (checker->imported); + const signed char *values = checker->values; + bool *marks = checker->marks; + bool res = false; + unsigned *p; + for (p = lits; !res && p != end_of_lits; p++) { + const unsigned lit = *p; + if (marks[lit]) + continue; + marks[lit] = true; + const unsigned not_lit = lit ^ 1; + if (marks[not_lit]) { + LOG3 ("simplified checker clause trivial (contains %u and %u)", + not_lit, lit); + res = true; + } else { + signed char lit_value = values[lit]; + if (lit_value < 0) { +#ifdef LOGGING + num_false++; +#endif + } else if (lit_value > 0) { + LOG3 ("simplified checker clause satisfied by %u", lit); + res = true; + } else { + if (!non_false) + SWAP (unsigned, *p, lits[0]); + else if (non_false == 1) + SWAP (unsigned, *p, lits[1]); + non_false++; + } + } + } + for (const unsigned *q = lits; q != p; q++) + marks[*q] = 0; + if (!res) { + if (!non_false) { + LOG3 ("simplified checker clause inconsistent"); + checker->inconsistent = true; + res = true; + } else if (non_false == 1) { + LOG3 ("simplified checker clause unit"); + checker_assign (solver, checker, lits[0], &unit_line); + res = true; + } + } + if (!res) { + LOG3 ("non-trivial and non-satisfied imported checker clause " + "has %u false and %u non-false literals", + num_false, non_false); + LOGIMPORTED3 ("simplified checker"); + } + return res; +} + +static void use_literal (kissat *solver, checker *checker, unsigned lit) { + if (checker->used[lit]) + return; + checker->used[lit] = true; +#ifdef LOGGING + LOG3 ("used checker literal %u", lit); +#else + (void) solver; +#endif +} + +static void large_literal (kissat *solver, checker *checker, unsigned lit) { + if (checker->large[lit]) + return; + checker->large[lit] = true; +#ifdef LOGGING + LOG3 ("large checker literal %u", lit); +#else + (void) solver; +#endif +} + +static void use_line (kissat *solver, checker *checker) { + bool large = (SIZE_STACK (checker->imported) > 2); + for (all_stack (unsigned, lit, checker->imported)) { + use_literal (solver, checker, lit); + if (large) + large_literal (solver, checker, lit); + } +} + +static void insert_imported (kissat *solver, checker *checker, + unsigned hash) { + size_t size = SIZE_STACK (checker->imported); + assert (size <= UINT_MAX); + if (checker->buckets == checker->hashed) + resize_hash (solver, checker); + bucket *bucket = new_line (solver, checker, size, hash); + const unsigned reduced = reduce_hash (hash, checker->hashed); + struct bucket **p = checker->table + reduced; + bucket->next = *p; + *p = bucket; + LOGLINE3 ("inserted checker"); + const unsigned *const lits = BEGIN_STACK (checker->imported); + const signed char *values = checker->values; + assert (!values[lits[0]]); + assert (!values[lits[1]]); + watch_checker_literal (solver, checker, bucket, lits[0]); + watch_checker_literal (solver, checker, bucket, lits[1]); + checker->buckets++; + checker->added++; +} + +static void insert_imported_if_not_simplified (kissat *solver, + checker *checker) { + sort_line (solver, checker); + const unsigned hash = hash_line (checker); + if (!simplify_imported (solver, checker)) { + insert_imported (solver, checker, hash); + use_line (solver, checker); + } +} + +static bool match_line (checker *checker, unsigned size, unsigned hash, + bucket *bucket) { + if (bucket->size != size) + return false; + if (bucket->hash != hash) + return false; + if (!checker->marked) + mark_line (checker); + const unsigned *const lits = bucket->lits; + const unsigned *const end_of_lits = lits + bucket->size; + const bool *const marks = checker->marks; + for (const unsigned *p = lits; p != end_of_lits; p++) + if (!marks[*p]) + return false; + return true; +} + +static void resize_checker (kissat *solver, checker *checker, + unsigned new_vars) { + const unsigned vars = checker->vars; + const unsigned size = checker->size; + if (new_vars > size) { + assert (new_vars <= MAX_SIZE); + unsigned new_size = size ? 2 * size : 1; + while (new_size < new_vars) + new_size *= 2; + assert (new_size <= MAX_SIZE); + LOG3 ("resizing checker form %u to %u", size, new_size); + const unsigned size2 = 2 * size; + const unsigned new_size2 = 2 * new_size; + checker->marks = kissat_realloc (solver, checker->marks, size2, + new_size2 * sizeof (bool)); + checker->used = kissat_realloc (solver, checker->used, size2, + new_size2 * sizeof (bool)); + checker->large = kissat_realloc (solver, checker->large, size2, + new_size2 * sizeof (bool)); + checker->values = + kissat_realloc (solver, checker->values, size2, new_size2); + checker->watches = kissat_realloc ( + solver, checker->watches, size2 * sizeof *checker->watches, + new_size2 * sizeof *checker->watches); + checker->size = new_size; + } + const unsigned delta = new_vars - vars; + if (delta == 1) + LOG3 ("initializing one checker variable %u", vars); + else + LOG3 ("initializing %u checker variables from %u to %u", delta, vars, + new_vars - 1); + const unsigned vars2 = 2 * vars; + const unsigned new_vars2 = 2 * new_vars; + const unsigned delta2 = 2 * delta; + assert (delta2 == new_vars2 - vars2); + memset (checker->watches + vars2, 0, delta2 * sizeof *checker->watches); + memset (checker->marks + vars2, 0, delta2); + memset (checker->used + vars2, 0, delta2); + memset (checker->large + vars2, 0, delta2); + memset (checker->values + vars2, 0, delta2); + checker->vars = new_vars; +} + +static inline unsigned +import_external_checker (kissat *solver, checker *checker, int elit) { + assert (elit); + const unsigned var = ABS (elit) - 1; + if (var >= checker->vars) + resize_checker (solver, checker, var + 1); + assert (var < checker->vars); + return 2 * var + (elit < 0); +} + +static inline unsigned +import_internal_checker (kissat *solver, checker *checker, unsigned ilit) { + const int elit = kissat_export_literal (solver, ilit); + return import_external_checker (solver, checker, elit); +} + +static inline int export_checker (checker *checker, unsigned ilit) { + assert (ilit <= 2 * checker->vars); + return (1 + (ilit >> 1)) * ((ilit & 1) ? -1 : 1); +} + +static bucket *find_line (kissat *solver, checker *checker, size_t size, + bool remove) { + if (!checker->hashed) + return 0; + sort_line (solver, checker); + checker->searches++; + const unsigned hash = hash_line (checker); + const unsigned reduced = reduce_hash (hash, checker->hashed); + struct bucket **p, *bucket; + for (p = checker->table + reduced; + (bucket = *p) && !match_line (checker, size, hash, bucket); + p = &bucket->next) + checker->collisions++; + if (checker->marked) + unmark_line (checker); + if (bucket && remove) + *p = bucket->next; + return bucket; +} + +static void remove_line (kissat *solver, checker *checker, size_t size) { + bucket *bucket = find_line (solver, checker, size, true); + if (!bucket) { + kissat_fatal_message_start (); + fputs ("trying to remove non-existing clause:\n", stderr); + for (all_stack (unsigned, lit, checker->imported)) + fprintf (stderr, "%d ", export_checker (checker, lit)); + fputs ("0\n", stderr); + fflush (stderr); + kissat_abort (); + } + unwatch_line (solver, checker, bucket); + LOGLINE3 ("removed checker"); + kissat_free (solver, bucket, bytes_line (size)); + assert (checker->buckets > 0); + checker->buckets--; + checker->removed++; +} + +static void import_external_literals (kissat *solver, checker *checker, + size_t size, const int *elits) { + if (size > UINT_MAX) + kissat_fatal ("can not check handle original clause of size %zu", size); + CLEAR_STACK (checker->imported); + for (size_t i = 0; i < size; i++) { + const unsigned lit = + import_external_checker (solver, checker, elits[i]); + PUSH_STACK (checker->imported, lit); + } + LOGIMPORTED3 ("checker imported external"); +} + +static void import_internal_literals (kissat *solver, checker *checker, + size_t size, const unsigned *ilits) { + assert (size <= UINT_MAX); + CLEAR_STACK (checker->imported); + for (size_t i = 0; i < size; i++) { + const unsigned ilit = ilits[i]; + const unsigned lit = import_internal_checker (solver, checker, ilit); + PUSH_STACK (checker->imported, lit); + } + LOGIMPORTED3 ("checker imported internal"); +} + +static void import_clause (kissat *solver, checker *checker, clause *c) { + import_internal_literals (solver, checker, c->size, c->lits); + LOGIMPORTED3 ("checker imported clause"); +} + +static void import_binary (kissat *solver, checker *checker, unsigned a, + unsigned b) { + CLEAR_STACK (checker->imported); + const unsigned c = import_internal_checker (solver, checker, a); + const unsigned d = import_internal_checker (solver, checker, b); + PUSH_STACK (checker->imported, c); + PUSH_STACK (checker->imported, d); + LOGIMPORTED3 ("checker imported binary"); +} + +static void import_internal_unit (kissat *solver, checker *checker, + unsigned a) { + CLEAR_STACK (checker->imported); + const unsigned b = import_internal_checker (solver, checker, a); + PUSH_STACK (checker->imported, b); + LOGIMPORTED3 ("checker imported unit"); +} + +static bool checker_propagate (kissat *solver, checker *checker) { + unsigned propagated = checker->propagated; + signed char *values = checker->values; + bool res = true; + while (res && propagated < SIZE_STACK (checker->trail)) { + const unsigned lit = PEEK_STACK (checker->trail, propagated); + const unsigned not_lit = lit ^ 1; + LOG3 ("checker propagate %u", lit); + assert (values[lit] > 0); + assert (values[not_lit] < 0); + propagated++; + buckets *buckets = checker_watches (checker, not_lit); + bucket **begin_of_lines = BEGIN_STACK (*buckets), **q = begin_of_lines; + bucket *const *end_of_lines = END_STACK (*buckets), *const *p = q; + while (p != end_of_lines) { + bucket *bucket = *q++ = *p++; + if (!res) + continue; + unsigned *lits = bucket->lits; + const unsigned other = not_lit ^ lits[0] ^ lits[1]; + const signed char other_value = values[other]; + if (other_value > 0) + continue; + const unsigned *const end_of_lits = lits + bucket->size; + unsigned replacement; + signed char replacement_value = -1; + unsigned *r; + for (r = lits + 2; r != end_of_lits; r++) { + replacement = *r; + if (replacement == other) + continue; + if (replacement == not_lit) + continue; + replacement_value = values[replacement]; + if (replacement_value >= 0) + break; + } + if (replacement_value >= 0) { + lits[0] = other; + lits[1] = replacement; + *r = not_lit; + LOGLINE3 ("checker unwatching %u in", not_lit); + watch_checker_literal (solver, checker, bucket, replacement); + q--; + } else if (other_value < 0) { + LOGLINE3 ("checker conflict"); + res = false; + } else + checker_assign (solver, checker, other, bucket); + } + SET_END_OF_STACK (*buckets, q); + } + checker->propagations += propagated - checker->propagated; + checker->propagated = propagated; + return res; +} + +static bool bucket_redundant (kissat *solver, checker *checker, + size_t size) { + if (!checker_propagate (solver, checker)) { + LOG3 ("root level checker unit propagations leads to conflict"); + LOG2 ("checker becomes inconsistent"); + checker->inconsistent = true; + return true; + } + if (checker->inconsistent) { + LOG3 ("skipping removal since checker already inconsistent"); + return true; + } + if (!size) + kissat_fatal ("checker can not remove empty checker clause"); + if (size == 1) { + const unsigned unit = PEEK_STACK (checker->imported, 0); + const signed char value = checker->values[unit]; + if (value < 0 && !checker->inconsistent) + kissat_fatal ("consistent checker can not remove falsified unit %d", + export_checker (checker, unit)); + if (!value) + kissat_fatal ("checker can not remove unassigned unit %d", + export_checker (checker, unit)); + LOG3 ("checker skips removal of satisfied unit %u", unit); + return true; + } else if (satisfied_or_trivial_imported (solver, checker)) { + LOGIMPORTED3 ("satisfied imported checker"); + return true; + } else + return false; +} + +static void remove_line_if_not_redundant (kissat *solver, + checker *checker) { + size_t size = SIZE_STACK (checker->imported); + if (!bucket_redundant (solver, checker, size)) + remove_line (solver, checker, size); +} + +static void checker_backtrack (checker *checker, unsigned saved) { + unsigned *begin = BEGIN_STACK (checker->trail) + saved; + unsigned *p = END_STACK (checker->trail); + signed char *values = checker->values; + while (p != begin) { + const unsigned lit = *--p; + assert (VALID_CHECKER_LIT (lit)); + const unsigned not_lit = lit ^ 1; + assert (values[lit] > 0); + assert (values[not_lit] < 0); + values[lit] = values[not_lit] = 0; + } + checker->propagated = saved; + SET_END_OF_STACK (checker->trail, begin); +} + +static bool checker_blocked_literal (kissat *solver, checker *checker, + unsigned lit) { + signed char *values = checker->values; + assert (values[lit] < 0); + const unsigned not_lit = lit ^ 1; + if (checker->large[not_lit]) + return false; + buckets *buckets = checker_watches (checker, not_lit); + bucket *const *const begin_of_lines = BEGIN_STACK (*buckets); + bucket *const *const end_of_lines = END_STACK (*buckets); + bucket *const *p = begin_of_lines; + while (p != end_of_lines) { + bucket *bucket = *p++; + const unsigned *const lits = bucket->lits; + const unsigned *const end_of_lits = lits + bucket->size; + const unsigned *l = lits; + while (l != end_of_lits) { + const unsigned other = *l++; + if (other == not_lit) + continue; + if (values[other] > 0) + goto CONTINUE_WITH_NEXT_BUCKET; + } + return false; + CONTINUE_WITH_NEXT_BUCKET:; + } +#ifdef LOGGING + LOG3 ("blocked literal %u", lit); +#else + (void) solver; +#endif + return true; +} + +static bool checker_blocked_imported (kissat *solver, checker *checker) { + for (all_stack (unsigned, lit, checker->imported)) + if (checker_blocked_literal (solver, checker, lit)) + return true; + return false; +} + +static void check_line (kissat *solver, checker *checker) { + checker->checked++; + if (checker->inconsistent) + return; + if (!checker_propagate (solver, checker)) { + LOG3 ("root level checker unit propagations leads to conflict"); + LOG2 ("checker becomes inconsistent"); + checker->inconsistent = true; + return; + } + const unsigned saved = SIZE_STACK (checker->trail); + signed char *values = checker->values; + bool satisfied = false, pure = false; + unsigned decisions = 0, prev = INVALID_LIT; + for (all_stack (unsigned, lit, checker->imported)) { + assert (prev != lit); + prev = lit; + signed char lit_value = values[lit]; + if (lit_value < 0) + continue; + if (lit_value > 0) { + LOG3 ("found satisfied literal %u", lit); + checker->satisfied++; + satisfied = true; + break; + } + const unsigned not_lit = lit ^ 1; + bool used = checker->used[not_lit]; + if (!used) { + LOG3 ("found pure literal %u", lit); + checker->pure++; + pure = true; + break; + } + checker_assign (solver, checker, not_lit, &decision_line); + decisions++; + } + checker->decisions += decisions; + if (!satisfied && !pure) { + if (!checker_propagate (solver, checker)) + LOG3 ("checker imported clause unit implied"); + else if (checker_blocked_imported (solver, checker)) { + LOG3 ("checker imported clause binary blocked"); + checker->blocked++; + } else { + kissat_fatal_message_start (); + fputs ("failed to check clause:\n", stderr); + for (all_stack (unsigned, lit, checker->imported)) + fprintf (stderr, "%d ", export_checker (checker, lit)); + fputs ("0\n", stderr); + fflush (stderr); + kissat_abort (); + } + } + checker_backtrack (checker, saved); +} + +void kissat_add_unchecked_external (kissat *solver, size_t size, + const int *elits) { + LOGINTS3 (size, elits, "adding unchecked external checker"); + checker *checker = solver->checker; + checker->unchecked++; + import_external_literals (solver, checker, size, elits); + insert_imported_if_not_simplified (solver, checker); +} + +void kissat_add_unchecked_internal (kissat *solver, size_t size, + unsigned *lits) { + LOGUNSIGNEDS3 (size, lits, "adding unchecked internal checker"); + checker *checker = solver->checker; + checker->unchecked++; + assert (size <= UINT_MAX); + import_internal_literals (solver, checker, size, lits); + insert_imported_if_not_simplified (solver, checker); +} + +void kissat_check_and_add_binary (kissat *solver, unsigned a, unsigned b) { + LOGBINARY3 (a, b, "checking and adding internal checker"); + checker *checker = solver->checker; + assert (VALID_INTERNAL_LITERAL (a)); + assert (VALID_INTERNAL_LITERAL (b)); + import_binary (solver, checker, a, b); + check_line (solver, checker); + insert_imported_if_not_simplified (solver, checker); +} + +void kissat_check_and_add_clause (kissat *solver, clause *clause) { + LOGCLS3 (clause, "checking and adding internal checker"); + checker *checker = solver->checker; + import_clause (solver, checker, clause); + check_line (solver, checker); + insert_imported_if_not_simplified (solver, checker); +} + +void kissat_check_and_add_empty (kissat *solver) { + LOG3 ("checking and adding empty checker clause"); + checker *checker = solver->checker; + CLEAR_STACK (checker->imported); + check_line (solver, checker); + insert_imported_if_not_simplified (solver, checker); +} + +void kissat_check_and_add_internal (kissat *solver, size_t size, + const unsigned *lits) { + LOGUNSIGNEDS3 (size, lits, "checking and adding internal checker"); + checker *checker = solver->checker; + import_internal_literals (solver, checker, size, lits); + check_line (solver, checker); + insert_imported_if_not_simplified (solver, checker); +} + +void kissat_check_and_add_unit (kissat *solver, unsigned a) { + LOG3 ("checking and adding internal checker internal unit %u", a); + checker *checker = solver->checker; + assert (VALID_INTERNAL_LITERAL (a)); + import_internal_unit (solver, checker, a); + check_line (solver, checker); + insert_imported_if_not_simplified (solver, checker); +} + +void kissat_check_shrink_clause (kissat *solver, clause *c, unsigned remove, + unsigned keep) { + LOGCLS3 (c, "checking and shrinking by %u internal checker", remove); + checker *checker = solver->checker; + CLEAR_STACK (checker->imported); + const value *const values = solver->values; + for (all_literals_in_clause (ilit, c)) { + if (ilit == remove) + continue; + if (ilit != keep && values[ilit] < 0 && !LEVEL (ilit)) + continue; + const unsigned lit = import_internal_checker (solver, checker, ilit); + PUSH_STACK (checker->imported, lit); + } + LOGIMPORTED3 ("checker imported internal"); + check_line (solver, checker); + insert_imported_if_not_simplified (solver, checker); + import_clause (solver, checker, c); + remove_line_if_not_redundant (solver, checker); +} + +void kissat_remove_checker_binary (kissat *solver, unsigned a, unsigned b) { + LOGBINARY3 (a, b, "removing internal checker"); + checker *checker = solver->checker; + assert (VALID_INTERNAL_LITERAL (a)); + assert (VALID_INTERNAL_LITERAL (b)); + import_binary (solver, checker, a, b); + remove_line_if_not_redundant (solver, checker); +} + +void kissat_remove_checker_clause (kissat *solver, clause *clause) { + LOGCLS3 (clause, "removing internal checker"); + checker *checker = solver->checker; + import_clause (solver, checker, clause); + remove_line_if_not_redundant (solver, checker); +} + +bool kissat_checker_contains_clause (kissat *solver, clause *clause) { + checker *checker = solver->checker; + import_clause (solver, checker, clause); + size_t size = SIZE_STACK (checker->imported); + if (bucket_redundant (solver, checker, size)) + return true; + return find_line (solver, checker, size, false); +} + +void kissat_remove_checker_external (kissat *solver, size_t size, + const int *elits) { + LOGINTS3 (size, elits, "removing external checker"); + checker *checker = solver->checker; + import_external_literals (solver, checker, size, elits); + remove_line_if_not_redundant (solver, checker); +} + +void kissat_remove_checker_internal (kissat *solver, size_t size, + const unsigned *ilits) { + LOGUNSIGNEDS3 (size, ilits, "removing internal checker"); + checker *checker = solver->checker; + import_internal_literals (solver, checker, size, ilits); + remove_line_if_not_redundant (solver, checker); +} + +void dump_line (bucket *bucket) { + printf ("bucket[%p]", (void *) bucket); + for (unsigned i = 0; i < bucket->size; i++) + printf (" %u", bucket->lits[i]); + fputc ('\n', stdout); +} + +void dump_checker (kissat *solver) { + checker *checker = solver->checker; + printf ("%s\n", checker->inconsistent ? "inconsistent" : "consistent"); + printf ("vars %u\n", checker->vars); + printf ("size %u\n", checker->size); + printf ("buckets %u\n", checker->buckets); + printf ("hashed %u\n", checker->hashed); + for (unsigned i = 0; i < SIZE_STACK (checker->trail); i++) + printf ("trail[%u] %u\n", i, PEEK_STACK (checker->trail, i)); + for (unsigned h = 0; h < checker->hashed; h++) + for (bucket *bucket = checker->table[h]; bucket; bucket = bucket->next) + dump_line (bucket); +} + +#else +int kissat_check_dummy_to_avoid_warning; +#endif diff --git a/src/sat/kissat/check.h b/src/sat/kissat/check.h new file mode 100644 index 000000000..f7eaf27a1 --- /dev/null +++ b/src/sat/kissat/check.h @@ -0,0 +1,175 @@ +#ifndef _check_h_INCLUDED +#define _check_h_INCLUDED + +#ifndef NDEBUG + +#include +#include + +struct kissat; + +void kissat_check_satisfying_assignment (struct kissat *); + +typedef struct checker checker; + +struct clause; + +void kissat_init_checker (struct kissat *); +void kissat_release_checker (struct kissat *); + +#ifndef QUIET +void kissat_print_checker_statistics (struct kissat *, bool verbose); +#endif + +void kissat_add_unchecked_external (struct kissat *, size_t, const int *); + +void kissat_check_and_add_binary (struct kissat *, unsigned, unsigned); +void kissat_check_and_add_clause (struct kissat *, struct clause *c); +void kissat_check_and_add_empty (struct kissat *); +void kissat_check_and_add_internal (struct kissat *, size_t, + const unsigned *); +void kissat_check_and_add_unit (struct kissat *, unsigned); + +void kissat_check_shrink_clause (struct kissat *, struct clause *, + unsigned remove, unsigned keep); + +void kissat_remove_checker_binary (struct kissat *, unsigned, unsigned); +void kissat_remove_checker_clause (struct kissat *, struct clause *c); +void kissat_remove_checker_external (struct kissat *, size_t, const int *); + +void kissat_remove_checker_internal (struct kissat *, size_t, + const unsigned *); + +#define ADD_UNCHECKED_EXTERNAL(SIZE, LITS) \ + do { \ + if (GET_OPTION (check) > 1) \ + kissat_add_unchecked_external (solver, (SIZE), (LITS)); \ + } while (0) + +#define CHECK_AND_ADD_BINARY(A, B) \ + do { \ + if (GET_OPTION (check) > 1) \ + kissat_check_and_add_binary (solver, (A), (B)); \ + } while (0) + +#define CHECK_AND_ADD_TERNARY(A, B, C) \ + do { \ + if (GET_OPTION (check) > 1) { \ + unsigned CLAUSE[3] = {(A), (B), (C)}; \ + kissat_check_and_add_internal (solver, 3, CLAUSE); \ + } \ + } while (0) + +#define CHECK_AND_ADD_CLAUSE(CLAUSE) \ + do { \ + if (GET_OPTION (check) > 1) \ + kissat_check_and_add_clause (solver, (CLAUSE)); \ + } while (0) + +#define CHECK_AND_ADD_EMPTY() \ + do { \ + if (GET_OPTION (check) > 1) \ + kissat_check_and_add_empty (solver); \ + } while (0) + +#define CHECK_AND_ADD_LITS(SIZE, LITS) \ + do { \ + if (GET_OPTION (check) > 1) \ + kissat_check_and_add_internal (solver, (SIZE), (LITS)); \ + } while (0) + +#define CHECK_AND_ADD_STACK(S) \ + CHECK_AND_ADD_LITS (SIZE_STACK (S), BEGIN_STACK (S)) + +#define CHECK_AND_ADD_UNIT(A) \ + do { \ + if (GET_OPTION (check) > 1) \ + kissat_check_and_add_unit (solver, (A)); \ + } while (0) + +#define CHECK_SHRINK_CLAUSE(C, REMOVE, KEEP) \ + do { \ + if (GET_OPTION (check) > 1) \ + kissat_check_shrink_clause (solver, (C), (REMOVE), (KEEP)); \ + } while (0) + +#define REMOVE_CHECKER_BINARY(A, B) \ + do { \ + if (GET_OPTION (check) > 1) \ + kissat_remove_checker_binary (solver, (A), (B)); \ + } while (0) + +#define REMOVE_CHECKER_TERNARY(A, B, C) \ + do { \ + if (GET_OPTION (check) > 1) { \ + unsigned CLAUSE[3] = {(A), (B), (C)}; \ + kissat_remove_checker_internal (solver, 3, CLAUSE); \ + } \ + } while (0) + +#define REMOVE_CHECKER_CLAUSE(CLAUSE) \ + do { \ + if (GET_OPTION (check) > 1) \ + kissat_remove_checker_clause (solver, (CLAUSE)); \ + } while (0) + +#define REMOVE_CHECKER_LITS(SIZE, LITS) \ + do { \ + if (GET_OPTION (check) > 1) \ + kissat_remove_checker_internal (solver, (SIZE), (LITS)); \ + } while (0) + +#define REMOVE_CHECKER_STACK(S) \ + do { \ + if (GET_OPTION (check) > 1) \ + kissat_remove_checker_internal (solver, SIZE_STACK (S), \ + BEGIN_STACK (S)); \ + } while (0) + +#else + +#define ADD_UNCHECKED_EXTERNAL(...) \ + do { \ + } while (0) +#define CHECK_AND_ADD_BINARY(...) \ + do { \ + } while (0) +#define CHECK_AND_ADD_TERNARY(...) \ + do { \ + } while (0) +#define CHECK_AND_ADD_CLAUSE(...) \ + do { \ + } while (0) +#define CHECK_AND_ADD_EMPTY(...) \ + do { \ + } while (0) +#define CHECK_AND_ADD_LITS(...) \ + do { \ + } while (0) +#define CHECK_AND_ADD_STACK(...) \ + do { \ + } while (0) +#define CHECK_AND_ADD_UNIT(...) \ + do { \ + } while (0) +#define CHECK_SHRINK_CLAUSE(...) \ + do { \ + } while (0) +#define REMOVE_CHECKER_BINARY(...) \ + do { \ + } while (0) +#define REMOVE_CHECKER_TERNARY(...) \ + do { \ + } while (0) +#define REMOVE_CHECKER_CLAUSE(...) \ + do { \ + } while (0) +#define REMOVE_CHECKER_LITS(...) \ + do { \ + } while (0) +#define REMOVE_CHECKER_STACK(...) \ + do { \ + } while (0) + +#endif +#endif diff --git a/src/sat/kissat/classify.c b/src/sat/kissat/classify.c new file mode 100644 index 000000000..4514fb7bb --- /dev/null +++ b/src/sat/kissat/classify.c @@ -0,0 +1,28 @@ +#include "classify.h" +#include "internal.h" +#include "print.h" + +void kissat_classify (struct kissat *solver) { + statistics *s = &solver->statistics; + uint64_t clauses = s->clauses_binary + s->clauses_irredundant; + unsigned small_clauses_limit = GET_OPTION (smallclauses); + if (clauses <= small_clauses_limit) { + solver->classification.small = true; + solver->classification.bigbig = false; + } else { + solver->classification.small = false; + unsigned bigbigfraction = GET_OPTION (bigbigfraction); + double percent = bigbigfraction / 1000.0; + double actual = kissat_percent (s->clauses_binary, clauses); + if (actual >= percent) + solver->classification.bigbig = true; + else + solver->classification.bigbig = false; + } + kissat_very_verbose ( + solver, "formula classified as having a %s total number of clauses", + solver->classification.small ? "small" : "large"); + kissat_very_verbose ( + solver, "formula classified to have a %s binary clauses fraction", + solver->classification.bigbig ? "large" : "small"); +} diff --git a/src/sat/kissat/classify.h b/src/sat/kissat/classify.h new file mode 100644 index 000000000..f1f9b84d7 --- /dev/null +++ b/src/sat/kissat/classify.h @@ -0,0 +1,17 @@ +#ifndef _classify_h_INCLUDED +#define _classify_h_INCLUDED + +#include + +struct kissat; + +struct classification { + bool small; + bool bigbig; +}; + +typedef struct classification classification; + +void kissat_classify (struct kissat *); + +#endif diff --git a/src/sat/kissat/clause.c b/src/sat/kissat/clause.c new file mode 100644 index 000000000..8d4859193 --- /dev/null +++ b/src/sat/kissat/clause.c @@ -0,0 +1,187 @@ +#include "allocate.h" +#include "collect.h" +#include "inline.h" + +#include + +static void inc_clause (kissat *solver, bool original, bool redundant, + bool binary) { + if (binary) + INC (clauses_binary); + else if (redundant) + INC (clauses_redundant); + else + INC (clauses_irredundant); + INC (clauses_added); + if (original) + INC (clauses_original); +} + +static void dec_clause (kissat *solver, bool redundant, bool binary) { + if (binary) + DEC (clauses_binary); + else if (redundant) + DEC (clauses_redundant); + else + DEC (clauses_irredundant); +} + +static void init_clause (clause *res, bool redundant, unsigned glue, + unsigned size) { + assert (size <= UINT_MAX); + assert (redundant || !glue); + + glue = MIN (MAX_GLUE, glue); + + res->glue = glue; + res->garbage = false; + res->quotient = false; + res->reason = false; + res->redundant = redundant; + res->shrunken = false; + res->subsume = false; + res->swept = false; + res->vivify = false; + + res->used = 0; + + res->searched = 2; + res->size = size; +} + +void kissat_connect_referenced (kissat *solver, reference ref) { + watches *all_watches = solver->watches; + clause *c = kissat_dereference_clause (solver, ref); + kissat_inlined_connect_clause (solver, all_watches, c, ref); +} + +void kissat_connect_clause (kissat *solver, clause *c) { + watches *all_watches = solver->watches; + const reference ref = kissat_reference_clause (solver, c); + kissat_inlined_connect_clause (solver, all_watches, c, ref); +} + +static reference new_binary_clause (kissat *solver, bool original, + bool watch, unsigned first, + unsigned second) { + assert (first != second); + assert (first != NOT (second)); + if (watch) + kissat_watch_binary (solver, first, second); + kissat_mark_added_literal (solver, first); + kissat_mark_added_literal (solver, second); + inc_clause (solver, original, false, true); + if (!original) { + CHECK_AND_ADD_BINARY (first, second); + ADD_BINARY_TO_PROOF (first, second); + } + return INVALID_REF; +} + +static reference new_large_clause (kissat *solver, bool original, + bool redundant, unsigned glue, + unsigned size, unsigned *lits) { + assert (size > 2); + reference res = kissat_allocate_clause (solver, size); + clause *c = kissat_unchecked_dereference_clause (solver, res); + init_clause (c, redundant, glue, size); + memcpy (c->lits, lits, size * sizeof (unsigned)); + LOGREF (res, "new"); + if (solver->watching) + kissat_watch_reference (solver, lits[0], lits[1], res); + else + kissat_connect_clause (solver, c); + if (redundant) { + if (solver->first_reducible == INVALID_REF) + solver->first_reducible = res; + } else { + kissat_mark_added_literals (solver, size, lits); + solver->last_irredundant = res; + } + inc_clause (solver, original, redundant, false); + if (!original) { + CHECK_AND_ADD_CLAUSE (c); + ADD_CLAUSE_TO_PROOF (c); + } + return res; +} + +static reference new_clause (kissat *solver, bool original, bool redundant, + unsigned glue, unsigned size, unsigned *lits) { + reference res; + if (size == 2) + res = new_binary_clause (solver, original, true, lits[0], lits[1]); + else + res = new_large_clause (solver, original, redundant, glue, size, lits); + kissat_defrag_watches_if_needed (solver); + return res; +} + +void kissat_new_binary_clause (kissat *solver, unsigned first, + unsigned second) { + (void) new_binary_clause (solver, false, true, first, second); +} + +void kissat_new_unwatched_binary_clause (kissat *solver, unsigned first, + unsigned second) { + (void) new_binary_clause (solver, false, false, first, second); +} + +reference kissat_new_original_clause (kissat *solver) { + const unsigned size = SIZE_STACK (solver->clause); + unsigned *lits = BEGIN_STACK (solver->clause); + kissat_sort_literals (solver, size, lits); + reference res = new_clause (solver, true, false, 0, size, lits); + return res; +} + +reference kissat_new_irredundant_clause (kissat *solver) { + const unsigned size = SIZE_STACK (solver->clause); + unsigned *lits = BEGIN_STACK (solver->clause); + return new_clause (solver, false, false, 0, size, lits); +} + +reference kissat_new_redundant_clause (kissat *solver, unsigned glue) { + const unsigned size = SIZE_STACK (solver->clause); + unsigned *lits = BEGIN_STACK (solver->clause); + return new_clause (solver, false, true, glue, size, lits); +} + +static void mark_clause_as_garbage (kissat *solver, clause *c) { + assert (!c->garbage); + LOGCLS (c, "garbage"); + if (!c->redundant) + kissat_mark_removed_literals (solver, c->size, c->lits); + REMOVE_CHECKER_CLAUSE (c); + DELETE_CLAUSE_FROM_PROOF (c); + assert (c->size > 2); + dec_clause (solver, c->redundant, false); + c->garbage = true; +} + +void kissat_mark_clause_as_garbage (kissat *solver, clause *c) { + assert (!c->garbage); + mark_clause_as_garbage (solver, c); + size_t bytes = kissat_actual_bytes_of_clause (c); + ADD (arena_garbage, bytes); +} + +clause *kissat_delete_clause (kissat *solver, clause *c) { + LOGCLS (c, "delete"); + assert (c->size > 2); + assert (c->garbage); + size_t bytes = kissat_actual_bytes_of_clause (c); + SUB (arena_garbage, bytes); + INC (clauses_deleted); + return (clause *) ((char *) c + bytes); +} + +void kissat_delete_binary (kissat *solver, unsigned a, unsigned b) { + LOGBINARY (a, b, "delete"); + kissat_mark_removed_literal (solver, a); + kissat_mark_removed_literal (solver, b); + REMOVE_CHECKER_BINARY (a, b); + DELETE_BINARY_FROM_PROOF (a, b); + dec_clause (solver, false, true); + INC (clauses_deleted); +} diff --git a/src/sat/kissat/clause.h b/src/sat/kissat/clause.h new file mode 100644 index 000000000..d926a6cc2 --- /dev/null +++ b/src/sat/kissat/clause.h @@ -0,0 +1,90 @@ +#ifndef _clause_h_INCLUDED +#define _clause_h_INCLUDED + +#include "arena.h" +#include "literal.h" +#include "reference.h" +#include "utilities.h" + +#include + +typedef struct clause clause; + +#define LD_MAX_GLUE 19 +#define LD_MAX_USED 5 + +#define MAX_GLUE ((1u << LD_MAX_GLUE) - 1) +#define MAX_USED ((1u << LD_MAX_USED) - 1) + +struct clause { + unsigned glue : LD_MAX_GLUE; + + bool garbage : 1; + bool quotient : 1; + bool reason : 1; + bool redundant : 1; + bool shrunken : 1; + bool subsume : 1; + bool swept : 1; + bool vivify : 1; + + unsigned used : LD_MAX_USED; + + unsigned searched; + unsigned size; + + unsigned lits[3]; +}; + +#define SIZE_OF_CLAUSE_HEADER ((size_t) & ((clause *) 0)->searched) + +#define BEGIN_LITS(C) ((C)->lits) +#define END_LITS(C) (BEGIN_LITS (C) + (C)->size) + +#define all_literals_in_clause(LIT, C) \ + unsigned LIT, \ + *LIT##_PTR = BEGIN_LITS (C), *const LIT##_END = END_LITS (C); \ + LIT##_PTR != LIT##_END && ((LIT = *LIT##_PTR), true); \ + ++LIT##_PTR + +static inline size_t kissat_bytes_of_clause (unsigned size) { + const size_t res = sizeof (clause) + (size - 3) * sizeof (unsigned); + return kissat_align_ward (res); +} + +static inline size_t kissat_actual_bytes_of_clause (clause *c) { + unsigned const *p = END_LITS (c); + if (c->shrunken) + while (*p++ != INVALID_LIT) + ; + return kissat_align_ward ((char *) p - (char *) c); +} + +static inline clause *kissat_next_clause (clause *c) { + word bytes = kissat_actual_bytes_of_clause (c); + return (clause *) ((char *) c + bytes); +} + +struct kissat; + +void kissat_new_binary_clause (struct kissat *, unsigned, unsigned); +void kissat_new_unwatched_binary_clause (struct kissat *, unsigned, + unsigned); + +reference kissat_new_original_clause (struct kissat *); +reference kissat_new_irredundant_clause (struct kissat *); +reference kissat_new_redundant_clause (struct kissat *, unsigned glue); + +#ifndef INLINE_SORT +void kissat_sort_literals (struct kissat *, unsigned size, unsigned *lits); +#endif + +void kissat_connect_clause (struct kissat *, clause *); +void kissat_connect_referenced (struct kissat *solver, reference); + +clause *kissat_delete_clause (struct kissat *, clause *); +void kissat_delete_binary (struct kissat *, unsigned, unsigned); + +void kissat_mark_clause_as_garbage (struct kissat *, clause *); + +#endif diff --git a/src/sat/kissat/collect.c b/src/sat/kissat/collect.c new file mode 100644 index 000000000..77d45319e --- /dev/null +++ b/src/sat/kissat/collect.c @@ -0,0 +1,738 @@ +#define INLINE_SORT + +#include "collect.h" +#include "allocate.h" +#include "colors.h" +#include "compact.h" +#include "inline.h" +#include "print.h" +#include "report.h" +#include "sort.c" +#include "trail.h" + +#include +#include + +static void flush_watched_clauses_by_literal (kissat *solver, unsigned lit, + bool compact, + reference start) { + assert (start != INVALID_REF); + + const value *const values = solver->values; + const assigned *const all_assigned = solver->assigned; + + const value lit_value = values[lit]; + const assigned *const lit_assigned = all_assigned + IDX (lit); + const value lit_fixed = + (lit_value && !lit_assigned->level) ? lit_value : 0; + const unsigned mlit = kissat_map_literal (solver, lit, true); + + watches *lit_watches = &WATCHES (lit); + watch *begin = BEGIN_WATCHES (*lit_watches), *q = begin; + const watch *const end_of_watches = END_WATCHES (*lit_watches), *p = q; + + while (p != end_of_watches) { + watch head = *p++; + if (head.type.binary) { + const unsigned other = head.binary.lit; + const unsigned other_idx = IDX (other); + const value other_value = values[other]; + const value other_fixed = + (other_value && !all_assigned[other_idx].level) ? other_value : 0; + const unsigned mother = kissat_map_literal (solver, other, compact); + if (lit_fixed > 0 || other_fixed > 0 || mother == INVALID_LIT) { + if (lit < other) + kissat_delete_binary (solver, lit, other); + } else { + assert (!lit_fixed); + assert (!other_fixed); + + { + head.binary.lit = mother; + *q++ = head; +#ifdef LOGGING + if (lit < other) { + LOGBINARY (lit, other, "SRC"); + LOGBINARY (mlit, mother, "DST"); + } +#endif + } + } + } else { + assert (solver->watching); + const watch tail = *p++; + if (!lit_fixed) { + const reference ref = tail.large.ref; + if (ref < start) { + *q++ = head; + *q++ = tail; + } + } + } + } + + assert (!lit_fixed || q == begin); + SET_END_OF_WATCHES (*lit_watches, q); +#ifdef LOGGING + const size_t size_lit_watches = SIZE_WATCHES (*lit_watches); + LOG ("keeping %zu watches[%u]", size_lit_watches, lit); +#endif + if (!compact) + return; + + if (mlit == INVALID_LIT) + return; + + watches *mlit_watches = &WATCHES (mlit); +#if defined(LOGGING) || !defined(NDEBUG) + const size_t size_mlit_watches = SIZE_WATCHES (*mlit_watches); +#endif + if (lit_fixed) + assert (!size_mlit_watches); + else if (mlit < lit) { + assert (mlit != INVALID_LIT); + assert (mlit < lit); + *mlit_watches = *lit_watches; + LOG ("copied watches[%u] = watches[%u] (size %zu)", mlit, lit, + size_mlit_watches); + memset (lit_watches, 0, sizeof *lit_watches); + } else + assert (mlit == lit); +} + +static void flush_all_watched_clauses (kissat *solver, bool compact, + reference start) { + assert (solver->watching); + LOG ("starting to flush watches at clause[%" REFERENCE_FORMAT "]", start); + for (all_variables (idx)) { + const unsigned lit = LIT (idx); + flush_watched_clauses_by_literal (solver, lit, compact, start); + const unsigned not_lit = NOT (lit); + flush_watched_clauses_by_literal (solver, not_lit, compact, start); + } +} + +static void update_large_reason (kissat *solver, assigned *assigned, + unsigned forced, clause *dst) { + assert (dst->reason); + assert (forced != INVALID_LIT); + reference dst_ref = kissat_reference_clause (solver, dst); + const unsigned forced_idx = IDX (forced); + struct assigned *a = assigned + forced_idx; + assert (!a->binary); + if (a->reason != dst_ref) { + LOG ("reason reference %u of %s updated to %u", a->reason, + LOGLIT (forced), dst_ref); + a->reason = dst_ref; + } + dst->reason = false; +} + +static unsigned get_forced (const value *values, clause *dst) { + assert (dst->reason); + unsigned forced = INVALID_LIT; + for (all_literals_in_clause (lit, dst)) { + const value value = values[lit]; + if (value <= 0) + continue; + forced = lit; + break; + } + assert (forced != INVALID_LIT); + return forced; +} + +static void get_forced_and_update_large_reason (kissat *solver, + assigned *assigned, + const value *const values, + clause *dst) { + const unsigned forced = get_forced (values, dst); + update_large_reason (solver, assigned, forced, dst); +} + +static void update_first_reducible (kissat *solver, const clause *end, + clause *first_reducible) { + if (first_reducible >= end) { + LOG ("first reducible after end of arena"); + solver->first_reducible = INVALID_REF; + } else if (first_reducible) { + LOGCLS (first_reducible, "updating first reducible clause to"); + solver->first_reducible = + kissat_reference_clause (solver, first_reducible); + } else { + LOG ("first reducible clause becomes invalid"); + solver->first_reducible = INVALID_REF; + } +} + +static void update_last_irredundant (kissat *solver, const clause *end, + clause *last_irredundant) { + if (!last_irredundant) { + LOG ("no more large irredundant clauses left"); + solver->last_irredundant = INVALID_REF; + } else if (end <= last_irredundant) { + LOG ("last irredundant clause after end of arena"); + solver->last_irredundant = INVALID_REF; + } else { + LOGCLS (last_irredundant, "updating last irredundant clause to"); + reference ref = kissat_reference_clause (solver, last_irredundant); + solver->last_irredundant = ref; + } +} + +void kissat_update_first_reducible (kissat *solver, clause *reducible) { + assert (reducible); + assert (!reducible->garbage); + assert (reducible->redundant); + if (solver->first_reducible != INVALID_REF) { + reference ref = kissat_reference_clause (solver, reducible); + if (ref >= solver->first_reducible) { + LOG ("no need to update larger first reducible"); + return; + } + } + clause *end = (clause *) END_STACK (solver->arena); + update_first_reducible (solver, end, reducible); +} + +void kissat_update_last_irredundant (kissat *solver, clause *irredundant) { + assert (irredundant); + assert (!irredundant->garbage); + assert (!irredundant->redundant); + if (solver->last_irredundant != INVALID_REF) { + reference ref = kissat_reference_clause (solver, irredundant); + if (ref <= solver->last_irredundant) { + LOG ("no need to update smaller last irredundant"); + return; + } + } + clause *end = (clause *) END_STACK (solver->arena); + update_last_irredundant (solver, end, irredundant); +} + +static void move_redundant_clauses_to_the_end (kissat *solver, + reference ref) { + INC (moved); + assert (ref != INVALID_REF); +#ifndef NDEBUG + const size_t size = SIZE_STACK (solver->arena); + assert ((size_t) ref <= size); +#endif + clause *begin = (clause *) (BEGIN_STACK (solver->arena) + ref); + clause *end = (clause *) END_STACK (solver->arena); + size_t bytes_redundant = (char *) end - (char *) begin; + kissat_phase (solver, "move", GET (moved), + "moving redundant clauses of %s to the end", + FORMAT_BYTES (bytes_redundant)); + kissat_mark_reason_clauses (solver, ref); + clause *redundant = (clause *) kissat_malloc (solver, bytes_redundant); + clause *p = begin, *q = begin, *r = redundant; + + const value *const values = solver->values; + assigned *assigned = solver->assigned; + + clause *last_irredundant = kissat_last_irredundant_clause (solver); + + while (p != end) { + assert (!p->shrunken); + size_t bytes = kissat_bytes_of_clause (p->size); + if (p->redundant) { + memcpy (r, p, bytes); + r = (clause *) (bytes + (char *) r); + } else { + LOGCLS (p, "old DST"); + memmove (q, p, bytes); + LOGCLS (q, "new DST"); + last_irredundant = q; + if (q->reason) + get_forced_and_update_large_reason (solver, assigned, values, q); + q = (clause *) (bytes + (char *) q); + } + p = (clause *) (bytes + (char *) p); + } + r = redundant; + clause *first_reducible = 0; + while (q != end) { + size_t bytes = kissat_bytes_of_clause (r->size); + memcpy (q, r, bytes); + LOGCLS (q, "new DST"); + if (q->reason) + get_forced_and_update_large_reason (solver, assigned, values, q); + assert (q->redundant); + if (!first_reducible) + first_reducible = q; + r = (clause *) (bytes + (char *) r); + q = (clause *) (bytes + (char *) q); + } + assert ((char *) r <= (char *) redundant + bytes_redundant); + kissat_free (solver, redundant, bytes_redundant); + + assert (!first_reducible || first_reducible < q); + + update_first_reducible (solver, q, first_reducible); + update_last_irredundant (solver, q, last_irredundant); + kissat_reset_last_learned (solver); +} + +static reference sparse_sweep_garbage_clauses (kissat *solver, bool compact, + reference start) { + assert (solver->watching); + LOG ("sparse garbage collection starting at clause[%" REFERENCE_FORMAT + "]", + start); +#ifdef CHECKING_OR_PROVING + const bool checking_or_proving = kissat_checking_or_proving (solver); +#endif + assert (EMPTY_STACK (solver->added)); + assert (EMPTY_STACK (solver->removed)); + + const value *const values = solver->values; + assigned *assigned = solver->assigned; + +#ifndef QUIET + size_t flushed_garbage_clauses = 0; + size_t flushed_satisfied_clauses = 0; +#endif + size_t flushed = 0; + + clause *begin = (clause *) BEGIN_STACK (solver->arena); + const clause *const end = (clause *) END_STACK (solver->arena); + + clause *first, *src, *dst; + if (start) + first = kissat_dereference_clause (solver, start); + else + first = begin; + src = dst = first; + + clause *first_redundant = 0; + clause *first_reducible = 0; + clause *last_irredundant; + + if (start) + last_irredundant = kissat_last_irredundant_clause (solver); + else + last_irredundant = 0; +#ifdef LOGGING + size_t redundant_bytes = 0; +#endif + for (clause *next; src != end; src = next) { + if (src->garbage) { + next = kissat_delete_clause (solver, src); +#ifndef QUIET + flushed_garbage_clauses++; +#endif + if (last_irredundant == src) { + if (first == begin) + last_irredundant = 0; + else + last_irredundant = first; + } + continue; + } + + assert (src->size > 1); + LOGCLS (src, "SRC"); + next = kissat_next_clause (src); +#if !defined(NDEBUG) || defined(CHECKING_OR_PROVING) + const unsigned old_size = src->size; +#endif + assert (SIZE_OF_CLAUSE_HEADER == sizeof (unsigned)); + *(unsigned *) dst = *(unsigned *) src; + + unsigned *q = dst->lits; + + unsigned mfirst = INVALID_LIT; + unsigned msecond = INVALID_LIT; + unsigned forced = INVALID_LIT; + unsigned other = INVALID_LIT; + unsigned non_false = 0; + + bool satisfied = false; + + for (all_literals_in_clause (lit, src)) { +#ifdef CHECKING_OR_PROVING + if (checking_or_proving) + PUSH_STACK (solver->removed, lit); +#endif + if (satisfied) + continue; + + const value tmp = values[lit]; + const unsigned idx = IDX (lit); + const unsigned level = tmp ? assigned[idx].level : INVALID_LEVEL; + + if (tmp < 0 && !level) + flushed++; + else if (tmp > 0 && !level) { + assert (!satisfied); + assert (!dst->reason); + LOG ("SRC satisfied by %s", LOGLIT (lit)); + satisfied = true; + } else { + const unsigned mlit = kissat_map_literal (solver, lit, compact); + + if (tmp > 0) { + assert (level); + forced = non_false++ ? INVALID_LIT : lit; + } else if (tmp < 0) + other = lit; + + if (mfirst == INVALID_LIT) + mfirst = mlit; + else if (msecond == INVALID_LIT) + msecond = mlit; + + *q++ = mlit; + +#ifdef CHECKING_OR_PROVING + if (checking_or_proving) + PUSH_STACK (solver->added, lit); +#endif + } + } + + if (satisfied) { + if (dst->redundant) + DEC (clauses_redundant); + else + DEC (clauses_irredundant); +#ifndef QUIET + flushed_satisfied_clauses++; +#endif +#ifdef CHECKING_OR_PROVING + if (checking_or_proving) { + REMOVE_CHECKER_STACK (solver->removed); + DELETE_STACK_FROM_PROOF (solver->removed); + CLEAR_STACK (solver->added); + CLEAR_STACK (solver->removed); + } +#endif + if (last_irredundant == src) { + if (first == begin) + last_irredundant = 0; + else + last_irredundant = first; + } + continue; + } + + const unsigned new_size = q - dst->lits; + assert (new_size <= old_size); + assert (1 < new_size); + + if (new_size == 2) { + assert (mfirst != INVALID_LIT); + assert (msecond != INVALID_LIT); + + statistics *statistics = &solver->statistics; + assert (statistics->clauses_binary < UINT64_MAX); + statistics->clauses_binary++; + bool redundant = dst->redundant; + if (redundant) { + assert (statistics->clauses_redundant > 0); + statistics->clauses_redundant--; + redundant = false; + } else { + assert (statistics->clauses_irredundant > 0); + statistics->clauses_irredundant--; + } + LOGBINARY (mfirst, msecond, "DST"); + kissat_watch_binary (solver, mfirst, msecond); + + if (dst->reason) { + assert (non_false == 1); + assert (other != INVALID_LIT); + assert (forced != INVALID_LIT); + + const unsigned forced_idx = IDX (forced); + struct assigned *a = assigned + forced_idx; + assert (!a->binary); + + LOGBINARY (mfirst, msecond, + "reason clause[%u] of %s updated to binary reason", + a->reason, LOGLIT (forced)); + + a->binary = true; + a->reason = other; + } + + if (!redundant && last_irredundant == src) { + if (first == begin) + last_irredundant = 0; + else + last_irredundant = first; + } + } else { + assert (2 < new_size); + + dst->size = new_size; + dst->shrunken = false; + dst->searched = 2; + + LOGCLS (dst, "DST"); + if (dst->reason) + update_large_reason (solver, assigned, forced, dst); + + clause *next_dst = kissat_next_clause (dst); + + if (dst->redundant) { + if (!first_reducible) + first_reducible = dst; +#ifdef LOGGING + redundant_bytes += (char *) next_dst - (char *) dst; +#endif + if (!first_redundant) + first_redundant = dst; + } else + last_irredundant = dst; + + dst = next_dst; + } + +#ifdef CHECKING_OR_PROVING + if (!checking_or_proving) + continue; + + if (new_size != old_size) { + assert (1 < new_size); + assert (new_size < old_size); + + CHECK_AND_ADD_STACK (solver->added); + ADD_STACK_TO_PROOF (solver->added); + + REMOVE_CHECKER_STACK (solver->removed); + DELETE_STACK_FROM_PROOF (solver->removed); + } + CLEAR_STACK (solver->added); + CLEAR_STACK (solver->removed); +#endif + } + + update_first_reducible (solver, dst, first_reducible); + update_last_irredundant (solver, dst, last_irredundant); + kissat_reset_last_learned (solver); + + if (first_redundant) + LOGCLS (first_redundant, "determined first redundant clause as"); + +#if !defined(QUIET) || defined(METRICS) + size_t bytes = (char *) END_STACK (solver->arena) - (char *) dst; +#endif +#ifndef QUIET + if (flushed) + kissat_phase (solver, "collect", GET (garbage_collections), + "flushed %zu falsified literals in large clauses", + flushed); + size_t flushed_clauses = + flushed_satisfied_clauses + flushed_garbage_clauses; + if (flushed_satisfied_clauses) + kissat_phase ( + solver, "collect", GET (garbage_collections), + "flushed %zu satisfied large clauses %.0f%%", + flushed_satisfied_clauses, + kissat_percent (flushed_satisfied_clauses, flushed_clauses)); + if (flushed_garbage_clauses) + kissat_phase ( + solver, "collect", GET (garbage_collections), + "flushed %zu large garbage clauses %.0f%%", flushed_garbage_clauses, + kissat_percent (flushed_garbage_clauses, flushed_clauses)); + kissat_phase (solver, "collect", GET (garbage_collections), + "collected %s in total", FORMAT_BYTES (bytes)); +#endif + ADD (flushed, flushed); +#ifdef METRICS + ADD (allocated_collected, bytes); +#endif + + reference res = INVALID_REF; + + if (first_redundant && last_irredundant && + first_redundant < last_irredundant) { +#ifdef LOGGING + size_t move_bytes = (char *) dst - (char *) first_redundant; + LOG ("redundant bytes %s (%.0f%%) out of %s moving bytes", + FORMAT_BYTES (redundant_bytes), + kissat_percent (redundant_bytes, move_bytes), + FORMAT_BYTES (move_bytes)); +#endif + assert (first_redundant < dst); + res = kissat_reference_clause (solver, first_redundant); + assert (res != INVALID_REF); + } + + SET_END_OF_STACK (solver->arena, (ward *) dst); + kissat_shrink_arena (solver); + +#ifdef METRICS + if (solver->statistics.arena_garbage) + kissat_very_verbose (solver, "still %s garbage left in arena", + FORMAT_BYTES (solver->statistics.arena_garbage)); + else + kissat_very_verbose (solver, "all garbage clauses in arena collected"); +#endif + + return res; +} + +static void rewatch_clauses (kissat *solver, reference start) { + LOG ("rewatching clause[%" REFERENCE_FORMAT "] and following clauses", + start); + assert (solver->watching); + + const value *const values = solver->values; + const assigned *const assigned = solver->assigned; + watches *watches = solver->watches; + ward *const arena = BEGIN_STACK (solver->arena); + + clause *end = (clause *) END_STACK (solver->arena); + clause *c = (clause *) (BEGIN_STACK (solver->arena) + start); + assert (c <= end); + + for (clause *next; c != end; c = next) { + next = kissat_next_clause (c); + + unsigned *lits = c->lits; + kissat_sort_literals (solver, values, assigned, c->size, lits); + c->searched = 2; + + const reference ref = (ward *) c - arena; + const unsigned l0 = lits[0]; + const unsigned l1 = lits[1]; + + kissat_push_blocking_watch (solver, watches + l0, l1, ref); + kissat_push_blocking_watch (solver, watches + l1, l0, ref); + } +} + +void kissat_sparse_collect (kissat *solver, bool compact, reference start) { + assert (solver->watching); + START (collect); + INC (garbage_collections); + INC (sparse_gcs); + REPORT (1, 'G'); + unsigned vars, mfixed; + if (compact) + vars = kissat_compact_literals (solver, &mfixed); + else { + vars = solver->vars; + mfixed = INVALID_LIT; + } + flush_all_watched_clauses (solver, compact, start); + reference move = sparse_sweep_garbage_clauses (solver, compact, start); + if (compact) + kissat_finalize_compacting (solver, vars, mfixed); + if (move != INVALID_REF) + move_redundant_clauses_to_the_end (solver, move); + rewatch_clauses (solver, start); + REPORT (1, 'C'); + kissat_check_statistics (solver); + STOP (collect); +} + +bool kissat_compacting (kissat *solver) { + if (!GET_OPTION (compact)) + return false; + unsigned inactive = solver->vars - solver->active; + unsigned limit = GET_OPTION (compactlim) / 1e2 * solver->vars; + bool compact = (inactive > limit); + LOG ("%u inactive variables %.0f%% <= limit %u %.0f%%", inactive, + kissat_percent (inactive, solver->vars), limit, + kissat_percent (limit, solver->vars)); + return compact; +} + +void kissat_initial_sparse_collect (kissat *solver) { + assert (!solver->level); + assert (!solver->inconsistent); + assert (solver->watching); + assert (kissat_trail_flushed (solver)); + if (solver->statistics.units) { + bool compact = GET_OPTION (compact); + kissat_sparse_collect (solver, compact, 0); + } + REPORT (0, '.'); +} + +static void dense_sweep_garbage_clauses (kissat *solver) { + assert (!solver->level); + assert (!solver->watching); + + LOG ("dense garbage collection"); + +#ifndef QUIET + size_t flushed_garbage_clauses = 0; +#endif + clause *first_reducible = 0; + clause *last_irredundant = 0; + + clause *begin = (clause *) BEGIN_STACK (solver->arena); + const clause *const end = (clause *) END_STACK (solver->arena); + + clause *src = begin; + clause *dst = src; + + for (clause *next; src != end; src = next) { + if (src->garbage) { + next = kissat_delete_clause (solver, src); +#ifndef QUIET + flushed_garbage_clauses++; +#endif + continue; + } + assert (src->size > 1); + LOGCLS (src, "SRC"); + next = kissat_next_clause (src); + assert (SIZE_OF_CLAUSE_HEADER == sizeof (unsigned)); + *(unsigned *) dst = *(unsigned *) src; + dst->searched = src->searched; + dst->size = src->size; + dst->shrunken = false; + memmove (dst->lits, src->lits, src->size * sizeof (unsigned)); + LOGCLS (dst, "DST"); + if (!dst->redundant) + last_irredundant = dst; + else if (!first_reducible) + first_reducible = dst; + dst = kissat_next_clause (dst); + } + + update_first_reducible (solver, dst, first_reducible); + update_last_irredundant (solver, dst, last_irredundant); + kissat_reset_last_learned (solver); + +#if !defined(QUIET) || defined(METRICS) + size_t bytes = (char *) END_STACK (solver->arena) - (char *) dst; +#endif + kissat_phase (solver, "collect", GET (garbage_collections), + "flushed %zu large garbage clauses", + flushed_garbage_clauses); + kissat_phase (solver, "collect", GET (garbage_collections), + "collected %s in total", FORMAT_BYTES (bytes)); +#ifdef METRICS + ADD (allocated_collected, bytes); +#endif + + SET_END_OF_STACK (solver->arena, (ward *) dst); + kissat_shrink_arena (solver); + +#ifdef METRICS + if (solver->statistics.arena_garbage) + kissat_very_verbose (solver, "still %s garbage left in arena", + FORMAT_BYTES (solver->statistics.arena_garbage)); + else + kissat_very_verbose (solver, "all garbage clauses in arena collected"); +#endif +} + +void kissat_dense_collect (kissat *solver) { + assert (!solver->watching); + assert (!solver->level); + START (collect); + INC (garbage_collections); + INC (dense_garbage_collections); + REPORT (1, 'G'); + dense_sweep_garbage_clauses (solver); + REPORT (1, 'C'); + STOP (collect); +} diff --git a/src/sat/kissat/collect.h b/src/sat/kissat/collect.h new file mode 100644 index 000000000..6a9c8c4ef --- /dev/null +++ b/src/sat/kissat/collect.h @@ -0,0 +1,33 @@ +#ifndef _collect_h_INCLUDED +#define _collect_h_INCLUDED + +#include "internal.h" + +bool kissat_compacting (kissat *); +void kissat_dense_collect (kissat *); +void kissat_sparse_collect (kissat *, bool compact, reference start); +void kissat_initial_sparse_collect (kissat *); + +static inline void kissat_defrag_watches (kissat *solver) { + kissat_defrag_vectors (solver, LITS, solver->watches); +} + +static inline void kissat_defrag_watches_if_needed (kissat *solver) { + const size_t size = SIZE_STACK (solver->vectors.stack); + const size_t size_limit = GET_OPTION (defragsize); + if (size <= size_limit) + return; + + const size_t usable = solver->vectors.usable; + const size_t usable_limit = (size * GET_OPTION (defraglim)) / 100; + if (usable <= usable_limit) + return; + + INC (vectors_defrags_needed); + kissat_defrag_watches (solver); +} + +void kissat_update_last_irredundant (kissat *, clause *last_irredundant); +void kissat_update_first_reducible (kissat *, clause *first_reducible); + +#endif diff --git a/src/sat/kissat/colors.c b/src/sat/kissat/colors.c new file mode 100644 index 000000000..a3f2e6db9 --- /dev/null +++ b/src/sat/kissat/colors.c @@ -0,0 +1,19 @@ +#include "colors.h" + +#include + +int kissat_is_terminal[3] = {0, -1, -1}; + +int kissat_initialize_terminal (int fd) { + assert (fd == 1 || fd == 2); + assert (kissat_is_terminal[fd] < 0); + return kissat_is_terminal[fd] = isatty (fd); +} + +void kissat_force_colors (void) { + kissat_is_terminal[1] = kissat_is_terminal[2] = 1; +} + +void kissat_force_no_colors (void) { + kissat_is_terminal[1] = kissat_is_terminal[2] = 0; +} diff --git a/src/sat/kissat/colors.h b/src/sat/kissat/colors.h new file mode 100644 index 000000000..fe981e505 --- /dev/null +++ b/src/sat/kissat/colors.h @@ -0,0 +1,68 @@ +#ifndef _colors_h_INCLUDED +#define _colors_h_INCLUDED + +#include +#include +#include + +#include "keatures.h" + +#define BLUE "\033[34m" +#define BOLD "\033[1m" +#define CYAN "\033[36m" +#define GREEN "\033[32m" +#define MAGENTA "\033[35m" +#define NORMAL "\033[0m" +#define RED "\033[31m" +#define WHITE "\037[34m" +#define YELLOW "\033[33m" + +#define LIGHT_GRAY "\033[1;37m" +#define DARK_GRAY "\033[0;37m" + +#ifdef KISSAT_HAS_FILENO +#define assert_if_has_fileno assert +#else +#define assert_if_has_fileno(...) \ + do { \ + } while (0) +#endif + +#define TERMINAL(F, I) \ + assert_if_has_fileno (fileno (F) == \ + I); /* 'fileno' only in POSIX not C99 */ \ + assert ((I == 1 && F == stdout) || (I == 2 && F == stderr)); \ + bool connected_to_terminal = kissat_connected_to_terminal (I); \ + FILE *terminal_file = F + +#define COLOR(CODE) \ + do { \ + if (!connected_to_terminal) \ + break; \ + fputs (CODE, terminal_file); \ + } while (0) + +extern int kissat_is_terminal[3]; + +int kissat_initialize_terminal (int fd); +void kissat_force_colors (void); +void kissat_force_no_colors (void); + +static inline bool kissat_connected_to_terminal (int fd) { + assert (fd == 1 || fd == 2); + int res = kissat_is_terminal[fd]; + if (res < 0) + res = kissat_initialize_terminal (fd); + assert (res == 0 || res == 1); + return res; +} + +static inline const char *kissat_bold_green_color_code (int fd) { + return kissat_connected_to_terminal (fd) ? BOLD GREEN : ""; +} + +static inline const char *kissat_normal_color_code (int fd) { + return kissat_connected_to_terminal (fd) ? NORMAL : ""; +} + +#endif diff --git a/src/sat/kissat/compact.c b/src/sat/kissat/compact.c new file mode 100644 index 000000000..2d27fa9ca --- /dev/null +++ b/src/sat/kissat/compact.c @@ -0,0 +1,376 @@ +#include "compact.h" +#include "inline.h" +#include "inlineheap.h" +#include "print.h" +#include "resize.h" + +#include + +static void reimport_literal (kissat *solver, unsigned eidx, + unsigned mlit) { + import *import = &PEEK_STACK (solver->import, eidx); + assert (import->imported); + assert (!import->eliminated); + LOG ("reimporting external variable %u as internal literal %u (was %u)", + eidx, mlit, import->lit); + import->lit = mlit; +} + +unsigned kissat_compact_literals (kissat *solver, unsigned *mfixed_ptr) { + INC (compacted); +#if !defined(QUIET) || !defined(NDEBUG) + const unsigned active = solver->active; +#ifndef QUIET + const unsigned inactive = solver->vars - active; + kissat_phase (solver, "compact", GET (compacted), + "compacting garbage collection " + "(%u inactive variables %.2f%%)", + inactive, kissat_percent (inactive, solver->vars)); +#endif +#endif +#ifdef LOGGING + assert (!solver->compacting); + solver->compacting = true; +#endif + unsigned mfixed = INVALID_LIT; + unsigned vars = 0; + for (all_variables (iidx)) { + const flags *const flags = FLAGS (iidx); + if (flags->eliminated) + continue; + const unsigned ilit = LIT (iidx); + unsigned mlit; + if (flags->fixed) { + const value value = kissat_fixed (solver, ilit); + assert (value); + if (mfixed == INVALID_LIT) { + mlit = mfixed = LIT (vars); + LOG2 ("first fixed %u mapped to %u assigned to %d", ilit, mfixed, + value); + if (value < 0) + mfixed = NOT (mfixed); + LOG2 ("all other fixed mapped to %u", mfixed); + vars++; + } else if (value < 0) { + mlit = NOT (mfixed); + LOG2 ("negatively fixed %u mapped to %u", ilit, mlit); + } else { + mlit = mfixed; + LOG2 ("positively fixed %u mapped to %u", ilit, mlit); + } + } else if (flags->active) { + assert (flags->active); + mlit = LIT (vars); + LOG2 ("remapping %u to %u", ilit, mlit); + vars++; + } else { + const int elit = PEEK_STACK (solver->export, iidx); + if (elit) { + const unsigned eidx = ABS (elit); + import *import = &PEEK_STACK (solver->import, eidx); + assert (import->imported); + assert (!import->eliminated); + import->imported = false; + LOG2 ("external variable %d not imported anymore", eidx); + POKE_STACK (solver->export, iidx, 0); + } else + LOG2 ("skipping inactive %u", ilit); + continue; + } + assert (mlit <= ilit); + assert (mlit != NOT (ilit)); + if (mlit == ilit) + continue; + const int elit = PEEK_STACK (solver->export, iidx); + const unsigned eidx = ABS (elit); + if (elit < 0) + mlit = NOT (mlit); + reimport_literal (solver, eidx, mlit); + } + *mfixed_ptr = mfixed; + LOG ("compacting to %u variables %.2f%% from %u", vars, + kissat_percent (vars, solver->vars), solver->vars); + assert (vars == active || vars == active + 1); + return vars; +} + +static void compact_literal (kissat *solver, unsigned dst_lit, + unsigned src_lit) { + assert (dst_lit < src_lit); + assert (dst_lit != NOT (src_lit)); + const unsigned dst_idx = IDX (dst_lit); + const unsigned src_idx = IDX (src_lit); + assert (dst_idx != src_idx); + LOG ("mapping old internal literal %u to %u", src_lit, dst_lit); + solver->assigned[dst_idx] = solver->assigned[src_idx]; + solver->flags[dst_idx] = solver->flags[src_idx]; + + solver->phases.best[dst_idx] = solver->phases.best[src_idx]; + solver->phases.saved[dst_idx] = solver->phases.saved[src_idx]; + solver->phases.target[dst_idx] = solver->phases.target[src_idx]; + + const unsigned not_src_lit = NOT (src_lit); + const unsigned not_dst_lit = NOT (dst_lit); + solver->values[dst_lit] = solver->values[src_lit]; + solver->values[not_dst_lit] = solver->values[not_src_lit]; +} + +static unsigned map_idx (kissat *solver, unsigned iidx) { + int elit = PEEK_STACK (solver->export, iidx); + if (!elit) + return INVALID_IDX; + assert (elit); + const unsigned eidx = ABS (elit); + assert (eidx); + import *import = &PEEK_STACK (solver->import, eidx); + assert (import->imported); + if (import->eliminated) + return INVALID_IDX; + const unsigned mlit = import->lit; + const unsigned midx = IDX (mlit); + assert (midx <= iidx); + return midx; +} + +static void compact_queue (kissat *solver) { + LOG ("compacting queue"); + links *links = solver->links, *l; + unsigned *p = &solver->queue.first, prev = DISCONNECT; + solver->queue.stamp = 0; + for (unsigned idx; !DISCONNECTED (idx = *p); p = &l->next) { + const unsigned midx = map_idx (solver, idx); + assert (midx != INVALID_IDX); + l = links + idx; + l->prev = prev; + l->stamp = ++solver->queue.stamp; + if (idx == solver->queue.search.idx) { + solver->queue.search.idx = midx; + solver->queue.search.stamp = l->stamp; + } + *p = prev = midx; + } + solver->queue.last = prev; + *p = DISCONNECT; + for (all_variables (idx)) { + const unsigned midx = map_idx (solver, idx); + if (midx == INVALID_IDX) + continue; + links[midx] = links[idx]; + } +} + +static void compact_stack (kissat *solver, unsigneds *stack) { + unsigned *q = BEGIN_STACK (*stack); + const unsigned *const end = END_STACK (*stack); + for (const unsigned *p = q; p != end; p++) { + const unsigned idx = *p; + const unsigned midx = map_idx (solver, idx); + if (midx == INVALID_IDX) + continue; + *q++ = midx; + } + SET_END_OF_STACK (*stack, q); + SHRINK_STACK (*stack); +} + +static void compact_scores (kissat *solver, heap *old_scores, + unsigned vars) { + LOG ("compacting scores"); + + heap new_scores; + memset (&new_scores, 0, sizeof new_scores); + kissat_resize_heap (solver, &new_scores, vars); + + if (old_scores->tainted) { + LOG ("copying scores of tainted old scores heap"); + for (all_variables (idx)) { + const unsigned midx = map_idx (solver, idx); + if (midx == INVALID_IDX) + continue; + const double score = kissat_get_heap_score (old_scores, idx); + kissat_update_heap (solver, &new_scores, midx, score); + } + } else + LOG ("no need to copy scores of old untainted scores heap"); + + LOG ("now pushing mapped literals onto new heap"); + for (all_stack (unsigned, idx, old_scores->stack)) { + const unsigned midx = map_idx (solver, idx); + if (midx == INVALID_IDX) + continue; + kissat_push_heap (solver, &new_scores, midx); + } + + kissat_release_heap (solver, old_scores); + *old_scores = new_scores; +} + +static void compact_trail (kissat *solver) { + LOG ("compacting trail"); + const size_t size = SIZE_ARRAY (solver->trail); + for (size_t i = 0; i < size; i++) { + const unsigned ilit = PEEK_ARRAY (solver->trail, i); + const unsigned mlit = kissat_map_literal (solver, ilit, true); + assert (mlit != INVALID_LIT); + POKE_ARRAY (solver->trail, i, mlit); + const unsigned idx = IDX (ilit); + assigned *a = solver->assigned + idx; + if (!a->binary) + continue; + const unsigned other = a->reason; + assert (VALID_INTERNAL_LITERAL (other)); + const unsigned mother = kissat_map_literal (solver, other, true); + assert (mother != INVALID_LIT); + a->reason = mother; + } +} + +static void compact_frames (kissat *solver) { + LOG ("compacting frames"); + const size_t size = SIZE_STACK (solver->frames); + for (size_t level = 1; level < size; level++) { + frame *frame = &FRAME (level); + const unsigned ilit = frame->decision; + const unsigned mlit = kissat_map_literal (solver, ilit, true); + assert (mlit != INVALID_LIT); + frame->decision = mlit; + } +} + +static void compact_export (kissat *solver, unsigned vars) { + LOG ("compacting export"); + const size_t size = SIZE_STACK (solver->export); + assert (size <= UINT_MAX); + assert (size == solver->vars); + for (unsigned iidx = 0; iidx < size; iidx++) { + const unsigned elit = PEEK_STACK (solver->export, iidx); + if (!elit) + continue; + const unsigned midx = map_idx (solver, iidx); + if (midx == INVALID_IDX) + continue; + POKE_STACK (solver->export, midx, elit); + } + RESIZE_STACK (solver->export, vars); + SHRINK_STACK (solver->export); +#ifndef NDEBUG + assert (SIZE_STACK (solver->export) == vars); + for (unsigned iidx = 0; iidx < vars; iidx++) { + const int elit = PEEK_STACK (solver->export, iidx); + assert (VALID_EXTERNAL_LITERAL (elit)); + const unsigned eidx = ABS (elit); + const import *const import = &PEEK_STACK (solver->import, eidx); + assert (import->imported); + if (import->eliminated) + continue; + unsigned mlit = import->lit; + if (elit < 0) + mlit = NOT (mlit); + const unsigned ilit = LIT (iidx); + assert (mlit == ilit); + } +#endif +} + +static void compact_units (kissat *solver, unsigned mfixed) { + LOG ("compacting units (first fixed %u)", mfixed); + assert (kissat_fixed (solver, mfixed) > 0); + for (all_stack (int, elit, solver->units)) { + const unsigned eidx = ABS (elit); + const unsigned mlit = elit < 0 ? NOT (mfixed) : mfixed; + const import *const import = &PEEK_STACK (solver->import, eidx); + assert (import->imported); + assert (!import->eliminated); + const unsigned ilit = import->lit; + if (mlit != ilit) + reimport_literal (solver, eidx, mlit); + } +} + +static void compact_best_and_target_values (kissat *solver, unsigned vars) { + const value *const best = solver->phases.best; + const value *const target = solver->phases.target; + const flags *const flags = solver->flags; + + unsigned best_assigned = 0; + unsigned target_assigned = 0; + + for (unsigned idx = 0; idx < vars; idx++) { + if (!flags[idx].active) + continue; + if (target[idx]) + target_assigned++; + if (best[idx]) + best_assigned++; + } + + if (solver->target_assigned != target_assigned) { + LOG ("compacting target assigned from %u to %u", + solver->target_assigned, target_assigned); + solver->target_assigned = target_assigned; + } + + if (solver->best_assigned != best_assigned) { + LOG ("compacting best assigned from %u to %u", solver->best_assigned, + best_assigned); + solver->best_assigned = best_assigned; + } +} + +void kissat_finalize_compacting (kissat *solver, unsigned vars, + unsigned mfixed) { + LOG ("finalizing compacting"); + assert (vars <= solver->vars); +#ifdef LOGGING + assert (solver->compacting); +#endif + if (vars == solver->vars) { +#ifdef LOGGING + solver->compacting = false; + LOG ("number of variables does not change"); +#endif + return; + } + + unsigned reduced = solver->vars - vars; + LOG ("compacted number of variables from %u to %u", solver->vars, vars); + + bool first = true; + for (all_variables (iidx)) { + flags *flags = FLAGS (iidx); + if (flags->fixed && first) + first = false; + else if (!flags->active) + POKE_STACK (solver->export, iidx, 0); + } + + compact_trail (solver); + + for (all_variables (iidx)) { + const unsigned ilit = LIT (iidx); + const unsigned mlit = kissat_map_literal (solver, ilit, true); + if (mlit != INVALID_LIT && ilit != mlit) + compact_literal (solver, mlit, ilit); + } + + if (mfixed != INVALID_LIT) + compact_units (solver, mfixed); + + memset (solver->assigned + vars, 0, reduced * sizeof (assigned)); + memset (solver->flags + vars, 0, reduced * sizeof (flags)); + memset (solver->values + 2 * vars, 0, 2 * reduced * sizeof (value)); + memset (solver->watches + 2 * vars, 0, 2 * reduced * sizeof (watches)); + + compact_queue (solver); + compact_stack (solver, &solver->sweep_schedule); + compact_scores (solver, SCORES, vars); + compact_frames (solver); + compact_export (solver, vars); + compact_best_and_target_values (solver, vars); + + solver->vars = vars; +#ifdef LOGGING + solver->compacting = false; +#endif + kissat_decrease_size (solver); +} diff --git a/src/sat/kissat/compact.h b/src/sat/kissat/compact.h new file mode 100644 index 000000000..89d5ecd31 --- /dev/null +++ b/src/sat/kissat/compact.h @@ -0,0 +1,9 @@ +#ifndef _compact_h_INCLUDED +#define _compact_h_INCLUDED + +struct kissat; + +unsigned kissat_compact_literals (struct kissat *, unsigned *mfixed_ptr); +void kissat_finalize_compacting (struct kissat *, unsigned vars, + unsigned mfixed); +#endif diff --git a/src/sat/kissat/config.c b/src/sat/kissat/config.c new file mode 100644 index 000000000..3c79f7a1e --- /dev/null +++ b/src/sat/kissat/config.c @@ -0,0 +1,83 @@ +#ifndef NOPTIONS + +#include "config.h" +#include "kissat.h" +#include "options.h" + +#include +#include + +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 diff --git a/src/sat/kissat/config.h b/src/sat/kissat/config.h new file mode 100644 index 000000000..16eac8c05 --- /dev/null +++ b/src/sat/kissat/config.h @@ -0,0 +1,8 @@ +#ifndef NOPTIONS +#ifndef _config_h_INCLUDED +#define _config_h_INCLUDED + +void kissat_configuration_usage (void); + +#endif +#endif diff --git a/src/sat/kissat/congruence.c b/src/sat/kissat/congruence.c new file mode 100644 index 000000000..01b7dde00 --- /dev/null +++ b/src/sat/kissat/congruence.c @@ -0,0 +1,4635 @@ +#include "congruence.h" +#include "dense.h" +#include "fifo.h" +#include "inline.h" +#include "inlinevector.h" +#include "internal.h" +#include "logging.h" +#include "print.h" +#include "proprobe.h" +#include "rank.h" +#include "reference.h" +#include "report.h" +#include "sort.h" +#include "terminate.h" +#include "trail.h" +#include "utilities.h" + +#include +#include +#include + +// #define INDEX_LARGE_CLAUSES +// #define INDEX_BINARY_CLAUSES +#define MERGE_CONDITIONAL_EQUIVALENCES + +#define AND_GATE 0 +#define XOR_GATE 1 +#define ITE_GATE 2 + +#define LD_MAX_ARITY 26 +#define MAX_ARITY ((1 << LD_MAX_ARITY) - 1) + +struct gate { +#if defined(LOGGING) || !defined(NDEBUG) + size_t id; +#endif + unsigned lhs; + unsigned hash; + unsigned tag : 2; + bool garbage : 1; + bool indexed : 1; + bool marked : 1; + bool shrunken : 1; + unsigned arity : LD_MAX_ARITY; + unsigned rhs[]; +}; + +typedef struct gate gate; +typedef STACK (gate *) gates; + +struct gate_hash_table { + gate **table; + size_t size; + size_t entries; +}; + +typedef struct gate_hash_table gate_hash_table; + +#define REMOVED ((gate *) (~(uintptr_t) 0)) + +#define BEGIN_RHS(G) ((G)->rhs) +#define END_RHS(G) (BEGIN_RHS (G) + (G)->arity) + +#define all_rhs_literals_in_gate(LIT, G) \ + unsigned LIT, \ + *LIT##_PTR = BEGIN_RHS (G), *const LIT##_END = END_RHS (G); \ + LIT##_PTR != LIT##_END && ((LIT = *LIT##_PTR), true); \ + ++LIT##_PTR + +#ifdef INDEX_BINARY_CLAUSES + +struct binary_clause { + unsigned lits[2]; +}; + +typedef struct binary_clause binary_clause; + +struct binary_hash_table { + binary_clause *table; + size_t size, size2, count; +}; + +typedef struct binary_hash_table binary_hash_table; + +#endif + +struct hash_ref { + unsigned hash; + reference ref; +}; + +#ifdef INDEX_LARGE_CLAUSES + +typedef struct hash_ref hash_ref; + +struct large_clause_hash_table { + hash_ref *table; + size_t size, size2, count; +}; + +typedef struct large_clause_hash_table large_clause_hash_table; + +#endif + +#define SIZE_NONCES 16 + +struct closure { + kissat *solver; + bool *scheduled; + gates *occurrences; + gates garbage; + unsigneds lits; + unsigneds rhs; + unsigneds unsimplified; + litpairs binaries; + unsigned_fifo schedule; + unsigned *repr; + gate_hash_table hash; + uint64_t nonces[SIZE_NONCES]; + unsigned *units; + unsigned *equivalences; + unsigned *negbincount; + unsigned *largecount; + litpairs condbin[2]; + litpairs condeq[2]; +#ifdef INDEX_BINARY_CLAUSES + binary_hash_table bintab; +#endif +#ifdef INDEX_LARGE_CLAUSES + large_clause_hash_table clauses; +#endif +#ifdef CHECKING_OR_PROVING + unsigneds chain; +#endif +#if defined(LOGGING) || !defined(NDEBUG) + size_t gates_added; +#endif +#ifndef NDEBUG + unsigneds implied; +#endif +}; + +typedef struct closure closure; + +static void init_closure (kissat *solver, closure *closure) { + closure->solver = solver; + CALLOC (closure->scheduled, VARS); + CALLOC (closure->occurrences, LITS); + INIT_STACK (closure->garbage); + INIT_STACK (closure->lits); + INIT_STACK (closure->rhs); + INIT_STACK (closure->unsimplified); + INIT_STACK (closure->binaries); + INIT_FIFO (closure->schedule); + + NALLOC (closure->repr, LITS); + for (all_literals (lit)) + closure->repr[lit] = lit; + + closure->hash.table = 0; + closure->hash.size = closure->hash.entries = 0; + + generator random = solver->random; + for (size_t i = 0; i != SIZE_NONCES; i++) + closure->nonces[i] = 1 | kissat_next_random64 (&random); + +#ifdef CHECKING_OR_PROVING + INIT_STACK (closure->chain); +#endif +#if defined(LOGGING) || !defined(NDEBUG) + closure->gates_added = 0; +#endif +#ifndef NDEBUG + INIT_STACK (closure->implied); +#endif +} + +static size_t bytes_gate (size_t arity) { + return sizeof (gate) + arity * sizeof (unsigned); +} + +static unsigned actual_gate_arity (gate *g) { + unsigned res = g->arity; + if (!g->shrunken) + return res; + while (g->rhs[res++] != INVALID_LIT) + ; + return res; +} + +#define CLOGANDGATE(G, ...) \ + do { \ + assert ((G)->tag == AND_GATE); \ + LOGANDGATE ((G)->id, closure->repr, (G)->lhs, (G)->arity, (G)->rhs, \ + __VA_ARGS__); \ + } while (0) + +#define CLOGXORGATE(G, ...) \ + do { \ + assert ((G)->tag == XOR_GATE); \ + LOGXORGATE ((G)->id, closure->repr, (G)->lhs, (G)->arity, (G)->rhs, \ + __VA_ARGS__); \ + } while (0) + +#define CLOGITEGATE(G, ...) \ + do { \ + assert ((G)->tag == ITE_GATE); \ + LOGITEGATE ((G)->id, closure->repr, (G)->lhs, (G)->rhs[0], \ + (G)->rhs[1], (G)->rhs[2], __VA_ARGS__); \ + } while (0) + +#define CLOGREPR(L) LOGREPR ((L), closure->repr) + +#define LOGATE(G, ...) \ + do { \ + if ((G)->tag == AND_GATE) \ + CLOGANDGATE (G, __VA_ARGS__); \ + else if ((G)->tag == XOR_GATE) \ + CLOGXORGATE (G, __VA_ARGS__); \ + else { \ + assert ((G)->tag == ITE_GATE); \ + CLOGITEGATE (G, __VA_ARGS__); \ + } \ + } while (0) + +static void delete_gate (closure *closure, gate *g) { + kissat *const solver = closure->solver; + LOGATE (g, "delete"); + unsigned actual_arity = actual_gate_arity (g); + size_t actual_bytes = bytes_gate (actual_arity); + kissat_free (solver, g, actual_bytes); +} + +void reset_gate_hash_table (closure *closure) { + kissat *const solver = closure->solver; + gate **table = closure->hash.table; + for (size_t pos = 0; pos != closure->hash.size; pos++) { + gate *g = table[pos]; + if (g && g != REMOVED && !g->garbage) + delete_gate (closure, g); + } + DEALLOC (table, closure->hash.size); +} + +static void reset_closure (closure *closure) { + kissat *const solver = closure->solver; + + gates *occurrences = closure->occurrences; + for (all_literals (lit)) + RELEASE_STACK (occurrences[lit]); + DEALLOC (occurrences, LITS); + + reset_gate_hash_table (closure); + for (all_pointers (gate, g, closure->garbage)) + delete_gate (closure, g); + + RELEASE_STACK (closure->garbage); + RELEASE_STACK (closure->binaries); + DEALLOC (closure->scheduled, VARS); + RELEASE_STACK (closure->lits); + RELEASE_STACK (closure->rhs); + RELEASE_STACK (closure->unsimplified); + RELEASE_FIFO (closure->schedule); +#ifdef CHECKING_OR_PROVING + RELEASE_STACK (closure->chain); +#endif +#ifndef NDEBUG + RELEASE_STACK (closure->implied); +#endif + + if (!solver->inconsistent && solver->unflushed) + kissat_flush_trail (solver); +} + +static unsigned reset_repr (closure *closure) { + kissat *const solver = closure->solver; + unsigned res = 0, *repr = closure->repr; + for (all_variables (idx)) { + unsigned lit = LIT (idx); + if (!VALUE (lit) && repr[lit] != lit) + res++; + } + DEALLOC (repr, LITS); + return res; +} + +#ifndef NDEBUG + +static void check_lits_sorted (size_t size, const unsigned *lits) { + unsigned prev = INVALID_LIT; + const unsigned *const end_lits = lits + size; + for (const unsigned *p = lits; p != end_lits; p++) { + const unsigned lit = *p; + if (prev != INVALID_LIT) { + assert (prev != lit); + const unsigned not_lit = lit ^ 1; + assert (prev != not_lit); + assert (prev < lit); + } + prev = lit; + } +} + +static void check_and_lits_normalized (size_t arity, const unsigned *lits) { + assert (arity > 1); + check_lits_sorted (arity, lits); +} + +static void check_xor_lits_normalized (const unsigned arity, + const unsigned *lits) { + assert (arity > 1); + check_lits_sorted (arity, lits); + for (size_t i = 1; i != arity; i++) + assert (lits[i - 1] < lits[i]); +} + +static void check_ite_lits_normalized (kissat *solver, + const unsigned *lits) { + assert (!NEGATED (lits[0])); + assert (!NEGATED (lits[1])); + assert (lits[0] != lits[1]); + assert (lits[0] != lits[2]); + assert (lits[1] != lits[2]); + assert (lits[0] != NOT (lits[1])); + assert (lits[0] != NOT (lits[2])); + assert (lits[1] != NOT (lits[2])); +} + +#else + +#define check_lits_sorted(...) \ + do { \ + } while (0) + +#define check_and_lits_normalized check_lits_sorted +#define check_xor_lits_normalized check_lits_sorted +#define check_ite_lits_normalized check_lits_sorted + +#endif + +#define LESS_LIT(A, B) ((A) < (B)) + +static void sort_lits (kissat *solver, size_t arity, unsigned *lits) { + SORT (unsigned, arity, lits, LESS_LIT); + check_lits_sorted (arity, lits); +} + +static unsigned hash_lits (closure *closure, unsigned tag, size_t arity, + const unsigned *lits) { +#ifndef NDEBUG + if (tag == AND_GATE) + check_and_lits_normalized (arity, lits); + else if (tag == XOR_GATE) + check_xor_lits_normalized (arity, lits); + else { + assert (tag == ITE_GATE); + check_ite_lits_normalized (closure->solver, lits); + } +#endif + const unsigned *end_lits = lits + arity; + const uint64_t *const nonces = closure->nonces; + const uint64_t *const end_nonces = nonces + SIZE_NONCES; + const uint64_t *n = nonces + tag; + uint64_t hash = 0; + assert (n < end_nonces); + for (const unsigned *l = lits; l != end_lits; l++) { + hash += *l; + hash *= *n++; + hash = (hash << 4) | (hash >> 60); + if (n == end_nonces) + n = nonces; + } + hash ^= hash >> 32; + return hash; +} + +#ifndef NDEBUG +static bool is_power_of_two (size_t n) { return n && ~(n & (n - 1)); } +#endif + +static size_t reduce_hash (unsigned hash, size_t size, size_t size2) { + assert (size <= size2); + assert (size2 <= 2 * size); + assert (is_power_of_two (size2)); + unsigned res = hash; + res &= size2 - 1; + if (res >= size) + res -= size; + assert (res < size); + return res; +} + +#define MAX_HASH_TABLE_SIZE ((size_t) 1 << 32) + +static bool closure_hash_table_is_full (closure *closure) { + if (closure->hash.size == MAX_HASH_TABLE_SIZE) + return false; + if (2 * closure->hash.entries < closure->hash.size) + return false; + return true; +} + +static bool match_lits (gate *g, unsigned tag, unsigned hash, size_t size, + const unsigned *lits) { + assert (!g->garbage); + if (g->tag != tag) + return false; + if (g->hash != hash) + return false; + if (g->arity != size) + return false; + const unsigned *p = lits; + for (all_rhs_literals_in_gate (lit, g)) + if (lit != *p++) + return false; + return true; +} + +static void resize_gate_hash_table (closure *closure) { + kissat *solver = closure->solver; + gate_hash_table *hash = &closure->hash; + const size_t old_size = hash->size; + const size_t new_size = old_size ? 2 * old_size : 1; + const size_t old_entries = hash->entries; + kissat_extremely_verbose ( + solver, + "resizing gate table of size %zu filled with %zu entries %.0f%%", + old_size, old_entries, kissat_percent (old_entries, old_size)); + gate **old_table = hash->table, **new_table; + CALLOC (new_table, new_size); + size_t flushed = 0; + for (size_t old_pos = 0; old_pos != old_size; old_pos++) { + gate *g = old_table[old_pos]; + if (!g) + continue; + if (g == REMOVED) { + flushed++; + continue; + } + size_t new_pos = reduce_hash (g->hash, new_size, new_size); + while (new_table[new_pos]) { + assert (new_table[new_pos] != REMOVED); + if (++new_pos == new_size) + new_pos = 0; + } + new_table[new_pos] = g; + } + kissat_extremely_verbose ( + solver, "flushed %zu entries %.0f%% resizing table of size %zu", + flushed, kissat_percent (flushed, old_size), old_size); + DEALLOC (old_table, old_size); + assert (flushed <= old_entries); + const size_t new_entries = old_entries - flushed; + hash->table = new_table; + hash->size = new_size; + hash->entries = new_entries; + kissat_very_verbose ( + solver, "resized gate table to %zu with %zu entries %.0f%%", new_size, + new_entries, kissat_percent (new_entries, new_size)); +} + +static bool remove_gate (closure *closure, gate *g) { + if (!g->indexed) + return false; + kissat *solver = closure->solver; + assert (!solver->inconsistent); + const size_t hash_size = closure->hash.size; + size_t pos = reduce_hash (g->hash, hash_size, hash_size); + gate **table = closure->hash.table; + INC (congruent_lookups); + INC (congruent_lookups_removed); + unsigned collisions = 0; + while (table[pos] != g) { + collisions++; + if (++pos == hash_size) + pos = 0; + } + ADD (congruent_collisions_removed, collisions); + ADD (congruent_collisions, collisions); + table[pos] = REMOVED; + LOGATE (g, "removing from hash table"); + g->indexed = false; + return true; +} + +static gate *find_gate (closure *closure, unsigned tag, unsigned hash, + size_t size, const unsigned *lits, gate *except) { + assert (!except || !except->garbage); + if (!closure->hash.entries) + return 0; + kissat *solver = closure->solver; + assert (!solver->inconsistent); + assert (hash == hash_lits (closure, tag, size, lits)); + const size_t hash_size = closure->hash.size; + size_t start_pos = reduce_hash (hash, hash_size, hash_size); + gate **table = closure->hash.table, *g; + INC (congruent_lookups); + INC (congruent_lookups_find); + size_t pos = start_pos; + unsigned collisions = 0; + gate *res = 0; + while ((g = table[pos])) { + if (g == REMOVED) + ; + else if (g->garbage) { + assert (g->indexed); + g->indexed = false; + table[pos] = REMOVED; + } else if (g != except && match_lits (g, tag, hash, size, lits)) { + INC (congruent_matched); + res = g; + break; + } + collisions++; + if (++pos == hash_size) + pos = 0; + if (pos == start_pos) + break; + } + ADD (congruent_collisions_find, collisions); + ADD (congruent_collisions, collisions); + return res; +} + +static void index_gate (closure *closure, gate *g) { + assert (!g->indexed); + kissat *solver = closure->solver; + assert (!solver->inconsistent); + assert (g->arity > 1); + if (closure_hash_table_is_full (closure)) + resize_gate_hash_table (closure); + LOGATE (g, "adding to hash table"); + INC (congruent_indexed); + assert (g->hash == hash_lits (closure, g->tag, g->arity, g->rhs)); + const size_t hash_size = closure->hash.size; + size_t pos = reduce_hash (g->hash, hash_size, hash_size); + gate **table = closure->hash.table, *h; + unsigned collisions = 0; + while ((h = table[pos]) && h != REMOVED) { + collisions++; + if (++pos == hash_size) + pos = 0; + } + ADD (congruent_collisions_index, collisions); + ADD (congruent_collisions, collisions); + table[pos] = g; + closure->hash.entries++; + g->indexed = true; +} + +static unsigned parity_lits (kissat *solver, unsigneds *lits) { + unsigned res = 0; + for (all_stack (unsigned, lit, *lits)) + res ^= NEGATED (lit); +#ifdef NDEBUG + (void) solver; +#endif + return res; +} + +static void inc_lits (kissat *solver, unsigneds *lits) { + unsigned *p = BEGIN_STACK (*lits); + unsigned *end = END_STACK (*lits); + unsigned carry = 1; + while (carry && p != end) { + unsigned lit = *p; + unsigned not_lit = NOT (lit); + carry = !NEGATED (not_lit); + *p++ = not_lit; + } +#ifdef NDEBUG + (void) solver; +#endif +} + +#ifndef NDEBUG + +#define LESS_LITERAL(A, B) ((A) < (B)) + +static void check_implied (closure *closure) { + kissat *const solver = closure->solver; + unsigneds *implied = &closure->implied; + SORT_STACK (unsigned, *implied, LESS_LITERAL); + unsigned *q = BEGIN_STACK (*implied); + const unsigned *const end = END_STACK (*implied); + unsigned prev = INVALID_LIT; + bool tautological = false; + for (const unsigned *p = q; p != end; p++) { + const unsigned lit = *p; + if (prev == lit) + continue; + const unsigned not_lit = NOT (lit); + if (prev == not_lit) { + tautological = true; + break; + } + *q++ = prev = lit; + } + if (!tautological) { + SET_END_OF_STACK (*implied, q); + CHECK_AND_ADD_STACK (*implied); + REMOVE_CHECKER_STACK (*implied); + } + CLEAR_STACK (*implied); +} + +static void check_clause (closure *closure) { + kissat *const solver = closure->solver; + unsigneds *implied = &closure->implied; + unsigneds *clause = &solver->clause; + for (all_stack (unsigned, lit, *clause)) + PUSH_STACK (*implied, lit); + check_implied (closure); +} + +static void check_binary_implied (closure *closure, unsigned a, + unsigned b) { + kissat *const solver = closure->solver; + unsigneds *implied = &closure->implied; + assert (EMPTY_STACK (*implied)); + PUSH_STACK (*implied, a); + PUSH_STACK (*implied, b); + check_implied (closure); +} + +static void check_and_gate_implied (closure *closure, gate *g) { + assert (g->tag == AND_GATE); + kissat *const solver = closure->solver; + if (GET_OPTION (check) < 2) + return; + CLOGANDGATE (g, "checking implied"); + const unsigned lhs = g->lhs; + const unsigned not_lhs = NOT (lhs); + for (all_rhs_literals_in_gate (other, g)) + check_binary_implied (closure, not_lhs, other); + unsigneds *implied = &closure->implied; + assert (EMPTY_STACK (*implied)); + PUSH_STACK (*implied, lhs); + for (all_rhs_literals_in_gate (other, g)) { + const unsigned not_other = NOT (other); + PUSH_STACK (*implied, not_other); + } + check_implied (closure); +} + +static void check_xor_gate_implied (closure *closure, gate *g) { + assert (g->tag == XOR_GATE); + kissat *const solver = closure->solver; + if (GET_OPTION (check) < 2) + return; + CLOGXORGATE (g, "checking implied"); + const unsigned lhs = g->lhs; + const unsigned not_lhs = NOT (lhs); + unsigneds *clause = &solver->clause; + assert (EMPTY_STACK (*clause)); + PUSH_STACK (*clause, not_lhs); + for (all_rhs_literals_in_gate (other, g)) { + assert (!NEGATED (other)); + PUSH_STACK (*clause, other); + } + unsigned arity = g->arity; + unsigned end = 1u << arity; + unsigned parity = NEGATED (not_lhs); + assert (parity == parity_lits (solver, clause)); + for (unsigned i = 0; i != end; i++) { + while (i && parity_lits (solver, clause) != parity) + inc_lits (solver, clause); + check_clause (closure); + inc_lits (solver, clause); + } + CLEAR_STACK (*clause); +} + +static void check_ternary (closure *closure, unsigned a, unsigned b, + unsigned c) { + kissat *const solver = closure->solver; + if (GET_OPTION (check) < 2) + return; + unsigneds *implied = &closure->implied; + PUSH_STACK (*implied, a); + PUSH_STACK (*implied, b); + PUSH_STACK (*implied, c); + check_implied (closure); +} + +static void check_ite_implied (closure *closure, unsigned lhs, + unsigned cond, unsigned then_lit, + unsigned else_lit) { + kissat *const solver = closure->solver; + if (GET_OPTION (check) < 2) + return; + LOG ("checking implied ITE gate %s := %s ? %s : %s", LOGLIT (lhs), + LOGLIT (cond), LOGLIT (then_lit), LOGLIT (else_lit)); + const unsigned not_lhs = NOT (lhs); + const unsigned not_cond = NOT (cond); + const unsigned not_then_lit = NOT (then_lit); + const unsigned not_else_lit = NOT (else_lit); + check_ternary (closure, cond, not_else_lit, lhs); + check_ternary (closure, cond, else_lit, not_lhs); + check_ternary (closure, not_cond, not_then_lit, lhs); + check_ternary (closure, not_cond, then_lit, not_lhs); +} + +static void check_ite_gate_implied (closure *closure, gate *g) { + assert (g->tag == ITE_GATE); + assert (g->arity == 3); +#ifndef NOPTIONS + kissat *const solver = closure->solver; +#endif + if (GET_OPTION (check) < 2) + return; + const unsigned lhs = g->lhs; + const unsigned cond = g->rhs[0]; + const unsigned then_lit = g->rhs[1]; + const unsigned else_lit = g->rhs[2]; + check_ite_implied (closure, lhs, cond, then_lit, else_lit); +} + +#else + +#define check_and_gate_implied(...) \ + do { \ + } while (0) + +#define check_xor_gate_implied check_and_gate_implied +#define check_ternary check_and_gate_implied +#define check_ite_implied check_and_gate_implied +#define check_ite_gate_implied check_and_gate_implied + +#endif + +static inline unsigned find_repr (closure *closure, unsigned lit) { + const unsigned *const repr = closure->repr; + unsigned res = lit, next = repr[res]; + while (res != next) + res = next, next = repr[res]; + return res; +} + +#ifndef MERGE_CONDITIONAL_EQUIVALENCES + +static clause *find_other_two (kissat *solver, watches *watches, unsigned a, + unsigned b, unsigned ignore) { + assert (!solver->watching); + const value *const values = solver->values; + const watch *const begin_watches = BEGIN_WATCHES (*watches); + const watch *const end_watches = END_WATCHES (*watches); + const watch *p = begin_watches; + while (p != end_watches) { + const watch watch = *p++; + assert (!watch.type.binary); + const reference ref = watch.large.ref; + clause *c = kissat_dereference_clause (solver, ref); + assert (!c->garbage); + unsigned found = 0; + for (all_literals_in_clause (lit, c)) { + if (values[lit]) + continue; + if (lit == ignore) + continue; + if (lit == a || lit == b) { + found++; + continue; + } + goto CONTINUE_WITH_NEXT_WATCH; + } + assert (found <= 2); + if (found == 2) + return c; + CONTINUE_WITH_NEXT_WATCH:; + } + return 0; +} + +static clause *find_ternary_clause (kissat *solver, unsigned a, unsigned b, + unsigned c) { + assert (!solver->watching); + watches *const a_watches = &WATCHES (a); + watches *const b_watches = &WATCHES (b); + watches *const c_watches = &WATCHES (c); + const size_t size_a = SIZE_WATCHES (*a_watches); + const size_t size_b = SIZE_WATCHES (*b_watches); + const size_t size_c = SIZE_WATCHES (*c_watches); + if (size_a <= size_b && size_a <= size_b) + return find_other_two (solver, a_watches, b, c, a); + if (size_b <= size_a && size_b <= size_c) + return find_other_two (solver, b_watches, a, c, b); + assert (size_c <= size_a && size_c <= size_b); + return find_other_two (solver, c_watches, a, b, c); +} + +#endif + +static bool learn_congruence_unit (closure *closure, unsigned unit) { + kissat *const solver = closure->solver; + assert (!solver->inconsistent); + const value value = solver->values[unit]; + if (value > 0) + return true; + INC (congruent_units); + if (value < 0) { + solver->inconsistent = 1; + LOG ("inconsistent congruence unit %s", LOGLIT (unit)); + CHECK_AND_ADD_EMPTY (); + ADD_EMPTY_TO_PROOF (); + return false; + } + LOG ("learning congruence unit %s", LOGLIT (unit)); + kissat_learned_unit (solver, unit); + clause *conflict = kissat_probing_propagate (solver, 0, false); + if (!conflict) + return true; + assert (solver->inconsistent); + LOG ("propagating congruence unit %s yields conflict", LOGLIT (unit)); + return false; +} + +static void add_binary_clause (closure *closure, unsigned a, unsigned b) { + kissat *const solver = closure->solver; + if (solver->inconsistent) + return; + if (a == NOT (b)) + return; + value a_value = VALUE (a); + if (a_value > 0) + return; + value b_value = VALUE (b); + if (b_value > 0) + return; + unsigned unit = INVALID_LIT; + if (a == b) + unit = a; + else if (a_value < 0 && !b_value) + unit = b; + else if (!a_value && b_value < 0) + unit = a; + if (unit != INVALID_LIT) { + (void) !learn_congruence_unit (closure, unit); + return; + } + assert (!a_value), assert (!b_value); + LOGBINARY (a, b, "adding representative"); + if (solver->watching) + kissat_new_binary_clause (solver, a, b); + else { + kissat_new_unwatched_binary_clause (solver, a, b); + litpair litpair = {.lits = {a < b ? a : b, a < b ? b : a}}; + PUSH_STACK (closure->binaries, litpair); + } +} + +static void schedule_literal (closure *closure, unsigned lit) { + kissat *const solver = closure->solver; + unsigned idx = IDX (lit); + bool *scheduled = closure->scheduled + idx; + if (*scheduled) + return; + *scheduled = true; + ENQUEUE_FIFO (closure->schedule, lit); + LOG ("scheduled propagation of merged %s", CLOGREPR (lit)); +} + +static unsigned dequeue_next_scheduled_literal (closure *closure) { + unsigned res; + DEQUEUE_FIFO (closure->schedule, res); +#if defined(LOGGING) || !defined(NDEBUG) + kissat *const solver = closure->solver; +#endif + unsigned idx = IDX (res); + bool *scheduled = closure->scheduled + idx; + assert (*scheduled); + *scheduled = false; + LOG ("dequeued from schedule %s", CLOGREPR (res)); + return res; +} + +static bool merge_literals (closure *closure, unsigned lit, + unsigned other) { + kissat *const solver = closure->solver; + assert (!solver->inconsistent); + unsigned repr_lit = find_repr (closure, lit); + unsigned repr_other = find_repr (closure, other); + unsigned *const repr = closure->repr; + if (repr_lit == repr_other) { + LOG ("already merged %s and %s", LOGREPR (lit, repr), + LOGREPR (other, repr)); + return false; + } + const value *const values = solver->values; + const value lit_value = values[lit]; + const value other_value = values[other]; + assert (lit_value == values[repr_lit]); + assert (other_value == values[repr_other]); + if (lit_value) { + if (lit_value == other_value) { + LOG ("not merging %s and %s assigned to the same value", + LOGREPR (lit, repr), LOGREPR (other, repr)); + return false; + } + if (lit_value == -other_value) { + LOG ("merging inconsistently assigned %s and %s", LOGREPR (lit, repr), + LOGREPR (other, repr)); + solver->inconsistent = true; + CHECK_AND_ADD_EMPTY (); + ADD_EMPTY_TO_PROOF (); + return false; + } + assert (!other_value); + LOG ("merging assigned %s and unassigned %s", LOGREPR (lit, repr), + LOGREPR (other, repr)); + const unsigned unit = (lit_value < 0) ? NOT (other) : other; + (void) learn_congruence_unit (closure, unit); + return false; + } + if (!lit_value && other_value) { + LOG ("merging unassigned %s and assigned %s", LOGREPR (lit, repr), + LOGREPR (other, repr)); + const unsigned unit = (other_value < 0) ? NOT (lit) : lit; + (void) learn_congruence_unit (closure, unit); + return false; + } + unsigned smaller = repr_lit; + unsigned larger = repr_other; + if (smaller > larger) + SWAP (unsigned, smaller, larger); + assert (repr[smaller] == smaller); + assert (repr[larger] > smaller); + if (repr_lit == NOT (repr_other)) { + LOG ("merging clashing %s and %s", LOGREPR (lit, repr), + LOGREPR (other, repr)); + kissat_learned_unit (solver, smaller); + solver->inconsistent = true; + CHECK_AND_ADD_EMPTY (); + ADD_EMPTY_TO_PROOF (); + return false; + } + LOG ("merging %s and %s", LOGREPR (lit, repr), LOGREPR (other, repr)); + const unsigned not_smaller = NOT (smaller); + const unsigned not_larger = NOT (larger); + repr[larger] = smaller; + repr[not_larger] = not_smaller; + LOG ("congruence repr[%s] = %s", LOGLIT (larger), LOGLIT (smaller)); + LOG ("congruence repr[%s] = %s", LOGLIT (not_larger), + LOGLIT (not_smaller)); + add_binary_clause (closure, not_larger, smaller); + add_binary_clause (closure, larger, not_smaller); + schedule_literal (closure, larger); + INC (congruent); + return true; +} + +static void connect_occurrence (closure *closure, unsigned lit, gate *g) { + gates *const occurrences = closure->occurrences; + kissat *const solver = closure->solver; + PUSH_STACK (occurrences[lit], g); + LOG ("connected %s to gate[%zu]", LOGLIT (lit), g->id); +} + +static gate *new_gate (closure *closure, unsigned tag, unsigned hash, + unsigned lhs, unsigned arity, const unsigned *lits) { + kissat *const solver = closure->solver; + const size_t bytes = bytes_gate (arity); + gate *g = kissat_malloc (solver, bytes); +#if defined(LOGGING) || !defined(NDEBUG) + g->id = closure->gates_added++; +#endif + g->tag = tag; + g->hash = hash; + g->lhs = lhs; + g->arity = arity; + g->garbage = false; + g->indexed = false; + g->marked = false; + g->shrunken = false; + memcpy (g->rhs, lits, arity * sizeof *lits); + for (all_rhs_literals_in_gate (lit, g)) + connect_occurrence (closure, lit, g); + LOGATE (g, "new"); + index_gate (closure, g); + ADD (congruent_arity, arity); + INC (congruent_gates); + return g; +} + +static gate *find_and_lits (closure *closure, unsigned *hash_ptr, + unsigned arity, unsigned *lits, gate *except) { + kissat *const solver = closure->solver; + sort_lits (solver, arity, lits); + const unsigned hash = hash_lits (closure, AND_GATE, arity, lits); + gate *g = find_gate (closure, AND_GATE, hash, arity, lits, except); + *hash_ptr = hash; + if (g) { + CLOGANDGATE (g, "found matching"); + INC (congruent_matched_ands); + } else + LOGANDGATE (INVALID_GATE_ID, closure->repr, INVALID_LIT, arity, lits, + "could not find matching"); + return g; +} + +static gate *find_and_gate (closure *closure, unsigned *h, gate *g) { + return find_and_lits (closure, h, g->arity, g->rhs, g); +} + +static gate *new_and_gate (closure *closure, unsigned lhs) { + kissat *const solver = closure->solver; + unsigneds *all_lits = &closure->lits; + unsigneds *rhs_stack = &closure->rhs; + CLEAR_STACK (*rhs_stack); + for (all_stack (unsigned, lit, *all_lits)) + if (lhs != lit) { + unsigned not_lit = NOT (lit); + assert (lhs != not_lit); + PUSH_STACK (*rhs_stack, not_lit); + } + const unsigned arity = SIZE_STACK (*rhs_stack); + unsigned *rhs_lits = BEGIN_STACK (*rhs_stack); + assert (arity + 1 == SIZE_STACK (*all_lits)); + unsigned hash; + gate *g = find_and_lits (closure, &hash, arity, rhs_lits, 0); + if (g) { + if (merge_literals (closure, g->lhs, lhs)) + INC (congruent_ands); + return 0; + } + g = new_gate (closure, AND_GATE, hash, lhs, arity, rhs_lits); + check_and_gate_implied (closure, g); + ADD (congruent_arity_ands, arity); + INC (congruent_gates_ands); + return g; +} + +#ifdef CHECKING_OR_PROVING + +static void copy_literals (kissat *solver, unsigneds *dst, + const unsigneds *src) { + for (all_stack (unsigned, lit, *src)) + PUSH_STACK (*dst, lit); + PUSH_STACK (*dst, INVALID_LIT); +} + +static void simplify_and_add_to_proof_chain (kissat *solver, mark *marks, + unsigneds *unsimplified, + unsigneds *clause, + unsigneds *chain) { + assert (EMPTY_STACK (*clause)); +#ifndef NDEBUG + for (all_stack (unsigned, lit, *unsimplified)) + assert (!(marks[lit] & 4)); +#endif + bool trivial = false; + for (all_stack (unsigned, lit, *unsimplified)) { + mark lit_mark = marks[lit]; + if (lit_mark & 4) + continue; + const unsigned not_lit = NOT (lit); + const mark not_lit_mark = marks[not_lit]; + if (not_lit_mark & 4) { + trivial = true; + break; + } + lit_mark |= 4; + marks[lit] = lit_mark; + PUSH_STACK (*clause, lit); + } + for (all_stack (unsigned, lit, *clause)) { + mark mark = marks[lit]; + assert (mark & 4); + mark &= ~4u; + marks[lit] = mark; + } + if (!trivial) { + CHECK_AND_ADD_STACK (*clause); + ADD_STACK_TO_PROOF (*clause); + copy_literals (solver, chain, clause); + } + CLEAR_STACK (*clause); +} + +#define SIMPLIFY_AND_ADD_TO_PROOF_CHAIN() \ + simplify_and_add_to_proof_chain (solver, marks, unsimplified, clause, \ + chain) + +static void add_xor_matching_proof_chain (closure *closure, gate *g, + unsigned lhs1, unsigned lhs2) { + if (lhs1 == lhs2) + return; + kissat *const solver = closure->solver; + if (!kissat_checking_or_proving (solver)) + return; + LOG ("starting XOR matching proof chain"); + unsigneds *const unsimplified = &closure->unsimplified; + unsigneds *const clause = &solver->clause; + unsigneds *const chain = &closure->chain; + mark *const marks = solver->marks; + assert (EMPTY_STACK (*unsimplified)); + assert (EMPTY_STACK (*chain)); + assert (g->arity > 1); + const unsigned reduced_arity = g->arity - 1; + for (unsigned i = 0; i != reduced_arity; i++) + PUSH_STACK (*unsimplified, g->rhs[i]); + const unsigned not_lhs1 = NOT (lhs1); + const unsigned not_lhs2 = NOT (lhs2); + do { + const size_t size = SIZE_STACK (*unsimplified); + assert (size < 32); + for (unsigned i = 0; i != 1u << size; i++) { + PUSH_STACK (*unsimplified, not_lhs1); + PUSH_STACK (*unsimplified, lhs2); + SIMPLIFY_AND_ADD_TO_PROOF_CHAIN (); + unsimplified->end -= 2; + PUSH_STACK (*unsimplified, lhs1); + PUSH_STACK (*unsimplified, not_lhs2); + SIMPLIFY_AND_ADD_TO_PROOF_CHAIN (); + unsimplified->end -= 2; + inc_lits (solver, unsimplified); + } + assert (!EMPTY_STACK (*unsimplified)); + unsimplified->end--; + } while (!EMPTY_STACK (*unsimplified)); + LOG ("finished XOR matching proof chain"); +} + +static void delete_proof_chain (closure *closure) { + kissat *const solver = closure->solver; + unsigneds *chain = &closure->chain; + if (!kissat_checking_or_proving (solver)) { + assert (EMPTY_STACK (*chain)); + return; + } + if (EMPTY_STACK (*chain)) + return; + LOG ("starting deletion of proof chain"); + unsigneds *clause = &solver->clause; + assert (EMPTY_STACK (*clause)); + const unsigned *start = BEGIN_STACK (*chain); + const unsigned *end = END_STACK (*chain); + const unsigned *p = start; + while (p != end) { + const unsigned lit = *p; + if (lit == INVALID_LIT) { + while (start != p) { + const unsigned other = *start++; + PUSH_STACK (*clause, other); + } + REMOVE_CHECKER_STACK (*clause); + DELETE_STACK_FROM_PROOF (*clause); + CLEAR_STACK (*clause); + start++; + } + p++; + } + assert (EMPTY_STACK (*clause)); + assert (start == end); + CLEAR_STACK (*chain); + LOG ("finished deletion of proof chain"); +} + +#else + +#define add_xor_matching_proof_chain(...) \ + do { \ + } while (0) + +#define delete_proof_chain(...) \ + do { \ + } while (0) + +#endif + +static gate *find_xor_lits (closure *closure, unsigned *hash_ptr, + unsigned arity, unsigned *lits, gate *except) { + kissat *const solver = closure->solver; + sort_lits (solver, arity, lits); + const unsigned hash = hash_lits (closure, XOR_GATE, arity, lits); + gate *g = find_gate (closure, XOR_GATE, hash, arity, lits, except); + *hash_ptr = hash; + if (g) { + CLOGXORGATE (g, "found matching"); + INC (congruent_matched_xors); + } else + LOGXORGATE (INVALID_GATE_ID, closure->repr, INVALID_LIT, arity, lits, + "tried but did not find matching"); + return g; +} + +static gate *find_xor_gate (closure *closure, unsigned *h, gate *g) { + return find_xor_lits (closure, h, g->arity, g->rhs, g); +} + +static gate *new_xor_gate (closure *closure, unsigned lhs) { + kissat *const solver = closure->solver; + unsigneds *all_lits = &closure->lits; + unsigneds *rhs_stack = &closure->rhs; + CLEAR_STACK (*rhs_stack); + const unsigned not_lhs = NOT (lhs); + for (all_stack (unsigned, lit, *all_lits)) + if (lit != lhs && lit != not_lhs) { + assert (!NEGATED (lit)); + PUSH_STACK (*rhs_stack, lit); + } + const unsigned arity = SIZE_STACK (*rhs_stack); + unsigned *rhs_lits = BEGIN_STACK (*rhs_stack); + assert (arity + 1 == SIZE_STACK (*all_lits)); + unsigned hash; + gate *g = find_xor_lits (closure, &hash, arity, rhs_lits, 0); + if (g) { + add_xor_matching_proof_chain (closure, g, g->lhs, lhs); + if (merge_literals (closure, g->lhs, lhs)) + INC (congruent_xors); + if (!solver->inconsistent) + delete_proof_chain (closure); + return 0; + } + g = new_gate (closure, XOR_GATE, hash, lhs, arity, rhs_lits); + check_xor_gate_implied (closure, g); + ADD (congruent_arity_xors, arity); + INC (congruent_gates_xors); + return g; +} + +#ifdef CHECKING_OR_PROVING + +static void add_ite_matching_proof_chain (closure *closure, gate *g, + unsigned lhs1, unsigned lhs2) { + if (lhs1 == lhs2) + return; + kissat *const solver = closure->solver; + if (!kissat_checking_or_proving (solver)) + return; + LOG ("starting ITE matching proof chain"); + unsigneds *const unsimplified = &closure->unsimplified; + unsigneds *clause = &solver->clause; + mark *const marks = solver->marks; + unsigneds *chain = &closure->chain; + assert (EMPTY_STACK (*clause)); + assert (EMPTY_STACK (*chain)); + const unsigned *rhs = g->rhs; + const unsigned cond = rhs[0]; + const unsigned not_cond = NOT (cond); + const unsigned not_lhs1 = NOT (lhs1); + const unsigned not_lhs2 = NOT (lhs2); + PUSH_STACK (*unsimplified, lhs1); + PUSH_STACK (*unsimplified, not_lhs2); + PUSH_STACK (*unsimplified, cond); + SIMPLIFY_AND_ADD_TO_PROOF_CHAIN (); + unsimplified->end--; + PUSH_STACK (*unsimplified, not_cond); + SIMPLIFY_AND_ADD_TO_PROOF_CHAIN (); + unsimplified->end--; + CHECK_AND_ADD_STACK (*unsimplified); + ADD_STACK_TO_PROOF (*unsimplified); + copy_literals (solver, chain, unsimplified); + CLEAR_STACK (*unsimplified); + PUSH_STACK (*unsimplified, not_lhs1); + PUSH_STACK (*unsimplified, lhs2); + PUSH_STACK (*unsimplified, cond); + SIMPLIFY_AND_ADD_TO_PROOF_CHAIN (); + unsimplified->end--; + PUSH_STACK (*unsimplified, not_cond); + SIMPLIFY_AND_ADD_TO_PROOF_CHAIN (); + unsimplified->end--; + SIMPLIFY_AND_ADD_TO_PROOF_CHAIN (); + CLEAR_STACK (*unsimplified); + LOG ("finished ITE matching proof chain"); +} + +static void add_ite_turned_and_binary_clauses (closure *closure, gate *g) { + kissat *const solver = closure->solver; + if (!kissat_checking_or_proving (solver)) + return; + LOG ("starting ITE turned AND supporting binary clauses"); + unsigneds *const unsimplified = &closure->unsimplified; + unsigneds *clause = &solver->clause; + unsigneds *chain = &closure->chain; + mark *const marks = solver->marks; + assert (EMPTY_STACK (*unsimplified)); + assert (EMPTY_STACK (*chain)); + const unsigned not_lhs = NOT (g->lhs); + const unsigned *rhs = g->rhs; + PUSH_STACK (*unsimplified, not_lhs); + PUSH_STACK (*unsimplified, rhs[0]); + SIMPLIFY_AND_ADD_TO_PROOF_CHAIN (); + unsimplified->end--; + PUSH_STACK (*unsimplified, rhs[1]); + SIMPLIFY_AND_ADD_TO_PROOF_CHAIN (); + CLEAR_STACK (*unsimplified); +} + +#else + +#define add_ite_matching_proof_chain(...) \ + do { \ + } while (0) + +#define add_ite_turned_and_binary_clauses add_ite_matching_proof_chain + +#endif + +static bool normalize_ite_lits (kissat *solver, unsigned *lits) { +#ifdef NDEBUG + (void) solver; +#endif + if (NEGATED (lits[0])) { + lits[0] = NOT (lits[0]); + SWAP (unsigned, lits[1], lits[2]); + } + if (!NEGATED (lits[1])) + return false; + lits[1] = NOT (lits[1]); + lits[2] = NOT (lits[2]); + return true; +} + +static gate *find_ite_lits (closure *closure, unsigned *hash_ptr, + bool *negate_lhs_ptr, unsigned arity, + unsigned *lits, gate *except) { + kissat *const solver = closure->solver; + assert (arity == 3); + LOGITEGATE (INVALID_GATE_ID, closure->repr, INVALID_LIT, lits[0], lits[1], + lits[2], "finding not yet normalized"); + bool negate_lhs = normalize_ite_lits (solver, lits); +#ifdef LOGGING + if (negate_lhs) + LOG ("normalization forces negation of LHS"); + LOGITEGATE (INVALID_GATE_ID, closure->repr, INVALID_LIT, lits[0], lits[1], + lits[2], "normalized"); +#endif + *negate_lhs_ptr = negate_lhs; + const unsigned hash = hash_lits (closure, ITE_GATE, arity, lits); + gate *g = find_gate (closure, ITE_GATE, hash, arity, lits, except); + *hash_ptr = hash; + if (g) { + CLOGITEGATE (g, "found matching"); + INC (congruent_matched_ites); + } else + LOGITEGATE (INVALID_GATE_ID, closure->repr, INVALID_LIT, lits[0], + lits[1], lits[2], "tried but did not find matching"); + return g; +} + +static gate *find_ite_gate (closure *closure, unsigned *h, + bool *negate_lhs_ptr, gate *g) { + return find_ite_lits (closure, h, negate_lhs_ptr, g->arity, g->rhs, g); +} + +static gate *new_ite_gate (closure *closure, unsigned lhs, unsigned cond, + unsigned then_lit, unsigned else_lit) { + kissat *const solver = closure->solver; + const unsigned not_then_lit = NOT (then_lit); + if (else_lit == not_then_lit) { +#ifdef LOGGING + if (NEGATED (then_lit)) + LOG ("skipping ternary XOR gate %s := %s ^ %s", LOGLIT (lhs), + LOGLIT (cond), LOGLIT (not_then_lit)); + else + LOG ("skipping ternary XOR gate %s := %s ^ %s", LOGLIT (NOT (lhs)), + LOGLIT (cond), LOGLIT (then_lit)); +#endif + return 0; + } + if (else_lit == then_lit) { + LOG ("found trivial ITE gate %s := %s ? %s : %s", LOGLIT (lhs), + LOGLIT (cond), LOGLIT (then_lit), LOGLIT (else_lit)); + if (merge_literals (closure, lhs, then_lit)) + INC (congruent_trivial_ite); + return 0; + } + unsigneds *rhs_stack = &closure->rhs; + CLEAR_STACK (*rhs_stack); + PUSH_STACK (*rhs_stack, cond); + PUSH_STACK (*rhs_stack, then_lit); + PUSH_STACK (*rhs_stack, else_lit); + assert (SIZE_STACK (*rhs_stack) == 3); + const unsigned arity = 3; + unsigned *rhs_lits = BEGIN_STACK (*rhs_stack); + bool negate_lhs; + unsigned hash; + gate *g = find_ite_lits (closure, &hash, &negate_lhs, arity, rhs_lits, 0); + if (g) { + if (negate_lhs) + lhs = NOT (lhs); + add_ite_matching_proof_chain (closure, g, g->lhs, lhs); + if (merge_literals (closure, g->lhs, lhs)) + INC (congruent_ites); + if (!solver->inconsistent) + delete_proof_chain (closure); + return 0; + } + if (negate_lhs) + lhs = NOT (lhs); + g = new_gate (closure, ITE_GATE, hash, lhs, arity, rhs_lits); + check_ite_gate_implied (closure, g); + INC (congruent_gates_ites); + return g; +} + +static void mark_gate_as_garbage (closure *closure, gate *g) { + kissat *const solver = closure->solver; + assert (!g->garbage); + g->garbage = true; + LOGATE (g, "marked as garbage"); + PUSH_STACK (closure->garbage, g); +} + +static void shrink_gate (closure *closure, gate *g, + const unsigned *new_end_rhs) { + unsigned *const rhs = g->rhs; + const unsigned old_arity = g->arity; + unsigned *const old_end_rhs = rhs + old_arity; + assert (rhs <= new_end_rhs); + assert (new_end_rhs <= old_end_rhs); + if (new_end_rhs == old_end_rhs) + return; + const unsigned new_arity = new_end_rhs - rhs; + if (!g->shrunken) { + assert (old_end_rhs[-1] != INVALID_LIT); + old_end_rhs[-1] = INVALID_LIT; + g->shrunken = true; + } + g->arity = new_arity; +#ifdef LOGGING + kissat *const solver = closure->solver; + LOGATE (g, "shrunken"); +#else + (void) closure; +#endif +} + +static bool skip_and_gate (closure *closure, gate *g) { + assert (g->tag == AND_GATE); + if (g->garbage) + return true; + kissat *const solver = closure->solver; + const value *const values = solver->values; + const unsigned lhs = g->lhs; + const value value_lhs = values[lhs]; + if (value_lhs > 0) { + mark_gate_as_garbage (closure, g); + return true; + } + assert (g->arity > 1); + return false; +} + +static bool gate_contains (gate *g, unsigned lit) { + for (all_rhs_literals_in_gate (other, g)) + if (lit == other) + return true; + return false; +} + +static bool rewriting_lhs (closure *closure, gate *g, unsigned dst) { +#ifndef NDEBUG + kissat *const solver = closure->solver; +#endif + if (dst != g->lhs && dst != NOT (g->lhs)) + return false; + mark_gate_as_garbage (closure, g); + return true; +} + +static void shrink_and_gate (closure *closure, gate *g, + unsigned *new_end_rhs, unsigned falsifies, + unsigned clashing) { + assert (g->tag == AND_GATE); +#ifndef NDEBUG + kissat *const solver = closure->solver; +#endif + if (falsifies != INVALID_LIT) { + assert (g->arity); + g->rhs[0] = falsifies; + new_end_rhs = g->rhs + 1; + } else if (clashing != INVALID_LIT) { + assert (1 < g->arity); + g->rhs[0] = clashing; + g->rhs[1] = NOT (clashing); + new_end_rhs = g->rhs + 2; + } + shrink_gate (closure, g, new_end_rhs); +} + +static void update_and_gate (closure *closure, gate *g, unsigned falsifies, + unsigned clashing) { + assert (g->tag == AND_GATE); + bool garbage = true; + kissat *const solver = closure->solver; + if (falsifies != INVALID_LIT || clashing != INVALID_LIT) + (void) learn_congruence_unit (closure, NOT (g->lhs)); + else if (g->arity == 1) { + const value value_lhs = VALUE (g->lhs); + if (value_lhs > 0) + (void) learn_congruence_unit (closure, g->rhs[0]); + else if (value_lhs < 0) + (void) learn_congruence_unit (closure, NOT (g->rhs[0])); + else if (merge_literals (closure, g->lhs, g->rhs[0])) { + INC (congruent_unary_ands); + INC (congruent_unary); + } + } else { + unsigned hash; + gate *h = find_and_gate (closure, &hash, g); + if (h) { + assert (garbage); + if (merge_literals (closure, g->lhs, h->lhs)) + INC (congruent_ands); + } else { + remove_gate (closure, g); + g->hash = hash; + index_gate (closure, g); + garbage = false; + } + } + if (garbage && !solver->inconsistent) + mark_gate_as_garbage (closure, g); +} + +static void simplify_and_gate (closure *closure, gate *g) { + if (skip_and_gate (closure, g)) + return; + kissat *const solver = closure->solver; + const value *const values = solver->values; + CLOGANDGATE (g, "simplifying"); + const unsigned old_arity = g->arity; + unsigned *const rhs = g->rhs; + unsigned *const end_of_rhs = rhs + old_arity; + const unsigned *p = rhs; + unsigned *q = rhs; + unsigned falsifies = INVALID_LIT; + while (p != end_of_rhs) { + const unsigned lit = *p++; + const value value = values[lit]; + if (value > 0) + continue; + if (value < 0) { + LOG ("found falsifying literal %s", LOGLIT (lit)); + falsifies = lit; + continue; + } + *q++ = lit; + } + shrink_and_gate (closure, g, q, falsifies, INVALID_LIT); + CLOGANDGATE (g, "simplified"); + check_and_gate_implied (closure, g); + update_and_gate (closure, g, falsifies, INVALID_LIT); + INC (congruent_simplified); + INC (congruent_simplified_ands); +} + +static void rewrite_and_gate (closure *closure, gate *g, unsigned dst, + unsigned src) { + if (skip_and_gate (closure, g)) + return; + if (!gate_contains (g, src)) + return; + assert (src != INVALID_LIT); + assert (dst != INVALID_LIT); + kissat *const solver = closure->solver; + const value *const values = solver->values; + assert (values[src] == values[dst]); + CLOGANDGATE (g, "rewriting %s by %s in", CLOGREPR (src), CLOGREPR (dst)); + const unsigned old_arity = g->arity; + const unsigned not_lhs = NOT (g->lhs); + unsigned *const rhs = g->rhs; + unsigned *const end_of_rhs = rhs + old_arity; + const unsigned *p = rhs; + unsigned *q = rhs; + unsigned falsifies = INVALID_LIT; + unsigned clashing = INVALID_LIT; + const unsigned not_dst = NOT (dst); + unsigned dst_count = 0, not_dst_count = 0; + while (p != end_of_rhs) { + unsigned lit = *p++; + if (lit == src) + lit = dst; + if (lit == not_lhs) { + LOG ("found negated LHS literal %s", LOGLIT (lit)); + clashing = lit; + break; + } + const value value = values[lit]; + if (value > 0) + continue; + if (value < 0) { + LOG ("found falsifying literal %s", LOGLIT (lit)); + falsifies = lit; + break; + } + if (lit == dst) { + if (not_dst_count) { + LOG ("clashing literals %s and %s", LOGLIT (not_dst), LOGLIT (dst)); + clashing = not_dst; + break; + } + if (dst_count++) + continue; + } + if (lit == not_dst) { + if (dst_count) { + assert (!not_dst_count); + LOG ("clashing literals %s and %s", LOGLIT (dst), LOGLIT (not_dst)); + clashing = dst; + break; + } + assert (!not_dst_count); + not_dst_count++; + } + *q++ = lit; + } + assert (dst_count <= 2); + assert (not_dst_count <= 1); + shrink_and_gate (closure, g, q, falsifies, clashing); + CLOGANDGATE (g, "rewritten"); + check_and_gate_implied (closure, g); + update_and_gate (closure, g, falsifies, clashing); + INC (congruent_rewritten); + INC (congruent_rewritten_ands); +} + +static bool skip_xor_gate (gate *g) { + assert (g->tag == XOR_GATE); + if (g->garbage) + return true; + assert (g->arity > 1); + return false; +} + +#ifdef CHECKING_OR_PROVING + +static void add_xor_shrinking_proof_chain (closure *closure, gate *g, + unsigned pivot) { + kissat *const solver = closure->solver; + if (!kissat_checking_or_proving (solver)) + return; + LOG ("starting XOR shrinking proof chain"); + unsigneds *clause = &solver->clause; + assert (EMPTY_STACK (*clause)); + for (unsigned i = 0; i != g->arity; i++) { + unsigned lit = g->rhs[i]; + PUSH_STACK (*clause, lit); + } + const unsigned lhs = g->lhs; + const unsigned not_lhs = NOT (lhs); + PUSH_STACK (*clause, not_lhs); + const unsigned parity = NEGATED (not_lhs); + assert (parity == parity_lits (solver, clause)); + const unsigned not_pivot = NOT (pivot); + const size_t size = SIZE_STACK (*clause); + assert (size < 32); + const unsigned end = 1u << size; + for (unsigned i = 0; i != end; i++) { + while (i && parity != parity_lits (solver, clause)) + inc_lits (solver, clause); + PUSH_STACK (*clause, pivot); + CHECK_AND_ADD_STACK (*clause); + ADD_STACK_TO_PROOF (*clause); + clause->end--; + PUSH_STACK (*clause, not_pivot); + CHECK_AND_ADD_STACK (*clause); + ADD_STACK_TO_PROOF (*clause); + clause->end--; + CHECK_AND_ADD_STACK (*clause); + ADD_STACK_TO_PROOF (*clause); + PUSH_STACK (*clause, pivot); + REMOVE_CHECKER_STACK (*clause); + DELETE_STACK_FROM_PROOF (*clause); + clause->end--; + PUSH_STACK (*clause, not_pivot); + REMOVE_CHECKER_STACK (*clause); + DELETE_STACK_FROM_PROOF (*clause); + clause->end--; + inc_lits (solver, clause); + } + CLEAR_STACK (*clause); + LOG ("finished XOR shrinking proof chain"); +} + +#else + +#define add_xor_shrinking_proof_chain(...) \ + do { \ + } while (0) +#endif + +static void shrink_xor_gate (closure *closure, gate *g, + unsigned *new_end_rhs) { + assert (g->tag == XOR_GATE); + shrink_gate (closure, g, new_end_rhs); +} + +static void update_xor_gate (closure *closure, gate *g) { + assert (g->tag == XOR_GATE); + kissat *const solver = closure->solver; + bool garbage = true; + if (g->arity == 0) + (void) learn_congruence_unit (closure, NOT (g->lhs)); + else if (g->arity == 1) { + const value value_lhs = VALUE (g->lhs); + if (value_lhs > 0) + (void) learn_congruence_unit (closure, g->rhs[0]); + else if (value_lhs < 0) + (void) learn_congruence_unit (closure, NOT (g->rhs[0])); + else if (merge_literals (closure, g->lhs, g->rhs[0])) { + INC (congruent_unary_xors); + INC (congruent_unary); + } + } else { + assert (g->arity > 1); + unsigned hash; + gate *h = find_xor_gate (closure, &hash, g); + if (h) { + assert (garbage); + add_xor_matching_proof_chain (closure, g, g->lhs, h->lhs); + if (merge_literals (closure, g->lhs, h->lhs)) + INC (congruent_xors); + if (!solver->inconsistent) + delete_proof_chain (closure); + } else { + remove_gate (closure, g); + g->hash = hash; + index_gate (closure, g); + garbage = false; + } + } + if (garbage && !solver->inconsistent) + mark_gate_as_garbage (closure, g); +} + +static void simplify_xor_gate (closure *closure, gate *g) { + if (skip_xor_gate (g)) + return; + kissat *const solver = closure->solver; + const value *const values = solver->values; + CLOGXORGATE (g, "simplifying"); + unsigned *q = g->rhs, *const end_of_rhs = q + g->arity; + unsigned negate = 0; + for (const unsigned *p = q; p != end_of_rhs; p++) { + const unsigned lit = *p; + assert (!NEGATED (lit)); + const value value = values[lit]; + if (value > 0) + negate ^= 1; + if (!value) + *q++ = lit; + } + if (negate) { + LOG ("flipping LHS literal %s", LOGLIT (g->lhs)); + g->lhs = NOT (g->lhs); + } + shrink_xor_gate (closure, g, q); + update_xor_gate (closure, g); + CLOGXORGATE (g, "simplified"); + check_xor_gate_implied (closure, g); + INC (congruent_simplified); + INC (congruent_simplified_xors); +} + +static void rewrite_xor_gate (closure *closure, gate *g, unsigned dst, + unsigned src) { + if (skip_xor_gate (g)) + return; + if (rewriting_lhs (closure, g, dst)) + return; + if (!gate_contains (g, src)) + return; + kissat *const solver = closure->solver; + CLOGXORGATE (g, "rewriting %s by %s in", CLOGREPR (src), CLOGREPR (dst)); + const value *const values = solver->values; + unsigned *q = g->rhs, *end_of_rhs = q + g->arity; + unsigned original_dst_negated = NEGATED (dst); + unsigned negate = original_dst_negated; + unsigned dst_count = 0; + dst = STRIP (dst); + for (const unsigned *p = q; p != end_of_rhs; p++) { + unsigned lit = *p; + assert (!NEGATED (lit)); + if (lit == src) + lit = dst; + const value value = values[lit]; + if (value > 0) + negate ^= 1; + if (value) + continue; + if (lit == dst) + dst_count++; + *q++ = lit; + } + if (negate) { + LOG ("flipping LHS literal %s", LOGLIT (g->lhs)); + g->lhs = NOT (g->lhs); + } + assert (dst_count <= 2); + if (dst_count == 2) { + CLOGXORGATE (g, "literals %s and %s were both in", LOGLIT (src), + LOGLIT (dst)); + end_of_rhs = q; + q = g->rhs; + for (const unsigned *p = q; p != end_of_rhs; p++) { + const unsigned lit = *p; + if (lit != dst) + *q++ = lit; + } + assert (q + 2 == end_of_rhs); + } + shrink_xor_gate (closure, g, q); + CLOGXORGATE (g, "rewritten"); + if (dst_count > 1) + add_xor_shrinking_proof_chain (closure, g, src); + update_xor_gate (closure, g); + if (!g->garbage && !solver->inconsistent && original_dst_negated && + dst_count == 1) { + assert (!NEGATED (dst)); + connect_occurrence (closure, dst, g); + } + check_xor_gate_implied (closure, g); + INC (congruent_rewritten); + INC (congruent_rewritten_xors); +} + +static bool skip_ite_gate (gate *g) { + assert (g->tag == ITE_GATE); + if (g->garbage) + return true; + return false; +} + +static void simplify_ite_gate (closure *closure, gate *g) { + if (skip_ite_gate (g)) + return; + kissat *const solver = closure->solver; + const value *const values = solver->values; + CLOGITEGATE (g, "simplifying"); + assert (g->arity == 3); + bool garbage = true; + const unsigned lhs = g->lhs; + unsigned *const rhs = g->rhs; + const unsigned cond = rhs[0]; + const unsigned then_lit = rhs[1]; + const unsigned else_lit = rhs[2]; + const value cond_value = values[cond]; + if (cond_value > 0) { + if (merge_literals (closure, lhs, then_lit)) { + INC (congruent_unary_ites); + INC (congruent_unary); + } + } else if (cond_value < 0) { + if (merge_literals (closure, lhs, else_lit)) { + INC (congruent_unary_ites); + INC (congruent_unary); + } + } else { + const value then_value = values[then_lit]; + const value else_value = values[else_lit]; + const unsigned not_lhs = NOT (lhs); + assert (then_value || else_value); + if (then_value > 0 && else_value > 0) + learn_congruence_unit (closure, lhs); + else if (then_value < 0 && else_value < 0) + learn_congruence_unit (closure, not_lhs); + else if (then_value > 0 && else_value < 0) { + if (merge_literals (closure, lhs, cond)) { + INC (congruent_unary_ites); + INC (congruent_unary); + } + } else if (then_value < 0 && else_value > 0) { + const unsigned not_cond = NOT (cond); + if (merge_literals (closure, lhs, not_cond)) { + INC (congruent_unary_ites); + INC (congruent_unary); + } + } else { + assert (!!else_value + !!then_value == 1); + if (then_value > 0) { + assert (!else_value); + g->lhs = not_lhs; + rhs[0] = NOT (cond); + rhs[1] = NOT (else_lit); + } else if (then_value < 0) { + assert (!else_value); + rhs[0] = NOT (cond); + rhs[1] = else_lit; + } else if (else_value > 0) { + assert (!then_value); + g->lhs = not_lhs; + rhs[0] = NOT (then_lit); + rhs[1] = cond; + } else { + assert (else_value < 0); + assert (!then_value); + rhs[0] = cond; + rhs[1] = then_lit; + } + if (rhs[0] > rhs[1]) + SWAP (unsigned, rhs[0], rhs[1]); + assert (!g->shrunken); + g->shrunken = true; + rhs[2] = INVALID_LIT; + g->arity = 2; + g->tag = AND_GATE; + assert (rhs[0] < rhs[1]); + assert (rhs[0] != NOT (rhs[1])); + CLOGANDGATE (g, "simplified"); + check_and_gate_implied (closure, g); + unsigned hash; + gate *h = find_and_gate (closure, &hash, g); + if (h) { + assert (garbage); + if (merge_literals (closure, g->lhs, h->lhs)) + INC (congruent_ands); + } else { + remove_gate (closure, g); + g->hash = hash; + index_gate (closure, g); + garbage = false; + for (all_rhs_literals_in_gate (lit, g)) + if (lit != cond && lit != then_lit && lit != else_lit) + connect_occurrence (closure, lit, g); + } + } + } + if (garbage && !solver->inconsistent) + mark_gate_as_garbage (closure, g); + INC (congruent_simplified); + INC (congruent_simplified_ites); +} + +static void rewrite_ite_gate (closure *closure, gate *g, unsigned dst, + unsigned src) { + if (skip_ite_gate (g)) + return; + if (!gate_contains (g, src)) + return; + kissat *const solver = closure->solver; + CLOGITEGATE (g, "rewriting %s by %s in", CLOGREPR (src), CLOGREPR (dst)); + unsigned *const rhs = g->rhs; + assert (g->arity == 3); + const unsigned lhs = g->lhs; + const unsigned cond = rhs[0]; + const unsigned then_lit = rhs[1]; + const unsigned else_lit = rhs[2]; + const unsigned not_lhs = NOT (lhs); + const unsigned not_dst = NOT (dst); + const unsigned not_cond = NOT (cond); + const unsigned not_then_lit = NOT (then_lit); + const unsigned not_else_lit = NOT (else_lit); + unsigned new_tag = AND_GATE; + bool garbage = false; + bool shrink = true; + if (src == cond) { + if (dst == then_lit) { + // then_lit ? then_lit : else_lit + // then_lit & then_lit | !then_lit & else_lit + // then_lit | !then_lit & else_lit + // then_lit | else_lit + // !(!then_lit & !else_lit) + g->lhs = not_lhs; + rhs[0] = not_then_lit; + rhs[1] = not_else_lit; + } else if (not_dst == then_lit) { + // !then_lit ? then_lit : else_lit + // !then_lit & then_lit | then_lit & else_lit + // then_lit & else_lit + rhs[0] = else_lit; + assert (rhs[1] == then_lit); + } else if (dst == else_lit) { + // else_list ? then_lit : else_lit + // else_list & then_lit | !else_list & else_lit + // else_list & then_lit + rhs[0] = else_lit; + assert (rhs[1] == then_lit); + } else if (not_dst == else_lit) { + // !else_list ? then_lit : else_lit + // !else_list & then_lit | else_lit & else_lit + // !else_list & then_lit | else_lit + // then_lit | else_lit + // !(!then_lit & !else_lit) + g->lhs = not_lhs; + rhs[0] = not_then_lit; + rhs[1] = not_else_lit; + } else { + shrink = false; + rhs[0] = dst; + } + } else if (src == then_lit) { + if (dst == cond) { + // cond ? cond : else_lit + // cond & cond | !cond & else_lit + // cond | !cond & else_lit + // cond | else_lit + // !(!cond & !else_lit) + g->lhs = not_lhs; + rhs[0] = not_cond; + rhs[1] = not_else_lit; + } else if (not_dst == cond) { + // cond ? !cond : else_lit + // cond & !cond | !cond & else_lit + // !cond & else_lit + rhs[0] = not_cond; + rhs[1] = else_lit; + } else if (dst == else_lit) { + // cond ? else_lit : else_lit + // else_lit + if (merge_literals (closure, lhs, else_lit)) { + INC (congruent_unary_ites); + INC (congruent_unary); + } + garbage = true; + } else if (not_dst == else_lit) { + // cond ? !else_lit : else_lit + // cond & !else_lit | !cond & else_lit + // cond ^ else_lit + new_tag = XOR_GATE; + assert (rhs[0] == cond); + rhs[1] = else_lit; + } else { + shrink = false; + rhs[1] = dst; + } + } else { + assert (src == else_lit); + if (dst == cond) { + // cond ? then_lit : cond + // cond & then_lit | !cond & cond + // cond & then_lit + assert (rhs[0] == cond); + assert (rhs[1] == then_lit); + } else if (not_dst == cond) { + // cond ? then_lit : !cond + // cond & then_lit | !cond & !cond + // cond & then_lit | !cond + // then_lit | !cond + // !(!then_lit & cond) + g->lhs = not_lhs; + assert (rhs[0] == cond); + rhs[1] = not_then_lit; + } else if (dst == then_lit) { + // cond ? then_lit : then_lit + // then_lit + if (merge_literals (closure, lhs, then_lit)) { + INC (congruent_unary_ites); + INC (congruent_unary); + } + garbage = true; + } else if (not_dst == then_lit) { + // cond ? then_lit : !then_lit + // cond & then_lit | !cond & !then_lit + // !(cond ^ then_lit) + new_tag = XOR_GATE; + g->lhs = not_lhs; + assert (rhs[0] == cond); + assert (rhs[1] == then_lit); + } else { + shrink = false; + rhs[2] = dst; + } + } + if (!garbage) { + if (shrink) { + if (rhs[0] > rhs[1]) + SWAP (unsigned, rhs[0], rhs[1]); + if (new_tag == XOR_GATE) { + bool negate_lhs = false; + if (NEGATED (rhs[0])) { + rhs[0] = NOT (rhs[0]); + negate_lhs = !negate_lhs; + } + if (NEGATED (rhs[1])) { + rhs[1] = NOT (rhs[1]); + negate_lhs = !negate_lhs; + } + if (negate_lhs) + g->lhs = NOT (g->lhs); + } + assert (!g->shrunken); + g->shrunken = true; + rhs[2] = INVALID_LIT; + g->arity = 2; + g->tag = new_tag; + assert (rhs[0] < rhs[1]); + assert (rhs[0] != NOT (rhs[1])); + LOGATE (g, "rewritten"); + gate *h; + unsigned hash; + if (new_tag == AND_GATE) { + check_and_gate_implied (closure, g); + h = find_and_gate (closure, &hash, g); + } else { + assert (new_tag == XOR_GATE); + check_xor_gate_implied (closure, g); + h = find_xor_gate (closure, &hash, g); + } + if (h) { + garbage = true; + if (new_tag == XOR_GATE) + add_xor_matching_proof_chain (closure, g, g->lhs, h->lhs); + else + add_ite_turned_and_binary_clauses (closure, g); + if (merge_literals (closure, g->lhs, h->lhs)) + INC (congruent_ands); + if (!solver->inconsistent) + delete_proof_chain (closure); + } else { + garbage = false; + remove_gate (closure, g); + g->hash = hash; + index_gate (closure, g); + assert (g->arity == 2); + for (all_rhs_literals_in_gate (lit, g)) + if (lit != dst) + if (lit != cond && lit != then_lit && lit != else_lit) + connect_occurrence (closure, lit, g); + if (g->tag == AND_GATE) + for (all_rhs_literals_in_gate (lit, g)) + add_binary_clause (closure, NOT (g->lhs), lit); + } + } else { + CLOGITEGATE (g, "rewritten"); + assert (rhs[0] != rhs[1]); + assert (rhs[0] != rhs[2]); + assert (rhs[1] != rhs[2]); + assert (rhs[0] != NOT (rhs[1])); + assert (rhs[0] != NOT (rhs[2])); + assert (rhs[1] != NOT (rhs[2])); + check_ite_gate_implied (closure, g); + unsigned hash; + bool negate_lhs; + gate *h = find_ite_gate (closure, &hash, &negate_lhs, g); + assert (lhs == g->lhs); + assert (not_lhs == NOT (g->lhs)); + if (h) { + garbage = true; + unsigned normalized_lhs = negate_lhs ? not_lhs : lhs; + add_ite_matching_proof_chain (closure, h, h->lhs, normalized_lhs); + if (merge_literals (closure, h->lhs, normalized_lhs)) + INC (congruent_ites); + if (!solver->inconsistent) + delete_proof_chain (closure); + } else { + garbage = false; + remove_gate (closure, g); + if (negate_lhs) + g->lhs = not_lhs; + CLOGITEGATE (g, "normalized"); + g->hash = hash; + index_gate (closure, g); + assert (g->arity == 3); + for (all_rhs_literals_in_gate (lit, g)) + if (lit != dst) + if (lit != cond && lit != then_lit && lit != else_lit) + connect_occurrence (closure, lit, g); + } + } + } + if (garbage && !solver->inconsistent) + mark_gate_as_garbage (closure, g); + INC (congruent_rewritten); + INC (congruent_rewritten_ites); +} + +static bool simplify_gate (closure *closure, gate *g) { + if (g->tag == AND_GATE) + simplify_and_gate (closure, g); + else if (g->tag == XOR_GATE) + simplify_xor_gate (closure, g); + else + simplify_ite_gate (closure, g); + return !closure->solver->inconsistent; +} + +static bool rewrite_gate (closure *closure, gate *g, unsigned dst, + unsigned src) { + if (g->tag == AND_GATE) + rewrite_and_gate (closure, g, dst, src); + else if (g->tag == XOR_GATE) + rewrite_xor_gate (closure, g, dst, src); + else + rewrite_ite_gate (closure, g, dst, src); + return !closure->solver->inconsistent; +} + +struct offsetsize { + unsigned offset, size; +}; + +typedef struct offsetsize offsetsize; + +#define RANK_OTHER(A) ((A).lits[1]) +#define LESS_OTHER(A, B) (RANK_OTHER (A) < RANK_OTHER (B)) + +static bool find_binary (kissat *solver, litpair *binaries, + offsetsize *offsetsize, unsigned lit, + unsigned other) { + assert (lit != other); + if (lit > other) + SWAP (unsigned, lit, other); + size_t l = offsetsize[lit].offset; + size_t r = l + offsetsize[lit].size; + while (l < r) { + const size_t m = (l + r) / 2; + const unsigned tmp = binaries[m].lits[1]; + if (tmp < other) + l = m + 1; + else if (tmp > other) + r = m; + else { + assert (binaries[m].lits[0] == lit); + assert (binaries[m].lits[1] == other); +#ifdef LOGGING + LOGBINARY (lit, other, "found"); +#else + (void) solver; +#endif + return true; + } + } + return false; +} + +static uint64_t rank_litpair (litpair p) { + uint64_t res = p.lits[0]; + res <<= 32; + res += p.lits[1]; + return res; +} + +static void extract_binaries (closure *closure) { + kissat *const solver = closure->solver; + if (!GET_OPTION (congruencebinaries)) + return; + START (extractbinaries); + litpair *binaries = BEGIN_STACK (closure->binaries); + offsetsize *offsetsize; + CALLOC (offsetsize, LITS); + { + litpair *end = END_STACK (closure->binaries); + litpair *p = binaries; + while (p != end) { + litpair *q = p + 1; + const unsigned lit = p->lits[0]; + while (q != end && q->lits[0] == lit) + q++; + const size_t size = q - p; + assert (size), assert (size <= UINT_MAX); + const size_t offset = p - binaries; + if (size < 32) + SORT (litpair, size, p, LESS_OTHER); + else + RADIX_SORT (litpair, unsigned, size, p, RANK_OTHER); + offsetsize[lit].offset = offset; + offsetsize[lit].size = size; + p = q; + } + } + clause *last_irredundant = kissat_last_irredundant_clause (solver); + const size_t before = SIZE_STACK (closure->binaries); + size_t extracted = 0, duplicated = 0; + const value *const values = solver->values; + for (all_clauses (d)) { + if (d->garbage) + continue; + if (last_irredundant && last_irredundant < d) + break; + if (d->redundant) + continue; + if (d->size != 3) + continue; + const unsigned *lits = d->lits; + const unsigned a = lits[0]; + if (values[a]) + continue; + const unsigned b = lits[1]; + if (values[b]) + continue; + const unsigned c = lits[2]; + if (values[c]) + continue; + const unsigned not_a = NOT (a); + const unsigned not_b = NOT (b); + const unsigned not_c = NOT (c); + unsigned l = INVALID_LIT, k = INVALID_LIT; + if (find_binary (solver, binaries, offsetsize, not_a, b) || + find_binary (solver, binaries, offsetsize, not_a, c)) + l = b, k = c; + else if (find_binary (solver, binaries, offsetsize, not_b, a) || + find_binary (solver, binaries, offsetsize, not_b, c)) + l = a, k = c; + else if (find_binary (solver, binaries, offsetsize, not_c, a) || + find_binary (solver, binaries, offsetsize, not_c, b)) + l = a, k = b; + else + continue; + LOGCLS (d, "strengthening"); + if (!find_binary (solver, binaries, offsetsize, l, k)) { + LOGBINARY (l, k, "strengthened"); + add_binary_clause (closure, l, k); + binaries = BEGIN_STACK (closure->binaries); + extracted++; + } + } + DEALLOC (offsetsize, LITS); + { + litpair *end = END_STACK (closure->binaries); + litpair *added = binaries + before; +#ifndef NDEBUG + const size_t after = end - binaries; + assert (after - before == extracted); +#endif + RADIX_SORT (litpair, uint64_t, extracted, added, rank_litpair); + litpair *q = added; + unsigned prev_lit = INVALID_LIT; + unsigned prev_other = INVALID_LIT; + for (const litpair *p = q; p != end; p++) { + const litpair pair = *p; + const unsigned lit = pair.lits[0]; + const unsigned other = pair.lits[1]; + if (p == added || lit != prev_lit || other != prev_other) { + q->lits[0] = lit; + q->lits[1] = other; + prev_lit = lit; + prev_other = other; + q++; + } else { + duplicated++; + LOGBINARY (lit, other, "removing duplicated"); + kissat_delete_binary (solver, lit, other); + } + } + SET_END_OF_STACK (closure->binaries, q); + } + ADD (congruent_binaries, extracted - duplicated); + kissat_verbose (solver, "extracted %zu binaries (plus %zu duplicated)", + extracted, duplicated); + STOP (extractbinaries); +} + +#ifndef INDEX_BINARY_CLAUSES + +static gate *find_first_and_gate (closure *closure, unsigned lhs, + unsigneds *lits) { + kissat *const solver = closure->solver; + assert (!solver->watching); + mark *const marks = solver->marks; + + const unsigned not_lhs = NOT (lhs); + LOG ("trying to find AND gate with first LHS %s", LOGLIT (lhs)); + LOG ("negated LHS %s occurs in %u binary clauses", LOGLIT (not_lhs), + closure->negbincount[lhs]); + + unsigneds *const marked = &solver->analyzed; + assert (EMPTY_STACK (*marked)); + + const unsigned arity = SIZE_STACK (*lits) - 1; + unsigned matched = 0; + assert (1 < arity); + + watches *watches = &WATCHES (not_lhs); + const watch *const end = END_WATCHES (*watches); + const watch *p = BEGIN_WATCHES (*watches); + + while (p != end) { + const watch watch = *p++; + assert (watch.type.binary); + const unsigned other = watch.binary.lit; + const mark tmp = marks[other]; + if (tmp) { + matched++; + assert (~(tmp & 2)); + marks[other] |= 2; + PUSH_STACK (*marked, other); + } + } + + LOG ("found %zu initial LHS candidates", SIZE_STACK (*marked)); + if (matched < arity) + return 0; + + return new_and_gate (closure, lhs); +} + +static gate *find_remaining_and_gate (closure *closure, unsigned lhs, + unsigneds *lits) { + kissat *const solver = closure->solver; + assert (!solver->watching); + mark *const marks = solver->marks; + const unsigned not_lhs = NOT (lhs); + + if (marks[not_lhs] < 2) { + LOG ("skipping no-candidate LHS %s", LOGLIT (lhs)); + return false; + } + + LOG ("trying to find AND gate with remaining LHS %s", LOGLIT (lhs)); + LOG ("negated LHS %s occurs times in %u binary clauses", LOGLIT (not_lhs), + closure->negbincount[lhs]); + + const unsigned arity = SIZE_STACK (*lits) - 1; + unsigned matched = 0; + assert (1 < arity); + + { + watches *watches = &WATCHES (not_lhs); + const watch *const end_watches = END_WATCHES (*watches); + const watch *p = BEGIN_WATCHES (*watches); + while (p != end_watches) { + const watch watch = *p++; + assert (watch.type.binary); + const unsigned other = watch.binary.lit; + mark mark = marks[other]; + if (!mark) + continue; + matched++; + if (!(mark & 2)) + continue; + assert (!(mark & 4)); + marks[other] = mark | 4; + } + } + + { + unsigneds *const marked = &solver->analyzed; + assert (!EMPTY_STACK (*marked)); + unsigned *const begin_marked = BEGIN_STACK (*marked); + const unsigned *const end_marked = END_STACK (*marked); + unsigned *q = begin_marked; + const unsigned *p = q; + assert (marks[not_lhs] == 3); + while (p != end_marked) { + const unsigned lit = *p++; + if (lit == not_lhs) { + marks[not_lhs] = 1; + continue; + } + mark mark = marks[lit]; + assert ((mark & 3) == 3); + if (mark & 4) { + mark = 3; + *q++ = lit; + LOG2 ("keeping LHS candidate %s", LOGLIT (NOT (lit))); + } else { + LOG2 ("dropping LHS candidate %s", LOGLIT (NOT (lit))); + mark = 1; + } + marks[lit] = mark; + } + assert (q != end_marked); + assert (marks[not_lhs] == 1); + SET_END_OF_STACK (*marked, q); + LOG ("after filtering %zu LHS candidates remain", SIZE_STACK (*marked)); + } + + if (matched < arity) + return 0; + + return new_and_gate (closure, lhs); +} + +#endif + +static inline bool smaller_negated_bin_count (const unsigned *negbincount, + unsigned a, unsigned b) { + unsigned c = negbincount[a]; + unsigned d = negbincount[b]; + if (c < d) + return true; + if (c > d) + return false; + return a < b; +} + +#define SMALLER_NEGATED_BIN_COUNT(A, B) \ + smaller_negated_bin_count (negbincount, A, B) + +static void sort_lits_by_negbincount (closure *closure, size_t size, + unsigned *lits) { + const unsigned *const negbincount = closure->negbincount; + kissat *const solver = closure->solver; + SORT (unsigned, size, lits, SMALLER_NEGATED_BIN_COUNT); +} + +#ifdef INDEX_BINARY_CLAUSES + +static unsigned hash_binary (closure *closure, binary_clause *binary) { + return hash_lits (closure, 0, 2, binary->lits); +} + +static bool indexed_binary (closure *closure, unsigned lit, + unsigned other) { + assert (lit != other); +#ifdef LOGGING + kissat *const solver = closure->solver; +#endif + binary_hash_table *bintab = &closure->bintab; + if (!bintab->count) { + LOG ("did not find binary %s %s", LOGLIT (lit), LOGLIT (other)); + return false; + } + assert (bintab->size); + SWAP (unsigned, lit, other); + if (lit > other) + SWAP (unsigned, lit, other); + binary_clause binary = {.lits = {lit, other}}; + const unsigned hash = hash_binary (closure, &binary); + const size_t size = bintab->size; + const size_t size2 = bintab->size2; + size_t pos = reduce_hash (hash, size, size2); + binary_clause *table = bintab->table; + unsigned lit0, lit1; + while ((lit1 = table[pos].lits[1])) { + if (lit1 == other) { + lit0 = table[pos].lits[0]; + assert (lit0 < other); + if (lit0 == lit) { + LOG ("found binary %s %s", LOGLIT (lit), LOGLIT (other)); + return true; + } + } + if (++pos == size) + pos = 0; + } + LOG ("did not find binary %s %s", LOGLIT (lit), LOGLIT (other)); + return false; +} + +#endif + +static void extract_and_gates_with_base_clause (closure *closure, + clause *c) { + assert (!c->garbage); + kissat *const solver = closure->solver; + assert (!solver->inconsistent); + value *values = solver->values; + unsigned arity_limit = MIN (GET_OPTION (congruenceandarity), MAX_ARITY); + const unsigned size_limit = arity_limit + 1; + const unsigned *const negbincount = closure->negbincount; + unsigneds *lits = &closure->lits; + unsigned size = 0, max_negbincount = 0; + CLEAR_STACK (*lits); + for (all_literals_in_clause (lit, c)) { + value value = values[lit]; + if (value < 0) + continue; + if (value > 0) { + assert (!solver->level); + LOGCLS (c, "found satisfied %s in", LOGLIT (lit)); + kissat_mark_clause_as_garbage (solver, c); + return; + } + if (++size > size_limit) { + LOGCLS (c, "too large actual size %u thus skipping", size); + return; + } + const unsigned count = negbincount[lit]; + if (!count) { + LOGCLS (c, + "%s negated does not occur in any binary clause " + "thus skipping", + LOGLIT (lit)); + return; + } + if (count > max_negbincount) + max_negbincount = count; + PUSH_STACK (*lits, lit); + } + if (size < 3) { + LOGCLS (c, "actual size %u too small thus skipping", size); + return; + } + const unsigned arity = size - 1; + if (max_negbincount < arity) { + LOGCLS (c, + "all literals have less than %u negated occurrences " + "thus skipping", + arity); + return; + } + unsigned *begin_lits = BEGIN_STACK (*lits), *reduced_lits = begin_lits; + LOGCOUNTEDLITS (size, begin_lits, negbincount, + "counted candidate arity %u AND gate base clause", arity); + const unsigned *const end_lits = END_STACK (*lits); +#ifndef INDEX_BINARY_CLAUSES + mark *const marks = solver->marks; + unsigneds *marked = &solver->analyzed; + assert (EMPTY_STACK (*marked)); +#endif + for (unsigned *p = begin_lits; p != end_lits; p++) { + const unsigned lit = *p, count = negbincount[lit]; +#ifndef INDEX_BINARY_CLAUSES + const unsigned not_lit = NOT (lit); + marks[not_lit] = 1; +#endif + if (count < arity) { + if (reduced_lits < p) + *p = *reduced_lits, *reduced_lits++ = lit; + else if (reduced_lits == p) + reduced_lits++; + } + } + assert (reduced_lits < end_lits); + const size_t reduced_size = end_lits - reduced_lits; + assert (reduced_size); + LOGCLS (c, "trying as base arity %u AND gate", arity); + sort_lits_by_negbincount (closure, reduced_size, reduced_lits); +#ifdef LOGGING + if (begin_lits < reduced_lits) { + LOGCOUNTEDLITS (reduced_lits - begin_lits, begin_lits, negbincount, + "skipping low occurrence"); + LOGCOUNTEDLITS (reduced_size, reduced_lits, negbincount, + "remaining LHS candidate"); + } else + LOGCOUNTEDLITS (reduced_size, reduced_lits, negbincount, + "all remain LHS candidate"); +#endif +#ifdef LOGGING + unsigned extracted = 0; +#endif +#ifndef INDEX_BINARY_CLAUSES + bool first = true; +#endif + for (unsigned *p = reduced_lits; p != end_lits; p++) { + if (solver->inconsistent) + break; + if (c->garbage) + break; + const unsigned lhs = *p; + LOG ("trying LHS candidate literal %s with %u negated occurrences", + LOGLIT (lhs), negbincount[lhs]); + assert (arity <= negbincount[lhs]); +#ifdef INDEX_BINARY_CLAUSES + const unsigned not_lhs = NOT (lhs); + for (const unsigned *q = begin_lits; q != end_lits; q++) + if (p != q) { + const unsigned rhs = *q, not_rhs = NOT (rhs); + if (!indexed_binary (closure, not_lhs, not_rhs)) + goto CONTINUE_WITH_NEXT_LHS; + } + (void) new_and_gate (closure, lhs); +#ifdef LOGGING + extracted++; +#endif + CONTINUE_WITH_NEXT_LHS:; +#else + if (first) { + first = false; + assert (EMPTY_STACK (*marked)); + if (find_first_and_gate (closure, lhs, lits)) { +#ifdef LOGGING + extracted++; +#endif + } + } else if (EMPTY_STACK (*marked)) { + LOG ("early abort AND gate search"); + break; + } else if (find_remaining_and_gate (closure, lhs, lits)) { +#ifdef LOGGING + extracted++; +#endif + } +#endif + } +#ifndef INDEX_BINARY_CLAUSES + for (const unsigned *p = begin_lits; p != end_lits; p++) { + const unsigned lit = *p, not_lit = NOT (lit); + marks[not_lit] = 0; + } + CLEAR_STACK (*marked); +#endif +#ifdef LOGGING + if (extracted) + LOGCLS (c, "extracted %u with arity %u AND base", extracted, arity); +#endif +} + +#ifdef INDEX_LARGE_CLAUSES + +static bool valid_large_clause (hash_ref *clause) { + return clause->hash || clause->ref; +} + +static clause *find_indexed_large_clause (closure *closure, + unsigneds *lits) { + kissat *const solver = closure->solver; + size_t size_lits = SIZE_STACK (*lits); + assert (size_lits > 2); +#ifdef LOGGING + { + unsigned *begin = BEGIN_STACK (*lits); + unsigned arity = size_lits - 1; + LOGCOUNTEDLITS (size_lits, begin, closure->largecount, + "trying to find arity %u XOR side clause", arity); + } +#endif + large_clause_hash_table *clauses = &closure->clauses; + if (!clauses->count) + return 0; + const value *const values = solver->values; + mark *const marks = solver->marks; + unsigneds *sorted = &solver->clause; + assert (EMPTY_STACK (*sorted)); + for (all_stack (unsigned, lit, *lits)) { + assert (!values[lit]); + PUSH_STACK (*sorted, lit); + marks[lit] = 1; + } + assert (size_lits == SIZE_STACK (*sorted)); + unsigned *begin_sorted = BEGIN_STACK (*sorted); + sort_lits (solver, size_lits, begin_sorted); + const unsigned hash = hash_lits (closure, 0, size_lits, begin_sorted); + const size_t hash_size = clauses->size; + const size_t hash_size2 = clauses->size2; + size_t pos = reduce_hash (hash, hash_size, hash_size2); + hash_ref *table = clauses->table, *hash_ref; + clause *res = 0; + while (valid_large_clause (hash_ref = table + pos)) { + if (hash_ref->hash == hash) { + reference ref = hash_ref->ref; + if (ref == INVALID_REF) { + assert (!hash); + ref = 0; + } + clause *c = kissat_dereference_clause (solver, ref); + for (all_literals_in_clause (other, c)) + if (!values[other] && !marks[other]) + goto CONTINUE_WITH_NEXT_HASH_BUCKET; + res = c; + break; + } + CONTINUE_WITH_NEXT_HASH_BUCKET: + if (++pos == hash_size) + pos = 0; + } + while (!EMPTY_STACK (*sorted)) { + const unsigned lit = POP_STACK (*sorted); + marks[lit] = 0; + } + if (res) + LOGCLS (res, "found indexed matching XOR side clause"); + else + LOG ("no matching XOR side clause found"); + return res; +} + +#else + +static clause *find_large_xor_side_clause (closure *closure, + unsigneds *lits) { + kissat *const solver = closure->solver; + assert (!solver->watching); + const unsigned *const largecount = closure->largecount; + unsigned least_occurring_literal = INVALID_LIT; + unsigned count_least_occurring = UINT_MAX; + mark *marks = solver->marks; + const size_t size_lits = SIZE_STACK (*lits); +#if defined(LOGGING) || !defined(NDEBUG) + const unsigned arity = size_lits - 1; +#endif +#ifndef NDEBUG + const unsigned count_limit = 1u << (arity - 1); +#endif + const value *const values = solver->values; + LOGCOUNTEDLITS (size_lits, BEGIN_STACK (*lits), largecount, + "trying to find arity %u XOR side clause", arity); + for (all_stack (unsigned, lit, *lits)) { + assert (!values[lit]); + marks[lit] = 1; + unsigned count = largecount[lit]; + assert (count_limit <= count); + if (count >= count_least_occurring) + continue; + count_least_occurring = count; + least_occurring_literal = lit; + } + clause *res = 0; + assert (least_occurring_literal != INVALID_LIT); + LOG ("searching XOR side clause watched by %s#%u", + LOGLIT (least_occurring_literal), count_least_occurring); + watches *const watches = &WATCHES (least_occurring_literal); + watch *p = BEGIN_WATCHES (*watches); + const watch *const end = END_WATCHES (*watches); + while (p != end) { + const watch watch = *p++; + if (watch.type.binary) + break; + const reference ref = watch.large.ref; + clause *const c = kissat_dereference_clause (solver, ref); + if (c->garbage) + continue; + if (c->size < size_lits) + continue; + size_t found = 0; + for (all_literals_in_clause (other, c)) { + const value value = values[other]; + if (value < 0) + continue; + if (value > 0) { + LOGCLS (c, "found satisfied %s in", LOGLIT (other)); + kissat_mark_clause_as_garbage (solver, c); + assert (c->garbage); + break; + } + if (marks[other]) + found++; + else { + found = UINT_MAX; + break; + } + } + if (found < UINT_MAX && !c->garbage) { + res = c; + break; + } + } + for (all_stack (unsigned, lit, *lits)) + marks[lit] = 0; + if (res) + LOGCLS (res, "found matching XOR side"); + else + LOG ("no matching XOR side clause found"); + return res; +} + +#endif + +static void extract_xor_gates_with_base_clause (closure *closure, + clause *c) { + assert (!c->garbage); + kissat *const solver = closure->solver; + assert (!solver->inconsistent); + const value *const values = solver->values; + unsigned smallest = INVALID_LIT, largest = INVALID_LIT; + const unsigned arity_limit = + MIN (GET_OPTION (congruencexorarity), MAX_ARITY); + const unsigned size_limit = arity_limit + 1; + unsigned negated = 0, size = 0; + unsigneds *lits = &closure->lits; + CLEAR_STACK (*lits); + bool first = true; + for (all_literals_in_clause (lit, c)) { + const value value = values[lit]; + if (value < 0) + continue; + if (value > 0) { + LOGCLS (c, "found satisfied %s in", LOGLIT (lit)); + kissat_mark_clause_as_garbage (solver, c); + return; + } + if (size == size_limit) { + LOGCLS (c, "size limit %u for XOR base clause exceeded in", + size_limit); + return; + } + if (first) { + largest = smallest = lit; + first = false; + } else { + assert (smallest != INVALID_LIT); + assert (largest != INVALID_LIT); + if (lit < smallest) + smallest = lit; + if (lit > largest) { + if (NEGATED (largest)) { + LOGCLS (c, "not largest literal %s occurs negated in XOR base", + LOGLIT (largest)); + return; + } + largest = lit; + } + } + if (NEGATED (lit) && lit < largest) { + LOGCLS (c, "negated literal %s not largest in XOR base", + LOGLIT (lit)); + return; + } + if (NEGATED (lit) && negated++) { + LOGCLS (c, "more than one negated literal in XOR base"); + return; + } + PUSH_STACK (*lits, lit); + size++; + } + assert (size == SIZE_STACK (*lits)); + if (size < 3) { + LOGCLS (c, "short XOR base clause"); + return; + } + const unsigned arity = size - 1; + const unsigned needed_clauses = 1u << (arity - 1); + const unsigned *const largecount = closure->largecount; + for (all_stack (unsigned, lit, *lits)) + for (unsigned sign = 0; sign != 2; sign++, lit = NOT (lit)) { + unsigned count = largecount[lit]; + if (count >= needed_clauses) + continue; + LOGCLS (c, + "literal %s in XOR base clause only occurs " + "%u times in large clauses thus skipping", + LOGLIT (lit), count); + return; + } + LOGCLS (c, "trying arity %u XOR base", arity); + assert (smallest != INVALID_LIT); + assert (largest != INVALID_LIT); + const unsigned end = 1u << arity; + assert (negated == parity_lits (solver, lits)); +#if !defined(NDEBUG) || defined(LOGGING) + unsigned found = 0; +#endif + for (unsigned i = 0; i != end; i++) { + while (i && parity_lits (solver, lits) != negated) + inc_lits (solver, lits); + if (i) { +#ifdef INDEX_LARGE_CLAUSES + clause *d = find_indexed_large_clause (closure, lits); +#else + clause *d = find_large_xor_side_clause (closure, lits); +#endif + if (!d) + return; + assert (!d->redundant); + } else + assert (!c->redundant); + inc_lits (solver, lits); +#if !defined(NDEBUG) || defined(LOGGING) + found++; +#endif + } + while (parity_lits (solver, lits) != negated) + inc_lits (solver, lits); + LOGUNSIGNEDS2 (size, BEGIN_STACK (*lits), "back to original"); + LOG ("found all needed %u matching clauses:", found); + assert (found == 1u << arity); + if (negated) { + unsigned *p = BEGIN_STACK (*lits), lit; + while (!NEGATED (lit = *p)) + p++; + LOG ("flipping RHS literal %s", LOGLIT (lit)); + *p = NOT (lit); + } + unsigned extracted = 0; + for (all_stack (unsigned, lhs, *lits)) { + if (!negated) + lhs = NOT (lhs); + gate *g = new_xor_gate (closure, lhs); + if (g) + extracted++; + if (solver->inconsistent) + break; + } + if (!extracted) + LOG ("no arity %u XOR gate extracted", arity); +} + +#ifdef INDEX_BINARY_CLAUSES + +static void init_bintab (closure *closure) { + kissat *const solver = closure->solver; + size_t limit = BINARY_CLAUSES; + size_t size = 2 * limit; + size_t size2 = 1; + while (size > size2) + size2 *= 2; + assert (!limit || size2 <= 2 * size); + binary_hash_table *bintab = &closure->bintab; + CALLOC (bintab->table, size); + bintab->count = 0; + bintab->size = size; + bintab->size2 = size2; + kissat_very_verbose ( + solver, "allocated binary clause hash table of size %zu", size); +} + +#ifndef NDEBUG + +static bool binaries_hash_table_is_full (binary_hash_table *bintab) { + if (bintab->size == MAX_HASH_TABLE_SIZE) + return false; + if (2 * bintab->count < bintab->size) + return false; + return true; +} + +#endif + +static void index_binary (closure *closure, unsigned lit, unsigned other) { + assert (lit < other); + binary_hash_table *bintab = &closure->bintab; + assert (!binaries_hash_table_is_full (bintab)); + binary_clause binary = {.lits = {lit, other}}; + const unsigned hash = hash_binary (closure, &binary); + const size_t size = bintab->size; + const size_t size2 = bintab->size2; + size_t pos = reduce_hash (hash, size, size2); + binary_clause *table = bintab->table; + while (table[pos].lits[1]) + if (++pos == size) + pos = 0; + table[pos] = binary; + bintab->count++; +#ifdef LOGGING + kissat *const solver = closure->solver; + LOG ("indexed binary %s %s", LOGLIT (lit), LOGLIT (other)); +#endif +} + +static void reset_bintab (closure *closure) { + kissat *const solver = closure->solver; + binary_hash_table *bintab = &closure->bintab; + DEALLOC (bintab->table, bintab->size); +} + +#endif + +static void init_and_gate_extraction (closure *closure) { + kissat *const solver = closure->solver; + assert (!solver->watching); + unsigned *negbincount; + CALLOC (negbincount, LITS); + litpairs *binaries = &closure->binaries; +#ifdef INDEX_BINARY_CLAUSES + init_bintab (closure); +#endif + for (all_stack (litpair, pair, *binaries)) { + const unsigned lit = pair.lits[0], other = pair.lits[1]; + const unsigned not_lit = NOT (lit), not_other = NOT (other); + negbincount[not_lit]++, negbincount[not_other]++; + kissat_watch_binary (solver, lit, other); +#ifdef INDEX_BINARY_CLAUSES + index_binary (closure, lit, other); +#endif + } +#ifndef QUIET + size_t connected = SIZE_STACK (*binaries); + kissat_very_verbose (solver, "connected %zu binary clauses", connected); +#endif + closure->negbincount = negbincount; +} + +static void reset_and_gate_extraction (closure *closure) { + kissat *const solver = closure->solver; + DEALLOC (closure->negbincount, LITS); + kissat_flush_all_connected (solver); +#ifdef INDEX_BINARY_CLAUSES + reset_bintab (closure); +#endif +} + +#ifdef INDEX_LARGE_CLAUSES + +static void init_large_clauses (closure *closure, size_t expected) { + kissat *const solver = closure->solver; + size_t size = 2 * expected; + size_t size2 = 1; + while (size > size2) + size2 *= 2; + assert (!expected || size2 <= 2 * size); + large_clause_hash_table *clauses = &closure->clauses; + CALLOC (clauses->table, size); + clauses->count = 0; + clauses->size = size; + clauses->size2 = size2; + kissat_very_verbose ( + solver, "allocated large clause hash table of size %zu", size); +} + +#ifndef NDEBUG + +static bool large_clause_hash_table_is_full (closure *closure) { + if (closure->clauses.size == MAX_HASH_TABLE_SIZE) + return false; + if (2 * closure->clauses.count < closure->clauses.size) + return false; + return true; +} + +#endif + +static void index_large_clause (closure *closure, reference ref) { + assert (!large_clause_hash_table_is_full (closure)); + kissat *const solver = closure->solver; + clause *c = kissat_dereference_clause (solver, ref); + const value *const values = solver->values; + unsigneds *lits = &closure->lits; + CLEAR_STACK (*lits); + for (all_literals_in_clause (lit, c)) + if (!values[lit]) + PUSH_STACK (*lits, lit); + const size_t size_lits = SIZE_STACK (*lits); + unsigned *begin_lits = BEGIN_STACK (*lits); + assert (3 <= size_lits); + sort_lits (solver, size_lits, begin_lits); + const unsigned hash = hash_lits (closure, 0, size_lits, begin_lits); + large_clause_hash_table *clauses = &closure->clauses; + if (!hash && !ref) { + ref = INVALID_REF; + assert (ref); + } + const size_t hash_size = clauses->size; + const size_t hash_size2 = clauses->size2; + size_t pos = reduce_hash (hash, hash_size, hash_size2); + hash_ref *table = clauses->table, *clause; + while (valid_large_clause (clause = table + pos)) + if (++pos == hash_size) + pos = 0; + clause->hash = hash; + clause->ref = ref; + assert (valid_large_clause (clause)); + clauses->count++; + LOGCLS (c, "indexed"); +} + +static void reset_large_clauses (closure *closure) { + large_clause_hash_table *clauses = &closure->clauses; + kissat *const solver = closure->solver; + DEALLOC (clauses->table, clauses->size); +} + +#endif + +static void init_xor_gate_extraction (closure *closure, + references *candidates) { + assert (EMPTY_STACK (*candidates)); + kissat *const solver = closure->solver; + assert (!solver->watching); + const unsigned arity_limit = GET_OPTION (congruencexorarity); + const unsigned size_limit = arity_limit + 1; + clause *last_irredundant = kissat_last_irredundant_clause (solver); + const value *const values = solver->values; + unsigned *largecount; + CALLOC (largecount, LITS); + for (all_clauses (c)) { + if (c->garbage) + continue; + if (last_irredundant && last_irredundant < c) + break; + if (c->redundant) + continue; + unsigned size = 0; + for (all_literals_in_clause (lit, c)) { + const value value = values[lit]; + if (value < 0) + continue; + if (value > 0) { + LOGCLS (c, "satisfied %s in", LOGLIT (lit)); + kissat_mark_clause_as_garbage (solver, c); + goto CONTINUE_COUNTING_NEXT_CLAUSE; + } + if (size == size_limit) + goto CONTINUE_COUNTING_NEXT_CLAUSE; + size++; + } + if (size < 3) + continue; + for (all_literals_in_clause (lit, c)) + if (!values[lit]) + largecount[lit]++; + reference ref = kissat_reference_clause (solver, c); + PUSH_STACK (*candidates, ref); + CONTINUE_COUNTING_NEXT_CLAUSE:; + } +#ifndef QUIET + size_t considered_clauses = IRREDUNDANT_CLAUSES; + size_t original_candidates = SIZE_STACK (*candidates); + kissat_very_verbose ( + solver, + "%zu original candidate XOR base clauses " + "(%.0f%% of %zu irredundant clauses)", + original_candidates, + kissat_percent (original_candidates, considered_clauses), + considered_clauses); +#endif + const unsigned counting_rounds = GET_OPTION (congruencexorcounts); + for (unsigned round = 1; round <= counting_rounds; round++) { + size_t removed = 0; + unsigned *new_largecount; + CALLOC (new_largecount, LITS); + const reference *const end_candidates = END_STACK (*candidates); + reference *q = BEGIN_STACK (*candidates), *p = q; + while (p != end_candidates) { + const reference ref = *p++; + clause *c = kissat_dereference_clause (solver, ref); + unsigned size = 0; + for (all_literals_in_clause (lit, c)) + if (!values[lit]) + size++; + assert (3 <= size); + assert (size <= size_limit); + const unsigned arity = size - 1; + const unsigned needed_clauses = 1u << (arity - 1); + for (all_literals_in_clause (lit, c)) + if (largecount[lit] < needed_clauses) { + removed++; + goto CONTINUE_WITH_NEXT_CANDIDATE_CLAUSE; + } + for (all_literals_in_clause (lit, c)) + if (!values[lit]) + new_largecount[lit]++; + *q++ = ref; + CONTINUE_WITH_NEXT_CANDIDATE_CLAUSE:; + } + DEALLOC (largecount, LITS); + largecount = new_largecount; + SET_END_OF_STACK (*candidates, q); + if (!removed) + break; +#ifndef QUIET + size_t remaining_candidates = SIZE_STACK (*candidates); + const char *how_often; + char buffer[64]; + if (round == 1) + how_often = "once"; + else if (round == 2) + how_often = "twice"; + else { + sprintf (buffer, "%u times", round); + how_often = buffer; + } + kissat_very_verbose ( + solver, + "%zu XOR base clause candidates remain (%.0f%% " + "original candidates)" + " after counting %s", + remaining_candidates, + kissat_percent (remaining_candidates, original_candidates), + how_often); +#endif + } + closure->largecount = largecount; +#ifdef INDEX_LARGE_CLAUSES + init_large_clauses (closure, SIZE_STACK (*candidates)); +#endif + for (all_stack (reference, ref, *candidates)) { + kissat_connect_referenced (solver, ref); +#ifdef INDEX_LARGE_CLAUSES + index_large_clause (closure, ref); +#endif + } +#ifndef QUIET + size_t connected = SIZE_STACK (*candidates); + kissat_very_verbose (solver, "connected %zu large clauses %.0f%%", + connected, + kissat_percent (connected, IRREDUNDANT_CLAUSES)); +#endif +} + +static void reset_xor_gate_extraction (closure *closure) { + kissat *const solver = closure->solver; + DEALLOC (closure->largecount, LITS); + kissat_flush_all_connected (solver); +#ifdef INDEX_LARGE_CLAUSES + reset_large_clauses (closure); +#endif +} + +static void init_ite_gate_extraction (closure *closure, + references *candidates) { + assert (EMPTY_STACK (*candidates)); + kissat *const solver = closure->solver; + clause *last_irredundant = kissat_last_irredundant_clause (solver); + const value *const values = solver->values; + unsigned *largecount; + CALLOC (largecount, LITS); + references ternary; + INIT_STACK (ternary); + for (all_clauses (c)) { + if (c->garbage) + continue; + if (last_irredundant && last_irredundant < c) + break; + if (c->redundant) + continue; + unsigned size = 0; + for (all_literals_in_clause (lit, c)) { + const value value = values[lit]; + if (value < 0) + continue; + if (value > 0) { + LOGCLS (c, "satisfied %s in", LOGLIT (lit)); + kissat_mark_clause_as_garbage (solver, c); + goto CONTINUE_COUNTING_NEXT_CLAUSE; + } + if (size == 3) + goto CONTINUE_COUNTING_NEXT_CLAUSE; + size++; + } + if (size < 3) + continue; + assert (size == 3); + const reference ref = kissat_reference_clause (solver, c); + PUSH_STACK (ternary, ref); + LOGCLS (c, "counting original ITE gate base"); + for (all_literals_in_clause (lit, c)) + if (!values[lit]) + largecount[lit]++; + CONTINUE_COUNTING_NEXT_CLAUSE:; + } +#ifndef QUIET + size_t counted = SIZE_STACK (ternary); + kissat_very_verbose (solver, + "counted %zu ternary ITE clauses " + "(%.0f%% of %" PRIu64 " irredundant clauses)", + counted, + kissat_percent (counted, IRREDUNDANT_CLAUSES), + IRREDUNDANT_CLAUSES); + size_t connected = 0; +#endif + for (all_stack (reference, ref, ternary)) { + clause *c = kissat_dereference_clause (solver, ref); + assert (!c->garbage); + unsigned positive = 0, negative = 0, twice = 0; + for (all_literals_in_clause (lit, c)) { + if (values[lit]) + continue; + const unsigned not_lit = NOT (lit); + const unsigned count_not_lit = largecount[not_lit]; + if (!count_not_lit) + goto CONTINUE_WITH_NEXT_TERNARY_CLAUSE; + const unsigned count_lit = largecount[lit]; + assert (count_lit); + if (count_lit > 1 && count_not_lit > 1) + twice++; + if (NEGATED (lit)) + negative++; + else + positive++; + } + if (twice < 2) + goto CONTINUE_WITH_NEXT_TERNARY_CLAUSE; +#ifndef QUIET + connected++; +#endif + kissat_connect_clause (solver, c); + if (positive && negative) + PUSH_STACK (*candidates, ref); + CONTINUE_WITH_NEXT_TERNARY_CLAUSE:; + } + RELEASE_STACK (ternary); +#ifndef QUIET + kissat_very_verbose (solver, + "connected %zu ITE clauses " + "(%.0f%% of %" PRIu64 " counted clauses)", + connected, kissat_percent (connected, counted), + IRREDUNDANT_CLAUSES); + size_t size_candidates = SIZE_STACK (*candidates); + kissat_very_verbose (solver, + "%zu candidates ITE base clauses " + "(%.0f%% of %zu connected)", + size_candidates, + kissat_percent (size_candidates, connected), + connected); +#endif + closure->largecount = largecount; + INIT_STACK (closure->condbin[0]); + INIT_STACK (closure->condbin[1]); + INIT_STACK (closure->condeq[0]); + INIT_STACK (closure->condeq[1]); +} + +static void reset_ite_gate_extraction (closure *closure) { + kissat *const solver = closure->solver; + RELEASE_STACK (closure->condbin[0]); + RELEASE_STACK (closure->condbin[1]); + RELEASE_STACK (closure->condeq[0]); + RELEASE_STACK (closure->condeq[1]); + DEALLOC (closure->largecount, LITS); + kissat_flush_all_connected (solver); +} + +static void unmark_all (unsigneds *marked, signed char *marks) { + for (all_stack (unsigned, lit, *marked)) + marks[lit] = 0; + CLEAR_STACK (*marked); +} + +#ifdef MERGE_CONDITIONAL_EQUIVALENCES + +static void copy_conditional_equivalences (kissat *solver, unsigned lit, + watches *watches, + litpairs *condbin) { + assert (EMPTY_STACK (*condbin)); + const value *const values = solver->values; + const watch *const begin_watches = BEGIN_WATCHES (*watches); + const watch *const end_watches = END_WATCHES (*watches); + for (const watch *p = begin_watches; p != end_watches; p++) { + const watch watch = *p; + if (watch.type.binary) + break; + const unsigned ref = watch.large.ref; + clause *c = kissat_dereference_clause (solver, ref); + unsigned first = INVALID_LIT, second = INVALID_LIT; + for (all_literals_in_clause (other, c)) { + if (values[other]) + continue; + if (other == lit) + continue; + if (first == INVALID_LIT) + first = other; + else { + assert (second == INVALID_LIT); + second = other; + } + } + assert (first != INVALID_LIT); + assert (second != INVALID_LIT); + litpair pair; + if (first < second) + pair = (litpair){.lits = {first, second}}; + else { + assert (second < first); + pair = (litpair){.lits = {second, first}}; + } + LOG ("literal %s conditional binary clause %s %s", LOGLIT (lit), + LOGLIT (first), LOGLIT (second)); + PUSH_STACK (*condbin, pair); + } +} + +static bool less_litpair (litpair p, litpair q) { + const unsigned a = p.lits[0], b = q.lits[0]; + if (a < b) + return true; + if (a > b) + return false; + const unsigned c = p.lits[1], d = q.lits[1]; + return c < d; +} + +#define RADIDX_SORT_PAIR_LIMIT 32 + +static void sort_pairs (kissat *solver, litpairs *pairs) { + const size_t size = SIZE_STACK (*pairs); + if (size < 32) + SORT_STACK (litpair, *pairs, less_litpair); + else + for (int i = 1; i >= 0; i--) + RADIX_STACK (litpair, uint64_t, *pairs, rank_litpair); +} + +static bool find_litpair_second_literal (unsigned lit, const litpair *begin, + const litpair *end) { + const litpair *l = begin, *r = end; + while (l != r) { + const litpair *m = l + (r - l) / 2; + assert (begin <= m), assert (m < end); + unsigned other = m->lits[1]; + if (other < lit) + l = m + 1; + else if (other > lit) + r = m; + else + return true; + } + return false; +} + +static void search_condeq (closure *closure, unsigned lit, unsigned pos_lit, + const litpair *pos_begin, const litpair *pos_end, + unsigned neg_lit, const litpair *neg_begin, + const litpair *neg_end, litpairs *condeq) { + kissat *const solver = closure->solver; + assert (neg_lit == NOT (pos_lit)); + assert (pos_begin < pos_end); + assert (neg_begin < neg_end); + assert (pos_begin->lits[0] == pos_lit); + assert (neg_begin->lits[0] == neg_lit); + assert (pos_end <= neg_begin || neg_end <= pos_begin); + for (const litpair *p = pos_begin; p != pos_end; p++) { + const unsigned other = p->lits[1]; + const unsigned not_other = NOT (other); + if (find_litpair_second_literal (not_other, neg_begin, neg_end)) { + unsigned first, second; + if (NEGATED (pos_lit)) + first = neg_lit, second = other; + else + first = pos_lit, second = not_other; + LOG ("found conditional %s equivalence %s = %s", LOGLIT (lit), + LOGLIT (first), LOGLIT (second)); + assert (!NEGATED (first)); + assert (first < second); + check_ternary (closure, lit, first, NOT (second)); + check_ternary (closure, lit, NOT (first), second); + litpair equivalence = {.lits = {first, second}}; + PUSH_STACK (*condeq, equivalence); + if (NEGATED (second)) { + litpair inverse_equivalence = {.lits = {NOT (second), NOT (first)}}; + PUSH_STACK (*condeq, inverse_equivalence); + } else { + litpair inverse_equivalence = {.lits = {second, first}}; + PUSH_STACK (*condeq, inverse_equivalence); + } + } + } +#ifndef LOGGING + (void) lit; +#endif +} + +static void extract_condeq_pairs (closure *closure, unsigned lit, + litpairs *condbin, litpairs *condeq) { +#if defined(LOGGING) || !defined(NDEBUG) + kissat *const solver = closure->solver; +#endif + const litpair *const begin = BEGIN_STACK (*condbin); + const litpair *const end = END_STACK (*condbin); + const litpair *pos_begin = begin; + unsigned next_lit; + for (;;) { + if (pos_begin == end) + return; + next_lit = pos_begin->lits[0]; + if (!NEGATED (next_lit)) + break; + pos_begin++; + } + for (;;) { + assert (pos_begin != end); + assert (next_lit == pos_begin->lits[0]); + assert (!NEGATED (next_lit)); + const unsigned pos_lit = next_lit; + const litpair *pos_end = pos_begin + 1; + for (;;) { + if (pos_end == end) + return; + next_lit = pos_end->lits[0]; + if (next_lit != pos_lit) + break; + pos_end++; + } + assert (pos_end != end); + assert (next_lit == pos_end->lits[0]); + const unsigned neg_lit = NOT (pos_lit); + if (next_lit != neg_lit) { + if (NEGATED (next_lit)) { + pos_begin = pos_end + 1; + for (;;) { + if (pos_begin == end) + return; + next_lit = pos_begin->lits[0]; + if (!NEGATED (next_lit)) + break; + pos_begin++; + } + } else + pos_begin = pos_end; + continue; + } + const litpair *const neg_begin = pos_end; + const litpair *neg_end = neg_begin + 1; + while (neg_end != end) { + next_lit = neg_end->lits[0]; + if (next_lit != neg_lit) + break; + neg_end++; + } +#ifdef LOGGING + if (kissat_logging (solver)) { + for (const litpair *p = pos_begin; p != pos_end; p++) + LOG ("conditional %s binary clause %s %s with positive %s", + LOGLIT (lit), LOGLIT (p->lits[0]), LOGLIT (p->lits[1]), + LOGLIT (pos_lit)); + for (const litpair *p = neg_begin; p != neg_end; p++) + LOG ("conditional %s binary clause %s %s with negative %s", + LOGLIT (lit), LOGLIT (p->lits[0]), LOGLIT (p->lits[1]), + LOGLIT (neg_lit)); + } +#endif + const size_t pos_size = pos_end - pos_begin; + const size_t neg_size = neg_end - neg_begin; + if (pos_size <= neg_size) { + LOG ("searching negation of %zu conditional binary clauses " + "with positive %s in %zu conditional binary clauses with %s", + pos_size, LOGLIT (pos_lit), neg_size, LOGLIT (neg_lit)); + search_condeq (closure, lit, pos_lit, pos_begin, pos_end, neg_lit, + neg_begin, neg_end, condeq); + } else { + LOG ("searching negation of %zu conditional binary clauses " + "with negative %s in %zu conditional binary clauses with %s", + neg_size, LOGLIT (neg_lit), pos_size, LOGLIT (pos_lit)); + search_condeq (closure, lit, neg_lit, neg_begin, neg_end, pos_lit, + pos_begin, pos_end, condeq); + } + if (neg_end == end) + return; + assert (next_lit == neg_end->lits[0]); + if (NEGATED (next_lit)) { + pos_begin = neg_end + 1; + for (;;) { + if (pos_begin == end) + return; + next_lit = pos_begin->lits[0]; + if (!NEGATED (next_lit)) + break; + pos_begin++; + } + } else + pos_begin = neg_end; + } +} + +static void find_conditional_equivalences (closure *closure, unsigned lit, + watches *watches, + litpairs *condbin, + litpairs *condeq) { + assert (EMPTY_STACK (*condbin)); + assert (EMPTY_STACK (*condeq)); + assert (SIZE_WATCHES (*watches) > 1); + kissat *const solver = closure->solver; + copy_conditional_equivalences (solver, lit, watches, condbin); + sort_pairs (solver, condbin); +#ifdef LOGGING + if (kissat_logging (solver)) { + for (all_stack (litpair, pair, *condbin)) + LOG ("sorted conditional %s binary clause %s %s", LOGLIT (lit), + LOGLIT (pair.lits[0]), LOGLIT (pair.lits[1])); + LOG ("found %zu conditional %s binary clauses", SIZE_STACK (*condbin), + LOGLIT (lit)); + } +#endif + extract_condeq_pairs (closure, lit, condbin, condeq); + sort_pairs (solver, condeq); +#ifdef LOGGING + if (kissat_logging (solver)) { + for (all_stack (litpair, pair, *condeq)) + LOG ("sorted conditional %s equivalence %s = %s", LOGLIT (lit), + LOGLIT (pair.lits[0]), LOGLIT (pair.lits[1])); + LOG ("found %zu conditional %s equivalences", SIZE_STACK (*condeq), + LOGLIT (lit)); + } +#endif +} + +static void merge_condeq (closure *closure, unsigned cond, litpairs *condeq, + litpairs *not_condeq) { + kissat *solver = closure->solver; + assert (!NEGATED (cond)); + const litpair *const begin_condeq = BEGIN_STACK (*condeq); + const litpair *const end_condeq = END_STACK (*condeq); + const litpair *const begin_not_condeq = BEGIN_STACK (*not_condeq); + const litpair *const end_not_condeq = END_STACK (*not_condeq); + const litpair *p = begin_condeq; + const litpair *q = begin_not_condeq; + while (p != end_condeq) { + litpair cond_pair = *p++; + const unsigned lhs = cond_pair.lits[0]; + const unsigned then_lit = cond_pair.lits[1]; + assert (!NEGATED (lhs)); + while (q != end_not_condeq && q->lits[0] < lhs) + q++; + while (q != end_not_condeq && q->lits[0] == lhs) { + litpair not_cond_pair = *q++; + const unsigned else_lit = not_cond_pair.lits[1]; + new_ite_gate (closure, lhs, cond, then_lit, else_lit); + if (solver->inconsistent) + return; + } + } +} + +static void extract_ite_gates_of_literal (closure *closure, unsigned lit, + unsigned not_lit, + watches *lit_watches, + watches *not_lit_watches) { +#ifndef NDEBUG + kissat *solver = closure->solver; +#endif + litpairs *condbin = closure->condbin; + litpairs *condeq = closure->condeq; + find_conditional_equivalences (closure, lit, lit_watches, condbin + 0, + condeq + 0); + if (EMPTY_STACK (condeq[0])) + goto CLEAN_UP; + find_conditional_equivalences (closure, not_lit, not_lit_watches, + condbin + 1, condeq + 1); + if (EMPTY_STACK (condeq[1])) + goto CLEAN_UP; + if (NEGATED (lit)) + merge_condeq (closure, not_lit, condeq + 0, condeq + 1); + else + merge_condeq (closure, lit, condeq + 1, condeq + 0); +CLEAN_UP: + CLEAR_STACK (condbin[0]); + CLEAR_STACK (condbin[1]); + CLEAR_STACK (condeq[0]); + CLEAR_STACK (condeq[1]); +} + +static void extract_ite_gates_of_variable (closure *closure, unsigned idx) { + kissat *const solver = closure->solver; + const unsigned lit = LIT (idx); + const unsigned not_lit = NOT (lit); + watches *lit_watches = &WATCHES (lit); + watches *not_lit_watches = &WATCHES (not_lit); + const size_t size_lit_watches = SIZE_WATCHES (*lit_watches); + const size_t size_not_lit_watches = SIZE_WATCHES (*not_lit_watches); + if (size_lit_watches <= size_not_lit_watches) { + if (size_lit_watches > 1) + extract_ite_gates_of_literal (closure, lit, not_lit, lit_watches, + not_lit_watches); + } else { + if (size_not_lit_watches > 1) + extract_ite_gates_of_literal (closure, not_lit, lit, not_lit_watches, + lit_watches); + } +} + +#else + +static void mark_third_literal_in_ternary_clauses ( + kissat *solver, const value *const values, unsigneds *marked, + mark *marks, unsigned a, unsigned b) { + assert (!solver->watching); + assert (EMPTY_STACK (*marked)); + watches *a_watches = &WATCHES (a); + watches *b_watches = &WATCHES (b); + const size_t size_a = SIZE_WATCHES (*a_watches); + const size_t size_b = SIZE_WATCHES (*b_watches); + watches *watches = size_a <= size_b ? a_watches : b_watches; + const watch *const begin = BEGIN_WATCHES (*watches); + const watch *const end = END_WATCHES (*watches); + for (const watch *p = begin; p != end; p++) { + const watch watch = *p; + assert (!watch.type.binary); + const reference ref = watch.large.ref; + clause *c = kissat_dereference_clause (solver, ref); + assert (!c->garbage); + unsigned third = INVALID_LIT, found = 0; + for (all_literals_in_clause (lit, c)) { + if (values[lit]) + continue; + if (lit == a || lit == b) { + found++; + continue; + } + if (third != INVALID_LIT) + goto NEXT_WATCH; + third = lit; + } + assert (found <= 2); + if (found < 2) + goto NEXT_WATCH; + assert (third != INVALID_LIT); + if (third == INVALID_LIT) + goto NEXT_WATCH; + if (marks[third]) + goto NEXT_WATCH; + LOGCLS (c, "marking %s as third literal in", LOGLIT (third)); + PUSH_STACK (*marked, third); + marks[third] = 1; + NEXT_WATCH:; + } +} + +static void extract_ite_gate (closure *closure, const value *const values, + mark *const marks, unsigned lhs, + unsigned cond, unsigned then_lit) { + kissat *const solver = closure->solver; + assert (!solver->watching); + unsigned a = NOT (lhs), b = cond; + watches *a_watches = &WATCHES (a); + watches *b_watches = &WATCHES (b); + const size_t size_a = SIZE_WATCHES (*a_watches); + const size_t size_b = SIZE_WATCHES (*b_watches); + watches *watches = size_a <= size_b ? a_watches : b_watches; + const watch *const begin = BEGIN_WATCHES (*watches); + const watch *const end = END_WATCHES (*watches); + for (const watch *p = begin; p != end; p++) { + const watch watch = *p; + assert (!watch.type.binary); + const reference ref = watch.large.ref; + clause *c = kissat_dereference_clause (solver, ref); + assert (!c->garbage); + unsigned else_lit = INVALID_LIT, found = 0; + for (all_literals_in_clause (lit, c)) { + if (values[lit]) + continue; + if (lit == a || lit == b) { + found++; + continue; + } + if (else_lit != INVALID_LIT) + goto NEXT_WATCH; + else_lit = lit; + } + assert (found <= 2); + if (found < 2) + goto NEXT_WATCH; + assert (else_lit != INVALID_LIT); + unsigned not_else_lit = NOT (else_lit); + if (!marks[not_else_lit]) + goto NEXT_WATCH; + LOGCLS (c, "found fourth matching"); + check_ite_implied (closure, lhs, cond, then_lit, else_lit); + marks[not_else_lit] = 0; + new_ite_gate (closure, lhs, cond, then_lit, else_lit); + NEXT_WATCH:; + } + SWAP (unsigned, a, b); +} + +static void extract_ite_gates_with_base_clause (closure *closure, + clause *c) { + assert (!c->garbage); + kissat *const solver = closure->solver; + assert (!solver->inconsistent); + const value *const values = solver->values; + const unsigned *const largecount = closure->largecount; + unsigneds *lits = &closure->lits; + CLEAR_STACK (*lits); + unsigned sum = 0; + for (all_literals_in_clause (lit, c)) { + const value value = values[lit]; + if (value < 0) + continue; + if (value > 0) { + LOGCLS (c, "found satisfied %s in", LOGLIT (lit)); + kissat_mark_clause_as_garbage (solver, c); + return; + } + PUSH_STACK (*lits, lit); + sum ^= lit; + } + const size_t size = SIZE_STACK (*lits); + assert (size <= 3); + if (size < 3) + return; + mark *const marks = solver->marks; + unsigneds *marked = &solver->analyzed; + for (all_stack (unsigned, lhs, *lits)) { + if (NEGATED (lhs)) + continue; + if (largecount[lhs] < 2) + continue; + const unsigned not_lhs = NOT (lhs); + if (largecount[not_lhs] < 2) + continue; + for (all_stack (unsigned, not_cond, *lits)) { + if (not_cond == lhs) + continue; + if (!NEGATED (not_cond)) + continue; + if (largecount[not_cond] < 2) + continue; + const unsigned cond = NOT (not_cond); + if (largecount[cond] < 2) + continue; + const unsigned not_then_lit = sum ^ lhs ^ not_cond; + const unsigned then_lit = NOT (not_then_lit); + if (!largecount[then_lit]) + continue; + LOGCLS (c, "found first ITE gate '%s := %s ? %s : ...' gate base", + LOGLIT (lhs), LOGLIT (cond), LOGLIT (then_lit)); + clause *d = find_ternary_clause (solver, not_lhs, not_cond, then_lit); + if (!d) + continue; + LOGCLS (d, "found matching second ITE gate"); + mark_third_literal_in_ternary_clauses (solver, values, marked, marks, + lhs, cond); + extract_ite_gate (closure, values, marks, lhs, cond, then_lit); + unmark_all (marked, marks); + } + } +} + +#endif + +static void extract_and_gates (closure *closure) { + kissat *const solver = closure->solver; + if (!GET_OPTION (congruenceands)) + return; + START (extractands); +#ifndef QUIET + const statistics *s = &solver->statistics; + const uint64_t matched_before = s->congruent_matched_ands; + const uint64_t gates_before = s->congruent_gates_ands; +#endif + init_and_gate_extraction (closure); + clause *last_irredundant = kissat_last_irredundant_clause (solver); + for (all_clauses (c)) { + if (TERMINATED (congruence_terminated_1)) + break; + if (solver->inconsistent) + break; + if (last_irredundant && last_irredundant < c) + break; + if (c->redundant) + continue; + if (c->garbage) + continue; + extract_and_gates_with_base_clause (closure, c); + } + reset_and_gate_extraction (closure); +#ifndef QUIET + const uint64_t matched = s->congruent_matched_ands - matched_before; + const uint64_t extracted = s->congruent_gates_ands - gates_before; + const uint64_t found = matched + extracted; + kissat_phase (solver, "congruence", GET (closures), + "found %" PRIu64 " AND gates (%" PRIu64 + " extracted %.0f%% + %" PRIu64 " matched %.0f%%)", + found, extracted, kissat_percent (extracted, found), + matched, kissat_percent (matched, found)); +#endif + STOP (extractands); +} + +static void extract_xor_gates (closure *closure) { + kissat *const solver = closure->solver; + if (!GET_OPTION (congruencexors)) + return; + START (extractxors); + references candidates; + INIT_STACK (candidates); + init_xor_gate_extraction (closure, &candidates); + SHRINK_STACK (candidates); +#ifndef QUIET + const statistics *s = &solver->statistics; + const uint64_t matched_before = s->congruent_matched_xors; + const uint64_t gates_before = s->congruent_gates_xors; +#endif + for (all_stack (reference, ref, candidates)) { + if (TERMINATED (congruence_terminated_2)) + break; + if (solver->inconsistent) + break; + clause *c = kissat_dereference_clause (solver, ref); + if (c->garbage) + continue; + extract_xor_gates_with_base_clause (closure, c); + } + reset_xor_gate_extraction (closure); + RELEASE_STACK (candidates); +#ifndef QUIET + const uint64_t matched = s->congruent_matched_xors - matched_before; + const uint64_t extracted = s->congruent_gates_xors - gates_before; + const uint64_t found = matched + extracted; + kissat_phase (solver, "congruence", GET (closures), + "found %" PRIu64 " XOR gates (%" PRIu64 + " extracted %.0f%% + %" PRIu64 " matched %.0f%%)", + found, extracted, kissat_percent (extracted, found), + matched, kissat_percent (matched, found)); +#endif + STOP (extractxors); +} + +static void extract_ite_gates (closure *closure) { + kissat *const solver = closure->solver; + if (!GET_OPTION (congruenceites)) + return; + START (extractites); + references candidates; + INIT_STACK (candidates); + init_ite_gate_extraction (closure, &candidates); +#ifndef QUIET + const statistics *s = &solver->statistics; + const uint64_t matched_before = s->congruent_matched_ites; + const uint64_t gates_before = s->congruent_gates_ites; +#endif +#ifdef MERGE_CONDITIONAL_EQUIVALENCES + for (all_variables (idx)) + if (ACTIVE (idx)) { + extract_ite_gates_of_variable (closure, idx); + if (solver->inconsistent) + break; + } +#else + for (all_stack (reference, ref, candidates)) { + if (TERMINATED (congruence_terminated_3)) + break; + if (solver->inconsistent) + break; + clause *c = kissat_dereference_clause (solver, ref); + if (c->garbage) + continue; + extract_ite_gates_with_base_clause (closure, c); + } +#endif + reset_ite_gate_extraction (closure); + RELEASE_STACK (candidates); +#ifndef QUIET + const uint64_t matched = s->congruent_matched_ites - matched_before; + const uint64_t extracted = s->congruent_gates_ites - gates_before; + const uint64_t found = matched + extracted; + kissat_phase (solver, "congruence", GET (closures), + "found %" PRIu64 " ITE gates (%" PRIu64 + " extracted %.0f%% + %" PRIu64 " matched %.0f%%)", + found, extracted, kissat_percent (extracted, found), + matched, kissat_percent (matched, found)); +#endif + STOP (extractites); +} + +static void init_extraction (closure *closure) { + kissat *const solver = closure->solver; + kissat_enter_dense_mode (solver, &closure->binaries); +} + +static void reset_extraction (closure *closure) { + kissat *const solver = closure->solver; + kissat_resume_sparse_mode (solver, false, &closure->binaries); + RELEASE_STACK (closure->binaries); +} + +static void extract_gates (closure *closure) { + kissat *const solver = closure->solver; + START (extract); + assert (!solver->level); +#ifndef QUIET + const statistics *s = &solver->statistics; + const uint64_t before = s->congruent_gates + s->congruent_matched; +#endif + init_extraction (closure); + extract_binaries (closure); + assert (!solver->inconsistent); + extract_and_gates (closure); + if (!solver->inconsistent && !TERMINATED (congruence_terminated_4)) { + extract_xor_gates (closure); + if (!solver->inconsistent && !TERMINATED (congruence_terminated_5)) + extract_ite_gates (closure); + } + reset_extraction (closure); +#ifndef QUIET + const uint64_t after = s->congruent_gates + s->congruent_matched; + const uint64_t found = after - before; + kissat_phase (solver, "congruence", GET (closures), + "found %" PRIu64 " gates (%.2f%% variables)", found, + kissat_percent (found, solver->active)); +#endif + STOP (extract); +} + +static void find_units (closure *closure) { + kissat *const solver = closure->solver; + assert (solver->watching); + assert (!solver->inconsistent); + assert (kissat_propagated (solver)); + closure->units = solver->propagate; + unsigneds *marked = &solver->analyzed; + mark *const marks = solver->marks; + size_t units = 0; + for (all_variables (idx)) { + RESTART: + if (!ACTIVE (idx)) + continue; + unsigned lit = LIT (idx); + for (unsigned sign = 0; sign != 2; sign++, lit++) { + watches *const watches = &WATCHES (lit); + const watch *p = BEGIN_WATCHES (*watches); + const watch *const end = END_WATCHES (*watches); + assert (EMPTY_STACK (*marked)); + while (p != end) { + const watch watch = *p++; + if (!watch.type.binary) + break; + const unsigned other = watch.binary.lit; + const unsigned not_other = NOT (other); + if (marks[not_other]) { + LOG ("binary clauses %s %s and %s %s yield unit %s", LOGLIT (lit), + LOGLIT (other), LOGLIT (lit), LOGLIT (not_other), + LOGLIT (lit)); + units++; + bool failed = !learn_congruence_unit (closure, lit); + unmark_all (marked, marks); + if (failed) + return; + else + goto RESTART; + } + if (marks[other]) + continue; + marks[other] = 1; + PUSH_STACK (*marked, other); + } + unmark_all (marked, marks); + } + } + assert (EMPTY_STACK (*marked)); +#ifndef QUIET + kissat_very_verbose (solver, "found %zu units", units); +#else + (void) units; +#endif +} + +static void find_equivalences (closure *closure) { + kissat *const solver = closure->solver; + assert (solver->watching); + assert (!solver->inconsistent); + unsigneds *const marked = &solver->analyzed; + mark *const marks = solver->marks; + assert (EMPTY_STACK (*marked)); + for (all_variables (idx)) { + RESTART: + if (!ACTIVE (idx)) + continue; + const unsigned lit = LIT (idx); + watches *lit_watches = &WATCHES (lit); + const watch *p = BEGIN_WATCHES (*lit_watches); + const watch *const end_lit_watches = END_WATCHES (*lit_watches); + assert (EMPTY_STACK (*marked)); + while (p != end_lit_watches) { + const watch watch = *p++; + if (!watch.type.binary) + break; + const unsigned other = watch.binary.lit; + if (lit > other) + continue; + if (marks[other]) + continue; + marks[other] = 1; + PUSH_STACK (*marked, other); + } + if (EMPTY_STACK (*marked)) + continue; + const unsigned not_lit = NOT (lit); + watches *not_lit_watches = &WATCHES (not_lit); + p = BEGIN_WATCHES (*not_lit_watches); + const watch *const end_not_lit_watches = END_WATCHES (*not_lit_watches); + while (p != end_not_lit_watches) { + const watch watch = *p++; + if (!watch.type.binary) + break; + const unsigned other = watch.binary.lit; + if (not_lit > other) + continue; + if (lit == other) + continue; + const unsigned not_other = NOT (other); + if (marks[not_other]) { + unsigned lit_repr = find_repr (closure, lit); + unsigned other_repr = find_repr (closure, other); + if (lit_repr != other_repr) { + if (merge_literals (closure, lit, other)) + INC (congruent_equivalences); + unmark_all (marked, marks); + if (solver->inconsistent) + return; + else + goto RESTART; + } + } + } + unmark_all (marked, marks); + } + assert (EMPTY_STACK (*marked)); +#ifndef QUIET + size_t found = SIZE_FIFO (closure->schedule); + kissat_very_verbose (solver, "found %zu equivalences", found); +#endif +} + +static bool simplify_gates (closure *closure, unsigned lit) { + kissat *const solver = closure->solver; + LOG ("simplifying gates with RHS literal %s", LOGLIT (lit)); + assert (solver->values[lit]); + gates *lit_occurrences = closure->occurrences + lit; + for (all_pointers (gate, g, *lit_occurrences)) + if (!simplify_gate (closure, g)) + return false; + RELEASE_STACK (*lit_occurrences); + return true; +} + +static bool rewrite_gates (closure *closure, unsigned dst, unsigned src) { + kissat *const solver = closure->solver; + LOG ("rewriting gates with RHS literal %s", LOGLIT (src)); + gates *occurrences = closure->occurrences; + gates *src_occurrences = occurrences + src; + gates *dst_occurrences = occurrences + dst; + for (all_pointers (gate, g, *src_occurrences)) + if (!rewrite_gate (closure, g, dst, src)) + return false; + else if (!g->garbage && gate_contains (g, dst)) + PUSH_STACK (*dst_occurrences, g); + RELEASE_STACK (*src_occurrences); + return true; +} + +static bool propagate_unit (closure *closure, unsigned lit) { + kissat *const solver = closure->solver; + LOG ("propagation of congruence unit %s", LOGLIT (lit)); + (void) solver; + assert (!solver->inconsistent); + const unsigned not_lit = NOT (lit); + return simplify_gates (closure, lit) && simplify_gates (closure, not_lit); +} + +static bool propagate_equivalence (closure *closure, unsigned lit) { + kissat *const solver = closure->solver; + LOG ("propagation of congruence equivalence %s", CLOGREPR (lit)); + assert (!solver->inconsistent); + if (VALUE (lit)) + return true; + const unsigned lit_repr = find_repr (closure, lit); + if (solver->inconsistent) + return false; + const unsigned not_lit = NOT (lit); + const unsigned not_lit_repr = NOT (lit_repr); + return rewrite_gates (closure, lit_repr, lit) && + rewrite_gates (closure, not_lit_repr, not_lit); +} + +static bool propagate_units (closure *closure) { + kissat *const solver = closure->solver; + assert (!solver->inconsistent); + const unsigned_array *const trail = &solver->trail; + while (closure->units != trail->end) + if (!propagate_unit (closure, *closure->units++)) + return false; + return true; +} + +static size_t propagate_units_and_equivalences (closure *closure) { + kissat *const solver = closure->solver; + assert (!solver->inconsistent); + START (merge); + unsigned_fifo *schedule = &closure->schedule; + size_t propagated = 0; + while (!TERMINATED (congruence_terminated_6) && + propagate_units (closure) && !EMPTY_FIFO (*schedule)) { + propagated++; + unsigned lit = dequeue_next_scheduled_literal (closure); + if (!propagate_equivalence (closure, lit)) + break; + } +#ifndef QUIET + const size_t units = closure->units - solver->trail.begin; + kissat_very_verbose (solver, "propagated %zu congruence units", units); + kissat_very_verbose (solver, "propagated %zu congruence equivalences", + propagated); +#endif + STOP (merge); + return propagated; +} + +#ifndef NDEBUG + +static void dump_closure_literal (closure *closure, unsigned ilit) { + kissat *const solver = closure->solver; + const int elit = kissat_export_literal (solver, ilit); + printf ("%u(%d)", ilit, elit); + unsigned repr_ilit = find_repr (closure, ilit); + if (repr_ilit != ilit) { + const int repr_elit = kissat_export_literal (solver, repr_ilit); + printf ("[%u(%d)]", repr_ilit, repr_elit); + } + const int value = VALUE (ilit); + assert (!solver->level); + if (value) + printf ("@0=%d", value); +} + +static void dump_units (closure *closure) { + unsigned_array *trail = &closure->solver->trail; + size_t i = 0, propagate = closure->units - trail->begin; + for (all_stack (unsigned, lit, *trail)) { + printf ("trail[%zu] ", i); + dump_closure_literal (closure, lit); + if (i == propagate) + fputs (" <-- next unit to propagate", stdout); + fputc ('\n', stdout); + i++; + } +} + +static void dump_equivalences (closure *closure) { + kissat *const solver = closure->solver; + for (all_variables (idx)) { + unsigned lit = LIT (idx); + unsigned repr = closure->repr[lit]; + if (repr != lit) + printf ("repr[%u(%d)] = %u(%d)\n", lit, + kissat_export_literal (solver, lit), repr, + kissat_export_literal (solver, repr)); + } +} + +static void dump_gate (closure *closure, gate *g) { + const unsigned tag = g->tag; + const char *str; + switch (tag) { + case AND_GATE: + str = "AND"; + break; + case ITE_GATE: + str = "ITE"; + break; + case XOR_GATE: + str = "XOR"; + break; + default: + str = "UNKNOWN"; + break; + } + printf ("%p %s gate[%zu] ", (void *) g, str, g->id); + dump_closure_literal (closure, g->lhs); + fputs (" := ", stdout); + if (g->tag == ITE_GATE) { + dump_closure_literal (closure, g->rhs[0]); + fputs (" ? ", stdout); + dump_closure_literal (closure, g->rhs[1]); + fputs (" : ", stdout); + dump_closure_literal (closure, g->rhs[2]); + } else { + bool first = true; + for (all_rhs_literals_in_gate (rhs, g)) { + if (first) + first = false; + else if (g->tag == AND_GATE) + fputs (" & ", stdout); + else + fputs (" ^ ", stdout); + dump_closure_literal (closure, rhs); + } + } + fputs (g->indexed ? " removed" : " indexed", stdout); + if (g->garbage) + fputs (" garbage", stdout); + fputc ('\n', stdout); +} + +#define LESS_GATE(G, H) ((G)->id < (H)->id) + +static void dump_gates (closure *closure) { + gates gates; + INIT_STACK (gates); + kissat *const solver = closure->solver; + for (unsigned pos = 0; pos != closure->hash.size; pos++) { + gate *g = closure->hash.table[pos]; + if (!g) + continue; + if (g == REMOVED) + continue; + PUSH_STACK (gates, g); + } + SORT_STACK (gate *, gates, LESS_GATE); + for (all_pointers (gate, g, gates)) + dump_gate (closure, g); + RELEASE_STACK (gates); +} + +void kissat_dump_closure (closure *closure) { + dump_units (closure); + dump_equivalences (closure); + dump_gates (closure); +} + +#endif + +static bool find_subsuming_clause (closure *closure, clause *c) { + assert (!c->garbage); + kissat *const solver = closure->solver; + const reference c_ref = kissat_reference_clause (solver, c); + const value *const values = solver->values; + mark *marks = solver->marks; + { + const unsigned *const end_lits = c->lits + c->size; + for (const unsigned *p = c->lits; p != end_lits; p++) { + const unsigned lit = *p; + assert (values[lit] <= 0); + const unsigned repr_lit = find_repr (closure, lit); + const value value_repr_lit = values[repr_lit]; + assert (value_repr_lit <= 0); + if (value_repr_lit < 0) + continue; + if (marks[repr_lit]) + continue; + assert (!marks[NOT (repr_lit)]); + marks[repr_lit] = 1; + } + } + unsigned least_occurring_literal = INVALID_LIT; + unsigned count_least_occurring = UINT_MAX; + LOGREPRCLS (c, closure->repr, "trying to forward subsume"); + clause *subsuming = 0; + for (all_literals_in_clause (lit, c)) { + const unsigned repr_lit = find_repr (closure, lit); + watches *const watches = &WATCHES (repr_lit); + const watch *p = BEGIN_WATCHES (*watches); + const watch *const end = END_WATCHES (*watches); + const size_t count = end - p; + assert (count <= UINT_MAX); + if (count < count_least_occurring) { + count_least_occurring = count; + least_occurring_literal = repr_lit; + } + while (p != end) { + const watch watch = *p++; + assert (!watch.type.binary); + const reference d_ref = watch.large.ref; + clause *const d = kissat_dereference_clause (solver, d_ref); + assert (c != d); + assert (!d->garbage); + if (!c->redundant && d->redundant) + continue; + for (all_literals_in_clause (other, d)) { + const value value = values[other]; + if (value < 0) + continue; + assert (!value); + const unsigned repr_other = find_repr (closure, other); + if (!marks[repr_other]) + goto CONTINUE_WITH_NEXT_CLAUSE; + } + subsuming = d; + goto FOUND_SUBSUMING; + CONTINUE_WITH_NEXT_CLAUSE:; + } + } +FOUND_SUBSUMING: + for (all_literals_in_clause (lit, c)) { + const unsigned repr_lit = find_repr (closure, lit); + const value value = values[repr_lit]; + if (!value) + marks[repr_lit] = 0; + } + if (subsuming) { + LOGREPRCLS (c, closure->repr, "subsumed"); + LOGREPRCLS (subsuming, closure->repr, "subsuming"); + kissat_mark_clause_as_garbage (solver, c); + INC (congruent_subsumed); + return true; + } else { + assert (least_occurring_literal != INVALID_LIT); + assert (count_least_occurring < UINT_MAX); + LOGCLS (c, "forward subsumption failed of"); + LOG ("connecting %u occurring %s", count_least_occurring, + LOGLIT (least_occurring_literal)); + kissat_connect_literal (solver, least_occurring_literal, c_ref); + return false; + } +} + +struct refsize { + reference ref; + unsigned size; +}; + +typedef struct refsize refsize; +typedef STACK (refsize) refsizes; + +#define RANKREFSIZE(REFSIZE) ((REFSIZE).size) + +static void sort_references_by_clause_size (kissat *solver, + refsizes *candidates) { + RADIX_STACK (refsize, unsigned, *candidates, RANKREFSIZE); +} + +static void forward_subsume_matching_clauses (closure *closure) { + kissat *const solver = closure->solver; + START (matching); + reset_closure (closure); + litpairs binaries; + INIT_STACK (binaries); + kissat_enter_dense_mode (solver, &binaries); + bool *matchable; +#ifndef QUIET + unsigned count_matchable = 0; +#endif + CALLOC (matchable, VARS); + for (all_variables (idx)) + if (ACTIVE (idx)) { + const unsigned lit = LIT (idx); + const unsigned repr = find_repr (closure, lit); + if (lit == repr) + continue; + const unsigned repr_idx = IDX (repr); + if (!matchable[idx]) { + LOG ("matchable %s", LOGVAR (idx)); + matchable[idx] = true; +#ifndef QUIET + count_matchable++; +#endif + } + if (!matchable[repr_idx]) { + LOG ("matchable %s", LOGVAR (repr_idx)); + matchable[repr_idx] = true; +#ifndef QUIET + count_matchable++; +#endif + } + } + kissat_phase (solver, "congruence", GET (closures), + "found %u matchable variables %.0f%%", count_matchable, + kissat_percent (count_matchable, solver->active)); + size_t potential = 0; + refsizes candidates; + INIT_STACK (candidates); + clause *last_irredundant = kissat_last_irredundant_clause (solver); + const value *const values = solver->values; + mark *const marks = solver->marks; + unsigneds *marked = &solver->analyzed; + for (all_clauses (c)) { + if (c->garbage) + continue; + if (last_irredundant && last_irredundant < c) + break; + potential++; + bool contains_matchable = false; + assert (EMPTY_STACK (*marked)); + LOGREPRCLS (c, closure->repr, "considering"); + for (all_literals_in_clause (lit, c)) { + const value value = values[lit]; + if (value < 0) + continue; + if (value > 0) { + LOGCLS (c, "satisfied %s in", LOGLIT (lit)); + kissat_mark_clause_as_garbage (solver, c); + break; + } + if (!contains_matchable) { + const unsigned lit_idx = IDX (lit); + if (matchable[lit_idx]) + contains_matchable = true; + } + const unsigned repr = find_repr (closure, lit); + assert (!values[repr]); + if (marks[repr]) + continue; + const unsigned not_repr = NOT (repr); + if (marks[not_repr]) { + LOGCLS (c, "matches both %s and %s", CLOGREPR (lit), + LOGLIT (not_repr)); + kissat_mark_clause_as_garbage (solver, c); + break; + } + marks[repr] = 1; + PUSH_STACK (*marked, repr); + } + const size_t size = SIZE_STACK (*marked); + for (all_stack (unsigned, repr, *marked)) + marks[repr] = 0; + CLEAR_STACK (*marked); + if (c->garbage) + continue; + if (!contains_matchable) { + LOGREPRCLS (c, closure->repr, "no matchable variable in"); + continue; + } + const reference ref = kissat_reference_clause (solver, c); + assert (size <= UINT_MAX); + refsize refsize = {.ref = ref, .size = size}; + PUSH_STACK (candidates, refsize); + } + DEALLOC (matchable, VARS); +#ifndef QUIET + const size_t size_candidates = SIZE_STACK (candidates); + kissat_very_verbose ( + solver, "considering %zu matchable subsumption candidates %.0f%%", + size_candidates, kissat_percent (size_candidates, potential)); +#else + (void) potential; +#endif + sort_references_by_clause_size (solver, &candidates); +#ifndef QUIET + size_t tried = 0, subsumed = 0; +#endif + for (all_stack (refsize, refsize, candidates)) { + if (TERMINATED (congruence_terminated_7)) + break; +#ifndef QUIET + tried++; +#endif + const unsigned ref = refsize.ref; + clause *c = kissat_dereference_clause (solver, ref); + if (find_subsuming_clause (closure, c)) { +#ifndef QUIET + subsumed++; +#endif + } + } + kissat_phase (solver, "congruence", GET (closures), + "subsumed %zu clauses out of %zu tried %.0f%%", subsumed, + tried, kissat_percent (subsumed, tried)); + kissat_resume_sparse_mode (solver, false, &binaries); + RELEASE_STACK (candidates); + RELEASE_STACK (binaries); + STOP (matching); +} + +bool kissat_congruence (kissat *solver) { + if (solver->inconsistent) + return false; + kissat_check_statistics (solver); + assert (!solver->level); + assert (solver->probing); + assert (solver->watching); + if (!GET_OPTION (congruence)) + return false; + if (!GET_OPTION (congruenceands) && !GET_OPTION (congruenceites) && + !GET_OPTION (congruencexors)) + return false; + if (GET_OPTION (congruenceonce) && solver->statistics.closures) + return false; + if (TERMINATED (congruence_terminated_8)) + return false; + if (DELAYING (congruence)) + return false; + START (congruence); + INC (closures); + closure closure; + init_closure (solver, &closure); + extract_gates (&closure); + bool reset = false; + if (!solver->inconsistent && !TERMINATED (congruence_terminated_9)) { + find_units (&closure); + if (!solver->inconsistent && !TERMINATED (congruence_terminated_10)) { + find_equivalences (&closure); + if (!solver->inconsistent && !TERMINATED (congruence_terminated_11)) { + size_t propagated = propagate_units_and_equivalences (&closure); + if (!solver->inconsistent && propagated && + !TERMINATED (congruence_terminated_12)) { + forward_subsume_matching_clauses (&closure); + reset = true; + } + } + } + } + if (!reset) + reset_closure (&closure); + unsigned equivalent = reset_repr (&closure); + kissat_phase (solver, "congruence", GET (closures), + "merged %u equivalent variables %.2f%%", equivalent, + kissat_percent (equivalent, solver->active)); + assert (solver->active >= equivalent); +#ifndef QUIET + solver->active -= equivalent; + REPORT (!equivalent, 'c'); + if (!solver->inconsistent) + solver->active += equivalent; +#endif + if (kissat_average (equivalent, solver->active) < 0.001) + BUMP_DELAY (congruence); + else + REDUCE_DELAY (congruence); + STOP (congruence); + kissat_check_statistics (solver); + return equivalent; +} diff --git a/src/sat/kissat/congruence.h b/src/sat/kissat/congruence.h new file mode 100644 index 000000000..84e1eb643 --- /dev/null +++ b/src/sat/kissat/congruence.h @@ -0,0 +1,9 @@ +#ifndef _congruence_h_INCLUDED +#define _congruence_h_INCLUDED + +#include + +struct kissat; +bool kissat_congruence (struct kissat *); + +#endif diff --git a/src/sat/kissat/cover.h b/src/sat/kissat/cover.h new file mode 100644 index 000000000..f5a82b71e --- /dev/null +++ b/src/sat/kissat/cover.h @@ -0,0 +1,28 @@ +#ifndef _cover_h_INCLUDED +#define _cover_h_INCLUDED + +#include +#include + +#define COVER(COND) \ + ((COND) ? \ +\ + (fflush (stdout), \ + fprintf (stderr, "%s:%ld: %s: Coverage goal `%s' reached.\n", \ + __FILE__, (long) __LINE__, __func__, #COND), \ + abort (), (void) 0) \ + : (void) 0) + +#ifdef COVERAGE +#define FLUSH_COVERAGE() \ + do { \ + void __gcov_dump (void); \ + __gcov_dump (); \ + } while (0) +#else +#define FLUSH_COVERAGE() \ + do { \ + } while (0) +#endif + +#endif diff --git a/src/sat/kissat/decide.c b/src/sat/kissat/decide.c new file mode 100644 index 000000000..522930e26 --- /dev/null +++ b/src/sat/kissat/decide.c @@ -0,0 +1,244 @@ +#include "decide.h" +#include "inlineframes.h" +#include "inlineheap.h" +#include "inlinequeue.h" +#include "print.h" + +#include + +static unsigned last_enqueued_unassigned_variable (kissat *solver) { + assert (solver->unassigned); + const links *const links = solver->links; + const value *const values = solver->values; + unsigned res = solver->queue.search.idx; + if (values[LIT (res)]) { + do { + res = links[res].prev; + assert (!DISCONNECTED (res)); + } while (values[LIT (res)]); + kissat_update_queue (solver, links, res); + } +#ifdef LOGGING + const unsigned stamp = links[res].stamp; + LOG ("last enqueued unassigned %s stamp %u", LOGVAR (res), stamp); +#endif +#ifdef CHECK_QUEUE + for (unsigned i = links[res].next; !DISCONNECTED (i); i = links[i].next) + assert (VALUE (LIT (i))); +#endif + return res; +} + +static unsigned largest_score_unassigned_variable (kissat *solver) { + heap *scores = SCORES; + unsigned res = kissat_max_heap (scores); + const value *const values = solver->values; + while (values[LIT (res)]) { + kissat_pop_max_heap (solver, scores); + res = kissat_max_heap (scores); + } +#if defined(LOGGING) || defined(CHECK_HEAP) + const double score = kissat_get_heap_score (scores, res); +#endif + LOG ("largest score unassigned %s score %g", LOGVAR (res), score); +#ifdef CHECK_HEAP + for (all_variables (idx)) { + if (!ACTIVE (idx)) + continue; + if (VALUE (LIT (idx))) + continue; + const double idx_score = kissat_get_heap_score (scores, idx); + assert (score >= idx_score); + } +#endif + return res; +} + +void kissat_start_random_sequence (kissat *solver) { + if (!GET_OPTION (randec)) + return; + + if (solver->stable && !GET_OPTION (randecstable)) + return; + + if (!solver->stable && !GET_OPTION (randecfocused)) + return; + + if (solver->randec) + kissat_very_verbose (solver, + "continuing random decision sequence " + "at %s conflicts", + FORMAT_COUNT (CONFLICTS)); + else { + INC (random_sequences); + const uint64_t count = solver->statistics.random_sequences; + const unsigned length = GET_OPTION (randeclength) * LOGN (count); + kissat_very_verbose (solver, + "starting random decision sequence " + "at %s conflicts for %s conflicts", + FORMAT_COUNT (CONFLICTS), FORMAT_COUNT (length)); + solver->randec = length; + + UPDATE_CONFLICT_LIMIT (randec, random_sequences, LOGN, false); + } +} + +static unsigned next_random_decision (kissat *solver) { + if (!VARS) + return INVALID_IDX; + + if (solver->warming) + return INVALID_IDX; + + if (!GET_OPTION (randec)) + return INVALID_IDX; + + if (solver->stable && !GET_OPTION (randecstable)) + return INVALID_IDX; + + if (!solver->stable && !GET_OPTION (randecfocused)) + return INVALID_IDX; + + if (!solver->randec) { + assert (solver->level); + if (solver->level > 1) + return INVALID_IDX; + + uint64_t conflicts = CONFLICTS; + limits *limits = &solver->limits; + if (conflicts < limits->randec.conflicts) + return INVALID_IDX; + + kissat_start_random_sequence (solver); + } + + for (;;) { + unsigned idx = kissat_next_random32 (&solver->random) % VARS; + if (!ACTIVE (idx)) + continue; + unsigned lit = LIT (idx); + if (solver->values[lit]) + continue; + return idx; + } +} + +unsigned kissat_next_decision_variable (kissat *solver) { +#ifdef LOGGING + const char *type = 0; +#endif + unsigned res = next_random_decision (solver); + if (res == INVALID_IDX) { + if (solver->stable) { +#ifdef LOGGING + type = "maximum score"; +#endif + res = largest_score_unassigned_variable (solver); + INC (score_decisions); + } else { +#ifdef LOGGING + type = "dequeued"; +#endif + res = last_enqueued_unassigned_variable (solver); + INC (queue_decisions); + } + } else { +#ifdef LOGGING + type = "random"; +#endif + INC (random_decisions); + } + LOG ("next %s decision %s", type, LOGVAR (res)); + return res; +} + +int kissat_decide_phase (kissat *solver, unsigned idx) { + bool force = GET_OPTION (forcephase); + + value *target; + if (force) + target = 0; + else if (!GET_OPTION (target)) + target = 0; + else if (solver->stable || GET_OPTION (target) > 1) + target = solver->phases.target + idx; + else + target = 0; + + value *saved; + if (force) + saved = 0; + else if (GET_OPTION (phasesaving)) + saved = solver->phases.saved + idx; + else + saved = 0; + + value res = 0; + + if (!solver->stable) { + switch ((solver->statistics.switched >> 1) & 7) { + case 1: + res = INITIAL_PHASE; + break; + case 3: + res = -INITIAL_PHASE; + break; + } + } + + if (!res && target && (res = *target)) { + LOG ("%s uses target decision phase %d", LOGVAR (idx), (int) res); + INC (target_decisions); + } + + if (!res && saved && (res = *saved)) { + LOG ("%s uses saved decision phase %d", LOGVAR (idx), (int) res); + INC (saved_decisions); + } + + if (!res) { + res = INITIAL_PHASE; + LOG ("%s uses initial decision phase %d", LOGVAR (idx), (int) res); + INC (initial_decisions); + } + assert (res); + + return res < 0 ? -1 : 1; +} + +void kissat_decide (kissat *solver) { + START (decide); + assert (solver->unassigned); + if (solver->warming) + INC (warming_decisions); + else { + INC (decisions); + if (solver->stable) + INC (stable_decisions); + else + INC (focused_decisions); + } + solver->level++; + assert (solver->level != INVALID_LEVEL); + const unsigned idx = kissat_next_decision_variable (solver); + const value value = kissat_decide_phase (solver, idx); + unsigned lit = LIT (idx); + if (value < 0) + lit = NOT (lit); + kissat_push_frame (solver, lit); + assert (solver->level < SIZE_STACK (solver->frames)); + LOG ("decide literal %s", LOGLIT (lit)); + kissat_assign_decision (solver, lit); + STOP (decide); +} + +void kissat_internal_assume (kissat *solver, unsigned lit) { + assert (solver->unassigned); + assert (!VALUE (lit)); + solver->level++; + assert (solver->level != INVALID_LEVEL); + kissat_push_frame (solver, lit); + assert (solver->level < SIZE_STACK (solver->frames)); + LOG ("assuming literal %s", LOGLIT (lit)); + kissat_assign_decision (solver, lit); +} diff --git a/src/sat/kissat/decide.h b/src/sat/kissat/decide.h new file mode 100644 index 000000000..9864ae2e1 --- /dev/null +++ b/src/sat/kissat/decide.h @@ -0,0 +1,14 @@ +#ifndef _decide_h_INCLUDED +#define _decide_h_INCLUDED + +struct kissat; + +void kissat_decide (struct kissat *); +void kissat_start_random_sequence (struct kissat *); +void kissat_internal_assume (struct kissat *, unsigned lit); +unsigned kissat_next_decision_variable (struct kissat *); +int kissat_decide_phase (struct kissat *, unsigned idx); + +#define INITIAL_PHASE (GET_OPTION (phase) ? 1 : -1) + +#endif diff --git a/src/sat/kissat/deduce.c b/src/sat/kissat/deduce.c new file mode 100644 index 000000000..be1235f69 --- /dev/null +++ b/src/sat/kissat/deduce.c @@ -0,0 +1,168 @@ +#include "deduce.h" +#include "inline.h" +#include "promote.h" +#include "strengthen.h" + +static inline void recompute_and_promote (kissat *solver, clause *c) { + assert (c->redundant); + const unsigned old_glue = c->glue; + const unsigned new_glue = kissat_recompute_glue (solver, c, old_glue); + if (new_glue < old_glue) + kissat_promote_clause (solver, c, new_glue); +} + +static inline void mark_clause_as_used (kissat *solver, clause *c) { + if (!c->redundant) + return; + INC (clauses_used); + c->used = MAX_USED; + LOGCLS (c, "using"); + recompute_and_promote (solver, c); + unsigned glue = MIN (c->glue, MAX_GLUE_USED); + solver->statistics.used[solver->stable].glue[glue]++; + if (solver->stable) + INC (clauses_used_stable); + else + INC (clauses_used_focused); +} + +bool kissat_recompute_and_promote (kissat *solver, clause *c) { + assert (c->redundant); + const unsigned old_glue = c->glue; + const unsigned new_glue = kissat_recompute_glue (solver, c, old_glue); + if (new_glue >= old_glue) + return false; + kissat_promote_clause (solver, c, new_glue); + return true; +} + +static inline bool analyze_literal (kissat *solver, assigned *all_assigned, + frame *frames, unsigned lit) { + assert (VALUE (lit) < 0); + const unsigned idx = IDX (lit); + assigned *a = all_assigned + idx; + const unsigned level = a->level; + if (!level) + return false; + solver->antecedent_size++; + if (a->analyzed) + return false; + LOG ("analyzing literal %s", LOGLIT (lit)); + kissat_push_analyzed (solver, all_assigned, idx); + assert (level <= solver->level); +#if defined(LOGGING) || !defined(NDEBUG) + PUSH_STACK (solver->resolvent, lit); +#endif + solver->resolvent_size++; + if (level == solver->level) + return true; + assert (a->analyzed); + PUSH_STACK (solver->clause, lit); + LOG ("learned literal %s", LOGLIT (lit)); + frame *f = frames + level; + if (f->used++) + return false; + LOG ("pulling in decision level %u", level); + PUSH_STACK (solver->levels, level); + return false; +} + +clause *kissat_deduce_first_uip_clause (kissat *solver, clause *conflict) { + START (deduce); + assert (EMPTY_STACK (solver->analyzed)); + assert (EMPTY_STACK (solver->levels)); + assert (EMPTY_STACK (solver->clause)); +#if defined(LOGGING) || !defined(NDEBUG) + CLEAR_STACK (solver->resolvent); +#endif + if (conflict->size > 2) + mark_clause_as_used (solver, conflict); + PUSH_STACK (solver->clause, INVALID_LIT); + solver->antecedent_size = 0; + solver->resolvent_size = 0; + unsigned unresolved_on_current_level = 0, conflict_size = 0; + assigned *all_assigned = solver->assigned; + frame *frames = BEGIN_STACK (solver->frames); + for (all_literals_in_clause (lit, conflict)) { + assert (VALUE (lit) < 0); + if (LEVEL (lit)) + conflict_size++; + if (analyze_literal (solver, all_assigned, frames, lit)) + unresolved_on_current_level++; + } + assert (unresolved_on_current_level > 1); + LOG ("starting with %u unresolved literals on current decision level", + unresolved_on_current_level); + assert (solver->antecedent_size == solver->resolvent_size); + LOGRES2 ("initial"); + const bool otfs = GET_OPTION (otfs); + unsigned const *t = END_ARRAY (solver->trail); + unsigned uip = INVALID_LIT; + unsigned resolved = 0; + assigned *a = 0; + for (;;) { + do { + assert (t > BEGIN_ARRAY (solver->trail)); + uip = *--t; + a = ASSIGNED (uip); + } while (!a->analyzed || a->level != solver->level); + if (unresolved_on_current_level == 1) + break; + assert (a->reason != DECISION_REASON); + assert (a->level == solver->level); + solver->antecedent_size = 1; + resolved++; + if (a->binary) { + const unsigned other = a->reason; + LOGBINARY (uip, other, "resolving %s reason", LOGLIT (uip)); + if (analyze_literal (solver, all_assigned, frames, other)) + unresolved_on_current_level++; + } else { + const reference ref = a->reason; + LOGREF (ref, "resolving %s reason", LOGLIT (uip)); + clause *reason = kissat_dereference_clause (solver, ref); + for (all_literals_in_clause (lit, reason)) + if (lit != uip && + analyze_literal (solver, all_assigned, frames, lit)) + unresolved_on_current_level++; + mark_clause_as_used (solver, reason); + } + assert (unresolved_on_current_level > 0); + unresolved_on_current_level--; + LOG ("after resolving %s there are %u literals left " + "on current decision level", + LOGLIT (uip), unresolved_on_current_level); + assert (solver->resolvent_size > 0); + solver->resolvent_size--; +#if defined(LOGGING) || !defined(NDEBUG) + LOG2 ("actual antecedent size %u", solver->antecedent_size); + REMOVE_STACK (unsigned, solver->resolvent, NOT (uip)); + assert (SIZE_STACK (solver->resolvent) == solver->resolvent_size); + LOGRES2 ("new"); +#endif + if (otfs && solver->antecedent_size > 2 && + solver->resolvent_size < solver->antecedent_size) { + assert (!a->binary); + assert (solver->antecedent_size && solver->resolvent_size + 1); + clause *reason = kissat_dereference_clause (solver, a->reason); + assert (!reason->garbage); + clause *res = kissat_on_the_fly_strengthen (solver, reason, uip); + if (resolved == 1 && solver->resolvent_size < conflict_size) { + assert (!conflict->garbage); + assert (conflict_size > 2); + kissat_on_the_fly_subsume (solver, res, conflict); + } + STOP (deduce); + return res; + } + } + assert (uip != INVALID_LIT); + LOG ("first unique implication point %s (1st UIP)", LOGLIT (uip)); + assert (PEEK_STACK (solver->clause, 0) == INVALID_LIT); + POKE_STACK (solver->clause, 0, NOT (uip)); + LOGTMP ("deduced not yet minimized 1st UIP"); + if (!solver->probing) + ADD (literals_deduced, SIZE_STACK (solver->clause)); + STOP (deduce); + return 0; +} diff --git a/src/sat/kissat/deduce.h b/src/sat/kissat/deduce.h new file mode 100644 index 000000000..38a5ec4c0 --- /dev/null +++ b/src/sat/kissat/deduce.h @@ -0,0 +1,14 @@ +#ifndef _deduce_h_INCLUDED +#define _deduce_h_INCLUDED + +#include + +struct clause; +struct kissat; + +struct clause *kissat_deduce_first_uip_clause (struct kissat *, + struct clause *); + +bool kissat_recompute_and_promote (struct kissat *, struct clause *); + +#endif diff --git a/src/sat/kissat/definition.c b/src/sat/kissat/definition.c new file mode 100644 index 000000000..759a4f906 --- /dev/null +++ b/src/sat/kissat/definition.c @@ -0,0 +1,230 @@ +#include "definition.h" +#include "allocate.h" +#include "gates.h" +#include "inline.h" +#include "kitten.h" +#include "print.h" + +typedef struct definition_extractor definition_extractor; + +struct definition_extractor { + unsigned lit; + kissat *solver; + watches *watches[2]; +}; + +static void traverse_definition_core (void *state, unsigned id) { + definition_extractor *extractor = state; + kissat *solver = extractor->solver; + watch watch; + watches *watches0 = extractor->watches[0]; + watches *watches1 = extractor->watches[1]; + const size_t size_watches0 = SIZE_WATCHES (*watches0); + assert (size_watches0 <= UINT_MAX); + unsigned sign; + if (id < size_watches0) { + watch = BEGIN_WATCHES (*watches0)[id]; + LOGWATCH (extractor->lit, watch, "gate[0]"); + sign = 0; + } else { + unsigned tmp = id - size_watches0; +#ifndef NDEBUG + const size_t size_watches1 = SIZE_WATCHES (*watches1); + assert (size_watches1 <= UINT_MAX); + assert (tmp < size_watches1); +#endif + watch = BEGIN_WATCHES (*watches1)[tmp]; + LOGWATCH (NOT (extractor->lit), watch, "gate[1]"); + sign = 1; + } + PUSH_STACK (solver->gates[sign], watch); +} + +#if !defined(NDEBUG) || !defined(NPROOFS) + +typedef struct lemma_extractor lemma_extractor; + +struct lemma_extractor { + kissat *solver; + unsigned lemmas; + unsigned unit; +}; + +static void traverse_one_sided_core_lemma (void *state, bool learned, + size_t size, + const unsigned *lits) { + if (!learned) + return; + lemma_extractor *extractor = state; + kissat *solver = extractor->solver; + const unsigned unit = extractor->unit; + unsigneds *added = &solver->added; + assert (extractor->lemmas || EMPTY_STACK (*added)); + if (size) { + PUSH_STACK (*added, size + 1); + const size_t offset = SIZE_STACK (*added); + PUSH_STACK (*added, unit); + const unsigned *end = lits + size; + for (const unsigned *p = lits; p != end; p++) + PUSH_STACK (*added, *p); + unsigned *extended = &PEEK_STACK (*added, offset); + assert (offset + size + 1 == SIZE_STACK (*added)); + CHECK_AND_ADD_LITS (size + 1, extended); + ADD_LITS_TO_PROOF (size + 1, extended); + } else { + kissat_learned_unit (solver, unit); + const unsigned *end = END_STACK (*added); + unsigned *begin = BEGIN_STACK (*added); + for (unsigned *p = begin, size; p != end; p += size) { + size = *p++; + assert (p + size <= end); + REMOVE_CHECKER_LITS (size, p); + DELETE_LITS_FROM_PROOF (size, p); + } + CLEAR_STACK (*added); + } + extractor->lemmas++; +} + +#endif + +bool kissat_find_definition (kissat *solver, unsigned lit) { + if (!GET_OPTION (definitions)) + return false; + START (definition); + struct kitten *kitten = solver->kitten; + assert (kitten); + kitten_clear (kitten); + const unsigned not_lit = NOT (lit); + definition_extractor extractor; + extractor.lit = lit; + extractor.solver = solver; + extractor.watches[0] = &WATCHES (lit); + extractor.watches[1] = &WATCHES (not_lit); + kitten_track_antecedents (kitten); + unsigned exported = 0; +#if !defined(QUIET) || !defined(NDEBUG) + size_t occs[2] = {0, 0}; +#endif + for (unsigned sign = 0; sign < 2; sign++) { + const unsigned except = sign ? not_lit : lit; + for (all_binary_large_watches (watch, *extractor.watches[sign])) { + if (watch.type.binary) { + const unsigned other = watch.binary.lit; + kitten_clause_with_id_and_exception (kitten, exported, 1, &other, + INVALID_LIT); + } else { + const reference ref = watch.large.ref; + clause *c = kissat_dereference_clause (solver, ref); + kitten_clause_with_id_and_exception (kitten, exported, c->size, + c->lits, except); + } +#if !defined(QUIET) || !defined(NDEBUG) + occs[sign]++; +#endif + exported++; + } + } + bool res = false; + LOG ("exported %u = %zu + %zu environment clauses to sub-solver", + exported, occs[0], occs[1]); + INC (definitions_checked); + const size_t limit = GET_OPTION (definitionticks); + kitten_set_ticks_limit (kitten, limit); + int status = kitten_solve (kitten); + if (status == 20) { + LOG ("sub-solver result UNSAT shows definition exists"); + uint64_t learned; + unsigned reduced = kitten_compute_clausal_core (kitten, &learned); + LOG ("1st sub-solver core of size %u original clauses out of %u", + reduced, exported); + for (int i = 2; i <= GET_OPTION (definitioncores); i++) { + kitten_shrink_to_clausal_core (kitten); + kitten_shuffle_clauses (kitten); + kitten_set_ticks_limit (kitten, 10 * limit); + int tmp = kitten_solve (kitten); + assert (!tmp || tmp == 20); + if (!tmp) { + LOG ("aborting core extraction"); + goto ABORT; + } +#ifndef NDEBUG + unsigned previous = reduced; +#endif + reduced = kitten_compute_clausal_core (kitten, &learned); + LOG ("%s sub-solver core of size %u original clauses out of %u", + FORMAT_ORDINAL (i), reduced, exported); + assert (reduced <= previous); +#if defined(QUIET) && defined(NDEBUG) + (void) reduced; +#endif + } + INC (definitions_extracted); + kitten_traverse_core_ids (kitten, &extractor, traverse_definition_core); + size_t size[2]; + size[0] = SIZE_STACK (solver->gates[0]); + size[1] = SIZE_STACK (solver->gates[1]); +#if !defined(QUIET) || !defined(NDEBUG) + assert (reduced == size[0] + size[1]); +#ifdef METRICS + kissat_extremely_verbose ( + solver, + "definition extracted[%" PRIu64 "] " + "size %u = %zu + %zu clauses %.0f%% " + "of %u = %zu + %zu (checked %" PRIu64 ")", + solver->statistics.definitions_extracted, reduced, size[0], size[1], + kissat_percent (reduced, exported), exported, occs[0], occs[1], + solver->statistics.definitions_checked); +#else + kissat_extremely_verbose (solver, + "definition extracted with core " + "size %u = %zu + %zu clauses %.0f%% " + "of %u = %zu + %zu", + reduced, size[0], size[1], + kissat_percent (reduced, exported), exported, + occs[0], occs[1]); +#endif +#endif + unsigned unit = INVALID_LIT; + if (!size[0]) { + unit = not_lit; + assert (size[1]); + } else if (!size[1]) + unit = lit; + + if (unit != INVALID_LIT) { + INC (definition_units); + + kissat_extremely_verbose (solver, "one sided core " + "definition extraction yields " + "failed literal"); +#if !defined(NDEBUG) || !defined(NPROOFS) + if (false +#ifndef NDEBUG + || GET_OPTION (check) > 1 +#endif +#ifndef NPROOFS + || solver->proof +#endif + ) { + lemma_extractor extractor; + extractor.solver = solver; + extractor.unit = unit; + extractor.lemmas = 0; + kitten_traverse_core_clauses (kitten, &extractor, + traverse_one_sided_core_lemma); + } else +#endif + kissat_learned_unit (solver, unit); + } + solver->gate_eliminated = GATE_ELIMINATED (definitions); + solver->resolve_gate = true; + res = true; + } else { + ABORT: + LOG ("sub-solver failed to show that definition exists"); + } + CLEAR_STACK (solver->analyzed); + STOP (definition); + return res; +} diff --git a/src/sat/kissat/definition.h b/src/sat/kissat/definition.h new file mode 100644 index 000000000..2fea782c0 --- /dev/null +++ b/src/sat/kissat/definition.h @@ -0,0 +1,10 @@ +#ifndef _definition_h_INCLUDED +#define _definition_h_INCLUDED + +#include + +struct kissat; + +bool kissat_find_definition (struct kissat *, unsigned lit); + +#endif diff --git a/src/sat/kissat/dense.c b/src/sat/kissat/dense.c new file mode 100644 index 000000000..d7592419a --- /dev/null +++ b/src/sat/kissat/dense.c @@ -0,0 +1,235 @@ +#define INLINE_SORT + +#include "dense.h" +#include "inline.h" +#include "proprobe.h" +#include "propsearch.h" +#include "trail.h" + +#include "sort.c" + +#include + +static void flush_large_watches (kissat *solver, litpairs *irredundant) { + assert (!solver->level); + assert (solver->watching); +#ifndef LOGGING + LOG ("flushing large watches"); + if (irredundant) + LOG ("flushing and saving irredundant binary clauses too"); + else + LOG ("keep watching irredundant binary clauses"); +#endif + const value *const values = solver->values; + mark *const marks = solver->marks; +#ifndef NDEBUG + for (all_literals (lit)) + assert (!marks[lit]); +#endif + size_t flushed = 0, collected = 0; +#ifdef LOGGING + size_t deduplicated = 0; +#endif + watches *all_watches = solver->watches; + unsigneds *marked = &solver->analyzed; + for (all_literals (lit)) { + const value lit_value = values[lit]; + watches *watches = all_watches + lit; + watch *begin = BEGIN_WATCHES (*watches), *q = begin; + const watch *const end_watches = END_WATCHES (*watches), *p = q; + assert (EMPTY_STACK (*marked)); + while (p != end_watches) { + const watch watch = *p++; + if (watch.type.binary) { + const unsigned other = watch.binary.lit; + const value other_value = values[other]; + if (!lit_value && !other_value) { + const mark mark = marks[other]; + if (mark) { + if (lit < other) { + kissat_delete_binary (solver, lit, other); +#ifdef LOGGING + deduplicated++; +#endif + } + } else { + marks[other] = 1; + PUSH_STACK (*marked, other); + if (irredundant) { + const unsigned other = watch.binary.lit; + if (lit < other) { + const litpair litpair = {.lits = {lit, other}}; + PUSH_STACK (*irredundant, litpair); + } + } else + *q++ = watch; + } + } else { + assert (lit_value > 0 || other_value > 0); + if (lit < other) { + kissat_delete_binary (solver, lit, other); + collected++; + } + } + } else { + flushed++; + p++; + } + } + if (irredundant) + memset (watches, 0, sizeof *watches); + else + SET_END_OF_WATCHES (*watches, q); + for (all_stack (unsigned, other, *marked)) + marks[other] = 0; + CLEAR_ARRAY (*marked); + } + assert (EMPTY_STACK (*marked)); + LOG ("flushed %zu large watches", flushed); + LOG ("removed %zu duplicated binary clauses", deduplicated); + LOG ("collected %zu satisfied binary clauses", collected); + if (irredundant) { + LOG ("saved %zu irredundant binary clauses", SIZE_STACK (*irredundant)); + kissat_release_vectors (solver); + } + (void) collected; + (void) flushed; +} + +void kissat_enter_dense_mode (kissat *solver, litpairs *irredundant) { + assert (!solver->level); + assert (solver->watching); + assert (kissat_propagated (solver)); + LOG ("entering dense mode with full occurrence lists"); + if (irredundant) + flush_large_watches (solver, irredundant); + else + kissat_flush_large_watches (solver); + LOG ("switched to full occurrence lists"); + solver->watching = false; +} + +static void resume_watching_irredundant_binaries (kissat *solver, + litpairs *binaries) { + assert (binaries); +#ifdef LOGGING + size_t resumed_watching = 0; +#endif + watches *all_watches = solver->watches; + for (all_stack (litpair, litpair, *binaries)) { + const unsigned first = litpair.lits[0]; + const unsigned second = litpair.lits[1]; + + assert (!ELIMINATED (IDX (first))); + assert (!ELIMINATED (IDX (second))); + + watches *first_watches = all_watches + first; + watch first_watch = kissat_binary_watch (second); + PUSH_WATCHES (*first_watches, first_watch); + + watches *second_watches = all_watches + second; + watch second_watch = kissat_binary_watch (first); + PUSH_WATCHES (*second_watches, second_watch); + +#ifdef LOGGING + resumed_watching++; +#endif + } + LOG ("resumed watching %zu binary clauses", resumed_watching); +} + +static void +resume_watching_large_clauses_after_elimination (kissat *solver) { +#ifdef LOGGING + size_t resumed_watching_redundant = 0; + size_t resumed_watching_irredundant = 0; +#endif + const flags *const flags = solver->flags; + watches *watches = solver->watches; + const value *const values = solver->values; + const assigned *const assigned = solver->assigned; + ward *const arena = BEGIN_STACK (solver->arena); + + for (all_clauses (c)) { + if (c->garbage) + continue; + bool collect = false; + for (all_literals_in_clause (lit, c)) { + if (values[lit] > 0) { + LOGCLS (c, "%s satisfied", LOGLIT (lit)); + collect = true; + break; + } + const unsigned idx = IDX (lit); + if (flags[idx].eliminated) { + LOGCLS (c, "containing eliminated %s", LOGLIT (lit)); + collect = true; + break; + } + } + if (collect) { + kissat_mark_clause_as_garbage (solver, c); + continue; + } + + assert (c->size > 2); + + unsigned *lits = c->lits; + kissat_sort_literals (solver, values, assigned, c->size, lits); + c->searched = 2; + + const reference ref = (ward *) c - arena; + const unsigned l0 = lits[0]; + const unsigned l1 = lits[1]; + + kissat_push_blocking_watch (solver, watches + l0, l1, ref); + kissat_push_blocking_watch (solver, watches + l1, l0, ref); + +#ifdef LOGGING + if (c->redundant) + resumed_watching_redundant++; + else + resumed_watching_irredundant++; +#endif + } + LOG ("resumed watching %zu irredundant and %zu redundant large clauses", + resumed_watching_irredundant, resumed_watching_redundant); +} + +void kissat_resume_sparse_mode (kissat *solver, bool flush_eliminated, + litpairs *irredundant) { + assert (!solver->level); + assert (!solver->watching); + if (solver->inconsistent) + return; + LOG ("resuming sparse mode watching clauses"); + kissat_flush_large_connected (solver); + LOG ("switched to watching clauses"); + solver->watching = true; + if (irredundant) { + LOG ("resuming watching %zu irredundant binaries", + SIZE_STACK (*irredundant)); + resume_watching_irredundant_binaries (solver, irredundant); + } + if (flush_eliminated) + resume_watching_large_clauses_after_elimination (solver); + else + kissat_watch_large_clauses (solver); + LOG ("forcing to propagate units on all clauses"); + kissat_reset_propagate (solver); + + clause *conflict; + if (solver->probing) + conflict = kissat_probing_propagate (solver, 0, true); + else + conflict = kissat_search_propagate (solver); + +#ifndef NDEBUG + if (conflict) + assert (solver->inconsistent); + else + assert (kissat_trail_flushed (solver)); +#else + (void) conflict; +#endif +} diff --git a/src/sat/kissat/dense.h b/src/sat/kissat/dense.h new file mode 100644 index 000000000..171e4e5ac --- /dev/null +++ b/src/sat/kissat/dense.h @@ -0,0 +1,12 @@ +#ifndef _dense_h_INCLUDED +#define _dense_h_INCLUDED + +#include "watch.h" + +void kissat_enter_dense_mode (struct kissat *, + litpairs *saved_irredundant_binary_clauses); + +void kissat_resume_sparse_mode (struct kissat *, bool flush_eliminated, + litpairs *); + +#endif diff --git a/src/sat/kissat/dump.c b/src/sat/kissat/dump.c new file mode 100644 index 000000000..e8598b130 --- /dev/null +++ b/src/sat/kissat/dump.c @@ -0,0 +1,293 @@ +#ifndef NDEBUG + +#include "inline.h" + +#include + +static void dump_literal (kissat *solver, unsigned ilit) { + const int elit = kissat_export_literal (solver, ilit); + printf ("%u(%d)", ilit, elit); + const int value = VALUE (ilit); + if (value) { + const unsigned ilit_level = LEVEL (ilit); + printf ("@%u=%d", ilit_level, value); + } +} + +static void dump_binary (kissat *solver, unsigned a, unsigned b) { + printf ("binary clause "); + dump_literal (solver, a); + fputc (' ', stdout); + dump_literal (solver, b); + fputc ('\n', stdout); +} + +static void dump_clause (kissat *solver, clause *c) { + if (c->redundant) + printf ("redundant glue %u", c->glue); + else + printf ("irredundant"); + const reference ref = kissat_reference_clause (solver, c); + if (c->garbage) + printf (" garbage"); + printf (" clause[%u]", ref); + for (all_literals_in_clause (lit, c)) { + fputc (' ', stdout); + dump_literal (solver, lit); + } + fputc ('\n', stdout); +} + +static void dump_ref (kissat *solver, reference ref) { + clause *c = kissat_dereference_clause (solver, ref); + dump_clause (solver, c); +} + +static void dump_trail (kissat *solver) { + unsigned prev = 0; + for (unsigned level = 0; level <= solver->level; level++) { + frame *frame = &FRAME (level); + unsigned next; + if (level < solver->level) + next = frame[1].trail; + else + next = SIZE_ARRAY (solver->trail); + if (next == prev) + printf ("frame[%u] has no assignments\n", level); + else { + printf ("frame[%u] has %u assignments\n", level, next - prev); + if (prev < next) + printf ("block[%u] = trail[%u..%u]\n", level, prev, next - 1); + } + for (unsigned i = prev; i < next; i++) { + printf ("trail[%u] ", i); + const unsigned lit = PEEK_ARRAY (solver->trail, i); + dump_literal (solver, lit); + const unsigned lit_level = LEVEL (lit); + assert (lit_level <= level); + if (lit_level < level) + printf (" out-of-order"); + assigned *a = ASSIGNED (lit); + if (!lit_level) { + printf (" UNIT\n"); + assert (!a->binary); + assert (a->reason == UNIT_REASON); + } else { + fputc (' ', stdout); + if (a->binary) { + const unsigned other = a->reason; + dump_binary (solver, lit, other); + } else if (a->reason == DECISION_REASON) + printf ("DECISION\n"); + else { + assert (a->reason != UNIT_REASON); + const reference ref = a->reason; + dump_ref (solver, ref); + } + } + } + prev = next; + } +} + +static void dump_values (kissat *solver) { + for (unsigned idx = 0; idx < VARS; idx++) { + unsigned lit = LIT (idx); + int value = solver->values[lit]; + printf ("val[%u] = ", lit); + if (!value) + printf ("unassigned\n"); + else + printf ("%d\n", value); + } +} + +static void dump_queue (kissat *solver) { + const queue *const queue = &solver->queue; + printf ("queue: first %u, last %u, stamp %u, search %u (stamp %u)\n", + queue->first, queue->last, queue->stamp, queue->search.idx, + queue->search.stamp); + const links *const links = solver->links; + for (unsigned idx = queue->first; !DISCONNECTED (idx); + idx = links[idx].next) { + const struct links *l = links + idx; + printf ("%u ( prev %u, next %u, stamp %u )\n", idx, l->prev, l->next, + l->stamp); + } +} + +static void dump_scores (kissat *solver) { + heap *heap = SCORES; + printf ("scores.vars = %u\n", heap->vars); + printf ("scores.size = %u\n", heap->size); + for (unsigned i = 0; i < SIZE_STACK (heap->stack); i++) + printf ("scores.stack[%u] = %u\n", i, PEEK_STACK (heap->stack, i)); + for (unsigned i = 0; i < heap->vars; i++) + printf ("scores.score[%u] = %g\n", i, heap->score[i]); + for (unsigned i = 0; i < heap->vars; i++) + printf ("scores.pos[%u] = %u\n", i, heap->pos[i]); +} + +static void dump_export (kissat *solver) { + const unsigned size = SIZE_STACK (solver->export); + for (unsigned idx = 0; idx < size; idx++) + printf ("export[%u] = %u\n", LIT (idx), + PEEK_STACK (solver->export, idx)); +} + +void dump_map (kissat *solver) { + const unsigned size = SIZE_STACK (solver->export); + unsigned first = INVALID_LIT; + for (unsigned idx = 0; idx < size; idx++) { + const unsigned ilit = LIT (idx); + const int elit = PEEK_STACK (solver->export, idx); + printf ("map[%u] -> %d", ilit, elit); + if (elit) { + const unsigned eidx = ABS (elit); + const import *const import = &PEEK_STACK (solver->import, eidx); + if (import->eliminated) + printf (" -> eliminated[%u]", import->lit); + else { + unsigned mlit = import->lit; + if (elit < 0) + mlit = NOT (mlit); + printf (" -> %u", mlit); + } + } + if (!LEVEL (ilit) && VALUE (ilit)) { + if (first == INVALID_LIT) { + first = ilit; + printf (" #"); + } else + printf (" *"); + } + fputc ('\n', stdout); + } +} + +static void dump_import (kissat *solver) { + const unsigned size = SIZE_STACK (solver->import); + for (unsigned idx = 1; idx < size; idx++) { + import *import = &PEEK_STACK (solver->import, idx); + printf ("import[%u] = ", idx); + if (!import->imported) + printf ("undefined\n"); + else if (import->eliminated) { + unsigned pos = import->lit; + printf ("eliminated[%u]", pos); + if (pos < SIZE_STACK (solver->eliminated)) { + int value = PEEK_STACK (solver->eliminated, pos); + if (value) + printf (" (assigned to %d)", value); + } + fputc ('\n', stdout); + } else + printf ("%u\n", import->lit); + } +} + +static void dump_etrail (kissat *solver) { + for (unsigned i = 0; i < SIZE_STACK (solver->etrail); i++) + printf ("etrail[%u] = %d\n", i, (int) PEEK_STACK (solver->etrail, i)); +} + +static void dump_extend (kissat *solver) { + const extension *const begin = BEGIN_STACK (solver->extend); + const extension *const end = END_STACK (solver->extend); + for (const extension *p = begin, *q; p != end; p = q) { + assert (p->blocking); + printf ("extend[%zu] %d", (size_t) (p - begin), p->lit); + if (!p[1].blocking) + fputs (" :", stdout); + for (q = p + 1; q != end && !q->blocking; q++) + printf (" %d", q->lit); + fputc ('\n', stdout); + } +} + +static void dump_binaries (kissat *solver) { + for (all_literals (lit)) { + if (solver->watching) { + for (all_binary_blocking_watches (watch, WATCHES (lit))) { + if (!watch.type.binary) + continue; + const unsigned other = watch.binary.lit; + if (lit > other) + continue; + dump_binary (solver, lit, other); + } + } else { + for (all_binary_large_watches (watch, WATCHES (lit))) { + if (!watch.type.binary) + continue; + const unsigned other = watch.binary.lit; + if (lit > other) + continue; + dump_binary (solver, lit, other); + } + } + } +} + +static void dump_clauses (kissat *solver) { + for (all_clauses (c)) + dump_clause (solver, c); +} + +void kissat_dump_vectors (kissat *solver) { + vectors *vectors = &solver->vectors; + unsigneds *stack = &vectors->stack; + printf ("vectors.size = %zu\n", SIZE_STACK (*stack)); + printf ("vectors.capacity = %zu\n", CAPACITY_STACK (*stack)); + printf ("vectors.usable = %zu\n", vectors->usable); + const unsigned *const begin = BEGIN_STACK (*stack); + const unsigned *const end = END_STACK (*stack); + if (begin == end) + return; + fputc ('-', stdout); + for (const unsigned *p = begin + 1; p != end; p++) + if (*p == INVALID_LIT) + fputs (" -", stdout); + else + printf (" %u", *p); + fputc ('\n', stdout); +} + +int kissat_dump (kissat *solver) { + if (!solver) + return 0; + printf ("vars = %u\n", solver->vars); + printf ("size = %u\n", solver->size); + printf ("level = %u\n", solver->level); + printf ("active = %u\n", solver->active); + printf ("assigned = %u\n", kissat_assigned (solver)); + printf ("unassigned = %u\n", solver->unassigned); + dump_import (solver); + dump_export (solver); +#ifdef LOGGING + if (solver->compacting) + dump_map (solver); +#endif + dump_etrail (solver); + dump_extend (solver); + dump_trail (solver); + printf ("stable = %u\n", (unsigned) solver->stable); + if (solver->stable) + dump_scores (solver); + else + dump_queue (solver); + dump_values (solver); + printf ("binary = %" PRIu64 "\n", solver->statistics.clauses_binary); + printf ("irredundant = %" PRIu64 "\n", + solver->statistics.clauses_irredundant); + printf ("redundant = %" PRIu64 "\n", + solver->statistics.clauses_redundant); + dump_binaries (solver); + dump_clauses (solver); + dump_extend (solver); + return 0; +} + +#else +int kissat_dump_dummy_to_avoid_warning; +#endif diff --git a/src/sat/kissat/eliminate.c b/src/sat/kissat/eliminate.c new file mode 100644 index 000000000..9b7164c83 --- /dev/null +++ b/src/sat/kissat/eliminate.c @@ -0,0 +1,603 @@ +#include "eliminate.h" +#include "allocate.h" +#include "backtrack.h" +#include "collect.h" +#include "dense.h" +#include "forward.h" +#include "inline.h" +#include "inlineheap.h" +#include "kitten.h" +#include "print.h" +#include "propdense.h" +#include "report.h" +#include "resolve.h" +#include "terminate.h" +#include "trail.h" +#include "weaken.h" + +#include +#include + +bool kissat_eliminating (kissat *solver) { + if (!solver->enabled.eliminate) + return false; + statistics *statistics = &solver->statistics; + if (!statistics->clauses_irredundant) + return false; + const uint64_t conflicts = statistics->conflicts; + if (solver->last.conflicts.reduce == conflicts) + return false; + limits *limits = &solver->limits; + if (limits->eliminate.conflicts > conflicts) + return false; + if (limits->eliminate.variables.eliminate < + statistics->variables_eliminate) + return true; + if (limits->eliminate.variables.subsume < statistics->variables_subsume) + return true; + return false; +} + +static inline double variable_score (kissat *solver, unsigned idx) { + const unsigned lit = LIT (idx); + const unsigned not_lit = NOT (lit); + size_t occlim = GET_OPTION (eliminateocclim); + size_t pos = SIZE_WATCHES (WATCHES (lit)); + size_t neg = SIZE_WATCHES (WATCHES (not_lit)); + if (pos > occlim) + pos = occlim; + if (neg > occlim) + neg = occlim; + double prod = pos * neg; + double sum = pos + neg; + double occlim2 = occlim * (double) occlim; + assert (prod <= occlim2); + double score = prod - sum; + assert (score <= occlim2); + double relevancy; + if (solver->stable) + relevancy = kissat_get_heap_score (&solver->scores, idx); + else + relevancy = LINK (idx).stamp; + double res = relevancy + score - occlim2; + LOG ("variable score of %s computed as " + "%g = %g + (%zu*%zu - %zu - %zu) - %g" + " = %g + %g - %g", + LOGVAR (idx), res, relevancy, pos, neg, pos, neg, occlim2, relevancy, + score, occlim2); + return res; +} + +static inline void update_variable_score (kissat *solver, heap *schedule, + unsigned idx) { + assert (schedule->size); + assert (schedule == &solver->schedule); + double new_score = variable_score (solver, idx); + LOG ("new score %g for variable %s", new_score, LOGVAR (idx)); + kissat_update_heap (solver, schedule, idx, -new_score); +} + +void kissat_update_variable_score (kissat *solver, unsigned idx) { + update_variable_score (solver, &solver->schedule, idx); +} + +static inline void update_after_adding_stack (kissat *solver, + unsigneds *stack) { + assert (!solver->probing); + heap *schedule = &solver->schedule; + if (!schedule->size) + return; + for (all_stack (unsigned, lit, *stack)) + update_variable_score (solver, schedule, IDX (lit)); +} + +static inline void update_after_removing_variable (kissat *solver, + unsigned idx) { + heap *schedule = &solver->schedule; + if (!schedule->size) + return; + assert (!solver->probing); + flags *f = solver->flags + idx; + if (f->fixed) + return; + assert (!f->eliminated); + update_variable_score (solver, schedule, idx); + if (!kissat_heap_contains (schedule, idx)) + kissat_push_heap (solver, schedule, idx); +} + +static inline void update_after_removing_clause (kissat *solver, clause *c, + unsigned except) { + if (!solver->schedule.size) + return; + assert (c->garbage); + for (all_literals_in_clause (lit, c)) + if (lit != except) + update_after_removing_variable (solver, IDX (lit)); +} + +void kissat_eliminate_binary (kissat *solver, unsigned lit, + unsigned other) { + kissat_disconnect_binary (solver, other, lit); + kissat_delete_binary (solver, lit, other); + update_after_removing_variable (solver, IDX (other)); +} + +void kissat_eliminate_clause (kissat *solver, clause *c, unsigned lit) { + kissat_mark_clause_as_garbage (solver, c); + update_after_removing_clause (solver, c, lit); +} + +static unsigned schedule_variables (kissat *solver) { + LOG ("initializing variable schedule"); + assert (!solver->schedule.size); + + kissat_resize_heap (solver, &solver->schedule, solver->vars); + + flags *all_flags = solver->flags; + + size_t scheduled = 0; + for (all_variables (idx)) { + flags *flags = all_flags + idx; + if (!flags->active) + continue; + if (!flags->eliminate) + continue; + LOG ("scheduling %s", LOGVAR (idx)); + scheduled++; + update_after_removing_variable (solver, idx); + } + assert (scheduled == kissat_size_heap (&solver->schedule)); +#ifndef QUIET + size_t active = solver->active; + kissat_phase (solver, "eliminate", GET (eliminations), + "scheduled %zu variables %.0f%%", scheduled, + kissat_percent (scheduled, active)); +#endif + return scheduled; +} + +void kissat_flush_units_while_connected (kissat *solver) { + const unsigned *propagate = solver->propagate; + const unsigned *end_trail = END_ARRAY (solver->trail); + assert (propagate <= end_trail); + const size_t units = end_trail - propagate; + if (!units) + return; +#ifdef LOGGING + LOG ("propagating and flushing %zu units", units); +#endif + if (!kissat_dense_propagate (solver)) + return; + LOG ("marking and flushing unit satisfied clauses"); + + end_trail = END_ARRAY (solver->trail); + while (propagate != end_trail) { + const unsigned unit = *propagate++; + watches *unit_watches = &WATCHES (unit); + watch *begin = BEGIN_WATCHES (*unit_watches), *q = begin; + const watch *const end = END_WATCHES (*unit_watches), *p = q; + if (begin == end) + continue; + LOG ("marking %s satisfied clauses as garbage", LOGLIT (unit)); + while (p != end) { + const watch watch = *q++ = *p++; + if (watch.type.binary) { + const unsigned other = watch.binary.lit; + if (!solver->values[other]) + update_after_removing_variable (solver, IDX (other)); + } else { + const reference ref = watch.large.ref; + clause *c = kissat_dereference_clause (solver, ref); + if (!c->garbage) + kissat_eliminate_clause (solver, c, unit); + assert (c->garbage); + q--; + } + } + assert (q <= end); + size_t flushed = end - q; + if (!flushed) + continue; + LOG ("flushing %zu references satisfied by %s", flushed, LOGLIT (unit)); + SET_END_OF_WATCHES (*unit_watches, q); + } +} + +static void connect_resolvents (kissat *solver) { + const value *const values = solver->values; + assert (EMPTY_STACK (solver->clause)); + bool satisfied = false; +#ifdef LOGGING + uint64_t added = 0; +#endif + for (all_stack (unsigned, other, solver->resolvents)) { + if (other == INVALID_LIT) { + if (satisfied) + satisfied = false; + else { + LOGTMP ("temporary resolvent"); + const size_t size = SIZE_STACK (solver->clause); + if (!size) { + assert (!solver->inconsistent); + LOG ("resolved empty clause"); + CHECK_AND_ADD_EMPTY (); + ADD_EMPTY_TO_PROOF (); + solver->inconsistent = true; + break; + } else if (size == 1) { + const unsigned unit = PEEK_STACK (solver->clause, 0); + LOG ("resolved unit clause %s", LOGLIT (unit)); + kissat_learned_unit (solver, unit); + } else { + assert (size > 1); + (void) kissat_new_irredundant_clause (solver); + update_after_adding_stack (solver, &solver->clause); +#ifdef LOGGING + added++; +#endif + } + } + CLEAR_STACK (solver->clause); + } else if (!satisfied) { + const value value = values[other]; + if (value > 0) { + LOGTMP ("now %s satisfied resolvent", LOGLIT (other)); + satisfied = true; + } else if (value < 0) + LOG2 ("dropping now falsified literal %s", LOGLIT (other)); + else + PUSH_STACK (solver->clause, other); + } + } + LOG ("added %" PRIu64 " new clauses", added); + CLEAR_STACK (solver->resolvents); +} + +static void weaken_clauses (kissat *solver, unsigned lit) { + const unsigned not_lit = NOT (lit); + + const value *const values = solver->values; + assert (!values[lit]); + + watches *pos_watches = &WATCHES (lit); + + for (all_binary_large_watches (watch, *pos_watches)) { + if (watch.type.binary) { + const unsigned other = watch.binary.lit; + const value value = values[other]; + if (value <= 0) + kissat_weaken_binary (solver, lit, other); + kissat_eliminate_binary (solver, lit, other); + } else { + const reference ref = watch.large.ref; + clause *c = kissat_dereference_clause (solver, ref); + if (c->garbage) + continue; + bool satisfied = false; + for (all_literals_in_clause (other, c)) { + const value value = values[other]; + if (value <= 0) + continue; + satisfied = true; + break; + } + if (!satisfied) + kissat_weaken_clause (solver, lit, c); + LOGCLS (c, "removing %s", LOGLIT (lit)); + kissat_eliminate_clause (solver, c, lit); + } + } + RELEASE_WATCHES (*pos_watches); + + watches *neg_watches = &WATCHES (not_lit); + + bool optimize = !GET_OPTION (incremental); + for (all_binary_large_watches (watch, *neg_watches)) { + if (watch.type.binary) { + const unsigned other = watch.binary.lit; + const value value = values[other]; + if (!optimize && value <= 0) + kissat_weaken_binary (solver, not_lit, other); + kissat_eliminate_binary (solver, not_lit, other); + } else { + const reference ref = watch.large.ref; + clause *d = kissat_dereference_clause (solver, ref); + if (d->garbage) + continue; + bool satisfied = false; + for (all_literals_in_clause (other, d)) { + const value value = values[other]; + if (value <= 0) + continue; + satisfied = true; + break; + } + if (!optimize && !satisfied) + kissat_weaken_clause (solver, not_lit, d); + LOGCLS (d, "removing %s", LOGLIT (not_lit)); + kissat_eliminate_clause (solver, d, not_lit); + } + } + if (optimize && !EMPTY_WATCHES (*neg_watches)) + kissat_weaken_unit (solver, not_lit); + RELEASE_WATCHES (*neg_watches); + + kissat_flush_units_while_connected (solver); +} + +static void try_to_eliminate_all_variables_again (kissat *solver) { + LOG ("trying to elimination all variables again"); + flags *all_flags = solver->flags; + for (all_variables (idx)) { + flags *flags = all_flags + idx; + flags->eliminate = true; + } + solver->limits.eliminate.variables.eliminate = 0; +} + +static void set_next_elimination_bound (kissat *solver, bool complete) { + const unsigned max_bound = GET_OPTION (eliminatebound); + const unsigned current_bound = + solver->bounds.eliminate.additional_clauses; + assert (current_bound <= max_bound); + + if (complete) { + if (current_bound == max_bound) { + kissat_phase (solver, "eliminate", GET (eliminations), + "completed maximum elimination bound %u", + current_bound); + limits *limits = &solver->limits; + statistics *statistics = &solver->statistics; + limits->eliminate.variables.eliminate = + statistics->variables_eliminate; + limits->eliminate.variables.subsume = statistics->variables_subsume; +#ifndef QUIET + bool first = !solver->bounds.eliminate.max_bound_completed++; + REPORT (!first, first ? '!' : ':'); +#endif + } else { + const unsigned next_bound = + !current_bound ? 1 : MIN (2 * current_bound, max_bound); + kissat_phase (solver, "eliminate", GET (eliminations), + "completed elimination bound %u next %u", current_bound, + next_bound); + solver->bounds.eliminate.additional_clauses = next_bound; + try_to_eliminate_all_variables_again (solver); + REPORT (0, '^'); + } + } else + kissat_phase (solver, "eliminate", GET (eliminations), + "incomplete elimination bound %u", current_bound); +} + +static bool can_eliminate_variable (kissat *solver, unsigned idx) { + flags *flags = FLAGS (idx); + + if (!flags->active) + return false; + if (!flags->eliminate) + return false; + + return true; +} + +static bool eliminate_variable (kissat *solver, unsigned idx) { + LOG ("next elimination candidate %s", LOGVAR (idx)); +#ifdef LOGGING + if (GET_OPTION (log)) + (void) variable_score (solver, idx); +#endif + + assert (!solver->inconsistent); + assert (can_eliminate_variable (solver, idx)); + + LOG ("marking %s as not removed", LOGVAR (idx)); + FLAGS (idx)->eliminate = false; + + unsigned lit; + if (!kissat_generate_resolvents (solver, idx, &lit)) + return false; + connect_resolvents (solver); + if (!solver->inconsistent) + weaken_clauses (solver, lit); + INC (eliminated); + kissat_mark_eliminated_variable (solver, idx); + if (solver->gate_eliminated) { + INC (gates_eliminated); +#ifdef METRICS + assert (*solver->gate_eliminated < UINT64_MAX); + *solver->gate_eliminated += 1; +#endif + } + return true; +} + +static void eliminate_variables (kissat *solver) { + kissat_very_verbose (solver, + "trying to eliminate variables with bound %u", + solver->bounds.eliminate.additional_clauses); + assert (!solver->inconsistent); +#ifndef QUIET + unsigned before = solver->active; + unsigned eliminated = 0; + uint64_t tried = 0; +#endif + unsigned last_round_eliminated = 0; + + SET_EFFORT_LIMIT (resolution_limit, eliminate, eliminate_resolutions); + + bool complete; + int round = 0; + + const bool forward = GET_OPTION (forward); + + for (;;) { + round++; + LOG ("starting new elimination round %d", round); + + if (forward) { + unsigned *propagate = solver->propagate; + complete = kissat_forward_subsume_during_elimination (solver); + if (solver->inconsistent) + break; + kissat_flush_large_connected (solver); + kissat_connect_irredundant_large_clauses (solver); + solver->propagate = propagate; + kissat_flush_units_while_connected (solver); + if (solver->inconsistent) + break; + } else { + kissat_connect_irredundant_large_clauses (solver); + complete = true; + } + +#ifndef QUIET + const unsigned last_round_scheduled = +#endif + schedule_variables (solver); + kissat_very_verbose ( + solver, + "scheduled %u variables %.0f%% to eliminate " + "in round %d", + last_round_scheduled, + kissat_percent (last_round_scheduled, solver->active), round); + + unsigned last_round_eliminated = 0; + + while (!solver->inconsistent && + !kissat_empty_heap (&solver->schedule)) { + if (TERMINATED (eliminate_terminated_1)) { + complete = false; + break; + } + unsigned idx = kissat_pop_max_heap (solver, &solver->schedule); + if (!can_eliminate_variable (solver, idx)) + continue; + statistics *s = &solver->statistics; + if (s->eliminate_resolutions > resolution_limit) { + kissat_extremely_verbose ( + solver, + "eliminate round %u hits " + "resolution limit %" PRIu64 " at %" PRIu64 " resolutions", + round, resolution_limit, s->eliminate_resolutions); + complete = false; + break; + } +#ifndef QUIET + tried++; +#endif + if (eliminate_variable (solver, idx)) + last_round_eliminated++; + if (solver->inconsistent) + break; + kissat_flush_units_while_connected (solver); + } + + if (last_round_eliminated) { + complete = false; +#ifndef QUIET + eliminated += last_round_eliminated; +#endif + } + + if (!solver->inconsistent) { + kissat_flush_large_connected (solver); + kissat_dense_collect (solver); + } + + kissat_phase ( + solver, "eliminate", GET (eliminations), + "eliminated %u variables %.0f%% in round %u", last_round_eliminated, + kissat_percent (last_round_eliminated, last_round_scheduled), + round); + REPORT (!last_round_eliminated, 'e'); + + if (solver->inconsistent) + break; + kissat_release_heap (solver, &solver->schedule); + if (complete) + break; + if (round == GET_OPTION (eliminaterounds)) + break; + if (solver->statistics.eliminate_resolutions > resolution_limit) + break; + if (TERMINATED (eliminate_terminated_2)) + break; + } + + const unsigned remain = kissat_size_heap (&solver->schedule); + kissat_release_heap (solver, &solver->schedule); +#ifndef QUIET + kissat_very_verbose (solver, + "eliminated %u variables %.0f%% of %" PRIu64 " tried" + " (%u remain %.0f%%)", + eliminated, kissat_percent (eliminated, tried), + tried, remain, + kissat_percent (remain, solver->active)); + kissat_phase (solver, "eliminate", GET (eliminations), + "eliminated %u variables %.0f%% out of %u in %d rounds", + eliminated, kissat_percent (eliminated, before), before, + round); +#endif + if (!solver->inconsistent) { + const bool complete = !remain && !last_round_eliminated; + set_next_elimination_bound (solver, complete); + if (!complete) { + const flags *end = solver->flags + VARS; +#ifndef QUIET + unsigned dropped = 0; +#endif + for (struct flags *f = solver->flags; f != end; f++) + if (f->eliminate) { + f->eliminate = false; +#ifndef QUIET + dropped++; +#endif + } + + kissat_very_verbose (solver, "dropping %u eliminate candidates", + dropped); + } + } +} + +static void init_map_and_kitten (kissat *solver) { + if (!GET_OPTION (definitions)) + return; + assert (!solver->kitten); + solver->kitten = kitten_embedded (solver); +} + +static void reset_map_and_kitten (kissat *solver) { + if (solver->kitten) { + kitten_release (solver->kitten); + solver->kitten = 0; + } +} + +static void eliminate (kissat *solver) { + kissat_backtrack_propagate_and_flush_trail (solver); + assert (!solver->inconsistent); + STOP_SEARCH_AND_START_SIMPLIFIER (eliminate); + kissat_phase (solver, "eliminate", GET (eliminations), + "elimination limit of %" PRIu64 " conflicts hit", + solver->limits.eliminate.conflicts); + init_map_and_kitten (solver); + kissat_enter_dense_mode (solver, 0); + eliminate_variables (solver); + kissat_resume_sparse_mode (solver, true, 0); + reset_map_and_kitten (solver); + kissat_check_statistics (solver); + STOP_SIMPLIFIER_AND_RESUME_SEARCH (eliminate); +} + +int kissat_eliminate (kissat *solver) { + assert (!solver->inconsistent); + INC (eliminations); + eliminate (solver); + kissat_classify (solver); + UPDATE_CONFLICT_LIMIT (eliminate, eliminations, NLOG2N, true); + solver->last.ticks.eliminate = solver->statistics.search_ticks; + return solver->inconsistent ? 20 : 0; +} diff --git a/src/sat/kissat/eliminate.h b/src/sat/kissat/eliminate.h new file mode 100644 index 000000000..0d6cfe9a5 --- /dev/null +++ b/src/sat/kissat/eliminate.h @@ -0,0 +1,19 @@ +#ifndef _eliminate_hpp_INCLUDED +#define _eliminate_hpp_INCLUDED + +#include + +struct kissat; +struct clause; +struct heap; + +void kissat_flush_units_while_connected (struct kissat *); + +bool kissat_eliminating (struct kissat *); +int kissat_eliminate (struct kissat *); + +void kissat_eliminate_binary (struct kissat *, unsigned, unsigned); +void kissat_eliminate_clause (struct kissat *, struct clause *, unsigned); +void kissat_update_variable_score (struct kissat *, unsigned idx); + +#endif diff --git a/src/sat/kissat/equivalences.c b/src/sat/kissat/equivalences.c new file mode 100644 index 000000000..c06215d24 --- /dev/null +++ b/src/sat/kissat/equivalences.c @@ -0,0 +1,37 @@ +#include "gates.h" +#include "inlinevector.h" +#include "logging.h" + +bool kissat_find_equivalence_gate (kissat *solver, unsigned lit) { + if (!GET_OPTION (equivalences)) + return false; + if (!kissat_mark_binaries (solver, lit)) + return false; + value *marks = solver->marks; + unsigned not_lit = NOT (lit); + watches *watches = &WATCHES (not_lit); + unsigned replace = INVALID_LIT; + for (all_binary_large_watches (watch, *watches)) { + if (!watch.type.binary) + continue; + const unsigned other = watch.binary.lit; + const unsigned not_other = NOT (other); + if (!marks[not_other]) + continue; + replace = other; + break; + } + kissat_unmark_binaries (solver, lit); + if (replace == INVALID_LIT) + return false; + LOG ("found equivalence gate %s = %s", LOGLIT (lit), LOGLIT (replace)); + + const watch watch1 = kissat_binary_watch (replace); + PUSH_STACK (solver->gates[1], watch1); + + const watch watch0 = kissat_binary_watch (NOT (replace)); + PUSH_STACK (solver->gates[0], watch0); + solver->gate_eliminated = GATE_ELIMINATED (equivalences); + INC (equivalences_extracted); + return true; +} diff --git a/src/sat/kissat/equivalences.h b/src/sat/kissat/equivalences.h new file mode 100644 index 000000000..ad9c14d57 --- /dev/null +++ b/src/sat/kissat/equivalences.h @@ -0,0 +1,10 @@ +#ifndef _equivs_h_INCLUDED +#define _equivs_h_INCLUDED + +#include + +struct kissat; + +bool kissat_find_equivalence_gate (struct kissat *, unsigned lit); + +#endif diff --git a/src/sat/kissat/error.c b/src/sat/kissat/error.c new file mode 100644 index 000000000..c4c55d18d --- /dev/null +++ b/src/sat/kissat/error.c @@ -0,0 +1,62 @@ +#include "error.h" +#include "colors.h" +#include "cover.h" + +#include +#include + +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 (); +} diff --git a/src/sat/kissat/error.h b/src/sat/kissat/error.h new file mode 100644 index 000000000..69ee50706 --- /dev/null +++ b/src/sat/kissat/error.h @@ -0,0 +1,18 @@ +#ifndef _error_h_INCLUDED +#define _error_h_INCLUDED + +#include "attribute.h" + +// clang-format off + +void kissat_error (const char *fmt, ...) ATTRIBUTE_FORMAT (1, 2); +void kissat_fatal (const char *fmt, ...) ATTRIBUTE_FORMAT (1, 2); + +void kissat_fatal_message_start (void); + +void kissat_call_function_instead_of_abort (void (*)(void)); +void kissat_abort (void); + +// clang-format on + +#endif diff --git a/src/sat/kissat/extend.c b/src/sat/kissat/extend.c new file mode 100644 index 000000000..cd0dfa006 --- /dev/null +++ b/src/sat/kissat/extend.c @@ -0,0 +1,181 @@ +#include "colors.h" +#include "inline.h" + +static void undo_eliminated_assignment (kissat *solver) { + size_t size_etrail = SIZE_STACK (solver->etrail); +#ifdef LOGGING + size_t size_eliminated = SIZE_STACK (solver->eliminated); +#endif + if (!size_etrail) { + LOG ("all %zu eliminated variables are unassigned", size_eliminated); + return; + } + + LOG ("unassigning %zu eliminated variables %.0f%%", size_etrail, + kissat_percent (size_etrail, size_eliminated)); + + value *values = BEGIN_STACK (solver->eliminated); + + while (!EMPTY_STACK (solver->etrail)) { + const unsigned pos = POP_STACK (solver->etrail); + assert (pos < SIZE_STACK (solver->eliminated)); + assert (values[pos]); + LOG2 ("unassigned eliminated[%u] external variable", pos); + values[pos] = 0; + } +} + +static void extend_assign (kissat *solver, value *values, int lit) { + assert (lit); + assert (lit != INT_MIN); + const unsigned idx = ABS (lit); + import *import = &PEEK_STACK (solver->import, idx); + assert (import->eliminated); + assert (import->imported); + const unsigned pos = import->lit; + assert (pos < SIZE_STACK (solver->eliminated)); + const value value = lit < 0 ? -1 : 1; + values[pos] = value; + assert (kissat_value (solver, lit) == lit); + LOG ("assigned eliminated[%u] external literal %d", pos, value * idx); + PUSH_STACK (solver->etrail, pos); +} + +void kissat_extend (kissat *solver) { + assert (!EMPTY_STACK (solver->extend)); + assert (!solver->extended); + + START (extend); + solver->extended = true; + + undo_eliminated_assignment (solver); + + LOG ("extending solution with reconstruction stack of size %zu", + SIZE_STACK (solver->extend)); + + value *evalues = BEGIN_STACK (solver->eliminated); + value *ivalues = solver->values; + + const import *const imports = BEGIN_STACK (solver->import); + + const extension *const begin = BEGIN_STACK (solver->extend); + extension const *p = END_STACK (solver->extend); + +#ifdef LOGGING + size_t assigned = 0; + size_t flipped = 0; +#endif + + while (p != begin) { + unsigned pos = UINT_MAX; + bool satisfied = false; + + int eliminated = 0; + int blocking = 0; + + size_t size = 0; +#ifndef LOGGING + (void) size; +#endif + do { + size++; + assert (begin < p); + const extension ext = *--p; + const int elit = ext.lit; + if (ext.blocking) + blocking = elit; + + if (satisfied) + continue; + + assert (elit != INT_MIN); + const unsigned eidx = ABS (elit); + assert (eidx < SIZE_STACK (solver->import)); + const import *const import = imports + eidx; + assert (import->imported); + + if (import->eliminated) { + const unsigned tmp = import->lit; + assert (tmp < SIZE_STACK (solver->eliminated)); + value value = evalues[tmp]; + + if (elit < 0) + value = -value; + + if (value > 0) { + LOG2 ("previously assigned eliminated literal %d " + "satisfies clause", + elit); + satisfied = true; + } else if (!value && (!eliminated || pos < tmp)) { +#ifdef LOGGING + if (eliminated) + LOG2 ("earlier unassigned eliminated literal %d", elit); + else + LOG2 ("found unassigned eliminated literal %d", elit); +#endif + eliminated = elit; + pos = tmp; + } + } else { + const unsigned ilit = import->lit; + value value = ivalues[ilit]; + assert (value); + + if (elit < 0) + value = -value; + + if (value > 0) { + LOG2 ("internal literal %s satisfies clause", LOGLIT (ilit)); + satisfied = true; + } + } + } while (!blocking); + + if (satisfied) { + LOGEXT2 (size, p, "satisfied"); + continue; + } + + if (eliminated && eliminated != blocking) { + LOGEXT2 (size, p, + "assigning eliminated unassigned external literal %d " + "to satisfy size %zu witness labelled clause at", + eliminated, size); + extend_assign (solver, evalues, eliminated); +#ifdef LOGGING + assigned++; +#endif + continue; + } + +#ifdef LOGGING + const unsigned blocking_idx = ABS (blocking); + assert (blocking_idx < SIZE_STACK (solver->import)); + assert (imports[blocking_idx].eliminated); + const unsigned blocking_pos = imports[blocking_idx].lit; + assert (blocking_pos < SIZE_STACK (solver->eliminated)); + const value blocking_value = evalues[blocking_pos]; + LOGEXT2 (size, p, + "%s blocking external literal %d " + "to satisfy size %zu witness labelled clause at", + blocking_value ? "flipping" : "assigning", blocking, size); + if (blocking_value) + flipped++; + else + assigned++; +#endif + extend_assign (solver, evalues, blocking); + } + +#ifdef LOGGING + size_t total = SIZE_STACK (solver->eliminated); + LOG ("assigned %zu external variables %.0f%% out of %zu eliminated", + assigned, kissat_percent (assigned, total), total); + LOG ("flipped %zu external variables %.0f%% out of %zu assigned", flipped, + kissat_percent (flipped, assigned), assigned); + LOG ("extended assignment complete"); +#endif + + STOP (extend); +} diff --git a/src/sat/kissat/extend.h b/src/sat/kissat/extend.h new file mode 100644 index 000000000..049028b25 --- /dev/null +++ b/src/sat/kissat/extend.h @@ -0,0 +1,30 @@ +#ifndef _extend_h_INCLUDED +#define _extend_h_INCLUDED + +#include "stack.h" +#include "utilities.h" + +typedef struct extension extension; + +struct extension { + signed int lit : 31; + bool blocking : 1; +}; + +// clang-format off +typedef STACK (extension) extensions; +// clang-format on + +static inline extension kissat_extension (bool blocking, int lit) { + assert (ABS (lit) < (1 << 30)); + extension res; + res.blocking = blocking; + res.lit = lit; + return res; +} + +struct kissat; + +void kissat_extend (struct kissat *solver); + +#endif diff --git a/src/sat/kissat/factor.c b/src/sat/kissat/factor.c new file mode 100644 index 000000000..e234d0957 --- /dev/null +++ b/src/sat/kissat/factor.c @@ -0,0 +1,1136 @@ +#include "factor.h" +#include "bump.h" +#include "clause.h" +#include "dense.h" +#include "heap.h" +#include "import.h" +#include "inline.h" +#include "inlineheap.h" +#include "inlinequeue.h" +#include "inlinevector.h" +#include "internal.h" +#include "logging.h" +#include "print.h" +#include "report.h" +#include "sort.h" +#include "terminate.h" +#include "vector.h" +#include "watch.h" + +#include + +#define FACTOR 1 +#define QUOTIENT 2 +#define NOUNTED 4 + +struct quotient { + size_t id; + struct quotient *prev, *next; + unsigned factor; + statches clauses; + sizes matches; + size_t matched; +}; + +typedef struct quotient quotient; + +struct scores { + double *score; + unsigneds scored; +}; + +typedef struct scores scores; + +struct factoring { + kissat *solver; + size_t size, allocated; + unsigned initial; + unsigned *count; + scores *scores; + unsigned hops; + unsigned bound; + unsigneds fresh; + unsigneds counted; + unsigneds nounted; + references qlauses; + uint64_t limit; + struct { + quotient *first, *last; + } quotients; + heap schedule; +}; + +typedef struct factoring factoring; + +static void init_factoring (kissat *solver, factoring *factoring, + uint64_t limit) { + memset (factoring, 0, sizeof *factoring); + factoring->solver = solver; + factoring->initial = factoring->allocated = factoring->size = LITS; + factoring->limit = limit; + factoring->bound = solver->bounds.eliminate.additional_clauses; + if (GET_OPTION (factorstructural)) + factoring->hops = GET_OPTION (factorhops); + const unsigned hops = factoring->hops; + if (hops) { + CALLOC (factoring->scores, hops); + for (unsigned i = 0; i != hops; i++) { + scores *scores = factoring->scores + i; + NALLOC (scores->score, VARS); + double *score = scores->score; + for (all_variables (idx)) + score[idx] = -1; + } + } + CALLOC (factoring->count, factoring->allocated); +#ifndef NDEBUG + for (all_literals (lit)) + assert (!solver->marks[lit]); +#endif +} + +static void release_quotients (factoring *factoring) { + kissat *const solver = factoring->solver; + mark *marks = solver->marks; + for (quotient *q = factoring->quotients.first, *next; q; q = next) { + next = q->next; + unsigned factor = q->factor; + assert (marks[factor] == FACTOR); + marks[factor] = 0; + RELEASE_STACK (q->clauses); + RELEASE_STACK (q->matches); + kissat_free (solver, q, sizeof *q); + } + const unsigned hops = factoring->hops; + if (hops) { + for (unsigned i = 0; i != hops; i++) { + scores *scores = factoring->scores + i; + unsigneds *scored = &scores->scored; + double *score = scores->score; + while (!EMPTY_STACK (*scored)) { + unsigned idx = POP_STACK (*scored); + score[idx] = -1; + } + } + } + factoring->quotients.first = factoring->quotients.last = 0; +} + +static void release_factoring (factoring *factoring) { + kissat *const solver = factoring->solver; + assert (EMPTY_STACK (solver->analyzed)); + assert (EMPTY_STACK (factoring->counted)); + assert (EMPTY_STACK (factoring->nounted)); + assert (EMPTY_STACK (factoring->qlauses)); + DEALLOC (factoring->count, factoring->allocated); + RELEASE_STACK (factoring->counted); + RELEASE_STACK (factoring->nounted); + RELEASE_STACK (factoring->fresh); + RELEASE_STACK (factoring->qlauses); + release_quotients (factoring); + kissat_release_heap (solver, &factoring->schedule); + assert (!(factoring->allocated & 1)); + const size_t allocated_score = factoring->allocated / 2; + const unsigned hops = factoring->hops; + if (hops) { + for (unsigned i = 0; i != hops; i++) { + scores *scores = factoring->scores + i; + double *score = scores->score; + DEALLOC (score, allocated_score); + RELEASE_STACK (scores->scored); + } + DEALLOC (factoring->scores, hops); + } +#ifndef NDEBUG + for (all_literals (lit)) + assert (!solver->marks[lit]); +#endif +} + +static void update_candidate (factoring *factoring, unsigned lit) { + heap *cands = &factoring->schedule; + kissat *const solver = factoring->solver; + const size_t size = SIZE_WATCHES (solver->watches[lit]); + if (size > 1) { + kissat_adjust_heap (solver, cands, lit); + kissat_update_heap (solver, cands, lit, size); + if (!kissat_heap_contains (cands, lit)) + kissat_push_heap (solver, cands, lit); + } else if (kissat_heap_contains (cands, lit)) + kissat_pop_heap (solver, cands, lit); +} + +static void schedule_factorization (factoring *factoring) { + kissat *const solver = factoring->solver; + flags *flags = solver->flags; + for (all_variables (idx)) { + if (ACTIVE (idx)) { + struct flags *f = flags + idx; + const unsigned lit = LIT (idx); + const unsigned not_lit = NOT (lit); + if (f->factor & 1) + update_candidate (factoring, lit); + if (f->factor & 2) + update_candidate (factoring, not_lit); + } + } +#ifndef QUIET + heap *cands = &factoring->schedule; + size_t size_cands = kissat_size_heap (cands); + kissat_very_verbose ( + solver, "scheduled %zu factorization candidate literals %.0f %%", + size_cands, kissat_percent (size_cands, LITS)); +#endif +} + +static quotient *new_quotient (factoring *factoring, unsigned factor) { + kissat *const solver = factoring->solver; + mark *marks = solver->marks; + assert (!marks[factor]); + marks[factor] = FACTOR; + quotient *res = kissat_malloc (solver, sizeof *res); + memset (res, 0, sizeof *res); + res->factor = factor; + quotient *last = factoring->quotients.last; + if (last) { + assert (factoring->quotients.first); + assert (!last->next); + last->next = res; + res->id = last->id + 1; + } else { + assert (!factoring->quotients.first); + factoring->quotients.first = res; + } + factoring->quotients.last = res; + res->prev = last; + LOG ("new quotient[%zu] with factor %s", res->id, LOGLIT (factor)); + return res; +} + +static size_t first_factor (factoring *factoring, unsigned factor) { + kissat *const solver = factoring->solver; + watches *all_watches = solver->watches; + watches *factor_watches = all_watches + factor; + assert (!factoring->quotients.first); + quotient *quotient = new_quotient (factoring, factor); + statches *clauses = "ient->clauses; + uint64_t ticks = 0; + for (all_binary_large_watches (watch, *factor_watches)) { + PUSH_STACK (*clauses, watch); +#ifndef NDEBUG + if (watch.type.binary) + continue; + const reference ref = watch.large.ref; + clause *const c = kissat_dereference_clause (solver, ref); + assert (!c->quotient); +#endif + ticks++; + } + size_t res = SIZE_STACK (*clauses); + LOG ("quotient[0] factor %s size %zu", LOGLIT (factor), res); + assert (res > 1); + ADD (factor_ticks, ticks); + return res; +} + +static void clear_nounted (kissat *solver, unsigneds *nounted) { + mark *marks = solver->marks; + for (all_stack (unsigned, lit, *nounted)) { + assert (marks[lit] & NOUNTED); + marks[lit] &= ~NOUNTED; + } + CLEAR_STACK (*nounted); +} + +static void clear_qlauses (kissat *solver, references *qlauses) { + ward *const arena = BEGIN_STACK (solver->arena); + for (all_stack (reference, ref, *qlauses)) { + clause *const c = (clause *) (arena + ref); + assert (c->quotient); + c->quotient = false; + } + CLEAR_STACK (*qlauses); +} + +static double distinct_paths (factoring *factoring, unsigned src_lit, + unsigned dst_idx, unsigned hops) { + kissat *const solver = factoring->solver; + const unsigned src_idx = IDX (src_lit); + bool matched = (src_idx == dst_idx); + if (!hops) + return matched; + const unsigned next_hops = hops - 1; + scores *scores = &factoring->scores[next_hops]; + double *score = scores->score; + double res = score[src_idx]; + if (res >= 0) + return res; + res = matched; + for (unsigned sign = 0; sign != 2; sign++) { + const unsigned signed_src_lit = src_lit ^ sign; + watches *const watches = &WATCHES (signed_src_lit); + uint64_t ticks = + 1 + kissat_cache_lines (SIZE_WATCHES (*watches), sizeof (watch)); + for (all_binary_large_watches (watch, *watches)) { + if (watch.type.binary) { + const unsigned other = watch.binary.lit; + res += distinct_paths (factoring, other, dst_idx, next_hops); + } else { + const reference ref = watch.large.ref; + clause *c = kissat_dereference_clause (solver, ref); + ticks++; + for (all_literals_in_clause (other, c)) + if (other != signed_src_lit) + res += distinct_paths (factoring, other, dst_idx, next_hops); + } + } + ADD (factor_ticks, ticks); + } + assert (res >= 0); + score[src_idx] = res; + unsigneds *scored = &scores->scored; + PUSH_STACK (*scored, src_idx); + LOG ("caching %g distinct paths from %s to %s in %u hops", res, + LOGVAR (src_idx), LOGVAR (dst_idx), hops); + return res; +} + +static double structural_score (factoring *factoring, unsigned lit) { + const quotient *first_quotient = factoring->quotients.first; + assert (first_quotient); + const unsigned first_factor = first_quotient->factor; +#ifndef NDEBUG + kissat *const solver = factoring->solver; +#endif + const unsigned first_factor_idx = IDX (first_factor); + return distinct_paths (factoring, lit, first_factor_idx, factoring->hops); +} + +static double watches_score (factoring *factoring, unsigned lit) { + kissat *const solver = factoring->solver; + watches *watches = solver->watches + lit; + double res = SIZE_WATCHES (*watches); + LOG ("watches score %g of %s", res, LOGLIT (lit)); + return res; +} + +static double tied_next_factor_score (factoring *factoring, unsigned lit) { + if (factoring->hops) + return structural_score (factoring, lit); + else + return watches_score (factoring, lit); +} + +static unsigned next_factor (factoring *factoring, + unsigned *next_count_ptr) { + quotient *last_quotient = factoring->quotients.last; + assert (last_quotient); + statches *last_clauses = &last_quotient->clauses; + kissat *const solver = factoring->solver; + watches *all_watches = solver->watches; + unsigned *count = factoring->count; + unsigneds *counted = &factoring->counted; + references *qlauses = &factoring->qlauses; + assert (EMPTY_STACK (*counted)); + assert (EMPTY_STACK (*qlauses)); + ward *const arena = BEGIN_STACK (solver->arena); + mark *marks = solver->marks; + const unsigned initial = factoring->initial; + uint64_t ticks = + 1 + kissat_cache_lines (SIZE_STACK (*last_clauses), sizeof (watch)); + for (all_stack (watch, quotient_watch, *last_clauses)) { + if (quotient_watch.type.binary) { + const unsigned q = quotient_watch.binary.lit; + watches *q_watches = all_watches + q; + ticks += 1 + kissat_cache_lines (SIZE_WATCHES (*q_watches), + sizeof (watch)); + for (all_binary_large_watches (next_watch, *q_watches)) { + if (!next_watch.type.binary) + continue; + const unsigned next = next_watch.binary.lit; + if (next > initial) + continue; + if (marks[next] & FACTOR) + continue; + const unsigned next_idx = IDX (next); + if (!ACTIVE (next_idx)) + continue; + if (!count[next]) + PUSH_STACK (*counted, next); + count[next]++; + } + } else { + const reference c_ref = quotient_watch.large.ref; + clause *const c = (clause *) (arena + c_ref); + assert (!c->quotient); + unsigned min_lit = INVALID_LIT, factors = 0; + size_t min_size = 0; + ticks++; + for (all_literals_in_clause (other, c)) { + if (marks[other] & FACTOR) { + if (factors++) + break; + } else { + assert (!(marks[other] & QUOTIENT)); + marks[other] |= QUOTIENT; + watches *other_watches = all_watches + other; + const size_t other_size = SIZE_WATCHES (*other_watches); + if (min_lit != INVALID_LIT && min_size <= other_size) + continue; + min_lit = other; + min_size = other_size; + } + } + assert (factors); + if (factors == 1) { + assert (min_lit != INVALID_LIT); + watches *min_watches = all_watches + min_lit; + unsigned c_size = c->size; + unsigneds *nounted = &factoring->nounted; + assert (EMPTY_STACK (*nounted)); + ticks += 1 + kissat_cache_lines (SIZE_WATCHES (*min_watches), + sizeof (watch)); + for (all_binary_large_watches (min_watch, *min_watches)) { + if (min_watch.type.binary) + continue; + const reference d_ref = min_watch.large.ref; + if (c_ref == d_ref) + continue; + clause *const d = (clause *) (arena + d_ref); + ticks++; + if (d->quotient) + continue; + if (d->size != c_size) + continue; + unsigned next = INVALID_LIT; + for (all_literals_in_clause (other, d)) { + const mark mark = marks[other]; + if (mark & QUOTIENT) + continue; + if (mark & FACTOR) + goto CONTINUE_WITH_NEXT_MIN_WATCH; + if (mark & NOUNTED) + goto CONTINUE_WITH_NEXT_MIN_WATCH; + if (next != INVALID_LIT) + goto CONTINUE_WITH_NEXT_MIN_WATCH; + next = other; + } + assert (next != INVALID_LIT); + if (next > initial) + continue; + const unsigned next_idx = IDX (next); + if (!ACTIVE (next_idx)) + continue; + assert (!(marks[next] & (FACTOR | NOUNTED))); + marks[next] |= NOUNTED; + PUSH_STACK (*nounted, next); + d->quotient = true; + PUSH_STACK (*qlauses, d_ref); + if (!count[next]) + PUSH_STACK (*counted, next); + count[next]++; + CONTINUE_WITH_NEXT_MIN_WATCH:; + } + clear_nounted (solver, nounted); + } + for (all_literals_in_clause (other, c)) + marks[other] &= ~QUOTIENT; + } + ADD (factor_ticks, ticks); + ticks = 0; + if (solver->statistics.factor_ticks > factoring->limit) + break; + } + clear_qlauses (solver, qlauses); + unsigned next_count = 0, next = INVALID_LIT; + if (solver->statistics.factor_ticks <= factoring->limit) { + unsigned ties = 0; + for (all_stack (unsigned, lit, *counted)) { + const unsigned lit_count = count[lit]; + if (lit_count < next_count) + continue; + if (lit_count == next_count) { + assert (lit_count); + ties++; + } else { + assert (lit_count > next_count); + next_count = lit_count; + next = lit; + ties = 1; + } + } + if (next_count < 2) { + LOG ("next factor count %u smaller than 2", next_count); + next = INVALID_LIT; + } else if (ties > 1) { + LOG ("found %u tied next factor candidate literals with count %u", + ties, next_count); + double next_score = -1; + for (all_stack (unsigned, lit, *counted)) { + const unsigned lit_count = count[lit]; + if (lit_count != next_count) + continue; + double lit_score = tied_next_factor_score (factoring, lit); + assert (lit_score >= 0); + LOG ("score %g of next factor candidate %s", lit_score, + LOGLIT (lit)); + if (lit_score <= next_score) + continue; + next_score = lit_score; + next = lit; + } + assert (next_score >= 0); + assert (next != INVALID_LIT); + LOG ("best score %g of next factor %s", next_score, LOGLIT (next)); + } else { + assert (ties == 1); + LOG ("single next factor %s with count %u", LOGLIT (next), + next_count); + } + } + for (all_stack (unsigned, lit, *counted)) + count[lit] = 0; + CLEAR_STACK (*counted); + assert (next == INVALID_LIT || next_count > 1); + *next_count_ptr = next_count; + return next; +} + +static void factorize_next (factoring *factoring, unsigned next, + unsigned expected_next_count) { + quotient *last_quotient = factoring->quotients.last; + quotient *next_quotient = new_quotient (factoring, next); + + kissat *const solver = factoring->solver; + watches *all_watches = solver->watches; + ward *const arena = BEGIN_STACK (solver->arena); + mark *marks = solver->marks; + + assert (last_quotient); + statches *last_clauses = &last_quotient->clauses; + statches *next_clauses = &next_quotient->clauses; + sizes *matches = &next_quotient->matches; + references *qlauses = &factoring->qlauses; + assert (EMPTY_STACK (*qlauses)); + + uint64_t ticks = + 1 + kissat_cache_lines (SIZE_STACK (*last_clauses), sizeof (watch)); + + size_t i = 0; + + for (all_stack (watch, last_watch, *last_clauses)) { + if (last_watch.type.binary) { + const unsigned q = last_watch.binary.lit; + watches *q_watches = all_watches + q; + ticks += 1 + kissat_cache_lines (SIZE_WATCHES (*q_watches), + sizeof (watch)); + for (all_binary_large_watches (q_watch, *q_watches)) + if (q_watch.type.binary && q_watch.binary.lit == next) { + LOGBINARY (last_quotient->factor, q, "matched"); + LOGBINARY (next, q, "keeping"); + PUSH_STACK (*next_clauses, last_watch); + PUSH_STACK (*matches, i); + break; + } + } else { + const reference c_ref = last_watch.large.ref; + clause *const c = (clause *) (arena + c_ref); + assert (!c->quotient); + unsigned min_lit = INVALID_LIT, factors = 0; + size_t min_size = 0; + ticks++; + for (all_literals_in_clause (other, c)) { + if (marks[other] & FACTOR) { + if (factors++) + break; + } else { + assert (!(marks[other] & QUOTIENT)); + marks[other] |= QUOTIENT; + watches *other_watches = all_watches + other; + const size_t other_size = SIZE_WATCHES (*other_watches); + if (min_lit != INVALID_LIT && min_size <= other_size) + continue; + min_lit = other; + min_size = other_size; + } + } + assert (factors); + if (factors == 1) { + assert (min_lit != INVALID_LIT); + watches *min_watches = all_watches + min_lit; + unsigned c_size = c->size; + ticks += 1 + kissat_cache_lines (SIZE_WATCHES (*min_watches), + sizeof (watch)); + for (all_binary_large_watches (min_watch, *min_watches)) { + if (min_watch.type.binary) + continue; + const reference d_ref = min_watch.large.ref; + if (c_ref == d_ref) + continue; + clause *const d = (clause *) (arena + d_ref); + ticks++; + if (d->quotient) + continue; + if (d->size != c_size) + continue; + for (all_literals_in_clause (other, d)) { + const mark mark = marks[other]; + if (mark & QUOTIENT) + continue; + if (other != next) + goto CONTINUE_WITH_NEXT_MIN_WATCH; + } + LOGCLS (c, "matched"); + LOGCLS (d, "keeping"); + PUSH_STACK (*next_clauses, min_watch); + PUSH_STACK (*matches, i); + PUSH_STACK (*qlauses, d_ref); + d->quotient = true; + break; + CONTINUE_WITH_NEXT_MIN_WATCH:; + } + } + for (all_literals_in_clause (other, c)) + marks[other] &= ~QUOTIENT; + } + i++; + } + + clear_qlauses (solver, qlauses); + ADD (factor_ticks, ticks); + + assert (expected_next_count <= SIZE_STACK (*next_clauses)); + (void) expected_next_count; +} + +static quotient *best_quotient (factoring *factoring, + size_t *best_reduction_ptr) { + size_t factors = 1, best_reduction = 0; + quotient *best = 0; + kissat *const solver = factoring->solver; + for (quotient *q = factoring->quotients.first; q; q = q->next) { + size_t quotients = SIZE_STACK (q->clauses); + size_t before_factorization = quotients * factors; + size_t after_factorization = quotients + factors; + if (before_factorization == after_factorization) + LOG ("quotient[%zu] factors %zu clauses into %zu thus no change", + factors - 1, before_factorization, after_factorization); + else if (before_factorization < after_factorization) + LOG ("quotient[%zu] factors %zu clauses into %zu thus %zu more", + factors - 1, before_factorization, after_factorization, + after_factorization - before_factorization); + else { + size_t delta = before_factorization - after_factorization; + LOG ("quotient[%zu] factors %zu clauses into %zu thus %zu less", + factors - 1, before_factorization, after_factorization, delta); + if (!best || best_reduction < delta) { + best_reduction = delta; + best = q; + } + } + factors++; + } + if (!best) { + LOG ("no decreasing quotient found"); + return 0; + } + LOG ("best decreasing quotient[%zu] with reduction %zu", best->id, + best_reduction); + *best_reduction_ptr = best_reduction; + (void) solver; + return best; +} + +static void resize_factoring (factoring *factoring, unsigned lit) { + kissat *const solver = factoring->solver; + assert (lit > NOT (lit)); + const size_t old_size = factoring->size; + assert (lit > old_size); + const size_t old_allocated = factoring->allocated; + size_t new_size = lit + 1; + if (new_size > old_allocated) { + size_t new_allocated = 2 * old_allocated; + while (new_size > new_allocated) + new_allocated *= 2; + unsigned *count = factoring->count; + count = kissat_nrealloc (solver, count, old_allocated, new_allocated, + sizeof *count); + const size_t delta_allocated = new_allocated - old_allocated; + const size_t delta_bytes = delta_allocated * sizeof *count; + memset (count + old_size, 0, delta_bytes); + factoring->count = count; + assert (!(old_allocated & 1)); + assert (!(new_allocated & 1)); + const size_t old_allocated_score = old_allocated / 2; + const size_t new_allocated_score = new_allocated / 2; + for (unsigned i = 0; i != factoring->hops; i++) { + scores *scores = factoring->scores + i; + double *score = scores->score; + score = kissat_nrealloc (solver, score, old_allocated_score, + new_allocated_score, sizeof *score); + for (size_t i = old_allocated_score; i != new_allocated_score; i++) + score[i] = -1; + scores->score = score; + } + factoring->allocated = new_allocated; + } + factoring->size = new_size; +} + +static void flush_unmatched_clauses (kissat *solver, quotient *q) { + quotient *prev = q->prev; + sizes *q_matches = &q->matches, *prev_matches = &prev->matches; + statches *q_clauses = &q->clauses, *prev_clauses = &prev->clauses; + const size_t n = SIZE_STACK (*q_clauses); + assert (n == SIZE_STACK (*q_matches)); + bool prev_is_first = !prev->id; + size_t i = 0; + while (i != n) { + size_t j = PEEK_STACK (*q_matches, i); + assert (i <= j); + if (!prev_is_first) { + size_t matches = PEEK_STACK (*prev_matches, j); + POKE_STACK (*prev_matches, i, matches); + } + watch watch = PEEK_STACK (*prev_clauses, j); + POKE_STACK (*prev_clauses, i, watch); + i++; + } + LOG ("flushing %zu clauses of quotient[%zu]", + SIZE_STACK (*prev_clauses) - n, prev->id); + if (!prev_is_first) + RESIZE_STACK (*prev_matches, n); + RESIZE_STACK (*prev_clauses, n); + (void) solver; +} + +static void add_factored_divider (factoring *factoring, quotient *q, + unsigned fresh) { + const unsigned factor = q->factor; + kissat *const solver = factoring->solver; + LOGBINARY (fresh, factor, "factored %s divider", LOGLIT (factor)); + kissat_new_binary_clause (solver, fresh, factor); + INC (clauses_factored); + ADD (literals_factored, 2); +} + +static void add_factored_quotient (factoring *factoring, quotient *q, + unsigned not_fresh) { + kissat *const solver = factoring->solver; + LOG ("adding factored quotient[%zu] clauses", q->id); + for (all_stack (watch, watch, q->clauses)) { + if (watch.type.binary) { + const unsigned other = watch.binary.lit; + LOGBINARY (not_fresh, other, "factored quotient"); + kissat_new_binary_clause (solver, not_fresh, other); + ADD (literals_factored, 2); + } else { + const reference c_ref = watch.large.ref; + clause *const c = kissat_dereference_clause (solver, c_ref); + unsigneds *clause = &solver->clause; + assert (EMPTY_STACK (*clause)); + const unsigned factor = q->factor; +#ifndef NDEBUG + bool found = false; +#endif + PUSH_STACK (*clause, not_fresh); + for (all_literals_in_clause (other, c)) { + if (other == factor) { +#ifndef NDEBUG + found = true; +#endif + continue; + } + PUSH_STACK (*clause, other); + } + assert (found); + ADD (literals_factored, c->size); + kissat_new_irredundant_clause (solver); + CLEAR_STACK (*clause); + } + INC (clauses_factored); + } +} + +static void eagerly_remove_watch (kissat *solver, watches *watches, + watch needle) { + watch *p = BEGIN_WATCHES (*watches); + watch *end = END_WATCHES (*watches); + assert (p != end); + watch *last = end - 1; + while (p->raw != needle.raw) + p++, assert (p != end); + if (p != last) + memmove (p, p + 1, (last - p) * sizeof *p); + SET_END_OF_WATCHES (*watches, last); +} + +static void eagerly_remove_binary (kissat *solver, watches *watches, + unsigned lit) { + const watch needle = kissat_binary_watch (lit); + eagerly_remove_watch (solver, watches, needle); +} + +static void delete_unfactored (factoring *factoring, quotient *q) { + kissat *const solver = factoring->solver; + LOG ("deleting unfactored quotient[%zu] clauses", q->id); + const unsigned factor = q->factor; + for (all_stack (watch, watch, q->clauses)) { + if (watch.type.binary) { + const unsigned other = watch.binary.lit; + LOGBINARY (factor, other, "deleting unfactored"); + eagerly_remove_binary (solver, &WATCHES (other), factor); + eagerly_remove_binary (solver, &WATCHES (factor), other); + kissat_delete_binary (solver, factor, other); + ADD (literals_unfactored, 2); + } else { + const reference ref = watch.large.ref; + clause *c = kissat_dereference_clause (solver, ref); + LOGCLS (c, "deleting unfactored"); + for (all_literals_in_clause (lit, c)) + eagerly_remove_watch (solver, &WATCHES (lit), watch); + kissat_mark_clause_as_garbage (solver, c); + ADD (literals_unfactored, c->size); + } + INC (clauses_unfactored); + } +} + +static void update_factored (factoring *factoring, quotient *q) { + kissat *const solver = factoring->solver; + const unsigned factor = q->factor; + update_candidate (factoring, factor); + update_candidate (factoring, NOT (factor)); + for (all_stack (watch, watch, q->clauses)) { + if (watch.type.binary) { + const unsigned other = watch.binary.lit; + update_candidate (factoring, other); + } else { + const reference ref = watch.large.ref; + clause *c = kissat_dereference_clause (solver, ref); + LOGCLS (c, "deleting unfactored"); + for (all_literals_in_clause (lit, c)) + if (lit != factor) + update_candidate (factoring, lit); + } + } +} + +static bool apply_factoring (factoring *factoring, quotient *q) { + kissat *const solver = factoring->solver; + const unsigned fresh = kissat_fresh_literal (solver); + if (fresh == INVALID_LIT) + return false; + INC (factored); + PUSH_STACK (factoring->fresh, fresh); + for (quotient *p = q; p->prev; p = p->prev) + flush_unmatched_clauses (solver, p); + for (quotient *p = q; p; p = p->prev) + add_factored_divider (factoring, p, fresh); + const unsigned not_fresh = NOT (fresh); + add_factored_quotient (factoring, q, not_fresh); + for (quotient *p = q; p; p = p->prev) + delete_unfactored (factoring, p); + for (quotient *p = q; p; p = p->prev) + update_factored (factoring, p); + assert (fresh < not_fresh); + resize_factoring (factoring, not_fresh); + return true; +} + +static void +adjust_scores_and_phases_of_fresh_varaibles (factoring *factoring) { + const unsigned *begin = BEGIN_STACK (factoring->fresh); + const unsigned *end = END_STACK (factoring->fresh); + kissat *const solver = factoring->solver; + { + const unsigned *p = begin; + while (p != end) { + const unsigned lit = *p++; + const unsigned idx = IDX (lit); + LOG ("unbumping fresh[%zu] %s", (size_t) (p - begin - 1), + LOGVAR (idx)); + const double score = 0; + kissat_update_heap (solver, &solver->scores, idx, score); + } + } + { + const unsigned *p = end; + links *links = solver->links; + queue *queue = &solver->queue; + while (p != begin) { + const unsigned lit = *--p; + const unsigned idx = IDX (lit); + kissat_dequeue_links (idx, links, queue); + } + queue->stamp = 0; + unsigned rest = queue->first; + p = end; + while (p != begin) { + const unsigned lit = *--p; + const unsigned idx = IDX (lit); + struct links *l = links + idx; + if (DISCONNECTED (queue->first)) { + assert (DISCONNECTED (queue->last)); + queue->last = idx; + } else { + struct links *first = links + queue->first; + assert (DISCONNECTED (first->prev)); + first->prev = idx; + } + l->next = queue->first; + queue->first = idx; + assert (DISCONNECTED (l->prev)); + l->stamp = ++queue->stamp; + } + while (!DISCONNECTED (rest)) { + struct links *l = links + rest; + l->stamp = ++queue->stamp; + rest = l->next; + } + solver->queue.search.idx = queue->last; + solver->queue.search.stamp = queue->stamp; + } +} + +static bool run_factorization (kissat *solver, uint64_t limit) { + factoring factoring; + init_factoring (solver, &factoring, limit); + schedule_factorization (&factoring); + bool done = false; +#ifndef QUIET + unsigned factored = 0; +#endif + uint64_t *ticks = &solver->statistics.factor_ticks; + kissat_extremely_verbose ( + solver, "factorization limit of %" PRIu64 " ticks", limit - *ticks); + while (!done && !kissat_empty_heap (&factoring.schedule)) { + const unsigned first = + kissat_pop_max_heap (solver, &factoring.schedule); + const unsigned first_idx = IDX (first); + if (!ACTIVE (first_idx)) + continue; + if (*ticks > limit) { + kissat_very_verbose (solver, "factorization ticks limit hit"); + break; + } + if (TERMINATED (factor_terminated_1)) + break; + struct flags *f = solver->flags + first_idx; + const unsigned bit = 1u << NEGATED (first); + if (!(f->factor & bit)) + continue; + f->factor &= ~bit; + const size_t first_count = first_factor (&factoring, first); + if (first_count > 1) { + for (;;) { + unsigned next_count; + const unsigned next = next_factor (&factoring, &next_count); + if (next == INVALID_LIT) + break; + assert (next_count > 1); + if (next_count < 2) + break; + factorize_next (&factoring, next, next_count); + } + size_t reduction; + quotient *q = best_quotient (&factoring, &reduction); + if (q && reduction > factoring.bound) { + if (apply_factoring (&factoring, q)) { +#ifndef QUIET + factored++; +#endif + } else + done = true; + } + } + release_quotients (&factoring); + } + bool completed = kissat_empty_heap (&factoring.schedule); + adjust_scores_and_phases_of_fresh_varaibles (&factoring); + release_factoring (&factoring); + REPORT (!factored, 'f'); + return completed; +} + +static void connect_clauses_to_factor (kissat *solver) { + const unsigned size_limit = GET_OPTION (factorsize); + if (size_limit < 3) { + kissat_extremely_verbose (solver, "only factorizing binary clauses"); + return; + } + kissat_very_verbose (solver, "factorizing clauses of maximum size %u", + size_limit); + clause *last_irredundant = kissat_last_irredundant_clause (solver); + ward *const arena = BEGIN_STACK (solver->arena); + watches *all_watches = solver->watches; + unsigned *bincount, *largecount; + CALLOC (bincount, LITS); + for (all_literals (lit)) { + if (!ACTIVE (IDX (lit))) + continue; + for (all_binary_large_watches (watch, WATCHES (lit))) { + assert (watch.type.binary); + const unsigned other = watch.type.lit; + if (lit > other) + continue; + bincount[lit]++; + bincount[other]++; + } + } + CALLOC (largecount, LITS); + size_t initial_candidates = 0; + for (all_clauses (c)) { + if (c->garbage) + continue; + if (last_irredundant && last_irredundant < c) + break; + if (c->redundant) + continue; + if (c->size > size_limit) + continue; + for (all_literals_in_clause (lit, c)) + largecount[lit]++; + initial_candidates++; + } + kissat_very_verbose (solver, + "initially found %zu large clause candidates", + initial_candidates); + size_t candidates = initial_candidates; + const unsigned rounds = GET_OPTION (factorcandrounds); + for (unsigned round = 1; round <= rounds; round++) { + size_t new_candidates = 0; + unsigned *newlargecount; + CALLOC (newlargecount, LITS); + for (all_clauses (c)) { + if (c->garbage) + continue; + if (last_irredundant && last_irredundant < c) + break; + if (c->redundant) + continue; + if (c->size > size_limit) + continue; + for (all_literals_in_clause (lit, c)) + if (bincount[lit] + largecount[lit] < 2) + goto CONTINUE_WITH_NEXT_CLAUSE1; + for (all_literals_in_clause (lit, c)) + newlargecount[lit]++; + new_candidates++; + CONTINUE_WITH_NEXT_CLAUSE1:; + } + DEALLOC (largecount, LITS); + largecount = newlargecount; + if (candidates == new_candidates) { + kissat_very_verbose (solver, + "no large factorization candidate clauses " + "reduction in round %u", + round); + break; + } + candidates = new_candidates; + kissat_very_verbose ( + solver, + "reduced to %zu large factorization candidate clauses %.0f%% in " + "round %u", + candidates, kissat_percent (candidates, initial_candidates), round); + } +#ifndef QUIET + size_t connected = 0; +#endif + for (all_clauses (c)) { + if (c->garbage) + continue; + if (last_irredundant && last_irredundant < c) + break; + if (c->redundant) + continue; + if (c->size > size_limit) + continue; + for (all_literals_in_clause (lit, c)) + if (bincount[lit] + largecount[lit] < 2) + goto CONTINUE_WITH_NEXT_CLAUSE2; + const reference ref = (ward *) c - arena; + kissat_inlined_connect_clause (solver, all_watches, c, ref); +#ifndef QUIET + connected++; +#endif + CONTINUE_WITH_NEXT_CLAUSE2:; + } + DEALLOC (largecount, LITS); + DEALLOC (bincount, LITS); + kissat_very_verbose ( + solver, "connected %zu large factorization candidate clauses %.0f%%", + connected, kissat_percent (candidates, initial_candidates)); +} + +void kissat_factor (kissat *solver) { + assert (!solver->level); + if (solver->inconsistent) + return; + if (!GET_OPTION (factor)) + return; + statistics *s = &solver->statistics; + if (solver->limits.factor.marked >= s->literals_factor) { + kissat_extremely_verbose ( + solver, + "factorization skipped as no literals have been marked to be added " + "(%" PRIu64 " < %" PRIu64, + solver->limits.factor.marked, s->literals_factor); + return; + } + START (factor); + INC (factorizations); + kissat_phase (solver, "factorization", GET (factorizations), + "binary clause bounded variable addition"); + uint64_t limit = GET_OPTION (factoriniticks); + if (s->factorizations > 1) { + SET_EFFORT_LIMIT (tmp, factor, factor_ticks); + limit = tmp; + } else { + kissat_very_verbose (solver, + "initially limiting to %" PRIu64 + " million factorization ticks", + limit); + limit *= 1e6; + limit += s->factor_ticks; + } +#ifndef QUIET + struct { + int64_t variables, binary, clauses, ticks; + } before, after, delta; + before.variables = s->variables_extension + s->variables_original; + before.binary = BINARY_CLAUSES; + before.clauses = IRREDUNDANT_CLAUSES; + before.ticks = s->factor_ticks; +#endif + kissat_enter_dense_mode (solver, 0); + connect_clauses_to_factor (solver); + bool completed = run_factorization (solver, limit); + kissat_resume_sparse_mode (solver, false, 0); +#ifndef QUIET + after.variables = s->variables_extension + s->variables_original; + after.binary = BINARY_CLAUSES; + after.clauses = IRREDUNDANT_CLAUSES; + after.ticks = s->factor_ticks; + delta.variables = after.variables - before.variables; + delta.binary = before.binary - after.binary; + delta.clauses = before.clauses - after.clauses; + delta.ticks = after.ticks - before.ticks; + kissat_very_verbose (solver, "used %f million factorization ticks", + delta.ticks * 1e-6); + kissat_phase (solver, "factorization", GET (factorizations), + "introduced %" PRId64 " extension variables %.0f%%", + delta.variables, + kissat_percent (delta.variables, before.variables)); + kissat_phase (solver, "factorization", GET (factorizations), + "removed %" PRId64 " binary clauses %.0f%%", delta.binary, + kissat_percent (delta.binary, before.binary)); + kissat_phase (solver, "factorization", GET (factorizations), + "removed %" PRId64 " large clauses %.0f%%", delta.clauses, + kissat_percent (delta.clauses, before.clauses)); +#endif + if (completed) + solver->limits.factor.marked = s->literals_factor; + STOP (factor); +} diff --git a/src/sat/kissat/factor.h b/src/sat/kissat/factor.h new file mode 100644 index 000000000..0223186cf --- /dev/null +++ b/src/sat/kissat/factor.h @@ -0,0 +1,9 @@ +#ifndef _factor_h_INCLUDED +#define _factor_h_INCLUDED + +#include + +struct kissat; +void kissat_factor (struct kissat *); + +#endif diff --git a/src/sat/kissat/fastassign.h b/src/sat/kissat/fastassign.h new file mode 100644 index 000000000..6951ed893 --- /dev/null +++ b/src/sat/kissat/fastassign.h @@ -0,0 +1,41 @@ +#ifndef _fastassign_h_INCLUDED +#define _fastassign_h_INCLUDED + +#define FAST_ASSIGN + +#include "inline.h" +#include "inlineassign.h" + +static inline void kissat_fast_binary_assign ( + kissat *solver, const bool probing, const unsigned level, value *values, + assigned *assigned, unsigned lit, unsigned other) { + if (GET_OPTION (jumpreasons) && level && solver->classification.bigbig) { + unsigned other_idx = IDX (other); + struct assigned *a = assigned + other_idx; + if (a->binary) { + LOGBINARY (lit, other, "jumping %s reason", LOGLIT (lit)); + INC (jumped_reasons); + other = a->reason; + } + } + kissat_fast_assign (solver, probing, level, values, assigned, true, lit, + other); + LOGBINARY (lit, other, "assign %s reason", LOGLIT (lit)); +} + +static inline void +kissat_fast_assign_reference (kissat *solver, value *values, + assigned *assigned, unsigned lit, + reference ref, clause *reason) { + assert (reason == kissat_dereference_clause (solver, ref)); + const unsigned level = + kissat_assignment_level (solver, values, assigned, lit, reason); + assert (level <= solver->level); + assert (ref != DECISION_REASON); + assert (ref != UNIT_REASON); + kissat_fast_assign (solver, solver->probing, level, values, assigned, + false, lit, ref); + LOGREF (ref, "assign %s reason", LOGLIT (lit)); +} + +#endif diff --git a/src/sat/kissat/fastel.c b/src/sat/kissat/fastel.c new file mode 100644 index 000000000..64ddccf3a --- /dev/null +++ b/src/sat/kissat/fastel.c @@ -0,0 +1,934 @@ +#include "fastel.h" +#include "dense.h" +#include "eliminate.h" +#include "inline.h" +#include "internal.h" +#include "print.h" +#include "rank.h" +#include "report.h" +#include "terminate.h" +#include "weaken.h" + +static bool fast_forward_subsumed (kissat *solver, clause *c) { + assert (!c->garbage); + assert (!c->redundant); + unsigned max_occurring = INVALID_LIT; + size_t max_occurrence = 0; + watches *all_watches = solver->watches; + mark *marks = solver->marks; + value *values = solver->values; + for (all_literals_in_clause (other, c)) { + const unsigned other_idx = IDX (other); + if (!ACTIVE (other_idx)) + continue; + watches *other_watches = all_watches + other; + size_t other_occurrence = SIZE_WATCHES (*other_watches); + if (other_occurrence <= max_occurrence) + continue; + max_occurrence = other_occurrence; + max_occurring = other; + marks[other] = 1; + } + bool subsumed = false; + const size_t fasteloccs = GET_OPTION (fasteloccs); + for (all_literals_in_clause (other, c)) { + if (other == max_occurring) + continue; + const unsigned other_idx = IDX (other); + if (!ACTIVE (other_idx)) + continue; + watches *other_watches = all_watches + other; + const size_t size_other_watches = SIZE_WATCHES (*other_watches); + if (size_other_watches > fasteloccs) + continue; + for (all_binary_large_watches (watch, *other_watches)) { + if (watch.type.binary) { + const unsigned other2 = watch.type.lit; + if (marks[other2]) { + LOGBINARY (other, other2, "subsuming"); + subsumed = true; + break; + } + } else { + const reference d_ref = watch.large.ref; + clause *d = kissat_dereference_clause (solver, d_ref); + if (d == c) + continue; + if (d->garbage) + continue; + if (d->size > c->size) + continue; + assert (!d->redundant); + subsumed = true; + for (all_literals_in_clause (other2, d)) { + if (values[other2] < 0) + continue; + if (!marks[other2]) { + subsumed = false; + break; + } + } + if (subsumed) + LOGCLS (d, "subsuming"); + } + } + if (subsumed) + break; + } + for (all_literals_in_clause (other, c)) + marks[other] = 0; + if (subsumed) { + LOGCLS (c, "subsumed"); + kissat_mark_clause_as_garbage (solver, c); + INC (subsumed); + INC (fast_subsumed); + } + return subsumed; +} + +static size_t flush_occurrences (kissat *solver, unsigned lit) { + const size_t fasteloccs = GET_OPTION (fasteloccs); + const size_t fastelclslim = GET_OPTION (fastelclslim); + const size_t fastelsub = GET_OPTION (fastelsub); + const value *const values = solver->values; + const flags *const all_flags = solver->flags; + watches *watches = &WATCHES (lit); + watch *begin = BEGIN_WATCHES (*watches); + watch *end = END_WATCHES (*watches); + watch *q = begin, *p = q; + size_t res = 0; + while (p != end) { + const watch watch = *q++ = *p++; + if (watch.type.binary) { + const unsigned other = watch.binary.lit; + if (values[other] > 0) + continue; + const unsigned other_idx = IDX (other); + const flags *other_flags = all_flags + other_idx; + if (other_flags->eliminated) { + q--; + continue; + } + } else { + const reference ref = watch.large.ref; + clause *c = kissat_dereference_clause (solver, ref); + if (c->garbage) { + q--; + continue; + } + if (c->size > fastelclslim) { + res = fasteloccs + 1; + break; + } + for (all_literals_in_clause (other, c)) { + value other_value = values[other]; + if (other_value > 0) { + LOGCLS (c, "%s satisfied", LOGLIT (other)); + kissat_mark_clause_as_garbage (solver, c); + q--; + continue; + } + } + if (fastelsub && fast_forward_subsumed (solver, c)) { + q--; + continue; + } + } + if (++res > fasteloccs) + break; + } + if (q < p) { + while (p != end) + *q++ = *p++; + SET_END_OF_WATCHES (*watches, q); + } + return res; +} + +static void do_fast_resolve_binary_binary (kissat *solver, unsigned pivot, + unsigned clit, unsigned dlit) { + assert (!FLAGS (IDX (clit))->eliminated); + assert (!FLAGS (IDX (dlit))->eliminated); + if (clit == NOT (dlit)) { + LOG ("resolvent tautological"); + return; + } + value *values = solver->values; + value cval = values[clit]; + if (cval > 0) { + LOG ("1st antecedent satisfied"); + return; + } + value dval = values[dlit]; + if (dval > 0) { + LOG ("2nd antecedent satisfied"); + return; + } + if (cval < 0 && dval < 0) { + assert (!solver->inconsistent); + solver->inconsistent = true; + LOG ("resolved empty clause"); + CHECK_AND_ADD_EMPTY (); + ADD_EMPTY_TO_PROOF (); + return; + } + if (cval < 0) { + LOG ("resolved unit clause %s", LOGLIT (dlit)); + INC (eliminate_units); + kissat_learned_unit (solver, dlit); + return; + } + if (dval < 0) { + LOG ("resolved unit clause %s", LOGLIT (clit)); + INC (eliminate_units); + kissat_learned_unit (solver, clit); + return; + } + if (clit == dlit) { + LOG ("resolved unit clause %s", LOGLIT (clit)); + INC (eliminate_units); + kissat_learned_unit (solver, clit); + return; + } + assert (!cval); + assert (!dval); + unsigneds *clause = &solver->clause; + assert (EMPTY_STACK (*clause)); + PUSH_STACK (*clause, clit); + PUSH_STACK (*clause, dlit); + LOGTMP ("%s resolvent", LOGVAR (pivot)); +#ifndef LOGGING + (void) pivot; +#endif + kissat_new_irredundant_clause (solver); + CLEAR_STACK (*clause); +} + +static void do_fast_resolve_binary_large (kissat *solver, unsigned pivot, + unsigned lit, clause *c) { + assert (!FLAGS (IDX (lit))->eliminated); + if (c->garbage) + return; + assert (!c->redundant); + value *values = solver->values; + value lit_val = values[lit]; + if (lit_val > 0) { + LOG ("binary clause antecedent satisfied"); + return; + } + unsigneds *clause = &solver->clause; + assert (EMPTY_STACK (*clause)); + if (!lit_val) + PUSH_STACK (*clause, lit); + bool satisfied = false, tautological = false; + const unsigned not_lit = NOT (lit); + for (all_literals_in_clause (other, c)) { + const unsigned idx_other = IDX (other); + if (idx_other == pivot) + continue; + if (other == lit) + continue; + if (other == not_lit) { + LOG ("resolvent tautological"); + tautological = true; + break; + } + value other_val = values[other]; + if (other_val < 0) + continue; + if (other_val > 0) { + LOG ("large clause antecedent satisfied"); + kissat_mark_clause_as_garbage (solver, c); + satisfied = true; + break; + } + PUSH_STACK (*clause, other); + } + if (satisfied || tautological) { + CLEAR_STACK (*clause); + return; + } + size_t size = SIZE_STACK (*clause); + if (!size) { + assert (!solver->inconsistent); + solver->inconsistent = true; + LOG ("resolved empty clause"); + CHECK_AND_ADD_EMPTY (); + ADD_EMPTY_TO_PROOF (); + return; + } + if (size == 1) { + const unsigned unit = PEEK_STACK (*clause, 0); + CLEAR_STACK (*clause); + LOG ("resolved unit clause %s", LOGLIT (unit)); + INC (eliminate_units); + kissat_learned_unit (solver, unit); + return; + } + LOGTMP ("%s resolvent", LOGVAR (pivot)); + kissat_new_irredundant_clause (solver); + CLEAR_STACK (*clause); +} + +static void do_fast_resolve_large_large (kissat *solver, unsigned pivot, + clause *c, clause *d) { + if (c->garbage) + return; + if (d->garbage) + return; + assert (!c->redundant); + assert (!d->redundant); + value *values = solver->values; + mark *marks = solver->marks; + unsigneds *clause = &solver->clause; + assert (EMPTY_STACK (*clause)); + bool satisfied = false, tautological = false; + for (all_literals_in_clause (other, c)) { + const unsigned idx_other = IDX (other); + if (idx_other == pivot) + continue; + value other_val = values[other]; + if (other_val < 0) + continue; + if (other_val > 0) { + LOG ("1st antecedent satisfied"); + satisfied = true; + break; + } + PUSH_STACK (*clause, other); + marks[other] = 1; + } + if (satisfied || tautological) { + for (all_stack (unsigned, other, *clause)) + marks[other] = 0; + CLEAR_STACK (*clause); + return; + } + size_t marked = SIZE_STACK (*clause); + for (all_literals_in_clause (other, d)) { + const unsigned idx_other = IDX (other); + if (idx_other == pivot) + continue; + value other_val = values[other]; + if (other_val < 0) + continue; + if (other_val > 0) { + LOG ("2nd antecedent satisfied"); + satisfied = true; + break; + } + mark mark_other = marks[other]; + if (mark_other) + continue; + const unsigned not_other = NOT (other); + mark mark_not_other = marks[not_other]; + if (mark_not_other) { + LOG ("tautological resolvent"); + tautological = true; + break; + } + PUSH_STACK (*clause, other); + } + if (satisfied || tautological) { + for (all_stack (unsigned, other, *clause)) + marks[other] = 0; + CLEAR_STACK (*clause); + return; + } + size_t size = SIZE_STACK (*clause); + if (!size) { + assert (!solver->inconsistent); + solver->inconsistent = true; + LOG ("resolved empty clause"); + CHECK_AND_ADD_EMPTY (); + ADD_EMPTY_TO_PROOF (); + return; + } + if (size == 1) { + const unsigned unit = PEEK_STACK (*clause, 0); + CLEAR_STACK (*clause); + marks[unit] = 0; + LOG ("resolved unit clause %s", LOGLIT (unit)); + INC (eliminate_units); + kissat_learned_unit (solver, unit); + return; + } + LOGTMP ("%s resolvent", LOGVAR (pivot)); + kissat_new_irredundant_clause (solver); + RESIZE_STACK (*clause, marked); + for (all_stack (unsigned, other, *clause)) + marks[other] = 0; + CLEAR_STACK (*clause); +} + +static void do_fast_resolve (kissat *solver, unsigned pivot, watch cwatch, + watch dwatch) { + assert (!solver->inconsistent); + LOGWATCH (LIT (pivot), cwatch, "1st fast %s elimination antecedent", + LOGVAR (pivot)); + LOGWATCH (NOT (LIT (pivot)), dwatch, "1st fast %s elimination antecedent", + LOGVAR (pivot)); + const unsigned clit = cwatch.binary.lit; + const unsigned dlit = dwatch.binary.lit; + const reference cref = cwatch.large.ref; + const reference dref = dwatch.large.ref; + const bool cbin = cwatch.type.binary; + const bool dbin = dwatch.type.binary; + clause *c = cbin ? 0 : kissat_dereference_clause (solver, cref); + clause *d = dbin ? 0 : kissat_dereference_clause (solver, dref); + if (cbin && dbin) + do_fast_resolve_binary_binary (solver, pivot, clit, dlit); + else if (cbin && !dbin) + do_fast_resolve_binary_large (solver, pivot, clit, d); + else if (!cbin && dbin) + do_fast_resolve_binary_large (solver, pivot, dlit, c); + else { + assert (!cbin), assert (!dbin); + do_fast_resolve_large_large (solver, pivot, c, d); + } +} + +static void fast_delete_and_weaken_clauses (kissat *solver, unsigned lit) { + watches *all_watches = solver->watches; + watches *lit_watches = all_watches + lit; + value *values = solver->values; + for (all_binary_large_watches (watch, *lit_watches)) { + if (watch.type.binary) { + const unsigned other = watch.binary.lit; + const value value = values[other]; + if (value <= 0) + kissat_weaken_binary (solver, lit, other); + kissat_delete_binary (solver, lit, other); + } else { + const reference ref = watch.large.ref; + clause *c = kissat_dereference_clause (solver, ref); + if (!c->garbage) { + bool satisfied = false; + for (all_literals_in_clause (other, c)) + if (values[other] > 0) { + satisfied = true; + break; + } + if (!satisfied) + kissat_weaken_clause (solver, lit, c); + kissat_mark_clause_as_garbage (solver, c); + } + } + } + RELEASE_WATCHES (*lit_watches); +} + +static void do_fast_eliminate (kissat *solver, unsigned pivot) { + LOG ("fast variable elimination of %s", LOGVAR (pivot)); + const unsigned lit = LIT (pivot); + const unsigned not_lit = NOT (lit); + watches *all_watches = solver->watches; + watches *lit_watches = all_watches + lit; + watches *not_lit_watches = all_watches + not_lit; + LOG ("occurs %zu positively", SIZE_WATCHES (*lit_watches)); + LOG ("occurs %zu negatively", SIZE_WATCHES (*not_lit_watches)); + watch *begin_lit_watches = BEGIN_WATCHES (*lit_watches); + watch *begin_not_lit_watches = BEGIN_WATCHES (*not_lit_watches); + watch *end_lit_watches = END_WATCHES (*lit_watches); + watch *end_not_lit_watches = END_WATCHES (*not_lit_watches); + for (watch *p = begin_lit_watches; p < end_lit_watches; p++) + for (watch *q = begin_not_lit_watches; q < end_not_lit_watches; q++) { + do_fast_resolve (solver, pivot, *p, *q); + if (solver->inconsistent) + return; + watches *new_all_watches = solver->watches; + const size_t i = p - begin_lit_watches; + const size_t j = q - begin_not_lit_watches; + all_watches = new_all_watches; + lit_watches = all_watches + lit; + not_lit_watches = all_watches + not_lit; + begin_lit_watches = BEGIN_WATCHES (*lit_watches); + begin_not_lit_watches = BEGIN_WATCHES (*not_lit_watches); + end_lit_watches = END_WATCHES (*lit_watches); + end_not_lit_watches = END_WATCHES (*not_lit_watches); + p = begin_lit_watches + i; + q = begin_not_lit_watches + j; + } + assert (!solver->inconsistent); + INC (eliminated); + INC (fast_eliminated); + kissat_mark_eliminated_variable (solver, pivot); + fast_delete_and_weaken_clauses (solver, lit); + fast_delete_and_weaken_clauses (solver, not_lit); +} + +static bool can_fast_resolve_binary_binary (kissat *solver, unsigned clit, + unsigned dlit) { + assert (!FLAGS (IDX (clit))->eliminated); + assert (!FLAGS (IDX (dlit))->eliminated); + if (clit == NOT (dlit)) + return false; + value *values = solver->values; + value cval = values[clit]; + if (cval > 0) + return false; + value dval = values[dlit]; + if (dval > 0) + return false; + if (cval < 0 && dval < 0) { + assert (!solver->inconsistent); + solver->inconsistent = true; + LOG ("resolved empty clause"); + CHECK_AND_ADD_EMPTY (); + ADD_EMPTY_TO_PROOF (); + return false; + } + if (cval < 0) { + LOG ("resolved unit clause %s", LOGLIT (dlit)); + INC (eliminate_units); + kissat_learned_unit (solver, dlit); + return false; + } + if (dval < 0) { + LOG ("resolved unit clause %s", LOGLIT (clit)); + INC (eliminate_units); + kissat_learned_unit (solver, clit); + return false; + } + if (clit == dlit) { + LOG ("resolved unit clause %s", LOGLIT (clit)); + INC (eliminate_units); + kissat_learned_unit (solver, clit); + return false; + } + assert (!cval); + assert (!dval); + return true; +} + +static bool can_fast_resolve_binary_large (kissat *solver, unsigned pivot, + unsigned lit, clause *c) { + assert (!FLAGS (IDX (lit))->eliminated); + if (c->garbage) + return false; + assert (!c->redundant); + value *values = solver->values; + value lit_val = values[lit]; + if (lit_val > 0) + return false; + const unsigned not_lit = NOT (lit); + bool found_lit = false; + for (all_literals_in_clause (other, c)) { + if (other == lit) + found_lit = true; + if (other == not_lit) + return false; + value other_val = values[other]; + if (other_val > 0) { + LOG ("large clause antecedent satisfied"); + kissat_mark_clause_as_garbage (solver, c); + return false; + } + } + if (found_lit) { + unsigneds *clause = &solver->clause; + assert (EMPTY_STACK (*clause)); + for (all_literals_in_clause (other, c)) { + const unsigned idx = IDX (other); + if (idx == pivot) + continue; + value value = values[other]; + if (value < 0) + continue; + assert (!value); + PUSH_STACK (*clause, other); + } + LOGTMP ("self-subsuming resolvent"); + INC (strengthened); + INC (fast_strengthened); + const size_t size = SIZE_STACK (*clause); + const reference ref = kissat_reference_clause (solver, c); + if (!size) { + assert (!solver->inconsistent); + solver->inconsistent = true; + LOG ("resolved empty clause"); + CHECK_AND_ADD_EMPTY (); + ADD_EMPTY_TO_PROOF (); + } else if (size == 1) { + const unsigned unit = PEEK_STACK (*clause, 0); + LOG ("resolved %s unit clause", LOGLIT (unit)); + INC (eliminate_units); + kissat_learned_unit (solver, unit); + } else + kissat_new_irredundant_clause (solver); + CLEAR_STACK (*clause); + c = kissat_dereference_clause (solver, ref); + LOGCLS (c, "self-subsuming antecedent"); + kissat_mark_clause_as_garbage (solver, c); + return false; + } + return true; +} + +static bool can_fast_resolve_large_large (kissat *solver, unsigned pivot, + clause *c, clause *d) { + if (c->garbage) + return false; + if (d->garbage) + return false; + assert (!c->redundant); + assert (!d->redundant); + value *values = solver->values; + mark *marks = solver->marks; + bool satisfied = false; + unsigneds *clause = &solver->clause; + assert (EMPTY_STACK (*clause)); + for (all_literals_in_clause (other, c)) { + const unsigned idx_other = IDX (other); + if (idx_other == pivot) + continue; + value other_val = values[other]; + if (other_val < 0) + continue; + if (other_val > 0) { + satisfied = true; + LOGCLS (c, "%s satisfied", LOGLIT (other)); + kissat_mark_clause_as_garbage (solver, c); + break; + } + assert (!marks[other]); + marks[other] = 1; + PUSH_STACK (*clause, other); + } + bool tautological = false; + if (!satisfied) { + for (all_literals_in_clause (other, d)) { + const unsigned idx_other = IDX (other); + if (idx_other == pivot) + continue; + value other_val = values[other]; + if (other_val < 0) + continue; + if (other_val > 0) { + satisfied = true; + LOGCLS (d, "%s satisfied", LOGLIT (other)); + kissat_mark_clause_as_garbage (solver, d); + break; + } + const unsigned not_other = NOT (other); + const mark mark_not_other = marks[not_other]; + if (mark_not_other) { + tautological = true; + break; + } + const mark other_mark = marks[other]; + if (other_mark) + continue; + PUSH_STACK (*clause, other); + } + } + for (all_literals_in_clause (other, c)) + marks[other] = 0; + bool strengthened = false; + if (!satisfied && !tautological) { + const size_t size = SIZE_STACK (*clause); + if (!size) { + assert (!solver->inconsistent); + solver->inconsistent = true; + LOG ("resolved empty clause"); + CHECK_AND_ADD_EMPTY (); + ADD_EMPTY_TO_PROOF (); + strengthened = true; + } else if (size == 1) { + const unsigned unit = PEEK_STACK (*clause, 0); + LOG ("resolved %s unit clause", LOGLIT (unit)); + INC (eliminate_units); + kissat_learned_unit (solver, unit); + strengthened = true; + } else { + bool c_subsumed = false, d_subsumed = false; + bool marked = false; + if (size < c->size) { + marked = true; + for (all_stack (unsigned, other, *clause)) + marks[other] = 1; + size_t count = 0; + for (all_literals_in_clause (other, c)) + if (marks[other]) + count++; + c_subsumed = (count >= size); + } + if (size < d->size) { + if (!marked) { + marked = true; + for (all_stack (unsigned, other, *clause)) + marks[other] = 1; + } + size_t count = 0; + for (all_literals_in_clause (other, d)) + if (marks[other]) + count++; + d_subsumed = (count >= size); + } + if (marked) { + for (all_stack (unsigned, other, *clause)) + marks[other] = 0; + } + if (c_subsumed || d_subsumed) { + LOGTMP ("self-subsuming resolvent"); + INC (strengthened); + INC (fast_strengthened); + const reference c_ref = kissat_reference_clause (solver, c); + const reference d_ref = kissat_reference_clause (solver, d); + kissat_new_irredundant_clause (solver); + strengthened = true; + if (c_subsumed) { + c = kissat_dereference_clause (solver, c_ref); + LOGCLS (c, "self-subsuming antecedent"); + kissat_mark_clause_as_garbage (solver, c); + } + if (d_subsumed) { + d = kissat_dereference_clause (solver, d_ref); + LOGCLS (d, "self-subsuming antecedent"); + kissat_mark_clause_as_garbage (solver, d); + } + if (c_subsumed && d_subsumed) + INC (fast_subsumed); + } + } + } + CLEAR_STACK (*clause); + return !satisfied && !tautological && !strengthened; +} + +static bool can_fast_resolve (kissat *solver, unsigned pivot, watch cwatch, + watch dwatch) { + assert (!solver->inconsistent); + const unsigned clit = cwatch.binary.lit; + const unsigned dlit = dwatch.binary.lit; + const reference cref = cwatch.large.ref; + const reference dref = dwatch.large.ref; + const bool cbin = cwatch.type.binary; + const bool dbin = dwatch.type.binary; + clause *c = cbin ? 0 : kissat_dereference_clause (solver, cref); + clause *d = dbin ? 0 : kissat_dereference_clause (solver, dref); + if (cbin && dbin) + return can_fast_resolve_binary_binary (solver, clit, dlit); + if (cbin && !dbin) + return can_fast_resolve_binary_large (solver, pivot, clit, d); + if (!cbin && dbin) + return can_fast_resolve_binary_large (solver, pivot, dlit, c); + assert (!cbin), assert (!dbin); + return can_fast_resolve_large_large (solver, pivot, c, d); +} + +static bool resolvents_limited (kissat *solver, unsigned pivot, + size_t limit) { + const unsigned lit = LIT (pivot); + const unsigned not_lit = NOT (lit); + watches *all_watches = solver->watches; + watches *lit_watches = all_watches + lit; + watches *not_lit_watches = all_watches + not_lit; + watch *begin_lit_watches = BEGIN_WATCHES (*lit_watches); + watch *begin_not_lit_watches = BEGIN_WATCHES (*not_lit_watches); + watch *end_lit_watches = END_WATCHES (*lit_watches); + watch *end_not_lit_watches = END_WATCHES (*not_lit_watches); + size_t resolved = 0; + for (watch *p = begin_lit_watches; p < end_lit_watches; p++) + for (watch *q = begin_not_lit_watches; q < end_not_lit_watches; q++) { + if (can_fast_resolve (solver, pivot, *p, *q) && ++resolved > limit) + return false; + if (solver->inconsistent) + return false; + watches *new_all_watches = solver->watches; + const size_t i = p - begin_lit_watches; + const size_t j = q - begin_not_lit_watches; + all_watches = new_all_watches; + lit_watches = all_watches + lit; + not_lit_watches = all_watches + not_lit; + begin_lit_watches = BEGIN_WATCHES (*lit_watches); + begin_not_lit_watches = BEGIN_WATCHES (*not_lit_watches); + end_lit_watches = END_WATCHES (*lit_watches); + end_not_lit_watches = END_WATCHES (*not_lit_watches); + p = begin_lit_watches + i; + q = begin_not_lit_watches + j; + } + return true; +} + +static bool try_to_fast_eliminate (kissat *solver, unsigned pivot) { + assert (!solver->inconsistent); + if (!ACTIVE (pivot)) + return false; + const unsigned lit = LIT (pivot); + const unsigned not_lit = NOT (lit); + const size_t fasteloccs = GET_OPTION (fasteloccs); + const size_t pos = flush_occurrences (solver, lit); + if (pos > fasteloccs) + return false; + const size_t neg = flush_occurrences (solver, not_lit); + if (neg > fasteloccs) + return false; + const size_t sum = pos + neg; + const size_t product = pos * neg; + if (sum > fasteloccs) + return false; + const size_t fastelim = GET_OPTION (fastelim); + if (product <= fastelim) { + do_fast_eliminate (solver, pivot); + return true; + } + if (resolvents_limited (solver, pivot, fastelim)) { + do_fast_eliminate (solver, pivot); + return true; + } + return false; +} + +static void flush_eliminated_binary_clauses_of_literal (kissat *solver, + unsigned lit) { + flags *all_flags = solver->flags; + watches *watches = &WATCHES (lit); + watch *begin = BEGIN_WATCHES (*watches); + watch *end = END_WATCHES (*watches); + watch *q = begin, *p = q; + while (p != end) { + watch watch = *q++ = *p++; + if (!watch.type.binary) + continue; + const unsigned other = watch.binary.lit; + const unsigned other_idx = IDX (other); + flags *other_flags = all_flags + other_idx; + if (other_flags->eliminated) + q--; + } + SET_END_OF_WATCHES (*watches, q); +} + +static void flush_eliminated_binary_clauses (kissat *solver) { + for (all_variables (idx)) { + const unsigned lit = LIT (idx); + const unsigned not_lit = NOT (lit); + flush_eliminated_binary_clauses_of_literal (solver, lit); + flush_eliminated_binary_clauses_of_literal (solver, not_lit); + } +} + +struct candidate { + unsigned pivot; + unsigned score; +}; + +typedef struct candidate candidate; +typedef STACK (candidate) candidates; + +#define RANK_CANDIDATE(CANDIDATE) ((CANDIDATE).score) + +void kissat_fast_variable_elimination (kissat *solver) { + if (solver->inconsistent) + return; + if (!GET_OPTION (fastel)) + return; +#ifndef QUIET + const unsigned variables_before = solver->active; +#endif + assert (!solver->level); + START (fastel); + kissat_enter_dense_mode (solver, 0); + kissat_connect_irredundant_large_clauses (solver); + const unsigned fastelrounds = GET_OPTION (fastelrounds); + const size_t fasteloccs = GET_OPTION (fasteloccs); +#ifndef QUIET + unsigned eliminated = 0; +#endif + unsigned round = 0; + candidates candidates; + INIT_STACK (candidates); + bool done = false; + do { + if (round++ >= fastelrounds) + break; + kissat_extremely_verbose ( + solver, "gathering candidates for fast elimination round %u", + round); + assert (EMPTY_STACK (candidates)); + flags *all_flags = solver->flags; + for (all_variables (pivot)) { + flags *pivot_flags = all_flags + pivot; + if (!pivot_flags->active) + continue; + if (!pivot_flags->eliminate) + continue; + const unsigned lit = LIT (pivot); + const size_t pos = flush_occurrences (solver, lit); + if (pos > fasteloccs) + continue; + const unsigned not_lit = LIT (pivot); + const size_t neg = flush_occurrences (solver, not_lit); + if (neg > fasteloccs) + continue; + const unsigned score = pos + neg; + if (score > fasteloccs) + continue; + candidate candidate = {pivot, score}; + PUSH_STACK (candidates, candidate); + } +#ifndef QUIET + const size_t size_candidates = SIZE_STACK (candidates); + const size_t active_variables = solver->active; + kissat_extremely_verbose ( + solver, "gathered %zu candidates %.0f%% in elimination round %u", + size_candidates, kissat_percent (size_candidates, active_variables), + round); +#endif + RADIX_STACK (candidate, unsigned, candidates, RANK_CANDIDATE); + unsigned eliminated_this_round = 0; + for (all_stack (candidate, candidate, candidates)) { + const unsigned pivot = candidate.pivot; + flags *pivot_flags = all_flags + pivot; + if (!pivot_flags->active) + continue; + if (!pivot_flags->eliminate) + continue; + if (TERMINATED (fastel_terminated_1)) { + done = true; + break; + } + if (try_to_fast_eliminate (solver, pivot)) + eliminated_this_round++; + if (solver->inconsistent) { + done = true; + break; + } + pivot_flags->eliminate = false; + kissat_flush_units_while_connected (solver); + if (solver->inconsistent) { + done = true; + break; + } + } + CLEAR_STACK (candidates); +#ifndef QUIET + eliminated += eliminated_this_round; + kissat_very_verbose ( + solver, "fast eliminated %u of %zu candidates %.0f%% in round %u", + eliminated_this_round, size_candidates, + kissat_percent (eliminated_this_round, size_candidates), round); +#endif + if (!eliminated_this_round) + done = true; + } while (!done); + RELEASE_STACK (candidates); + for (all_variables (idx)) + FLAGS (idx)->eliminate = true; + flush_eliminated_binary_clauses (solver); + kissat_resume_sparse_mode (solver, true, 0); +#ifndef QUIET + const unsigned original_variables = solver->statistics.variables_original; + const unsigned variables_after = solver->active; + kissat_verbose ( + solver, + "[fastel] " + "fast elimination of %u variables %.0f%% (%u remain %.0f%%)", + eliminated, kissat_percent (eliminated, variables_before), + variables_after, + kissat_percent (variables_after, original_variables)); +#endif + STOP (fastel); + REPORT (!eliminated, 'e'); +} diff --git a/src/sat/kissat/fastel.h b/src/sat/kissat/fastel.h new file mode 100644 index 000000000..a2a5cfcd5 --- /dev/null +++ b/src/sat/kissat/fastel.h @@ -0,0 +1,6 @@ +#ifndef _fastel_h_INCLUDED + +struct kissat; +void kissat_fast_variable_elimination (struct kissat *); + +#endif diff --git a/src/sat/kissat/fifo.h b/src/sat/kissat/fifo.h new file mode 100644 index 000000000..508989aa5 --- /dev/null +++ b/src/sat/kissat/fifo.h @@ -0,0 +1,97 @@ +#ifndef _fifo_h_INCLUDED +#define _fifo_h_INCLUDED + +#include "stack.h" + +#include + +#define FIFO(TYPE) \ + struct { \ + TYPE *begin; \ + TYPE *end; \ + TYPE *start; \ + TYPE *limit; \ + TYPE *allocated; \ + } + +#define BEGIN_FIFO(F) ((F).begin) +#define END_FIFO(F) ((F).end) +#define START_FIFO(F) ((F).start) +#define LIMIT_FIFO(F) ((F).limit) +#define ALLOCATED_FIFO(F) ((F).allocated) + +#define INIT_FIFO(F) memset (&(F), 0, sizeof (F)) + +#define EMPTY_FIFO(F) (END_FIFO (F) == BEGIN_FIFO (F)) +#define FULL_FIFO(F) (END_FIFO (F) == ALLOCATED_FIFO (F)) +#define SIZE_FIFO(F) (END_FIFO (F) - BEGIN_FIFO (F)) + +#define MOVABLE_FIFO(F) (BEGIN_FIFO (F) == LIMIT_FIFO (F)) +#define CAPACITY_FIFO(F) (ALLOCATED_FIFO (F) - START_FIFO (F)) + +#define ENLARGE_FIFO(F) \ + do { \ + size_t OLD_BEGIN_OFFSET = BEGIN_FIFO (F) - START_FIFO (F); \ + size_t OLD_END_OFFSET = END_FIFO (F) - START_FIFO (F); \ + size_t OLD_CAPACITY = CAPACITY_FIFO (F); \ + size_t NEW_CAPACITY = OLD_CAPACITY ? 2 * OLD_CAPACITY : 2; \ + size_t OLD_BYTES = OLD_CAPACITY * sizeof *BEGIN_FIFO (F); \ + size_t NEW_BYTES = NEW_CAPACITY * sizeof *BEGIN_FIFO (F); \ + START_FIFO (F) = \ + kissat_realloc (solver, START_FIFO (F), OLD_BYTES, NEW_BYTES); \ + ALLOCATED_FIFO (F) = START_FIFO (F) + NEW_CAPACITY; \ + LIMIT_FIFO (F) = START_FIFO (F) + NEW_CAPACITY / 2; \ + BEGIN_FIFO (F) = START_FIFO (F) + OLD_BEGIN_OFFSET; \ + END_FIFO (F) = START_FIFO (F) + OLD_END_OFFSET; \ + assert (BEGIN_FIFO (F) < LIMIT_FIFO (F)); \ + } while (0) + +#define MOVE_FIFO(F) \ + do { \ + size_t SIZE = SIZE_FIFO (F); \ + size_t BYTES = SIZE * sizeof *BEGIN_FIFO (F); \ + memmove (START_FIFO (F), BEGIN_FIFO (F), BYTES); \ + BEGIN_FIFO (F) = START_FIFO (F); \ + END_FIFO (F) = BEGIN_FIFO (F) + SIZE; \ + } while (0) + +#define ENQUEUE_FIFO(F, E) \ + do { \ + if (FULL_FIFO (F)) \ + ENLARGE_FIFO (F); \ + *END_FIFO (F)++ = (E); \ + } while (0) + +#define DEQUEUE_FIFO(F, E) \ + do { \ + assert (!EMPTY_FIFO (F)); \ + (E) = *BEGIN_FIFO (F)++; \ + if (MOVABLE_FIFO (F)) \ + MOVE_FIFO (F); \ + } while (0) + +#define POP_FIFO(F) (assert (!EMPTY_FIFO (F)), *--END_FIFO (F)) + +#define RELEASE_FIFO(F) \ + do { \ + size_t CAPACITY = CAPACITY_FIFO (F); \ + size_t BYTES = CAPACITY * sizeof *BEGIN_FIFO (F); \ + kissat_free (solver, START_FIFO (F), BYTES); \ + INIT_FIFO (F); \ + } while (0) + +#define CLEAR_FIFO(F) \ + do { \ + BEGIN_FIFO (F) = END_FIFO (F) = START_FIFO (F); \ + } while (0) + +struct unsigned_fifo { + unsigned *begin, *end; + unsigned *start, *limit, *allocated; +}; + +typedef struct unsigned_fifo unsigned_fifo; + +#define all_fifo all_stack + +#endif diff --git a/src/sat/kissat/file.c b/src/sat/kissat/file.c new file mode 100644 index 000000000..b6bda097b --- /dev/null +++ b/src/sat/kissat/file.c @@ -0,0 +1,310 @@ +#include "file.h" +#include "keatures.h" +#include "utilities.h" + +#include +#include +#include +#include +#include +#include + +bool kissat_file_exists (const char *path) { + if (!path) + return false; + struct stat buf; + if (stat (path, &buf)) + return false; + return true; +} + +bool kissat_file_readable (const char *path) { + if (!path) + return false; + struct stat buf; + if (stat (path, &buf)) + return false; + if (access (path, R_OK)) + return false; + return true; +} + +bool kissat_file_writable (const char *path) { + int res; + if (!path) + res = 1; + else if (!strcmp (path, "/dev/null")) + res = 0; + else { + if (!*path) + res = 2; + else { + struct stat buf; + const char *p = strrchr (path, '/'); + if (!p) { + if (stat (path, &buf)) { + if (errno == ENOENT) + res = 0; + else + res = -2; + } else if (S_ISDIR (buf.st_mode)) + res = 3; + else if (access (path, W_OK)) + res = 4; + else + res = 0; + } else if (!p[1]) + res = 5; + else { + const size_t len = p - path; + char *dirname = malloc (len + 1); + if (dirname) { + strncpy (dirname, path, len); + dirname[len] = 0; + if (stat (dirname, &buf)) + res = 6; + else if (!S_ISDIR (buf.st_mode)) + res = 7; + else if (access (dirname, W_OK)) + res = 8; + else if (stat (path, &buf)) { + if (errno == ENOENT) + res = 0; + else + res = -3; + } else if (access (path, W_OK)) + res = 9; + else + res = 0; + free (dirname); + } else + res = 10; + } + } + } + return !res; +} + +size_t kissat_file_size (const char *path) { + struct stat buf; + if (stat (path, &buf)) + return 0; + return (size_t) buf.st_size; +} + +bool kissat_find_executable (const char *name) { + const size_t name_len = strlen (name); + const char *environment = getenv ("PATH"); + if (!environment) + return false; + const size_t dirs_len = strlen (environment); + char *dirs = malloc (dirs_len + 1); + if (!dirs) + return false; + strcpy (dirs, environment); + bool res = false; + const char *end = dirs + dirs_len + 1; + for (char *dir = dirs, *q; !res && dir != end; dir = q) { + for (q = dir; *q && *q != ':'; q++) + assert (q + 1 < end); + *q++ = 0; + const size_t path_len = (q - dir) + name_len; + char *path = malloc (path_len + 1); + if (!path) { + free (dirs); + return false; + } + sprintf (path, "%s/%s", dir, name); + assert (strlen (path) == path_len); + res = kissat_file_readable (path); + free (path); + } + free (dirs); + return res; +} + +static int bz2sig[] = {0x42, 0x5A, 0x68, EOF}; +static int gzsig[] = {0x1F, 0x8B, EOF}; +static int lzmasig[] = {0x5D, 0x00, 0x00, 0x80, 0x00, EOF}; +static int sig7z[] = {0x37, 0x7A, 0xBC, 0xAF, 0x27, 0x1C, EOF}; +static int xzsig[] = {0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, EOF}; +static int Zsig[] = {0x1F, 0x9D, 0x90, EOF}; + +static bool match_signature (const char *path, const int *sig) { + assert (path); + FILE *tmp = fopen (path, "r"); + if (!tmp) + return false; + bool res = true; + for (const int *p = sig; res && (*p != EOF); p++) + res = (getc (tmp) == *p); + fclose (tmp); + return res; +} + +#ifdef KISSAT_HAS_COMPRESSION + +static FILE *open_pipe (const char *fmt, const char *path, + const char *mode) { + size_t name_len = 0; + while (fmt[name_len] && fmt[name_len] != ' ') + name_len++; + char *name = malloc (name_len + 1); + if (!name) + return 0; + strncpy (name, fmt, name_len); + name[name_len] = 0; + bool found = kissat_find_executable (name); + free (name); + if (!found) + return 0; + char *cmd = malloc (strlen (fmt) + strlen (path)); + if (!cmd) + return 0; + sprintf (cmd, fmt, path); + FILE *res = popen (cmd, mode); + free (cmd); + return res; +} + +static FILE *read_pipe (const char *fmt, const int *sig, const char *path) { + if (!kissat_file_readable (path)) + return 0; + if (sig && !match_signature (path, sig)) + return 0; + return open_pipe (fmt, path, "r"); +} + +#ifndef SAFE + +static FILE *write_pipe (const char *fmt, const char *path) { + return open_pipe (fmt, path, "w"); +} + +#endif + +#endif + +void kissat_read_already_open_file (file *file, FILE *f, const char *path) { + file->file = f; + file->close = false; + file->reading = true; + file->compressed = false; + file->path = path; + file->bytes = 0; +} + +void kissat_write_already_open_file (file *file, FILE *f, + const char *path) { + file->file = f; + file->close = false; + file->reading = false; + file->compressed = false; + file->path = path; + file->bytes = 0; +} + +#ifndef KISSAT_HAS_COMPRESSION + +bool kissat_looks_like_a_compressed_file (const char *path) { +#define RETURN_TRUE_IF_COMPRESSED(SUFFIX, SIGNATURE) \ + if (kissat_has_suffix (path, SUFFIX) && \ + match_signature (path, SIGNATURE)) \ + return true + + RETURN_TRUE_IF_COMPRESSED (".bz2", bz2sig); + RETURN_TRUE_IF_COMPRESSED (".gz", gzsig); + RETURN_TRUE_IF_COMPRESSED (".lzma", lzmasig); + RETURN_TRUE_IF_COMPRESSED (".7z", sig7z); + RETURN_TRUE_IF_COMPRESSED (".xz", xzsig); + RETURN_TRUE_IF_COMPRESSED (".Z", Zsig); + + return false; +} + +#endif + +bool kissat_open_to_read_file (file *file, const char *path) { +#ifdef KISSAT_HAS_COMPRESSION +#define READ_PIPE(SUFFIX, CMD, SIG) \ + do { \ + if (kissat_has_suffix (path, SUFFIX)) { \ + file->file = read_pipe (CMD, SIG, path); \ + if (!file->file) \ + break; \ + file->close = true; \ + file->reading = true; \ + file->compressed = true; \ + file->path = path; \ + file->bytes = 0; \ + return true; \ + } \ + } while (0) + READ_PIPE (".bz2", "bzip2 -c -d %s", bz2sig); + READ_PIPE (".gz", "gzip -c -d %s", gzsig); + READ_PIPE (".lzma", "lzma -c -d %s", lzmasig); + READ_PIPE (".7z", "7z x -so %s 2>/dev/null", sig7z); + READ_PIPE (".xz", "xz -c -d %s", xzsig); + READ_PIPE (".Z", "gzip -c -d %s", Zsig); +#endif + file->file = fopen (path, "r"); + if (!file->file) + return false; + file->close = true; + file->reading = true; + file->compressed = false; + file->path = path; + file->bytes = 0; + + return true; +} + +bool kissat_open_to_write_file (file *file, const char *path) { +#if defined(KISSAT_HAS_COMPRESSION) && !defined(SAFE) +#define WRITE_PIPE(SUFFIX, CMD) \ + do { \ + if (kissat_has_suffix (path, SUFFIX)) { \ + if (SUFFIX[1] == '7' && kissat_file_readable (path) && \ + unlink (path)) \ + return false; \ + file->file = write_pipe (CMD, path); \ + if (!file->file) \ + return false; \ + file->close = true; \ + file->reading = false; \ + file->compressed = true; \ + file->path = path; \ + file->bytes = 0; \ + return true; \ + } \ + } while (0) + WRITE_PIPE (".bz2", "bzip2 -c > %s"); + WRITE_PIPE (".gz", "gzip -c > %s"); + WRITE_PIPE (".lzma", "lzma -c > %s"); + WRITE_PIPE (".7z", "7z a -si %s 2>/dev/null"); + WRITE_PIPE (".xz", "xz -c > %s"); +#endif + file->file = fopen (path, "w"); + if (!file->file) + return false; + file->close = true; + file->reading = false; + file->compressed = false; + file->path = path; + file->bytes = 0; + return true; +} + +void kissat_close_file (file *file) { + assert (file); + assert (file->file); +#ifdef KISSAT_HAS_COMPRESSION + if (file->close && file->compressed) + pclose (file->file); +#else + assert (!file->compressed); +#endif + if (file->close && !file->compressed) + fclose (file->file); + file->file = 0; +} diff --git a/src/sat/kissat/file.h b/src/sat/kissat/file.h new file mode 100644 index 000000000..300cdb138 --- /dev/null +++ b/src/sat/kissat/file.h @@ -0,0 +1,124 @@ +#ifndef _file_h_INCLUDED +#define _file_h_INCLUDED + +#include +#include +#include +#include + +#include "attribute.h" +#include "keatures.h" + +bool kissat_file_exists (const char *path); +bool kissat_file_readable (const char *path); +bool kissat_file_writable (const char *path); +size_t kissat_file_size (const char *path); +bool kissat_find_executable (const char *name); + +typedef struct file file; + +struct file { + FILE *file; + bool close; + bool reading; + bool compressed; + const char *path; + uint64_t bytes; +}; + +void kissat_read_already_open_file (file *, FILE *, const char *path); +void kissat_write_already_open_file (file *, FILE *, const char *path); + +bool kissat_open_to_read_file (file *, const char *path); +bool kissat_open_to_write_file (file *, const char *path); + +void kissat_close_file (file *); + +#ifndef KISSAT_HAS_COMPRESSION + +bool kissat_looks_like_a_compressed_file (const char *path); + +#endif + +// clang-format off + +static inline size_t +kissat_read (file *, void *, size_t) ATTRIBUTE_ALWAYS_INLINE; + +static inline size_t +kissat_write (file *, void *, size_t) ATTRIBUTE_ALWAYS_INLINE; + +static inline int kissat_getc (file *) ATTRIBUTE_ALWAYS_INLINE; + +static inline int kissat_putc (file *, int) ATTRIBUTE_ALWAYS_INLINE; + +static inline void kissat_flush (file *) ATTRIBUTE_ALWAYS_INLINE; + +// clang-format on + +static inline size_t kissat_read (file *file, void *ptr, size_t bytes) { + assert (file); + assert (file->file); + assert (file->reading); +#ifdef KISSAT_HAS_UNLOCKEDIO + size_t res = fread_unlocked (ptr, 1, bytes, file->file); +#else + size_t res = fread (ptr, 1, bytes, file->file); +#endif + file->bytes += res; + return res; +} + +static inline size_t kissat_write (file *file, void *ptr, size_t bytes) { + assert (file); + assert (file->file); + assert (!file->reading); +#ifdef KISSAT_HAS_UNLOCKEDIO + size_t res = fwrite_unlocked (ptr, 1, bytes, file->file); +#else + size_t res = fwrite (ptr, 1, bytes, file->file); +#endif + file->bytes += res; + return res; +} + +static inline int kissat_getc (file *file) { + assert (file); + assert (file->file); + assert (file->reading); +#ifdef KISSAT_HAS_UNLOCKEDIO + int res = getc_unlocked (file->file); +#else + int res = getc (file->file); +#endif + if (res != EOF) + file->bytes++; + return res; +} + +static inline int kissat_putc (file *file, int ch) { + assert (file); + assert (file->file); + assert (!file->reading); +#ifdef KISSAT_HAS_UNLOCKEDIO + int res = putc_unlocked (ch, file->file); +#else + int res = putc (ch, file->file); +#endif + if (res != EOF) + file->bytes++; + return ch; +} + +static inline void kissat_flush (file *file) { + assert (file); + assert (file->file); + assert (!file->reading); +#ifdef KISSAT_HAS_UNLOCKEDIO + fflush_unlocked (file->file); +#else + fflush (file->file); +#endif +} + +#endif diff --git a/src/sat/kissat/flags.c b/src/sat/kissat/flags.c new file mode 100644 index 000000000..b7189350e --- /dev/null +++ b/src/sat/kissat/flags.c @@ -0,0 +1,115 @@ +#include "inline.h" +#include "inlineheap.h" +#include "inlinequeue.h" + +static inline void activate_literal (kissat *solver, unsigned lit) { + const unsigned idx = IDX (lit); + flags *f = FLAGS (idx); + if (f->active) + return; + lit = STRIP (lit); + LOG ("activating %s", LOGVAR (idx)); + f->active = true; + assert (!f->fixed); + assert (!f->eliminated); + solver->active++; + INC (variables_activated); + kissat_enqueue (solver, idx); + const double score = 1.0 - 1.0 / solver->statistics.variables_activated; + kissat_update_heap (solver, &solver->scores, idx, score); + if (solver->stable) { + const unsigned lit = LIT (idx); + if (!VALUE (lit)) + kissat_push_heap (solver, &solver->scores, idx); + } + assert (solver->unassigned < UINT_MAX); + solver->unassigned++; + kissat_mark_removed_literal (solver, lit); + kissat_mark_added_literal (solver, lit); + assert (!VALUE (lit)); + assert (!VALUE (NOT (lit))); + assert (!SAVED (idx)); + assert (!TARGET (idx)); + assert (!BEST (idx)); +} + +static inline void deactivate_variable (kissat *solver, flags *f, + unsigned idx) { + assert (solver->flags + idx == f); + LOG ("deactivating %s", LOGVAR (idx)); + assert (f->active); + assert (f->eliminated || f->fixed); + f->active = false; + assert (solver->active > 0); + solver->active--; + kissat_dequeue (solver, idx); + if (kissat_heap_contains (SCORES, idx)) + kissat_pop_heap (solver, SCORES, idx); +} + +void kissat_activate_literal (kissat *solver, unsigned lit) { + activate_literal (solver, lit); +} + +void kissat_activate_literals (kissat *solver, unsigned size, + unsigned *lits) { + for (unsigned i = 0; i < size; i++) + activate_literal (solver, lits[i]); +} + +void kissat_mark_fixed_literal (kissat *solver, unsigned lit) { + assert (VALUE (lit) > 0); + const unsigned idx = IDX (lit); + LOG ("marking internal %s as fixed", LOGVAR (idx)); + flags *f = FLAGS (idx); + assert (f->active); + assert (!f->eliminated); + assert (!f->fixed); + f->fixed = true; + deactivate_variable (solver, f, idx); + INC (units); + int elit = kissat_export_literal (solver, lit); + assert (elit); + PUSH_STACK (solver->units, elit); + LOG ("pushed external unit literal %d (internal %u)", elit, lit); +} + +void kissat_mark_eliminated_variable (kissat *solver, unsigned idx) { + const unsigned lit = LIT (idx); + assert (!VALUE (lit)); + LOG ("marking internal %s as eliminated", LOGVAR (idx)); + flags *f = FLAGS (idx); + assert (f->active); + assert (!f->eliminated); + assert (!f->fixed); + f->eliminated = true; + deactivate_variable (solver, f, idx); + int elit = kissat_export_literal (solver, lit); + assert (elit); + assert (elit != INT_MIN); + unsigned eidx = ABS (elit); + import *import = &PEEK_STACK (solver->import, eidx); + assert (!import->eliminated); + assert (import->imported); + assert (STRIP (import->lit) == STRIP (lit)); + size_t pos = SIZE_STACK (solver->eliminated); + assert (pos < (1u << 30)); + import->lit = pos; + import->eliminated = true; + PUSH_STACK (solver->eliminated, (value) 0); + LOG ("marked external variable %u as eliminated", eidx); + assert (solver->unassigned > 0); + solver->unassigned--; +} + +void kissat_mark_removed_literals (kissat *solver, unsigned size, + unsigned *lits) { + for (unsigned i = 0; i < size; i++) + kissat_mark_removed_literal (solver, lits[i]); +} + +void kissat_mark_added_literals (kissat *solver, unsigned size, + unsigned *lits) { + for (unsigned i = 0; i < size; i++) + kissat_mark_added_literal (solver, lits[i]); +} diff --git a/src/sat/kissat/flags.h b/src/sat/kissat/flags.h new file mode 100644 index 000000000..fd73b2f5b --- /dev/null +++ b/src/sat/kissat/flags.h @@ -0,0 +1,37 @@ +#ifndef _flags_h_INCLUDED +#define _flags_h_INCLUDED + +#include + +typedef struct flags flags; + +struct flags { + bool active : 1; + bool backbone0 : 1; + bool backbone1 : 1; + bool eliminate : 1; + bool eliminated : 1; + unsigned factor : 2; + bool fixed : 1; + bool subsume : 1; + bool sweep : 1; + bool transitive : 1; +}; + +#define FLAGS(IDX) (assert ((IDX) < VARS), (solver->flags + (IDX))) + +#define ACTIVE(IDX) (FLAGS (IDX)->active) +#define ELIMINATED(IDX) (FLAGS (IDX)->eliminated) + +struct kissat; + +void kissat_activate_literal (struct kissat *, unsigned); +void kissat_activate_literals (struct kissat *, unsigned, unsigned *); + +void kissat_mark_eliminated_variable (struct kissat *, unsigned idx); +void kissat_mark_fixed_literal (struct kissat *, unsigned lit); + +void kissat_mark_added_literals (struct kissat *, unsigned, unsigned *); +void kissat_mark_removed_literals (struct kissat *, unsigned, unsigned *); + +#endif diff --git a/src/sat/kissat/format.c b/src/sat/kissat/format.c new file mode 100644 index 000000000..d8e247d1a --- /dev/null +++ b/src/sat/kissat/format.c @@ -0,0 +1,145 @@ +#include "format.h" + +#include +#include +#include +#include +#include +#include + +char *kissat_next_format_string (format *format) { + assert (format->pos < NUM_FORMAT_STRINGS); + char *res = format->str[format->pos++]; + if (format->pos == NUM_FORMAT_STRINGS) + format->pos = 0; + return res; +} + +static void format_count (char *res, uint64_t w) { + if (w >= 128 && kissat_is_power_of_two (w)) { + unsigned l; + for (l = 0; ((uint64_t) 1 << l) != w; l++) + assert (l + 1 < 8 * sizeof (word)); + sprintf (res, "2^%u", l); + } else if (w >= 1000 && !(w % 1000)) { + unsigned l; + for (l = 0; !(w % 10); l++) + w /= 10; + sprintf (res, "%" PRIu64 "e%u", w, l); + } else + sprintf (res, "%" PRIu64, w); +} + +const char *kissat_format_count (format *format, uint64_t w) { + char *res = kissat_next_format_string (format); + format_count (res, w); + return res; +} + +const char *kissat_format_value (format *format, bool boolean, int value) { + if (boolean && value) + return "true"; + if (boolean && !value) + return "false"; + if (value == INT_MAX) + return "INT_MAX"; + if (value == INT_MIN) + return "INT_MIN"; + char *res = kissat_next_format_string (format); + if (value < 0) { + *res = '-'; + format_count (res + 1, ABS (value)); + } else + format_count (res, value); + return res; +} + +const char *kissat_format_bytes (format *format, uint64_t bytes) { + char *res = kissat_next_format_string (format); + if (bytes < (1u << 10)) + sprintf (res, "%" PRIu64 " bytes", bytes); + else if (bytes < (1u << 20)) + sprintf (res, "%" PRIu64 " bytes (%" PRIu64 " KB)", bytes, + (bytes + (1 << 9)) >> 10); + else if (bytes < (1u << 30)) + sprintf (res, "%" PRIu64 " bytes (%" PRIu64 " MB)", bytes, + (bytes + (1u << 19)) >> 20); + else + sprintf (res, "%" PRIu64 " bytes (%" PRIu64 " GB)", bytes, + (bytes + (1u << 29)) >> 30); + return res; +} + +const char *kissat_format_time (format *format, double seconds) { + if (!seconds) + return "0s"; + char *res = kissat_next_format_string (format); + uint64_t rounded = round (seconds); + uint64_t minutes = rounded / 60; + rounded %= 60; + uint64_t hours = minutes / 60; + minutes %= 60; + uint64_t days = hours / 24; + hours %= 24; + char *tmp = res; + if (days) { + sprintf (res, "%" PRIu64 "d", days); + tmp += strlen (res); + } + if (hours) { + if (tmp != res) + *tmp++ = ' '; + sprintf (tmp, "%" PRIu64 "h", hours); + tmp += strlen (tmp); + } + if (minutes) { + if (tmp != res) + *tmp++ = ' '; + sprintf (tmp, "%" PRIu64 "m", minutes); + tmp += strlen (tmp); + } + if (rounded) { + if (tmp != res) + *tmp++ = ' '; + sprintf (tmp, "%" PRIu64 "s", rounded); + } + return res; +} + +const char *kissat_format_signs (format *format, unsigned size, + word signs) { + char *res = kissat_next_format_string (format); + assert (size + 1 < FORMAT_STRING_SIZE); + char *p = res; + word bit = 1; + for (unsigned i = 0; i < size; i++, bit <<= 1) + *p++ = (bit & signs) ? '1' : '0'; + *p = 0; + return res; +} + +const char *kissat_format_ordinal (format *format, uint64_t ordinal) { + char const *suffix; + unsigned mod100 = ordinal % 100; + if (10 <= mod100 && mod100 <= 19) + suffix = "th"; + else { + switch (mod100 % 10) { + case 1: + suffix = "st"; + break; + case 2: + suffix = "nd"; + break; + case 3: + suffix = "rd"; + break; + default: + suffix = "th"; + break; + } + } + char *res = kissat_next_format_string (format); + sprintf (res, "%" PRIu64 "%s", ordinal, suffix); + return res; +} diff --git a/src/sat/kissat/format.h b/src/sat/kissat/format.h new file mode 100644 index 000000000..d52e93d71 --- /dev/null +++ b/src/sat/kissat/format.h @@ -0,0 +1,42 @@ +#ifndef _format_h_INCLUDED +#define _format_h_INCLUDED + +#include "utilities.h" + +#include +#include + +#define NUM_FORMAT_STRINGS 16 +#define FORMAT_STRING_SIZE 128 + +typedef struct format format; + +struct format { + unsigned pos; + char str[NUM_FORMAT_STRINGS][FORMAT_STRING_SIZE]; +}; + +char *kissat_next_format_string (format *); + +char const *kissat_format_bytes (format *, uint64_t bytes); +char const *kissat_format_count (format *, uint64_t); +char const *kissat_format_ordinal (format *, uint64_t); +char const *kissat_format_signs (format *, unsigned size, word); +char const *kissat_format_time (format *, double seconds); +char const *kissat_format_value (format *, bool boolean, int value); + +#define FORMAT_BYTES(BYTES) kissat_format_bytes (&solver->format, BYTES) + +#define FORMAT_COUNT(WORD) kissat_format_count (&solver->format, WORD) + +#define FORMAT_ORDINAL(WORD) kissat_format_ordinal (&solver->format, WORD) + +#define FORMAT_SIGNS(SIZE, SIGNS) \ + kissat_format_signs (&solver->format, SIZE, SIGNS) + +#define FORMAT_TIME(SECONDS) kissat_format_time (&solver->format, SECONDS) + +#define FORMAT_VALUE(BOOLEAN, VALUE) \ + kissat_format_value (&solver->format, BOOLEAN, VALUE) + +#endif diff --git a/src/sat/kissat/forward.c b/src/sat/kissat/forward.c new file mode 100644 index 000000000..d2bbbab47 --- /dev/null +++ b/src/sat/kissat/forward.c @@ -0,0 +1,691 @@ +#include "forward.h" +#include "allocate.h" +#include "eliminate.h" +#include "inline.h" +#include "print.h" +#include "rank.h" +#include "report.h" +#include "sort.h" +#include "terminate.h" + +#include + +static size_t remove_duplicated_binaries_with_literal (kissat *solver, + unsigned lit) { + watches *watches = &WATCHES (lit); + value *marks = solver->marks; + flags *flags = solver->flags; + + watch *begin = BEGIN_WATCHES (*watches), *q = begin; + const watch *const end = END_WATCHES (*watches), *p = q; + + while (p != end) { + const watch watch = *q++ = *p++; + assert (watch.type.binary); + const unsigned other = watch.binary.lit; + struct flags *f = flags + IDX (other); + if (!f->active) + continue; + if (!f->subsume) + continue; + const value marked = marks[other]; + if (marked) { + q--; + if (lit < other) { + kissat_delete_binary (solver, lit, other); + INC (duplicated); + } + } else { + const unsigned not_other = NOT (other); + if (marks[not_other]) { + LOGBINARY (lit, other, + "duplicate hyper unary resolution on %s " + "first antecedent", + LOGLIT (other)); + LOGBINARY (lit, not_other, + "duplicate hyper unary resolution on %s " + "second antecedent", + LOGLIT (not_other)); + PUSH_STACK (solver->delayed, lit); + } + marks[other] = 1; + } + } + + for (const watch *r = begin; r != q; r++) + marks[r->binary.lit] = 0; + + if (q == end) + return 0; + + size_t removed = end - q; + SET_END_OF_WATCHES (*watches, q); + LOG ("removed %zu watches with literal %s", removed, LOGLIT (lit)); + + return removed; +} + +static void remove_all_duplicated_binary_clauses (kissat *solver) { + LOG ("removing all duplicated irredundant binary clauses"); +#if !defined(QUIET) || !defined(NDEBUG) + size_t removed = 0; +#endif + assert (EMPTY_STACK (solver->delayed)); + + const flags *const all_flags = solver->flags; + + for (all_variables (idx)) { + const flags *const flags = all_flags + idx; + if (!flags->active) + continue; + if (!flags->subsume) + continue; + const unsigned int lit = LIT (idx); + const unsigned int not_lit = NOT (lit); +#if !defined(QUIET) || !defined(NDEBUG) + removed += +#endif + remove_duplicated_binaries_with_literal (solver, lit); +#if !defined(QUIET) || !defined(NDEBUG) + removed += +#endif + remove_duplicated_binaries_with_literal (solver, not_lit); + } + assert (!(removed & 1)); + + size_t units = SIZE_STACK (solver->delayed); + if (units) { + LOG ("found %zu hyper unary resolved units", units); + const value *const values = solver->values; + for (all_stack (unsigned, unit, solver->delayed)) { + + const value value = values[unit]; + if (value > 0) { + LOG ("skipping satisfied resolved unit %s", LOGLIT (unit)); + continue; + } + if (value < 0) { + LOG ("found falsified resolved unit %s", LOGLIT (unit)); + CHECK_AND_ADD_EMPTY (); + ADD_EMPTY_TO_PROOF (); + solver->inconsistent = true; + break; + } + LOG ("new resolved unit clause %s", LOGLIT (unit)); + kissat_learned_unit (solver, unit); + } + CLEAR_STACK (solver->delayed); + if (!solver->inconsistent) + kissat_flush_units_while_connected (solver); + } + + REPORT (!removed && !units, '2'); +} + +static void find_forward_subsumption_candidates (kissat *solver, + references *candidates) { + const unsigned clslim = GET_OPTION (subsumeclslim); + + const value *const values = solver->values; + const flags *const flags = solver->flags; + + clause *last_irredundant = kissat_last_irredundant_clause (solver); + + for (all_clauses (c)) { + if (last_irredundant && c > last_irredundant) + break; + if (c->garbage) + continue; + c->subsume = false; + if (c->redundant) + continue; + if (c->size > clslim) + continue; + assert (c->size > 2); + unsigned subsume = 0; + for (all_literals_in_clause (lit, c)) { + const unsigned idx = IDX (lit); + const struct flags *f = flags + idx; + if (f->subsume) + subsume++; + if (values[lit] > 0) { + LOGCLS (c, "satisfied by %s", LOGLIT (lit)); + kissat_mark_clause_as_garbage (solver, c); + assert (c->garbage); + break; + } + } + if (c->garbage) + continue; + if (subsume < 2) + continue; + const unsigned ref = kissat_reference_clause (solver, c); + PUSH_STACK (*candidates, ref); + } +} + +static inline unsigned +get_size_of_reference (kissat *solver, ward *const arena, reference ref) { + assert (ref < SIZE_STACK (solver->arena)); + const clause *const c = (clause *) (arena + ref); + (void) solver; + return c->size; +} + +#define GET_SIZE_OF_REFERENCE(REF) \ + get_size_of_reference (solver, arena, (REF)) + +static void sort_forward_subsumption_candidates (kissat *solver, + references *candidates) { + reference *references = BEGIN_STACK (*candidates); + size_t size = SIZE_STACK (*candidates); + ward *const arena = BEGIN_STACK (solver->arena); + RADIX_SORT (reference, unsigned, size, references, GET_SIZE_OF_REFERENCE); +} + +static inline bool forward_literal (kissat *solver, unsigned lit, + bool binaries, unsigned *remove, + unsigned limit) { + watches *watches = &WATCHES (lit); + const size_t size_watches = SIZE_WATCHES (*watches); + + if (!size_watches) + return false; + + if (size_watches > limit) + return false; + + watch *begin = BEGIN_WATCHES (*watches), *q = begin; + const watch *const end = END_WATCHES (*watches), *p = q; + + uint64_t steps = 1 + kissat_cache_lines (size_watches, sizeof (watch)); + uint64_t checks = 0; + + const value *const values = solver->values; + const value *const marks = solver->marks; + ward *const arena = BEGIN_STACK (solver->arena); + + bool subsume = false; + + while (p != end) { + const watch watch = *q++ = *p++; + + if (watch.type.binary) { + if (!binaries) + continue; + + const unsigned other = watch.binary.lit; + if (marks[other]) { + LOGBINARY (lit, other, "forward subsuming"); + subsume = true; + break; + } else { + const unsigned not_other = NOT (other); + if (marks[not_other]) { + LOGBINARY (lit, other, "forward %s strengthener", LOGLIT (other)); + assert (!subsume); + *remove = not_other; + break; + } + } + } else { + const reference ref = watch.large.ref; + assert (ref < SIZE_STACK (solver->arena)); + clause *d = (clause *) (arena + ref); + steps++; + + if (d->garbage) { + q--; + continue; + } + + checks++; + subsume = true; + + unsigned candidate = INVALID_LIT; + + for (all_literals_in_clause (other, d)) { + if (marks[other]) + continue; + const value value = values[other]; + if (value < 0) + continue; + if (value > 0) { + LOGCLS (d, "satisfied by %s", LOGLIT (other)); + kissat_mark_clause_as_garbage (solver, d); + assert (d->garbage); + candidate = INVALID_LIT; + subsume = false; + break; + } + if (!subsume) { + assert (candidate != INVALID_LIT); + candidate = INVALID_LIT; + break; + } + subsume = false; + const unsigned not_other = NOT (other); + if (!marks[not_other]) { + assert (candidate == INVALID_LIT); + break; + } + candidate = not_other; + } + + if (d->garbage) { + assert (!subsume); + q--; + break; + } + + if (subsume) { + LOGCLS (d, "forward subsuming"); + assert (subsume); + break; + } + + if (candidate != INVALID_LIT) { + LOGCLS (d, "forward %s strengthener", LOGLIT (candidate)); + *remove = candidate; + } + } + } + + if (p != q) { + while (p != end) + *q++ = *p++; + + SET_END_OF_WATCHES (*watches, q); + } + + ADD (subsumption_checks, checks); + ADD (forward_checks, checks); + ADD (forward_steps, steps); + + return subsume; +} + +static inline bool forward_marked_clause (kissat *solver, clause *c, + unsigned *remove) { + const unsigned limit = GET_OPTION (subsumeocclim); + const flags *const flags = solver->flags; + INC (forward_steps); + + for (all_literals_in_clause (lit, c)) { + const unsigned idx = IDX (lit); + if (!flags[idx].active) + continue; + + assert (!VALUE (lit)); + + if (forward_literal (solver, lit, true, remove, limit)) + return true; + + if (forward_literal (solver, NOT (lit), false, remove, limit)) + return true; + } + return false; +} + +static bool forward_subsumed_clause (kissat *solver, clause *c, + bool *strengthened, + unsigneds *new_binaries) { + assert (!c->garbage); + LOGCLS2 (c, "trying to forward subsume"); + + value *marks = solver->marks; + const value *const values = solver->values; + unsigned non_false = 0, unit = INVALID_LIT; + + for (all_literals_in_clause (lit, c)) { + const value value = values[lit]; + if (value < 0) + continue; + if (value > 0) { + LOGCLS (c, "satisfied by %s", LOGLIT (lit)); + kissat_mark_clause_as_garbage (solver, c); + assert (c->garbage); + break; + } + marks[lit] = 1; + if (non_false++) + unit ^= lit; + else + unit = lit; + } + + if (c->garbage || non_false <= 1) + for (all_literals_in_clause (lit, c)) + marks[lit] = 0; + + if (c->garbage) + return false; + + if (!non_false) { + LOGCLS (c, "found falsified clause"); + CHECK_AND_ADD_EMPTY (); + ADD_EMPTY_TO_PROOF (); + solver->inconsistent = true; + return false; + } + + if (non_false == 1) { + assert (VALID_INTERNAL_LITERAL (unit)); + LOG ("new remaining non-false literal unit clause %s", LOGLIT (unit)); + kissat_learned_unit (solver, unit); + kissat_mark_clause_as_garbage (solver, c); + kissat_flush_units_while_connected (solver); + return false; + } + + unsigned remove = INVALID_LIT; + const bool subsume = forward_marked_clause (solver, c, &remove); + + for (all_literals_in_clause (lit, c)) + marks[lit] = 0; + + if (subsume) { + LOGCLS (c, "forward subsumed"); + kissat_mark_clause_as_garbage (solver, c); + INC (subsumed); + INC (forward_subsumed); + } else if (remove != INVALID_LIT) { + *strengthened = true; + INC (strengthened); + INC (forward_strengthened); + LOGCLS (c, "forward strengthening by removing %s in", LOGLIT (remove)); + if (non_false == 2) { + unit ^= remove; + assert (VALID_INTERNAL_LITERAL (unit)); + LOG ("forward strengthened unit clause %s", LOGLIT (unit)); + kissat_learned_unit (solver, unit); + kissat_mark_clause_as_garbage (solver, c); + kissat_flush_units_while_connected (solver); + LOGCLS (c, "%s satisfied", LOGLIT (unit)); + } else { + SHRINK_CLAUSE_IN_PROOF (c, remove, INVALID_LIT); + CHECK_SHRINK_CLAUSE (c, remove, INVALID_LIT); + kissat_mark_removed_literal (solver, remove); + if (non_false > 3) { + unsigned *lits = c->lits; + unsigned new_size = 0; + for (unsigned i = 0; i < c->size; i++) { + const unsigned lit = lits[i]; + if (remove == lit) + continue; + const value value = values[lit]; + if (value < 0) + continue; + assert (!value); + lits[new_size++] = lit; + kissat_mark_added_literal (solver, lit); + } + assert (new_size == non_false - 1); + assert (new_size > 2); + if (!c->shrunken) { + c->shrunken = true; + lits[c->size - 1] = INVALID_LIT; + } + c->size = new_size; + c->searched = 2; + c->subsume = true; + LOGCLS (c, "forward strengthened"); + } else { + assert (non_false == 3); + LOGCLS (c, "garbage"); + assert (!c->garbage); + const size_t bytes = kissat_actual_bytes_of_clause (c); + ADD (arena_garbage, bytes); + c->garbage = true; + unsigned first = INVALID_LIT, second = INVALID_LIT; + for (all_literals_in_clause (lit, c)) { + if (lit == remove) + continue; + const value value = values[lit]; + if (value < 0) + continue; + assert (!value); + if (first == INVALID_LIT) + first = lit; + else { + assert (second == INVALID_LIT); + second = lit; + } + kissat_mark_added_literal (solver, lit); + } + assert (first != INVALID_LIT); + assert (second != INVALID_LIT); + LOGBINARY (first, second, "forward strengthened"); + kissat_watch_other (solver, first, second); + kissat_watch_other (solver, second, first); + assert (new_binaries); + assert (solver->statistics.clauses_irredundant); + solver->statistics.clauses_irredundant--; + assert (solver->statistics.clauses_binary < UINT64_MAX); + solver->statistics.clauses_binary++; + PUSH_STACK (*new_binaries, first); + PUSH_STACK (*new_binaries, second); + } + } + } + + return subsume; +} + +static void connect_subsuming (kissat *solver, unsigned occlim, clause *c) { + assert (!c->garbage); + + unsigned min_lit = INVALID_LIT; + size_t min_occs = MAX_SIZE_T; + + const flags *const all_flags = solver->flags; + + bool subsume = true; + + for (all_literals_in_clause (lit, c)) { + const unsigned idx = IDX (lit); + const flags *const flags = all_flags + idx; + if (!flags->active) + continue; + if (!flags->subsume) { + subsume = false; + break; + } + watches *watches = &WATCHES (lit); + const size_t occs = SIZE_WATCHES (*watches); + if (min_lit != INVALID_LIT && occs > min_occs) + continue; + min_lit = lit; + min_occs = occs; + } + if (!subsume) + return; + + if (min_occs > occlim) + return; + LOG ("connecting %s with %zu occurrences", LOGLIT (min_lit), min_occs); + const reference ref = kissat_reference_clause (solver, c); + kissat_connect_literal (solver, min_lit, ref); +} + +static bool forward_subsume_all_clauses (kissat *solver) { + references candidates; + INIT_STACK (candidates); + + find_forward_subsumption_candidates (solver, &candidates); +#ifndef QUIET + size_t scheduled = SIZE_STACK (candidates); + kissat_phase ( + solver, "forward", GET (forward_subsumptions), + "scheduled %zu irredundant clauses %.0f%%", scheduled, + kissat_percent (scheduled, solver->statistics.clauses_irredundant)); +#endif + sort_forward_subsumption_candidates (solver, &candidates); + + const reference *const end_of_candidates = END_STACK (candidates); + reference *p = BEGIN_STACK (candidates); + +#ifndef QUIET + size_t subsumed = 0; + size_t strengthened = 0; + size_t checked = 0; +#endif + const unsigned occlim = GET_OPTION (subsumeocclim); + + unsigneds new_binaries; + INIT_STACK (new_binaries); + + { + SET_EFFORT_LIMIT (steps_limit, forward, forward_steps); + + ward *arena = BEGIN_STACK (solver->arena); + + while (p != end_of_candidates) { + if (solver->statistics.forward_steps > steps_limit) + break; + if (TERMINATED (forward_terminated_1)) + break; + reference ref = *p++; + clause *c = (clause *) (arena + ref); + assert (kissat_clause_in_arena (solver, c)); + assert (!c->garbage); +#ifndef QUIET + checked++; +#endif + bool not_subsumed_but_strengthened = false; + if (forward_subsumed_clause ( + solver, c, ¬_subsumed_but_strengthened, &new_binaries)) { +#ifndef QUIET + subsumed++; +#endif + } else if (not_subsumed_but_strengthened) { +#ifndef QUIET + strengthened++; +#endif + } + if (solver->inconsistent) + break; + if (!c->garbage) + connect_subsuming (solver, occlim, c); + } + } +#ifndef QUIET + if (subsumed) + kissat_phase (solver, "forward", GET (forward_subsumptions), + "subsumed %zu clauses %.2f%% of %zu checked %.0f%%", + subsumed, kissat_percent (subsumed, checked), checked, + kissat_percent (checked, scheduled)); + if (strengthened) + kissat_phase (solver, "forward", GET (forward_subsumptions), + "strengthened %zu clauses %.2f%% of %zu checked %.0f%%", + strengthened, kissat_percent (strengthened, checked), + checked, kissat_percent (checked, scheduled)); + if (!subsumed && !strengthened) + kissat_phase (solver, "forward", GET (forward_subsumptions), + "no clause subsumed nor strengthened " + "out of %zu checked %.0f%%", + checked, kissat_percent (checked, scheduled)); +#endif + struct flags *flags = solver->flags; + + for (all_variables (idx)) + flags[idx].subsume = false; + + ward *arena = BEGIN_STACK (solver->arena); + unsigned reactivated = 0; +#ifndef QUIET + size_t remain = 0; +#endif + for (reference *q = BEGIN_STACK (candidates); q != end_of_candidates; + q++) { + const reference ref = *q; + clause *c = (clause *) (arena + ref); + assert (kissat_clause_in_arena (solver, c)); + if (c->garbage) + continue; + if (q < p && !c->subsume) + continue; +#ifndef QUIET + remain++; +#endif + for (all_literals_in_clause (lit, c)) { + const unsigned idx = IDX (lit); + struct flags *f = flags + idx; + if (f->subsume) + continue; + LOGCLS (c, + "reactivating subsume flag of %s " + "in remaining or strengthened", + LOGVAR (idx)); + f->subsume = true; + assert (reactivated < UINT_MAX); + reactivated++; + } + } + + while (!EMPTY_STACK (new_binaries)) { + unsigned lits[2]; + lits[1] = POP_STACK (new_binaries); + lits[0] = POP_STACK (new_binaries); + for (unsigned i = 0; i < 2; i++) { + const unsigned lit = lits[i]; + const unsigned idx = IDX (lit); + struct flags *f = flags + idx; + if (f->subsume) + continue; + LOGBINARY (lits[0], lits[1], + "reactivating subsume flag of %s " + "in strengthened binary clause", + LOGVAR (idx)); + f->subsume = true; + assert (reactivated < UINT_MAX); + reactivated++; + } + } + RELEASE_STACK (new_binaries); + + kissat_very_verbose (solver, + "marked %u variables %.0f%% to be reconsidered " + "in next forward subsumption", + reactivated, + kissat_percent (reactivated, solver->active)); +#ifndef QUIET + if (remain) + kissat_phase (solver, "forward", GET (forward_subsumptions), + "%zu unchecked clauses remain %.0f%%", remain, + kissat_percent (remain, scheduled)); + else + kissat_phase (solver, "forward", GET (forward_subsumptions), + "all %zu scheduled clauses checked", scheduled); +#endif + RELEASE_STACK (candidates); + REPORT (!subsumed, 's'); + + bool completed; + if (solver->inconsistent) + completed = true; + else if (reactivated) + completed = false; + else + completed = true; +#ifndef QUIET + kissat_very_verbose (solver, "forward subsumption considered %scomplete", + completed ? "" : "in"); +#endif + return completed; +} + +bool kissat_forward_subsume_during_elimination (kissat *solver) { + START (subsume); + START (forward); + assert (GET_OPTION (forward)); + INC (forward_subsumptions); + assert (!solver->watching); + remove_all_duplicated_binary_clauses (solver); + bool complete = true; + if (!solver->inconsistent) + complete = forward_subsume_all_clauses (solver); + STOP (forward); + STOP (subsume); + return complete; +} diff --git a/src/sat/kissat/forward.h b/src/sat/kissat/forward.h new file mode 100644 index 000000000..95a8dc5d3 --- /dev/null +++ b/src/sat/kissat/forward.h @@ -0,0 +1,10 @@ +#ifndef _forward_h_INCLUDED +#define _forward_h_INCLUDED + +#include + +struct kissat; + +bool kissat_forward_subsume_during_elimination (struct kissat *); + +#endif diff --git a/src/sat/kissat/frames.h b/src/sat/kissat/frames.h new file mode 100644 index 000000000..088877b2a --- /dev/null +++ b/src/sat/kissat/frames.h @@ -0,0 +1,32 @@ +#ifndef _frames_h_INCLUDED +#define _frames_h_INCLUDED + +#include "literal.h" +#include "stack.h" + +#include + +typedef struct frame frame; +typedef struct slice slice; + +struct frame { + bool promote; + unsigned decision; + unsigned trail; + unsigned used; +#ifndef NDEBUG + unsigned saved; +#endif +}; + +// clang-format off + +typedef STACK (frame) frames; + +// clang-format on + +struct kissat; + +#define FRAME(LEVEL) (PEEK_STACK (solver->frames, (LEVEL))) + +#endif diff --git a/src/sat/kissat/gates.c b/src/sat/kissat/gates.c new file mode 100644 index 000000000..7da560181 --- /dev/null +++ b/src/sat/kissat/gates.c @@ -0,0 +1,104 @@ +#include "gates.h" +#include "ands.h" +#include "definition.h" +#include "eliminate.h" +#include "equivalences.h" +#include "ifthenelse.h" +#include "inline.h" + +size_t kissat_mark_binaries (kissat *solver, unsigned lit) { + value *marks = solver->marks; + size_t res = 0; + watches *watches = &WATCHES (lit); + for (all_binary_large_watches (watch, *watches)) { + if (!watch.type.binary) + continue; + const unsigned other = watch.binary.lit; + assert (!solver->values[other]); + if (marks[other]) + continue; + marks[other] = 1; + res++; + } + return res; +} + +void kissat_unmark_binaries (kissat *solver, unsigned lit) { + value *marks = solver->marks; + watches *watches = &WATCHES (lit); + for (all_binary_large_watches (watch, *watches)) + if (watch.type.binary) + marks[watch.binary.lit] = 0; +} + +bool kissat_find_gates (kissat *solver, unsigned lit) { + solver->gate_eliminated = 0; + solver->resolve_gate = false; + if (!GET_OPTION (extract)) + return false; + INC (gates_checked); + const unsigned not_lit = NOT (lit); + if (EMPTY_WATCHES (WATCHES (not_lit))) + return false; + bool res = false; + if (kissat_find_equivalence_gate (solver, lit)) + res = true; + else if (kissat_find_and_gate (solver, lit, 0)) + res = true; + else if (kissat_find_and_gate (solver, not_lit, 1)) + res = true; + else if (kissat_find_if_then_else_gate (solver, lit, 0)) + res = true; + else if (kissat_find_if_then_else_gate (solver, not_lit, 1)) + res = true; + else if (kissat_find_definition (solver, lit)) + res = true; + if (res) + INC (gates_extracted); + return res; +} + +static void get_antecedents (kissat *solver, unsigned lit, + unsigned negative) { + assert (!solver->watching); + assert (!negative || negative == 1); + + statches *gates = solver->gates + negative; + watches *watches = &WATCHES (lit); + + statches *antecedents = solver->antecedents + negative; + assert (EMPTY_STACK (*antecedents)); + + const watch *const begin_gates = BEGIN_STACK (*gates); + const watch *const end_gates = END_STACK (*gates); + watch const *g = begin_gates; + + const watch *const begin_watches = BEGIN_WATCHES (*watches); + const watch *const end_watches = END_WATCHES (*watches); + watch const *w = begin_watches; + + while (w != end_watches) { + const watch watch = *w++; + if (g != end_gates && g->raw == watch.raw) + g++; + else + PUSH_STACK (*antecedents, watch); + } + + assert (g == end_gates); +#ifdef LOGGING + size_t size_gates = SIZE_STACK (*gates); + size_t size_antecedents = SIZE_STACK (*antecedents); + size_t size_watches = SIZE_WATCHES (*watches); + LOG ("got %zu antecedent %.0f%% and %zu gate clauses %.0f%% " + "out of %zu watches of literal %s", + size_antecedents, kissat_percent (size_antecedents, size_watches), + size_gates, kissat_percent (size_gates, size_watches), size_watches, + LOGLIT (lit)); +#endif +} + +void kissat_get_antecedents (kissat *solver, unsigned lit) { + get_antecedents (solver, lit, 0); + get_antecedents (solver, NOT (lit), 1); +} diff --git a/src/sat/kissat/gates.h b/src/sat/kissat/gates.h new file mode 100644 index 000000000..f5ce18a90 --- /dev/null +++ b/src/sat/kissat/gates.h @@ -0,0 +1,22 @@ +#ifndef _gates_h_INCLUDED +#define _gates_h_INCLUDED + +#include +#include + +struct kissat; +struct clause; + +bool kissat_find_gates (struct kissat *, unsigned lit); +void kissat_get_antecedents (struct kissat *, unsigned lit); + +size_t kissat_mark_binaries (struct kissat *, unsigned lit); +void kissat_unmark_binaries (struct kissat *, unsigned lit); + +#ifndef METRICS +#define GATE_ELIMINATED(...) true +#else +#define GATE_ELIMINATED(NAME) (&solver->statistics.NAME##_eliminated) +#endif + +#endif diff --git a/src/sat/kissat/handle.h b/src/sat/kissat/handle.h new file mode 100644 index 000000000..132fc3b68 --- /dev/null +++ b/src/sat/kissat/handle.h @@ -0,0 +1,43 @@ +#ifndef _handle_h_INCLUDED +#define _handle_h_INCLUDED + +#include + +void kissat_init_signal_handler (void (*handler) (int)); +void kissat_reset_signal_handler (void); + +void kissat_init_alarm (void (*handler) (void)); +void kissat_reset_alarm (void); + +#ifdef __MINGW32__ +#define SIGNAL_SIGBUS +#else +#define SIGNAL_SIGBUS SIGNAL (SIGBUS) +#endif + +#define SIGNALS \ + SIGNAL (SIGABRT) \ + SIGNAL_SIGBUS \ + SIGNAL (SIGINT) \ + SIGNAL (SIGSEGV) \ + SIGNAL (SIGTERM) + +// clang-format off + +static inline const char * +kissat_signal_name (int sig) +{ +#define SIGNAL(SIG) \ + if (sig == SIG) return #SIG; + SIGNALS +#undef SIGNAL +#ifndef __MINGW32__ + if (sig == SIGALRM) + return "SIGALRM"; +#endif + return "SIGUNKNOWN"; +} + +// clang-format on + +#endif diff --git a/src/sat/kissat/heap.c b/src/sat/kissat/heap.c new file mode 100644 index 000000000..12deaad75 --- /dev/null +++ b/src/sat/kissat/heap.c @@ -0,0 +1,108 @@ +#include "allocate.h" +#include "inlineheap.h" +#include "internal.h" +#include "logging.h" + +#include + +void kissat_release_heap (kissat *solver, heap *heap) { + RELEASE_STACK (heap->stack); + DEALLOC (heap->pos, heap->size); + DEALLOC (heap->score, heap->size); + memset (heap, 0, sizeof *heap); +} + +#ifndef NDEBUG + +void kissat_check_heap (heap *heap) { + const unsigned *const stack = BEGIN_STACK (heap->stack); + const unsigned end = SIZE_STACK (heap->stack); + const unsigned *const pos = heap->pos; + const double *const score = heap->score; + for (unsigned i = 0; i < end; i++) { + const unsigned idx = stack[i]; + const unsigned idx_pos = pos[idx]; + assert (idx_pos == i); + unsigned child_pos = HEAP_CHILD (idx_pos); + unsigned parent_pos = HEAP_PARENT (child_pos); + assert (parent_pos == idx_pos); + if (child_pos < end) { + unsigned child = stack[child_pos]; + assert (score[idx] >= score[child]); + if (++child_pos < end) { + parent_pos = HEAP_PARENT (child_pos); + assert (parent_pos == idx_pos); + child = stack[child_pos]; + assert (score[idx] >= score[child]); + } + } + } +} + +#endif + +void kissat_resize_heap (kissat *solver, heap *heap, unsigned new_size) { + const unsigned old_size = heap->size; + if (old_size >= new_size) + return; + LOG ("resizing %s heap from %u to %u", + (heap->tainted ? "tainted" : "untainted"), old_size, new_size); + + heap->pos = kissat_nrealloc (solver, heap->pos, old_size, new_size, + sizeof (unsigned)); + if (heap->tainted) { + heap->score = kissat_nrealloc (solver, heap->score, old_size, new_size, + sizeof (double)); + } else { + if (old_size) + DEALLOC (heap->score, old_size); + heap->score = kissat_calloc (solver, new_size, sizeof (double)); + } + heap->size = new_size; +#ifdef CHECK_HEAP + kissat_check_heap (heap); +#endif +} + +void kissat_rescale_heap (kissat *solver, heap *heap, double factor) { + LOG ("rescaling scores on heap with factor %g", factor); + double *score = heap->score; + for (unsigned i = 0; i < heap->vars; i++) + score[i] *= factor; +#ifndef NDEBUG + kissat_check_heap (heap); +#endif +#ifndef LOGGING + (void) solver; +#endif +} + +void kissat_enlarge_heap (kissat *solver, heap *heap, unsigned new_vars) { + const unsigned old_vars = heap->vars; + assert (old_vars < new_vars); + assert (new_vars <= heap->size); + const size_t delta = new_vars - heap->vars; + memset (heap->pos + old_vars, 0xff, delta * sizeof (unsigned)); + heap->vars = new_vars; + if (heap->tainted) + memset (heap->score + old_vars, 0, delta * sizeof (double)); + LOG ("enlarged heap from %u to %u", old_vars, new_vars); +#ifndef LOGGING + (void) solver; +#endif +} + +#ifndef NDEBUG + +static void dump_heap (heap *heap) { + for (unsigned i = 0; i < SIZE_STACK (heap->stack); i++) + printf ("heap.stack[%u] = %u\n", i, PEEK_STACK (heap->stack, i)); + for (unsigned i = 0; i < heap->vars; i++) + printf ("heap.pos[%u] = %u\n", i, heap->pos[i]); + for (unsigned i = 0; i < heap->vars; i++) + printf ("heap.score[%u] = %g\n", i, heap->score[i]); +} + +void kissat_dump_heap (heap *heap) { dump_heap (heap); } + +#endif diff --git a/src/sat/kissat/heap.h b/src/sat/kissat/heap.h new file mode 100644 index 000000000..8a9736ee2 --- /dev/null +++ b/src/sat/kissat/heap.h @@ -0,0 +1,85 @@ +#ifndef _heap_h_INCLUDED +#define _heap_h_INCLUDED + +#include "stack.h" +#include "utilities.h" + +#include +#include +#include + +#define DISCONTAIN UINT_MAX +#define DISCONTAINED(IDX) ((int) (IDX) < 0) + +typedef struct heap heap; + +struct heap { + bool tainted; + unsigned vars; + unsigned size; + unsigneds stack; + double *score; + unsigned *pos; +}; + +struct kissat; + +void kissat_resize_heap (struct kissat *, heap *, unsigned size); +void kissat_release_heap (struct kissat *, heap *); + +static inline bool kissat_heap_contains (heap *heap, unsigned idx) { + return idx < heap->vars && !DISCONTAINED (heap->pos[idx]); +} + +static inline unsigned kissat_get_heap_pos (const heap *heap, + unsigned idx) { + return idx < heap->vars ? heap->pos[idx] : DISCONTAIN; +} + +static inline double kissat_get_heap_score (const heap *heap, + unsigned idx) { + return idx < heap->vars ? heap->score[idx] : 0.0; +} + +static inline bool kissat_empty_heap (heap *heap) { + return EMPTY_STACK (heap->stack); +} + +static inline size_t kissat_size_heap (heap *heap) { + return SIZE_STACK (heap->stack); +} + +static inline unsigned kissat_max_heap (heap *heap) { + assert (!kissat_empty_heap (heap)); + return PEEK_STACK (heap->stack, 0); +} + +void kissat_rescale_heap (struct kissat *, heap *heap, double factor); + +void kissat_enlarge_heap (struct kissat *, heap *, unsigned new_vars); + +static inline double kissat_max_score_on_heap (heap *heap) { + if (!heap->tainted) + return 0; + assert (heap->vars); + const double *const score = heap->score; + const double *const end = score + heap->vars; + double res = score[0]; + for (const double *p = score + 1; p != end; p++) + res = MAX (res, *p); + return res; +} + +#ifndef NDEBUG +void kissat_dump_heap (heap *); +#endif + +#ifndef NDEBUG +void kissat_check_heap (heap *); +#else +#define kissat_check_heap(...) \ + do { \ + } while (0) +#endif + +#endif diff --git a/src/sat/kissat/ifthenelse.c b/src/sat/kissat/ifthenelse.c new file mode 100644 index 000000000..db4031f68 --- /dev/null +++ b/src/sat/kissat/ifthenelse.c @@ -0,0 +1,174 @@ +#include "ifthenelse.h" +#include "eliminate.h" +#include "gates.h" +#include "inline.h" + +static bool get_ternary_clause (kissat *solver, reference ref, unsigned *p, + unsigned *q, unsigned *r) { + clause *clause = kissat_dereference_clause (solver, ref); + if (clause->garbage) + return false; + const value *const values = solver->values; + unsigned a = INVALID_LIT, b = INVALID_LIT, c = INVALID_LIT; + unsigned found = 0; + for (all_literals_in_clause (other, clause)) { + const value value = values[other]; + if (value > 0) { + kissat_eliminate_clause (solver, clause, INVALID_LIT); + return false; + } + if (value < 0) + continue; + if (++found == 1) + a = other; + else if (found == 2) + b = other; + else if (found == 3) + c = other; + else + return false; + } + if (found != 3) + return false; + assert (a != INVALID_LIT); + assert (b != INVALID_LIT); + assert (c != INVALID_LIT); + *p = a; + *q = b; + *r = c; + return true; +} + +static bool match_ternary_ref (kissat *solver, reference ref, unsigned a, + unsigned b, unsigned c) { + clause *clause = kissat_dereference_clause (solver, ref); + if (clause->garbage) + return false; + const value *const values = solver->values; + unsigned found = 0; + for (all_literals_in_clause (other, clause)) { + const value value = values[other]; + if (value > 0) { + kissat_eliminate_clause (solver, clause, INVALID_LIT); + return false; + } + if (value < 0) + continue; + if (a != other && b != other && c != other) + return false; + found++; + } + if (found == 3) + return true; + solver->resolve_gate = true; + return true; +} + +static bool match_ternary_watch (kissat *solver, watch watch, unsigned a, + unsigned b, unsigned c) { + if (watch.type.binary) { + const unsigned other = watch.binary.lit; + if (other != b && other != c) + return false; + solver->resolve_gate = true; + return true; + } else { + const reference ref = watch.large.ref; + return match_ternary_ref (solver, ref, a, b, c); + } +} + +static inline const watch *find_ternary_clause (kissat *solver, + uint64_t *steps, unsigned a, + unsigned b, unsigned c) { + watches *watches = &WATCHES (a); + const watch *const begin = BEGIN_WATCHES (*watches); + const watch *const end = END_WATCHES (*watches); + for (const watch *p = begin; p != end; p++) { + *steps += 1; + if (match_ternary_watch (solver, *p, a, b, c)) + return p; + } + return 0; +} + +bool kissat_find_if_then_else_gate (kissat *solver, unsigned lit, + unsigned negative) { + if (!GET_OPTION (ifthenelse)) + return false; + watches *watches = &WATCHES (lit); + const watch *const begin = BEGIN_WATCHES (*watches); + const watch *const end = END_WATCHES (*watches); + if (begin == end) + return false; + uint64_t large_clauses = 0; + for (const watch *p = begin; p != end; p++) + if (!p->type.binary) + large_clauses++; + const uint64_t limit = GET_OPTION (eliminateocclim); + if (large_clauses * large_clauses > limit) + return false; + const watch *const last = end - 1; + uint64_t steps = 0; + for (const watch *p1 = begin; steps < limit && p1 != last; p1++) { + watch w1 = *p1; + if (w1.type.binary) + continue; + unsigned a1, b1, c1; + if (!get_ternary_clause (solver, p1->large.ref, &a1, &b1, &c1)) + continue; + if (b1 == lit) + SWAP (unsigned, a1, b1); + if (c1 == lit) + SWAP (unsigned, a1, c1); + assert (a1 == lit); + for (const watch *p2 = p1 + 1; steps < limit && p2 != end; p2++) { + watch w2 = *p2; + if (w2.type.binary) + continue; + unsigned a2, b2, c2; + if (!get_ternary_clause (solver, p2->large.ref, &a2, &b2, &c2)) + continue; + if (b2 == lit) + SWAP (unsigned, a2, b2); + if (c2 == lit) + SWAP (unsigned, a2, c2); + assert (a2 == lit); + if (STRIP (b1) == STRIP (c2)) + SWAP (unsigned, b2, c2); + if (STRIP (c1) == STRIP (c2)) + continue; + const unsigned not_b2 = NOT (b2); + if (b1 != not_b2) + continue; + solver->resolve_gate = false; + const unsigned not_lit = NOT (lit); + const unsigned not_c1 = NOT (c1); + const watch *const p3 = + find_ternary_clause (solver, &steps, not_lit, b1, not_c1); + if (!p3) + continue; + const unsigned not_c2 = NOT (c2); + const watch *const p4 = + find_ternary_clause (solver, &steps, not_lit, b2, not_c2); + if (!p4) + continue; + watch w3 = p3 < p4 ? *p3 : *p4; + watch w4 = p3 < p4 ? *p4 : *p3; + LOGWATCH (lit, w1, "1st if-then-else"); + LOGWATCH (lit, w2, "2nd if-then-else"); + LOGWATCH (not_lit, w3, "3rd if-then-else"); + LOGWATCH (not_lit, w4, "4th if-then-else"); + LOG ("found if-then-else gate %s = (%s ? %s : %s)", LOGLIT (lit), + LOGLIT (NOT (b1)), LOGLIT (not_c1), LOGLIT (not_c2)); + solver->gate_eliminated = GATE_ELIMINATED (if_then_else); + PUSH_STACK (solver->gates[negative], w1); + PUSH_STACK (solver->gates[negative], w2); + PUSH_STACK (solver->gates[!negative], w3); + PUSH_STACK (solver->gates[!negative], w4); + INC (if_then_else_extracted); + return true; + } + } + return false; +} diff --git a/src/sat/kissat/ifthenelse.h b/src/sat/kissat/ifthenelse.h new file mode 100644 index 000000000..82097883e --- /dev/null +++ b/src/sat/kissat/ifthenelse.h @@ -0,0 +1,11 @@ +#ifndef _ifthenelse_h_INCLUDED +#define _ifthenelse_h_INCLUDED + +#include + +struct kissat; + +bool kissat_find_if_then_else_gate (struct kissat *, unsigned lit, + unsigned negative); + +#endif diff --git a/src/sat/kissat/import.c b/src/sat/kissat/import.c new file mode 100644 index 000000000..38ca379c0 --- /dev/null +++ b/src/sat/kissat/import.c @@ -0,0 +1,100 @@ +#include "internal.h" +#include "logging.h" +#include "resize.h" + +static void adjust_imports_for_external_literal (kissat *solver, + unsigned eidx) { + while (eidx >= SIZE_STACK (solver->import)) { + struct import import; + import.lit = 0; + import.extension = false; + import.imported = false; + import.eliminated = false; + PUSH_STACK (solver->import, import); + } +} + +static void adjust_exports_for_external_literal (kissat *solver, + unsigned eidx, + bool extension) { + struct import *import = &PEEK_STACK (solver->import, eidx); + unsigned iidx = solver->vars; + kissat_enlarge_variables (solver, iidx + 1); + unsigned ilit = 2 * iidx; + import->extension = extension; + import->imported = true; + if (extension) + INC (variables_extension); + else + INC (variables_original); + assert (!import->eliminated); + import->lit = ilit; + LOG ("importing %s external variable %u as internal literal %u", + extension ? "extension" : "original", eidx, ilit); + while (iidx >= SIZE_STACK (solver->export)) + PUSH_STACK (solver->export, 0); + POKE_STACK (solver->export, iidx, (int) eidx); + LOG ("exporting internal variable %u as external literal %u", iidx, eidx); +} + +static inline unsigned import_literal (kissat *solver, int elit, + bool extension) { + const unsigned eidx = ABS (elit); + adjust_imports_for_external_literal (solver, eidx); + struct import *import = &PEEK_STACK (solver->import, eidx); + if (import->eliminated) + return INVALID_LIT; + unsigned ilit; + if (!import->imported) + adjust_exports_for_external_literal (solver, eidx, extension); + assert (import->imported); + ilit = import->lit; + if (elit < 0) + ilit = NOT (ilit); + assert (VALID_INTERNAL_LITERAL (ilit)); + return ilit; +} + +unsigned kissat_import_literal (kissat *solver, int elit) { + assert (VALID_EXTERNAL_LITERAL (elit)); + if (GET_OPTION (tumble)) + return import_literal (solver, elit, false); + const unsigned eidx = ABS (elit); + assert (SIZE_STACK (solver->import) <= UINT_MAX); + unsigned other = SIZE_STACK (solver->import); + if (eidx < other) + return import_literal (solver, elit, false); + if (!other) + adjust_imports_for_external_literal (solver, other++); + + unsigned ilit = 0; + do { + assert (VALID_EXTERNAL_LITERAL ((int) other)); + ilit = import_literal (solver, other, false); + } while (other++ < eidx); + + if (elit < 0) + ilit = NOT (ilit); + + return ilit; +} + +unsigned kissat_fresh_literal (kissat *solver) { + size_t imported = SIZE_STACK (solver->import); + assert (imported <= EXTERNAL_MAX_VAR); + if (imported == EXTERNAL_MAX_VAR) { + LOG ("can not get another external variable"); + return INVALID_LIT; + } + assert (imported <= (unsigned) INT_MAX); + int eidx = (int) imported; + unsigned res = import_literal (solver, eidx, true); +#ifndef NDEBUG + struct import *import = &PEEK_STACK (solver->import, imported); + assert (import->imported); + assert (import->extension); +#endif + INC (fresh); + kissat_activate_literal (solver, res); + return res; +} diff --git a/src/sat/kissat/import.h b/src/sat/kissat/import.h new file mode 100644 index 000000000..4b82a5f3c --- /dev/null +++ b/src/sat/kissat/import.h @@ -0,0 +1,9 @@ +#ifndef _import_h_INLCUDED +#define _import_h_INLCUDED + +struct kissat; + +unsigned kissat_import_literal (struct kissat *solver, int lit); +unsigned kissat_fresh_literal (struct kissat *solver); + +#endif diff --git a/src/sat/kissat/inline.h b/src/sat/kissat/inline.h new file mode 100644 index 000000000..d1f9b789f --- /dev/null +++ b/src/sat/kissat/inline.h @@ -0,0 +1,328 @@ +#ifndef _inline_h_INCLUDED +#define _inline_h_INCLUDED + +#include "inlinevector.h" +#include "logging.h" + +#ifdef METRICS + +static inline size_t kissat_allocated (kissat *solver) { + return solver->statistics.allocated_current; +} + +#endif + +static inline bool kissat_propagated (kissat *solver) { + assert (BEGIN_ARRAY (solver->trail) <= solver->propagate); + assert (solver->propagate <= END_ARRAY (solver->trail)); + return solver->propagate == END_ARRAY (solver->trail); +} + +static inline bool kissat_trail_flushed (kissat *solver) { + return !solver->unflushed && EMPTY_ARRAY (solver->trail); +} + +static inline void kissat_reset_propagate (kissat *solver) { + solver->propagate = BEGIN_ARRAY (solver->trail); +} + +static inline value kissat_fixed (kissat *solver, unsigned lit) { + assert (lit < LITS); + const value res = solver->values[lit]; + if (!res) + return 0; + if (LEVEL (lit)) + return 0; + return res; +} + +static inline void kissat_mark_removed_literal (kissat *solver, + unsigned lit) { + const unsigned idx = IDX (lit); + flags *flags = FLAGS (idx); + if (flags->fixed) + return; + if (!flags->eliminate) { + LOG ("marking %s to be eliminated", LOGVAR (idx)); + flags->eliminate = true; + INC (variables_eliminate); + } +} + +static inline void kissat_mark_added_literal (kissat *solver, + unsigned lit) { + const unsigned idx = IDX (lit); + flags *flags = FLAGS (idx); + if (!flags->subsume) { + LOG ("marking %s to forward subsume", LOGVAR (idx)); + flags->subsume = true; + INC (variables_subsume); + } + const unsigned bit = 1u << NEGATED (lit); + if (!(flags->factor & bit)) { + flags->factor |= bit; + LOG ("marking literal %s to factor", LOGLIT (lit)); + INC (literals_factor); + } +} + +static inline void +kissat_push_large_watch (kissat *solver, watches *watches, reference ref) { + const watch watch = kissat_large_watch (ref); + PUSH_WATCHES (*watches, watch); +} + +static inline void kissat_push_binary_watch (kissat *solver, + watches *watches, + unsigned other) { + const watch watch = kissat_binary_watch (other); + PUSH_WATCHES (*watches, watch); +} + +static inline void kissat_push_blocking_watch (kissat *solver, + watches *watches, + unsigned blocking, + reference ref) { + assert (solver->watching); + const watch head = kissat_blocking_watch (blocking); + PUSH_WATCHES (*watches, head); + const watch tail = kissat_large_watch (ref); + PUSH_WATCHES (*watches, tail); +} + +static inline void kissat_watch_other (kissat *solver, unsigned lit, + unsigned other) { + LOGBINARY (lit, other, "watching %s blocking %s in", LOGLIT (lit), + LOGLIT (other)); + watches *watches = &WATCHES (lit); + kissat_push_binary_watch (solver, watches, other); +} + +static inline void kissat_watch_binary (kissat *solver, unsigned a, + unsigned b) { + kissat_watch_other (solver, a, b); + kissat_watch_other (solver, b, a); +} + +static inline void kissat_watch_blocking (kissat *solver, unsigned lit, + unsigned blocking, + reference ref) { + assert (solver->watching); + LOGREF3 (ref, "watching %s blocking %s in", LOGLIT (lit), + LOGLIT (blocking)); + watches *watches = &WATCHES (lit); + kissat_push_blocking_watch (solver, watches, blocking, ref); +} + +static inline void kissat_unwatch_blocking (kissat *solver, unsigned lit, + reference ref) { + assert (solver->watching); + LOGREF3 (ref, "unwatching %s in", LOGLIT (lit)); + watches *watches = &WATCHES (lit); + kissat_remove_blocking_watch (solver, watches, ref); +} + +static inline void kissat_disconnect_binary (kissat *solver, unsigned lit, + unsigned other) { + assert (!solver->watching); + watches *watches = &WATCHES (lit); + const watch watch = kissat_binary_watch (other); + REMOVE_WATCHES (*watches, watch); +} + +static inline void +kissat_disconnect_reference (kissat *solver, unsigned lit, reference ref) { + assert (!solver->watching); + LOGREF3 (ref, "disconnecting %s in", LOGLIT (lit)); + const watch watch = kissat_large_watch (ref); + watches *watches = &WATCHES (lit); + REMOVE_WATCHES (*watches, watch); +} + +static inline void kissat_watch_reference (kissat *solver, unsigned a, + unsigned b, reference ref) { + assert (solver->watching); + kissat_watch_blocking (solver, a, b, ref); + kissat_watch_blocking (solver, b, a, ref); +} + +static inline void kissat_connect_literal (kissat *solver, unsigned lit, + reference ref) { + assert (!solver->watching); + LOGREF3 (ref, "connecting %s in", LOGLIT (lit)); + watches *watches = &WATCHES (lit); + kissat_push_large_watch (solver, watches, ref); +} + +static inline clause *kissat_unchecked_dereference_clause (kissat *solver, + reference ref) { + return (clause *) &PEEK_STACK (solver->arena, ref); +} + +static inline clause *kissat_dereference_clause (kissat *solver, + reference ref) { + clause *res = kissat_unchecked_dereference_clause (solver, ref); + assert (kissat_clause_in_arena (solver, res)); + return res; +} + +static inline reference kissat_reference_clause (kissat *solver, + const clause *c) { + assert (kissat_clause_in_arena (solver, c)); + return (ward *) c - BEGIN_STACK (solver->arena); +} + +static inline void kissat_inlined_connect_clause (kissat *solver, + watches *all_watches, + clause *c, + reference ref) { + assert (!solver->watching); + assert (ref == kissat_reference_clause (solver, c)); + assert (c == kissat_dereference_clause (solver, ref)); + for (all_literals_in_clause (lit, c)) { + assert (!solver->watching); + LOGREF3 (ref, "connecting %s in", LOGLIT (lit)); + assert (lit < LITS); + watches *lit_watches = all_watches + lit; + kissat_push_large_watch (solver, lit_watches, ref); + } +} + +static inline void kissat_watch_clause (kissat *solver, clause *c) { + assert (c->searched < c->size); + const reference ref = kissat_reference_clause (solver, c); + kissat_watch_reference (solver, c->lits[0], c->lits[1], ref); +} + +static inline int kissat_export_literal (kissat *solver, unsigned ilit) { + const unsigned iidx = IDX (ilit); + assert (iidx < (unsigned) INT_MAX); + int elit = PEEK_STACK (solver->export, iidx); + if (!elit) + return 0; + if (NEGATED (ilit)) + elit = -elit; + assert (VALID_EXTERNAL_LITERAL (elit)); + return elit; +} + +static inline unsigned kissat_map_literal (kissat *solver, unsigned ilit, + bool map) { + if (!map) + return ilit; + int elit = kissat_export_literal (solver, ilit); + if (!elit) + return INVALID_LIT; + const unsigned eidx = ABS (elit); + const import *const import = &PEEK_STACK (solver->import, eidx); + if (import->eliminated) + return INVALID_LIT; + unsigned mlit = import->lit; + if (elit < 0) + mlit = NOT (mlit); + return mlit; +} + +static inline clause *kissat_last_irredundant_clause (kissat *solver) { + return (solver->last_irredundant == INVALID_REF) + ? 0 + : kissat_dereference_clause (solver, solver->last_irredundant); +} + +static inline clause *kissat_binary_conflict (kissat *solver, unsigned a, + unsigned b) { + LOGBINARY (a, b, "conflicting"); + clause *res = &solver->conflict; + res->size = 2; + unsigned *lits = res->lits; + lits[0] = a; + lits[1] = b; + return res; +} + +static inline void kissat_push_analyzed (kissat *solver, assigned *assigned, + unsigned idx) { + assert (idx < VARS); + struct assigned *a = assigned + idx; + assert (!a->analyzed); + a->analyzed = true; + PUSH_STACK (solver->analyzed, idx); + LOG2 ("%s analyzed", LOGVAR (idx)); +} + +static inline bool kissat_analyzed (kissat *solver) { + return !EMPTY_STACK (solver->analyzed); +} + +static inline void +kissat_push_removable (kissat *solver, assigned *assigned, unsigned idx) { + assert (idx < VARS); + struct assigned *a = assigned + idx; + assert (!a->removable); + a->removable = true; + PUSH_STACK (solver->removable, idx); + LOG2 ("%s removable", LOGVAR (idx)); +} + +static inline void kissat_push_poisoned (kissat *solver, assigned *assigned, + unsigned idx) { + assert (idx < VARS); + struct assigned *a = assigned + idx; + assert (!a->poisoned); + a->poisoned = true; + PUSH_STACK (solver->poisoned, idx); + LOG2 ("%s poisoned", LOGVAR (idx)); +} + +static inline void +kissat_push_shrinkable (kissat *solver, assigned *assigned, unsigned idx) { + assert (idx < VARS); + struct assigned *a = assigned + idx; + assert (!a->shrinkable); + a->shrinkable = true; + PUSH_STACK (solver->shrinkable, idx); + LOG2 ("%s shrinkable", LOGVAR (idx)); +} + +static inline int kissat_checking (kissat *solver) { +#ifndef NDEBUG +#ifdef NOPTIONS + (void) solver; +#endif + return GET_OPTION (check); +#else + (void) solver; + return 0; +#endif +} + +static inline bool kissat_logging (kissat *solver) { +#ifdef LOGGING +#ifdef NOPTIONS + (void) solver; +#endif + return GET_OPTION (log) > 0; +#else + (void) solver; + return false; +#endif +} + +static inline bool kissat_proving (kissat *solver) { +#ifdef NPROOFS + (void) solver; + return false; +#else + return solver->proof != 0; +#endif +} + +static inline bool kissat_checking_or_proving (kissat *solver) { + return kissat_checking (solver) || kissat_proving (solver); +} + +#if !defined(NDEBUG) || !defined(NPROOFS) +#define CHECKING_OR_PROVING +#endif + +#endif diff --git a/src/sat/kissat/inlineassign.h b/src/sat/kissat/inlineassign.h new file mode 100644 index 000000000..b8d3b88a1 --- /dev/null +++ b/src/sat/kissat/inlineassign.h @@ -0,0 +1,100 @@ +#ifndef _inlineassign_h_INLCUDED +#define _inlineassign_h_INLCUDED + +#ifdef FAST_ASSIGN +#define kissat_assign kissat_fast_assign +#endif + +static inline void kissat_assign (kissat *solver, const bool probing, + const unsigned level, +#ifdef FAST_ASSIGN + value *values, assigned *assigned, +#endif + bool binary, unsigned lit, + unsigned reason) { + const unsigned not_lit = NOT (lit); + + watches watches = WATCHES (not_lit); + if (!kissat_empty_vector (&watches)) { + watch *w = BEGIN_WATCHES (watches); + __builtin_prefetch (w, 0, 1); + } + +#ifndef FAST_ASSIGN + value *values = solver->values; +#endif + assert (!values[lit]); + assert (!values[not_lit]); + + values[lit] = 1; + values[not_lit] = -1; + + assert (solver->unassigned > 0); + solver->unassigned--; + + if (!level) { + kissat_mark_fixed_literal (solver, lit); + assert (solver->unflushed < UINT_MAX); + solver->unflushed++; + if (reason != UNIT_REASON) { + CHECK_AND_ADD_UNIT (lit); + ADD_UNIT_TO_PROOF (lit); + reason = UNIT_REASON; + binary = false; + } + } + + const size_t trail = SIZE_ARRAY (solver->trail); + PUSH_ARRAY (solver->trail, lit); + + const unsigned idx = IDX (lit); + +#if !defined(PROBING_PROPAGATION) + if (!probing) { + const bool negated = NEGATED (lit); + const value new_value = BOOL_TO_VALUE (negated); + value *saved = &SAVED (idx); + *saved = new_value; + } +#endif + + struct assigned b; + + b.level = level; + b.trail = trail; + + b.analyzed = false; + b.binary = binary; + b.poisoned = false; + b.reason = reason; + b.removable = false; + b.shrinkable = false; + +#ifndef FAST_ASSIGN + assigned *assigned = solver->assigned; +#endif + struct assigned *a = assigned + idx; + *a = b; +} + +static inline unsigned +kissat_assignment_level (kissat *solver, value *values, assigned *assigned, + unsigned lit, clause *reason) { + unsigned res = 0; + for (all_literals_in_clause (other, reason)) { + if (other == lit) + continue; + assert (values[other] < 0), (void) values; + const unsigned other_idx = IDX (other); + struct assigned *a = assigned + other_idx; + const unsigned level = a->level; + if (res < level) + res = level; + } +#ifdef NDEBUG + (void) solver; +#endif + return res; +} + +#endif diff --git a/src/sat/kissat/inlineframes.h b/src/sat/kissat/inlineframes.h new file mode 100644 index 000000000..75c5186a6 --- /dev/null +++ b/src/sat/kissat/inlineframes.h @@ -0,0 +1,18 @@ +#ifndef _inlineframes_h_INCLUDEDd +#define _inlineframes_h_INCLUDEDd + +#include "allocate.h" +#include "internal.h" + +static inline void kissat_push_frame (kissat *solver, unsigned decision) { + assert (!solver->level || decision != UINT_MAX); + const size_t trail = SIZE_ARRAY (solver->trail); + frame frame; + frame.decision = decision; + frame.promote = false; + frame.trail = trail; + frame.used = 0; + PUSH_STACK (solver->frames, frame); +} + +#endif diff --git a/src/sat/kissat/inlineheap.h b/src/sat/kissat/inlineheap.h new file mode 100644 index 000000000..0bc8c122d --- /dev/null +++ b/src/sat/kissat/inlineheap.h @@ -0,0 +1,176 @@ +#ifndef _inlineheap_h_INCLUDED +#define _inlineheap_h_INCLUDED + +#include "allocate.h" +#include "internal.h" +#include "logging.h" + +#define HEAP_CHILD(POS) (assert ((POS) < (1u << 31)), (2 * (POS) + 1)) + +#define HEAP_PARENT(POS) (assert ((POS) > 0), (((POS) - 1) / 2)) + +static inline void kissat_bubble_up (kissat *solver, heap *heap, + unsigned idx) { + unsigned *stack = BEGIN_STACK (heap->stack); + unsigned *pos = heap->pos; + unsigned idx_pos = pos[idx]; + const double *const score = heap->score; + const double idx_score = score[idx]; + while (idx_pos) { + const unsigned parent_pos = HEAP_PARENT (idx_pos); + const unsigned parent = stack[parent_pos]; + if (score[parent] >= idx_score) + break; + LOG ("heap bubble up: %u@%u = %g swapped with %u@%u = %g", parent, + parent_pos, score[parent], idx, idx_pos, idx_score); + stack[idx_pos] = parent; + pos[parent] = idx_pos; + idx_pos = parent_pos; + } + stack[idx_pos] = idx; + pos[idx] = idx_pos; +#ifndef LOGGING + (void) solver; +#endif +} + +static inline void kissat_bubble_down (kissat *solver, heap *heap, + unsigned idx) { + unsigned *stack = BEGIN_STACK (heap->stack); + const unsigned end = SIZE_STACK (heap->stack); + unsigned *pos = heap->pos; + unsigned idx_pos = pos[idx]; + const double *const score = heap->score; + const double idx_score = score[idx]; + for (;;) { + unsigned child_pos = HEAP_CHILD (idx_pos); + if (child_pos >= end) + break; + unsigned child = stack[child_pos]; + double child_score = score[child]; + const unsigned sibling_pos = child_pos + 1; + if (sibling_pos < end) { + const unsigned sibling = stack[sibling_pos]; + const double sibling_score = score[sibling]; + if (sibling_score > child_score) { + child = sibling; + child_pos = sibling_pos; + child_score = sibling_score; + } + } + if (child_score <= idx_score) + break; + LOG ("heap bubble down: %u@%u = %g swapped with %u@%u = %g", child, + child_pos, score[child], idx, idx_pos, idx_score); + stack[idx_pos] = child; + pos[child] = idx_pos; + idx_pos = child_pos; + } + stack[idx_pos] = idx; + pos[idx] = idx_pos; +#ifndef LOGGING + (void) solver; +#endif +} + +#define HEAP_IMPORT(IDX) \ + do { \ + assert ((IDX) < UINT_MAX - 1); \ + if (heap->vars <= (IDX)) \ + kissat_enlarge_heap (solver, heap, (IDX) + 1); \ + } while (0) + +#define CHECK_HEAP_IMPORTED(IDX) + +static inline void kissat_push_heap (kissat *solver, heap *heap, + unsigned idx) { + LOG ("push heap %u", idx); + assert (!kissat_heap_contains (heap, idx)); + HEAP_IMPORT (idx); + heap->pos[idx] = SIZE_STACK (heap->stack); + PUSH_STACK (heap->stack, idx); + kissat_bubble_up (solver, heap, idx); +} + +static inline void kissat_pop_heap (kissat *solver, heap *heap, + unsigned idx) { + LOG ("pop heap %u", idx); + assert (kissat_heap_contains (heap, idx)); + const unsigned last = POP_STACK (heap->stack); + heap->pos[last] = DISCONTAIN; + if (last == idx) + return; + const unsigned idx_pos = heap->pos[idx]; + heap->pos[idx] = DISCONTAIN; + POKE_STACK (heap->stack, idx_pos, last); + heap->pos[last] = idx_pos; + kissat_bubble_up (solver, heap, last); + kissat_bubble_down (solver, heap, last); +#ifdef CHECK_HEAP + kissat_check_heap (heap); +#endif +} + +static inline unsigned kissat_pop_max_heap (kissat *solver, heap *heap) { + assert (!EMPTY_STACK (heap->stack)); + unsigneds *stack = &heap->stack; + unsigned *const begin = BEGIN_STACK (*stack); + const unsigned idx = *begin; + assert (!heap->pos[idx]); + LOG ("pop max heap %u", idx); + const unsigned last = POP_STACK (*stack); + unsigned *const pos = heap->pos; + pos[last] = DISCONTAIN; + if (last == idx) + return idx; + pos[idx] = DISCONTAIN; + *begin = last; + pos[last] = 0; + kissat_bubble_down (solver, heap, last); +#ifdef CHECK_HEAP + kissat_check_heap (heap); +#endif + return idx; +} + +static inline void kissat_adjust_heap (kissat *solver, heap *heap, + unsigned idx) { + const unsigned new_vars = idx + 1; + const unsigned old_vars = heap->vars; + if (new_vars <= old_vars) + return; + const unsigned old_size = heap->size; + if (idx >= old_size) { + size_t new_size = old_size ? 2 * old_size : 1; + while (idx >= new_size) + new_size *= 2; + assert (new_size < DISCONTAIN); + kissat_resize_heap (solver, heap, new_size); + } + kissat_enlarge_heap (solver, heap, idx + 1); +} + +static inline void kissat_update_heap (kissat *solver, heap *heap, + unsigned idx, double new_score) { + const double old_score = kissat_get_heap_score (heap, idx); + if (old_score == new_score) + return; + HEAP_IMPORT (idx); + LOG ("update heap %u score from %g to %g", idx, old_score, new_score); + heap->score[idx] = new_score; + if (!heap->tainted) { + heap->tainted = true; + LOG ("tainted heap"); + } + if (!kissat_heap_contains (heap, idx)) + return; + if (new_score > old_score) + kissat_bubble_up (solver, heap, idx); + else + kissat_bubble_down (solver, heap, idx); +#ifdef CHECK_HEAP + kissat_check_heap (heap); +#endif +} + +#endif diff --git a/src/sat/kissat/inlinequeue.h b/src/sat/kissat/inlinequeue.h new file mode 100644 index 000000000..017522679 --- /dev/null +++ b/src/sat/kissat/inlinequeue.h @@ -0,0 +1,117 @@ +#ifndef _inlinequeue_h_INCLUDED +#define _inlinequeue_h_INCLUDED + +#include "internal.h" +#include "logging.h" + +static inline void kissat_update_queue (kissat *solver, const links *links, + unsigned idx) { + assert (!DISCONNECTED (idx)); + const unsigned stamp = links[idx].stamp; + LOG ("queue updated to %s stamped %u", LOGVAR (idx), stamp); + solver->queue.search.idx = idx; + solver->queue.search.stamp = stamp; +} + +static inline void kissat_enqueue_links (kissat *solver, unsigned i, + links *links, queue *queue) { + struct links *p = links + i; + assert (DISCONNECTED (p->prev)); + assert (DISCONNECTED (p->next)); + const unsigned j = p->prev = queue->last; + queue->last = i; + if (DISCONNECTED (j)) + queue->first = i; + else { + struct links *l = links + j; + assert (DISCONNECTED (l->next)); + l->next = i; + } + if (queue->stamp == UINT_MAX) { + kissat_reassign_queue_stamps (solver); + assert (p->stamp == queue->stamp); + } else + p->stamp = ++queue->stamp; +} + +static inline void kissat_dequeue_links (unsigned i, links *links, + queue *queue) { + struct links *l = links + i; + const unsigned j = l->prev, k = l->next; + l->prev = l->next = DISCONNECT; + if (DISCONNECTED (j)) { + assert (queue->first == i); + queue->first = k; + } else { + struct links *p = links + j; + assert (p->next == i); + p->next = k; + } + if (DISCONNECTED (k)) { + assert (queue->last == i); + queue->last = j; + } else { + struct links *n = links + k; + assert (n->prev == i); + n->prev = j; + } +} + +static inline void kissat_enqueue (kissat *solver, unsigned idx) { + assert (idx < solver->vars); + links *links = solver->links, *l = links + idx; + l->prev = l->next = DISCONNECT; + kissat_enqueue_links (solver, idx, links, &solver->queue); + LOG ("enqueued %s stamped %u", LOGVAR (idx), l->stamp); + if (!VALUE (LIT (idx))) + kissat_update_queue (solver, links, idx); + kissat_check_queue (solver); +} + +static inline void kissat_dequeue (kissat *solver, unsigned idx) { + assert (idx < solver->vars); + LOG ("dequeued %s", LOGVAR (idx)); + links *links = solver->links; + if (solver->queue.search.idx == idx) { + struct links *l = links + idx; + unsigned search = l->next; + if (search == DISCONNECT) + search = l->prev; + if (search == DISCONNECT) { + solver->queue.search.idx = DISCONNECT; + solver->queue.search.stamp = 0; + } else + kissat_update_queue (solver, links, search); + } + kissat_dequeue_links (idx, links, &solver->queue); + kissat_check_queue (solver); +} + +static inline void kissat_move_to_front (kissat *solver, unsigned idx) { + queue *queue = &solver->queue; + links *links = solver->links; + if (idx == queue->last) { + assert (DISCONNECTED (links[idx].next)); + return; + } + assert (idx < solver->vars); + const value tmp = VALUE (LIT (idx)); + if (tmp && queue->search.idx == idx) { + unsigned prev = links[idx].prev; + if (!DISCONNECTED (prev)) + kissat_update_queue (solver, links, prev); + else { + unsigned next = links[idx].next; + assert (!DISCONNECTED (next)); + kissat_update_queue (solver, links, next); + } + } + kissat_dequeue_links (idx, links, queue); + kissat_enqueue_links (solver, idx, links, queue); + LOG ("moved-to-front %s stamped %u", LOGVAR (idx), LINK (idx).stamp); + if (!tmp) + kissat_update_queue (solver, links, idx); + kissat_check_queue (solver); +} + +#endif diff --git a/src/sat/kissat/inlinevector.h b/src/sat/kissat/inlinevector.h new file mode 100644 index 000000000..b7adbbf7e --- /dev/null +++ b/src/sat/kissat/inlinevector.h @@ -0,0 +1,193 @@ +#ifndef _inlinevector_h_INCLUDED +#define _inlinevector_h_INCLUDED + +#include "internal.h" + +static inline unsigned *kissat_begin_vector (kissat *solver, + vector *vector) { +#ifdef COMPACT + return BEGIN_STACK (solver->vectors.stack) + vector->offset; +#else + (void) solver; + return vector->begin; +#endif +} + +static inline unsigned *kissat_end_vector (kissat *solver, vector *vector) { +#ifdef COMPACT + return kissat_begin_vector (solver, vector) + vector->size; +#else + (void) solver; + return vector->end; +#endif +} + +static inline const unsigned * +kissat_begin_const_vector (kissat *solver, const vector *vector) { +#ifdef COMPACT + return BEGIN_STACK (solver->vectors.stack) + vector->offset; +#else + (void) solver; + return vector->begin; +#endif +} + +static inline const unsigned * +kissat_end_const_vector (kissat *solver, const vector *vector) { +#ifdef COMPACT + return kissat_begin_const_vector (solver, vector) + vector->size; +#else + (void) solver; + return vector->end; +#endif +} + +#if defined(LOGGING) || defined(TEST_VECTOR) + +static inline size_t kissat_offset_vector (kissat *solver, vector *vector) { +#ifdef COMPACT + (void) solver; + return vector->offset; +#else + unsigned *begin_vector = vector->begin; + unsigned *begin_stack = BEGIN_STACK (solver->vectors.stack); + return begin_vector ? begin_vector - begin_stack : 0; +#endif +} + +#endif + +static inline size_t kissat_size_vector (const vector *vector) { +#ifdef COMPACT + return vector->size; +#else + return vector->end - vector->begin; +#endif +} + +static inline bool kissat_empty_vector (vector *vector) { +#ifdef COMPACT + return !vector->size; +#else + return vector->end == vector->begin; +#endif +} + +static inline void kissat_inc_usable (kissat *solver) { + assert (MAX_SECTOR > solver->vectors.usable); + solver->vectors.usable++; +} + +static inline void kissat_add_usable (kissat *solver, size_t inc) { + assert (MAX_SECTOR - inc >= solver->vectors.usable); + solver->vectors.usable += inc; +} + +static inline unsigned *kissat_last_vector_pointer (kissat *solver, + vector *vector) { + assert (!kissat_empty_vector (vector)); +#ifdef COMPACT + assert (vector->size); + unsigned *begin = kissat_begin_vector (solver, vector); + return begin + vector->size - 1; +#else + (void) solver; + return vector->end - 1; +#endif +} + +#ifdef TEST_VECTOR + +static inline void kissat_pop_vector (kissat *solver, vector *vector) { + assert (!kissat_empty_vector (vector)); +#ifdef COMPACT + unsigned *p = kissat_last_vector_pointer (solver, vector); + vector->size--; + *p = INVALID_VECTOR_ELEMENT; +#else + *--vector->end = INVALID_VECTOR_ELEMENT; + (void) solver; +#endif + kissat_inc_usable (solver); +} + +#endif + +static inline void kissat_release_vector (kissat *solver, vector *vector) { + kissat_resize_vector (solver, vector, 0); +} + +static inline void kissat_dec_usable (kissat *solver) { + assert (solver->vectors.usable > 0); + solver->vectors.usable--; +} + +static inline void kissat_push_vectors (kissat *solver, vector *vector, + unsigned e) { + unsigneds *stack = &solver->vectors.stack; + assert (e != INVALID_VECTOR_ELEMENT); + if ( +#ifdef COMPACT + !vector->size && !vector->offset +#else + !vector->begin +#endif + ) { + if (EMPTY_STACK (*stack)) + PUSH_STACK (*stack, 0); + if (FULL_STACK (*stack)) { + unsigned *end = kissat_enlarge_vector (solver, vector); + assert (*end == INVALID_VECTOR_ELEMENT); + *end = e; + kissat_dec_usable (solver); + } else { +#ifdef COMPACT + assert ((uint64_t) SIZE_STACK (*stack) < MAX_VECTORS); + vector->offset = SIZE_STACK (*stack); + assert (vector->offset); + *stack->end++ = e; +#else + assert (stack->end < stack->allocated); + *(vector->begin = stack->end++) = e; +#endif + } +#if !defined(COMPACT) + vector->end = vector->begin; +#endif + } else { + unsigned *end = kissat_end_vector (solver, vector); + if (end == END_STACK (*stack)) { + if (FULL_STACK (*stack)) { + end = kissat_enlarge_vector (solver, vector); + assert (*end == INVALID_VECTOR_ELEMENT); + *end = e; + kissat_dec_usable (solver); + } else + *stack->end++ = e; + } else { + if (*end != INVALID_VECTOR_ELEMENT) + end = kissat_enlarge_vector (solver, vector); + assert (*end == INVALID_VECTOR_ELEMENT); + *end = e; + kissat_dec_usable (solver); + } + } +#ifndef COMPACT + vector->end++; +#else + vector->size++; +#endif + kissat_check_vectors (solver); +} + +#ifdef TEST_VECTOR + +#define all_vector(E, V) \ + unsigned E, *E##_PTR = kissat_begin_vector (solver, &V), \ + *const E##_END = kissat_end_vector (solver, &V); \ + E##_PTR != E##_END && (E = *E##_PTR, true); \ + E##_PTR++ + +#endif + +#endif diff --git a/src/sat/kissat/internal.c b/src/sat/kissat/internal.c new file mode 100644 index 000000000..1c0002019 --- /dev/null +++ b/src/sat/kissat/internal.c @@ -0,0 +1,520 @@ +#include "allocate.h" +#include "backtrack.h" +#include "error.h" +#include "import.h" +#include "inline.h" +#include "inlineframes.h" +#include "print.h" +#include "propsearch.h" +#include "require.h" +#include "resize.h" +#include "resources.h" +#include "search.h" + +#include +#include +#include +#include +#include + +void kissat_reset_last_learned (kissat *solver) { + for (really_all_last_learned (p)) + *p = INVALID_REF; +} + +kissat *kissat_init (void) { + kissat *solver = kissat_calloc (0, 1, sizeof *solver); +#ifndef NOPTIONS + kissat_init_options (&solver->options); +#else + kissat_init_options (); +#endif +#ifndef QUIET + kissat_init_profiles (&solver->profiles); +#endif + START (total); + kissat_init_queue (solver); + assert (INTERNAL_MAX_LIT < UINT_MAX); + kissat_push_frame (solver, UINT_MAX); + solver->watching = true; + solver->conflict.size = 2; + solver->scinc = 1.0; + solver->first_reducible = INVALID_REF; + solver->last_irredundant = INVALID_REF; + kissat_reset_last_learned (solver); +#ifndef NDEBUG + kissat_init_checker (solver); +#endif + solver->prefix = kissat_strdup (solver, "c "); + return solver; +} + +void kissat_set_prefix (kissat *solver, const char *prefix) { + kissat_freestr (solver, solver->prefix); + solver->prefix = kissat_strdup (solver, prefix); +} + +#define DEALLOC_GENERIC(NAME, ELEMENTS_PER_BLOCK) \ + do { \ + const size_t block_size = ELEMENTS_PER_BLOCK * sizeof *solver->NAME; \ + kissat_dealloc (solver, solver->NAME, solver->size, block_size); \ + solver->NAME = 0; \ + } while (0) + +#define DEALLOC_VARIABLE_INDEXED(NAME) DEALLOC_GENERIC (NAME, 1) + +#define DEALLOC_LITERAL_INDEXED(NAME) DEALLOC_GENERIC (NAME, 2) + +#define RELEASE_LITERAL_INDEXED_STACKS(NAME, ACCESS) \ + do { \ + for (all_stack (unsigned, IDX_RILIS, solver->active)) { \ + const unsigned LIT_RILIS = LIT (IDX_RILIS); \ + const unsigned NOT_LIT_RILIS = NOT (LIT_RILIS); \ + RELEASE_STACK (ACCESS (LIT_RILIS)); \ + RELEASE_STACK (ACCESS (NOT_LIT_RILIS)); \ + } \ + DEALLOC_LITERAL_INDEXED (NAME); \ + } while (0) + +void kissat_release (kissat *solver) { + kissat_require_initialized (solver); + kissat_release_heap (solver, SCORES); + kissat_release_heap (solver, &solver->schedule); + kissat_release_vectors (solver); + kissat_release_phases (solver); + + RELEASE_STACK (solver->export); + RELEASE_STACK (solver->import); + + DEALLOC_VARIABLE_INDEXED (assigned); + DEALLOC_VARIABLE_INDEXED (flags); + DEALLOC_VARIABLE_INDEXED (links); + + DEALLOC_LITERAL_INDEXED (marks); + DEALLOC_LITERAL_INDEXED (values); + DEALLOC_LITERAL_INDEXED (watches); + + RELEASE_STACK (solver->import); + RELEASE_STACK (solver->eliminated); + RELEASE_STACK (solver->extend); + RELEASE_STACK (solver->witness); + RELEASE_STACK (solver->etrail); + + RELEASE_STACK (solver->delayed); + + RELEASE_STACK (solver->clause); + RELEASE_STACK (solver->shadow); +#if defined(LOGGING) || !defined(NDEBUG) + RELEASE_STACK (solver->resolvent); +#endif + + RELEASE_STACK (solver->arena); + + RELEASE_STACK (solver->units); + RELEASE_STACK (solver->frames); + RELEASE_STACK (solver->sorter); + + RELEASE_ARRAY (solver->trail, solver->size); + + RELEASE_STACK (solver->analyzed); + RELEASE_STACK (solver->levels); + RELEASE_STACK (solver->minimize); + RELEASE_STACK (solver->poisoned); + RELEASE_STACK (solver->promote); + RELEASE_STACK (solver->removable); + RELEASE_STACK (solver->shrinkable); + RELEASE_STACK (solver->xorted[0]); + RELEASE_STACK (solver->xorted[1]); + + RELEASE_STACK (solver->sweep_schedule); + + RELEASE_STACK (solver->ranks); + + RELEASE_STACK (solver->antecedents[0]); + RELEASE_STACK (solver->antecedents[1]); + RELEASE_STACK (solver->gates[0]); + RELEASE_STACK (solver->gates[1]); + RELEASE_STACK (solver->resolvents); + +#if !defined(NDEBUG) || !defined(NPROOFS) + RELEASE_STACK (solver->added); + RELEASE_STACK (solver->removed); +#endif + +#if !defined(NDEBUG) || !defined(NPROOFS) || defined(LOGGING) + RELEASE_STACK (solver->original); +#endif + +#ifndef QUIET + RELEASE_STACK (solver->profiles.stack); +#endif + + kissat_freestr (solver, solver->prefix); + +#ifndef NDEBUG + kissat_release_checker (solver); +#endif +#if !defined(NDEBUG) && defined(METRICS) + uint64_t leaked = solver->statistics.allocated_current; + if (leaked) + if (!getenv ("LEAK")) + kissat_fatal ("internally leaking %" PRIu64 " bytes", leaked); +#endif + + kissat_free (0, solver, sizeof *solver); +} + +void kissat_reserve (kissat *solver, int max_var) { + kissat_require_initialized (solver); + kissat_require (0 <= max_var, "negative maximum variable argument '%d'", + max_var); + kissat_require (max_var <= EXTERNAL_MAX_VAR, + "invalid maximum variable argument '%d'", max_var); + kissat_increase_size (solver, (unsigned) max_var); + if (!GET_OPTION (tumble)) { + for (int idx = 1; idx <= max_var; idx++) + (void) kissat_import_literal (solver, idx); + for (unsigned idx = 0; idx != (unsigned) max_var; idx++) + kissat_activate_literal (solver, LIT (idx)); + } +} + +int kissat_get_option (kissat *solver, const char *name) { + kissat_require_initialized (solver); + kissat_require (name, "name zero pointer"); +#ifndef NOPTIONS + return kissat_options_get (&solver->options, name); +#else + (void) solver; + return kissat_options_get (name); +#endif +} + +int kissat_set_option (kissat *solver, const char *name, int new_value) { +#ifndef NOPTIONS + kissat_require_initialized (solver); + kissat_require (name, "name zero pointer"); +#ifndef NOPTIONS + return kissat_options_set (&solver->options, name, new_value); +#else + return kissat_options_set (name, new_value); +#endif +#else + (void) solver, (void) new_value; + return kissat_options_get (name); +#endif +} + +void kissat_set_decision_limit (kissat *solver, unsigned limit) { + kissat_require_initialized (solver); + limits *limits = &solver->limits; + limited *limited = &solver->limited; + statistics *statistics = &solver->statistics; + limited->decisions = true; + assert (UINT64_MAX - limit >= statistics->decisions); + limits->decisions = statistics->decisions + limit; + LOG ("set decision limit to %" PRIu64 " after %u decisions", + limits->decisions, limit); +} + +void kissat_set_conflict_limit (kissat *solver, unsigned limit) { + kissat_require_initialized (solver); + limits *limits = &solver->limits; + limited *limited = &solver->limited; + statistics *statistics = &solver->statistics; + limited->conflicts = true; + assert (UINT64_MAX - limit >= statistics->conflicts); + limits->conflicts = statistics->conflicts + limit; + LOG ("set conflict limit to %" PRIu64 " after %u conflicts", + limits->conflicts, limit); +} + +void kissat_print_statistics (kissat *solver) { +#ifndef QUIET + kissat_require_initialized (solver); + const int verbosity = kissat_verbosity (solver); + if (verbosity < 0) + return; + if (GET_OPTION (profile)) { + kissat_section (solver, "profiling"); + kissat_profiles_print (solver); + } + const bool complete = GET_OPTION (statistics); + kissat_section (solver, "statistics"); + const bool verbose = (complete || verbosity > 0); + kissat_statistics_print (solver, verbose); +#ifndef NPROOFS + if (solver->proof) { + kissat_section (solver, "proof"); + kissat_print_proof_statistics (solver, verbose); + } +#endif +#ifndef NDEBUG + if (GET_OPTION (check) > 1) { + kissat_section (solver, "checker"); + kissat_print_checker_statistics (solver, verbose); + } +#endif + kissat_section (solver, "glue usage"); + kissat_print_glue_usage (solver); + kissat_section (solver, "resources"); + kissat_print_resources (solver); +#endif + (void) solver; +} + +void kissat_add (kissat *solver, int elit) { + kissat_require_initialized (solver); + kissat_require (!GET (searches), "incremental solving not supported"); +#if !defined(NDEBUG) || !defined(NPROOFS) || defined(LOGGING) + const int checking = kissat_checking (solver); + const bool logging = kissat_logging (solver); + const bool proving = kissat_proving (solver); +#endif + if (elit) { + kissat_require_valid_external_internal (elit); +#if !defined(NDEBUG) || !defined(NPROOFS) || defined(LOGGING) + if (checking || logging || proving) + PUSH_STACK (solver->original, elit); +#endif + unsigned ilit = kissat_import_literal (solver, elit); + + const mark mark = MARK (ilit); + if (!mark) { + const value value = kissat_fixed (solver, ilit); + if (value > 0) { + if (!solver->clause_satisfied) { + LOG ("adding root level satisfied literal %u(%d)@0=1", ilit, + elit); + solver->clause_satisfied = true; + } + } else if (value < 0) { + LOG ("adding root level falsified literal %u(%d)@0=-1", ilit, elit); + if (!solver->clause_shrink) { + solver->clause_shrink = true; + LOG ("thus original clause needs shrinking"); + } + } else { + MARK (ilit) = 1; + MARK (NOT (ilit)) = -1; + assert (SIZE_STACK (solver->clause) < UINT_MAX); + PUSH_STACK (solver->clause, ilit); + } + } else if (mark < 0) { + assert (mark < 0); + if (!solver->clause_trivial) { + LOG ("adding dual literal %u(%d) and %u(%d)", NOT (ilit), -elit, + ilit, elit); + solver->clause_trivial = true; + } + } else { + assert (mark > 0); + LOG ("adding duplicated literal %u(%d)", ilit, elit); + if (!solver->clause_shrink) { + solver->clause_shrink = true; + LOG ("thus original clause needs shrinking"); + } + } + } else { +#if !defined(NDEBUG) || !defined(NPROOFS) || defined(LOGGING) + const size_t offset = solver->offset_of_last_original_clause; + size_t esize = SIZE_STACK (solver->original) - offset; + int *elits = BEGIN_STACK (solver->original) + offset; + assert (esize <= UINT_MAX); +#endif + ADD_UNCHECKED_EXTERNAL (esize, elits); + const size_t isize = SIZE_STACK (solver->clause); + unsigned *ilits = BEGIN_STACK (solver->clause); + assert (isize < (unsigned) INT_MAX); + + if (solver->inconsistent) + LOG ("inconsistent thus skipping original clause"); + else if (solver->clause_satisfied) + LOG ("skipping satisfied original clause"); + else if (solver->clause_trivial) + LOG ("skipping trivial original clause"); + else { + kissat_activate_literals (solver, isize, ilits); + + if (!isize) { + if (solver->clause_shrink) + LOG ("all original clause literals root level falsified"); + else + LOG ("found empty original clause"); + + if (!solver->inconsistent) { + LOG ("thus solver becomes inconsistent"); + solver->inconsistent = true; + CHECK_AND_ADD_EMPTY (); + ADD_EMPTY_TO_PROOF (); + } + } else if (isize == 1) { + unsigned unit = TOP_STACK (solver->clause); + + if (solver->clause_shrink) + LOGUNARY (unit, "original clause shrinks to"); + else + LOGUNARY (unit, "found original"); + + kissat_original_unit (solver, unit); + + COVER (solver->level); + if (!solver->level) + (void) kissat_search_propagate (solver); + } else { + reference res = kissat_new_original_clause (solver); + + const unsigned a = ilits[0]; + const unsigned b = ilits[1]; + + const value u = VALUE (a); + const value v = VALUE (b); + + const unsigned k = u ? LEVEL (a) : UINT_MAX; + const unsigned l = v ? LEVEL (b) : UINT_MAX; + + bool assign = false; + + if (!u && v < 0) { + LOG ("original clause immediately forcing"); + assign = true; + } else if (u < 0 && k == l) { + LOG ("both watches falsified at level @%u", k); + assert (v < 0); + assert (k > 0); + kissat_backtrack_without_updating_phases (solver, k - 1); + } else if (u < 0) { + LOG ("watches falsified at levels @%u and @%u", k, l); + assert (v < 0); + assert (k > l); + assert (l > 0); + assign = true; + } else if (u > 0 && v < 0) { + LOG ("first watch satisfied at level @%u " + "second falsified at level @%u", + k, l); + assert (k <= l); + } else if (!u && v > 0) { + LOG ("first watch unassigned " + "second falsified at level @%u", + l); + assign = true; + } else { + assert (!u); + assert (!v); + } + + if (assign) { + assert (solver->level > 0); + + if (isize == 2) { + assert (res == INVALID_REF); + kissat_assign_binary (solver, a, b); + } else { + assert (res != INVALID_REF); + clause *c = kissat_dereference_clause (solver, res); + kissat_assign_reference (solver, a, res, c); + } + } + } + } + +#if !defined(NDEBUG) || !defined(NPROOFS) + if (solver->clause_satisfied || solver->clause_trivial) { +#ifndef NDEBUG + if (checking > 1) + kissat_remove_checker_external (solver, esize, elits); +#endif +#ifndef NPROOFS + if (proving) { + if (esize == 1) + LOG ("skipping deleting unit from proof"); + else + kissat_delete_external_from_proof (solver, esize, elits); + } +#endif + } else if (!solver->inconsistent && solver->clause_shrink) { +#ifndef NDEBUG + if (checking > 1) { + kissat_check_and_add_internal (solver, isize, ilits); + kissat_remove_checker_external (solver, esize, elits); + } +#endif +#ifndef NPROOFS + if (proving) { + kissat_add_lits_to_proof (solver, isize, ilits); + kissat_delete_external_from_proof (solver, esize, elits); + } +#endif + } +#endif + +#if !defined(NDEBUG) || !defined(NPROOFS) || defined(LOGGING) + if (checking) { + LOGINTS (esize, elits, "saved original"); + PUSH_STACK (solver->original, 0); + solver->offset_of_last_original_clause = + SIZE_STACK (solver->original); + } else if (logging || proving) { + LOGINTS (esize, elits, "reset original"); + CLEAR_STACK (solver->original); + solver->offset_of_last_original_clause = 0; + } +#endif + for (all_stack (unsigned, lit, solver->clause)) + MARK (lit) = MARK (NOT (lit)) = 0; + + CLEAR_STACK (solver->clause); + + solver->clause_satisfied = false; + solver->clause_trivial = false; + solver->clause_shrink = false; + } +} + +int kissat_solve (kissat *solver) { + kissat_require_initialized (solver); + kissat_require (EMPTY_STACK (solver->clause), + "incomplete clause (terminating zero not added)"); + kissat_require (!GET (searches), "incremental solving not supported"); + return kissat_search (solver); +} + +void kissat_terminate (kissat *solver) { + kissat_require_initialized (solver); + solver->termination.flagged = ~(unsigned) 0; + assert (solver->termination.flagged); +} + +void kissat_set_terminate (kissat *solver, void *state, + int (*terminate) (void *)) { + solver->termination.terminate = 0; + solver->termination.state = state; + solver->termination.terminate = terminate; +} + +int kissat_value (kissat *solver, int elit) { + kissat_require_initialized (solver); + kissat_require_valid_external_internal (elit); + const unsigned eidx = ABS (elit); + if (eidx >= SIZE_STACK (solver->import)) + return 0; + const import *const import = &PEEK_STACK (solver->import, eidx); + if (!import->imported) + return 0; + value tmp; + if (import->eliminated) { + if (!solver->extended && !EMPTY_STACK (solver->extend)) + kissat_extend (solver); + const unsigned eliminated = import->lit; + tmp = PEEK_STACK (solver->eliminated, eliminated); + } else { + const unsigned ilit = import->lit; + tmp = VALUE (ilit); + } + if (!tmp) + return 0; + if (elit < 0) + tmp = -tmp; + return tmp < 0 ? -elit : elit; +} diff --git a/src/sat/kissat/internal.h b/src/sat/kissat/internal.h new file mode 100644 index 000000000..8a4b46c80 --- /dev/null +++ b/src/sat/kissat/internal.h @@ -0,0 +1,295 @@ +#ifndef _internal_h_INCLUDED +#define _internal_h_INCLUDED + +#include "arena.h" +#include "array.h" +#include "assign.h" +#include "averages.h" +#include "check.h" +#include "classify.h" +#include "clause.h" +#include "cover.h" +#include "extend.h" +#include "flags.h" +#include "format.h" +#include "frames.h" +#include "heap.h" +#include "kimits.h" +#include "kissat.h" +#include "literal.h" +#include "mode.h" +#include "options.h" +#include "phases.h" +#include "profile.h" +#include "proof.h" +#include "queue.h" +#include "random.h" +#include "reluctant.h" +#include "rephase.h" +#include "smooth.h" +#include "stack.h" +#include "statistics.h" +#include "value.h" +#include "vector.h" +#include "watch.h" + +typedef struct datarank datarank; + +struct datarank { + unsigned data; + unsigned rank; +}; + +typedef struct import import; + +struct import { + unsigned lit; + bool extension; + bool imported; + bool eliminated; +}; + +typedef struct termination termination; + +struct termination { +#ifdef COVERAGE + volatile uint64_t flagged; +#else + volatile bool flagged; +#endif + volatile void *state; + int (*volatile terminate) (void *); +}; + +// clang-format off + +typedef STACK (value) eliminated; +typedef STACK (import) imports; +typedef STACK (datarank) dataranks; +typedef STACK (watch) statches; +typedef STACK (watch *) patches; + +// clang-format on + +struct kitten; + +struct kissat { +#if !defined(NDEBUG) || defined(METRICS) + bool backbone_computing; +#endif +#ifdef LOGGING + bool compacting; +#endif + bool extended; + bool inconsistent; + bool iterating; + bool preprocessing; + bool probing; +#ifndef QUIET + bool sectioned; +#endif + bool stable; +#if !defined(NDEBUG) || defined(METRICS) + bool transitive_reducing; + bool vivifying; +#endif + bool warming; + bool watching; + + bool large_clauses_watched_after_binary_clauses; + + termination termination; + + unsigned vars; + unsigned size; + unsigned active; + unsigned randec; + + ints export; + ints units; + imports import; + extensions extend; + unsigneds witness; + + assigned *assigned; + flags *flags; + + mark *marks; + + value *values; + phases phases; + + eliminated eliminated; + unsigneds etrail; + + links *links; + queue queue; + + heap scores; + double scinc; + + heap schedule; + double scoreshift; + + unsigned level; + frames frames; + + unsigned_array trail; + unsigned *propagate; + + unsigned best_assigned; + unsigned target_assigned; + unsigned unflushed; + unsigned unassigned; + + unsigneds delayed; + +#if defined(LOGGING) || !defined(NDEBUG) + unsigneds resolvent; +#endif + unsigned resolvent_size; + unsigned antecedent_size; + + dataranks ranks; + + unsigneds analyzed; + unsigneds levels; + unsigneds minimize; + unsigneds poisoned; + unsigneds promote; + unsigneds removable; + unsigneds shrinkable; + + clause conflict; + + bool clause_satisfied; + bool clause_shrink; + bool clause_trivial; + + unsigneds clause; + unsigneds shadow; + + arena arena; + vectors vectors; + reference first_reducible; + reference last_irredundant; + watches *watches; + + reference last_learned[4]; + + sizes sorter; + + generator random; + averages averages[2]; + unsigned tier1[2], tier2[2]; + reluctant reluctant; + + bounds bounds; + classification classification; + delays delays; + enabled enabled; + limited limited; + limits limits; + remember last; + unsigned walked; + + mode mode; + + uint64_t ticks; + + format format; + char *prefix; + + statches antecedents[2]; + statches gates[2]; + patches xorted[2]; + unsigneds resolvents; + bool resolve_gate; + + struct kitten *kitten; +#ifdef METRICS + uint64_t *gate_eliminated; +#else + bool gate_eliminated; +#endif + bool sweep_incomplete; + unsigneds sweep_schedule; + +#if !defined(NDEBUG) || !defined(NPROOFS) + unsigneds added; + unsigneds removed; +#endif + +#if !defined(NDEBUG) || !defined(NPROOFS) || defined(LOGGING) + ints original; + size_t offset_of_last_original_clause; +#endif + +#ifndef QUIET + profiles profiles; +#endif + +#ifndef NOPTIONS + options options; +#endif + +#ifndef NDEBUG + checker *checker; +#endif + +#ifndef NPROOFS + proof *proof; +#endif + + statistics statistics; +}; + +#define VARS (solver->vars) +#define LITS (2 * solver->vars) + +#if 0 +#define TIEDX (GET_OPTION (focusedtiers) ? 0 : solver->stable) +#define TIER1 (solver->tier1[TIEDX]) +#define TIER2 (solver->tier2[TIEDX]) +#else +#define TIER1 (solver->tier1[0]) +#define TIER2 (solver->tier2[1]) +#endif + +#define SCORES (&solver->scores) + +static inline unsigned kissat_assigned (kissat *solver) { + assert (VARS >= solver->unassigned); + return VARS - solver->unassigned; +} + +#define all_variables(IDX) \ + unsigned IDX = 0, IDX##_END = solver->vars; \ + IDX != IDX##_END; \ + ++IDX + +#define all_literals(LIT) \ + unsigned LIT = 0, LIT##_END = LITS; \ + LIT != LIT##_END; \ + ++LIT + +#define all_clauses(C) \ + clause *C = (clause *) BEGIN_STACK (solver->arena), \ + *const C##_END = (clause *) END_STACK (solver->arena), *C##_NEXT; \ + C != C##_END && (C##_NEXT = kissat_next_clause (C), true); \ + C = C##_NEXT + +#define capacity_last_learned \ + (sizeof solver->last_learned / sizeof *solver->last_learned) + +#define real_end_last_learned (solver->last_learned + capacity_last_learned) + +#define really_all_last_learned(REF_PTR) \ + reference *REF_PTR = solver->last_learned, \ + *REF_PTR##_END = real_end_last_learned; \ + REF_PTR != REF_PTR##_END; \ + REF_PTR++ + +void kissat_reset_last_learned (kissat *solver); + +#endif diff --git a/src/sat/kissat/keatures.h b/src/sat/kissat/keatures.h new file mode 100644 index 000000000..d0652be99 --- /dev/null +++ b/src/sat/kissat/keatures.h @@ -0,0 +1,18 @@ +#ifndef _keatures_h_INCLUDED +#define _keatures_h_INCLUDED + +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define KISSAT_IS_BIG_ENDIAN +#endif + +#if defined(_POSIX_C_SOURCE) || defined(__APPLE__) +#define KISSAT_HAS_COMPRESSION +#define KISSAT_HAS_COLORS +#define KISSAT_HAS_FILENO +#endif + +#if defined(_POSIX_C_SOURCE) +#define KISSAT_HAS_UNLOCKEDIO +#endif + +#endif diff --git a/src/sat/kissat/kimits.c b/src/sat/kissat/kimits.c new file mode 100644 index 000000000..9fe4dcf05 --- /dev/null +++ b/src/sat/kissat/kimits.c @@ -0,0 +1,194 @@ +#include "internal.h" +#include "logging.h" +#include "mode.h" +#include "print.h" +#include "reduce.h" +#include "rephase.h" +#include "resources.h" +#include "restart.h" + +#include +#include + +double kissat_logn (uint64_t count) { + assert (count > 0); + const double res = log10 (count + 9); + assert (res >= 1); + return res; +} + +double kissat_sqrt (uint64_t count) { + assert (count > 0); + const double res = sqrt (count); + assert (res >= 1); + return res; +} + +double kissat_nlogpown (uint64_t count, unsigned exponent) { + assert (count > 0); + const double tmp = log10 (count + 9); + double factor = 1; + while (exponent--) + factor *= tmp; + assert (factor >= 1); + const double res = count * factor; + assert (res >= 1); + return res; +} + +uint64_t kissat_scale_delta (kissat *solver, const char *pretty, + uint64_t delta) { + const uint64_t C = BINIRR_CLAUSES; + double f = kissat_logn (C + 1) - 5; + const double ff = f * f; + assert (ff >= 0); + const double fff = 4.5 * ff + 25; + uint64_t scaled = fff * delta; + assert (delta <= scaled); + // clang-format off + kissat_very_verbose (solver, + "scaled %s delta %" PRIu64 + " = %g * %" PRIu64 + " = (4.5 (log10(%" PRIu64 ") - 5)^2 + 25) * %" PRIu64, + pretty, scaled, fff, delta, C, delta); + // clang-format on + (void) pretty; + return scaled; +} + +static void init_enabled (kissat *solver) { + bool probe; + if (!GET_OPTION (simplify)) + probe = false; + else if (!GET_OPTION (probe)) + probe = false; + else if (GET_OPTION (substitute)) + probe = true; + else if (GET_OPTION (sweep)) + probe = true; + else if (GET_OPTION (vivify)) + probe = true; + else + probe = false; + kissat_very_verbose (solver, "probing %sabled", probe ? "en" : "dis"); + solver->enabled.probe = probe; + + bool eliminate; + if (!GET_OPTION (simplify)) + eliminate = false; + else if (!GET_OPTION (eliminate)) + eliminate = false; + else + eliminate = true; + kissat_very_verbose (solver, "eliminate %sabled", + eliminate ? "en" : "dis"); + solver->enabled.eliminate = eliminate; +} + +#define INIT_CONFLICT_LIMIT(NAME, SCALE) \ + do { \ + const uint64_t DELTA = GET_OPTION (NAME##init); \ + const uint64_t SCALED = \ + !(SCALE) ? DELTA : kissat_scale_delta (solver, #NAME, DELTA); \ + limits->NAME.conflicts = CONFLICTS + SCALED; \ + kissat_very_verbose (solver, \ + "initial " #NAME " limit of %s conflicts", \ + FORMAT_COUNT (limits->NAME.conflicts)); \ + } while (0) + +void kissat_init_limits (kissat *solver) { + assert (solver->statistics.searches == 1); + + init_enabled (solver); + + limits *limits = &solver->limits; + + if (GET_OPTION (randec)) + INIT_CONFLICT_LIMIT (randec, false); + + if (GET_OPTION (reduce)) + INIT_CONFLICT_LIMIT (reduce, false); + + if (GET_OPTION (reorder)) + INIT_CONFLICT_LIMIT (reorder, false); + + if (GET_OPTION (rephase)) + INIT_CONFLICT_LIMIT (rephase, false); + + if (!solver->stable) + kissat_update_focused_restart_limit (solver); + + kissat_init_mode_limit (solver); + + if (solver->enabled.eliminate) { + INIT_CONFLICT_LIMIT (eliminate, true); + solver->bounds.eliminate.max_bound_completed = 0; + solver->bounds.eliminate.additional_clauses = 0; + kissat_very_verbose (solver, "reset elimination bound to zero"); + } + + if (solver->enabled.probe) + INIT_CONFLICT_LIMIT (probe, true); +} + +#ifndef QUIET + +static const char *delay_description (kissat *solver, delay *delay) { + delays *delays = &solver->delays; + if (delay == &delays->bumpreasons) + return "bumping reason side literals"; + else if (delay == &delays->congruence) + return "congruence closure"; + else if (delay == &delays->sweep) + return "sweeping"; + else { + assert (delay == &delays->vivifyirr); + return "vivifying irredundant clauses"; + } +} + +#endif + +#define VERY_VERBOSE_IF_NOT_BUMPREASONS(...) \ + VERY_VERBOSE_OR_LOG (delay == &solver->delays.bumpreasons, __VA_ARGS__) + +void kissat_reduce_delay (kissat *solver, delay *delay) { + if (!delay->current) + return; + delay->current /= 2; + VERY_VERBOSE_IF_NOT_BUMPREASONS ( + solver, "%s delay interval decreased to %u", + delay_description (solver, delay), delay->current); + delay->count = delay->current; +#ifdef QUIET + (void) solver; +#endif +} + +void kissat_bump_delay (kissat *solver, delay *delay) { + delay->current += delay->current < UINT_MAX; + VERY_VERBOSE_IF_NOT_BUMPREASONS ( + solver, "%s delay interval increased to %u", + delay_description (solver, delay), delay->current); + delay->count = delay->current; +#ifdef QUIET + (void) solver; +#endif +} + +bool kissat_delaying (kissat *solver, delay *delay) { + if (delay->count) { + delay->count--; + VERY_VERBOSE_IF_NOT_BUMPREASONS ( + solver, "%s still delayed (%u more times)", + delay_description (solver, delay), delay->current); + return true; + } else { + VERY_VERBOSE_IF_NOT_BUMPREASONS (solver, "%s not delayed", + delay_description (solver, delay)); + return false; + } +#ifdef QUIET + (void) solver; +#endif +} diff --git a/src/sat/kissat/kimits.h b/src/sat/kissat/kimits.h new file mode 100644 index 000000000..93339b3b5 --- /dev/null +++ b/src/sat/kissat/kimits.h @@ -0,0 +1,185 @@ +#ifndef _limits_h_INCLUDED +#define _limits_h_INCLUDED + +#include +#include + +typedef struct bounds bounds; +typedef struct changes changes; +typedef struct delays delays; +typedef struct delay delay; +typedef struct remember remember; +typedef struct enabled enabled; +typedef struct limited limited; +typedef struct limits limits; + +struct bounds { + struct { + uint64_t max_bound_completed; + unsigned additional_clauses; + } eliminate; +}; + +struct limits { + uint64_t conflicts; + uint64_t decisions; + uint64_t reports; + + struct { + uint64_t count; + uint64_t ticks; + uint64_t conflicts; + } mode; + + struct { + struct { + uint64_t eliminate; + uint64_t subsume; + } variables; + uint64_t conflicts; + } eliminate; + + struct { + uint64_t marked; + } factor; + + struct { + uint64_t conflicts; + } probe, randec, reduce, reorder, rephase, restart; + + struct { + uint64_t conflicts; + uint64_t interval; + } glue; +}; + +struct limited { + bool conflicts; + bool decisions; +}; + +struct enabled { + bool eliminate; + bool focus; + bool mode; + bool probe; +}; + +struct delay { + unsigned count; + unsigned current; +}; + +struct delays { + delay bumpreasons; + delay congruence; + delay sweep; + delay vivifyirr; +}; + +struct remember { + struct { + uint64_t eliminate; + uint64_t probe; + } ticks; + struct { + uint64_t reduce; + } conflicts; +}; + +struct kissat; + +changes kissat_changes (struct kissat *); + +bool kissat_changed (changes before, changes after); + +void kissat_init_limits (struct kissat *); + +uint64_t kissat_scale_delta (struct kissat *, const char *, uint64_t); + +double kissat_nlogpown (uint64_t, unsigned); +double kissat_sqrt (uint64_t); +double kissat_logn (uint64_t); + +#define LOGN(COUNT) kissat_logn (COUNT) +#define LINEAR(COUNT) (COUNT) +#define NLOGN(COUNT) kissat_nlogpown (COUNT, 1) +#define NLOG2N(COUNT) kissat_nlogpown (COUNT, 2) +#define NLOG3N(COUNT) kissat_nlogpown (COUNT, 3) + +#define SQRT(COUNT) kissat_sqrt (COUNT) + +#define UPDATE_CONFLICT_LIMIT(NAME, COUNT, SCALE_COUNT_FUNCTION, \ + SCALE_DELTA) \ + do { \ + if (solver->inconsistent) \ + break; \ + const struct statistics *statistics = &solver->statistics; \ + assert (statistics->COUNT > 0); \ + struct limits *limits = &solver->limits; \ + uint64_t DELTA = GET_OPTION (NAME##int); \ + const double SCALING = SCALE_COUNT_FUNCTION (statistics->COUNT); \ + assert (SCALING >= 1); \ + DELTA *= SCALING; \ + const uint64_t SCALED = \ + !(SCALE_DELTA) ? DELTA \ + : kissat_scale_delta (solver, #NAME, DELTA); \ + limits->NAME.conflicts = CONFLICTS + SCALED; \ + kissat_phase ( \ + solver, #NAME, GET (COUNT), "new limit of %s after %s conflicts", \ + FORMAT_COUNT (limits->NAME.conflicts), FORMAT_COUNT (SCALED)); \ + } while (0) + +#include + +#define SET_EFFORT_LIMIT(LIMIT, NAME, START) \ + uint64_t LIMIT; \ + do { \ + const uint64_t OLD_LIMIT = solver->statistics.START; \ + const uint64_t TICKS = solver->statistics.search_ticks; \ + const uint64_t LAST = solver->probing ? solver->last.ticks.probe \ + : solver->last.ticks.eliminate; \ + uint64_t REFERENCE = TICKS - LAST; \ + const uint64_t MINEFFORT = 1e6 * GET_OPTION (mineffort); \ + if (REFERENCE < MINEFFORT) { \ + REFERENCE = MINEFFORT; \ + kissat_extremely_verbose ( \ + solver, #NAME " effort reference %s set to 'mineffort'", \ + FORMAT_COUNT (REFERENCE)); \ + } else { \ + kissat_extremely_verbose ( \ + solver, #NAME " effort reference %s = %s - %s 'search_ticks'", \ + FORMAT_COUNT (REFERENCE), FORMAT_COUNT (TICKS), \ + FORMAT_COUNT (LAST)); \ + } \ + const double EFFORT = (double) GET_OPTION (NAME##effort) * 1e-3; \ + const uint64_t DELTA = EFFORT * REFERENCE; \ +\ + kissat_extremely_verbose ( \ + solver, #NAME " effort delta %s = %g * %s '" #START "'", \ + FORMAT_COUNT (DELTA), EFFORT, FORMAT_COUNT (REFERENCE)); \ +\ + const uint64_t NEW_LIMIT = OLD_LIMIT + DELTA; \ + kissat_very_verbose (solver, \ + #NAME " effort limit %s = %s + %s '" #START "'", \ + FORMAT_COUNT (NEW_LIMIT), \ + FORMAT_COUNT (OLD_LIMIT), FORMAT_COUNT (DELTA)); \ +\ + LIMIT = NEW_LIMIT; \ +\ + } while (0) + +struct kissat; + +bool kissat_delaying (struct kissat *, delay *); +void kissat_bump_delay (struct kissat *, delay *); +void kissat_reduce_delay (struct kissat *, delay *); + +#define DELAYING(NAME) kissat_delaying (solver, &solver->delays.NAME) + +#define BUMP_DELAY(NAME) kissat_bump_delay (solver, &solver->delays.NAME) + +#define REDUCE_DELAY(NAME) \ + kissat_reduce_delay (solver, &solver->delays.NAME) + +#endif diff --git a/src/sat/kissat/kissat.h b/src/sat/kissat/kissat.h new file mode 100644 index 000000000..eec380566 --- /dev/null +++ b/src/sat/kissat/kissat.h @@ -0,0 +1,44 @@ +#ifndef _kissat_h_INCLUDED +#define _kissat_h_INCLUDED + +typedef struct kissat kissat; + +// Default (partial) IPASIR interface. + +const char *kissat_signature (void); +kissat *kissat_init (void); +void kissat_add (kissat *solver, int lit); +int kissat_solve (kissat *solver); +int kissat_value (kissat *solver, int lit); +void kissat_release (kissat *solver); + +void kissat_set_terminate (kissat *solver, void *state, + int (*terminate) (void *state)); + +// Additional API functions. + +void kissat_terminate (kissat *solver); +void kissat_reserve (kissat *solver, int max_var); + +const char *kissat_id (void); +const char *kissat_version (void); +const char *kissat_compiler (void); + +const char **kissat_copyright (void); +void kissat_build (const char *line_prefix); +void kissat_banner (const char *line_prefix, const char *name_of_app); + +int kissat_get_option (kissat *solver, const char *name); +int kissat_set_option (kissat *solver, const char *name, int new_value); + +void kissat_set_prefix (kissat *solver, const char *prefix); + +int kissat_has_configuration (const char *name); +int kissat_set_configuration (kissat *solver, const char *name); + +void kissat_set_conflict_limit (kissat *solver, unsigned); +void kissat_set_decision_limit (kissat *solver, unsigned); + +void kissat_print_statistics (kissat *solver); + +#endif diff --git a/src/sat/kissat/kitten.c b/src/sat/kissat/kitten.c new file mode 100644 index 000000000..903230f81 --- /dev/null +++ b/src/sat/kissat/kitten.c @@ -0,0 +1,2794 @@ +#include "kitten.h" +#include "random.h" +#include "stack.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/*------------------------------------------------------------------------*/ +#ifdef STAND_ALONE_KITTEN +/*------------------------------------------------------------------------*/ + +#include + +// clang-format off + +static const char * usage = +"usage: kitten [-h]" +#ifdef LOGGING +" [-l]" +#endif +" [-n] [-O[]] [-p] [ [ ] ]\n" +"\n" +"where\n" +"\n" +#ifdef LOGGING +" -l enable low-level logging\n" +#endif +" -n do not print witness\n" +" -O[] core shrinking effort\n" +" -p produce DRAT proof\n" +" -a assume a literal\n" +" -t set time limit\n" +"\n" +"and\n" +"\n" +" input in DIMACS format (default '')\n" +" DRAT proof or clausal core file\n" +; + +// clang-format on + +// Replacement for 'kissat' allocators in the stand alone variant. + +typedef signed char value; + +static void die (const char *fmt, ...) { + fputs ("kitten: error: ", stderr); + va_list ap; + va_start (ap, fmt); + vfprintf (stderr, fmt, ap); + va_end (ap); + fputc ('\n', stderr); + exit (1); +} + +static inline void *kitten_calloc (size_t n, size_t size) { + void *res = calloc (n, size); + if (n && size && !res) + die ("out of memory allocating '%zu * %zu' bytes", n, size); + return res; +} + +#define CALLOC(P, N) \ + do { \ + (P) = kitten_calloc (N, sizeof *(P)); \ + } while (0) +#define DEALLOC(P, N) free (P) + +#undef ENLARGE_STACK + +#define ENLARGE_STACK(S) \ + do { \ + assert (FULL_STACK (S)); \ + const size_t SIZE = SIZE_STACK (S); \ + const size_t OLD_CAPACITY = CAPACITY_STACK (S); \ + const size_t NEW_CAPACITY = OLD_CAPACITY ? 2 * OLD_CAPACITY : 1; \ + const size_t BYTES = NEW_CAPACITY * sizeof *(S).begin; \ + (S).begin = realloc ((S).begin, BYTES); \ + if (!(S).begin) \ + die ("out of memory reallocating '%zu' bytes", BYTES); \ + (S).allocated = (S).begin + NEW_CAPACITY; \ + (S).end = (S).begin + SIZE; \ + } while (0) + +// Beside allocators above also use stand alone statistics counters. + +#define INC(NAME) \ + do { \ + statistics *statistics = &kitten->statistics; \ + assert (statistics->NAME < UINT64_MAX); \ + statistics->NAME++; \ + } while (0) + +#define ADD(NAME, DELTA) \ + do { \ + statistics *statistics = &kitten->statistics; \ + assert (statistics->NAME <= UINT64_MAX - (DELTA)); \ + statistics->NAME += (DELTA); \ + } while (0) + +#define KITTEN_TICKS (kitten->statistics.kitten_ticks) + +/*------------------------------------------------------------------------*/ +#else // '#ifdef STAND_ALONE_KITTEN' +/*------------------------------------------------------------------------*/ + +#include "allocate.h" // Use 'kissat' allocator if embedded. +#include "error.h" // Use 'kissat_fatal' if embedded. +#include "internal.h" // Also use 'kissat' statistics if embedded. +#include "terminate.h" // For macros defining termination macro. + +#define KITTEN_TICKS (solver->statistics.kitten_ticks) + +/*------------------------------------------------------------------------*/ +#endif // STAND_ALONE_KITTEN +/*------------------------------------------------------------------------*/ + +#define INVALID UINT_MAX +#define MAX_VARS ((1u << 31) - 1) + +#define CORE_FLAG (1u) +#define LEARNED_FLAG (2u) + +// clang-format off + +typedef struct kar kar; +typedef struct kink kink; +typedef struct klause klause; +typedef struct katch katch; +typedef STACK (unsigned) klauses; +typedef STACK (katch) katches; + +// clang-format on + +struct kar { + unsigned level; + unsigned reason; +}; + +struct kink { + unsigned next; + unsigned prev; + uint64_t stamp; +}; + +#define KITTEN_BLIT + +#ifdef KITTEN_BLIT + +struct katch { + unsigned blit; + unsigned ref : 31; + bool binary : 1; +}; + +#else + +struct katch { + unsigned ref; +}; + +#endif + +struct klause { + unsigned aux; + unsigned size; + unsigned flags; + unsigned lits[1]; +}; + +#ifdef STAND_ALONE_KITTEN + +typedef struct statistics statistics; + +struct statistics { + uint64_t learned; + uint64_t original; + uint64_t kitten_flip; + uint64_t kitten_flipped; + uint64_t kitten_sat; + uint64_t kitten_solve; + uint64_t kitten_solved; + uint64_t kitten_conflicts; + uint64_t kitten_decisions; + uint64_t kitten_propagations; + uint64_t kitten_ticks; + uint64_t kitten_unknown; + uint64_t kitten_unsat; +}; + +#endif + +typedef struct kimits kimits; + +struct kimits { + uint64_t ticks; +}; + +struct kitten { +#ifndef STAND_ALONE_KITTEN + struct kissat *kissat; +#define solver (kitten->kissat) +#endif + + // First zero initialized field in 'clear_kitten' is 'status'. + // + int status; + +#if defined(STAND_ALONE_KITTEN) && defined(LOGGING) + bool logging; +#endif + bool antecedents; + bool learned; + + unsigned level; + unsigned propagated; + unsigned unassigned; + unsigned inconsistent; + unsigned failing; + + uint64_t generator; + + size_t lits; + size_t evars; + + size_t end_original_ref; + + struct { + unsigned first, last; + uint64_t stamp; + unsigned search; + } queue; + + // The 'size' field below is the first not zero reinitialized field + // by 'memset' in 'clear_kitten' (after 'kissat'). + + size_t size; + size_t esize; + + kar *vars; + kink *links; + value *marks; + value *values; + bool *failed; + unsigned char *phases; + unsigned *import; + katches *watches; + + unsigneds analyzed; + unsigneds assumptions; + unsigneds core; + unsigneds eclause; + unsigneds export; + unsigneds klause; + unsigneds klauses; + unsigneds resolved; + unsigneds trail; + unsigneds units; + + kimits limits; + uint64_t initialized; + +#ifdef STAND_ALONE_KITTEN + statistics statistics; +#endif +}; + +/*------------------------------------------------------------------------*/ + +static inline bool is_core_klause (klause *c) { + return c->flags & CORE_FLAG; +} + +static inline bool is_learned_klause (klause *c) { + return c->flags & LEARNED_FLAG; +} + +static inline void set_core_klause (klause *c) { c->flags |= CORE_FLAG; } + +static inline void unset_core_klause (klause *c) { c->flags &= ~CORE_FLAG; } + +static inline klause *dereference_klause (kitten *kitten, unsigned ref) { + unsigned *res = BEGIN_STACK (kitten->klauses) + ref; + assert (res < END_STACK (kitten->klauses)); + return (klause *) res; +} + +#ifdef LOGGING + +static inline unsigned reference_klause (kitten *kitten, const klause *c) { + const unsigned *const begin = BEGIN_STACK (kitten->klauses); + const unsigned *p = (const unsigned *) c; + assert (begin <= p); + assert (p < END_STACK (kitten->klauses)); + const unsigned res = p - begin; + return res; +} + +#endif + +/*------------------------------------------------------------------------*/ + +#define KATCHES(KIT) (kitten->watches[assert ((KIT) < kitten->lits), (KIT)]) + +#define all_klauses(C) \ + klause *C = begin_klauses (kitten), *end_##C = end_klauses (kitten); \ + (C) != end_##C; \ + (C) = next_klause (kitten, C) + +#define all_original_klauses(C) \ + klause *C = begin_klauses (kitten), \ + *end_##C = end_original_klauses (kitten); \ + (C) != end_##C; \ + (C) = next_klause (kitten, C) + +#define all_learned_klauses(C) \ + klause *C = begin_learned_klauses (kitten), \ + *end_##C = end_klauses (kitten); \ + (C) != end_##C; \ + (C) = next_klause (kitten, C) + +#define all_kits(KIT) \ + size_t KIT = 0, KIT_##END = kitten->lits; \ + KIT != KIT_##END; \ + KIT++ + +#define BEGIN_KLAUSE(C) (C)->lits + +#define END_KLAUSE(C) (BEGIN_KLAUSE (C) + (C)->size) + +#define all_literals_in_klause(KIT, C) \ + unsigned KIT, *KIT##_PTR = BEGIN_KLAUSE (C), \ + *KIT##_END = END_KLAUSE (C); \ + KIT##_PTR != KIT##_END && ((KIT = *KIT##_PTR), true); \ + ++KIT##_PTR + +#define all_antecedents(REF, C) \ + unsigned REF, *REF##_PTR = antecedents (C), \ + *REF##_END = REF##_PTR + (C)->aux; \ + REF##_PTR != REF##_END && ((REF = *REF##_PTR), true); \ + ++REF##_PTR + +#ifdef LOGGING + +#ifdef STAND_ALONE_KITTEN +#define logging (kitten->logging) +#else +#define logging GET_OPTION (log) +#endif + +static void log_basic (kitten *, const char *, ...) + __attribute__ ((format (printf, 2, 3))); + +static void log_basic (kitten *kitten, const char *fmt, ...) { + assert (logging); + printf ("c KITTEN %u ", kitten->level); + va_list ap; + va_start (ap, fmt); + vprintf (fmt, ap); + va_end (ap); + fputc ('\n', stdout); + fflush (stdout); +} + +static void log_reference (kitten *, unsigned, const char *, ...) + __attribute__ ((format (printf, 3, 4))); + +static void log_reference (kitten *kitten, unsigned ref, const char *fmt, + ...) { + klause *c = dereference_klause (kitten, ref); + assert (logging); + printf ("c KITTEN %u ", kitten->level); + va_list ap; + va_start (ap, fmt); + vprintf (fmt, ap); + va_end (ap); + if (is_learned_klause (c)) { + fputs (" learned", stdout); + if (c->aux) + printf ("[%u]", c->aux); + } else { + fputs (" original", stdout); + if (c->aux != INVALID) + printf ("[%u]", c->aux); + } + printf (" size %u clause[%u]", c->size, ref); + value *values = kitten->values; + kar *vars = kitten->vars; + for (all_literals_in_klause (lit, c)) { + printf (" %u", lit); + const value value = values[lit]; + if (value) + printf ("@%u=%d", vars[lit / 2].level, (int) value); + } + fputc ('\n', stdout); + fflush (stdout); +} + +#define LOG(...) \ + do { \ + if (logging) \ + log_basic (kitten, __VA_ARGS__); \ + } while (0) + +#define ROG(...) \ + do { \ + if (logging) \ + log_reference (kitten, __VA_ARGS__); \ + } while (0) + +#else + +#define LOG(...) \ + do { \ + } while (0) +#define ROG(...) \ + do { \ + } while (0) + +#endif + +static void check_queue (kitten *kitten) { +#ifdef CHECK_KITTEN + const unsigned vars = kitten->lits / 2; + unsigned found = 0, prev = INVALID; + kink *links = kitten->links; + uint64_t stamp = 0; + for (unsigned idx = kitten->queue.first, next; idx != INVALID; + idx = next) { + kink *link = links + idx; + assert (link->prev == prev); + assert (!found || stamp < link->stamp); + assert (link->stamp < kitten->queue.stamp); + stamp = link->stamp; + next = link->next; + prev = idx; + found++; + } + assert (found == vars); + unsigned next = INVALID; + found = 0; + for (unsigned idx = kitten->queue.last, prev; idx != INVALID; + idx = prev) { + kink *link = links + idx; + assert (link->next == next); + prev = link->prev; + next = idx; + found++; + } + assert (found == vars); + value *values = kitten->values; + bool first = true; + for (unsigned idx = kitten->queue.search, next; idx != INVALID; + idx = next) { + kink *link = links + idx; + next = link->next; + const unsigned lit = 2 * idx; + assert (first || values[lit]); + first = false; + } +#else + (void) kitten; +#endif +} + +static void update_search (kitten *kitten, unsigned idx) { + if (kitten->queue.search == idx) + return; + kitten->queue.search = idx; + LOG ("search updated to %u stamped %" PRIu64, idx, + kitten->links[idx].stamp); +} + +static void enqueue (kitten *kitten, unsigned idx) { + LOG ("enqueue %u", idx); + kink *links = kitten->links; + kink *l = links + idx; + const unsigned last = kitten->queue.last; + if (last == INVALID) + kitten->queue.first = idx; + else + links[last].next = idx; + l->prev = last; + l->next = INVALID; + kitten->queue.last = idx; + l->stamp = kitten->queue.stamp++; + LOG ("stamp %" PRIu64, l->stamp); +} + +static void dequeue (kitten *kitten, unsigned idx) { + LOG ("dequeue %u", idx); + kink *links = kitten->links; + kink *l = links + idx; + const unsigned prev = l->prev; + const unsigned next = l->next; + if (prev == INVALID) + kitten->queue.first = next; + else + links[prev].next = next; + if (next == INVALID) + kitten->queue.last = prev; + else + links[next].prev = prev; +} + +static void init_queue (kitten *kitten, size_t old_vars, size_t new_vars) { + for (size_t idx = old_vars; idx < new_vars; idx++) { + assert (!kitten->values[2 * idx]); + assert (kitten->unassigned < UINT_MAX); + kitten->unassigned++; + enqueue (kitten, idx); + } + LOG ("initialized decision queue from %zu to %zu", old_vars, new_vars); + update_search (kitten, kitten->queue.last); + check_queue (kitten); +} + +static void initialize_kitten (kitten *kitten) { + kitten->queue.first = INVALID; + kitten->queue.last = INVALID; + kitten->inconsistent = INVALID; + kitten->failing = INVALID; + kitten->queue.search = INVALID; + kitten->limits.ticks = UINT64_MAX; + kitten->generator = kitten->initialized++; +} + +static void clear_kitten (kitten *kitten) { + size_t bytes = (char *) &kitten->size - (char *) &kitten->status; + memset (&kitten->status, 0, bytes); +#ifdef STAND_ALONE_KITTEN + memset (&kitten->statistics, 0, sizeof (statistics)); +#endif + initialize_kitten (kitten); +} + +#define RESIZE1(P) \ + do { \ + void *OLD_PTR = (P); \ + CALLOC ((P), new_size / 2); \ + const size_t BYTES = old_vars * sizeof *(P); \ + if (BYTES) \ + memcpy ((P), OLD_PTR, BYTES); \ + void *NEW_PTR = (P); \ + (P) = OLD_PTR; \ + DEALLOC ((P), old_size / 2); \ + (P) = NEW_PTR; \ + } while (0) + +#define RESIZE2(P) \ + do { \ + void *OLD_PTR = (P); \ + CALLOC ((P), new_size); \ + const size_t BYTES = old_lits * sizeof *(P); \ + if (BYTES) \ + memcpy ((P), OLD_PTR, BYTES); \ + void *NEW_PTR = (P); \ + (P) = OLD_PTR; \ + DEALLOC ((P), old_size); \ + (P) = NEW_PTR; \ + } while (0) + +static void enlarge_internal (kitten *kitten, size_t new_lits) { + const size_t old_lits = kitten->lits; + assert (old_lits < new_lits); + const size_t old_size = kitten->size; + const unsigned new_vars = new_lits / 2; + const unsigned old_vars = old_lits / 2; + if (old_size < new_lits) { + size_t new_size = old_size ? 2 * old_size : 2; + while (new_size <= new_lits) + new_size *= 2; + LOG ("internal literals resized to %zu from %zu (requested %zu)", + new_size, old_size, new_lits); + + RESIZE1 (kitten->marks); + RESIZE1 (kitten->phases); + RESIZE2 (kitten->values); + RESIZE2 (kitten->failed); + RESIZE1 (kitten->vars); + RESIZE1 (kitten->links); + RESIZE2 (kitten->watches); + + kitten->size = new_size; + } + kitten->lits = new_lits; + init_queue (kitten, old_vars, new_vars); + LOG ("internal literals activated until %zu literals", new_lits); + return; +} + +static const char *status_to_string (int status) { + switch (status) { + case 10: + return "formula satisfied"; + case 20: + return "formula inconsistent"; + case 21: + return "formula inconsistent and core computed"; + default: + assert (!status); + return "formula unsolved"; + } +} + +static void invalid_api_usage (const char *fun, const char *fmt, ...) { + fprintf (stderr, "kitten: fatal error: invalid API usage in '%s': ", fun); + va_list ap; + va_start (ap, fmt); + vfprintf (stderr, fmt, ap); + va_end (ap); + fputc ('\n', stderr); + fflush (stderr); + abort (); +} + +#define INVALID_API_USAGE(...) invalid_api_usage (__func__, __VA_ARGS__) + +#define REQUIRE_INITIALIZED() \ + do { \ + if (!kitten) \ + INVALID_API_USAGE ("solver argument zero"); \ + } while (0) + +#define REQUIRE_STATUS(EXPECTED) \ + do { \ + REQUIRE_INITIALIZED (); \ + if (kitten->status != (EXPECTED)) \ + INVALID_API_USAGE ("invalid status '%s' (expected '%s')", \ + status_to_string (kitten->status), \ + status_to_string (EXPECTED)); \ + } while (0) + +#define UPDATE_STATUS(STATUS) \ + do { \ + if (kitten->status != (STATUS)) \ + LOG ("updating status from '%s' to '%s'", \ + status_to_string (kitten->status), status_to_string (STATUS)); \ + else \ + LOG ("keeping status at '%s'", status_to_string (STATUS)); \ + kitten->status = (STATUS); \ + } while (0) + +#ifdef STAND_ALONE_KITTEN + +kitten *kitten_init (void) { + kitten *kitten; + CALLOC (kitten, 1); + initialize_kitten (kitten); + return kitten; +} + +#else + +kitten *kitten_embedded (struct kissat *kissat) { + if (!kissat) + INVALID_API_USAGE ("'kissat' argument zero"); + + kitten *kitten; + struct kitten dummy; + dummy.kissat = kissat; + kitten = &dummy; + CALLOC (kitten, 1); + kitten->kissat = kissat; + initialize_kitten (kitten); + return kitten; +} + +#endif + +void kitten_track_antecedents (kitten *kitten) { + REQUIRE_STATUS (0); + + if (kitten->learned) + INVALID_API_USAGE ("can not start tracking antecedents after learning"); + + LOG ("enabling antecedents tracking"); + kitten->antecedents = true; +} + +void kitten_randomize_phases (kitten *kitten) { + REQUIRE_INITIALIZED (); + + LOG ("randomizing phases"); + + unsigned char *phases = kitten->phases; + const unsigned vars = kitten->size / 2; + + uint64_t random = kissat_next_random64 (&kitten->generator); + + unsigned i = 0; + const unsigned rest = vars & ~63u; + + while (i != rest) { + uint64_t *p = (uint64_t *) (phases + i); + p[0] = (random >> 0) & 0x0101010101010101; + p[1] = (random >> 1) & 0x0101010101010101; + p[2] = (random >> 2) & 0x0101010101010101; + p[3] = (random >> 3) & 0x0101010101010101; + p[4] = (random >> 4) & 0x0101010101010101; + p[5] = (random >> 5) & 0x0101010101010101; + p[6] = (random >> 6) & 0x0101010101010101; + p[7] = (random >> 7) & 0x0101010101010101; + random = kissat_next_random64 (&kitten->generator); + i += 64; + } + + unsigned shift = 0; + while (i != vars) + phases[i++] = (random >> shift++) & 1; +} + +void kitten_flip_phases (kitten *kitten) { + REQUIRE_INITIALIZED (); + + LOG ("flipping phases"); + + unsigned char *phases = kitten->phases; + const unsigned vars = kitten->size / 2; + + unsigned i = 0; + const unsigned rest = vars & ~7u; + + while (i != rest) { + uint64_t *p = (uint64_t *) (phases + i); + *p ^= 0x0101010101010101; + i += 8; + } + + while (i != vars) + phases[i++] ^= 1; +} + +void kitten_no_ticks_limit (kitten *kitten) { + REQUIRE_INITIALIZED (); + LOG ("forcing no ticks limit"); + kitten->limits.ticks = UINT64_MAX; +} + +void kitten_set_ticks_limit (kitten *kitten, uint64_t delta) { + REQUIRE_INITIALIZED (); + const uint64_t current = KITTEN_TICKS; + uint64_t limit; + if (UINT64_MAX - delta <= current) { + LOG ("forcing unlimited ticks limit"); + limit = UINT64_MAX; + } else { + limit = current + delta; + LOG ("new limit of %" PRIu64 " ticks after %" PRIu64, limit, delta); + } + + kitten->limits.ticks = limit; +} + +static void shuffle_unsigned_array (kitten *kitten, size_t size, + unsigned *a) { + for (size_t i = 0; i != size; i++) { + const size_t j = kissat_pick_random (&kitten->generator, 0, i); + if (j == i) + continue; + const unsigned first = a[i]; + const unsigned second = a[j]; + a[i] = second; + a[j] = first; + } +} + +static void shuffle_unsigned_stack (kitten *kitten, unsigneds *stack) { + const size_t size = SIZE_STACK (*stack); + unsigned *a = BEGIN_STACK (*stack); + shuffle_unsigned_array (kitten, size, a); +} + +static void shuffle_katches_array (kitten *kitten, size_t size, katch *a) { + for (size_t i = 0; i != size; i++) { + const size_t j = kissat_pick_random (&kitten->generator, 0, i); + if (j == i) + continue; + const katch first = a[i]; + const katch second = a[j]; + a[i] = second; + a[j] = first; + } +} + +static void shuffle_katches_stack (kitten *kitten, katches *stack) { + const size_t size = SIZE_STACK (*stack); + katch *a = BEGIN_STACK (*stack); + shuffle_katches_array (kitten, size, a); +} + +static void shuffle_katches (kitten *kitten) { + LOG ("shuffling watch lists"); + const size_t lits = kitten->lits; + for (size_t lit = 0; lit != lits; lit++) + shuffle_katches_stack (kitten, &KATCHES (lit)); +} + +static void shuffle_queue (kitten *kitten) { + LOG ("shuffling variable decision order"); + + const unsigned vars = kitten->lits / 2; + for (unsigned i = 0; i != vars; i++) { + const unsigned idx = kissat_pick_random (&kitten->generator, 0, vars); + dequeue (kitten, idx); + enqueue (kitten, idx); + } + update_search (kitten, kitten->queue.last); +} + +static void shuffle_units (kitten *kitten) { + LOG ("shuffling units"); + shuffle_unsigned_stack (kitten, &kitten->units); +} + +void kitten_shuffle_clauses (kitten *kitten) { + REQUIRE_STATUS (0); + shuffle_queue (kitten); + shuffle_katches (kitten); + shuffle_units (kitten); +} + +static inline unsigned *antecedents (klause *c) { + assert (is_learned_klause (c)); + return c->lits + c->size; +} + +static inline void watch_klause (kitten *kitten, unsigned lit, klause *c, + unsigned ref) { + ROG (ref, "watching %u in", lit); + katches *watches = &KATCHES (lit); + katch katch; + katch.ref = ref; +#ifdef KITTEN_BLIT + const unsigned size = c->size; + assert (lit == c->lits[0] || lit == c->lits[1]); + const unsigned blit = c->lits[0] ^ c->lits[1] ^ lit; + const bool binary = size == 2; + assert (size > 1); + assert (ref < (1u << 31)); + katch.blit = blit; + katch.binary = binary; +#else + (void) c; +#endif + PUSH_STACK (*watches, katch); +} + +static inline void connect_new_klause (kitten *kitten, unsigned ref) { + ROG (ref, "new"); + + klause *c = dereference_klause (kitten, ref); + + if (!c->size) { + if (kitten->inconsistent == INVALID) { + ROG (ref, "registering inconsistent empty"); + kitten->inconsistent = ref; + } else + ROG (ref, "ignoring inconsistent empty"); + } else if (c->size == 1) { + ROG (ref, "watching unit"); + PUSH_STACK (kitten->units, ref); + } else { + watch_klause (kitten, c->lits[0], c, ref); + watch_klause (kitten, c->lits[1], c, ref); + } +} + +static unsigned new_reference (kitten *kitten) { + size_t ref = SIZE_STACK (kitten->klauses); + if (ref >= INVALID) { +#ifdef STAND_ALONE_KITTEN + die ("maximum number of literals exhausted"); +#else + kissat_fatal ("kitten: maximum number of literals exhausted"); +#endif + } + const unsigned res = (unsigned) ref; + assert (res != INVALID); + INC (kitten_ticks); + return res; +} + +static void new_original_klause (kitten *kitten, unsigned id) { + unsigned res = new_reference (kitten); + unsigned size = SIZE_STACK (kitten->klause); + unsigneds *klauses = &kitten->klauses; + PUSH_STACK (*klauses, id); + PUSH_STACK (*klauses, size); + PUSH_STACK (*klauses, 0); + for (all_stack (unsigned, lit, kitten->klause)) + PUSH_STACK (*klauses, lit); + connect_new_klause (kitten, res); + kitten->end_original_ref = SIZE_STACK (*klauses); +#ifdef STAND_ALONE_KITTEN + kitten->statistics.original++; +#endif +} + +static void enlarge_external (kitten *kitten, size_t eidx) { + const size_t old_size = kitten->esize; + const unsigned old_evars = kitten->evars; + assert (old_evars <= eidx); + const unsigned new_evars = eidx + 1; + if (old_size <= eidx) { + size_t new_size = old_size ? 2 * old_size : 1; + while (new_size <= eidx) + new_size *= 2; + LOG ("external resizing to %zu variables from %zu (requested %u)", + new_size, old_size, new_evars); + unsigned *old_import = kitten->import; + CALLOC (kitten->import, new_size); + const size_t bytes = old_evars * sizeof *kitten->import; + if (bytes) + memcpy (kitten->import, old_import, bytes); + DEALLOC (old_import, old_size); + kitten->esize = new_size; + } + kitten->evars = new_evars; + LOG ("external variables enlarged to %u", new_evars); +} + +static unsigned import_literal (kitten *kitten, unsigned elit) { + const unsigned eidx = elit / 2; + if (eidx >= kitten->evars) + enlarge_external (kitten, eidx); + + unsigned iidx = kitten->import[eidx]; + if (!iidx) { + iidx = SIZE_STACK (kitten->export); + PUSH_STACK (kitten->export, eidx); + kitten->import[eidx] = iidx + 1; + } else + iidx--; + unsigned ilit = 2 * iidx + (elit & 1); + LOG ("imported external literal %u as internal literal %u", elit, ilit); + const size_t new_lits = (ilit | 1) + (size_t) 1; + assert (ilit < new_lits); + assert (ilit / 2 < new_lits / 2); + if (new_lits > kitten->lits) + enlarge_internal (kitten, new_lits); + return ilit; +} + +static unsigned export_literal (kitten *kitten, unsigned ilit) { + const unsigned iidx = ilit / 2; + assert (iidx < SIZE_STACK (kitten->export)); + const unsigned eidx = PEEK_STACK (kitten->export, iidx); + const unsigned elit = 2 * eidx + (ilit & 1); + return elit; +} + +unsigned new_learned_klause (kitten *kitten) { + unsigned res = new_reference (kitten); + unsigneds *klauses = &kitten->klauses; + const size_t size = SIZE_STACK (kitten->klause); + assert (size <= UINT_MAX); + const size_t aux = + kitten->antecedents ? SIZE_STACK (kitten->resolved) : 0; + assert (aux <= UINT_MAX); + PUSH_STACK (*klauses, (unsigned) aux); + PUSH_STACK (*klauses, (unsigned) size); + PUSH_STACK (*klauses, LEARNED_FLAG); + for (all_stack (unsigned, lit, kitten->klause)) + PUSH_STACK (*klauses, lit); + if (aux) + for (all_stack (unsigned, ref, kitten->resolved)) + PUSH_STACK (*klauses, ref); + connect_new_klause (kitten, res); + kitten->learned = true; +#ifdef STAND_ALONE_KITTEN + kitten->statistics.learned++; +#endif + return res; +} + +void kitten_clear (kitten *kitten) { + LOG ("clear kitten of size %zu", kitten->size); + + assert (EMPTY_STACK (kitten->analyzed)); + assert (EMPTY_STACK (kitten->klause)); + assert (EMPTY_STACK (kitten->eclause)); + assert (EMPTY_STACK (kitten->resolved)); + + CLEAR_STACK (kitten->assumptions); + CLEAR_STACK (kitten->core); + CLEAR_STACK (kitten->klause); + CLEAR_STACK (kitten->klauses); + CLEAR_STACK (kitten->trail); + CLEAR_STACK (kitten->units); + + for (all_kits (kit)) + CLEAR_STACK (KATCHES (kit)); + + while (!EMPTY_STACK (kitten->export)) + kitten->import[POP_STACK (kitten->export)] = 0; + + const size_t lits = kitten->size; + const unsigned vars = lits / 2; + +#ifndef NDEBUG + for (unsigned i = 0; i < vars; i++) + assert (!kitten->marks[i]); +#endif + + if (vars) { + memset (kitten->phases, 0, vars); + memset (kitten->vars, 0, vars); + } + + if (lits) { + memset (kitten->values, 0, lits); + memset (kitten->failed, 0, lits); + } + + clear_kitten (kitten); +} + +void kitten_release (kitten *kitten) { + RELEASE_STACK (kitten->analyzed); + RELEASE_STACK (kitten->assumptions); + RELEASE_STACK (kitten->core); + RELEASE_STACK (kitten->eclause); + RELEASE_STACK (kitten->export); + RELEASE_STACK (kitten->klause); + RELEASE_STACK (kitten->klauses); + RELEASE_STACK (kitten->resolved); + RELEASE_STACK (kitten->trail); + RELEASE_STACK (kitten->units); + + for (size_t lit = 0; lit < kitten->size; lit++) + RELEASE_STACK (kitten->watches[lit]); + +#ifndef STAND_ALONE_KITTEN + const size_t lits = kitten->size; + const unsigned vars = lits / 2; +#endif + DEALLOC (kitten->marks, vars); + DEALLOC (kitten->phases, vars); + DEALLOC (kitten->values, lits); + DEALLOC (kitten->failed, lits); + DEALLOC (kitten->vars, vars); + DEALLOC (kitten->links, vars); + DEALLOC (kitten->watches, lits); + DEALLOC (kitten->import, kitten->esize); +#ifdef STAND_ALONE_KITTEN + free (kitten); +#else + kissat_free (kitten->kissat, kitten, sizeof *kitten); +#endif +} + +static inline void move_to_front (kitten *kitten, unsigned idx) { + if (idx == kitten->queue.last) + return; + LOG ("move to front variable %u", idx); + dequeue (kitten, idx); + enqueue (kitten, idx); + assert (kitten->values[2 * idx]); +} + +static inline void assign (kitten *kitten, unsigned lit, unsigned reason) { +#ifdef LOGGING + if (reason == INVALID) + LOG ("assign %u as decision", lit); + else + ROG (reason, "assign %u reason", lit); +#endif + value *values = kitten->values; + const unsigned not_lit = lit ^ 1; + assert (!values[lit]); + assert (!values[not_lit]); + values[lit] = 1; + values[not_lit] = -1; + const unsigned idx = lit / 2; + const unsigned sign = lit & 1; + kitten->phases[idx] = sign; + PUSH_STACK (kitten->trail, lit); + kar *v = kitten->vars + idx; + v->level = kitten->level; + if (!v->level) { + assert (reason != INVALID); + klause *c = dereference_klause (kitten, reason); + if (c->size > 1) { + if (kitten->antecedents) { + PUSH_STACK (kitten->resolved, reason); + for (all_literals_in_klause (other, c)) + if (other != lit) { + const unsigned other_idx = other / 2; + const unsigned other_ref = kitten->vars[other_idx].reason; + assert (other_ref != INVALID); + PUSH_STACK (kitten->resolved, other_ref); + } + } + PUSH_STACK (kitten->klause, lit); + reason = new_learned_klause (kitten); + CLEAR_STACK (kitten->resolved); + CLEAR_STACK (kitten->klause); + } + } + v->reason = reason; + assert (kitten->unassigned); + kitten->unassigned--; +} + +static inline unsigned propagate_literal (kitten *kitten, unsigned lit) { + LOG ("propagating %u", lit); + value *values = kitten->values; + assert (values[lit] > 0); + const unsigned not_lit = lit ^ 1; + katches *watches = kitten->watches + not_lit; + unsigned conflict = INVALID; + katch *q = BEGIN_STACK (*watches); + const katch *const end_watches = END_STACK (*watches); + katch const *p = q; + uint64_t ticks = (((char *) end_watches - (char *) q) >> 7) + 1; + while (p != end_watches) { + katch katch = *q++ = *p++; + const unsigned ref = katch.ref; +#ifdef KITTEN_BLIT + const unsigned blit = katch.blit; + assert (blit != not_lit); + const value blit_value = values[blit]; + if (blit_value > 0) + continue; + if (katch.binary) { + if (blit_value < 0) { + ROG (ref, "conflict"); + INC (kitten_conflicts); + conflict = ref; + break; + } else { + assert (!blit_value); + assign (kitten, blit, ref); + continue; + } + } +#endif + klause *c = dereference_klause (kitten, ref); + assert (c->size > 1); + unsigned *lits = c->lits; + const unsigned other = lits[0] ^ lits[1] ^ not_lit; + const value other_value = values[other]; + ticks++; + if (other_value > 0) { +#ifdef KITTEN_BLIT + q[-1].blit = other; +#endif + continue; + } + value replacement_value = -1; + unsigned replacement = INVALID; + const unsigned *const end_lits = lits + c->size; + unsigned *r; + for (r = lits + 2; r != end_lits; r++) { + replacement = *r; + replacement_value = values[replacement]; + if (replacement_value >= 0) + break; + } + if (replacement_value >= 0) { + assert (replacement != INVALID); + ROG (ref, "unwatching %u in", not_lit); + lits[0] = other; + lits[1] = replacement; + *r = not_lit; + watch_klause (kitten, replacement, c, ref); + q--; + } else if (other_value < 0) { + ROG (ref, "conflict"); + INC (kitten_conflicts); + conflict = ref; + break; + } else { + assert (!other_value); + assign (kitten, other, ref); + } + } + while (p != end_watches) + *q++ = *p++; + SET_END_OF_STACK (*watches, q); + ADD (kitten_ticks, ticks); + return conflict; +} + +static inline unsigned propagate (kitten *kitten) { + assert (kitten->inconsistent == INVALID); + unsigned propagated = 0; + unsigned conflict = INVALID; + while (conflict == INVALID && + kitten->propagated < SIZE_STACK (kitten->trail)) { + const unsigned lit = PEEK_STACK (kitten->trail, kitten->propagated); + conflict = propagate_literal (kitten, lit); + kitten->propagated++; + propagated++; + } + ADD (kitten_propagations, propagated); + return conflict; +} + +static void bump (kitten *kitten) { + value *marks = kitten->marks; + for (all_stack (unsigned, idx, kitten->analyzed)) { + marks[idx] = 0; + move_to_front (kitten, idx); + } + check_queue (kitten); +} + +static inline void unassign (kitten *kitten, value *values, unsigned lit) { + const unsigned not_lit = lit ^ 1; + assert (values[lit]); + assert (values[not_lit]); + const unsigned idx = lit / 2; +#ifdef LOGGING + kar *var = kitten->vars + idx; + kitten->level = var->level; + LOG ("unassign %u", lit); +#endif + values[lit] = values[not_lit] = 0; + assert (kitten->unassigned < kitten->lits / 2); + kitten->unassigned++; + kink *links = kitten->links; + kink *link = links + idx; + if (link->stamp > links[kitten->queue.search].stamp) + update_search (kitten, idx); +} + +static void backtrack (kitten *kitten, unsigned jump) { + check_queue (kitten); + assert (jump < kitten->level); + LOG ("back%s to level %u", + (kitten->level == jump + 1 ? "tracking" : "jumping"), jump); + kar *vars = kitten->vars; + value *values = kitten->values; + unsigneds *trail = &kitten->trail; + while (!EMPTY_STACK (*trail)) { + const unsigned lit = TOP_STACK (*trail); + const unsigned idx = lit / 2; + const unsigned level = vars[idx].level; + if (level == jump) + break; + (void) POP_STACK (*trail); + unassign (kitten, values, lit); + } + kitten->propagated = SIZE_STACK (*trail); + kitten->level = jump; + check_queue (kitten); +} + +void completely_backtrack_to_root_level (kitten *kitten) { + check_queue (kitten); + LOG ("completely backtracking to level 0"); + value *values = kitten->values; + unsigneds *trail = &kitten->trail; +#ifndef NDEBUG + kar *vars = kitten->vars; +#endif + for (all_stack (unsigned, lit, *trail)) { + assert (vars[lit / 2].level); + unassign (kitten, values, lit); + } + CLEAR_STACK (*trail); + kitten->propagated = 0; + kitten->level = 0; + check_queue (kitten); +} + +static void analyze (kitten *kitten, unsigned conflict) { + assert (kitten->level); + assert (kitten->inconsistent == INVALID); + assert (EMPTY_STACK (kitten->analyzed)); + assert (EMPTY_STACK (kitten->resolved)); + assert (EMPTY_STACK (kitten->klause)); + PUSH_STACK (kitten->klause, INVALID); + unsigned reason = conflict; + value *marks = kitten->marks; + const kar *const vars = kitten->vars; + const unsigned level = kitten->level; + unsigned const *p = END_STACK (kitten->trail); + unsigned open = 0, jump = 0, size = 1, uip; + for (;;) { + assert (reason != INVALID); + klause *c = dereference_klause (kitten, reason); + assert (c); + ROG (reason, "analyzing"); + PUSH_STACK (kitten->resolved, reason); + for (all_literals_in_klause (lit, c)) { + const unsigned idx = lit / 2; + if (marks[idx]) + continue; + assert (kitten->values[lit] < 0); + LOG ("analyzed %u", lit); + marks[idx] = true; + PUSH_STACK (kitten->analyzed, idx); + const kar *const v = vars + idx; + const unsigned tmp = v->level; + if (tmp < level) { + if (tmp > jump) { + jump = tmp; + if (size > 1) { + const unsigned other = PEEK_STACK (kitten->klause, 1); + POKE_STACK (kitten->klause, 1, lit); + lit = other; + } + } + PUSH_STACK (kitten->klause, lit); + size++; + } else + open++; + } + unsigned idx; + do { + assert (BEGIN_STACK (kitten->trail) < p); + uip = *--p; + } while (!marks[idx = uip / 2]); + assert (open); + if (!--open) + break; + reason = vars[idx].reason; + } + const unsigned not_uip = uip ^ 1; + LOG ("first UIP %u jump level %u size %u", not_uip, jump, size); + POKE_STACK (kitten->klause, 0, not_uip); + bump (kitten); + CLEAR_STACK (kitten->analyzed); + const unsigned learned_ref = new_learned_klause (kitten); + CLEAR_STACK (kitten->resolved); + CLEAR_STACK (kitten->klause); + backtrack (kitten, jump); + assign (kitten, not_uip, learned_ref); +} + +static void failing (kitten *kitten) { + assert (kitten->inconsistent == INVALID); + assert (!EMPTY_STACK (kitten->assumptions)); + assert (EMPTY_STACK (kitten->analyzed)); + assert (EMPTY_STACK (kitten->resolved)); + assert (EMPTY_STACK (kitten->klause)); + LOG ("analyzing failing assumptions"); + const value *const values = kitten->values; + const kar *const vars = kitten->vars; + unsigned failed_clashing = INVALID; + unsigned first_failed = INVALID; + unsigned failed_unit = INVALID; + for (all_stack (unsigned, lit, kitten->assumptions)) { + if (values[lit] >= 0) + continue; + if (first_failed == INVALID) + first_failed = lit; + const unsigned failed_idx = lit / 2; + const kar *const failed_var = vars + failed_idx; + if (!failed_var->level) { + failed_unit = lit; + break; + } + if (failed_clashing == INVALID && failed_var->reason == INVALID) + failed_clashing = lit; + } + unsigned failed; + if (failed_unit != INVALID) + failed = failed_unit; + else if (failed_clashing != INVALID) + failed = failed_clashing; + else + failed = first_failed; + assert (failed != INVALID); + const unsigned failed_idx = failed / 2; + const kar *const failed_var = vars + failed_idx; + const unsigned failed_reason = failed_var->reason; + LOG ("first failed assumption %u", failed); + kitten->failed[failed] = true; + + if (failed_unit != INVALID) { + assert (dereference_klause (kitten, failed_reason)->size == 1); + LOG ("root-level falsified assumption %u", failed); + kitten->failing = failed_reason; + ROG (kitten->failing, "failing reason"); + return; + } + + const unsigned not_failed = failed ^ 1; + if (failed_clashing != INVALID) { + LOG ("clashing with negated assumption %u", not_failed); + kitten->failed[not_failed] = true; + assert (kitten->failing == INVALID); + return; + } + + value *marks = kitten->marks; + assert (!marks[failed_idx]); + marks[failed_idx] = true; + PUSH_STACK (kitten->analyzed, failed_idx); + PUSH_STACK (kitten->klause, not_failed); + + for (size_t next = 0; next < SIZE_STACK (kitten->analyzed); next++) { + const unsigned idx = PEEK_STACK (kitten->analyzed, next); + assert (marks[idx]); + const kar *var = vars + idx; + const unsigned reason = var->reason; + if (reason == INVALID) { + unsigned lit = 2 * idx; + if (values[lit] < 0) + lit ^= 1; + LOG ("failed assumption %u", lit); + assert (!kitten->failed[lit]); + kitten->failed[lit] = true; + const unsigned not_lit = lit ^ 1; + PUSH_STACK (kitten->klause, not_lit); + } else { + ROG (reason, "analyzing"); + PUSH_STACK (kitten->resolved, reason); + klause *c = dereference_klause (kitten, reason); + for (all_literals_in_klause (other, c)) { + const unsigned other_idx = other / 2; + if (other_idx == idx) + continue; + if (marks[other_idx]) + continue; + marks[other_idx] = true; + PUSH_STACK (kitten->analyzed, other_idx); + LOG ("analyzing final literal %u", other ^ 1); + } + } + } + + for (all_stack (unsigned, idx, kitten->analyzed)) + assert (marks[idx]), marks[idx] = 0; + CLEAR_STACK (kitten->analyzed); + + const size_t resolved = SIZE_STACK (kitten->resolved); + assert (resolved); + + if (resolved == 1) { + kitten->failing = PEEK_STACK (kitten->resolved, 0); + ROG (kitten->failing, "reusing as core"); + } else { + kitten->failing = new_learned_klause (kitten); + ROG (kitten->failing, "new core"); + } + + CLEAR_STACK (kitten->resolved); + CLEAR_STACK (kitten->klause); +} + +static void flush_trail (kitten *kitten) { + unsigneds *trail = &kitten->trail; + LOG ("flushing %zu root-level literals from trail", SIZE_STACK (*trail)); + assert (!kitten->level); + kitten->propagated = 0; + CLEAR_STACK (*trail); +} + +static int decide (kitten *kitten) { + if (!kitten->level && !EMPTY_STACK (kitten->trail)) + flush_trail (kitten); + + const value *const values = kitten->values; + unsigned decision = INVALID; + const size_t assumptions = SIZE_STACK (kitten->assumptions); + while (kitten->level < assumptions) { + unsigned assumption = PEEK_STACK (kitten->assumptions, kitten->level); + value value = values[assumption]; + if (value < 0) { + LOG ("found failing assumption %u", assumption); + failing (kitten); + return 20; + } else if (value > 0) { + + kitten->level++; + LOG ("pseudo decision level %u for already satisfied assumption %u", + kitten->level, assumption); + } else { + decision = assumption; + LOG ("using assumption %u as decision", decision); + break; + } + } + + if (!kitten->unassigned) + return 10; + + if (KITTEN_TICKS >= kitten->limits.ticks) { + LOG ("ticks limit %" PRIu64 " hit after %" PRIu64 " ticks", + kitten->limits.ticks, KITTEN_TICKS); + return -1; + } + +#ifndef STAND_ALONE_KITTEN + if (TERMINATED (kitten_terminated_1)) + return -1; +#endif + + if (decision == INVALID) { + unsigned idx = kitten->queue.search; + const kink *const links = kitten->links; + for (;;) { + assert (idx != INVALID); + if (!values[2 * idx]) + break; + idx = links[idx].prev; + } + update_search (kitten, idx); + const unsigned phase = kitten->phases[idx]; + decision = 2 * idx + phase; + LOG ("decision %u variable %u phase %u", decision, idx, phase); + } + INC (kitten_decisions); + kitten->level++; + assign (kitten, decision, INVALID); + return 0; +} + +static void inconsistent (kitten *kitten, unsigned ref) { + assert (ref != INVALID); + assert (kitten->inconsistent == INVALID); + + if (!kitten->antecedents) { + kitten->inconsistent = ref; + ROG (ref, "registering inconsistent virtually empty"); + return; + } + + unsigneds *analyzed = &kitten->analyzed; + unsigneds *resolved = &kitten->resolved; + + assert (EMPTY_STACK (*analyzed)); + assert (EMPTY_STACK (*resolved)); + + value *marks = kitten->marks; + const kar *const vars = kitten->vars; + unsigned next = 0; + + for (;;) { + assert (ref != INVALID); + klause *c = dereference_klause (kitten, ref); + assert (c); + ROG (ref, "analyzing inconsistent"); + PUSH_STACK (*resolved, ref); + for (all_literals_in_klause (lit, c)) { + const unsigned idx = lit / 2; + assert (!vars[idx].level); + if (marks[idx]) + continue; + assert (kitten->values[lit] < 0); + LOG ("analyzed %u", lit); + marks[idx] = true; + PUSH_STACK (kitten->analyzed, idx); + } + if (next == SIZE_STACK (kitten->analyzed)) + break; + const unsigned idx = PEEK_STACK (kitten->analyzed, next); + next++; + const kar *const v = vars + idx; + assert (!v->level); + ref = v->reason; + } + assert (EMPTY_STACK (kitten->klause)); + ref = new_learned_klause (kitten); + ROG (ref, "registering final inconsistent empty"); + kitten->inconsistent = ref; + + for (all_stack (unsigned, idx, *analyzed)) + marks[idx] = 0; + + CLEAR_STACK (*analyzed); + CLEAR_STACK (*resolved); +} + +static int propagate_units (kitten *kitten) { + if (kitten->inconsistent != INVALID) + return 20; + + if (EMPTY_STACK (kitten->units)) { + LOG ("no root level unit clauses"); + return 0; + } + + LOG ("propagating %zu root level unit clauses", + SIZE_STACK (kitten->units)); + + const value *const values = kitten->values; + + for (size_t next = 0; next < SIZE_STACK (kitten->units); next++) { + const unsigned ref = PEEK_STACK (kitten->units, next); + assert (ref != INVALID); + klause *c = dereference_klause (kitten, ref); + assert (c->size == 1); + ROG (ref, "propagating unit"); + const unsigned unit = c->lits[0]; + const value value = values[unit]; + if (value > 0) + continue; + if (value < 0) { + inconsistent (kitten, ref); + return 20; + } + assign (kitten, unit, ref); + const unsigned conflict = propagate (kitten); + if (conflict == INVALID) + continue; + inconsistent (kitten, conflict); + return 20; + } + return 0; +} + +/*------------------------------------------------------------------------*/ + +static klause *begin_klauses (kitten *kitten) { + return (klause *) BEGIN_STACK (kitten->klauses); +} + +static klause *end_original_klauses (kitten *kitten) { + return (klause *) (BEGIN_STACK (kitten->klauses) + + kitten->end_original_ref); +} + +static klause *end_klauses (kitten *kitten) { + return (klause *) END_STACK (kitten->klauses); +} + +static klause *next_klause (kitten *kitten, klause *c) { + assert (begin_klauses (kitten) <= c); + assert (c < end_klauses (kitten)); + unsigned *res = c->lits + c->size; + if (kitten->antecedents && is_learned_klause (c)) + res += c->aux; + return (klause *) res; +} + +/*------------------------------------------------------------------------*/ + +static void reset_core (kitten *kitten) { + LOG ("resetting core clauses"); + size_t reset = 0; + for (all_klauses (c)) + if (is_core_klause (c)) + unset_core_klause (c), reset++; + LOG ("reset %zu core clauses", reset); + CLEAR_STACK (kitten->core); +} + +static void reset_assumptions (kitten *kitten) { + LOG ("reset %zu assumptions", SIZE_STACK (kitten->assumptions)); + while (!EMPTY_STACK (kitten->assumptions)) { + const unsigned assumption = POP_STACK (kitten->assumptions); + kitten->failed[assumption] = false; + } +#ifndef NDEBUG + for (size_t i = 0; i < kitten->size; i++) + assert (!kitten->failed[i]); +#endif + CLEAR_STACK (kitten->assumptions); + if (kitten->failing != INVALID) { + ROG (kitten->failing, "reset failed assumption reason"); + kitten->failing = INVALID; + } +} + +static void reset_incremental (kitten *kitten) { + if (kitten->level) + completely_backtrack_to_root_level (kitten); + if (!EMPTY_STACK (kitten->assumptions)) + reset_assumptions (kitten); + else + assert (kitten->failing == INVALID); + if (kitten->status == 21) + reset_core (kitten); + UPDATE_STATUS (0); +} + +/*------------------------------------------------------------------------*/ + +static bool flip_literal (kitten *kitten, unsigned lit) { + INC (kitten_flip); + signed char *values = kitten->values; + assert (values[lit]); + if (!kitten->vars[lit / 2].level) { + LOG ("can not flip root-level assigned literal %u", lit); + return false; + } + if (values[lit] < 0) + lit ^= 1; + LOG ("trying to flip value of satisfied literal %u", lit); + assert (values[lit] > 0); + katches *watches = kitten->watches + lit; + katch *q = BEGIN_STACK (*watches); + const katch *const end_watches = END_STACK (*watches); + katch const *p = q; + uint64_t ticks = (((char *) end_watches - (char *) q) >> 7) + 1; + bool res = true; + while (p != end_watches) { + const katch katch = *q++ = *p++; +#ifdef KITTEN_BLIT + const unsigned blit = katch.blit; + assert (blit != lit); + const value blit_value = values[blit]; + if (blit_value > 0) + continue; +#endif + const unsigned ref = katch.ref; + klause *c = dereference_klause (kitten, ref); + unsigned *lits = c->lits; + const unsigned other = lits[0] ^ lits[1] ^ lit; + const value other_value = values[other]; + ticks++; + if (other_value > 0) + continue; + value replacement_value = -1; + unsigned replacement = INVALID; + const unsigned *const end_lits = lits + c->size; + unsigned *r; + for (r = lits + 2; r != end_lits; r++) { + replacement = *r; + assert (replacement != lit); + replacement_value = values[replacement]; + assert (replacement_value); + if (replacement_value > 0) + break; + } + if (replacement_value > 0) { + assert (replacement != INVALID); + ROG (ref, "unwatching %u in", lit); + lits[0] = other; + lits[1] = replacement; + *r = lit; + watch_klause (kitten, replacement, c, ref); + q--; + } else { + assert (replacement_value < 0); + ROG (ref, "single satisfied"); + res = false; + break; + } + } + while (p != end_watches) + *q++ = *p++; + SET_END_OF_STACK (*watches, q); + ADD (kitten_ticks, ticks); + if (res) { + LOG ("flipping value of %u", lit); + values[lit] = -1; + const unsigned not_lit = lit ^ 1; + values[not_lit] = 1; + INC (kitten_flipped); + } else + LOG ("failed to flip value of %u", lit); + return res; +} + +/*------------------------------------------------------------------------*/ + +void kitten_assume (kitten *kitten, unsigned elit) { + REQUIRE_INITIALIZED (); + if (kitten->status) + reset_incremental (kitten); + const unsigned ilit = import_literal (kitten, elit); + LOG ("registering assumption %u", ilit); + PUSH_STACK (kitten->assumptions, ilit); +} + +void kitten_clause_with_id_and_exception (kitten *kitten, unsigned id, + size_t size, + const unsigned *elits, + unsigned except) { + REQUIRE_INITIALIZED (); + if (kitten->status) + reset_incremental (kitten); + assert (EMPTY_STACK (kitten->klause)); + const unsigned *const end = elits + size; + for (const unsigned *p = elits; p != end; p++) { + const unsigned elit = *p; + if (elit == except) + continue; + const unsigned ilit = import_literal (kitten, elit); + assert (ilit < kitten->lits); + const unsigned iidx = ilit / 2; + if (kitten->marks[iidx]) + INVALID_API_USAGE ("variable '%u' of literal '%u' occurs twice", + elit / 2, elit); + kitten->marks[iidx] = true; + PUSH_STACK (kitten->klause, ilit); + } + for (unsigned *p = kitten->klause.begin; p != kitten->klause.end; p++) + kitten->marks[*p / 2] = false; + new_original_klause (kitten, id); + CLEAR_STACK (kitten->klause); +} + +void kitten_clause (kitten *kitten, size_t size, unsigned *elits) { + kitten_clause_with_id_and_exception (kitten, INVALID, size, elits, + INVALID); +} + +void kitten_unit (kitten *kitten, unsigned lit) { + kitten_clause (kitten, 1, &lit); +} + +void kitten_binary (kitten *kitten, unsigned a, unsigned b) { + unsigned clause[2] = {a, b}; + kitten_clause (kitten, 2, clause); +} + +#ifdef STAND_ALONE_KITTEN +static volatile bool time_limit_hit; +#endif + +int kitten_solve (kitten *kitten) { + REQUIRE_INITIALIZED (); + if (kitten->status) + reset_incremental (kitten); + else if (kitten->level) + completely_backtrack_to_root_level (kitten); + + LOG ("starting solving under %zu assumptions", + SIZE_STACK (kitten->assumptions)); + + INC (kitten_solved); + + int res = propagate_units (kitten); + while (!res) { + const unsigned conflict = propagate (kitten); + if (conflict != INVALID) { + if (kitten->level) + analyze (kitten, conflict); + else { + inconsistent (kitten, conflict); + res = 20; + } + } else +#ifdef STAND_ALONE_KITTEN + if (time_limit_hit) { + time_limit_hit = false; + break; + } else +#endif + res = decide (kitten); + } + + if (res < 0) + res = 0; + + if (!res && !EMPTY_STACK (kitten->assumptions)) + reset_assumptions (kitten); + + UPDATE_STATUS (res); + + if (res == 10) + INC (kitten_sat); + else if (res == 20) + INC (kitten_unsat); + else + INC (kitten_unknown); + + LOG ("finished solving with result %d", res); + + return res; +} + +int kitten_status (kitten *kitten) { return kitten->status; } + +unsigned kitten_compute_clausal_core (kitten *kitten, + uint64_t *learned_ptr) { + REQUIRE_STATUS (20); + + if (!kitten->antecedents) + INVALID_API_USAGE ("antecedents not tracked"); + + LOG ("computing clausal core"); + + unsigneds *resolved = &kitten->resolved; + assert (EMPTY_STACK (*resolved)); + + unsigned original = 0; + uint64_t learned = 0; + + unsigned reason_ref = kitten->inconsistent; + + if (reason_ref == INVALID) { + assert (!EMPTY_STACK (kitten->assumptions)); + reason_ref = kitten->failing; + if (reason_ref == INVALID) { + LOG ("assumptions mutually inconsistent"); + goto DONE; + } + } + + PUSH_STACK (*resolved, reason_ref); + unsigneds *core = &kitten->core; + assert (EMPTY_STACK (*core)); + + while (!EMPTY_STACK (*resolved)) { + const unsigned c_ref = POP_STACK (*resolved); + if (c_ref == INVALID) { + const unsigned d_ref = POP_STACK (*resolved); + ROG (d_ref, "core[%zu]", SIZE_STACK (*core)); + PUSH_STACK (*core, d_ref); + klause *d = dereference_klause (kitten, d_ref); + assert (!is_core_klause (d)); + set_core_klause (d); + if (is_learned_klause (d)) + learned++; + else + original++; + } else { + klause *c = dereference_klause (kitten, c_ref); + if (is_core_klause (c)) + continue; + PUSH_STACK (*resolved, c_ref); + PUSH_STACK (*resolved, INVALID); + ROG (c_ref, "analyzing antecedent core"); + if (!is_learned_klause (c)) + continue; + for (all_antecedents (d_ref, c)) { + klause *d = dereference_klause (kitten, d_ref); + if (!is_core_klause (d)) + PUSH_STACK (*resolved, d_ref); + } + } + } + +DONE: + + if (learned_ptr) + *learned_ptr = learned; + + LOG ("clausal core of %u original clauses", original); + LOG ("clausal core of %" PRIu64 " learned clauses", learned); +#ifdef STAND_ALONE_KITTEN + kitten->statistics.original = original; + kitten->statistics.learned = 0; +#endif + UPDATE_STATUS (21); + + return original; +} + +void kitten_traverse_core_ids (kitten *kitten, void *state, + void (*traverse) (void *, unsigned)) { + REQUIRE_STATUS (21); + + LOG ("traversing core of original clauses"); + + unsigned traversed = 0; + + for (all_original_klauses (c)) { + assert (!is_learned_klause (c)); + if (is_learned_klause (c)) + continue; + if (!is_core_klause (c)) + continue; + ROG (reference_klause (kitten, c), "traversing"); + traverse (state, c->aux); + traversed++; + } + + LOG ("traversed %u original core clauses", traversed); + (void) traversed; + + assert (kitten->status == 21); +} + +void kitten_traverse_core_clauses (kitten *kitten, void *state, + void (*traverse) (void *, bool, size_t, + const unsigned *)) { + REQUIRE_STATUS (21); + + LOG ("traversing clausal core"); + + unsigned traversed = 0; + + for (all_stack (unsigned, c_ref, kitten->core)) { + klause *c = dereference_klause (kitten, c_ref); + assert (is_core_klause (c)); + const bool learned = is_learned_klause (c); + unsigneds *eclause = &kitten->eclause; + assert (EMPTY_STACK (*eclause)); + for (all_literals_in_klause (ilit, c)) { + const unsigned elit = export_literal (kitten, ilit); + PUSH_STACK (*eclause, elit); + } + const size_t size = SIZE_STACK (*eclause); + const unsigned *elits = eclause->begin; + ROG (reference_klause (kitten, c), "traversing"); + traverse (state, learned, size, elits); + CLEAR_STACK (*eclause); + traversed++; + } + + LOG ("traversed %u core clauses", traversed); + (void) traversed; + + assert (kitten->status == 21); +} + +void kitten_shrink_to_clausal_core (kitten *kitten) { + REQUIRE_STATUS (21); + + LOG ("shrinking formula to core of original clauses"); + + CLEAR_STACK (kitten->trail); + + kitten->unassigned = kitten->lits / 2; + kitten->propagated = 0; + kitten->level = 0; + + update_search (kitten, kitten->queue.last); + + memset (kitten->values, 0, kitten->lits); + + for (all_kits (lit)) + CLEAR_STACK (KATCHES (lit)); + + assert (kitten->inconsistent != INVALID); + klause *inconsistent = dereference_klause (kitten, kitten->inconsistent); + if (is_learned_klause (inconsistent) || inconsistent->size) { + ROG (kitten->inconsistent, "resetting inconsistent"); + kitten->inconsistent = INVALID; + } else + ROG (kitten->inconsistent, "keeping inconsistent"); + + CLEAR_STACK (kitten->units); + + klause *begin = begin_klauses (kitten), *q = begin; + klause const *const end = end_original_klauses (kitten); +#ifdef LOGGING + unsigned original = 0; +#endif + for (klause *c = begin, *next; c != end; c = next) { + next = next_klause (kitten, c); + assert (!is_learned_klause (c)); + if (is_learned_klause (c)) + continue; + if (!is_core_klause (c)) + continue; + unset_core_klause (c); + const unsigned dst = (unsigned *) q - (unsigned *) begin; + const unsigned size = c->size; + if (!size) { + if (!kitten->inconsistent) + kitten->inconsistent = dst; + } else if (size == 1) + PUSH_STACK (kitten->units, dst); + else { + watch_klause (kitten, c->lits[0], c, dst); + watch_klause (kitten, c->lits[1], c, dst); + } + if (c == q) + q = next; + else { + const size_t bytes = (char *) next - (char *) c; + memmove (q, c, bytes); + q = (klause *) ((char *) q + bytes); + } +#ifdef LOGGING + original++; +#endif + } + SET_END_OF_STACK (kitten->klauses, (unsigned *) q); + kitten->end_original_ref = SIZE_STACK (kitten->klauses); + LOG ("end of original clauses at %zu", kitten->end_original_ref); + LOG ("%u original clauses left", original); + + CLEAR_STACK (kitten->core); + + UPDATE_STATUS (0); +} + +signed char kitten_value (kitten *kitten, unsigned elit) { + REQUIRE_STATUS (10); + const unsigned eidx = elit / 2; + if (eidx >= kitten->evars) + return 0; + unsigned iidx = kitten->import[eidx]; + if (!iidx) + return 0; + const unsigned ilit = 2 * (iidx - 1) + (elit & 1); + return kitten->values[ilit]; +} + +signed char kitten_fixed (kitten *kitten, unsigned elit) { + const unsigned eidx = elit / 2; + if (eidx >= kitten->evars) + return 0; + unsigned iidx = kitten->import[eidx]; + if (!iidx) + return 0; + iidx--; + const unsigned ilit = 2 * iidx + (elit & 1); + signed char res = kitten->values[ilit]; + if (!res) + return 0; + kar *v = kitten->vars + iidx; + if (v->level) + return 0; + return res; +} + +bool kitten_flip_literal (kitten *kitten, unsigned elit) { + REQUIRE_STATUS (10); + const unsigned eidx = elit / 2; + if (eidx >= kitten->evars) + return false; + unsigned iidx = kitten->import[eidx]; + if (!iidx) + return false; + const unsigned ilit = 2 * (iidx - 1) + (elit & 1); + return flip_literal (kitten, ilit); +} + +bool kitten_failed (kitten *kitten, unsigned elit) { + REQUIRE_STATUS (20); + const unsigned eidx = elit / 2; + if (eidx >= kitten->evars) + return false; + unsigned iidx = kitten->import[eidx]; + if (!iidx) + return false; + const unsigned ilit = 2 * (iidx - 1) + (elit & 1); + return kitten->failed[ilit]; +} + +/*------------------------------------------------------------------------*/ + +#ifdef STAND_ALONE_KITTEN + +#include +#include +#include +#include + +static double process_time (void) { + struct rusage u; + double res; + if (getrusage (RUSAGE_SELF, &u)) + return 0; + res = u.ru_utime.tv_sec + 1e-6 * u.ru_utime.tv_usec; + res += u.ru_stime.tv_sec + 1e-6 * u.ru_stime.tv_usec; + return res; +} + +static double maximum_resident_set_size (void) { + struct rusage u; + if (getrusage (RUSAGE_SELF, &u)) + return 0; + const uint64_t bytes = ((uint64_t) u.ru_maxrss) << 10; + return bytes / (double) (1 << 20); +} + +#include "attribute.h" + +static void msg (const char *, ...) __attribute__ ((format (printf, 1, 2))); + +static void msg (const char *fmt, ...) { + fputs ("c ", stdout); + va_list ap; + va_start (ap, fmt); + vprintf (fmt, ap); + va_end (ap); + fputc ('\n', stdout); + fflush (stdout); +} + +#undef logging + +typedef struct parser parser; + +struct parser { + const char *path; + uint64_t lineno; + FILE *file; +#ifdef LOGGING + bool logging; +#endif +}; + +static void parse_error (parser *parser, const char *msg) { + fprintf (stderr, "kitten: error: %s:%" PRIu64 ": parse error: %s\n", + parser->path, parser->lineno, msg); + exit (1); +} + +#define ERROR(...) parse_error (parser, __VA_ARGS__) + +static inline int next_char (parser *parser) { + int res = getc (parser->file); + if (res == '\r') { + res = getc (parser->file); + if (res != '\n') + ERROR ("expected new line after carriage return"); + } + if (res == '\n') + parser->lineno++; + return res; +} + +#define NEXT() next_char (parser) + +#define FAILED INT_MIN + +static int parse_number (parser *parser, int *res_ptr) { + int ch = NEXT (); + if (!isdigit (ch)) + return FAILED; + int res = ch - '0'; + while (isdigit (ch = NEXT ())) { + if (!res) + return FAILED; + if (INT_MAX / 10 < res) + return FAILED; + res *= 10; + const int digit = ch - '0'; + if (INT_MAX - digit < res) + return FAILED; + res += digit; + } + *res_ptr = res; + return ch; +} + +static kitten *parse (parser *parser, ints *originals, int *max_var) { + signed char *marks = 0; + size_t size_marks = 0; + int last = '\n', ch; + for (;;) { + ch = NEXT (); + if (ch == 'c') { + while ((ch = NEXT ()) != '\n') + if (ch == EOF) + ERROR ("unexpected end-of-file in comment"); + } else if (ch != ' ' && ch != '\t' && ch != '\n') + break; + last = ch; + } + if (ch != 'p' || last != '\n') + ERROR ("expected 'c' or 'p' at start of line"); + bool valid = (NEXT () == ' ' && NEXT () == 'c' && NEXT () == 'n' && + NEXT () == 'f' && NEXT () == ' '); + int vars = 0; + int clauses = 0; + if (valid && (parse_number (parser, &vars) != ' ' || + parse_number (parser, &clauses) != '\n')) + valid = false; + if (!valid) + ERROR ("invalid header"); + msg ("found header 'p cnf %d %d'", vars, clauses); + *max_var = vars; + kitten *kitten = kitten_init (); +#ifdef LOGGING + kitten->logging = parser->logging; +#define logging (kitten->logging) +#endif + unsigneds clause; + INIT_STACK (clause); + int iidx = 0; + int parsed = 0; + bool tautological = false; + uint64_t offset = 0; + for (;;) { + ch = NEXT (); + if (ch == EOF) { + if (parsed < clauses) + ERROR ("clause missing"); + if (iidx) + ERROR ("zero missing"); + break; + } + if (ch == ' ' || ch == '\t' || ch == '\n') + continue; + if (ch == 'c') { + while ((ch = NEXT ()) != '\n') + if (ch == EOF) + ERROR ("unexpected end-of-file in comment"); + continue; + } + int sign = 1; + if (ch == '-') + sign = -1; + else + ungetc (ch, parser->file); + ch = parse_number (parser, &iidx); + if (ch == FAILED) + ERROR ("invalid literal"); + if (ch == EOF) + ERROR ("unexpected end-of-file after literal"); + if (ch == 'c') { + while ((ch = NEXT ()) != '\n') + if (ch == EOF) + ERROR ("unexpected end-of-file in comment"); + } else if (ch != ' ' && ch != '\t' && ch != '\n') + ERROR ("expected comment or white space after literal"); + if (iidx > vars) + ERROR ("maximum variable exceeded"); + if (parsed == clauses) + ERROR ("too many clauses"); + const int ilit = sign * iidx; + if (originals) + PUSH_STACK (*originals, ilit); + if (!iidx) { + for (all_stack (unsigned, ulit, clause)) + marks[ulit / 2] = 0; + if (tautological) { + LOG ("skipping tautological clause"); + tautological = false; + } else if (offset > UINT_MAX) + ERROR ("too many original literals"); + else { + assert (SIZE_STACK (clause) <= UINT_MAX); + const unsigned size = SIZE_STACK (clause); + const unsigned *const lits = BEGIN_STACK (clause); + kitten_clause_with_id_and_exception (kitten, offset, size, lits, + INVALID); + } + CLEAR_STACK (clause); + parsed++; + + if (originals) + offset = SIZE_STACK (*originals); + else + offset = parsed; + } else if (!tautological) { + const unsigned uidx = iidx - 1; + const unsigned ulit = 2 * uidx + (sign < 0); + if (uidx >= size_marks) { + size_t new_size_marks = size_marks ? 2 * size_marks : 1; + while (uidx >= new_size_marks) + new_size_marks *= 2; + signed char *new_marks; + CALLOC (new_marks, new_size_marks); + if (size_marks) + memcpy (new_marks, marks, size_marks); + DEALLOC (marks, size_marks); + size_marks = new_size_marks; + marks = new_marks; + } + value mark = marks[uidx]; + if (sign < 0) + mark = -mark; + if (mark > 0) + LOG ("dropping repeated %d in parsed clause", ilit); + else if (mark < 0) { + LOG ("parsed clause contains both %d and %d", -ilit, ilit); + tautological = true; + } else { + LOG ("adding parsed integer literal %d as external literal %u", + ilit, ulit); + marks[uidx] = sign; + PUSH_STACK (clause, ulit); + } + } + } + RELEASE_STACK (clause); + free (marks); + return kitten; +} + +typedef struct line line; + +struct line { + char buffer[80]; + size_t size; +}; + +static void flush_line (line *line) { + if (!line->size) + return; + for (size_t i = 0; i < line->size; i++) + fputc (line->buffer[i], stdout); + fputc ('\n', stdout); + line->size = 0; +} + +static inline void print_lit (line *line, int lit) { + char tmp[16]; + sprintf (tmp, " %d", lit); + const size_t len = strlen (tmp); + if (line->size + len > 78) + flush_line (line); + if (!line->size) { + line->buffer[0] = 'v'; + line->size = 1; + } + strcpy (line->buffer + line->size, tmp); + line->size += len; +} + +static void print_witness (kitten *kitten, int max_var) { + assert (max_var >= 0); + line line = {.size = 0}; + const size_t parsed_lits = 2 * (size_t) max_var; + for (size_t ulit = 0; ulit < parsed_lits; ulit += 2) { + const value sign = kitten_value (kitten, ulit); + const int iidx = ulit / 2 + 1; + const int ilit = (sign > 0 ? iidx : -iidx); + print_lit (&line, ilit); + } + print_lit (&line, 0); + flush_line (&line); +} + +static double percent (double a, double b) { return b ? 100 * a / b : 0; } + +typedef struct core_writer core_writer; + +struct core_writer { + FILE *file; + ints *originals; +#ifndef NDEBUG + unsigned written; +#endif +}; + +static void write_offset (void *ptr, unsigned offset) { + core_writer *writer = ptr; +#ifndef NDEBUG + writer->written++; +#endif + int const *p = &PEEK_STACK (*writer->originals, offset); + FILE *file = writer->file; + while (*p) + fprintf (file, "%d ", *p++); + fputs ("0\n", file); +} + +static void write_core (kitten *kitten, unsigned reduced, ints *originals, + FILE *file) { + assert (originals); + fprintf (file, "p cnf %zu %u\n", kitten->evars, reduced); + core_writer writer; + writer.file = file; + writer.originals = originals; +#ifndef NDEBUG + writer.written = 0; +#endif + kitten_traverse_core_ids (kitten, &writer, write_offset); + assert (writer.written == reduced); +} + +#ifndef NDEBUG + +typedef struct lemma_writer lemma_writer; + +struct lemma_writer { + FILE *file; + uint64_t written; +}; + +#endif + +static void write_lemma (void *ptr, bool learned, size_t size, + const unsigned *lits) { + if (!learned) + return; + const unsigned *const end = lits + size; +#ifdef NDEBUG + FILE *file = ptr; +#else + lemma_writer *writer = ptr; + FILE *file = writer->file; + writer->written++; +#endif + for (const unsigned *p = lits; p != end; p++) { + const unsigned ulit = *p; + const unsigned idx = ulit / 2; + const unsigned sign = ulit & 1; + assert (idx + 1 <= (unsigned) INT_MAX); + int ilit = idx + 1; + if (sign) + ilit = -ilit; + fprintf (file, "%d ", ilit); + } + fputs ("0\n", file); +} + +static void write_lemmas (kitten *kitten, uint64_t reduced, FILE *file) { + void *state; +#ifdef NDEBUG + state = file; + (void) reduced; +#else + lemma_writer writer; + writer.file = file; + writer.written = 0; + state = &writer; +#endif + kitten_traverse_core_clauses (kitten, state, write_lemma); + assert (writer.written == reduced); +} + +static void print_statistics (statistics statistics) { + msg ("conflicts: %20" PRIu64, + statistics.kitten_conflicts); + msg ("decisions: %20" PRIu64, + statistics.kitten_decisions); + msg ("propagations: %20" PRIu64, + statistics.kitten_propagations); + msg ("maximum-resident-set-size: %23.2f MB", + maximum_resident_set_size ()); + msg ("process-time: %23.2f seconds", process_time ()); +} + +static volatile int time_limit; +static volatile kitten *static_kitten; + +#define SIGNALS \ + SIGNAL (SIGABRT) \ + SIGNAL (SIGBUS) \ + SIGNAL (SIGINT) \ + SIGNAL (SIGSEGV) \ + SIGNAL (SIGTERM) + +// clang-format off + +#define SIGNAL(SIG) \ +static void (*SIG ## _handler)(int); +SIGNALS +#undef SIGNAL + +static void (*SIGALRM_handler)(int); + +// clang-format on + +static void reset_alarm (void) { + if (time_limit > 0) { + time_limit = 0; + time_limit_hit = false; + } +} + +static void reset_signals (void) { +#define SIGNAL(SIG) signal (SIG, SIG##_handler); + SIGNALS +#undef SIGNAL + static_kitten = 0; +} + +static const char *signal_name (int sig) { +#define SIGNAL(SIG) \ + if (sig == SIG) \ + return #SIG; + SIGNALS +#undef SIGNAL + return "SIGUNKNOWN"; +} + +static void catch_signal (int sig) { + if (!static_kitten) + return; + statistics statistics = static_kitten->statistics; + reset_signals (); + msg ("caught signal %d (%s)", sig, signal_name (sig)); + print_statistics (statistics); + raise (sig); +} + +static void catch_alarm (int sig) { + assert (sig == SIGALRM); + if (time_limit > 0) + time_limit_hit = true; + (void) sig; +} + +static void init_signals (kitten *kitten) { + static_kitten = kitten; +#define SIGNAL(SIG) SIG##_handler = signal (SIG, catch_signal); + SIGNALS +#undef SIGNAL + if (time_limit > 0) { + SIGALRM_handler = signal (SIGALRM, catch_alarm); + alarm (time_limit); + } +} + +static bool parse_arg (const char *arg, unsigned *res_ptr) { + unsigned res = 0; + int ch; + while ((ch = *arg++)) { + if (!isdigit (ch)) + return false; + if (UINT_MAX / 10 < res) + return false; + res *= 10; + const unsigned digit = ch - '0'; + if (UINT_MAX - digit < res) + return false; + res += digit; + } + *res_ptr = res; + return true; +} + +static bool parse_lit (const char *arg, int *res_ptr) { + int res = 0, sign, ch; + if (*arg == '-') { + sign = -1; + if (*++arg == '0') + return false; + } else + sign = 1; + while ((ch = *arg++)) { + if (!isdigit (ch)) + return false; + if (INT_MAX / 10 < res) + return false; + res *= 10; + const int digit = ch - '0'; + if (INT_MAX - digit < res) + return false; + res += digit; + } + res *= sign; + *res_ptr = res; + return true; +} + +#undef logging + +int main (int argc, char **argv) { + ints assumptions; + INIT_STACK (assumptions); + const char *dimacs_path = 0; + const char *output_path = 0; + unsigned shrink = 0; + bool witness = true; + bool proof = false; +#ifdef LOGGING + bool logging = false; +#endif + for (int i = 1; i < argc; i++) { + const char *arg = argv[i]; + if (!strcmp (arg, "-h")) + fputs (usage, stdout), exit (0); +#ifdef LOGGING + else if (!strcmp (arg, "-l")) + logging = true; +#endif + else if (!strcmp (arg, "-n")) + witness = false; + else if (!strcmp (arg, "-p")) + proof = true; + else if (!strcmp (arg, "-a")) { + if (++i == argc) + die ("argument to '-a' missing"); + int lit; + if (!parse_lit (argv[i], &lit) || !lit) + die ("invalid '-a %s'", argv[i]); + PUSH_STACK (assumptions, lit); + } else if (!strcmp (arg, "-t")) { + if (++i == argc) + die ("argument to '-t' missing"); + if ((time_limit = atoi (argv[i])) <= 0) + die ("invalid argument in '-t %s'", argv[i]); + } else if (arg[0] == '-' && arg[1] == 'O' && !arg[2]) + shrink = 1; + else if (arg[0] == '-' && arg[1] == 'O' && parse_arg (arg + 2, &shrink)) + ; + else if (*arg == '-') + die ("invalid option '%s' (try '-h')", arg); + else if (output_path) + die ("too many arguments (try '-h')"); + else if (dimacs_path) + output_path = arg; + else + dimacs_path = arg; + } + if (proof && !output_path) + die ("option '-p' without output file"); + if (shrink && !EMPTY_STACK (assumptions)) + die ("can not using shrinking with assumptions"); + FILE *dimacs_file; + bool close_dimacs_file = true; + if (!dimacs_path) + close_dimacs_file = false, dimacs_file = stdin, dimacs_path = ""; + else if (!(dimacs_file = fopen (dimacs_path, "r"))) + die ("can not open '%s' for reading", dimacs_path); + msg ("Kitten SAT Solver"); + msg ("Copyright (c) 2021-2024 Armin Biere University of Freiburg"); + msg ("Copyright (c) 2020-2021 Armin Biere Johannes Kepler University " + "Linz"); + msg ("reading '%s'", dimacs_path); + ints originals; + INIT_STACK (originals); + kitten *kitten; + int max_var; + { + parser parser; + parser.path = dimacs_path; + parser.lineno = 1; + parser.file = dimacs_file; +#ifdef LOGGING + parser.logging = logging; +#endif + kitten = parse (&parser, ((output_path && !proof) ? &originals : 0), + &max_var); + } + if (close_dimacs_file) + fclose (dimacs_file); + msg ("parsed DIMACS file in %.2f seconds", process_time ()); + init_signals (kitten); + if (output_path) { + msg ("tracking antecedents"); + kitten_track_antecedents (kitten); + } + if (!EMPTY_STACK (assumptions)) { + msg ("assuming %zu assumptions", SIZE_STACK (assumptions)); + for (all_stack (int, ilit, assumptions)) { + unsigned ulit = 2u * (abs (ilit) - 1) + (ilit < 0); + kitten_assume (kitten, ulit); + } + } + int res = kitten_solve (kitten); + if (res == 10) { + printf ("s SATISFIABLE\n"); + fflush (stdout); + if (witness) + print_witness (kitten, max_var); + } else if (res == 20) { + printf ("s UNSATISFIABLE\n"); + fflush (stdout); + if (output_path) { + const unsigned original = kitten->statistics.original; + const uint64_t learned = kitten->statistics.learned; + unsigned reduced_original, round = 0; + uint64_t reduced_learned; + + for (;;) { + msg ("computing clausal core of %" PRIu64 " clauses", + kitten->statistics.original + kitten->statistics.learned); + + reduced_original = + kitten_compute_clausal_core (kitten, &reduced_learned); + + msg ("found %" PRIu64 " core lemmas %.0f%% " + "out of %" PRIu64 " learned clauses", + reduced_learned, percent (reduced_learned, learned), learned); + + if (!shrink--) + break; + + msg ("shrinking round %u", ++round); + + msg ("reduced to %u core clauses %.0f%% " + "out of %u original clauses", + reduced_original, percent (reduced_original, original), + original); + + kitten_shrink_to_clausal_core (kitten); + kitten_shuffle_clauses (kitten); + + reset_alarm (); + res = kitten_solve (kitten); + assert (res == 20); + } + FILE *output_file = fopen (output_path, "w"); + if (!output_file) + die ("can not open '%s' for writing", output_path); + if (proof) { + msg ("writing proof to '%s'", output_path); + write_lemmas (kitten, reduced_learned, output_file); + msg ("written %" PRIu64 " core lemmas %.0f%% of %" PRIu64 + " learned clauses", + reduced_learned, percent (reduced_learned, learned), learned); + } else { + msg ("writing original clausal core to '%s'", output_path); + write_core (kitten, reduced_original, &originals, output_file); + msg ("written %u core clauses %.0f%% of %u original clauses", + reduced_original, percent (reduced_original, original), + original); + } + fclose (output_file); + } + } else { + fputs ("s UNKNOWN\n", stdout); + fflush (stdout); + } + RELEASE_STACK (originals); + RELEASE_STACK (assumptions); + statistics statistics = kitten->statistics; + reset_signals (); + kitten_release (kitten); + print_statistics (statistics); + msg ("exit %d", res); + return res; +} + +#endif diff --git a/src/sat/kissat/kitten.h b/src/sat/kissat/kitten.h new file mode 100644 index 000000000..e7ead94dc --- /dev/null +++ b/src/sat/kissat/kitten.h @@ -0,0 +1,54 @@ +#ifndef _kitten_h_INCLUDED +#define _kitten_h_INCLUDED + +#include +#include +#include + +typedef struct kitten kitten; + +kitten *kitten_init (void); +void kitten_clear (kitten *); +void kitten_release (kitten *); + +void kitten_track_antecedents (kitten *); + +void kitten_shuffle_clauses (kitten *); +void kitten_flip_phases (kitten *); +void kitten_randomize_phases (kitten *); + +void kitten_assume (kitten *, unsigned lit); + +void kitten_clause (kitten *, size_t size, unsigned *); +void kitten_unit (kitten *, unsigned); +void kitten_binary (kitten *, unsigned, unsigned); + +void kitten_clause_with_id_and_exception (kitten *, unsigned id, + size_t size, const unsigned *, + unsigned except); + +void kitten_no_ticks_limit (kitten *); +void kitten_set_ticks_limit (kitten *, uint64_t); + +int kitten_solve (kitten *); +int kitten_status (kitten *); + +signed char kitten_value (kitten *, unsigned); +signed char kitten_fixed (kitten *, unsigned); +bool kitten_failed (kitten *, unsigned); +bool kitten_flip_literal (kitten *, unsigned); + +unsigned kitten_compute_clausal_core (kitten *, uint64_t *learned); +void kitten_shrink_to_clausal_core (kitten *); + +void kitten_traverse_core_ids (kitten *, void *state, + void (*traverse) (void *state, unsigned id)); + +void kitten_traverse_core_clauses (kitten *, void *state, + void (*traverse) (void *state, + bool learned, size_t, + const unsigned *)); +struct kissat; +kitten *kitten_embedded (struct kissat *); + +#endif diff --git a/src/sat/kissat/krite.c b/src/sat/kissat/krite.c new file mode 100644 index 000000000..85d91d9d9 --- /dev/null +++ b/src/sat/kissat/krite.c @@ -0,0 +1,45 @@ +#include "krite.h" +#include "inline.h" +#include "internal.h" +#include "watch.h" + +#include + +void kissat_write_dimacs (kissat *solver, FILE *file) { + size_t imported = SIZE_STACK (solver->import); + if (imported) + imported--; + fprintf (file, "p cnf %zu %" PRIu64 "\n", imported, BINIRR_CLAUSES); + assert (solver->watching); + if (solver->watching) { + for (all_literals (ilit)) + for (all_binary_blocking_watches (watch, WATCHES (ilit))) + if (watch.type.binary) { + const unsigned iother = watch.binary.lit; + if (iother < ilit) + continue; + const int elit = kissat_export_literal (solver, ilit); + const int eother = kissat_export_literal (solver, iother); + fprintf (file, "%d %d 0\n", elit, eother); + } + } else { + for (all_literals (ilit)) + for (all_binary_large_watches (watch, WATCHES (ilit))) + if (watch.type.binary) { + const unsigned iother = watch.binary.lit; + if (iother < ilit) + continue; + const int elit = kissat_export_literal (solver, ilit); + const int eother = kissat_export_literal (solver, iother); + fprintf (file, "%d %d 0\n", elit, eother); + } + } + for (all_clauses (c)) + if (!c->garbage && !c->redundant) { + for (all_literals_in_clause (ilit, c)) { + const int elit = kissat_export_literal (solver, ilit); + fprintf (file, "%d ", elit); + } + fputs ("0\n", file); + } +} diff --git a/src/sat/kissat/krite.h b/src/sat/kissat/krite.h new file mode 100644 index 000000000..a8af42c9c --- /dev/null +++ b/src/sat/kissat/krite.h @@ -0,0 +1,9 @@ +#ifndef _krite_h_INCLUDED +#define _krite_h_INCLUDED + +#include + +struct kissat; +void kissat_write_dimacs (struct kissat *, FILE *); + +#endif diff --git a/src/sat/kissat/learn.c b/src/sat/kissat/learn.c new file mode 100644 index 000000000..36a25be89 --- /dev/null +++ b/src/sat/kissat/learn.c @@ -0,0 +1,210 @@ +#include "learn.h" +#include "backtrack.h" +#include "inline.h" +#include "reluctant.h" + +#include + +static unsigned backjump_limit (struct kissat *solver) { +#ifdef NOPTIONS + (void) solver; +#endif + return GET_OPTION (chrono) ? (unsigned) GET_OPTION (chronolevels) + : UINT_MAX; +} + +unsigned kissat_determine_new_level (kissat *solver, unsigned jump) { + assert (solver->level); + const unsigned back = solver->level - 1; + assert (jump <= back); + + const unsigned delta = back - jump; + const unsigned limit = backjump_limit (solver); + + unsigned res; + + if (!delta) { + res = jump; + LOG ("using identical backtrack and jump level %u", res); + } else if (delta > limit) { + res = back; + LOG ("backjumping over %u levels (%u - %u) considered inefficient", + delta, back, jump); + LOG ("backtracking chronologically to backtrack level %u", res); + INC (chronological); + } else { + res = jump; + LOG ("backjumping over %u levels (%u - %u) considered efficient", delta, + back, jump); + LOG ("backjumping non-chronologically to jump level %u", res); + } + return res; +} + +static void learn_unit (kissat *solver, unsigned not_uip) { + assert (not_uip == PEEK_STACK (solver->clause, 0)); + LOG ("learned unit clause %s triggers iteration", LOGLIT (not_uip)); + const unsigned new_level = kissat_determine_new_level (solver, 0); + kissat_backtrack_after_conflict (solver, new_level); + kissat_learned_unit (solver, not_uip); + if (!solver->probing) { + solver->iterating = true; + INC (iterations); + } +} + +static void learn_binary (kissat *solver, unsigned not_uip) { + const unsigned other = PEEK_STACK (solver->clause, 1); + const unsigned jump_level = LEVEL (other); + const unsigned new_level = + kissat_determine_new_level (solver, jump_level); + kissat_backtrack_after_conflict (solver, new_level); +#ifndef NDEBUG + const reference ref = +#endif + kissat_new_redundant_clause (solver, 1); + assert (ref == INVALID_REF); + kissat_assign_binary (solver, not_uip, other); +} + +static void insert_last_learned (kissat *solver, reference ref) { + const reference *const end = + solver->last_learned + GET_OPTION (eagersubsume); + reference prev = ref; + for (reference *p = solver->last_learned; p != end; p++) { + reference tmp = *p; + *p = prev; + prev = tmp; + } +} + +static reference learn_reference (kissat *solver, unsigned not_uip, + unsigned glue) { + assert (solver->level > 1); + assert (SIZE_STACK (solver->clause) > 2); + unsigned *lits = BEGIN_STACK (solver->clause); + assert (lits[0] == not_uip); + unsigned *q = lits + 1; + unsigned jump_lit = *q; + unsigned jump_level = LEVEL (jump_lit); + const unsigned *const end = END_STACK (solver->clause); + const unsigned backtrack_level = solver->level - 1; + assigned *all_assigned = solver->assigned; + for (unsigned *p = lits + 2; p != end; p++) { + const unsigned lit = *p; + const unsigned idx = IDX (lit); + const unsigned level = all_assigned[idx].level; + if (jump_level >= level) + continue; + jump_level = level; + jump_lit = lit; + q = p; + if (level == backtrack_level) + break; + } + *q = lits[1]; + lits[1] = jump_lit; + const reference ref = kissat_new_redundant_clause (solver, glue); + assert (ref != INVALID_REF); + clause *c = kissat_dereference_clause (solver, ref); + c->used = MAX_USED; + const unsigned new_level = + kissat_determine_new_level (solver, jump_level); + kissat_backtrack_after_conflict (solver, new_level); + kissat_assign_reference (solver, not_uip, ref, c); + return ref; +} + +void kissat_update_learned (kissat *solver, unsigned glue, unsigned size) { + assert (!solver->probing); + INC (clauses_learned); + LOG ("learned[%" PRIu64 "] clause glue %u size %u", GET (clauses_learned), + glue, size); + if (solver->stable) + kissat_tick_reluctant (&solver->reluctant); + ADD (literals_learned, size); +#ifndef QUIET + UPDATE_AVERAGE (size, size); +#endif + UPDATE_AVERAGE (fast_glue, glue); + UPDATE_AVERAGE (slow_glue, glue); +} + +static void flush_last_learned (kissat *solver) { + reference *q = solver->last_learned; + const reference *const end = q + GET_OPTION (eagersubsume), *p = q; + while (p != end) { + reference ref = *p++; + if (ref != INVALID_REF) + *q++ = ref; + } + while (q != end) + *q++ = INVALID_REF; +} + +static void eagerly_subsume_last_learned (kissat *solver) { + value *marks = solver->marks; + for (all_stack (unsigned, lit, solver->clause)) { + assert (!marks[lit]); + marks[lit] = 1; + } + unsigned clause_size = SIZE_STACK (solver->clause); + unsigned subsumed = 0; + reference *p = solver->last_learned; + const reference *const end = p + GET_OPTION (eagersubsume); + while (p != end) { + reference ref = *p++; + if (ref == INVALID_REF) + continue; + clause *c = kissat_dereference_clause (solver, ref); + if (c->garbage) + continue; + if (!c->redundant) + continue; + unsigned c_size = c->size; + if (c_size <= clause_size) + continue; + LOGCLS2 (c, "trying to eagerly subsume"); + unsigned needed = clause_size; + unsigned remain = c_size; + for (all_literals_in_clause (lit, c)) { + if (marks[lit] && !--needed) + break; + else if (--remain < needed) + break; + } + if (needed) + continue; + LOGCLS (c, "eagerly subsumed"); + kissat_mark_clause_as_garbage (solver, c); + p[-1] = INVALID_REF; + subsumed++; + INC (eagerly_subsumed); + } + for (all_stack (unsigned, lit, solver->clause)) + marks[lit] = 0; + if (subsumed) + flush_last_learned (solver); +} + +void kissat_learn_clause (kissat *solver) { + const unsigned not_uip = PEEK_STACK (solver->clause, 0); + const unsigned size = SIZE_STACK (solver->clause); + const size_t glue = SIZE_STACK (solver->levels); + assert (glue <= UINT_MAX); + if (!solver->probing) + kissat_update_learned (solver, glue, size); + assert (size > 0); + reference ref = INVALID_REF; + if (size == 1) + learn_unit (solver, not_uip); + else if (size == 2) + learn_binary (solver, not_uip); + else + ref = learn_reference (solver, not_uip, glue); + if (GET_OPTION (eagersubsume)) { + eagerly_subsume_last_learned (solver); + if (ref != INVALID_REF) + insert_last_learned (solver, ref); + } +} diff --git a/src/sat/kissat/learn.h b/src/sat/kissat/learn.h new file mode 100644 index 000000000..b11923966 --- /dev/null +++ b/src/sat/kissat/learn.h @@ -0,0 +1,10 @@ +#ifndef _learn_h_INCLUDED +#define _learn_h_INCLUDED + +struct kissat; + +void kissat_learn_clause (struct kissat *); +void kissat_update_learned (struct kissat *, unsigned glue, unsigned size); +unsigned kissat_determine_new_level (struct kissat *, unsigned jump); + +#endif diff --git a/src/sat/kissat/literal.h b/src/sat/kissat/literal.h new file mode 100644 index 000000000..75d7814c6 --- /dev/null +++ b/src/sat/kissat/literal.h @@ -0,0 +1,36 @@ +#ifndef _literal_h_INCLUDED +#define _literal_h_INCLUDED + +#include + +#define LD_MAX_VAR 30u +#define LD_MAX_LIT (1 + LD_MAX_VAR) + +#define EXTERNAL_MAX_VAR ((1 << LD_MAX_VAR) - 1) +#define INTERNAL_MAX_VAR ((1u << LD_MAX_VAR) - 2) +#define INTERNAL_MAX_LIT (2 * INTERNAL_MAX_VAR + 1) + +#define ILLEGAL_LIT ((1u << LD_MAX_LIT) - 1) + +#define INVALID_IDX UINT_MAX +#define INVALID_LIT UINT_MAX + +#define VALID_INTERNAL_INDEX(IDX) ((IDX) < VARS) + +#define VALID_INTERNAL_LITERAL(LIT) ((LIT) < LITS) + +#define VALID_EXTERNAL_LITERAL(LIT) \ + ((LIT) && ((LIT) != INT_MIN) && ABS (LIT) <= EXTERNAL_MAX_VAR) + +#define IDX(LIT) \ + (assert (VALID_INTERNAL_LITERAL (LIT)), (((unsigned) (LIT)) >> 1)) + +#define LIT(IDX) (assert (VALID_INTERNAL_INDEX (IDX)), ((IDX) << 1)) + +#define NOT(LIT) (assert (VALID_INTERNAL_LITERAL (LIT)), ((LIT) ^ 1u)) + +#define NEGATED(LIT) (assert (VALID_INTERNAL_LITERAL (LIT)), ((LIT) & 1u)) + +#define STRIP(LIT) (assert (VALID_INTERNAL_LITERAL (LIT)), ((LIT) & ~1u)) + +#endif diff --git a/src/sat/kissat/logging.c b/src/sat/kissat/logging.c new file mode 100644 index 000000000..36abd33ce --- /dev/null +++ b/src/sat/kissat/logging.c @@ -0,0 +1,456 @@ +#if defined(LOGGING) && !defined(QUIET) + +#include "colors.h" +#include "inline.h" + +#include +#include + +static void begin_logging (kissat *solver, const char *prefix, + const char *fmt, va_list *ap) { + TERMINAL (stdout, 1); + assert (GET_OPTION (log)); + fputs (solver->prefix, stdout); + COLOR (MAGENTA); + printf ("%s %u ", prefix, solver->level); + vprintf (fmt, *ap); +} + +static void end_logging (void) { + TERMINAL (stdout, 1); + fputc ('\n', stdout); + COLOR (NORMAL); + fflush (stdout); +} + +void kissat_begin_logging (kissat *solver, const char *prefix, + const char *fmt, ...) { + va_list ap; + va_start (ap, fmt); + begin_logging (solver, prefix, fmt, &ap); + va_end (ap); +} + +void kissat_end_logging (void) { end_logging (); } + +void kissat_log_msg (kissat *solver, const char *prefix, const char *fmt, + ...) { + va_list ap; + va_start (ap, fmt); + begin_logging (solver, prefix, fmt, &ap); + va_end (ap); + end_logging (); +} + +static void append_sprintf (char *str, const char *fmt, ...) { + va_list ap; + va_start (ap, fmt); + const size_t len = strlen (str); + vsprintf (str + len, fmt, ap); + va_end (ap); +} + +const char *kissat_log_repr (kissat *solver, unsigned lit, + const unsigned *repr) { + assert (solver); + char *res = kissat_next_format_string (&solver->format); + sprintf (res, "%u", lit); + if (!solver->compacting && GET_OPTION (log) > 1) + append_sprintf (res, "(%d)", kissat_export_literal (solver, lit)); + if (repr && repr[lit] != lit) { + strcat (res, "["); + unsigned repr_lit = repr[lit]; + append_sprintf (res, "%u", repr_lit); + if (!solver->compacting && GET_OPTION (log) > 1) + append_sprintf (res, "(%d)", + kissat_export_literal (solver, repr_lit)); + strcat (res, "]"); + } + if (!solver->compacting && GET_OPTION (log) > 1 && solver->values) { + const value value = VALUE (lit); + if (value) { + append_sprintf (res, "=%d", value); + if (solver->assigned) + append_sprintf (res, "@%u", LEVEL (lit)); + } + } + assert (strlen (res) < FORMAT_STRING_SIZE); + return res; +} + +const char *kissat_log_lit (kissat *solver, unsigned lit) { + return kissat_log_repr (solver, lit, 0); +} + +const char *kissat_log_var (kissat *solver, unsigned idx) { + assert (solver); + char *res = kissat_next_format_string (&solver->format); + const unsigned lit = LIT (idx); + sprintf (res, "variable %u (literal %s)", idx, LOGLIT (lit)); + assert (strlen (res) < FORMAT_STRING_SIZE); + return res; +} + +static void log_lits (kissat *solver, size_t size, const unsigned *lits, + const unsigned *counts) { + for (size_t i = 0; i < size; i++) { + const unsigned lit = lits[i]; + fputc (' ', stdout); + fputs (LOGLIT (lit), stdout); + if (counts) + printf ("#%u", counts[lit]); + } +} + +static void log_reprs (kissat *solver, size_t size, const unsigned *lits, + const unsigned *repr) { + for (size_t i = 0; i < size; i++) { + const unsigned lit = lits[i]; + fputc (' ', stdout); + fputs (LOGREPR (lit, repr), stdout); + } +} + +void kissat_log_lits (kissat *solver, const char *prefix, size_t size, + const unsigned *const lits, const char *fmt, ...) { + va_list ap; + va_start (ap, fmt); + begin_logging (solver, prefix, fmt, &ap); + va_end (ap); + printf (" size %zu clause", size); + log_lits (solver, size, lits, 0); + end_logging (); +} + +void kissat_log_litset (kissat *solver, const char *prefix, size_t size, + const unsigned *const lits, const char *fmt, ...) { + va_list ap; + va_start (ap, fmt); + begin_logging (solver, prefix, fmt, &ap); + va_end (ap); + printf (" size %zu literal set {", size); + log_lits (solver, size, lits, 0); + fputs (" }", stdout); + end_logging (); +} + +void kissat_log_litpart (kissat *solver, const char *prefix, size_t size, + const unsigned *const lits, const char *fmt, ...) { + va_list ap; + va_start (ap, fmt); + begin_logging (solver, prefix, fmt, &ap); + va_end (ap); + size_t classes = 0; + for (size_t i = 0; i < size; i++) + if (lits[i] == INVALID_LIT) + classes++; + printf (" %zu literals %zu classes literal partition [", size - classes, + classes); + for (size_t i = 0; i < size; i++) { + const unsigned lit = lits[i]; + if (lit == INVALID_LIT) { + if (i + 1 != size) + fputs (" |", stdout); + } else { + fputc (' ', stdout); + fputs (LOGLIT (lit), stdout); + } + } + fputs (" ]", stdout); + end_logging (); +} + +void kissat_log_counted_ref_lits (kissat *solver, const char *prefix, + reference ref, size_t size, + const unsigned *const lits, + const unsigned *const counts, + const char *fmt, ...) { + va_list ap; + va_start (ap, fmt); + begin_logging (solver, prefix, fmt, &ap); + va_end (ap); + printf (" size %zu clause", size); + printf ("[%u]", ref); + log_lits (solver, size, lits, counts); + end_logging (); +} + +void kissat_log_counted_lits (kissat *solver, const char *prefix, + size_t size, const unsigned *const lits, + const unsigned *const counts, const char *fmt, + ...) { + va_list ap; + va_start (ap, fmt); + begin_logging (solver, prefix, fmt, &ap); + va_end (ap); + printf (" size %zu literals", size); + log_lits (solver, size, lits, counts); + end_logging (); +} + +void kissat_log_resolvent (kissat *solver, const char *prefix, + const char *fmt, ...) { + va_list ap; + va_start (ap, fmt); + begin_logging (solver, prefix, fmt, &ap); + va_end (ap); + const size_t size = SIZE_STACK (solver->resolvent); + printf (" size %zu resolvent", size); + const unsigned *const lits = BEGIN_STACK (solver->resolvent); + log_lits (solver, size, lits, 0); + end_logging (); +} + +void kissat_log_ints (kissat *solver, const char *prefix, size_t size, + const int *const lits, const char *fmt, ...) { + va_list ap; + va_start (ap, fmt); + begin_logging (solver, prefix, fmt, &ap); + va_end (ap); + printf (" size %zu external literals clause", size); + for (size_t i = 0; i < size; i++) + printf (" %d", lits[i]); + end_logging (); +} + +void kissat_log_unsigneds (kissat *solver, const char *prefix, size_t size, + const unsigned *const lits, const char *fmt, + ...) { + va_list ap; + va_start (ap, fmt); + begin_logging (solver, prefix, fmt, &ap); + va_end (ap); + printf (" size %zu clause", size); + for (size_t i = 0; i < size; i++) + printf (" %u", lits[i]); + end_logging (); +} + +static void log_gate (kissat *solver, size_t id, const char *type, + const char *op, const char *empty_rhs_constant, + const unsigned *repr, unsigned lhs, size_t size, + const unsigned *rhs) { + printf (" arity %zu %s gate", size, type); + if (id != INVALID_GATE_ID) + printf ("[%zu]", id); + fputc (' ', stdout); + if (lhs == INVALID_LIT) + fputs ("", stdout); + else + fputs (LOGREPR (lhs, repr), stdout); + if (size) + for (size_t i = 0; i < size; i++) { + fputc (' ', stdout); + fputs (i ? op : ":=", stdout); + fputc (' ', stdout); + fputs (LOGREPR (rhs[i], repr), stdout); + } + else { + fputs (" := ", stdout); + fputs (empty_rhs_constant, stdout); + } +} + +void kissat_log_and_gate (kissat *solver, const char *prefix, size_t id, + unsigned *repr, unsigned lhs, size_t size, + const unsigned *rhs, const char *fmt, ...) { + va_list ap; + va_start (ap, fmt); + begin_logging (solver, prefix, fmt, &ap); + va_end (ap); + log_gate (solver, id, "AND", "&", "", repr, lhs, size, rhs); + end_logging (); +} + +void kissat_log_xor_gate (kissat *solver, const char *prefix, size_t id, + unsigned *repr, unsigned lhs, size_t size, + const unsigned *rhs, const char *fmt, ...) { + va_list ap; + va_start (ap, fmt); + begin_logging (solver, prefix, fmt, &ap); + va_end (ap); + log_gate (solver, id, "XOR", "^", "", repr, lhs, size, rhs); + end_logging (); +} + +void kissat_log_ite_gate (kissat *solver, const char *prefix, size_t id, + unsigned *repr, unsigned lhs, unsigned cond, + unsigned then_lit, unsigned else_lit, + const char *fmt, ...) { + va_list ap; + va_start (ap, fmt); + begin_logging (solver, prefix, fmt, &ap); + va_end (ap); + printf (" ITE gate"); + if (id != INVALID_GATE_ID) + printf ("[%zu]", id); + fputc (' ', stdout); + if (lhs == INVALID_LIT) + fputs ("", stdout); + else + fputs (LOGREPR (lhs, repr), stdout); + fputs (" := ", stdout); + fputs (LOGREPR (cond, repr), stdout); + fputs (" ? ", stdout); + fputs (LOGREPR (then_lit, repr), stdout); + fputs (" : ", stdout); + fputs (LOGREPR (else_lit, repr), stdout); + end_logging (); +} + +void kissat_log_extensions (kissat *solver, const char *prefix, size_t size, + const extension *const exts, const char *fmt, + ...) { + assert (size > 0); + va_list ap; + va_start (ap, fmt); + begin_logging (solver, prefix, fmt, &ap); + va_end (ap); + const extension *const begin = BEGIN_STACK (solver->extend); + const size_t pos = exts - begin; + printf (" extend[%zu]", pos); + printf (" %d", exts[0].lit); + if (size > 1) + fputs (" :", stdout); + for (size_t i = 1; i < size; i++) + printf (" %d", exts[i].lit); + end_logging (); +} + +static void log_clause (kissat *solver, const clause *c) { + fputc (' ', stdout); + if (c == &solver->conflict) { + fputs ("static ", stdout); + fputs (c->redundant ? "redundant" : "irredundant", stdout); + fputs (" binary conflict clause", stdout); + } else { + if (c->redundant) + printf ("redundant glue %u", c->glue); + else + fputs ("irredundant", stdout); + printf (" size %u", c->size); + if (c->reason) + fputs (" reason", stdout); + if (c->garbage) + fputs (" garbage", stdout); + fputs (" clause", stdout); + if (kissat_clause_in_arena (solver, c)) { + reference ref = kissat_reference_clause (solver, c); + printf ("[%u]", ref); + } + } +} + +void kissat_log_clause (kissat *solver, const char *prefix, const clause *c, + const char *fmt, ...) { + va_list ap; + va_start (ap, fmt); + begin_logging (solver, prefix, fmt, &ap); + va_end (ap); + log_clause (solver, c); + log_lits (solver, c->size, c->lits, 0); + end_logging (); +} + +void kissat_log_counted_clause (kissat *solver, const char *prefix, + const clause *c, const unsigned *counts, + const char *fmt, ...) { + va_list ap; + va_start (ap, fmt); + begin_logging (solver, prefix, fmt, &ap); + va_end (ap); + log_clause (solver, c); + log_lits (solver, c->size, c->lits, counts); + end_logging (); +} + +void kissat_log_repr_clause (kissat *solver, const char *prefix, + const clause *c, const unsigned *repr, + const char *fmt, ...) { + va_list ap; + va_start (ap, fmt); + begin_logging (solver, prefix, fmt, &ap); + va_end (ap); + log_clause (solver, c); + log_reprs (solver, c->size, c->lits, repr); + end_logging (); +} + +static void log_binary (kissat *solver, unsigned a, unsigned b) { + printf (" binary clause %s %s", LOGLIT (a), LOGLIT (b)); +} + +void kissat_log_binary (kissat *solver, const char *prefix, unsigned a, + unsigned b, const char *fmt, ...) { + va_list ap; + va_start (ap, fmt); + begin_logging (solver, prefix, fmt, &ap); + va_end (ap); + log_binary (solver, a, b); + end_logging (); +} + +void kissat_log_unary (kissat *solver, const char *prefix, unsigned a, + const char *fmt, ...) { + va_list ap; + va_start (ap, fmt); + begin_logging (solver, prefix, fmt, &ap); + va_end (ap); + printf (" unary clause %s", LOGLIT (a)); + end_logging (); +} + +static void log_ref (kissat *solver, reference ref) { + clause *c = kissat_dereference_clause (solver, ref); + log_clause (solver, c); + log_lits (solver, c->size, c->lits, 0); +} + +void kissat_log_ref (kissat *solver, const char *prefix, reference ref, + const char *fmt, ...) { + va_list ap; + va_start (ap, fmt); + begin_logging (solver, prefix, fmt, &ap); + va_end (ap); + log_ref (solver, ref); + end_logging (); +} + +void kissat_log_watch (kissat *solver, const char *prefix, unsigned lit, + watch watch, const char *fmt, ...) { + va_list ap; + va_start (ap, fmt); + begin_logging (solver, prefix, fmt, &ap); + va_end (ap); + if (watch.type.binary) + log_binary (solver, lit, watch.binary.lit); + else + log_ref (solver, watch.large.ref); + end_logging (); +} + +void kissat_log_xor (kissat *solver, const char *prefix, unsigned lit, + unsigned size, const unsigned *lits, const char *fmt, + ...) { + va_list ap; + va_start (ap, fmt); + begin_logging (solver, prefix, fmt, &ap); + va_end (ap); + printf (" size %u XOR gate ", size); + fputs (kissat_log_lit (solver, lit), stdout); + printf (" ="); + for (unsigned i = 0; i < size; i++) { + if (i) + fputs (" ^ ", stdout); + else + fputc (' ', stdout); + fputs (kissat_log_lit (solver, lits[i]), stdout); + } + end_logging (); +} + +#else + +int kissat_log_dummy_to_avoid_pedantic_warning; + +#endif diff --git a/src/sat/kissat/logging.h b/src/sat/kissat/logging.h new file mode 100644 index 000000000..bb2b53218 --- /dev/null +++ b/src/sat/kissat/logging.h @@ -0,0 +1,464 @@ +#ifndef _logging_h_INCLUDED +#define _logging_h_INCLUDED + +#if defined(LOGGING) && !defined(QUIET) + +#include "attribute.h" +#include "extend.h" +#include "reference.h" +#include "watch.h" + +#include + +// clang-format off + +const char * kissat_log_lit (kissat *, unsigned lit); +const char * kissat_log_var (kissat *, unsigned idx); +const char * kissat_log_repr (kissat *, unsigned lit, const unsigned *); + +void kissat_begin_logging (kissat *, const char *prefix, + const char *fmt, ...) +ATTRIBUTE_FORMAT (3, 4); + +void kissat_end_logging (void); + +void kissat_log_msg (kissat *, const char*, const char *fmt, ...) +ATTRIBUTE_FORMAT (3, 4); + +void kissat_log_clause (kissat *, const char*, const clause *, + const char *, ...) +ATTRIBUTE_FORMAT (4, 5); + +void kissat_log_counted_clause (kissat *, const char*, const clause *, + const unsigned *, const char *, ...) +ATTRIBUTE_FORMAT (5, 6); + +void kissat_log_repr_clause (kissat *, const char*, const clause *, + const unsigned *, const char *, ...) +ATTRIBUTE_FORMAT (5, 6); + +void kissat_log_binary (kissat *, const char*, + unsigned, unsigned, const char *, ...) +ATTRIBUTE_FORMAT (5, 6); + +void kissat_log_unary (kissat *, const char*, unsigned, const char *, ...) +ATTRIBUTE_FORMAT (4, 5); + +void kissat_log_lits (kissat *, const char*, + size_t, const unsigned *, const char *, ...) +ATTRIBUTE_FORMAT (5, 6); + +void kissat_log_litset (kissat *, const char*, + size_t, const unsigned *, const char *, ...) +ATTRIBUTE_FORMAT (5, 6); + +void kissat_log_litpart (kissat *, const char*, + size_t, const unsigned *, const char *, ...) +ATTRIBUTE_FORMAT (5, 6); + +void kissat_log_counted_ref_lits (kissat *, const char*, reference, + size_t, const unsigned *, + const unsigned * counts, const char *, ...) +ATTRIBUTE_FORMAT (7, 8); + +void kissat_log_counted_lits (kissat *, const char*, + size_t, const unsigned *, + const unsigned * counts, const char *, ...) +ATTRIBUTE_FORMAT (6, 7); + +void kissat_log_unsigneds (kissat *, const char*, + size_t, const unsigned *, const char *, ...) +ATTRIBUTE_FORMAT (5, 6); + +#define INVALID_GATE_ID (~(size_t)0) + +void kissat_log_and_gate (kissat *, const char*, size_t id, unsigned * repr, + unsigned lhs, size_t, const unsigned * rhs, + const char *, ...) +ATTRIBUTE_FORMAT (8, 9); + +void kissat_log_xor_gate (kissat *, const char*, size_t id, unsigned * repr, + unsigned lhs, size_t, const unsigned * rhs, + const char *, ...) +ATTRIBUTE_FORMAT (8, 9); + +void kissat_log_ite_gate (kissat *, const char*, size_t id, unsigned * repr, + unsigned lhs, unsigned cond, unsigned then_lit, + unsigned else_lit, const char *, ...) +ATTRIBUTE_FORMAT (9, 10); + +void kissat_log_ints (kissat *, const char*, + size_t, const int *, const char *, ...) +ATTRIBUTE_FORMAT (5, 6); + +void kissat_log_extensions (kissat *, const char *, + size_t, const extension *, const char *, ...) +ATTRIBUTE_FORMAT (5, 6); + +void kissat_log_xor (struct kissat *, const char*, unsigned lit, + unsigned size, const unsigned *lits, const char *fmt, ...) +ATTRIBUTE_FORMAT (6, 7); + +void kissat_log_ref (kissat *, const char*, reference, const char *, ...) +ATTRIBUTE_FORMAT (4, 5); + +void kissat_log_resolvent (kissat *, const char*, const char *, ...) +ATTRIBUTE_FORMAT (3, 4); + +void kissat_log_watch (kissat *, const char*, + unsigned, watch, const char *, ...) +ATTRIBUTE_FORMAT (5, 6); + +// clang-format on + +#ifndef LOGPREFIX +#define LOGPREFIX "LOG" +#endif + +#define LOG(...) \ + do { \ + if (solver && GET_OPTION (log)) \ + kissat_log_msg (solver, LOGPREFIX, __VA_ARGS__); \ + } while (0) + +#define LOG2(...) \ + do { \ + if (solver && GET_OPTION (log) > 1) \ + kissat_log_msg (solver, LOGPREFIX, __VA_ARGS__); \ + } while (0) + +#define LOG3(...) \ + do { \ + if (solver && GET_OPTION (log) > 2) \ + kissat_log_msg (solver, LOGPREFIX, __VA_ARGS__); \ + } while (0) + +#define LOG4(...) \ + do { \ + if (solver && GET_OPTION (log) > 3) \ + kissat_log_msg (solver, LOGPREFIX, __VA_ARGS__); \ + } while (0) + +#define LOG5(...) \ + do { \ + if (solver && GET_OPTION (log) > 4) \ + kissat_log_msg (solver, LOGPREFIX, __VA_ARGS__); \ + } while (0) + +#define LOGLITS(...) \ + do { \ + if (solver && GET_OPTION (log)) \ + kissat_log_lits (solver, LOGPREFIX, __VA_ARGS__); \ + } while (0) + +#define LOGLITSET(...) \ + do { \ + if (solver && GET_OPTION (log)) \ + kissat_log_litset (solver, LOGPREFIX, __VA_ARGS__); \ + } while (0) + +#define LOGLITPART(...) \ + do { \ + if (solver && GET_OPTION (log)) \ + kissat_log_litpart (solver, LOGPREFIX, __VA_ARGS__); \ + } while (0) + +#define LOGCOUNTEDREFLITS(...) \ + do { \ + if (solver && GET_OPTION (log)) \ + kissat_log_counted_ref_lits (solver, LOGPREFIX, __VA_ARGS__); \ + } while (0) + +#define LOGCOUNTEDLITS(...) \ + do { \ + if (solver && GET_OPTION (log)) \ + kissat_log_counted_lits (solver, LOGPREFIX, __VA_ARGS__); \ + } while (0) + +#define LOGLITS3(...) \ + do { \ + if (GET_OPTION (log) > 2) \ + kissat_log_lits (solver, LOGPREFIX, __VA_ARGS__); \ + } while (0) + +#define LOGRES(...) \ + do { \ + if (solver && GET_OPTION (log)) \ + kissat_log_resolvent (solver, LOGPREFIX, __VA_ARGS__); \ + } while (0) + +#define LOGRES2(...) \ + do { \ + if (solver && GET_OPTION (log) > 1) \ + kissat_log_resolvent (solver, LOGPREFIX, __VA_ARGS__); \ + } while (0) + +#define LOGEXT(...) \ + do { \ + if (GET_OPTION (log)) \ + kissat_log_extensions (solver, LOGPREFIX, __VA_ARGS__); \ + } while (0) + +#define LOGEXT2(...) \ + do { \ + if (GET_OPTION (log) > 1) \ + kissat_log_extensions (solver, LOGPREFIX, __VA_ARGS__); \ + } while (0) + +#define LOGINTS(...) \ + do { \ + if (solver && GET_OPTION (log)) \ + kissat_log_ints (solver, LOGPREFIX, __VA_ARGS__); \ + } while (0) + +#define LOGINTS3(...) \ + do { \ + if (GET_OPTION (log) > 2) \ + kissat_log_ints (solver, LOGPREFIX, __VA_ARGS__); \ + } while (0) + +#define LOGUNSIGNEDS2(...) \ + do { \ + if (GET_OPTION (log) > 1) \ + kissat_log_unsigneds (solver, LOGPREFIX, __VA_ARGS__); \ + } while (0) + +#define LOGUNSIGNEDS3(...) \ + do { \ + if (GET_OPTION (log) > 2) \ + kissat_log_unsigneds (solver, LOGPREFIX, __VA_ARGS__); \ + } while (0) + +#define LOGANDGATE(...) \ + do { \ + if (GET_OPTION (log) > 0) \ + kissat_log_and_gate (solver, LOGPREFIX, __VA_ARGS__); \ + } while (0) + +#define LOGXORGATE(...) \ + do { \ + if (GET_OPTION (log) > 0) \ + kissat_log_xor_gate (solver, LOGPREFIX, __VA_ARGS__); \ + } while (0) + +#define LOGITEGATE(...) \ + do { \ + if (GET_OPTION (log) > 0) \ + kissat_log_ite_gate (solver, LOGPREFIX, __VA_ARGS__); \ + } while (0) + +#define LOGCLS(...) \ + do { \ + if (solver && GET_OPTION (log)) \ + kissat_log_clause (solver, LOGPREFIX, __VA_ARGS__); \ + } while (0) + +#define LOGCOUNTEDCLS(...) \ + do { \ + if (solver && GET_OPTION (log)) \ + kissat_log_counted_clause (solver, LOGPREFIX, __VA_ARGS__); \ + } while (0) + +#define LOGREPRCLS(...) \ + do { \ + if (solver && GET_OPTION (log)) \ + kissat_log_repr_clause (solver, LOGPREFIX, __VA_ARGS__); \ + } while (0) + +#define LOGLINE(...) \ + do { \ + if (solver && GET_OPTION (log)) \ + kissat_log_line (solver, LOGPREFIX, __VA_ARGS__); \ + } while (0) + +#define LOGCLS2(...) \ + do { \ + if (GET_OPTION (log) > 1) \ + kissat_log_clause (solver, LOGPREFIX, __VA_ARGS__); \ + } while (0) + +#define LOGCLS3(...) \ + do { \ + if (GET_OPTION (log) > 2) \ + kissat_log_clause (solver, LOGPREFIX, __VA_ARGS__); \ + } while (0) + +#define LOGREF(...) \ + do { \ + if (solver && GET_OPTION (log)) \ + kissat_log_ref (solver, LOGPREFIX, __VA_ARGS__); \ + } while (0) + +#define LOGREF2(...) \ + do { \ + if (solver && GET_OPTION (log) > 1) \ + kissat_log_ref (solver, LOGPREFIX, __VA_ARGS__); \ + } while (0) + +#define LOGREF3(...) \ + do { \ + if (solver && GET_OPTION (log) > 2) \ + kissat_log_ref (solver, LOGPREFIX, __VA_ARGS__); \ + } while (0) + +#define LOGBINARY(...) \ + do { \ + if (solver && GET_OPTION (log)) \ + kissat_log_binary (solver, LOGPREFIX, __VA_ARGS__); \ + } while (0) + +#define LOGBINARY2(...) \ + do { \ + if (GET_OPTION (log) > 1) \ + kissat_log_binary (solver, LOGPREFIX, __VA_ARGS__); \ + } while (0) + +#define LOGBINARY3(...) \ + do { \ + if (GET_OPTION (log) > 2) \ + kissat_log_binary (solver, LOGPREFIX, __VA_ARGS__); \ + } while (0) + +#define LOGUNARY(...) \ + do { \ + if (solver && GET_OPTION (log)) \ + kissat_log_unary (solver, LOGPREFIX, __VA_ARGS__); \ + } while (0) + +#define LOGLIT(LIT) kissat_log_lit (solver, (LIT)) +#define LOGVAR(IDX) kissat_log_var (solver, (IDX)) +#define LOGREPR(LIT, REPR) kissat_log_repr (solver, (LIT), (REPR)) + +#define LOGWATCH(...) \ + do { \ + if (GET_OPTION (log)) \ + kissat_log_watch (solver, LOGPREFIX, __VA_ARGS__); \ + } while (0) + +#define LOGXOR(...) \ + do { \ + if (GET_OPTION (log)) \ + kissat_log_xor (solver, LOGPREFIX, __VA_ARGS__); \ + } while (0) + +#else + +#define LOG(...) \ + do { \ + } while (0) +#define LOG2(...) \ + do { \ + } while (0) +#define LOG3(...) \ + do { \ + } while (0) +#define LOG4(...) \ + do { \ + } while (0) +#define LOG5(...) \ + do { \ + } while (0) +#define LOGRES(...) \ + do { \ + } while (0) +#define LOGRES2(...) \ + do { \ + } while (0) +#define LOGLITS(...) \ + do { \ + } while (0) +#define LOGLITSET(...) \ + do { \ + } while (0) +#define LOGLITPART(...) \ + do { \ + } while (0) +#define LOGLITS3(...) \ + do { \ + } while (0) +#define LOGCOUNTEDREFLITS(...) \ + do { \ + } while (0) +#define LOGCOUNTEDLITS(...) \ + do { \ + } while (0) +#define LOGEXT(...) \ + do { \ + } while (0) +#define LOGEXT2(...) \ + do { \ + } while (0) +#define LOGINTS(...) \ + do { \ + } while (0) +#define LOGINTS3(...) \ + do { \ + } while (0) +#define LOGUNSIGNEDS2(...) \ + do { \ + } while (0) +#define LOGUNSIGNEDS3(...) \ + do { \ + } while (0) +#define LOGANDGATE(...) \ + do { \ + } while (0) +#define LOGXORGATE(...) \ + do { \ + } while (0) +#define LOGITEGATE(...) \ + do { \ + } while (0) +#define LOGCLS(...) \ + do { \ + } while (0) +#define LOGCLS2(...) \ + do { \ + } while (0) +#define LOGCLS3(...) \ + do { \ + } while (0) +#define LOGCOUNTEDCLS(...) \ + do { \ + } while (0) +#define LOGREPRCLS(...) \ + do { \ + } while (0) +#define LOGLINE(...) \ + do { \ + } while (0) +#define LOGREF(...) \ + do { \ + } while (0) +#define LOGREF2(...) \ + do { \ + } while (0) +#define LOGREF3(...) \ + do { \ + } while (0) +#define LOGBINARY(...) \ + do { \ + } while (0) +#define LOGBINARY2(...) \ + do { \ + } while (0) +#define LOGBINARY3(...) \ + do { \ + } while (0) +#define LOGUNARY(...) \ + do { \ + } while (0) +#define LOGWATCH(...) \ + do { \ + } while (0) +#define LOGXOR(...) \ + do { \ + } while (0) + +#endif + +#define LOGTMP(...) \ + LOGLITS (SIZE_STACK (solver->clause), BEGIN_STACK (solver->clause), \ + __VA_ARGS__) + +#endif diff --git a/src/sat/kissat/lucky.c b/src/sat/kissat/lucky.c new file mode 100644 index 000000000..74219b095 --- /dev/null +++ b/src/sat/kissat/lucky.c @@ -0,0 +1,393 @@ +#include "lucky.h" +#include "analyze.h" +#include "backtrack.h" +#include "decide.h" +#include "inline.h" +#include "internal.h" +#include "print.h" +#include "proprobe.h" +#include "report.h" + +static bool no_all_negative_clauses (struct kissat *solver) { + clause *last_irredundant = kissat_last_irredundant_clause (solver); + for (all_clauses (c)) { + if (last_irredundant && last_irredundant < c) + break; + if (c->redundant) + continue; + if (c->garbage) + continue; + for (all_literals_in_clause (lit, c)) + if (!NEGATED (lit) && VALUE (lit) >= 0) + goto CONTINUE_WITH_NEXT_CLAUSE; + kissat_verbose (solver, "found all negative large clause"); + return false; + CONTINUE_WITH_NEXT_CLAUSE:; + } + assert (solver->watching); + for (all_variables (idx)) { + if (!ACTIVE (idx)) + continue; + const unsigned lit = LIT (idx); + const unsigned not_lit = NOT (lit); + for (all_binary_blocking_watches (watch, WATCHES (not_lit))) { + if (!watch.type.binary) + continue; + const unsigned other = watch.binary.lit; + if (NEGATED (other) && ACTIVE (IDX (other))) { + kissat_verbose (solver, "found all negative binary clause"); + return false; + } + } + } + kissat_message (solver, "lucky no all-negative clause"); + return true; +} + +static bool no_all_positive_clauses (struct kissat *solver) { + clause *last_irredundant = kissat_last_irredundant_clause (solver); + for (all_clauses (c)) { + if (last_irredundant && last_irredundant < c) + break; + if (c->redundant) + continue; + if (c->garbage) + continue; + for (all_literals_in_clause (lit, c)) + if (NEGATED (lit) && VALUE (lit) >= 0) + goto CONTINUE_WITH_NEXT_CLAUSE; + kissat_verbose (solver, "found all positive large clause"); + return false; + CONTINUE_WITH_NEXT_CLAUSE:; + } + assert (solver->watching); + for (all_variables (idx)) { + if (!ACTIVE (idx)) + continue; + const unsigned lit = LIT (idx); + for (all_binary_blocking_watches (watch, WATCHES (lit))) { + if (!watch.type.binary) + continue; + const unsigned other = watch.binary.lit; + if (!NEGATED (other) && ACTIVE (IDX (other))) { + kissat_verbose (solver, "found all positive binary clause"); + return false; + } + } + } + kissat_message (solver, "lucky no all-positive clause"); + return true; +} + +static int forward_false_satisfiable (struct kissat *solver) { + assert (!solver->level); +#ifndef QUIET + unsigned conflicts = 0; +#endif + for (all_stack (import, import, solver->import)) { + if (!import.imported) + continue; + if (import.eliminated) + continue; + const unsigned lit = import.lit; + const unsigned idx = IDX (lit); + if (!ACTIVE (idx)) + continue; + if (VALUE (lit)) + continue; + const unsigned not_lit = NOT (lit); + kissat_internal_assume (solver, not_lit); + clause *c = kissat_probing_propagate (solver, 0, true); + if (!c) + continue; +#ifndef QUIET + conflicts++; +#endif + if (solver->level > 1) { + kissat_backtrack_without_updating_phases (solver, solver->level - 1); + kissat_internal_assume (solver, lit); + clause *d = kissat_probing_propagate (solver, 0, true); + if (!d) + continue; + kissat_verbose (solver, + "inconsistency after %u conflicts " + "forward assigning %u variables to false", + conflicts, solver->level); + kissat_backtrack_without_updating_phases (solver, 0); + return 0; + } else { + LOG ("failed literal %s", LOGLIT (not_lit)); + kissat_analyze (solver, c); + assert (!solver->level); + clause *d = kissat_probing_propagate (solver, 0, true); + if (d) { + kissat_analyze (solver, d); + assert (solver->inconsistent); + kissat_verbose (solver, + "lucky inconsistency forward assigning to false"); + return 20; + } + } + } + + kissat_message (solver, "lucky in forward setting literals to false"); + return 10; +} + +static int forward_true_satisfiable (struct kissat *solver) { + assert (!solver->level); +#ifndef QUIET + unsigned conflicts = 0; +#endif + for (all_stack (import, import, solver->import)) { + if (!import.imported) + continue; + if (import.eliminated) + continue; + const unsigned lit = import.lit; + const unsigned idx = IDX (lit); + if (!ACTIVE (idx)) + continue; + if (VALUE (lit)) + continue; + kissat_internal_assume (solver, lit); + clause *c = kissat_probing_propagate (solver, 0, true); + if (!c) + continue; +#ifndef QUIET + conflicts++; +#endif + if (solver->level > 1) { + kissat_backtrack_without_updating_phases (solver, solver->level - 1); + const unsigned not_lit = NOT (lit); + kissat_internal_assume (solver, not_lit); + clause *d = kissat_probing_propagate (solver, 0, true); + if (!d) + continue; + kissat_verbose (solver, + "inconsistency after %u conflicts " + "forward assigning %u variables to true", + conflicts, solver->level); + kissat_backtrack_without_updating_phases (solver, 0); + return 0; + } else { + LOG ("failed literal %s", LOGLIT (lit)); + kissat_analyze (solver, c); + assert (!solver->level); + clause *d = kissat_probing_propagate (solver, 0, true); + if (d) { + kissat_analyze (solver, d); + assert (solver->inconsistent); + kissat_verbose (solver, + "lucky inconsistency forward assigning to true"); + return 20; + } + } + } + kissat_message (solver, "lucky in forward setting literals to true"); + return 10; +} + +static int backward_false_satisfiable (struct kissat *solver) { + assert (!solver->level); +#ifndef QUIET + unsigned conflicts = 0; +#endif + import *begin = BEGIN_STACK (solver->import); + import *end = END_STACK (solver->import); + import *p = end; + while (p != begin) { + const import import = *--p; + if (!import.imported) + continue; + if (import.eliminated) + continue; + const unsigned lit = import.lit; + const unsigned idx = IDX (lit); + if (!ACTIVE (idx)) + continue; + if (VALUE (lit)) + continue; + const unsigned not_lit = NOT (lit); + kissat_internal_assume (solver, not_lit); + clause *c = kissat_probing_propagate (solver, 0, true); + if (!c) + continue; +#ifndef QUIET + conflicts++; +#endif + if (solver->level > 1) { + kissat_backtrack_without_updating_phases (solver, solver->level - 1); + kissat_internal_assume (solver, lit); + clause *d = kissat_probing_propagate (solver, 0, true); + if (!d) + continue; + kissat_verbose (solver, + "inconsistency after %u conflicts " + "backward assigning %u variables to false", + conflicts, solver->level); + kissat_backtrack_without_updating_phases (solver, 0); + return 0; + } else { + LOG ("failed literal %s", LOGLIT (not_lit)); + kissat_analyze (solver, c); + assert (!solver->level); + clause *d = kissat_probing_propagate (solver, 0, true); + if (d) { + kissat_analyze (solver, d); + assert (solver->inconsistent); + kissat_verbose (solver, + "lucky inconsistency backward assigning to false"); + return 20; + } + } + } + kissat_message (solver, "lucky in backward setting literals to false"); + return 10; +} + +static int backward_true_satisfiable (struct kissat *solver) { + assert (!solver->level); +#ifndef QUIET + unsigned conflicts = 0; +#endif + import *begin = BEGIN_STACK (solver->import); + import *end = END_STACK (solver->import); + import *p = end; + while (p != begin) { + const import import = *--p; + if (!import.imported) + continue; + if (import.eliminated) + continue; + const unsigned lit = import.lit; + const unsigned idx = IDX (lit); + if (!ACTIVE (idx)) + continue; + if (VALUE (lit)) + continue; + kissat_internal_assume (solver, lit); + clause *c = kissat_probing_propagate (solver, 0, true); + if (!c) + continue; +#ifndef QUIET + conflicts++; +#endif + if (solver->level > 1) { + kissat_backtrack_without_updating_phases (solver, solver->level - 1); + const unsigned not_lit = NOT (lit); + kissat_internal_assume (solver, not_lit); + clause *d = kissat_probing_propagate (solver, 0, true); + if (!d) + continue; + kissat_verbose (solver, + "inconsistency after %u conflicts " + "backward assigning %u variables to true", + conflicts, solver->level); + kissat_backtrack_without_updating_phases (solver, 0); + return 0; + } else { + LOG ("failed literal %s", LOGLIT (lit)); + kissat_analyze (solver, c); + assert (!solver->level); + clause *d = kissat_probing_propagate (solver, 0, true); + if (d) { + kissat_analyze (solver, d); + assert (solver->inconsistent); + kissat_verbose (solver, + "lucky inconsistency backward assigning to true"); + return 20; + } + } + } + kissat_message (solver, "lucky in backward setting literals to true"); + return 10; +} + +int kissat_lucky (struct kissat *solver) { + + if (solver->inconsistent) + return 0; + + if (!GET_OPTION (lucky)) + return 0; + + START (lucky); + assert (!solver->level); + assert (!solver->probing); + solver->probing = true; + assert (kissat_propagated (solver)); + + int res = 0; + + if (no_all_negative_clauses (solver)) { + for (all_variables (idx)) { + if (!ACTIVE (idx)) + continue; + const unsigned lit = LIT (idx); + if (VALUE (lit)) + continue; + kissat_internal_assume (solver, lit); +#ifndef NDEBUG + clause *c = +#endif + kissat_probing_propagate (solver, 0, true); + assert (!c); + } + kissat_verbose (solver, "set all variables to true"); + assert (kissat_propagated (solver)); + assert (!solver->unassigned); + res = 10; + } + + if (!res && no_all_positive_clauses (solver)) { + for (all_variables (idx)) { + if (!ACTIVE (idx)) + continue; + const unsigned lit = LIT (idx); + if (VALUE (lit)) + continue; + const unsigned not_lit = NOT (lit); + kissat_internal_assume (solver, not_lit); +#ifndef NDEBUG + clause *c = +#endif + kissat_probing_propagate (solver, 0, true); + assert (!c); + } + kissat_verbose (solver, "set all variables to false"); + assert (kissat_propagated (solver)); + assert (!solver->unassigned); + res = 10; + } + + const unsigned active_before = solver->active; + + if (!res) + res = forward_false_satisfiable (solver); + + if (!res) + res = forward_true_satisfiable (solver); + + if (!res) + res = backward_false_satisfiable (solver); + + if (!res) + res = backward_true_satisfiable (solver); + + const unsigned active_after = solver->active; + const unsigned units = active_before - active_after; + + if (!res && units) + kissat_message (solver, "lucky %u units", units); + +#ifndef QUIET + bool success = res || units; +#endif + assert (solver->probing); + solver->probing = false; + REPORT (!success, 'l'); + STOP (lucky); + + return res; +} diff --git a/src/sat/kissat/lucky.h b/src/sat/kissat/lucky.h new file mode 100644 index 000000000..ef97c67dc --- /dev/null +++ b/src/sat/kissat/lucky.h @@ -0,0 +1,7 @@ +#ifndef _lucky_h_INCLUDED +#define _lucky_h_INCLUDED + +struct kissat; +int kissat_lucky (struct kissat *); + +#endif diff --git a/src/sat/kissat/minimize.c b/src/sat/kissat/minimize.c new file mode 100644 index 000000000..94dcb63d5 --- /dev/null +++ b/src/sat/kissat/minimize.c @@ -0,0 +1,211 @@ +#include "minimize.h" +#include "inline.h" + +static inline int minimized_index (kissat *solver, bool minimizing, + assigned *a, unsigned lit, unsigned idx, + unsigned depth) { +#if !defined(LOGGING) && defined(NDEBUG) + (void) lit; +#endif +#ifdef NDEBUG + (void) idx; +#endif + assert (IDX (lit) == idx); + assert (solver->assigned + idx == a); + if (!a->level) { + LOG2 ("skipping root level literal %s", LOGLIT (lit)); + return 1; + } + if (a->removable && depth) { + LOG2 ("skipping removable literal %s", LOGLIT (lit)); + return 1; + } + assert (a->reason != UNIT_REASON); + if (a->reason == DECISION_REASON) { + LOG2 ("can not remove decision literal %s", LOGLIT (lit)); + return -1; + } + if (a->poisoned) { + LOG2 ("can not remove poisoned literal %s", LOGLIT (lit)); + return -1; + } + if (minimizing || !depth) { + frame *frame = &FRAME (a->level); + if (frame->used <= 1) { + LOG2 ("can not remove singleton frame literal %s", LOGLIT (lit)); + return -1; + } + } + return 0; +} + +static bool minimize_literal (kissat *, bool, assigned *, unsigned lit, + unsigned depth); + +static inline bool minimize_reference (kissat *solver, bool minimizing, + assigned *assigned, reference ref, + unsigned lit, unsigned depth) { + const unsigned next_depth = (depth == UINT_MAX) ? depth : depth + 1; + const unsigned not_lit = NOT (lit); + clause *c = kissat_dereference_clause (solver, ref); + if (GET_OPTION (minimizeticks)) + INC (search_ticks); + for (all_literals_in_clause (other, c)) + if (other != not_lit && + !minimize_literal (solver, minimizing, assigned, other, next_depth)) + return false; + return true; +} + +static inline bool minimize_binary (kissat *solver, bool minimizing, + assigned *assigned, unsigned lit, + unsigned depth) { + const size_t saved = SIZE_STACK (solver->minimize); + bool res; + for (unsigned next = lit;;) { + const unsigned next_idx = IDX (next); + struct assigned *a = assigned + next_idx; + int tmp = minimized_index (solver, minimizing, a, next, next_idx, 1); + if (tmp) { + res = (tmp > 0); + break; + } + PUSH_STACK (solver->minimize, next_idx); + if (!a->binary) { + const unsigned next_depth = (depth == UINT_MAX) ? depth : depth + 1; + res = minimize_reference (solver, minimizing, assigned, a->reason, + next, next_depth); + break; + } + next = a->reason; + } + unsigned *begin = BEGIN_STACK (solver->minimize) + saved; + const unsigned *const end = END_STACK (solver->minimize); + assert (begin <= end); + if (res) + for (const unsigned *p = begin; p != end; p++) + kissat_push_removable (solver, assigned, *p); + else + for (const unsigned *p = begin; p != end; p++) + kissat_push_poisoned (solver, assigned, *p); + SET_END_OF_STACK (solver->minimize, begin); + return res; +} + +static bool minimize_literal (kissat *solver, bool minimizing, + assigned *assigned, unsigned lit, + unsigned depth) { + LOG ("trying to minimize literal %s at recursion depth %d", LOGLIT (lit), + depth); + assert (VALUE (lit) < 0); + assert (depth || EMPTY_STACK (solver->minimize)); + assert (GET_OPTION (minimizedepth) > 0); + if (depth >= (unsigned) GET_OPTION (minimizedepth)) + return false; + const unsigned idx = IDX (lit); + struct assigned *a = assigned + idx; + int tmp = minimized_index (solver, minimizing, a, lit, idx, depth); + if (tmp > 0) + return true; + if (tmp < 0) + return false; +#ifdef LOGGING + const unsigned not_lit = NOT (lit); +#endif + bool res; + if (a->binary) { + const unsigned other = a->reason; + LOGBINARY2 (not_lit, other, "minimizing along %s reason", + LOGLIT (not_lit)); + res = minimize_binary (solver, minimizing, assigned, other, depth); + } else { + const reference ref = a->reason; + LOGREF2 (ref, "minimizing along %s reason", LOGLIT (not_lit)); + res = + minimize_reference (solver, minimizing, assigned, ref, lit, depth); + } + if (!depth) + return res; + if (!res) + kissat_push_poisoned (solver, assigned, idx); + else if (!a->removable) + kissat_push_removable (solver, assigned, idx); + return res; +} + +bool kissat_minimize_literal (kissat *solver, unsigned lit, + bool lit_in_clause) { + assert (EMPTY_STACK (solver->minimize)); + return minimize_literal (solver, false, solver->assigned, lit, + !lit_in_clause); +} + +void kissat_reset_poisoned (kissat *solver) { + LOG ("reset %zu poisoned variables", SIZE_STACK (solver->poisoned)); + assigned *assigned = solver->assigned; + for (all_stack (unsigned, idx, solver->poisoned)) { + assert (idx < VARS); + struct assigned *a = assigned + idx; + assert (a->poisoned); + a->poisoned = false; + } + CLEAR_STACK (solver->poisoned); +} + +void kissat_minimize_clause (kissat *solver) { + START (minimize); + + assert (EMPTY_STACK (solver->minimize)); + assert (EMPTY_STACK (solver->removable)); + assert (EMPTY_STACK (solver->poisoned)); + assert (!EMPTY_STACK (solver->clause)); + + unsigned *lits = BEGIN_STACK (solver->clause); + unsigned *end = END_STACK (solver->clause); + + assigned *assigned = solver->assigned; +#ifndef NDEBUG + assert (lits < end); + const unsigned not_uip = lits[0]; + assert (assigned[IDX (not_uip)].level == solver->level); +#endif + for (const unsigned *p = lits; p != end; p++) + kissat_push_removable (solver, assigned, IDX (*p)); + + if (GET_OPTION (shrink) > 2) { + STOP (minimize); + return; + } + + unsigned minimized = 0; + + for (unsigned *p = end; --p > lits;) { + const unsigned lit = *p; + assert (lit != not_uip); + if (minimize_literal (solver, true, assigned, lit, 0)) { + LOG ("minimized literal %s", LOGLIT (lit)); + *p = INVALID_LIT; + minimized++; + } else + LOG ("keeping literal %s", LOGLIT (lit)); + } + + unsigned *q = lits; + for (const unsigned *p = lits; p != end; p++) { + const unsigned lit = *p; + if (lit != INVALID_LIT) + *q++ = lit; + } + assert (q + minimized == end); + SET_END_OF_STACK (solver->clause, q); + LOG ("clause minimization removed %u literals", minimized); + + assert (!solver->probing); + ADD (literals_minimized, minimized); + + LOGTMP ("minimized learned"); + + kissat_reset_poisoned (solver); + + STOP (minimize); +} diff --git a/src/sat/kissat/minimize.h b/src/sat/kissat/minimize.h new file mode 100644 index 000000000..ae06fb9ad --- /dev/null +++ b/src/sat/kissat/minimize.h @@ -0,0 +1,14 @@ +#ifndef _minimize_h_INCLUDED +#define _minimize_h_INCLUDED + +#include + +struct kissat; + +void kissat_reset_poisoned (struct kissat *); + +void kissat_minimize_clause (struct kissat *); +bool kissat_minimize_literal (struct kissat *, unsigned, + bool lit_in_clause); + +#endif diff --git a/src/sat/kissat/mode.c b/src/sat/kissat/mode.c new file mode 100644 index 000000000..b1390eca1 --- /dev/null +++ b/src/sat/kissat/mode.c @@ -0,0 +1,215 @@ +#include "bump.h" +#include "decide.h" +#include "inline.h" +#include "print.h" +#include "report.h" +#include "resources.h" +#include "restart.h" + +#include + +#ifndef QUIET + +static const char *mode_string (kissat *solver) { + return solver->stable ? "stable" : "focused"; +} + +#endif + +void kissat_init_mode_limit (kissat *solver) { + limits *limits = &solver->limits; + + if (GET_OPTION (stable) == 1) { + assert (!solver->stable); + + const uint64_t conflicts_delta = GET_OPTION (modeinit); + const uint64_t conflicts_limit = CONFLICTS + conflicts_delta; + + assert (conflicts_limit); + + limits->mode.conflicts = conflicts_limit; + limits->mode.ticks = 0; + limits->mode.count = 0; + + kissat_very_verbose (solver, + "initial %s mode switching limit " + "at %s after %s conflicts", + mode_string (solver), + FORMAT_COUNT (conflicts_limit), + FORMAT_COUNT (conflicts_delta)); + + solver->mode.ticks = solver->statistics.search_ticks; +#ifndef QUIET + solver->mode.conflicts = CONFLICTS; +#ifdef METRICS + solver->mode.propagations = solver->statistics.search_propagations; +#endif + // clang-format off + solver->mode.entered = kissat_process_time (); + kissat_very_verbose (solver, + "starting %s mode at %.2f seconds " + "(%" PRIu64 " conflicts, %" PRIu64 " ticks" +#ifdef METRICS + ", %" PRIu64 " propagations, %" PRIu64 " visits" +#endif + ")", mode_string (solver), + solver->mode.entered, solver->mode.conflicts, solver->mode.ticks +#ifdef METRICS + , solver->mode.propagations, solver->mode.visits +#endif + ); +// clang-format on +#endif + } else + kissat_very_verbose (solver, + "no need to set mode limit (only %s mode enabled)", + mode_string (solver)); +} + +static void update_mode_limit (kissat *solver, uint64_t delta_ticks) { + kissat_init_averages (solver, &AVERAGES); + + limits *limits = &solver->limits; + statistics *statistics = &solver->statistics; + + assert (GET_OPTION (stable) == 1); + + if (limits->mode.count & 1) { + limits->mode.ticks = statistics->search_ticks + delta_ticks; +#ifndef QUIET + assert (solver->stable); + kissat_phase (solver, "stable", GET (stable_modes), + "new stable mode switching limit of %s " + "after %s ticks", + FORMAT_COUNT (limits->mode.ticks), + FORMAT_COUNT (delta_ticks)); +#endif + } else { + assert (limits->mode.ticks); + const uint64_t interval = GET_OPTION (modeint); + const uint64_t count = (statistics->switched + 1) / 2; + const uint64_t scaled = interval * kissat_nlogpown (count, 4); + limits->mode.conflicts = statistics->conflicts + scaled; +#ifndef QUIET + assert (!solver->stable); + kissat_phase (solver, "focused", GET (focused_modes), + "new focused mode switching limit of %s " + "after %s conflicts", + FORMAT_COUNT (limits->mode.conflicts), + FORMAT_COUNT (scaled)); +#endif + } + + solver->mode.ticks = statistics->search_ticks; +#ifndef QUIET + solver->mode.conflicts = statistics->conflicts; +#ifdef METRICS + solver->mode.propagations = statistics->search_propagations; +#endif +#endif +} + +static void report_switching_from_mode (kissat *solver, + uint64_t *delta_ticks) { + statistics *statistics = &solver->statistics; + *delta_ticks = statistics->search_ticks - solver->mode.ticks; + +#ifndef QUIET + if (kissat_verbosity (solver) < 2) + return; + + const double current_time = kissat_process_time (); + const double delta_time = current_time - solver->mode.entered; + + const uint64_t delta_conflicts = + statistics->conflicts - solver->mode.conflicts; +#ifdef METRICS + const uint64_t delta_propagations = + statistics->search_propagations - solver->mode.propagations; +#endif + solver->mode.entered = current_time; + + // clang-format off + kissat_very_verbose (solver, "%s mode took %.2f seconds " + "(%s conflicts, %s ticks" +#ifdef METRICS + ", %s propagations" +#endif + ")", solver->stable ? "stable" : "focused", + delta_time, FORMAT_COUNT (delta_conflicts), FORMAT_COUNT (*delta_ticks) +#ifdef METRICS + , FORMAT_COUNT (delta_propagations) +#endif + ); + // clang-format on +#else + (void) solver; +#endif +} + +static void switch_to_focused_mode (kissat *solver) { + assert (solver->stable); + uint64_t delta; + report_switching_from_mode (solver, &delta); + REPORT (0, ']'); + STOP (stable); + INC (focused_modes); + kissat_phase (solver, "focus", GET (focused_modes), + "switching to focused mode after %s conflicts", + FORMAT_COUNT (CONFLICTS)); + solver->stable = false; + update_mode_limit (solver, delta); + START (focused); + REPORT (0, '{'); + kissat_reset_search_of_queue (solver); + kissat_update_focused_restart_limit (solver); +} + +static void switch_to_stable_mode (kissat *solver) { + assert (!solver->stable); + uint64_t delta; + report_switching_from_mode (solver, &delta); + REPORT (0, '}'); + STOP (focused); + INC (stable_modes); + solver->stable = true; + kissat_phase (solver, "stable", GET (stable_modes), + "switched to stable mode after %" PRIu64 " conflicts", + CONFLICTS); + update_mode_limit (solver, delta); + START (stable); + REPORT (0, '['); + kissat_init_reluctant (solver); + kissat_update_scores (solver); +} + +bool kissat_switching_search_mode (kissat *solver) { + assert (!solver->inconsistent); + + if (GET_OPTION (stable) != 1) + return false; + + limits *limits = &solver->limits; + statistics *statistics = &solver->statistics; + + if (limits->mode.count & 1) + return statistics->search_ticks >= limits->mode.ticks; + else + return statistics->conflicts >= limits->mode.conflicts; +} + +void kissat_switch_search_mode (kissat *solver) { + assert (kissat_switching_search_mode (solver)); + + INC (switched); + solver->limits.mode.count++; + + if (solver->stable) + switch_to_focused_mode (solver); + else + switch_to_stable_mode (solver); + + solver->averages[solver->stable].saved_decisions = DECISIONS; + + kissat_start_random_sequence (solver); +} diff --git a/src/sat/kissat/mode.h b/src/sat/kissat/mode.h new file mode 100644 index 000000000..915e746e4 --- /dev/null +++ b/src/sat/kissat/mode.h @@ -0,0 +1,24 @@ +#ifndef _mode_h_INCLUDED +#define _mode_h_INCLUDED + +struct kissat; + +typedef struct mode mode; + +struct mode { + uint64_t ticks; +#ifndef QUIET + double entered; + uint64_t conflicts; +#ifdef METRICS + uint64_t propagations; + uint64_t visits; +#endif +#endif +}; + +void kissat_init_mode_limit (struct kissat *); +bool kissat_switching_search_mode (struct kissat *); +void kissat_switch_search_mode (struct kissat *); + +#endif diff --git a/src/sat/kissat/options.c b/src/sat/kissat/options.c new file mode 100644 index 000000000..cf618905e --- /dev/null +++ b/src/sat/kissat/options.c @@ -0,0 +1,396 @@ +#include "options.h" +#include "error.h" +#include "print.h" + +#include +#include +#include +#include +#include + +#ifdef NOPTIONS + +static const opt table[] = { +#define OPTION(N, V, L, H, D) {#N, (int) (V), D}, + OPTIONS +#undef OPTION +}; + +#else + +static const opt table[] = { +#define OPTION(N, V, L, H, D) {#N, (int) (V), (int) (L), (int) (H), D}, + OPTIONS +#undef OPTION +}; + +#endif + +#define size_table (sizeof table / sizeof *table) + +const opt *kissat_options_begin = table; +const opt *kissat_options_end = table + size_table; + +static void check_table_sorted (void) { +#ifndef NDEBUG + opt const *p = 0; + for (all_options (o)) + if (p && strcmp (p->name, o->name) >= 0) + kissat_fatal ("option '%s' before option '%s'", p->name, o->name); + else + p = o; +#endif +} + +const opt *kissat_options_has (const char *name) { + size_t l = 0, m, r = size_table; + int tmp; + opt const *o; + assert (l < r); + while (l + 1 < r) { + m = l + (r - l) / 2; + tmp = strcmp (name, (o = table + m)->name); + if (tmp < 0) + r = m; + else if (tmp > 0) + l = m; + else + return o; + } + o = table + l; + tmp = strcmp (o->name, name); + return tmp ? 0 : o; +} + +bool kissat_parse_option_value (const char *val_str, int *res_ptr) { + if (!strcmp (val_str, "true")) { + *res_ptr = 1; + return true; + } + if (!strcmp (val_str, "false")) { + *res_ptr = 0; + return true; + } + int sign = 1; + char const *p = val_str; + int ch = *p++; + if (ch == '-') { + sign = -1; + ch = *p++; + } + if (!isdigit (ch)) // at least one digit + return false; + const unsigned max = -(unsigned) INT_MIN; + unsigned res = ch - '0'; + while (isdigit ((ch = *p++))) { + if (max / 10 < res) + return false; + res *= 10; + const unsigned digit = ch - '0'; + if (max - digit < res) + return false; + res += digit; + if (!res) + return false; // invalid '00' + } + if (ch == 'e') // parse '13e5' etc. + { + if (!isdigit ((ch = *p++))) // at least one digit + return false; + if (res) { + if (*p) // exactly one digit + return false; + const unsigned digit = ch - '0'; + for (unsigned i = 0; i < digit; i++) { + if (max / 10 < res) + return false; + res *= 10; + } + } else // parse '0^123123123' etc. + { + while (isdigit (ch = *p++)) // arbitrary many digits + ; + if (ch) + return false; + } + } else if (ch == '^') // parse '2^11' etc. + { + const unsigned base = res; + if (!isdigit ((ch = *p++))) // at least one digit + return false; + unsigned exp = ch - '0'; + if (base < 2) // parse '0^123123123' etc. + { + while (isdigit (ch = *p++)) // arbitrary many digits + ; + if (ch) + return false; + } else if (isdigit (ch = *p++)) // parse '2^30' etc. + { + if (*p) // at most two digits + return false; + exp *= 10; + const unsigned digit = ch - '0'; + exp += digit; + if (!exp) // '2^00' invalid + return false; + } else if (ch) + return false; + if (exp) + for (unsigned i = 1; i < exp; i++) { + if (max / base < res) + return false; + res *= base; + } + else if (base) + res = 1; // parse '3^0' + else + return false; // '0^0' invalid + } else if (ch) + return false; + assert (res <= max); + if (sign > 0 && res == max) + return false; + res *= sign; + *res_ptr = res; + return true; +} + +const char *kissat_parse_option_name (const char *arg, const char *name) { + if (arg[0] != '-' || arg[1] != '-') + return 0; + char const *p = arg + 2, *q = name; + if (p[0] == 'n' && p[1] == 'o' && p[2] == '-') + return strcmp (p + 3, name) ? 0 : "0"; + while (*p && *p == *q) + p++, q++; + if (*q) + return 0; + if (*p != '=') + return 0; + return p + 1; +} + +#ifdef NOPTIONS + +void kissat_init_options (void) { check_table_sorted (); } + +int kissat_options_get (const char *name) { + const opt *const o = kissat_options_has (name); + return o ? o->value : 0; +} + +#else + +#include "format.h" + +#include +#include +#include + +static void kissat_printf_usage (const char *option, const char *fmt, ...) { + va_list ap; + printf (" %-26s ", option); + va_start (ap, fmt); + vprintf (fmt, ap); + va_end (ap); + fputc ('\n', stdout); +} + +static void check_ranges (void) { +#define OPTION(N, V, L, H, D) \ + do { \ + if ((int) (L) > (int) (H)) \ + kissat_fatal ("minimum '%d' of option '%s' above maximum '%d'", \ + (int) (L), #N, (int) (H)); \ + if ((int) (V) < (int) (L)) \ + kissat_fatal ( \ + "default value '%d' of option '%s' below minimum '%d'", \ + (int) (V), #N, (int) (L)); \ + if ((int) (V) > (int) (H)) \ + kissat_fatal ( \ + "default value '%d' of option '%s' above maximum '%d'", \ + (int) (V), #N, (int) (H)); \ + } while (0); + OPTIONS +#undef OPTION +} + +static void check_name_length (void) { +#ifndef NDEBUG +#define OPTION(N, V, L, H, D) \ + if (strlen (#N) + 1 > kissat_options_max_name_buffer_size) \ + kissat_fatal ("option '%s' name length %zu " \ + "exceeds maximum name buffer size %zu", \ + #N, strlen (#N), kissat_options_max_name_buffer_size); + OPTIONS +#undef OPTION +#endif +} + +int kissat_options_get (const options *options, const char *name) { + const int *const p = + kissat_options_ref (options, kissat_options_has (name)); + return p ? *p : 0; +} + +int kissat_options_set_opt (options *options, const opt *o, int value) { + assert (kissat_options_begin <= o); + assert (o < kissat_options_end); + int *p = (int *) options + (o - table); + int res = *p; + if (value == res) + return res; + if (value < o->low) + value = o->low; + if (value > o->high) + value = o->high; + *p = value; + return res; +} + +int kissat_options_set (options *options, const char *name, int value) { + const opt *const o = kissat_options_has (name); + if (!o) + return 0; + return kissat_options_set_opt (options, o, value); +} + +void kissat_init_options (options *options) { + check_ranges (); + check_name_length (); + check_table_sorted (); +#define OPTION(N, V, L, H, D) \ + assert ((L) <= (V)); \ + assert ((V) <= (H)); \ + options->N = (V); + OPTIONS +#undef OPTION +} + +#define FORMAT_OPTION_LIMIT(V) \ + (((V) == INT_MIN || (V) == INT_MAX) \ + ? "." \ + : kissat_format_value (&format, false, (V))) + +void kissat_options_usage (void) { + check_ranges (); + check_name_length (); + check_table_sorted (); + format format; + memset (&format, 0, sizeof format); +#define OPTION(N, V, L, H, D) \ + do { \ + const bool b = ((L) == 0 && (H) == 1); \ + char buffer[96]; \ + if (b) \ + sprintf (buffer, "--%s=", #N); \ + else { \ + const char *low_str = FORMAT_OPTION_LIMIT ((L)); \ + const char *high_str = FORMAT_OPTION_LIMIT ((H)); \ + sprintf (buffer, "--%s=%s..%s", #N, low_str, high_str); \ + } \ + const char *val_str = kissat_format_value (&format, b, (V)); \ + kissat_printf_usage (buffer, "%s [%s]", D, val_str); \ + } while (0); + OPTIONS +#undef OPTION +} + +bool kissat_options_parse_arg (const char *arg, char *buffer, + int *val_ptr) { + if (arg[0] != '-' || arg[1] != '-') + return false; + char const *name = arg + 2, *p = name; + int ch; + while ((ch = *p) && ch != '=') + p++; + if (ch) { + assert (ch == '='); + const size_t len = p - name; + if (len >= kissat_options_max_name_buffer_size) + return false; + memcpy (buffer, name, len); + buffer[len] = 0; + const opt *const o = kissat_options_has (buffer); + if (!o) + return false; + int value; + if (!kissat_parse_option_value (p + 1, &value)) + return false; + if (value < o->low || value > o->high) + return false; + *val_ptr = value; + } else { + int value = 0; + if (arg[2] == 'n' && arg[3] == 'o' && arg[4] == '-') { + name += 3; + const opt *const o = kissat_options_has (name); + if (!o || o->low > (value = 0)) + return false; + } else { + const opt *const o = kissat_options_has (name); + if (!o || o->high < (value = 1)) + return false; + } + assert (strlen (name) < kissat_options_max_name_buffer_size); + strcpy (buffer, name); + *val_ptr = value; + } + return true; +} + +static bool ignore_embedded_option_for_fuzzing (const char *name) { +#ifdef EMBEDDED + if (!strcmp (name, "embedded")) + return true; +#endif +#ifndef QUIET + if (!strcmp (name, "quiet")) + return true; +#endif + (void) name; + return false; +} + +void kissat_print_embedded_option_list () { +#define OPTION(N, V, L, H, D) \ + if (!ignore_embedded_option_for_fuzzing (#N)) \ + printf ("c --%s=%d\n", #N, (int) (V)); + OPTIONS +#undef OPTION +} + +static bool ignore_range_option_for_fuzzing (const char *name) { +#ifdef LOGGING + if (!strcmp (name, "log")) + return true; +#endif +#ifdef EMBEDDED + if (!strcmp (name, "embedded")) + return true; +#endif +#ifndef QUIET + if (!strcmp (name, "quiet")) + return true; +#endif + if (!strcmp (name, "reduce")) + return true; + if (!strcmp (name, "reluctant")) + return true; + if (!strcmp (name, "rephase")) + return true; + if (!strcmp (name, "restart")) + return true; + return false; +} + +void kissat_print_option_range_list (void) { +#define OPTION(N, V, L, H, D) \ + if (!ignore_range_option_for_fuzzing (#N)) \ + printf ("%s %d %d %d\n", #N, (int) (L), (int) (V), (int) (H)); + OPTIONS +#undef OPTION +} + +#endif diff --git a/src/sat/kissat/options.h b/src/sat/kissat/options.h new file mode 100644 index 000000000..26cd6f066 --- /dev/null +++ b/src/sat/kissat/options.h @@ -0,0 +1,299 @@ +#ifndef _options_h_INLCUDED +#define _options_h_INLCUDED + +#include +#include + +// clang-format off + +#define OPTIONS \ + OPTION (ands, 1, 0, 1, "extract and eliminate and gates") \ + OPTION (backbone, 1, 0, 2, "binary clause backbone (2=eager)") \ + OPTION (backboneeffort, 20, 0, 1e5, "effort in per mille") \ + OPTION (backbonemaxrounds, 1e3, 1, INT_MAX, "maximum backbone rounds") \ + OPTION (backbonerounds, 100, 1, INT_MAX, "backbone rounds limit") \ + OPTION (bigbigfraction, 990, 0, 1000, "big binary clause fraction per mille") \ + OPTION (bump, 1, 0, 1, "enable variable bumping") \ + OPTION (bumpreasons, 1, 0, 1, "bump reason side literals too") \ + OPTION (bumpreasonslimit, 10, 1, INT_MAX, "relative reason literals limit") \ + OPTION (bumpreasonsrate, 10, 1, INT_MAX, "decision rate limit") \ + DBGOPT (check, 2, 0, 2, "check model (1) and derived clauses (2)") \ + OPTION (chrono, 1, 0, 1, "allow chronological backtracking") \ + OPTION (chronolevels, 100, 0, INT_MAX, "maximum jumped over levels") \ + OPTION (compact, 1, 0, 1, "enable compacting garbage collection") \ + OPTION (compactlim, 10, 0, 100, "compact inactive limit (in percent)") \ + OPTION (congruence, 1, 0, 1, "congruence closure on extracted gates") \ + OPTION (congruenceandarity, 1000000, 2, 50000000, "AND gate arity limit") \ + OPTION (congruenceands, 1, 0, 1, "extract AND gates for congruence closure") \ + OPTION (congruencebinaries, 1, 0, 1, "extract certain binary clauses") \ + OPTION (congruenceites, 1, 0, 1, "extract ITE gates for congruence closure") \ + OPTION (congruenceonce, 0, 0, 1, "congruence closure only initially") \ + OPTION (congruencexorarity, 4, 2, 20, "congruence XOR gate arity limit") \ + OPTION (congruencexorcounts, 2, 1, INT_MAX, "XOR counting rounds") \ + OPTION (congruencexors, 1, 0, 1, "extract XOR gates for congruence closure") \ + OPTION (decay, 50, 1, 200, "per mille scores decay") \ + OPTION (definitioncores, 2, 1, 100, "how many cores") \ + OPTION (definitions, 1, 0, 1, "extract general definitions") \ + OPTION (definitionticks, 1e6, 0, INT_MAX, "kitten ticks limits") \ + OPTION (defraglim, 75, 50, 100, "usable defragmentation limit in percent") \ + OPTION (defragsize, 1 << 18, 10, INT_MAX, "size defragmentation limit") \ + OPTION (eagersubsume, 4, 0, 4, "eagerly subsume previous learned clauses") \ + OPTION (eliminate, 1, 0, 1, "bounded variable elimination BVE") \ + OPTION (eliminatebound, 16, 0, 1 << 13, "maximum elimination bound") \ + OPTION (eliminateclslim, 100, 1, INT_MAX, "elimination clause size limit") \ + OPTION (eliminateeffort, 100, 0, 2e3, "effort in per mille") \ + OPTION (eliminateinit, 500, 0, INT_MAX, "initial elimination interval") \ + OPTION (eliminateint, 500, 10, INT_MAX, "base elimination interval") \ + OPTION (eliminateocclim, 2e3, 0, INT_MAX, "elimination occurrence limit") \ + OPTION (eliminaterounds, 2, 1, 1e4, "elimination rounds limit") \ + OPTION (emafast, 33, 10, 1e6, "fast exponential moving average window") \ + OPTION (emaslow, 1e5, 100, 1e6, "slow exponential moving average window") \ + EMBOPT (embedded, 1, 0, 1, "parse and apply embedded options") \ + OPTION (equivalences, 1, 0, 1, "extract and eliminate equivalence gates") \ + OPTION (extract, 1, 0, 1, "extract gates in variable elimination") \ + OPTION (factor, 1, 0, 1, "bounded variable addition") \ + OPTION (factorcandrounds, 2, 0, INT_MAX, "candidates reduction rounds") \ + OPTION (factoreffort, 50, 0, 1e6, "bounded variable effort in per mille") \ + OPTION (factorhops, 3, 1, 10, "structural factoring heuristic hops") \ + OPTION (factoriniticks, 700, 1, 1000000, "initial ticks ticks in millions") \ + OPTION (factorsize, 5, 2, INT_MAX, "bounded variable addition clause size") \ + OPTION (factorstructural, 0, 0, 1, "structural bounded variable addition") \ + OPTION (fastel, 1, 0, 1, "initial fast variable elimination") \ + OPTION (fastelclslim, 100, 1, INT_MAX, "fast elimination clause length limit") \ + OPTION (fastelim, 8, 1, 1000, "fast elimination resolvents limit") \ + OPTION (fasteloccs, 100, 1, 1000, "fast elimination occurrence limit") \ + OPTION (fastelrounds, 4, 1, 1000, "fast elimination rounds") \ + OPTION (fastelsub, 1, 0, 1, "forward subsuming fast variable elimination") \ + OPTION (flushproof, 0, 0, 1, "flush proof lines immediately") \ + OPTION (focusedtiers, 1, 0, 1, "always used focused mode tiers") \ + OPTION (forcephase, 0, 0, 1, "force initial phase") \ + OPTION (forward, 1, 0, 1, "forward subsumption in BVE") \ + OPTION (forwardeffort, 100, 0, 1e6, "effort in per mille") \ + OPTION (ifthenelse, 1, 0, 1, "extract and eliminate if-then-else gates") \ + OPTION (incremental, 0, 0, 1, "enable incremental solving") \ + OPTION (jumpreasons, 1, 0, 1, "jump binary reasons") \ + LOGOPT (log, 0, 0, 5, "logging level (1=on,2=more,3=check,4/5=mem)") \ + OPTION (lucky, 1, 0, 1, "try some lucky assignments") \ + OPTION (luckyearly, 1, 0, 1, "lucky assignments before preprocessing") \ + OPTION (luckylate, 1, 0, 1, "lucky assignments after preprocessing") \ + OPTION (mineffort, 10, 0, INT_MAX, "minimum absolute effort in millions") \ + OPTION (minimize, 1, 0, 1, "learned clause minimization") \ + OPTION (minimizedepth, 1e3, 1, 1e6, "minimization depth") \ + OPTION (minimizeticks, 1, 0, 1, "count ticks in minimize and shrink") \ + OPTION (modeinit, 1e3, 10, 1e8, "initial focused conflicts limit") \ + OPTION (modeint, 1e3, 10, 1e8, "focused conflicts interval") \ + OPTION (otfs, 1, 0, 1, "on-the-fly strengthening") \ + OPTION (phase, 1, 0, 1, "initial decision phase") \ + OPTION (phasesaving, 1, 0, 1, "enable phase saving") \ + OPTION (preprocess, 1, 0, 1, "initial preprocessing") \ + OPTION (preprocessbackbone, 1, 0, 1, "backbone preprocessing") \ + OPTION (preprocesscongruence, 1, 0, 1, "congruence preprocessing") \ + OPTION (preprocessfactor, 1, 0, 1, "variable addition preprocessing") \ + OPTION (preprocessprobe, 1, 0, 1, "probing preprocessing") \ + OPTION (preprocessrounds, 1, 1, INT_MAX, "initial preprocessing rounds") \ + OPTION (preprocessweep, 1, 0, 1, "sweep preprocessing") \ + OPTION (probe, 1, 0, 1, "enable probing") \ + OPTION (probeinit, 100, 0, INT_MAX, "initial probing interval") \ + OPTION (probeint, 100, 2, INT_MAX, "probing interval") \ + OPTION (proberounds, 2, 1, INT_MAX, "probing rounds") \ + NQTOPT (profile, 2, 0, 4, "profile level") \ + OPTION (promote, 1, 0, 1, "promote clauses") \ + NQTOPT (quiet, 0, 0, 1, "disable all messages") \ + OPTION (randec, 1, 0, 1, "random decisions") \ + OPTION (randecfocused, 1, 0, 1, "random decisions in focused mode") \ + OPTION (randecinit, 500, 0, INT_MAX, "random decisions interval") \ + OPTION (randecint, 500, 0, INT_MAX, "initial random decisions interval") \ + OPTION (randeclength, 10, 1, INT_MAX, "random conflicts length") \ + OPTION (randecstable, 0, 0, 1, "random decisions in stable mode") \ + OPTION (reduce, 1, 0, 1, "learned clause reduction") \ + OPTION (reducehigh, 900, 0, 1000, "high reduce fraction per mille") \ + OPTION (reduceinit, 1e3, 2, 1e5, "initial reduce interval") \ + OPTION (reduceint, 1e3, 2, 1e5, "base reduce interval") \ + OPTION (reducelow, 500, 0, 1000, "low reduce fraction per mille") \ + OPTION (reluctant, 1, 0, 1, "stable reluctant doubling restarting") \ + OPTION (reluctantint, 1 << 10, 2, 1 << 15, "reluctant interval") \ + OPTION (reluctantlim, 1 << 20, 0, 1 << 30, "reluctant limit (0=unlimited)") \ + OPTION (reorder, 2, 0, 2, "reorder decisions (1=stable-mode-only)") \ + OPTION (reorderinit, 1e4, 0, 1e5, "initial reorder interval") \ + OPTION (reorderint, 1e4, 1, 1e5, "base reorder interval") \ + OPTION (reordermaxsize, 100, 2, 256, "reorder maximum clause size") \ + OPTION (rephase, 1, 0, 1, "reinitialization of decision phases") \ + OPTION (rephaseinit, 1e3, 10, 1e5, "initial rephase interval") \ + OPTION (rephaseint, 1e3, 10, 1e5, "base rephase interval") \ + OPTION (restart, 1, 0, 1, "enable restarts") \ + OPTION (restartint, RESTARTINT_DEFAULT, 1, 1e4, "base restart interval") \ + OPTION (restartmargin, 10, 0, 25, "fast/slow margin in percent") \ + OPTION (restartreusetrail, 1, 0, 1, "restarts tries to reuse trail") \ + OPTION (seed, 0, 0, INT_MAX, "random seed") \ + OPTION (shrink, 3, 0, 3, "learned clauses (1=bin,2=lrg,3=rec)") \ + OPTION (simplify, 1, 0, 1, "enable probing and elimination") \ + OPTION (smallclauses, 1e5, 0, INT_MAX, "small clauses limit") \ + OPTION (stable, STABLE_DEFAULT, 0, 2, "enable stable search mode") \ + NQTOPT (statistics, 0, 0, 1, "print complete statistics") \ + OPTION (substitute, 1, 0, 1, "equivalent literal substitution") \ + OPTION (substituteeffort, 10, 1, 1e3, "effort in per mille") \ + OPTION (substituterounds, 2, 1, 100, "maximum substitution rounds") \ + OPTION (subsumeclslim, 1e3, 1, INT_MAX, "subsumption clause size limit") \ + OPTION (subsumeocclim, 1e3, 0, INT_MAX, "subsumption occurrence limit") \ + OPTION (sweep, 1, 0, 1, "enable SAT sweeping") \ + OPTION (sweepclauses, 1024, 0, INT_MAX, "environment clauses") \ + OPTION (sweepcomplete, 0, 0, 1, "run SAT sweeping until completion") \ + OPTION (sweepdepth, 2, 0, INT_MAX, "environment depth") \ + OPTION (sweepeffort, 100, 0, 1e4, "effort in per mille") \ + OPTION (sweepfliprounds, 1, 0, INT_MAX, "flipping rounds") \ + OPTION (sweepmaxclauses, 32768, 2, INT_MAX, "maximum environment clauses") \ + OPTION (sweepmaxdepth, 3, 1, INT_MAX, "maximum environment depth") \ + OPTION (sweepmaxvars, 8192, 2, INT_MAX, "maximum environment variables") \ + OPTION (sweeprand, 0, 0, 1, "randomize sweeping environment") \ + OPTION (sweepvars, 256, 0, INT_MAX, "environment variables") \ + OPTION (target, TARGET_DEFAULT, 0, 2, "target phases (1=stable,2=focused)") \ + OPTION (tier1, 2, 1, 100, "learned clause tier one glue limit") \ + OPTION (tier1relative, 500, 0, 1000, "relative tier one glue limit") \ + OPTION (tier2, 6, 1, 1e3, "learned clause tier two glue limit") \ + OPTION (tier2relative, 900, 0, 1000, "relative tier two glue limit") \ + OPTION (transitive, 1, 0, 1, "transitive reduction of binary clauses") \ + OPTION (transitiveeffort, 20, 0, 2e3, "effort in per mille") \ + OPTION (transitivekeep, 1, 0, 1, "keep transitivity candidates") \ + OPTION (tumble, 1, 0, 1, "tumbled external indices order") \ + NQTOPT (verbose, 0, 0, 3, "verbosity level") \ + OPTION (vivify, 1, 0, 1, "vivify clauses") \ + OPTION (vivifyeffort, 100, 0, 1e3, "effort in per mille") \ + OPTION (vivifyfocusedtiers, 1, 0, 1, "use focused tier limits") \ + OPTION (vivifyirr, 3, 0, 100, "relative irredundant effort") \ + OPTION (vivifysort, 1, 0, 1, "sort vivification candidates") \ + OPTION (vivifytier1, 3, 0, 100, "relative tier1 effort") \ + OPTION (vivifytier2, 3, 0, 100, "relative tier2 effort") \ + OPTION (vivifytier3, 1, 0, 100, "relative tier3 effort") \ + OPTION (walkeffort, 50, 0, 1e6, "effort in per mille") \ + OPTION (walkinitially, 0, 0, 1, "initial local search") \ + OPTION (warmup, 1, 0, 1, "initialize phases by unit propagation") + +// clang-format on + +#define TARGET_SAT 2 +#define TARGET_DEFAULT 1 + +#define STABLE_DEFAULT 1 +#define STABLE_UNSAT 0 + +#define RESTARTINT_DEFAULT 1 +#define RESTARTINT_SAT 50 + +#ifdef SAT +#undef TARGET_DEFAULT +#define TARGET_DEFAULT TARGET_SAT +#undef RESTARTINT_DEFAULT +#define RESTARTINT_DEFAULT RESTARTINT_SAT +#endif + +#ifdef UNSAT +#undef STABLE_DEFAULT +#define STABLE_DEFAULT STABLE_UNSAT +#endif + +#if defined(LOGGING) && !defined(QUIET) +#define LOGOPT OPTION +#else +#define LOGOPT(...) /**/ +#endif + +#ifndef QUIET +#define NQTOPT OPTION +#else +#define NQTOPT(...) /**/ +#endif + +#ifndef NDEBUG +#define DBGOPT OPTION +#else +#define DBGOPT(...) /**/ +#endif + +#ifdef EMBEDDED +#define EMBOPT OPTION +#else +#define EMBOPT(...) /**/ +#endif + +// clang-format on + +#define TIER1RELATIVE (GET_OPTION (tier1relative) / 1000.0) +#define TIER2RELATIVE (GET_OPTION (tier2relative) / 1000.0) + +typedef struct opt opt; + +struct opt { + const char *name; +#ifndef NOPTIONS + int value; + const int low; + const int high; +#else + const int value; +#endif + const char *description; +}; + +extern const opt *kissat_options_begin; +extern const opt *kissat_options_end; + +#define all_options(O) \ + opt const *O = kissat_options_begin; \ + O != kissat_options_end; \ + ++O + +const char *kissat_parse_option_name (const char *arg, const char *name); +bool kissat_parse_option_value (const char *val_str, int *res_ptr); + +#ifndef NOPTIONS + +void kissat_options_usage (void); + +const opt *kissat_options_has (const char *name); + +#define kissat_options_max_name_buffer_size ((size_t) 32) + +bool kissat_options_parse_arg (const char *arg, char *name, int *val_str); +void kissat_options_print_value (int value, char *buffer); + +typedef struct options options; + +struct options { +#define OPTION(N, V, L, H, D) int N; + OPTIONS +#undef OPTION +}; + +void kissat_init_options (options *); + +int kissat_options_get (const options *, const char *name); +int kissat_options_set_opt (options *, const opt *, int new_value); +int kissat_options_set (options *, const char *name, int new_value); + +void kissat_print_embedded_option_list (void); +void kissat_print_option_range_list (void); + +static inline int *kissat_options_ref (const options *options, + const opt *o) { + if (!o) + return 0; + assert (kissat_options_begin <= o); + assert (o < kissat_options_end); + return (int *) options + (o - kissat_options_begin); +} + +#define GET_OPTION(NAME) ((int) solver->options.NAME) + +#else + +void kissat_init_options (void); +int kissat_options_get (const char *name); + +#define GET_OPTION(N) kissat_options_##N + +#define OPTION(N, V, L, H, D) static const int GET_OPTION (N) = (int) (V); +OPTIONS +#undef OPTION +#endif +#define GET1K_OPTION(NAME) (((int64_t) 1000) * GET_OPTION (NAME)) +#endif diff --git a/src/sat/kissat/parse.h b/src/sat/kissat/parse.h new file mode 100644 index 000000000..665371259 --- /dev/null +++ b/src/sat/kissat/parse.h @@ -0,0 +1,19 @@ +#ifndef _parse_h_INCLUDED +#define _parse_h_INCLUDED + +#include "file.h" + +enum strictness { + RELAXED_PARSING = 0, + NORMAL_PARSING = 1, + PEDANTIC_PARSING = 2, +}; + +typedef enum strictness strictness; + +struct kissat; + +const char *kissat_parse_dimacs (struct kissat *, strictness, file *, + uint64_t *linenoptr, int *max_var_ptr); + +#endif diff --git a/src/sat/kissat/phases.c b/src/sat/kissat/phases.c new file mode 100644 index 000000000..5fb84c20d --- /dev/null +++ b/src/sat/kissat/phases.c @@ -0,0 +1,68 @@ +#include "allocate.h" +#include "internal.h" +#include "logging.h" + +#include + +#define realloc_phases(NAME) \ + do { \ + solver->phases.NAME = \ + kissat_realloc (solver, solver->phases.NAME, old_size, new_size); \ + } while (0) + +#define increase_phases(NAME) \ + do { \ + assert (old_size < new_size); \ + realloc_phases (NAME); \ + memset (solver->phases.NAME + old_size, 0, new_size - old_size); \ + } while (0) + +void kissat_increase_phases (kissat *solver, unsigned new_size) { + const unsigned old_size = solver->size; + assert (old_size < new_size); + LOG ("increasing phases from %u to %u", old_size, new_size); + increase_phases (best); + increase_phases (saved); + increase_phases (target); +} + +void kissat_decrease_phases (kissat *solver, unsigned new_size) { + const unsigned old_size = solver->size; + assert (old_size > new_size); + LOG ("decreasing phases from %u to %u", old_size, new_size); + realloc_phases (best); + realloc_phases (saved); + realloc_phases (target); +} + +#define release_phases(NAME, SIZE) \ + kissat_free (solver, solver->phases.NAME, SIZE) + +void kissat_release_phases (kissat *solver) { + const unsigned size = solver->size; + release_phases (best, size); + release_phases (saved, size); + release_phases (target, size); +} + +static void save_phases (kissat *solver, value *phases) { + const value *const values = solver->values; + const value *const end = phases + VARS; + value const *v = values; + for (value *p = phases, tmp; p != end; p++, v += 2) + if ((tmp = *v)) + *p = tmp; + assert (v == values + LITS); +} + +void kissat_save_best_phases (kissat *solver) { + assert (sizeof (value) == 1); + LOG ("saving %u best values", VARS); + save_phases (solver, solver->phases.best); +} + +void kissat_save_target_phases (kissat *solver) { + assert (sizeof (value) == 1); + LOG ("saving %u target values", VARS); + save_phases (solver, solver->phases.target); +} diff --git a/src/sat/kissat/phases.h b/src/sat/kissat/phases.h new file mode 100644 index 000000000..4a2456fec --- /dev/null +++ b/src/sat/kissat/phases.h @@ -0,0 +1,32 @@ +#ifndef _phases_h_INCLUDED +#define _phases_h_INCLUDED + +#include "value.h" + +typedef struct phases phases; + +struct phases { + value *best; + value *saved; + value *target; +}; + +#define BEST(IDX) \ + (solver->phases.best[assert (VALID_INTERNAL_INDEX (IDX)), (IDX)]) + +#define SAVED(IDX) \ + (solver->phases.saved[assert (VALID_INTERNAL_INDEX (IDX)), (IDX)]) + +#define TARGET(IDX) \ + (solver->phases.target[assert (VALID_INTERNAL_INDEX (IDX)), (IDX)]) + +struct kissat; + +void kissat_increase_phases (struct kissat *, unsigned); +void kissat_decrease_phases (struct kissat *, unsigned); +void kissat_release_phases (struct kissat *); + +void kissat_save_best_phases (struct kissat *); +void kissat_save_target_phases (struct kissat *); + +#endif diff --git a/src/sat/kissat/preprocess.c b/src/sat/kissat/preprocess.c new file mode 100644 index 000000000..96a0beee0 --- /dev/null +++ b/src/sat/kissat/preprocess.c @@ -0,0 +1,178 @@ +#include "preprocess.h" +#include "collect.h" +#include "fastel.h" +#include "internal.h" +#include "print.h" +#include "probe.h" +#include "propinitially.h" +#include "report.h" +#include "sweep.h" +#include "terminate.h" + +#include + +bool kissat_preprocessing (struct kissat *solver) { + assert (!solver->level); + assert (!solver->inconsistent); + if (!GET_OPTION (preprocess)) + return false; + if (!GET_OPTION (probe)) + return false; + if (!GET_OPTION (preprocessprobe)) + return false; +#if defined(NDEBUG) && defined(NOPTIONS) + (void) solver; +#endif + return true; +} + +int kissat_preprocess (struct kissat *solver) { + assert (kissat_preprocessing (solver)); + if (!kissat_initially_propagate (solver)) { + assert (solver->inconsistent); + return 20; + } + START (preprocess); + assert (!solver->preprocessing); + solver->preprocessing = true; + REPORT (0, '('); + const unsigned max_rounds = GET_OPTION (preprocessrounds); +#ifndef QUIET + const unsigned variables_initially = solver->active; + const uint64_t clauses_initially = BINIRR_CLAUSES; + const unsigned variables_originally = SIZE_STACK (solver->import); + const uint64_t clauses_originally = solver->statistics.clauses_original; + kissat_verbose (solver, + "[preprocess] running at most %u preprocesing rounds", + max_rounds); + kissat_verbose ( + solver, + "[preprocess] initially %u variables %.0f%% and %" PRIu64 + " clauses %.0f%%", + variables_initially, + kissat_percent (variables_initially, variables_originally), + clauses_initially, + kissat_percent (clauses_initially, clauses_originally)); +#endif + kissat_initial_sparse_collect (solver); + unsigned round = 1; + for (;;) { + if (solver->inconsistent) + break; + if (TERMINATED (preprocess_terminated_1)) + break; + const unsigned variables_before = solver->active; + const uint64_t clauses_before = BINIRR_CLAUSES; +#ifndef QUIET + kissat_verbose (solver, + "[preprocess-%u] started preprocessing round %u", round, + round); +#endif + if (GET_OPTION (preprocessprobe)) + kissat_probe_initially (solver); + if (GET_OPTION (fastel)) + kissat_fast_variable_elimination (solver); + const unsigned variables_after = solver->active; + const uint64_t clauses_after = BINIRR_CLAUSES; +#ifndef QUIET + if (variables_after < variables_before) { + unsigned removed = variables_before - variables_after; + kissat_verbose ( + solver, "[preprocess-%u] removed %u variables %.0f%% in round %u", + round, removed, kissat_percent (removed, variables_before), + round); + } else if (variables_after > variables_before) { + unsigned added = variables_after - variables_before; + kissat_verbose ( + solver, "[preprocess-%u] added %u variables %.0f%% in round %u", + round, added, kissat_percent (added, variables_before), round); + } else + kissat_verbose ( + solver, + "[preprocess-%u] number variables %u unchanged in round %u", + round, variables_before, round); + if (clauses_after < clauses_before) { + uint64_t removed = clauses_before - clauses_after; + kissat_verbose (solver, + "[preprocess-%u] removed %" PRIu64 + " irredundant and binary clauses %.0f%% in round %u", + round, removed, + kissat_percent (removed, clauses_before), round); + } else if (clauses_after > clauses_before) { + uint64_t added = clauses_after - clauses_before; + kissat_verbose (solver, + "[preprocess-%u] added %" PRIu64 + " irredundant and binary clauses %.0f%% in round %u", + round, added, kissat_percent (added, clauses_before), + round); + } else + kissat_verbose ( + solver, + "[preprocess-%u] number irredundant and binary clauses %" PRIu64 + " unchanged in round %u", + round, clauses_before, round); +#endif + if (round == max_rounds) + break; + if (variables_before == variables_after && + clauses_before == clauses_after) + break; + round++; + } +#ifndef QUIET + const unsigned variables_finally = solver->active; + const uint64_t clauses_finally = BINIRR_CLAUSES; + kissat_verbose (solver, "[preprocess] finished after %u rounds", round); + if (variables_finally < variables_initially) { + unsigned removed = variables_initially - variables_finally; + kissat_verbose ( + solver, + "[preprocess] removed %u variables %.0f%% (%u remain %.0f%%)", + removed, kissat_percent (removed, variables_initially), + variables_finally, + kissat_percent (variables_finally, variables_originally)); + } else if (variables_finally > variables_initially) { + unsigned added = variables_finally - variables_initially; + kissat_verbose ( + solver, "[preprocess] added %u variables %.0f%% (%u remain %.0f%%)", + added, kissat_percent (added, variables_initially), + variables_finally, + kissat_percent (variables_finally, variables_originally)); + } else + kissat_verbose ( + solver, + "[preprocess] number variables %u unchanged (%u remain %.0f%%)", + variables_initially, variables_finally, + kissat_percent (variables_finally, variables_originally)); + if (clauses_finally < clauses_initially) { + uint64_t removed = clauses_initially - clauses_finally; + kissat_verbose (solver, + "[preprocess] removed %" PRIu64 + " irredundant and binary clauses %.0f%% (%" PRIu64 + " remain %.0f%%)", + removed, kissat_percent (removed, clauses_initially), + clauses_finally, + kissat_percent (clauses_finally, clauses_originally)); + } else if (clauses_finally > clauses_initially) { + uint64_t added = clauses_finally - clauses_initially; + kissat_verbose (solver, + "[preprocess] added %" PRIu64 + " irredundant and binary clauses %.0f%% (%" PRIu64 + " remain %.0f%%)", + added, kissat_percent (added, clauses_initially), + clauses_finally, + kissat_percent (clauses_finally, clauses_originally)); + } else + kissat_verbose ( + solver, + "[preprocess] number irredundant and binary clauses %" PRIu64 + " unchanged (%" PRIu64 " remain %.0f%%)", + clauses_initially, clauses_finally, + kissat_percent (clauses_finally, clauses_originally)); +#endif + REPORT (0, ')'); + assert (solver->preprocessing); + solver->preprocessing = false; + STOP (preprocess); + return solver->inconsistent ? 20 : 0; +} diff --git a/src/sat/kissat/preprocess.h b/src/sat/kissat/preprocess.h new file mode 100644 index 000000000..056b5ecde --- /dev/null +++ b/src/sat/kissat/preprocess.h @@ -0,0 +1,10 @@ +#ifndef _kissat_preprocess_h_INCLUDED +#define _kissat_preprocess_h_INCLUDED + +#include + +struct kissat; +bool kissat_preprocessing (struct kissat *); +int kissat_preprocess (struct kissat *); + +#endif diff --git a/src/sat/kissat/print.c b/src/sat/kissat/print.c new file mode 100644 index 000000000..454b8f343 --- /dev/null +++ b/src/sat/kissat/print.c @@ -0,0 +1,172 @@ +#ifndef QUIET + +#include "print.h" +#include "colors.h" +#include "handle.h" +#include "internal.h" + +#include +#include +#include + +static inline int verbosity (kissat *solver) { + if (!solver) + return -1; +#ifdef LOGGING + if (GET_OPTION (log)) + return 3; +#endif +#ifndef QUIET + if (GET_OPTION (quiet)) + return -1; + return GET_OPTION (verbose); +#else + return 0; +#endif +} + +void kissat_warning (kissat *solver, const char *fmt, ...) { + if (verbosity (solver) < 0) + return; + TERMINAL (stdout, 1); + fputs (solver->prefix, stdout); + COLOR (BOLD YELLOW); + fputs ("warning:", stdout); + COLOR (NORMAL); + fputc (' ', stdout); + va_list ap; + va_start (ap, fmt); + vprintf (fmt, ap); + va_end (ap); + fputc ('\n', stdout); +#ifdef NOPTIONS + (void) solver; +#endif +} + +void kissat_signal (kissat *solver, const char *type, int sig) { + if (verbosity (solver) < 0) + return; + TERMINAL (stdout, 1); + fputs (solver->prefix, stdout); + COLOR (BOLD RED); + printf ("%s signal %d (%s)", type, sig, kissat_signal_name (sig)); + COLOR (NORMAL); + fputc ('\n', stdout); + fflush (stdout); +} + +static void print_message (kissat *solver, const char *color, + const char *fmt, va_list *ap) { + TERMINAL (stdout, 1); + fputs (solver->prefix, stdout); + COLOR (color); + vprintf (fmt, *ap); + fputc ('\n', stdout); + COLOR (NORMAL); + fflush (stdout); +} + +static void print_line (kissat *solver) { + char ch; + for (const char *p = solver->prefix; (ch = *p); p++) + if (ch && (ch != ' ' || p[1])) + fputc (ch, stdout); + fputc ('\n', stdout); + fflush (stdout); +} + +int kissat_verbosity (kissat *solver) { return verbosity (solver); } + +void kissat_message (kissat *solver, const char *fmt, ...) { + if (verbosity (solver) < 0) + return; + va_list ap; + va_start (ap, fmt); + print_message (solver, "", fmt, &ap); + va_end (ap); +} + +void kissat_line (kissat *solver) { + if (verbosity (solver) >= 0) + print_line (solver); +} + +void kissat_prefix (kissat *solver) { fputs (solver->prefix, stdout); } + +void kissat_verbose (kissat *solver, const char *fmt, ...) { + if (verbosity (solver) < 1) + return; + va_list ap; + va_start (ap, fmt); + print_message (solver, LIGHT_GRAY, fmt, &ap); + va_end (ap); +} + +void kissat_very_verbose (kissat *solver, const char *fmt, ...) { + if (verbosity (solver) < 2) + return; + va_list ap; + va_start (ap, fmt); + print_message (solver, DARK_GRAY, fmt, &ap); + va_end (ap); +} + +void kissat_extremely_verbose (kissat *solver, const char *fmt, ...) { + if (verbosity (solver) < 3) + return; + va_list ap; + va_start (ap, fmt); + print_message (solver, DARK_GRAY, fmt, &ap); + va_end (ap); +} + +void kissat_section (kissat *solver, const char *name) { + if (verbosity (solver) < 0) + return; + TERMINAL (stdout, 1); + if (solver->sectioned) + kissat_line (solver); + else + solver->sectioned = true; + fputs (solver->prefix, stdout); + COLOR (BLUE); + fputs ("---- [ ", stdout); + COLOR (BOLD BLUE); + fputs (name, stdout); + COLOR (NORMAL BLUE); + fputs (" ] ", stdout); + for (size_t i = strlen (name); i < 66; i++) + fputc ('-', stdout); + COLOR (NORMAL); + fputc ('\n', stdout); + print_line (solver); + fflush (stdout); +} + +void kissat_phase (kissat *solver, const char *name, uint64_t count, + const char *fmt, ...) { + if (verbosity (solver) < 1) + return; + TERMINAL (stdout, 1); + fputs (solver->prefix, stdout); + if (solver->stable) + COLOR (CYAN); + else + COLOR (BOLD CYAN); + printf ("[%s", name); + if (count != UINT64_MAX) + printf ("-%" PRIu64, count); + fputs ("] ", stdout); + va_list ap; + va_start (ap, fmt); + vprintf (fmt, ap); + va_end (ap); + COLOR (NORMAL); + fputc ('\n', stdout); + fflush (stdout); +} + +#else +int kissat_print_dummy_to_avoid_warning; +#endif diff --git a/src/sat/kissat/print.h b/src/sat/kissat/print.h new file mode 100644 index 000000000..d6f8a329f --- /dev/null +++ b/src/sat/kissat/print.h @@ -0,0 +1,65 @@ +// clang-format off + +#ifndef _print_h_INCLUDED +#define _print_h_INCLUDED + +#ifndef QUIET + +#include + +#include "attribute.h" + +struct kissat; + +int kissat_verbosity (struct kissat *); + +void kissat_line (struct kissat *); +void kissat_prefix (struct kissat*); +void kissat_signal (struct kissat *, const char *type, int sig); +void kissat_section (struct kissat *, const char *name); + +void +kissat_message (struct kissat *, const char *fmt, ...) +ATTRIBUTE_FORMAT (2, 3); + +void kissat_verbose (struct kissat *, const char *fmt, ...) +ATTRIBUTE_FORMAT (2, 3); + +void kissat_very_verbose (struct kissat *, const char *fmt, ...) +ATTRIBUTE_FORMAT (2, 3); + +void kissat_extremely_verbose (struct kissat *, const char *fmt, ...) +ATTRIBUTE_FORMAT (2, 3); + +void kissat_warning (struct kissat *, const char *fmt, ...) +ATTRIBUTE_FORMAT (2, 3); + +void kissat_phase (struct kissat *, const char *name, uint64_t, + const char * fmt, ...) +ATTRIBUTE_FORMAT (4, 5); + +#else + +#define kissat_line(...) do { } while (0) +#define kissat_message(...) do { } while (0) +#define kissat_phase(...) do { } while (0) +#define kissat_section(...) do { } while (0) +#define kissat_signal(...) do { } while (0) +#define kissat_verbose(...) do { } while (0) +#define kissat_very_verbose(...) do { } while (0) +#define kissat_extremely_verbose(...) do { } while (0) +#define kissat_warning(...) do { } while (0) + +#endif + +#define VERY_VERBOSE_OR_LOG(ONLY_LOG, SOLVER, ...) \ +do { \ + if (ONLY_LOG) \ + LOG (__VA_ARGS__); \ + else \ + kissat_very_verbose (SOLVER, __VA_ARGS__); \ +} while (0) + +#endif + +// clang-format on diff --git a/src/sat/kissat/probe.c b/src/sat/kissat/probe.c new file mode 100644 index 000000000..606710577 --- /dev/null +++ b/src/sat/kissat/probe.c @@ -0,0 +1,104 @@ +#include "probe.h" +#include "backbone.h" +#include "backtrack.h" +#include "congruence.h" +#include "factor.h" +#include "internal.h" +#include "print.h" +#include "substitute.h" +#include "sweep.h" +#include "terminate.h" +#include "transitive.h" +#include "vivify.h" + +#include + +bool kissat_probing (kissat *solver) { + if (!solver->enabled.probe) + return false; + statistics *statistics = &solver->statistics; + const uint64_t conflicts = statistics->conflicts; + if (solver->last.conflicts.reduce == conflicts) + return false; + return solver->limits.probe.conflicts < conflicts; +} + +static void probe (kissat *solver) { + kissat_backtrack_propagate_and_flush_trail (solver); + assert (!solver->inconsistent); + STOP_SEARCH_AND_START_SIMPLIFIER (probe); + kissat_phase (solver, "probe", GET (probings), + "probing limit hit after %" PRIu64 " conflicts", + solver->limits.probe.conflicts); + kissat_congruence (solver); + kissat_substitute (solver, false); + kissat_binary_clauses_backbone (solver); + kissat_vivify (solver); + kissat_sweep (solver); + kissat_substitute (solver, false); + kissat_transitive_reduction (solver); + kissat_binary_clauses_backbone (solver); + kissat_factor (solver); + STOP_SIMPLIFIER_AND_RESUME_SEARCH (probe); +} + +static void probe_initially (kissat *solver) { + assert (!solver->level); + assert (!solver->inconsistent); + kissat_phase (solver, "probe", GET (probings), "initial probing"); + bool substitute_at_the_end = true; + if (GET_OPTION (preprocesscongruence)) { + if (kissat_congruence (solver)) { + kissat_substitute (solver, true); + substitute_at_the_end = false; + } + } + if (GET_OPTION (preprocessbackbone)) + kissat_binary_clauses_backbone (solver); + if (GET_OPTION (preprocessweep)) { + if (kissat_sweep (solver)) { + kissat_substitute (solver, true); + substitute_at_the_end = false; + } + } + if (substitute_at_the_end) + kissat_substitute (solver, false); + if (GET_OPTION (preprocessfactor)) + kissat_factor (solver); +} + +int kissat_probe (kissat *solver) { + assert (!solver->inconsistent); + INC (probings); + assert (!solver->probing); + solver->probing = true; + const unsigned max_rounds = GET_OPTION (proberounds); + for (unsigned round = 0; round != max_rounds; round++) { + unsigned before = solver->active; + probe (solver); + if (solver->inconsistent) + break; + if (before == solver->active) + break; + } + kissat_classify (solver); + UPDATE_CONFLICT_LIMIT (probe, probings, NLOGN, true); + solver->last.ticks.probe = solver->statistics.search_ticks; + assert (solver->probing); + solver->probing = false; + return solver->inconsistent ? 20 : 0; +} + +int kissat_probe_initially (kissat *solver) { + assert (!solver->level); + assert (!solver->inconsistent); + INC (probings); + START (probe); + assert (!solver->probing); + solver->probing = true; + probe_initially (solver); + assert (solver->probing); + solver->probing = false; + STOP (probe); + return solver->inconsistent ? 20 : 0; +} diff --git a/src/sat/kissat/probe.h b/src/sat/kissat/probe.h new file mode 100644 index 000000000..a788918f3 --- /dev/null +++ b/src/sat/kissat/probe.h @@ -0,0 +1,12 @@ +#ifndef _probe_h_INCLUDED +#define _probe_h_INCLUDED + +#include + +struct kissat; + +bool kissat_probing (struct kissat *); +int kissat_probe (struct kissat *); +int kissat_probe_initially (struct kissat *); + +#endif diff --git a/src/sat/kissat/profile.c b/src/sat/kissat/profile.c new file mode 100644 index 000000000..01cd65573 --- /dev/null +++ b/src/sat/kissat/profile.c @@ -0,0 +1,148 @@ +#ifndef QUIET + +#include "internal.h" +#include "resources.h" +#include "sort.h" + +#include +#include + +void kissat_init_profiles (profiles *profiles) { +#define PROF(NAME, LEVEL) profiles->NAME = (profile){LEVEL, #NAME, 0, 0}; + PROFS +#undef PROF +} + +#define SIZE_PROFS (sizeof (profiles) / sizeof (profile)) + +static inline bool less_profile (profile *p, profile *q) { + if (p->time > q->time) + return true; + if (p->time < q->time) + return false; + return strcmp (p->name, q->name) < 0; +} + +static void print_profile (kissat *solver, profile *p, double total) { + printf ("%s%14.2f %7.2f %% %s\n", solver->prefix, p->time, + kissat_percent (p->time, total), p->name); +} + +static double flush_profile (profile *profile, double now) { + const double delta = now - profile->entered; + profile->time += delta; + profile->entered = now; + return delta; +} + +static void flush_profiles (profiles *profiles, const double now) { + for (all_pointers (profile, p, profiles->stack)) + flush_profile (p, now); +} + +static void push_profile (kissat *solver, profile *profile, double now) { + profile->entered = now; + PUSH_STACK (solver->profiles.stack, profile); +} + +void kissat_profiles_print (kissat *solver) { + profiles *named = &solver->profiles; + double now = kissat_process_time (); + flush_profiles (named, now); + profile *unsorted = (profile *) named; + profile *sorted[SIZE_PROFS]; + const profile *const end = unsorted + SIZE_PROFS; + size_t size = 0; + for (profile *p = unsorted; p != end; p++) + if (p->level <= GET_OPTION (profile) && + (p == &named->search || p == &named->simplify || + (p != &named->total && p->time))) + sorted[size++] = p; + INSERTION_SORT (profile *, size, sorted, less_profile); + const double total = named->total.time; + for (size_t i = 0; i < size; i++) + print_profile (solver, sorted[i], total); + printf ("%s=============================================\n", + solver->prefix); + print_profile (solver, &named->total, total); +} + +void kissat_start (kissat *solver, profile *profile) { + const double now = kissat_process_time (); + push_profile (solver, profile, now); +} + +void kissat_stop (kissat *solver, profile *profile) { + assert (TOP_STACK (solver->profiles.stack) == profile); + (void) POP_STACK (solver->profiles.stack); + const double now = kissat_process_time (); + flush_profile (profile, now); +} + +void kissat_stop_search_and_start_simplifier (kissat *solver, + profile *profile) { + struct profile *search = &PROFILE (search); + assert (search->level <= GET_OPTION (profile)); + const double now = kissat_process_time (); + while (TOP_STACK (solver->profiles.stack) != search) { + struct profile *mode = POP_STACK (solver->profiles.stack); + assert (search->level <= mode->level); +#ifndef NDEBUG + if (solver->stable) + assert (mode == &PROFILE (stable)); + else + assert (mode == &PROFILE (focused)); +#endif + flush_profile (mode, now); + } + (void) POP_STACK (solver->profiles.stack); + struct profile *simplify = &PROFILE (simplify); + assert (search->level == simplify->level); + assert (simplify->level <= profile->level); + flush_profile (search, now); + push_profile (solver, simplify, now); + if (profile->level <= GET_OPTION (profile)) + push_profile (solver, profile, now); +} + +void kissat_stop_simplifier_and_resume_search (kissat *solver, + profile *profile) { + struct profile *simplify = &PROFILE (simplify); + struct profile *top = POP_STACK (solver->profiles.stack); + const double now = kissat_process_time (); + const double delta = flush_profile (simplify, now); +#ifndef NDEBUG + const double entered = now - delta; + assert (solver->mode.entered <= entered); +#endif + solver->mode.entered += delta; + if (top == profile) { + flush_profile (profile, now); + assert (TOP_STACK (solver->profiles.stack) == simplify); + (void) POP_STACK (solver->profiles.stack); + } else { + assert (simplify == top); + assert (profile->level > GET_OPTION (profile)); + } +#ifndef NDEBUG + struct profile *search = &PROFILE (search); + assert (search->level == simplify->level); +#endif + assert (simplify->level <= profile->level); + push_profile (solver, &PROFILE (search), now); + struct profile *mode = + solver->stable ? &PROFILE (stable) : &PROFILE (focused); + assert (search->level <= mode->level); + if (mode->level <= GET_OPTION (profile)) + push_profile (solver, mode, now); +} + +double kissat_time (kissat *solver) { + const double now = kissat_process_time (); + flush_profiles (&solver->profiles, now); + return PROFILE (total).time; +} + +#else +int kissat_profile_dummy_to_avoid_warning; +#endif diff --git a/src/sat/kissat/profile.h b/src/sat/kissat/profile.h new file mode 100644 index 000000000..62d03cf71 --- /dev/null +++ b/src/sat/kissat/profile.h @@ -0,0 +1,143 @@ +#ifndef _profile_h_INCLUDED +#define _profile_h_INCLUDED + +#ifndef QUIET + +#include "stack.h" + +typedef struct profile profile; +typedef struct profiles profiles; + +#define PROFS \ + PROF (analyze, 3) \ + PROF (backbone, 2) \ + PROF (bump, 3) \ + PROF (collect, 3) \ + PROF (congruence, 2) \ + PROF (decide, 4) \ + PROF (deduce, 3) \ + PROF (definition, 3) \ + PROF (defrag, 3) \ + PROF (dominate, 4) \ + PROF (eliminate, 2) \ + PROF (extend, 2) \ + PROF (extract, 3) \ + PROF (extractands, 3) \ + PROF (extractbinaries, 3) \ + PROF (extractites, 3) \ + PROF (extractxors, 3) \ + PROF (factor, 2) \ + PROF (fastel, 2) \ + PROF (focused, 2) \ + PROF (forward, 4) \ + PROF (lucky, 2) \ + PROF (matching, 3) \ + PROF (merge, 3) \ + PROF (minimize, 3) \ + PROF (parse, 1) \ + PROF (preprocess, 2) \ + PROF (probe, 2) \ + PROF (propagate, 4) \ + PROF (radix, 4) \ + PROF (reduce, 2) \ + PROF (reorder, 3) \ + PROF (rephase, 3) \ + PROF (restart, 3) \ + PROF (search, 1) \ + PROF (shrink, 3) \ + PROF (simplify, 1) \ + PROF (sort, 4) \ + PROF (stable, 2) \ + PROF (substitute, 2) \ + PROF (subsume, 2) \ + PROF (sweep, 2) \ + PROF (sweepbackbone, 3) \ + PROF (sweepequivalences, 3) \ + PROF (total, 0) \ + PROF (transitive, 2) \ + PROF (vivify, 2) \ + PROF (vivify0, 3) \ + PROF (vivify1, 3) \ + PROF (vivify2, 3) \ + PROF (vivify3, 3) \ + PROF (vivifysort, 4) \ + PROF (walking, 2) \ + PROF (warmup, 3) + +struct profile { + int level; + const char *name; + double entered; + double time; +}; + +struct profiles { +#define PROF(NAME, LEVEL) profile NAME; + PROFS +#undef PROF + STACK (profile *) stack; +}; + +struct kissat; + +void kissat_init_profiles (profiles *); +void kissat_profiles_print (struct kissat *); +void kissat_start (struct kissat *, profile *); +void kissat_stop (struct kissat *, profile *); + +void kissat_stop_search_and_start_simplifier (struct kissat *, profile *); +void kissat_stop_simplifier_and_resume_search (struct kissat *, profile *); + +double kissat_time (struct kissat *); + +#define PROFILE(NAME) (solver->profiles.NAME) + +#define START(NAME) \ + do { \ + profile *profile = &PROFILE (NAME); \ + if (GET_OPTION (profile) >= profile->level) \ + kissat_start (solver, profile); \ + } while (0) + +#define STOP(NAME) \ + do { \ + profile *profile = &PROFILE (NAME); \ + if (GET_OPTION (profile) >= profile->level) \ + kissat_stop (solver, profile); \ + } while (0) + +#define STOP_SEARCH_AND_START_SIMPLIFIER(NAME) \ + do { \ + if (GET_OPTION (profile) >= PROFILE (search).level) \ + kissat_stop_search_and_start_simplifier (solver, &PROFILE (NAME)); \ + } while (0) + +#define STOP_SIMPLIFIER_AND_RESUME_SEARCH(NAME) \ + do { \ + if (GET_OPTION (profile) >= PROFILE (search).level) \ + kissat_stop_simplifier_and_resume_search (solver, &PROFILE (NAME)); \ + } while (0) + +#else + +#define START(...) \ + do { \ + } while (0) +#define STOP(...) \ + do { \ + } while (0) + +#define STOP_SEARCH_AND_START_SIMPLIFIER(...) \ + do { \ + } while (0) +#define STOP_SIMPLIFIER_AND_RESUME_SEARCH(...) \ + do { \ + } while (0) + +#define STOP_AND_START(...) \ + do { \ + } while (0) + +#endif + +#endif diff --git a/src/sat/kissat/promote.c b/src/sat/kissat/promote.c new file mode 100644 index 000000000..152cfed4c --- /dev/null +++ b/src/sat/kissat/promote.c @@ -0,0 +1,42 @@ +#include "promote.h" +#include "internal.h" +#include "logging.h" + +void kissat_promote_clause (kissat *solver, clause *c, unsigned new_glue) { + if (!GET_OPTION (promote)) + return; + assert (c->redundant); + const unsigned old_glue = c->glue; + assert (new_glue < old_glue); + const unsigned tier1 = TIER1; + const unsigned tier2 = MAX (TIER2, TIER1); + if (old_glue <= tier1) { + LOGCLS (c, "keeping with new glue %u in tier1", new_glue); + INC (clauses_kept1); + } else if (new_glue <= tier1) { + assert (tier1 < old_glue); + assert (new_glue <= tier1); + LOGCLS (c, "promoting with new glue %u to tier1", new_glue); + INC (clauses_promoted1); + } else if (tier2 < old_glue && new_glue <= tier2) { + assert (tier2 < old_glue); + assert (tier1 < new_glue), assert (new_glue <= tier2); + LOGCLS (c, "promoting with new glue %u to tier2", new_glue); + INC (clauses_promoted2); + } else if (old_glue <= tier2) { + assert (tier1 < old_glue), assert (old_glue <= tier2); + assert (tier1 < new_glue), assert (new_glue <= tier2); + LOGCLS (c, "keeping with new glue %u in tier2", new_glue); + INC (clauses_kept2); + } else { + assert (tier2 < old_glue); + assert (tier2 < new_glue); + LOGCLS (c, "keeping with new glue %u in tier3", new_glue); + INC (clauses_kept3); + } + INC (clauses_improved); + c->glue = new_glue; +#ifndef LOGGING + (void) solver; +#endif +} diff --git a/src/sat/kissat/promote.h b/src/sat/kissat/promote.h new file mode 100644 index 000000000..3a6073cf6 --- /dev/null +++ b/src/sat/kissat/promote.h @@ -0,0 +1,33 @@ +#ifndef _promote_h_INCLUDED +#define _promote_h_INCLUDED + +#include "internal.h" + +void kissat_promote_clause (struct kissat *, clause *, unsigned new_glue); + +static inline unsigned kissat_recompute_glue (kissat *solver, clause *c, + unsigned limit) { + assert (limit); + assert (EMPTY_STACK (solver->promote)); + unsigned res = 0; + for (all_literals_in_clause (lit, c)) { + assert (VALUE (lit)); + const unsigned level = LEVEL (lit); + frame *frame = &FRAME (level); + if (frame->promote) + continue; + if (++res == limit) + break; + frame->promote = true; + PUSH_STACK (solver->promote, level); + } + for (all_stack (unsigned, level, solver->promote)) { + frame *frame = &FRAME (level); + assert (frame->promote); + frame->promote = false; + } + CLEAR_STACK (solver->promote); + return res; +} + +#endif diff --git a/src/sat/kissat/proof.c b/src/sat/kissat/proof.c new file mode 100644 index 000000000..5c819906b --- /dev/null +++ b/src/sat/kissat/proof.c @@ -0,0 +1,408 @@ +#ifndef NPROOFS + +#include "allocate.h" +#include "error.h" +#include "file.h" +#include "inline.h" + +#undef NDEBUG + +#ifndef NDEBUG +#include +#endif + +#define size_buffer (1u << 20) + +struct write_buffer { + unsigned char chars[size_buffer]; + size_t pos; +}; + +typedef struct write_buffer write_buffer; + +struct proof { + write_buffer buffer; + kissat *solver; + bool binary; + file *file; + ints line; + uint64_t added; + uint64_t deleted; + uint64_t lines; + uint64_t literals; +#ifndef NDEBUG + bool empty; + char *units; + size_t size_units; +#endif +#if !defined(NDEBUG) || defined(LOGGING) + unsigneds imported; +#endif +}; + +#undef LOGPREFIX +#define LOGPREFIX "PROOF" + +#define LOGIMPORTED3(...) \ + LOGLITS3 (SIZE_STACK (proof->imported), BEGIN_STACK (proof->imported), \ + __VA_ARGS__) + +#define LOGLINE3(...) \ + LOGINTS3 (SIZE_STACK (proof->line), BEGIN_STACK (proof->line), \ + __VA_ARGS__) + +void kissat_init_proof (kissat *solver, file *file, bool binary) { + assert (file); + assert (!solver->proof); + proof *proof = kissat_calloc (solver, 1, sizeof (struct proof)); + proof->binary = binary; + proof->file = file; + proof->solver = solver; + solver->proof = proof; + LOG ("starting to trace %s proof", binary ? "binary" : "non-binary"); +} + +static void flush_buffer (proof *proof) { + size_t bytes = proof->buffer.pos; + if (!bytes) + return; + size_t written = kissat_write (proof->file, proof->buffer.chars, bytes); + if (bytes != written) + kissat_fatal ("flushing %zu bytes in proof write-buffer failed", bytes); + proof->buffer.pos = 0; +} + +void kissat_release_proof (kissat *solver) { + proof *proof = solver->proof; + assert (proof); + LOG ("stopping to trace proof"); + flush_buffer (proof); + kissat_flush (proof->file); + RELEASE_STACK (proof->line); +#ifndef NDEBUG + kissat_free (solver, proof->units, proof->size_units); +#endif +#if !defined(NDEBUG) || defined(LOGGING) + RELEASE_STACK (proof->imported); +#endif + kissat_free (solver, proof, sizeof (struct proof)); + solver->proof = 0; +} + +#ifndef QUIET + +#include + +#define PERCENT_LINES(NAME) kissat_percent (proof->NAME, proof->lines) + +void kissat_print_proof_statistics (kissat *solver, bool verbose) { + proof *proof = solver->proof; + PRINT_STAT ("proof_added", proof->added, PERCENT_LINES (added), "%", + "per line"); + PRINT_STAT ("proof_bytes", proof->file->bytes, + proof->file->bytes / (double) (1 << 20), "MB", ""); + PRINT_STAT ("proof_deleted", proof->deleted, PERCENT_LINES (deleted), "%", + "per line"); + if (verbose) + PRINT_STAT ("proof_lines", proof->lines, 100, "%", ""); + if (verbose) + PRINT_STAT ("proof_literals", proof->literals, + kissat_average (proof->literals, proof->lines), "", + "per line"); +} + +#endif + +// clang-format off + +static inline void write_char (proof *, unsigned char) + ATTRIBUTE_ALWAYS_INLINE; + +static inline void import_external_proof_literal (kissat *, proof *, int) + ATTRIBUTE_ALWAYS_INLINE; + +static inline void +import_internal_proof_literal (kissat *, proof *, unsigned) + ATTRIBUTE_ALWAYS_INLINE; + +// clang-format on + +static inline void write_char (proof *proof, unsigned char ch) { + write_buffer *buffer = &proof->buffer; + if (buffer->pos == size_buffer) + flush_buffer (proof); + buffer->chars[buffer->pos++] = ch; +} + +static inline void import_internal_proof_literal (kissat *solver, + proof *proof, + unsigned ilit) { + int elit = kissat_export_literal (solver, ilit); + assert (elit); + PUSH_STACK (proof->line, elit); + proof->literals++; +#if !defined(NDEBUG) || defined(LOGGING) + PUSH_STACK (proof->imported, ilit); +#endif +} + +static inline void import_external_proof_literal (kissat *solver, + proof *proof, int elit) { + assert (elit); + PUSH_STACK (proof->line, elit); + proof->literals++; +#ifndef NDEBUG + assert (EMPTY_STACK (proof->imported)); +#endif +} + +static void import_internal_proof_binary (kissat *solver, proof *proof, + unsigned a, unsigned b) { + assert (EMPTY_STACK (proof->line)); + import_internal_proof_literal (solver, proof, a); + import_internal_proof_literal (solver, proof, b); +} + +static void import_internal_proof_literals (kissat *solver, proof *proof, + size_t size, + const unsigned *ilits) { + assert (EMPTY_STACK (proof->line)); + assert (size <= UINT_MAX); + for (size_t i = 0; i < size; i++) + import_internal_proof_literal (solver, proof, ilits[i]); +} + +static void import_external_proof_literals (kissat *solver, proof *proof, + size_t size, const int *elits) { + assert (EMPTY_STACK (proof->line)); + assert (size <= UINT_MAX); + for (size_t i = 0; i < size; i++) + import_external_proof_literal (solver, proof, elits[i]); +} + +static void import_proof_clause (kissat *solver, proof *proof, + const clause *c) { + import_internal_proof_literals (solver, proof, c->size, c->lits); +} + +static void print_binary_proof_line (proof *proof) { + assert (proof->binary); + for (all_stack (int, elit, proof->line)) { + unsigned x = 2u * ABS (elit) + (elit < 0); + unsigned char ch; + while (x & ~0x7f) { + ch = (x & 0x7f) | 0x80; + write_char (proof, ch); + x >>= 7; + } + write_char (proof, x); + } + write_char (proof, 0); +} + +static void print_non_binary_proof_line (proof *proof) { + assert (!proof->binary); + char buffer[16]; + char *end_of_buffer = buffer + sizeof buffer; + *--end_of_buffer = 0; + for (all_stack (int, elit, proof->line)) { + char *p = end_of_buffer; + assert (!*p); + assert (elit); + assert (elit != INT_MIN); + unsigned eidx; + if (elit < 0) { + write_char (proof, '-'); + eidx = -elit; + } else + eidx = elit; + for (unsigned tmp = eidx; tmp; tmp /= 10) + *--p = '0' + (tmp % 10); + while (p != end_of_buffer) + write_char (proof, *p++); + write_char (proof, ' '); + } + write_char (proof, '0'); + write_char (proof, '\n'); +} + +static void print_proof_line (proof *proof) { + proof->lines++; + if (proof->binary) + print_binary_proof_line (proof); + else + print_non_binary_proof_line (proof); + CLEAR_STACK (proof->line); +#if !defined(NDEBUG) || defined(LOGGING) + CLEAR_STACK (proof->imported); +#endif +#ifndef NOPTIONS + kissat *solver = proof->solver; +#endif + if (GET_OPTION (flushproof)) { + flush_buffer (proof); + kissat_flush (proof->file); + } +} + +#ifndef NDEBUG + +static unsigned external_to_proof_literal (int elit) { + assert (elit); + assert (elit != INT_MIN); + return 2u * (abs (elit) - 1) + (elit < 0); +} + +static void resize_proof_units (proof *proof, unsigned plit) { + kissat *solver = proof->solver; + const size_t old_size = proof->size_units; + size_t new_size = old_size ? old_size : 2; + while (new_size <= plit) + new_size *= 2; + char *new_units = kissat_calloc (solver, new_size, 1); + if (old_size) + memcpy (new_units, proof->units, old_size); + kissat_dealloc (solver, proof->units, old_size, 1); + proof->units = new_units; + proof->size_units = new_size; +} + +static void check_repeated_proof_lines (proof *proof) { + size_t size = SIZE_STACK (proof->line); + if (!size) { + assert (!proof->empty); + proof->empty = true; + } else if (size == 1) { + const int eunit = PEEK_STACK (proof->line, 0); + const unsigned punit = external_to_proof_literal (eunit); + assert (punit != INVALID_LIT); + if (!proof->size_units || proof->size_units <= punit) + resize_proof_units (proof, punit); + proof->units[punit] = 1; + } +} + +#endif + +static void print_added_proof_line (proof *proof) { + proof->added++; +#ifdef LOGGING + struct kissat *solver = proof->solver; + assert (SIZE_STACK (proof->imported) == SIZE_STACK (proof->line)); + LOGIMPORTED3 ("added proof line"); + LOGLINE3 ("added proof line"); +#endif +#ifndef NDEBUG + check_repeated_proof_lines (proof); +#endif + if (proof->binary) + write_char (proof, 'a'); + print_proof_line (proof); +} + +static void print_delete_proof_line (proof *proof) { + proof->deleted++; +#ifdef LOGGING + struct kissat *solver = proof->solver; + if (SIZE_STACK (proof->imported) == SIZE_STACK (proof->line)) + LOGIMPORTED3 ("deleted internal proof line"); + LOGLINE3 ("deleted external proof line"); +#endif + write_char (proof, 'd'); + if (!proof->binary) + write_char (proof, ' '); + print_proof_line (proof); +} + +void kissat_add_binary_to_proof (kissat *solver, unsigned a, unsigned b) { + proof *proof = solver->proof; + assert (proof); + import_internal_proof_binary (solver, proof, a, b); + print_added_proof_line (proof); +} + +void kissat_add_clause_to_proof (kissat *solver, const clause *c) { + proof *proof = solver->proof; + assert (proof); + import_proof_clause (solver, proof, c); + print_added_proof_line (proof); +} + +void kissat_add_empty_to_proof (kissat *solver) { + proof *proof = solver->proof; + assert (proof); + assert (EMPTY_STACK (proof->line)); + print_added_proof_line (proof); +} + +void kissat_add_lits_to_proof (kissat *solver, size_t size, + const unsigned *ilits) { + proof *proof = solver->proof; + assert (proof); + import_internal_proof_literals (solver, proof, size, ilits); + print_added_proof_line (proof); +} + +void kissat_add_unit_to_proof (kissat *solver, unsigned ilit) { + proof *proof = solver->proof; + assert (proof); + assert (EMPTY_STACK (proof->line)); + import_internal_proof_literal (solver, proof, ilit); + print_added_proof_line (proof); +} + +void kissat_shrink_clause_in_proof (kissat *solver, const clause *c, + unsigned remove, unsigned keep) { + proof *proof = solver->proof; + const value *const values = solver->values; + assert (EMPTY_STACK (proof->line)); + const unsigned *ilits = c->lits; + const unsigned size = c->size; + for (unsigned i = 0; i != size; i++) { + const unsigned ilit = ilits[i]; + if (ilit == remove) + continue; + if (ilit != keep && values[ilit] < 0 && !LEVEL (ilit)) + continue; + import_internal_proof_literal (solver, proof, ilit); + } + print_added_proof_line (proof); + import_proof_clause (solver, proof, c); + print_delete_proof_line (proof); +} + +void kissat_delete_binary_from_proof (kissat *solver, unsigned a, + unsigned b) { + proof *proof = solver->proof; + assert (proof); + import_internal_proof_binary (solver, proof, a, b); + print_delete_proof_line (proof); +} + +void kissat_delete_clause_from_proof (kissat *solver, const clause *c) { + proof *proof = solver->proof; + assert (proof); + import_proof_clause (solver, proof, c); + print_delete_proof_line (proof); +} + +void kissat_delete_external_from_proof (kissat *solver, size_t size, + const int *elits) { + proof *proof = solver->proof; + assert (proof); + LOGINTS3 (size, elits, "explicitly deleted"); + import_external_proof_literals (solver, proof, size, elits); + print_delete_proof_line (proof); +} + +void kissat_delete_internal_from_proof (kissat *solver, size_t size, + const unsigned *ilits) { + proof *proof = solver->proof; + assert (proof); + import_internal_proof_literals (solver, proof, size, ilits); + print_delete_proof_line (proof); +} + +#else +int kissat_proof_dummy_to_avoid_warning; +#endif diff --git a/src/sat/kissat/proof.h b/src/sat/kissat/proof.h new file mode 100644 index 000000000..a87e60de5 --- /dev/null +++ b/src/sat/kissat/proof.h @@ -0,0 +1,164 @@ +#ifndef _proof_h_INCLUDED +#define _proof_h_INCLUDED + +#ifndef NPROOFS + +#include +#include + +typedef struct proof proof; + +struct clause; +struct file; + +void kissat_init_proof (struct kissat *, struct file *, bool binary); +void kissat_release_proof (struct kissat *); + +#ifndef QUIET +void kissat_print_proof_statistics (struct kissat *, bool verbose); +#endif + +void kissat_add_binary_to_proof (struct kissat *, unsigned, unsigned); +void kissat_add_clause_to_proof (struct kissat *, const struct clause *c); +void kissat_add_empty_to_proof (struct kissat *); +void kissat_add_lits_to_proof (struct kissat *, size_t, const unsigned *); +void kissat_add_unit_to_proof (struct kissat *, unsigned); + +void kissat_shrink_clause_in_proof (struct kissat *, const struct clause *, + unsigned remove, unsigned keep); + +void kissat_delete_binary_from_proof (struct kissat *, unsigned, unsigned); +void kissat_delete_clause_from_proof (struct kissat *, + const struct clause *c); +void kissat_delete_external_from_proof (struct kissat *, size_t, + const int *); +void kissat_delete_internal_from_proof (struct kissat *, size_t, + const unsigned *); + +#define ADD_BINARY_TO_PROOF(A, B) \ + do { \ + if (solver->proof) \ + kissat_add_binary_to_proof (solver, (A), (B)); \ + } while (0) + +#define ADD_TERNARY_TO_PROOF(A, B, C) \ + do { \ + if (solver->proof) { \ + unsigned CLAUSE[3] = {(A), (B), (C)}; \ + kissat_add_lits_to_proof (solver, 3, CLAUSE); \ + } \ + } while (0) + +#define ADD_CLAUSE_TO_PROOF(CLAUSE) \ + do { \ + if (solver->proof) \ + kissat_add_clause_to_proof (solver, (CLAUSE)); \ + } while (0) + +#define ADD_EMPTY_TO_PROOF() \ + do { \ + if (solver->proof) \ + kissat_add_empty_to_proof (solver); \ + } while (0) + +#define ADD_LITS_TO_PROOF(SIZE, LITS) \ + do { \ + if (solver->proof) \ + kissat_add_lits_to_proof (solver, (SIZE), (LITS)); \ + } while (0) + +#define ADD_STACK_TO_PROOF(S) \ + ADD_LITS_TO_PROOF (SIZE_STACK (S), BEGIN_STACK (S)) + +#define ADD_UNIT_TO_PROOF(A) \ + do { \ + if (solver->proof) \ + kissat_add_unit_to_proof (solver, (A)); \ + } while (0) + +#define SHRINK_CLAUSE_IN_PROOF(C, REMOVE, KEEP) \ + do { \ + if (solver->proof) \ + kissat_shrink_clause_in_proof (solver, (C), (REMOVE), (KEEP)); \ + } while (0) + +#define DELETE_BINARY_FROM_PROOF(A, B) \ + do { \ + if (solver->proof) \ + kissat_delete_binary_from_proof (solver, (A), (B)); \ + } while (0) + +#define DELETE_TERNARY_FROM_PROOF(A, B, C) \ + do { \ + if (solver->proof) { \ + unsigned CLAUSE[3] = {(A), (B), (C)}; \ + kissat_delete_internal_from_proof (solver, 3, CLAUSE); \ + } \ + } while (0) + +#define DELETE_CLAUSE_FROM_PROOF(CLAUSE) \ + do { \ + if (solver->proof) \ + kissat_delete_clause_from_proof (solver, (CLAUSE)); \ + } while (0) + +#define DELETE_LITS_FROM_PROOF(SIZE, LITS) \ + do { \ + if (solver->proof) \ + kissat_delete_internal_from_proof (solver, (SIZE), (LITS)); \ + } while (0) + +#define DELETE_STACK_FROM_PROOF(S) \ + do { \ + if (solver->proof) \ + kissat_delete_internal_from_proof (solver, SIZE_STACK (S), \ + BEGIN_STACK (S)); \ + } while (0) + +#else + +#define ADD_BINARY_TO_PROOF(...) \ + do { \ + } while (0) +#define ADD_TERNARY_TO_PROOF(...) \ + do { \ + } while (0) +#define ADD_CLAUSE_TO_PROOF(...) \ + do { \ + } while (0) +#define ADD_LITS_TO_PROOF(...) \ + do { \ + } while (0) +#define ADD_EMPTY_TO_PROOF(...) \ + do { \ + } while (0) +#define ADD_STACK_TO_PROOF(...) \ + do { \ + } while (0) +#define ADD_UNIT_TO_PROOF(...) \ + do { \ + } while (0) + +#define SHRINK_CLAUSE_IN_PROOF(...) \ + do { \ + } while (0) + +#define DELETE_BINARY_FROM_PROOF(...) \ + do { \ + } while (0) +#define DELETE_TERNARY_FROM_PROOF(...) \ + do { \ + } while (0) +#define DELETE_CLAUSE_FROM_PROOF(...) \ + do { \ + } while (0) +#define DELETE_LITS_FROM_PROOF(...) \ + do { \ + } while (0) +#define DELETE_STACK_FROM_PROOF(...) \ + do { \ + } while (0) + +#endif + +#endif diff --git a/src/sat/kissat/propbeyond.c b/src/sat/kissat/propbeyond.c new file mode 100644 index 000000000..b42192b05 --- /dev/null +++ b/src/sat/kissat/propbeyond.c @@ -0,0 +1,48 @@ +#include "propbeyond.h" +#include "fastassign.h" +#include "trail.h" + +#define PROPAGATE_LITERAL propagate_literal_beyond_conflicts +#define CONTINUE_PROPAGATING_AFTER_CONFLICT +#define PROPAGATION_TYPE "beyond conflict" + +#include "proplit.h" + +static inline void +update_beyond_propagation_statistics (kissat *solver, + const unsigned *saved_propagate) { + assert (saved_propagate <= solver->propagate); + const unsigned propagated = solver->propagate - saved_propagate; + + LOG ("propagated %u literals", propagated); + LOG ("propagation took %" PRIu64 " ticks", solver->ticks); + + ADD (ticks, solver->ticks); + + ADD (propagations, propagated); + ADD (warming_propagations, propagated); +} + +static void propagate_literals_beyond_conflicts (kissat *solver) { + unsigned *propagate = solver->propagate; + while (propagate != END_ARRAY (solver->trail)) + if (propagate_literal_beyond_conflicts (solver, *propagate++)) + INC (warming_conflicts); + solver->propagate = propagate; +} + +void kissat_propagate_beyond_conflicts (kissat *solver) { + assert (!solver->probing); + assert (solver->watching); + assert (solver->warming); + assert (!solver->inconsistent); + + START (propagate); + + solver->ticks = 0; + const unsigned *saved_propagate = solver->propagate; + propagate_literals_beyond_conflicts (solver); + update_beyond_propagation_statistics (solver, saved_propagate); + + STOP (propagate); +} diff --git a/src/sat/kissat/propbeyond.h b/src/sat/kissat/propbeyond.h new file mode 100644 index 000000000..09eaf1b4e --- /dev/null +++ b/src/sat/kissat/propbeyond.h @@ -0,0 +1,9 @@ +#ifndef _propall_h_INCLUDED +#define _propall_h_INCLUDED + +struct kissat; +struct clause; + +void kissat_propagate_beyond_conflicts (struct kissat *); + +#endif diff --git a/src/sat/kissat/propdense.c b/src/sat/kissat/propdense.c new file mode 100644 index 000000000..48ccecb4f --- /dev/null +++ b/src/sat/kissat/propdense.c @@ -0,0 +1,108 @@ +#include "propdense.h" +#include "fastassign.h" + +static inline bool non_watching_propagate_literal (kissat *solver, + unsigned lit) { + assert (!solver->watching); + LOG ("propagating %s", LOGLIT (lit)); + assert (VALUE (lit) > 0); + const unsigned not_lit = NOT (lit); + + watches *watches = &WATCHES (not_lit); + const size_t size_watches = SIZE_WATCHES (*watches); + unsigned ticks = 1 + kissat_cache_lines (size_watches, sizeof (watch)); + + ward *const arena = BEGIN_STACK (solver->arena); + assigned *assigned = solver->assigned; + value *values = solver->values; + flags *flags = solver->flags; + + for (all_binary_large_watches (watch, *watches)) { + if (watch.type.binary) { + const unsigned other = watch.binary.lit; + assert (VALID_INTERNAL_LITERAL (other)); + const value other_value = values[other]; + if (other_value > 0) + continue; + if (other_value < 0) { + LOGBINARY (not_lit, other, "conflicting"); + return false; + } + const unsigned other_idx = IDX (other); + if (flags[other_idx].eliminated) + continue; + assert (!solver->level); + kissat_fast_binary_assign (solver, solver->probing, 0, values, + assigned, other, not_lit); + } else { + const reference ref = watch.large.ref; + assert (ref < SIZE_STACK (solver->arena)); + clause *c = (clause *) (arena + ref); + assert (c->size > 2); + assert (!c->redundant); + ticks++; + if (c->garbage) + continue; + unsigned non_false = 0; + unsigned unit = INVALID_LIT; + bool satisfied = false; + for (all_literals_in_clause (other, c)) { + if (other == not_lit) + continue; + assert (VALID_INTERNAL_LITERAL (other)); + const value other_value = values[other]; + if (other_value < 0) + continue; + if (other_value > 0) { + satisfied = true; + assert (!solver->level); + LOGCLS (c, "%s satisfied", LOGLIT (other)); + kissat_mark_clause_as_garbage (solver, c); + break; + } + if (!non_false++) + unit = other; + else if (non_false > 1) + break; + } + if (satisfied) + continue; + if (!non_false) { + LOGREF (ref, "conflicting"); + return false; + } + if (non_false == 1) + kissat_fast_assign_reference (solver, values, assigned, unit, ref, + c); + } + } + + ADD (ticks, ticks); + ADD (dense_ticks, ticks); + + return true; +} + +bool kissat_dense_propagate (kissat *solver) { + assert (!solver->level); + assert (!solver->watching); + assert (!solver->inconsistent); + START (propagate); + unsigned *propagate = solver->propagate; + bool res = true; + while (res && propagate != END_ARRAY (solver->trail)) + res = non_watching_propagate_literal (solver, *propagate++); + const unsigned propagated = propagate - solver->propagate; + solver->propagate = propagate; + ADD (dense_propagations, propagated); + ADD (propagations, propagated); + if (!res) { + assert (!solver->inconsistent); + LOG ("inconsistent root propagation"); + CHECK_AND_ADD_EMPTY (); + ADD_EMPTY_TO_PROOF (); + solver->inconsistent = true; + } + STOP (propagate); + return res; +} diff --git a/src/sat/kissat/propdense.h b/src/sat/kissat/propdense.h new file mode 100644 index 000000000..adbaae1cd --- /dev/null +++ b/src/sat/kissat/propdense.h @@ -0,0 +1,11 @@ +#ifndef _propdense_h_INCLUDED +#define _propdense_h_INCLUDED + +#include +#include + +struct kissat; + +bool kissat_dense_propagate (struct kissat *); + +#endif diff --git a/src/sat/kissat/propinitially.c b/src/sat/kissat/propinitially.c new file mode 100644 index 000000000..5f66db3d1 --- /dev/null +++ b/src/sat/kissat/propinitially.c @@ -0,0 +1,56 @@ +#include "propinitially.h" +#include "analyze.h" +#include "fastassign.h" +#include "print.h" +#include "trail.h" + +#define PROPAGATE_LITERAL initially_propagate_literal +#define PROPAGATION_TYPE "initially" + +#include "proplit.h" + +static inline void +update_initial_propagation_statistics (kissat *solver, + const unsigned *saved_propagate) { + assert (saved_propagate <= solver->propagate); + const unsigned propagated = solver->propagate - saved_propagate; + + LOG ("propagated %u literals", propagated); + LOG ("propagation took %" PRIu64 " ticks", solver->ticks); + + ADD (propagations, propagated); + ADD (ticks, solver->ticks); +} + +static clause *initially_propagate (kissat *solver) { + clause *res = 0; + unsigned *propagate = solver->propagate; + while (!res && propagate != END_ARRAY (solver->trail)) + res = initially_propagate_literal (solver, *propagate++); + solver->propagate = propagate; + return res; +} + +bool kissat_initially_propagate (kissat *solver) { + assert (!solver->probing); + assert (solver->watching); + assert (!solver->inconsistent); + + START (propagate); + + solver->ticks = 0; + const unsigned *saved_propagate = solver->propagate; + clause *conflict = initially_propagate (solver); + update_initial_propagation_statistics (solver, saved_propagate); + kissat_update_conflicts_and_trail (solver, conflict, true); + if (conflict) { + int res = kissat_analyze (solver, conflict); + assert (solver->inconsistent); + assert (res == 20); + (void) res; + } + + STOP (propagate); + + return !conflict; +} diff --git a/src/sat/kissat/propinitially.h b/src/sat/kissat/propinitially.h new file mode 100644 index 000000000..d53f84c9a --- /dev/null +++ b/src/sat/kissat/propinitially.h @@ -0,0 +1,10 @@ +#ifndef _propinitially_h_INCLUDED +#define _propinitially_h_INCLUDED + +#include + +struct kissat; + +bool kissat_initially_propagate (struct kissat *); + +#endif diff --git a/src/sat/kissat/proplit.h b/src/sat/kissat/proplit.h new file mode 100644 index 000000000..c8ae9c1cb --- /dev/null +++ b/src/sat/kissat/proplit.h @@ -0,0 +1,204 @@ +static inline void kissat_watch_large_delayed (kissat *solver, + watches *all_watches, + unsigneds *delayed) { + assert (all_watches == solver->watches); + assert (delayed == &solver->delayed); + const unsigned *const end_delayed = END_STACK (*delayed); + unsigned const *d = BEGIN_STACK (*delayed); + while (d != end_delayed) { + const unsigned lit = *d++; + assert (d != end_delayed); + const watch watch = {.raw = *d++}; + assert (!watch.type.binary); + assert (lit < LITS); + watches *const lit_watches = all_watches + lit; + assert (d != end_delayed); + const reference ref = *d++; + const unsigned blocking = watch.blocking.lit; + LOGREF3 (ref, "watching %s blocking %s in", LOGLIT (lit), + LOGLIT (blocking)); + kissat_push_blocking_watch (solver, lit_watches, blocking, ref); + } + CLEAR_STACK (*delayed); +} + +static inline void +kissat_delay_watching_large (kissat *solver, unsigneds *const delayed, + unsigned lit, unsigned other, reference ref) { + const watch watch = kissat_blocking_watch (other); + PUSH_STACK (*delayed, lit); + PUSH_STACK (*delayed, watch.raw); + PUSH_STACK (*delayed, ref); +} + +static inline clause *PROPAGATE_LITERAL (kissat *solver, +#if defined(PROBING_PROPAGATION) + const clause *const ignore, +#endif + const unsigned lit) { + assert (solver->watching); + LOG (PROPAGATION_TYPE " propagating %s", LOGLIT (lit)); + assert (VALUE (lit) > 0); + assert (EMPTY_STACK (solver->delayed)); + + watches *const all_watches = solver->watches; + ward *const arena = BEGIN_STACK (solver->arena); + assigned *const assigned = solver->assigned; + value *const values = solver->values; + + const unsigned not_lit = NOT (lit); + + assert (not_lit < LITS); + watches *watches = all_watches + not_lit; + + watch *const begin_watches = BEGIN_WATCHES (*watches); + const watch *const end_watches = END_WATCHES (*watches); + + watch *q = begin_watches; + const watch *p = q; + + unsigneds *const delayed = &solver->delayed; + assert (EMPTY_STACK (*delayed)); + + const size_t size_watches = SIZE_WATCHES (*watches); + uint64_t ticks = 1 + kissat_cache_lines (size_watches, sizeof (watch)); + const unsigned idx = IDX (lit); + struct assigned *const a = assigned + idx; + const bool probing = solver->probing; + const unsigned level = a->level; + clause *res = 0; + + while (p != end_watches) { + const watch head = *q++ = *p++; + const unsigned blocking = head.blocking.lit; + assert (VALID_INTERNAL_LITERAL (blocking)); + const value blocking_value = values[blocking]; + const bool binary = head.type.binary; + watch tail; + if (!binary) + tail = *q++ = *p++; + if (blocking_value > 0) + continue; + if (binary) { + if (blocking_value < 0) { + res = kissat_binary_conflict (solver, not_lit, blocking); +#ifndef CONTINUE_PROPAGATING_AFTER_CONFLICT + break; +#endif + } else { + assert (!blocking_value); + kissat_fast_binary_assign (solver, probing, level, values, assigned, + blocking, not_lit); + ticks++; + } + } else { + const reference ref = tail.raw; + assert (ref < SIZE_STACK (solver->arena)); + clause *const c = (clause *) (arena + ref); + ticks++; + if (c->garbage) { + q -= 2; + continue; + } + unsigned *const lits = BEGIN_LITS (c); + const unsigned other = lits[0] ^ lits[1] ^ not_lit; + assert (lits[0] != lits[1]); + assert (VALID_INTERNAL_LITERAL (other)); + assert (not_lit != other); + assert (lit != other); + const value other_value = values[other]; + if (other_value > 0) { + q[-2].blocking.lit = other; + continue; + } + const unsigned *const end_lits = lits + c->size; + unsigned *const searched = lits + c->searched; + assert (c->lits + 2 <= searched); + assert (searched < end_lits); + unsigned *r, replacement = INVALID_LIT; + value replacement_value = -1; + for (r = searched; r != end_lits; r++) { + replacement = *r; + assert (VALID_INTERNAL_LITERAL (replacement)); + replacement_value = values[replacement]; + if (replacement_value >= 0) + break; + } + if (replacement_value < 0) { + for (r = lits + 2; r != searched; r++) { + replacement = *r; + assert (VALID_INTERNAL_LITERAL (replacement)); + replacement_value = values[replacement]; + if (replacement_value >= 0) + break; + } + } + + if (replacement_value >= 0) { + c->searched = r - lits; + assert (replacement != INVALID_LIT); + LOGREF3 (ref, "unwatching %s in", LOGLIT (not_lit)); + q -= 2; + lits[0] = other; + lits[1] = replacement; + assert (lits[0] != lits[1]); + *r = not_lit; + kissat_delay_watching_large (solver, delayed, replacement, other, + ref); + ticks++; + } else if (other_value) { + assert (replacement_value < 0); + assert (blocking_value < 0); + assert (other_value < 0); +#if defined(PROBING_PROPAGATION) + if (c == ignore) { + LOGREF (ref, "conflicting but ignored"); + continue; + } +#endif + LOGREF (ref, "conflicting"); + res = c; +#ifndef CONTINUE_PROPAGATING_AFTER_CONFLICT + break; +#endif + } else { + assert (replacement_value < 0); +#if defined(PROBING_PROPAGATION) + if (c == ignore) { + LOGREF (ref, "forcing %s but ignored", LOGLIT (other)); + continue; + } +#endif + kissat_fast_assign_reference (solver, values, assigned, other, ref, + c); + ticks++; + } + } + } + solver->ticks += ticks; + + while (p != end_watches) + *q++ = *p++; + SET_END_OF_WATCHES (*watches, q); + + kissat_watch_large_delayed (solver, all_watches, delayed); + + return res; +} + +static inline void kissat_update_conflicts_and_trail (kissat *solver, + clause *conflict, + bool flush) { + if (conflict) { +#ifndef PROBING_PROPAGATION + INC (conflicts); +#endif + if (!solver->level) { + LOG (PROPAGATION_TYPE " propagation on root-level failed"); + solver->inconsistent = true; + CHECK_AND_ADD_EMPTY (); + ADD_EMPTY_TO_PROOF (); + } + } else if (flush && !solver->level && solver->unflushed) + kissat_flush_trail (solver); +} diff --git a/src/sat/kissat/proprobe.c b/src/sat/kissat/proprobe.c new file mode 100644 index 000000000..e95873317 --- /dev/null +++ b/src/sat/kissat/proprobe.c @@ -0,0 +1,59 @@ +#include "proprobe.h" +#include "fastassign.h" +#include "trail.h" + +#define PROPAGATE_LITERAL probing_propagate_literal +#define PROPAGATION_TYPE "probing" +#define PROBING_PROPAGATION + +#include "proplit.h" + +static void update_probing_propagation_statistics (kissat *solver, + unsigned propagated) { + const uint64_t ticks = solver->ticks; + LOG (PROPAGATION_TYPE " propagation took %u propagations", propagated); + LOG (PROPAGATION_TYPE " propagation took %" PRIu64 " ticks", ticks); + + ADD (propagations, propagated); + ADD (probing_propagations, propagated); + +#if defined(METRICS) + if (solver->backbone_computing) { + ADD (backbone_propagations, propagated); + ADD (backbone_ticks, ticks); + } + if (solver->vivifying) { + ADD (vivify_propagations, propagated); + ADD (vivify_ticks, ticks); + } +#endif + + ADD (probing_ticks, ticks); + ADD (ticks, ticks); +} + +clause *kissat_probing_propagate (kissat *solver, clause *ignore, + bool flush) { + assert (solver->probing); + assert (solver->watching); + assert (!solver->inconsistent); + + START (propagate); + + clause *conflict = 0; + unsigned *propagate = solver->propagate; + solver->ticks = 0; + while (!conflict && propagate != END_ARRAY (solver->trail)) { + const unsigned lit = *propagate++; + conflict = probing_propagate_literal (solver, ignore, lit); + } + + const unsigned propagated = propagate - solver->propagate; + solver->propagate = propagate; + update_probing_propagation_statistics (solver, propagated); + kissat_update_conflicts_and_trail (solver, conflict, flush); + + STOP (propagate); + + return conflict; +} diff --git a/src/sat/kissat/proprobe.h b/src/sat/kissat/proprobe.h new file mode 100644 index 000000000..9fbebe8cc --- /dev/null +++ b/src/sat/kissat/proprobe.h @@ -0,0 +1,12 @@ +#ifndef _proprobe_h_INCLUDED +#define _proprobe_h_INCLUDED + +#include + +struct kissat; +struct clause; + +struct clause *kissat_probing_propagate (struct kissat *, struct clause *, + bool flush); + +#endif diff --git a/src/sat/kissat/propsearch.c b/src/sat/kissat/propsearch.c new file mode 100644 index 000000000..c1265301c --- /dev/null +++ b/src/sat/kissat/propsearch.c @@ -0,0 +1,71 @@ +#include "propsearch.h" +#include "fastassign.h" +#include "print.h" +#include "trail.h" + +#define PROPAGATE_LITERAL search_propagate_literal +#define PROPAGATION_TYPE "search" + +#include "proplit.h" + +static inline void +update_search_propagation_statistics (kissat *solver, + const unsigned *saved_propagate) { + assert (saved_propagate <= solver->propagate); + const unsigned propagated = solver->propagate - saved_propagate; + + LOG ("propagated %u literals", propagated); + LOG ("propagation took %" PRIu64 " ticks", solver->ticks); + + ADD (propagations, propagated); + ADD (ticks, solver->ticks); + + ADD (search_propagations, propagated); + ADD (search_ticks, solver->ticks); + + if (solver->stable) { + ADD (stable_propagations, propagated); + ADD (stable_ticks, solver->ticks); + } else { + ADD (focused_propagations, propagated); + ADD (focused_ticks, solver->ticks); + } +} + +static clause *search_propagate (kissat *solver) { + clause *res = 0; + unsigned *propagate = solver->propagate; + while (!res && propagate != END_ARRAY (solver->trail)) + res = search_propagate_literal (solver, *propagate++); + solver->propagate = propagate; + return res; +} + +clause *kissat_search_propagate (kissat *solver) { + assert (!solver->probing); + assert (solver->watching); + assert (!solver->inconsistent); + + START (propagate); + + solver->ticks = 0; + const unsigned *saved_propagate = solver->propagate; + clause *conflict = search_propagate (solver); + update_search_propagation_statistics (solver, saved_propagate); + kissat_update_conflicts_and_trail (solver, conflict, true); + if (conflict && solver->randec) { + if (!--solver->randec) + kissat_very_verbose (solver, "last random decision conflict"); + else if (solver->randec == 1) + kissat_very_verbose (solver, + "one more random decision conflict to go"); + else + kissat_very_verbose (solver, + "%s more random decision conflicts to go", + FORMAT_COUNT (solver->randec)); + } + + STOP (propagate); + + return conflict; +} diff --git a/src/sat/kissat/propsearch.h b/src/sat/kissat/propsearch.h new file mode 100644 index 000000000..a774d9c5b --- /dev/null +++ b/src/sat/kissat/propsearch.h @@ -0,0 +1,9 @@ +#ifndef _propsearch_h_INCLUDED +#define _propsearch_h_INCLUDED + +struct kissat; +struct clause; + +struct clause *kissat_search_propagate (struct kissat *); + +#endif diff --git a/src/sat/kissat/queue.c b/src/sat/kissat/queue.c new file mode 100644 index 000000000..f64dfe2a3 --- /dev/null +++ b/src/sat/kissat/queue.c @@ -0,0 +1,55 @@ +#include "inline.h" +#include "inlinequeue.h" +#include "print.h" + +void kissat_init_queue (kissat *solver) { + queue *queue = &solver->queue; + queue->first = queue->last = DISCONNECT; + assert (!queue->stamp); + queue->search.idx = DISCONNECT; + assert (!queue->search.stamp); +} + +void kissat_reset_search_of_queue (kissat *solver) { + LOG ("reset last search cache of queue"); + queue *queue = &solver->queue; + links *links = solver->links; + const unsigned last = queue->last; + assert (!DISCONNECTED (last)); + kissat_update_queue (solver, links, last); +} + +void kissat_reassign_queue_stamps (kissat *solver) { + kissat_very_verbose (solver, "need to reassign enqueue stamps on queue"); + + queue *queue = &solver->queue; + links *links = solver->links; + queue->stamp = 0; + + struct links *l; + for (unsigned idx = queue->first; !DISCONNECTED (idx); idx = l->next) + (l = links + idx)->stamp = ++queue->stamp; + + if (!DISCONNECTED (queue->search.idx)) + queue->search.stamp = links[queue->search.idx].stamp; +} + +#if defined(CHECK_QUEUE) && !defined(NDEBUG) +void kissat_check_queue (kissat *solver) { + links *links = solver->links; + queue *queue = &solver->queue; + bool passed_search_idx = false; + const bool focused = !solver->stable; + for (unsigned idx = queue->first, prev = DISCONNECT; !DISCONNECTED (idx); + idx = links[idx].next) { + if (!DISCONNECTED (prev)) + assert (links[prev].stamp < links[idx].stamp); + if (focused && passed_search_idx) + assert (VALUE (LIT (idx))); + if (idx == queue->search.idx) + passed_search_idx = true; + } + if (!DISCONNECTED (queue->search.idx)) + assert (links[queue->search.idx].stamp == queue->search.stamp); +} +#endif diff --git a/src/sat/kissat/queue.h b/src/sat/kissat/queue.h new file mode 100644 index 000000000..271e7e567 --- /dev/null +++ b/src/sat/kissat/queue.h @@ -0,0 +1,38 @@ +#ifndef _queue_h_INCLUDED +#define _queue_h_INCLUDED + +#define DISCONNECT UINT_MAX +#define DISCONNECTED(IDX) ((int) (IDX) < 0) + +struct kissat; + +typedef struct links links; +typedef struct queue queue; + +struct links { + unsigned prev, next; + unsigned stamp; +}; + +struct queue { + unsigned first, last, stamp; + struct { + unsigned idx, stamp; + } search; +}; + +void kissat_init_queue (struct kissat *); +void kissat_reset_search_of_queue (struct kissat *); +void kissat_reassign_queue_stamps (struct kissat *); + +#define LINK(IDX) (solver->links[assert ((IDX) < VARS), (IDX)]) + +#if defined(CHECK_QUEUE) && !defined(NDEBUG) +void kissat_check_queue (struct kissat *); +#else +#define kissat_check_queue(...) \ + do { \ + } while (0) +#endif + +#endif diff --git a/src/sat/kissat/random.h b/src/sat/kissat/random.h new file mode 100644 index 000000000..7f00fbf99 --- /dev/null +++ b/src/sat/kissat/random.h @@ -0,0 +1,44 @@ +#ifndef _random_h_INCLUDED +#define _random_h_INCLUDED + +#include +#include +#include + +typedef uint64_t generator; + +static inline uint64_t kissat_next_random64 (generator *rng) { + *rng *= 6364136223846793005ul; + *rng += 1442695040888963407ul; + return *rng; +} + +static inline unsigned kissat_next_random32 (generator *rng) { + return kissat_next_random64 (rng) >> 32; +} + +static inline unsigned kissat_pick_random (generator *rng, unsigned l, + unsigned r) { + assert (l <= r); + if (l == r) + return l; + const unsigned delta = r - l; + const unsigned tmp = kissat_next_random32 (rng); + const double fraction = tmp / 4294967296.0; + assert (0 <= fraction), assert (fraction < 1); + const unsigned scaled = delta * fraction; + assert (scaled < delta); + const unsigned res = l + scaled; + assert (l <= res), assert (res < r); + return res; +} + +static inline bool kissat_pick_bool (generator *rng) { + return kissat_pick_random (rng, 0, 2); +} + +static inline double kissat_pick_double (generator *rng) { + return kissat_next_random32 (rng) / 4294967296.0; +} + +#endif diff --git a/src/sat/kissat/rank.h b/src/sat/kissat/rank.h new file mode 100644 index 000000000..283536536 --- /dev/null +++ b/src/sat/kissat/rank.h @@ -0,0 +1,140 @@ +#ifndef _rank_h_INCLUDED +#define _rank_h_INCLUDED + +#include "allocate.h" + +#include + +#ifdef NDEBUG +#define CHECK_RANKED(...) \ + do { \ + } while (0) +#else +#define CHECK_RANKED(N, A, RANK) \ + do { \ + assert (0 < (N)); \ + for (size_t I_CHECK_RANKED = 0; I_CHECK_RANKED < N - 1; \ + I_CHECK_RANKED++) \ + assert (RANK (A[I_CHECK_RANKED]) <= RANK (A[I_CHECK_RANKED + 1])); \ + } while (0) +#endif + +#define RADIX_SORT(VTYPE, RTYPE, N, V, RANK) \ + do { \ + const size_t N_RADIX = (N); \ + if (N_RADIX <= 1) \ + break; \ +\ + START (radix); \ +\ + VTYPE *V_RADIX = (V); \ +\ + const size_t LENGTH_RADIX = 8; \ + const size_t WIDTH_RADIX = (1 << LENGTH_RADIX); \ + const RTYPE MASK_RADIX = WIDTH_RADIX - 1; \ +\ + size_t COUNT_RADIX[WIDTH_RADIX]; \ +\ + VTYPE *TMP_RADIX = 0; \ + const size_t BYTES_TMP_RADIX = N_RADIX * sizeof (VTYPE); \ +\ + VTYPE *A_RADIX = V_RADIX; \ + VTYPE *B_RADIX = 0; \ + VTYPE *C_RADIX = A_RADIX; \ +\ + RTYPE MLOWER_RADIX = 0; \ + RTYPE MUPPER_RADIX = MASK_RADIX; \ +\ + bool BOUNDED_RADIX = false; \ + RTYPE UPPER_RADIX = 0; \ + RTYPE LOWER_RADIX = ~UPPER_RADIX; \ + RTYPE SHIFT_RADIX = MASK_RADIX; \ +\ + for (size_t I_RADIX = 0; I_RADIX < 8 * sizeof (RTYPE); \ + I_RADIX += LENGTH_RADIX, SHIFT_RADIX <<= LENGTH_RADIX) { \ + if (BOUNDED_RADIX && \ + (LOWER_RADIX & SHIFT_RADIX) == (UPPER_RADIX & SHIFT_RADIX)) \ + continue; \ +\ + memset (COUNT_RADIX + MLOWER_RADIX, 0, \ + (MUPPER_RADIX - MLOWER_RADIX + 1) * sizeof *COUNT_RADIX); \ +\ + VTYPE *END_RADIX = C_RADIX + N_RADIX; \ +\ + bool SORTED_RADIX = true; \ + RTYPE LAST_RADIX = 0; \ +\ + for (VTYPE *P_RADIX = C_RADIX; P_RADIX != END_RADIX; P_RADIX++) { \ + RTYPE R_RADIX = RANK (*P_RADIX); \ + if (!BOUNDED_RADIX) { \ + LOWER_RADIX &= R_RADIX; \ + UPPER_RADIX |= R_RADIX; \ + } \ + RTYPE S_RADIX = R_RADIX >> I_RADIX; \ + RTYPE M_RADIX = S_RADIX & MASK_RADIX; \ + if (SORTED_RADIX && LAST_RADIX > M_RADIX) \ + SORTED_RADIX = false; \ + else \ + LAST_RADIX = M_RADIX; \ + COUNT_RADIX[M_RADIX]++; \ + } \ +\ + MLOWER_RADIX = (LOWER_RADIX >> I_RADIX) & MASK_RADIX; \ + MUPPER_RADIX = (UPPER_RADIX >> I_RADIX) & MASK_RADIX; \ +\ + if (!BOUNDED_RADIX) { \ + BOUNDED_RADIX = true; \ + if ((LOWER_RADIX & SHIFT_RADIX) == (UPPER_RADIX & SHIFT_RADIX)) \ + continue; \ + } \ +\ + if (SORTED_RADIX) \ + continue; \ +\ + size_t POS_RADIX = 0; \ + for (size_t J_RADIX = MLOWER_RADIX; J_RADIX <= MUPPER_RADIX; \ + J_RADIX++) { \ + const size_t DELTA_RADIX = COUNT_RADIX[J_RADIX]; \ + COUNT_RADIX[J_RADIX] = POS_RADIX; \ + POS_RADIX += DELTA_RADIX; \ + } \ +\ + if (!TMP_RADIX) { \ + assert (C_RADIX == A_RADIX); \ + TMP_RADIX = kissat_malloc (solver, BYTES_TMP_RADIX); \ + B_RADIX = TMP_RADIX; \ + } \ +\ + assert (B_RADIX == TMP_RADIX); \ +\ + VTYPE *D_RADIX = (C_RADIX == A_RADIX) ? B_RADIX : A_RADIX; \ +\ + for (VTYPE *P_RADIX = C_RADIX; P_RADIX != END_RADIX; P_RADIX++) { \ + RTYPE R_RADIX = RANK (*P_RADIX); \ + RTYPE S_RADIX = R_RADIX >> I_RADIX; \ + RTYPE M_RADIX = S_RADIX & MASK_RADIX; \ + const size_t POS_RADIX = COUNT_RADIX[M_RADIX]++; \ + D_RADIX[POS_RADIX] = *P_RADIX; \ + } \ +\ + C_RADIX = D_RADIX; \ + } \ +\ + if (C_RADIX == B_RADIX) \ + memcpy (A_RADIX, B_RADIX, N_RADIX * sizeof *A_RADIX); \ +\ + if (TMP_RADIX) \ + kissat_free (solver, TMP_RADIX, BYTES_TMP_RADIX); \ +\ + CHECK_RANKED (N_RADIX, V_RADIX, RANK); \ + STOP (radix); \ + } while (0) + +#define RADIX_STACK(VTYPE, RTYPE, S, RANK) \ + do { \ + const size_t N_RADIX_STACK = SIZE_STACK (S); \ + VTYPE *A_RADIX_STACK = BEGIN_STACK (S); \ + RADIX_SORT (VTYPE, RTYPE, N_RADIX_STACK, A_RADIX_STACK, RANK); \ + } while (0) + +#endif diff --git a/src/sat/kissat/reduce.c b/src/sat/kissat/reduce.c new file mode 100644 index 000000000..027798520 --- /dev/null +++ b/src/sat/kissat/reduce.c @@ -0,0 +1,198 @@ +#include "reduce.h" +#include "allocate.h" +#include "collect.h" +#include "inline.h" +#include "print.h" +#include "rank.h" +#include "report.h" +#include "tiers.h" +#include "trail.h" + +#include +#include + +bool kissat_reducing (kissat *solver) { + if (!GET_OPTION (reduce)) + return false; + if (!solver->statistics.clauses_redundant) + return false; + if (CONFLICTS < solver->limits.reduce.conflicts) + return false; + return true; +} + +typedef struct reducible reducible; + +struct reducible { + uint64_t rank; + unsigned ref; +}; + +#define RANK_REDUCIBLE(RED) (RED).rank + +// clang-format off +typedef STACK (reducible) reducibles; +// clang-format on + +static bool collect_reducibles (kissat *solver, reducibles *reds, + reference start_ref) { + assert (start_ref != INVALID_REF); + assert (start_ref <= SIZE_STACK (solver->arena)); + ward *const arena = BEGIN_STACK (solver->arena); + clause *start = (clause *) (arena + start_ref); + const clause *const end = (clause *) END_STACK (solver->arena); + assert (start < end); + while (start != end && !start->redundant) + start = kissat_next_clause (start); + if (start == end) { + solver->first_reducible = INVALID_REF; + LOG ("no reducible clause candidate left"); + return false; + } + const reference redundant = (ward *) start - arena; +#ifdef LOGGING + if (redundant < solver->first_reducible) + LOG ("updating start of redundant clauses from %zu to %zu", + (size_t) solver->first_reducible, (size_t) redundant); + else + LOG ("no update to start of redundant clauses %zu", + (size_t) solver->first_reducible); +#endif + solver->first_reducible = redundant; + const unsigned tier1 = TIER1; + const unsigned tier2 = MAX (tier1, TIER2); + assert (tier1 <= tier2); + for (clause *c = start; c != end; c = kissat_next_clause (c)) { + if (!c->redundant) + continue; + if (c->garbage) + continue; + const unsigned used = c->used; + if (used) + c->used = used - 1; + if (c->reason) + continue; + const unsigned glue = c->glue; + if (glue <= tier1 && used) + continue; + if (glue <= tier2 && used >= MAX_USED - 1) + continue; + assert (kissat_clause_in_arena (solver, c)); + reducible red; + const uint64_t negative_size = ~c->size; + const uint64_t negative_glue = ~c->glue; + red.rank = negative_size | (negative_glue << 32); + red.ref = (ward *) c - arena; + PUSH_STACK (*reds, red); + } + if (EMPTY_STACK (*reds)) { + kissat_phase (solver, "reduce", GET (reductions), + "did not find any reducible redundant clause"); + return false; + } + return true; +} + +#define USEFULNESS RANK_REDUCIBLE + +static void sort_reducibles (kissat *solver, reducibles *reds) { + RADIX_STACK (reducible, uint64_t, *reds, USEFULNESS); +} + +static void mark_less_useful_clauses_as_garbage (kissat *solver, + reducibles *reds) { + statistics *statistics = &solver->statistics; + const double high = GET_OPTION (reducehigh) * 0.1; + const double low = GET_OPTION (reducelow) * 0.1; + double percent; + if (low < high) { + const double delta = high - low; + percent = high - delta / log10 (statistics->reductions + 9); + } else + percent = low; + const double fraction = percent / 100.0; + const size_t size = SIZE_STACK (*reds); + size_t target = size * fraction; +#ifndef QUIET + const size_t clauses = + statistics->clauses_irredundant + statistics->clauses_redundant; + kissat_phase (solver, "reduce", GET (reductions), + "reducing %zu (%.0f%%) out of %zu (%.0f%%) " + "reducible clauses", + target, kissat_percent (target, size), size, + kissat_percent (size, clauses)); +#endif + unsigned reduced = 0, reduced1 = 0, reduced2 = 0, reduced3 = 0; + ward *arena = BEGIN_STACK (solver->arena); + const reducible *const begin = BEGIN_STACK (*reds); + const reducible *const end = END_STACK (*reds); + const unsigned tier1 = TIER1; + const unsigned tier2 = TIER2; + for (const reducible *p = begin; p != end && target--; p++) { + clause *c = (clause *) (arena + p->ref); + assert (kissat_clause_in_arena (solver, c)); + assert (!c->garbage); + assert (!c->reason); + assert (c->redundant); + LOGCLS (c, "reducing"); + kissat_mark_clause_as_garbage (solver, c); + reduced++; + if (c->glue <= tier1) + reduced1++; + else if (c->glue <= tier2) + reduced2++; + else + reduced3++; + } + ADD (clauses_reduced_tier1, reduced1); + ADD (clauses_reduced_tier2, reduced2); + ADD (clauses_reduced_tier3, reduced3); + ADD (clauses_reduced, reduced); +} + +int kissat_reduce (kissat *solver) { + START (reduce); + INC (reductions); + kissat_phase (solver, "reduce", GET (reductions), + "reduce limit %" PRIu64 " hit after %" PRIu64 " conflicts", + solver->limits.reduce.conflicts, CONFLICTS); + kissat_compute_and_set_tier_limits (solver); + bool compact = kissat_compacting (solver); + reference start = compact ? 0 : solver->first_reducible; + if (start != INVALID_REF) { +#ifndef QUIET + size_t arena_size = SIZE_STACK (solver->arena); + size_t words_to_sweep = arena_size - start; + size_t bytes_to_sweep = sizeof (word) * words_to_sweep; + kissat_phase (solver, "reduce", GET (reductions), + "reducing clauses after offset %" REFERENCE_FORMAT + " in arena", + start); + kissat_phase (solver, "reduce", GET (reductions), + "reducing %zu words %s %.0f%%", words_to_sweep, + FORMAT_BYTES (bytes_to_sweep), + kissat_percent (words_to_sweep, arena_size)); +#endif + if (kissat_flush_and_mark_reason_clauses (solver, start)) { + reducibles reds; + INIT_STACK (reds); + if (collect_reducibles (solver, &reds, start)) { + sort_reducibles (solver, &reds); + mark_less_useful_clauses_as_garbage (solver, &reds); + RELEASE_STACK (reds); + kissat_sparse_collect (solver, compact, start); + } else if (compact) + kissat_sparse_collect (solver, compact, start); + else + kissat_unmark_reason_clauses (solver, start); + } else + assert (solver->inconsistent); + } else + kissat_phase (solver, "reduce", GET (reductions), "nothing to reduce"); + kissat_classify (solver); + UPDATE_CONFLICT_LIMIT (reduce, reductions, SQRT, false); + solver->last.conflicts.reduce = CONFLICTS; + REPORT (0, '-'); + STOP (reduce); + return solver->inconsistent ? 20 : 0; +} diff --git a/src/sat/kissat/reduce.h b/src/sat/kissat/reduce.h new file mode 100644 index 000000000..c82c0481d --- /dev/null +++ b/src/sat/kissat/reduce.h @@ -0,0 +1,11 @@ +#ifndef _reduce_h_INCLUDED +#define _reduce_h_INCLUDED + +#include + +struct kissat; + +bool kissat_reducing (struct kissat *); +int kissat_reduce (struct kissat *); + +#endif diff --git a/src/sat/kissat/reference.h b/src/sat/kissat/reference.h new file mode 100644 index 000000000..028fc4b5f --- /dev/null +++ b/src/sat/kissat/reference.h @@ -0,0 +1,19 @@ +#ifndef _reference_h_INCLUDED +#define _reference_h_INCLUDED + +#include "stack.h" + +typedef unsigned reference; + +#define REFERENCE_FORMAT "u" + +#define LD_MAX_REF 31u +#define MAX_REF ((1u << LD_MAX_REF) - 1) + +#define INVALID_REF UINT_MAX + +// clang-format off +typedef STACK (reference) references; +// clang-format on + +#endif diff --git a/src/sat/kissat/reluctant.c b/src/sat/kissat/reluctant.c new file mode 100644 index 000000000..54b4558e5 --- /dev/null +++ b/src/sat/kissat/reluctant.c @@ -0,0 +1,67 @@ +#include "internal.h" +#include "logging.h" + +void kissat_enable_reluctant (reluctant *reluctant, uint64_t period, + uint64_t limit) { + if (limit && period > limit) + period = limit; + reluctant->limited = (limit > 0); + reluctant->trigger = false; + reluctant->period = period; + reluctant->wait = period; + reluctant->u = reluctant->v = 1; + reluctant->limit = limit; +} + +void kissat_disable_reluctant (reluctant *reluctant) { + reluctant->period = 0; +} + +void kissat_tick_reluctant (reluctant *reluctant) { + if (!reluctant->period) + return; + + if (reluctant->trigger) + return; + + assert (reluctant->wait > 0); + if (--reluctant->wait) + return; + + uint64_t u = reluctant->u; + uint64_t v = reluctant->v; + + if ((u & -u) == v) { + u++; + v = 1; + } else { + assert (UINT64_MAX / 2 >= v); + v *= 2; + } + + assert (v); + assert (UINT64_MAX / v >= reluctant->period); + uint64_t wait = v * reluctant->period; + + if (reluctant->limited && wait > reluctant->limit) { + u = v = 1; + wait = reluctant->period; + } + + reluctant->trigger = true; + reluctant->wait = wait; + reluctant->u = u; + reluctant->v = v; +} + +void kissat_init_reluctant (kissat *solver) { + if (GET_OPTION (reluctant)) { + LOG ("enable reluctant doubling with period %d limit %d", + GET_OPTION (reluctantint), GET_OPTION (reluctantlim)); + kissat_enable_reluctant (&solver->reluctant, GET_OPTION (reluctantint), + GET_OPTION (reluctantlim)); + } else { + LOG ("reluctant doubling disabled and thus no stable restarts"); + kissat_disable_reluctant (&solver->reluctant); + } +} diff --git a/src/sat/kissat/reluctant.h b/src/sat/kissat/reluctant.h new file mode 100644 index 000000000..93513aabe --- /dev/null +++ b/src/sat/kissat/reluctant.h @@ -0,0 +1,33 @@ +#ifndef _reluctant_h_INCLUDED +#define _reluctant_h_INCLUDED + +#include +#include + +typedef struct reluctant reluctant; + +struct reluctant { + bool limited; + bool trigger; + uint64_t period; + uint64_t wait; + uint64_t u, v; + uint64_t limit; +}; + +void kissat_enable_reluctant (reluctant *, uint64_t period, uint64_t limit); +void kissat_disable_reluctant (reluctant *); +void kissat_tick_reluctant (reluctant *); + +static inline bool kissat_reluctant_triggered (reluctant *reluctant) { + if (!reluctant->trigger) + return false; + reluctant->trigger = false; + return true; +} + +struct kissat; + +void kissat_init_reluctant (struct kissat *); + +#endif diff --git a/src/sat/kissat/reorder.c b/src/sat/kissat/reorder.c new file mode 100644 index 000000000..e1d4fe8c5 --- /dev/null +++ b/src/sat/kissat/reorder.c @@ -0,0 +1,217 @@ +#include "reorder.h" +#include "backtrack.h" +#include "bump.h" +#include "inline.h" +#include "inlineheap.h" +#include "inlinequeue.h" +#include "inlinevector.h" +#include "internal.h" +#include "logging.h" +#include "print.h" +#include "report.h" +#include "sort.h" + +bool kissat_reordering (kissat *solver) { + if (!GET_OPTION (reorder)) + return false; + if (!solver->stable && GET_OPTION (reorder) < 2) + return false; + if (solver->level) + return false; + return CONFLICTS >= solver->limits.reorder.conflicts; +} + +static double *compute_weights (kissat *solver) { + double *weights = kissat_calloc (solver, LITS, sizeof *weights); + const unsigned max_size = GET_OPTION (reordermaxsize); + LOG ("limiting weight computation to maximum clause size %u", max_size); + assert (2 <= max_size); + double *table = kissat_nalloc (solver, max_size + 1, sizeof *table); + { + double weight = 1; + for (unsigned size = 2; size <= max_size; size++) { + LOG ("score table[%u] = %g", size, weight); + table[size] = weight, weight /= 2.0; + } + } + { + assert (!solver->level); + const signed char *const values = solver->values; + const clause *last = kissat_last_irredundant_clause (solver); + for (all_clauses (c)) { + if (last && c > last) + break; + if (c->redundant) + continue; + if (c->garbage) + continue; + unsigned size = 0; + for (all_literals_in_clause (lit, c)) { + const signed char value = values[lit]; + if (value > 0) + goto CONTINUE_WITH_NEXT_CLAUSE; + if (!value && size < max_size && ++size == max_size) + break; + } + const double weight = table[size]; + for (all_literals_in_clause (lit, c)) + weights[lit] += weight; + CONTINUE_WITH_NEXT_CLAUSE:; + } + } + assert (solver->watching); + { + double weight = table[2]; + kissat_dealloc (solver, table, max_size + 1, sizeof *table); + for (all_literals (lit)) { + const unsigned idx = IDX (lit); + if (!ACTIVE (idx)) + continue; + watches *watches = &WATCHES (lit); + for (all_binary_blocking_watches (watch, *watches)) { + if (!watch.type.binary) + continue; + const unsigned other = watch.type.lit; + if (other < lit) + continue; + const unsigned other_idx = IDX (other); + if (!ACTIVE (other_idx)) + continue; + weights[lit] += weight; + weights[other] += weight; + } + } + } + for (all_variables (idx)) { + if (!ACTIVE (idx)) + continue; + unsigned lit = LIT (idx), not_lit = NOT (lit); + double pos = weights[lit], neg = weights[not_lit]; + double max_pos_neg = MAX (pos, neg); + double min_pos_neg = MIN (pos, neg); + double scaled_min_pos_neg = 2 * min_pos_neg; + double weight = max_pos_neg + scaled_min_pos_neg; + LOG ("computed weight %g " + "= %g + %g = max (%g, %g) + 2 * min (%g, %g) of %s", + weight, max_pos_neg, scaled_min_pos_neg, pos, neg, pos, neg, + LOGVAR (idx)); + weights[idx] = weight; + } + return weights; +} + +static bool less_focused_order (unsigned a, unsigned b, links *links, + double *weights) { + double u = weights[a], v = weights[b]; + if (u < v) + return true; + if (u > v) + return false; + unsigned s = links[a].stamp, t = links[b].stamp; + return s < t; +} + +static bool less_stable_order (unsigned a, unsigned b, heap *scores, + double *weights) { + double u = weights[a], v = weights[b]; + if (u < v) + return true; + if (u > v) + return false; + double s = kissat_get_heap_score (scores, a); + double t = kissat_get_heap_score (scores, b); + if (s < t) + return true; + if (s > t) + return false; + return b < a; +} + +#define LESS_FOCUSED_ORDER(A, B) less_focused_order (A, B, links, weights) + +#define LESS_STABLE_ORDER(A, B) less_stable_order (A, B, scores, weights) + +static void sort_active_variables_by_weight (kissat *solver, + unsigneds *sorted, + double *weights) { + INIT_STACK (*sorted); + for (all_variables (idx)) + if (ACTIVE (idx)) + PUSH_STACK (*sorted, idx); + if (solver->stable) { + heap *scores = SCORES; + SORT_STACK (unsigned, *sorted, LESS_STABLE_ORDER); +#ifdef LOGGING + for (all_stack (unsigned, idx, *sorted)) + if (ACTIVE (idx)) + LOG ("reordered %s with weight %g score %g", LOGVAR (idx), + weights[idx], kissat_get_heap_score (scores, idx)); +#endif + } else { + struct links *links = solver->links; + SORT_STACK (unsigned, *sorted, LESS_FOCUSED_ORDER); +#ifdef LOGGING + for (all_stack (unsigned, idx, *sorted)) + if (ACTIVE (idx)) + LOG ("reordered %s with weight %g stamp %u", LOGVAR (idx), + weights[idx], links[idx].stamp); +#endif + } +} + +static void reorder_focused (kissat *solver) { + INC (reordered_focused); + assert (!solver->stable); + double *weights = compute_weights (solver); + unsigneds sorted; + sort_active_variables_by_weight (solver, &sorted, weights); + kissat_dealloc (solver, weights, LITS, sizeof *weights); + for (all_stack (unsigned, idx, sorted)) { + assert (ACTIVE (idx)); + kissat_move_to_front (solver, idx); + } + RELEASE_STACK (sorted); +} + +static void reorder_stable (kissat *solver) { + INC (reordered_stable); + assert (solver->stable); + double *weights = compute_weights (solver); + kissat_rescale_scores (solver); + unsigneds sorted; + sort_active_variables_by_weight (solver, &sorted, weights); + heap *scores = SCORES; + while (!EMPTY_STACK (sorted)) { + unsigned idx = POP_STACK (sorted); + assert (ACTIVE (idx)); + const double old_score = kissat_get_heap_score (scores, idx); + const double weight = weights[idx]; + const double new_score = old_score + weight; + LOG ("updating score of %s to %g = %g (old score) + %g (weight)", + LOGVAR (idx), new_score, old_score, weight); + kissat_update_heap (solver, scores, idx, new_score); + } + kissat_dealloc (solver, weights, LITS, sizeof *weights); + RELEASE_STACK (sorted); +} + +void kissat_reorder (kissat *solver) { + START (reorder); + INC (reordered); + assert (!solver->level); + kissat_phase (solver, "reorder", GET (reordered), + "reorder limit %" PRIu64 " hit a after %" PRIu64 + " conflicts in %s mode ", + solver->limits.reorder.conflicts, CONFLICTS, + solver->stable ? "stable" : "focused"); + if (solver->stable) + reorder_stable (solver); + else + reorder_focused (solver); + kissat_phase (solver, "reorder", GET (reordered), + "reordered decisions in %s search mode", + solver->stable ? "stable" : "focused"); + UPDATE_CONFLICT_LIMIT (reorder, reordered, LINEAR, false); + REPORT (0, 'o'); + STOP (reorder); +} diff --git a/src/sat/kissat/reorder.h b/src/sat/kissat/reorder.h new file mode 100644 index 000000000..24351927e --- /dev/null +++ b/src/sat/kissat/reorder.h @@ -0,0 +1,11 @@ +#ifndef _reorder_h_INCLUDED +#define _reorder_h_INCLUDED + +#include + +struct kissat; + +bool kissat_reordering (struct kissat *); +void kissat_reorder (struct kissat *); + +#endif diff --git a/src/sat/kissat/rephase.c b/src/sat/kissat/rephase.c new file mode 100644 index 000000000..33783f675 --- /dev/null +++ b/src/sat/kissat/rephase.c @@ -0,0 +1,137 @@ +#include "rephase.h" +#include "backtrack.h" +#include "decide.h" +#include "internal.h" +#include "logging.h" +#include "print.h" +#include "report.h" +#include "terminate.h" +#include "walk.h" + +#include +#include + +static void kissat_reset_best_assigned (kissat *solver) { + if (!solver->best_assigned) + return; + kissat_extremely_verbose (solver, + "resetting best assigned trail height %u to 0", + solver->best_assigned); + solver->best_assigned = 0; +} + +static void kissat_reset_target_assigned (kissat *solver) { + if (!solver->target_assigned) + return; + kissat_extremely_verbose ( + solver, "resetting target assigned trail height %u to 0", + solver->target_assigned); + solver->target_assigned = 0; +} + +bool kissat_rephasing (kissat *solver) { + if (!GET_OPTION (rephase)) + return false; + if (!solver->stable) + return false; + return CONFLICTS > solver->limits.rephase.conflicts; +} + +static char rephase_best (kissat *solver) { + const value *const best = solver->phases.best; + const value *const end_of_best = best + VARS; + value const *b; + + value *const saved = solver->phases.saved; + value *s, tmp; + + for (s = saved, b = best; b != end_of_best; s++, b++) + if ((tmp = *b)) + *s = tmp; + + INC (rephased_best); + + return 'B'; +} + +static char rephase_original (kissat *solver) { + const value initial_phase = INITIAL_PHASE; + value *s = solver->phases.saved; + const value *const end = s + VARS; + while (s != end) + *s++ = initial_phase; + INC (rephased_original); + return 'O'; +} + +static char rephase_inverted (kissat *solver) { + const value inverted_initial_phase = -INITIAL_PHASE; + value *s = solver->phases.saved; + const value *const end = s + VARS; + while (s != end) + *s++ = inverted_initial_phase; + INC (rephased_inverted); + return 'I'; +} + +static char rephase_walking (kissat *solver) { + assert (kissat_walking (solver)); + STOP (rephase); + kissat_walk (solver); + START (rephase); + INC (rephased_walking); + return 'W'; +} + +static char (*rephase_schedule[]) (kissat *) = { + rephase_best, rephase_walking, rephase_inverted, + rephase_best, rephase_walking, rephase_original, +}; + +#define size_rephase_schedule \ + (sizeof rephase_schedule / sizeof *rephase_schedule) + +#ifndef QUIET + +static const char *rephase_type_as_string (char type) { + if (type == 'B') + return "best"; + if (type == 'I') + return "inverted"; + if (type == 'O') + return "original"; + assert (type == 'W'); + return "walking"; +} + +#endif + +static char reset_phases (kissat *solver) { + const uint64_t count = GET (rephased); + assert (count > 0); + const uint64_t select = (count - 1) % (uint64_t) size_rephase_schedule; + const char type = rephase_schedule[select](solver); + kissat_phase ( + solver, "rephase", GET (rephased), "%s phases in %s search mode", + rephase_type_as_string (type), solver->stable ? "stable" : "focused"); + LOG ("copying saved phases as target phases"); + memcpy (solver->phases.target, solver->phases.saved, VARS); + UPDATE_CONFLICT_LIMIT (rephase, rephased, NLOG3N, false); + kissat_reset_target_assigned (solver); + if (type == 'B') + kissat_reset_best_assigned (solver); + return type; +} + +void kissat_rephase (kissat *solver) { + kissat_backtrack_propagate_and_flush_trail (solver); + assert (!solver->inconsistent); + START (rephase); + INC (rephased); +#ifndef QUIET + const char type = +#endif + reset_phases (solver); + REPORT (0, type); + STOP (rephase); +} diff --git a/src/sat/kissat/rephase.h b/src/sat/kissat/rephase.h new file mode 100644 index 000000000..b59382e4e --- /dev/null +++ b/src/sat/kissat/rephase.h @@ -0,0 +1,11 @@ +#ifndef _rephase_h_INCLUDED +#define _rephase_h_INCLUDED + +#include + +struct kissat; + +bool kissat_rephasing (struct kissat *); +void kissat_rephase (struct kissat *); + +#endif diff --git a/src/sat/kissat/report.c b/src/sat/kissat/report.c new file mode 100644 index 000000000..a9fc092b5 --- /dev/null +++ b/src/sat/kissat/report.c @@ -0,0 +1,159 @@ +#ifndef QUIET + +#include "report.h" +#include "colors.h" +#include "internal.h" +#include "print.h" +#include "resources.h" + +#include +#include + +#define MB (kissat_current_resident_set_size () / (double) (1 << 20)) + +#define REMAINING_VARIABLES \ + kissat_percent (solver->active, statistics->variables_original) + +#define REPORTS \ + REP ("seconds", "5.2f", kissat_time (solver)) \ + REP ("MB", "2.0f", MB) \ + REP ("level", ".0f", AVERAGE (level)) \ + REP ("switched", "1" PRIu64, statistics->switched) \ + REP ("reductions", "1" PRIu64, statistics->reductions) \ + REP ("restarts", "2" PRIu64, statistics->restarts) \ + REP ("rate", ".0f", AVERAGE (decision_rate)) \ + REP ("conflicts", "3" PRIu64, CONFLICTS) \ + REP ("redundant", "3" PRIu64, REDUNDANT_CLAUSES) \ + REP ("size/glue", ".1f", \ + kissat_average (AVERAGE (size), AVERAGE (slow_glue))) \ + REP ("size", ".0f", AVERAGE (size)) \ + REP ("glue", ".0f", AVERAGE (slow_glue)) \ + REP ("tier1", "1u", solver->tier1[solver->stable]) \ + REP ("tier2", "1u", solver->tier2[solver->stable]) \ + REP ("trail", ".0f%%", AVERAGE (trail)) \ + REP ("binary", "3" PRIu64, BINARY_CLAUSES) \ + REP ("irredundant", "2" PRIu64, IRREDUNDANT_CLAUSES) \ + REP ("variables", "2u", solver->active) \ + REP ("remaining", "1.0f%%", REMAINING_VARIABLES) + +void kissat_report (kissat *solver, bool verbose, char type) { + statistics *statistics = &solver->statistics; + const int verbosity = kissat_verbosity (solver); + if (verbosity < 0) + return; + if (verbose && verbosity < 2) + return; + char line[128], *p = line; + unsigned pad[32], n = 1, pos = 0; + pad[0] = 0; + // clang-format off +#define REP(NAME,FMT,VALUE) \ + do { \ + *p++ = ' ', pos++; \ + sprintf (p, "%" FMT, VALUE); \ + while (*p) \ + p++, pos++; \ + pad[n++] = pos; \ + } while (0); + REPORTS +#undef REP + // clang-format on + assert (p < line + sizeof line); + TERMINAL (stdout, 1); + if (!(solver->limits.reports++ % 20)) { +#define ROWS 3 + unsigned last[ROWS]; + char rows[ROWS][128], *r[ROWS]; + for (unsigned j = 0; j < ROWS; j++) + last[j] = 0, rows[j][0] = 0, r[j] = rows[j]; + unsigned row = 0, i = 1; +#define REP(NAME, FMT, VALUE) \ + do { \ + if (last[row]) \ + *r[row]++ = ' ', last[row]++; \ + unsigned target = pad[i]; \ + const unsigned name_len = strlen (NAME); \ + const unsigned val_len = target - pad[i - 1] - 1; \ + if (val_len < name_len) \ + target += (name_len - val_len) / 2; \ + while (last[row] + name_len < target) \ + *r[row]++ = ' ', last[row]++; \ + for (const char *p = NAME; *p; p++) \ + *r[row]++ = *p, last[row]++; \ + if (++row == ROWS) \ + row = 0; \ + i++; \ + } while (0); + REPORTS +#undef REP + assert (i == n); + for (unsigned j = 0; j < ROWS; j++) { + assert (r[j] < rows[j] + sizeof rows[j]); + *r[j] = 0; + } + if (solver->limits.reports > 1) + kissat_line (solver); + for (unsigned j = 0; j < ROWS; j++) { + fputs (solver->prefix, stdout); + COLOR (CYAN); + fputs (rows[j], stdout); + COLOR (NORMAL); + fputc ('\n', stdout); + } + kissat_line (solver); + } + kissat_prefix (solver); + switch (type) { + case '1': + case '0': + case '?': + case 'i': + case '.': + COLOR (BOLD); + break; + case 'e': + COLOR (BOLD GREEN); + break; + case '2': + case 's': + COLOR (GREEN); + break; + case 'f': + case 't': + case 'u': + case 'v': + case 'w': + case 'x': + COLOR (BLUE); + break; + case 'b': + case 'c': + case 'd': + case '=': + COLOR (BOLD BLUE); + break; + case '[': + case ']': + COLOR (MAGENTA); + break; + case '(': + case ')': + COLOR (BOLD YELLOW); + } + fputc (type, stdout); + COLOR (NORMAL); + if (solver->preprocessing) + COLOR (YELLOW); + else if (solver->stable) + COLOR (MAGENTA); + fputs (line, stdout); + COLOR (NORMAL); + fputc ('\n', stdout); + fflush (stdout); +} + +#else + +int kissat_report_dummy_to_avoid_warning; + +#endif diff --git a/src/sat/kissat/report.h b/src/sat/kissat/report.h new file mode 100644 index 000000000..744aea32a --- /dev/null +++ b/src/sat/kissat/report.h @@ -0,0 +1,22 @@ +#ifndef _report_h_INCLUDED +#define _report_h_INCLUDED + +#ifdef QUIET + +#define REPORT(...) \ + do { \ + } while (0) + +#else + +#include + +struct kissat; + +void kissat_report (struct kissat *, bool verbose, char type); + +#define REPORT(LEVEL, TYPE) kissat_report (solver, (LEVEL), (TYPE)) + +#endif + +#endif diff --git a/src/sat/kissat/require.h b/src/sat/kissat/require.h new file mode 100644 index 000000000..9325c9b3f --- /dev/null +++ b/src/sat/kissat/require.h @@ -0,0 +1,30 @@ +#ifndef _require_h_INCLUDED +#define _require_h_INCLUDED + +#define kissat_require(COND, ...) \ + do { \ + if ((COND)) \ + break; \ + kissat_fatal_message_start (); \ + fprintf (stderr, "calling '%s': ", __func__); \ + fprintf (stderr, __VA_ARGS__); \ + fputc ('\n', stderr); \ + fflush (stderr); \ + kissat_abort (); \ + } while (0) + +#define kissat_require_initialized(SOLVER) \ + kissat_require (SOLVER, "uninitialized") + +#define kissat_require_valid_external_internal(LIT) \ + do { \ + kissat_require ((LIT) != INT_MIN, "invalid literal '%d' (INT_MIN)", \ + (LIT)); \ + const int TMP_IDX = ABS (LIT); \ + kissat_require (TMP_IDX <= EXTERNAL_MAX_VAR, \ + "invalid literal '%d' (variable larger than %d)", \ + (LIT), EXTERNAL_MAX_VAR); \ + assert (VALID_EXTERNAL_LITERAL (LIT)); \ + } while (0) + +#endif diff --git a/src/sat/kissat/resize.c b/src/sat/kissat/resize.c new file mode 100644 index 000000000..593d813c8 --- /dev/null +++ b/src/sat/kissat/resize.c @@ -0,0 +1,137 @@ +#include "resize.h" +#include "allocate.h" +#include "inline.h" +#include "require.h" + +#include +#include + +#define NREALLOC_GENERIC(TYPE, NAME, ELEMENTS_PER_BLOCK) \ + do { \ + const size_t block_size = sizeof (TYPE); \ + solver->NAME = \ + kissat_nrealloc (solver, solver->NAME, old_size, new_size, \ + ELEMENTS_PER_BLOCK * block_size); \ + } while (0) + +#define CREALLOC_GENERIC(TYPE, NAME, ELEMENTS_PER_BLOCK) \ + do { \ + const size_t block_size = sizeof (TYPE); \ + TYPE *NAME = \ + kissat_calloc (solver, ELEMENTS_PER_BLOCK * new_size, block_size); \ + if (old_size) { \ + const size_t bytes = ELEMENTS_PER_BLOCK * old_size * block_size; \ + memcpy (NAME, solver->NAME, bytes); \ + } \ + kissat_dealloc (solver, solver->NAME, ELEMENTS_PER_BLOCK *old_size, \ + block_size); \ + solver->NAME = NAME; \ + } while (0) + +#define NREALLOC_VARIABLE_INDEXED(TYPE, NAME) \ + NREALLOC_GENERIC (TYPE, NAME, 1) + +#define NREALLOC_LITERAL_INDEXED(TYPE, NAME) \ + NREALLOC_GENERIC (TYPE, NAME, 2) + +#define CREALLOC_VARIABLE_INDEXED(TYPE, NAME) \ + CREALLOC_GENERIC (TYPE, NAME, 1) + +#define CREALLOC_LITERAL_INDEXED(TYPE, NAME) \ + CREALLOC_GENERIC (TYPE, NAME, 2) + +static void reallocate_trail (kissat *solver, unsigned old_size, + unsigned new_size) { + unsigned propagated = solver->propagate - BEGIN_ARRAY (solver->trail); + REALLOCATE_ARRAY (solver->trail, old_size, new_size); + solver->propagate = BEGIN_ARRAY (solver->trail) + propagated; +} + +void kissat_increase_size (kissat *solver, unsigned new_size) { + assert (solver->vars <= new_size); + const unsigned old_size = solver->size; + if (old_size >= new_size) + return; + +#ifdef METRICS + LOG ("%s before increasing size from %u to %u", + FORMAT_BYTES (kissat_allocated (solver)), old_size, new_size); +#endif + CREALLOC_VARIABLE_INDEXED (assigned, assigned); + CREALLOC_VARIABLE_INDEXED (flags, flags); + NREALLOC_VARIABLE_INDEXED (links, links); + + CREALLOC_LITERAL_INDEXED (mark, marks); + CREALLOC_LITERAL_INDEXED (value, values); + CREALLOC_LITERAL_INDEXED (watches, watches); + + reallocate_trail (solver, old_size, new_size); + kissat_resize_heap (solver, SCORES, new_size); + kissat_increase_phases (solver, new_size); + + solver->size = new_size; + +#ifdef METRICS + LOG ("%s after increasing size from %u to %u", + FORMAT_BYTES (kissat_allocated (solver)), old_size, new_size); +#endif +} + +void kissat_decrease_size (kissat *solver) { + const unsigned old_size = solver->size; + const unsigned new_size = solver->vars; + +#ifdef METRICS + LOG ("%s before decreasing size from %u to %u", + FORMAT_BYTES (kissat_allocated (solver)), old_size, new_size); +#endif + + NREALLOC_VARIABLE_INDEXED (assigned, assigned); + NREALLOC_VARIABLE_INDEXED (flags, flags); + NREALLOC_VARIABLE_INDEXED (links, links); + + NREALLOC_LITERAL_INDEXED (mark, marks); + NREALLOC_LITERAL_INDEXED (value, values); + NREALLOC_LITERAL_INDEXED (watches, watches); + + reallocate_trail (solver, old_size, new_size); + kissat_resize_heap (solver, SCORES, new_size); + kissat_decrease_phases (solver, new_size); + + solver->size = new_size; + +#ifdef METRICS + LOG ("%s after decreasing size from %u to %u", + FORMAT_BYTES (kissat_allocated (solver)), old_size, new_size); +#endif +} + +void kissat_enlarge_variables (kissat *solver, unsigned new_vars) { + if (solver->vars >= new_vars) + return; + assert (new_vars <= INTERNAL_MAX_VAR + 1); + LOG ("enlarging variables from %u to %u", solver->vars, new_vars); + const size_t old_size = solver->size; + if (old_size < new_vars) { + LOG ("old size %zu below requested new number of variables %u", + old_size, new_vars); + size_t new_size; + if (!old_size) + new_size = new_vars; + else { + if (kissat_is_power_of_two (old_size)) { + assert (old_size <= UINT_MAX / 2); + new_size = 2 * old_size; + } else { + assert (1 < old_size); + new_size = 2; + } + while (new_size < new_vars) { + assert (new_size <= UINT_MAX / 2); + new_size *= 2; + } + } + kissat_increase_size (solver, new_size); + } + solver->vars = new_vars; +} diff --git a/src/sat/kissat/resize.h b/src/sat/kissat/resize.h new file mode 100644 index 000000000..089fe9394 --- /dev/null +++ b/src/sat/kissat/resize.h @@ -0,0 +1,10 @@ +#ifndef _resize_h_INCLUDED +#define _resize_h_INCLUDED + +struct kissat; + +void kissat_decrease_size (struct kissat *solver); +void kissat_increase_size (struct kissat *, unsigned new_size); +void kissat_enlarge_variables (struct kissat *, unsigned new_vars); + +#endif diff --git a/src/sat/kissat/resolve.c b/src/sat/kissat/resolve.c new file mode 100644 index 000000000..49567b768 --- /dev/null +++ b/src/sat/kissat/resolve.c @@ -0,0 +1,370 @@ +#include "resolve.h" +#include "eliminate.h" +#include "gates.h" +#include "inline.h" +#include "print.h" + +#include +#include + +static inline unsigned occurrences_literal (kissat *solver, unsigned lit, + bool *update) { + assert (!solver->watching); + + watches *watches = &WATCHES (lit); +#ifdef LOGGING + const size_t size_watches = SIZE_WATCHES (*watches); + LOG ("literal %s has %zu watches", LOGLIT (lit), size_watches); +#endif + const unsigned clslim = GET_OPTION (eliminateclslim); + + watch *const begin = BEGIN_WATCHES (*watches), *q = begin; + const watch *const end = END_WATCHES (*watches), *p = q; + + const value *const values = solver->values; + ward *const arena = BEGIN_STACK (solver->arena); + + bool failed = false; + unsigned res = 0; + + while (p != end) { + const watch head = *q++ = *p++; + if (head.type.binary) { + const unsigned other = head.binary.lit; + const value value = values[other]; + assert (value >= 0); + if (value > 0) { + kissat_eliminate_binary (solver, lit, other); + q--; + } else + res++; + } else { + const reference ref = head.large.ref; + assert (ref < SIZE_STACK (solver->arena)); + clause *const c = (struct clause *) (arena + ref); + if (c->garbage) + q--; + else if (c->size > clslim) { + LOG ("literal %s watches too long clause of size %u", LOGLIT (lit), + c->size); + failed = true; + break; + } else + res++; + } + } + while (p != end) + *q++ = *p++; + SET_END_OF_WATCHES (*watches, q); + if (failed) + return UINT_MAX; + if (q != end) { + *update = true; + LOG ("literal %s actually occurs only %u times", LOGLIT (lit), res); + } + return res; +} + +static inline clause *watch_to_clause (kissat *solver, ward *const arena, + clause *const tmp, unsigned lit, + watch watch) { + clause *res; + if (watch.type.binary) { + const unsigned other = watch.binary.lit; + tmp->lits[0] = lit; + tmp->lits[1] = other; + res = tmp; + } else { + const reference ref = watch.large.ref; + assert (ref < SIZE_STACK (solver->arena)); + res = (struct clause *) (arena + ref); + } +#ifdef NDEBUG + (void) solver; +#endif + return res; +} + +static bool generate_resolvents (kissat *solver, unsigned lit, + statches *const watches0, + statches *const watches1, + uint64_t *const resolved_ptr, + uint64_t limit) { + const unsigned not_lit = NOT (lit); + unsigned resolved = *resolved_ptr; + bool failed = false; + + clause tmp0, tmp1; + memset (&tmp0, 0, sizeof tmp0); + memset (&tmp1, 0, sizeof tmp1); + tmp0.size = tmp1.size = 2; + + ward *const arena = BEGIN_STACK (solver->arena); + const value *const values = solver->values; + value *const marks = solver->marks; + + const unsigned clslim = GET_OPTION (eliminateclslim); + + for (all_stack (watch, watch0, *watches0)) { + clause *const c = watch_to_clause (solver, arena, &tmp0, lit, watch0); + + if (c->garbage) { + assert (c != &tmp0); + continue; + } + + bool first_antecedent_satisfied = false; + + for (all_literals_in_clause (other, c)) { + if (other == lit) + continue; + const value value = values[other]; + if (value < 0) + continue; + if (value > 0) { + first_antecedent_satisfied = true; + if (c != &tmp0) + kissat_eliminate_clause (solver, c, other); + break; + } + } + + if (first_antecedent_satisfied) + continue; + + for (all_literals_in_clause (other, c)) { + if (other == lit) + continue; + assert (!marks[other]); + marks[other] = 1; + } + + for (all_stack (watch, watch1, *watches1)) { + clause *const d = + watch_to_clause (solver, arena, &tmp1, not_lit, watch1); + + if (d->garbage) { + assert (d != &tmp1); + continue; + } + + LOGCLS (c, "first %s antecedent", LOGLIT (lit)); + LOGCLS (d, "second %s antecedent", LOGLIT (not_lit)); + + bool resolvent_satisfied_or_tautological = false; + const size_t saved = SIZE_STACK (solver->resolvents); + + INC (eliminate_resolutions); + + for (all_literals_in_clause (other, d)) { + if (other == not_lit) + continue; + const value value = values[other]; + if (value < 0) { + LOG2 ("dropping falsified literal %s", LOGLIT (other)); + continue; + } + if (value > 0) { + if (d != &tmp1) + kissat_eliminate_clause (solver, d, other); + resolvent_satisfied_or_tautological = true; + break; + } + if (marks[other]) { + LOG2 ("dropping repeated %s literal", LOGLIT (other)); + continue; + } + const unsigned not_other = NOT (other); + if (marks[not_other]) { + LOG ("resolvent tautological on %s and %s " + "with second %s antecedent", + LOGLIT (NOT (other)), LOGLIT (other), LOGLIT (not_lit)); + resolvent_satisfied_or_tautological = true; + break; + } + LOG2 ("including unassigned literal %s", LOGLIT (other)); + PUSH_STACK (solver->resolvents, other); + } + + if (resolvent_satisfied_or_tautological) { + RESIZE_STACK (solver->resolvents, saved); + continue; + } + + if (++resolved > limit) { + LOG ("limit of %" PRIu64 " resolvent exceeded", limit); + failed = true; + break; + } + + for (all_literals_in_clause (other, c)) { + if (other == lit) + continue; + const value value = values[other]; + assert (value <= 0); + if (value < 0) { + LOG2 ("dropping falsified literal %s", LOGLIT (other)); + continue; + } + PUSH_STACK (solver->resolvents, other); + } + + size_t size_resolvent = SIZE_STACK (solver->resolvents) - saved; + LOGLITS (size_resolvent, BEGIN_STACK (solver->resolvents) + saved, + "resolvent"); + + if (!size_resolvent) { + assert (!solver->inconsistent); + solver->inconsistent = true; + LOG ("resolved empty clause"); + CHECK_AND_ADD_EMPTY (); + ADD_EMPTY_TO_PROOF (); + failed = true; + break; + } + + if (size_resolvent == 1) { + const unsigned unit = PEEK_STACK (solver->resolvents, saved); + INC (eliminate_units); + kissat_learned_unit (solver, unit); + RESIZE_STACK (solver->resolvents, saved); + if (marks[unit] <= 0) + continue; + LOGCLS (c, "first antecedent becomes satisfied"); + first_antecedent_satisfied = true; + (void) first_antecedent_satisfied; + break; + } + + if (size_resolvent > clslim) { + LOG ("resolvent size limit exceeded"); + failed = true; + break; + } + + PUSH_STACK (solver->resolvents, INVALID_LIT); + } + + for (all_literals_in_clause (other, c)) { + if (other == lit) + continue; + assert (marks[other] == 1); + marks[other] = 0; + } + + if (failed) + break; + } + + *resolved_ptr = resolved; + + return !failed; +} + +bool kissat_generate_resolvents (kissat *solver, unsigned idx, + unsigned *lit_ptr) { + unsigned lit = LIT (idx); + unsigned not_lit = NOT (lit); + + bool update = false; + bool pure = false; + uint64_t limit; + + { + unsigned pos_count = occurrences_literal (solver, lit, &update); + unsigned neg_count = occurrences_literal (solver, not_lit, &update); + + if (pos_count > neg_count) { + SWAP (unsigned, lit, not_lit); + SWAP (size_t, pos_count, neg_count); + } + + const unsigned occlim = GET_OPTION (eliminateocclim); + limit = pos_count + (uint64_t) neg_count; + + if (pos_count && limit > occlim) { + LOG ("no elimination of variable %u " + "since it has %" PRIu64 " > %u occurrences", + idx, limit, occlim); + return false; + } + + if (pos_count) { + const uint64_t bound = solver->bounds.eliminate.additional_clauses; + limit += bound; + LOG ("trying to eliminate %s " + "limit %" PRIu64 " bound %" PRIu64, + LOGVAR (idx), limit, bound); + } else { + LOG ("eliminating pure literal %s thus its variable %u", LOGLIT (lit), + idx); + pure = true; + } + } + + *lit_ptr = lit; + + INC (eliminate_attempted); + if (pure) + return true; + + const bool gates = !pure && kissat_find_gates (solver, lit); + + statches *const gates0 = &solver->gates[0]; + statches *const gates1 = &solver->gates[1]; + + if (solver->values[lit]) { + kissat_extremely_verbose (solver, "definition produced unit"); + CLEAR_STACK (*gates0); + CLEAR_STACK (*gates1); + return false; + } + + bool failed = false; + uint64_t resolved = 0; + + kissat_get_antecedents (solver, lit); + statches *const antecedents0 = &solver->antecedents[0]; + statches *const antecedents1 = &solver->antecedents[1]; + + if (gates) { + LOG ("resolving gates[0] against antecedents[1] clauses"); + if (!generate_resolvents (solver, lit, gates0, antecedents1, &resolved, + limit)) + failed = true; + else { + LOG ("resolving gates[1] against antecedents[0] clauses"); + if (!generate_resolvents (solver, not_lit, gates1, antecedents0, + &resolved, limit)) { + failed = true; + } else if (solver->resolve_gate) { + LOG ("need to resolved gates[0] against gates[1] too"); + if (!generate_resolvents (solver, lit, gates0, gates1, &resolved, + limit)) + failed = true; + } + } + } else { + LOG ("no gate extracted thus resolving all clauses"); + if (!generate_resolvents (solver, lit, antecedents0, antecedents1, + &resolved, limit)) + failed = true; + } + + CLEAR_STACK (*antecedents0); + CLEAR_STACK (*antecedents1); + + if (failed) { + LOG ("elimination of %s failed", LOGVAR (IDX (lit))); + CLEAR_STACK (solver->resolvents); + if (update) + kissat_update_variable_score (solver, idx); + } + + LOG ("resolved %" PRIu64 " resolvents", resolved); + + CLEAR_STACK (*gates0); + CLEAR_STACK (*gates1); + + return !failed; +} diff --git a/src/sat/kissat/resolve.h b/src/sat/kissat/resolve.h new file mode 100644 index 000000000..26bf7a0e9 --- /dev/null +++ b/src/sat/kissat/resolve.h @@ -0,0 +1,11 @@ +#ifndef _resolve_h_INCLUDED +#define _resolve_h_INCLUDED + +#include + +struct kissat; + +bool kissat_generate_resolvents (struct kissat *, unsigned idx, + unsigned *lit_ptr); + +#endif diff --git a/src/sat/kissat/resources.c b/src/sat/kissat/resources.c new file mode 100644 index 000000000..31c0378af --- /dev/null +++ b/src/sat/kissat/resources.c @@ -0,0 +1,104 @@ +#include "resources.h" + +#include + +double kissat_wall_clock_time (void) { + struct timeval tv; + if (gettimeofday (&tv, 0)) + return 0; + return 1e-6 * tv.tv_usec + tv.tv_sec; +} + +#ifndef QUIET + +#include "internal.h" +#include "statistics.h" +#include "utilities.h" + +#include +#include +#include +#include +#include +#include + +double kissat_process_time (void) { + struct rusage u; + double res; + if (getrusage (RUSAGE_SELF, &u)) + return 0; + res = u.ru_utime.tv_sec + 1e-6 * u.ru_utime.tv_usec; + res += u.ru_stime.tv_sec + 1e-6 * u.ru_stime.tv_usec; + return res; +} + +uint64_t kissat_maximum_resident_set_size (void) { + struct rusage u; + if (getrusage (RUSAGE_SELF, &u)) + return 0; + return ((uint64_t) u.ru_maxrss) << 10; +} + +#ifdef __APPLE__ + +#include +mach_port_t mach_task_self (void); + +uint64_t kissat_current_resident_set_size (void) { + struct task_basic_info info; + mach_msg_type_number_t count = TASK_BASIC_INFO_COUNT; + if (KERN_SUCCESS != task_info (mach_task_self (), TASK_BASIC_INFO, + (task_info_t) &info, &count)) + return 0; + return info.resident_size; +} + +#else + +uint64_t kissat_current_resident_set_size (void) { + char path[48]; + sprintf (path, "/proc/%" PRIu64 "/statm", (uint64_t) getpid ()); + FILE *file = fopen (path, "r"); + if (!file) + return 0; + uint64_t dummy, rss; + int scanned = fscanf (file, "%" PRIu64 " %" PRIu64 "", &dummy, &rss); + fclose (file); + return scanned == 2 ? rss * sysconf (_SC_PAGESIZE) : 0; +} + +#endif + +void kissat_print_resources (kissat *solver) { + uint64_t rss = kissat_maximum_resident_set_size (); + double t = kissat_time (solver); + printf ("%s" + "%-" SFW1 "s " + "%" SFW2 PRIu64 " " + "%-" SFW3 "s " + "%" SFW4 ".0f " + "MB\n", + solver->prefix, "maximum-resident-set-size:", rss, "bytes", + rss / (double) (1 << 20)); +#ifdef METRICS + statistics *statistics = &solver->statistics; + uint64_t max_allocated = statistics->allocated_max + sizeof (kissat); + printf ("%s" + "%-" SFW1 "s " + "%" SFW2 PRIu64 " " + "%-" SFW3 "s " + "%" SFW4 ".0f " + "%%\n", + solver->prefix, "max-allocated:", max_allocated, "bytes", + kissat_percent (max_allocated, rss)); +#endif + { + format buffer; + memset (&buffer, 0, sizeof buffer); + printf ("%sprocess-time: %30s %18.2f seconds\n", solver->prefix, + kissat_format_time (&buffer, t), t); + } + fflush (stdout); +} + +#endif diff --git a/src/sat/kissat/resources.h b/src/sat/kissat/resources.h new file mode 100644 index 000000000..d9bce7853 --- /dev/null +++ b/src/sat/kissat/resources.h @@ -0,0 +1,23 @@ +#ifndef _resources_h_INCLUDED +#define _resources_h_INCLUDED + +double kissat_wall_clock_time (void); + +#ifndef QUIET + +#ifndef _resources_h_INLCUDED +#define _resources_h_INLCUDED + +#include + +struct kissat; + +double kissat_process_time (void); +uint64_t kissat_current_resident_set_size (void); +uint64_t kissat_maximum_resident_set_size (void); +void kissat_print_resources (struct kissat *); + +#endif + +#endif +#endif diff --git a/src/sat/kissat/restart.c b/src/sat/kissat/restart.c new file mode 100644 index 000000000..dc4edf634 --- /dev/null +++ b/src/sat/kissat/restart.c @@ -0,0 +1,131 @@ +#include "restart.h" +#include "backtrack.h" +#include "bump.h" +#include "decide.h" +#include "internal.h" +#include "kimits.h" +#include "logging.h" +#include "print.h" +#include "reluctant.h" +#include "report.h" + +#include + +bool kissat_restarting (kissat *solver) { + assert (solver->unassigned); + if (!GET_OPTION (restart)) + return false; + if (!solver->level) + return false; + if (CONFLICTS < solver->limits.restart.conflicts) + return false; + if (solver->stable) + return kissat_reluctant_triggered (&solver->reluctant); + const double fast = AVERAGE (fast_glue); + const double slow = AVERAGE (slow_glue); + const double margin = (100.0 + GET_OPTION (restartmargin)) / 100.0; + const double limit = margin * slow; + kissat_extremely_verbose (solver, + "restart glue limit %g = " + "%.02f * %g (slow glue) %c %g (fast glue)", + limit, margin, slow, + (limit > fast ? '>' + : limit == fast ? '=' + : '<'), + fast); + return (limit <= fast); +} + +void kissat_update_focused_restart_limit (kissat *solver) { + assert (!solver->stable); + limits *limits = &solver->limits; + uint64_t restarts = solver->statistics.restarts; + uint64_t delta = GET_OPTION (restartint); + if (restarts) + delta += kissat_logn (restarts) - 1; + limits->restart.conflicts = CONFLICTS + delta; + kissat_extremely_verbose (solver, + "focused restart limit at %" PRIu64 + " after %" PRIu64 " conflicts ", + limits->restart.conflicts, delta); +} + +static unsigned reuse_stable_trail (kissat *solver) { + const heap *const scores = SCORES; + const unsigned next_idx = kissat_next_decision_variable (solver); + const double limit = kissat_get_heap_score (scores, next_idx); + unsigned level = solver->level, res = 0; + while (res < level) { + frame *f = &FRAME (res + 1); + const unsigned idx = IDX (f->decision); + const double score = kissat_get_heap_score (scores, idx); + if (score <= limit) + break; + res++; + } + return res; +} + +static unsigned reuse_focused_trail (kissat *solver) { + const links *const links = solver->links; + const unsigned next_idx = kissat_next_decision_variable (solver); + const unsigned limit = links[next_idx].stamp; + LOG ("next decision variable stamp %u", limit); + unsigned level = solver->level, res = 0; + while (res < level) { + frame *f = &FRAME (res + 1); + const unsigned idx = IDX (f->decision); + const unsigned score = links[idx].stamp; + if (score <= limit) + break; + res++; + } + return res; +} + +static unsigned reuse_trail (kissat *solver) { + assert (solver->level); + assert (!EMPTY_STACK (solver->trail)); + + if (!GET_OPTION (restartreusetrail)) + return 0; + + unsigned res; + + if (solver->stable) + res = reuse_stable_trail (solver); + else + res = reuse_focused_trail (solver); + + LOG ("matching trail level %u", res); + + if (res) { + INC (restarts_reused_trails); + ADD (restarts_reused_levels, res); + LOG ("restart reuses trail at decision level %u", res); + } else + LOG ("restarts does not reuse the trail"); + + return res; +} + +void kissat_restart (kissat *solver) { + START (restart); + INC (restarts); + ADD (restarts_levels, solver->level); + if (solver->stable) + INC (stable_restarts); + else + INC (focused_restarts); + unsigned level = reuse_trail (solver); + kissat_extremely_verbose (solver, + "restarting after %" PRIu64 " conflicts" + " (limit %" PRIu64 ")", + CONFLICTS, solver->limits.restart.conflicts); + LOG ("restarting to level %u", level); + kissat_backtrack_in_consistent_state (solver, level); + if (!solver->stable) + kissat_update_focused_restart_limit (solver); + REPORT (1, 'R'); + STOP (restart); +} diff --git a/src/sat/kissat/restart.h b/src/sat/kissat/restart.h new file mode 100644 index 000000000..c17ab6499 --- /dev/null +++ b/src/sat/kissat/restart.h @@ -0,0 +1,13 @@ +#ifndef _restart_h_INCLUDED +#define _restart_h_INCLUDED + +#include + +struct kissat; + +bool kissat_restarting (struct kissat *); +void kissat_restart (struct kissat *); + +void kissat_update_focused_restart_limit (struct kissat *); + +#endif diff --git a/src/sat/kissat/search.c b/src/sat/kissat/search.c new file mode 100644 index 000000000..77f44ad99 --- /dev/null +++ b/src/sat/kissat/search.c @@ -0,0 +1,229 @@ +#include "search.h" +#include "analyze.h" +#include "bump.h" +#include "classify.h" +#include "decide.h" +#include "eliminate.h" +#include "inline.h" +#include "internal.h" +#include "logging.h" +#include "lucky.h" +#include "preprocess.h" +#include "print.h" +#include "probe.h" +#include "propsearch.h" +#include "reduce.h" +#include "reluctant.h" +#include "reorder.h" +#include "rephase.h" +#include "report.h" +#include "restart.h" +#include "terminate.h" +#include "trail.h" +#include "walk.h" + +#include + +static void init_tiers (kissat *solver) { + for (unsigned stable = 0; stable != 2; stable++) { + if (!solver->tier1[stable]) { + assert (!solver->tier2[stable]); + solver->tier1[stable] = GET_OPTION (tier1); + solver->tier2[stable] = GET_OPTION (tier2); + if (solver->tier2[stable] <= solver->tier1[stable]) + solver->tier2[stable] = solver->tier1[stable]; + LOG ("initialized tier1[%u] glue to %u", stable, + solver->tier1[stable]); + LOG ("initialized tier2[%u] glue to %u", stable, + solver->tier2[stable]); + if (!solver->limits.glue.interval) + solver->limits.glue.interval = 2; + } + } +} + +static void start_search (kissat *solver) { + START (search); + INC (searches); + + bool stable = (GET_OPTION (stable) == 2); + + solver->stable = stable; + kissat_phase (solver, "search", GET (searches), + "initializing %s search after %" PRIu64 " conflicts", + (stable ? "stable" : "focus"), CONFLICTS); + + kissat_init_averages (solver, &AVERAGES); + + kissat_classify (solver); + + if (solver->stable) { + kissat_init_reluctant (solver); + kissat_update_scores (solver); + } + + init_tiers (solver); + + kissat_init_limits (solver); + + unsigned seed = GET_OPTION (seed); + solver->random = seed; + LOG ("initialized random number generator with seed %u", seed); + +#ifndef QUIET + limits *limits = &solver->limits; + limited *limited = &solver->limited; + if (!limited->conflicts && !limited->decisions) + kissat_very_verbose (solver, "starting unlimited search"); + else if (limited->conflicts && !limited->decisions) + kissat_very_verbose ( + solver, "starting search with conflicts limited to %" PRIu64, + limits->conflicts); + else if (!limited->conflicts && limited->decisions) + kissat_very_verbose ( + solver, "starting search with decisions limited to %" PRIu64, + limits->decisions); + else + kissat_very_verbose ( + solver, + "starting search with decisions limited to %" PRIu64 + " and conflicts limited to %" PRIu64, + limits->decisions, limits->conflicts); + if (stable) { + START (stable); + REPORT (0, '['); + } else { + START (focused); + REPORT (0, '{'); + } +#endif +} + +static void stop_search (kissat *solver) { + if (solver->limited.conflicts) { + LOG ("reset conflict limit"); + solver->limited.conflicts = false; + } + + if (solver->limited.decisions) { + LOG ("reset decision limit"); + solver->limited.decisions = false; + } + + if (solver->termination.flagged) { + kissat_very_verbose (solver, "termination forced externally"); + solver->termination.flagged = 0; + } + + if (solver->stable) { + REPORT (0, ']'); + STOP (stable); + solver->stable = false; + } else { + REPORT (0, '}'); + STOP (focused); + } + STOP (search); +} + +static void report_search_result (kissat *solver, int res) { +#ifndef QUIET + LOG ("search result %d", res); + char type = (res == 10 ? '1' : res == 20 ? '0' : '?'); + REPORT (0, type); +#else + (void) solver, (void) res; +#endif +} + +static void iterate (kissat *solver) { + assert (solver->iterating); + solver->iterating = false; + REPORT (0, 'i'); +} + +static bool conflict_limit_hit (kissat *solver) { + if (!solver->limited.conflicts) + return false; + if (solver->limits.conflicts > solver->statistics.conflicts) + return false; + kissat_very_verbose ( + solver, "conflict limit %" PRIu64 " hit after %" PRIu64 " conflicts", + solver->limits.conflicts, solver->statistics.conflicts); + return true; +} + +static bool decision_limit_hit (kissat *solver) { + if (!solver->limited.decisions) + return false; + if (solver->limits.decisions > solver->statistics.decisions) + return false; + kissat_very_verbose ( + solver, "decision limit %" PRIu64 " hit after %" PRIu64 " decisions", + solver->limits.decisions, solver->statistics.decisions); + return true; +} + +static bool searching (kissat *solver) { + if (!kissat_propagated (solver)) + return true; + if (!GET_OPTION (probeinit)) + return true; + if (!GET_OPTION (eliminateinit)) + return true; + if (conflict_limit_hit (solver)) + return false; + return true; +} + +int kissat_search (kissat *solver) { + REPORT (0, '*'); + int res = 0; + if (solver->inconsistent) + res = 20; + if (!res && GET_OPTION (luckyearly)) + res = kissat_lucky (solver); + if (!res && kissat_preprocessing (solver)) + res = kissat_preprocess (solver); + if (!res && GET_OPTION (luckylate)) + res = kissat_lucky (solver); + if (!res) + kissat_classify (solver); + if (!res && searching (solver)) { + start_search (solver); + while (!res) { + clause *conflict = kissat_search_propagate (solver); + if (conflict) + res = kissat_analyze (solver, conflict); + else if (solver->iterating) + iterate (solver); + else if (!solver->unassigned) + res = 10; + else if (TERMINATED (search_terminated_1)) + break; + else if (kissat_reducing (solver)) + res = kissat_reduce (solver); + else if (kissat_switching_search_mode (solver)) + kissat_switch_search_mode (solver); + else if (kissat_restarting (solver)) + kissat_restart (solver); + else if (kissat_reordering (solver)) + kissat_reorder (solver); + else if (kissat_rephasing (solver)) + kissat_rephase (solver); + else if (kissat_probing (solver)) + res = kissat_probe (solver); + else if (kissat_eliminating (solver)) + res = kissat_eliminate (solver); + else if (conflict_limit_hit (solver)) + break; + else if (decision_limit_hit (solver)) + break; + else + kissat_decide (solver); + } + stop_search (solver); + } + report_search_result (solver, res); + return res; +} diff --git a/src/sat/kissat/search.h b/src/sat/kissat/search.h new file mode 100644 index 000000000..b7f17f894 --- /dev/null +++ b/src/sat/kissat/search.h @@ -0,0 +1,8 @@ +#ifndef _search_h_INCLUDED +#define _search_h_INCLUDED + +struct kissat; + +int kissat_search (struct kissat *); + +#endif diff --git a/src/sat/kissat/shrink.c b/src/sat/kissat/shrink.c new file mode 100644 index 000000000..d0614df97 --- /dev/null +++ b/src/sat/kissat/shrink.c @@ -0,0 +1,395 @@ +#include "shrink.h" +#include "allocate.h" +#include "inline.h" +#include "minimize.h" + +static void reset_shrinkable (kissat *solver) { +#ifdef LOGGING + size_t reset = 0; +#endif + while (!EMPTY_STACK (solver->shrinkable)) { + const unsigned idx = POP_STACK (solver->shrinkable); + assigned *a = solver->assigned + idx; + assert (a->shrinkable); + a->shrinkable = false; +#ifdef LOGGING + reset++; +#endif + } + LOG ("resetting %zu shrinkable variables", reset); +} + +static void mark_shrinkable_as_removable (kissat *solver) { +#ifdef LOGGING + size_t marked = 0, reset = 0; +#endif + struct assigned *assigned = solver->assigned; + while (!EMPTY_STACK (solver->shrinkable)) { + const unsigned idx = POP_STACK (solver->shrinkable); + struct assigned *a = assigned + idx; + assert (a->shrinkable); + a->shrinkable = false; + assert (!a->poisoned); +#ifdef LOGGING + reset++; +#endif + if (a->removable) + continue; + kissat_push_removable (solver, assigned, idx); +#ifdef LOGGING + marked++; +#endif + } + LOG ("resetting %zu shrinkable variables", reset); + LOG ("marked %zu removable variables", marked); +} + +static inline int shrink_literal (kissat *solver, assigned *assigned, + unsigned level, unsigned lit) { + assert (solver->assigned == assigned); + assert (VALUE (lit) < 0); + + const unsigned idx = IDX (lit); + struct assigned *a = assigned + idx; + assert (a->level <= level); + if (!a->level) { + LOG2 ("skipping root level assigned %s", LOGLIT (lit)); + return 0; + } + if (a->shrinkable) { + LOG2 ("skipping already shrinkable literal %s", LOGLIT (lit)); + return 0; + } + if (a->level < level) { + if (a->removable) { + LOG2 ("skipping removable thus shrinkable %s", LOGLIT (lit)); + return 0; + } + const bool always_minimize_on_lower_level = (GET_OPTION (shrink) > 2); + if (always_minimize_on_lower_level && + kissat_minimize_literal (solver, lit, false)) { + LOG2 ("minimized thus shrinkable %s", LOGLIT (lit)); + return 0; + } + LOG ("literal %s on lower level %u < %u not removable/shrinkable", + LOGLIT (lit), a->level, level); + return -1; + } + LOG2 ("marking %s as shrinkable", LOGLIT (lit)); + a->shrinkable = true; + PUSH_STACK (solver->shrinkable, idx); + return 1; +} + +static inline unsigned shrunken_block (kissat *solver, unsigned level, + unsigned *begin_block, + unsigned *end_block, unsigned uip) { + assert (uip != INVALID_LIT); + const unsigned not_uip = NOT (uip); + LOG ("found unique implication point %s on level %u", LOGLIT (uip), + level); + + assert (begin_block < end_block); +#if defined(LOGGING) || !defined(NDEBUG) + const size_t tmp = end_block - begin_block; + LOG ("shrinking %zu literals on level %u to single literal %s", tmp, + level, LOGLIT (not_uip)); + assert (tmp > 1); +#endif + +#ifdef LOGGING + bool not_uip_was_in_clause = false; +#endif + unsigned block_shrunken = 0; + + for (unsigned *p = begin_block; p != end_block; p++) { + const unsigned lit = *p; + if (lit == INVALID_LIT) + continue; +#ifdef LOGGING + if (lit == not_uip) + not_uip_was_in_clause = true; + else + LOG ("shrunken literal %s", LOGLIT (lit)); +#endif + *p = INVALID_LIT; + block_shrunken++; + } + *begin_block = not_uip; + assert (block_shrunken); + block_shrunken--; +#ifdef LOGGING + if (not_uip_was_in_clause) + LOG ("keeping single literal %s on level %u", LOGLIT (not_uip), level); + else + LOG ("shrunken all literals on level %u and added %s instead", level, + LOGLIT (not_uip)); +#endif + const unsigned uip_idx = IDX (uip); + assigned *assigned = solver->assigned; + struct assigned *a = assigned + uip_idx; + if (!a->analyzed) + kissat_push_analyzed (solver, assigned, uip_idx); + + mark_shrinkable_as_removable (solver); +#ifndef LOGGING + (void) level; +#endif + return block_shrunken; +} + +static inline void push_literals_of_block (kissat *solver, + assigned *assigned, + unsigned *begin_block, + unsigned *end_block, + unsigned level) { + assert (assigned == solver->assigned); + + for (const unsigned *p = begin_block; p != end_block; p++) { + const unsigned lit = *p; + if (lit == INVALID_LIT) + continue; +#ifndef NDEBUG + int tmp = +#endif + shrink_literal (solver, assigned, level, lit); + assert (tmp > 0); + } +} + +static inline unsigned shrink_along_binary (kissat *solver, + assigned *assigned, + unsigned level, unsigned uip, + unsigned other) { + assert (VALUE (other) < 0); + LOGBINARY2 (uip, other, "shrinking along %s reason", LOGLIT (uip)); + int tmp = shrink_literal (solver, assigned, level, other); +#ifndef LOGGING + (void) uip; +#endif + return tmp > 0; +} + +static inline unsigned +shrink_along_large (kissat *solver, assigned *assigned, unsigned level, + unsigned uip, reference ref, bool *failed_ptr) { + unsigned open = 0; + LOGREF2 (ref, "shrinking along %s reason", LOGLIT (uip)); + clause *c = kissat_dereference_clause (solver, ref); + if (GET_OPTION (minimizeticks)) + INC (search_ticks); + for (all_literals_in_clause (other, c)) { + if (other == uip) + continue; + assert (VALUE (other) < 0); + int tmp = shrink_literal (solver, assigned, level, other); + if (tmp < 0) { + *failed_ptr = true; + break; + } + if (tmp > 0) + open++; + } + return open; +} + +static inline unsigned shrink_along_reason (kissat *solver, + assigned *assigned, + unsigned level, unsigned uip, + bool resolve_large_clauses, + bool *failed_ptr) { + unsigned open = 0; + const unsigned uip_idx = IDX (uip); + struct assigned *a = assigned + uip_idx; + assert (a->shrinkable); + assert (a->level == level); + assert (a->reason != DECISION_REASON); + if (a->binary) { + const unsigned other = a->reason; + open = shrink_along_binary (solver, assigned, level, uip, other); + } else { + reference ref = a->reason; + if (resolve_large_clauses) + open = shrink_along_large (solver, assigned, level, uip, ref, + failed_ptr); + else { + LOGREF (ref, "not shrinking %s reason", LOGLIT (uip)); + *failed_ptr = true; + } + } + return open; +} + +static inline unsigned shrink_block (kissat *solver, unsigned *begin_block, + unsigned *end_block, unsigned level, + unsigned max_trail) { + assert (level < solver->level); + + unsigned open = end_block - begin_block; + + LOG ("trying to shrink %u literals on level %u", open, level); + LOG ("maximum trail position %u on level %u", max_trail, level); + + assigned *assigned = solver->assigned; + + push_literals_of_block (solver, assigned, begin_block, end_block, level); + + assert (SIZE_STACK (solver->shrinkable) == open); + + const unsigned *const begin_trail = BEGIN_ARRAY (solver->trail); + + const bool resolve_large_clauses = (GET_OPTION (shrink) > 1); + unsigned uip = INVALID_LIT; + bool failed = false; + + const unsigned *t = begin_trail + max_trail; + + while (!failed) { + { + do + assert (begin_trail <= t), uip = *t--; + while (!assigned[IDX (uip)].shrinkable); + } + if (open == 1) + break; + open += shrink_along_reason (solver, assigned, level, uip, + resolve_large_clauses, &failed); + assert (open > 1); + open--; + } + + unsigned block_shrunken = 0; + if (failed) + reset_shrinkable (solver); + else + block_shrunken = + shrunken_block (solver, level, begin_block, end_block, uip); + + return block_shrunken; +} + +static unsigned *next_block (kissat *solver, unsigned *begin_lits, + unsigned *end_block, unsigned *level_ptr, + unsigned *max_trail_ptr) { + assigned *assigned = solver->assigned; + + unsigned level = INVALID_LEVEL; + unsigned max_trail = 0; + + unsigned *begin_block = end_block; + + while (begin_lits < begin_block) { + const unsigned lit = begin_block[-1]; + assert (lit != INVALID_LIT); + const unsigned idx = IDX (lit); + struct assigned *a = assigned + idx; + unsigned lit_level = a->level; + if (level == INVALID_LEVEL) { + level = lit_level; + LOG ("starting to shrink level %u", level); + } else { + assert (lit_level >= level); + if (lit_level > level) + break; + } + begin_block--; + const unsigned trail = a->trail; + if (trail > max_trail) + max_trail = trail; + } + + *level_ptr = level; + *max_trail_ptr = max_trail; + + return begin_block; +} + +static unsigned minimize_block (kissat *solver, unsigned *begin_block, + unsigned *end_block) { + unsigned minimized = 0; + + for (unsigned *p = begin_block; p != end_block; p++) { + const unsigned lit = *p; + assert (lit != INVALID_LIT); + if (!kissat_minimize_literal (solver, lit, true)) + continue; + LOG ("minimize-shrunken literal %s", LOGLIT (lit)); + *p = INVALID_LIT; + minimized++; + } + + return minimized; +} + +static inline unsigned * +minimize_and_shrink_block (kissat *solver, unsigned *begin_lits, + unsigned *end_block, unsigned *total_shrunken, + unsigned *total_minimized) { + assert (EMPTY_STACK (solver->shrinkable)); + + unsigned level, max_trail; + + unsigned *begin_block = + next_block (solver, begin_lits, end_block, &level, &max_trail); + + unsigned open = end_block - begin_block; + assert (open > 0); + + unsigned block_shrunken = 0; + unsigned block_minimized = 0; + + if (open < 2) + LOG ("only one literal on level %u", level); + else { + block_shrunken = + shrink_block (solver, begin_block, end_block, level, max_trail); + if (!block_shrunken) + block_minimized = minimize_block (solver, begin_block, end_block); + } + + block_shrunken += block_minimized; + LOG ("shrunken %u literals on level %u (including %u minimized)", + block_shrunken, level, block_minimized); + + *total_minimized += block_minimized; + *total_shrunken += block_shrunken; + + return begin_block; +} + +void kissat_shrink_clause (kissat *solver) { + assert (GET_OPTION (minimize) > 0); + assert (GET_OPTION (shrink) > 0); + assert (!EMPTY_STACK (solver->clause)); + + START (shrink); + + unsigned total_shrunken = 0; + unsigned total_minimized = 0; + + unsigned *begin_lits = BEGIN_STACK (solver->clause); + unsigned *end_lits = END_STACK (solver->clause); + + unsigned *end_block = END_STACK (solver->clause); + + while (end_block != begin_lits) + end_block = minimize_and_shrink_block ( + solver, begin_lits, end_block, &total_shrunken, &total_minimized); + unsigned *q = begin_lits; + for (const unsigned *p = q; p != end_lits; p++) { + const unsigned lit = *p; + if (lit != INVALID_LIT) + *q++ = lit; + } + LOG ("clause shrunken by %u literals (including %u minimized)", + total_shrunken, total_minimized); + assert (q + total_shrunken == end_lits); + SET_END_OF_STACK (solver->clause, q); + ADD (literals_shrunken, total_shrunken); + ADD (literals_minshrunken, total_minimized); + + LOGTMP ("shrunken learned"); + kissat_reset_poisoned (solver); + + STOP (shrink); +} diff --git a/src/sat/kissat/shrink.h b/src/sat/kissat/shrink.h new file mode 100644 index 000000000..662df06ee --- /dev/null +++ b/src/sat/kissat/shrink.h @@ -0,0 +1,8 @@ +#ifndef _shrink_h_INCLUDED +#define _shrink_h_INCLUDED + +struct kissat; + +void kissat_shrink_clause (struct kissat *); + +#endif diff --git a/src/sat/kissat/smooth.c b/src/sat/kissat/smooth.c new file mode 100644 index 000000000..487680f06 --- /dev/null +++ b/src/sat/kissat/smooth.c @@ -0,0 +1,73 @@ +#include "allocate.h" +#include "internal.h" +#include "logging.h" + +void kissat_init_smooth (kissat *solver, smooth *smooth, int window, + const char *name) { + assert (window > 0); + const double alpha = 1.0 / window; + LOG ("initialized %s EMA alpha %g window %d", name, alpha, window); + smooth->value = 0; + smooth->biased = 0; + smooth->alpha = alpha; + smooth->beta = 1.0 - alpha; + assert (smooth->beta > 0); + smooth->exp = 1.0; +#ifdef LOGGING + smooth->name = name; + smooth->updated = 0; +#else + (void) solver; + (void) name; +#endif +} + +void kissat_update_smooth (kissat *solver, smooth *smooth, double y) { +#ifdef LOGGING + smooth->updated++; + const double old_value = smooth->value; +#endif + const double old_biased = smooth->biased; + const double alpha = smooth->alpha; + const double beta = smooth->beta; + const double delta = y - old_biased; + const double scaled_delta = alpha * delta; + const double new_biased = old_biased + scaled_delta; + LOG ("update %" PRIu64 " of biased %s EMA %g with %g (delta %g) " + "yields %g (scaled delta %g)", + smooth->updated, smooth->name, old_biased, y, delta, new_biased, + scaled_delta); + smooth->biased = new_biased; + double old_exp = smooth->exp; + double new_exp, div, new_value; + if (old_exp) { + new_exp = old_exp * beta; + assert (new_exp < 1); + if (new_exp == old_exp) { + new_exp = 0; + new_value = new_biased; +#ifdef LOGGING + div = 1; +#endif + } else { + div = 1 - new_exp; + assert (div > 0); + new_value = new_biased / div; + } + smooth->exp = new_exp; + } else { + new_value = new_biased; +#ifdef LOGGING + new_exp = 0; + div = 1; +#endif + } + smooth->value = new_value; + LOG ("update %" PRIu64 " of corrected %s EMA %g " + "with %g (delta %g) yields %g (exponent %g, div %g)", + smooth->updated, smooth->name, old_value, y, delta, new_value, + new_exp, div); +#ifndef LOGGING + (void) solver; +#endif +} diff --git a/src/sat/kissat/smooth.h b/src/sat/kissat/smooth.h new file mode 100644 index 000000000..11f2efe9f --- /dev/null +++ b/src/sat/kissat/smooth.h @@ -0,0 +1,22 @@ +#ifndef _smooth_h_INCLUDED +#define _smooth_h_INCLUDED + +#include + +typedef struct smooth smooth; + +struct smooth { + double value, biased, alpha, beta, exp; +#ifdef LOGGING + const char *name; + uint64_t updated; +#endif +}; + +struct kissat; + +void kissat_init_smooth (struct kissat *, smooth *, int window, + const char *); +void kissat_update_smooth (struct kissat *, smooth *, double); + +#endif diff --git a/src/sat/kissat/sort.c b/src/sat/kissat/sort.c new file mode 100644 index 000000000..ba1ea32b2 --- /dev/null +++ b/src/sat/kissat/sort.c @@ -0,0 +1,98 @@ +#include "internal.h" +#include "logging.h" + +static inline value +move_smallest_literal_to_front (kissat *solver, const value *const values, + const assigned *const assigned, + bool satisfied_is_enough, unsigned start, + unsigned size, unsigned *lits) { + assert (1 < size); + assert (start < size); + + unsigned a = lits[start]; + + value u = values[a]; + if (!u || (u > 0 && satisfied_is_enough)) + return u; + + unsigned pos = 0, best = a; + + { + const unsigned i = IDX (a); + unsigned k = (u ? assigned[i].level : UINT_MAX); + + assert (start < UINT_MAX); + for (unsigned i = start + 1; i < size; i++) { + const unsigned b = lits[i]; + const value v = values[b]; + + if (!v || (v > 0 && satisfied_is_enough)) { + best = b; + pos = i; + u = v; + break; + } + + const unsigned j = IDX (b); + const unsigned l = (v ? assigned[j].level : UINT_MAX); + + bool better; + + if (u < 0 && v > 0) + better = true; + else if (u > 0 && v < 0) + better = false; + else if (u < 0) { + assert (v < 0); + better = (k < l); + } else { + assert (u > 0); + assert (v > 0); + assert (!satisfied_is_enough); + better = (k > l); + } + + if (!better) + continue; + + best = b; + pos = i; + u = v; + k = l; + } + } + + if (!pos) + return u; + + lits[start] = best; + lits[pos] = a; + + LOG ("new smallest literal %s at %u swapped with %s at %u", LOGLIT (best), + pos, LOGLIT (a), start); +#ifndef LOGGING + (void) solver; +#endif + return u; +} + +#ifdef INLINE_SORT +static inline +#endif + void + kissat_sort_literals (kissat *solver, +#ifdef INLINE_SORT + const value *const values, + const assigned *assigned, +#endif + unsigned size, unsigned *lits) { +#ifndef INLINE_SORT + const value *const values = solver->values; + const assigned *const assigned = solver->assigned; +#endif + value u = move_smallest_literal_to_front (solver, values, assigned, false, + 0, size, lits); + if (size > 2) + move_smallest_literal_to_front (solver, values, assigned, (u >= 0), 1, + size, lits); +} diff --git a/src/sat/kissat/sort.h b/src/sat/kissat/sort.h new file mode 100644 index 000000000..9e0e6ee94 --- /dev/null +++ b/src/sat/kissat/sort.h @@ -0,0 +1,154 @@ +#ifndef _sort_h_INCLUDED +#define _sort_h_INCLUDED + +#include "utilities.h" + +#define GREATER_SWAP(TYPE, P, Q, LESS) \ + do { \ + if (LESS (Q, P)) \ + SWAP (TYPE, P, Q); \ + } while (0) + +#define SORTER (solver->sorter) + +#define PARTITION(TYPE, L, R, A, LESS) \ + do { \ + const size_t L_PARTITION = (L); \ + I_QUICK_SORT = L_PARTITION - 1; \ +\ + size_t J_PARTITION = (R); \ +\ + TYPE PIVOT_PARTITION = A[J_PARTITION]; \ +\ + for (;;) { \ + while (LESS (A[++I_QUICK_SORT], PIVOT_PARTITION)) \ + ; \ + while (LESS (PIVOT_PARTITION, A[--J_PARTITION])) \ + if (J_PARTITION == L_PARTITION) \ + break; \ +\ + if (I_QUICK_SORT >= J_PARTITION) \ + break; \ +\ + SWAP (TYPE, A[I_QUICK_SORT], A[J_PARTITION]); \ + } \ +\ + SWAP (TYPE, A[I_QUICK_SORT], A[R]); \ + } while (0) + +#define QUICK_SORT_LIMIT 10 + +#define QUICK_SORT(TYPE, N, A, LESS) \ + do { \ + assert (N); \ + assert (EMPTY_STACK (SORTER)); \ +\ + size_t L_QUICK_SORT = 0; \ + size_t R_QUICK_SORT = N - 1; \ +\ + if (R_QUICK_SORT - L_QUICK_SORT <= QUICK_SORT_LIMIT) \ + break; \ +\ + for (;;) { \ + const size_t M = L_QUICK_SORT + (R_QUICK_SORT - L_QUICK_SORT) / 2; \ +\ + SWAP (TYPE, A[M], A[R_QUICK_SORT - 1]); \ +\ + GREATER_SWAP (TYPE, A[L_QUICK_SORT], A[R_QUICK_SORT - 1], LESS); \ + GREATER_SWAP (TYPE, A[L_QUICK_SORT], A[R_QUICK_SORT], LESS); \ + GREATER_SWAP (TYPE, A[R_QUICK_SORT - 1], A[R_QUICK_SORT], LESS); \ +\ + size_t I_QUICK_SORT; \ +\ + PARTITION (TYPE, L_QUICK_SORT + 1, R_QUICK_SORT - 1, A, LESS); \ + assert (L_QUICK_SORT < I_QUICK_SORT); \ + assert (I_QUICK_SORT <= R_QUICK_SORT); \ +\ + size_t LL_QUICK_SORT; \ + size_t RR_QUICK_SORT; \ +\ + if (I_QUICK_SORT - L_QUICK_SORT < R_QUICK_SORT - I_QUICK_SORT) { \ + LL_QUICK_SORT = I_QUICK_SORT + 1; \ + RR_QUICK_SORT = R_QUICK_SORT; \ + R_QUICK_SORT = I_QUICK_SORT - 1; \ + } else { \ + LL_QUICK_SORT = L_QUICK_SORT; \ + RR_QUICK_SORT = I_QUICK_SORT - 1; \ + L_QUICK_SORT = I_QUICK_SORT + 1; \ + } \ + if (R_QUICK_SORT - L_QUICK_SORT > QUICK_SORT_LIMIT) { \ + assert (RR_QUICK_SORT - LL_QUICK_SORT > QUICK_SORT_LIMIT); \ + PUSH_STACK (SORTER, LL_QUICK_SORT); \ + PUSH_STACK (SORTER, RR_QUICK_SORT); \ + } else if (RR_QUICK_SORT - LL_QUICK_SORT > QUICK_SORT_LIMIT) { \ + L_QUICK_SORT = LL_QUICK_SORT; \ + R_QUICK_SORT = RR_QUICK_SORT; \ + } else if (!EMPTY_STACK (SORTER)) { \ + R_QUICK_SORT = POP_STACK (SORTER); \ + L_QUICK_SORT = POP_STACK (SORTER); \ + } else \ + break; \ + } \ + } while (0) + +#define INSERTION_SORT(TYPE, N, A, LESS) \ + do { \ + size_t L_INSERTION_SORT = 0; \ + size_t R_INSERTION_SORT = N - 1; \ +\ + for (size_t I_INSERTION_SORT = R_INSERTION_SORT; \ + I_INSERTION_SORT > L_INSERTION_SORT; I_INSERTION_SORT--) \ + GREATER_SWAP (TYPE, A[I_INSERTION_SORT - 1], A[I_INSERTION_SORT], \ + LESS); \ +\ + for (size_t I_INSERTION_SORT = L_INSERTION_SORT + 2; \ + I_INSERTION_SORT <= R_INSERTION_SORT; I_INSERTION_SORT++) { \ + TYPE PIVOT_INSERTION_SORT = A[I_INSERTION_SORT]; \ +\ + size_t J_INSERTION_SORT = I_INSERTION_SORT; \ +\ + while (LESS (PIVOT_INSERTION_SORT, A[J_INSERTION_SORT - 1])) { \ + A[J_INSERTION_SORT] = A[J_INSERTION_SORT - 1]; \ + J_INSERTION_SORT--; \ + } \ +\ + A[J_INSERTION_SORT] = PIVOT_INSERTION_SORT; \ + } \ + } while (0) + +#ifdef NDEBUG +#define CHECK_SORTED(...) \ + do { \ + } while (0) +#else +#define CHECK_SORTED(N, A, LESS) \ + do { \ + for (size_t I_CHECK_SORTED = 0; I_CHECK_SORTED < N - 1; \ + I_CHECK_SORTED++) \ + assert (!LESS (A[I_CHECK_SORTED + 1], A[I_CHECK_SORTED])); \ + } while (0) +#endif + +#define SORT(TYPE, N, A, LESS) \ + do { \ + const size_t N_SORT = (N); \ + if (!N_SORT) \ + break; \ + START (sort); \ + TYPE *A_SORT = (A); \ + QUICK_SORT (TYPE, N_SORT, A_SORT, LESS); \ + INSERTION_SORT (TYPE, N_SORT, A_SORT, LESS); \ + CHECK_SORTED (N_SORT, A_SORT, LESS); \ + STOP (sort); \ + } while (0) + +#define SORT_STACK(TYPE, S, LESS) \ + do { \ + const size_t N_SORT_STACK = SIZE_STACK (S); \ + if (N_SORT_STACK <= 1) \ + break; \ + TYPE *A_SORT_STACK = BEGIN_STACK (S); \ + SORT (TYPE, N_SORT_STACK, A_SORT_STACK, LESS); \ + } while (0) + +#endif diff --git a/src/sat/kissat/stack.c b/src/sat/kissat/stack.c new file mode 100644 index 000000000..4fc7f3352 --- /dev/null +++ b/src/sat/kissat/stack.c @@ -0,0 +1,51 @@ +#include "stack.h" +#include "allocate.h" +#include "utilities.h" + +#include + +void kissat_stack_enlarge (struct kissat *solver, chars *s, size_t bytes) { + const size_t size = SIZE_STACK (*s); + const size_t old_bytes = CAPACITY_STACK (*s); + assert (MAX_SIZE_T / 2 >= old_bytes); + size_t new_bytes; + if (old_bytes) + new_bytes = 2 * old_bytes; + else { + new_bytes = bytes; + while (!kissat_aligned_word (new_bytes)) + new_bytes <<= 1; + } + s->begin = kissat_realloc (solver, s->begin, old_bytes, new_bytes); + s->allocated = s->begin + new_bytes; + s->end = s->begin + size; +} + +void kissat_shrink_stack (struct kissat *solver, chars *s, size_t bytes) { + assert (bytes > 0); + const size_t old_bytes_capacity = CAPACITY_STACK (*s); + assert (kissat_aligned_word (old_bytes_capacity)); + assert (!(old_bytes_capacity % bytes)); + assert (kissat_is_zero_or_power_of_two (old_bytes_capacity / bytes)); + const size_t old_bytes_size = SIZE_STACK (*s); + assert (!(old_bytes_size % bytes)); + const size_t old_size = old_bytes_size / bytes; + size_t new_capacity; + if (old_size) { + const unsigned ld_old_size = kissat_log2_ceiling_of_word (old_size); + new_capacity = ((size_t) 1) << ld_old_size; + } else + new_capacity = 0; + assert (kissat_is_zero_or_power_of_two (new_capacity)); + size_t new_bytes_capacity = new_capacity * bytes; + while (!kissat_aligned_word (new_bytes_capacity)) + new_bytes_capacity <<= 1; + if (new_bytes_capacity == old_bytes_capacity) + return; + assert (new_bytes_capacity < old_bytes_capacity); + s->begin = kissat_realloc (solver, s->begin, old_bytes_capacity, + new_bytes_capacity); + s->allocated = s->begin + new_bytes_capacity; + s->end = s->begin + old_bytes_size; + assert (s->end <= s->allocated); +} diff --git a/src/sat/kissat/stack.h b/src/sat/kissat/stack.h new file mode 100644 index 000000000..23e07f597 --- /dev/null +++ b/src/sat/kissat/stack.h @@ -0,0 +1,140 @@ +#ifndef _stack_h_INCLUDED +#define _stack_h_INCLUDED + +#include + +#define STACK(TYPE) \ + struct { \ + TYPE *begin; \ + TYPE *end; \ + TYPE *allocated; \ + } + +#define FULL_STACK(S) ((S).end == (S).allocated) +#define EMPTY_STACK(S) ((S).begin == (S).end) +#define SIZE_STACK(S) ((size_t) ((S).end - (S).begin)) +#define CAPACITY_STACK(S) ((size_t) ((S).allocated - (S).begin)) + +#define INIT_STACK(S) \ + do { \ + (S).begin = (S).end = (S).allocated = 0; \ + } while (0) + +#define TOP_STACK(S) (END_STACK (S)[assert (!EMPTY_STACK (S)), -1]) + +#define PEEK_STACK(S, N) \ + (BEGIN_STACK (S)[assert ((N) < SIZE_STACK (S)), (N)]) + +#define POKE_STACK(S, N, E) \ + do { \ + PEEK_STACK (S, N) = (E); \ + } while (0) + +#define POP_STACK(S) (assert (!EMPTY_STACK (S)), *--(S).end) + +#define ENLARGE_STACK(S) \ + do { \ + assert (FULL_STACK (S)); \ + kissat_stack_enlarge (solver, (chars *) &(S), sizeof *(S).begin); \ + } while (0) + +#define SHRINK_STACK(S) \ + do { \ + if (!FULL_STACK (S)) \ + kissat_shrink_stack (solver, (chars *) &(S), sizeof *(S).begin); \ + } while (0) + +#define PUSH_STACK(S, E) \ + do { \ + if (FULL_STACK (S)) \ + ENLARGE_STACK (S); \ + *(S).end++ = (E); \ + } while (0) + +#define BEGIN_STACK(S) (S).begin + +#define END_STACK(S) (S).end + +#define CLEAR_STACK(S) \ + do { \ + (S).end = (S).begin; \ + } while (0) + +#define RESIZE_STACK(S, NEW_SIZE) \ + do { \ + const size_t TMP_NEW_SIZE = (NEW_SIZE); \ + assert (TMP_NEW_SIZE <= SIZE_STACK (S)); \ + (S).end = (S).begin + TMP_NEW_SIZE; \ + } while (0) + +#define SET_END_OF_STACK(S, P) \ + do { \ + assert (BEGIN_STACK (S) <= (P)); \ + assert ((P) <= END_STACK (S)); \ + if ((P) == END_STACK (S)) \ + break; \ + (S).end = (P); \ + } while (0) + +#define RELEASE_STACK(S) \ + do { \ + DEALLOC ((S).begin, CAPACITY_STACK (S)); \ + INIT_STACK (S); \ + } while (0) + +#define REMOVE_STACK(T, S, E) \ + do { \ + assert (!EMPTY_STACK (S)); \ + T *END_REMOVE_STACK = END_STACK (S); \ + T *P_REMOVE_STACK = BEGIN_STACK (S); \ + while (*P_REMOVE_STACK != (E)) { \ + P_REMOVE_STACK++; \ + assert (P_REMOVE_STACK != END_REMOVE_STACK); \ + } \ + P_REMOVE_STACK++; \ + while (P_REMOVE_STACK != END_REMOVE_STACK) { \ + P_REMOVE_STACK[-1] = *P_REMOVE_STACK; \ + P_REMOVE_STACK++; \ + } \ + (S).end--; \ + } while (0) + +#define REVERSE_STACK(T, S) \ + do { \ + if (SIZE_STACK (S) < 2) \ + break; \ + T *HEAD = (S).begin, *TAIL = (S).end - 1; \ + while (HEAD < TAIL) { \ + T TMP = *HEAD; \ + *HEAD++ = *TAIL; \ + *TAIL-- = TMP; \ + } \ + } while (0) + +#define all_stack(T, E, S) \ + T E, *E##_PTR = BEGIN_STACK (S), *const E##_END = END_STACK (S); \ + E##_PTR != E##_END && (E = *E##_PTR, true); \ + ++E##_PTR + +#define all_pointers(T, E, S) \ + T *E, *const *E##_PTR = BEGIN_STACK (S), \ + *const *const E##_END = END_STACK (S); \ + E##_PTR != E##_END && (E = *E##_PTR, true); \ + ++E##_PTR + +// clang-format off + +typedef STACK (char) chars; +typedef STACK (int) ints; +typedef STACK (size_t) sizes; +typedef STACK (unsigned) unsigneds; + +// clang-format on + +struct kissat; + +void kissat_stack_enlarge (struct kissat *, chars *, + size_t size_of_element); +void kissat_shrink_stack (struct kissat *, chars *, size_t size_of_element); + +#endif diff --git a/src/sat/kissat/statistics.c b/src/sat/kissat/statistics.c new file mode 100644 index 000000000..ad4bfa068 --- /dev/null +++ b/src/sat/kissat/statistics.c @@ -0,0 +1,414 @@ +#if !defined(QUIET) || !defined(NDEBUG) +#include "internal.h" +#endif + +#ifndef QUIET + +#include "resources.h" +#include "tiers.h" +#include "utilities.h" + +#include +#include +#include +#include + +void kissat_print_glue_usage (kissat *solver) { + const int64_t stable = solver->statistics.clauses_used_stable; + const int64_t focused = solver->statistics.clauses_used_focused; + if (!stable && !focused) + printf ("%sno clauses used at all\n", solver->prefix); + else { + if (focused) + kissat_print_tier_usage_statistics (solver, false); + if (focused && stable) + printf ("c\n"); + if (stable) + kissat_print_tier_usage_statistics (solver, true); + } + fflush (stdout); +} + +// clang-format off + +void +kissat_statistics_print (kissat * solver, bool verbose) +{ + statistics *statistics = &solver->statistics; + + const double time = kissat_process_time (); + size_t variables = solver->statistics.variables_original; +#ifdef METRICS + const double rss = kissat_maximum_resident_set_size (); +#endif + +/*------------------------------------------------------------------------*/ + +#define RELATIVE(FIRST,SECOND) \ + kissat_average (statistics->FIRST, statistics->SECOND) + +/*------------------------------------------------------------------------*/ + +#define CONF_INT(NAME) \ + RELATIVE (conflicts, NAME) + +#define SWEEPS_PER_COMPLETED(NAME) \ + RELATIVE (sweep, NAME) + +#define NO_SECONDARY(NAME) \ + 0 + +/*------------------------------------------------------------------------*/ + +#define PER_BACKBONE(NAME) \ + RELATIVE (NAME, backbone_computations) + +#define PER_BACKBONE_UNIT(NAME) \ + RELATIVE (NAME, backbone_units) + +#define PER_CLOSURE(NAME) \ + RELATIVE(NAME, closures) + +#define PER_CLS_ADDED(NAME) \ + RELATIVE (NAME, clauses_added) + +#define PER_CLS_FACTORED(NAME) \ + RELATIVE (NAME, clauses_factored) + +#define PER_CLS_LEARNED(NAME) \ + RELATIVE (NAME, clauses_learned) + +#define PER_CLS_UNFACTORED(NAME) \ + RELATIVE (NAME, clauses_unfactored) + +#define PER_CONFLICT(NAME) \ + RELATIVE (NAME, conflicts) + +#define PER_CONGRANDS(NAME) \ + RELATIVE (NAME, congruent_gates_ands) + +#define PER_CONGRGATES(NAME) \ + RELATIVE (NAME, congruent_gates) + +#define PER_CONGRITES(NAME) \ + RELATIVE (NAME, congruent_gates_ites) + +#define PER_CONGRLOOKUP(NAME) \ + RELATIVE (NAME, congruent_lookups) + +#define PER_CONGRXORS(NAME) \ + RELATIVE (NAME, congruent_gates_xors) + +#define PER_FIXED(NAME) \ + RELATIVE (NAME, units) + +#ifndef STATISTICS +#define PER_FLIPPED(NAME) \ + -1 +#else +#define PER_FLIPPED(NAME) \ + RELATIVE (NAME, flipped) +#endif + +#define PER_FORWARD_CHECK(NAME) \ + RELATIVE (NAME, forward_checks) + +#define PER_KITTEN_PROP(NAME) \ + RELATIVE (NAME, kitten_propagations) + +#define PER_KITTEN_SOLVED(NAME) \ + RELATIVE (NAME, kitten_solved) + +#define PER_PROPAGATION(NAME) \ + RELATIVE (NAME, propagations) + +#define PER_RESTART(NAME) \ + RELATIVE (NAME, restarts) + +#define PER_SECOND(NAME) \ + kissat_average (statistics->NAME, time) + +#define PER_SWEEP_VARIABLES(NAME) \ + kissat_average (statistics->NAME, statistics->sweep_variables) + +#define PER_VARIABLE(NAME) \ + kissat_average (statistics->NAME, variables) + +#define PER_VIVIFICATION(NAME) \ + RELATIVE (NAME, vivifications) + +#define PER_VIVIFY_CHECK(NAME) \ + RELATIVE (NAME, vivify_checks) + +#if 0 //ndef STATISTICS +#define PER_WALKS(NAME) \ + -1 +#else +#define PER_WALKS(NAME) \ + RELATIVE (NAME, walks) +#endif + +/*------------------------------------------------------------------------*/ + +#define PERCENT(FIRST,SECOND) \ + kissat_percent (statistics->FIRST, statistics->SECOND) + +/*------------------------------------------------------------------------*/ + +#define PCNT_ARENA_RESIZED(NAME) \ + PERCENT (NAME, arena_resized) + +#define PCNT_CLS_ADDED(NAME) \ + PERCENT (NAME, clauses_added) + +#define PCNT_CLS_IMPROVED(NAME) \ + PERCENT (NAME, clauses_improved) + +#define PCNT_CLS_IMPROVED(NAME) \ + PERCENT (NAME, clauses_improved) + +#define PCNT_CLS_FACTORED(NAME) \ + PERCENT (NAME, clauses_factored) + +#define PCNT_CLS_LEARNED(NAME) \ + PERCENT (NAME, clauses_learned) + +#define PCNT_CLS_ORIGINAL(NAME) \ + PERCENT (NAME, clauses_original) + +#define PCNT_CLS_REDUCED(NAME) \ + PERCENT (NAME, clauses_reduced) + +#define PCNT_CLS_USED(NAME) \ + PERCENT (NAME, clauses_used) + +#define PCNT_COLLECTIONS(NAME) \ + PERCENT (NAME, garbage_collections) + +#define PCNT_CONFLICTS(NAME) \ + PERCENT (NAME, conflicts) + +#define PCNT_CONGRCOLS(NAME) \ + PERCENT (NAME, congruent_collisions) + +#define PCNT_CONGRGATES(NAME) \ + PERCENT (NAME, congruent_gates) + +#define PCNT_CONGRLOOKUP(NAME) \ + PERCENT (NAME, congruent_lookups) + +#define PCNT_CONGRMATCHED(NAME) \ + PERCENT (NAME, congruent_matched) + +#define PCNT_CONGREWR(NAME) \ + PERCENT (NAME, congruent_rewritten) + +#define PCNT_CONGRSIMPS(NAME) \ + PERCENT (NAME, congruent_simplified) + +#define PCNT_CONGRUENT(NAME) \ + PERCENT (NAME, congruent) + +#define PCNT_CONGRUNARY(NAME) \ + PERCENT (NAME, congruent_unary) + +#define PCNT_DECISIONS(NAME) \ + PERCENT (NAME, decisions) + +#define PCNT_DEFRAGS(NAME) \ + PERCENT (NAME, defragmentations) + +#define PCNT_ELIM_ATTEMPTS(NAME) \ + PERCENT (NAME, eliminate_attempted) + +#define PCNT_ELIMINATED(NAME) \ + PERCENT (NAME, eliminated) + +#define PCNT_EXTRACTED(NAME) \ + PERCENT (NAME, gates_extracted) + +#define PCNT_IRREDUNDANT(NAME) \ + PERCENT (NAME, clauses_irredundant) + +#define PCNT_KITTEN_FLIP(NAME) \ + PERCENT (NAME, kitten_flip) + +#define PCNT_KITTEN_SOLVED(NAME) \ + PERCENT (NAME, kitten_solved) + +#define PCNT_LITS_DEDUCED(NAME) \ + PERCENT (NAME, literals_deduced) + +#define PCNT_LITS_SHRUNKEN(NAME) \ + PERCENT (NAME, literals_shrunken) + +#define PCNT_PROPS(NAME) \ + PERCENT (NAME, propagations) + +#define PCNT_REDUCTIONS(NAME) \ + PERCENT (NAME, reductions) + +#define PCNT_REDUNDANT_CLAUSES(NAME) \ + PERCENT (NAME, clauses_redundant) + +#define PCNT_REORDERED(NAME) \ + PERCENT (NAME, reordered) + +#define PCNT_REPHASED(NAME) \ + PERCENT (NAME, rephased) + +#define PCNT_RESIDENT_SET(NAME) \ + kissat_percent (statistics->NAME, rss) + +#define PCNT_RESTARTS(NAME) \ + PERCENT (NAME, restarts) + +#define PCNT_RESTARTS_LEVELS(NAME) \ + PERCENT (NAME, restarts_levels) + +#define PCNT_SEARCHES(NAME) \ + PERCENT (NAME, searches) + +#define PCNT_STRENGTHENED(NAME) \ + PERCENT (NAME, strengthened) + +#define PCNT_SUBSUMED(NAME) \ + PERCENT (NAME, subsumed) + +#define PCNT_SUBSUMPTION_CHECK(NAME) \ + PERCENT (NAME, subsumption_checks) + +#define PCNT_SWEEP_FLIP_BACKBONE(NAME) \ + PERCENT (NAME, sweep_flip_backbone) + +#define PCNT_SWEEP_FLIP_EQUIVALENCES(NAME) \ + PERCENT (NAME, sweep_flip_equivalences) + +#define PCNT_SWEEP_SOLVED_BACKBONE(NAME) \ + PERCENT (NAME, sweep_solved_backbone) + +#define PCNT_SWEEP_SOLVED_EQUIVALENCES(NAME) \ + PERCENT (NAME, sweep_solved_equivalences) + +#define PCNT_SWEEP_SOLVED(NAME) \ + PERCENT (NAME, sweep_solved) + +#ifndef STATISTICS +#define PCNT_TICKS(NAME) \ + -1 +#else +#define PCNT_TICKS(NAME) \ + PERCENT (NAME, ticks) +#endif + +#define PCNT_VARIABLES(NAME) \ + kissat_percent (statistics->NAME, variables) + +#define PCNT_VIVIFIED(NAME) \ + PERCENT (NAME, vivified) + +#define PCNT_VIVIFY_IMP(NAME) \ + PERCENT (NAME, vivified_implied) + +#define PCNT_VIVIFY_INST(NAME) \ + PERCENT (NAME, vivified_instantiated) + +#define PCNT_VIVIFY_CHECK(NAME) \ + PERCENT (NAME, vivify_checks) + +#define PCNT_VIVIFY_PROBES(NAME) \ + PERCENT (NAME, vivify_probes) + +#define PCNT_VIVIFY_SHRUNKEN(NAME) \ + PERCENT (NAME, vivified_shrunken) + +#define PCNT_VIVIFY_SUB(NAME) \ + PERCENT (NAME, vivified_subsumed) + +#define PCNT_WALKS(NAME) \ + PERCENT (NAME, walks) + +#define COUNTER(NAME,VERBOSE,OTHER,UNITS,TYPE) \ + if (verbose || !VERBOSE || (VERBOSE == 1 && statistics->NAME)) \ + PRINT_STAT (#NAME, statistics->NAME, OTHER(NAME), UNITS, TYPE); +#define IGNORE(...) + + METRICS_COUNTERS_AND_STATISTICS + +#undef COUNTER +#undef METRIC +#undef STATISTIC + + fflush (stdout); +} + +// clang-format on + +#elif defined(NDEBUG) +int kissat_statistics_dummy_to_avoid_warning; +#endif + +/*------------------------------------------------------------------------*/ + +#ifndef NDEBUG + +#include "inlinevector.h" + +void kissat_check_statistics (kissat *solver) { + if (solver->inconsistent) + return; + + size_t redundant = 0; + size_t irredundant = 0; + size_t arena_garbage = 0; + + for (all_clauses (c)) { + if (c->garbage) { + arena_garbage += kissat_actual_bytes_of_clause (c); + continue; + } + if (c->redundant) + redundant++; + else + irredundant++; + } + + size_t binary = 0; + + if (solver->watching) { + for (all_literals (lit)) { + watches *watches = &WATCHES (lit); + + for (all_binary_blocking_watches (watch, *watches)) { + if (watch.type.binary) { + binary++; + } + } + } + } else { + for (all_literals (lit)) { + watches *watches = &WATCHES (lit); + + for (all_binary_large_watches (watch, *watches)) { + if (watch.type.binary) { + binary++; + } + } + } + } + + assert (!(binary & 1)); + binary /= 2; + + statistics *statistics = &solver->statistics; + assert (statistics->clauses_binary == binary); + assert (statistics->clauses_redundant == redundant); + assert (statistics->clauses_irredundant == irredundant); +#ifdef METRICS + assert (statistics->arena_garbage == arena_garbage); +#else + (void) arena_garbage; +#endif +} + +#endif diff --git a/src/sat/kissat/statistics.h b/src/sat/kissat/statistics.h new file mode 100644 index 000000000..8c04f4d33 --- /dev/null +++ b/src/sat/kissat/statistics.h @@ -0,0 +1,467 @@ +#ifndef _statistics_h_INCLUDED +#define _statistics_h_INCLUDED + +#include +#include + +// clang-format off + +#define METRICS_COUNTERS_AND_STATISTICS \ +\ + METRIC (allocated_collected, 2, PCNT_RESIDENT_SET, "%", "resident set") \ + METRIC (allocated_current, 2, PCNT_RESIDENT_SET, "%", "resident set") \ + METRIC (allocated_max, 2, PCNT_RESIDENT_SET, "%", "resident set") \ + STATISTIC (ands_eliminated, 1, PCNT_ELIMINATED, "%", "eliminated") \ + METRIC (ands_extracted, 1, PCNT_EXTRACTED, "%", "extracted") \ + METRIC (arena_enlarged, 1, PCNT_ARENA_RESIZED, "%", "resize") \ + METRIC (arena_garbage, 1, PCNT_RESIDENT_SET, "%", "resident set") \ + METRIC (arena_resized, 1, CONF_INT, "", "interval") \ + METRIC (arena_shrunken, 1, PCNT_ARENA_RESIZED, "%", "resize") \ + COUNTER (backbone_computations, 2, CONF_INT, "", "interval") \ + METRIC (backbone_implied, 1, PER_BACKBONE_UNIT, 0, "per unit") \ + METRIC (backbone_probes, 2, PER_VARIABLE, "", "per variable") \ + METRIC (backbone_propagations, 2, PCNT_PROPS, "%", "propagations") \ + METRIC (backbone_rounds, 2, PER_BACKBONE, 0, "per backbone") \ + COUNTER (backbone_ticks, 2, PCNT_TICKS, "%", "ticks") \ + STATISTIC (backbone_units, 1, PCNT_VARIABLES, "%", "variables") \ + METRIC (best_saved, 1, CONF_INT, "", "interval") \ + COUNTER (chronological, 1, PCNT_CONFLICTS, "%", "conflicts") \ + COUNTER (clauses_added, 2, PCNT_CLS_ADDED, "%", "added") \ + COUNTER (clauses_binary, 2, PCNT_CLS_ADDED, "%", "added") \ + STATISTIC (clauses_deleted, 1, PCNT_CLS_ADDED, "%", "added") \ + STATISTIC (clauses_factored, 1, PCNT_CLS_ADDED, "%", "added") \ + STATISTIC (clauses_improved, 1, PCNT_CLS_LEARNED, "%", "learned") \ + COUNTER (clauses_irredundant, 2, PCNT_CLS_ADDED, "%", "added") \ + STATISTIC (clauses_kept1, 1, PCNT_CLS_IMPROVED, "%", "improved") \ + STATISTIC (clauses_kept2, 1, PCNT_CLS_IMPROVED, "%", "improved") \ + STATISTIC (clauses_kept3, 1, PCNT_CLS_IMPROVED, "%", "improved") \ + COUNTER (clauses_learned, 2, PCNT_CONFLICTS, "%", "conflicts") \ + COUNTER (clauses_original, 2, PCNT_CLS_ADDED, "%", "added") \ + STATISTIC (clauses_promoted1, 1, PCNT_CLS_IMPROVED, "%", "improved") \ + STATISTIC (clauses_promoted2, 1, PCNT_CLS_IMPROVED, "%", "improved") \ + STATISTIC (clauses_reduced, 1, PCNT_CLS_LEARNED, "%", "learned") \ + STATISTIC (clauses_reduced_tier1, 1, PCNT_CLS_REDUCED, "%", "reduced") \ + STATISTIC (clauses_reduced_tier2, 1, PCNT_CLS_REDUCED, "%", "reduced") \ + STATISTIC (clauses_reduced_tier3, 1, PCNT_CLS_REDUCED, "%", "reduced") \ + COUNTER (clauses_redundant, 2, NO_SECONDARY, 0, 0) \ + STATISTIC (clauses_unfactored, 1, PCNT_CLS_FACTORED, "%", "factored") \ + COUNTER (clauses_used, 2, PCNT_CLS_LEARNED, "%", "learned") \ + COUNTER (clauses_used_focused, 2, PCNT_CLS_USED, "%", "used") \ + COUNTER (clauses_used_stable, 2, PCNT_CLS_USED, "%", "used") \ + COUNTER (closures, 2, CONF_INT, "", "interval") \ + METRIC (compacted, 1, PCNT_REDUCTIONS, "%", "reductions") \ + COUNTER (conflicts, 0, PER_SECOND, 0, "per second") \ + COUNTER (congruent, 1, PCNT_VARIABLES, "%", "variables") \ + STATISTIC (congruent_ands, 1, PCNT_CONGRUENT, "%", "congruent") \ + STATISTIC (congruent_arity, 1, PER_CONGRGATES, 0, "per gate") \ + STATISTIC (congruent_arity_ands, 1, PER_CONGRANDS, 0, "per AND") \ + STATISTIC (congruent_arity_xors, 1, PER_CONGRXORS, 0, "per XOR") \ + STATISTIC (congruent_binaries, 1, PCNT_CLS_ADDED, "%", "clauses added") \ + STATISTIC (congruent_ites, 1, PCNT_CONGRUENT, "%", "congruent") \ + STATISTIC (congruent_collisions, 1, PER_CONGRLOOKUP, 0, "per lookup") \ + STATISTIC (congruent_collisions_find, 1, PCNT_CONGRCOLS, "%", "collisions") \ + STATISTIC (congruent_collisions_index, 1, PCNT_CONGRCOLS, "%", "collisions") \ + STATISTIC (congruent_collisions_removed, 1, PCNT_CONGRCOLS, "%", "collisions") \ + STATISTIC (congruent_equivalences, 1, PCNT_CONGRUENT, "%", "congruent") \ + COUNTER (congruent_gates, 2, PER_CLOSURE, 0, "per closure") \ + COUNTER (congruent_gates_ands, 2, PCNT_CONGRGATES, "%", "gates") \ + COUNTER (congruent_gates_ites, 2, PCNT_CONGRGATES, "%", "gates") \ + COUNTER (congruent_gates_xors, 2, PCNT_CONGRGATES, "%", "gates") \ + STATISTIC (congruent_indexed, 1, PER_CONGRGATES, 0, "per gate") \ + STATISTIC (congruent_lookups, 1, PER_CONGRGATES, 0, "per gate") \ + STATISTIC (congruent_lookups_find, 1, PCNT_CONGRLOOKUP, "%", "lookups") \ + STATISTIC (congruent_lookups_removed, 1, PCNT_CONGRLOOKUP, "%", "lookups") \ + COUNTER (congruent_matched, 2, PCNT_CONGRUENT, "%", "congruent") \ + COUNTER (congruent_matched_ands, 2, PCNT_CONGRMATCHED, "%", "matched") \ + COUNTER (congruent_matched_ites, 2, PCNT_CONGRMATCHED, "%", "matched") \ + COUNTER (congruent_matched_xors, 2, PCNT_CONGRMATCHED, "%", "matched") \ + STATISTIC (congruent_rewritten, 1, PCNT_CONGRGATES, "%", "gates") \ + STATISTIC (congruent_rewritten_ands, 1, PCNT_CONGREWR, "%", "rewritten") \ + STATISTIC (congruent_rewritten_ites, 1, PCNT_CONGREWR, "%", "rewritten") \ + STATISTIC (congruent_rewritten_xors, 1, PCNT_CONGREWR, "%", "rewritten") \ + STATISTIC (congruent_simplified, 1, PCNT_CONGRGATES, "%", "gates") \ + STATISTIC (congruent_simplified_ands, 1, PCNT_CONGRSIMPS, "%", "simplified") \ + STATISTIC (congruent_simplified_ites, 1, PCNT_CONGRSIMPS, "%", "simplified") \ + STATISTIC (congruent_simplified_xors, 1, PCNT_CONGRSIMPS, "%", "simplified") \ + STATISTIC (congruent_subsumed, 1, PCNT_CLS_ORIGINAL, "%", "original") \ + STATISTIC (congruent_trivial_ite, 1, PCNT_CONGRUENT, "%", "congruent") \ + STATISTIC (congruent_unary, 1, PCNT_CONGRUENT, "%", "congruent") \ + STATISTIC (congruent_unary_ands, 1, PCNT_CONGRUNARY, "%", "unary") \ + STATISTIC (congruent_unary_ites, 1, PCNT_CONGRUNARY, "%", "unary") \ + STATISTIC (congruent_unary_xors, 1, PCNT_CONGRUNARY, "%", "unary") \ + STATISTIC (congruent_units, 1, PCNT_VARIABLES, "%", "variables") \ + STATISTIC (congruent_xors, 1, PCNT_CONGRUENT, "%", "congruent") \ + COUNTER (decisions, 0, PER_CONFLICT, 0, "per conflict") \ + METRIC (definitions_checked, 1, PCNT_ELIM_ATTEMPTS, "%", "attempts") \ + STATISTIC (definitions_eliminated, 1, PCNT_ELIMINATED, "%", "eliminated") \ + METRIC (definitions_extracted, 1, PCNT_EXTRACTED, "%", "extracted") \ + STATISTIC (definition_units, 1, PCNT_VARIABLES, "%", "variables") \ + METRIC (defragmentations, 1, CONF_INT, "", "interval") \ + METRIC (dense_garbage_collections, 2, PCNT_COLLECTIONS, "%", "collections") \ + METRIC (dense_propagations, 1, PCNT_PROPS, "%", "propagations") \ + METRIC (dense_ticks, 1, PCNT_TICKS, "%", "ticks") \ + METRIC (duplicated, 1, PCNT_CLS_ADDED, "%", "added") \ + STATISTIC (eagerly_subsumed, 1, PCNT_CLS_LEARNED, "%", "learned") \ + STATISTIC (eliminate_attempted, 1, PER_VARIABLE, 0, "per variable") \ + COUNTER (eliminated, 1, PCNT_VARIABLES, "%", "variables") \ + COUNTER (eliminate_resolutions, 2, PER_SECOND, 0, "per second") \ + STATISTIC (eliminate_units, 1, PCNT_VARIABLES, "%", "variables") \ + COUNTER (eliminations, 2, CONF_INT, "", "interval") \ + STATISTIC (equivalences_eliminated, 1, PCNT_ELIMINATED, "%", "eliminated") \ + METRIC (equivalences_extracted, 1, PCNT_EXTRACTED, "%", "extracted") \ + METRIC (extensions, 1, PCNT_SEARCHES, "%", "searches") \ + COUNTER (factored, 1, PCNT_VARIABLES, "%", "variables") \ + COUNTER (factorizations, 2, CONF_INT, "", "interval") \ + COUNTER (factor_ticks, 2, PCNT_TICKS, "%", "ticks") \ + COUNTER (fast_eliminated, 1, PCNT_ELIMINATED, "%", "eliminated") \ + COUNTER (fast_strengthened, 1, PCNT_STRENGTHENED, "%", "per strengthened") \ + COUNTER (fast_subsumed, 1, PCNT_SUBSUMED, "%", "per subsumed") \ + STATISTIC (fresh, 1, PCNT_VARIABLES, "%", "variables") \ + STATISTIC (flipped, 1, PER_WALKS, 0, "per walk") \ + METRIC (flushed, 2, PER_FIXED, 0, "per fixed") \ + METRIC (focused_decisions, 1, PCNT_DECISIONS, "%", "decisions") \ + METRIC (focused_modes, 1, CONF_INT, "", "interval") \ + METRIC (focused_propagations, 1, PCNT_PROPS, "%", "propagations") \ + METRIC (focused_restarts, 1, PCNT_RESTARTS, "%", "restarts") \ + METRIC (focused_ticks, 1, PCNT_TICKS, "%", "ticks") \ + COUNTER (forward_checks, 2, NO_SECONDARY, 0, 0) \ + COUNTER (forward_steps, 2, PER_FORWARD_CHECK, 0, "per check") \ + STATISTIC (forward_strengthened, 1, PCNT_STRENGTHENED, "%", "per strengthened") \ + STATISTIC (forward_subsumed, 1, PCNT_SUBSUMED, "%", "per subsumed") \ + METRIC (forward_subsumptions, 1, CONF_INT, "", "interval") \ + METRIC (garbage_collections, 2, CONF_INT, "", "interval") \ + METRIC (gates_checked, 1, PCNT_ELIM_ATTEMPTS, "%", "attempts") \ + STATISTIC (gates_eliminated, 1, PCNT_ELIMINATED, "%", "eliminated") \ + METRIC (gates_extracted, 1, PCNT_ELIM_ATTEMPTS, "%", "attempts") \ + STATISTIC (if_then_else_eliminated, 1, PCNT_ELIMINATED, "%", "eliminated") \ + METRIC (if_then_else_extracted, 1, PCNT_EXTRACTED, "%", "extracted") \ + METRIC (initial_decisions, 1, PCNT_DECISIONS, "%", "decisions") \ + COUNTER (iterations, 1, PCNT_VARIABLES, "%", "variables") \ + STATISTIC (jumped_reasons, 1, PCNT_PROPS, "%", "propagations") \ + STATISTIC (kitten_conflicts, 1, PER_KITTEN_SOLVED, 0, "per solved") \ + STATISTIC (kitten_decisions, 1, PER_KITTEN_SOLVED, 0, "per solved") \ + STATISTIC (kitten_flip, 1, NO_SECONDARY, 0, 0) \ + STATISTIC (kitten_flipped, 1, PCNT_KITTEN_FLIP, "%", "flip") \ + COUNTER (kitten_propagations, 2, PER_KITTEN_SOLVED, 0, "per solved") \ + STATISTIC (kitten_sat, 1, PCNT_KITTEN_SOLVED, "%", "solved") \ + COUNTER (kitten_solved, 2, NO_SECONDARY, 0, 0) \ + COUNTER (kitten_ticks, 2, PER_KITTEN_PROP, 0, "per prop") \ + STATISTIC (kitten_unknown, 1, PCNT_KITTEN_SOLVED, "%", "solved") \ + STATISTIC (kitten_unsat, 1, PCNT_KITTEN_SOLVED, "%", "solved") \ + METRIC (literals_bumped, 1, PER_CLS_LEARNED, 0, "per clause") \ + METRIC (literals_deduced, 1, PER_CLS_LEARNED, 0, "per clause") \ + COUNTER (literals_factor, 2, PER_VARIABLE, 0, "per variable") \ + STATISTIC (literals_factored, 1, PER_CLS_FACTORED, 0, "per factored") \ + METRIC (literals_learned, 1, PER_CLS_LEARNED, 0, "per clause") \ + METRIC (literals_minimized, 1, PCNT_LITS_DEDUCED, "%", "deduced") \ + METRIC (literals_minshrunken, 1, PCNT_LITS_SHRUNKEN, "%", "shrunken") \ + METRIC (literals_shrunken, 1, PCNT_LITS_DEDUCED, "%", "deduced") \ + STATISTIC (literals_unfactored, 2, PER_CLS_UNFACTORED, 0, "per unfactored") \ + METRIC (moved, 1, PCNT_REDUCTIONS, "%", "reductions") \ + STATISTIC (on_the_fly_strengthened, 1, PCNT_CONFLICTS, "%", "of conflicts") \ + STATISTIC (on_the_fly_subsumed, 1, PCNT_CONFLICTS, "%", "of conflicts") \ + METRIC (probing_propagations, 1, PCNT_PROPS, "%", "propagations") \ + COUNTER (probings, 2, CONF_INT, "", "interval") \ + COUNTER (probing_ticks, 2, PCNT_TICKS, "%", "ticks") \ + COUNTER (propagations, 0, PER_SECOND, "", "per second") \ + STATISTIC (queue_decisions, 1, PCNT_DECISIONS, "%", "decision") \ + STATISTIC (random_decisions, 1, PCNT_DECISIONS, "%", "decision") \ + COUNTER (random_sequences, 2, CONF_INT, "", "interval") \ + COUNTER (reductions, 1, CONF_INT, "", "interval") \ + COUNTER (reordered, 1, CONF_INT, "", "interval") \ + STATISTIC (reordered_focused, 1, PCNT_REORDERED, "%", "reordered") \ + STATISTIC (reordered_stable, 1, PCNT_REORDERED, "%", "reordered") \ + COUNTER (rephased, 1, CONF_INT, "", "interval") \ + METRIC (rephased_best, 1, PCNT_REPHASED, "%", "rephased") \ + METRIC (rephased_inverted, 1, PCNT_REPHASED, "%", "rephased") \ + METRIC (rephased_original, 1, PCNT_REPHASED, "%", "rephased") \ + METRIC (rephased_walking, 1, PCNT_REPHASED, "%", "rephased") \ + METRIC (rescaled, 2, CONF_INT, "", "interval") \ + COUNTER (restarts, 1, CONF_INT, "", "interval") \ + STATISTIC (restarts_levels, 1, PER_RESTART, 0, "per restart") \ + STATISTIC (restarts_reused_levels, 1, PCNT_RESTARTS_LEVELS, "%", "levels") \ + STATISTIC (restarts_reused_trails, 1, PCNT_RESTARTS, "%", "restarts") \ + COUNTER (retiered, 2, CONF_INT, "", "interval") \ + METRIC (saved_decisions, 1, PCNT_DECISIONS, "%", "decisions") \ + METRIC (score_decisions, 0, PCNT_DECISIONS, "%", "decision") \ + COUNTER (searches, 2, CONF_INT, "", "interval") \ + METRIC (search_propagations, 2, PCNT_PROPS, "%", "propagations") \ + COUNTER (search_ticks, 2, PCNT_TICKS, "%", "ticks") \ + METRIC (sparse_gcs, 2, PCNT_COLLECTIONS, "%", "collections") \ + METRIC (stable_decisions, 1, PCNT_DECISIONS, "%", "decisions") \ + METRIC (stable_modes, 2, CONF_INT, "", "interval") \ + METRIC (stable_propagations, 1, PCNT_PROPS, "%", "propagations") \ + METRIC (stable_restarts, 1, PCNT_RESTARTS, "%", "restarts") \ + METRIC (stable_ticks, 2, PCNT_TICKS, "%", "ticks") \ + COUNTER (strengthened, 1, PCNT_SUBSUMPTION_CHECK, "%", "checks") \ + COUNTER (substituted, 1, PCNT_VARIABLES, "%", "variables") \ + COUNTER (substitute_ticks, 2, PCNT_TICKS, "%", "ticks") \ + STATISTIC (substitute_units, 1, PCNT_VARIABLES, "%", "variables") \ + STATISTIC (substitutions, 2, CONF_INT, "", "interval") \ + COUNTER (subsumed, 1, PCNT_SUBSUMPTION_CHECK, "%", "checks") \ + COUNTER (subsumption_checks, 2, NO_SECONDARY, 0, 0) \ + COUNTER (sweep, 2, CONF_INT, "", "interval") \ + STATISTIC (sweep_clauses, 1, PER_SWEEP_VARIABLES, 0, "per sweep_variables") \ + COUNTER (sweep_completed, 2, SWEEPS_PER_COMPLETED, 0, "sweeps") \ + STATISTIC (sweep_depth, 1, PER_SWEEP_VARIABLES, 0, "per sweep_variables") \ + STATISTIC (sweep_environment, 1, PER_SWEEP_VARIABLES, 0, "per sweep_variables") \ + COUNTER (sweep_equivalences, 2, PCNT_VARIABLES, "%", "variables") \ + STATISTIC (sweep_fixed_backbone, 1, PER_SWEEP_VARIABLES, 0, "per sweep_variables") \ + STATISTIC (sweep_flip_backbone, 1, PER_SWEEP_VARIABLES, 0, "per sweep_variables") \ + STATISTIC (sweep_flipped_backbone, 1, PCNT_SWEEP_FLIP_BACKBONE, "%", "sweep_flip_backbone") \ + STATISTIC (sweep_flip_equivalences, 1, PER_SWEEP_VARIABLES, 0, "per sweep_variables") \ + STATISTIC (sweep_flipped_equivalences, 1, PCNT_SWEEP_FLIP_EQUIVALENCES, "%", "sweep_flip_equivalences") \ + STATISTIC (sweep_sat, 1, PCNT_SWEEP_SOLVED, "%", "sweep_solved") \ + STATISTIC (sweep_sat_backbone, 1, PCNT_SWEEP_SOLVED_BACKBONE, "%", "sweep_solved_backbone") \ + STATISTIC (sweep_sat_equivalences, 1, PCNT_SWEEP_SOLVED_EQUIVALENCES, "%", "sweep_solved_equivalences") \ + COUNTER (sweep_solved, 2, PCNT_KITTEN_SOLVED, "%", "kitten_solved") \ + STATISTIC (sweep_solved_backbone, 1, PCNT_SWEEP_SOLVED, "%", "sweep_solved") \ + STATISTIC (sweep_solved_equivalences, 1, PCNT_SWEEP_SOLVED, "%", "sweep_solved") \ + STATISTIC (sweep_unknown_backbone, 1, PCNT_SWEEP_SOLVED_BACKBONE, "%", "sweep_solved_backbone") \ + STATISTIC (sweep_unknown_equivalences, 1, PCNT_SWEEP_SOLVED_EQUIVALENCES, "%", "sweep_solved_equivalences") \ + COUNTER (sweep_units, 2, PCNT_VARIABLES, "%", "variables") \ + STATISTIC (sweep_unsat, 1, PCNT_SWEEP_SOLVED, "%", "sweep_solved") \ + STATISTIC (sweep_unsat_backbone, 1, PCNT_SWEEP_SOLVED_BACKBONE, "%", "sweep_solve_backbone") \ + STATISTIC (sweep_unsat_equivalences, 1, PCNT_SWEEP_SOLVED_EQUIVALENCES, "%", "sweep_solve_equivalences") \ + STATISTIC (sweep_variables, 1, PCNT_VARIABLES, "%", "variables") \ + COUNTER (switched, 0, CONF_INT, "", "interval") \ + METRIC (target_decisions, 1, PCNT_DECISIONS, "%", "decisions") \ + METRIC (target_saved, 1, CONF_INT, "", "interval") \ + STATISTIC (ticks, 2, PER_PROPAGATION, 0, "per prop") \ + METRIC (transitive_probes, 2, PER_VARIABLE, "", "per variable") \ + METRIC (transitive_propagations, 2, PCNT_PROPS, "%", "propagations") \ + METRIC (transitive_reduced, 1, PCNT_CLS_ADDED, "%", "added") \ + METRIC (transitive_reductions, 1, CONF_INT, "", "interval") \ + COUNTER (transitive_ticks, 2, PCNT_TICKS, "%", "ticks") \ + METRIC (transitive_units, 1, PCNT_VARIABLES, "%", "variables") \ + COUNTER (units, 2, PCNT_VARIABLES, "%", "variables") \ + COUNTER (variables_activated, 2, PER_VARIABLE, 0, "per variable") \ + COUNTER (variables_eliminate, 2, PER_VARIABLE, 0, "variables") \ + COUNTER (variables_extension, 2, PER_VARIABLE, 0, "per variable") \ + COUNTER (variables_factor, 2, PER_VARIABLE, 0, "per variable") \ + COUNTER (variables_original, 2, PER_VARIABLE, 0, "per variable") \ + COUNTER (variables_subsume, 2, PER_VARIABLE, 0, "per variable") \ + METRIC (vectors_defrags_needed, 1, PCNT_DEFRAGS, "%", "defrags") \ + METRIC (vectors_enlarged, 2, CONF_INT, "", "interval") \ + COUNTER (vivifications, 2, CONF_INT, "", "interval") \ + COUNTER (vivified, 1, PCNT_VIVIFY_CHECK, "%", "checks") \ + STATISTIC (vivified_asym, 1, PCNT_VIVIFIED, "%", "vivified") \ + STATISTIC (vivified_implied, 1, PCNT_VIVIFIED, "%", "vivified") \ + STATISTIC (vivified_instantiated, 1, PCNT_VIVIFIED, "%", "vivified") \ + STATISTIC (vivified_instirr, 1, PCNT_VIVIFY_INST, "%", "instantiated") \ + STATISTIC (vivified_instred, 1, PCNT_VIVIFY_INST, "%", "instantiated") \ + STATISTIC (vivified_irredundant, 1, PCNT_VIVIFIED, "%", "vivified") \ + STATISTIC (vivified_promoted, 1, PCNT_VIVIFIED, "%", "vivified") \ + STATISTIC (vivified_shrunken, 1, PCNT_VIVIFIED, "%", "vivified") \ + STATISTIC (vivified_shrunkirr, 1, PCNT_VIVIFY_SHRUNKEN, "%", "shrunken") \ + STATISTIC (vivified_shrunkred, 1, PCNT_VIVIFY_SHRUNKEN, "%", "shrunken") \ + STATISTIC (vivified_subirr, 1, PCNT_VIVIFY_SUB, "%", "subsumed") \ + STATISTIC (vivified_subred, 1, PCNT_VIVIFY_SUB, "%", "subsumed") \ + STATISTIC (vivified_subsumed, 1, PCNT_VIVIFIED, "%", "vivified") \ + STATISTIC (vivified_tier1, 1, PCNT_VIVIFIED, "%", "vivified") \ + STATISTIC (vivified_tier2, 1, PCNT_VIVIFIED, "%", "vivified") \ + STATISTIC (vivified_tier3, 1, PCNT_VIVIFIED, "%", "vivified") \ + STATISTIC (vivified_unlearn, 1, PCNT_VIVIFIED, "%", "vivified") \ + COUNTER (vivify_checks, 2, PER_VIVIFICATION, "", "per vivify") \ + COUNTER (vivify_probes, 2, PER_VIVIFY_CHECK, 0, "per check") \ + STATISTIC (vivify_propagations, 2, PCNT_PROPS, "%", "propagations") \ + COUNTER (vivify_reused, 2, PCNT_VIVIFY_PROBES, "%", "probes") \ + STATISTIC (vivify_ticks, 2, PCNT_TICKS, "%", "ticks") \ + STATISTIC (vivify_units, 1, PCNT_VARIABLES, "%", "variables") \ + METRIC (walk_decisions, 1, PCNT_WALKS, "%", "walks") \ + STATISTIC (walk_improved, 1, PCNT_WALKS, "%", "walks") \ + METRIC (walk_previous, 1, PCNT_WALKS, "%", "walks") \ + COUNTER (walks, 1, CONF_INT, "", "interval") \ + COUNTER (walk_steps, 2, PER_FLIPPED, 0, "per flipped") \ + STATISTIC (warming_conflicts, 1, PER_WALKS, 0, "per walk") \ + COUNTER (warming_decisions, 2, PER_WALKS, 0, "per walk") \ + COUNTER (warming_propagations, 2, PCNT_PROPS, "%", "propagations") \ + COUNTER (warmups, 2, PCNT_WALKS, "%", "walks") \ + METRIC (weakened, 1, PCNT_CLS_ADDED, "%", "added") + +// clang-format on + +/*------------------------------------------------------------------------*/ +#ifdef METRICS + +#define METRIC COUNTER +#define STATISTIC COUNTER + +#ifndef STATISTICS +#define STATISTICS +#endif + +#elif STATISTICS + +#define METRIC IGNORE +#define STATISTIC COUNTER + +#else + +#define METRIC IGNORE +#define STATISTIC IGNORE + +#endif +/*------------------------------------------------------------------------*/ +// clang-format off + +typedef struct statistics statistics; + +#define MAX_GLUE_USED 127 + +struct statistics +{ +#define COUNTER(NAME,VERBOSE,OTHER,UNITS,TYPE) \ + uint64_t NAME; +#define IGNORE(...) + + METRICS_COUNTERS_AND_STATISTICS + +#undef COUNTER +#undef IGNORE + + struct { + uint64_t glue[MAX_GLUE_USED + 1]; + } used[2]; +}; + +// clang-format on +/*------------------------------------------------------------------------*/ + +#define CLAUSES (IRREDUNDANT_CLAUSES + BINARY_CLAUSES + REDUNDANT_CLAUSES) +#define CONFLICTS (solver->statistics.conflicts) +#define DECISIONS (solver->statistics.decisions) +#define IRREDUNDANT_CLAUSES (solver->statistics.clauses_irredundant) +#define LEARNED_CLAUSES (solver->statistics.learned) +#define REDUNDANT_CLAUSES (solver->statistics.clauses_redundant) +#define BINARY_CLAUSES (solver->statistics.clauses_binary) +#define BINIRR_CLAUSES (BINARY_CLAUSES + IRREDUNDANT_CLAUSES) + +/*------------------------------------------------------------------------*/ + +#define COUNTER(NAME, VERBOSE, OTHER, UNITS, TYPE) \ +\ + static inline void kissat_inc_##NAME (statistics *statistics) { \ + assert (statistics->NAME < UINT64_MAX); \ + statistics->NAME++; \ + } \ +\ + static inline void kissat_dec_##NAME (statistics *statistics) { \ + assert (statistics->NAME); \ + statistics->NAME--; \ + } \ +\ + static inline void kissat_add_##NAME (statistics *statistics, \ + uint64_t n) { \ + assert (UINT64_MAX - n >= statistics->NAME); \ + statistics->NAME += n; \ + } \ +\ + static inline void kissat_sub_##NAME (statistics *statistics, \ + uint64_t n) { \ + assert (n <= statistics->NAME); \ + statistics->NAME -= n; \ + } \ +\ + static inline uint64_t kissat_get_##NAME (statistics *statistics) { \ + return statistics->NAME; \ + } + +/*------------------------------------------------------------------------*/ + +#define IGNORE(NAME, VERBOSE, OTHER, UNITS, TYPE) \ +\ + static inline void kissat_inc_##NAME (statistics *statistics) { \ + (void) statistics; \ + } \ +\ + static inline void kissat_dec_##NAME (statistics *statistics) { \ + (void) statistics; \ + } \ +\ + static inline void kissat_add_##NAME (statistics *statistics, \ + uint64_t n) { \ + (void) statistics; \ + (void) n; \ + } \ +\ + static inline void kissat_sub_##NAME (statistics *statistics, \ + uint64_t n) { \ + (void) statistics; \ + (void) n; \ + } \ + static inline uint64_t kissat_get_##NAME (statistics *statistics) { \ + (void) statistics; \ + return UINT64_MAX; \ + } + +/*------------------------------------------------------------------------*/ +// clang-format off + +METRICS_COUNTERS_AND_STATISTICS + +#undef COUNTER +#undef IGNORE + +// clang-format on +/*------------------------------------------------------------------------*/ + +#define INC(NAME) kissat_inc_##NAME (&solver->statistics) +#define DEC(NAME) kissat_dec_##NAME (&solver->statistics) +#define ADD(NAME, N) kissat_add_##NAME (&solver->statistics, (N)) +#define SUB(NAME, N) kissat_sub_##NAME (&solver->statistics, (N)) +#define GET(NAME) kissat_get_##NAME (&solver->statistics) + +/*------------------------------------------------------------------------*/ +#ifndef QUIET + +struct kissat; + +void kissat_statistics_print (struct kissat *, bool verbose); +void kissat_print_glue_usage (struct kissat *); + +// Format widths of individual parts during printing statistics lines. +// Shared between 'statistics.c' and 'resources.c' to align the printing. + +#define SFW1 "30" +#define SFW2 "12" +#define SFW3 "5" +#define SFW4 "10" + +#define SFW34 "16" // SFE3 + space + SFE 4 +#define SFW34EXTENDED "19" // SFE3 + space + SFE 4 + ".2" + +#define PRINT_STAT(NAME, PRIMARY, SECONDARY, UNITS, TYPE) \ + do { \ + printf ("%s%-" SFW1 "s %" SFW2 PRIu64 " ", solver->prefix, NAME ":", \ + (uint64_t) PRIMARY); \ + const double SAVED_SECONDARY = (double) (SECONDARY); \ + const char *SAVED_UNITS = (const char *) (UNITS); \ + const char *SAVED_TYPE = (const char *) (TYPE); \ + if (SAVED_TYPE && SAVED_SECONDARY >= 0) { \ + if (SAVED_UNITS) \ + printf ("%" SFW34 ".0f %-2s", SAVED_SECONDARY, SAVED_UNITS); \ + else \ + printf ("%" SFW34EXTENDED ".2f", SAVED_SECONDARY); \ + fputc (' ', stdout); \ + fputs (SAVED_TYPE, stdout); \ + } \ + fputc ('\n', stdout); \ + } while (0) + +#endif + +#ifndef NDEBUG + +struct kissat; +void kissat_check_statistics (struct kissat *); + +#else + +#define kissat_check_statistics(...) \ + do { \ + } while (0) + +#endif + +#endif diff --git a/src/sat/kissat/strengthen.c b/src/sat/kissat/strengthen.c new file mode 100644 index 000000000..d5107d7f5 --- /dev/null +++ b/src/sat/kissat/strengthen.c @@ -0,0 +1,187 @@ +#include "strengthen.h" +#include "collect.h" +#include "inline.h" +#include "promote.h" + +static clause *large_on_the_fly_strengthen (kissat *solver, clause *c, + unsigned lit) { + assert (solver->antecedent_size > 3); + LOGCLS (c, + "large on-the-fly strengthening " + "by removing %s from", + LOGLIT (lit)); + unsigned *lits = c->lits; + assert (lits[0] == lit || lits[1] == lit); + INC (on_the_fly_strengthened); +#ifndef NDEBUG + clause *old_next = kissat_next_clause (c); +#endif + if (lits[0] == lit) + SWAP (unsigned, lits[0], lits[1]); + assert (lits[1] == lit); + const reference ref = kissat_reference_clause (solver, c); + kissat_unwatch_blocking (solver, lit, ref); + SHRINK_CLAUSE_IN_PROOF (c, lit, lits[0]); + CHECK_SHRINK_CLAUSE (c, lit, lits[0]); + { + const unsigned old_size = c->size; + unsigned new_size = 1; + const bool irredundant = !c->redundant; + for (unsigned i = 2; i < old_size; i++) { + const unsigned other = lits[i]; + assert (VALUE (other) < 0); + if (!LEVEL (other)) + continue; + lits[new_size++] = other; + if (irredundant) + kissat_mark_added_literal (solver, other); + } + assert (new_size > 2); + c->size = new_size; + c->searched = 2; + if (c->redundant && c->glue >= new_size) + kissat_promote_clause (solver, c, new_size - 1); + if (!c->shrunken) { + c->shrunken = true; + lits[old_size - 1] = INVALID_LIT; + } + } + LOGCLS (c, "unsorted on-the-fly strengthened"); + { + assert (VALUE (lits[1]) < 0); + unsigned highest_pos = 1; + unsigned highest_level = LEVEL (lits[1]); + const unsigned size = c->size; + for (unsigned i = 2; i < size; i++) { + const unsigned other = lits[i]; + assert (VALUE (other) < 0); + const unsigned level = LEVEL (other); + if (level <= highest_level) + continue; + highest_pos = i; + highest_level = level; + } + if (highest_pos != 1) + SWAP (unsigned, lits[1], lits[highest_pos]); + LOGCLS (c, "sorted on-the-fly strengthened"); + kissat_watch_blocking (solver, lits[1], lits[0], ref); + } + { + watches *watches = &WATCHES (lits[0]); +#ifndef NDEBUG + const watch *const end_of_watches = END_WATCHES (*watches); +#endif + watch *p = BEGIN_WATCHES (*watches); + assert (solver->watching); + for (;;) { + assert (p != end_of_watches); + const watch head = *p++; + if (head.type.binary) + continue; + assert (p != end_of_watches); + const watch tail = *p++; + if (tail.large.ref == ref) + break; + } + p[-2].blocking.lit = lits[1]; + LOGREF (ref, "updating watching %s now blocking %s in", + LOGLIT (lits[0]), LOGLIT (lits[1])); + } +#ifndef NDEBUG + clause *new_next = kissat_next_clause (c); + assert (old_next == new_next); +#endif + LOGCLS (c, "conflicting"); + return c; +} + +static clause *binary_on_the_fly_strengthen (kissat *solver, clause *c, + unsigned lit) { + assert (solver->antecedent_size == 3); + LOGCLS (c, + "binary on-the-fly strengthening " + "by removing %s from", + LOGLIT (lit)); + unsigned first = INVALID_LIT, second = INVALID_LIT; +#ifndef NDEBUG + bool found = false; +#endif + for (all_literals_in_clause (other, c)) { + if (other == lit) { +#ifndef NDEBUG + assert (!found); + found = true; +#endif + continue; + } + assert (VALUE (other) < 0); + if (!LEVEL (other)) + continue; + if (first == INVALID_LIT) + first = other; + else { + assert (second == INVALID_LIT); + second = other; +#ifndef NDEBUG + break; +#endif + } + } + assert (found); + assert (second != INVALID_LIT); + LOGBINARY (first, second, "on-the-fly strengthened"); + kissat_new_binary_clause (solver, first, second); + const reference ref = kissat_reference_clause (solver, c); + kissat_unwatch_blocking (solver, c->lits[0], ref); + kissat_unwatch_blocking (solver, c->lits[1], ref); + kissat_mark_clause_as_garbage (solver, c); + clause *conflict = kissat_binary_conflict (solver, first, second); + return conflict; +} + +clause *kissat_on_the_fly_strengthen (kissat *solver, clause *c, + unsigned lit) { + assert (!c->garbage); + assert (solver->antecedent_size > 2); + if (!c->redundant) + kissat_mark_removed_literal (solver, lit); + clause *res; + if (solver->antecedent_size == 3) + res = binary_on_the_fly_strengthen (solver, c, lit); + else + res = large_on_the_fly_strengthen (solver, c, lit); + return res; +} + +void kissat_on_the_fly_subsume (kissat *solver, clause *c, clause *d) { + LOGCLS (c, "on-the-fly subsuming"); + LOGCLS (d, "on-the-fly subsumed"); + assert (c != d); + assert (!d->garbage); + assert (c->size > 1); + assert (c->size <= d->size); + kissat_mark_clause_as_garbage (solver, d); + INC (on_the_fly_subsumed); + if (d->redundant) { + if (c->redundant && c->glue > d->glue) + kissat_promote_clause (solver, c, d->glue); + return; + } + if (!c->redundant) + return; + if (c->size > 2) { + c->redundant = false; + LOGCLS (c, "turned"); + kissat_update_last_irredundant (solver, c); + } + statistics *statistics = &solver->statistics; + if (c->size > 2) { + assert (statistics->clauses_irredundant < UINT64_MAX); + statistics->clauses_irredundant++; + } else { + assert (statistics->clauses_binary < UINT64_MAX); + statistics->clauses_binary++; + } + assert (statistics->clauses_redundant > 0); + statistics->clauses_redundant--; +} diff --git a/src/sat/kissat/strengthen.h b/src/sat/kissat/strengthen.h new file mode 100644 index 000000000..1e6a395fc --- /dev/null +++ b/src/sat/kissat/strengthen.h @@ -0,0 +1,17 @@ +#ifndef _strengthen_h_INCLUDED +#define _strengthen_h_INCLUDED + +#include + +struct clause; +struct kissat; + +struct clause *kissat_on_the_fly_strengthen (struct kissat *, + struct clause *, unsigned lit); + +void kissat_on_the_fly_subsume (struct kissat *, struct clause *, + struct clause *); + +bool issat_strengthen_clause (struct kissat *, struct clause *, unsigned); + +#endif diff --git a/src/sat/kissat/substitute.c b/src/sat/kissat/substitute.c new file mode 100644 index 000000000..f95efe746 --- /dev/null +++ b/src/sat/kissat/substitute.c @@ -0,0 +1,617 @@ +#include "substitute.h" +#include "allocate.h" +#include "backtrack.h" +#include "inline.h" +#include "print.h" +#include "proprobe.h" +#include "report.h" +#include "terminate.h" +#include "trail.h" +#include "weaken.h" + +#include + +static void assign_and_propagate_units (kissat *solver, unsigneds *units) { + if (EMPTY_STACK (*units)) + return; + LOG ("assigning and propagating %zu units", SIZE_STACK (*units)); + while (!solver->inconsistent && !EMPTY_STACK (*units)) { + const unsigned unit = POP_STACK (*units); + LOG ("trying to assign and propagate unit %s now", LOGLIT (unit)); + const value value = VALUE (unit); + if (value > 0) { + LOG ("skipping satisfied unit %s", LOGLIT (unit)); + } else if (value < 0) { + LOG ("inconsistent unit %s", LOGLIT (unit)); + CHECK_AND_ADD_EMPTY (); + ADD_EMPTY_TO_PROOF (); + solver->inconsistent = true; + } else { + kissat_learned_unit (solver, unit); + INC (substitute_units); + assert (!solver->level); + (void) kissat_probing_propagate (solver, 0, false); + } + } +} + +static void determine_representatives (kissat *solver, unsigned *repr) { + size_t bytes = LITS * sizeof (unsigned); + unsigned *mark = kissat_calloc (solver, LITS, sizeof *mark); + unsigned *reach = kissat_malloc (solver, LITS * sizeof *reach); + watches *all_watches = solver->watches; + const flags *const flags = solver->flags; + unsigned reached = 0; + unsigneds scc; + unsigneds work; + unsigneds units; + INIT_STACK (scc); + INIT_STACK (work); + INIT_STACK (units); +#ifdef LOGGING + unsigned trivial_sccs = 0; + unsigned non_trivial_sccs = 0; +#endif + bool inconsistent = false; + uint64_t ticks = 0; + for (all_literals (root)) { + if (inconsistent) + break; + if (mark[root]) + continue; + if (!ACTIVE (IDX (root))) + continue; + assert (EMPTY_STACK (scc)); + assert (EMPTY_STACK (work)); + LOG ("substitute root %s", LOGLIT (root)); + PUSH_STACK (work, root); + bool failed = false; + const unsigned mark_root = reached + 1; + while (!inconsistent && !EMPTY_STACK (work)) { + unsigned lit = TOP_STACK (work); + if (lit == INVALID_LIT) { + (void) POP_STACK (work); + lit = POP_STACK (work); + const unsigned not_lit = NOT (lit); + unsigned reach_lit = reach[lit]; + unsigned mark_lit = mark[lit]; + assert (reach_lit == mark_lit); + assert (repr[lit] == INVALID_LIT); + watches *watches = all_watches + not_lit; + const size_t size_watches = SIZE_WATCHES (*watches); + ticks += 1 + kissat_cache_lines (size_watches, sizeof (watch)); + for (all_binary_blocking_watches (watch, *watches)) { + if (!watch.type.binary) + continue; + const unsigned other = watch.binary.lit; + const unsigned idx_other = IDX (other); + if (!flags[idx_other].active) + continue; + assert (mark[other]); + unsigned reach_other = reach[other]; + if (reach_other < reach_lit) + reach_lit = reach_other; + } + if (reach_lit != mark_lit) { + LOG ("reach[%s] = %u", LOGLIT (lit), reach_lit); + reach[lit] = reach_lit; + continue; + } + unsigned *end_scc = END_STACK (scc); + unsigned *begin_scc = end_scc; + do + assert (begin_scc != BEGIN_STACK (scc)); + while (*--begin_scc != lit); + SET_END_OF_STACK (scc, begin_scc); + const size_t size_scc = end_scc - begin_scc; + unsigned min_lit = lit; + if (size_scc > 1) { + for (const unsigned *p = begin_scc; p != end_scc; p++) { + const unsigned other = *p; + if (other < min_lit) + min_lit = other; + } +#ifdef LOGGING + non_trivial_sccs++; +#endif + LOG ("size %zu SCC entered trough %s representative %s", size_scc, + LOGLIT (lit), LOGLIT (min_lit)); + } else { +#ifdef LOGGING + trivial_sccs++; +#endif + LOG ("trivial size one SCC with %s", LOGLIT (lit)); + assert (min_lit == lit); + } + for (const unsigned *p = begin_scc; p != end_scc; p++) { + const unsigned other = *p; + LOG ("substitute repr[%s] = %s", LOGLIT (other), + LOGLIT (min_lit)); + repr[other] = min_lit; + reach[other] = UINT_MAX; + + const unsigned not_other = NOT (other); + const unsigned repr_not_other = repr[not_other]; + if (repr_not_other == INVALID_LIT) + continue; + if (min_lit == repr_not_other) { + LOG ("clashing literals %s and %s in same SCC", LOGLIT (other), + LOGLIT (not_other)); + PUSH_STACK (units, min_lit); + inconsistent = true; + break; + } + assert (NOT (min_lit) == repr_not_other); + if (failed) + continue; + const unsigned mark_not_other = mark[not_other]; + assert (mark_not_other != INVALID_LIT); + assert (mark[root] == mark_root); + if (mark_root > mark_not_other) + continue; + LOG ("root %s implies both %s and %s", LOGLIT (root), + LOGLIT (other), LOGLIT (not_other)); + const unsigned unit = NOT (root); + PUSH_STACK (units, unit); + failed = true; + } + if (inconsistent) + break; + } else if (!mark[lit]) { + PUSH_STACK (work, INVALID_LIT); + PUSH_STACK (scc, lit); + mark[lit] = reach[lit] = ++reached; + LOG ("substitute mark[%s] = %u", LOGLIT (lit), reached); + const unsigned not_lit = NOT (lit); + watches *watches = all_watches + not_lit; + const size_t size_watches = SIZE_WATCHES (*watches); + ticks += 1 + kissat_cache_lines (size_watches, sizeof (watch)); + for (all_binary_blocking_watches (watch, *watches)) { + if (!watch.type.binary) + continue; + const unsigned other = watch.binary.lit; + const unsigned idx_other = IDX (other); + if (!flags[idx_other].active) + continue; + if (!mark[other]) + PUSH_STACK (work, other); + } + } else + (void) POP_STACK (work); + } + } + RELEASE_STACK (work); + RELEASE_STACK (scc); + kissat_extremely_verbose (solver, + "determining substitution " + "representatives took %" PRIu64 + " 'substitute_ticks'", + ticks); + ADD (substitute_ticks, ticks); + LOG ("reached %u literals", reached); + LOG ("found %u non-trivial SCCs", non_trivial_sccs); + LOG ("found %u trivial SCCs", trivial_sccs); + LOG ("found %zu units", SIZE_STACK (units)); + assign_and_propagate_units (solver, &units); + assert (!inconsistent || solver->inconsistent); + RELEASE_STACK (units); + kissat_free (solver, reach, bytes); + kissat_free (solver, mark, bytes); + for (all_literals (lit)) + if (repr[lit] == INVALID_LIT) + repr[lit] = lit; +} + +static bool *add_representative_equivalences (kissat *solver, + unsigned *repr) { + if (solver->inconsistent) + return 0; + bool *eliminate = kissat_calloc (solver, VARS, sizeof *eliminate); + for (all_variables (idx)) { + if (!ACTIVE (idx)) + continue; + const unsigned lit = LIT (idx); + const unsigned other = repr[lit]; + if (lit == other) + continue; + assert (other < lit); +#ifdef CHECKING_OR_PROVING + const unsigned not_lit = NOT (lit); + const unsigned not_other = NOT (other); + + CHECK_AND_ADD_BINARY (not_lit, other); + ADD_BINARY_TO_PROOF (not_lit, other); + + CHECK_AND_ADD_BINARY (lit, not_other); + ADD_BINARY_TO_PROOF (lit, not_other); +#endif + eliminate[idx] = true; + } + return eliminate; +} + +static void remove_representative_equivalences (kissat *solver, + unsigned *repr, + bool *eliminate) { + if (!solver->inconsistent) { + value *values = solver->values; + const bool incremental = GET_OPTION (incremental); + for (all_variables (idx)) { + if (!eliminate[idx]) + continue; + + assert (ACTIVE (idx)); + + const unsigned lit = LIT (idx); + const unsigned other = repr[lit]; + const unsigned not_lit = NOT (lit); + const unsigned not_other = NOT (other); + assert (other < lit); + assert (not_other < not_lit); + + REMOVE_CHECKER_BINARY (not_lit, other); + DELETE_BINARY_FROM_PROOF (not_lit, other); + + REMOVE_CHECKER_BINARY (lit, not_other); + DELETE_BINARY_FROM_PROOF (lit, not_other); + + INC (substituted); + kissat_mark_eliminated_variable (solver, idx); + const value other_value = values[other]; + if (incremental || other_value) { + if (other_value <= 0) + kissat_weaken_binary (solver, not_lit, other); + if (other_value >= 0) + kissat_weaken_binary (solver, lit, not_other); + } else { + kissat_weaken_binary (solver, not_lit, other); + kissat_weaken_unit (solver, lit); + } + } + } + if (eliminate) + kissat_dealloc (solver, eliminate, VARS, sizeof *eliminate); +} + +static void substitute_binaries (kissat *solver, unsigned *repr) { + if (solver->inconsistent) + return; + assert (sizeof (watch) == sizeof (unsigned)); + statches *delayed_watched = (statches *) &solver->delayed; + watches *all_watches = solver->watches; +#ifdef LOGGING + size_t removed = 0; + size_t substituted = 0; +#endif + unsigneds units; + INIT_STACK (units); + litwatches delayed_deleted; + INIT_STACK (delayed_deleted); +#ifdef CHECKING_OR_PROVING + litpairs delayed_removed; + INIT_STACK (delayed_removed); +#endif + for (all_literals (lit)) { + const unsigned repr_lit = repr[lit]; + const unsigned not_repr_lit = NOT (repr_lit); + assert (EMPTY_STACK (*delayed_watched)); + watches *watches = all_watches + lit; + watch *begin = BEGIN_WATCHES (*watches), *q = begin; + const watch *const end = END_WATCHES (*watches), *p = q; + while (p != end) { + const watch src = *p++; + if (!src.type.binary) + continue; + const unsigned other = src.binary.lit; + const unsigned repr_other = repr[other]; + LOGBINARY (lit, other, "substituting"); + const litwatch litwatch = {lit, src}; + if (repr_other == not_repr_lit) { + LOGBINARY (repr_other, repr_lit, "becomes tautological"); + if (lit < other) { +#ifdef LOGGING + removed++; +#endif + PUSH_STACK (delayed_deleted, litwatch); + } + } else if (repr_other == repr_lit) { + const unsigned unit = repr_lit; + LOG ("simplifies to unit %s", LOGLIT (unit)); + if (lit < other) { +#ifdef LOGGING + removed++; +#endif + PUSH_STACK (units, unit); + PUSH_STACK (delayed_deleted, litwatch); + } + } else { + watch dst = src; + dst.binary.lit = repr_other; + if (lit == repr_lit && other == repr_other) { + LOGBINARY (lit, other, "unchanged"); + *q++ = dst; + } else { + if (lit == repr_lit) { + LOGBINARY (repr_lit, repr_other, "substituted in place"); + *q++ = dst; + } else { + LOGBINARY (repr_lit, repr_other, "delayed substituted"); + PUSH_STACK (*delayed_watched, dst); + } + + if (lit < other) { +#ifdef LOGGING + substituted++; +#endif +#ifdef CHECKING_OR_PROVING + ADD_BINARY_TO_PROOF (repr_lit, repr_other); + CHECK_AND_ADD_BINARY (repr_lit, repr_other); + const litpair litpair = {{lit, other}}; + PUSH_STACK (delayed_removed, litpair); +#endif + } + } + } + } + SET_END_OF_WATCHES (*watches, q); + if (lit == repr_lit) + continue; + watches = all_watches + repr_lit; + for (all_stack (watch, watch, *delayed_watched)) + PUSH_WATCHES (*watches, watch); + CLEAR_STACK (*delayed_watched); + } + assign_and_propagate_units (solver, &units); + RELEASE_STACK (units); + for (all_stack (litwatch, litwatch, delayed_deleted)) { + const unsigned lit = litwatch.lit; + const watch watch = litwatch.watch; + assert (watch.type.binary); + const unsigned other = watch.binary.lit; + kissat_delete_binary (solver, lit, other); + } + RELEASE_STACK (delayed_deleted); +#ifdef CHECKING_OR_PROVING + for (all_stack (litpair, litpair, delayed_removed)) { + const unsigned lit = litpair.lits[0]; + const unsigned other = litpair.lits[1]; + DELETE_BINARY_FROM_PROOF (lit, other); + REMOVE_CHECKER_BINARY (lit, other); + } + RELEASE_STACK (delayed_removed); +#endif + LOG ("substituted %zu binary clauses", substituted); + LOG ("removed %zu binary clauses", removed); +} + +static void substitute_clauses (kissat *solver, unsigned *repr) { + if (solver->inconsistent) + return; + const value *const values = solver->values; + value *marks = solver->marks; +#ifdef LOGGING + size_t substituted = 0; + size_t removed = 0; +#endif + unsigneds units; + INIT_STACK (units); + references delayed_garbage; + INIT_STACK (delayed_garbage); + for (all_clauses (c)) { + if (c->garbage) + continue; + LOGCLS (c, "substituting"); + assert (EMPTY_STACK (solver->clause)); + bool shrink = false; + bool satisfied = false; + bool substitute = false; + bool tautological = false; + for (all_literals_in_clause (lit, c)) { + const value lit_value = values[lit]; + if (lit_value < 0) { + LOG ("dropping falsified %s", LOGLIT (lit)); + shrink = true; + continue; + } + if (lit_value > 0) { + LOGCLS (c, "satisfied by %s", LOGLIT (lit)); + satisfied = true; + break; + } + const unsigned repr_lit = repr[lit]; + const value repr_value = values[repr_lit]; + if (repr_value < 0) { + LOG ("dropping falsified substituted %s (was %s)", + LOGLIT (repr_lit), LOGLIT (lit)); + shrink = true; + continue; + } + if (repr_value > 0) { + LOGCLS (c, "satisfied by substituted %s (was %s)", + LOGLIT (repr_lit), LOGLIT (lit)); + satisfied = true; + break; + } + if (lit != repr_lit) { + assert (!values[repr_lit]); + LOG ("substituted literal %s (was %s)", LOGLIT (repr_lit), + LOGLIT (lit)); + substitute = true; + } else + LOG ("copying literal %s", LOGLIT (lit)); + if (marks[repr_lit]) { + shrink = true; + LOG ("skipping duplicated %s", LOGLIT (repr_lit)); + continue; + } + const unsigned not_repr_lit = NOT (repr_lit); + if (marks[not_repr_lit]) { + LOG ("substituted clause tautological " + "containing both %s and %s", + LOGLIT (not_repr_lit), LOGLIT (repr_lit)); + tautological = true; + break; + } + marks[repr_lit] = true; + PUSH_STACK (solver->clause, repr_lit); + } + if (satisfied || tautological) { + kissat_mark_clause_as_garbage (solver, c); +#ifdef LOGGING + removed++; +#endif + } else if (substitute || shrink) { + const unsigned size = SIZE_STACK (solver->clause); + if (!size) { + LOG ("simplifies to empty clause"); + + CHECK_AND_ADD_EMPTY (); + ADD_EMPTY_TO_PROOF (); + + solver->inconsistent = true; + break; + } else if (size == 1) { + assert (shrink); +#ifdef LOGGING + removed++; +#endif + const unsigned unit = PEEK_STACK (solver->clause, 0); + LOGCLS (c, "simplifies to unit %s", LOGLIT (unit)); + PUSH_STACK (units, unit); + const reference ref = kissat_reference_clause (solver, c); + PUSH_STACK (delayed_garbage, ref); + } else if (size == 2) { + assert (shrink); +#ifdef LOGGING + substituted++; +#endif + const unsigned first = PEEK_STACK (solver->clause, 0); + const unsigned second = PEEK_STACK (solver->clause, 1); + LOGCLS (c, "unsubstituted"); + LOGBINARY (first, second, "substituted"); + kissat_new_binary_clause (solver, first, second); + kissat_mark_clause_as_garbage (solver, c); + } else { +#ifdef LOGGING + substituted++; +#endif + LOGCLS (c, "unsubstituted"); + + const unsigned new_size = SIZE_STACK (solver->clause); + unsigned *new_lits = BEGIN_STACK (solver->clause); + + ADD_LITS_TO_PROOF (new_size, new_lits); + CHECK_AND_ADD_LITS (new_size, new_lits); + + DELETE_CLAUSE_FROM_PROOF (c); + REMOVE_CHECKER_CLAUSE (c); + + const unsigned old_size = c->size; + unsigned *old_lits = c->lits; + + assert (new_size <= old_size); + memcpy (old_lits, new_lits, new_size * sizeof *old_lits); + + assert (shrink == (new_size < old_size)); + if (new_size < old_size) { + c->size = new_size; + c->searched = 2; + if (!c->shrunken) { + c->shrunken = true; + assert (c->lits == old_lits); + old_lits[old_size - 1] = INVALID_LIT; + } + } + LOGCLS (c, "unsorted substituted"); + } + } else + LOGCLS (c, "unchanged"); + for (all_stack (unsigned, lit, solver->clause)) + marks[lit] = 0; + CLEAR_STACK (solver->clause); + } + assign_and_propagate_units (solver, &units); + RELEASE_STACK (units); + for (all_stack (reference, ref, delayed_garbage)) { + clause *c = kissat_dereference_clause (solver, ref); + kissat_mark_clause_as_garbage (solver, c); + } + RELEASE_STACK (delayed_garbage); + LOG ("substituted %zu large clauses", substituted); + LOG ("removed %zu substituted large clauses", removed); +} + +static bool substitute_round (kissat *solver, unsigned round) { + assert (!solver->inconsistent); + const unsigned active = solver->active; + size_t bytes = LITS * sizeof (unsigned); + unsigned *repr = kissat_malloc (solver, bytes); + memset (repr, 0xff, bytes); + determine_representatives (solver, repr); + bool *eliminate = add_representative_equivalences (solver, repr); + substitute_binaries (solver, repr); + substitute_clauses (solver, repr); + remove_representative_equivalences (solver, repr, eliminate); + kissat_dealloc (solver, repr, LITS, sizeof *repr); + unsigned removed = active - solver->active; + kissat_phase (solver, "substitute", GET (substitutions), + "round %u removed %u variables %.0f%%", round, removed, + kissat_percent (removed, active)); + kissat_check_statistics (solver); + REPORT (!removed, 'd'); +#ifdef QUIET + (void) round; +#endif + return !solver->inconsistent && removed; +} + +static void substitute_rounds (kissat *solver, bool complete) { + START (substitute); + INC (substitutions); + const unsigned maxrounds = GET_OPTION (substituterounds); + for (unsigned round = 1; round <= maxrounds; round++) { + const uint64_t before = solver->statistics.substitute_ticks; + if (!substitute_round (solver, round)) + break; + const uint64_t after = solver->statistics.substitute_ticks; + const uint64_t ticks = after - before; + if (!complete) { + const uint64_t reference = + solver->statistics.search_ticks - solver->last.ticks.probe; + const double fraction = GET_OPTION (substituteeffort) * 1e-3; + const uint64_t limit = fraction * reference; + if (ticks > limit) { + kissat_extremely_verbose ( + solver, + "last substitute round took %" PRIu64 " 'substitute_ticks' " + "> limit %" PRIu64 " = %g * %" PRIu64 " 'search_ticks'", + ticks, limit, fraction, reference); + break; + } + } + } + if (!solver->inconsistent) { + kissat_watch_large_clauses (solver); + LOG ("now all large clauses are watched after binary clauses"); + solver->large_clauses_watched_after_binary_clauses = true; + kissat_reset_propagate (solver); + assert (!solver->level); + (void) kissat_probing_propagate (solver, 0, true); + } + STOP (substitute); +} + +void kissat_substitute (kissat *solver, bool complete) { + if (solver->inconsistent) + return; + assert (solver->probing); + assert (solver->watching); + assert (!solver->level); + LOG ("assuming not all large clauses watched after binary clauses"); + solver->large_clauses_watched_after_binary_clauses = false; + if (!GET_OPTION (substitute)) + return; + if (TERMINATED (substitute_terminated_1)) + return; + substitute_rounds (solver, complete); +} diff --git a/src/sat/kissat/substitute.h b/src/sat/kissat/substitute.h new file mode 100644 index 000000000..63a464ee9 --- /dev/null +++ b/src/sat/kissat/substitute.h @@ -0,0 +1,10 @@ +#ifndef _substitute_h_INCLUDED +#define _substitute_h_INCLUDED + +#include + +struct kissat; + +void kissat_substitute (struct kissat *, bool complete); + +#endif diff --git a/src/sat/kissat/sweep.c b/src/sat/kissat/sweep.c new file mode 100644 index 000000000..866867112 --- /dev/null +++ b/src/sat/kissat/sweep.c @@ -0,0 +1,1724 @@ +#include "sweep.h" +#include "dense.h" +#include "inline.h" +#include "kitten.h" +#include "logging.h" +#include "print.h" +#include "promote.h" +#include "propdense.h" +#include "proprobe.h" +#include "random.h" +#include "rank.h" +#include "report.h" +#include "terminate.h" + +#include +#include + +struct sweeper { + kissat *solver; + unsigned *depths; + unsigned *reprs; + unsigned *next, *prev; + unsigned first, last; + unsigned encoded; + unsigned save; + unsigneds vars; + references refs; + unsigneds clause; + unsigneds backbone; + unsigneds partition; + unsigneds core[2]; + struct { + uint64_t ticks; + unsigned clauses, depth, vars; + } limit; +}; + +typedef struct sweeper sweeper; + +static int sweep_solve (sweeper *sweeper) { + kissat *solver = sweeper->solver; + kitten *kitten = solver->kitten; + kitten_randomize_phases (kitten); + INC (sweep_solved); + int res = kitten_solve (kitten); + if (res == 10) + INC (sweep_sat); + if (res == 20) + INC (sweep_unsat); + return res; +} + +static void set_kitten_ticks_limit (sweeper *sweeper) { + uint64_t remaining = 0; + kissat *solver = sweeper->solver; + if (solver->statistics.kitten_ticks < sweeper->limit.ticks) + remaining = sweeper->limit.ticks - solver->statistics.kitten_ticks; + LOG ("'kitten_ticks' remaining %" PRIu64, remaining); + kitten_set_ticks_limit (solver->kitten, remaining); +} + +static bool kitten_ticks_limit_hit (sweeper *sweeper, const char *when) { + kissat *solver = sweeper->solver; + if (solver->statistics.kitten_ticks >= sweeper->limit.ticks) { + LOG ("'kitten_ticks' limit of %" PRIu64 " ticks hit after %" PRIu64 + " ticks during %s", + sweeper->limit.ticks, solver->statistics.kitten_ticks, when); + return true; + } +#ifndef LOGGING + (void) when; +#endif + return false; +} + +static void init_sweeper (kissat *solver, sweeper *sweeper) { + sweeper->solver = solver; + sweeper->encoded = 0; + CALLOC (sweeper->depths, VARS); + NALLOC (sweeper->reprs, LITS); + for (all_literals (lit)) + sweeper->reprs[lit] = lit; + NALLOC (sweeper->prev, VARS); + memset (sweeper->prev, 0xff, VARS * sizeof *sweeper->prev); + NALLOC (sweeper->next, VARS); + memset (sweeper->next, 0xff, VARS * sizeof *sweeper->next); +#ifndef NDEBUG + for (all_variables (idx)) + assert (sweeper->prev[idx] == INVALID_IDX); + for (all_variables (idx)) + assert (sweeper->next[idx] == INVALID_IDX); +#endif + sweeper->first = sweeper->last = INVALID_IDX; + INIT_STACK (sweeper->vars); + INIT_STACK (sweeper->refs); + INIT_STACK (sweeper->clause); + INIT_STACK (sweeper->backbone); + INIT_STACK (sweeper->partition); + INIT_STACK (sweeper->core[0]); + INIT_STACK (sweeper->core[1]); + assert (!solver->kitten); + solver->kitten = kitten_embedded (solver); + kitten_track_antecedents (solver->kitten); + kissat_enter_dense_mode (solver, 0); + kissat_connect_irredundant_large_clauses (solver); + + unsigned completed = solver->statistics.sweep_completed; + const unsigned max_completed = 32; + if (completed > max_completed) + completed = max_completed; + + uint64_t vars_limit = GET_OPTION (sweepvars); + vars_limit <<= completed; + const unsigned max_vars_limit = GET_OPTION (sweepmaxvars); + if (vars_limit > max_vars_limit) + vars_limit = max_vars_limit; + sweeper->limit.vars = vars_limit; + kissat_extremely_verbose (solver, "sweeper variable limit %u", + sweeper->limit.vars); + + uint64_t depth_limit = solver->statistics.sweep_completed; + depth_limit += GET_OPTION (sweepdepth); + const unsigned max_depth = GET_OPTION (sweepmaxdepth); + if (depth_limit > max_depth) + depth_limit = max_depth; + sweeper->limit.depth = depth_limit; + kissat_extremely_verbose (solver, "sweeper depth limit %u", + sweeper->limit.depth); + + uint64_t clause_limit = GET_OPTION (sweepclauses); + clause_limit <<= completed; + const unsigned max_clause_limit = GET_OPTION (sweepmaxclauses); + if (clause_limit > max_clause_limit) + clause_limit = max_clause_limit; + sweeper->limit.clauses = clause_limit; + kissat_extremely_verbose (solver, "sweeper clause limit %u", + sweeper->limit.clauses); + + if (GET_OPTION (sweepcomplete)) { + sweeper->limit.ticks = UINT64_MAX; + kissat_extremely_verbose (solver, "unlimited sweeper ticks limit"); + } else { + SET_EFFORT_LIMIT (ticks_limit, sweep, kitten_ticks); + sweeper->limit.ticks = ticks_limit; + } + set_kitten_ticks_limit (sweeper); +} + +static unsigned release_sweeper (sweeper *sweeper) { + kissat *solver = sweeper->solver; + + unsigned merged = 0; + for (all_variables (idx)) { + if (!ACTIVE (idx)) + continue; + const unsigned lit = LIT (idx); + if (sweeper->reprs[lit] != lit) + merged++; + } + DEALLOC (sweeper->depths, VARS); + DEALLOC (sweeper->reprs, LITS); + DEALLOC (sweeper->prev, VARS); + DEALLOC (sweeper->next, VARS); + RELEASE_STACK (sweeper->vars); + RELEASE_STACK (sweeper->refs); + RELEASE_STACK (sweeper->clause); + RELEASE_STACK (sweeper->backbone); + RELEASE_STACK (sweeper->partition); + RELEASE_STACK (sweeper->core[0]); + RELEASE_STACK (sweeper->core[1]); + kitten_release (solver->kitten); + solver->kitten = 0; + kissat_resume_sparse_mode (solver, false, 0); + return merged; +} + +static void clear_sweeper (sweeper *sweeper) { + kissat *solver = sweeper->solver; + LOG ("clearing sweeping environment"); + kitten_clear (solver->kitten); + kitten_track_antecedents (solver->kitten); + for (all_stack (unsigned, idx, sweeper->vars)) { + assert (sweeper->depths[idx]); + sweeper->depths[idx] = 0; + } + CLEAR_STACK (sweeper->vars); + for (all_stack (reference, ref, sweeper->refs)) { + clause *c = kissat_dereference_clause (solver, ref); + assert (c->swept); + c->swept = false; + } + CLEAR_STACK (sweeper->refs); + CLEAR_STACK (sweeper->backbone); + CLEAR_STACK (sweeper->partition); + sweeper->encoded = 0; + set_kitten_ticks_limit (sweeper); +} + +static unsigned sweep_repr (sweeper *sweeper, unsigned lit) { + unsigned res; + { + unsigned prev = lit; + while ((res = sweeper->reprs[prev]) != prev) + prev = res; + } + if (res == lit) + return res; +#if defined(LOGGING) || !defined(NDEBUG) + kissat *solver = sweeper->solver; +#endif + LOG ("sweeping repr[%s] = %s", LOGLIT (lit), LOGLIT (res)); + { + const unsigned not_res = NOT (res); + unsigned next, prev = lit; + ; + while ((next = sweeper->reprs[prev]) != res) { + const unsigned not_prev = NOT (prev); + sweeper->reprs[not_prev] = not_res; + sweeper->reprs[prev] = res; + prev = next; + } + assert (sweeper->reprs[NOT (prev)] == not_res); + } + return res; +} + +static void add_literal_to_environment (sweeper *sweeper, unsigned depth, + unsigned lit) { + const unsigned repr = sweep_repr (sweeper, lit); + if (repr != lit) + return; + kissat *solver = sweeper->solver; + const unsigned idx = IDX (lit); + if (sweeper->depths[idx]) + return; + assert (depth < UINT_MAX); + sweeper->depths[idx] = depth + 1; + PUSH_STACK (sweeper->vars, idx); + LOG ("sweeping[%u] adding literal %s", depth, LOGLIT (lit)); +} + +static void sweep_clause (sweeper *sweeper, unsigned depth) { + kissat *solver = sweeper->solver; + assert (SIZE_STACK (sweeper->clause) > 1); + for (all_stack (unsigned, lit, sweeper->clause)) + add_literal_to_environment (sweeper, depth, lit); + kitten_clause (solver->kitten, SIZE_STACK (sweeper->clause), + BEGIN_STACK (sweeper->clause)); + CLEAR_STACK (sweeper->clause); + sweeper->encoded++; +} + +static void sweep_binary (sweeper *sweeper, unsigned depth, unsigned lit, + unsigned other) { + if (sweep_repr (sweeper, lit) != lit) + return; + if (sweep_repr (sweeper, other) != other) + return; + kissat *solver = sweeper->solver; + LOGBINARY (lit, other, "sweeping[%u]", depth); + value *values = solver->values; + assert (!values[lit]); + const value other_value = values[other]; + if (other_value > 0) { + LOGBINARY (lit, other, "skipping satisfied"); + return; + } + const unsigned *depths = sweeper->depths; + const unsigned other_idx = IDX (other); + const unsigned other_depth = depths[other_idx]; + const unsigned lit_idx = IDX (lit); + const unsigned lit_depth = depths[lit_idx]; + if (other_depth && other_depth < lit_depth) { + LOGBINARY (lit, other, "skipping depth %u copied", other_depth); + return; + } + assert (!other_value); + assert (EMPTY_STACK (sweeper->clause)); + PUSH_STACK (sweeper->clause, lit); + PUSH_STACK (sweeper->clause, other); + sweep_clause (sweeper, depth); +} + +static void sweep_reference (sweeper *sweeper, unsigned depth, + reference ref) { + assert (EMPTY_STACK (sweeper->clause)); + kissat *solver = sweeper->solver; + clause *c = kissat_dereference_clause (solver, ref); + if (c->swept) + return; + if (c->garbage) + return; + LOGCLS (c, "sweeping[%u]", depth); + value *values = solver->values; + for (all_literals_in_clause (lit, c)) { + const value value = values[lit]; + if (value > 0) { + kissat_mark_clause_as_garbage (solver, c); + CLEAR_STACK (sweeper->clause); + return; + } + if (value < 0) + continue; + PUSH_STACK (sweeper->clause, lit); + } + PUSH_STACK (sweeper->refs, ref); + c->swept = true; + sweep_clause (sweeper, depth); +} + +static void save_core_clause (void *state, bool learned, size_t size, + const unsigned *lits) { + sweeper *sweeper = state; + kissat *solver = sweeper->solver; + if (solver->inconsistent) + return; + const value *const values = solver->values; + unsigneds *core = sweeper->core + sweeper->save; + size_t saved = SIZE_STACK (*core); + const unsigned *end = lits + size; + unsigned non_false = 0; + for (const unsigned *p = lits; p != end; p++) { + const unsigned lit = *p; + const value value = values[lit]; + if (value > 0) { + LOGLITS (size, lits, "extracted %s satisfied lemma", LOGLIT (lit)); + RESIZE_STACK (*core, saved); + return; + } + PUSH_STACK (*core, lit); + if (value < 0) + continue; + if (!learned && ++non_false > 1) { + LOGLITS (size, lits, "ignoring extracted original clause"); + RESIZE_STACK (*core, saved); + return; + } + } +#ifdef LOGGING + unsigned *saved_lits = BEGIN_STACK (*core) + saved; + size_t saved_size = SIZE_STACK (*core) - saved; + LOGLITS (saved_size, saved_lits, "saved core[%u]", sweeper->save); +#endif + PUSH_STACK (*core, INVALID_LIT); +} + +static void add_core (sweeper *sweeper, unsigned core_idx) { + kissat *solver = sweeper->solver; + if (solver->inconsistent) + return; + LOG ("check and add extracted core[%u] lemmas to proof", core_idx); + assert (core_idx == 0 || core_idx == 1); + unsigneds *core = sweeper->core + core_idx; + const value *const values = solver->values; + + unsigned *q = BEGIN_STACK (*core); + const unsigned *const end_core = END_STACK (*core), *p = q; + + while (p != end_core) { + const unsigned *c = p; + while (*p != INVALID_LIT) + p++; +#ifdef LOGGING + size_t old_size = p - c; + LOGLITS (old_size, c, "simplifying extracted core[%u] lemma", core_idx); +#endif + bool satisfied = false; + unsigned unit = INVALID_LIT; + + unsigned *d = q; + + for (const unsigned *l = c; !satisfied && l != p; l++) { + const unsigned lit = *l; + const value value = values[lit]; + if (value > 0) { + satisfied = true; + break; + } + if (!value) + unit = *q++ = lit; + } + + size_t new_size = q - d; + p++; + + if (satisfied) { + q = d; + LOG ("not adding satisfied clause"); + continue; + } + + if (!new_size) { + LOG ("sweeping produced empty clause"); + CHECK_AND_ADD_EMPTY (); + ADD_EMPTY_TO_PROOF (); + solver->inconsistent = true; + CLEAR_STACK (*core); + return; + } + + if (new_size == 1) { + q = d; + assert (unit != INVALID_LIT); + LOG ("sweeping produced unit %s", LOGLIT (unit)); + CHECK_AND_ADD_UNIT (unit); + ADD_UNIT_TO_PROOF (unit); + kissat_assign_unit (solver, unit, "sweeping backbone reason"); + INC (sweep_units); + continue; + } + + *q++ = INVALID_LIT; + + assert (new_size > 1); + LOGLITS (new_size, d, "adding extracted core[%u] lemma", core_idx); + CHECK_AND_ADD_LITS (new_size, d); + ADD_LITS_TO_PROOF (new_size, d); + } + SET_END_OF_STACK (*core, q); +#ifndef LOGGING + (void) core_idx; +#endif +} + +static void save_core (sweeper *sweeper, unsigned core) { + kissat *solver = sweeper->solver; + LOG ("saving extracted core[%u] lemmas", core); + assert (core == 0 || core == 1); + assert (EMPTY_STACK (sweeper->core[core])); + sweeper->save = core; + kitten_compute_clausal_core (solver->kitten, 0); + kitten_traverse_core_clauses (solver->kitten, sweeper, save_core_clause); +} + +static void clear_core (sweeper *sweeper, unsigned core_idx) { + kissat *solver = sweeper->solver; + if (solver->inconsistent) + return; +#if defined(LOGGING) || !defined(NDEBUG) || !defined(NPROOFS) + assert (core_idx == 0 || core_idx == 1); + LOG ("clearing core[%u] lemmas", core_idx); +#endif + unsigneds *core = sweeper->core + core_idx; +#ifdef CHECKING_OR_PROVING + LOG ("deleting sub-solver core clauses"); + const unsigned *const end = END_STACK (*core); + const unsigned *c = BEGIN_STACK (*core); + for (const unsigned *p = c; c != end; c = ++p) { + while (*p != INVALID_LIT) + p++; + const size_t size = p - c; + assert (size > 1); + REMOVE_CHECKER_LITS (size, c); + DELETE_LITS_FROM_PROOF (size, c); + } +#endif + CLEAR_STACK (*core); +} + +static void save_add_clear_core (sweeper *sweeper) { + save_core (sweeper, 0); + add_core (sweeper, 0); + clear_core (sweeper, 0); +} + +#define LOGBACKBONE(MESSAGE) \ + LOGLITSET (SIZE_STACK (sweeper->backbone), \ + BEGIN_STACK (sweeper->backbone), MESSAGE) + +#define LOGPARTITION(MESSAGE) \ + LOGLITPART (SIZE_STACK (sweeper->partition), \ + BEGIN_STACK (sweeper->partition), MESSAGE) + +static void init_backbone_and_partition (sweeper *sweeper) { + kissat *solver = sweeper->solver; + LOG ("initializing backbone and equivalent literals candidates"); + for (all_stack (unsigned, idx, sweeper->vars)) { + if (!ACTIVE (idx)) + continue; + const unsigned lit = LIT (idx); + const unsigned not_lit = NOT (lit); + const signed char tmp = kitten_value (solver->kitten, lit); + const unsigned candidate = (tmp < 0) ? not_lit : lit; + LOG ("sweeping candidate %s", LOGLIT (candidate)); + PUSH_STACK (sweeper->backbone, candidate); + PUSH_STACK (sweeper->partition, candidate); + } + PUSH_STACK (sweeper->partition, INVALID_LIT); + + LOGBACKBONE ("initialized backbone candidates"); + LOGPARTITION ("initialized equivalence candidates"); +} + +static void sweep_empty_clause (sweeper *sweeper) { + assert (!sweeper->solver->inconsistent); + save_add_clear_core (sweeper); + assert (sweeper->solver->inconsistent); +} + +static void sweep_refine_partition (sweeper *sweeper) { + kissat *solver = sweeper->solver; + LOG ("refining partition"); + kitten *kitten = solver->kitten; + unsigneds old_partition = sweeper->partition; + unsigneds new_partition; + INIT_STACK (new_partition); + const value *const values = solver->values; + const unsigned *const old_begin = BEGIN_STACK (old_partition); + const unsigned *const old_end = END_STACK (old_partition); +#ifdef LOGGING + unsigned old_classes = 0; + unsigned new_classes = 0; +#endif + for (const unsigned *p = old_begin, *q; p != old_end; p = q + 1) { + unsigned assigned_true = 0, other; + for (q = p; (other = *q) != INVALID_LIT; q++) { + if (sweep_repr (sweeper, other) != other) + continue; + if (values[other]) + continue; + signed char value = kitten_value (kitten, other); + if (!value) + LOG ("dropping sub-solver unassigned %s", LOGLIT (other)); + else if (value > 0) { + PUSH_STACK (new_partition, other); + assigned_true++; + } + } +#ifdef LOGGING + LOG ("refining class %u of size %zu", old_classes, (size_t) (q - p)); + old_classes++; +#endif + if (assigned_true == 0) + LOG ("no positive literal in class"); + else if (assigned_true == 1) { +#ifdef LOGGING + other = +#else + (void) +#endif + POP_STACK (new_partition); + LOG ("dropping singleton class %s", LOGLIT (other)); + } else { + LOG ("%u positive literal in class", assigned_true); + PUSH_STACK (new_partition, INVALID_LIT); +#ifdef LOGGING + new_classes++; +#endif + } + + unsigned assigned_false = 0; + for (q = p; (other = *q) != INVALID_LIT; q++) { + if (sweep_repr (sweeper, other) != other) + continue; + if (values[other]) + continue; + signed char value = kitten_value (kitten, other); + if (value < 0) { + PUSH_STACK (new_partition, other); + assigned_false++; + } + } + + if (assigned_false == 0) + LOG ("no negative literal in class"); + else if (assigned_false == 1) { +#ifdef LOGGING + other = +#else + (void) +#endif + POP_STACK (new_partition); + LOG ("dropping singleton class %s", LOGLIT (other)); + } else { + LOG ("%u negative literal in class", assigned_false); + PUSH_STACK (new_partition, INVALID_LIT); +#ifdef LOGGING + new_classes++; +#endif + } + } + RELEASE_STACK (old_partition); + sweeper->partition = new_partition; + LOG ("refined %u classes into %u", old_classes, new_classes); + LOGPARTITION ("refined equivalence candidates"); +} + +static void sweep_refine_backbone (sweeper *sweeper) { + kissat *solver = sweeper->solver; + LOG ("refining backbone candidates"); + const unsigned *const end = END_STACK (sweeper->backbone); + unsigned *q = BEGIN_STACK (sweeper->backbone); + const value *const values = solver->values; + kitten *kitten = solver->kitten; + for (const unsigned *p = q; p != end; p++) { + const unsigned lit = *p; + if (values[lit]) + continue; + signed char value = kitten_value (kitten, lit); + if (!value) + LOG ("dropping sub-solver unassigned %s", LOGLIT (lit)); + else if (value >= 0) + *q++ = lit; + } + SET_END_OF_STACK (sweeper->backbone, q); + LOGBACKBONE ("refined backbone candidates"); +} + +static void sweep_refine (sweeper *sweeper) { +#ifdef LOGGING + kissat *solver = sweeper->solver; +#endif + if (EMPTY_STACK (sweeper->backbone)) + LOG ("no need to refine empty backbone candidates"); + else + sweep_refine_backbone (sweeper); + if (EMPTY_STACK (sweeper->partition)) + LOG ("no need to refine empty partition candidates"); + else + sweep_refine_partition (sweeper); +} + +static void flip_backbone_literals (struct sweeper *sweeper) { + struct kissat *solver = sweeper->solver; + const unsigned max_rounds = GET_OPTION (sweepfliprounds); + if (!max_rounds) + return; + assert (!EMPTY_STACK (sweeper->backbone)); + struct kitten *kitten = solver->kitten; + if (kitten_status (kitten) != 10) + return; +#ifdef LOGGING + unsigned total_flipped = 0; +#endif + unsigned flipped, round = 0; + do { + round++; + flipped = 0; + unsigned *begin = BEGIN_STACK (sweeper->backbone), *q = begin; + const unsigned *const end = END_STACK (sweeper->backbone), *p = q; + while (p != end) { + const unsigned lit = *p++; + INC (sweep_flip_backbone); + if (kitten_flip_literal (kitten, lit)) { + LOG ("flipping backbone candidate %s succeeded", LOGLIT (lit)); +#ifdef LOGGING + total_flipped++; +#endif + INC (sweep_flipped_backbone); + flipped++; + } else { + LOG ("flipping backbone candidate %s failed", LOGLIT (lit)); + *q++ = lit; + } + } + SET_END_OF_STACK (sweeper->backbone, q); + LOG ("flipped %u backbone candidates in round %u", flipped, round); + + if (TERMINATED (sweep_terminated_1)) + break; + if (solver->statistics.kitten_ticks > sweeper->limit.ticks) + break; + } while (flipped && round < max_rounds); + LOG ("flipped %u backbone candidates in total in %u rounds", + total_flipped, round); +} + +static bool sweep_backbone_candidate (sweeper *sweeper, unsigned lit) { + kissat *solver = sweeper->solver; + LOG ("trying backbone candidate %s", LOGLIT (lit)); + kitten *kitten = solver->kitten; + signed char value = kitten_fixed (kitten, lit); + if (value) { + INC (sweep_fixed_backbone); + LOG ("literal %s already fixed", LOGLIT (lit)); + assert (value > 0); + return false; + } + + INC (sweep_flip_backbone); + if (kitten_status (kitten) == 10 && kitten_flip_literal (kitten, lit)) { + INC (sweep_flipped_backbone); + LOG ("flipping %s succeeded", LOGLIT (lit)); + LOGBACKBONE ("refined backbone candidates"); + return false; + } + + LOG ("flipping %s failed", LOGLIT (lit)); + const unsigned not_lit = NOT (lit); + INC (sweep_solved_backbone); + kitten_assume (kitten, not_lit); + int res = sweep_solve (sweeper); + if (res == 10) { + LOG ("sweeping backbone candidate %s failed", LOGLIT (lit)); + sweep_refine (sweeper); + INC (sweep_sat_backbone); + return false; + } + + if (res == 20) { + LOG ("sweep unit %s", LOGLIT (lit)); + save_add_clear_core (sweeper); + INC (sweep_unsat_backbone); + return true; + } + + INC (sweep_unknown_backbone); + + LOG ("sweeping backbone candidate %s failed", LOGLIT (lit)); + return false; +} + +static void add_binary (kissat *solver, unsigned lit, unsigned other) { + kissat_new_binary_clause (solver, lit, other); +} + +static bool scheduled_variable (sweeper *sweeper, unsigned idx) { +#ifndef NDEBUG + kissat *const solver = sweeper->solver; + assert (VALID_INTERNAL_INDEX (idx)); +#endif + return sweeper->prev[idx] != INVALID_IDX || sweeper->first == idx; +} + +static void schedule_inner (sweeper *sweeper, unsigned idx) { + kissat *const solver = sweeper->solver; + assert (VALID_INTERNAL_INDEX (idx)); + if (!ACTIVE (idx)) + return; + const unsigned next = sweeper->next[idx]; + if (next != INVALID_IDX) { + LOG ("rescheduling inner %s as last", LOGVAR (idx)); + const unsigned prev = sweeper->prev[idx]; + assert (sweeper->prev[next] == idx); + sweeper->prev[next] = prev; + if (prev == INVALID_IDX) { + assert (sweeper->first == idx); + sweeper->first = next; + } else { + assert (sweeper->next[prev] == idx); + sweeper->next[prev] = next; + } + const unsigned last = sweeper->last; + if (last == INVALID_IDX) { + assert (sweeper->first == INVALID_IDX); + sweeper->first = idx; + } else { + assert (sweeper->next[last] == INVALID_IDX); + sweeper->next[last] = idx; + } + sweeper->prev[idx] = last; + sweeper->next[idx] = INVALID_IDX; + sweeper->last = idx; + } else if (sweeper->last != idx) { + LOG ("scheduling inner %s as last", LOGVAR (idx)); + const unsigned last = sweeper->last; + if (last == INVALID_IDX) { + assert (sweeper->first == INVALID_IDX); + sweeper->first = idx; + } else { + assert (sweeper->next[last] == INVALID_IDX); + sweeper->next[last] = idx; + } + assert (sweeper->next[idx] == INVALID_IDX); + sweeper->prev[idx] = last; + sweeper->last = idx; + } else + LOG ("keeping inner %s scheduled as last", LOGVAR (idx)); +} + +static void schedule_outer (sweeper *sweeper, unsigned idx) { +#if !defined(NDEBUG) || defined(LOGGING) + kissat *const solver = sweeper->solver; +#endif + assert (VALID_INTERNAL_INDEX (idx)); + assert (!scheduled_variable (sweeper, idx)); + assert (ACTIVE (idx)); + const unsigned first = sweeper->first; + if (first == INVALID_IDX) { + assert (sweeper->last == INVALID_IDX); + sweeper->last = idx; + } else { + assert (sweeper->prev[first] == INVALID_IDX); + sweeper->prev[first] = idx; + } + assert (sweeper->prev[idx] == INVALID_IDX); + sweeper->next[idx] = first; + sweeper->first = idx; + LOG ("scheduling outer %s as first", LOGVAR (idx)); +} + +static unsigned next_scheduled (sweeper *sweeper) { +#if !defined(NDEBUG) || defined(LOGGING) + kissat *const solver = sweeper->solver; +#endif + unsigned res = sweeper->last; + if (res == INVALID_IDX) { + LOG ("no more scheduled variables left"); + return INVALID_IDX; + } + assert (VALID_INTERNAL_INDEX (res)); + LOG ("dequeuing next scheduled %s", LOGVAR (res)); + const unsigned prev = sweeper->prev[res]; + assert (sweeper->next[res] == INVALID_IDX); + sweeper->prev[res] = INVALID_IDX; + if (prev == INVALID_IDX) { + assert (sweeper->first == res); + sweeper->first = INVALID_IDX; + } else { + assert (sweeper->next[prev] == res); + sweeper->next[prev] = INVALID_IDX; + } + sweeper->last = prev; + return res; +} + +#define all_scheduled(IDX) \ + unsigned IDX = sweeper->first, NEXT_##IDX; \ + IDX != INVALID_IDX && (NEXT_##IDX = sweeper->next[IDX], true); \ + IDX = NEXT_##IDX + +static void substitute_connected_clauses (sweeper *sweeper, unsigned lit, + unsigned repr) { + kissat *solver = sweeper->solver; + if (solver->inconsistent) + return; + value *const values = solver->values; + if (values[lit]) + return; + if (values[repr]) + return; + LOG ("substituting %s with %s in all irredundant clauses", LOGLIT (lit), + LOGLIT (repr)); + + assert (lit != repr); + assert (lit != NOT (repr)); + +#ifdef CHECKING_OR_PROVING + const bool checking_or_proving = kissat_checking_or_proving (solver); + assert (EMPTY_STACK (solver->added)); + assert (EMPTY_STACK (solver->removed)); +#endif + + unsigneds *const delayed = &solver->delayed; + assert (EMPTY_STACK (*delayed)); + + { + watches *lit_watches = &WATCHES (lit); + watch *const begin_watches = BEGIN_WATCHES (*lit_watches); + const watch *const end_watches = END_WATCHES (*lit_watches); + + watch *q = begin_watches; + const watch *p = q; + + while (p != end_watches) { + const watch head = *q++ = *p++; + if (head.type.binary) { + const unsigned other = head.binary.lit; + const value other_value = values[other]; + if (other == NOT (repr)) + continue; + if (other_value < 0) + break; + if (other_value > 0) + continue; + if (other == repr) { + CHECK_AND_ADD_UNIT (lit); + ADD_UNIT_TO_PROOF (lit); + kissat_assign_unit (solver, lit, "substituted binary clause"); + INC (sweep_units); + break; + } + CHECK_AND_ADD_BINARY (repr, other); + ADD_BINARY_TO_PROOF (repr, other); + REMOVE_CHECKER_BINARY (lit, other); + DELETE_BINARY_FROM_PROOF (lit, other); + PUSH_STACK (*delayed, head.raw); + watch src = {.raw = head.raw}; + watch dst = {.raw = head.raw}; + src.binary.lit = lit; + dst.binary.lit = repr; + watches *other_watches = &WATCHES (other); + kissat_substitute_large_watch (solver, other_watches, src, dst); + q--; + } else { + const reference ref = head.large.ref; + assert (EMPTY_STACK (sweeper->clause)); + clause *c = kissat_dereference_clause (solver, ref); + if (c->garbage) + continue; + + bool satisfied = false; + bool repr_already_watched = false; + const unsigned not_repr = NOT (repr); +#ifndef NDEBUG + bool found = false; +#endif + for (all_literals_in_clause (other, c)) { + if (other == lit) { +#ifndef NDEBUG + assert (!found); + found = true; +#endif + PUSH_STACK (solver->clause, repr); + continue; + } + assert (other != NOT (lit)); + if (other == repr) { + assert (!repr_already_watched); + repr_already_watched = true; + continue; + } + if (other == not_repr) { + satisfied = true; + break; + } + const value tmp = values[other]; + if (tmp < 0) + continue; + if (tmp > 0) { + satisfied = true; + break; + } + PUSH_STACK (solver->clause, other); + } + + if (satisfied) { + CLEAR_STACK (solver->clause); + kissat_mark_clause_as_garbage (solver, c); + continue; + } + assert (found); + + const unsigned new_size = SIZE_STACK (solver->clause); + + if (new_size == 0) { + LOGCLS (c, "substituted empty clause"); + assert (!solver->inconsistent); + solver->inconsistent = true; + CHECK_AND_ADD_EMPTY (); + ADD_EMPTY_TO_PROOF (); + break; + } + + if (new_size == 1) { + LOGCLS (c, "reduces to unit"); + const unsigned unit = POP_STACK (solver->clause); + CHECK_AND_ADD_UNIT (unit); + ADD_UNIT_TO_PROOF (unit); + kissat_assign_unit (solver, unit, "substituted large clause"); + INC (sweep_units); + break; + } + + CHECK_AND_ADD_STACK (solver->clause); + ADD_STACK_TO_PROOF (solver->clause); + REMOVE_CHECKER_CLAUSE (c); + DELETE_CLAUSE_FROM_PROOF (c); + + if (!c->redundant) + kissat_mark_added_literals (solver, new_size, + BEGIN_STACK (solver->clause)); + + if (new_size == 2) { + const unsigned second = POP_STACK (solver->clause); + const unsigned first = POP_STACK (solver->clause); + LOGCLS (c, "reduces to binary clause %s %s", LOGLIT (first), + LOGLIT (second)); + assert (first == repr || second == repr); + const unsigned other = first ^ second ^ repr; + const watch src = {.raw = head.raw}; + watch dst = kissat_binary_watch (repr); + watches *other_watches = &WATCHES (other); + kissat_substitute_large_watch (solver, other_watches, src, dst); + assert (solver->statistics.clauses_irredundant); + solver->statistics.clauses_irredundant--; + assert (solver->statistics.clauses_binary < UINT64_MAX); + solver->statistics.clauses_binary++; + dst.binary.lit = other; + PUSH_STACK (*delayed, dst.raw); + const size_t bytes = kissat_actual_bytes_of_clause (c); + ADD (arena_garbage, bytes); + c->garbage = true; + q--; + continue; + } + + assert (2 < new_size); + const unsigned old_size = c->size; + assert (new_size <= old_size); + + const unsigned *const begin = BEGIN_STACK (solver->clause); + const unsigned *const end = END_STACK (solver->clause); + + unsigned *lits = c->lits; + unsigned *q = lits; + + for (const unsigned *p = begin; p != end; p++) { + const unsigned other = *p; + *q++ = other; + } + + if (new_size < old_size) { + c->size = new_size; + c->searched = 2; + if (c->redundant && c->glue >= new_size) + kissat_promote_clause (solver, c, new_size - 1); + if (!c->shrunken) { + c->shrunken = true; + lits[old_size - 1] = INVALID_LIT; + } + } + + LOGCLS (c, "substituted"); + + if (!repr_already_watched) + PUSH_STACK (*delayed, head.raw); + CLEAR_STACK (solver->clause); + q--; + } + } + while (p != end_watches) + *q++ = *p++; + SET_END_OF_WATCHES (*lit_watches, q); + } + { + const unsigned *const begin_delayed = BEGIN_STACK (*delayed); + const unsigned *const end_delayed = END_STACK (*delayed); + for (const unsigned *p = begin_delayed; p != end_delayed; p++) { + const watch head = {.raw = *p}; + watches *repr_watches = &WATCHES (repr); + PUSH_WATCHES (*repr_watches, head); + } + + CLEAR_STACK (*delayed); + } + +#ifdef CHECKING_OR_PROVING + if (checking_or_proving) { + CLEAR_STACK (solver->added); + CLEAR_STACK (solver->removed); + } +#endif +} + +static void sweep_remove (sweeper *sweeper, unsigned lit) { + kissat *solver = sweeper->solver; + assert (sweeper->reprs[lit] != lit); + unsigneds *partition = &sweeper->partition; + unsigned *const begin_partition = BEGIN_STACK (*partition), *p; + const unsigned *const end_partition = END_STACK (*partition); + for (p = begin_partition; *p != lit; p++) + assert (p + 1 != end_partition); + unsigned *begin_class = p; + while (begin_class != begin_partition && begin_class[-1] != INVALID_LIT) + begin_class--; + const unsigned *end_class = p; + while (*end_class != INVALID_LIT) + end_class++; + const unsigned size = end_class - begin_class; + LOG ("removing non-representative %s from equivalence class of size %u", + LOGLIT (lit), size); + assert (size > 1); + unsigned *q = begin_class; + if (size == 2) { + LOG ("completely squashing equivalence class of %s", LOGLIT (lit)); + for (const unsigned *r = end_class + 1; r != end_partition; r++) + *q++ = *r; + } else { + for (const unsigned *r = begin_class; r != end_partition; r++) + if (r != p) + *q++ = *r; + } + SET_END_OF_STACK (*partition, q); +#ifndef LOGGING + (void) solver; +#endif +} + +static void flip_partition_literals (struct sweeper *sweeper) { + struct kissat *solver = sweeper->solver; + const unsigned max_rounds = GET_OPTION (sweepfliprounds); + if (!max_rounds) + return; + assert (!EMPTY_STACK (sweeper->partition)); + struct kitten *kitten = solver->kitten; + if (kitten_status (kitten) != 10) + return; +#ifdef LOGGING + unsigned total_flipped = 0; +#endif + unsigned flipped, round = 0; + do { + round++; + flipped = 0; + unsigned *begin = BEGIN_STACK (sweeper->partition), *dst = begin; + const unsigned *const end = END_STACK (sweeper->partition), *src = dst; + while (src != end) { + const unsigned *end_src = src; + while (assert (end_src != end), *end_src != INVALID_LIT) + end_src++; + unsigned size = end_src - src; + assert (size > 1); + unsigned *q = dst; + for (const unsigned *p = src; p != end_src; p++) { + const unsigned lit = *p; + if (kitten_flip_literal (kitten, lit)) { + LOG ("flipping equivalence candidate %s succeeded", LOGLIT (lit)); +#ifdef LOGGING + total_flipped++; +#endif + flipped++; + if (--size < 2) + break; + } else { + LOG ("flipping equivalence candidate %s failed", LOGLIT (lit)); + *q++ = lit; + } + } + if (size > 1) { + *q++ = INVALID_LIT; + dst = q; + } + src = end_src + 1; + } + SET_END_OF_STACK (sweeper->partition, dst); + LOG ("flipped %u equivalence candidates in round %u", flipped, round); + + if (TERMINATED (sweep_terminated_2)) + break; + if (solver->statistics.kitten_ticks > sweeper->limit.ticks) + break; + } while (flipped && round < max_rounds); + LOG ("flipped %u equivalence candidates in total in %u rounds", + total_flipped, round); +} + +static bool sweep_equivalence_candidates (sweeper *sweeper, unsigned lit, + unsigned other) { + kissat *solver = sweeper->solver; + LOG ("trying equivalence candidates %s = %s", LOGLIT (lit), + LOGLIT (other)); + const unsigned not_other = NOT (other); + const unsigned not_lit = NOT (lit); + kitten *kitten = solver->kitten; + const unsigned *const begin = BEGIN_STACK (sweeper->partition); + unsigned *const end = END_STACK (sweeper->partition); + assert (begin + 3 <= end); + assert (end[-3] == lit); + assert (end[-2] == other); + const unsigned third = (end - begin == 3) ? INVALID_LIT : end[-4]; + const int status = kitten_status (kitten); + if (status == 10 && kitten_flip_literal (kitten, lit)) { + INC (sweep_flip_equivalences); + INC (sweep_flipped_equivalences); + LOG ("flipping %s succeeded", LOGLIT (lit)); + if (third == INVALID_LIT) { + LOG ("squashing equivalence class of %s", LOGLIT (lit)); + SET_END_OF_STACK (sweeper->partition, end - 3); + } else { + LOG ("removing %s from equivalence class of %s", LOGLIT (lit), + LOGLIT (other)); + end[-3] = other; + end[-2] = INVALID_LIT; + SET_END_OF_STACK (sweeper->partition, end - 1); + } + LOGPARTITION ("refined equivalence candidates"); + return false; + } else if (status == 10 && kitten_flip_literal (kitten, other)) { + ADD (sweep_flip_equivalences, 2); + INC (sweep_flipped_equivalences); + LOG ("flipping %s succeeded", LOGLIT (other)); + if (third == INVALID_LIT) { + LOG ("squashing equivalence class of %s", LOGLIT (lit)); + SET_END_OF_STACK (sweeper->partition, end - 3); + } else { + LOG ("removing %s from equivalence class of %s", LOGLIT (other), + LOGLIT (lit)); + end[-2] = INVALID_LIT; + SET_END_OF_STACK (sweeper->partition, end - 1); + } + LOGPARTITION ("refined equivalence candidates"); + return false; + } + if (status == 10) + ADD (sweep_flip_equivalences, 2); + LOG ("flipping %s and %s both failed", LOGLIT (lit), LOGLIT (other)); + kitten_assume (kitten, not_lit); + kitten_assume (kitten, other); + INC (sweep_solved_equivalences); + int res = sweep_solve (sweeper); + if (res == 10) { + INC (sweep_sat_equivalences); + LOG ("first sweeping implication %s -> %s failed", LOGLIT (other), + LOGLIT (lit)); + sweep_refine (sweeper); + } else if (!res) { + INC (sweep_unknown_equivalences); + LOG ("first sweeping implication %s -> %s hit ticks limit", + LOGLIT (other), LOGLIT (lit)); + } + + if (res != 20) + return false; + + INC (sweep_unsat_equivalences); + LOG ("first sweeping implication %s -> %s succeeded", LOGLIT (other), + LOGLIT (lit)); + + save_core (sweeper, 0); + + kitten_assume (kitten, lit); + kitten_assume (kitten, not_other); + res = sweep_solve (sweeper); + INC (sweep_solved_equivalences); + if (res == 10) { + INC (sweep_sat_equivalences); + LOG ("second sweeping implication %s <- %s failed", LOGLIT (other), + LOGLIT (lit)); + sweep_refine (sweeper); + } else if (!res) { + INC (sweep_unknown_equivalences); + LOG ("second sweeping implication %s <- %s hit ticks limit", + LOGLIT (other), LOGLIT (lit)); + } + + if (res != 20) { + CLEAR_STACK (sweeper->core[0]); + return false; + } + + INC (sweep_unsat_equivalences); + LOG ("second sweeping implication %s <- %s succeeded too", LOGLIT (other), + LOGLIT (lit)); + + save_core (sweeper, 1); + + LOG ("sweep equivalence %s = %s", LOGLIT (lit), LOGLIT (other)); + INC (sweep_equivalences); + + add_core (sweeper, 0); + add_binary (solver, lit, not_other); + clear_core (sweeper, 0); + + add_core (sweeper, 1); + add_binary (solver, not_lit, other); + clear_core (sweeper, 1); + + unsigned repr; + if (lit < other) { + repr = sweeper->reprs[other] = lit; + sweeper->reprs[not_other] = not_lit; + substitute_connected_clauses (sweeper, other, lit); + substitute_connected_clauses (sweeper, not_other, not_lit); + sweep_remove (sweeper, other); + } else { + repr = sweeper->reprs[lit] = other; + sweeper->reprs[not_lit] = not_other; + substitute_connected_clauses (sweeper, lit, other); + substitute_connected_clauses (sweeper, not_lit, not_other); + sweep_remove (sweeper, lit); + } + + const unsigned repr_idx = IDX (repr); + schedule_inner (sweeper, repr_idx); + + return true; +} + +static const char *sweep_variable (sweeper *sweeper, unsigned idx) { + kissat *solver = sweeper->solver; + assert (!solver->inconsistent); + if (!ACTIVE (idx)) + return "inactive variable"; + const unsigned start = LIT (idx); + if (sweeper->reprs[start] != start) + return "non-representative variable"; + assert (EMPTY_STACK (sweeper->vars)); + assert (EMPTY_STACK (sweeper->refs)); + assert (EMPTY_STACK (sweeper->backbone)); + assert (EMPTY_STACK (sweeper->partition)); + assert (!sweeper->encoded); + + INC (sweep_variables); + + LOG ("sweeping %s", LOGVAR (idx)); + assert (!VALUE (start)); + LOG ("starting sweeping[0]"); + add_literal_to_environment (sweeper, 0, start); + LOG ("finished sweeping[0]"); + LOG ("starting sweeping[1]"); + + bool limit_reached = false; + size_t expand = 0, next = 1; + bool success = false; + unsigned depth = 1; + + while (!limit_reached) { + if (sweeper->encoded >= sweeper->limit.clauses) { + LOG ("environment clause limit reached"); + limit_reached = true; + break; + } + if (expand == next) { + LOG ("finished sweeping[%u]", depth); + if (depth >= sweeper->limit.depth) { + LOG ("environment depth limit reached"); + break; + } + next = SIZE_STACK (sweeper->vars); + if (expand == next) { + LOG ("completely copied all clauses"); + break; + } + depth++; + LOG ("starting sweeping[%u]", depth); + } + const unsigned choices = next - expand; + if (GET_OPTION (sweeprand) && choices > 1) { + const unsigned swap = + kissat_pick_random (&solver->random, 0, choices); + if (swap) { + unsigned *vars = sweeper->vars.begin; + SWAP (unsigned, vars[expand], vars[expand + swap]); + } + } + const unsigned idx = PEEK_STACK (sweeper->vars, expand); + LOG ("traversing and adding clauses of %s", LOGVAR (idx)); + for (unsigned sign = 0; sign < 2; sign++) { + const unsigned lit = LIT (idx) + sign; + watches *watches = &WATCHES (lit); + for (all_binary_large_watches (watch, *watches)) { + if (watch.type.binary) { + const unsigned other = watch.binary.lit; + sweep_binary (sweeper, depth, lit, other); + } else { + reference ref = watch.large.ref; + sweep_reference (sweeper, depth, ref); + } + if (SIZE_STACK (sweeper->vars) >= sweeper->limit.vars) { + LOG ("environment variable limit reached"); + limit_reached = true; + break; + } + } + if (limit_reached) + break; + } + expand++; + } + ADD (sweep_depth, depth); + ADD (sweep_clauses, sweeper->encoded); + ADD (sweep_environment, SIZE_STACK (sweeper->vars)); + kissat_extremely_verbose (solver, + "sweeping variable %d environment of " + "%zu variables %u clauses depth %u", + kissat_export_literal (solver, LIT (idx)), + SIZE_STACK (sweeper->vars), sweeper->encoded, + depth); + int res = sweep_solve (sweeper); + LOG ("sub-solver returns '%d'", res); + if (res == 10) { + init_backbone_and_partition (sweeper); +#ifndef QUIET + uint64_t units = solver->statistics.sweep_units; + uint64_t solved = solver->statistics.sweep_solved; +#endif + START (sweepbackbone); + while (!EMPTY_STACK (sweeper->backbone)) { + if (solver->inconsistent || TERMINATED (sweep_terminated_3) || + kitten_ticks_limit_hit (sweeper, "backbone refinement")) { + limit_reached = true; + STOP_SWEEP_BACKBONE: + STOP (sweepbackbone); + goto DONE; + } + flip_backbone_literals (sweeper); + if (TERMINATED (sweep_terminated_4) || + kitten_ticks_limit_hit (sweeper, "backbone refinement")) { + limit_reached = true; + goto STOP_SWEEP_BACKBONE; + } + if (EMPTY_STACK (sweeper->backbone)) + break; + const unsigned lit = POP_STACK (sweeper->backbone); + if (!ACTIVE (IDX (lit))) + continue; + if (sweep_backbone_candidate (sweeper, lit)) + success = true; + } + STOP (sweepbackbone); +#ifndef QUIET + units = solver->statistics.sweep_units - units; + solved = solver->statistics.sweep_solved - solved; + kissat_extremely_verbose ( + solver, + "complete swept variable %d backbone with %" PRIu64 + " units in %" PRIu64 " solver calls", + kissat_export_literal (solver, LIT (idx)), units, solved); +#endif + assert (EMPTY_STACK (sweeper->backbone)); +#ifndef QUIET + uint64_t equivalences = solver->statistics.sweep_equivalences; + solved = solver->statistics.sweep_solved; +#endif + START (sweepequivalences); + while (!EMPTY_STACK (sweeper->partition)) { + if (solver->inconsistent || TERMINATED (sweep_terminated_5) || + kitten_ticks_limit_hit (sweeper, "partition refinement")) { + limit_reached = true; + STOP_SWEEP_EQUIVALENCES: + STOP (sweepequivalences); + goto DONE; + } + flip_partition_literals (sweeper); + if (TERMINATED (sweep_terminated_6) || + kitten_ticks_limit_hit (sweeper, "backbone refinement")) { + limit_reached = true; + goto STOP_SWEEP_EQUIVALENCES; + } + if (EMPTY_STACK (sweeper->partition)) + break; + if (SIZE_STACK (sweeper->partition) > 2) { + const unsigned *end = END_STACK (sweeper->partition); + assert (end[-1] == INVALID_LIT); + unsigned lit = end[-3]; + unsigned other = end[-2]; + if (sweep_equivalence_candidates (sweeper, lit, other)) + success = true; + } else + CLEAR_STACK (sweeper->partition); + } + STOP (sweepequivalences); +#ifndef QUIET + equivalences = solver->statistics.sweep_equivalences - equivalences; + solved = solver->statistics.sweep_solved - solved; + if (equivalences) + kissat_extremely_verbose ( + solver, + "complete swept variable %d partition with %" PRIu64 + " equivalences in %" PRIu64 " solver calls", + kissat_export_literal (solver, LIT (idx)), equivalences, solved); +#endif + } else if (res == 20) + sweep_empty_clause (sweeper); + +DONE: + clear_sweeper (sweeper); + + if (!solver->inconsistent && !kissat_propagated (solver)) + (void) kissat_dense_propagate (solver); + + if (success && limit_reached) + return "successfully despite reaching limit"; + if (!success && !limit_reached) + return "unsuccessfully without reaching limit"; + else if (success && !limit_reached) + return "successfully without reaching limit"; + assert (!success && limit_reached); + return "unsuccessfully and reached limit"; +} + +typedef struct sweep_candidate sweep_candidate; + +struct sweep_candidate { + unsigned rank; + unsigned idx; +}; + +// clang-format off + +typedef STACK(sweep_candidate) sweep_candidates; + +// clang-format on + +#define RANK_SWEEP_CANDIDATE(CAND) (CAND).rank + +static bool scheduable_variable (sweeper *sweeper, unsigned idx, + size_t *occ_ptr) { + kissat *solver = sweeper->solver; + const unsigned lit = LIT (idx); + const size_t pos = SIZE_WATCHES (WATCHES (lit)); + if (!pos) + return false; + const unsigned max_occurrences = sweeper->limit.clauses; + if (pos > max_occurrences) + return false; + const unsigned not_lit = NOT (lit); + const size_t neg = SIZE_WATCHES (WATCHES (not_lit)); + if (!neg) + return false; + if (neg > max_occurrences) + return false; + *occ_ptr = pos + neg; + return true; +} + +static unsigned schedule_all_other_not_scheduled_yet (sweeper *sweeper) { + kissat *solver = sweeper->solver; + sweep_candidates fresh; + INIT_STACK (fresh); + flags *const flags = solver->flags; + const bool incomplete = solver->sweep_incomplete; + for (all_variables (idx)) { + struct flags *const f = flags + idx; + if (!f->active) + continue; + if (incomplete && !f->sweep) + continue; + if (scheduled_variable (sweeper, idx)) + continue; + size_t occ; + if (!scheduable_variable (sweeper, idx, &occ)) { + FLAGS (idx)->sweep = false; + continue; + } + sweep_candidate cand; + cand.rank = occ; + cand.idx = idx; + PUSH_STACK (fresh, cand); + } + const size_t size = SIZE_STACK (fresh); + assert (size <= UINT_MAX); + RADIX_STACK (sweep_candidate, unsigned, fresh, RANK_SWEEP_CANDIDATE); + for (all_stack (sweep_candidate, cand, fresh)) + schedule_outer (sweeper, cand.idx); + RELEASE_STACK (fresh); + return size; +} + +static unsigned reschedule_previously_remaining (sweeper *sweeper) { + kissat *solver = sweeper->solver; + flags *flags = solver->flags; + unsigned rescheduled = 0; + unsigneds *remaining = &solver->sweep_schedule; + for (all_stack (unsigned, idx, *remaining)) { + struct flags *f = flags + idx; + if (!f->active) + continue; + if (scheduled_variable (sweeper, idx)) + continue; + size_t occ; + if (!scheduable_variable (sweeper, idx, &occ)) { + f->sweep = false; + continue; + } + schedule_inner (sweeper, idx); + rescheduled++; + } + RELEASE_STACK (*remaining); + return rescheduled; +} + +static unsigned incomplete_variables (sweeper *sweeper) { + kissat *solver = sweeper->solver; + flags *flags = solver->flags; + unsigned res = 0; + for (all_variables (idx)) { + struct flags *f = flags + idx; + if (!f->active) + continue; + if (f->sweep) + res++; + } + return res; +} + +static void mark_incomplete (sweeper *sweeper) { + kissat *solver = sweeper->solver; + flags *flags = solver->flags; + unsigned marked = 0; + for (all_scheduled (idx)) + if (!flags[idx].sweep) { + flags[idx].sweep = true; + marked++; + } + solver->sweep_incomplete = true; +#ifndef QUIET + kissat_extremely_verbose ( + solver, "marked %u scheduled sweeping variables as incomplete", + marked); +#else + (void) marked; +#endif +} + +static unsigned schedule_sweeping (sweeper *sweeper) { + const unsigned rescheduled = reschedule_previously_remaining (sweeper); + const unsigned fresh = schedule_all_other_not_scheduled_yet (sweeper); + const unsigned scheduled = fresh + rescheduled; + const unsigned incomplete = incomplete_variables (sweeper); + kissat *solver = sweeper->solver; +#ifndef QUIET + kissat_phase (solver, "sweep", GET (sweep), + "scheduled %u variables %.0f%% " + "(%u rescheduled %.0f%%, %u incomplete %.0f%%)", + scheduled, + kissat_percent (scheduled, sweeper->solver->active), + rescheduled, kissat_percent (rescheduled, scheduled), + incomplete, kissat_percent (incomplete, scheduled)); +#endif + if (incomplete) + assert (solver->sweep_incomplete); + else { + if (solver->sweep_incomplete) + INC (sweep_completed); + mark_incomplete (sweeper); + } + return scheduled; +} + +static void unschedule_sweeping (sweeper *sweeper, unsigned swept, + unsigned scheduled) { + kissat *solver = sweeper->solver; +#ifdef QUIET + (void) scheduled, (void) swept; +#endif + assert (EMPTY_STACK (solver->sweep_schedule)); + assert (solver->sweep_incomplete); + flags *flags = solver->flags; + for (all_scheduled (idx)) + if (flags[idx].active) { + PUSH_STACK (solver->sweep_schedule, idx); + LOG ("untried scheduled %s", LOGVAR (idx)); + } +#ifndef QUIET + const unsigned retained = SIZE_STACK (solver->sweep_schedule); + kissat_extremely_verbose ( + solver, "retained %u variables %.0f%% to be swept next time", + retained, kissat_percent (retained, solver->active)); +#endif + const unsigned incomplete = incomplete_variables (sweeper); + if (incomplete) + kissat_extremely_verbose ( + solver, "need to sweep %u more variables %.0f%% for completion", + incomplete, kissat_percent (incomplete, solver->active)); + else { + kissat_extremely_verbose (solver, + "no more variables needed to complete sweep"); + solver->sweep_incomplete = false; + INC (sweep_completed); + } + kissat_phase (solver, "sweep", GET (sweep), + "swept %u variables (%u remain %.0f%%)", swept, incomplete, + kissat_percent (incomplete, scheduled)); +} + +bool kissat_sweep (kissat *solver) { + if (!GET_OPTION (sweep)) + return false; + if (solver->inconsistent) + return false; + if (TERMINATED (sweep_terminated_7)) + return false; + if (DELAYING (sweep)) + return false; + assert (!solver->level); + assert (!solver->unflushed); + START (sweep); + INC (sweep); + statistics *statistics = &solver->statistics; + uint64_t equivalences = statistics->sweep_equivalences; + uint64_t units = statistics->sweep_units; + sweeper sweeper; + init_sweeper (solver, &sweeper); + const unsigned scheduled = schedule_sweeping (&sweeper); + uint64_t swept = 0, limit = 10; + for (;;) { + if (solver->inconsistent) + break; + if (TERMINATED (sweep_terminated_8)) + break; + if (solver->statistics.kitten_ticks > sweeper.limit.ticks) + break; + unsigned idx = next_scheduled (&sweeper); + if (idx == INVALID_IDX) + break; + FLAGS (idx)->sweep = false; +#ifndef QUIET + const char *res = +#endif + sweep_variable (&sweeper, idx); + kissat_extremely_verbose ( + solver, "swept[%" PRIu64 "] external variable %d %s", swept, + kissat_export_literal (solver, LIT (idx)), res); + if (++swept == limit) { + kissat_very_verbose (solver, + "found %" PRIu64 " equivalences and %" PRIu64 + " units after sweeping %" PRIu64 " variables ", + statistics->sweep_equivalences - equivalences, + solver->statistics.sweep_units - units, swept); + limit *= 10; + } + } + kissat_very_verbose (solver, "swept %" PRIu64 " variables", swept); + equivalences = statistics->sweep_equivalences - equivalences, + units = solver->statistics.sweep_units - units; + kissat_phase (solver, "sweep", GET (sweep), + "found %" PRIu64 " equivalences and %" PRIu64 " units", + equivalences, units); + unschedule_sweeping (&sweeper, swept, scheduled); + unsigned inactive = release_sweeper (&sweeper); + + if (!solver->inconsistent) { + solver->propagate = solver->trail.begin; + kissat_probing_propagate (solver, 0, true); + } + + uint64_t eliminated = equivalences + units; +#ifndef QUIET + assert (solver->active >= inactive); + solver->active -= inactive; + REPORT (!eliminated, '='); + solver->active += inactive; +#else + (void) inactive; +#endif + if (kissat_average (eliminated, swept) < 0.001) + BUMP_DELAY (sweep); + else + REDUCE_DELAY (sweep); + STOP (sweep); + return eliminated; +} diff --git a/src/sat/kissat/sweep.h b/src/sat/kissat/sweep.h new file mode 100644 index 000000000..a0f81b8b0 --- /dev/null +++ b/src/sat/kissat/sweep.h @@ -0,0 +1,9 @@ +#ifndef _sweep_h_INCLUDED +#define _sweep_h_INCLUDED + +#include + +struct kissat; +bool kissat_sweep (struct kissat *); + +#endif diff --git a/src/sat/kissat/terminate.c b/src/sat/kissat/terminate.c new file mode 100644 index 000000000..c1cfe7549 --- /dev/null +++ b/src/sat/kissat/terminate.c @@ -0,0 +1,15 @@ +#include "terminate.h" +#include "print.h" + +#ifndef QUIET + +void kissat_report_termination (kissat *solver, const char *name, + const char *file, long lineno, + const char *fun) { + kissat_very_verbose (solver, "%s:%ld: %s: 'TERMINATED (%s)' triggered", + file, lineno, fun, name); +} + +#else +int kissat_terminate_dummy_to_avoid_warning; +#endif diff --git a/src/sat/kissat/terminate.h b/src/sat/kissat/terminate.h new file mode 100644 index 000000000..731f584b8 --- /dev/null +++ b/src/sat/kissat/terminate.h @@ -0,0 +1,86 @@ +#ifndef _terminate_h_INCLUDED +#define _terminate_h_INCLUDED + +#include "internal.h" + +#ifndef QUIET +void kissat_report_termination (kissat *, const char *name, + const char *file, long lineno, + const char *fun); +#endif + +static inline bool kissat_terminated (kissat *solver, int bit, + const char *name, const char *file, + long lineno, const char *fun) { + assert (0 <= bit), assert (bit < 64); +#ifdef COVERAGE + const uint64_t mask = (uint64_t) 1 << bit; + if (!(solver->termination.flagged & mask)) + return false; + solver->termination.flagged = ~(uint64_t) 0; +#else + if (!solver->termination.flagged) + return false; +#endif +#ifndef QUIET + kissat_report_termination (solver, name, file, lineno, fun); +#else + (void) file; + (void) fun; + (void) lineno; + (void) name; +#endif +#if !defined(COVERAGE) && defined(NDEBUG) + (void) bit; +#endif + return true; +} + +#define TERMINATED(BIT) \ + kissat_terminated (solver, BIT, #BIT, __FILE__, __LINE__, __func__) + +#define backbone_terminated_1 1 +#define backbone_terminated_2 2 +#define backbone_terminated_3 3 +#define congruence_terminated_1 4 +#define congruence_terminated_2 5 +#define congruence_terminated_3 6 +#define congruence_terminated_4 7 +#define congruence_terminated_5 8 +#define congruence_terminated_6 9 +#define congruence_terminated_7 10 +#define congruence_terminated_8 11 +#define congruence_terminated_9 12 +#define congruence_terminated_10 13 +#define congruence_terminated_11 14 +#define congruence_terminated_12 15 +#define eliminate_terminated_1 16 +#define eliminate_terminated_2 17 +#define factor_terminated_1 18 +#define fastel_terminated_1 19 +#define forward_terminated_1 20 +#define kitten_terminated_1 21 +#define kitten_terminated_2 22 +#define preprocess_terminated_1 23 +#define search_terminated_1 24 +#define substitute_terminated_1 25 +#define sweep_terminated_1 26 +#define sweep_terminated_2 27 +#define sweep_terminated_3 28 +#define sweep_terminated_4 29 +#define sweep_terminated_5 30 +#define sweep_terminated_6 31 +#define sweep_terminated_7 32 +#define sweep_terminated_8 33 +#define transitive_terminated_1 34 +#define transitive_terminated_2 35 +#define transitive_terminated_3 36 +#define vivify_terminated_1 37 +#define vivify_terminated_2 38 +#define vivify_terminated_3 39 +#define vivify_terminated_4 40 +#define vivify_terminated_5 41 +#define walk_terminated_1 42 +#define warmup_terminated_1 43 + +#endif diff --git a/src/sat/kissat/tiers.c b/src/sat/kissat/tiers.c new file mode 100644 index 000000000..3fb49e104 --- /dev/null +++ b/src/sat/kissat/tiers.c @@ -0,0 +1,161 @@ +#include "tiers.h" +#include "internal.h" +#include "logging.h" +#include "print.h" + +static void compute_tier_limits (kissat *solver, bool stable, + unsigned *tier1_ptr, unsigned *tier2_ptr) { + statistics *statistics = &solver->statistics; + uint64_t *used_stats = statistics->used[stable].glue; + uint64_t total_used = 0; + for (unsigned glue = 0; glue <= MAX_GLUE_USED; glue++) + total_used += used_stats[glue]; + int tier1 = -1, tier2 = -1; + if (total_used) { + uint64_t accumulated_tier1_limit = total_used * TIER1RELATIVE; + uint64_t accumulated_tier2_limit = total_used * TIER2RELATIVE; + uint64_t accumulated_used = 0; + unsigned glue; + for (glue = 0; glue <= MAX_GLUE_USED; glue++) { + uint64_t glue_used = used_stats[glue]; + accumulated_used += glue_used; + if (accumulated_used >= accumulated_tier1_limit) { + tier1 = glue; + break; + } + } + if (accumulated_used < accumulated_tier2_limit) { + for (glue = tier1 + 1; glue <= MAX_GLUE_USED; glue++) { + uint64_t glue_used = used_stats[glue]; + accumulated_used += glue_used; + if (accumulated_used >= accumulated_tier2_limit) { + tier2 = glue; + break; + } + } + } + } + if (tier1 < 0) { + tier1 = GET_OPTION (tier1); + tier2 = MAX (GET_OPTION (tier2), tier1); + } else if (tier2 < 0) + tier2 = tier1; + assert (0 <= tier1); + assert (0 <= tier2); + *tier1_ptr = tier1; + *tier2_ptr = tier2; + LOG ("%s tier1 limit %u", stable ? "stable" : "focused", tier1); + LOG ("%s tier2 limit %u", stable ? "stable" : "focused", tier2); +} + +void kissat_compute_and_set_tier_limits (struct kissat *solver) { + bool stable = solver->stable; + unsigned tier1, tier2; + compute_tier_limits (solver, stable, &tier1, &tier2); + solver->tier1[stable] = tier1; + solver->tier2[stable] = tier2; + kissat_phase (solver, "retiered", GET (retiered), + "recomputed %s tier1 limit %u and tier2 limit %u " + "after %" PRIu64 " conflicts", + stable ? "stable" : "focused", tier1, tier2, CONFLICTS); +} + +static unsigned decimal_digits (uint64_t i) { + unsigned res = 1; + uint64_t limit = 10; + for (;;) { + if (i < limit) + return res; + limit *= 10; + res++; + } +} + +void kissat_print_tier_usage_statistics (kissat *solver, bool stable) { + unsigned tier1, tier2; + compute_tier_limits (solver, stable, &tier1, &tier2); + statistics *statistics = &solver->statistics; + uint64_t *used_stats = statistics->used[stable].glue; + uint64_t total_used = 0; + for (unsigned glue = 0; glue <= MAX_GLUE_USED; glue++) + total_used += used_stats[glue]; + const char *mode = stable ? "stable" : "focused"; + assert (tier1 <= tier2); + unsigned span = tier2 - tier1 + 1; + const unsigned max_printed = 5; + assert (max_printed & 1), assert (max_printed / 2 > 0); + unsigned prefix, suffix; + if (span > max_printed) { + prefix = tier1 + max_printed / 2 - 1; + suffix = tier2 - max_printed / 2 + 1; + } else + prefix = UINT_MAX, suffix = 0; + uint64_t accumulated_middle = 0; + int glue_digits = 1, clauses_digits = 1; + for (unsigned glue = 0; glue <= MAX_GLUE_USED; glue++) { + if (glue < tier1) + continue; + uint64_t used = used_stats[glue]; + int tmp_glue = 0, tmp_clauses = 0; + if (glue <= prefix || suffix <= glue) { + tmp_glue = decimal_digits (glue); + tmp_clauses = decimal_digits (used); + } else { + accumulated_middle += used; + if (glue + 1 == suffix) { + tmp_glue = decimal_digits (prefix + 1) + decimal_digits (glue) + 1; + tmp_clauses = decimal_digits (accumulated_middle); + } + } + if (tmp_glue > glue_digits) + glue_digits = tmp_glue; + if (tmp_clauses > clauses_digits) + clauses_digits = tmp_clauses; + if (glue == tier2) + break; + } + char fmt[32]; + sprintf (fmt, "%%%d" PRIu64, clauses_digits); + accumulated_middle = 0; + uint64_t accumulated = 0; + for (unsigned glue = 0; glue <= MAX_GLUE_USED; glue++) { + uint64_t used = used_stats[glue]; + accumulated += used; + if (glue < tier1) + continue; + if (glue <= prefix || suffix <= glue + 1) { + fputs (solver->prefix, stdout); + fputs (mode, stdout); + fputs (" glue ", stdout); + } + if (glue <= prefix || suffix <= glue) { + int len = printf ("%u", glue); + while (len > 0 && len < glue_digits) + fputc (' ', stdout), len++; + fputs (" used ", stdout); + printf (fmt, used); + printf (" clauses %5.2f%% accumulated %5.2f%%", + kissat_percent (used, total_used), + kissat_percent (accumulated, total_used)); + if (glue == tier1) + fputs (" tier1", stdout); + if (glue == tier2) + fputs (" tier2", stdout); + fputc ('\n', stdout); + } else { + accumulated_middle += used; + if (glue + 1 == suffix) { + int len = printf ("%u-%u", prefix + 1, suffix - 1); + while (len > 0 && len < glue_digits) + fputc (' ', stdout), len++; + fputs (" used ", stdout); + printf (fmt, accumulated_middle); + printf (" clauses %5.2f%% accumulated %5.2f%%\n", + kissat_percent (accumulated_middle, total_used), + kissat_percent (accumulated, total_used)); + } + } + if (glue == tier2) + break; + } +} diff --git a/src/sat/kissat/tiers.h b/src/sat/kissat/tiers.h new file mode 100644 index 000000000..3b7acb284 --- /dev/null +++ b/src/sat/kissat/tiers.h @@ -0,0 +1,12 @@ +#ifndef _tiers_h_INCLUDED +#define _tiers_h_INCLUDED + +#include + +struct kissat; + +void kissat_compute_and_set_tier_limits (struct kissat *); +void kissat_print_tier_usage_statistics (struct kissat *solver, + bool stable); + +#endif diff --git a/src/sat/kissat/trail.c b/src/sat/kissat/trail.c new file mode 100644 index 000000000..8b1882f53 --- /dev/null +++ b/src/sat/kissat/trail.c @@ -0,0 +1,92 @@ +#include "trail.h" +#include "backtrack.h" +#include "inline.h" +#include "propsearch.h" + +void kissat_flush_trail (kissat *solver) { + assert (!solver->level); + assert (solver->unflushed); + assert (!solver->inconsistent); + assert (kissat_propagated (solver)); + assert (SIZE_ARRAY (solver->trail) == solver->unflushed); + LOG ("flushed %zu units from trail", SIZE_ARRAY (solver->trail)); + CLEAR_ARRAY (solver->trail); + kissat_reset_propagate (solver); + solver->unflushed = 0; +} + +void kissat_mark_reason_clauses (kissat *solver, reference start) { + LOG ("starting marking reason clauses at clause[%" REFERENCE_FORMAT "]", + start); + assert (!solver->unflushed); +#ifdef LOGGING + unsigned reasons = 0; +#endif + ward *arena = BEGIN_STACK (solver->arena); + for (all_stack (unsigned, lit, solver->trail)) { + assigned *a = ASSIGNED (lit); + assert (a->level > 0); + if (a->binary) + continue; + const reference ref = a->reason; + assert (ref != UNIT_REASON); + if (ref == DECISION_REASON) + continue; + if (ref < start) + continue; + clause *c = (clause *) (arena + ref); + assert (kissat_clause_in_arena (solver, c)); + c->reason = true; +#ifdef LOGGING + reasons++; +#endif + } + LOG ("marked %u reason clauses", reasons); +} + +bool kissat_flush_and_mark_reason_clauses (kissat *solver, + reference start) { + assert (solver->watching); + assert (!solver->inconsistent); + assert (kissat_propagated (solver)); + + if (solver->unflushed) { + LOG ("need to flush %u units from trail", solver->unflushed); + kissat_backtrack_propagate_and_flush_trail (solver); + } else { + LOG ("no need to flush units from trail (all units already flushed)"); + kissat_mark_reason_clauses (solver, start); + } + + return true; +} + +void kissat_unmark_reason_clauses (kissat *solver, reference start) { + LOG ("starting unmarking reason clauses at clause[%" REFERENCE_FORMAT "]", + start); + assert (!solver->unflushed); +#ifdef LOGGING + unsigned reasons = 0; +#endif + ward *arena = BEGIN_STACK (solver->arena); + for (all_stack (unsigned, lit, solver->trail)) { + assigned *a = ASSIGNED (lit); + assert (a->level > 0); + if (a->binary) + continue; + const reference ref = a->reason; + assert (ref != UNIT_REASON); + if (ref == DECISION_REASON) + continue; + if (ref < start) + continue; + clause *c = (clause *) (arena + ref); + assert (kissat_clause_in_arena (solver, c)); + assert (c->reason); + c->reason = false; +#ifdef LOGGING + reasons++; +#endif + } + LOG ("unmarked %u reason clauses", reasons); +} diff --git a/src/sat/kissat/trail.h b/src/sat/kissat/trail.h new file mode 100644 index 000000000..ca84203f2 --- /dev/null +++ b/src/sat/kissat/trail.h @@ -0,0 +1,16 @@ +#ifndef _trail_h_INLCUDED +#define _trail_h_INLCUDED + +#include "reference.h" + +#include + +struct kissat; + +void kissat_flush_trail (struct kissat *); +bool kissat_flush_and_mark_reason_clauses (struct kissat *, + reference start); +void kissat_unmark_reason_clauses (struct kissat *, reference start); +void kissat_mark_reason_clauses (struct kissat *, reference start); + +#endif diff --git a/src/sat/kissat/transitive.c b/src/sat/kissat/transitive.c new file mode 100644 index 000000000..2c06ff5e5 --- /dev/null +++ b/src/sat/kissat/transitive.c @@ -0,0 +1,389 @@ +#include "transitive.h" +#include "allocate.h" +#include "analyze.h" +#include "heap.h" +#include "inline.h" +#include "inlinevector.h" +#include "logging.h" +#include "print.h" +#include "proprobe.h" +#include "report.h" +#include "sort.h" +#include "terminate.h" +#include "trail.h" + +#include + +static void transitive_assign (kissat *solver, unsigned lit) { + LOG ("transitive assign %s", LOGLIT (lit)); + value *values = solver->values; + const unsigned not_lit = NOT (lit); + assert (!values[lit]); + assert (!values[not_lit]); + values[lit] = 1; + values[not_lit] = -1; + PUSH_ARRAY (solver->trail, lit); +} + +static void transitive_backtrack (kissat *solver, unsigned *saved) { + value *values = solver->values; + + unsigned *end_trail = END_ARRAY (solver->trail); + assert (saved <= end_trail); + + while (end_trail != saved) { + const unsigned lit = *--end_trail; + LOG ("transitive unassign %s", LOGLIT (lit)); + const unsigned not_lit = NOT (lit); + assert (values[lit] > 0); + assert (values[not_lit] < 0); + values[lit] = values[not_lit] = 0; + } + + SET_END_OF_ARRAY (solver->trail, saved); + solver->propagate = saved; + solver->level = 0; +} + +static void prioritize_binaries (kissat *solver) { + assert (solver->watching); + statches large; + INIT_STACK (large); + watches *all_watches = solver->watches; + for (all_literals (lit)) { + assert (EMPTY_STACK (large)); + watches *watches = all_watches + lit; + watch *begin_watches = BEGIN_WATCHES (*watches), *q = begin_watches; + const watch *const end_watches = END_WATCHES (*watches), *p = q; + while (p != end_watches) { + const watch head = *q++ = *p++; + if (head.type.binary) + continue; + const watch tail = *p++; + PUSH_STACK (large, head); + PUSH_STACK (large, tail); + q--; + } + const watch *const end_large = END_STACK (large); + watch const *r = BEGIN_STACK (large); + while (r != end_large) + *q++ = *r++; + assert (q == end_watches); + CLEAR_STACK (large); + } + RELEASE_STACK (large); +} + +static bool transitive_reduce (kissat *solver, unsigned src, uint64_t limit, + uint64_t *reduced_ptr, unsigned *units) { + bool res = false; + assert (!VALUE (src)); + LOG ("transitive reduce %s", LOGLIT (src)); + watches *all_watches = solver->watches; + watches *src_watches = all_watches + src; + watch *end_src = END_WATCHES (*src_watches); + watch *begin_src = BEGIN_WATCHES (*src_watches); + const size_t size_src_watches = SIZE_WATCHES (*src_watches); + const unsigned src_ticks = + 1 + kissat_cache_lines (size_src_watches, sizeof (watch)); + ADD (transitive_ticks, src_ticks); + ADD (probing_ticks, src_ticks); + ADD (ticks, src_ticks); + INC (transitive_probes); + const unsigned not_src = NOT (src); + unsigned reduced = 0; + bool failed = false; + for (watch *p = begin_src; p != end_src; p++) { + const watch src_watch = *p; + if (!src_watch.type.binary) + break; + const unsigned dst = src_watch.binary.lit; + if (dst < src) + continue; + if (VALUE (dst)) + continue; + assert (kissat_propagated (solver)); + unsigned *saved = solver->propagate; + assert (!solver->level); + solver->level = 1; + transitive_assign (solver, not_src); + bool transitive = false; + unsigned inner_ticks = 0; + unsigned *propagate = solver->propagate; + while (!transitive && !failed && + propagate != END_ARRAY (solver->trail)) { + const unsigned lit = *propagate++; + LOG ("transitive propagate %s", LOGLIT (lit)); + assert (VALUE (lit) > 0); + const unsigned not_lit = NOT (lit); + watches *lit_watches = all_watches + not_lit; + const watch *const end_lit = END_WATCHES (*lit_watches); + const watch *const begin_lit = BEGIN_WATCHES (*lit_watches); + const size_t size_lit_watches = SIZE_WATCHES (*lit_watches); + inner_ticks += + 1 + kissat_cache_lines (size_lit_watches, sizeof (watch)); + for (const watch *q = begin_lit; q != end_lit; q++) { + if (p == q) + continue; + const watch lit_watch = *q; + if (!lit_watch.type.binary) + break; + if (not_lit == src && lit_watch.binary.lit == ILLEGAL_LIT) + continue; + const unsigned other = lit_watch.binary.lit; + if (other == dst) { + transitive = true; + break; + } + const value value = VALUE (other); + if (value < 0) { + LOG ("both %s and %s reachable from %s", LOGLIT (NOT (other)), + LOGLIT (other), LOGLIT (src)); + failed = true; + break; + } + if (!value) + transitive_assign (solver, other); + } + } + + assert (solver->probing); + + assert (solver->propagate <= propagate); + const unsigned propagated = propagate - solver->propagate; + + ADD (transitive_propagations, propagated); + ADD (probing_propagations, propagated); + ADD (propagations, propagated); + + ADD (transitive_ticks, inner_ticks); + ADD (probing_ticks, inner_ticks); + ADD (ticks, inner_ticks); + + transitive_backtrack (solver, saved); + + if (transitive) { + LOGBINARY (src, dst, "transitive reduce"); + INC (transitive_reduced); + watches *dst_watches = all_watches + dst; + watch dst_watch = src_watch; + assert (dst_watch.binary.lit == dst); + dst_watch.binary.lit = src; + REMOVE_WATCHES (*dst_watches, dst_watch); + kissat_delete_binary (solver, src, dst); + p->binary.lit = ILLEGAL_LIT; + reduced++; + res = true; + } + + if (failed) + break; + if (solver->statistics.transitive_ticks > limit) + break; + if (TERMINATED (transitive_terminated_1)) + break; + } + + if (reduced) { + *reduced_ptr += reduced; + assert (begin_src == BEGIN_WATCHES (WATCHES (src))); + assert (end_src == END_WATCHES (WATCHES (src))); + watch *q = begin_src; + for (const watch *p = begin_src; p != end_src; p++) { + const watch src_watch = *q++ = *p; + if (!src_watch.type.binary) { + *q++ = *++p; + continue; + } + if (src_watch.binary.lit == ILLEGAL_LIT) + q--; + } + assert (end_src - q == (ptrdiff_t) reduced); + SET_END_OF_WATCHES (*src_watches, q); + } + + if (failed) { + LOG ("transitive failed literal %s", LOGLIT (not_src)); + INC (transitive_units); + *units += 1; + res = true; + + kissat_learned_unit (solver, src); + + assert (!solver->level); + (void) kissat_probing_propagate (solver, 0, true); + } + + return res; +} + +static inline bool less_stable_transitive (kissat *solver, + const flags *const flags, + const heap *scores, unsigned a, + unsigned b) { +#ifdef NDEBUG + (void) solver; +#endif + const unsigned i = IDX (a); + const unsigned j = IDX (b); + const bool p = flags[i].transitive; + const bool q = flags[j].transitive; + if (!p && q) + return true; + if (p && !q) + return false; + const double s = kissat_get_heap_score (scores, i); + const double t = kissat_get_heap_score (scores, j); + if (s < t) + return true; + if (s > t) + return false; + return i < j; +} + +static inline unsigned less_focused_transitive (kissat *solver, + const flags *const flags, + const links *links, + unsigned a, unsigned b) { +#ifdef NDEBUG + (void) solver; +#endif + const unsigned i = IDX (a); + const unsigned j = IDX (b); + const bool p = flags[i].transitive; + const bool q = flags[j].transitive; + if (!p && q) + return true; + if (p && !q) + return false; + const unsigned s = links[i].stamp; + const unsigned t = links[j].stamp; + return s < t; +} + +#define LESS_STABLE_PROBE(A, B) \ + less_stable_transitive (solver, flags, scores, (A), (B)) + +#define LESS_FOCUSED_PROBE(A, B) \ + less_focused_transitive (solver, flags, links, (A), (B)) + +static void sort_stable_transitive (kissat *solver, unsigneds *probes) { + const flags *const flags = solver->flags; + const heap *const scores = SCORES; + SORT_STACK (unsigned, *probes, LESS_STABLE_PROBE); +} + +static void sort_focused_transitive (kissat *solver, unsigneds *probes) { + const flags *const flags = solver->flags; + const links *const links = solver->links; + SORT_STACK (unsigned, *probes, LESS_FOCUSED_PROBE); +} + +static void sort_transitive (kissat *solver, unsigneds *probes) { + if (solver->stable) + sort_stable_transitive (solver, probes); + else + sort_focused_transitive (solver, probes); +} + +static void schedule_transitive (kissat *solver, unsigneds *probes) { + assert (EMPTY_STACK (*probes)); + for (all_variables (idx)) + if (ACTIVE (idx)) + PUSH_STACK (*probes, idx); + sort_transitive (solver, probes); + kissat_very_verbose (solver, "scheduled %zu transitive probes", + SIZE_STACK (*probes)); +} + +void kissat_transitive_reduction (kissat *solver) { + if (solver->inconsistent) + return; + assert (solver->watching); + assert (solver->probing); + assert (!solver->level); + if (!GET_OPTION (transitive)) + return; + if (TERMINATED (transitive_terminated_2)) + return; + START (transitive); + INC (transitive_reductions); +#if !defined(NDEBUG) || defined(METRICS) + assert (!solver->transitive_reducing); + solver->transitive_reducing = true; +#endif + prioritize_binaries (solver); + bool success = false; + uint64_t reduced = 0; + unsigned units = 0; + + SET_EFFORT_LIMIT (limit, transitive, transitive_ticks); + +#ifndef QUIET + const unsigned active = solver->active; + const uint64_t old_ticks = solver->statistics.transitive_ticks; + kissat_extremely_verbose ( + solver, "starting with %" PRIu64 " transitive ticks", old_ticks); + unsigned probed = 0; +#endif + unsigneds probes; + INIT_STACK (probes); + schedule_transitive (solver, &probes); + bool terminate = false; + while (!terminate && !EMPTY_STACK (probes)) { + const unsigned idx = POP_STACK (probes); + solver->flags[idx].transitive = false; + if (!ACTIVE (idx)) + continue; + for (unsigned sign = 0; !terminate && sign < 2; sign++) { + const unsigned lit = 2 * idx + sign; + if (solver->values[lit]) + continue; +#ifndef QUIET + probed++; +#endif + if (transitive_reduce (solver, lit, limit, &reduced, &units)) + success = true; + if (solver->inconsistent) + terminate = true; + else if (solver->statistics.transitive_ticks > limit) + terminate = true; + else if (TERMINATED (transitive_terminated_3)) + terminate = true; + } + } + const size_t remain = SIZE_STACK (probes); + if (remain) { + if (!GET_OPTION (transitivekeep)) { + kissat_very_verbose ( + solver, "dropping remaining %zu transitive candidates", remain); + while (!EMPTY_STACK (probes)) { + const unsigned idx = POP_STACK (probes); + solver->flags[idx].transitive = false; + } + } + } else + kissat_very_verbose (solver, "transitive reduction complete"); + RELEASE_STACK (probes); + +#ifndef QUIET + const uint64_t new_ticks = solver->statistics.transitive_ticks; + const uint64_t delta_ticks = new_ticks - old_ticks; + kissat_extremely_verbose ( + solver, "finished at %" PRIu64 " after %" PRIu64 " transitive ticks", + new_ticks, delta_ticks); +#endif + kissat_phase (solver, "transitive", GET (probings), + "probed %u (%.0f%%): reduced %" PRIu64 ", units %u", probed, + kissat_percent (probed, 2 * active), reduced, units); + +#if !defined(NDEBUG) || defined(METRICS) + assert (solver->transitive_reducing); + solver->transitive_reducing = false; +#endif + REPORT (!success, 't'); + STOP (transitive); +#ifdef QUIET + (void) success; +#endif +} diff --git a/src/sat/kissat/transitive.h b/src/sat/kissat/transitive.h new file mode 100644 index 000000000..ec0011460 --- /dev/null +++ b/src/sat/kissat/transitive.h @@ -0,0 +1,8 @@ +#ifndef _transitive_h_INCLUDED +#define _transitive_h_INCLUDED + +struct kissat; + +void kissat_transitive_reduction (struct kissat *); + +#endif diff --git a/src/sat/kissat/utilities.c b/src/sat/kissat/utilities.c new file mode 100644 index 000000000..4ea4e0b8f --- /dev/null +++ b/src/sat/kissat/utilities.c @@ -0,0 +1,16 @@ +#include "utilities.h" + +#include + +bool kissat_has_suffix (const char *str, const char *suffix) { + const char *p = str; + while (*p) + p++; + const char *q = suffix; + while (*q) + q++; + while (p > str && q > suffix) + if (*--p != *--q) + return false; + return q == suffix; +} diff --git a/src/sat/kissat/utilities.h b/src/sat/kissat/utilities.h new file mode 100644 index 000000000..392aaafef --- /dev/null +++ b/src/sat/kissat/utilities.h @@ -0,0 +1,136 @@ +#ifndef _utilities_h_INCLUDED +#define _utilities_h_INCLUDED + +#include +#include +#include +#include + +typedef uintptr_t word; +typedef uintptr_t w2rd[2]; + +#define WORD_ALIGNMENT_MASK (sizeof (word) - 1) +#define W2RD_ALIGNMENT_MASK (sizeof (w2rd) - 1) + +#define WORD_FORMAT PRIuPTR + +#define MAX_SIZE_T (~(size_t) 0) + +#define ASSUMED_LD_CACHE_LINE_BYTES 7u + +static inline word kissat_cache_lines (word n, size_t size) { + if (!n) + return 0; +#ifdef NDEBUG + (void) size; +#endif + assert (size == 4); + assert (ASSUMED_LD_CACHE_LINE_BYTES > 2); + const unsigned shift = ASSUMED_LD_CACHE_LINE_BYTES - 2u; + const word mask = (((word) 1) << shift) - 1; + const word masked = n + mask; + const word res = masked >> shift; + return res; +} + +static inline double kissat_average (double a, double b) { + return b ? a / b : 0.0; +} + +static inline double kissat_percent (double a, double b) { + return kissat_average (100.0 * a, b); +} + +static inline bool kissat_aligned_word (word word) { + return !(word & WORD_ALIGNMENT_MASK); +} + +static inline bool kissat_aligned_pointer (const void *p) { + return kissat_aligned_word ((word) p); +} + +static inline word kissat_align_word (word w) { + word res = w; + if (res & WORD_ALIGNMENT_MASK) + res = 1 + (res | WORD_ALIGNMENT_MASK); + return res; +} + +static inline word kissat_align_w2rd (word w) { + word res = w; + if (res & W2RD_ALIGNMENT_MASK) + res = 1 + (res | W2RD_ALIGNMENT_MASK); + return res; +} + +bool kissat_has_suffix (const char *str, const char *suffix); + +static inline bool kissat_is_power_of_two (uint64_t w) { + return w && !(w & (w - 1)); +} + +static inline bool kissat_is_zero_or_power_of_two (word w) { + return !(w & (w - 1)); +} + +static inline unsigned kissat_leading_zeroes_of_unsigned (unsigned x) { + return x ? __builtin_clz (x) : sizeof (unsigned) * 8; +} + +static inline unsigned kissat_leading_zeroes_of_word (word x) { + if (!x) + return sizeof (word) * 8; + if (sizeof (word) == sizeof (unsigned long long)) + return __builtin_clzll (x); + if (sizeof (word) == sizeof (unsigned long)) + return __builtin_clzl (x); + return __builtin_clz (x); +} + +static inline unsigned kissat_log2_floor_of_word (word x) { + return x ? sizeof (word) * 8 - 1 - kissat_leading_zeroes_of_word (x) : 0; +} + +static inline unsigned kissat_log2_ceiling_of_word (word x) { + if (!x) + return 0; + unsigned tmp = kissat_log2_floor_of_word (x); + return tmp + !!(x ^ (((word) 1) << tmp)); +} + +static inline unsigned kissat_leading_zeroes_of_uint64 (uint64_t x) { + if (!x) + return sizeof (uint64_t) * 8; + if (sizeof (uint64_t) == sizeof (unsigned long long)) + return __builtin_clzll (x); + if (sizeof (uint64_t) == sizeof (unsigned long)) + return __builtin_clzl (x); + return __builtin_clz (x); +} + +static inline unsigned kissat_log2_floor_of_uint64 (uint64_t x) { + return x ? sizeof (uint64_t) * 8 - 1 - kissat_leading_zeroes_of_uint64 (x) + : 0; +} + +static inline unsigned kissat_log2_ceiling_of_uint64 (uint64_t x) { + if (!x) + return 0; + unsigned tmp = kissat_log2_floor_of_uint64 (x); + return tmp + !!(x ^ (((uint64_t) 1) << tmp)); +} + +#define SWAP(TYPE, A, B) \ + do { \ + TYPE TMP_SWAP = (A); \ + (A) = (B); \ + (B) = (TMP_SWAP); \ + } while (0) + +#define MIN(A, B) ((A) > (B) ? (B) : (A)) + +#define MAX(A, B) ((A) < (B) ? (B) : (A)) + +#define ABS(A) (assert ((int) (A) != INT_MIN), (A) < 0 ? -(A) : (A)) + +#endif diff --git a/src/sat/kissat/value.h b/src/sat/kissat/value.h new file mode 100644 index 000000000..efea7391a --- /dev/null +++ b/src/sat/kissat/value.h @@ -0,0 +1,13 @@ +#ifndef _value_h_INCLUDED +#define _value_h_INCLUDED + +typedef signed char value; +typedef signed char mark; + +#define VALUE(LIT) (solver->values[assert ((LIT) < LITS), (LIT)]) + +#define MARK(LIT) (solver->marks[assert ((LIT) < LITS), (LIT)]) + +#define BOOL_TO_VALUE(B) ((signed char) ((B) ? -1 : 1)) + +#endif diff --git a/src/sat/kissat/vector.c b/src/sat/kissat/vector.c new file mode 100644 index 000000000..728a66f6d --- /dev/null +++ b/src/sat/kissat/vector.c @@ -0,0 +1,320 @@ +#include "allocate.h" +#include "collect.h" +#include "error.h" +#include "inlinevector.h" +#include "logging.h" +#include "print.h" +#include "rank.h" + +#include +#include + +#ifndef COMPACT + +static void fix_vector_pointers_after_moving_stack (kissat *solver, + ptrdiff_t moved) { +#ifdef LOGGING + uint64_t bytes = moved < 0 ? -moved : moved; + LOG ("fixing begin and end pointers of all watches " + "since the global watches stack has been moved by %s", + FORMAT_BYTES (bytes)); +#endif + struct vector *begin_watches = solver->watches; + struct vector *end_watches = begin_watches + LITS; + for (struct vector *p = begin_watches; p != end_watches; p++) { + +#define FIX_POINTER(PTR) \ + do { \ + char *old_char_ptr_value = (char *) (PTR); \ + if (!old_char_ptr_value) \ + break; \ + char *new_char_ptr_value = old_char_ptr_value + moved; \ + unsigned *new_unsigned_ptr_value = (unsigned *) new_char_ptr_value; \ + (PTR) = new_unsigned_ptr_value; \ + } while (0) + + FIX_POINTER (p->begin); + FIX_POINTER (p->end); + } +} + +#endif + +unsigned *kissat_enlarge_vector (kissat *solver, vector *vector) { + unsigneds *stack = &solver->vectors.stack; + const size_t old_vector_size = kissat_size_vector (vector); +#ifdef LOGGING + const size_t old_offset = kissat_offset_vector (solver, vector); + LOG2 ("enlarging vector %zu[%zu] at %p", old_offset, old_vector_size, + (void *) vector); +#endif + assert (old_vector_size < MAX_VECTORS / 2); + const size_t new_vector_size = old_vector_size ? 2 * old_vector_size : 1; + size_t old_stack_size = SIZE_STACK (*stack); + size_t capacity = CAPACITY_STACK (*stack); + assert (kissat_is_power_of_two (MAX_VECTORS)); + assert (capacity <= MAX_VECTORS); + size_t available = capacity - old_stack_size; + if (new_vector_size > available) { +#if !defined(QUIET) || !defined(COMPACT) + unsigned *old_begin_stack = BEGIN_STACK (*stack); +#endif + unsigned enlarged = 0; + do { + assert (kissat_is_zero_or_power_of_two (capacity)); + + if (capacity == MAX_VECTORS) + kissat_fatal ("maximum vector stack size " + "of 2^%u entries %s exhausted", + LD_MAX_VECTORS, + FORMAT_BYTES (MAX_VECTORS * sizeof (unsigned))); + enlarged++; + kissat_stack_enlarge (solver, (chars *) stack, sizeof (unsigned)); + + capacity = CAPACITY_STACK (*stack); + available = capacity - old_stack_size; + } while (new_vector_size > available); + + if (enlarged) { + INC (vectors_enlarged); +#if !defined(QUIET) || !defined(COMPACT) + unsigned *new_begin_stack = BEGIN_STACK (*stack); + const ptrdiff_t moved = + (char *) new_begin_stack - (char *) old_begin_stack; +#endif +#ifndef QUIET + kissat_phase (solver, "vectors", GET (vectors_enlarged), + "enlarged to %s entries %s (%s)", + FORMAT_COUNT (capacity), + FORMAT_BYTES (capacity * sizeof (unsigned)), + (moved ? "moved" : "in place")); +#endif +#ifndef COMPACT + if (moved) + fix_vector_pointers_after_moving_stack (solver, moved); +#endif + } + assert (capacity <= MAX_VECTORS); + assert (new_vector_size <= available); + } + unsigned *begin_old_vector = kissat_begin_vector (solver, vector); + unsigned *begin_new_vector = END_STACK (*stack); + unsigned *middle_new_vector = begin_new_vector + old_vector_size; + unsigned *end_new_vector = begin_new_vector + new_vector_size; + assert (end_new_vector <= stack->allocated); + const size_t old_bytes = old_vector_size * sizeof (unsigned); + const size_t delta_size = new_vector_size - old_vector_size; + assert (MAX_SIZE_T / sizeof (unsigned) >= delta_size); + const size_t delta_bytes = delta_size * sizeof (unsigned); + if (old_bytes) { + memcpy (begin_new_vector, begin_old_vector, old_bytes); + memset (begin_old_vector, 0xff, old_bytes); + } + solver->vectors.usable += old_vector_size; + kissat_add_usable (solver, delta_size); + if (delta_bytes) + memset (middle_new_vector, 0xff, delta_bytes); +#ifdef COMPACT + const uint64_t offset = SIZE_STACK (*stack); + assert (offset <= MAX_VECTORS); + vector->offset = offset; + LOG2 ("enlarged vector at %p to %u[%u]", (void *) vector, vector->offset, + vector->size); +#else + vector->begin = begin_new_vector; + vector->end = middle_new_vector; +#ifdef LOGGING + const size_t new_offset = vector->begin - stack->begin; + LOG2 ("enlarged vector at %p to %zu[%zu]", (void *) vector, new_offset, + old_vector_size); +#endif +#endif + stack->end = end_new_vector; + assert (begin_new_vector < end_new_vector); + assert (kissat_size_vector (vector) == old_vector_size); + return middle_new_vector; +} + +#ifdef COMPACT + +typedef unsigned rank; + +static inline rank rank_offset (vector *unsorted, unsigned i) { + return unsorted[i].offset; +} + +#else + +typedef uintptr_t rank; + +static inline rank rank_offset (vector *unsorted, unsigned i) { + const unsigned *begin = unsorted[i].begin; + return (uintptr_t) begin; +} + +#endif + +#define RANK_OFFSET(A) rank_offset (unsorted, (A)) + +void kissat_defrag_vectors (kissat *solver, size_t size_unsorted, + vector *unsorted) { + unsigneds *stack = &solver->vectors.stack; + const size_t size_vectors = SIZE_STACK (*stack); + if (size_vectors < 2) + return; + START (defrag); + INC (defragmentations); + LOG ("defragmenting vectors size %zu capacity %zu usable %zu", + size_vectors, CAPACITY_STACK (*stack), solver->vectors.usable); + size_t bytes = size_unsorted * sizeof (unsigned); + unsigned *sorted = kissat_malloc (solver, bytes); + unsigned size_sorted = 0; + for (unsigned i = 0; i < size_unsorted; i++) { + vector *vector = unsorted + i; + if (kissat_empty_vector (vector)) +#ifdef COMPACT + vector->offset = 0; +#else + vector->begin = vector->end = 0; +#endif + else + sorted[size_sorted++] = i; + } + RADIX_SORT (unsigned, rank, size_sorted, sorted, RANK_OFFSET); + unsigned *old_begin_stack = BEGIN_STACK (*stack); + unsigned *p = old_begin_stack + 1; + for (unsigned i = 0; i < size_sorted; i++) { + unsigned j = sorted[i]; + vector *vector = unsorted + j; + const size_t size = kissat_size_vector (vector); + unsigned *new_end_of_vector = p + size; +#ifdef COMPACT + const unsigned old_offset = vector->offset; + const unsigned new_offset = p - old_begin_stack; + assert (new_offset <= old_offset); + vector->offset = new_offset; + const unsigned *const q = old_begin_stack + old_offset; +#else + if (!size) { + vector->begin = vector->end = 0; + continue; + } + const unsigned *const q = vector->begin; + vector->begin = p; + vector->end = new_end_of_vector; +#endif + assert (MAX_SIZE_T / sizeof (unsigned) >= size); + memmove (p, q, size * sizeof (unsigned)); + p = new_end_of_vector; + } + kissat_free (solver, sorted, bytes); +#ifndef QUIET + const size_t freed = END_STACK (*stack) - p; + double freed_fraction = kissat_percent (freed, size_vectors); + kissat_phase (solver, "defrag", GET (defragmentations), + "freed %zu usable entries %.0f%% thus %s", freed, + freed_fraction, FORMAT_BYTES (freed * sizeof (unsigned))); + assert (freed == solver->vectors.usable); +#endif + SET_END_OF_STACK (*stack, p); +#ifndef COMPACT + assert (old_begin_stack == BEGIN_STACK (*stack)); +#endif + SHRINK_STACK (*stack); +#ifndef COMPACT + unsigned *new_begin_stack = BEGIN_STACK (*stack); + const ptrdiff_t moved = + (char *) new_begin_stack - (char *) old_begin_stack; + if (moved) + fix_vector_pointers_after_moving_stack (solver, moved); +#endif + solver->vectors.usable = 0; + kissat_check_vectors (solver); + STOP (defrag); +} + +void kissat_remove_from_vector (kissat *solver, vector *vector, + unsigned remove) { + unsigned *begin = kissat_begin_vector (solver, vector), *p = begin; + const unsigned *const end = kissat_end_vector (solver, vector); + assert (p != end); + while (*p != remove) + p++, assert (p != end); + while (++p != end) + p[-1] = *p; + p[-1] = INVALID_VECTOR_ELEMENT; +#ifdef COMPACT + vector->size--; +#else + assert (vector->begin < vector->end); + vector->end--; +#endif + kissat_inc_usable (solver); + kissat_check_vectors (solver); +#ifndef CHECK_VECTORS + (void) solver; +#endif +} + +void kissat_resize_vector (kissat *solver, vector *vector, + size_t new_size) { + const size_t old_size = kissat_size_vector (vector); + assert (new_size <= old_size); + if (new_size == old_size) + return; +#ifdef COMPACT + vector->size = new_size; +#else + vector->end = vector->begin + new_size; +#endif + unsigned *begin = kissat_begin_vector (solver, vector); + unsigned *end = begin + new_size; + size_t delta = old_size - new_size; + kissat_add_usable (solver, delta); + size_t bytes = delta * sizeof (unsigned); + memset (end, 0xff, bytes); + kissat_check_vectors (solver); +#ifndef CHECK_VECTORS + (void) solver; +#endif +} + +void kissat_release_vectors (kissat *solver) { + RELEASE_STACK (solver->vectors.stack); + solver->vectors.usable = 0; +} + +#ifdef CHECK_VECTORS + +void kissat_check_vector (kissat *solver, vector *vector) { + const unsigned *const begin = kissat_begin_vector (solver, vector); + const unsigned *const end = kissat_end_vector (solver, vector); + if (!solver->transitive_reducing) + for (const unsigned *p = begin; p != end; p++) + assert (*p != INVALID_VECTOR_ELEMENT); +#ifdef NDEBUG + (void) solver; +#endif +} + +void kissat_check_vectors (kissat *solver) { + if (solver->transitive_reducing) + return; + for (all_literals (lit)) { + vector *vector = &WATCHES (lit); + kissat_check_vector (solver, vector); + } + vectors *vectors = &solver->vectors; + unsigneds *stack = &vectors->stack; + const unsigned *const begin = BEGIN_STACK (*stack); + const unsigned *const end = END_STACK (*stack); + if (begin == end) + return; + size_t invalid = 0; + for (const unsigned *p = begin + 1; p != end; p++) + if (*p == INVALID_VECTOR_ELEMENT) + invalid++; + assert (invalid == solver->vectors.usable); +} + +#endif diff --git a/src/sat/kissat/vector.h b/src/sat/kissat/vector.h new file mode 100644 index 000000000..55ff2ac1d --- /dev/null +++ b/src/sat/kissat/vector.h @@ -0,0 +1,55 @@ +#ifndef _vector_h_INCLUDED +#define _vector_h_INCLUDED + +#include "stack.h" +#include "utilities.h" + +#include + +#ifdef COMPACT +#define LD_MAX_VECTORS (sizeof (word) == 8 ? 32u : 28u) +#else +#define LD_MAX_VECTORS (sizeof (word) == 8 ? 48u : 28u) +#endif + +#define MAX_VECTORS (((uint64_t) 1) << LD_MAX_VECTORS) + +#define INVALID_VECTOR_ELEMENT UINT_MAX + +#define MAX_SECTOR MAX_SIZE_T + +typedef struct vector vector; +typedef struct vectors vectors; + +struct vectors { + unsigneds stack; + size_t usable; +}; + +struct vector { +#ifdef COMPACT + unsigned offset; + unsigned size; +#else + unsigned *begin; + unsigned *end; +#endif +}; + +struct kissat; + +#ifdef CHECK_VECTORS +void kissat_check_vectors (struct kissat *); +#else +#define kissat_check_vectors(...) \ + do { \ + } while (0) +#endif + +unsigned *kissat_enlarge_vector (struct kissat *, vector *); +void kissat_defrag_vectors (struct kissat *, size_t, vector *); +void kissat_remove_from_vector (struct kissat *, vector *, unsigned); +void kissat_resize_vector (struct kissat *, vector *, size_t); +void kissat_release_vectors (struct kissat *); + +#endif diff --git a/src/sat/kissat/vivify.c b/src/sat/kissat/vivify.c new file mode 100644 index 000000000..6627c640e --- /dev/null +++ b/src/sat/kissat/vivify.c @@ -0,0 +1,1480 @@ +#include "vivify.h" +#include "allocate.h" +#include "backtrack.h" +#include "collect.h" +#include "colors.h" +#include "decide.h" +#include "deduce.h" +#include "inline.h" +#include "print.h" +#include "promote.h" +#include "proprobe.h" +#include "rank.h" +#include "report.h" +#include "sort.h" +#include "terminate.h" +#include "tiers.h" +#include "trail.h" + +#include "cover.h" + +#include +#include + +static inline bool more_occurrences (unsigned *counts, unsigned a, + unsigned b) { + const unsigned s = counts[a], t = counts[b]; + return ((t - s) | ((b - a) & ~(s - t))) >> 31; +} + +#define MORE_OCCURRENCES(A, B) more_occurrences (counts, (A), (B)) + +static void vivify_sort_lits_by_counts (kissat *solver, size_t size, + unsigned *lits, unsigned *counts) { + SORT (unsigned, size, lits, MORE_OCCURRENCES); +} + +static void vivify_sort_stack_by_counts (kissat *solver, unsigneds *stack, + unsigned *counts) { + const size_t size = SIZE_STACK (*stack); + unsigned *lits = BEGIN_STACK (*stack); + vivify_sort_lits_by_counts (solver, size, lits, counts); +} + +static void vivify_sort_clause_by_counts (kissat *solver, clause *c, + unsigned *counts) { + vivify_sort_lits_by_counts (solver, c->size, c->lits, counts); +} + +static inline void count_literal (unsigned lit, unsigned *counts) { + counts[lit] += counts[lit] < (unsigned) INT_MAX; +} + +static void count_clause (clause *c, unsigned *counts) { + for (all_literals_in_clause (lit, c)) + count_literal (lit, counts); +} + +static bool simplify_vivification_candidate (kissat *solver, + clause *const c) { + assert (!solver->level); + CLEAR_STACK (solver->clause); + + const value *const values = solver->values; + + for (all_literals_in_clause (lit, c)) { + const value value = values[lit]; + if (value > 0) { + LOGCLS (c, "vivification %s satisfied candidate", LOGLIT (lit)); + kissat_mark_clause_as_garbage (solver, c); + return true; + } + if (!value) + PUSH_STACK (solver->clause, lit); + } + + unsigned non_false = SIZE_STACK (solver->clause); + assert (non_false <= c->size); + if (non_false == c->size) + return false; + + if (non_false == 2) { + const unsigned first = PEEK_STACK (solver->clause, 0); + const unsigned second = PEEK_STACK (solver->clause, 1); + LOGBINARY (first, second, "vivification shrunken candidate"); + kissat_new_binary_clause (solver, first, second); + kissat_mark_clause_as_garbage (solver, c); + return true; + } + + assert (2 < non_false); + + CHECK_AND_ADD_STACK (solver->clause); + ADD_STACK_TO_PROOF (solver->clause); + + REMOVE_CHECKER_CLAUSE (c); + DELETE_CLAUSE_FROM_PROOF (c); + + const unsigned old_size = c->size; + unsigned new_size = 0, *lits = c->lits; + for (unsigned i = 0; i < old_size; i++) { + const unsigned lit = lits[i]; + const value value = values[lit]; + assert (value <= 0); + if (!value) + lits[new_size++] = lit; + } + + assert (2 < new_size); + assert (new_size == non_false); + assert (new_size < old_size); + + c->size = new_size; + c->searched = 2; + + if (c->redundant && c->glue >= new_size) + kissat_promote_clause (solver, c, new_size - 1); + if (!c->shrunken) { + c->shrunken = true; + lits[old_size - 1] = INVALID_LIT; + } + + LOGCLS (c, "vivification shrunken candidate"); + LOG ("vivification candidate does not need to be simplified"); + + return false; +} + +static unsigned vivify_tier1_limit (kissat *solver) { + return GET_OPTION (vivifyfocusedtiers) ? solver->tier1[0] : TIER1; +} + +static unsigned vivify_tier2_limit (kissat *solver) { + return GET_OPTION (vivifyfocusedtiers) ? solver->tier2[0] : TIER2; +} + +#define COUNTREF_COUNTS 1 +#define LD_MAX_COUNTREF_SIZE 31 +#define MAX_COUNTREF_SIZE ((1u << LD_MAX_COUNTREF_SIZE) - 1) + +struct countref { + unsigned vivify : 1; + unsigned size : LD_MAX_COUNTREF_SIZE; + unsigned count[COUNTREF_COUNTS]; + reference ref; +}; + +typedef struct countref countref; +typedef STACK (countref) countrefs; + +struct vivifier { + kissat *solver; + unsigned *counts; + references schedule; + size_t scheduled, tried, vivified; + countrefs countrefs; + unsigneds sorted; +#ifndef QUIET + const char *mode; + const char *name; + char tag; +#endif + int tier; +}; + +typedef struct vivifier vivifier; + +static void init_vivifier (kissat *solver, vivifier *vivifier) { + vivifier->solver = solver; + vivifier->counts = kissat_calloc (solver, LITS, sizeof (unsigned)); + INIT_STACK (vivifier->schedule); + INIT_STACK (vivifier->countrefs); + INIT_STACK (vivifier->sorted); + LOG ("initialized vivifier"); +} + +static void set_vivifier_mode (vivifier *vivifier, int tier) { + vivifier->tier = tier; +#ifndef QUIET + switch (tier) { + case 1: + vivifier->mode = "vivify-tier1"; + vivifier->name = "tier1"; + vivifier->tag = 'u'; + break; + case 2: + vivifier->mode = "vivify-tier2"; + vivifier->name = "tier2"; + vivifier->tag = 'v'; + break; + case 3: + assert (tier == 3); + vivifier->mode = "vivify-tier3"; + vivifier->name = "tier3"; + vivifier->tag = 'w'; + break; + default: + assert (tier == 0); + vivifier->mode = "vivify-irredundant"; + vivifier->name = "irredundant"; + vivifier->tag = 'x'; + break; + } +#ifdef LOGGING + kissat *solver = vivifier->solver; + LOG ("set vivifier tier %d mode '%s' with tag '%c'", tier, vivifier->mode, + vivifier->tag); +#endif +#endif +} + +static void clear_vivifier (vivifier *vivifier) { + kissat *solver = vivifier->solver; + LOG ("clearing vivifier"); + unsigned *counts = vivifier->counts; + memset (counts, 0, LITS * sizeof *counts); + CLEAR_STACK (vivifier->schedule); + CLEAR_STACK (vivifier->countrefs); + CLEAR_STACK (vivifier->sorted); +} + +static void release_vivifier (vivifier *vivifier) { + kissat *solver = vivifier->solver; + LOG ("releasing vivifier"); + unsigned *counts = vivifier->counts; + kissat_dealloc (solver, counts, LITS, sizeof *counts); + RELEASE_STACK (vivifier->schedule); + RELEASE_STACK (vivifier->countrefs); + RELEASE_STACK (vivifier->sorted); +} + +static void schedule_vivification_candidates (vivifier *vivifier) { + kissat *solver = vivifier->solver; + LOG ("scheduling vivification candidates"); + int tier = vivifier->tier; + unsigned lower_glue_limit, upper_glue_limit; + unsigned tier1 = vivify_tier1_limit (solver); + unsigned tier2 = MAX (tier1, vivify_tier2_limit (solver)); + assert (tier1 <= tier2); + switch (tier) { + case 1: + lower_glue_limit = 0; + upper_glue_limit = tier1; + break; + case 2: + lower_glue_limit = tier1 < tier2 ? tier1 + 1 : 0; + upper_glue_limit = tier2; + break; + case 3: + lower_glue_limit = tier2 + 1; + upper_glue_limit = UINT_MAX; + break; + default: + assert (tier == 0); + lower_glue_limit = 0; + upper_glue_limit = UINT_MAX; + break; + } + assert (lower_glue_limit <= upper_glue_limit); + ward *const arena = BEGIN_STACK (solver->arena); + size_t prioritized = 0; + unsigned *counts = vivifier->counts; + references *schedule = &vivifier->schedule; + for (unsigned prioritize = 0; prioritize < 2; prioritize++) { + for (all_clauses (c)) { + if (c->garbage) + continue; + if (prioritize) + count_clause (c, counts); + if (tier) { + if (!c->redundant) + continue; + if (c->glue < lower_glue_limit) + continue; + if (c->glue > upper_glue_limit) + continue; + } else if (c->redundant) + continue; + if (c->vivify != prioritize) + continue; + if (simplify_vivification_candidate (solver, c)) + continue; + if (prioritize) + prioritized++; + const reference ref = (ward *) c - arena; + PUSH_STACK (*schedule, ref); + } + } + CLEAR_STACK (solver->clause); + size_t scheduled = SIZE_STACK (*schedule); + if (prioritized) { + kissat_phase (solver, vivifier->mode, GET (vivifications), + "prioritized %zu clauses %.0f%%", prioritized, + kissat_percent (prioritized, scheduled)); + } else { + kissat_phase (solver, vivifier->mode, GET (vivifications), + "prioritizing all %zu scheduled clauses", scheduled); + for (all_stack (reference, ref, *schedule)) { + clause *c = (clause *) (arena + ref); + assert (kissat_clause_in_arena (solver, c)); + c->vivify = true; + } + } + vivifier->scheduled = scheduled; + vivifier->tried = vivifier->vivified = 0; +} + +static inline bool worse_candidate (kissat *solver, unsigned *counts, + reference r, reference s) { + const clause *const c = kissat_dereference_clause (solver, r); + const clause *const d = kissat_dereference_clause (solver, s); + + if (!c->vivify && d->vivify) + return true; + + if (c->vivify && !d->vivify) + return false; + + unsigned const *p = BEGIN_LITS (c); + unsigned const *q = BEGIN_LITS (d); + const unsigned *const e = END_LITS (c); + const unsigned *const f = END_LITS (d); + + unsigned a = INVALID_LIT, b = INVALID_LIT; + + while (p != e && q != f) { + a = *p++; + b = *q++; + const unsigned u = counts[a]; + const unsigned v = counts[b]; + if (u < v) + return true; + if (u > v) + return false; + } + + if (p != e && q == f) + return true; + + if (p == e && q != f) + return false; + + assert (p == e && q == f); + + if (a < b) + return true; + if (a > b) + return false; + + return r < s; +} + +#define WORSE_CANDIDATE(A, B) worse_candidate (solver, counts, (A), (B)) + +static void +sort_vivification_candidates_after_sorting_literals (vivifier *vivifier) { + kissat *solver = vivifier->solver; + unsigned *counts = vivifier->counts; + references *schedule = &vivifier->schedule; + SORT_STACK (reference, *schedule, WORSE_CANDIDATE); +} + +static void sort_scheduled_candidate_literals (vivifier *vivifier) { + kissat *solver = vivifier->solver; + unsigned *counts = vivifier->counts; + references *schedule = &vivifier->schedule; + for (all_stack (reference, ref, *schedule)) { + clause *c = kissat_dereference_clause (solver, ref); + vivify_sort_clause_by_counts (solver, c, counts); + } +} + +static inline void init_countref (countref *cr, clause *c, reference ref, + unsigned *counts) { + assert (COUNTREF_COUNTS <= c->size); + assert (c->size <= MAX_COUNTREF_SIZE); + cr->size = c->size; + cr->vivify = c->vivify; + cr->ref = ref; + unsigned lits[COUNTREF_COUNTS]; + for (unsigned i = 0; i != COUNTREF_COUNTS; i++) { + unsigned best = INVALID_LIT; + unsigned best_count = 0; + for (all_literals_in_clause (lit, c)) { + for (unsigned j = 0; j != i; j++) + if (lits[j] == lit) + goto CONTINUE_WITH_NEXT_LITERAL; + const unsigned lit_count = counts[lit]; + assert (lit_count); + if (lit_count <= best_count) + continue; + best_count = lit_count; + best = lit; + CONTINUE_WITH_NEXT_LITERAL:; + } + assert (best != INVALID_LIT); + assert (best_count); + cr->count[i] = best_count; + lits[i] = best; + } +} + +static void init_countrefs (vivifier *vivifier) { + kissat *const solver = vivifier->solver; + references *schedule = &vivifier->schedule; + countrefs *countrefs = &vivifier->countrefs; + unsigned *counts = vivifier->counts; + assert (EMPTY_STACK (*countrefs)); + for (all_stack (reference, ref, *schedule)) { + clause *c = kissat_dereference_clause (solver, ref); + countref countref; + init_countref (&countref, c, ref, counts); + PUSH_STACK (*countrefs, countref); + } + RELEASE_STACK (*schedule); +} + +#define RANK_COUNTREF_BY_INVERSE_SIZE(CR) ((unsigned) (~(CR).size)) +#define RANK_COUNTREF_BY_VIVIFY(CR) ((unsigned) ((CR).vivify)) +#define RANK_COUNTREF_BY_COUNT(CR) \ + ((unsigned) ((CR).count[COUNTREF_COUNTS - 1 - i])) + +static void rank_vivification_candidates (vivifier *vivifier) { + kissat *solver = vivifier->solver; + countrefs *countrefs = &vivifier->countrefs; + RADIX_STACK (countref, unsigned, *countrefs, + RANK_COUNTREF_BY_INVERSE_SIZE); + for (unsigned i = 0; i != COUNTREF_COUNTS; i++) + RADIX_STACK (countref, unsigned, *countrefs, RANK_COUNTREF_BY_COUNT); + RADIX_STACK (countref, unsigned, *countrefs, RANK_COUNTREF_BY_VIVIFY); +} + +static void copy_countrefs (vivifier *vivifier) { + kissat *solver = vivifier->solver; + references *schedule = &vivifier->schedule; + countrefs *countrefs = &vivifier->countrefs; + assert (EMPTY_STACK (*schedule)); + for (all_stack (countref, cr, *countrefs)) + PUSH_STACK (*schedule, cr.ref); + RELEASE_STACK (*countrefs); +} + +static void sort_vivification_candidates (vivifier *vivifier) { +#ifndef QUIET + kissat *solver = vivifier->solver; +#endif + START (vivifysort); + if (vivifier->tier) { + kissat_extremely_verbose ( + solver, "sorting %s vivification candidates precisely", + vivifier->name); + sort_scheduled_candidate_literals (vivifier); + sort_vivification_candidates_after_sorting_literals (vivifier); + } else { + kissat_extremely_verbose ( + solver, + "sorting %s vivification candidates imprecisely " + "by first %u literals", + vivifier->name, (unsigned) COUNTREF_COUNTS); + init_countrefs (vivifier); + rank_vivification_candidates (vivifier); + copy_countrefs (vivifier); + } + STOP (vivifysort); +} + +static void vivify_deduce (vivifier *vivifier, clause *candidate, + clause *conflict, unsigned implied, + clause **subsuming_ptr, bool *redundant_ptr) { + kissat *solver = vivifier->solver; + LOG ("starting vivification conflict analysis"); + bool redundant = false; + bool subsumes = false; + + assert (solver->level); + assert (EMPTY_STACK (solver->clause)); + assert (EMPTY_STACK (solver->analyzed)); + + if (implied != INVALID_LIT) { + unsigned not_implied = NOT (implied); + LOG ("vivify analyzing %s", LOGLIT (not_implied)); + assigned *const a = ASSIGNED (not_implied); + assert (a->level); + assert (!a->analyzed); + a->analyzed = true; + PUSH_STACK (solver->analyzed, not_implied); + PUSH_STACK (solver->clause, implied); + } else { + clause *reason = conflict ? conflict : candidate; + assert (reason), assert (!reason->garbage); + if (reason->redundant) + redundant = true; + subsumes = (reason != candidate); + for (all_literals_in_clause (other, reason)) { + assert (VALUE (other) < 0); + const value value = kissat_fixed (solver, other); + if (value < 0) + continue; + LOG ("vivify analyzing %s", LOGLIT (other)); + assert (!value); + assigned *const a = ASSIGNED (other); + assert (a->level); + assert (!a->analyzed); + a->analyzed = true; + PUSH_STACK (solver->analyzed, other); + if (solver->marks[other] <= 0) + subsumes = false; + } + if (reason != candidate && reason->redundant) + kissat_recompute_and_promote (solver, reason); + if (subsumes) { + LOGCLS (candidate, "vivify subsumed"); + LOGCLS (reason, "vivify subsuming"); + *subsuming_ptr = reason; + return; + } + } + + const mark *const marks = solver->marks; + size_t analyzed = 0; + while (analyzed < SIZE_STACK (solver->analyzed)) { + const unsigned not_lit = PEEK_STACK (solver->analyzed, analyzed); + const unsigned lit = NOT (not_lit); + assert (VALUE (lit) > 0); + analyzed++; + assigned *a = ASSIGNED (lit); + assert (a->level); + assert (a->analyzed); + if (a->reason == DECISION_REASON) { + LOG ("vivify analyzing decision %s", LOGLIT (not_lit)); + PUSH_STACK (solver->clause, not_lit); + } else if (a->binary) { + const unsigned other = a->reason; + if (marks[lit] > 0 && marks[other] > 0) { + LOGCLS (candidate, "vivify subsumed"); + LOGBINARY (lit, other, "vivify subsuming"); // Might be jumped! + *subsuming_ptr = kissat_binary_conflict (solver, lit, other); + return; + } + assert (VALUE (other) < 0); + assigned *b = ASSIGNED (other); + assert (b->level); + if (b->analyzed) + continue; + LOGBINARY (lit, other, "vivify analyzing %s reason", LOGLIT (lit)); + b->analyzed = true; + PUSH_STACK (solver->analyzed, other); + } else { + const reference ref = a->reason; + LOGREF (ref, "vivify analyzing %s reason", LOGLIT (lit)); + clause *reason = kissat_dereference_clause (solver, ref); + assert (reason != candidate); + if (reason->redundant) + redundant = true; + subsumes = true; + for (all_literals_in_clause (other, reason)) { + if (marks[other] <= 0) + subsumes = false; + if (other == lit) + continue; + assert (other != not_lit); + assert (VALUE (other) < 0); + assigned *b = ASSIGNED (other); + if (!b->level) + continue; + if (b->analyzed) + continue; + b->analyzed = true; + PUSH_STACK (solver->analyzed, other); + } + if (reason->redundant) + kissat_recompute_and_promote (solver, reason); + if (subsumes) { + LOGCLS (candidate, "vivify subsumed"); + LOGCLS (reason, "vivify subsuming"); + *subsuming_ptr = reason; + return; + } + } + } + + LOG ("vivification analysis %s redundant clause", + redundant ? "used" : "without"); + LOGTMP ("vivification analysis"); + + *redundant_ptr = redundant; +} + +static void reset_vivify_analyzed (vivifier *vivifier) { + kissat *solver = vivifier->solver; + LOG ("reset vivification conflict analysis"); + struct assigned *assigned = solver->assigned; + for (all_stack (unsigned, lit, solver->analyzed)) { + const unsigned idx = IDX (lit); + struct assigned *a = assigned + idx; + a->analyzed = false; + } + CLEAR_STACK (solver->analyzed); + CLEAR_STACK (solver->clause); +} + +static bool vivify_shrinkable (kissat *solver, unsigneds *sorted, + clause *conflict) { + assert (SIZE_STACK (solver->clause) <= SIZE_STACK (*sorted)); + if (SIZE_STACK (solver->clause) == SIZE_STACK (*sorted)) + return false; + const assigned *const assigned = solver->assigned; + const value *const values = solver->values; + unsigned count_implied = 0; + for (all_stack (unsigned, lit, *sorted)) { + value value = values[lit]; + if (!value) { + LOG ("vivification unassigned %s thus shrinking", LOGLIT (lit)); + return true; + } + if (value > 0) { + LOG ("vivification implied satisfied %s", LOGLIT (lit)); + if (conflict) { + LOG ("at least one implied literal with conflict thus shrinking"); + return true; + } + if (count_implied++) { + LOG ("at least two implied literals thus shrinking"); + return true; + } + } else { + assert (value < 0); + const unsigned idx = IDX (lit); + const struct assigned *const a = assigned + idx; + assert (a->level); + if (!a->analyzed) { + LOG ("vivification non-analyzed %s thus shrinking", LOGLIT (lit)); + return true; + } + if (a->reason != DECISION_REASON) { + LOG ("vivification implied falsified %s thus shrinking", + LOGLIT (lit)); + return true; + } + } + } + LOG ("vivification learned clause not shrinkable"); + return false; +} + +static void vivify_learn_unit (kissat *solver, clause *c) { + LOG ("vivification learns unit clause"); + assert (SIZE_STACK (solver->clause) == 1); + kissat_backtrack_without_updating_phases (solver, 0); + const unsigned unit = PEEK_STACK (solver->clause, 0); + kissat_learned_unit (solver, unit); + solver->iterating = true; + kissat_mark_clause_as_garbage (solver, c); + assert (!solver->level); + clause *conflict = kissat_probing_propagate (solver, 0, true); + assert (!conflict || solver->inconsistent); + INC (vivify_units); + (void) conflict; +} + +static void vivify_learn_binary (kissat *solver, clause *c) { + LOG ("vivification learns binary clause"); + kissat_backtrack_without_updating_phases (solver, 0); + assert (SIZE_STACK (solver->clause) == 2); + if (c->redundant) + (void) kissat_new_redundant_clause (solver, 1); + else + (void) kissat_new_irredundant_clause (solver); + kissat_mark_clause_as_garbage (solver, c); +} + +static void swap_first_literal_with_best_watch (kissat *solver, + unsigned *lits, + unsigned size) { + assert (size); + unsigned *best_ptr = lits; + unsigned first = *best_ptr, best = first; + signed char value = VALUE (best); + unsigned best_level = LEVEL (best); + const unsigned *const end = lits + size; + for (unsigned *p = lits + 1; value < 0 && p != end; p++) { + unsigned lit = *p; + const signed char value = VALUE (lit); + if (value < 0) { + const unsigned level = LEVEL (lit); + if (level <= best_level) + continue; + best_level = level; + } + best_ptr = p; + best = lit; + } + if (best_ptr == lits) + return; + LOG ("better watch %s instead of %s", LOGLIT (best), LOGLIT (first)); + *best_ptr = first; + *lits = best; +} + +static void vivify_unwatch_clause (kissat *solver, clause *c) { + unsigned *lits = c->lits; + const reference ref = kissat_reference_clause (solver, c); + kissat_unwatch_blocking (solver, lits[0], ref); + kissat_unwatch_blocking (solver, lits[1], ref); +} + +static void vivify_watch_clause (kissat *solver, clause *c) { + unsigned size = c->size; + unsigned *lits = c->lits; + const reference ref = kissat_reference_clause (solver, c); + swap_first_literal_with_best_watch (solver, lits, size); + swap_first_literal_with_best_watch (solver, lits + 1, size - 1); + kissat_watch_blocking (solver, lits[0], lits[1], ref); + kissat_watch_blocking (solver, lits[1], lits[0], ref); +} + +static void vivify_learn_large (kissat *solver, clause *c, + unsigned implied) { + assert (!c->garbage); + LOG ("vivification learns large clause"); + + CHECK_AND_ADD_STACK (solver->clause); + ADD_STACK_TO_PROOF (solver->clause); + + REMOVE_CHECKER_CLAUSE (c); + DELETE_CLAUSE_FROM_PROOF (c); + + vivify_unwatch_clause (solver, c); + + bool irredundant = !c->redundant; + + if (irredundant) { // TODO this could be made more precise. + for (all_literals_in_clause (lit, c)) + kissat_mark_removed_literal (solver, lit); + } + + unsigneds *learned = &solver->clause; + const unsigned old_size = c->size; + const unsigned new_size = SIZE_STACK (*learned); + assert (new_size <= old_size); + + unsigned *lits = c->lits; + memcpy (lits, BEGIN_STACK (*learned), new_size * sizeof *lits); + + if (irredundant) + for (all_literals_in_clause (lit, c)) + kissat_mark_added_literal (solver, lit); + + assert (new_size < old_size); + if (!c->shrunken) { + c->shrunken = true; + lits[old_size - 1] = INVALID_LIT; + } + c->size = new_size; + if (!irredundant && c->glue >= new_size) + kissat_promote_clause (solver, c, new_size - 1); + c->searched = 2; + + if (implied == INVALID_LIT) { + LOGCLS (c, "vivified shrunken after conflict"); + kissat_backtrack_without_updating_phases (solver, new_size - 2); + } else { + LOGCLS (c, "vivified shrunken after implied"); + assert (solver->level >= new_size - 1); + } + + vivify_watch_clause (solver, c); +} + +static void vivify_learn (kissat *solver, clause *c, unsigned implied) { + size_t size = SIZE_STACK (solver->clause); + if (size == 1) + vivify_learn_unit (solver, c); + else if (size == 2) + vivify_learn_binary (solver, c); + else + vivify_learn_large (solver, c, implied); +} + +static void binary_strengthen_after_instantiation (kissat *solver, + clause *c, + unsigned remove) { + LOG ("vivification instantiation yields binary clause"); + assert (solver->level == 3); + + unsigned first = INVALID_LIT, second = INVALID_LIT; + for (all_literals_in_clause (lit, c)) + if (lit != remove) { + assert (VALUE (lit) < 0); + if (LEVEL (lit)) { + if (first == INVALID_LIT) + first = lit; + else { + assert (second == INVALID_LIT); + second = lit; + } + } + } + assert (first != INVALID_LIT); + assert (second != INVALID_LIT); + LOGBINARY (first, second, "vivified strengthened through instantiation"); + CLEAR_STACK (solver->clause); + PUSH_STACK (solver->clause, first); + PUSH_STACK (solver->clause, second); + if (c->redundant) + (void) kissat_new_redundant_clause (solver, 1); + else + (void) kissat_new_irredundant_clause (solver); + + kissat_mark_clause_as_garbage (solver, c); + kissat_backtrack_without_updating_phases (solver, 0); +} + +static void large_strengthen_after_instantiation (kissat *solver, clause *c, + unsigned remove) { + LOG ("vivification instantiation yields large clause"); + assert (solver->level > 3); + + SHRINK_CLAUSE_IN_PROOF (c, remove, INVALID_LIT); + CHECK_SHRINK_CLAUSE (c, remove, INVALID_LIT); + + vivify_unwatch_clause (solver, c); + + bool irredundant = !c->redundant; + const unsigned old_size = c->size; + assert (old_size > 3); + unsigned new_size = 0, *lits = c->lits; + for (unsigned i = 0; i != old_size; i++) { + const unsigned lit = lits[i]; + if (lit == remove) { + if (irredundant) + kissat_mark_removed_literal (solver, lit); + } else if (kissat_fixed (solver, lit) >= 0) { + lits[new_size++] = lit; + if (irredundant) + kissat_mark_added_literal (solver, lit); + } + } + assert (2 < new_size); + assert (new_size < old_size); + if (!c->shrunken) { + c->shrunken = true; + lits[old_size - 1] = INVALID_LIT; + } + c->size = new_size; + if (!irredundant && c->glue >= new_size) + kissat_promote_clause (solver, c, new_size - 1); + c->searched = 2; + LOGCLS (c, "vivified strengthened through instantiation"); + + kissat_backtrack_without_updating_phases (solver, solver->level - 2); + vivify_watch_clause (solver, c); +} + +static void vivify_strengthen_after_instantiation (kissat *solver, + clause *c, + unsigned remove) { + assert (solver->level >= 3); + assert (VALUE (remove) > 0); + assert (LEVEL (remove) == solver->level); + + if (solver->level == 3) + binary_strengthen_after_instantiation (solver, c, remove); + else + large_strengthen_after_instantiation (solver, c, remove); +} + +static void vivify_mark_sorted_literals (vivifier *vivifier) { + kissat *solver = vivifier->solver; + LOG ("marking sorted literals"); + unsigneds *sorted = &vivifier->sorted; + value *marks = solver->marks; + for (all_stack (unsigned, lit, *sorted)) + assert (!marks[lit]), marks[lit] = 1, marks[NOT (lit)] = -1; +} + +static void vivify_unmark_sorted_literals (vivifier *vivifier) { + kissat *solver = vivifier->solver; + LOG ("unmarking sorted literals"); + unsigneds *sorted = &vivifier->sorted; + value *marks = solver->marks; + for (all_stack (unsigned, lit, *sorted)) + assert (solver->marks[lit] > 0), assert (marks[NOT (lit)] < 0), + marks[lit] = marks[NOT (lit)] = 0; +} + +static void reestablish_watch_invariant_for_candidate (kissat *solver, + clause *candidate) { + if (!solver->level) + return; + if (candidate->garbage) + return; + unsigned *lits = candidate->lits; + unsigned first = lits[0]; + unsigned second = lits[1]; + const signed char first_val = VALUE (first); + const signed char second_val = VALUE (second); + unsigned first_level = first_val ? LEVEL (first) : 0; + unsigned second_level = second_val ? LEVEL (second) : 0; + unsigned new_level; + if (first_val >= 0 && second_val >= 0) + return; + if (first_val < 0 && !second_val) + new_level = first_level; + else if (first_val < 0 && second_val > 0) { + if (first_level >= second_level) + return; + new_level = first_level; + } else if (second_val < 0 && !first_val) + new_level = second_level; + else if (second_val < 0 && first_val > 0) { + if (second_level >= first_level) + return; + new_level = second_level; + } else { + assert (first_val < 0), assert (second_val < 0); + new_level = MIN (first_level, second_level); + } + assert (new_level); + LOGCLS (candidate, "reestablish watch invariant by backtracking to %u", + new_level - 1); + kissat_backtrack_without_updating_phases (solver, new_level - 1); +} + +static bool vivify_clause (vivifier *vivifier, clause *candidate) { + + assert (!candidate->garbage); + + kissat *solver = vivifier->solver; + + assert (solver->probing); + assert (solver->watching); + assert (!solver->inconsistent); + + LOGCLS (candidate, "vivifying candidate"); + LOGCOUNTEDCLS (candidate, vivifier->counts, + "vivifying unsorted counted candidate"); + + unsigneds *sorted = &vivifier->sorted; + CLEAR_STACK (*sorted); + + for (all_literals_in_clause (lit, candidate)) { + const value value = kissat_fixed (solver, lit); + if (value < 0) + continue; + if (value > 0) { + LOGCLS (candidate, "%s satisfied", LOGLIT (lit)); + kissat_mark_clause_as_garbage (solver, candidate); + return false; + } + PUSH_STACK (*sorted, lit); + } + + assert (!candidate->garbage); + + const unsigned non_false = SIZE_STACK (*sorted); + + assert (1 < non_false); + assert (non_false <= candidate->size); + +#ifdef LOGGING + if (non_false == candidate->size) + LOG ("all literals root level unassigned"); + else + LOG ("found %u root level non-falsified literals", non_false); +#endif + + if (non_false == 2) { + LOGCLS (candidate, "skipping actually binary"); + return false; + } + + INC (vivify_checks); + + unsigned unit = INVALID_LIT; + for (all_literals_in_clause (lit, candidate)) { + const value value = VALUE (lit); + if (value < 0) + continue; + if (!value) { + unit = INVALID_LIT; + break; + } + assert (value > 0); + if (unit != INVALID_LIT) { + unit = INVALID_LIT; + break; + } + unit = lit; + } + reference cand_ref = kissat_reference_clause (solver, candidate); + if (unit != INVALID_LIT) { + assigned *a = ASSIGNED (unit); + assert (a->level); + if (a->binary) + unit = INVALID_LIT; + else { + if (a->reason != cand_ref) + unit = INVALID_LIT; + } + } + if (unit == INVALID_LIT) + LOG ("non-reason candidate clause"); + else { + LOG ("candidate is the reason of %s", LOGLIT (unit)); + const unsigned level = LEVEL (unit); + assert (level > 0); + LOG ("forced to backtrack to level %u", level - 1); + kissat_backtrack_without_updating_phases (solver, level - 1); + } + + assert (EMPTY_STACK (solver->analyzed)); + assert (EMPTY_STACK (solver->clause)); + + unsigned *counts = vivifier->counts; + vivify_sort_stack_by_counts (solver, sorted, counts); + +#ifdef LOGGING + if (candidate->redundant) + LOGCOUNTEDREFLITS (cand_ref, SIZE_STACK (*sorted), sorted->begin, + counts, "vivifying sorted redundant glue %u", + candidate->glue); + else + LOGCOUNTEDREFLITS (cand_ref, SIZE_STACK (*sorted), sorted->begin, + counts, "vivifying sorted irredundant"); +#endif + + vivify_mark_sorted_literals (vivifier); + + unsigned implied = INVALID_LIT; + clause *conflict = 0; + unsigned level = 0; + + for (all_stack (unsigned, lit, *sorted)) { + if (level++ < solver->level) { + frame *frame = &FRAME (level); + const unsigned not_lit = NOT (lit); + if (frame->decision == not_lit) { + LOG ("reusing assumption %s", LOGLIT (not_lit)); + INC (vivify_reused); + INC (vivify_probes); + assert (VALUE (lit) < 0); + continue; + } + + LOG ("forced to backtrack to decision level %u", level - 1); + kissat_backtrack_without_updating_phases (solver, level - 1); + } + + const value value = VALUE (lit); + assert (!value || LEVEL (lit) <= level); + + if (value < 0) { + assert (LEVEL (lit)); + LOG ("literal %s already falsified", LOGLIT (lit)); + continue; + } + + if (value > 0) { + assert (LEVEL (lit)); + LOG ("literal %s already initially satisfied", LOGLIT (lit)); + implied = lit; + break; + } + + assert (!value); + + LOG ("literal %s unassigned", LOGLIT (lit)); + const unsigned not_lit = NOT (lit); + INC (vivify_probes); + + kissat_internal_assume (solver, not_lit); + assert (solver->level >= 1); + + const unsigned *p = solver->propagate; + conflict = kissat_probing_propagate (solver, candidate, true); + if (conflict) + break; + + const unsigned *end = END_ARRAY (solver->trail); + const signed char *const marks = solver->marks; + while (p != end) { + const unsigned other = *p++; + const signed char mark = marks[other]; + if (mark > 0) { + LOG ("literal %s already implied satisfied", LOGLIT (other)); + implied = other; + goto EXIT_ASSUMPTION_LOOP; + } + } + } +EXIT_ASSUMPTION_LOOP:; + +#ifdef LOGGING + if (!conflict && implied == INVALID_LIT) + LOG ("vivification assumptions propagate without conflict nor " + "producing an implied literal"); +#endif + assert (!conflict || implied == INVALID_LIT); + + if (implied != INVALID_LIT) { + unsigned better_implied = INVALID_LIT; + unsigned better_implied_trail = INVALID_TRAIL; + for (all_stack (unsigned, lit, *sorted)) { + if (VALUE (lit) <= 0) + continue; + unsigned lit_trail = TRAIL (lit); + if (lit_trail > better_implied_trail) + continue; + better_implied_trail = lit_trail; + better_implied = lit; + } + if (better_implied != implied) { + LOG ("better implied satisfied literal %s at level %u", + LOGLIT (better_implied), LEVEL (better_implied)); + implied = better_implied; + } + } + + unsigned level_after_assumptions = solver->level; + assert (level_after_assumptions); + + clause *subsuming = 0; + bool redundant = false; + vivify_deduce (vivifier, candidate, conflict, implied, &subsuming, + &redundant); + + vivify_unmark_sorted_literals (vivifier); + + bool res; + + if (subsuming) { + assert (!subsuming->garbage); + if (candidate->redundant) { + LOGCLS (candidate, "vivification subsumed"); + kissat_mark_clause_as_garbage (solver, candidate); + if (subsuming->redundant && candidate->glue < subsuming->glue) { + LOG ("vivify candidate with smaller glue than subsuming clause"); + kissat_promote_clause (solver, subsuming, candidate->glue); + } + INC (vivified_subred); + INC (vivified_subsumed); + res = true; + } else if (!subsuming->redundant) { + assert (!candidate->redundant); + LOGCLS (candidate, "vivification subsumed"); + kissat_mark_clause_as_garbage (solver, candidate); + INC (vivified_subirr); + INC (vivified_subsumed); + res = true; + } else { + assert (!candidate->redundant); + assert (subsuming->redundant); + LOGCLS (candidate, "vivification subsumed"); + kissat_mark_clause_as_garbage (solver, candidate); + subsuming->redundant = false; + assert (solver->statistics.clauses_redundant); + solver->statistics.clauses_redundant--; + assert (solver->statistics.clauses_irredundant < UINT64_MAX); + solver->statistics.clauses_irredundant++; + INC (vivified_promoted); + LOGCLS (subsuming, "vivification promoted from redundant to"); + kissat_update_last_irredundant (solver, subsuming); + kissat_mark_added_literals (solver, subsuming->size, subsuming->lits); + INC (vivified_subirr); + INC (vivified_subsumed); + res = true; + } + } else if (vivify_shrinkable (solver, sorted, conflict)) { + vivify_learn (solver, candidate, implied); + INC (vivified_shrunken); + if (candidate->redundant) + INC (vivified_shrunkred); + else + INC (vivified_shrunkirr); + res = true; + } else if (implied != INVALID_LIT && candidate->redundant) { + LOGCLS (candidate, "vivification implied"); + kissat_mark_clause_as_garbage (solver, candidate); + INC (vivified_implied); + res = true; + } else if ((conflict || implied != INVALID_LIT) && + !candidate->redundant && !redundant) { + LOGCLS (candidate, "vivification asymmetric tautology"); + kissat_mark_clause_as_garbage (solver, candidate); + INC (vivified_asym); + res = true; + } else if (implied != INVALID_LIT) { + LOGCLS (candidate, + "no vivification instantiation with implied literal %s", + LOGLIT (implied)); + assert (!candidate->redundant); + assert (redundant); + res = false; + } else { + assert (solver->level > 2); + assert (solver->level == SIZE_STACK (*sorted)); + unsigned lit = TOP_STACK (*sorted); + assert (VALUE (lit) < 0); + assert (LEVEL (lit) == solver->level); + LOG ("trying vivification instantiation of %s#%u respectively %s#%u", + LOGLIT (lit), counts[lit], LOGLIT (NOT (lit)), counts[NOT (lit)]); + kissat_backtrack_without_updating_phases (solver, solver->level - 1); + conflict = 0; + assert (!VALUE (lit)); + kissat_internal_assume (solver, lit); + LOGCLS (candidate, "vivification instantiation candidate"); + conflict = kissat_probing_propagate (solver, candidate, true); + if (conflict) { + LOG ("vivification instantiation succeeded"); + vivify_strengthen_after_instantiation (solver, candidate, lit); + INC (vivified_instantiated); + if (candidate->redundant) + INC (vivified_instred); + else + INC (vivified_instirr); + res = true; + } else { + LOG ("vivification instantiation failed"); + kissat_backtrack_without_updating_phases (solver, solver->level - 2); + res = false; + } + } + + reset_vivify_analyzed (vivifier); + if (conflict && solver->level == level_after_assumptions) { + LOG ("forcing backtracking at least one level after conflict"); + kissat_backtrack_without_updating_phases (solver, solver->level - 1); + } + reestablish_watch_invariant_for_candidate (solver, candidate); + + if (res) { + INC (vivified); + switch (vivifier->tier) { + case 1: + INC (vivified_tier1); + break; + case 2: + INC (vivified_tier2); + break; + case 3: + INC (vivified_tier3); + break; + default: + assert (vivifier->tier == 0); + INC (vivified_irredundant); + break; + } + } + + LOG ("vivification %s", res ? "succeeded" : "failed"); + return res; +} + +static void vivify_round (vivifier *vivifier, uint64_t limit) { + int tier = vivifier->tier; + kissat *solver = vivifier->solver; + + if (tier && !REDUNDANT_CLAUSES) + return; + + assert (0 <= tier && tier <= 3); + assert (solver->watching); + assert (solver->probing); + + kissat_flush_large_watches (solver); + + schedule_vivification_candidates (vivifier); + if (GET_OPTION (vivifysort)) { + if (tier || IRREDUNDANT_CLAUSES / 10 <= REDUNDANT_CLAUSES) + sort_vivification_candidates (vivifier); + else + kissat_extremely_verbose ( + solver, "not sorting %s vivification candidates", vivifier->name); + } + + kissat_watch_large_clauses (solver); +#ifndef QUIET + uint64_t start = solver->statistics.probing_ticks; + uint64_t delta = limit - start; + kissat_very_verbose (solver, + "vivification %s effort limit %" PRIu64 " = %" PRIu64 + " + %" PRIu64 " 'probing_ticks'", + vivifier->name, limit, start, delta); + const size_t total = tier ? REDUNDANT_CLAUSES : IRREDUNDANT_CLAUSES; + const size_t scheduled = SIZE_STACK (vivifier->schedule); + kissat_phase (solver, vivifier->mode, GET (vivifications), + "scheduled %zu clauses %.0f%% of %zu", scheduled, + kissat_percent (scheduled, total), total); +#endif + assert (!vivifier->vivified); + assert (!vivifier->tried); + while (!EMPTY_STACK (vivifier->schedule)) { + const uint64_t probing_ticks = solver->statistics.probing_ticks; + if (probing_ticks > limit) { + kissat_extremely_verbose (solver, + "vivification %s ticks limit %" PRIu64 + " hit after %" PRIu64 " 'probing_ticks'", + vivifier->name, limit, probing_ticks); + break; + } + if (TERMINATED (vivify_terminated_1)) + break; + const reference ref = POP_STACK (vivifier->schedule); + clause *candidate = kissat_dereference_clause (solver, ref); + assert (!candidate->garbage); + vivifier->tried++; + if (vivify_clause (vivifier, candidate)) + vivifier->vivified++; + if (solver->inconsistent) + break; + candidate->vivify = false; + } + if (solver->level) + kissat_backtrack_without_updating_phases (solver, 0); +#ifndef QUIET + kissat_phase (solver, vivifier->mode, GET (vivifications), + "vivified %zu clauses %.0f%% out of %zu tried", + vivifier->vivified, + kissat_percent (vivifier->vivified, vivifier->tried), + vivifier->tried); + if (!solver->inconsistent) { + size_t remain = SIZE_STACK (vivifier->schedule); + if (remain) { + kissat_phase (solver, vivifier->mode, GET (vivifications), + "%zu clauses remain %.0f%% out of %zu scheduled", + remain, kissat_percent (remain, scheduled), scheduled); + + ward *const arena = BEGIN_STACK (solver->arena); + size_t prioritized = 0; + while (!EMPTY_STACK (vivifier->schedule)) { + const reference ref = POP_STACK (vivifier->schedule); + clause *c = (clause *) (arena + ref); + if (c->vivify) + prioritized++; + } + if (!prioritized) + kissat_phase (solver, vivifier->mode, GET (vivifications), + "no remaining prioritized clauses"); + else + kissat_phase (solver, vivifier->mode, GET (vivifications), + "keeping all %zu remaining clauses " + "prioritized %.0f%%", + prioritized, kissat_percent (prioritized, remain)); + } else + kissat_phase (solver, vivifier->mode, GET (vivifications), + "no untried clauses remain"); + } +#endif + REPORT (!vivifier->vivified, vivifier->tag); +} + +static void vivify_tier1 (vivifier *vivifier, uint64_t limit) { +#ifndef QUIET + kissat *solver = vivifier->solver; +#endif + START (vivify1); + set_vivifier_mode (vivifier, 1); + vivify_round (vivifier, limit); + STOP (vivify1); +} + +static void vivify_tier2 (vivifier *vivifier, uint64_t limit) { +#ifndef QUIET + kissat *solver = vivifier->solver; +#endif + START (vivify2); + clear_vivifier (vivifier); + set_vivifier_mode (vivifier, 2); + vivify_round (vivifier, limit); + STOP (vivify2); +} + +static void vivify_tier3 (vivifier *vivifier, uint64_t limit) { +#ifndef QUIET + kissat *solver = vivifier->solver; +#endif + START (vivify3); + clear_vivifier (vivifier); + set_vivifier_mode (vivifier, 3); + vivify_round (vivifier, limit); + STOP (vivify3); +} + +static void vivify_irredundant (vivifier *vivifier, uint64_t limit) { +#ifndef QUIET + kissat *solver = vivifier->solver; +#endif + START (vivify0); + clear_vivifier (vivifier); + set_vivifier_mode (vivifier, 0); + vivify_round (vivifier, limit); + STOP (vivify0); +} + +void kissat_vivify (kissat *solver) { + if (solver->inconsistent) + return; + assert (!solver->level); + assert (solver->probing); + assert (solver->watching); + if (!GET_OPTION (vivify)) + return; + if (TERMINATED (vivify_terminated_2)) + return; + double irr_budget = DELAYING (vivifyirr) ? 0 : GET_OPTION (vivifyirr); + double tier1_budget = GET_OPTION (vivifytier1); + double tier2_budget = GET_OPTION (vivifytier2); + double tier3_buget = GET_OPTION (vivifytier3); + if (!REDUNDANT_CLAUSES) + tier1_budget = tier2_budget = tier3_buget = 0; + double sum = irr_budget + tier1_budget + tier2_budget + tier3_buget; + if (!sum) + return; + + START (vivify); + INC (vivifications); +#if !defined(NDEBUG) || defined(METRICS) + assert (!solver->vivifying); + solver->vivifying = true; +#endif + + SET_EFFORT_LIMIT (limit, vivify, probing_ticks); + const uint64_t total = limit - solver->statistics.probing_ticks; + limit = solver->statistics.probing_ticks; + unsigned tier1_limit = vivify_tier1_limit (solver); + unsigned tier2_limit = vivify_tier2_limit (solver); + if (tier1_budget && tier2_budget && tier1_limit == tier2_limit) { + tier1_budget += tier2_budget, tier2_budget = 0; + LOG ("vivification tier1 matches tier2 " + "thus using tier2 budget for tier1"); + } + + { + vivifier vivifier; + init_vivifier (solver, &vivifier); + if (tier1_budget) { + limit += (total * tier1_budget) / sum; + vivify_tier1 (&vivifier, limit); + } + if (tier2_budget && !solver->inconsistent && + !TERMINATED (vivify_terminated_3)) { + limit += (total * tier2_budget) / sum; + vivify_tier2 (&vivifier, limit); + } + if (tier3_buget && !solver->inconsistent && + !TERMINATED (vivify_terminated_4)) { + limit += (total * tier3_buget) / sum; + vivify_tier3 (&vivifier, limit); + } + if (irr_budget && !solver->inconsistent && + !TERMINATED (vivify_terminated_5)) { + limit += (total * irr_budget) / sum; + vivify_irredundant (&vivifier, limit); + if (kissat_average (vivifier.vivified, vivifier.tried) < 0.01) + BUMP_DELAY (vivifyirr); + else + REDUCE_DELAY (vivifyirr); + } + release_vivifier (&vivifier); + } + +#ifndef QUIET + if (solver->statistics.probing_ticks < limit) { + uint64_t delta = limit - solver->statistics.probing_ticks; + kissat_phase (solver, "vivify-limit", GET (vivifications), + "has %" PRIu64 " ticks left %.2f%%", delta, + kissat_percent (delta, total)); + } else { + uint64_t delta = solver->statistics.probing_ticks - limit; + kissat_phase (solver, "vivify-limit", GET (vivifications), + "exceeded by %" PRIu64 " ticks %.2f%%", delta, + kissat_percent (delta, total)); + } +#endif +#if !defined(NDEBUG) || defined(METRICS) + assert (solver->vivifying); + solver->vivifying = false; +#endif + STOP (vivify); +} diff --git a/src/sat/kissat/vivify.h b/src/sat/kissat/vivify.h new file mode 100644 index 000000000..a83ac9303 --- /dev/null +++ b/src/sat/kissat/vivify.h @@ -0,0 +1,8 @@ +#ifndef _vivify_h_INCLUDED +#define _vivify_h_INCLUDED + +struct kissat; + +void kissat_vivify (struct kissat *); + +#endif diff --git a/src/sat/kissat/walk.c b/src/sat/kissat/walk.c new file mode 100644 index 000000000..88974ee7a --- /dev/null +++ b/src/sat/kissat/walk.c @@ -0,0 +1,966 @@ +#include "walk.h" +#include "allocate.h" +#include "decide.h" +#include "dense.h" +#include "inline.h" +#include "phases.h" +#include "print.h" +#include "rephase.h" +#include "report.h" +#include "terminate.h" +#include "warmup.h" + +#include + +typedef struct tagged tagged; +typedef struct counter counter; +typedef struct walker walker; + +#define LD_MAX_WALK_REF 31 +#define MAX_WALK_REF ((1u << LD_MAX_WALK_REF) - 1) + +struct tagged { + unsigned ref : LD_MAX_WALK_REF; + bool binary : 1; +}; + +static inline tagged make_tagged (bool binary, unsigned ref) { + assert (ref <= MAX_WALK_REF); + tagged res = {.binary = binary, .ref = ref}; + return res; +} + +struct counter { + unsigned count; + unsigned pos; +}; + +// clang-format off +typedef STACK (double) doubles; +// clang-format on + +#define INVALID_BEST_TRAIL_POS UINT_MAX + +struct walker { + kissat *solver; + + unsigned best_trail_pos; + unsigned clauses; + unsigned current; + unsigned exponents; + unsigned initial; + unsigned minimum; + unsigned offset; + + generator random; + + counter *counters; + litpairs *binaries; + tagged *refs; + double *table; + + value *original_values; + value *best_values; + + doubles scores; + unsigneds unsat; + unsigneds trail; + + double size; + double epsilon; + + uint64_t limit; + uint64_t flipped; +#ifndef QUIET + uint64_t start; + struct { + uint64_t flipped; + unsigned minimum; + } report; +#endif +}; + +static const unsigned *dereference_literals (kissat *solver, walker *walker, + unsigned counter_ref, + unsigned *size_ptr) { + assert (counter_ref < walker->clauses); + tagged tagged = walker->refs[counter_ref]; + unsigned const *lits; + if (tagged.binary) { + const unsigned binary_ref = tagged.ref; + lits = PEEK_STACK (*walker->binaries, binary_ref).lits; + *size_ptr = 2; + } else { + const reference clause_ref = tagged.ref; + clause *c = kissat_dereference_clause (solver, clause_ref); + *size_ptr = c->size; + lits = c->lits; + } + return lits; +} + +static void push_unsat (kissat *solver, walker *walker, counter *counters, + unsigned counter_ref) { + assert (counter_ref < walker->clauses); + counter *counter = counters + counter_ref; + assert (SIZE_STACK (walker->unsat) <= UINT_MAX); + counter->pos = SIZE_STACK (walker->unsat); + PUSH_STACK (walker->unsat, counter_ref); +#ifdef LOGGING + unsigned size; + const unsigned *const lits = + dereference_literals (solver, walker, counter_ref, &size); + LOGLITS (size, lits, "pushed unsatisfied[%u]", counter->pos); +#endif +} + +static bool pop_unsat (kissat *solver, walker *walker, counter *counters, + unsigned counter_ref, unsigned pos) { + assert (walker->current); + assert (counter_ref < walker->clauses); + assert (counters[counter_ref].pos == pos); + assert (walker->current == SIZE_STACK (walker->unsat)); + const unsigned other_counter_ref = POP_STACK (walker->unsat); + walker->current--; + bool res = false; + if (counter_ref != other_counter_ref) { + assert (other_counter_ref < walker->clauses); + counter *other_counter = counters + other_counter_ref; + assert (other_counter->pos == walker->current); + assert (pos < other_counter->pos); + other_counter->pos = pos; + POKE_STACK (walker->unsat, pos, other_counter_ref); + res = true; + } +#ifdef LOGGING + unsigned size; + const unsigned *const lits = + dereference_literals (solver, walker, counter_ref, &size); + LOGLITS (size, lits, "popped unsatisfied[%u]", pos); +#else + (void) solver; +#endif + return res; +} + +static double cbvals[][2] = {{0.0, 2.00}, {3.0, 2.50}, {4.0, 2.85}, + {5.0, 3.70}, {6.0, 5.10}, {7.0, 7.40}}; + +static double fit_cbval (double size) { + const size_t num_cbvals = sizeof cbvals / sizeof *cbvals; + size_t i = 0; + while (i + 2 < num_cbvals && + (cbvals[i][0] > size || cbvals[i + 1][0] < size)) + i++; + const double x2 = cbvals[i + 1][0], x1 = cbvals[i][0]; + const double y2 = cbvals[i + 1][1], y1 = cbvals[i][1]; + const double dx = x2 - x1, dy = y2 - y1; + assert (dx); + const double res = dy * (size - x1) / dx + y1; + assert (res > 0); + return res; +} + +static void init_score_table (walker *walker) { + kissat *solver = walker->solver; + + const double cb = (GET (walks) & 1) ? fit_cbval (walker->size) : 2.0; + const double base = 1 / cb; + + double next; + unsigned exponents = 0; + for (next = 1; next; next *= base) + exponents++; + + walker->table = kissat_malloc (solver, exponents * sizeof (double)); + + unsigned i = 0; + double epsilon; + for (epsilon = next = 1; next; next = epsilon * base) + walker->table[i++] = epsilon = next; + + assert (i == exponents); + walker->exponents = exponents; + walker->epsilon = epsilon; + + kissat_phase (solver, "walk", GET (walks), + "CB %.2f with inverse %.2f as base", cb, base); + kissat_phase (solver, "walk", GET (walks), "table size %u and epsilon %g", + exponents, epsilon); +} + +static unsigned currently_unsatified (walker *walker) { + return SIZE_STACK (walker->unsat); +} + +static void import_decision_phases (walker *walker) { + kissat *solver = walker->solver; + INC (walk_decisions); + const flags *const flags = solver->flags; + value *values = solver->values; + walker->best_values = kissat_calloc (solver, VARS, 1); + value *best_values = walker->best_values; +#ifndef QUIET + unsigned imported = 0; +#endif + for (all_variables (idx)) { + if (!flags[idx].active) + continue; + value value = kissat_decide_phase (solver, idx); + assert (value); + best_values[idx] = value; + const unsigned lit = LIT (idx); + const unsigned not_lit = NOT (lit); + values[lit] = value; + values[not_lit] = -value; +#ifndef QUIET + imported++; +#endif + LOG ("copied %s decision phase %d", LOGVAR (idx), (int) value); + } + kissat_phase (solver, "walk", GET (walks), + "imported %u decision phases %.0f%%", imported, + kissat_percent (imported, solver->active)); +} + +static unsigned connect_binary_counters (walker *walker) { + kissat *solver = walker->solver; + value *values = solver->values; + tagged *refs = walker->refs; + watches *all_watches = solver->watches; + counter *counters = walker->counters; + + assert (SIZE_STACK (*walker->binaries) <= UINT_MAX); + const unsigned size = SIZE_STACK (*walker->binaries); + litpair *binaries = BEGIN_STACK (*walker->binaries); + unsigned unsat = 0, counter_ref = 0; + + for (unsigned binary_ref = 0; binary_ref < size; binary_ref++) { + const litpair *const litpair = binaries + binary_ref; + const unsigned first = litpair->lits[0]; + const unsigned second = litpair->lits[1]; + assert (first < LITS), assert (second < LITS); + const value first_value = values[first]; + const value second_value = values[second]; + if (!first_value || !second_value) + continue; + assert (counter_ref < walker->clauses); + refs[counter_ref] = make_tagged (true, binary_ref); + watches *first_watches = all_watches + first; + watches *second_watches = all_watches + second; + kissat_push_large_watch (solver, first_watches, counter_ref); + kissat_push_large_watch (solver, second_watches, counter_ref); + const unsigned count = (first_value > 0) + (second_value > 0); + counter *counter = counters + counter_ref; + counter->count = count; + if (!count) { + push_unsat (solver, walker, counters, counter_ref); + unsat++; + } + counter_ref++; + } + kissat_phase (solver, "walk", GET (walks), + "initially %u unsatisfied binary clauses %.0f%% out of %u", + unsat, kissat_percent (unsat, counter_ref), counter_ref); +#ifdef QUIET + (void) unsat; +#endif + walker->size += 2.0 * counter_ref; + return counter_ref; +} + +static void connect_large_counters (walker *walker, unsigned counter_ref) { + kissat *solver = walker->solver; + assert (!solver->level); + const value *const original_values = walker->original_values; + const value *const local_search_values = solver->values; + ward *const arena = BEGIN_STACK (solver->arena); + counter *counters = walker->counters; + tagged *refs = walker->refs; + + unsigned unsat = 0; + unsigned large = 0; + + clause *last_irredundant = kissat_last_irredundant_clause (solver); + + for (all_clauses (c)) { + if (last_irredundant && c > last_irredundant) + break; + if (c->garbage) + continue; + if (c->redundant) + continue; + bool continue_with_next_clause = false; + for (all_literals_in_clause (lit, c)) { + const value value = original_values[lit]; + if (value <= 0) + continue; + LOGCLS (c, "%s satisfied", LOGLIT (lit)); + kissat_mark_clause_as_garbage (solver, c); + assert (c->garbage); + continue_with_next_clause = true; + break; + } + if (continue_with_next_clause) + continue; + large++; + assert (kissat_clause_in_arena (solver, c)); + reference clause_ref = (ward *) c - arena; + assert (clause_ref <= MAX_WALK_REF); + assert (counter_ref < walker->clauses); + refs[counter_ref] = make_tagged (false, clause_ref); + unsigned count = 0, size = 0; + for (all_literals_in_clause (lit, c)) { + const value value = local_search_values[lit]; + if (!value) { + assert (original_values[lit] < 0); + continue; + } + watches *watches = &WATCHES (lit); + kissat_push_large_watch (solver, watches, counter_ref); + size++; + if (value > 0) + count++; + } + counter *counter = walker->counters + counter_ref; + counter->count = count; + + if (!count) { + push_unsat (solver, walker, counters, counter_ref); + unsat++; + } + counter_ref++; + walker->size += size; + } + kissat_phase (solver, "walk", GET (walks), + "initially %u unsatisfied large clauses %.0f%% out of %u", + unsat, kissat_percent (unsat, large), large); +#ifdef QUIET + (void) large; + (void) unsat; +#endif +} + +#ifndef QUIET + +static void report_initial_minimum (kissat *solver, walker *walker) { + walker->report.minimum = walker->minimum; + kissat_very_verbose (solver, "initial minimum of %u unsatisfied clauses", + walker->minimum); +} + +static void report_minimum (const char *type, kissat *solver, + walker *walker) { + assert (walker->minimum <= walker->report.minimum); + kissat_very_verbose (solver, + "%s minimum of %u unsatisfied clauses after %" PRIu64 + " flipped literals", + type, walker->minimum, walker->flipped); + walker->report.minimum = walker->minimum; +} +#else +#define report_initial_minimum(...) \ + do { \ + } while (0) +#define report_minimum(...) \ + do { \ + } while (0) +#endif + +static void init_walker (kissat *solver, walker *walker, + litpairs *binaries) { + uint64_t clauses = BINIRR_CLAUSES; + assert (clauses <= MAX_WALK_REF); + + memset (walker, 0, sizeof *walker); + + walker->solver = solver; + walker->clauses = clauses; + walker->binaries = binaries; + walker->random = solver->random ^ solver->statistics.walks; + + walker->original_values = solver->values; + solver->values = kissat_calloc (solver, LITS, 1); + + import_decision_phases (walker); + + walker->counters = kissat_malloc (solver, clauses * sizeof (counter)); + walker->refs = kissat_malloc (solver, clauses * sizeof (tagged)); + + assert (!walker->size); + const unsigned counter_ref = connect_binary_counters (walker); + connect_large_counters (walker, counter_ref); + + walker->current = walker->initial = currently_unsatified (walker); + + kissat_phase (solver, "walk", GET (walks), + "initially %u unsatisfied irredundant clauses %.0f%% " + "out of %" PRIu64, + walker->initial, kissat_percent (walker->initial, clauses), + clauses); + + walker->size = kissat_average (walker->size, clauses); + kissat_phase (solver, "walk", GET (walks), "average clause size %.2f", + walker->size); + + walker->minimum = walker->current; + init_score_table (walker); + + report_initial_minimum (solver, walker); +} + +static void init_walker_limit (kissat *solver, walker *walker) { + SET_EFFORT_LIMIT (limit, walk, walk_steps); + walker->limit = limit; + walker->flipped = 0; +#ifndef QUIET + walker->start = solver->statistics.walk_steps; + walker->report.minimum = UINT_MAX; + walker->report.flipped = 0; +#endif +} + +static void release_walker (walker *walker) { + kissat *solver = walker->solver; + kissat_dealloc (solver, walker->table, walker->exponents, + sizeof (double)); + unsigned clauses = walker->clauses; + kissat_dealloc (solver, walker->refs, clauses, sizeof (tagged)); + kissat_dealloc (solver, walker->counters, clauses, sizeof (counter)); + RELEASE_STACK (walker->unsat); + RELEASE_STACK (walker->scores); + RELEASE_STACK (walker->trail); + kissat_free (solver, solver->values, LITS); + kissat_free (solver, walker->best_values, VARS); + RELEASE_STACK (walker->unsat); + solver->values = walker->original_values; +} + +static unsigned break_value (kissat *solver, walker *walker, value *values, + unsigned lit) { + assert (values[lit] < 0); + const unsigned not_lit = NOT (lit); + watches *watches = &WATCHES (not_lit); + unsigned steps = 1; + unsigned res = 0; + for (all_binary_large_watches (watch, *watches)) { + steps++; + assert (!watch.type.binary); + reference counter_ref = watch.large.ref; + assert (counter_ref < walker->clauses); + counter *counter = walker->counters + counter_ref; + res += (counter->count == 1); + } + ADD (walk_steps, steps); +#ifdef NDEBUG + (void) values; +#endif + return res; +} + +static double scale_score (walker *walker, unsigned breaks) { + if (breaks < walker->exponents) + return walker->table[breaks]; + else + return walker->epsilon; +} + +static unsigned pick_literal (kissat *solver, walker *walker) { + assert (walker->current == SIZE_STACK (walker->unsat)); + const unsigned pos = walker->flipped++ % walker->current; + const unsigned counter_ref = PEEK_STACK (walker->unsat, pos); + unsigned size; + const unsigned *const lits = + dereference_literals (solver, walker, counter_ref, &size); + + LOGLITS (size, lits, "picked unsatisfied[%u]", pos); + assert (EMPTY_STACK (walker->scores)); + + value *values = solver->values; + + double sum = 0; + unsigned picked_lit = INVALID_LIT; + + const unsigned *const end_of_lits = lits + size; + for (const unsigned *p = lits; p != end_of_lits; p++) { + const unsigned lit = *p; + if (!values[lit]) + continue; + picked_lit = lit; + const unsigned breaks = break_value (solver, walker, values, lit); + const double score = scale_score (walker, breaks); + assert (score > 0); + LOG ("literal %s breaks %u score %g", LOGLIT (lit), breaks, score); + PUSH_STACK (walker->scores, score); + sum += score; + } + assert (picked_lit != INVALID_LIT); + assert (0 < sum); + + const double random = kissat_pick_double (&walker->random); + assert (0 <= random), assert (random < 1); + + const double threshold = sum * random; + LOG ("score sum %g and random threshold %g", sum, threshold); + + // assert (threshold < sum); // NOT TRUE!!!! + + double *scores = BEGIN_STACK (walker->scores); +#ifdef LOGGING + double picked_score = 0; +#endif + + sum = 0; + + for (const unsigned *p = lits; p != end_of_lits; p++) { + const unsigned lit = *p; + if (!values[lit]) + continue; + const double score = *scores++; + sum += score; + if (threshold < sum) { + picked_lit = lit; +#ifdef LOGGING + picked_score = score; +#endif + break; + } + } + assert (picked_lit != INVALID_LIT); + LOG ("picked literal %s with score %g", LOGLIT (picked_lit), + picked_score); + + CLEAR_STACK (walker->scores); + + return picked_lit; +} + +static void break_clauses (kissat *solver, walker *walker, + const value *const values, unsigned flipped) { +#ifdef LOGGING + unsigned broken = 0; +#endif + const unsigned not_flipped = NOT (flipped); + assert (values[not_flipped] < 0); + LOG ("breaking one-satisfied clauses containing negated flipped literal " + "%s", + LOGLIT (not_flipped)); + watches *watches = &WATCHES (not_flipped); + counter *counters = walker->counters; + unsigned steps = 1; + for (all_binary_large_watches (watch, *watches)) { + steps++; + assert (!watch.type.binary); + const unsigned counter_ref = watch.large.ref; + assert (counter_ref < walker->clauses); + counter *counter = counters + counter_ref; + assert (counter->count); + if (--counter->count) + continue; + push_unsat (solver, walker, counters, counter_ref); +#ifdef LOGGING + broken++; +#endif + } + LOG ("broken %u one-satisfied clauses containing " + "negated flipped literal %s", + broken, LOGLIT (not_flipped)); + ADD (walk_steps, steps); +#ifdef NDEBUG + (void) values; +#endif +} + +static void make_clauses (kissat *solver, walker *walker, + const value *const values, unsigned flipped) { + assert (values[flipped] > 0); + LOG ("making unsatisfied clauses containing flipped literal %s", + LOGLIT (flipped)); + watches *watches = &WATCHES (flipped); + counter *counters = walker->counters; + unsigned steps = 1; +#ifdef LOGGING + unsigned made = 0; +#endif + for (all_binary_large_watches (watch, *watches)) { + steps++; + assert (!watch.type.binary); + const unsigned counter_ref = watch.large.ref; + assert (counter_ref < walker->clauses); + counter *counter = counters + counter_ref; + assert (counter->count < UINT_MAX); + if (counter->count++) + continue; + if (pop_unsat (solver, walker, counters, counter_ref, counter->pos)) + steps++; +#ifdef LOGGING + made++; +#endif + } + LOG ("made %u unsatisfied clauses containing flipped literal %s", made, + LOGLIT (flipped)); + ADD (walk_steps, steps); +#ifdef NDEBUG + (void) values; +#endif +} + +static void save_all_values (kissat *solver, walker *walker) { + assert (EMPTY_STACK (walker->trail)); + assert (walker->best_trail_pos == INVALID_BEST_TRAIL_POS); + LOG ("copying all values as best phases since trail is invalid"); + const value *const current_values = solver->values; + value *best_values = walker->best_values; + for (all_variables (idx)) { + const unsigned lit = LIT (idx); + const value value = current_values[lit]; + if (value) + best_values[idx] = value; + } + LOG ("reset best trail position to 0"); + walker->best_trail_pos = 0; +} + +static void save_walker_trail (kissat *solver, walker *walker, bool keep) { +#if defined(LOGGING) || !defined(NDEBUG) + assert (walker->best_trail_pos != INVALID_BEST_TRAIL_POS); + assert (SIZE_STACK (walker->trail) <= UINT_MAX); + const unsigned size_trail = SIZE_STACK (walker->trail); + assert (walker->best_trail_pos <= size_trail); + const unsigned kept = size_trail - walker->best_trail_pos; + LOG ("saving %u values of flipped literals on trail of size %u", + walker->best_trail_pos, size_trail); +#else + (void) solver; +#endif + value *best_values = walker->best_values; + unsigned *begin = BEGIN_STACK (walker->trail); + const unsigned *const best = begin + walker->best_trail_pos; + for (const unsigned *p = begin; p != best; p++) { + const unsigned lit = *p; + const value value = NEGATED (lit) ? -1 : 1; + const unsigned idx = IDX (lit); + best_values[idx] = value; + } + if (!keep) { + LOG ("no need to shift and keep remaining %u literals", kept); + return; + } + LOG ("flushed %u literals %.0f%% from trail", walker->best_trail_pos, + kissat_percent (walker->best_trail_pos, size_trail)); + const unsigned *const end = END_STACK (walker->trail); + unsigned *q = begin; + for (const unsigned *p = best; p != end; p++) + *q++ = *p; + assert ((size_t) (end - q) == walker->best_trail_pos); + assert ((size_t) (q - begin) == kept); + SET_END_OF_STACK (walker->trail, q); + LOG ("keeping %u literals %.0f%% on trail", kept, + kissat_percent (kept, size_trail)); + LOG ("reset best trail position to 0"); + walker->best_trail_pos = 0; +} + +static void push_flipped (kissat *solver, walker *walker, + unsigned flipped) { + if (walker->best_trail_pos == INVALID_BEST_TRAIL_POS) { + LOG ("not pushing flipped %s to already invalid trail", + LOGLIT (flipped)); + assert (EMPTY_STACK (walker->trail)); + } else { + assert (SIZE_STACK (walker->trail) <= UINT_MAX); + const unsigned size_trail = SIZE_STACK (walker->trail); + assert (walker->best_trail_pos <= size_trail); + const unsigned limit = VARS / 4 + 1; + assert (limit < INVALID_BEST_TRAIL_POS); + if (size_trail < limit) { + PUSH_STACK (walker->trail, flipped); + LOG ("pushed flipped %s to trail which now has size %u", + LOGLIT (flipped), size_trail + 1); + } else if (walker->best_trail_pos) { + LOG ("trail reached limit %u but has best position %u", limit, + walker->best_trail_pos); + save_walker_trail (solver, walker, true); + PUSH_STACK (walker->trail, flipped); + assert (SIZE_STACK (walker->trail) <= UINT_MAX); + LOG ("pushed flipped %s to trail which now has size %zu", + LOGLIT (flipped), SIZE_STACK (walker->trail)); + } else { + LOG ("trail reached limit %u without best position", limit); + CLEAR_STACK (walker->trail); + LOG ("not pushing %s to invalidated trail", LOGLIT (flipped)); + walker->best_trail_pos = INVALID_BEST_TRAIL_POS; + LOG ("best trail position becomes invalid"); + } + } +} + +static void flip_literal (kissat *solver, walker *walker, unsigned flip) { + LOG ("flipping literal %s", LOGLIT (flip)); + value *values = solver->values; + const value value = values[flip]; + assert (value < 0); + values[flip] = -value; + values[NOT (flip)] = value; + make_clauses (solver, walker, values, flip); + break_clauses (solver, walker, values, flip); + walker->current = currently_unsatified (walker); +} + +static void update_best (kissat *solver, walker *walker) { + assert (walker->current < walker->minimum); + walker->minimum = walker->current; +#ifndef QUIET + int verbosity = kissat_verbosity (solver); + bool report = (verbosity > 2); + if (verbosity == 2) { + if (walker->flipped / 2 >= walker->report.flipped) + report = true; + else if (walker->minimum < 5 || walker->report.minimum == UINT_MAX || + walker->minimum <= walker->report.minimum / 2) + report = true; + if (report) { + walker->report.minimum = walker->minimum; + walker->report.flipped = walker->flipped; + } + } + if (report) + report_minimum ("new", solver, walker); +#endif + if (walker->best_trail_pos == INVALID_BEST_TRAIL_POS) + save_all_values (solver, walker); + else { + assert (SIZE_STACK (walker->trail) < INVALID_BEST_TRAIL_POS); + walker->best_trail_pos = SIZE_STACK (walker->trail); + LOG ("new best trail position %u", walker->best_trail_pos); + } +} + +static void local_search_step (kissat *solver, walker *walker) { + assert (walker->current); + INC (flipped); + assert (walker->flipped < UINT64_MAX); + walker->flipped++; + LOG ("starting local search flip %" PRIu64 " with %u unsatisfied clauses", + GET (flipped), walker->current); + unsigned lit = pick_literal (solver, walker); + flip_literal (solver, walker, lit); + push_flipped (solver, walker, lit); + if (walker->current < walker->minimum) + update_best (solver, walker); + LOG ("ending local search step %" PRIu64 " with %u unsatisfied clauses", + GET (flipped), walker->current); +} + +static void local_search_round (walker *walker) { + kissat *solver = walker->solver; +#ifndef QUIET + const unsigned before = walker->minimum; +#endif + statistics *statistics = &solver->statistics; + while (walker->minimum && walker->limit > statistics->walk_steps) { + if (TERMINATED (walk_terminated_1)) + break; + local_search_step (solver, walker); + } +#ifndef QUIET + report_minimum ("last", solver, walker); + assert (statistics->walk_steps >= walker->start); + const uint64_t steps = statistics->walk_steps - walker->start; + // clang-format off + kissat_very_verbose (solver, + "walking ends with %u unsatisfied clauses", walker->current); + kissat_very_verbose (solver, + "flipping %" PRIu64 " literals took %" PRIu64 " steps (%.2f per flipped)", + walker->flipped, steps, kissat_average (steps, walker->flipped)); + // clang-format on + const unsigned after = walker->minimum; + kissat_phase ( + solver, "walk", GET (walks), "%s minimum %u after %" PRIu64 " flips", + after < before ? "new" : "unchanged", after, walker->flipped); +#endif +} + +static void export_best_values (walker *walker) { + kissat *const solver = walker->solver; + const value *const best = walker->best_values; + value *const saved = solver->phases.saved; + assert (sizeof *saved == 1); + assert (sizeof *best == 1); + memcpy (saved, best, VARS); +} + +static bool save_final_minimum (walker *walker) { + kissat *solver = walker->solver; + + assert (walker->minimum <= walker->initial); + if (walker->minimum == walker->initial) { + kissat_phase (solver, "walk", GET (walks), + "no improvement thus keeping saved phases"); + return false; + } + + kissat_phase (solver, "walk", GET (walks), + "saving improved assignment of %u unsatisfied clauses", + walker->minimum); + + if (!walker->best_trail_pos || + walker->best_trail_pos == INVALID_BEST_TRAIL_POS) + LOG ("minimum already saved"); + else + save_walker_trail (solver, walker, false); + + export_best_values (walker); + INC (walk_improved); + + return true; +} + +#ifdef CHECK_WALK + +static void check_walk (kissat *solver, unsigned expected) { + unsigned unsatisfied = 0; + watches *all_watches = solver->watches; + const value *const saved = solver->phases.saved; + for (all_literals (lit)) { + assert (lit < LITS); + watches *watches = all_watches + lit; + if (kissat_empty_vector (watches)) + continue; + value value = solver->values[lit]; + if (!value) { + value = saved[IDX (lit)]; + assert (value); + if (NEGATED (lit)) + value = -value; + } + if (value > 0) + continue; + for (all_binary_blocking_watches (watch, *watches)) + if (watch.type.binary) { + const unsigned other = watch.binary.lit; + if (other < lit) + continue; + value = solver->values[other]; + if (!value) { + value = saved[IDX (other)]; + assert (value); + if (NEGATED (other)) + value = -value; + } + if (value > 0) + continue; + unsatisfied++; + LOGBINARY (lit, other, "unsat"); + } + } + for (all_clauses (c)) { + if (c->redundant) + continue; + if (c->garbage) + continue; + bool satisfied = false; + for (all_literals_in_clause (lit, c)) { + value value = solver->values[lit]; + if (!value) { + value = saved[IDX (lit)]; + assert (value); + if (NEGATED (lit)) + value = -value; + } + if (value > 0) + satisfied = true; + } + if (satisfied) + continue; + LOGCLS (c, "unsatisfied"); + unsatisfied++; + } + LOG ("expected %u unsatisfied", expected); + LOG ("actually %u unsatisfied", unsatisfied); + assert (expected == unsatisfied); +} + +#endif + +static void walking_phase (kissat *solver) { + INC (walks); + litpairs irredundant; + INIT_STACK (irredundant); + kissat_enter_dense_mode (solver, &irredundant); + walker walker; + init_walker (solver, &walker, &irredundant); + init_walker_limit (solver, &walker); + local_search_round (&walker); +#ifdef CHECK_WALK + bool improved = +#endif + save_final_minimum (&walker); +#ifdef CHECK_WALK + unsigned expected = walker.minimum; +#endif + release_walker (&walker); + kissat_resume_sparse_mode (solver, false, &irredundant); + RELEASE_STACK (irredundant); +#if CHECK_WALK + if (improved) + check_walk (solver, expected); +#endif +} + +bool kissat_walking (kissat *solver) { + reference last_irredundant = solver->last_irredundant; + if (last_irredundant == INVALID_REF) + last_irredundant = SIZE_STACK (solver->arena); + + if (last_irredundant > MAX_WALK_REF) { + kissat_extremely_verbose (solver, + "can not walk since last " + "irredundant clause reference %u too large", + last_irredundant); + return false; + } + + uint64_t clauses = BINIRR_CLAUSES; + if (clauses > MAX_WALK_REF) { + kissat_extremely_verbose (solver, + "can not walk due to " + "way too many irredundant clauses %" PRIu64, + clauses); + return false; + } + + return true; +} + +void kissat_walk (kissat *solver) { + assert (!solver->level); + assert (!solver->inconsistent); + assert (kissat_propagated (solver)); + assert (kissat_walking (solver)); + + reference last_irredundant = solver->last_irredundant; + if (last_irredundant == INVALID_REF) + last_irredundant = SIZE_STACK (solver->arena); + + if (last_irredundant > MAX_WALK_REF) { + kissat_phase (solver, "walk", GET (walks), + "last irredundant clause reference %u too large", + last_irredundant); + return; + } + + uint64_t clauses = BINIRR_CLAUSES; + if (clauses > MAX_WALK_REF) { + kissat_phase (solver, "walk", GET (walks), + "way too many irredundant clauses %" PRIu64, clauses); + return; + } + + if (GET_OPTION (warmup)) + kissat_warmup (solver); + + STOP_SEARCH_AND_START_SIMPLIFIER (walking); + walking_phase (solver); + STOP_SIMPLIFIER_AND_RESUME_SEARCH (walking); +} diff --git a/src/sat/kissat/walk.h b/src/sat/kissat/walk.h new file mode 100644 index 000000000..0acc19193 --- /dev/null +++ b/src/sat/kissat/walk.h @@ -0,0 +1,11 @@ +#ifndef _walk_h_INCLUDED +#define _walk_h_INCLUDED + +#include + +struct kissat; + +bool kissat_walking (struct kissat *); +void kissat_walk (struct kissat *); + +#endif diff --git a/src/sat/kissat/warmup.c b/src/sat/kissat/warmup.c new file mode 100644 index 000000000..d9fa9f534 --- /dev/null +++ b/src/sat/kissat/warmup.c @@ -0,0 +1,54 @@ +#include "warmup.h" +#include "backtrack.h" +#include "decide.h" +#include "internal.h" +#include "print.h" +#include "propbeyond.h" +#include "terminate.h" + +void kissat_warmup (kissat *solver) { + assert (!solver->level); + assert (solver->watching); + assert (!solver->inconsistent); + assert (GET_OPTION (warmup)); + START (warmup); + assert (!solver->warming); + solver->warming = true; + INC (warmups); +#ifndef QUIET + const statistics *stats = &solver->statistics; + uint64_t propagations = stats->warming_propagations; + uint64_t decisions = stats->warming_decisions; +#endif + while (solver->unassigned) { + if (TERMINATED (warmup_terminated_1)) + break; + kissat_decide (solver); + kissat_propagate_beyond_conflicts (solver); + } + assert (!solver->inconsistent); +#ifndef QUIET + decisions = stats->warming_decisions - decisions; + propagations = stats->warming_propagations - propagations; + + kissat_very_verbose (solver, + "warming-up needed %" PRIu64 + " decisions and %" PRIu64 " propagations", + decisions, propagations); + + if (solver->unassigned) + kissat_verbose (solver, + "reached decision level %u " + "during warming-up saved phases", + solver->level); + else + kissat_verbose (solver, + "all variables assigned at decision level %u " + "during warming-up saved phases", + solver->level); +#endif + kissat_backtrack_without_updating_phases (solver, 0); + assert (solver->warming); + solver->warming = false; + STOP (warmup); +} diff --git a/src/sat/kissat/warmup.h b/src/sat/kissat/warmup.h new file mode 100644 index 000000000..e0fd47122 --- /dev/null +++ b/src/sat/kissat/warmup.h @@ -0,0 +1,8 @@ +#ifndef _warmup_h_INCLUDED +#define _warmup_h_INCLUDED + +struct kissat; + +void kissat_warmup (struct kissat *); + +#endif diff --git a/src/sat/kissat/watch.c b/src/sat/kissat/watch.c new file mode 100644 index 000000000..39ceace6e --- /dev/null +++ b/src/sat/kissat/watch.c @@ -0,0 +1,223 @@ +#define INLINE_SORT + +#include "inline.h" +#include "sort.c" + +void kissat_remove_binary_watch (kissat *solver, watches *watches, + unsigned lit) { + watch *const begin = BEGIN_WATCHES (*watches); + watch *const end = END_WATCHES (*watches); + watch *q = begin; + watch const *p = q; +#ifndef NDEBUG + bool found = false; +#endif + while (p != end) { + const watch watch = *q++ = *p++; + if (!watch.type.binary) { + *q++ = *p++; + continue; + } + const unsigned other = watch.binary.lit; + if (other != lit) + continue; +#ifndef NDEBUG + assert (!found); + found = true; +#endif + q--; + } + assert (found); +#ifdef COMPACT + watches->size -= 1; +#else + assert (begin + 1 <= end); + watches->end -= 1; +#endif + const watch empty = {.raw = INVALID_VECTOR_ELEMENT}; + end[-1] = empty; + assert (solver->vectors.usable < MAX_SECTOR - 1); + solver->vectors.usable += 1; + kissat_check_vectors (solver); +} + +void kissat_remove_blocking_watch (kissat *solver, watches *watches, + reference ref) { + assert (solver->watching); + watch *const begin = BEGIN_WATCHES (*watches); + watch *const end = END_WATCHES (*watches); + watch *q = begin; + watch const *p = q; +#ifndef NDEBUG + bool found = false; +#endif + while (p != end) { + const watch head = *q++ = *p++; + if (head.type.binary) + continue; + const watch tail = *q++ = *p++; + if (tail.raw != ref) + continue; +#ifndef NDEBUG + assert (!found); + found = true; +#endif + q -= 2; + } + assert (found); +#ifdef COMPACT + watches->size -= 2; +#else + assert (begin + 2 <= end); + watches->end -= 2; +#endif + const watch empty = {.raw = INVALID_VECTOR_ELEMENT}; + end[-2] = end[-1] = empty; + assert (solver->vectors.usable < MAX_SECTOR - 2); + solver->vectors.usable += 2; + kissat_check_vectors (solver); +} + +void kissat_substitute_large_watch (kissat *solver, watches *watches, + watch src, watch dst) { + assert (!solver->watching); + watch *const begin = BEGIN_WATCHES (*watches); + const watch *const end = END_WATCHES (*watches); +#ifndef NDEBUG + bool found = false; +#endif + for (watch *p = begin; p != end; p++) { + const watch head = *p; + if (head.raw != src.raw) + continue; +#ifndef NDEBUG + found = true; +#endif + *p = dst; + break; + } + assert (found); +} + +void kissat_flush_all_connected (kissat *solver) { + assert (!solver->watching); + LOG ("flush all connected binaries and clauses"); + watches *all_watches = solver->watches; + for (all_literals (lit)) + RELEASE_WATCHES (all_watches[lit]); +} + +void kissat_flush_large_watches (kissat *solver) { + assert (solver->watching); + LOG ("flush large clause watches"); + watches *all_watches = solver->watches; + signed char *marks = solver->marks; + for (all_literals (lit)) { + watches *lit_watches = all_watches + lit; + watch *begin = BEGIN_WATCHES (*lit_watches), *q = begin; + const watch *const end = END_WATCHES (*lit_watches), *p = q; + while (p != end) { + const watch watch = *q++ = *p++; + if (!watch.type.binary) + p++, q--; + else { + const unsigned other = watch.binary.lit; + if (marks[other]) { + if (lit < other) { + LOGBINARY (lit, other, "flushing duplicated"); + kissat_delete_binary (solver, lit, other); + } + q--; + } else + marks[other] = 1; + } + } + SET_END_OF_WATCHES (*lit_watches, q); + for (p = begin; p != q; p++) { + assert (p->type.binary); + marks[p->binary.lit] = 0; + } + } +} + +void kissat_watch_large_clauses (kissat *solver) { + LOG ("watching all large clauses"); + 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); + + for (all_clauses (c)) { + if (c->garbage) + continue; + + 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_connect_irredundant_large_clauses (kissat *solver) { + assert (!solver->watching); + LOG ("connecting all large irredundant clauses"); + + clause *last_irredundant = kissat_last_irredundant_clause (solver); + + const value *const values = solver->values; + watches *all_watches = solver->watches; + ward *const arena = BEGIN_STACK (solver->arena); + + for (all_clauses (c)) { + if (last_irredundant && c > last_irredundant) + break; + if (c->redundant) + continue; + if (c->garbage) + continue; + bool satisfied = false; + assert (!solver->level); + for (all_literals_in_clause (lit, c)) { + const value value = values[lit]; + if (value <= 0) + continue; + satisfied = true; + break; + } + if (satisfied) { + kissat_mark_clause_as_garbage (solver, c); + continue; + } + const reference ref = (ward *) c - arena; + kissat_inlined_connect_clause (solver, all_watches, c, ref); + } +} + +void kissat_flush_large_connected (kissat *solver) { + assert (!solver->watching); + LOG ("flushing large connected clause references"); + size_t flushed = 0; + for (all_literals (lit)) { + watches *watches = &WATCHES (lit); + watch *begin = BEGIN_WATCHES (*watches), *q = begin; + const watch *const end_watches = END_WATCHES (*watches), *p = q; + while (p != end_watches) { + const watch head = *p++; + if (head.type.binary) + *q++ = head; + else + flushed++; + } + SET_END_OF_WATCHES (*watches, q); + } + LOG ("flushed %zu large clause references", flushed); + (void) flushed; +} diff --git a/src/sat/kissat/watch.h b/src/sat/kissat/watch.h new file mode 100644 index 000000000..50afdb083 --- /dev/null +++ b/src/sat/kissat/watch.h @@ -0,0 +1,176 @@ +#ifndef _watch_h_INCLUDED +#define _watch_h_INCLUDED + +#include "keatures.h" +#include "reference.h" +#include "stack.h" +#include "vector.h" + +#include + +typedef union watch watch; + +typedef struct binary_tagged_literal watch_type; +typedef struct binary_tagged_literal binary_watch; +typedef struct binary_tagged_literal blocking_watch; +typedef struct binary_tagged_reference large_watch; + +struct binary_tagged_literal { +#ifdef KISSAT_IS_BIG_ENDIAN + bool binary : 1; + unsigned lit : 31; +#else + unsigned lit : 31; + bool binary : 1; +#endif +}; + +struct binary_tagged_reference { +#ifdef KISSAT_IS_BIG_ENDIAN + bool binary : 1; + unsigned ref : 31; +#else + unsigned ref : 31; + bool binary : 1; +#endif +}; + +union watch { + watch_type type; + binary_watch binary; + blocking_watch blocking; + large_watch large; + unsigned raw; +}; + +typedef vector watches; + +typedef struct litwatch litwatch; +typedef struct litpair litpair; +typedef struct litriple litriple; + +typedef STACK (litwatch) litwatches; +typedef STACK (litpair) litpairs; +typedef STACK (litriple) litriples; + +struct litwatch { + unsigned lit; + watch watch; +}; + +struct litpair { + unsigned lits[2]; +}; + +struct litriple { + unsigned lits[3]; +}; + +static inline litpair kissat_litpair (unsigned lit, unsigned other) { + litpair res; + res.lits[0] = lit < other ? lit : other; + res.lits[1] = lit < other ? other : lit; + return res; +} + +static inline watch kissat_binary_watch (unsigned lit) { + watch res; + res.binary.lit = lit; + res.binary.binary = true; + assert (res.type.binary); + return res; +} + +static inline watch kissat_large_watch (reference ref) { + watch res; + res.large.ref = ref; + res.large.binary = false; + assert (!res.type.binary); + return res; +} + +static inline watch kissat_blocking_watch (unsigned lit) { + watch res; + res.blocking.lit = lit; + res.blocking.binary = false; + assert (!res.type.binary); + return res; +} + +#define EMPTY_WATCHES(W) kissat_empty_vector (&W) +#define SIZE_WATCHES(W) kissat_size_vector (&W) + +#define PUSH_WATCHES(W, E) \ + do { \ + assert (sizeof (E) == sizeof (unsigned)); \ + kissat_push_vectors (solver, &(W), (E).raw); \ + } while (0) + +#define LAST_WATCH_POINTER(WS) \ + (watch *) kissat_last_vector_pointer (solver, &WS) + +#define BEGIN_WATCHES(WS) \ + ((union watch *) kissat_begin_vector (solver, &(WS))) + +#define END_WATCHES(WS) ((union watch *) kissat_end_vector (solver, &(WS))) + +#define BEGIN_CONST_WATCHES(WS) \ + ((union watch *) kissat_begin_const_vector (solver, &(WS))) + +#define END_CONST_WATCHES(WS) \ + ((union watch *) kissat_end_const_vector (solver, &(WS))) + +#define RELEASE_WATCHES(WS) kissat_release_vector (solver, &(WS)) + +#define SET_END_OF_WATCHES(WS, P) \ + do { \ + size_t SIZE = (unsigned *) (P) - kissat_begin_vector (solver, &WS); \ + kissat_resize_vector (solver, &WS, SIZE); \ + } while (0) + +#define REMOVE_WATCHES(W, E) \ + kissat_remove_from_vector (solver, &(W), (E).raw) + +#define WATCHES(LIT) (solver->watches[assert ((LIT) < LITS), (LIT)]) + +// This iterator is currently only used in 'testreferences.c'. +// +#define all_binary_blocking_watch_ref(WATCH, REF, WATCHES) \ + watch WATCH, \ + *WATCH##_PTR = (assert (solver->watching), BEGIN_WATCHES (WATCHES)), \ + *const WATCH##_END = END_WATCHES (WATCHES); \ + WATCH##_PTR != WATCH##_END && \ + ((WATCH = *WATCH##_PTR), \ + (REF = WATCH.type.binary ? INVALID_REF : WATCH##_PTR[1].large.ref), \ + true); \ + WATCH##_PTR += 1u + !WATCH.type.binary + +#define all_binary_blocking_watches(WATCH, WATCHES) \ + watch WATCH, \ + *WATCH##_PTR = (assert (solver->watching), BEGIN_WATCHES (WATCHES)), \ + *const WATCH##_END = END_WATCHES (WATCHES); \ + WATCH##_PTR != WATCH##_END && ((WATCH = *WATCH##_PTR), true); \ + WATCH##_PTR += 1u + !WATCH.type.binary + +#define all_binary_large_watches(WATCH, WATCHES) \ + watch WATCH, \ + *WATCH##_PTR = \ + (assert (!solver->watching), BEGIN_WATCHES (WATCHES)), \ + *const WATCH##_END = END_WATCHES (WATCHES); \ + WATCH##_PTR != WATCH##_END && ((WATCH = *WATCH##_PTR), true); \ + ++WATCH##_PTR + +void kissat_remove_binary_watch (struct kissat *, watches *, unsigned); +void kissat_remove_blocking_watch (struct kissat *, watches *, reference); + +void kissat_substitute_large_watch (struct kissat *, watches *, watch src, + watch dst); + +void kissat_flush_all_connected (struct kissat *); +void kissat_flush_large_watches (struct kissat *); +void kissat_watch_large_clauses (struct kissat *); +void kissat_flush_large_connected (struct kissat *); + +void kissat_connect_irredundant_large_clauses (struct kissat *); + +#endif diff --git a/src/sat/kissat/weaken.c b/src/sat/kissat/weaken.c new file mode 100644 index 000000000..149616546 --- /dev/null +++ b/src/sat/kissat/weaken.c @@ -0,0 +1,60 @@ +#include "weaken.h" +#include "inline.h" + +static void push_witness_literal (kissat *solver, unsigned ilit) { + assert (!VALUE (ilit)); + int elit = kissat_export_literal (solver, ilit); + assert (elit); + LOG2 ("pushing external witness literal %d on extension stack", elit); + const extension ext = kissat_extension (true, elit); + PUSH_STACK (solver->extend, ext); +} + +static void push_clause_literal (kissat *solver, unsigned ilit) { + const value value = VALUE (ilit); + assert (value <= 0); + if (value < 0) + LOG ("not pushing internal falsified clause literal %s " + "on extension stack", + LOGLIT (ilit)); + else { + int elit = kissat_export_literal (solver, ilit); + assert (elit); + LOG2 ("pushing external clause literal %d on extension stack", elit); + const extension ext = kissat_extension (false, elit); + PUSH_STACK (solver->extend, ext); + } +} + +#define LOGPUSHED(SIZE) \ + do { \ + LOGEXT ((SIZE), END_STACK (solver->extend) - (SIZE), \ + "pushed size %zu witness labelled clause at", \ + (size_t) (SIZE)); \ + } while (0) + +void kissat_weaken_clause (kissat *solver, unsigned lit, clause *c) { + INC (weakened); + LOGCLS (c, "blocking on %s and weakening", LOGLIT (lit)); + push_witness_literal (solver, lit); + for (all_literals_in_clause (other, c)) + if (lit != other) + push_clause_literal (solver, other); + LOGPUSHED (c->size); +} + +void kissat_weaken_binary (kissat *solver, unsigned lit, unsigned other) { + INC (weakened); + LOGBINARY (lit, other, "blocking on %s and weakening", LOGLIT (lit)); + push_witness_literal (solver, lit); + push_clause_literal (solver, other); + LOGPUSHED (2); +} + +void kissat_weaken_unit (kissat *solver, unsigned lit) { + INC (weakened); + LOG ("blocking and weakening unit %s", LOGLIT (lit)); + push_witness_literal (solver, lit); + LOGEXT (1, END_STACK (solver->extend) - 1, + "pushed witness labelled unit clause at"); +} diff --git a/src/sat/kissat/weaken.h b/src/sat/kissat/weaken.h new file mode 100644 index 000000000..beabcb0ce --- /dev/null +++ b/src/sat/kissat/weaken.h @@ -0,0 +1,11 @@ +#ifndef _weaken_h_INCLUDED +#define _weaken_h_INCLUDED + +struct clause; +struct kissat; + +void kissat_weaken_unit (struct kissat *, unsigned lit); +void kissat_weaken_binary (struct kissat *, unsigned lit, unsigned other); +void kissat_weaken_clause (struct kissat *, unsigned lit, struct clause *); + +#endif diff --git a/src/sat/kissat/witness.h b/src/sat/kissat/witness.h new file mode 100644 index 000000000..2b0fdea63 --- /dev/null +++ b/src/sat/kissat/witness.h @@ -0,0 +1,10 @@ +#ifndef _witness_h_INCLUDED +#define _witness_h_INCLUDED + +#include + +struct kissat; + +void kissat_print_witness (struct kissat *, int max_var, bool partial); + +#endif From 664d285fcb18cbd7e51ece366b15ae3dc3f8154b Mon Sep 17 00:00:00 2001 From: MyskYko Date: Wed, 5 Mar 2025 04:10:49 -0800 Subject: [PATCH 2/3] patch --- Makefile | 2 +- abclib.dsp | 368 +++++++++++ src/base/abci/abc.c | 5 + src/sat/kissat/allocate.c | 14 +- src/sat/kissat/allocate.h | 13 +- src/sat/kissat/analyze.c | 144 ++--- src/sat/kissat/analyze.h | 5 + src/sat/kissat/ands.c | 12 +- src/sat/kissat/ands.h | 5 + src/sat/kissat/application.h | 5 + src/sat/kissat/arena.c | 28 +- src/sat/kissat/arena.h | 11 +- src/sat/kissat/array.h | 9 +- src/sat/kissat/assign.c | 14 +- src/sat/kissat/assign.h | 11 +- src/sat/kissat/attribute.h | 17 +- src/sat/kissat/averages.c | 6 +- src/sat/kissat/averages.h | 7 +- src/sat/kissat/backbone.c | 140 ++--- src/sat/kissat/backbone.h | 5 + src/sat/kissat/backtrack.c | 36 +- src/sat/kissat/backtrack.h | 5 + src/sat/kissat/build.c | 4 + src/sat/kissat/build.h | 10 + src/sat/kissat/bump.c | 12 +- src/sat/kissat/bump.h | 5 + src/sat/kissat/check.c | 72 +-- src/sat/kissat/check.h | 12 +- src/sat/kissat/classify.c | 6 +- src/sat/kissat/classify.h | 5 + src/sat/kissat/clause.c | 24 +- src/sat/kissat/clause.h | 5 + src/sat/kissat/collect.c | 166 ++--- src/sat/kissat/collect.h | 5 + src/sat/kissat/colors.c | 12 +- src/sat/kissat/colors.h | 17 +- src/sat/kissat/compact.c | 98 +-- src/sat/kissat/compact.h | 5 + src/sat/kissat/config.c | 4 +- src/sat/kissat/config.h | 8 +- src/sat/kissat/congruence.c | 774 ++++++++++++------------ src/sat/kissat/congruence.h | 5 + src/sat/kissat/cover.h | 5 + src/sat/kissat/decide.c | 34 +- src/sat/kissat/decide.h | 5 + src/sat/kissat/deduce.c | 60 +- src/sat/kissat/deduce.h | 5 + src/sat/kissat/definition.c | 48 +- src/sat/kissat/definition.h | 5 + src/sat/kissat/dense.c | 42 +- src/sat/kissat/dense.h | 5 + src/sat/kissat/dump.c | 22 +- src/sat/kissat/eliminate.c | 82 +-- src/sat/kissat/eliminate.h | 5 + src/sat/kissat/equivalences.c | 4 + src/sat/kissat/equivalences.h | 5 + src/sat/kissat/error.c | 4 + src/sat/kissat/error.h | 5 + src/sat/kissat/extend.c | 42 +- src/sat/kissat/extend.h | 7 +- src/sat/kissat/factor.c | 210 ++++--- src/sat/kissat/factor.h | 5 + src/sat/kissat/fastassign.h | 13 +- src/sat/kissat/fastel.c | 94 +-- src/sat/kissat/fastel.h | 5 + src/sat/kissat/fifo.h | 19 +- src/sat/kissat/file.c | 34 +- src/sat/kissat/file.h | 35 +- src/sat/kissat/flags.c | 62 +- src/sat/kissat/flags.h | 7 +- src/sat/kissat/format.c | 24 +- src/sat/kissat/format.h | 23 +- src/sat/kissat/forward.c | 114 ++-- src/sat/kissat/forward.h | 5 + src/sat/kissat/frames.h | 7 +- src/sat/kissat/gates.c | 14 +- src/sat/kissat/gates.h | 5 + src/sat/kissat/global.h | 14 + src/sat/kissat/handle.h | 5 + src/sat/kissat/heap.c | 30 +- src/sat/kissat/heap.h | 13 +- src/sat/kissat/ifthenelse.c | 14 +- src/sat/kissat/ifthenelse.h | 5 + src/sat/kissat/import.c | 32 +- src/sat/kissat/import.h | 5 + src/sat/kissat/inline.h | 73 +-- src/sat/kissat/inlineassign.h | 19 +- src/sat/kissat/inlineframes.h | 7 +- src/sat/kissat/inlineheap.h | 21 +- src/sat/kissat/inlinequeue.h | 33 +- src/sat/kissat/inlinevector.h | 57 +- src/sat/kissat/internal.c | 106 ++-- src/sat/kissat/internal.h | 33 +- src/sat/kissat/keatures.h | 5 + src/sat/kissat/kimits.c | 34 +- src/sat/kissat/kimits.h | 15 +- src/sat/kissat/kissat.h | 8 + src/sat/kissat/kissatSolver.c | 198 ++++++ src/sat/kissat/kissatSolver.h | 71 +++ src/sat/kissat/kissatTest.c | 133 ++++ src/sat/kissat/kitten.c | 350 ++++++----- src/sat/kissat/kitten.h | 5 + src/sat/kissat/{options.c => kptions.c} | 36 +- src/sat/kissat/krite.c | 6 +- src/sat/kissat/krite.h | 5 + src/sat/kissat/{lucky.c => kucky.c} | 74 +-- src/sat/kissat/learn.c | 34 +- src/sat/kissat/learn.h | 5 + src/sat/kissat/literal.h | 15 +- src/sat/kissat/logging.c | 16 +- src/sat/kissat/logging.h | 9 +- src/sat/kissat/lucky.h | 5 + src/sat/kissat/minimize.c | 48 +- src/sat/kissat/minimize.h | 5 + src/sat/kissat/mode.c | 46 +- src/sat/kissat/mode.h | 7 +- src/sat/kissat/module.make | 91 +++ src/sat/kissat/options.h | 19 +- src/sat/kissat/parse.h | 5 + src/sat/kissat/phases.c | 18 +- src/sat/kissat/phases.h | 11 +- src/sat/kissat/preprocess.c | 26 +- src/sat/kissat/preprocess.h | 5 + src/sat/kissat/print.c | 8 +- src/sat/kissat/print.h | 9 +- src/sat/kissat/probe.c | 28 +- src/sat/kissat/probe.h | 5 + src/sat/kissat/profile.c | 38 +- src/sat/kissat/profile.h | 9 +- src/sat/kissat/promote.c | 24 +- src/sat/kissat/promote.h | 13 +- src/sat/kissat/proof.c | 96 +-- src/sat/kissat/proof.h | 11 +- src/sat/kissat/propbeyond.c | 14 +- src/sat/kissat/propbeyond.h | 5 + src/sat/kissat/propdense.c | 30 +- src/sat/kissat/propdense.h | 5 + src/sat/kissat/propinitially.c | 16 +- src/sat/kissat/propinitially.h | 5 + src/sat/kissat/proplit.h | 56 +- src/sat/kissat/proprobe.c | 10 +- src/sat/kissat/proprobe.h | 5 + src/sat/kissat/propsearch.c | 12 +- src/sat/kissat/propsearch.h | 5 + src/sat/kissat/queue.c | 18 +- src/sat/kissat/queue.h | 9 +- src/sat/kissat/random.h | 13 +- src/sat/kissat/rank.h | 19 +- src/sat/kissat/reduce.c | 32 +- src/sat/kissat/reduce.h | 5 + src/sat/kissat/reference.h | 5 + src/sat/kissat/reluctant.c | 12 +- src/sat/kissat/reluctant.h | 5 + src/sat/kissat/reorder.c | 35 +- src/sat/kissat/reorder.h | 5 + src/sat/kissat/rephase.c | 16 +- src/sat/kissat/rephase.h | 5 + src/sat/kissat/report.c | 10 +- src/sat/kissat/report.h | 10 +- src/sat/kissat/require.h | 7 +- src/sat/kissat/resize.c | 28 +- src/sat/kissat/resize.h | 5 + src/sat/kissat/resolve.c | 26 +- src/sat/kissat/resolve.h | 5 + src/sat/kissat/resources.c | 20 +- src/sat/kissat/resources.h | 7 +- src/sat/kissat/restart.c | 14 +- src/sat/kissat/restart.h | 5 + src/sat/kissat/search.c | 20 +- src/sat/kissat/search.h | 5 + src/sat/kissat/shrink.c | 68 ++- src/sat/kissat/shrink.h | 5 + src/sat/kissat/smooth.c | 12 +- src/sat/kissat/smooth.h | 5 + src/sat/kissat/sort.c | 18 +- src/sat/kissat/sort.h | 19 +- src/sat/kissat/stack.c | 26 +- src/sat/kissat/stack.h | 23 +- src/sat/kissat/statistics.c | 20 +- src/sat/kissat/statistics.h | 39 +- src/sat/kissat/strengthen.c | 70 ++- src/sat/kissat/strengthen.h | 5 + src/sat/kissat/substitute.c | 82 +-- src/sat/kissat/substitute.h | 5 + src/sat/kissat/sweep.c | 264 ++++---- src/sat/kissat/sweep.h | 5 + src/sat/kissat/terminate.c | 6 +- src/sat/kissat/terminate.h | 13 +- src/sat/kissat/tiers.c | 16 +- src/sat/kissat/tiers.h | 5 + src/sat/kissat/trail.c | 38 +- src/sat/kissat/trail.h | 5 + src/sat/kissat/transitive.c | 78 +-- src/sat/kissat/transitive.h | 5 + src/sat/kissat/utilities.c | 4 + src/sat/kissat/utilities.h | 40 +- src/sat/kissat/value.h | 9 +- src/sat/kissat/vector.c | 78 +-- src/sat/kissat/vector.h | 9 +- src/sat/kissat/vivify.c | 283 ++++----- src/sat/kissat/vivify.h | 5 + src/sat/kissat/walk.c | 202 ++++--- src/sat/kissat/walk.h | 5 + src/sat/kissat/warmup.c | 22 +- src/sat/kissat/warmup.h | 5 + src/sat/kissat/watch.c | 56 +- src/sat/kissat/watch.h | 21 +- src/sat/kissat/weaken.c | 12 +- src/sat/kissat/weaken.h | 5 + src/sat/kissat/witness.h | 5 + 210 files changed, 4590 insertions(+), 2692 deletions(-) create mode 100644 src/sat/kissat/build.h create mode 100644 src/sat/kissat/global.h create mode 100644 src/sat/kissat/kissatSolver.c create mode 100644 src/sat/kissat/kissatSolver.h create mode 100644 src/sat/kissat/kissatTest.c rename src/sat/kissat/{options.c => kptions.c} (94%) rename src/sat/kissat/{lucky.c => kucky.c} (89%) create mode 100644 src/sat/kissat/module.make diff --git a/Makefile b/Makefile index 9b4838ce8..2da81734b 100644 --- a/Makefile +++ b/Makefile @@ -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 \ diff --git a/abclib.dsp b/abclib.dsp index 358a966a7..7f6af6f81 100644 --- a/abclib.dsp +++ b/abclib.dsp @@ -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" diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index ac178258f..e036283f0 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -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" ); diff --git a/src/sat/kissat/allocate.c b/src/sat/kissat/allocate.c index 68bb68a88..61f8c202f 100644 --- a/src/sat/kissat/allocate.c +++ b/src/sat/kissat/allocate.c @@ -12,6 +12,8 @@ #include #endif +ABC_NAMESPACE_IMPL_START + static void inc_bytes (kissat *solver, size_t bytes) { #ifdef METRICS if (!solver) @@ -62,16 +64,16 @@ void kissat_free (kissat *solver, void *ptr, size_t bytes) { dec_bytes (solver, bytes); free (ptr); } else - assert (!bytes); + KISSAT_assert (!bytes); } char *kissat_strdup (kissat *solver, const char *str) { - char *res = kissat_malloc (solver, strlen (str) + 1); + char *res = (char*)kissat_malloc (solver, strlen (str) + 1); return strcpy (res, str); } void kissat_freestr (struct kissat *solver, char *str) { - assert (str); + KISSAT_assert (str); kissat_free (solver, str, strlen (str) + 1); } @@ -149,8 +151,8 @@ void *kissat_realloc (kissat *solver, void *p, size_t old_bytes, void *kissat_nrealloc (kissat *solver, void *p, size_t o, size_t n, size_t size) { if (!size) { - assert (!p); - assert (!o); + KISSAT_assert (!p); + KISSAT_assert (!o); return 0; } const size_t max = MAX_SIZE_T / size; @@ -159,3 +161,5 @@ void *kissat_nrealloc (kissat *solver, void *p, size_t o, size_t n, n, size); return kissat_realloc (solver, p, o * size, n * size); } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/allocate.h b/src/sat/kissat/allocate.h index db24fd5f8..bdac75bd2 100644 --- a/src/sat/kissat/allocate.h +++ b/src/sat/kissat/allocate.h @@ -3,6 +3,9 @@ #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + struct kissat; void *kissat_malloc (struct kissat *, size_t bytes); @@ -18,14 +21,14 @@ void kissat_dealloc (struct kissat *, void *ptr, size_t n, size_t size); void *kissat_realloc (struct kissat *, void *, size_t old, size_t bytes); void *kissat_nrealloc (struct kissat *, void *, size_t o, size_t n, size_t); -#define NALLOC(P, N) \ +#define NALLOC(T, P, N) \ do { \ - (P) = kissat_nalloc (solver, (N), sizeof *(P)); \ + (P) = (T*) kissat_nalloc (solver, (N), sizeof *(P)); \ } while (0) -#define CALLOC(P, N) \ +#define CALLOC(T, P, N) \ do { \ - (P) = kissat_calloc (solver, (N), sizeof *(P)); \ + (P) = (T*) kissat_calloc (solver, (N), sizeof *(P)); \ } while (0) #define DEALLOC(P, N) \ @@ -33,4 +36,6 @@ void *kissat_nrealloc (struct kissat *, void *, size_t o, size_t n, size_t); kissat_dealloc (solver, (P), (N), sizeof *(P)); \ } while (0) +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/analyze.c b/src/sat/kissat/analyze.c index d21b0a74b..70a68ae0e 100644 --- a/src/sat/kissat/analyze.c +++ b/src/sat/kissat/analyze.c @@ -13,10 +13,12 @@ #include +ABC_NAMESPACE_IMPL_START + static bool one_literal_on_conflict_level (kissat *solver, clause *conflict, unsigned *conflict_level_ptr) { - assert (conflict); - assert (conflict->size > 1); + KISSAT_assert (conflict); + KISSAT_assert (conflict->size > 1); unsigned jump_level = INVALID_LEVEL; unsigned conflict_level = INVALID_LEVEL; @@ -31,7 +33,7 @@ static bool one_literal_on_conflict_level (kissat *solver, clause *conflict, for (const unsigned *p = lits; p != end_of_lits; p++) { const unsigned lit = *p; - assert (VALUE (lit) < 0); + 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) { @@ -48,8 +50,8 @@ static bool one_literal_on_conflict_level (kissat *solver, clause *conflict, if (literals_on_conflict_level > 1 && conflict_level == solver->level) break; } - assert (conflict_level != INVALID_LEVEL); - assert (literals_on_conflict_level); + 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); @@ -105,10 +107,10 @@ static bool one_literal_on_conflict_level (kissat *solver, clause *conflict, if (literals_on_conflict_level > 1) return false; - assert (literals_on_conflict_level == 1); - assert (forced_lit != INVALID_LIT); - assert (jump_level != INVALID_LEVEL); - assert (jump_level < conflict_level); + 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)); @@ -116,7 +118,7 @@ static bool one_literal_on_conflict_level (kissat *solver, clause *conflict, kissat_backtrack_after_conflict (solver, new_level); if (conflict_size == 2) { - assert (conflict == &solver->conflict); + KISSAT_assert (conflict == &solver->conflict); const unsigned other = lits[0] ^ lits[1] ^ forced_lit; kissat_assign_binary (solver, forced_lit, other); } else { @@ -142,9 +144,9 @@ static inline void analyze_reason_side_literal (kissat *solver, unsigned lit) { const unsigned idx = IDX (lit); const assigned *a = all_assigned + idx; - assert (a->level); - assert (a->analyzed); - assert (a->reason != UNIT_REASON); + KISSAT_assert (a->level); + KISSAT_assert (a->analyzed); + KISSAT_assert (a->reason != UNIT_REASON); if (a->reason == DECISION_REASON) return; if (a->binary) { @@ -152,13 +154,13 @@ static inline void analyze_reason_side_literal (kissat *solver, mark_reason_side_literal (solver, all_assigned, other); } else { const reference ref = a->reason; - assert (ref < SIZE_STACK (solver->arena)); + 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) { - assert (other != lit); + KISSAT_assert (other != lit); mark_reason_side_literal (solver, all_assigned, other); if (SIZE_STACK (solver->analyzed) > limit) break; @@ -183,9 +185,9 @@ static void analyze_reason_side_literals (kissat *solver) { return; } assigned *all_assigned = solver->assigned; -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG for (all_stack (unsigned, lit, solver->clause)) - assert (all_assigned[IDX (lit)].analyzed); + KISSAT_assert (all_assigned[IDX (lit)].analyzed); #endif LOG ("trying to bump reason side literals too"); const size_t saved = SIZE_STACK (solver->analyzed); @@ -203,7 +205,7 @@ static void analyze_reason_side_literals (kissat *solver) { const unsigned idx = POP_STACK (solver->analyzed); struct assigned *a = all_assigned + idx; LOG ("marking %s as not analyzed", LOGVAR (idx)); - assert (a->analyzed); + KISSAT_assert (a->analyzed); a->analyzed = false; } BUMP_DELAY (bumpreasons); @@ -228,7 +230,7 @@ static void sort_levels (kissat *solver) { static void sort_deduced_clause (kissat *solver) { sort_levels (solver); -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG const size_t size_frames = SIZE_STACK (solver->frames); #endif frame *frames = BEGIN_STACK (solver->frames); @@ -238,25 +240,25 @@ static void sort_deduced_clause (kissat *solver) { unsigned const *p = end_levels; while (p != begin_levels) { const unsigned level = *--p; - assert (level < size_frames); + KISSAT_assert (level < size_frames); frame *f = frames + level; const unsigned used = f->used; -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG f->saved = used; #endif - assert (used > 0); - assert (UINT_MAX - used >= pos); + 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 NDEBUG - assert (pos == size_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); - assert (begin_clause < end_clause); + KISSAT_assert (begin_clause < end_clause); unsigneds *shadow = &solver->shadow; while (SIZE_STACK (*shadow) < size_clause) @@ -272,37 +274,37 @@ static void sort_deduced_clause (kissat *solver) { const unsigned idx = IDX (lit); const struct assigned *a = assigned + idx; const unsigned level = a->level; - assert (level < size_frames); + KISSAT_assert (level < size_frames); frame *f = frames + level; const unsigned pos = f->used++; POKE_STACK (*shadow, pos, lit); } - assert (size_clause == SIZE_STACK (*shadow)); + KISSAT_assert (size_clause == SIZE_STACK (*shadow)); SWAP (unsigneds, *clause, *shadow); pos = 1; p = end_levels; while (p != begin_levels) { const unsigned level = *--p; - assert (level < size_frames); + KISSAT_assert (level < size_frames); frame *f = frames + level; const unsigned end = f->used; - assert (pos < end); + KISSAT_assert (pos < end); f->used = end - pos; - assert (f->used == f->saved); + KISSAT_assert (f->used == f->saved); pos = end; } CLEAR_STACK (*shadow); LOGTMP ("level sorted deduced"); -#ifndef NDEBUG +#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; - assert (prev_level >= lit_level); + KISSAT_assert (prev_level >= lit_level); prev_level = lit_level; } #endif @@ -311,13 +313,13 @@ static void sort_deduced_clause (kissat *solver) { static void reset_levels (kissat *solver) { LOG ("reset %zu marked levels", SIZE_STACK (solver->levels)); frame *frames = BEGIN_STACK (solver->frames); -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG const size_t size_frames = SIZE_STACK (solver->frames); #endif for (all_stack (unsigned, level, solver->levels)) { - assert (level < size_frames); + KISSAT_assert (level < size_frames); frame *f = frames + level; - assert (f->used > 0); + KISSAT_assert (f->used > 0); f->used = 0; } CLEAR_STACK (solver->levels); @@ -327,11 +329,11 @@ void kissat_reset_only_analyzed_literals (kissat *solver) { LOG ("reset %zu analyzed variables", SIZE_STACK (solver->analyzed)); assigned *assigned = solver->assigned; for (all_stack (unsigned, idx, solver->analyzed)) { - assert (idx < VARS); + KISSAT_assert (idx < VARS); struct assigned *a = assigned + idx; - assert (!a->poisoned); - assert (!a->removable); - assert (!a->shrinkable); + KISSAT_assert (!a->poisoned); + KISSAT_assert (!a->removable); + KISSAT_assert (!a->shrinkable); a->analyzed = false; } CLEAR_STACK (solver->analyzed); @@ -340,13 +342,13 @@ void kissat_reset_only_analyzed_literals (kissat *solver) { static void reset_removable (kissat *solver) { LOG ("reset %zu removable variables", SIZE_STACK (solver->removable)); assigned *assigned = solver->assigned; -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG unsigned not_removable = 0; #endif for (all_stack (unsigned, idx, solver->removable)) { - assert (idx < VARS); + KISSAT_assert (idx < VARS); struct assigned *a = assigned + idx; - assert (a->removable || !not_removable++); + KISSAT_assert (a->removable || !not_removable++); a->removable = false; } CLEAR_STACK (solver->removable); @@ -360,8 +362,8 @@ static void reset_analysis_but_not_analyzed_literals (kissat *solver) { } static void update_trail_average (kissat *solver) { - assert (!solver->probing); -#if defined(LOGGING) || !defined(QUIET) + 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; @@ -371,36 +373,36 @@ static void update_trail_average (kissat *solver) { #endif LOG ("trail filled %.0f%% (size %u, unflushed %u, active %u)", filled, size, solver->unflushed, active); -#ifndef QUIET +#ifndef KISSAT_QUIET UPDATE_AVERAGE (trail, filled); #endif } static void update_decision_rate_average (kissat *solver) { - assert (!solver->probing); + KISSAT_assert (!solver->probing); const uint64_t current = DECISIONS; const uint64_t previous = solver->averages[solver->stable].saved_decisions; - assert (previous <= current); + 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) { - assert (solver->level == 1); + KISSAT_assert (solver->level == 1); const unsigned failed = FRAME (1).decision; LOGCLS (conflict, "analyzing failed literal %s conflict", LOGLIT (failed)); unsigneds *units = &solver->clause; - assert (EMPTY_STACK (*units)); - assert (EMPTY_STACK (solver->analyzed)); + KISSAT_assert (EMPTY_STACK (*units)); + KISSAT_assert (EMPTY_STACK (solver->analyzed)); const unsigned not_failed = NOT (failed); assigned *all_assigned = solver->assigned; -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG const value *const values = solver->values; #endif unsigned const *t = END_ARRAY (solver->trail); @@ -408,18 +410,18 @@ static void analyze_failed_literal (kissat *solver, clause *conflict) { unsigned unit = INVALID_LIT; for (all_literals_in_clause (lit, conflict)) { - assert (lit != failed); + 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; } - assert (values[lit] < 0); + KISSAT_assert (values[lit] < 0); const unsigned idx = IDX (lit); assigned *a = all_assigned + idx; if (!a->level) continue; - assert (a->level == 1); + KISSAT_assert (a->level == 1); LOG ("analyzing conflict literal %s", LOGLIT (lit)); kissat_push_analyzed (solver, all_assigned, idx); unresolved++; @@ -429,9 +431,9 @@ static void analyze_failed_literal (kissat *solver, clause *conflict) { unsigned lit; assigned *a; do { - assert (t > BEGIN_ARRAY (solver->trail)); + KISSAT_assert (t > BEGIN_ARRAY (solver->trail)); lit = *--t; - assert (values[lit] > 0); + KISSAT_assert (values[lit] > 0); const unsigned idx = IDX (lit); a = all_assigned + idx; } while (!a->analyzed); @@ -443,9 +445,9 @@ static void analyze_failed_literal (kissat *solver, clause *conflict) { if (a->binary) { const unsigned other = a->reason; LOGBINARY (lit, other, "resolving %s reason", LOGLIT (lit)); - assert (other != failed); - assert (other != unit); - assert (values[other] < 0); + 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)); @@ -453,21 +455,21 @@ static void analyze_failed_literal (kissat *solver, clause *conflict) { } const unsigned idx = IDX (other); assigned *b = all_assigned + idx; - assert (b->level == 1); + KISSAT_assert (b->level == 1); if (!b->analyzed) { LOG ("analyzing reason literal %s", LOGLIT (other)); kissat_push_analyzed (solver, all_assigned, idx); unresolved++; } } else { - assert (a->reason != UNIT_REASON); - assert (a->reason != DECISION_REASON); + 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)) { - assert (other != NOT (lit)); - assert (other != failed); + KISSAT_assert (other != NOT (lit)); + KISSAT_assert (other != failed); if (other == lit) continue; if (other == unit) @@ -477,12 +479,12 @@ static void analyze_failed_literal (kissat *solver, clause *conflict) { LOGLIT (not_failed), LOGLIT (failed)); goto DONE; } - assert (values[other] < 0); + KISSAT_assert (values[other] < 0); const unsigned idx = IDX (other); assigned *b = all_assigned + idx; if (!b->level) continue; - assert (b->level == 1); + KISSAT_assert (b->level == 1); if (b->analyzed) continue; LOG ("analyzing reason literal %s", LOGLIT (other)); @@ -490,7 +492,7 @@ static void analyze_failed_literal (kissat *solver, clause *conflict) { unresolved++; } } - assert (unresolved > 0); + KISSAT_assert (unresolved > 0); unresolved--; LOG ("after resolving %s there are %u unresolved literals", LOGLIT (lit), unresolved); @@ -526,7 +528,7 @@ static void update_tier_limits (kissat *solver) { int kissat_analyze (kissat *solver, clause *conflict) { if (solver->inconsistent) { - assert (!solver->level); + KISSAT_assert (!solver->level); return 20; } @@ -534,7 +536,7 @@ int kissat_analyze (kissat *solver, clause *conflict) { if (!solver->probing) { update_trail_average (solver); update_decision_rate_average (solver); -#ifndef QUIET +#ifndef KISSAT_QUIET UPDATE_AVERAGE (level, solver->level); #endif } @@ -577,3 +579,5 @@ int kissat_analyze (kissat *solver, clause *conflict) { STOP (analyze); return res > 0 ? 0 : 20; } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/analyze.h b/src/sat/kissat/analyze.h index be4393c76..ec0b2af4e 100644 --- a/src/sat/kissat/analyze.h +++ b/src/sat/kissat/analyze.h @@ -3,10 +3,15 @@ #include +#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 diff --git a/src/sat/kissat/ands.c b/src/sat/kissat/ands.c index 51bff792a..bd53b9489 100644 --- a/src/sat/kissat/ands.c +++ b/src/sat/kissat/ands.c @@ -3,6 +3,8 @@ #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)) @@ -27,9 +29,9 @@ bool kissat_find_and_gate (kissat *solver, unsigned lit, if (watch.type.binary) continue; const reference ref = watch.large.ref; - assert (ref < SIZE_STACK (solver->arena)); + KISSAT_assert (ref < SIZE_STACK (solver->arena)); clause *c = (clause *) (arena + ref); - assert (!c->garbage); + KISSAT_assert (!c->garbage); base = c; for (all_literals_in_clause (other, c)) { if (other == not_lit) @@ -63,7 +65,7 @@ bool kissat_find_and_gate (kissat *solver, unsigned lit, if (values[other]) continue; const unsigned not_other = NOT (other); - assert (marks[not_other]); + KISSAT_assert (marks[not_other]); marks[not_other] = 0; } watch tmp = kissat_binary_watch (0); @@ -72,7 +74,7 @@ bool kissat_find_and_gate (kissat *solver, unsigned lit, if (!watch.type.binary) continue; const unsigned other = watch.binary.lit; - assert (!solver->values[other]); + KISSAT_assert (!solver->values[other]); if (marks[other]) { marks[other] = 0; continue; @@ -86,3 +88,5 @@ bool kissat_find_and_gate (kissat *solver, unsigned lit, INC (ands_extracted); return true; } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/ands.h b/src/sat/kissat/ands.h index 606c41d6e..4780d1138 100644 --- a/src/sat/kissat/ands.h +++ b/src/sat/kissat/ands.h @@ -3,9 +3,14 @@ #include +#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 diff --git a/src/sat/kissat/application.h b/src/sat/kissat/application.h index f4a5b12f7..25c23f178 100644 --- a/src/sat/kissat/application.h +++ b/src/sat/kissat/application.h @@ -1,8 +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 diff --git a/src/sat/kissat/arena.c b/src/sat/kissat/arena.c index 7296d2605..2ee25018f 100644 --- a/src/sat/kissat/arena.c +++ b/src/sat/kissat/arena.c @@ -3,9 +3,11 @@ #include "logging.h" #include "print.h" +ABC_NAMESPACE_IMPL_START + static void report_resized (kissat *solver, const char *mode, arena before) { -#ifndef QUIET +#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); @@ -23,25 +25,25 @@ static void report_resized (kissat *solver, const char *mode, } reference kissat_allocate_clause (kissat *solver, size_t size) { - assert (size <= UINT_MAX); + KISSAT_assert (size <= UINT_MAX); const size_t res = SIZE_STACK (solver->arena); - assert (res <= MAX_REF); + KISSAT_assert (res <= MAX_REF); const size_t bytes = kissat_bytes_of_clause (size); - assert (kissat_aligned_word (bytes)); + KISSAT_assert (kissat_aligned_word (bytes)); const size_t needed = bytes / sizeof (ward); - assert (needed <= UINT_MAX); + KISSAT_assert (needed <= UINT_MAX); size_t capacity = CAPACITY_STACK (solver->arena); - assert (kissat_is_power_of_two (MAX_ARENA)); - assert (capacity <= MAX_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 { - assert (kissat_is_zero_or_power_of_two (capacity)); + 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 COMPACT +#ifdef KISSAT_COMPACT " (consider a configuration without '--compact')" #endif , @@ -55,7 +57,7 @@ reference kissat_allocate_clause (kissat *solver, size_t size) { INC (arena_resized); INC (arena_enlarged); report_resized (solver, "enlarged", before); - assert (capacity <= MAX_ARENA); + KISSAT_assert (capacity <= MAX_ARENA); } solver->arena.end += needed; LOG ("allocated clause[%zu] of size %zu bytes %s", res, size, @@ -67,7 +69,7 @@ void kissat_shrink_arena (kissat *solver) { const arena before = solver->arena; const size_t capacity = CAPACITY_STACK (before); const size_t size = SIZE_STACK (before); -#ifndef QUIET +#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), @@ -89,7 +91,7 @@ void kissat_shrink_arena (kissat *solver) { report_resized (solver, "shrunken", before); } -#if !defined(NDEBUG) || defined(LOGGING) +#if !defined(KISSAT_NDEBUG) || defined(LOGGING) bool kissat_clause_in_arena (const kissat *solver, const clause *c) { if (!kissat_aligned_pointer (c)) @@ -106,3 +108,5 @@ bool kissat_clause_in_arena (const kissat *solver, const clause *c) { } #endif + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/arena.h b/src/sat/kissat/arena.h index da83c7e39..8e1750ce7 100644 --- a/src/sat/kissat/arena.h +++ b/src/sat/kissat/arena.h @@ -5,7 +5,10 @@ #include "stack.h" #include "utilities.h" -#ifdef COMPACT +#include "global.h" +ABC_NAMESPACE_HEADER_START + +#ifdef KISSAT_COMPACT typedef word ward; #else typedef w2rd ward; @@ -29,18 +32,20 @@ struct kissat; reference kissat_allocate_clause (struct kissat *, size_t size); void kissat_shrink_arena (struct kissat *); -#if !defined(NDEBUG) || defined(LOGGING) +#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 COMPACT +#ifdef KISSAT_COMPACT return kissat_align_word (w); #else return kissat_align_w2rd (w); #endif } +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/array.h b/src/sat/kissat/array.h index 3ae23f90b..a3a71d202 100644 --- a/src/sat/kissat/array.h +++ b/src/sat/kissat/array.h @@ -4,6 +4,9 @@ #include "allocate.h" #include "stack.h" +#include "global.h" +ABC_NAMESPACE_HEADER_START + #define ARRAY(TYPE) \ struct { \ TYPE *begin; \ @@ -25,11 +28,11 @@ *(A).end++ = (E); \ } while (0) -#define REALLOCATE_ARRAY(A, O, N) \ +#define REALLOCATE_ARRAY(T, A, O, N) \ do { \ const size_t SIZE = SIZE_ARRAY (A); \ (A).begin = \ - kissat_nrealloc (solver, (A).begin, (O), (N), sizeof *(A).begin); \ + (T*) kissat_nrealloc (solver, (A).begin, (O), (N), sizeof *(A).begin); \ (A).end = (A).begin + SIZE; \ } while (0) @@ -55,4 +58,6 @@ typedef ARRAY (unsigned) unsigned_array; // clang-format on +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/assign.c b/src/sat/kissat/assign.c index 6a34f3529..c2fb61b4b 100644 --- a/src/sat/kissat/assign.c +++ b/src/sat/kissat/assign.c @@ -5,6 +5,8 @@ #include +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); @@ -30,7 +32,7 @@ void kissat_assign_decision (kissat *solver, unsigned lit) { } void kissat_assign_binary (kissat *solver, unsigned lit, unsigned other) { - assert (VALUE (other) < 0); + KISSAT_assert (VALUE (other) < 0); assigned *assigned = solver->assigned; const unsigned other_idx = IDX (other); struct assigned *a = assigned + other_idx; @@ -46,14 +48,16 @@ void kissat_assign_binary (kissat *solver, unsigned lit, unsigned other) { void kissat_assign_reference (kissat *solver, unsigned lit, reference ref, clause *reason) { - assert (reason == kissat_dereference_clause (solver, ref)); + 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); - assert (level <= solver->level); - assert (ref != DECISION_REASON); - assert (ref != UNIT_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 diff --git a/src/sat/kissat/assign.h b/src/sat/kissat/assign.h index 64ac2027d..d063d17f6 100644 --- a/src/sat/kissat/assign.h +++ b/src/sat/kissat/assign.h @@ -3,6 +3,9 @@ #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + #define DECISION_REASON UINT_MAX #define UNIT_REASON (DECISION_REASON - 1) @@ -26,7 +29,7 @@ struct assigned { }; #define ASSIGNED(LIT) \ - (assert (VALID_INTERNAL_LITERAL (LIT)), solver->assigned + IDX (LIT)) + (KISSAT_assert (VALID_INTERNAL_LITERAL (LIT)), solver->assigned + IDX (LIT)) #define LEVEL(LIT) (ASSIGNED (LIT)->level) #define TRAIL(LIT) (ASSIGNED (LIT)->trail) @@ -34,8 +37,12 @@ struct assigned { #ifndef FAST_ASSIGN +ABC_NAMESPACE_HEADER_END + #include "reference.h" +ABC_NAMESPACE_HEADER_START + struct kissat; struct clause; @@ -52,4 +59,6 @@ void kissat_assign_reference (struct kissat *, unsigned lit, reference, #endif +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/attribute.h b/src/sat/kissat/attribute.h index 9ec5f40ab..4e43ac83f 100644 --- a/src/sat/kissat/attribute.h +++ b/src/sat/kissat/attribute.h @@ -1,10 +1,19 @@ #ifndef _attribute_h_INCLUDED #define _attribute_h_INCLUDED -#define ATTRIBUTE_FORMAT(FORMAT_POSITION, VARIADIC_ARGUMENT_POSITION) \ - __attribute__ (( \ - format (printf, FORMAT_POSITION, VARIADIC_ARGUMENT_POSITION))) +#include "global.h" +ABC_NAMESPACE_HEADER_START -#define ATTRIBUTE_ALWAYS_INLINE __attribute__ ((always_inline)) +/* #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 diff --git a/src/sat/kissat/averages.c b/src/sat/kissat/averages.c index 03c96a73f..c59a6c2ed 100644 --- a/src/sat/kissat/averages.c +++ b/src/sat/kissat/averages.c @@ -1,11 +1,13 @@ #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 QUIET +#ifndef KISSAT_QUIET INIT_EMA (level, GET_OPTION (emaslow)); INIT_EMA (size, GET_OPTION (emaslow)); INIT_EMA (trail, GET_OPTION (emaslow)); @@ -15,3 +17,5 @@ void kissat_init_averages (kissat *solver, averages *averages) { INIT_EMA (decision_rate, GET_OPTION (emaslow)); averages->initialized = true; } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/averages.h b/src/sat/kissat/averages.h index d8cd03045..b793e0b69 100644 --- a/src/sat/kissat/averages.h +++ b/src/sat/kissat/averages.h @@ -5,12 +5,15 @@ #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + typedef struct averages averages; struct averages { bool initialized; smooth fast_glue, slow_glue; -#ifndef QUIET +#ifndef KISSAT_QUIET smooth level, size, trail; #endif smooth decision_rate; @@ -30,4 +33,6 @@ void kissat_init_averages (struct kissat *, averages *); #define UPDATE_AVERAGE(NAME, VALUE) \ kissat_update_smooth (solver, &EMA (NAME), VALUE) +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/backbone.c b/src/sat/kissat/backbone.c index 6a774efce..6db42d77a 100644 --- a/src/sat/kissat/backbone.c +++ b/src/sat/kissat/backbone.c @@ -13,6 +13,8 @@ #include "trail.h" #include "utilities.h" +ABC_NAMESPACE_IMPL_START + static void schedule_backbone_candidates (kissat *solver, unsigneds *candidates) { flags *flags = solver->flags; @@ -34,7 +36,7 @@ static void schedule_backbone_candidates (kissat *solver, } else not_rescheduled++; } -#ifndef QUIET +#ifndef KISSAT_QUIET const size_t rescheduled = SIZE_STACK (*candidates); const unsigned active_literals = 2u * solver->active; kissat_very_verbose ( @@ -58,7 +60,7 @@ static void schedule_backbone_candidates (kissat *solver, } } } -#ifndef QUIET +#ifndef KISSAT_QUIET const size_t total = SIZE_STACK (*candidates); kissat_very_verbose (solver, "scheduled %zu backbone candidate literals %.0f%%" @@ -83,21 +85,21 @@ static void keep_backbone_candidates (kissat *solver, else prioritized += f->backbone0; } - assert (prioritized <= remain); + KISSAT_assert (prioritized <= remain); if (!remain) { kissat_very_verbose (solver, "no backbone candidates remain"); -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG for (all_variables (idx)) { const struct flags *f = flags + idx; if (!f->active) continue; - assert (!f->backbone0); - assert (!f->backbone1); + KISSAT_assert (!f->backbone0); + KISSAT_assert (!f->backbone1); } #endif return; } -#ifndef QUIET +#ifndef KISSAT_QUIET const size_t active_literals = 2u * solver->active; #endif if (prioritized == remain) @@ -112,10 +114,10 @@ static void keep_backbone_candidates (kissat *solver, if (!f->active) continue; if (NEGATED (lit)) { - assert (!f->backbone1); + KISSAT_assert (!f->backbone1); f->backbone1 = true; } else { - assert (!f->backbone0); + KISSAT_assert (!f->backbone0); f->backbone0 = true; } } @@ -137,8 +139,8 @@ static inline void backbone_assign (kissat *solver, unsigned_array *trail, value *values, assigned *assigned, unsigned lit, unsigned reason) { const unsigned not_lit = NOT (lit); - assert (!values[lit]); - assert (!values[not_lit]); + KISSAT_assert (!values[lit]); + KISSAT_assert (!values[not_lit]); values[lit] = 1; values[not_lit] = -1; PUSH_ARRAY (*trail, lit); @@ -154,13 +156,13 @@ backbone_propagate_literal (kissat *solver, const bool stop_early, unsigned_array *trail, value *values, assigned *assigned, unsigned lit) { LOG ("backbone propagating %s", LOGLIT (lit)); - assert (VALID_INTERNAL_LITERAL (lit)); - assert (values[lit] > 0); + KISSAT_assert (VALID_INTERNAL_LITERAL (lit)); + KISSAT_assert (values[lit] > 0); const unsigned not_lit = NOT (lit); - assert (values[not_lit] < 0); + KISSAT_assert (values[not_lit] < 0); - assert (not_lit < LITS); + KISSAT_assert (not_lit < LITS); const watches *const watches = all_watches + not_lit; const watch *const begin_watches = BEGIN_CONST_WATCHES (*watches); @@ -171,22 +173,22 @@ backbone_propagate_literal (kissat *solver, const bool stop_early, const watch watch = *p++; if (watch.type.binary) { const unsigned other = watch.binary.lit; - assert (VALID_INTERNAL_LITERAL (other)); + 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); - assert (!value); + 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 NDEBUG +#ifndef KISSAT_NDEBUG for (const union watch *q = p + 1; q != end_watches; q++) { const union watch watch = *q++; - assert (!watch.type.binary); + KISSAT_assert (!watch.type.binary); } #endif break; @@ -219,7 +221,7 @@ static inline clause *backbone_propagate (kissat *solver, conflict = backbone_propagate_literal ( solver, stop_early, watches, trail, values, assigned, *propagate++); - assert (solver->propagate <= propagate); + KISSAT_assert (solver->propagate <= propagate); const unsigned propagated = propagate - solver->propagate; solver->propagate = propagate; @@ -240,17 +242,17 @@ static inline void backbone_backtrack (kissat *solver, unsigned_array *trail, value *values, unsigned *saved, unsigned decision_level) { - assert (decision_level <= solver->level); + KISSAT_assert (decision_level <= solver->level); unsigned *end_trail = END_ARRAY (*trail); - assert (saved != end_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)); - assert (values[lit] > 0); - assert (values[not_lit] < 0); + KISSAT_assert (values[lit] > 0); + KISSAT_assert (values[not_lit] < 0); values[lit] = values[not_lit] = 0; } SET_END_OF_ARRAY (solver->trail, saved); @@ -259,9 +261,9 @@ static inline void backbone_backtrack (kissat *solver, } static unsigned backbone_analyze (kissat *solver, clause *conflict) { - assert (conflict); + KISSAT_assert (conflict); LOGCLS (conflict, "backbone analyzing"); - assert (conflict->size == 2); + KISSAT_assert (conflict->size == 2); assigned *const assigned = solver->assigned; @@ -271,7 +273,7 @@ static unsigned backbone_analyze (kissat *solver, clause *conflict) { const unsigned *t = END_ARRAY (solver->trail); for (;;) { - assert (t > BEGIN_ARRAY (solver->trail)); + KISSAT_assert (t > BEGIN_ARRAY (solver->trail)); unsigned lit = *--t; @@ -282,8 +284,8 @@ static unsigned backbone_analyze (kissat *solver, clause *conflict) { LOG ("backbone analyzing %s", LOGLIT (lit)); const unsigned reason = a->reason; - assert (reason != UNIT_REASON); - assert (reason != DECISION_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) { @@ -298,7 +300,7 @@ static unsigned backbone_analyze (kissat *solver, clause *conflict) { } } -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG static void check_large_clauses_watched_after_binary_clauses (kissat *solver) { @@ -306,7 +308,7 @@ check_large_clauses_watched_after_binary_clauses (kissat *solver) { bool large = false; for (all_binary_blocking_watches (watch, WATCHES (lit))) if (watch.type.binary) - assert (!large); + KISSAT_assert (!large); else large = true; } @@ -315,7 +317,7 @@ check_large_clauses_watched_after_binary_clauses (kissat *solver) { #endif static unsigned compute_backbone (kissat *solver) { -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG if (solver->large_clauses_watched_after_binary_clauses) check_large_clauses_watched_after_binary_clauses (solver); #endif @@ -325,26 +327,26 @@ static unsigned compute_backbone (kissat *solver) { INIT_STACK (candidates); INIT_STACK (units); schedule_backbone_candidates (solver, &candidates); -#ifndef QUIET +#ifndef KISSAT_QUIET const size_t scheduled = SIZE_STACK (candidates); #endif -#if defined(METRICS) && (!defined(QUIET) || !defined(NDEBUG)) - const uint64_t implied_before = solver->statistics.backbone_implied; +#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; - assert (kissat_propagated (solver)); - assert (kissat_trail_flushed (solver)); + 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); - assert (solver->statistics.backbone_computations); - round_limit *= solver->statistics.backbone_computations; + 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; @@ -356,7 +358,7 @@ static unsigned compute_backbone (kissat *solver) { kissat_very_verbose (solver, "backbone round limit %zu hit", round); break; } - const uint64_t ticks = solver->statistics.backbone_ticks; + const uint64_t ticks = solver->statistics_.backbone_ticks; if (ticks > ticks_limit) { kissat_very_verbose (solver, "backbone ticks limit %" PRIu64 " hit " @@ -365,17 +367,17 @@ static unsigned compute_backbone (kissat *solver) { break; } size_t previous = failed; - assert (!solver->inconsistent); + 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); - assert (!solver->level); -#if !defined(QUIET) && defined(METRICS) + KISSAT_assert (!solver->level); +#if !defined(KISSAT_QUIET) && defined(METRICS) size_t decisions = 0; - uint64_t propagated = solver->statistics.backbone_propagations; + uint64_t propagated = solver->statistics_.backbone_propagations; #endif unsigned active_before = solver->active; { @@ -383,7 +385,7 @@ static unsigned compute_backbone (kissat *solver) { const unsigned *p = begin_candidates; const unsigned *const end_candidates = END_STACK (candidates); while (p != end_candidates) { - assert (!solver->inconsistent); + KISSAT_assert (!solver->inconsistent); const unsigned probe = *q++ = *p++; const value value = values[probe]; if (value > 0) { @@ -409,14 +411,14 @@ static unsigned compute_backbone (kissat *solver) { } continue; } - if (solver->statistics.backbone_ticks > ticks_limit) + if (solver->statistics_.backbone_ticks > ticks_limit) break; if (TERMINATED (backbone_terminated_2)) break; const unsigned level = solver->level; unsigned *const saved = END_ARRAY (*trail); - assert (level != UINT_MAX); -#if !defined(QUIET) && defined(METRICS) + KISSAT_assert (level != UINT_MAX); +#if !defined(KISSAT_QUIET) && defined(METRICS) decisions++; #endif solver->level = level + 1; @@ -444,7 +446,7 @@ static unsigned compute_backbone (kissat *solver) { backbone_assign (solver, trail, values, assigned, not_uip, UNIT_REASON); LOG ("backbone forced assign %s", LOGLIT (not_uip)); - assert (failed == SIZE_STACK (units)); + KISSAT_assert (failed == SIZE_STACK (units)); conflict = backbone_propagate (solver, trail, values, assigned); if (conflict) { @@ -455,7 +457,7 @@ static unsigned compute_backbone (kissat *solver) { LOG ("propagating backbone forced %s successful", LOGLIT (not_uip)); } -#ifndef QUIET +#ifndef KISSAT_QUIET size_t remain = end_candidates - p; if (remain) kissat_extremely_verbose (solver, @@ -497,7 +499,7 @@ static unsigned compute_backbone (kissat *solver) { LOG ("keeping falsified probe %s", LOGLIT (probe)); continue; } - assert (!value); + KISSAT_assert (!value); LOG ("keeping unassigned probe %s", LOGLIT (probe)); } LOG ("flushed %zu probe candidates", @@ -515,13 +517,13 @@ static unsigned compute_backbone (kissat *solver) { if (kissat_probing_propagate (solver, 0, true)) break; } - assert (solver->active <= active_before); + KISSAT_assert (solver->active <= active_before); unsigned implied = active_before - solver->active; - assert (failed <= failed); + KISSAT_assert (failed <= failed); ADD (backbone_implied, implied); -#ifndef QUIET +#ifndef KISSAT_QUIET #ifdef METRICS - propagated = solver->statistics.backbone_propagations - propagated; + propagated = solver->statistics_.backbone_propagations - propagated; kissat_very_verbose (solver, "backbone round %zu with %zu decisions " "(%.2f propagations per decision)", @@ -545,7 +547,7 @@ static unsigned compute_backbone (kissat *solver) { LOG ("assuming forced unit %s", LOGLIT (inconsistent)); kissat_learned_unit (solver, inconsistent); (void) kissat_probing_propagate (solver, 0, true); - assert (solver->inconsistent); + KISSAT_assert (solver->inconsistent); } RELEASE_STACK (units); if (solver->inconsistent) @@ -553,12 +555,12 @@ static unsigned compute_backbone (kissat *solver) { "inconsistent binary clauses"); else { keep_backbone_candidates (solver, &candidates); -#if defined(METRICS) && (!defined(QUIET) || !defined(NDEBUG)) - assert (implied_before <= solver->statistics.backbone_implied); +#if defined(METRICS) && (!defined(KISSAT_QUIET) || !defined(KISSAT_NDEBUG)) + KISSAT_assert (implied_before <= solver->statistics_.backbone_implied); #endif -#if defined(METRICS) && !defined(QUIET) +#if defined(METRICS) && !defined(KISSAT_QUIET) const uint64_t total_implied = - solver->statistics.backbone_implied - implied_before; + solver->statistics_.backbone_implied - implied_before; kissat_phase (solver, "backbone", GET (backbone_computations), "found %zu backbone literals %" PRIu64 " implied in %zu rounds", @@ -576,23 +578,25 @@ void kissat_binary_clauses_backbone (kissat *solver) { return; if (TERMINATED (backbone_terminated_3)) return; - assert (solver->watching); - assert (solver->probing); - assert (!solver->level); + KISSAT_assert (solver->watching); + KISSAT_assert (solver->probing); + KISSAT_assert (!solver->level); START (backbone); INC (backbone_computations); -#if !defined(NDEBUG) || defined(METRICS) - assert (!solver->backbone_computing); +#if !defined(KISSAT_NDEBUG) || defined(METRICS) + KISSAT_assert (!solver->backbone_computing); solver->backbone_computing = true; #endif -#ifndef QUIET +#ifndef KISSAT_QUIET const unsigned failed = #endif compute_backbone (solver); REPORT (!failed, 'b'); -#if !defined(NDEBUG) || defined(METRICS) - assert (solver->backbone_computing); +#if !defined(KISSAT_NDEBUG) || defined(METRICS) + KISSAT_assert (solver->backbone_computing); solver->backbone_computing = false; #endif STOP (backbone); } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/backbone.h b/src/sat/kissat/backbone.h index 0ddf87c99..4cb189c9d 100644 --- a/src/sat/kissat/backbone.h +++ b/src/sat/kissat/backbone.h @@ -3,7 +3,12 @@ #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + struct kissat; void kissat_binary_clauses_backbone (struct kissat *); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/backtrack.c b/src/sat/kissat/backtrack.c index 09ba8df70..ef33f1010 100644 --- a/src/sat/kissat/backtrack.c +++ b/src/sat/kissat/backtrack.c @@ -8,19 +8,21 @@ #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)); - assert (values[lit] > 0); + KISSAT_assert (values[lit] > 0); const unsigned not_lit = NOT (lit); values[lit] = values[not_lit] = 0; - assert (solver->unassigned < VARS); + KISSAT_assert (solver->unassigned < VARS); solver->unassigned++; } static inline void add_unassigned_variable_back_to_queue (kissat *solver, links *links, unsigned lit) { - assert (!solver->stable); + KISSAT_assert (!solver->stable); const unsigned idx = IDX (lit); if (links[idx].stamp > solver->queue.search.stamp) kissat_update_queue (solver, links, idx); @@ -29,7 +31,7 @@ static inline void add_unassigned_variable_back_to_queue (kissat *solver, static inline void add_unassigned_variable_back_to_heap (kissat *solver, heap *scores, unsigned lit) { - assert (solver->stable); + KISSAT_assert (solver->stable); const unsigned idx = IDX (lit); if (!kissat_heap_contains (scores, idx)) kissat_push_heap (solver, scores, idx); @@ -71,7 +73,7 @@ static void kissat_update_target_and_best_phases (kissat *solver) { void kissat_backtrack_without_updating_phases (kissat *solver, unsigned new_level) { - assert (solver->level >= new_level); + KISSAT_assert (solver->level >= new_level); if (solver->level == new_level) return; @@ -94,12 +96,12 @@ void kissat_backtrack_without_updating_phases (kissat *solver, for (const unsigned *p = q; p != old_end; p++) { const unsigned lit = *p; const unsigned idx = IDX (lit); - assert (idx < VARS); + KISSAT_assert (idx < VARS); struct assigned *a = assigned + idx; const unsigned level = a->level; if (level <= new_level) { const unsigned new_trail = q - trail; - assert (new_trail <= a->trail); + KISSAT_assert (new_trail <= a->trail); a->trail = new_trail; *q++ = lit; LOG ("reassign %s", LOGLIT (lit)); @@ -115,12 +117,12 @@ void kissat_backtrack_without_updating_phases (kissat *solver, for (const unsigned *p = q; p != old_end; p++) { const unsigned lit = *p; const unsigned idx = IDX (lit); - assert (idx < VARS); + KISSAT_assert (idx < VARS); struct assigned *a = assigned + idx; const unsigned level = a->level; if (level <= new_level) { const unsigned new_trail = q - trail; - assert (new_trail <= a->trail); + KISSAT_assert (new_trail <= a->trail); a->trail = new_trail; *q++ = lit; LOG ("reassign %s", LOGLIT (lit)); @@ -139,12 +141,12 @@ void kissat_backtrack_without_updating_phases (kissat *solver, LOG ("reassigned %u literals", reassigned); (void) unassigned, (void) reassigned; - assert (new_end <= END_ARRAY (solver->trail)); + 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; - assert (!solver->extended); + KISSAT_assert (!solver->extended); } void kissat_backtrack_in_consistent_state (kissat *solver, @@ -162,16 +164,18 @@ void kissat_backtrack_after_conflict (kissat *solver, unsigned new_level) { void kissat_backtrack_propagate_and_flush_trail (kissat *solver) { if (solver->level) { - assert (solver->watching); + KISSAT_assert (solver->watching); kissat_backtrack_in_consistent_state (solver, 0); -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG clause *conflict = #endif solver->probing ? kissat_probing_propagate (solver, 0, true) : kissat_search_propagate (solver); - assert (!conflict); + KISSAT_assert (!conflict); } - assert (kissat_propagated (solver)); - assert (kissat_trail_flushed (solver)); + KISSAT_assert (kissat_propagated (solver)); + KISSAT_assert (kissat_trail_flushed (solver)); } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/backtrack.h b/src/sat/kissat/backtrack.h index 7a9b93bf7..0df13f8b8 100644 --- a/src/sat/kissat/backtrack.h +++ b/src/sat/kissat/backtrack.h @@ -1,6 +1,9 @@ #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); @@ -8,4 +11,6 @@ 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 diff --git a/src/sat/kissat/build.c b/src/sat/kissat/build.c index 0426854a2..d1f21e937 100644 --- a/src/sat/kissat/build.c +++ b/src/sat/kissat/build.c @@ -5,6 +5,8 @@ #include +ABC_NAMESPACE_IMPL_START + const char *kissat_signature (void) { return "kissat-" VERSION; } const char *kissat_id (void) { return ID; } @@ -79,3 +81,5 @@ void kissat_banner (const char *prefix, const char *name) { kissat_build (prefix); } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/build.h b/src/sat/kissat/build.h new file mode 100644 index 000000000..cd418ecfd --- /dev/null +++ b/src/sat/kissat/build.h @@ -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 diff --git a/src/sat/kissat/bump.c b/src/sat/kissat/bump.c index 5771db4ac..5dc365f51 100644 --- a/src/sat/kissat/bump.c +++ b/src/sat/kissat/bump.c @@ -9,6 +9,8 @@ #include "rank.h" #include "sort.h" +ABC_NAMESPACE_IMPL_START + #define RANK(A) ((A).rank) #define SMALLER(A, B) (RANK (A) < RANK (B)) @@ -32,7 +34,7 @@ void kissat_rescale_scores (kissat *solver) { kissat_phase (solver, "rescale", GET (rescaled), "maximum score %g increment %g", max_score, solver->scinc); const double rescale = MAX (max_score, solver->scinc); - assert (rescale > 0); + KISSAT_assert (rescale > 0); const double factor = 1.0 / rescale; kissat_rescale_heap (solver, scores, factor); solver->scinc *= factor; @@ -43,7 +45,7 @@ void kissat_rescale_scores (kissat *solver) { void kissat_bump_score_increment (kissat *solver) { const double old_scinc = solver->scinc; const double decay = GET_OPTION (decay) * 1e-3; - assert (0 <= decay), assert (decay <= 0.5); + 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); @@ -79,7 +81,7 @@ static void bump_analyzed_variable_scores (kissat *solver) { } static void move_analyzed_variables_to_front_of_queue (kissat *solver) { - assert (EMPTY_STACK (solver->ranks)); + KISSAT_assert (EMPTY_STACK (solver->ranks)); const links *const links = solver->links; for (all_stack (unsigned, idx, solver->analyzed)) { // clang-format off @@ -112,9 +114,11 @@ void kissat_bump_analyzed (kissat *solver) { } void kissat_update_scores (kissat *solver) { - assert (solver->stable); + 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 diff --git a/src/sat/kissat/bump.h b/src/sat/kissat/bump.h index 55d541562..036324502 100644 --- a/src/sat/kissat/bump.h +++ b/src/sat/kissat/bump.h @@ -3,6 +3,9 @@ #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + struct kissat; void kissat_bump_analyzed (struct kissat *); @@ -13,4 +16,6 @@ void kissat_bump_score_increment (struct kissat *); #define MAX_SCORE 1e150 +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/check.c b/src/sat/kissat/check.c index 0245a0866..fa771f2c7 100644 --- a/src/sat/kissat/check.c +++ b/src/sat/kissat/check.c @@ -1,4 +1,6 @@ -#ifndef NDEBUG +#include "global.h" + +#ifndef KISSAT_NDEBUG #include "check.h" #include "error.h" @@ -187,7 +189,7 @@ void kissat_release_checker (kissat *solver) { kissat_free (solver, checker, sizeof (struct checker)); } -#ifndef QUIET +#ifndef KISSAT_QUIET #include @@ -234,18 +236,18 @@ void kissat_print_checker_statistics (kissat *solver, bool verbose) { static unsigned reduce_hash (unsigned hash, unsigned mod) { if (mod < 2) return 0; - assert (mod); + KISSAT_assert (mod); unsigned res = hash; for (unsigned shift = 16, mask = 0xffff; res >= mod; mask >>= (shift >>= 1)) res = (res >> shift) & mask; - assert (res < mod); + KISSAT_assert (res < mod); return res; } static void resize_hash (kissat *solver, checker *checker) { const unsigned old_hashed = checker->hashed; - assert (old_hashed < MAX_SIZE); + KISSAT_assert (old_hashed < MAX_SIZE); const unsigned new_hashed = old_hashed ? 2 * old_hashed : 1; bucket **table = kissat_calloc (solver, new_hashed, sizeof (bucket *)); bucket **old_table = checker->table; @@ -264,7 +266,7 @@ static void resize_hash (kissat *solver, checker *checker) { static bucket *new_line (kissat *solver, checker *checker, unsigned size, unsigned hash) { - bucket *res = kissat_malloc (solver, bytes_line (size)); + bucket *res = (bucket*)kissat_malloc (solver, bytes_line (size)); res->next = 0; res->size = size; res->hash = hash; @@ -291,18 +293,18 @@ static void checker_assign (kissat *solver, checker *checker, unsigned lit, #else (void) bucket; #endif - assert (VALID_CHECKER_LIT (lit)); + KISSAT_assert (VALID_CHECKER_LIT (lit)); const unsigned not_lit = lit ^ 1; signed char *values = checker->values; - assert (!values[lit]); - assert (!values[not_lit]); + KISSAT_assert (!values[lit]); + KISSAT_assert (!values[not_lit]); values[lit] = 1; values[not_lit] = -1; PUSH_STACK (checker->trail, lit); } static buckets *checker_watches (checker *checker, unsigned lit) { - assert (VALID_CHECKER_LIT (lit)); + KISSAT_assert (VALID_CHECKER_LIT (lit)); return checker->watches + lit; } @@ -325,7 +327,7 @@ static void unwatch_checker_literal (kissat *solver, checker *checker, static void unwatch_line (kissat *solver, checker *checker, bucket *bucket) { - assert (bucket->size > 1); + KISSAT_assert (bucket->size > 1); const unsigned *const lits = bucket->lits; unwatch_checker_literal (solver, checker, bucket, lits[0]); unwatch_checker_literal (solver, checker, bucket, lits[1]); @@ -474,7 +476,7 @@ static void use_line (kissat *solver, checker *checker) { static void insert_imported (kissat *solver, checker *checker, unsigned hash) { size_t size = SIZE_STACK (checker->imported); - assert (size <= UINT_MAX); + KISSAT_assert (size <= UINT_MAX); if (checker->buckets == checker->hashed) resize_hash (solver, checker); bucket *bucket = new_line (solver, checker, size, hash); @@ -485,8 +487,8 @@ static void insert_imported (kissat *solver, checker *checker, LOGLINE3 ("inserted checker"); const unsigned *const lits = BEGIN_STACK (checker->imported); const signed char *values = checker->values; - assert (!values[lits[0]]); - assert (!values[lits[1]]); + KISSAT_assert (!values[lits[0]]); + KISSAT_assert (!values[lits[1]]); watch_checker_literal (solver, checker, bucket, lits[0]); watch_checker_literal (solver, checker, bucket, lits[1]); checker->buckets++; @@ -525,11 +527,11 @@ static void resize_checker (kissat *solver, checker *checker, const unsigned vars = checker->vars; const unsigned size = checker->size; if (new_vars > size) { - assert (new_vars <= MAX_SIZE); + KISSAT_assert (new_vars <= MAX_SIZE); unsigned new_size = size ? 2 * size : 1; while (new_size < new_vars) new_size *= 2; - assert (new_size <= MAX_SIZE); + KISSAT_assert (new_size <= MAX_SIZE); LOG3 ("resizing checker form %u to %u", size, new_size); const unsigned size2 = 2 * size; const unsigned new_size2 = 2 * new_size; @@ -555,7 +557,7 @@ static void resize_checker (kissat *solver, checker *checker, const unsigned vars2 = 2 * vars; const unsigned new_vars2 = 2 * new_vars; const unsigned delta2 = 2 * delta; - assert (delta2 == new_vars2 - vars2); + KISSAT_assert (delta2 == new_vars2 - vars2); memset (checker->watches + vars2, 0, delta2 * sizeof *checker->watches); memset (checker->marks + vars2, 0, delta2); memset (checker->used + vars2, 0, delta2); @@ -566,11 +568,11 @@ static void resize_checker (kissat *solver, checker *checker, static inline unsigned import_external_checker (kissat *solver, checker *checker, int elit) { - assert (elit); + KISSAT_assert (elit); const unsigned var = ABS (elit) - 1; if (var >= checker->vars) resize_checker (solver, checker, var + 1); - assert (var < checker->vars); + KISSAT_assert (var < checker->vars); return 2 * var + (elit < 0); } @@ -581,7 +583,7 @@ import_internal_checker (kissat *solver, checker *checker, unsigned ilit) { } static inline int export_checker (checker *checker, unsigned ilit) { - assert (ilit <= 2 * checker->vars); + KISSAT_assert (ilit <= 2 * checker->vars); return (1 + (ilit >> 1)) * ((ilit & 1) ? -1 : 1); } @@ -619,7 +621,7 @@ static void remove_line (kissat *solver, checker *checker, size_t size) { unwatch_line (solver, checker, bucket); LOGLINE3 ("removed checker"); kissat_free (solver, bucket, bytes_line (size)); - assert (checker->buckets > 0); + KISSAT_assert (checker->buckets > 0); checker->buckets--; checker->removed++; } @@ -639,7 +641,7 @@ static void import_external_literals (kissat *solver, checker *checker, static void import_internal_literals (kissat *solver, checker *checker, size_t size, const unsigned *ilits) { - assert (size <= UINT_MAX); + KISSAT_assert (size <= UINT_MAX); CLEAR_STACK (checker->imported); for (size_t i = 0; i < size; i++) { const unsigned ilit = ilits[i]; @@ -680,8 +682,8 @@ static bool checker_propagate (kissat *solver, checker *checker) { const unsigned lit = PEEK_STACK (checker->trail, propagated); const unsigned not_lit = lit ^ 1; LOG3 ("checker propagate %u", lit); - assert (values[lit] > 0); - assert (values[not_lit] < 0); + KISSAT_assert (values[lit] > 0); + KISSAT_assert (values[not_lit] < 0); propagated++; buckets *buckets = checker_watches (checker, not_lit); bucket **begin_of_lines = BEGIN_STACK (*buckets), **q = begin_of_lines; @@ -774,10 +776,10 @@ static void checker_backtrack (checker *checker, unsigned saved) { signed char *values = checker->values; while (p != begin) { const unsigned lit = *--p; - assert (VALID_CHECKER_LIT (lit)); + KISSAT_assert (VALID_CHECKER_LIT (lit)); const unsigned not_lit = lit ^ 1; - assert (values[lit] > 0); - assert (values[not_lit] < 0); + KISSAT_assert (values[lit] > 0); + KISSAT_assert (values[not_lit] < 0); values[lit] = values[not_lit] = 0; } checker->propagated = saved; @@ -787,7 +789,7 @@ static void checker_backtrack (checker *checker, unsigned saved) { static bool checker_blocked_literal (kissat *solver, checker *checker, unsigned lit) { signed char *values = checker->values; - assert (values[lit] < 0); + KISSAT_assert (values[lit] < 0); const unsigned not_lit = lit ^ 1; if (checker->large[not_lit]) return false; @@ -840,7 +842,7 @@ static void check_line (kissat *solver, checker *checker) { bool satisfied = false, pure = false; unsigned decisions = 0, prev = INVALID_LIT; for (all_stack (unsigned, lit, checker->imported)) { - assert (prev != lit); + KISSAT_assert (prev != lit); prev = lit; signed char lit_value = values[lit]; if (lit_value < 0) @@ -896,7 +898,7 @@ void kissat_add_unchecked_internal (kissat *solver, size_t size, LOGUNSIGNEDS3 (size, lits, "adding unchecked internal checker"); checker *checker = solver->checker; checker->unchecked++; - assert (size <= UINT_MAX); + KISSAT_assert (size <= UINT_MAX); import_internal_literals (solver, checker, size, lits); insert_imported_if_not_simplified (solver, checker); } @@ -904,8 +906,8 @@ void kissat_add_unchecked_internal (kissat *solver, size_t size, void kissat_check_and_add_binary (kissat *solver, unsigned a, unsigned b) { LOGBINARY3 (a, b, "checking and adding internal checker"); checker *checker = solver->checker; - assert (VALID_INTERNAL_LITERAL (a)); - assert (VALID_INTERNAL_LITERAL (b)); + KISSAT_assert (VALID_INTERNAL_LITERAL (a)); + KISSAT_assert (VALID_INTERNAL_LITERAL (b)); import_binary (solver, checker, a, b); check_line (solver, checker); insert_imported_if_not_simplified (solver, checker); @@ -939,7 +941,7 @@ void kissat_check_and_add_internal (kissat *solver, size_t size, void kissat_check_and_add_unit (kissat *solver, unsigned a) { LOG3 ("checking and adding internal checker internal unit %u", a); checker *checker = solver->checker; - assert (VALID_INTERNAL_LITERAL (a)); + KISSAT_assert (VALID_INTERNAL_LITERAL (a)); import_internal_unit (solver, checker, a); check_line (solver, checker); insert_imported_if_not_simplified (solver, checker); @@ -969,8 +971,8 @@ void kissat_check_shrink_clause (kissat *solver, clause *c, unsigned remove, void kissat_remove_checker_binary (kissat *solver, unsigned a, unsigned b) { LOGBINARY3 (a, b, "removing internal checker"); checker *checker = solver->checker; - assert (VALID_INTERNAL_LITERAL (a)); - assert (VALID_INTERNAL_LITERAL (b)); + KISSAT_assert (VALID_INTERNAL_LITERAL (a)); + KISSAT_assert (VALID_INTERNAL_LITERAL (b)); import_binary (solver, checker, a, b); remove_line_if_not_redundant (solver, checker); } diff --git a/src/sat/kissat/check.h b/src/sat/kissat/check.h index f7eaf27a1..e6065fd1d 100644 --- a/src/sat/kissat/check.h +++ b/src/sat/kissat/check.h @@ -1,11 +1,14 @@ #ifndef _check_h_INCLUDED #define _check_h_INCLUDED -#ifndef NDEBUG - #include #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + +#ifndef KISSAT_NDEBUG + struct kissat; void kissat_check_satisfying_assignment (struct kissat *); @@ -17,7 +20,7 @@ struct clause; void kissat_init_checker (struct kissat *); void kissat_release_checker (struct kissat *); -#ifndef QUIET +#ifndef KISSAT_QUIET void kissat_print_checker_statistics (struct kissat *, bool verbose); #endif @@ -172,4 +175,7 @@ void kissat_remove_checker_internal (struct kissat *, size_t, } while (0) #endif + +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/classify.c b/src/sat/kissat/classify.c index 4514fb7bb..5b86239bf 100644 --- a/src/sat/kissat/classify.c +++ b/src/sat/kissat/classify.c @@ -2,8 +2,10 @@ #include "internal.h" #include "print.h" +ABC_NAMESPACE_IMPL_START + void kissat_classify (struct kissat *solver) { - statistics *s = &solver->statistics; + 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) { @@ -26,3 +28,5 @@ void kissat_classify (struct kissat *solver) { solver, "formula classified to have a %s binary clauses fraction", solver->classification.bigbig ? "large" : "small"); } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/classify.h b/src/sat/kissat/classify.h index f1f9b84d7..7590e72d0 100644 --- a/src/sat/kissat/classify.h +++ b/src/sat/kissat/classify.h @@ -3,6 +3,9 @@ #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + struct kissat; struct classification { @@ -14,4 +17,6 @@ typedef struct classification classification; void kissat_classify (struct kissat *); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/clause.c b/src/sat/kissat/clause.c index 8d4859193..9e50462cb 100644 --- a/src/sat/kissat/clause.c +++ b/src/sat/kissat/clause.c @@ -4,6 +4,8 @@ #include +ABC_NAMESPACE_IMPL_START + static void inc_clause (kissat *solver, bool original, bool redundant, bool binary) { if (binary) @@ -28,8 +30,8 @@ static void dec_clause (kissat *solver, bool redundant, bool binary) { static void init_clause (clause *res, bool redundant, unsigned glue, unsigned size) { - assert (size <= UINT_MAX); - assert (redundant || !glue); + KISSAT_assert (size <= UINT_MAX); + KISSAT_assert (redundant || !glue); glue = MIN (MAX_GLUE, glue); @@ -64,8 +66,8 @@ void kissat_connect_clause (kissat *solver, clause *c) { static reference new_binary_clause (kissat *solver, bool original, bool watch, unsigned first, unsigned second) { - assert (first != second); - assert (first != NOT (second)); + KISSAT_assert (first != second); + KISSAT_assert (first != NOT (second)); if (watch) kissat_watch_binary (solver, first, second); kissat_mark_added_literal (solver, first); @@ -81,7 +83,7 @@ static reference new_binary_clause (kissat *solver, bool original, static reference new_large_clause (kissat *solver, bool original, bool redundant, unsigned glue, unsigned size, unsigned *lits) { - assert (size > 2); + 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); @@ -148,19 +150,19 @@ reference kissat_new_redundant_clause (kissat *solver, unsigned glue) { } static void mark_clause_as_garbage (kissat *solver, clause *c) { - assert (!c->garbage); + 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); - assert (c->size > 2); + KISSAT_assert (c->size > 2); dec_clause (solver, c->redundant, false); c->garbage = true; } void kissat_mark_clause_as_garbage (kissat *solver, clause *c) { - assert (!c->garbage); + KISSAT_assert (!c->garbage); mark_clause_as_garbage (solver, c); size_t bytes = kissat_actual_bytes_of_clause (c); ADD (arena_garbage, bytes); @@ -168,8 +170,8 @@ void kissat_mark_clause_as_garbage (kissat *solver, clause *c) { clause *kissat_delete_clause (kissat *solver, clause *c) { LOGCLS (c, "delete"); - assert (c->size > 2); - assert (c->garbage); + 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); @@ -185,3 +187,5 @@ void kissat_delete_binary (kissat *solver, unsigned a, unsigned b) { dec_clause (solver, false, true); INC (clauses_deleted); } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/clause.h b/src/sat/kissat/clause.h index d926a6cc2..52e9c6fd1 100644 --- a/src/sat/kissat/clause.h +++ b/src/sat/kissat/clause.h @@ -8,6 +8,9 @@ #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + typedef struct clause clause; #define LD_MAX_GLUE 19 @@ -87,4 +90,6 @@ void kissat_delete_binary (struct kissat *, unsigned, unsigned); void kissat_mark_clause_as_garbage (struct kissat *, clause *); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/collect.c b/src/sat/kissat/collect.c index 77d45319e..3dfffe2db 100644 --- a/src/sat/kissat/collect.c +++ b/src/sat/kissat/collect.c @@ -13,10 +13,12 @@ #include #include +ABC_NAMESPACE_IMPL_START + static void flush_watched_clauses_by_literal (kissat *solver, unsigned lit, bool compact, reference start) { - assert (start != INVALID_REF); + KISSAT_assert (start != INVALID_REF); const value *const values = solver->values; const assigned *const all_assigned = solver->assigned; @@ -44,8 +46,8 @@ static void flush_watched_clauses_by_literal (kissat *solver, unsigned lit, if (lit < other) kissat_delete_binary (solver, lit, other); } else { - assert (!lit_fixed); - assert (!other_fixed); + KISSAT_assert (!lit_fixed); + KISSAT_assert (!other_fixed); { head.binary.lit = mother; @@ -59,7 +61,7 @@ static void flush_watched_clauses_by_literal (kissat *solver, unsigned lit, } } } else { - assert (solver->watching); + KISSAT_assert (solver->watching); const watch tail = *p++; if (!lit_fixed) { const reference ref = tail.large.ref; @@ -71,7 +73,7 @@ static void flush_watched_clauses_by_literal (kissat *solver, unsigned lit, } } - assert (!lit_fixed || q == begin); + 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); @@ -84,25 +86,25 @@ static void flush_watched_clauses_by_literal (kissat *solver, unsigned lit, return; watches *mlit_watches = &WATCHES (mlit); -#if defined(LOGGING) || !defined(NDEBUG) +#if defined(LOGGING) || !defined(KISSAT_NDEBUG) const size_t size_mlit_watches = SIZE_WATCHES (*mlit_watches); #endif if (lit_fixed) - assert (!size_mlit_watches); + KISSAT_assert (!size_mlit_watches); else if (mlit < lit) { - assert (mlit != INVALID_LIT); - assert (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 - assert (mlit == lit); + KISSAT_assert (mlit == lit); } static void flush_all_watched_clauses (kissat *solver, bool compact, reference start) { - assert (solver->watching); + KISSAT_assert (solver->watching); LOG ("starting to flush watches at clause[%" REFERENCE_FORMAT "]", start); for (all_variables (idx)) { const unsigned lit = LIT (idx); @@ -114,12 +116,12 @@ static void flush_all_watched_clauses (kissat *solver, bool compact, static void update_large_reason (kissat *solver, assigned *assigned, unsigned forced, clause *dst) { - assert (dst->reason); - assert (forced != INVALID_LIT); + 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; - assert (!a->binary); + KISSAT_assert (!a->binary); if (a->reason != dst_ref) { LOG ("reason reference %u of %s updated to %u", a->reason, LOGLIT (forced), dst_ref); @@ -129,7 +131,7 @@ static void update_large_reason (kissat *solver, assigned *assigned, } static unsigned get_forced (const value *values, clause *dst) { - assert (dst->reason); + KISSAT_assert (dst->reason); unsigned forced = INVALID_LIT; for (all_literals_in_clause (lit, dst)) { const value value = values[lit]; @@ -138,7 +140,7 @@ static unsigned get_forced (const value *values, clause *dst) { forced = lit; break; } - assert (forced != INVALID_LIT); + KISSAT_assert (forced != INVALID_LIT); return forced; } @@ -181,9 +183,9 @@ static void update_last_irredundant (kissat *solver, const clause *end, } void kissat_update_first_reducible (kissat *solver, clause *reducible) { - assert (reducible); - assert (!reducible->garbage); - assert (reducible->redundant); + 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) { @@ -196,9 +198,9 @@ void kissat_update_first_reducible (kissat *solver, clause *reducible) { } void kissat_update_last_irredundant (kissat *solver, clause *irredundant) { - assert (irredundant); - assert (!irredundant->garbage); - assert (!irredundant->redundant); + 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) { @@ -213,10 +215,10 @@ void kissat_update_last_irredundant (kissat *solver, clause *irredundant) { static void move_redundant_clauses_to_the_end (kissat *solver, reference ref) { INC (moved); - assert (ref != INVALID_REF); -#ifndef NDEBUG + KISSAT_assert (ref != INVALID_REF); +#ifndef KISSAT_NDEBUG const size_t size = SIZE_STACK (solver->arena); - assert ((size_t) ref <= size); + KISSAT_assert ((size_t) ref <= size); #endif clause *begin = (clause *) (BEGIN_STACK (solver->arena) + ref); clause *end = (clause *) END_STACK (solver->arena); @@ -234,7 +236,7 @@ static void move_redundant_clauses_to_the_end (kissat *solver, clause *last_irredundant = kissat_last_irredundant_clause (solver); while (p != end) { - assert (!p->shrunken); + KISSAT_assert (!p->shrunken); size_t bytes = kissat_bytes_of_clause (p->size); if (p->redundant) { memcpy (r, p, bytes); @@ -258,16 +260,16 @@ static void move_redundant_clauses_to_the_end (kissat *solver, LOGCLS (q, "new DST"); if (q->reason) get_forced_and_update_large_reason (solver, assigned, values, q); - assert (q->redundant); + KISSAT_assert (q->redundant); if (!first_reducible) first_reducible = q; r = (clause *) (bytes + (char *) r); q = (clause *) (bytes + (char *) q); } - assert ((char *) r <= (char *) redundant + bytes_redundant); + KISSAT_assert ((char *) r <= (char *) redundant + bytes_redundant); kissat_free (solver, redundant, bytes_redundant); - assert (!first_reducible || first_reducible < q); + KISSAT_assert (!first_reducible || first_reducible < q); update_first_reducible (solver, q, first_reducible); update_last_irredundant (solver, q, last_irredundant); @@ -276,20 +278,20 @@ static void move_redundant_clauses_to_the_end (kissat *solver, static reference sparse_sweep_garbage_clauses (kissat *solver, bool compact, reference start) { - assert (solver->watching); + 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 - assert (EMPTY_STACK (solver->added)); - assert (EMPTY_STACK (solver->removed)); + KISSAT_assert (EMPTY_STACK (solver->added)); + KISSAT_assert (EMPTY_STACK (solver->removed)); const value *const values = solver->values; assigned *assigned = solver->assigned; -#ifndef QUIET +#ifndef KISSAT_QUIET size_t flushed_garbage_clauses = 0; size_t flushed_satisfied_clauses = 0; #endif @@ -319,7 +321,7 @@ static reference sparse_sweep_garbage_clauses (kissat *solver, bool compact, for (clause *next; src != end; src = next) { if (src->garbage) { next = kissat_delete_clause (solver, src); -#ifndef QUIET +#ifndef KISSAT_QUIET flushed_garbage_clauses++; #endif if (last_irredundant == src) { @@ -331,13 +333,13 @@ static reference sparse_sweep_garbage_clauses (kissat *solver, bool compact, continue; } - assert (src->size > 1); + KISSAT_assert (src->size > 1); LOGCLS (src, "SRC"); next = kissat_next_clause (src); -#if !defined(NDEBUG) || defined(CHECKING_OR_PROVING) +#if !defined(KISSAT_NDEBUG) || defined(CHECKING_OR_PROVING) const unsigned old_size = src->size; #endif - assert (SIZE_OF_CLAUSE_HEADER == sizeof (unsigned)); + KISSAT_assert (SIZE_OF_CLAUSE_HEADER == sizeof (unsigned)); *(unsigned *) dst = *(unsigned *) src; unsigned *q = dst->lits; @@ -365,15 +367,15 @@ static reference sparse_sweep_garbage_clauses (kissat *solver, bool compact, if (tmp < 0 && !level) flushed++; else if (tmp > 0 && !level) { - assert (!satisfied); - assert (!dst->reason); + 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) { - assert (level); + KISSAT_assert (level); forced = non_false++ ? INVALID_LIT : lit; } else if (tmp < 0) other = lit; @@ -397,7 +399,7 @@ static reference sparse_sweep_garbage_clauses (kissat *solver, bool compact, DEC (clauses_redundant); else DEC (clauses_irredundant); -#ifndef QUIET +#ifndef KISSAT_QUIET flushed_satisfied_clauses++; #endif #ifdef CHECKING_OR_PROVING @@ -418,36 +420,36 @@ static reference sparse_sweep_garbage_clauses (kissat *solver, bool compact, } const unsigned new_size = q - dst->lits; - assert (new_size <= old_size); - assert (1 < new_size); + KISSAT_assert (new_size <= old_size); + KISSAT_assert (1 < new_size); if (new_size == 2) { - assert (mfirst != INVALID_LIT); - assert (msecond != INVALID_LIT); + KISSAT_assert (mfirst != INVALID_LIT); + KISSAT_assert (msecond != INVALID_LIT); - statistics *statistics = &solver->statistics; - assert (statistics->clauses_binary < UINT64_MAX); + statistics *statistics = &solver->statistics_; + KISSAT_assert (statistics->clauses_binary < UINT64_MAX); statistics->clauses_binary++; bool redundant = dst->redundant; if (redundant) { - assert (statistics->clauses_redundant > 0); + KISSAT_assert (statistics->clauses_redundant > 0); statistics->clauses_redundant--; redundant = false; } else { - assert (statistics->clauses_irredundant > 0); + KISSAT_assert (statistics->clauses_irredundant > 0); statistics->clauses_irredundant--; } LOGBINARY (mfirst, msecond, "DST"); kissat_watch_binary (solver, mfirst, msecond); if (dst->reason) { - assert (non_false == 1); - assert (other != INVALID_LIT); - assert (forced != INVALID_LIT); + 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; - assert (!a->binary); + KISSAT_assert (!a->binary); LOGBINARY (mfirst, msecond, "reason clause[%u] of %s updated to binary reason", @@ -464,7 +466,7 @@ static reference sparse_sweep_garbage_clauses (kissat *solver, bool compact, last_irredundant = first; } } else { - assert (2 < new_size); + KISSAT_assert (2 < new_size); dst->size = new_size; dst->shrunken = false; @@ -495,8 +497,8 @@ static reference sparse_sweep_garbage_clauses (kissat *solver, bool compact, continue; if (new_size != old_size) { - assert (1 < new_size); - assert (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); @@ -516,10 +518,10 @@ static reference sparse_sweep_garbage_clauses (kissat *solver, bool compact, if (first_redundant) LOGCLS (first_redundant, "determined first redundant clause as"); -#if !defined(QUIET) || defined(METRICS) +#if !defined(KISSAT_QUIET) || defined(METRICS) size_t bytes = (char *) END_STACK (solver->arena) - (char *) dst; #endif -#ifndef QUIET +#ifndef KISSAT_QUIET if (flushed) kissat_phase (solver, "collect", GET (garbage_collections), "flushed %zu falsified literals in large clauses", @@ -556,18 +558,18 @@ static reference sparse_sweep_garbage_clauses (kissat *solver, bool compact, kissat_percent (redundant_bytes, move_bytes), FORMAT_BYTES (move_bytes)); #endif - assert (first_redundant < dst); + KISSAT_assert (first_redundant < dst); res = kissat_reference_clause (solver, first_redundant); - assert (res != INVALID_REF); + KISSAT_assert (res != INVALID_REF); } SET_END_OF_STACK (solver->arena, (ward *) dst); kissat_shrink_arena (solver); #ifdef METRICS - if (solver->statistics.arena_garbage) + if (solver->statistics_.arena_garbage) kissat_very_verbose (solver, "still %s garbage left in arena", - FORMAT_BYTES (solver->statistics.arena_garbage)); + FORMAT_BYTES (solver->statistics_.arena_garbage)); else kissat_very_verbose (solver, "all garbage clauses in arena collected"); #endif @@ -578,7 +580,7 @@ static reference sparse_sweep_garbage_clauses (kissat *solver, bool compact, static void rewatch_clauses (kissat *solver, reference start) { LOG ("rewatching clause[%" REFERENCE_FORMAT "] and following clauses", start); - assert (solver->watching); + KISSAT_assert (solver->watching); const value *const values = solver->values; const assigned *const assigned = solver->assigned; @@ -587,7 +589,7 @@ static void rewatch_clauses (kissat *solver, reference start) { clause *end = (clause *) END_STACK (solver->arena); clause *c = (clause *) (BEGIN_STACK (solver->arena) + start); - assert (c <= end); + KISSAT_assert (c <= end); for (clause *next; c != end; c = next) { next = kissat_next_clause (c); @@ -606,7 +608,7 @@ static void rewatch_clauses (kissat *solver, reference start) { } void kissat_sparse_collect (kissat *solver, bool compact, reference start) { - assert (solver->watching); + KISSAT_assert (solver->watching); START (collect); INC (garbage_collections); INC (sparse_gcs); @@ -643,11 +645,11 @@ bool kissat_compacting (kissat *solver) { } void kissat_initial_sparse_collect (kissat *solver) { - assert (!solver->level); - assert (!solver->inconsistent); - assert (solver->watching); - assert (kissat_trail_flushed (solver)); - if (solver->statistics.units) { + 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); } @@ -655,12 +657,12 @@ void kissat_initial_sparse_collect (kissat *solver) { } static void dense_sweep_garbage_clauses (kissat *solver) { - assert (!solver->level); - assert (!solver->watching); + KISSAT_assert (!solver->level); + KISSAT_assert (!solver->watching); LOG ("dense garbage collection"); -#ifndef QUIET +#ifndef KISSAT_QUIET size_t flushed_garbage_clauses = 0; #endif clause *first_reducible = 0; @@ -675,15 +677,15 @@ static void dense_sweep_garbage_clauses (kissat *solver) { for (clause *next; src != end; src = next) { if (src->garbage) { next = kissat_delete_clause (solver, src); -#ifndef QUIET +#ifndef KISSAT_QUIET flushed_garbage_clauses++; #endif continue; } - assert (src->size > 1); + KISSAT_assert (src->size > 1); LOGCLS (src, "SRC"); next = kissat_next_clause (src); - assert (SIZE_OF_CLAUSE_HEADER == sizeof (unsigned)); + KISSAT_assert (SIZE_OF_CLAUSE_HEADER == sizeof (unsigned)); *(unsigned *) dst = *(unsigned *) src; dst->searched = src->searched; dst->size = src->size; @@ -701,7 +703,7 @@ static void dense_sweep_garbage_clauses (kissat *solver) { update_last_irredundant (solver, dst, last_irredundant); kissat_reset_last_learned (solver); -#if !defined(QUIET) || defined(METRICS) +#if !defined(KISSAT_QUIET) || defined(METRICS) size_t bytes = (char *) END_STACK (solver->arena) - (char *) dst; #endif kissat_phase (solver, "collect", GET (garbage_collections), @@ -717,17 +719,17 @@ static void dense_sweep_garbage_clauses (kissat *solver) { kissat_shrink_arena (solver); #ifdef METRICS - if (solver->statistics.arena_garbage) + if (solver->statistics_.arena_garbage) kissat_very_verbose (solver, "still %s garbage left in arena", - FORMAT_BYTES (solver->statistics.arena_garbage)); + FORMAT_BYTES (solver->statistics_.arena_garbage)); else kissat_very_verbose (solver, "all garbage clauses in arena collected"); #endif } void kissat_dense_collect (kissat *solver) { - assert (!solver->watching); - assert (!solver->level); + KISSAT_assert (!solver->watching); + KISSAT_assert (!solver->level); START (collect); INC (garbage_collections); INC (dense_garbage_collections); @@ -736,3 +738,5 @@ void kissat_dense_collect (kissat *solver) { REPORT (1, 'C'); STOP (collect); } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/collect.h b/src/sat/kissat/collect.h index 6a9c8c4ef..f6222ded4 100644 --- a/src/sat/kissat/collect.h +++ b/src/sat/kissat/collect.h @@ -3,6 +3,9 @@ #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); @@ -30,4 +33,6 @@ static inline void kissat_defrag_watches_if_needed (kissat *solver) { void kissat_update_last_irredundant (kissat *, clause *last_irredundant); void kissat_update_first_reducible (kissat *, clause *first_reducible); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/colors.c b/src/sat/kissat/colors.c index a3f2e6db9..f45260b29 100644 --- a/src/sat/kissat/colors.c +++ b/src/sat/kissat/colors.c @@ -1,12 +1,18 @@ #include "colors.h" +#ifdef WIN32 +#define isatty _isatty +#else #include +#endif + +ABC_NAMESPACE_IMPL_START int kissat_is_terminal[3] = {0, -1, -1}; int kissat_initialize_terminal (int fd) { - assert (fd == 1 || fd == 2); - assert (kissat_is_terminal[fd] < 0); + KISSAT_assert (fd == 1 || fd == 2); + KISSAT_assert (kissat_is_terminal[fd] < 0); return kissat_is_terminal[fd] = isatty (fd); } @@ -17,3 +23,5 @@ void kissat_force_colors (void) { void kissat_force_no_colors (void) { kissat_is_terminal[1] = kissat_is_terminal[2] = 0; } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/colors.h b/src/sat/kissat/colors.h index fe981e505..0d79c79e8 100644 --- a/src/sat/kissat/colors.h +++ b/src/sat/kissat/colors.h @@ -7,6 +7,9 @@ #include "keatures.h" +#include "global.h" +ABC_NAMESPACE_HEADER_START + #define BLUE "\033[34m" #define BOLD "\033[1m" #define CYAN "\033[36m" @@ -21,17 +24,17 @@ #define DARK_GRAY "\033[0;37m" #ifdef KISSAT_HAS_FILENO -#define assert_if_has_fileno assert +#define KISSAT_assert_if_has_fileno KISSAT_assert #else -#define assert_if_has_fileno(...) \ +#define KISSAT_assert_if_has_fileno(...) \ do { \ } while (0) #endif #define TERMINAL(F, I) \ - assert_if_has_fileno (fileno (F) == \ + KISSAT_assert_if_has_fileno (fileno (F) == \ I); /* 'fileno' only in POSIX not C99 */ \ - assert ((I == 1 && F == stdout) || (I == 2 && F == stderr)); \ + KISSAT_assert ((I == 1 && F == stdout) || (I == 2 && F == stderr)); \ bool connected_to_terminal = kissat_connected_to_terminal (I); \ FILE *terminal_file = F @@ -49,11 +52,11 @@ void kissat_force_colors (void); void kissat_force_no_colors (void); static inline bool kissat_connected_to_terminal (int fd) { - assert (fd == 1 || fd == 2); + KISSAT_assert (fd == 1 || fd == 2); int res = kissat_is_terminal[fd]; if (res < 0) res = kissat_initialize_terminal (fd); - assert (res == 0 || res == 1); + KISSAT_assert (res == 0 || res == 1); return res; } @@ -65,4 +68,6 @@ static inline const char *kissat_normal_color_code (int fd) { return kissat_connected_to_terminal (fd) ? NORMAL : ""; } +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/compact.c b/src/sat/kissat/compact.c index 2d27fa9ca..cb89cb9a9 100644 --- a/src/sat/kissat/compact.c +++ b/src/sat/kissat/compact.c @@ -6,11 +6,13 @@ #include +ABC_NAMESPACE_IMPL_START + static void reimport_literal (kissat *solver, unsigned eidx, unsigned mlit) { import *import = &PEEK_STACK (solver->import, eidx); - assert (import->imported); - assert (!import->eliminated); + 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; @@ -18,9 +20,9 @@ static void reimport_literal (kissat *solver, unsigned eidx, unsigned kissat_compact_literals (kissat *solver, unsigned *mfixed_ptr) { INC (compacted); -#if !defined(QUIET) || !defined(NDEBUG) +#if !defined(KISSAT_QUIET) || !defined(KISSAT_NDEBUG) const unsigned active = solver->active; -#ifndef QUIET +#ifndef KISSAT_QUIET const unsigned inactive = solver->vars - active; kissat_phase (solver, "compact", GET (compacted), "compacting garbage collection " @@ -29,7 +31,7 @@ unsigned kissat_compact_literals (kissat *solver, unsigned *mfixed_ptr) { #endif #endif #ifdef LOGGING - assert (!solver->compacting); + KISSAT_assert (!solver->compacting); solver->compacting = true; #endif unsigned mfixed = INVALID_LIT; @@ -42,7 +44,7 @@ unsigned kissat_compact_literals (kissat *solver, unsigned *mfixed_ptr) { unsigned mlit; if (flags->fixed) { const value value = kissat_fixed (solver, ilit); - assert (value); + KISSAT_assert (value); if (mfixed == INVALID_LIT) { mlit = mfixed = LIT (vars); LOG2 ("first fixed %u mapped to %u assigned to %d", ilit, mfixed, @@ -59,29 +61,29 @@ unsigned kissat_compact_literals (kissat *solver, unsigned *mfixed_ptr) { LOG2 ("positively fixed %u mapped to %u", ilit, mlit); } } else if (flags->active) { - assert (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); + const int elit = PEEK_STACK (solver->export_, iidx); if (elit) { const unsigned eidx = ABS (elit); import *import = &PEEK_STACK (solver->import, eidx); - assert (import->imported); - assert (!import->eliminated); + 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); + POKE_STACK (solver->export_, iidx, 0); } else LOG2 ("skipping inactive %u", ilit); continue; } - assert (mlit <= ilit); - assert (mlit != NOT (ilit)); + KISSAT_assert (mlit <= ilit); + KISSAT_assert (mlit != NOT (ilit)); if (mlit == ilit) continue; - const int elit = PEEK_STACK (solver->export, iidx); + const int elit = PEEK_STACK (solver->export_, iidx); const unsigned eidx = ABS (elit); if (elit < 0) mlit = NOT (mlit); @@ -90,17 +92,17 @@ unsigned kissat_compact_literals (kissat *solver, unsigned *mfixed_ptr) { *mfixed_ptr = mfixed; LOG ("compacting to %u variables %.2f%% from %u", vars, kissat_percent (vars, solver->vars), solver->vars); - assert (vars == active || vars == active + 1); + KISSAT_assert (vars == active || vars == active + 1); return vars; } static void compact_literal (kissat *solver, unsigned dst_lit, unsigned src_lit) { - assert (dst_lit < src_lit); - assert (dst_lit != NOT (src_lit)); + 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); - assert (dst_idx != src_idx); + 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]; @@ -116,19 +118,19 @@ static void compact_literal (kissat *solver, unsigned dst_lit, } static unsigned map_idx (kissat *solver, unsigned iidx) { - int elit = PEEK_STACK (solver->export, iidx); + int elit = PEEK_STACK (solver->export_, iidx); if (!elit) return INVALID_IDX; - assert (elit); + KISSAT_assert (elit); const unsigned eidx = ABS (elit); - assert (eidx); + KISSAT_assert (eidx); import *import = &PEEK_STACK (solver->import, eidx); - assert (import->imported); + KISSAT_assert (import->imported); if (import->eliminated) return INVALID_IDX; const unsigned mlit = import->lit; const unsigned midx = IDX (mlit); - assert (midx <= iidx); + KISSAT_assert (midx <= iidx); return midx; } @@ -139,7 +141,7 @@ static void compact_queue (kissat *solver) { solver->queue.stamp = 0; for (unsigned idx; !DISCONNECTED (idx = *p); p = &l->next) { const unsigned midx = map_idx (solver, idx); - assert (midx != INVALID_IDX); + KISSAT_assert (midx != INVALID_IDX); l = links + idx; l->prev = prev; l->stamp = ++solver->queue.stamp; @@ -211,16 +213,16 @@ static void compact_trail (kissat *solver) { for (size_t i = 0; i < size; i++) { const unsigned ilit = PEEK_ARRAY (solver->trail, i); const unsigned mlit = kissat_map_literal (solver, ilit, true); - assert (mlit != INVALID_LIT); + 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; - assert (VALID_INTERNAL_LITERAL (other)); + KISSAT_assert (VALID_INTERNAL_LITERAL (other)); const unsigned mother = kissat_map_literal (solver, other, true); - assert (mother != INVALID_LIT); + KISSAT_assert (mother != INVALID_LIT); a->reason = mother; } } @@ -232,55 +234,55 @@ static void compact_frames (kissat *solver) { frame *frame = &FRAME (level); const unsigned ilit = frame->decision; const unsigned mlit = kissat_map_literal (solver, ilit, true); - assert (mlit != INVALID_LIT); + 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); - assert (size <= UINT_MAX); - assert (size == solver->vars); + 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); + 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); + POKE_STACK (solver->export_, midx, elit); } - RESIZE_STACK (solver->export, vars); - SHRINK_STACK (solver->export); -#ifndef NDEBUG - assert (SIZE_STACK (solver->export) == vars); + 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); - assert (VALID_EXTERNAL_LITERAL (elit)); + 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); - assert (import->imported); + KISSAT_assert (import->imported); if (import->eliminated) continue; unsigned mlit = import->lit; if (elit < 0) mlit = NOT (mlit); const unsigned ilit = LIT (iidx); - assert (mlit == ilit); + KISSAT_assert (mlit == ilit); } #endif } static void compact_units (kissat *solver, unsigned mfixed) { LOG ("compacting units (first fixed %u)", mfixed); - assert (kissat_fixed (solver, mfixed) > 0); + 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); - assert (import->imported); - assert (!import->eliminated); + KISSAT_assert (import->imported); + KISSAT_assert (!import->eliminated); const unsigned ilit = import->lit; if (mlit != ilit) reimport_literal (solver, eidx, mlit); @@ -320,9 +322,9 @@ static void compact_best_and_target_values (kissat *solver, unsigned vars) { void kissat_finalize_compacting (kissat *solver, unsigned vars, unsigned mfixed) { LOG ("finalizing compacting"); - assert (vars <= solver->vars); + KISSAT_assert (vars <= solver->vars); #ifdef LOGGING - assert (solver->compacting); + KISSAT_assert (solver->compacting); #endif if (vars == solver->vars) { #ifdef LOGGING @@ -341,7 +343,7 @@ void kissat_finalize_compacting (kissat *solver, unsigned vars, if (flags->fixed && first) first = false; else if (!flags->active) - POKE_STACK (solver->export, iidx, 0); + POKE_STACK (solver->export_, iidx, 0); } compact_trail (solver); @@ -374,3 +376,5 @@ void kissat_finalize_compacting (kissat *solver, unsigned vars, #endif kissat_decrease_size (solver); } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/compact.h b/src/sat/kissat/compact.h index 89d5ecd31..6c281af23 100644 --- a/src/sat/kissat/compact.h +++ b/src/sat/kissat/compact.h @@ -1,9 +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 diff --git a/src/sat/kissat/config.c b/src/sat/kissat/config.c index 3c79f7a1e..b1f322ba4 100644 --- a/src/sat/kissat/config.c +++ b/src/sat/kissat/config.c @@ -1,4 +1,6 @@ -#ifndef NOPTIONS +#include "global.h" + +#ifndef KISSAT_NOPTIONS #include "config.h" #include "kissat.h" diff --git a/src/sat/kissat/config.h b/src/sat/kissat/config.h index 16eac8c05..d3d34fe49 100644 --- a/src/sat/kissat/config.h +++ b/src/sat/kissat/config.h @@ -1,8 +1,14 @@ -#ifndef NOPTIONS #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 diff --git a/src/sat/kissat/congruence.c b/src/sat/kissat/congruence.c index 01b7dde00..221f6a13a 100644 --- a/src/sat/kissat/congruence.c +++ b/src/sat/kissat/congruence.c @@ -19,6 +19,8 @@ #include #include +ABC_NAMESPACE_IMPL_START + // #define INDEX_LARGE_CLAUSES // #define INDEX_BINARY_CLAUSES #define MERGE_CONDITIONAL_EQUIVALENCES @@ -31,7 +33,7 @@ #define MAX_ARITY ((1 << LD_MAX_ARITY) - 1) struct gate { -#if defined(LOGGING) || !defined(NDEBUG) +#if defined(LOGGING) || !defined(KISSAT_NDEBUG) size_t id; #endif unsigned lhs; @@ -132,10 +134,10 @@ struct closure { #ifdef CHECKING_OR_PROVING unsigneds chain; #endif -#if defined(LOGGING) || !defined(NDEBUG) +#if defined(LOGGING) || !defined(KISSAT_NDEBUG) size_t gates_added; #endif -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG unsigneds implied; #endif }; @@ -144,8 +146,8 @@ typedef struct closure closure; static void init_closure (kissat *solver, closure *closure) { closure->solver = solver; - CALLOC (closure->scheduled, VARS); - CALLOC (closure->occurrences, LITS); + CALLOC (bool, closure->scheduled, VARS); + CALLOC (gates, closure->occurrences, LITS); INIT_STACK (closure->garbage); INIT_STACK (closure->lits); INIT_STACK (closure->rhs); @@ -153,7 +155,7 @@ static void init_closure (kissat *solver, closure *closure) { INIT_STACK (closure->binaries); INIT_FIFO (closure->schedule); - NALLOC (closure->repr, LITS); + NALLOC (unsigned, closure->repr, LITS); for (all_literals (lit)) closure->repr[lit] = lit; @@ -167,10 +169,10 @@ static void init_closure (kissat *solver, closure *closure) { #ifdef CHECKING_OR_PROVING INIT_STACK (closure->chain); #endif -#if defined(LOGGING) || !defined(NDEBUG) +#if defined(LOGGING) || !defined(KISSAT_NDEBUG) closure->gates_added = 0; #endif -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG INIT_STACK (closure->implied); #endif } @@ -190,21 +192,21 @@ static unsigned actual_gate_arity (gate *g) { #define CLOGANDGATE(G, ...) \ do { \ - assert ((G)->tag == AND_GATE); \ + KISSAT_assert ((G)->tag == AND_GATE); \ LOGANDGATE ((G)->id, closure->repr, (G)->lhs, (G)->arity, (G)->rhs, \ __VA_ARGS__); \ } while (0) #define CLOGXORGATE(G, ...) \ do { \ - assert ((G)->tag == XOR_GATE); \ + KISSAT_assert ((G)->tag == XOR_GATE); \ LOGXORGATE ((G)->id, closure->repr, (G)->lhs, (G)->arity, (G)->rhs, \ __VA_ARGS__); \ } while (0) #define CLOGITEGATE(G, ...) \ do { \ - assert ((G)->tag == ITE_GATE); \ + KISSAT_assert ((G)->tag == ITE_GATE); \ LOGITEGATE ((G)->id, closure->repr, (G)->lhs, (G)->rhs[0], \ (G)->rhs[1], (G)->rhs[2], __VA_ARGS__); \ } while (0) @@ -218,7 +220,7 @@ static unsigned actual_gate_arity (gate *g) { else if ((G)->tag == XOR_GATE) \ CLOGXORGATE (G, __VA_ARGS__); \ else { \ - assert ((G)->tag == ITE_GATE); \ + KISSAT_assert ((G)->tag == ITE_GATE); \ CLOGITEGATE (G, __VA_ARGS__); \ } \ } while (0) @@ -264,7 +266,7 @@ static void reset_closure (closure *closure) { #ifdef CHECKING_OR_PROVING RELEASE_STACK (closure->chain); #endif -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG RELEASE_STACK (closure->implied); #endif @@ -284,7 +286,7 @@ static unsigned reset_repr (closure *closure) { return res; } -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG static void check_lits_sorted (size_t size, const unsigned *lits) { unsigned prev = INVALID_LIT; @@ -292,38 +294,38 @@ static void check_lits_sorted (size_t size, const unsigned *lits) { for (const unsigned *p = lits; p != end_lits; p++) { const unsigned lit = *p; if (prev != INVALID_LIT) { - assert (prev != lit); + KISSAT_assert (prev != lit); const unsigned not_lit = lit ^ 1; - assert (prev != not_lit); - assert (prev < lit); + KISSAT_assert (prev != not_lit); + KISSAT_assert (prev < lit); } prev = lit; } } static void check_and_lits_normalized (size_t arity, const unsigned *lits) { - assert (arity > 1); + KISSAT_assert (arity > 1); check_lits_sorted (arity, lits); } static void check_xor_lits_normalized (const unsigned arity, const unsigned *lits) { - assert (arity > 1); + KISSAT_assert (arity > 1); check_lits_sorted (arity, lits); for (size_t i = 1; i != arity; i++) - assert (lits[i - 1] < lits[i]); + KISSAT_assert (lits[i - 1] < lits[i]); } static void check_ite_lits_normalized (kissat *solver, const unsigned *lits) { - assert (!NEGATED (lits[0])); - assert (!NEGATED (lits[1])); - assert (lits[0] != lits[1]); - assert (lits[0] != lits[2]); - assert (lits[1] != lits[2]); - assert (lits[0] != NOT (lits[1])); - assert (lits[0] != NOT (lits[2])); - assert (lits[1] != NOT (lits[2])); + KISSAT_assert (!NEGATED (lits[0])); + KISSAT_assert (!NEGATED (lits[1])); + KISSAT_assert (lits[0] != lits[1]); + KISSAT_assert (lits[0] != lits[2]); + KISSAT_assert (lits[1] != lits[2]); + KISSAT_assert (lits[0] != NOT (lits[1])); + KISSAT_assert (lits[0] != NOT (lits[2])); + KISSAT_assert (lits[1] != NOT (lits[2])); } #else @@ -347,13 +349,13 @@ static void sort_lits (kissat *solver, size_t arity, unsigned *lits) { static unsigned hash_lits (closure *closure, unsigned tag, size_t arity, const unsigned *lits) { -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG if (tag == AND_GATE) check_and_lits_normalized (arity, lits); else if (tag == XOR_GATE) check_xor_lits_normalized (arity, lits); else { - assert (tag == ITE_GATE); + KISSAT_assert (tag == ITE_GATE); check_ite_lits_normalized (closure->solver, lits); } #endif @@ -362,7 +364,7 @@ static unsigned hash_lits (closure *closure, unsigned tag, size_t arity, const uint64_t *const end_nonces = nonces + SIZE_NONCES; const uint64_t *n = nonces + tag; uint64_t hash = 0; - assert (n < end_nonces); + KISSAT_assert (n < end_nonces); for (const unsigned *l = lits; l != end_lits; l++) { hash += *l; hash *= *n++; @@ -374,19 +376,19 @@ static unsigned hash_lits (closure *closure, unsigned tag, size_t arity, return hash; } -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG static bool is_power_of_two (size_t n) { return n && ~(n & (n - 1)); } #endif static size_t reduce_hash (unsigned hash, size_t size, size_t size2) { - assert (size <= size2); - assert (size2 <= 2 * size); - assert (is_power_of_two (size2)); + KISSAT_assert (size <= size2); + KISSAT_assert (size2 <= 2 * size); + KISSAT_assert (is_power_of_two (size2)); unsigned res = hash; res &= size2 - 1; if (res >= size) res -= size; - assert (res < size); + KISSAT_assert (res < size); return res; } @@ -402,7 +404,7 @@ static bool closure_hash_table_is_full (closure *closure) { static bool match_lits (gate *g, unsigned tag, unsigned hash, size_t size, const unsigned *lits) { - assert (!g->garbage); + KISSAT_assert (!g->garbage); if (g->tag != tag) return false; if (g->hash != hash) @@ -427,7 +429,7 @@ static void resize_gate_hash_table (closure *closure) { "resizing gate table of size %zu filled with %zu entries %.0f%%", old_size, old_entries, kissat_percent (old_entries, old_size)); gate **old_table = hash->table, **new_table; - CALLOC (new_table, new_size); + CALLOC (gate*, new_table, new_size); size_t flushed = 0; for (size_t old_pos = 0; old_pos != old_size; old_pos++) { gate *g = old_table[old_pos]; @@ -439,7 +441,7 @@ static void resize_gate_hash_table (closure *closure) { } size_t new_pos = reduce_hash (g->hash, new_size, new_size); while (new_table[new_pos]) { - assert (new_table[new_pos] != REMOVED); + KISSAT_assert (new_table[new_pos] != REMOVED); if (++new_pos == new_size) new_pos = 0; } @@ -449,7 +451,7 @@ static void resize_gate_hash_table (closure *closure) { solver, "flushed %zu entries %.0f%% resizing table of size %zu", flushed, kissat_percent (flushed, old_size), old_size); DEALLOC (old_table, old_size); - assert (flushed <= old_entries); + KISSAT_assert (flushed <= old_entries); const size_t new_entries = old_entries - flushed; hash->table = new_table; hash->size = new_size; @@ -463,7 +465,7 @@ static bool remove_gate (closure *closure, gate *g) { if (!g->indexed) return false; kissat *solver = closure->solver; - assert (!solver->inconsistent); + KISSAT_assert (!solver->inconsistent); const size_t hash_size = closure->hash.size; size_t pos = reduce_hash (g->hash, hash_size, hash_size); gate **table = closure->hash.table; @@ -485,12 +487,12 @@ static bool remove_gate (closure *closure, gate *g) { static gate *find_gate (closure *closure, unsigned tag, unsigned hash, size_t size, const unsigned *lits, gate *except) { - assert (!except || !except->garbage); + KISSAT_assert (!except || !except->garbage); if (!closure->hash.entries) return 0; kissat *solver = closure->solver; - assert (!solver->inconsistent); - assert (hash == hash_lits (closure, tag, size, lits)); + KISSAT_assert (!solver->inconsistent); + KISSAT_assert (hash == hash_lits (closure, tag, size, lits)); const size_t hash_size = closure->hash.size; size_t start_pos = reduce_hash (hash, hash_size, hash_size); gate **table = closure->hash.table, *g; @@ -503,7 +505,7 @@ static gate *find_gate (closure *closure, unsigned tag, unsigned hash, if (g == REMOVED) ; else if (g->garbage) { - assert (g->indexed); + KISSAT_assert (g->indexed); g->indexed = false; table[pos] = REMOVED; } else if (g != except && match_lits (g, tag, hash, size, lits)) { @@ -523,15 +525,15 @@ static gate *find_gate (closure *closure, unsigned tag, unsigned hash, } static void index_gate (closure *closure, gate *g) { - assert (!g->indexed); + KISSAT_assert (!g->indexed); kissat *solver = closure->solver; - assert (!solver->inconsistent); - assert (g->arity > 1); + KISSAT_assert (!solver->inconsistent); + KISSAT_assert (g->arity > 1); if (closure_hash_table_is_full (closure)) resize_gate_hash_table (closure); LOGATE (g, "adding to hash table"); INC (congruent_indexed); - assert (g->hash == hash_lits (closure, g->tag, g->arity, g->rhs)); + KISSAT_assert (g->hash == hash_lits (closure, g->tag, g->arity, g->rhs)); const size_t hash_size = closure->hash.size; size_t pos = reduce_hash (g->hash, hash_size, hash_size); gate **table = closure->hash.table, *h; @@ -552,7 +554,7 @@ static unsigned parity_lits (kissat *solver, unsigneds *lits) { unsigned res = 0; for (all_stack (unsigned, lit, *lits)) res ^= NEGATED (lit); -#ifdef NDEBUG +#ifdef KISSAT_NDEBUG (void) solver; #endif return res; @@ -568,12 +570,12 @@ static void inc_lits (kissat *solver, unsigneds *lits) { carry = !NEGATED (not_lit); *p++ = not_lit; } -#ifdef NDEBUG +#ifdef KISSAT_NDEBUG (void) solver; #endif } -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG #define LESS_LITERAL(A, B) ((A) < (B)) @@ -617,14 +619,14 @@ static void check_binary_implied (closure *closure, unsigned a, unsigned b) { kissat *const solver = closure->solver; unsigneds *implied = &closure->implied; - assert (EMPTY_STACK (*implied)); + KISSAT_assert (EMPTY_STACK (*implied)); PUSH_STACK (*implied, a); PUSH_STACK (*implied, b); check_implied (closure); } static void check_and_gate_implied (closure *closure, gate *g) { - assert (g->tag == AND_GATE); + KISSAT_assert (g->tag == AND_GATE); kissat *const solver = closure->solver; if (GET_OPTION (check) < 2) return; @@ -634,7 +636,7 @@ static void check_and_gate_implied (closure *closure, gate *g) { for (all_rhs_literals_in_gate (other, g)) check_binary_implied (closure, not_lhs, other); unsigneds *implied = &closure->implied; - assert (EMPTY_STACK (*implied)); + KISSAT_assert (EMPTY_STACK (*implied)); PUSH_STACK (*implied, lhs); for (all_rhs_literals_in_gate (other, g)) { const unsigned not_other = NOT (other); @@ -644,7 +646,7 @@ static void check_and_gate_implied (closure *closure, gate *g) { } static void check_xor_gate_implied (closure *closure, gate *g) { - assert (g->tag == XOR_GATE); + KISSAT_assert (g->tag == XOR_GATE); kissat *const solver = closure->solver; if (GET_OPTION (check) < 2) return; @@ -652,16 +654,16 @@ static void check_xor_gate_implied (closure *closure, gate *g) { const unsigned lhs = g->lhs; const unsigned not_lhs = NOT (lhs); unsigneds *clause = &solver->clause; - assert (EMPTY_STACK (*clause)); + KISSAT_assert (EMPTY_STACK (*clause)); PUSH_STACK (*clause, not_lhs); for (all_rhs_literals_in_gate (other, g)) { - assert (!NEGATED (other)); + KISSAT_assert (!NEGATED (other)); PUSH_STACK (*clause, other); } unsigned arity = g->arity; unsigned end = 1u << arity; unsigned parity = NEGATED (not_lhs); - assert (parity == parity_lits (solver, clause)); + KISSAT_assert (parity == parity_lits (solver, clause)); for (unsigned i = 0; i != end; i++) { while (i && parity_lits (solver, clause) != parity) inc_lits (solver, clause); @@ -702,9 +704,9 @@ static void check_ite_implied (closure *closure, unsigned lhs, } static void check_ite_gate_implied (closure *closure, gate *g) { - assert (g->tag == ITE_GATE); - assert (g->arity == 3); -#ifndef NOPTIONS + KISSAT_assert (g->tag == ITE_GATE); + KISSAT_assert (g->arity == 3); +#ifndef KISSAT_NOPTIONS kissat *const solver = closure->solver; #endif if (GET_OPTION (check) < 2) @@ -741,17 +743,17 @@ static inline unsigned find_repr (closure *closure, unsigned lit) { static clause *find_other_two (kissat *solver, watches *watches, unsigned a, unsigned b, unsigned ignore) { - assert (!solver->watching); + KISSAT_assert (!solver->watching); const value *const values = solver->values; const watch *const begin_watches = BEGIN_WATCHES (*watches); const watch *const end_watches = END_WATCHES (*watches); const watch *p = begin_watches; while (p != end_watches) { const watch watch = *p++; - assert (!watch.type.binary); + KISSAT_assert (!watch.type.binary); const reference ref = watch.large.ref; clause *c = kissat_dereference_clause (solver, ref); - assert (!c->garbage); + KISSAT_assert (!c->garbage); unsigned found = 0; for (all_literals_in_clause (lit, c)) { if (values[lit]) @@ -764,7 +766,7 @@ static clause *find_other_two (kissat *solver, watches *watches, unsigned a, } goto CONTINUE_WITH_NEXT_WATCH; } - assert (found <= 2); + KISSAT_assert (found <= 2); if (found == 2) return c; CONTINUE_WITH_NEXT_WATCH:; @@ -774,7 +776,7 @@ static clause *find_other_two (kissat *solver, watches *watches, unsigned a, static clause *find_ternary_clause (kissat *solver, unsigned a, unsigned b, unsigned c) { - assert (!solver->watching); + KISSAT_assert (!solver->watching); watches *const a_watches = &WATCHES (a); watches *const b_watches = &WATCHES (b); watches *const c_watches = &WATCHES (c); @@ -785,7 +787,7 @@ static clause *find_ternary_clause (kissat *solver, unsigned a, unsigned b, return find_other_two (solver, a_watches, b, c, a); if (size_b <= size_a && size_b <= size_c) return find_other_two (solver, b_watches, a, c, b); - assert (size_c <= size_a && size_c <= size_b); + KISSAT_assert (size_c <= size_a && size_c <= size_b); return find_other_two (solver, c_watches, a, b, c); } @@ -793,7 +795,7 @@ static clause *find_ternary_clause (kissat *solver, unsigned a, unsigned b, static bool learn_congruence_unit (closure *closure, unsigned unit) { kissat *const solver = closure->solver; - assert (!solver->inconsistent); + KISSAT_assert (!solver->inconsistent); const value value = solver->values[unit]; if (value > 0) return true; @@ -810,7 +812,7 @@ static bool learn_congruence_unit (closure *closure, unsigned unit) { clause *conflict = kissat_probing_propagate (solver, 0, false); if (!conflict) return true; - assert (solver->inconsistent); + KISSAT_assert (solver->inconsistent); LOG ("propagating congruence unit %s yields conflict", LOGLIT (unit)); return false; } @@ -838,7 +840,7 @@ static void add_binary_clause (closure *closure, unsigned a, unsigned b) { (void) !learn_congruence_unit (closure, unit); return; } - assert (!a_value), assert (!b_value); + KISSAT_assert (!a_value), KISSAT_assert (!b_value); LOGBINARY (a, b, "adding representative"); if (solver->watching) kissat_new_binary_clause (solver, a, b); @@ -856,19 +858,19 @@ static void schedule_literal (closure *closure, unsigned lit) { if (*scheduled) return; *scheduled = true; - ENQUEUE_FIFO (closure->schedule, lit); + ENQUEUE_FIFO (unsigned, closure->schedule, lit); LOG ("scheduled propagation of merged %s", CLOGREPR (lit)); } static unsigned dequeue_next_scheduled_literal (closure *closure) { unsigned res; DEQUEUE_FIFO (closure->schedule, res); -#if defined(LOGGING) || !defined(NDEBUG) +#if defined(LOGGING) || !defined(KISSAT_NDEBUG) kissat *const solver = closure->solver; #endif unsigned idx = IDX (res); bool *scheduled = closure->scheduled + idx; - assert (*scheduled); + KISSAT_assert (*scheduled); *scheduled = false; LOG ("dequeued from schedule %s", CLOGREPR (res)); return res; @@ -877,7 +879,7 @@ static unsigned dequeue_next_scheduled_literal (closure *closure) { static bool merge_literals (closure *closure, unsigned lit, unsigned other) { kissat *const solver = closure->solver; - assert (!solver->inconsistent); + KISSAT_assert (!solver->inconsistent); unsigned repr_lit = find_repr (closure, lit); unsigned repr_other = find_repr (closure, other); unsigned *const repr = closure->repr; @@ -889,8 +891,8 @@ static bool merge_literals (closure *closure, unsigned lit, const value *const values = solver->values; const value lit_value = values[lit]; const value other_value = values[other]; - assert (lit_value == values[repr_lit]); - assert (other_value == values[repr_other]); + KISSAT_assert (lit_value == values[repr_lit]); + KISSAT_assert (other_value == values[repr_other]); if (lit_value) { if (lit_value == other_value) { LOG ("not merging %s and %s assigned to the same value", @@ -905,7 +907,7 @@ static bool merge_literals (closure *closure, unsigned lit, ADD_EMPTY_TO_PROOF (); return false; } - assert (!other_value); + KISSAT_assert (!other_value); LOG ("merging assigned %s and unassigned %s", LOGREPR (lit, repr), LOGREPR (other, repr)); const unsigned unit = (lit_value < 0) ? NOT (other) : other; @@ -923,8 +925,8 @@ static bool merge_literals (closure *closure, unsigned lit, unsigned larger = repr_other; if (smaller > larger) SWAP (unsigned, smaller, larger); - assert (repr[smaller] == smaller); - assert (repr[larger] > smaller); + KISSAT_assert (repr[smaller] == smaller); + KISSAT_assert (repr[larger] > smaller); if (repr_lit == NOT (repr_other)) { LOG ("merging clashing %s and %s", LOGREPR (lit, repr), LOGREPR (other, repr)); @@ -960,8 +962,8 @@ static gate *new_gate (closure *closure, unsigned tag, unsigned hash, unsigned lhs, unsigned arity, const unsigned *lits) { kissat *const solver = closure->solver; const size_t bytes = bytes_gate (arity); - gate *g = kissat_malloc (solver, bytes); -#if defined(LOGGING) || !defined(NDEBUG) + gate *g = (gate*)kissat_malloc (solver, bytes); +#if defined(LOGGING) || !defined(KISSAT_NDEBUG) g->id = closure->gates_added++; #endif g->tag = tag; @@ -1010,12 +1012,12 @@ static gate *new_and_gate (closure *closure, unsigned lhs) { for (all_stack (unsigned, lit, *all_lits)) if (lhs != lit) { unsigned not_lit = NOT (lit); - assert (lhs != not_lit); + KISSAT_assert (lhs != not_lit); PUSH_STACK (*rhs_stack, not_lit); } const unsigned arity = SIZE_STACK (*rhs_stack); unsigned *rhs_lits = BEGIN_STACK (*rhs_stack); - assert (arity + 1 == SIZE_STACK (*all_lits)); + KISSAT_assert (arity + 1 == SIZE_STACK (*all_lits)); unsigned hash; gate *g = find_and_lits (closure, &hash, arity, rhs_lits, 0); if (g) { @@ -1043,10 +1045,10 @@ static void simplify_and_add_to_proof_chain (kissat *solver, mark *marks, unsigneds *unsimplified, unsigneds *clause, unsigneds *chain) { - assert (EMPTY_STACK (*clause)); -#ifndef NDEBUG + KISSAT_assert (EMPTY_STACK (*clause)); +#ifndef KISSAT_NDEBUG for (all_stack (unsigned, lit, *unsimplified)) - assert (!(marks[lit] & 4)); + KISSAT_assert (!(marks[lit] & 4)); #endif bool trivial = false; for (all_stack (unsigned, lit, *unsimplified)) { @@ -1065,7 +1067,7 @@ static void simplify_and_add_to_proof_chain (kissat *solver, mark *marks, } for (all_stack (unsigned, lit, *clause)) { mark mark = marks[lit]; - assert (mark & 4); + KISSAT_assert (mark & 4); mark &= ~4u; marks[lit] = mark; } @@ -1093,9 +1095,9 @@ static void add_xor_matching_proof_chain (closure *closure, gate *g, unsigneds *const clause = &solver->clause; unsigneds *const chain = &closure->chain; mark *const marks = solver->marks; - assert (EMPTY_STACK (*unsimplified)); - assert (EMPTY_STACK (*chain)); - assert (g->arity > 1); + KISSAT_assert (EMPTY_STACK (*unsimplified)); + KISSAT_assert (EMPTY_STACK (*chain)); + KISSAT_assert (g->arity > 1); const unsigned reduced_arity = g->arity - 1; for (unsigned i = 0; i != reduced_arity; i++) PUSH_STACK (*unsimplified, g->rhs[i]); @@ -1103,7 +1105,7 @@ static void add_xor_matching_proof_chain (closure *closure, gate *g, const unsigned not_lhs2 = NOT (lhs2); do { const size_t size = SIZE_STACK (*unsimplified); - assert (size < 32); + KISSAT_assert (size < 32); for (unsigned i = 0; i != 1u << size; i++) { PUSH_STACK (*unsimplified, not_lhs1); PUSH_STACK (*unsimplified, lhs2); @@ -1115,7 +1117,7 @@ static void add_xor_matching_proof_chain (closure *closure, gate *g, unsimplified->end -= 2; inc_lits (solver, unsimplified); } - assert (!EMPTY_STACK (*unsimplified)); + KISSAT_assert (!EMPTY_STACK (*unsimplified)); unsimplified->end--; } while (!EMPTY_STACK (*unsimplified)); LOG ("finished XOR matching proof chain"); @@ -1125,14 +1127,14 @@ static void delete_proof_chain (closure *closure) { kissat *const solver = closure->solver; unsigneds *chain = &closure->chain; if (!kissat_checking_or_proving (solver)) { - assert (EMPTY_STACK (*chain)); + KISSAT_assert (EMPTY_STACK (*chain)); return; } if (EMPTY_STACK (*chain)) return; LOG ("starting deletion of proof chain"); unsigneds *clause = &solver->clause; - assert (EMPTY_STACK (*clause)); + KISSAT_assert (EMPTY_STACK (*clause)); const unsigned *start = BEGIN_STACK (*chain); const unsigned *end = END_STACK (*chain); const unsigned *p = start; @@ -1150,8 +1152,8 @@ static void delete_proof_chain (closure *closure) { } p++; } - assert (EMPTY_STACK (*clause)); - assert (start == end); + KISSAT_assert (EMPTY_STACK (*clause)); + KISSAT_assert (start == end); CLEAR_STACK (*chain); LOG ("finished deletion of proof chain"); } @@ -1196,12 +1198,12 @@ static gate *new_xor_gate (closure *closure, unsigned lhs) { const unsigned not_lhs = NOT (lhs); for (all_stack (unsigned, lit, *all_lits)) if (lit != lhs && lit != not_lhs) { - assert (!NEGATED (lit)); + KISSAT_assert (!NEGATED (lit)); PUSH_STACK (*rhs_stack, lit); } const unsigned arity = SIZE_STACK (*rhs_stack); unsigned *rhs_lits = BEGIN_STACK (*rhs_stack); - assert (arity + 1 == SIZE_STACK (*all_lits)); + KISSAT_assert (arity + 1 == SIZE_STACK (*all_lits)); unsigned hash; gate *g = find_xor_lits (closure, &hash, arity, rhs_lits, 0); if (g) { @@ -1233,8 +1235,8 @@ static void add_ite_matching_proof_chain (closure *closure, gate *g, unsigneds *clause = &solver->clause; mark *const marks = solver->marks; unsigneds *chain = &closure->chain; - assert (EMPTY_STACK (*clause)); - assert (EMPTY_STACK (*chain)); + KISSAT_assert (EMPTY_STACK (*clause)); + KISSAT_assert (EMPTY_STACK (*chain)); const unsigned *rhs = g->rhs; const unsigned cond = rhs[0]; const unsigned not_cond = NOT (cond); @@ -1274,8 +1276,8 @@ static void add_ite_turned_and_binary_clauses (closure *closure, gate *g) { unsigneds *clause = &solver->clause; unsigneds *chain = &closure->chain; mark *const marks = solver->marks; - assert (EMPTY_STACK (*unsimplified)); - assert (EMPTY_STACK (*chain)); + KISSAT_assert (EMPTY_STACK (*unsimplified)); + KISSAT_assert (EMPTY_STACK (*chain)); const unsigned not_lhs = NOT (g->lhs); const unsigned *rhs = g->rhs; PUSH_STACK (*unsimplified, not_lhs); @@ -1298,7 +1300,7 @@ static void add_ite_turned_and_binary_clauses (closure *closure, gate *g) { #endif static bool normalize_ite_lits (kissat *solver, unsigned *lits) { -#ifdef NDEBUG +#ifdef KISSAT_NDEBUG (void) solver; #endif if (NEGATED (lits[0])) { @@ -1316,7 +1318,7 @@ static gate *find_ite_lits (closure *closure, unsigned *hash_ptr, bool *negate_lhs_ptr, unsigned arity, unsigned *lits, gate *except) { kissat *const solver = closure->solver; - assert (arity == 3); + KISSAT_assert (arity == 3); LOGITEGATE (INVALID_GATE_ID, closure->repr, INVALID_LIT, lits[0], lits[1], lits[2], "finding not yet normalized"); bool negate_lhs = normalize_ite_lits (solver, lits); @@ -1371,7 +1373,7 @@ static gate *new_ite_gate (closure *closure, unsigned lhs, unsigned cond, PUSH_STACK (*rhs_stack, cond); PUSH_STACK (*rhs_stack, then_lit); PUSH_STACK (*rhs_stack, else_lit); - assert (SIZE_STACK (*rhs_stack) == 3); + KISSAT_assert (SIZE_STACK (*rhs_stack) == 3); const unsigned arity = 3; unsigned *rhs_lits = BEGIN_STACK (*rhs_stack); bool negate_lhs; @@ -1397,7 +1399,7 @@ static gate *new_ite_gate (closure *closure, unsigned lhs, unsigned cond, static void mark_gate_as_garbage (closure *closure, gate *g) { kissat *const solver = closure->solver; - assert (!g->garbage); + KISSAT_assert (!g->garbage); g->garbage = true; LOGATE (g, "marked as garbage"); PUSH_STACK (closure->garbage, g); @@ -1408,13 +1410,13 @@ static void shrink_gate (closure *closure, gate *g, unsigned *const rhs = g->rhs; const unsigned old_arity = g->arity; unsigned *const old_end_rhs = rhs + old_arity; - assert (rhs <= new_end_rhs); - assert (new_end_rhs <= old_end_rhs); + KISSAT_assert (rhs <= new_end_rhs); + KISSAT_assert (new_end_rhs <= old_end_rhs); if (new_end_rhs == old_end_rhs) return; const unsigned new_arity = new_end_rhs - rhs; if (!g->shrunken) { - assert (old_end_rhs[-1] != INVALID_LIT); + KISSAT_assert (old_end_rhs[-1] != INVALID_LIT); old_end_rhs[-1] = INVALID_LIT; g->shrunken = true; } @@ -1428,7 +1430,7 @@ static void shrink_gate (closure *closure, gate *g, } static bool skip_and_gate (closure *closure, gate *g) { - assert (g->tag == AND_GATE); + KISSAT_assert (g->tag == AND_GATE); if (g->garbage) return true; kissat *const solver = closure->solver; @@ -1439,7 +1441,7 @@ static bool skip_and_gate (closure *closure, gate *g) { mark_gate_as_garbage (closure, g); return true; } - assert (g->arity > 1); + KISSAT_assert (g->arity > 1); return false; } @@ -1451,7 +1453,7 @@ static bool gate_contains (gate *g, unsigned lit) { } static bool rewriting_lhs (closure *closure, gate *g, unsigned dst) { -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG kissat *const solver = closure->solver; #endif if (dst != g->lhs && dst != NOT (g->lhs)) @@ -1463,16 +1465,16 @@ static bool rewriting_lhs (closure *closure, gate *g, unsigned dst) { static void shrink_and_gate (closure *closure, gate *g, unsigned *new_end_rhs, unsigned falsifies, unsigned clashing) { - assert (g->tag == AND_GATE); -#ifndef NDEBUG + KISSAT_assert (g->tag == AND_GATE); +#ifndef KISSAT_NDEBUG kissat *const solver = closure->solver; #endif if (falsifies != INVALID_LIT) { - assert (g->arity); + KISSAT_assert (g->arity); g->rhs[0] = falsifies; new_end_rhs = g->rhs + 1; } else if (clashing != INVALID_LIT) { - assert (1 < g->arity); + KISSAT_assert (1 < g->arity); g->rhs[0] = clashing; g->rhs[1] = NOT (clashing); new_end_rhs = g->rhs + 2; @@ -1482,7 +1484,7 @@ static void shrink_and_gate (closure *closure, gate *g, static void update_and_gate (closure *closure, gate *g, unsigned falsifies, unsigned clashing) { - assert (g->tag == AND_GATE); + KISSAT_assert (g->tag == AND_GATE); bool garbage = true; kissat *const solver = closure->solver; if (falsifies != INVALID_LIT || clashing != INVALID_LIT) @@ -1501,7 +1503,7 @@ static void update_and_gate (closure *closure, gate *g, unsigned falsifies, unsigned hash; gate *h = find_and_gate (closure, &hash, g); if (h) { - assert (garbage); + KISSAT_assert (garbage); if (merge_literals (closure, g->lhs, h->lhs)) INC (congruent_ands); } else { @@ -1553,11 +1555,11 @@ static void rewrite_and_gate (closure *closure, gate *g, unsigned dst, return; if (!gate_contains (g, src)) return; - assert (src != INVALID_LIT); - assert (dst != INVALID_LIT); + KISSAT_assert (src != INVALID_LIT); + KISSAT_assert (dst != INVALID_LIT); kissat *const solver = closure->solver; const value *const values = solver->values; - assert (values[src] == values[dst]); + KISSAT_assert (values[src] == values[dst]); CLOGANDGATE (g, "rewriting %s by %s in", CLOGREPR (src), CLOGREPR (dst)); const unsigned old_arity = g->arity; const unsigned not_lhs = NOT (g->lhs); @@ -1597,18 +1599,18 @@ static void rewrite_and_gate (closure *closure, gate *g, unsigned dst, } if (lit == not_dst) { if (dst_count) { - assert (!not_dst_count); + KISSAT_assert (!not_dst_count); LOG ("clashing literals %s and %s", LOGLIT (dst), LOGLIT (not_dst)); clashing = dst; break; } - assert (!not_dst_count); + KISSAT_assert (!not_dst_count); not_dst_count++; } *q++ = lit; } - assert (dst_count <= 2); - assert (not_dst_count <= 1); + KISSAT_assert (dst_count <= 2); + KISSAT_assert (not_dst_count <= 1); shrink_and_gate (closure, g, q, falsifies, clashing); CLOGANDGATE (g, "rewritten"); check_and_gate_implied (closure, g); @@ -1618,10 +1620,10 @@ static void rewrite_and_gate (closure *closure, gate *g, unsigned dst, } static bool skip_xor_gate (gate *g) { - assert (g->tag == XOR_GATE); + KISSAT_assert (g->tag == XOR_GATE); if (g->garbage) return true; - assert (g->arity > 1); + KISSAT_assert (g->arity > 1); return false; } @@ -1634,7 +1636,7 @@ static void add_xor_shrinking_proof_chain (closure *closure, gate *g, return; LOG ("starting XOR shrinking proof chain"); unsigneds *clause = &solver->clause; - assert (EMPTY_STACK (*clause)); + KISSAT_assert (EMPTY_STACK (*clause)); for (unsigned i = 0; i != g->arity; i++) { unsigned lit = g->rhs[i]; PUSH_STACK (*clause, lit); @@ -1643,10 +1645,10 @@ static void add_xor_shrinking_proof_chain (closure *closure, gate *g, const unsigned not_lhs = NOT (lhs); PUSH_STACK (*clause, not_lhs); const unsigned parity = NEGATED (not_lhs); - assert (parity == parity_lits (solver, clause)); + KISSAT_assert (parity == parity_lits (solver, clause)); const unsigned not_pivot = NOT (pivot); const size_t size = SIZE_STACK (*clause); - assert (size < 32); + KISSAT_assert (size < 32); const unsigned end = 1u << size; for (unsigned i = 0; i != end; i++) { while (i && parity != parity_lits (solver, clause)) @@ -1684,12 +1686,12 @@ static void add_xor_shrinking_proof_chain (closure *closure, gate *g, static void shrink_xor_gate (closure *closure, gate *g, unsigned *new_end_rhs) { - assert (g->tag == XOR_GATE); + KISSAT_assert (g->tag == XOR_GATE); shrink_gate (closure, g, new_end_rhs); } static void update_xor_gate (closure *closure, gate *g) { - assert (g->tag == XOR_GATE); + KISSAT_assert (g->tag == XOR_GATE); kissat *const solver = closure->solver; bool garbage = true; if (g->arity == 0) @@ -1705,11 +1707,11 @@ static void update_xor_gate (closure *closure, gate *g) { INC (congruent_unary); } } else { - assert (g->arity > 1); + KISSAT_assert (g->arity > 1); unsigned hash; gate *h = find_xor_gate (closure, &hash, g); if (h) { - assert (garbage); + KISSAT_assert (garbage); add_xor_matching_proof_chain (closure, g, g->lhs, h->lhs); if (merge_literals (closure, g->lhs, h->lhs)) INC (congruent_xors); @@ -1736,7 +1738,7 @@ static void simplify_xor_gate (closure *closure, gate *g) { unsigned negate = 0; for (const unsigned *p = q; p != end_of_rhs; p++) { const unsigned lit = *p; - assert (!NEGATED (lit)); + KISSAT_assert (!NEGATED (lit)); const value value = values[lit]; if (value > 0) negate ^= 1; @@ -1773,7 +1775,7 @@ static void rewrite_xor_gate (closure *closure, gate *g, unsigned dst, dst = STRIP (dst); for (const unsigned *p = q; p != end_of_rhs; p++) { unsigned lit = *p; - assert (!NEGATED (lit)); + KISSAT_assert (!NEGATED (lit)); if (lit == src) lit = dst; const value value = values[lit]; @@ -1789,7 +1791,7 @@ static void rewrite_xor_gate (closure *closure, gate *g, unsigned dst, LOG ("flipping LHS literal %s", LOGLIT (g->lhs)); g->lhs = NOT (g->lhs); } - assert (dst_count <= 2); + KISSAT_assert (dst_count <= 2); if (dst_count == 2) { CLOGXORGATE (g, "literals %s and %s were both in", LOGLIT (src), LOGLIT (dst)); @@ -1800,7 +1802,7 @@ static void rewrite_xor_gate (closure *closure, gate *g, unsigned dst, if (lit != dst) *q++ = lit; } - assert (q + 2 == end_of_rhs); + KISSAT_assert (q + 2 == end_of_rhs); } shrink_xor_gate (closure, g, q); CLOGXORGATE (g, "rewritten"); @@ -1809,7 +1811,7 @@ static void rewrite_xor_gate (closure *closure, gate *g, unsigned dst, update_xor_gate (closure, g); if (!g->garbage && !solver->inconsistent && original_dst_negated && dst_count == 1) { - assert (!NEGATED (dst)); + KISSAT_assert (!NEGATED (dst)); connect_occurrence (closure, dst, g); } check_xor_gate_implied (closure, g); @@ -1818,7 +1820,7 @@ static void rewrite_xor_gate (closure *closure, gate *g, unsigned dst, } static bool skip_ite_gate (gate *g) { - assert (g->tag == ITE_GATE); + KISSAT_assert (g->tag == ITE_GATE); if (g->garbage) return true; return false; @@ -1830,7 +1832,7 @@ static void simplify_ite_gate (closure *closure, gate *g) { kissat *const solver = closure->solver; const value *const values = solver->values; CLOGITEGATE (g, "simplifying"); - assert (g->arity == 3); + KISSAT_assert (g->arity == 3); bool garbage = true; const unsigned lhs = g->lhs; unsigned *const rhs = g->rhs; @@ -1852,7 +1854,7 @@ static void simplify_ite_gate (closure *closure, gate *g) { const value then_value = values[then_lit]; const value else_value = values[else_lit]; const unsigned not_lhs = NOT (lhs); - assert (then_value || else_value); + KISSAT_assert (then_value || else_value); if (then_value > 0 && else_value > 0) learn_congruence_unit (closure, lhs); else if (then_value < 0 && else_value < 0) @@ -1869,42 +1871,42 @@ static void simplify_ite_gate (closure *closure, gate *g) { INC (congruent_unary); } } else { - assert (!!else_value + !!then_value == 1); + KISSAT_assert (!!else_value + !!then_value == 1); if (then_value > 0) { - assert (!else_value); + KISSAT_assert (!else_value); g->lhs = not_lhs; rhs[0] = NOT (cond); rhs[1] = NOT (else_lit); } else if (then_value < 0) { - assert (!else_value); + KISSAT_assert (!else_value); rhs[0] = NOT (cond); rhs[1] = else_lit; } else if (else_value > 0) { - assert (!then_value); + KISSAT_assert (!then_value); g->lhs = not_lhs; rhs[0] = NOT (then_lit); rhs[1] = cond; } else { - assert (else_value < 0); - assert (!then_value); + KISSAT_assert (else_value < 0); + KISSAT_assert (!then_value); rhs[0] = cond; rhs[1] = then_lit; } if (rhs[0] > rhs[1]) SWAP (unsigned, rhs[0], rhs[1]); - assert (!g->shrunken); + KISSAT_assert (!g->shrunken); g->shrunken = true; rhs[2] = INVALID_LIT; g->arity = 2; g->tag = AND_GATE; - assert (rhs[0] < rhs[1]); - assert (rhs[0] != NOT (rhs[1])); + KISSAT_assert (rhs[0] < rhs[1]); + KISSAT_assert (rhs[0] != NOT (rhs[1])); CLOGANDGATE (g, "simplified"); check_and_gate_implied (closure, g); unsigned hash; gate *h = find_and_gate (closure, &hash, g); if (h) { - assert (garbage); + KISSAT_assert (garbage); if (merge_literals (closure, g->lhs, h->lhs)) INC (congruent_ands); } else { @@ -1933,7 +1935,7 @@ static void rewrite_ite_gate (closure *closure, gate *g, unsigned dst, kissat *const solver = closure->solver; CLOGITEGATE (g, "rewriting %s by %s in", CLOGREPR (src), CLOGREPR (dst)); unsigned *const rhs = g->rhs; - assert (g->arity == 3); + KISSAT_assert (g->arity == 3); const unsigned lhs = g->lhs; const unsigned cond = rhs[0]; const unsigned then_lit = rhs[1]; @@ -1961,13 +1963,13 @@ static void rewrite_ite_gate (closure *closure, gate *g, unsigned dst, // !then_lit & then_lit | then_lit & else_lit // then_lit & else_lit rhs[0] = else_lit; - assert (rhs[1] == then_lit); + KISSAT_assert (rhs[1] == then_lit); } else if (dst == else_lit) { // else_list ? then_lit : else_lit // else_list & then_lit | !else_list & else_lit // else_list & then_lit rhs[0] = else_lit; - assert (rhs[1] == then_lit); + KISSAT_assert (rhs[1] == then_lit); } else if (not_dst == else_lit) { // !else_list ? then_lit : else_lit // !else_list & then_lit | else_lit & else_lit @@ -2010,20 +2012,20 @@ static void rewrite_ite_gate (closure *closure, gate *g, unsigned dst, // cond & !else_lit | !cond & else_lit // cond ^ else_lit new_tag = XOR_GATE; - assert (rhs[0] == cond); + KISSAT_assert (rhs[0] == cond); rhs[1] = else_lit; } else { shrink = false; rhs[1] = dst; } } else { - assert (src == else_lit); + KISSAT_assert (src == else_lit); if (dst == cond) { // cond ? then_lit : cond // cond & then_lit | !cond & cond // cond & then_lit - assert (rhs[0] == cond); - assert (rhs[1] == then_lit); + KISSAT_assert (rhs[0] == cond); + KISSAT_assert (rhs[1] == then_lit); } else if (not_dst == cond) { // cond ? then_lit : !cond // cond & then_lit | !cond & !cond @@ -2031,7 +2033,7 @@ static void rewrite_ite_gate (closure *closure, gate *g, unsigned dst, // then_lit | !cond // !(!then_lit & cond) g->lhs = not_lhs; - assert (rhs[0] == cond); + KISSAT_assert (rhs[0] == cond); rhs[1] = not_then_lit; } else if (dst == then_lit) { // cond ? then_lit : then_lit @@ -2047,8 +2049,8 @@ static void rewrite_ite_gate (closure *closure, gate *g, unsigned dst, // !(cond ^ then_lit) new_tag = XOR_GATE; g->lhs = not_lhs; - assert (rhs[0] == cond); - assert (rhs[1] == then_lit); + KISSAT_assert (rhs[0] == cond); + KISSAT_assert (rhs[1] == then_lit); } else { shrink = false; rhs[2] = dst; @@ -2071,13 +2073,13 @@ static void rewrite_ite_gate (closure *closure, gate *g, unsigned dst, if (negate_lhs) g->lhs = NOT (g->lhs); } - assert (!g->shrunken); + KISSAT_assert (!g->shrunken); g->shrunken = true; rhs[2] = INVALID_LIT; g->arity = 2; g->tag = new_tag; - assert (rhs[0] < rhs[1]); - assert (rhs[0] != NOT (rhs[1])); + KISSAT_assert (rhs[0] < rhs[1]); + KISSAT_assert (rhs[0] != NOT (rhs[1])); LOGATE (g, "rewritten"); gate *h; unsigned hash; @@ -2085,7 +2087,7 @@ static void rewrite_ite_gate (closure *closure, gate *g, unsigned dst, check_and_gate_implied (closure, g); h = find_and_gate (closure, &hash, g); } else { - assert (new_tag == XOR_GATE); + KISSAT_assert (new_tag == XOR_GATE); check_xor_gate_implied (closure, g); h = find_xor_gate (closure, &hash, g); } @@ -2104,7 +2106,7 @@ static void rewrite_ite_gate (closure *closure, gate *g, unsigned dst, remove_gate (closure, g); g->hash = hash; index_gate (closure, g); - assert (g->arity == 2); + KISSAT_assert (g->arity == 2); for (all_rhs_literals_in_gate (lit, g)) if (lit != dst) if (lit != cond && lit != then_lit && lit != else_lit) @@ -2115,18 +2117,18 @@ static void rewrite_ite_gate (closure *closure, gate *g, unsigned dst, } } else { CLOGITEGATE (g, "rewritten"); - assert (rhs[0] != rhs[1]); - assert (rhs[0] != rhs[2]); - assert (rhs[1] != rhs[2]); - assert (rhs[0] != NOT (rhs[1])); - assert (rhs[0] != NOT (rhs[2])); - assert (rhs[1] != NOT (rhs[2])); + KISSAT_assert (rhs[0] != rhs[1]); + KISSAT_assert (rhs[0] != rhs[2]); + KISSAT_assert (rhs[1] != rhs[2]); + KISSAT_assert (rhs[0] != NOT (rhs[1])); + KISSAT_assert (rhs[0] != NOT (rhs[2])); + KISSAT_assert (rhs[1] != NOT (rhs[2])); check_ite_gate_implied (closure, g); unsigned hash; bool negate_lhs; gate *h = find_ite_gate (closure, &hash, &negate_lhs, g); - assert (lhs == g->lhs); - assert (not_lhs == NOT (g->lhs)); + KISSAT_assert (lhs == g->lhs); + KISSAT_assert (not_lhs == NOT (g->lhs)); if (h) { garbage = true; unsigned normalized_lhs = negate_lhs ? not_lhs : lhs; @@ -2143,7 +2145,7 @@ static void rewrite_ite_gate (closure *closure, gate *g, unsigned dst, CLOGITEGATE (g, "normalized"); g->hash = hash; index_gate (closure, g); - assert (g->arity == 3); + KISSAT_assert (g->arity == 3); for (all_rhs_literals_in_gate (lit, g)) if (lit != dst) if (lit != cond && lit != then_lit && lit != else_lit) @@ -2190,7 +2192,7 @@ typedef struct offsetsize offsetsize; static bool find_binary (kissat *solver, litpair *binaries, offsetsize *offsetsize, unsigned lit, unsigned other) { - assert (lit != other); + KISSAT_assert (lit != other); if (lit > other) SWAP (unsigned, lit, other); size_t l = offsetsize[lit].offset; @@ -2203,8 +2205,8 @@ static bool find_binary (kissat *solver, litpair *binaries, else if (tmp > other) r = m; else { - assert (binaries[m].lits[0] == lit); - assert (binaries[m].lits[1] == other); + KISSAT_assert (binaries[m].lits[0] == lit); + KISSAT_assert (binaries[m].lits[1] == other); #ifdef LOGGING LOGBINARY (lit, other, "found"); #else @@ -2230,7 +2232,7 @@ static void extract_binaries (closure *closure) { START (extractbinaries); litpair *binaries = BEGIN_STACK (closure->binaries); offsetsize *offsetsize; - CALLOC (offsetsize, LITS); + CALLOC (struct offsetsize, offsetsize, LITS); { litpair *end = END_STACK (closure->binaries); litpair *p = binaries; @@ -2240,7 +2242,7 @@ static void extract_binaries (closure *closure) { while (q != end && q->lits[0] == lit) q++; const size_t size = q - p; - assert (size), assert (size <= UINT_MAX); + KISSAT_assert (size), KISSAT_assert (size <= UINT_MAX); const size_t offset = p - binaries; if (size < 32) SORT (litpair, size, p, LESS_OTHER); @@ -2301,9 +2303,9 @@ static void extract_binaries (closure *closure) { { litpair *end = END_STACK (closure->binaries); litpair *added = binaries + before; -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG const size_t after = end - binaries; - assert (after - before == extracted); + KISSAT_assert (after - before == extracted); #endif RADIX_SORT (litpair, uint64_t, extracted, added, rank_litpair); litpair *q = added; @@ -2338,7 +2340,7 @@ static void extract_binaries (closure *closure) { static gate *find_first_and_gate (closure *closure, unsigned lhs, unsigneds *lits) { kissat *const solver = closure->solver; - assert (!solver->watching); + KISSAT_assert (!solver->watching); mark *const marks = solver->marks; const unsigned not_lhs = NOT (lhs); @@ -2347,11 +2349,11 @@ static gate *find_first_and_gate (closure *closure, unsigned lhs, closure->negbincount[lhs]); unsigneds *const marked = &solver->analyzed; - assert (EMPTY_STACK (*marked)); + KISSAT_assert (EMPTY_STACK (*marked)); const unsigned arity = SIZE_STACK (*lits) - 1; unsigned matched = 0; - assert (1 < arity); + KISSAT_assert (1 < arity); watches *watches = &WATCHES (not_lhs); const watch *const end = END_WATCHES (*watches); @@ -2359,12 +2361,12 @@ static gate *find_first_and_gate (closure *closure, unsigned lhs, while (p != end) { const watch watch = *p++; - assert (watch.type.binary); + KISSAT_assert (watch.type.binary); const unsigned other = watch.binary.lit; const mark tmp = marks[other]; if (tmp) { matched++; - assert (~(tmp & 2)); + KISSAT_assert (~(tmp & 2)); marks[other] |= 2; PUSH_STACK (*marked, other); } @@ -2380,13 +2382,13 @@ static gate *find_first_and_gate (closure *closure, unsigned lhs, static gate *find_remaining_and_gate (closure *closure, unsigned lhs, unsigneds *lits) { kissat *const solver = closure->solver; - assert (!solver->watching); + KISSAT_assert (!solver->watching); mark *const marks = solver->marks; const unsigned not_lhs = NOT (lhs); if (marks[not_lhs] < 2) { LOG ("skipping no-candidate LHS %s", LOGLIT (lhs)); - return false; + return NULL; } LOG ("trying to find AND gate with remaining LHS %s", LOGLIT (lhs)); @@ -2395,7 +2397,7 @@ static gate *find_remaining_and_gate (closure *closure, unsigned lhs, const unsigned arity = SIZE_STACK (*lits) - 1; unsigned matched = 0; - assert (1 < arity); + KISSAT_assert (1 < arity); { watches *watches = &WATCHES (not_lhs); @@ -2403,7 +2405,7 @@ static gate *find_remaining_and_gate (closure *closure, unsigned lhs, const watch *p = BEGIN_WATCHES (*watches); while (p != end_watches) { const watch watch = *p++; - assert (watch.type.binary); + KISSAT_assert (watch.type.binary); const unsigned other = watch.binary.lit; mark mark = marks[other]; if (!mark) @@ -2411,19 +2413,19 @@ static gate *find_remaining_and_gate (closure *closure, unsigned lhs, matched++; if (!(mark & 2)) continue; - assert (!(mark & 4)); + KISSAT_assert (!(mark & 4)); marks[other] = mark | 4; } } { unsigneds *const marked = &solver->analyzed; - assert (!EMPTY_STACK (*marked)); + KISSAT_assert (!EMPTY_STACK (*marked)); unsigned *const begin_marked = BEGIN_STACK (*marked); const unsigned *const end_marked = END_STACK (*marked); unsigned *q = begin_marked; const unsigned *p = q; - assert (marks[not_lhs] == 3); + KISSAT_assert (marks[not_lhs] == 3); while (p != end_marked) { const unsigned lit = *p++; if (lit == not_lhs) { @@ -2431,7 +2433,7 @@ static gate *find_remaining_and_gate (closure *closure, unsigned lhs, continue; } mark mark = marks[lit]; - assert ((mark & 3) == 3); + KISSAT_assert ((mark & 3) == 3); if (mark & 4) { mark = 3; *q++ = lit; @@ -2442,8 +2444,8 @@ static gate *find_remaining_and_gate (closure *closure, unsigned lhs, } marks[lit] = mark; } - assert (q != end_marked); - assert (marks[not_lhs] == 1); + KISSAT_assert (q != end_marked); + KISSAT_assert (marks[not_lhs] == 1); SET_END_OF_STACK (*marked, q); LOG ("after filtering %zu LHS candidates remain", SIZE_STACK (*marked)); } @@ -2485,7 +2487,7 @@ static unsigned hash_binary (closure *closure, binary_clause *binary) { static bool indexed_binary (closure *closure, unsigned lit, unsigned other) { - assert (lit != other); + KISSAT_assert (lit != other); #ifdef LOGGING kissat *const solver = closure->solver; #endif @@ -2494,7 +2496,7 @@ static bool indexed_binary (closure *closure, unsigned lit, LOG ("did not find binary %s %s", LOGLIT (lit), LOGLIT (other)); return false; } - assert (bintab->size); + KISSAT_assert (bintab->size); SWAP (unsigned, lit, other); if (lit > other) SWAP (unsigned, lit, other); @@ -2508,7 +2510,7 @@ static bool indexed_binary (closure *closure, unsigned lit, while ((lit1 = table[pos].lits[1])) { if (lit1 == other) { lit0 = table[pos].lits[0]; - assert (lit0 < other); + KISSAT_assert (lit0 < other); if (lit0 == lit) { LOG ("found binary %s %s", LOGLIT (lit), LOGLIT (other)); return true; @@ -2525,9 +2527,9 @@ static bool indexed_binary (closure *closure, unsigned lit, static void extract_and_gates_with_base_clause (closure *closure, clause *c) { - assert (!c->garbage); + KISSAT_assert (!c->garbage); kissat *const solver = closure->solver; - assert (!solver->inconsistent); + KISSAT_assert (!solver->inconsistent); value *values = solver->values; unsigned arity_limit = MIN (GET_OPTION (congruenceandarity), MAX_ARITY); const unsigned size_limit = arity_limit + 1; @@ -2540,7 +2542,7 @@ static void extract_and_gates_with_base_clause (closure *closure, if (value < 0) continue; if (value > 0) { - assert (!solver->level); + KISSAT_assert (!solver->level); LOGCLS (c, "found satisfied %s in", LOGLIT (lit)); kissat_mark_clause_as_garbage (solver, c); return; @@ -2580,7 +2582,7 @@ static void extract_and_gates_with_base_clause (closure *closure, #ifndef INDEX_BINARY_CLAUSES mark *const marks = solver->marks; unsigneds *marked = &solver->analyzed; - assert (EMPTY_STACK (*marked)); + KISSAT_assert (EMPTY_STACK (*marked)); #endif for (unsigned *p = begin_lits; p != end_lits; p++) { const unsigned lit = *p, count = negbincount[lit]; @@ -2595,9 +2597,9 @@ static void extract_and_gates_with_base_clause (closure *closure, reduced_lits++; } } - assert (reduced_lits < end_lits); + KISSAT_assert (reduced_lits < end_lits); const size_t reduced_size = end_lits - reduced_lits; - assert (reduced_size); + KISSAT_assert (reduced_size); LOGCLS (c, "trying as base arity %u AND gate", arity); sort_lits_by_negbincount (closure, reduced_size, reduced_lits); #ifdef LOGGING @@ -2624,7 +2626,7 @@ static void extract_and_gates_with_base_clause (closure *closure, const unsigned lhs = *p; LOG ("trying LHS candidate literal %s with %u negated occurrences", LOGLIT (lhs), negbincount[lhs]); - assert (arity <= negbincount[lhs]); + KISSAT_assert (arity <= negbincount[lhs]); #ifdef INDEX_BINARY_CLAUSES const unsigned not_lhs = NOT (lhs); for (const unsigned *q = begin_lits; q != end_lits; q++) @@ -2641,7 +2643,7 @@ static void extract_and_gates_with_base_clause (closure *closure, #else if (first) { first = false; - assert (EMPTY_STACK (*marked)); + KISSAT_assert (EMPTY_STACK (*marked)); if (find_first_and_gate (closure, lhs, lits)) { #ifdef LOGGING extracted++; @@ -2680,7 +2682,7 @@ static clause *find_indexed_large_clause (closure *closure, unsigneds *lits) { kissat *const solver = closure->solver; size_t size_lits = SIZE_STACK (*lits); - assert (size_lits > 2); + KISSAT_assert (size_lits > 2); #ifdef LOGGING { unsigned *begin = BEGIN_STACK (*lits); @@ -2695,13 +2697,13 @@ static clause *find_indexed_large_clause (closure *closure, const value *const values = solver->values; mark *const marks = solver->marks; unsigneds *sorted = &solver->clause; - assert (EMPTY_STACK (*sorted)); + KISSAT_assert (EMPTY_STACK (*sorted)); for (all_stack (unsigned, lit, *lits)) { - assert (!values[lit]); + KISSAT_assert (!values[lit]); PUSH_STACK (*sorted, lit); marks[lit] = 1; } - assert (size_lits == SIZE_STACK (*sorted)); + KISSAT_assert (size_lits == SIZE_STACK (*sorted)); unsigned *begin_sorted = BEGIN_STACK (*sorted); sort_lits (solver, size_lits, begin_sorted); const unsigned hash = hash_lits (closure, 0, size_lits, begin_sorted); @@ -2714,7 +2716,7 @@ static clause *find_indexed_large_clause (closure *closure, if (hash_ref->hash == hash) { reference ref = hash_ref->ref; if (ref == INVALID_REF) { - assert (!hash); + KISSAT_assert (!hash); ref = 0; } clause *c = kissat_dereference_clause (solver, ref); @@ -2744,33 +2746,33 @@ static clause *find_indexed_large_clause (closure *closure, static clause *find_large_xor_side_clause (closure *closure, unsigneds *lits) { kissat *const solver = closure->solver; - assert (!solver->watching); + KISSAT_assert (!solver->watching); const unsigned *const largecount = closure->largecount; unsigned least_occurring_literal = INVALID_LIT; unsigned count_least_occurring = UINT_MAX; mark *marks = solver->marks; const size_t size_lits = SIZE_STACK (*lits); -#if defined(LOGGING) || !defined(NDEBUG) +#if defined(LOGGING) || !defined(KISSAT_NDEBUG) const unsigned arity = size_lits - 1; #endif -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG const unsigned count_limit = 1u << (arity - 1); #endif const value *const values = solver->values; LOGCOUNTEDLITS (size_lits, BEGIN_STACK (*lits), largecount, "trying to find arity %u XOR side clause", arity); for (all_stack (unsigned, lit, *lits)) { - assert (!values[lit]); + KISSAT_assert (!values[lit]); marks[lit] = 1; unsigned count = largecount[lit]; - assert (count_limit <= count); + KISSAT_assert (count_limit <= count); if (count >= count_least_occurring) continue; count_least_occurring = count; least_occurring_literal = lit; } clause *res = 0; - assert (least_occurring_literal != INVALID_LIT); + KISSAT_assert (least_occurring_literal != INVALID_LIT); LOG ("searching XOR side clause watched by %s#%u", LOGLIT (least_occurring_literal), count_least_occurring); watches *const watches = &WATCHES (least_occurring_literal); @@ -2794,7 +2796,7 @@ static clause *find_large_xor_side_clause (closure *closure, if (value > 0) { LOGCLS (c, "found satisfied %s in", LOGLIT (other)); kissat_mark_clause_as_garbage (solver, c); - assert (c->garbage); + KISSAT_assert (c->garbage); break; } if (marks[other]) @@ -2822,9 +2824,9 @@ static clause *find_large_xor_side_clause (closure *closure, static void extract_xor_gates_with_base_clause (closure *closure, clause *c) { - assert (!c->garbage); + KISSAT_assert (!c->garbage); kissat *const solver = closure->solver; - assert (!solver->inconsistent); + KISSAT_assert (!solver->inconsistent); const value *const values = solver->values; unsigned smallest = INVALID_LIT, largest = INVALID_LIT; const unsigned arity_limit = @@ -2852,8 +2854,8 @@ static void extract_xor_gates_with_base_clause (closure *closure, largest = smallest = lit; first = false; } else { - assert (smallest != INVALID_LIT); - assert (largest != INVALID_LIT); + KISSAT_assert (smallest != INVALID_LIT); + KISSAT_assert (largest != INVALID_LIT); if (lit < smallest) smallest = lit; if (lit > largest) { @@ -2877,7 +2879,7 @@ static void extract_xor_gates_with_base_clause (closure *closure, PUSH_STACK (*lits, lit); size++; } - assert (size == SIZE_STACK (*lits)); + KISSAT_assert (size == SIZE_STACK (*lits)); if (size < 3) { LOGCLS (c, "short XOR base clause"); return; @@ -2897,11 +2899,11 @@ static void extract_xor_gates_with_base_clause (closure *closure, return; } LOGCLS (c, "trying arity %u XOR base", arity); - assert (smallest != INVALID_LIT); - assert (largest != INVALID_LIT); + KISSAT_assert (smallest != INVALID_LIT); + KISSAT_assert (largest != INVALID_LIT); const unsigned end = 1u << arity; - assert (negated == parity_lits (solver, lits)); -#if !defined(NDEBUG) || defined(LOGGING) + KISSAT_assert (negated == parity_lits (solver, lits)); +#if !defined(KISSAT_NDEBUG) || defined(LOGGING) unsigned found = 0; #endif for (unsigned i = 0; i != end; i++) { @@ -2915,11 +2917,11 @@ static void extract_xor_gates_with_base_clause (closure *closure, #endif if (!d) return; - assert (!d->redundant); + KISSAT_assert (!d->redundant); } else - assert (!c->redundant); + KISSAT_assert (!c->redundant); inc_lits (solver, lits); -#if !defined(NDEBUG) || defined(LOGGING) +#if !defined(KISSAT_NDEBUG) || defined(LOGGING) found++; #endif } @@ -2927,7 +2929,7 @@ static void extract_xor_gates_with_base_clause (closure *closure, inc_lits (solver, lits); LOGUNSIGNEDS2 (size, BEGIN_STACK (*lits), "back to original"); LOG ("found all needed %u matching clauses:", found); - assert (found == 1u << arity); + KISSAT_assert (found == 1u << arity); if (negated) { unsigned *p = BEGIN_STACK (*lits), lit; while (!NEGATED (lit = *p)) @@ -2958,9 +2960,9 @@ static void init_bintab (closure *closure) { size_t size2 = 1; while (size > size2) size2 *= 2; - assert (!limit || size2 <= 2 * size); + KISSAT_assert (!limit || size2 <= 2 * size); binary_hash_table *bintab = &closure->bintab; - CALLOC (bintab->table, size); + CALLOC (binary_hash_table, bintab->table, size); bintab->count = 0; bintab->size = size; bintab->size2 = size2; @@ -2968,7 +2970,7 @@ static void init_bintab (closure *closure) { solver, "allocated binary clause hash table of size %zu", size); } -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG static bool binaries_hash_table_is_full (binary_hash_table *bintab) { if (bintab->size == MAX_HASH_TABLE_SIZE) @@ -2981,9 +2983,9 @@ static bool binaries_hash_table_is_full (binary_hash_table *bintab) { #endif static void index_binary (closure *closure, unsigned lit, unsigned other) { - assert (lit < other); + KISSAT_assert (lit < other); binary_hash_table *bintab = &closure->bintab; - assert (!binaries_hash_table_is_full (bintab)); + KISSAT_assert (!binaries_hash_table_is_full (bintab)); binary_clause binary = {.lits = {lit, other}}; const unsigned hash = hash_binary (closure, &binary); const size_t size = bintab->size; @@ -3011,9 +3013,9 @@ static void reset_bintab (closure *closure) { static void init_and_gate_extraction (closure *closure) { kissat *const solver = closure->solver; - assert (!solver->watching); + KISSAT_assert (!solver->watching); unsigned *negbincount; - CALLOC (negbincount, LITS); + CALLOC (unsigned, negbincount, LITS); litpairs *binaries = &closure->binaries; #ifdef INDEX_BINARY_CLAUSES init_bintab (closure); @@ -3027,7 +3029,7 @@ static void init_and_gate_extraction (closure *closure) { index_binary (closure, lit, other); #endif } -#ifndef QUIET +#ifndef KISSAT_QUIET size_t connected = SIZE_STACK (*binaries); kissat_very_verbose (solver, "connected %zu binary clauses", connected); #endif @@ -3051,9 +3053,9 @@ static void init_large_clauses (closure *closure, size_t expected) { size_t size2 = 1; while (size > size2) size2 *= 2; - assert (!expected || size2 <= 2 * size); + KISSAT_assert (!expected || size2 <= 2 * size); large_clause_hash_table *clauses = &closure->clauses; - CALLOC (clauses->table, size); + CALLOC (large_clause_hash_table, clauses->table, size); clauses->count = 0; clauses->size = size; clauses->size2 = size2; @@ -3061,7 +3063,7 @@ static void init_large_clauses (closure *closure, size_t expected) { solver, "allocated large clause hash table of size %zu", size); } -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG static bool large_clause_hash_table_is_full (closure *closure) { if (closure->clauses.size == MAX_HASH_TABLE_SIZE) @@ -3074,7 +3076,7 @@ static bool large_clause_hash_table_is_full (closure *closure) { #endif static void index_large_clause (closure *closure, reference ref) { - assert (!large_clause_hash_table_is_full (closure)); + KISSAT_assert (!large_clause_hash_table_is_full (closure)); kissat *const solver = closure->solver; clause *c = kissat_dereference_clause (solver, ref); const value *const values = solver->values; @@ -3085,13 +3087,13 @@ static void index_large_clause (closure *closure, reference ref) { PUSH_STACK (*lits, lit); const size_t size_lits = SIZE_STACK (*lits); unsigned *begin_lits = BEGIN_STACK (*lits); - assert (3 <= size_lits); + KISSAT_assert (3 <= size_lits); sort_lits (solver, size_lits, begin_lits); const unsigned hash = hash_lits (closure, 0, size_lits, begin_lits); large_clause_hash_table *clauses = &closure->clauses; if (!hash && !ref) { ref = INVALID_REF; - assert (ref); + KISSAT_assert (ref); } const size_t hash_size = clauses->size; const size_t hash_size2 = clauses->size2; @@ -3102,7 +3104,7 @@ static void index_large_clause (closure *closure, reference ref) { pos = 0; clause->hash = hash; clause->ref = ref; - assert (valid_large_clause (clause)); + KISSAT_assert (valid_large_clause (clause)); clauses->count++; LOGCLS (c, "indexed"); } @@ -3117,15 +3119,15 @@ static void reset_large_clauses (closure *closure) { static void init_xor_gate_extraction (closure *closure, references *candidates) { - assert (EMPTY_STACK (*candidates)); + KISSAT_assert (EMPTY_STACK (*candidates)); kissat *const solver = closure->solver; - assert (!solver->watching); + KISSAT_assert (!solver->watching); const unsigned arity_limit = GET_OPTION (congruencexorarity); const unsigned size_limit = arity_limit + 1; clause *last_irredundant = kissat_last_irredundant_clause (solver); const value *const values = solver->values; unsigned *largecount; - CALLOC (largecount, LITS); + CALLOC (unsigned, largecount, LITS); for (all_clauses (c)) { if (c->garbage) continue; @@ -3134,6 +3136,7 @@ static void init_xor_gate_extraction (closure *closure, if (c->redundant) continue; unsigned size = 0; + int continue_counting_next_clause = 0; for (all_literals_in_clause (lit, c)) { const value value = values[lit]; if (value < 0) @@ -3141,12 +3144,18 @@ static void init_xor_gate_extraction (closure *closure, if (value > 0) { LOGCLS (c, "satisfied %s in", LOGLIT (lit)); kissat_mark_clause_as_garbage (solver, c); - goto CONTINUE_COUNTING_NEXT_CLAUSE; + continue_counting_next_clause = 1; + break; + } + if (size == size_limit) { + continue_counting_next_clause = 1; + break; } - if (size == size_limit) - goto CONTINUE_COUNTING_NEXT_CLAUSE; size++; } + if(continue_counting_next_clause) { + continue; + } if (size < 3) continue; for (all_literals_in_clause (lit, c)) @@ -3154,9 +3163,8 @@ static void init_xor_gate_extraction (closure *closure, largecount[lit]++; reference ref = kissat_reference_clause (solver, c); PUSH_STACK (*candidates, ref); - CONTINUE_COUNTING_NEXT_CLAUSE:; } -#ifndef QUIET +#ifndef KISSAT_QUIET size_t considered_clauses = IRREDUNDANT_CLAUSES; size_t original_candidates = SIZE_STACK (*candidates); kissat_very_verbose ( @@ -3171,7 +3179,7 @@ static void init_xor_gate_extraction (closure *closure, for (unsigned round = 1; round <= counting_rounds; round++) { size_t removed = 0; unsigned *new_largecount; - CALLOC (new_largecount, LITS); + CALLOC (unsigned, new_largecount, LITS); const reference *const end_candidates = END_STACK (*candidates); reference *q = BEGIN_STACK (*candidates), *p = q; while (p != end_candidates) { @@ -3181,8 +3189,8 @@ static void init_xor_gate_extraction (closure *closure, for (all_literals_in_clause (lit, c)) if (!values[lit]) size++; - assert (3 <= size); - assert (size <= size_limit); + KISSAT_assert (3 <= size); + KISSAT_assert (size <= size_limit); const unsigned arity = size - 1; const unsigned needed_clauses = 1u << (arity - 1); for (all_literals_in_clause (lit, c)) @@ -3201,7 +3209,7 @@ static void init_xor_gate_extraction (closure *closure, SET_END_OF_STACK (*candidates, q); if (!removed) break; -#ifndef QUIET +#ifndef KISSAT_QUIET size_t remaining_candidates = SIZE_STACK (*candidates); const char *how_often; char buffer[64]; @@ -3233,7 +3241,7 @@ static void init_xor_gate_extraction (closure *closure, index_large_clause (closure, ref); #endif } -#ifndef QUIET +#ifndef KISSAT_QUIET size_t connected = SIZE_STACK (*candidates); kissat_very_verbose (solver, "connected %zu large clauses %.0f%%", connected, @@ -3252,12 +3260,12 @@ static void reset_xor_gate_extraction (closure *closure) { static void init_ite_gate_extraction (closure *closure, references *candidates) { - assert (EMPTY_STACK (*candidates)); + KISSAT_assert (EMPTY_STACK (*candidates)); kissat *const solver = closure->solver; clause *last_irredundant = kissat_last_irredundant_clause (solver); const value *const values = solver->values; unsigned *largecount; - CALLOC (largecount, LITS); + CALLOC (unsigned, largecount, LITS); references ternary; INIT_STACK (ternary); for (all_clauses (c)) { @@ -3268,6 +3276,7 @@ static void init_ite_gate_extraction (closure *closure, if (c->redundant) continue; unsigned size = 0; + int continue_counting_next_clause = 0; for (all_literals_in_clause (lit, c)) { const value value = values[lit]; if (value < 0) @@ -3275,24 +3284,29 @@ static void init_ite_gate_extraction (closure *closure, if (value > 0) { LOGCLS (c, "satisfied %s in", LOGLIT (lit)); kissat_mark_clause_as_garbage (solver, c); - goto CONTINUE_COUNTING_NEXT_CLAUSE; + continue_counting_next_clause = 1; + break; + } + if (size == 3) { + continue_counting_next_clause = 1; + break; } - if (size == 3) - goto CONTINUE_COUNTING_NEXT_CLAUSE; size++; } + if(continue_counting_next_clause) { + continue; + } if (size < 3) continue; - assert (size == 3); + KISSAT_assert (size == 3); const reference ref = kissat_reference_clause (solver, c); PUSH_STACK (ternary, ref); LOGCLS (c, "counting original ITE gate base"); for (all_literals_in_clause (lit, c)) if (!values[lit]) largecount[lit]++; - CONTINUE_COUNTING_NEXT_CLAUSE:; } -#ifndef QUIET +#ifndef KISSAT_QUIET size_t counted = SIZE_STACK (ternary); kissat_very_verbose (solver, "counted %zu ternary ITE clauses " @@ -3304,7 +3318,7 @@ static void init_ite_gate_extraction (closure *closure, #endif for (all_stack (reference, ref, ternary)) { clause *c = kissat_dereference_clause (solver, ref); - assert (!c->garbage); + KISSAT_assert (!c->garbage); unsigned positive = 0, negative = 0, twice = 0; for (all_literals_in_clause (lit, c)) { if (values[lit]) @@ -3314,7 +3328,7 @@ static void init_ite_gate_extraction (closure *closure, if (!count_not_lit) goto CONTINUE_WITH_NEXT_TERNARY_CLAUSE; const unsigned count_lit = largecount[lit]; - assert (count_lit); + KISSAT_assert (count_lit); if (count_lit > 1 && count_not_lit > 1) twice++; if (NEGATED (lit)) @@ -3324,7 +3338,7 @@ static void init_ite_gate_extraction (closure *closure, } if (twice < 2) goto CONTINUE_WITH_NEXT_TERNARY_CLAUSE; -#ifndef QUIET +#ifndef KISSAT_QUIET connected++; #endif kissat_connect_clause (solver, c); @@ -3333,7 +3347,7 @@ static void init_ite_gate_extraction (closure *closure, CONTINUE_WITH_NEXT_TERNARY_CLAUSE:; } RELEASE_STACK (ternary); -#ifndef QUIET +#ifndef KISSAT_QUIET kissat_very_verbose (solver, "connected %zu ITE clauses " "(%.0f%% of %" PRIu64 " counted clauses)", @@ -3375,7 +3389,7 @@ static void unmark_all (unsigneds *marked, signed char *marks) { static void copy_conditional_equivalences (kissat *solver, unsigned lit, watches *watches, litpairs *condbin) { - assert (EMPTY_STACK (*condbin)); + KISSAT_assert (EMPTY_STACK (*condbin)); const value *const values = solver->values; const watch *const begin_watches = BEGIN_WATCHES (*watches); const watch *const end_watches = END_WATCHES (*watches); @@ -3394,17 +3408,17 @@ static void copy_conditional_equivalences (kissat *solver, unsigned lit, if (first == INVALID_LIT) first = other; else { - assert (second == INVALID_LIT); + KISSAT_assert (second == INVALID_LIT); second = other; } } - assert (first != INVALID_LIT); - assert (second != INVALID_LIT); + KISSAT_assert (first != INVALID_LIT); + KISSAT_assert (second != INVALID_LIT); litpair pair; if (first < second) pair = (litpair){.lits = {first, second}}; else { - assert (second < first); + KISSAT_assert (second < first); pair = (litpair){.lits = {second, first}}; } LOG ("literal %s conditional binary clause %s %s", LOGLIT (lit), @@ -3439,7 +3453,7 @@ static bool find_litpair_second_literal (unsigned lit, const litpair *begin, const litpair *l = begin, *r = end; while (l != r) { const litpair *m = l + (r - l) / 2; - assert (begin <= m), assert (m < end); + KISSAT_assert (begin <= m), KISSAT_assert (m < end); unsigned other = m->lits[1]; if (other < lit) l = m + 1; @@ -3456,12 +3470,12 @@ static void search_condeq (closure *closure, unsigned lit, unsigned pos_lit, unsigned neg_lit, const litpair *neg_begin, const litpair *neg_end, litpairs *condeq) { kissat *const solver = closure->solver; - assert (neg_lit == NOT (pos_lit)); - assert (pos_begin < pos_end); - assert (neg_begin < neg_end); - assert (pos_begin->lits[0] == pos_lit); - assert (neg_begin->lits[0] == neg_lit); - assert (pos_end <= neg_begin || neg_end <= pos_begin); + KISSAT_assert (neg_lit == NOT (pos_lit)); + KISSAT_assert (pos_begin < pos_end); + KISSAT_assert (neg_begin < neg_end); + KISSAT_assert (pos_begin->lits[0] == pos_lit); + KISSAT_assert (neg_begin->lits[0] == neg_lit); + KISSAT_assert (pos_end <= neg_begin || neg_end <= pos_begin); for (const litpair *p = pos_begin; p != pos_end; p++) { const unsigned other = p->lits[1]; const unsigned not_other = NOT (other); @@ -3473,8 +3487,8 @@ static void search_condeq (closure *closure, unsigned lit, unsigned pos_lit, first = pos_lit, second = not_other; LOG ("found conditional %s equivalence %s = %s", LOGLIT (lit), LOGLIT (first), LOGLIT (second)); - assert (!NEGATED (first)); - assert (first < second); + KISSAT_assert (!NEGATED (first)); + KISSAT_assert (first < second); check_ternary (closure, lit, first, NOT (second)); check_ternary (closure, lit, NOT (first), second); litpair equivalence = {.lits = {first, second}}; @@ -3495,7 +3509,7 @@ static void search_condeq (closure *closure, unsigned lit, unsigned pos_lit, static void extract_condeq_pairs (closure *closure, unsigned lit, litpairs *condbin, litpairs *condeq) { -#if defined(LOGGING) || !defined(NDEBUG) +#if defined(LOGGING) || !defined(KISSAT_NDEBUG) kissat *const solver = closure->solver; #endif const litpair *const begin = BEGIN_STACK (*condbin); @@ -3511,9 +3525,9 @@ static void extract_condeq_pairs (closure *closure, unsigned lit, pos_begin++; } for (;;) { - assert (pos_begin != end); - assert (next_lit == pos_begin->lits[0]); - assert (!NEGATED (next_lit)); + KISSAT_assert (pos_begin != end); + KISSAT_assert (next_lit == pos_begin->lits[0]); + KISSAT_assert (!NEGATED (next_lit)); const unsigned pos_lit = next_lit; const litpair *pos_end = pos_begin + 1; for (;;) { @@ -3524,8 +3538,8 @@ static void extract_condeq_pairs (closure *closure, unsigned lit, break; pos_end++; } - assert (pos_end != end); - assert (next_lit == pos_end->lits[0]); + KISSAT_assert (pos_end != end); + KISSAT_assert (next_lit == pos_end->lits[0]); const unsigned neg_lit = NOT (pos_lit); if (next_lit != neg_lit) { if (NEGATED (next_lit)) { @@ -3579,7 +3593,7 @@ static void extract_condeq_pairs (closure *closure, unsigned lit, } if (neg_end == end) return; - assert (next_lit == neg_end->lits[0]); + KISSAT_assert (next_lit == neg_end->lits[0]); if (NEGATED (next_lit)) { pos_begin = neg_end + 1; for (;;) { @@ -3599,9 +3613,9 @@ static void find_conditional_equivalences (closure *closure, unsigned lit, watches *watches, litpairs *condbin, litpairs *condeq) { - assert (EMPTY_STACK (*condbin)); - assert (EMPTY_STACK (*condeq)); - assert (SIZE_WATCHES (*watches) > 1); + KISSAT_assert (EMPTY_STACK (*condbin)); + KISSAT_assert (EMPTY_STACK (*condeq)); + KISSAT_assert (SIZE_WATCHES (*watches) > 1); kissat *const solver = closure->solver; copy_conditional_equivalences (solver, lit, watches, condbin); sort_pairs (solver, condbin); @@ -3630,7 +3644,7 @@ static void find_conditional_equivalences (closure *closure, unsigned lit, static void merge_condeq (closure *closure, unsigned cond, litpairs *condeq, litpairs *not_condeq) { kissat *solver = closure->solver; - assert (!NEGATED (cond)); + KISSAT_assert (!NEGATED (cond)); const litpair *const begin_condeq = BEGIN_STACK (*condeq); const litpair *const end_condeq = END_STACK (*condeq); const litpair *const begin_not_condeq = BEGIN_STACK (*not_condeq); @@ -3641,7 +3655,7 @@ static void merge_condeq (closure *closure, unsigned cond, litpairs *condeq, litpair cond_pair = *p++; const unsigned lhs = cond_pair.lits[0]; const unsigned then_lit = cond_pair.lits[1]; - assert (!NEGATED (lhs)); + KISSAT_assert (!NEGATED (lhs)); while (q != end_not_condeq && q->lits[0] < lhs) q++; while (q != end_not_condeq && q->lits[0] == lhs) { @@ -3658,7 +3672,7 @@ static void extract_ite_gates_of_literal (closure *closure, unsigned lit, unsigned not_lit, watches *lit_watches, watches *not_lit_watches) { -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG kissat *solver = closure->solver; #endif litpairs *condbin = closure->condbin; @@ -3706,8 +3720,8 @@ static void extract_ite_gates_of_variable (closure *closure, unsigned idx) { static void mark_third_literal_in_ternary_clauses ( kissat *solver, const value *const values, unsigneds *marked, mark *marks, unsigned a, unsigned b) { - assert (!solver->watching); - assert (EMPTY_STACK (*marked)); + KISSAT_assert (!solver->watching); + KISSAT_assert (EMPTY_STACK (*marked)); watches *a_watches = &WATCHES (a); watches *b_watches = &WATCHES (b); const size_t size_a = SIZE_WATCHES (*a_watches); @@ -3717,10 +3731,10 @@ static void mark_third_literal_in_ternary_clauses ( const watch *const end = END_WATCHES (*watches); for (const watch *p = begin; p != end; p++) { const watch watch = *p; - assert (!watch.type.binary); + KISSAT_assert (!watch.type.binary); const reference ref = watch.large.ref; clause *c = kissat_dereference_clause (solver, ref); - assert (!c->garbage); + KISSAT_assert (!c->garbage); unsigned third = INVALID_LIT, found = 0; for (all_literals_in_clause (lit, c)) { if (values[lit]) @@ -3733,10 +3747,10 @@ static void mark_third_literal_in_ternary_clauses ( goto NEXT_WATCH; third = lit; } - assert (found <= 2); + KISSAT_assert (found <= 2); if (found < 2) goto NEXT_WATCH; - assert (third != INVALID_LIT); + KISSAT_assert (third != INVALID_LIT); if (third == INVALID_LIT) goto NEXT_WATCH; if (marks[third]) @@ -3752,7 +3766,7 @@ static void extract_ite_gate (closure *closure, const value *const values, mark *const marks, unsigned lhs, unsigned cond, unsigned then_lit) { kissat *const solver = closure->solver; - assert (!solver->watching); + KISSAT_assert (!solver->watching); unsigned a = NOT (lhs), b = cond; watches *a_watches = &WATCHES (a); watches *b_watches = &WATCHES (b); @@ -3763,10 +3777,10 @@ static void extract_ite_gate (closure *closure, const value *const values, const watch *const end = END_WATCHES (*watches); for (const watch *p = begin; p != end; p++) { const watch watch = *p; - assert (!watch.type.binary); + KISSAT_assert (!watch.type.binary); const reference ref = watch.large.ref; clause *c = kissat_dereference_clause (solver, ref); - assert (!c->garbage); + KISSAT_assert (!c->garbage); unsigned else_lit = INVALID_LIT, found = 0; for (all_literals_in_clause (lit, c)) { if (values[lit]) @@ -3779,10 +3793,10 @@ static void extract_ite_gate (closure *closure, const value *const values, goto NEXT_WATCH; else_lit = lit; } - assert (found <= 2); + KISSAT_assert (found <= 2); if (found < 2) goto NEXT_WATCH; - assert (else_lit != INVALID_LIT); + KISSAT_assert (else_lit != INVALID_LIT); unsigned not_else_lit = NOT (else_lit); if (!marks[not_else_lit]) goto NEXT_WATCH; @@ -3797,9 +3811,9 @@ static void extract_ite_gate (closure *closure, const value *const values, static void extract_ite_gates_with_base_clause (closure *closure, clause *c) { - assert (!c->garbage); + KISSAT_assert (!c->garbage); kissat *const solver = closure->solver; - assert (!solver->inconsistent); + KISSAT_assert (!solver->inconsistent); const value *const values = solver->values; const unsigned *const largecount = closure->largecount; unsigneds *lits = &closure->lits; @@ -3818,7 +3832,7 @@ static void extract_ite_gates_with_base_clause (closure *closure, sum ^= lit; } const size_t size = SIZE_STACK (*lits); - assert (size <= 3); + KISSAT_assert (size <= 3); if (size < 3) return; mark *const marks = solver->marks; @@ -3866,8 +3880,8 @@ static void extract_and_gates (closure *closure) { if (!GET_OPTION (congruenceands)) return; START (extractands); -#ifndef QUIET - const statistics *s = &solver->statistics; +#ifndef KISSAT_QUIET + const statistics *s = &solver->statistics_; const uint64_t matched_before = s->congruent_matched_ands; const uint64_t gates_before = s->congruent_gates_ands; #endif @@ -3887,7 +3901,7 @@ static void extract_and_gates (closure *closure) { extract_and_gates_with_base_clause (closure, c); } reset_and_gate_extraction (closure); -#ifndef QUIET +#ifndef KISSAT_QUIET const uint64_t matched = s->congruent_matched_ands - matched_before; const uint64_t extracted = s->congruent_gates_ands - gates_before; const uint64_t found = matched + extracted; @@ -3909,8 +3923,8 @@ static void extract_xor_gates (closure *closure) { INIT_STACK (candidates); init_xor_gate_extraction (closure, &candidates); SHRINK_STACK (candidates); -#ifndef QUIET - const statistics *s = &solver->statistics; +#ifndef KISSAT_QUIET + const statistics *s = &solver->statistics_; const uint64_t matched_before = s->congruent_matched_xors; const uint64_t gates_before = s->congruent_gates_xors; #endif @@ -3926,7 +3940,7 @@ static void extract_xor_gates (closure *closure) { } reset_xor_gate_extraction (closure); RELEASE_STACK (candidates); -#ifndef QUIET +#ifndef KISSAT_QUIET const uint64_t matched = s->congruent_matched_xors - matched_before; const uint64_t extracted = s->congruent_gates_xors - gates_before; const uint64_t found = matched + extracted; @@ -3947,8 +3961,8 @@ static void extract_ite_gates (closure *closure) { references candidates; INIT_STACK (candidates); init_ite_gate_extraction (closure, &candidates); -#ifndef QUIET - const statistics *s = &solver->statistics; +#ifndef KISSAT_QUIET + const statistics *s = &solver->statistics_; const uint64_t matched_before = s->congruent_matched_ites; const uint64_t gates_before = s->congruent_gates_ites; #endif @@ -3973,7 +3987,7 @@ static void extract_ite_gates (closure *closure) { #endif reset_ite_gate_extraction (closure); RELEASE_STACK (candidates); -#ifndef QUIET +#ifndef KISSAT_QUIET const uint64_t matched = s->congruent_matched_ites - matched_before; const uint64_t extracted = s->congruent_gates_ites - gates_before; const uint64_t found = matched + extracted; @@ -4000,14 +4014,14 @@ static void reset_extraction (closure *closure) { static void extract_gates (closure *closure) { kissat *const solver = closure->solver; START (extract); - assert (!solver->level); -#ifndef QUIET - const statistics *s = &solver->statistics; + KISSAT_assert (!solver->level); +#ifndef KISSAT_QUIET + const statistics *s = &solver->statistics_; const uint64_t before = s->congruent_gates + s->congruent_matched; #endif init_extraction (closure); extract_binaries (closure); - assert (!solver->inconsistent); + KISSAT_assert (!solver->inconsistent); extract_and_gates (closure); if (!solver->inconsistent && !TERMINATED (congruence_terminated_4)) { extract_xor_gates (closure); @@ -4015,7 +4029,7 @@ static void extract_gates (closure *closure) { extract_ite_gates (closure); } reset_extraction (closure); -#ifndef QUIET +#ifndef KISSAT_QUIET const uint64_t after = s->congruent_gates + s->congruent_matched; const uint64_t found = after - before; kissat_phase (solver, "congruence", GET (closures), @@ -4027,9 +4041,9 @@ static void extract_gates (closure *closure) { static void find_units (closure *closure) { kissat *const solver = closure->solver; - assert (solver->watching); - assert (!solver->inconsistent); - assert (kissat_propagated (solver)); + KISSAT_assert (solver->watching); + KISSAT_assert (!solver->inconsistent); + KISSAT_assert (kissat_propagated (solver)); closure->units = solver->propagate; unsigneds *marked = &solver->analyzed; mark *const marks = solver->marks; @@ -4043,7 +4057,7 @@ static void find_units (closure *closure) { watches *const watches = &WATCHES (lit); const watch *p = BEGIN_WATCHES (*watches); const watch *const end = END_WATCHES (*watches); - assert (EMPTY_STACK (*marked)); + KISSAT_assert (EMPTY_STACK (*marked)); while (p != end) { const watch watch = *p++; if (!watch.type.binary) @@ -4070,8 +4084,8 @@ static void find_units (closure *closure) { unmark_all (marked, marks); } } - assert (EMPTY_STACK (*marked)); -#ifndef QUIET + KISSAT_assert (EMPTY_STACK (*marked)); +#ifndef KISSAT_QUIET kissat_very_verbose (solver, "found %zu units", units); #else (void) units; @@ -4080,11 +4094,11 @@ static void find_units (closure *closure) { static void find_equivalences (closure *closure) { kissat *const solver = closure->solver; - assert (solver->watching); - assert (!solver->inconsistent); + KISSAT_assert (solver->watching); + KISSAT_assert (!solver->inconsistent); unsigneds *const marked = &solver->analyzed; mark *const marks = solver->marks; - assert (EMPTY_STACK (*marked)); + KISSAT_assert (EMPTY_STACK (*marked)); for (all_variables (idx)) { RESTART: if (!ACTIVE (idx)) @@ -4093,7 +4107,7 @@ static void find_equivalences (closure *closure) { watches *lit_watches = &WATCHES (lit); const watch *p = BEGIN_WATCHES (*lit_watches); const watch *const end_lit_watches = END_WATCHES (*lit_watches); - assert (EMPTY_STACK (*marked)); + KISSAT_assert (EMPTY_STACK (*marked)); while (p != end_lit_watches) { const watch watch = *p++; if (!watch.type.binary) @@ -4138,8 +4152,8 @@ static void find_equivalences (closure *closure) { } unmark_all (marked, marks); } - assert (EMPTY_STACK (*marked)); -#ifndef QUIET + KISSAT_assert (EMPTY_STACK (*marked)); +#ifndef KISSAT_QUIET size_t found = SIZE_FIFO (closure->schedule); kissat_very_verbose (solver, "found %zu equivalences", found); #endif @@ -4148,7 +4162,7 @@ static void find_equivalences (closure *closure) { static bool simplify_gates (closure *closure, unsigned lit) { kissat *const solver = closure->solver; LOG ("simplifying gates with RHS literal %s", LOGLIT (lit)); - assert (solver->values[lit]); + KISSAT_assert (solver->values[lit]); gates *lit_occurrences = closure->occurrences + lit; for (all_pointers (gate, g, *lit_occurrences)) if (!simplify_gate (closure, g)) @@ -4176,7 +4190,7 @@ static bool propagate_unit (closure *closure, unsigned lit) { kissat *const solver = closure->solver; LOG ("propagation of congruence unit %s", LOGLIT (lit)); (void) solver; - assert (!solver->inconsistent); + KISSAT_assert (!solver->inconsistent); const unsigned not_lit = NOT (lit); return simplify_gates (closure, lit) && simplify_gates (closure, not_lit); } @@ -4184,7 +4198,7 @@ static bool propagate_unit (closure *closure, unsigned lit) { static bool propagate_equivalence (closure *closure, unsigned lit) { kissat *const solver = closure->solver; LOG ("propagation of congruence equivalence %s", CLOGREPR (lit)); - assert (!solver->inconsistent); + KISSAT_assert (!solver->inconsistent); if (VALUE (lit)) return true; const unsigned lit_repr = find_repr (closure, lit); @@ -4198,7 +4212,7 @@ static bool propagate_equivalence (closure *closure, unsigned lit) { static bool propagate_units (closure *closure) { kissat *const solver = closure->solver; - assert (!solver->inconsistent); + KISSAT_assert (!solver->inconsistent); const unsigned_array *const trail = &solver->trail; while (closure->units != trail->end) if (!propagate_unit (closure, *closure->units++)) @@ -4208,7 +4222,7 @@ static bool propagate_units (closure *closure) { static size_t propagate_units_and_equivalences (closure *closure) { kissat *const solver = closure->solver; - assert (!solver->inconsistent); + KISSAT_assert (!solver->inconsistent); START (merge); unsigned_fifo *schedule = &closure->schedule; size_t propagated = 0; @@ -4219,7 +4233,7 @@ static size_t propagate_units_and_equivalences (closure *closure) { if (!propagate_equivalence (closure, lit)) break; } -#ifndef QUIET +#ifndef KISSAT_QUIET const size_t units = closure->units - solver->trail.begin; kissat_very_verbose (solver, "propagated %zu congruence units", units); kissat_very_verbose (solver, "propagated %zu congruence equivalences", @@ -4229,7 +4243,7 @@ static size_t propagate_units_and_equivalences (closure *closure) { return propagated; } -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG static void dump_closure_literal (closure *closure, unsigned ilit) { kissat *const solver = closure->solver; @@ -4241,7 +4255,7 @@ static void dump_closure_literal (closure *closure, unsigned ilit) { printf ("[%u(%d)]", repr_ilit, repr_elit); } const int value = VALUE (ilit); - assert (!solver->level); + KISSAT_assert (!solver->level); if (value) printf ("@0=%d", value); } @@ -4344,7 +4358,7 @@ void kissat_dump_closure (closure *closure) { #endif static bool find_subsuming_clause (closure *closure, clause *c) { - assert (!c->garbage); + KISSAT_assert (!c->garbage); kissat *const solver = closure->solver; const reference c_ref = kissat_reference_clause (solver, c); const value *const values = solver->values; @@ -4353,15 +4367,15 @@ static bool find_subsuming_clause (closure *closure, clause *c) { const unsigned *const end_lits = c->lits + c->size; for (const unsigned *p = c->lits; p != end_lits; p++) { const unsigned lit = *p; - assert (values[lit] <= 0); + KISSAT_assert (values[lit] <= 0); const unsigned repr_lit = find_repr (closure, lit); const value value_repr_lit = values[repr_lit]; - assert (value_repr_lit <= 0); + KISSAT_assert (value_repr_lit <= 0); if (value_repr_lit < 0) continue; if (marks[repr_lit]) continue; - assert (!marks[NOT (repr_lit)]); + KISSAT_assert (!marks[NOT (repr_lit)]); marks[repr_lit] = 1; } } @@ -4375,25 +4389,25 @@ static bool find_subsuming_clause (closure *closure, clause *c) { const watch *p = BEGIN_WATCHES (*watches); const watch *const end = END_WATCHES (*watches); const size_t count = end - p; - assert (count <= UINT_MAX); + KISSAT_assert (count <= UINT_MAX); if (count < count_least_occurring) { count_least_occurring = count; least_occurring_literal = repr_lit; } while (p != end) { const watch watch = *p++; - assert (!watch.type.binary); + KISSAT_assert (!watch.type.binary); const reference d_ref = watch.large.ref; clause *const d = kissat_dereference_clause (solver, d_ref); - assert (c != d); - assert (!d->garbage); + KISSAT_assert (c != d); + KISSAT_assert (!d->garbage); if (!c->redundant && d->redundant) continue; for (all_literals_in_clause (other, d)) { const value value = values[other]; if (value < 0) continue; - assert (!value); + KISSAT_assert (!value); const unsigned repr_other = find_repr (closure, other); if (!marks[repr_other]) goto CONTINUE_WITH_NEXT_CLAUSE; @@ -4417,8 +4431,8 @@ FOUND_SUBSUMING: INC (congruent_subsumed); return true; } else { - assert (least_occurring_literal != INVALID_LIT); - assert (count_least_occurring < UINT_MAX); + KISSAT_assert (least_occurring_literal != INVALID_LIT); + KISSAT_assert (count_least_occurring < UINT_MAX); LOGCLS (c, "forward subsumption failed of"); LOG ("connecting %u occurring %s", count_least_occurring, LOGLIT (least_occurring_literal)); @@ -4450,10 +4464,10 @@ static void forward_subsume_matching_clauses (closure *closure) { INIT_STACK (binaries); kissat_enter_dense_mode (solver, &binaries); bool *matchable; -#ifndef QUIET +#ifndef KISSAT_QUIET unsigned count_matchable = 0; #endif - CALLOC (matchable, VARS); + CALLOC (bool, matchable, VARS); for (all_variables (idx)) if (ACTIVE (idx)) { const unsigned lit = LIT (idx); @@ -4464,14 +4478,14 @@ static void forward_subsume_matching_clauses (closure *closure) { if (!matchable[idx]) { LOG ("matchable %s", LOGVAR (idx)); matchable[idx] = true; -#ifndef QUIET +#ifndef KISSAT_QUIET count_matchable++; #endif } if (!matchable[repr_idx]) { LOG ("matchable %s", LOGVAR (repr_idx)); matchable[repr_idx] = true; -#ifndef QUIET +#ifndef KISSAT_QUIET count_matchable++; #endif } @@ -4493,7 +4507,7 @@ static void forward_subsume_matching_clauses (closure *closure) { break; potential++; bool contains_matchable = false; - assert (EMPTY_STACK (*marked)); + KISSAT_assert (EMPTY_STACK (*marked)); LOGREPRCLS (c, closure->repr, "considering"); for (all_literals_in_clause (lit, c)) { const value value = values[lit]; @@ -4510,7 +4524,7 @@ static void forward_subsume_matching_clauses (closure *closure) { contains_matchable = true; } const unsigned repr = find_repr (closure, lit); - assert (!values[repr]); + KISSAT_assert (!values[repr]); if (marks[repr]) continue; const unsigned not_repr = NOT (repr); @@ -4534,12 +4548,12 @@ static void forward_subsume_matching_clauses (closure *closure) { continue; } const reference ref = kissat_reference_clause (solver, c); - assert (size <= UINT_MAX); - refsize refsize = {.ref = ref, .size = size}; + KISSAT_assert (size <= UINT_MAX); + refsize refsize = {.ref = ref, .size = (unsigned)size}; PUSH_STACK (candidates, refsize); } DEALLOC (matchable, VARS); -#ifndef QUIET +#ifndef KISSAT_QUIET const size_t size_candidates = SIZE_STACK (candidates); kissat_very_verbose ( solver, "considering %zu matchable subsumption candidates %.0f%%", @@ -4548,19 +4562,19 @@ static void forward_subsume_matching_clauses (closure *closure) { (void) potential; #endif sort_references_by_clause_size (solver, &candidates); -#ifndef QUIET +#ifndef KISSAT_QUIET size_t tried = 0, subsumed = 0; #endif for (all_stack (refsize, refsize, candidates)) { if (TERMINATED (congruence_terminated_7)) break; -#ifndef QUIET +#ifndef KISSAT_QUIET tried++; #endif const unsigned ref = refsize.ref; clause *c = kissat_dereference_clause (solver, ref); if (find_subsuming_clause (closure, c)) { -#ifndef QUIET +#ifndef KISSAT_QUIET subsumed++; #endif } @@ -4578,15 +4592,15 @@ bool kissat_congruence (kissat *solver) { if (solver->inconsistent) return false; kissat_check_statistics (solver); - assert (!solver->level); - assert (solver->probing); - assert (solver->watching); + KISSAT_assert (!solver->level); + KISSAT_assert (solver->probing); + KISSAT_assert (solver->watching); if (!GET_OPTION (congruence)) return false; if (!GET_OPTION (congruenceands) && !GET_OPTION (congruenceites) && !GET_OPTION (congruencexors)) return false; - if (GET_OPTION (congruenceonce) && solver->statistics.closures) + if (GET_OPTION (congruenceonce) && solver->statistics_.closures) return false; if (TERMINATED (congruence_terminated_8)) return false; @@ -4618,8 +4632,8 @@ bool kissat_congruence (kissat *solver) { kissat_phase (solver, "congruence", GET (closures), "merged %u equivalent variables %.2f%%", equivalent, kissat_percent (equivalent, solver->active)); - assert (solver->active >= equivalent); -#ifndef QUIET + KISSAT_assert (solver->active >= equivalent); +#ifndef KISSAT_QUIET solver->active -= equivalent; REPORT (!equivalent, 'c'); if (!solver->inconsistent) @@ -4633,3 +4647,5 @@ bool kissat_congruence (kissat *solver) { kissat_check_statistics (solver); return equivalent; } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/congruence.h b/src/sat/kissat/congruence.h index 84e1eb643..79a2ff0f6 100644 --- a/src/sat/kissat/congruence.h +++ b/src/sat/kissat/congruence.h @@ -3,7 +3,12 @@ #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + struct kissat; bool kissat_congruence (struct kissat *); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/cover.h b/src/sat/kissat/cover.h index f5a82b71e..6c8eb1ee6 100644 --- a/src/sat/kissat/cover.h +++ b/src/sat/kissat/cover.h @@ -4,6 +4,9 @@ #include #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + #define COVER(COND) \ ((COND) ? \ \ @@ -25,4 +28,6 @@ } while (0) #endif +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/decide.c b/src/sat/kissat/decide.c index 522930e26..7c2fa82d9 100644 --- a/src/sat/kissat/decide.c +++ b/src/sat/kissat/decide.c @@ -6,15 +6,17 @@ #include +ABC_NAMESPACE_IMPL_START + static unsigned last_enqueued_unassigned_variable (kissat *solver) { - assert (solver->unassigned); + 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; - assert (!DISCONNECTED (res)); + KISSAT_assert (!DISCONNECTED (res)); } while (values[LIT (res)]); kissat_update_queue (solver, links, res); } @@ -24,7 +26,7 @@ static unsigned last_enqueued_unassigned_variable (kissat *solver) { #endif #ifdef CHECK_QUEUE for (unsigned i = links[res].next; !DISCONNECTED (i); i = links[i].next) - assert (VALUE (LIT (i))); + KISSAT_assert (VALUE (LIT (i))); #endif return res; } @@ -48,7 +50,7 @@ static unsigned largest_score_unassigned_variable (kissat *solver) { if (VALUE (LIT (idx))) continue; const double idx_score = kissat_get_heap_score (scores, idx); - assert (score >= idx_score); + KISSAT_assert (score >= idx_score); } #endif return res; @@ -71,7 +73,7 @@ void kissat_start_random_sequence (kissat *solver) { FORMAT_COUNT (CONFLICTS)); else { INC (random_sequences); - const uint64_t count = solver->statistics.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 " @@ -100,7 +102,7 @@ static unsigned next_random_decision (kissat *solver) { return INVALID_IDX; if (!solver->randec) { - assert (solver->level); + KISSAT_assert (solver->level); if (solver->level > 1) return INVALID_IDX; @@ -176,7 +178,7 @@ int kissat_decide_phase (kissat *solver, unsigned idx) { value res = 0; if (!solver->stable) { - switch ((solver->statistics.switched >> 1) & 7) { + switch ((solver->statistics_.switched >> 1) & 7) { case 1: res = INITIAL_PHASE; break; @@ -201,14 +203,14 @@ int kissat_decide_phase (kissat *solver, unsigned idx) { LOG ("%s uses initial decision phase %d", LOGVAR (idx), (int) res); INC (initial_decisions); } - assert (res); + KISSAT_assert (res); return res < 0 ? -1 : 1; } void kissat_decide (kissat *solver) { START (decide); - assert (solver->unassigned); + KISSAT_assert (solver->unassigned); if (solver->warming) INC (warming_decisions); else { @@ -219,26 +221,28 @@ void kissat_decide (kissat *solver) { INC (focused_decisions); } solver->level++; - assert (solver->level != INVALID_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); - assert (solver->level < SIZE_STACK (solver->frames)); + 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) { - assert (solver->unassigned); - assert (!VALUE (lit)); + KISSAT_assert (solver->unassigned); + KISSAT_assert (!VALUE (lit)); solver->level++; - assert (solver->level != INVALID_LEVEL); + KISSAT_assert (solver->level != INVALID_LEVEL); kissat_push_frame (solver, lit); - assert (solver->level < SIZE_STACK (solver->frames)); + KISSAT_assert (solver->level < SIZE_STACK (solver->frames)); LOG ("assuming literal %s", LOGLIT (lit)); kissat_assign_decision (solver, lit); } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/decide.h b/src/sat/kissat/decide.h index 9864ae2e1..df368771f 100644 --- a/src/sat/kissat/decide.h +++ b/src/sat/kissat/decide.h @@ -1,6 +1,9 @@ #ifndef _decide_h_INCLUDED #define _decide_h_INCLUDED +#include "global.h" +ABC_NAMESPACE_HEADER_START + struct kissat; void kissat_decide (struct kissat *); @@ -11,4 +14,6 @@ int kissat_decide_phase (struct kissat *, unsigned idx); #define INITIAL_PHASE (GET_OPTION (phase) ? 1 : -1) +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/deduce.c b/src/sat/kissat/deduce.c index be1235f69..dc2ceaa53 100644 --- a/src/sat/kissat/deduce.c +++ b/src/sat/kissat/deduce.c @@ -3,8 +3,10 @@ #include "promote.h" #include "strengthen.h" +ABC_NAMESPACE_IMPL_START + static inline void recompute_and_promote (kissat *solver, clause *c) { - assert (c->redundant); + 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) @@ -19,7 +21,7 @@ static inline void mark_clause_as_used (kissat *solver, clause *c) { LOGCLS (c, "using"); recompute_and_promote (solver, c); unsigned glue = MIN (c->glue, MAX_GLUE_USED); - solver->statistics.used[solver->stable].glue[glue]++; + solver->statistics_.used[solver->stable].glue[glue]++; if (solver->stable) INC (clauses_used_stable); else @@ -27,7 +29,7 @@ static inline void mark_clause_as_used (kissat *solver, clause *c) { } bool kissat_recompute_and_promote (kissat *solver, clause *c) { - assert (c->redundant); + 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) @@ -38,7 +40,7 @@ bool kissat_recompute_and_promote (kissat *solver, clause *c) { static inline bool analyze_literal (kissat *solver, assigned *all_assigned, frame *frames, unsigned lit) { - assert (VALUE (lit) < 0); + KISSAT_assert (VALUE (lit) < 0); const unsigned idx = IDX (lit); assigned *a = all_assigned + idx; const unsigned level = a->level; @@ -49,14 +51,14 @@ static inline bool analyze_literal (kissat *solver, assigned *all_assigned, return false; LOG ("analyzing literal %s", LOGLIT (lit)); kissat_push_analyzed (solver, all_assigned, idx); - assert (level <= solver->level); -#if defined(LOGGING) || !defined(NDEBUG) + 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; - assert (a->analyzed); + KISSAT_assert (a->analyzed); PUSH_STACK (solver->clause, lit); LOG ("learned literal %s", LOGLIT (lit)); frame *f = frames + level; @@ -69,10 +71,10 @@ static inline bool analyze_literal (kissat *solver, assigned *all_assigned, clause *kissat_deduce_first_uip_clause (kissat *solver, clause *conflict) { START (deduce); - assert (EMPTY_STACK (solver->analyzed)); - assert (EMPTY_STACK (solver->levels)); - assert (EMPTY_STACK (solver->clause)); -#if defined(LOGGING) || !defined(NDEBUG) + 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) @@ -84,16 +86,16 @@ clause *kissat_deduce_first_uip_clause (kissat *solver, clause *conflict) { assigned *all_assigned = solver->assigned; frame *frames = BEGIN_STACK (solver->frames); for (all_literals_in_clause (lit, conflict)) { - assert (VALUE (lit) < 0); + KISSAT_assert (VALUE (lit) < 0); if (LEVEL (lit)) conflict_size++; if (analyze_literal (solver, all_assigned, frames, lit)) unresolved_on_current_level++; } - assert (unresolved_on_current_level > 1); + KISSAT_assert (unresolved_on_current_level > 1); LOG ("starting with %u unresolved literals on current decision level", unresolved_on_current_level); - assert (solver->antecedent_size == solver->resolvent_size); + KISSAT_assert (solver->antecedent_size == solver->resolvent_size); LOGRES2 ("initial"); const bool otfs = GET_OPTION (otfs); unsigned const *t = END_ARRAY (solver->trail); @@ -102,14 +104,14 @@ clause *kissat_deduce_first_uip_clause (kissat *solver, clause *conflict) { assigned *a = 0; for (;;) { do { - assert (t > BEGIN_ARRAY (solver->trail)); + 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; - assert (a->reason != DECISION_REASON); - assert (a->level == solver->level); + KISSAT_assert (a->reason != DECISION_REASON); + KISSAT_assert (a->level == solver->level); solver->antecedent_size = 1; resolved++; if (a->binary) { @@ -127,38 +129,38 @@ clause *kissat_deduce_first_uip_clause (kissat *solver, clause *conflict) { unresolved_on_current_level++; mark_clause_as_used (solver, reason); } - assert (unresolved_on_current_level > 0); + 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); - assert (solver->resolvent_size > 0); + KISSAT_assert (solver->resolvent_size > 0); solver->resolvent_size--; -#if defined(LOGGING) || !defined(NDEBUG) +#if defined(LOGGING) || !defined(KISSAT_NDEBUG) LOG2 ("actual antecedent size %u", solver->antecedent_size); REMOVE_STACK (unsigned, solver->resolvent, NOT (uip)); - assert (SIZE_STACK (solver->resolvent) == solver->resolvent_size); + KISSAT_assert (SIZE_STACK (solver->resolvent) == solver->resolvent_size); LOGRES2 ("new"); #endif if (otfs && solver->antecedent_size > 2 && solver->resolvent_size < solver->antecedent_size) { - assert (!a->binary); - assert (solver->antecedent_size && solver->resolvent_size + 1); + KISSAT_assert (!a->binary); + KISSAT_assert (solver->antecedent_size && solver->resolvent_size + 1); clause *reason = kissat_dereference_clause (solver, a->reason); - assert (!reason->garbage); + KISSAT_assert (!reason->garbage); clause *res = kissat_on_the_fly_strengthen (solver, reason, uip); if (resolved == 1 && solver->resolvent_size < conflict_size) { - assert (!conflict->garbage); - assert (conflict_size > 2); + KISSAT_assert (!conflict->garbage); + KISSAT_assert (conflict_size > 2); kissat_on_the_fly_subsume (solver, res, conflict); } STOP (deduce); return res; } } - assert (uip != INVALID_LIT); + KISSAT_assert (uip != INVALID_LIT); LOG ("first unique implication point %s (1st UIP)", LOGLIT (uip)); - assert (PEEK_STACK (solver->clause, 0) == INVALID_LIT); + 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) @@ -166,3 +168,5 @@ clause *kissat_deduce_first_uip_clause (kissat *solver, clause *conflict) { STOP (deduce); return 0; } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/deduce.h b/src/sat/kissat/deduce.h index 38a5ec4c0..1783ce955 100644 --- a/src/sat/kissat/deduce.h +++ b/src/sat/kissat/deduce.h @@ -3,6 +3,9 @@ #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + struct clause; struct kissat; @@ -11,4 +14,6 @@ struct clause *kissat_deduce_first_uip_clause (struct kissat *, bool kissat_recompute_and_promote (struct kissat *, struct clause *); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/definition.c b/src/sat/kissat/definition.c index 759a4f906..75db5b8f5 100644 --- a/src/sat/kissat/definition.c +++ b/src/sat/kissat/definition.c @@ -5,6 +5,8 @@ #include "kitten.h" #include "print.h" +ABC_NAMESPACE_IMPL_START + typedef struct definition_extractor definition_extractor; struct definition_extractor { @@ -14,13 +16,13 @@ struct definition_extractor { }; static void traverse_definition_core (void *state, unsigned id) { - definition_extractor *extractor = state; + 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); - assert (size_watches0 <= UINT_MAX); + KISSAT_assert (size_watches0 <= UINT_MAX); unsigned sign; if (id < size_watches0) { watch = BEGIN_WATCHES (*watches0)[id]; @@ -28,10 +30,10 @@ static void traverse_definition_core (void *state, unsigned id) { sign = 0; } else { unsigned tmp = id - size_watches0; -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG const size_t size_watches1 = SIZE_WATCHES (*watches1); - assert (size_watches1 <= UINT_MAX); - assert (tmp < size_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]"); @@ -40,7 +42,7 @@ static void traverse_definition_core (void *state, unsigned id) { PUSH_STACK (solver->gates[sign], watch); } -#if !defined(NDEBUG) || !defined(NPROOFS) +#if !defined(KISSAT_NDEBUG) || !defined(KISSAT_NPROOFS) typedef struct lemma_extractor lemma_extractor; @@ -59,7 +61,7 @@ static void traverse_one_sided_core_lemma (void *state, bool learned, kissat *solver = extractor->solver; const unsigned unit = extractor->unit; unsigneds *added = &solver->added; - assert (extractor->lemmas || EMPTY_STACK (*added)); + KISSAT_assert (extractor->lemmas || EMPTY_STACK (*added)); if (size) { PUSH_STACK (*added, size + 1); const size_t offset = SIZE_STACK (*added); @@ -68,7 +70,7 @@ static void traverse_one_sided_core_lemma (void *state, bool learned, for (const unsigned *p = lits; p != end; p++) PUSH_STACK (*added, *p); unsigned *extended = &PEEK_STACK (*added, offset); - assert (offset + size + 1 == SIZE_STACK (*added)); + KISSAT_assert (offset + size + 1 == SIZE_STACK (*added)); CHECK_AND_ADD_LITS (size + 1, extended); ADD_LITS_TO_PROOF (size + 1, extended); } else { @@ -77,7 +79,7 @@ static void traverse_one_sided_core_lemma (void *state, bool learned, unsigned *begin = BEGIN_STACK (*added); for (unsigned *p = begin, size; p != end; p += size) { size = *p++; - assert (p + size <= end); + KISSAT_assert (p + size <= end); REMOVE_CHECKER_LITS (size, p); DELETE_LITS_FROM_PROOF (size, p); } @@ -93,7 +95,7 @@ bool kissat_find_definition (kissat *solver, unsigned lit) { return false; START (definition); struct kitten *kitten = solver->kitten; - assert (kitten); + KISSAT_assert (kitten); kitten_clear (kitten); const unsigned not_lit = NOT (lit); definition_extractor extractor; @@ -103,7 +105,7 @@ bool kissat_find_definition (kissat *solver, unsigned lit) { extractor.watches[1] = &WATCHES (not_lit); kitten_track_antecedents (kitten); unsigned exported = 0; -#if !defined(QUIET) || !defined(NDEBUG) +#if !defined(KISSAT_QUIET) || !defined(KISSAT_NDEBUG) size_t occs[2] = {0, 0}; #endif for (unsigned sign = 0; sign < 2; sign++) { @@ -119,7 +121,7 @@ bool kissat_find_definition (kissat *solver, unsigned lit) { kitten_clause_with_id_and_exception (kitten, exported, c->size, c->lits, except); } -#if !defined(QUIET) || !defined(NDEBUG) +#if !defined(KISSAT_QUIET) || !defined(KISSAT_NDEBUG) occs[sign]++; #endif exported++; @@ -143,19 +145,19 @@ bool kissat_find_definition (kissat *solver, unsigned lit) { kitten_shuffle_clauses (kitten); kitten_set_ticks_limit (kitten, 10 * limit); int tmp = kitten_solve (kitten); - assert (!tmp || tmp == 20); + KISSAT_assert (!tmp || tmp == 20); if (!tmp) { LOG ("aborting core extraction"); goto ABORT; } -#ifndef NDEBUG +#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); - assert (reduced <= previous); -#if defined(QUIET) && defined(NDEBUG) + KISSAT_assert (reduced <= previous); +#if defined(KISSAT_QUIET) && defined(KISSAT_NDEBUG) (void) reduced; #endif } @@ -164,8 +166,8 @@ bool kissat_find_definition (kissat *solver, unsigned lit) { size_t size[2]; size[0] = SIZE_STACK (solver->gates[0]); size[1] = SIZE_STACK (solver->gates[1]); -#if !defined(QUIET) || !defined(NDEBUG) - assert (reduced == size[0] + size[1]); +#if !defined(KISSAT_QUIET) || !defined(KISSAT_NDEBUG) + KISSAT_assert (reduced == size[0] + size[1]); #ifdef METRICS kissat_extremely_verbose ( solver, @@ -188,7 +190,7 @@ bool kissat_find_definition (kissat *solver, unsigned lit) { unsigned unit = INVALID_LIT; if (!size[0]) { unit = not_lit; - assert (size[1]); + KISSAT_assert (size[1]); } else if (!size[1]) unit = lit; @@ -198,12 +200,12 @@ bool kissat_find_definition (kissat *solver, unsigned lit) { kissat_extremely_verbose (solver, "one sided core " "definition extraction yields " "failed literal"); -#if !defined(NDEBUG) || !defined(NPROOFS) +#if !defined(KISSAT_NDEBUG) || !defined(KISSAT_NPROOFS) if (false -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG || GET_OPTION (check) > 1 #endif -#ifndef NPROOFS +#ifndef KISSAT_NPROOFS || solver->proof #endif ) { @@ -228,3 +230,5 @@ bool kissat_find_definition (kissat *solver, unsigned lit) { STOP (definition); return res; } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/definition.h b/src/sat/kissat/definition.h index 2fea782c0..9d87de466 100644 --- a/src/sat/kissat/definition.h +++ b/src/sat/kissat/definition.h @@ -3,8 +3,13 @@ #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + struct kissat; bool kissat_find_definition (struct kissat *, unsigned lit); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/dense.c b/src/sat/kissat/dense.c index d7592419a..65c668cbc 100644 --- a/src/sat/kissat/dense.c +++ b/src/sat/kissat/dense.c @@ -10,9 +10,11 @@ #include +ABC_NAMESPACE_IMPL_START + static void flush_large_watches (kissat *solver, litpairs *irredundant) { - assert (!solver->level); - assert (solver->watching); + KISSAT_assert (!solver->level); + KISSAT_assert (solver->watching); #ifndef LOGGING LOG ("flushing large watches"); if (irredundant) @@ -22,9 +24,9 @@ static void flush_large_watches (kissat *solver, litpairs *irredundant) { #endif const value *const values = solver->values; mark *const marks = solver->marks; -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG for (all_literals (lit)) - assert (!marks[lit]); + KISSAT_assert (!marks[lit]); #endif size_t flushed = 0, collected = 0; #ifdef LOGGING @@ -37,7 +39,7 @@ static void flush_large_watches (kissat *solver, litpairs *irredundant) { watches *watches = all_watches + lit; watch *begin = BEGIN_WATCHES (*watches), *q = begin; const watch *const end_watches = END_WATCHES (*watches), *p = q; - assert (EMPTY_STACK (*marked)); + KISSAT_assert (EMPTY_STACK (*marked)); while (p != end_watches) { const watch watch = *p++; if (watch.type.binary) { @@ -65,7 +67,7 @@ static void flush_large_watches (kissat *solver, litpairs *irredundant) { *q++ = watch; } } else { - assert (lit_value > 0 || other_value > 0); + KISSAT_assert (lit_value > 0 || other_value > 0); if (lit < other) { kissat_delete_binary (solver, lit, other); collected++; @@ -84,7 +86,7 @@ static void flush_large_watches (kissat *solver, litpairs *irredundant) { marks[other] = 0; CLEAR_ARRAY (*marked); } - assert (EMPTY_STACK (*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); @@ -97,9 +99,9 @@ static void flush_large_watches (kissat *solver, litpairs *irredundant) { } void kissat_enter_dense_mode (kissat *solver, litpairs *irredundant) { - assert (!solver->level); - assert (solver->watching); - assert (kissat_propagated (solver)); + 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); @@ -111,7 +113,7 @@ void kissat_enter_dense_mode (kissat *solver, litpairs *irredundant) { static void resume_watching_irredundant_binaries (kissat *solver, litpairs *binaries) { - assert (binaries); + KISSAT_assert (binaries); #ifdef LOGGING size_t resumed_watching = 0; #endif @@ -120,8 +122,8 @@ static void resume_watching_irredundant_binaries (kissat *solver, const unsigned first = litpair.lits[0]; const unsigned second = litpair.lits[1]; - assert (!ELIMINATED (IDX (first))); - assert (!ELIMINATED (IDX (second))); + KISSAT_assert (!ELIMINATED (IDX (first))); + KISSAT_assert (!ELIMINATED (IDX (second))); watches *first_watches = all_watches + first; watch first_watch = kissat_binary_watch (second); @@ -172,7 +174,7 @@ resume_watching_large_clauses_after_elimination (kissat *solver) { continue; } - assert (c->size > 2); + KISSAT_assert (c->size > 2); unsigned *lits = c->lits; kissat_sort_literals (solver, values, assigned, c->size, lits); @@ -198,8 +200,8 @@ resume_watching_large_clauses_after_elimination (kissat *solver) { void kissat_resume_sparse_mode (kissat *solver, bool flush_eliminated, litpairs *irredundant) { - assert (!solver->level); - assert (!solver->watching); + KISSAT_assert (!solver->level); + KISSAT_assert (!solver->watching); if (solver->inconsistent) return; LOG ("resuming sparse mode watching clauses"); @@ -224,12 +226,14 @@ void kissat_resume_sparse_mode (kissat *solver, bool flush_eliminated, else conflict = kissat_search_propagate (solver); -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG if (conflict) - assert (solver->inconsistent); + KISSAT_assert (solver->inconsistent); else - assert (kissat_trail_flushed (solver)); + KISSAT_assert (kissat_trail_flushed (solver)); #else (void) conflict; #endif } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/dense.h b/src/sat/kissat/dense.h index 171e4e5ac..225d7367d 100644 --- a/src/sat/kissat/dense.h +++ b/src/sat/kissat/dense.h @@ -3,10 +3,15 @@ #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 diff --git a/src/sat/kissat/dump.c b/src/sat/kissat/dump.c index e8598b130..c1b2796d3 100644 --- a/src/sat/kissat/dump.c +++ b/src/sat/kissat/dump.c @@ -1,4 +1,6 @@ -#ifndef NDEBUG +#include "global.h" + +#ifndef KISSAT_NDEBUG #include "inline.h" @@ -64,14 +66,14 @@ static void dump_trail (kissat *solver) { const unsigned lit = PEEK_ARRAY (solver->trail, i); dump_literal (solver, lit); const unsigned lit_level = LEVEL (lit); - assert (lit_level <= level); + KISSAT_assert (lit_level <= level); if (lit_level < level) printf (" out-of-order"); assigned *a = ASSIGNED (lit); if (!lit_level) { printf (" UNIT\n"); - assert (!a->binary); - assert (a->reason == UNIT_REASON); + KISSAT_assert (!a->binary); + KISSAT_assert (a->reason == UNIT_REASON); } else { fputc (' ', stdout); if (a->binary) { @@ -80,7 +82,7 @@ static void dump_trail (kissat *solver) { } else if (a->reason == DECISION_REASON) printf ("DECISION\n"); else { - assert (a->reason != UNIT_REASON); + KISSAT_assert (a->reason != UNIT_REASON); const reference ref = a->reason; dump_ref (solver, ref); } @@ -129,18 +131,18 @@ static void dump_scores (kissat *solver) { } static void dump_export (kissat *solver) { - const unsigned size = SIZE_STACK (solver->export); + 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)); + PEEK_STACK (solver->export_, idx)); } void dump_map (kissat *solver) { - const unsigned size = SIZE_STACK (solver->export); + 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); + const int elit = PEEK_STACK (solver->export_, idx); printf ("map[%u] -> %d", ilit, elit); if (elit) { const unsigned eidx = ABS (elit); @@ -195,7 +197,7 @@ static void dump_extend (kissat *solver) { const extension *const begin = BEGIN_STACK (solver->extend); const extension *const end = END_STACK (solver->extend); for (const extension *p = begin, *q; p != end; p = q) { - assert (p->blocking); + KISSAT_assert (p->blocking); printf ("extend[%zu] %d", (size_t) (p - begin), p->lit); if (!p[1].blocking) fputs (" :", stdout); diff --git a/src/sat/kissat/eliminate.c b/src/sat/kissat/eliminate.c index 9b7164c83..7b3bb713f 100644 --- a/src/sat/kissat/eliminate.c +++ b/src/sat/kissat/eliminate.c @@ -18,10 +18,12 @@ #include #include +ABC_NAMESPACE_IMPL_START + bool kissat_eliminating (kissat *solver) { if (!solver->enabled.eliminate) return false; - statistics *statistics = &solver->statistics; + statistics *statistics = &solver->statistics_; if (!statistics->clauses_irredundant) return false; const uint64_t conflicts = statistics->conflicts; @@ -51,9 +53,9 @@ static inline double variable_score (kissat *solver, unsigned idx) { double prod = pos * neg; double sum = pos + neg; double occlim2 = occlim * (double) occlim; - assert (prod <= occlim2); + KISSAT_assert (prod <= occlim2); double score = prod - sum; - assert (score <= occlim2); + KISSAT_assert (score <= occlim2); double relevancy; if (solver->stable) relevancy = kissat_get_heap_score (&solver->scores, idx); @@ -70,8 +72,8 @@ static inline double variable_score (kissat *solver, unsigned idx) { static inline void update_variable_score (kissat *solver, heap *schedule, unsigned idx) { - assert (schedule->size); - assert (schedule == &solver->schedule); + 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); @@ -83,7 +85,7 @@ void kissat_update_variable_score (kissat *solver, unsigned idx) { static inline void update_after_adding_stack (kissat *solver, unsigneds *stack) { - assert (!solver->probing); + KISSAT_assert (!solver->probing); heap *schedule = &solver->schedule; if (!schedule->size) return; @@ -96,11 +98,11 @@ static inline void update_after_removing_variable (kissat *solver, heap *schedule = &solver->schedule; if (!schedule->size) return; - assert (!solver->probing); + KISSAT_assert (!solver->probing); flags *f = solver->flags + idx; if (f->fixed) return; - assert (!f->eliminated); + KISSAT_assert (!f->eliminated); update_variable_score (solver, schedule, idx); if (!kissat_heap_contains (schedule, idx)) kissat_push_heap (solver, schedule, idx); @@ -110,7 +112,7 @@ static inline void update_after_removing_clause (kissat *solver, clause *c, unsigned except) { if (!solver->schedule.size) return; - assert (c->garbage); + KISSAT_assert (c->garbage); for (all_literals_in_clause (lit, c)) if (lit != except) update_after_removing_variable (solver, IDX (lit)); @@ -130,7 +132,7 @@ void kissat_eliminate_clause (kissat *solver, clause *c, unsigned lit) { static unsigned schedule_variables (kissat *solver) { LOG ("initializing variable schedule"); - assert (!solver->schedule.size); + KISSAT_assert (!solver->schedule.size); kissat_resize_heap (solver, &solver->schedule, solver->vars); @@ -147,8 +149,8 @@ static unsigned schedule_variables (kissat *solver) { scheduled++; update_after_removing_variable (solver, idx); } - assert (scheduled == kissat_size_heap (&solver->schedule)); -#ifndef QUIET + 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, @@ -160,7 +162,7 @@ static unsigned schedule_variables (kissat *solver) { void kissat_flush_units_while_connected (kissat *solver) { const unsigned *propagate = solver->propagate; const unsigned *end_trail = END_ARRAY (solver->trail); - assert (propagate <= end_trail); + KISSAT_assert (propagate <= end_trail); const size_t units = end_trail - propagate; if (!units) return; @@ -191,11 +193,11 @@ void kissat_flush_units_while_connected (kissat *solver) { clause *c = kissat_dereference_clause (solver, ref); if (!c->garbage) kissat_eliminate_clause (solver, c, unit); - assert (c->garbage); + KISSAT_assert (c->garbage); q--; } } - assert (q <= end); + KISSAT_assert (q <= end); size_t flushed = end - q; if (!flushed) continue; @@ -206,7 +208,7 @@ void kissat_flush_units_while_connected (kissat *solver) { static void connect_resolvents (kissat *solver) { const value *const values = solver->values; - assert (EMPTY_STACK (solver->clause)); + KISSAT_assert (EMPTY_STACK (solver->clause)); bool satisfied = false; #ifdef LOGGING uint64_t added = 0; @@ -219,7 +221,7 @@ static void connect_resolvents (kissat *solver) { LOGTMP ("temporary resolvent"); const size_t size = SIZE_STACK (solver->clause); if (!size) { - assert (!solver->inconsistent); + KISSAT_assert (!solver->inconsistent); LOG ("resolved empty clause"); CHECK_AND_ADD_EMPTY (); ADD_EMPTY_TO_PROOF (); @@ -230,7 +232,7 @@ static void connect_resolvents (kissat *solver) { LOG ("resolved unit clause %s", LOGLIT (unit)); kissat_learned_unit (solver, unit); } else { - assert (size > 1); + KISSAT_assert (size > 1); (void) kissat_new_irredundant_clause (solver); update_after_adding_stack (solver, &solver->clause); #ifdef LOGGING @@ -258,7 +260,7 @@ static void weaken_clauses (kissat *solver, unsigned lit) { const unsigned not_lit = NOT (lit); const value *const values = solver->values; - assert (!values[lit]); + KISSAT_assert (!values[lit]); watches *pos_watches = &WATCHES (lit); @@ -340,7 +342,7 @@ static void set_next_elimination_bound (kissat *solver, bool complete) { const unsigned max_bound = GET_OPTION (eliminatebound); const unsigned current_bound = solver->bounds.eliminate.additional_clauses; - assert (current_bound <= max_bound); + KISSAT_assert (current_bound <= max_bound); if (complete) { if (current_bound == max_bound) { @@ -348,11 +350,11 @@ static void set_next_elimination_bound (kissat *solver, bool complete) { "completed maximum elimination bound %u", current_bound); limits *limits = &solver->limits; - statistics *statistics = &solver->statistics; + statistics *statistics = &solver->statistics_; limits->eliminate.variables.eliminate = statistics->variables_eliminate; limits->eliminate.variables.subsume = statistics->variables_subsume; -#ifndef QUIET +#ifndef KISSAT_QUIET bool first = !solver->bounds.eliminate.max_bound_completed++; REPORT (!first, first ? '!' : ':'); #endif @@ -389,8 +391,8 @@ static bool eliminate_variable (kissat *solver, unsigned idx) { (void) variable_score (solver, idx); #endif - assert (!solver->inconsistent); - assert (can_eliminate_variable (solver, idx)); + KISSAT_assert (!solver->inconsistent); + KISSAT_assert (can_eliminate_variable (solver, idx)); LOG ("marking %s as not removed", LOGVAR (idx)); FLAGS (idx)->eliminate = false; @@ -406,7 +408,7 @@ static bool eliminate_variable (kissat *solver, unsigned idx) { if (solver->gate_eliminated) { INC (gates_eliminated); #ifdef METRICS - assert (*solver->gate_eliminated < UINT64_MAX); + KISSAT_assert (*solver->gate_eliminated < UINT64_MAX); *solver->gate_eliminated += 1; #endif } @@ -417,8 +419,8 @@ static void eliminate_variables (kissat *solver) { kissat_very_verbose (solver, "trying to eliminate variables with bound %u", solver->bounds.eliminate.additional_clauses); - assert (!solver->inconsistent); -#ifndef QUIET + KISSAT_assert (!solver->inconsistent); +#ifndef KISSAT_QUIET unsigned before = solver->active; unsigned eliminated = 0; uint64_t tried = 0; @@ -452,7 +454,7 @@ static void eliminate_variables (kissat *solver) { complete = true; } -#ifndef QUIET +#ifndef KISSAT_QUIET const unsigned last_round_scheduled = #endif schedule_variables (solver); @@ -474,7 +476,7 @@ static void eliminate_variables (kissat *solver) { unsigned idx = kissat_pop_max_heap (solver, &solver->schedule); if (!can_eliminate_variable (solver, idx)) continue; - statistics *s = &solver->statistics; + statistics *s = &solver->statistics_; if (s->eliminate_resolutions > resolution_limit) { kissat_extremely_verbose ( solver, @@ -484,7 +486,7 @@ static void eliminate_variables (kissat *solver) { complete = false; break; } -#ifndef QUIET +#ifndef KISSAT_QUIET tried++; #endif if (eliminate_variable (solver, idx)) @@ -496,7 +498,7 @@ static void eliminate_variables (kissat *solver) { if (last_round_eliminated) { complete = false; -#ifndef QUIET +#ifndef KISSAT_QUIET eliminated += last_round_eliminated; #endif } @@ -520,7 +522,7 @@ static void eliminate_variables (kissat *solver) { break; if (round == GET_OPTION (eliminaterounds)) break; - if (solver->statistics.eliminate_resolutions > resolution_limit) + if (solver->statistics_.eliminate_resolutions > resolution_limit) break; if (TERMINATED (eliminate_terminated_2)) break; @@ -528,7 +530,7 @@ static void eliminate_variables (kissat *solver) { const unsigned remain = kissat_size_heap (&solver->schedule); kissat_release_heap (solver, &solver->schedule); -#ifndef QUIET +#ifndef KISSAT_QUIET kissat_very_verbose (solver, "eliminated %u variables %.0f%% of %" PRIu64 " tried" " (%u remain %.0f%%)", @@ -545,13 +547,13 @@ static void eliminate_variables (kissat *solver) { set_next_elimination_bound (solver, complete); if (!complete) { const flags *end = solver->flags + VARS; -#ifndef QUIET +#ifndef KISSAT_QUIET unsigned dropped = 0; #endif for (struct flags *f = solver->flags; f != end; f++) if (f->eliminate) { f->eliminate = false; -#ifndef QUIET +#ifndef KISSAT_QUIET dropped++; #endif } @@ -565,7 +567,7 @@ static void eliminate_variables (kissat *solver) { static void init_map_and_kitten (kissat *solver) { if (!GET_OPTION (definitions)) return; - assert (!solver->kitten); + KISSAT_assert (!solver->kitten); solver->kitten = kitten_embedded (solver); } @@ -578,7 +580,7 @@ static void reset_map_and_kitten (kissat *solver) { static void eliminate (kissat *solver) { kissat_backtrack_propagate_and_flush_trail (solver); - assert (!solver->inconsistent); + KISSAT_assert (!solver->inconsistent); STOP_SEARCH_AND_START_SIMPLIFIER (eliminate); kissat_phase (solver, "eliminate", GET (eliminations), "elimination limit of %" PRIu64 " conflicts hit", @@ -593,11 +595,13 @@ static void eliminate (kissat *solver) { } int kissat_eliminate (kissat *solver) { - assert (!solver->inconsistent); + 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; + solver->last.ticks.eliminate = solver->statistics_.search_ticks; return solver->inconsistent ? 20 : 0; } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/eliminate.h b/src/sat/kissat/eliminate.h index 0d6cfe9a5..cdc73b98b 100644 --- a/src/sat/kissat/eliminate.h +++ b/src/sat/kissat/eliminate.h @@ -3,6 +3,9 @@ #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + struct kissat; struct clause; struct heap; @@ -16,4 +19,6 @@ 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 diff --git a/src/sat/kissat/equivalences.c b/src/sat/kissat/equivalences.c index c06215d24..41bf9a34c 100644 --- a/src/sat/kissat/equivalences.c +++ b/src/sat/kissat/equivalences.c @@ -2,6 +2,8 @@ #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; @@ -35,3 +37,5 @@ bool kissat_find_equivalence_gate (kissat *solver, unsigned lit) { INC (equivalences_extracted); return true; } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/equivalences.h b/src/sat/kissat/equivalences.h index ad9c14d57..30ada11a7 100644 --- a/src/sat/kissat/equivalences.h +++ b/src/sat/kissat/equivalences.h @@ -3,8 +3,13 @@ #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + struct kissat; bool kissat_find_equivalence_gate (struct kissat *, unsigned lit); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/error.c b/src/sat/kissat/error.c index c4c55d18d..8b687e604 100644 --- a/src/sat/kissat/error.c +++ b/src/sat/kissat/error.c @@ -5,6 +5,8 @@ #include #include +ABC_NAMESPACE_IMPL_START + static void (*kissat_abort_function) (void); void kissat_call_function_instead_of_abort (void (*f) (void)) { @@ -60,3 +62,5 @@ void kissat_fatal (const char *fmt, ...) { va_end (ap); kissat_abort (); } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/error.h b/src/sat/kissat/error.h index 69ee50706..32a265f86 100644 --- a/src/sat/kissat/error.h +++ b/src/sat/kissat/error.h @@ -3,6 +3,9 @@ #include "attribute.h" +#include "global.h" +ABC_NAMESPACE_HEADER_START + // clang-format off void kissat_error (const char *fmt, ...) ATTRIBUTE_FORMAT (1, 2); @@ -15,4 +18,6 @@ void kissat_abort (void); // clang-format on +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/extend.c b/src/sat/kissat/extend.c index cd0dfa006..67a0839a5 100644 --- a/src/sat/kissat/extend.c +++ b/src/sat/kissat/extend.c @@ -1,6 +1,8 @@ #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 @@ -18,32 +20,32 @@ static void undo_eliminated_assignment (kissat *solver) { while (!EMPTY_STACK (solver->etrail)) { const unsigned pos = POP_STACK (solver->etrail); - assert (pos < SIZE_STACK (solver->eliminated)); - assert (values[pos]); + 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) { - assert (lit); - assert (lit != INT_MIN); + KISSAT_assert (lit); + KISSAT_assert (lit != INT_MIN); const unsigned idx = ABS (lit); import *import = &PEEK_STACK (solver->import, idx); - assert (import->eliminated); - assert (import->imported); + KISSAT_assert (import->eliminated); + KISSAT_assert (import->imported); const unsigned pos = import->lit; - assert (pos < SIZE_STACK (solver->eliminated)); + KISSAT_assert (pos < SIZE_STACK (solver->eliminated)); const value value = lit < 0 ? -1 : 1; values[pos] = value; - assert (kissat_value (solver, lit) == lit); + 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) { - assert (!EMPTY_STACK (solver->extend)); - assert (!solver->extended); + KISSAT_assert (!EMPTY_STACK (solver->extend)); + KISSAT_assert (!solver->extended); START (extend); solver->extended = true; @@ -79,7 +81,7 @@ void kissat_extend (kissat *solver) { #endif do { size++; - assert (begin < p); + KISSAT_assert (begin < p); const extension ext = *--p; const int elit = ext.lit; if (ext.blocking) @@ -88,15 +90,15 @@ void kissat_extend (kissat *solver) { if (satisfied) continue; - assert (elit != INT_MIN); + KISSAT_assert (elit != INT_MIN); const unsigned eidx = ABS (elit); - assert (eidx < SIZE_STACK (solver->import)); + KISSAT_assert (eidx < SIZE_STACK (solver->import)); const import *const import = imports + eidx; - assert (import->imported); + KISSAT_assert (import->imported); if (import->eliminated) { const unsigned tmp = import->lit; - assert (tmp < SIZE_STACK (solver->eliminated)); + KISSAT_assert (tmp < SIZE_STACK (solver->eliminated)); value value = evalues[tmp]; if (elit < 0) @@ -120,7 +122,7 @@ void kissat_extend (kissat *solver) { } else { const unsigned ilit = import->lit; value value = ivalues[ilit]; - assert (value); + KISSAT_assert (value); if (elit < 0) value = -value; @@ -151,10 +153,10 @@ void kissat_extend (kissat *solver) { #ifdef LOGGING const unsigned blocking_idx = ABS (blocking); - assert (blocking_idx < SIZE_STACK (solver->import)); - assert (imports[blocking_idx].eliminated); + KISSAT_assert (blocking_idx < SIZE_STACK (solver->import)); + KISSAT_assert (imports[blocking_idx].eliminated); const unsigned blocking_pos = imports[blocking_idx].lit; - assert (blocking_pos < SIZE_STACK (solver->eliminated)); + KISSAT_assert (blocking_pos < SIZE_STACK (solver->eliminated)); const value blocking_value = evalues[blocking_pos]; LOGEXT2 (size, p, "%s blocking external literal %d " @@ -179,3 +181,5 @@ void kissat_extend (kissat *solver) { STOP (extend); } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/extend.h b/src/sat/kissat/extend.h index 049028b25..c66d9efd2 100644 --- a/src/sat/kissat/extend.h +++ b/src/sat/kissat/extend.h @@ -4,6 +4,9 @@ #include "stack.h" #include "utilities.h" +#include "global.h" +ABC_NAMESPACE_HEADER_START + typedef struct extension extension; struct extension { @@ -16,7 +19,7 @@ typedef STACK (extension) extensions; // clang-format on static inline extension kissat_extension (bool blocking, int lit) { - assert (ABS (lit) < (1 << 30)); + KISSAT_assert (ABS (lit) < (1 << 30)); extension res; res.blocking = blocking; res.lit = lit; @@ -27,4 +30,6 @@ struct kissat; void kissat_extend (struct kissat *solver); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/factor.c b/src/sat/kissat/factor.c index e234d0957..5586243c8 100644 --- a/src/sat/kissat/factor.c +++ b/src/sat/kissat/factor.c @@ -19,6 +19,8 @@ #include +ABC_NAMESPACE_IMPL_START + #define FACTOR 1 #define QUOTIENT 2 #define NOUNTED 4 @@ -73,19 +75,19 @@ static void init_factoring (kissat *solver, factoring *factoring, factoring->hops = GET_OPTION (factorhops); const unsigned hops = factoring->hops; if (hops) { - CALLOC (factoring->scores, hops); + CALLOC (scores, factoring->scores, hops); for (unsigned i = 0; i != hops; i++) { scores *scores = factoring->scores + i; - NALLOC (scores->score, VARS); + NALLOC (double, scores->score, VARS); double *score = scores->score; for (all_variables (idx)) score[idx] = -1; } } - CALLOC (factoring->count, factoring->allocated); -#ifndef NDEBUG + CALLOC (unsigned, factoring->count, factoring->allocated); +#ifndef KISSAT_NDEBUG for (all_literals (lit)) - assert (!solver->marks[lit]); + KISSAT_assert (!solver->marks[lit]); #endif } @@ -95,7 +97,7 @@ static void release_quotients (factoring *factoring) { for (quotient *q = factoring->quotients.first, *next; q; q = next) { next = q->next; unsigned factor = q->factor; - assert (marks[factor] == FACTOR); + KISSAT_assert (marks[factor] == FACTOR); marks[factor] = 0; RELEASE_STACK (q->clauses); RELEASE_STACK (q->matches); @@ -118,10 +120,10 @@ static void release_quotients (factoring *factoring) { static void release_factoring (factoring *factoring) { kissat *const solver = factoring->solver; - assert (EMPTY_STACK (solver->analyzed)); - assert (EMPTY_STACK (factoring->counted)); - assert (EMPTY_STACK (factoring->nounted)); - assert (EMPTY_STACK (factoring->qlauses)); + KISSAT_assert (EMPTY_STACK (solver->analyzed)); + KISSAT_assert (EMPTY_STACK (factoring->counted)); + KISSAT_assert (EMPTY_STACK (factoring->nounted)); + KISSAT_assert (EMPTY_STACK (factoring->qlauses)); DEALLOC (factoring->count, factoring->allocated); RELEASE_STACK (factoring->counted); RELEASE_STACK (factoring->nounted); @@ -129,7 +131,7 @@ static void release_factoring (factoring *factoring) { RELEASE_STACK (factoring->qlauses); release_quotients (factoring); kissat_release_heap (solver, &factoring->schedule); - assert (!(factoring->allocated & 1)); + KISSAT_assert (!(factoring->allocated & 1)); const size_t allocated_score = factoring->allocated / 2; const unsigned hops = factoring->hops; if (hops) { @@ -141,9 +143,9 @@ static void release_factoring (factoring *factoring) { } DEALLOC (factoring->scores, hops); } -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG for (all_literals (lit)) - assert (!solver->marks[lit]); + KISSAT_assert (!solver->marks[lit]); #endif } @@ -174,7 +176,7 @@ static void schedule_factorization (factoring *factoring) { update_candidate (factoring, not_lit); } } -#ifndef QUIET +#ifndef KISSAT_QUIET heap *cands = &factoring->schedule; size_t size_cands = kissat_size_heap (cands); kissat_very_verbose ( @@ -186,19 +188,19 @@ static void schedule_factorization (factoring *factoring) { static quotient *new_quotient (factoring *factoring, unsigned factor) { kissat *const solver = factoring->solver; mark *marks = solver->marks; - assert (!marks[factor]); + KISSAT_assert (!marks[factor]); marks[factor] = FACTOR; - quotient *res = kissat_malloc (solver, sizeof *res); + quotient *res = (quotient*)kissat_malloc (solver, sizeof *res); memset (res, 0, sizeof *res); res->factor = factor; quotient *last = factoring->quotients.last; if (last) { - assert (factoring->quotients.first); - assert (!last->next); + KISSAT_assert (factoring->quotients.first); + KISSAT_assert (!last->next); last->next = res; res->id = last->id + 1; } else { - assert (!factoring->quotients.first); + KISSAT_assert (!factoring->quotients.first); factoring->quotients.first = res; } factoring->quotients.last = res; @@ -211,24 +213,24 @@ static size_t first_factor (factoring *factoring, unsigned factor) { kissat *const solver = factoring->solver; watches *all_watches = solver->watches; watches *factor_watches = all_watches + factor; - assert (!factoring->quotients.first); + KISSAT_assert (!factoring->quotients.first); quotient *quotient = new_quotient (factoring, factor); statches *clauses = "ient->clauses; uint64_t ticks = 0; for (all_binary_large_watches (watch, *factor_watches)) { PUSH_STACK (*clauses, watch); -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG if (watch.type.binary) continue; const reference ref = watch.large.ref; clause *const c = kissat_dereference_clause (solver, ref); - assert (!c->quotient); + KISSAT_assert (!c->quotient); #endif ticks++; } size_t res = SIZE_STACK (*clauses); LOG ("quotient[0] factor %s size %zu", LOGLIT (factor), res); - assert (res > 1); + KISSAT_assert (res > 1); ADD (factor_ticks, ticks); return res; } @@ -236,7 +238,7 @@ static size_t first_factor (factoring *factoring, unsigned factor) { static void clear_nounted (kissat *solver, unsigneds *nounted) { mark *marks = solver->marks; for (all_stack (unsigned, lit, *nounted)) { - assert (marks[lit] & NOUNTED); + KISSAT_assert (marks[lit] & NOUNTED); marks[lit] &= ~NOUNTED; } CLEAR_STACK (*nounted); @@ -246,7 +248,7 @@ static void clear_qlauses (kissat *solver, references *qlauses) { ward *const arena = BEGIN_STACK (solver->arena); for (all_stack (reference, ref, *qlauses)) { clause *const c = (clause *) (arena + ref); - assert (c->quotient); + KISSAT_assert (c->quotient); c->quotient = false; } CLEAR_STACK (*qlauses); @@ -286,7 +288,7 @@ static double distinct_paths (factoring *factoring, unsigned src_lit, } ADD (factor_ticks, ticks); } - assert (res >= 0); + KISSAT_assert (res >= 0); score[src_idx] = res; unsigneds *scored = &scores->scored; PUSH_STACK (*scored, src_idx); @@ -297,9 +299,9 @@ static double distinct_paths (factoring *factoring, unsigned src_lit, static double structural_score (factoring *factoring, unsigned lit) { const quotient *first_quotient = factoring->quotients.first; - assert (first_quotient); + KISSAT_assert (first_quotient); const unsigned first_factor = first_quotient->factor; -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG kissat *const solver = factoring->solver; #endif const unsigned first_factor_idx = IDX (first_factor); @@ -324,15 +326,15 @@ static double tied_next_factor_score (factoring *factoring, unsigned lit) { static unsigned next_factor (factoring *factoring, unsigned *next_count_ptr) { quotient *last_quotient = factoring->quotients.last; - assert (last_quotient); + KISSAT_assert (last_quotient); statches *last_clauses = &last_quotient->clauses; kissat *const solver = factoring->solver; watches *all_watches = solver->watches; unsigned *count = factoring->count; unsigneds *counted = &factoring->counted; references *qlauses = &factoring->qlauses; - assert (EMPTY_STACK (*counted)); - assert (EMPTY_STACK (*qlauses)); + KISSAT_assert (EMPTY_STACK (*counted)); + KISSAT_assert (EMPTY_STACK (*qlauses)); ward *const arena = BEGIN_STACK (solver->arena); mark *marks = solver->marks; const unsigned initial = factoring->initial; @@ -362,7 +364,7 @@ static unsigned next_factor (factoring *factoring, } else { const reference c_ref = quotient_watch.large.ref; clause *const c = (clause *) (arena + c_ref); - assert (!c->quotient); + KISSAT_assert (!c->quotient); unsigned min_lit = INVALID_LIT, factors = 0; size_t min_size = 0; ticks++; @@ -371,7 +373,7 @@ static unsigned next_factor (factoring *factoring, if (factors++) break; } else { - assert (!(marks[other] & QUOTIENT)); + KISSAT_assert (!(marks[other] & QUOTIENT)); marks[other] |= QUOTIENT; watches *other_watches = all_watches + other; const size_t other_size = SIZE_WATCHES (*other_watches); @@ -381,13 +383,13 @@ static unsigned next_factor (factoring *factoring, min_size = other_size; } } - assert (factors); + KISSAT_assert (factors); if (factors == 1) { - assert (min_lit != INVALID_LIT); + KISSAT_assert (min_lit != INVALID_LIT); watches *min_watches = all_watches + min_lit; unsigned c_size = c->size; unsigneds *nounted = &factoring->nounted; - assert (EMPTY_STACK (*nounted)); + KISSAT_assert (EMPTY_STACK (*nounted)); ticks += 1 + kissat_cache_lines (SIZE_WATCHES (*min_watches), sizeof (watch)); for (all_binary_large_watches (min_watch, *min_watches)) { @@ -403,25 +405,35 @@ static unsigned next_factor (factoring *factoring, if (d->size != c_size) continue; unsigned next = INVALID_LIT; + int continue_with_next_min_watch = 0; for (all_literals_in_clause (other, d)) { const mark mark = marks[other]; if (mark & QUOTIENT) continue; - if (mark & FACTOR) - goto CONTINUE_WITH_NEXT_MIN_WATCH; - if (mark & NOUNTED) - goto CONTINUE_WITH_NEXT_MIN_WATCH; - if (next != INVALID_LIT) - goto CONTINUE_WITH_NEXT_MIN_WATCH; + if (mark & FACTOR) { + continue_with_next_min_watch = 1; + break; + } + if (mark & NOUNTED) { + continue_with_next_min_watch = 1; + break; + } + if (next != INVALID_LIT) { + continue_with_next_min_watch = 1; + break; + } next = other; } - assert (next != INVALID_LIT); + if(continue_with_next_min_watch) { + continue; + } + KISSAT_assert (next != INVALID_LIT); if (next > initial) continue; const unsigned next_idx = IDX (next); if (!ACTIVE (next_idx)) continue; - assert (!(marks[next] & (FACTOR | NOUNTED))); + KISSAT_assert (!(marks[next] & (FACTOR | NOUNTED))); marks[next] |= NOUNTED; PUSH_STACK (*nounted, next); d->quotient = true; @@ -429,7 +441,6 @@ static unsigned next_factor (factoring *factoring, if (!count[next]) PUSH_STACK (*counted, next); count[next]++; - CONTINUE_WITH_NEXT_MIN_WATCH:; } clear_nounted (solver, nounted); } @@ -438,22 +449,22 @@ static unsigned next_factor (factoring *factoring, } ADD (factor_ticks, ticks); ticks = 0; - if (solver->statistics.factor_ticks > factoring->limit) + if (solver->statistics_.factor_ticks > factoring->limit) break; } clear_qlauses (solver, qlauses); unsigned next_count = 0, next = INVALID_LIT; - if (solver->statistics.factor_ticks <= factoring->limit) { + if (solver->statistics_.factor_ticks <= factoring->limit) { unsigned ties = 0; for (all_stack (unsigned, lit, *counted)) { const unsigned lit_count = count[lit]; if (lit_count < next_count) continue; if (lit_count == next_count) { - assert (lit_count); + KISSAT_assert (lit_count); ties++; } else { - assert (lit_count > next_count); + KISSAT_assert (lit_count > next_count); next_count = lit_count; next = lit; ties = 1; @@ -471,7 +482,7 @@ static unsigned next_factor (factoring *factoring, if (lit_count != next_count) continue; double lit_score = tied_next_factor_score (factoring, lit); - assert (lit_score >= 0); + KISSAT_assert (lit_score >= 0); LOG ("score %g of next factor candidate %s", lit_score, LOGLIT (lit)); if (lit_score <= next_score) @@ -479,11 +490,11 @@ static unsigned next_factor (factoring *factoring, next_score = lit_score; next = lit; } - assert (next_score >= 0); - assert (next != INVALID_LIT); + KISSAT_assert (next_score >= 0); + KISSAT_assert (next != INVALID_LIT); LOG ("best score %g of next factor %s", next_score, LOGLIT (next)); } else { - assert (ties == 1); + KISSAT_assert (ties == 1); LOG ("single next factor %s with count %u", LOGLIT (next), next_count); } @@ -491,7 +502,7 @@ static unsigned next_factor (factoring *factoring, for (all_stack (unsigned, lit, *counted)) count[lit] = 0; CLEAR_STACK (*counted); - assert (next == INVALID_LIT || next_count > 1); + KISSAT_assert (next == INVALID_LIT || next_count > 1); *next_count_ptr = next_count; return next; } @@ -506,12 +517,12 @@ static void factorize_next (factoring *factoring, unsigned next, ward *const arena = BEGIN_STACK (solver->arena); mark *marks = solver->marks; - assert (last_quotient); + KISSAT_assert (last_quotient); statches *last_clauses = &last_quotient->clauses; statches *next_clauses = &next_quotient->clauses; sizes *matches = &next_quotient->matches; references *qlauses = &factoring->qlauses; - assert (EMPTY_STACK (*qlauses)); + KISSAT_assert (EMPTY_STACK (*qlauses)); uint64_t ticks = 1 + kissat_cache_lines (SIZE_STACK (*last_clauses), sizeof (watch)); @@ -535,7 +546,7 @@ static void factorize_next (factoring *factoring, unsigned next, } else { const reference c_ref = last_watch.large.ref; clause *const c = (clause *) (arena + c_ref); - assert (!c->quotient); + KISSAT_assert (!c->quotient); unsigned min_lit = INVALID_LIT, factors = 0; size_t min_size = 0; ticks++; @@ -544,7 +555,7 @@ static void factorize_next (factoring *factoring, unsigned next, if (factors++) break; } else { - assert (!(marks[other] & QUOTIENT)); + KISSAT_assert (!(marks[other] & QUOTIENT)); marks[other] |= QUOTIENT; watches *other_watches = all_watches + other; const size_t other_size = SIZE_WATCHES (*other_watches); @@ -554,9 +565,9 @@ static void factorize_next (factoring *factoring, unsigned next, min_size = other_size; } } - assert (factors); + KISSAT_assert (factors); if (factors == 1) { - assert (min_lit != INVALID_LIT); + KISSAT_assert (min_lit != INVALID_LIT); watches *min_watches = all_watches + min_lit; unsigned c_size = c->size; ticks += 1 + kissat_cache_lines (SIZE_WATCHES (*min_watches), @@ -599,7 +610,7 @@ static void factorize_next (factoring *factoring, unsigned next, clear_qlauses (solver, qlauses); ADD (factor_ticks, ticks); - assert (expected_next_count <= SIZE_STACK (*next_clauses)); + KISSAT_assert (expected_next_count <= SIZE_STACK (*next_clauses)); (void) expected_next_count; } @@ -643,9 +654,9 @@ static quotient *best_quotient (factoring *factoring, static void resize_factoring (factoring *factoring, unsigned lit) { kissat *const solver = factoring->solver; - assert (lit > NOT (lit)); + KISSAT_assert (lit > NOT (lit)); const size_t old_size = factoring->size; - assert (lit > old_size); + KISSAT_assert (lit > old_size); const size_t old_allocated = factoring->allocated; size_t new_size = lit + 1; if (new_size > old_allocated) { @@ -653,20 +664,20 @@ static void resize_factoring (factoring *factoring, unsigned lit) { while (new_size > new_allocated) new_allocated *= 2; unsigned *count = factoring->count; - count = kissat_nrealloc (solver, count, old_allocated, new_allocated, + count = (unsigned*)kissat_nrealloc (solver, count, old_allocated, new_allocated, sizeof *count); const size_t delta_allocated = new_allocated - old_allocated; const size_t delta_bytes = delta_allocated * sizeof *count; memset (count + old_size, 0, delta_bytes); factoring->count = count; - assert (!(old_allocated & 1)); - assert (!(new_allocated & 1)); + KISSAT_assert (!(old_allocated & 1)); + KISSAT_assert (!(new_allocated & 1)); const size_t old_allocated_score = old_allocated / 2; const size_t new_allocated_score = new_allocated / 2; for (unsigned i = 0; i != factoring->hops; i++) { scores *scores = factoring->scores + i; double *score = scores->score; - score = kissat_nrealloc (solver, score, old_allocated_score, + score = (double*)kissat_nrealloc (solver, score, old_allocated_score, new_allocated_score, sizeof *score); for (size_t i = old_allocated_score; i != new_allocated_score; i++) score[i] = -1; @@ -682,12 +693,12 @@ static void flush_unmatched_clauses (kissat *solver, quotient *q) { sizes *q_matches = &q->matches, *prev_matches = &prev->matches; statches *q_clauses = &q->clauses, *prev_clauses = &prev->clauses; const size_t n = SIZE_STACK (*q_clauses); - assert (n == SIZE_STACK (*q_matches)); + KISSAT_assert (n == SIZE_STACK (*q_matches)); bool prev_is_first = !prev->id; size_t i = 0; while (i != n) { size_t j = PEEK_STACK (*q_matches, i); - assert (i <= j); + KISSAT_assert (i <= j); if (!prev_is_first) { size_t matches = PEEK_STACK (*prev_matches, j); POKE_STACK (*prev_matches, i, matches); @@ -728,22 +739,22 @@ static void add_factored_quotient (factoring *factoring, quotient *q, const reference c_ref = watch.large.ref; clause *const c = kissat_dereference_clause (solver, c_ref); unsigneds *clause = &solver->clause; - assert (EMPTY_STACK (*clause)); + KISSAT_assert (EMPTY_STACK (*clause)); const unsigned factor = q->factor; -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG bool found = false; #endif PUSH_STACK (*clause, not_fresh); for (all_literals_in_clause (other, c)) { if (other == factor) { -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG found = true; #endif continue; } PUSH_STACK (*clause, other); } - assert (found); + KISSAT_assert (found); ADD (literals_factored, c->size); kissat_new_irredundant_clause (solver); CLEAR_STACK (*clause); @@ -756,10 +767,10 @@ static void eagerly_remove_watch (kissat *solver, watches *watches, watch needle) { watch *p = BEGIN_WATCHES (*watches); watch *end = END_WATCHES (*watches); - assert (p != end); + KISSAT_assert (p != end); watch *last = end - 1; while (p->raw != needle.raw) - p++, assert (p != end); + p++, KISSAT_assert (p != end); if (p != last) memmove (p, p + 1, (last - p) * sizeof *p); SET_END_OF_WATCHES (*watches, last); @@ -833,7 +844,7 @@ static bool apply_factoring (factoring *factoring, quotient *q) { delete_unfactored (factoring, p); for (quotient *p = q; p; p = p->prev) update_factored (factoring, p); - assert (fresh < not_fresh); + KISSAT_assert (fresh < not_fresh); resize_factoring (factoring, not_fresh); return true; } @@ -871,16 +882,16 @@ adjust_scores_and_phases_of_fresh_varaibles (factoring *factoring) { const unsigned idx = IDX (lit); struct links *l = links + idx; if (DISCONNECTED (queue->first)) { - assert (DISCONNECTED (queue->last)); + KISSAT_assert (DISCONNECTED (queue->last)); queue->last = idx; } else { struct links *first = links + queue->first; - assert (DISCONNECTED (first->prev)); + KISSAT_assert (DISCONNECTED (first->prev)); first->prev = idx; } l->next = queue->first; queue->first = idx; - assert (DISCONNECTED (l->prev)); + KISSAT_assert (DISCONNECTED (l->prev)); l->stamp = ++queue->stamp; } while (!DISCONNECTED (rest)) { @@ -898,10 +909,10 @@ static bool run_factorization (kissat *solver, uint64_t limit) { init_factoring (solver, &factoring, limit); schedule_factorization (&factoring); bool done = false; -#ifndef QUIET +#ifndef KISSAT_QUIET unsigned factored = 0; #endif - uint64_t *ticks = &solver->statistics.factor_ticks; + uint64_t *ticks = &solver->statistics_.factor_ticks; kissat_extremely_verbose ( solver, "factorization limit of %" PRIu64 " ticks", limit - *ticks); while (!done && !kissat_empty_heap (&factoring.schedule)) { @@ -928,7 +939,7 @@ static bool run_factorization (kissat *solver, uint64_t limit) { const unsigned next = next_factor (&factoring, &next_count); if (next == INVALID_LIT) break; - assert (next_count > 1); + KISSAT_assert (next_count > 1); if (next_count < 2) break; factorize_next (&factoring, next, next_count); @@ -937,7 +948,7 @@ static bool run_factorization (kissat *solver, uint64_t limit) { quotient *q = best_quotient (&factoring, &reduction); if (q && reduction > factoring.bound) { if (apply_factoring (&factoring, q)) { -#ifndef QUIET +#ifndef KISSAT_QUIET factored++; #endif } else @@ -965,12 +976,12 @@ static void connect_clauses_to_factor (kissat *solver) { ward *const arena = BEGIN_STACK (solver->arena); watches *all_watches = solver->watches; unsigned *bincount, *largecount; - CALLOC (bincount, LITS); + CALLOC (unsigned, bincount, LITS); for (all_literals (lit)) { if (!ACTIVE (IDX (lit))) continue; for (all_binary_large_watches (watch, WATCHES (lit))) { - assert (watch.type.binary); + KISSAT_assert (watch.type.binary); const unsigned other = watch.type.lit; if (lit > other) continue; @@ -978,7 +989,7 @@ static void connect_clauses_to_factor (kissat *solver) { bincount[other]++; } } - CALLOC (largecount, LITS); + CALLOC (unsigned, largecount, LITS); size_t initial_candidates = 0; for (all_clauses (c)) { if (c->garbage) @@ -1001,7 +1012,7 @@ static void connect_clauses_to_factor (kissat *solver) { for (unsigned round = 1; round <= rounds; round++) { size_t new_candidates = 0; unsigned *newlargecount; - CALLOC (newlargecount, LITS); + CALLOC (unsigned, newlargecount, LITS); for (all_clauses (c)) { if (c->garbage) continue; @@ -1035,7 +1046,7 @@ static void connect_clauses_to_factor (kissat *solver) { "round %u", candidates, kissat_percent (candidates, initial_candidates), round); } -#ifndef QUIET +#ifndef KISSAT_QUIET size_t connected = 0; #endif for (all_clauses (c)) { @@ -1047,15 +1058,20 @@ static void connect_clauses_to_factor (kissat *solver) { continue; if (c->size > size_limit) continue; + int continue_with_next_clause2 = 0; for (all_literals_in_clause (lit, c)) - if (bincount[lit] + largecount[lit] < 2) - goto CONTINUE_WITH_NEXT_CLAUSE2; + if (bincount[lit] + largecount[lit] < 2) { + continue_with_next_clause2 = 1; + break; + } + if(continue_with_next_clause2) { + continue; + } const reference ref = (ward *) c - arena; kissat_inlined_connect_clause (solver, all_watches, c, ref); -#ifndef QUIET +#ifndef KISSAT_QUIET connected++; #endif - CONTINUE_WITH_NEXT_CLAUSE2:; } DEALLOC (largecount, LITS); DEALLOC (bincount, LITS); @@ -1065,12 +1081,12 @@ static void connect_clauses_to_factor (kissat *solver) { } void kissat_factor (kissat *solver) { - assert (!solver->level); + KISSAT_assert (!solver->level); if (solver->inconsistent) return; if (!GET_OPTION (factor)) return; - statistics *s = &solver->statistics; + statistics *s = &solver->statistics_; if (solver->limits.factor.marked >= s->literals_factor) { kissat_extremely_verbose ( solver, @@ -1095,7 +1111,7 @@ void kissat_factor (kissat *solver) { limit *= 1e6; limit += s->factor_ticks; } -#ifndef QUIET +#ifndef KISSAT_QUIET struct { int64_t variables, binary, clauses, ticks; } before, after, delta; @@ -1108,7 +1124,7 @@ void kissat_factor (kissat *solver) { connect_clauses_to_factor (solver); bool completed = run_factorization (solver, limit); kissat_resume_sparse_mode (solver, false, 0); -#ifndef QUIET +#ifndef KISSAT_QUIET after.variables = s->variables_extension + s->variables_original; after.binary = BINARY_CLAUSES; after.clauses = IRREDUNDANT_CLAUSES; @@ -1134,3 +1150,5 @@ void kissat_factor (kissat *solver) { solver->limits.factor.marked = s->literals_factor; STOP (factor); } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/factor.h b/src/sat/kissat/factor.h index 0223186cf..fd433c8eb 100644 --- a/src/sat/kissat/factor.h +++ b/src/sat/kissat/factor.h @@ -3,7 +3,12 @@ #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + struct kissat; void kissat_factor (struct kissat *); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/fastassign.h b/src/sat/kissat/fastassign.h index 6951ed893..c0ad7b9ce 100644 --- a/src/sat/kissat/fastassign.h +++ b/src/sat/kissat/fastassign.h @@ -6,6 +6,9 @@ #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) { @@ -27,15 +30,17 @@ static inline void kissat_fast_assign_reference (kissat *solver, value *values, assigned *assigned, unsigned lit, reference ref, clause *reason) { - assert (reason == kissat_dereference_clause (solver, ref)); + KISSAT_assert (reason == kissat_dereference_clause (solver, ref)); const unsigned level = kissat_assignment_level (solver, values, assigned, lit, reason); - assert (level <= solver->level); - assert (ref != DECISION_REASON); - assert (ref != UNIT_REASON); + KISSAT_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 diff --git a/src/sat/kissat/fastel.c b/src/sat/kissat/fastel.c index 64ddccf3a..a6de22f82 100644 --- a/src/sat/kissat/fastel.c +++ b/src/sat/kissat/fastel.c @@ -9,9 +9,11 @@ #include "terminate.h" #include "weaken.h" +ABC_NAMESPACE_IMPL_START + static bool fast_forward_subsumed (kissat *solver, clause *c) { - assert (!c->garbage); - assert (!c->redundant); + KISSAT_assert (!c->garbage); + KISSAT_assert (!c->redundant); unsigned max_occurring = INVALID_LIT; size_t max_occurrence = 0; watches *all_watches = solver->watches; @@ -58,7 +60,7 @@ static bool fast_forward_subsumed (kissat *solver, clause *c) { continue; if (d->size > c->size) continue; - assert (!d->redundant); + KISSAT_assert (!d->redundant); subsumed = true; for (all_literals_in_clause (other2, d)) { if (values[other2] < 0) @@ -147,8 +149,8 @@ static size_t flush_occurrences (kissat *solver, unsigned lit) { static void do_fast_resolve_binary_binary (kissat *solver, unsigned pivot, unsigned clit, unsigned dlit) { - assert (!FLAGS (IDX (clit))->eliminated); - assert (!FLAGS (IDX (dlit))->eliminated); + KISSAT_assert (!FLAGS (IDX (clit))->eliminated); + KISSAT_assert (!FLAGS (IDX (dlit))->eliminated); if (clit == NOT (dlit)) { LOG ("resolvent tautological"); return; @@ -165,7 +167,7 @@ static void do_fast_resolve_binary_binary (kissat *solver, unsigned pivot, return; } if (cval < 0 && dval < 0) { - assert (!solver->inconsistent); + KISSAT_assert (!solver->inconsistent); solver->inconsistent = true; LOG ("resolved empty clause"); CHECK_AND_ADD_EMPTY (); @@ -190,10 +192,10 @@ static void do_fast_resolve_binary_binary (kissat *solver, unsigned pivot, kissat_learned_unit (solver, clit); return; } - assert (!cval); - assert (!dval); + KISSAT_assert (!cval); + KISSAT_assert (!dval); unsigneds *clause = &solver->clause; - assert (EMPTY_STACK (*clause)); + KISSAT_assert (EMPTY_STACK (*clause)); PUSH_STACK (*clause, clit); PUSH_STACK (*clause, dlit); LOGTMP ("%s resolvent", LOGVAR (pivot)); @@ -206,10 +208,10 @@ static void do_fast_resolve_binary_binary (kissat *solver, unsigned pivot, static void do_fast_resolve_binary_large (kissat *solver, unsigned pivot, unsigned lit, clause *c) { - assert (!FLAGS (IDX (lit))->eliminated); + KISSAT_assert (!FLAGS (IDX (lit))->eliminated); if (c->garbage) return; - assert (!c->redundant); + KISSAT_assert (!c->redundant); value *values = solver->values; value lit_val = values[lit]; if (lit_val > 0) { @@ -217,7 +219,7 @@ static void do_fast_resolve_binary_large (kissat *solver, unsigned pivot, return; } unsigneds *clause = &solver->clause; - assert (EMPTY_STACK (*clause)); + KISSAT_assert (EMPTY_STACK (*clause)); if (!lit_val) PUSH_STACK (*clause, lit); bool satisfied = false, tautological = false; @@ -250,7 +252,7 @@ static void do_fast_resolve_binary_large (kissat *solver, unsigned pivot, } size_t size = SIZE_STACK (*clause); if (!size) { - assert (!solver->inconsistent); + KISSAT_assert (!solver->inconsistent); solver->inconsistent = true; LOG ("resolved empty clause"); CHECK_AND_ADD_EMPTY (); @@ -276,12 +278,12 @@ static void do_fast_resolve_large_large (kissat *solver, unsigned pivot, return; if (d->garbage) return; - assert (!c->redundant); - assert (!d->redundant); + KISSAT_assert (!c->redundant); + KISSAT_assert (!d->redundant); value *values = solver->values; mark *marks = solver->marks; unsigneds *clause = &solver->clause; - assert (EMPTY_STACK (*clause)); + KISSAT_assert (EMPTY_STACK (*clause)); bool satisfied = false, tautological = false; for (all_literals_in_clause (other, c)) { const unsigned idx_other = IDX (other); @@ -337,7 +339,7 @@ static void do_fast_resolve_large_large (kissat *solver, unsigned pivot, } size_t size = SIZE_STACK (*clause); if (!size) { - assert (!solver->inconsistent); + KISSAT_assert (!solver->inconsistent); solver->inconsistent = true; LOG ("resolved empty clause"); CHECK_AND_ADD_EMPTY (); @@ -363,7 +365,7 @@ static void do_fast_resolve_large_large (kissat *solver, unsigned pivot, static void do_fast_resolve (kissat *solver, unsigned pivot, watch cwatch, watch dwatch) { - assert (!solver->inconsistent); + 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", @@ -383,7 +385,7 @@ static void do_fast_resolve (kissat *solver, unsigned pivot, watch cwatch, else if (!cbin && dbin) do_fast_resolve_binary_large (solver, pivot, dlit, c); else { - assert (!cbin), assert (!dbin); + KISSAT_assert (!cbin), KISSAT_assert (!dbin); do_fast_resolve_large_large (solver, pivot, c, d); } } @@ -449,7 +451,7 @@ static void do_fast_eliminate (kissat *solver, unsigned pivot) { p = begin_lit_watches + i; q = begin_not_lit_watches + j; } - assert (!solver->inconsistent); + KISSAT_assert (!solver->inconsistent); INC (eliminated); INC (fast_eliminated); kissat_mark_eliminated_variable (solver, pivot); @@ -459,8 +461,8 @@ static void do_fast_eliminate (kissat *solver, unsigned pivot) { static bool can_fast_resolve_binary_binary (kissat *solver, unsigned clit, unsigned dlit) { - assert (!FLAGS (IDX (clit))->eliminated); - assert (!FLAGS (IDX (dlit))->eliminated); + KISSAT_assert (!FLAGS (IDX (clit))->eliminated); + KISSAT_assert (!FLAGS (IDX (dlit))->eliminated); if (clit == NOT (dlit)) return false; value *values = solver->values; @@ -471,7 +473,7 @@ static bool can_fast_resolve_binary_binary (kissat *solver, unsigned clit, if (dval > 0) return false; if (cval < 0 && dval < 0) { - assert (!solver->inconsistent); + KISSAT_assert (!solver->inconsistent); solver->inconsistent = true; LOG ("resolved empty clause"); CHECK_AND_ADD_EMPTY (); @@ -496,17 +498,17 @@ static bool can_fast_resolve_binary_binary (kissat *solver, unsigned clit, kissat_learned_unit (solver, clit); return false; } - assert (!cval); - assert (!dval); + KISSAT_assert (!cval); + KISSAT_assert (!dval); return true; } static bool can_fast_resolve_binary_large (kissat *solver, unsigned pivot, unsigned lit, clause *c) { - assert (!FLAGS (IDX (lit))->eliminated); + KISSAT_assert (!FLAGS (IDX (lit))->eliminated); if (c->garbage) return false; - assert (!c->redundant); + KISSAT_assert (!c->redundant); value *values = solver->values; value lit_val = values[lit]; if (lit_val > 0) @@ -527,7 +529,7 @@ static bool can_fast_resolve_binary_large (kissat *solver, unsigned pivot, } if (found_lit) { unsigneds *clause = &solver->clause; - assert (EMPTY_STACK (*clause)); + KISSAT_assert (EMPTY_STACK (*clause)); for (all_literals_in_clause (other, c)) { const unsigned idx = IDX (other); if (idx == pivot) @@ -535,7 +537,7 @@ static bool can_fast_resolve_binary_large (kissat *solver, unsigned pivot, value value = values[other]; if (value < 0) continue; - assert (!value); + KISSAT_assert (!value); PUSH_STACK (*clause, other); } LOGTMP ("self-subsuming resolvent"); @@ -544,7 +546,7 @@ static bool can_fast_resolve_binary_large (kissat *solver, unsigned pivot, const size_t size = SIZE_STACK (*clause); const reference ref = kissat_reference_clause (solver, c); if (!size) { - assert (!solver->inconsistent); + KISSAT_assert (!solver->inconsistent); solver->inconsistent = true; LOG ("resolved empty clause"); CHECK_AND_ADD_EMPTY (); @@ -571,13 +573,13 @@ static bool can_fast_resolve_large_large (kissat *solver, unsigned pivot, return false; if (d->garbage) return false; - assert (!c->redundant); - assert (!d->redundant); + KISSAT_assert (!c->redundant); + KISSAT_assert (!d->redundant); value *values = solver->values; mark *marks = solver->marks; bool satisfied = false; unsigneds *clause = &solver->clause; - assert (EMPTY_STACK (*clause)); + KISSAT_assert (EMPTY_STACK (*clause)); for (all_literals_in_clause (other, c)) { const unsigned idx_other = IDX (other); if (idx_other == pivot) @@ -591,7 +593,7 @@ static bool can_fast_resolve_large_large (kissat *solver, unsigned pivot, kissat_mark_clause_as_garbage (solver, c); break; } - assert (!marks[other]); + KISSAT_assert (!marks[other]); marks[other] = 1; PUSH_STACK (*clause, other); } @@ -628,7 +630,7 @@ static bool can_fast_resolve_large_large (kissat *solver, unsigned pivot, if (!satisfied && !tautological) { const size_t size = SIZE_STACK (*clause); if (!size) { - assert (!solver->inconsistent); + KISSAT_assert (!solver->inconsistent); solver->inconsistent = true; LOG ("resolved empty clause"); CHECK_AND_ADD_EMPTY (); @@ -698,7 +700,7 @@ static bool can_fast_resolve_large_large (kissat *solver, unsigned pivot, static bool can_fast_resolve (kissat *solver, unsigned pivot, watch cwatch, watch dwatch) { - assert (!solver->inconsistent); + KISSAT_assert (!solver->inconsistent); const unsigned clit = cwatch.binary.lit; const unsigned dlit = dwatch.binary.lit; const reference cref = cwatch.large.ref; @@ -713,7 +715,7 @@ static bool can_fast_resolve (kissat *solver, unsigned pivot, watch cwatch, return can_fast_resolve_binary_large (solver, pivot, clit, d); if (!cbin && dbin) return can_fast_resolve_binary_large (solver, pivot, dlit, c); - assert (!cbin), assert (!dbin); + KISSAT_assert (!cbin), KISSAT_assert (!dbin); return can_fast_resolve_large_large (solver, pivot, c, d); } @@ -752,7 +754,7 @@ static bool resolvents_limited (kissat *solver, unsigned pivot, } static bool try_to_fast_eliminate (kissat *solver, unsigned pivot) { - assert (!solver->inconsistent); + KISSAT_assert (!solver->inconsistent); if (!ACTIVE (pivot)) return false; const unsigned lit = LIT (pivot); @@ -824,16 +826,16 @@ void kissat_fast_variable_elimination (kissat *solver) { return; if (!GET_OPTION (fastel)) return; -#ifndef QUIET +#ifndef KISSAT_QUIET const unsigned variables_before = solver->active; #endif - assert (!solver->level); + 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 QUIET +#ifndef KISSAT_QUIET unsigned eliminated = 0; #endif unsigned round = 0; @@ -846,7 +848,7 @@ void kissat_fast_variable_elimination (kissat *solver) { kissat_extremely_verbose ( solver, "gathering candidates for fast elimination round %u", round); - assert (EMPTY_STACK (candidates)); + KISSAT_assert (EMPTY_STACK (candidates)); flags *all_flags = solver->flags; for (all_variables (pivot)) { flags *pivot_flags = all_flags + pivot; @@ -868,7 +870,7 @@ void kissat_fast_variable_elimination (kissat *solver) { candidate candidate = {pivot, score}; PUSH_STACK (candidates, candidate); } -#ifndef QUIET +#ifndef KISSAT_QUIET const size_t size_candidates = SIZE_STACK (candidates); const size_t active_variables = solver->active; kissat_extremely_verbose ( @@ -903,7 +905,7 @@ void kissat_fast_variable_elimination (kissat *solver) { } } CLEAR_STACK (candidates); -#ifndef QUIET +#ifndef KISSAT_QUIET eliminated += eliminated_this_round; kissat_very_verbose ( solver, "fast eliminated %u of %zu candidates %.0f%% in round %u", @@ -918,7 +920,7 @@ void kissat_fast_variable_elimination (kissat *solver) { FLAGS (idx)->eliminate = true; flush_eliminated_binary_clauses (solver); kissat_resume_sparse_mode (solver, true, 0); -#ifndef QUIET +#ifndef KISSAT_QUIET const unsigned original_variables = solver->statistics.variables_original; const unsigned variables_after = solver->active; kissat_verbose ( @@ -932,3 +934,5 @@ void kissat_fast_variable_elimination (kissat *solver) { STOP (fastel); REPORT (!eliminated, 'e'); } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/fastel.h b/src/sat/kissat/fastel.h index a2a5cfcd5..56d711edd 100644 --- a/src/sat/kissat/fastel.h +++ b/src/sat/kissat/fastel.h @@ -1,6 +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 diff --git a/src/sat/kissat/fifo.h b/src/sat/kissat/fifo.h index 508989aa5..b94cfa628 100644 --- a/src/sat/kissat/fifo.h +++ b/src/sat/kissat/fifo.h @@ -5,6 +5,9 @@ #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + #define FIFO(TYPE) \ struct { \ TYPE *begin; \ @@ -29,7 +32,7 @@ #define MOVABLE_FIFO(F) (BEGIN_FIFO (F) == LIMIT_FIFO (F)) #define CAPACITY_FIFO(F) (ALLOCATED_FIFO (F) - START_FIFO (F)) -#define ENLARGE_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); \ @@ -38,12 +41,12 @@ size_t OLD_BYTES = OLD_CAPACITY * sizeof *BEGIN_FIFO (F); \ size_t NEW_BYTES = NEW_CAPACITY * sizeof *BEGIN_FIFO (F); \ START_FIFO (F) = \ - kissat_realloc (solver, START_FIFO (F), OLD_BYTES, NEW_BYTES); \ + (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; \ - assert (BEGIN_FIFO (F) < LIMIT_FIFO (F)); \ + KISSAT_assert (BEGIN_FIFO (F) < LIMIT_FIFO (F)); \ } while (0) #define MOVE_FIFO(F) \ @@ -55,22 +58,22 @@ END_FIFO (F) = BEGIN_FIFO (F) + SIZE; \ } while (0) -#define ENQUEUE_FIFO(F, E) \ +#define ENQUEUE_FIFO(T, F, E) \ do { \ if (FULL_FIFO (F)) \ - ENLARGE_FIFO (F); \ + ENLARGE_FIFO (T, F); \ *END_FIFO (F)++ = (E); \ } while (0) #define DEQUEUE_FIFO(F, E) \ do { \ - assert (!EMPTY_FIFO (F)); \ + KISSAT_assert (!EMPTY_FIFO (F)); \ (E) = *BEGIN_FIFO (F)++; \ if (MOVABLE_FIFO (F)) \ MOVE_FIFO (F); \ } while (0) -#define POP_FIFO(F) (assert (!EMPTY_FIFO (F)), *--END_FIFO (F)) +#define POP_FIFO(F) (KISSAT_assert (!EMPTY_FIFO (F)), *--END_FIFO (F)) #define RELEASE_FIFO(F) \ do { \ @@ -94,4 +97,6 @@ typedef struct unsigned_fifo unsigned_fifo; #define all_fifo all_stack +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/file.c b/src/sat/kissat/file.c index b6bda097b..e4486783d 100644 --- a/src/sat/kissat/file.c +++ b/src/sat/kissat/file.c @@ -7,7 +7,17 @@ #include #include #include + +#ifdef WIN32 +#define unlink _unlink +#define access _access +#define R_OK 4 +#define W_OK 2 +#else #include +#endif + +ABC_NAMESPACE_IMPL_START bool kissat_file_exists (const char *path) { if (!path) @@ -57,7 +67,7 @@ bool kissat_file_writable (const char *path) { res = 5; else { const size_t len = p - path; - char *dirname = malloc (len + 1); + char *dirname = (char*)malloc (len + 1); if (dirname) { strncpy (dirname, path, len); dirname[len] = 0; @@ -98,7 +108,7 @@ bool kissat_find_executable (const char *name) { if (!environment) return false; const size_t dirs_len = strlen (environment); - char *dirs = malloc (dirs_len + 1); + char *dirs = (char*)malloc (dirs_len + 1); if (!dirs) return false; strcpy (dirs, environment); @@ -106,16 +116,16 @@ bool kissat_find_executable (const char *name) { const char *end = dirs + dirs_len + 1; for (char *dir = dirs, *q; !res && dir != end; dir = q) { for (q = dir; *q && *q != ':'; q++) - assert (q + 1 < end); + KISSAT_assert (q + 1 < end); *q++ = 0; const size_t path_len = (q - dir) + name_len; - char *path = malloc (path_len + 1); + char *path = (char*)malloc (path_len + 1); if (!path) { free (dirs); return false; } sprintf (path, "%s/%s", dir, name); - assert (strlen (path) == path_len); + KISSAT_assert (strlen (path) == path_len); res = kissat_file_readable (path); free (path); } @@ -131,7 +141,7 @@ static int xzsig[] = {0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, EOF}; static int Zsig[] = {0x1F, 0x9D, 0x90, EOF}; static bool match_signature (const char *path, const int *sig) { - assert (path); + KISSAT_assert (path); FILE *tmp = fopen (path, "r"); if (!tmp) return false; @@ -149,7 +159,7 @@ static FILE *open_pipe (const char *fmt, const char *path, size_t name_len = 0; while (fmt[name_len] && fmt[name_len] != ' ') name_len++; - char *name = malloc (name_len + 1); + char *name = (char*)malloc (name_len + 1); if (!name) return 0; strncpy (name, fmt, name_len); @@ -158,7 +168,7 @@ static FILE *open_pipe (const char *fmt, const char *path, free (name); if (!found) return 0; - char *cmd = malloc (strlen (fmt) + strlen (path)); + char *cmd = (char*)malloc (strlen (fmt) + strlen (path)); if (!cmd) return 0; sprintf (cmd, fmt, path); @@ -296,15 +306,17 @@ bool kissat_open_to_write_file (file *file, const char *path) { } void kissat_close_file (file *file) { - assert (file); - assert (file->file); + KISSAT_assert (file); + KISSAT_assert (file->file); #ifdef KISSAT_HAS_COMPRESSION if (file->close && file->compressed) pclose (file->file); #else - assert (!file->compressed); + KISSAT_assert (!file->compressed); #endif if (file->close && !file->compressed) fclose (file->file); file->file = 0; } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/file.h b/src/sat/kissat/file.h index 300cdb138..7658fa7d2 100644 --- a/src/sat/kissat/file.h +++ b/src/sat/kissat/file.h @@ -9,6 +9,9 @@ #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); @@ -57,9 +60,9 @@ static inline void kissat_flush (file *) ATTRIBUTE_ALWAYS_INLINE; // clang-format on static inline size_t kissat_read (file *file, void *ptr, size_t bytes) { - assert (file); - assert (file->file); - assert (file->reading); + 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 @@ -70,9 +73,9 @@ static inline size_t kissat_read (file *file, void *ptr, size_t bytes) { } static inline size_t kissat_write (file *file, void *ptr, size_t bytes) { - assert (file); - assert (file->file); - assert (!file->reading); + 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 @@ -83,9 +86,9 @@ static inline size_t kissat_write (file *file, void *ptr, size_t bytes) { } static inline int kissat_getc (file *file) { - assert (file); - assert (file->file); - assert (file->reading); + KISSAT_assert (file); + KISSAT_assert (file->file); + KISSAT_assert (file->reading); #ifdef KISSAT_HAS_UNLOCKEDIO int res = getc_unlocked (file->file); #else @@ -97,9 +100,9 @@ static inline int kissat_getc (file *file) { } static inline int kissat_putc (file *file, int ch) { - assert (file); - assert (file->file); - assert (!file->reading); + KISSAT_assert (file); + KISSAT_assert (file->file); + KISSAT_assert (!file->reading); #ifdef KISSAT_HAS_UNLOCKEDIO int res = putc_unlocked (ch, file->file); #else @@ -111,9 +114,9 @@ static inline int kissat_putc (file *file, int ch) { } static inline void kissat_flush (file *file) { - assert (file); - assert (file->file); - assert (!file->reading); + KISSAT_assert (file); + KISSAT_assert (file->file); + KISSAT_assert (!file->reading); #ifdef KISSAT_HAS_UNLOCKEDIO fflush_unlocked (file->file); #else @@ -121,4 +124,6 @@ static inline void kissat_flush (file *file) { #endif } +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/flags.c b/src/sat/kissat/flags.c index b7189350e..86a6d6186 100644 --- a/src/sat/kissat/flags.c +++ b/src/sat/kissat/flags.c @@ -2,6 +2,8 @@ #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); @@ -10,37 +12,37 @@ static inline void activate_literal (kissat *solver, unsigned lit) { lit = STRIP (lit); LOG ("activating %s", LOGVAR (idx)); f->active = true; - assert (!f->fixed); - assert (!f->eliminated); + 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; + const double score = 1.0 - 1.0 / solver->statistics_.variables_activated; kissat_update_heap (solver, &solver->scores, idx, score); if (solver->stable) { const unsigned lit = LIT (idx); if (!VALUE (lit)) kissat_push_heap (solver, &solver->scores, idx); } - assert (solver->unassigned < UINT_MAX); + KISSAT_assert (solver->unassigned < UINT_MAX); solver->unassigned++; kissat_mark_removed_literal (solver, lit); kissat_mark_added_literal (solver, lit); - assert (!VALUE (lit)); - assert (!VALUE (NOT (lit))); - assert (!SAVED (idx)); - assert (!TARGET (idx)); - assert (!BEST (idx)); + 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) { - assert (solver->flags + idx == f); + KISSAT_assert (solver->flags + idx == f); LOG ("deactivating %s", LOGVAR (idx)); - assert (f->active); - assert (f->eliminated || f->fixed); + KISSAT_assert (f->active); + KISSAT_assert (f->eliminated || f->fixed); f->active = false; - assert (solver->active > 0); + KISSAT_assert (solver->active > 0); solver->active--; kissat_dequeue (solver, idx); if (kissat_heap_contains (SCORES, idx)) @@ -58,47 +60,47 @@ void kissat_activate_literals (kissat *solver, unsigned size, } void kissat_mark_fixed_literal (kissat *solver, unsigned lit) { - assert (VALUE (lit) > 0); + KISSAT_assert (VALUE (lit) > 0); const unsigned idx = IDX (lit); LOG ("marking internal %s as fixed", LOGVAR (idx)); flags *f = FLAGS (idx); - assert (f->active); - assert (!f->eliminated); - assert (!f->fixed); + 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); - assert (elit); + 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); - assert (!VALUE (lit)); + KISSAT_assert (!VALUE (lit)); LOG ("marking internal %s as eliminated", LOGVAR (idx)); flags *f = FLAGS (idx); - assert (f->active); - assert (!f->eliminated); - assert (!f->fixed); + 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); - assert (elit); - assert (elit != INT_MIN); + KISSAT_assert (elit); + KISSAT_assert (elit != INT_MIN); unsigned eidx = ABS (elit); import *import = &PEEK_STACK (solver->import, eidx); - assert (!import->eliminated); - assert (import->imported); - assert (STRIP (import->lit) == STRIP (lit)); + KISSAT_assert (!import->eliminated); + KISSAT_assert (import->imported); + KISSAT_assert (STRIP (import->lit) == STRIP (lit)); size_t pos = SIZE_STACK (solver->eliminated); - assert (pos < (1u << 30)); + 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); - assert (solver->unassigned > 0); + KISSAT_assert (solver->unassigned > 0); solver->unassigned--; } @@ -113,3 +115,5 @@ void kissat_mark_added_literals (kissat *solver, unsigned size, for (unsigned i = 0; i < size; i++) kissat_mark_added_literal (solver, lits[i]); } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/flags.h b/src/sat/kissat/flags.h index fd73b2f5b..33248314a 100644 --- a/src/sat/kissat/flags.h +++ b/src/sat/kissat/flags.h @@ -3,6 +3,9 @@ #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + typedef struct flags flags; struct flags { @@ -18,7 +21,7 @@ struct flags { bool transitive : 1; }; -#define FLAGS(IDX) (assert ((IDX) < VARS), (solver->flags + (IDX))) +#define FLAGS(IDX) (KISSAT_assert ((IDX) < VARS), (solver->flags + (IDX))) #define ACTIVE(IDX) (FLAGS (IDX)->active) #define ELIMINATED(IDX) (FLAGS (IDX)->eliminated) @@ -34,4 +37,6 @@ 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 diff --git a/src/sat/kissat/format.c b/src/sat/kissat/format.c index d8e247d1a..b091a86bb 100644 --- a/src/sat/kissat/format.c +++ b/src/sat/kissat/format.c @@ -7,8 +7,10 @@ #include #include -char *kissat_next_format_string (format *format) { - assert (format->pos < NUM_FORMAT_STRINGS); +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; @@ -19,7 +21,7 @@ static void format_count (char *res, uint64_t w) { if (w >= 128 && kissat_is_power_of_two (w)) { unsigned l; for (l = 0; ((uint64_t) 1 << l) != w; l++) - assert (l + 1 < 8 * sizeof (word)); + KISSAT_assert (l + 1 < 8 * sizeof (word)); sprintf (res, "2^%u", l); } else if (w >= 1000 && !(w % 1000)) { unsigned l; @@ -30,13 +32,13 @@ static void format_count (char *res, uint64_t w) { sprintf (res, "%" PRIu64, w); } -const char *kissat_format_count (format *format, uint64_t 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 (format *format, bool boolean, int value) { +const char *kissat_format_value (kormat *format, bool boolean, int value) { if (boolean && value) return "true"; if (boolean && !value) @@ -54,7 +56,7 @@ const char *kissat_format_value (format *format, bool boolean, int value) { return res; } -const char *kissat_format_bytes (format *format, uint64_t bytes) { +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); @@ -70,7 +72,7 @@ const char *kissat_format_bytes (format *format, uint64_t bytes) { return res; } -const char *kissat_format_time (format *format, double seconds) { +const char *kissat_format_time (kormat *format, double seconds) { if (!seconds) return "0s"; char *res = kissat_next_format_string (format); @@ -106,10 +108,10 @@ const char *kissat_format_time (format *format, double seconds) { return res; } -const char *kissat_format_signs (format *format, unsigned size, +const char *kissat_format_signs (kormat *format, unsigned size, word signs) { char *res = kissat_next_format_string (format); - assert (size + 1 < FORMAT_STRING_SIZE); + KISSAT_assert (size + 1 < FORMAT_STRING_SIZE); char *p = res; word bit = 1; for (unsigned i = 0; i < size; i++, bit <<= 1) @@ -118,7 +120,7 @@ const char *kissat_format_signs (format *format, unsigned size, return res; } -const char *kissat_format_ordinal (format *format, uint64_t ordinal) { +const char *kissat_format_ordinal (kormat *format, uint64_t ordinal) { char const *suffix; unsigned mod100 = ordinal % 100; if (10 <= mod100 && mod100 <= 19) @@ -143,3 +145,5 @@ const char *kissat_format_ordinal (format *format, uint64_t ordinal) { sprintf (res, "%" PRIu64 "%s", ordinal, suffix); return res; } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/format.h b/src/sat/kissat/format.h index d52e93d71..62e345e3b 100644 --- a/src/sat/kissat/format.h +++ b/src/sat/kissat/format.h @@ -6,24 +6,27 @@ #include #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + #define NUM_FORMAT_STRINGS 16 #define FORMAT_STRING_SIZE 128 -typedef struct format format; +typedef struct kormat kormat; -struct format { +struct kormat { unsigned pos; char str[NUM_FORMAT_STRINGS][FORMAT_STRING_SIZE]; }; -char *kissat_next_format_string (format *); +char *kissat_next_format_string (kormat *); -char const *kissat_format_bytes (format *, uint64_t bytes); -char const *kissat_format_count (format *, uint64_t); -char const *kissat_format_ordinal (format *, uint64_t); -char const *kissat_format_signs (format *, unsigned size, word); -char const *kissat_format_time (format *, double seconds); -char const *kissat_format_value (format *, bool boolean, int value); +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) @@ -39,4 +42,6 @@ char const *kissat_format_value (format *, bool boolean, int value); #define FORMAT_VALUE(BOOLEAN, VALUE) \ kissat_format_value (&solver->format, BOOLEAN, VALUE) +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/forward.c b/src/sat/kissat/forward.c index d2bbbab47..098de2367 100644 --- a/src/sat/kissat/forward.c +++ b/src/sat/kissat/forward.c @@ -10,6 +10,8 @@ #include +ABC_NAMESPACE_IMPL_START + static size_t remove_duplicated_binaries_with_literal (kissat *solver, unsigned lit) { watches *watches = &WATCHES (lit); @@ -21,7 +23,7 @@ static size_t remove_duplicated_binaries_with_literal (kissat *solver, while (p != end) { const watch watch = *q++ = *p++; - assert (watch.type.binary); + KISSAT_assert (watch.type.binary); const unsigned other = watch.binary.lit; struct flags *f = flags + IDX (other); if (!f->active) @@ -67,10 +69,10 @@ static size_t remove_duplicated_binaries_with_literal (kissat *solver, static void remove_all_duplicated_binary_clauses (kissat *solver) { LOG ("removing all duplicated irredundant binary clauses"); -#if !defined(QUIET) || !defined(NDEBUG) +#if !defined(KISSAT_QUIET) || !defined(KISSAT_NDEBUG) size_t removed = 0; #endif - assert (EMPTY_STACK (solver->delayed)); + KISSAT_assert (EMPTY_STACK (solver->delayed)); const flags *const all_flags = solver->flags; @@ -82,16 +84,16 @@ static void remove_all_duplicated_binary_clauses (kissat *solver) { continue; const unsigned int lit = LIT (idx); const unsigned int not_lit = NOT (lit); -#if !defined(QUIET) || !defined(NDEBUG) +#if !defined(KISSAT_QUIET) || !defined(KISSAT_NDEBUG) removed += #endif remove_duplicated_binaries_with_literal (solver, lit); -#if !defined(QUIET) || !defined(NDEBUG) +#if !defined(KISSAT_QUIET) || !defined(KISSAT_NDEBUG) removed += #endif remove_duplicated_binaries_with_literal (solver, not_lit); } - assert (!(removed & 1)); + KISSAT_assert (!(removed & 1)); size_t units = SIZE_STACK (solver->delayed); if (units) { @@ -141,7 +143,7 @@ static void find_forward_subsumption_candidates (kissat *solver, continue; if (c->size > clslim) continue; - assert (c->size > 2); + KISSAT_assert (c->size > 2); unsigned subsume = 0; for (all_literals_in_clause (lit, c)) { const unsigned idx = IDX (lit); @@ -151,7 +153,7 @@ static void find_forward_subsumption_candidates (kissat *solver, if (values[lit] > 0) { LOGCLS (c, "satisfied by %s", LOGLIT (lit)); kissat_mark_clause_as_garbage (solver, c); - assert (c->garbage); + KISSAT_assert (c->garbage); break; } } @@ -166,7 +168,7 @@ static void find_forward_subsumption_candidates (kissat *solver, static inline unsigned get_size_of_reference (kissat *solver, ward *const arena, reference ref) { - assert (ref < SIZE_STACK (solver->arena)); + KISSAT_assert (ref < SIZE_STACK (solver->arena)); const clause *const c = (clause *) (arena + ref); (void) solver; return c->size; @@ -223,14 +225,14 @@ static inline bool forward_literal (kissat *solver, unsigned lit, const unsigned not_other = NOT (other); if (marks[not_other]) { LOGBINARY (lit, other, "forward %s strengthener", LOGLIT (other)); - assert (!subsume); + KISSAT_assert (!subsume); *remove = not_other; break; } } } else { const reference ref = watch.large.ref; - assert (ref < SIZE_STACK (solver->arena)); + KISSAT_assert (ref < SIZE_STACK (solver->arena)); clause *d = (clause *) (arena + ref); steps++; @@ -253,34 +255,34 @@ static inline bool forward_literal (kissat *solver, unsigned lit, if (value > 0) { LOGCLS (d, "satisfied by %s", LOGLIT (other)); kissat_mark_clause_as_garbage (solver, d); - assert (d->garbage); + KISSAT_assert (d->garbage); candidate = INVALID_LIT; subsume = false; break; } if (!subsume) { - assert (candidate != INVALID_LIT); + KISSAT_assert (candidate != INVALID_LIT); candidate = INVALID_LIT; break; } subsume = false; const unsigned not_other = NOT (other); if (!marks[not_other]) { - assert (candidate == INVALID_LIT); + KISSAT_assert (candidate == INVALID_LIT); break; } candidate = not_other; } if (d->garbage) { - assert (!subsume); + KISSAT_assert (!subsume); q--; break; } if (subsume) { LOGCLS (d, "forward subsuming"); - assert (subsume); + KISSAT_assert (subsume); break; } @@ -316,7 +318,7 @@ static inline bool forward_marked_clause (kissat *solver, clause *c, if (!flags[idx].active) continue; - assert (!VALUE (lit)); + KISSAT_assert (!VALUE (lit)); if (forward_literal (solver, lit, true, remove, limit)) return true; @@ -330,7 +332,7 @@ static inline bool forward_marked_clause (kissat *solver, clause *c, static bool forward_subsumed_clause (kissat *solver, clause *c, bool *strengthened, unsigneds *new_binaries) { - assert (!c->garbage); + KISSAT_assert (!c->garbage); LOGCLS2 (c, "trying to forward subsume"); value *marks = solver->marks; @@ -344,7 +346,7 @@ static bool forward_subsumed_clause (kissat *solver, clause *c, if (value > 0) { LOGCLS (c, "satisfied by %s", LOGLIT (lit)); kissat_mark_clause_as_garbage (solver, c); - assert (c->garbage); + KISSAT_assert (c->garbage); break; } marks[lit] = 1; @@ -370,7 +372,7 @@ static bool forward_subsumed_clause (kissat *solver, clause *c, } if (non_false == 1) { - assert (VALID_INTERNAL_LITERAL (unit)); + 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); @@ -396,7 +398,7 @@ static bool forward_subsumed_clause (kissat *solver, clause *c, LOGCLS (c, "forward strengthening by removing %s in", LOGLIT (remove)); if (non_false == 2) { unit ^= remove; - assert (VALID_INTERNAL_LITERAL (unit)); + 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); @@ -416,12 +418,12 @@ static bool forward_subsumed_clause (kissat *solver, clause *c, const value value = values[lit]; if (value < 0) continue; - assert (!value); + KISSAT_assert (!value); lits[new_size++] = lit; kissat_mark_added_literal (solver, lit); } - assert (new_size == non_false - 1); - assert (new_size > 2); + KISSAT_assert (new_size == non_false - 1); + KISSAT_assert (new_size > 2); if (!c->shrunken) { c->shrunken = true; lits[c->size - 1] = INVALID_LIT; @@ -431,9 +433,9 @@ static bool forward_subsumed_clause (kissat *solver, clause *c, c->subsume = true; LOGCLS (c, "forward strengthened"); } else { - assert (non_false == 3); + KISSAT_assert (non_false == 3); LOGCLS (c, "garbage"); - assert (!c->garbage); + KISSAT_assert (!c->garbage); const size_t bytes = kissat_actual_bytes_of_clause (c); ADD (arena_garbage, bytes); c->garbage = true; @@ -444,25 +446,25 @@ static bool forward_subsumed_clause (kissat *solver, clause *c, const value value = values[lit]; if (value < 0) continue; - assert (!value); + KISSAT_assert (!value); if (first == INVALID_LIT) first = lit; else { - assert (second == INVALID_LIT); + KISSAT_assert (second == INVALID_LIT); second = lit; } kissat_mark_added_literal (solver, lit); } - assert (first != INVALID_LIT); - assert (second != INVALID_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); - assert (new_binaries); - assert (solver->statistics.clauses_irredundant); - solver->statistics.clauses_irredundant--; - assert (solver->statistics.clauses_binary < UINT64_MAX); - solver->statistics.clauses_binary++; + 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); } @@ -473,7 +475,7 @@ static bool forward_subsumed_clause (kissat *solver, clause *c, } static void connect_subsuming (kissat *solver, unsigned occlim, clause *c) { - assert (!c->garbage); + KISSAT_assert (!c->garbage); unsigned min_lit = INVALID_LIT; size_t min_occs = MAX_SIZE_T; @@ -513,19 +515,19 @@ static bool forward_subsume_all_clauses (kissat *solver) { INIT_STACK (candidates); find_forward_subsumption_candidates (solver, &candidates); -#ifndef QUIET +#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)); + kissat_percent (scheduled, solver->statistics_.clauses_irredundant)); #endif sort_forward_subsumption_candidates (solver, &candidates); const reference *const end_of_candidates = END_STACK (candidates); reference *p = BEGIN_STACK (candidates); -#ifndef QUIET +#ifndef KISSAT_QUIET size_t subsumed = 0; size_t strengthened = 0; size_t checked = 0; @@ -541,25 +543,25 @@ static bool forward_subsume_all_clauses (kissat *solver) { ward *arena = BEGIN_STACK (solver->arena); while (p != end_of_candidates) { - if (solver->statistics.forward_steps > steps_limit) + if (solver->statistics_.forward_steps > steps_limit) break; if (TERMINATED (forward_terminated_1)) break; reference ref = *p++; clause *c = (clause *) (arena + ref); - assert (kissat_clause_in_arena (solver, c)); - assert (!c->garbage); -#ifndef QUIET + 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, ¬_subsumed_but_strengthened, &new_binaries)) { -#ifndef QUIET +#ifndef KISSAT_QUIET subsumed++; #endif } else if (not_subsumed_but_strengthened) { -#ifndef QUIET +#ifndef KISSAT_QUIET strengthened++; #endif } @@ -569,7 +571,7 @@ static bool forward_subsume_all_clauses (kissat *solver) { connect_subsuming (solver, occlim, c); } } -#ifndef QUIET +#ifndef KISSAT_QUIET if (subsumed) kissat_phase (solver, "forward", GET (forward_subsumptions), "subsumed %zu clauses %.2f%% of %zu checked %.0f%%", @@ -593,19 +595,19 @@ static bool forward_subsume_all_clauses (kissat *solver) { ward *arena = BEGIN_STACK (solver->arena); unsigned reactivated = 0; -#ifndef QUIET +#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); - assert (kissat_clause_in_arena (solver, c)); + KISSAT_assert (kissat_clause_in_arena (solver, c)); if (c->garbage) continue; if (q < p && !c->subsume) continue; -#ifndef QUIET +#ifndef KISSAT_QUIET remain++; #endif for (all_literals_in_clause (lit, c)) { @@ -618,7 +620,7 @@ static bool forward_subsume_all_clauses (kissat *solver) { "in remaining or strengthened", LOGVAR (idx)); f->subsume = true; - assert (reactivated < UINT_MAX); + KISSAT_assert (reactivated < UINT_MAX); reactivated++; } } @@ -638,7 +640,7 @@ static bool forward_subsume_all_clauses (kissat *solver) { "in strengthened binary clause", LOGVAR (idx)); f->subsume = true; - assert (reactivated < UINT_MAX); + KISSAT_assert (reactivated < UINT_MAX); reactivated++; } } @@ -649,7 +651,7 @@ static bool forward_subsume_all_clauses (kissat *solver) { "in next forward subsumption", reactivated, kissat_percent (reactivated, solver->active)); -#ifndef QUIET +#ifndef KISSAT_QUIET if (remain) kissat_phase (solver, "forward", GET (forward_subsumptions), "%zu unchecked clauses remain %.0f%%", remain, @@ -668,7 +670,7 @@ static bool forward_subsume_all_clauses (kissat *solver) { completed = false; else completed = true; -#ifndef QUIET +#ifndef KISSAT_QUIET kissat_very_verbose (solver, "forward subsumption considered %scomplete", completed ? "" : "in"); #endif @@ -678,9 +680,9 @@ static bool forward_subsume_all_clauses (kissat *solver) { bool kissat_forward_subsume_during_elimination (kissat *solver) { START (subsume); START (forward); - assert (GET_OPTION (forward)); + KISSAT_assert (GET_OPTION (forward)); INC (forward_subsumptions); - assert (!solver->watching); + KISSAT_assert (!solver->watching); remove_all_duplicated_binary_clauses (solver); bool complete = true; if (!solver->inconsistent) @@ -689,3 +691,5 @@ bool kissat_forward_subsume_during_elimination (kissat *solver) { STOP (subsume); return complete; } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/forward.h b/src/sat/kissat/forward.h index 95a8dc5d3..193173166 100644 --- a/src/sat/kissat/forward.h +++ b/src/sat/kissat/forward.h @@ -3,8 +3,13 @@ #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + struct kissat; bool kissat_forward_subsume_during_elimination (struct kissat *); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/frames.h b/src/sat/kissat/frames.h index 088877b2a..fd997cda9 100644 --- a/src/sat/kissat/frames.h +++ b/src/sat/kissat/frames.h @@ -6,6 +6,9 @@ #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + typedef struct frame frame; typedef struct slice slice; @@ -14,7 +17,7 @@ struct frame { unsigned decision; unsigned trail; unsigned used; -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG unsigned saved; #endif }; @@ -29,4 +32,6 @@ struct kissat; #define FRAME(LEVEL) (PEEK_STACK (solver->frames, (LEVEL))) +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/gates.c b/src/sat/kissat/gates.c index 7da560181..b63d4b25b 100644 --- a/src/sat/kissat/gates.c +++ b/src/sat/kissat/gates.c @@ -6,6 +6,8 @@ #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; @@ -14,7 +16,7 @@ size_t kissat_mark_binaries (kissat *solver, unsigned lit) { if (!watch.type.binary) continue; const unsigned other = watch.binary.lit; - assert (!solver->values[other]); + KISSAT_assert (!solver->values[other]); if (marks[other]) continue; marks[other] = 1; @@ -60,14 +62,14 @@ bool kissat_find_gates (kissat *solver, unsigned lit) { static void get_antecedents (kissat *solver, unsigned lit, unsigned negative) { - assert (!solver->watching); - assert (!negative || negative == 1); + KISSAT_assert (!solver->watching); + KISSAT_assert (!negative || negative == 1); statches *gates = solver->gates + negative; watches *watches = &WATCHES (lit); statches *antecedents = solver->antecedents + negative; - assert (EMPTY_STACK (*antecedents)); + KISSAT_assert (EMPTY_STACK (*antecedents)); const watch *const begin_gates = BEGIN_STACK (*gates); const watch *const end_gates = END_STACK (*gates); @@ -85,7 +87,7 @@ static void get_antecedents (kissat *solver, unsigned lit, PUSH_STACK (*antecedents, watch); } - assert (g == end_gates); + KISSAT_assert (g == end_gates); #ifdef LOGGING size_t size_gates = SIZE_STACK (*gates); size_t size_antecedents = SIZE_STACK (*antecedents); @@ -102,3 +104,5 @@ void kissat_get_antecedents (kissat *solver, unsigned lit) { get_antecedents (solver, lit, 0); get_antecedents (solver, NOT (lit), 1); } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/gates.h b/src/sat/kissat/gates.h index f5ce18a90..8f941aa3d 100644 --- a/src/sat/kissat/gates.h +++ b/src/sat/kissat/gates.h @@ -4,6 +4,9 @@ #include #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + struct kissat; struct clause; @@ -19,4 +22,6 @@ void kissat_unmark_binaries (struct kissat *, unsigned lit); #define GATE_ELIMINATED(NAME) (&solver->statistics.NAME##_eliminated) #endif +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/global.h b/src/sat/kissat/global.h new file mode 100644 index 000000000..e6c20bc05 --- /dev/null +++ b/src/sat/kissat/global.h @@ -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 diff --git a/src/sat/kissat/handle.h b/src/sat/kissat/handle.h index 132fc3b68..03e5529ba 100644 --- a/src/sat/kissat/handle.h +++ b/src/sat/kissat/handle.h @@ -3,6 +3,9 @@ #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + void kissat_init_signal_handler (void (*handler) (int)); void kissat_reset_signal_handler (void); @@ -40,4 +43,6 @@ kissat_signal_name (int sig) // clang-format on +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/heap.c b/src/sat/kissat/heap.c index 12deaad75..584c58e6b 100644 --- a/src/sat/kissat/heap.c +++ b/src/sat/kissat/heap.c @@ -5,6 +5,8 @@ #include +ABC_NAMESPACE_IMPL_START + void kissat_release_heap (kissat *solver, heap *heap) { RELEASE_STACK (heap->stack); DEALLOC (heap->pos, heap->size); @@ -12,7 +14,7 @@ void kissat_release_heap (kissat *solver, heap *heap) { memset (heap, 0, sizeof *heap); } -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG void kissat_check_heap (heap *heap) { const unsigned *const stack = BEGIN_STACK (heap->stack); @@ -22,18 +24,18 @@ void kissat_check_heap (heap *heap) { for (unsigned i = 0; i < end; i++) { const unsigned idx = stack[i]; const unsigned idx_pos = pos[idx]; - assert (idx_pos == i); + KISSAT_assert (idx_pos == i); unsigned child_pos = HEAP_CHILD (idx_pos); unsigned parent_pos = HEAP_PARENT (child_pos); - assert (parent_pos == idx_pos); + KISSAT_assert (parent_pos == idx_pos); if (child_pos < end) { unsigned child = stack[child_pos]; - assert (score[idx] >= score[child]); + KISSAT_assert (score[idx] >= score[child]); if (++child_pos < end) { parent_pos = HEAP_PARENT (child_pos); - assert (parent_pos == idx_pos); + KISSAT_assert (parent_pos == idx_pos); child = stack[child_pos]; - assert (score[idx] >= score[child]); + KISSAT_assert (score[idx] >= score[child]); } } } @@ -48,15 +50,15 @@ void kissat_resize_heap (kissat *solver, heap *heap, unsigned new_size) { LOG ("resizing %s heap from %u to %u", (heap->tainted ? "tainted" : "untainted"), old_size, new_size); - heap->pos = kissat_nrealloc (solver, heap->pos, old_size, new_size, + heap->pos = (unsigned*)kissat_nrealloc (solver, heap->pos, old_size, new_size, sizeof (unsigned)); if (heap->tainted) { - heap->score = kissat_nrealloc (solver, heap->score, old_size, new_size, + 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 = kissat_calloc (solver, new_size, sizeof (double)); + heap->score = (double*)kissat_calloc (solver, new_size, sizeof (double)); } heap->size = new_size; #ifdef CHECK_HEAP @@ -69,7 +71,7 @@ void kissat_rescale_heap (kissat *solver, heap *heap, double factor) { double *score = heap->score; for (unsigned i = 0; i < heap->vars; i++) score[i] *= factor; -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG kissat_check_heap (heap); #endif #ifndef LOGGING @@ -79,8 +81,8 @@ void kissat_rescale_heap (kissat *solver, heap *heap, double factor) { void kissat_enlarge_heap (kissat *solver, heap *heap, unsigned new_vars) { const unsigned old_vars = heap->vars; - assert (old_vars < new_vars); - assert (new_vars <= heap->size); + 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; @@ -92,7 +94,7 @@ void kissat_enlarge_heap (kissat *solver, heap *heap, unsigned new_vars) { #endif } -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG static void dump_heap (heap *heap) { for (unsigned i = 0; i < SIZE_STACK (heap->stack); i++) @@ -106,3 +108,5 @@ static void dump_heap (heap *heap) { void kissat_dump_heap (heap *heap) { dump_heap (heap); } #endif + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/heap.h b/src/sat/kissat/heap.h index 8a9736ee2..724ff2ab3 100644 --- a/src/sat/kissat/heap.h +++ b/src/sat/kissat/heap.h @@ -8,6 +8,9 @@ #include #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + #define DISCONTAIN UINT_MAX #define DISCONTAINED(IDX) ((int) (IDX) < 0) @@ -50,7 +53,7 @@ static inline size_t kissat_size_heap (heap *heap) { } static inline unsigned kissat_max_heap (heap *heap) { - assert (!kissat_empty_heap (heap)); + KISSAT_assert (!kissat_empty_heap (heap)); return PEEK_STACK (heap->stack, 0); } @@ -61,7 +64,7 @@ void kissat_enlarge_heap (struct kissat *, heap *, unsigned new_vars); static inline double kissat_max_score_on_heap (heap *heap) { if (!heap->tainted) return 0; - assert (heap->vars); + KISSAT_assert (heap->vars); const double *const score = heap->score; const double *const end = score + heap->vars; double res = score[0]; @@ -70,11 +73,11 @@ static inline double kissat_max_score_on_heap (heap *heap) { return res; } -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG void kissat_dump_heap (heap *); #endif -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG void kissat_check_heap (heap *); #else #define kissat_check_heap(...) \ @@ -82,4 +85,6 @@ void kissat_check_heap (heap *); } while (0) #endif +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/ifthenelse.c b/src/sat/kissat/ifthenelse.c index db4031f68..b4224422e 100644 --- a/src/sat/kissat/ifthenelse.c +++ b/src/sat/kissat/ifthenelse.c @@ -3,6 +3,8 @@ #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); @@ -30,9 +32,9 @@ static bool get_ternary_clause (kissat *solver, reference ref, unsigned *p, } if (found != 3) return false; - assert (a != INVALID_LIT); - assert (b != INVALID_LIT); - assert (c != INVALID_LIT); + KISSAT_assert (a != INVALID_LIT); + KISSAT_assert (b != INVALID_LIT); + KISSAT_assert (c != INVALID_LIT); *p = a; *q = b; *r = c; @@ -121,7 +123,7 @@ bool kissat_find_if_then_else_gate (kissat *solver, unsigned lit, SWAP (unsigned, a1, b1); if (c1 == lit) SWAP (unsigned, a1, c1); - assert (a1 == lit); + KISSAT_assert (a1 == lit); for (const watch *p2 = p1 + 1; steps < limit && p2 != end; p2++) { watch w2 = *p2; if (w2.type.binary) @@ -133,7 +135,7 @@ bool kissat_find_if_then_else_gate (kissat *solver, unsigned lit, SWAP (unsigned, a2, b2); if (c2 == lit) SWAP (unsigned, a2, c2); - assert (a2 == lit); + KISSAT_assert (a2 == lit); if (STRIP (b1) == STRIP (c2)) SWAP (unsigned, b2, c2); if (STRIP (c1) == STRIP (c2)) @@ -172,3 +174,5 @@ bool kissat_find_if_then_else_gate (kissat *solver, unsigned lit, } return false; } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/ifthenelse.h b/src/sat/kissat/ifthenelse.h index 82097883e..8a9437d65 100644 --- a/src/sat/kissat/ifthenelse.h +++ b/src/sat/kissat/ifthenelse.h @@ -3,9 +3,14 @@ #include +#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 diff --git a/src/sat/kissat/import.c b/src/sat/kissat/import.c index 38ca379c0..6f70ff58f 100644 --- a/src/sat/kissat/import.c +++ b/src/sat/kissat/import.c @@ -2,6 +2,8 @@ #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)) { @@ -27,13 +29,13 @@ static void adjust_exports_for_external_literal (kissat *solver, INC (variables_extension); else INC (variables_original); - assert (!import->eliminated); + 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); + 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); } @@ -47,20 +49,20 @@ static inline unsigned import_literal (kissat *solver, int elit, unsigned ilit; if (!import->imported) adjust_exports_for_external_literal (solver, eidx, extension); - assert (import->imported); + KISSAT_assert (import->imported); ilit = import->lit; if (elit < 0) ilit = NOT (ilit); - assert (VALID_INTERNAL_LITERAL (ilit)); + KISSAT_assert (VALID_INTERNAL_LITERAL (ilit)); return ilit; } unsigned kissat_import_literal (kissat *solver, int elit) { - assert (VALID_EXTERNAL_LITERAL (elit)); + KISSAT_assert (VALID_EXTERNAL_LITERAL (elit)); if (GET_OPTION (tumble)) return import_literal (solver, elit, false); const unsigned eidx = ABS (elit); - assert (SIZE_STACK (solver->import) <= UINT_MAX); + KISSAT_assert (SIZE_STACK (solver->import) <= UINT_MAX); unsigned other = SIZE_STACK (solver->import); if (eidx < other) return import_literal (solver, elit, false); @@ -69,7 +71,7 @@ unsigned kissat_import_literal (kissat *solver, int elit) { unsigned ilit = 0; do { - assert (VALID_EXTERNAL_LITERAL ((int) other)); + KISSAT_assert (VALID_EXTERNAL_LITERAL ((int) other)); ilit = import_literal (solver, other, false); } while (other++ < eidx); @@ -81,20 +83,22 @@ unsigned kissat_import_literal (kissat *solver, int elit) { unsigned kissat_fresh_literal (kissat *solver) { size_t imported = SIZE_STACK (solver->import); - assert (imported <= EXTERNAL_MAX_VAR); + KISSAT_assert (imported <= EXTERNAL_MAX_VAR); if (imported == EXTERNAL_MAX_VAR) { LOG ("can not get another external variable"); return INVALID_LIT; } - assert (imported <= (unsigned) INT_MAX); + KISSAT_assert (imported <= (unsigned) INT_MAX); int eidx = (int) imported; unsigned res = import_literal (solver, eidx, true); -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG struct import *import = &PEEK_STACK (solver->import, imported); - assert (import->imported); - assert (import->extension); + KISSAT_assert (import->imported); + KISSAT_assert (import->extension); #endif INC (fresh); kissat_activate_literal (solver, res); return res; } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/import.h b/src/sat/kissat/import.h index 4b82a5f3c..87261ec2f 100644 --- a/src/sat/kissat/import.h +++ b/src/sat/kissat/import.h @@ -1,9 +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 diff --git a/src/sat/kissat/inline.h b/src/sat/kissat/inline.h index d1f9b789f..e78cdeeea 100644 --- a/src/sat/kissat/inline.h +++ b/src/sat/kissat/inline.h @@ -4,6 +4,9 @@ #include "inlinevector.h" #include "logging.h" +#include "global.h" +ABC_NAMESPACE_HEADER_START + #ifdef METRICS static inline size_t kissat_allocated (kissat *solver) { @@ -13,8 +16,8 @@ static inline size_t kissat_allocated (kissat *solver) { #endif static inline bool kissat_propagated (kissat *solver) { - assert (BEGIN_ARRAY (solver->trail) <= solver->propagate); - assert (solver->propagate <= END_ARRAY (solver->trail)); + KISSAT_assert (BEGIN_ARRAY (solver->trail) <= solver->propagate); + KISSAT_assert (solver->propagate <= END_ARRAY (solver->trail)); return solver->propagate == END_ARRAY (solver->trail); } @@ -27,7 +30,7 @@ static inline void kissat_reset_propagate (kissat *solver) { } static inline value kissat_fixed (kissat *solver, unsigned lit) { - assert (lit < LITS); + KISSAT_assert (lit < LITS); const value res = solver->values[lit]; if (!res) return 0; @@ -83,7 +86,7 @@ static inline void kissat_push_blocking_watch (kissat *solver, watches *watches, unsigned blocking, reference ref) { - assert (solver->watching); + KISSAT_assert (solver->watching); const watch head = kissat_blocking_watch (blocking); PUSH_WATCHES (*watches, head); const watch tail = kissat_large_watch (ref); @@ -107,7 +110,7 @@ static inline void kissat_watch_binary (kissat *solver, unsigned a, static inline void kissat_watch_blocking (kissat *solver, unsigned lit, unsigned blocking, reference ref) { - assert (solver->watching); + KISSAT_assert (solver->watching); LOGREF3 (ref, "watching %s blocking %s in", LOGLIT (lit), LOGLIT (blocking)); watches *watches = &WATCHES (lit); @@ -116,7 +119,7 @@ static inline void kissat_watch_blocking (kissat *solver, unsigned lit, static inline void kissat_unwatch_blocking (kissat *solver, unsigned lit, reference ref) { - assert (solver->watching); + KISSAT_assert (solver->watching); LOGREF3 (ref, "unwatching %s in", LOGLIT (lit)); watches *watches = &WATCHES (lit); kissat_remove_blocking_watch (solver, watches, ref); @@ -124,7 +127,7 @@ static inline void kissat_unwatch_blocking (kissat *solver, unsigned lit, static inline void kissat_disconnect_binary (kissat *solver, unsigned lit, unsigned other) { - assert (!solver->watching); + KISSAT_assert (!solver->watching); watches *watches = &WATCHES (lit); const watch watch = kissat_binary_watch (other); REMOVE_WATCHES (*watches, watch); @@ -132,7 +135,7 @@ static inline void kissat_disconnect_binary (kissat *solver, unsigned lit, static inline void kissat_disconnect_reference (kissat *solver, unsigned lit, reference ref) { - assert (!solver->watching); + KISSAT_assert (!solver->watching); LOGREF3 (ref, "disconnecting %s in", LOGLIT (lit)); const watch watch = kissat_large_watch (ref); watches *watches = &WATCHES (lit); @@ -141,14 +144,14 @@ kissat_disconnect_reference (kissat *solver, unsigned lit, reference ref) { static inline void kissat_watch_reference (kissat *solver, unsigned a, unsigned b, reference ref) { - assert (solver->watching); + 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) { - assert (!solver->watching); + KISSAT_assert (!solver->watching); LOGREF3 (ref, "connecting %s in", LOGLIT (lit)); watches *watches = &WATCHES (lit); kissat_push_large_watch (solver, watches, ref); @@ -162,13 +165,13 @@ static inline clause *kissat_unchecked_dereference_clause (kissat *solver, static inline clause *kissat_dereference_clause (kissat *solver, reference ref) { clause *res = kissat_unchecked_dereference_clause (solver, ref); - assert (kissat_clause_in_arena (solver, res)); + KISSAT_assert (kissat_clause_in_arena (solver, res)); return res; } static inline reference kissat_reference_clause (kissat *solver, const clause *c) { - assert (kissat_clause_in_arena (solver, c)); + KISSAT_assert (kissat_clause_in_arena (solver, c)); return (ward *) c - BEGIN_STACK (solver->arena); } @@ -176,33 +179,33 @@ static inline void kissat_inlined_connect_clause (kissat *solver, watches *all_watches, clause *c, reference ref) { - assert (!solver->watching); - assert (ref == kissat_reference_clause (solver, c)); - assert (c == kissat_dereference_clause (solver, ref)); + 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)) { - assert (!solver->watching); + KISSAT_assert (!solver->watching); LOGREF3 (ref, "connecting %s in", LOGLIT (lit)); - assert (lit < LITS); + 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) { - assert (c->searched < c->size); + 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); - assert (iidx < (unsigned) INT_MAX); - int elit = PEEK_STACK (solver->export, iidx); + KISSAT_assert (iidx < (unsigned) INT_MAX); + int elit = PEEK_STACK (solver->export_, iidx); if (!elit) return 0; if (NEGATED (ilit)) elit = -elit; - assert (VALID_EXTERNAL_LITERAL (elit)); + KISSAT_assert (VALID_EXTERNAL_LITERAL (elit)); return elit; } @@ -242,9 +245,9 @@ static inline clause *kissat_binary_conflict (kissat *solver, unsigned a, static inline void kissat_push_analyzed (kissat *solver, assigned *assigned, unsigned idx) { - assert (idx < VARS); + KISSAT_assert (idx < VARS); struct assigned *a = assigned + idx; - assert (!a->analyzed); + KISSAT_assert (!a->analyzed); a->analyzed = true; PUSH_STACK (solver->analyzed, idx); LOG2 ("%s analyzed", LOGVAR (idx)); @@ -256,9 +259,9 @@ static inline bool kissat_analyzed (kissat *solver) { static inline void kissat_push_removable (kissat *solver, assigned *assigned, unsigned idx) { - assert (idx < VARS); + KISSAT_assert (idx < VARS); struct assigned *a = assigned + idx; - assert (!a->removable); + KISSAT_assert (!a->removable); a->removable = true; PUSH_STACK (solver->removable, idx); LOG2 ("%s removable", LOGVAR (idx)); @@ -266,9 +269,9 @@ kissat_push_removable (kissat *solver, assigned *assigned, unsigned idx) { static inline void kissat_push_poisoned (kissat *solver, assigned *assigned, unsigned idx) { - assert (idx < VARS); + KISSAT_assert (idx < VARS); struct assigned *a = assigned + idx; - assert (!a->poisoned); + KISSAT_assert (!a->poisoned); a->poisoned = true; PUSH_STACK (solver->poisoned, idx); LOG2 ("%s poisoned", LOGVAR (idx)); @@ -276,17 +279,17 @@ static inline void kissat_push_poisoned (kissat *solver, assigned *assigned, static inline void kissat_push_shrinkable (kissat *solver, assigned *assigned, unsigned idx) { - assert (idx < VARS); + KISSAT_assert (idx < VARS); struct assigned *a = assigned + idx; - assert (!a->shrinkable); + 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 NDEBUG -#ifdef NOPTIONS +#ifndef KISSAT_NDEBUG +#ifdef KISSAT_NOPTIONS (void) solver; #endif return GET_OPTION (check); @@ -298,7 +301,7 @@ static inline int kissat_checking (kissat *solver) { static inline bool kissat_logging (kissat *solver) { #ifdef LOGGING -#ifdef NOPTIONS +#ifdef KISSAT_NOPTIONS (void) solver; #endif return GET_OPTION (log) > 0; @@ -309,7 +312,7 @@ static inline bool kissat_logging (kissat *solver) { } static inline bool kissat_proving (kissat *solver) { -#ifdef NPROOFS +#ifdef KISSAT_NPROOFS (void) solver; return false; #else @@ -321,8 +324,10 @@ static inline bool kissat_checking_or_proving (kissat *solver) { return kissat_checking (solver) || kissat_proving (solver); } -#if !defined(NDEBUG) || !defined(NPROOFS) +#if !defined(KISSAT_NDEBUG) || !defined(KISSAT_NPROOFS) #define CHECKING_OR_PROVING #endif +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/inlineassign.h b/src/sat/kissat/inlineassign.h index b8d3b88a1..8ac2b7c7c 100644 --- a/src/sat/kissat/inlineassign.h +++ b/src/sat/kissat/inlineassign.h @@ -1,6 +1,9 @@ #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 @@ -17,24 +20,26 @@ static inline void kissat_assign (kissat *solver, const bool probing, 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 - assert (!values[lit]); - assert (!values[not_lit]); + KISSAT_assert (!values[lit]); + KISSAT_assert (!values[not_lit]); values[lit] = 1; values[not_lit] = -1; - assert (solver->unassigned > 0); + KISSAT_assert (solver->unassigned > 0); solver->unassigned--; if (!level) { kissat_mark_fixed_literal (solver, lit); - assert (solver->unflushed < UINT_MAX); + KISSAT_assert (solver->unflushed < UINT_MAX); solver->unflushed++; if (reason != UNIT_REASON) { CHECK_AND_ADD_UNIT (lit); @@ -84,17 +89,19 @@ kissat_assignment_level (kissat *solver, value *values, assigned *assigned, for (all_literals_in_clause (other, reason)) { if (other == lit) continue; - assert (values[other] < 0), (void) values; + 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 NDEBUG +#ifdef KISSAT_NDEBUG (void) solver; #endif return res; } +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/inlineframes.h b/src/sat/kissat/inlineframes.h index 75c5186a6..09c772681 100644 --- a/src/sat/kissat/inlineframes.h +++ b/src/sat/kissat/inlineframes.h @@ -4,8 +4,11 @@ #include "allocate.h" #include "internal.h" +#include "global.h" +ABC_NAMESPACE_HEADER_START + static inline void kissat_push_frame (kissat *solver, unsigned decision) { - assert (!solver->level || decision != UINT_MAX); + KISSAT_assert (!solver->level || decision != UINT_MAX); const size_t trail = SIZE_ARRAY (solver->trail); frame frame; frame.decision = decision; @@ -15,4 +18,6 @@ static inline void kissat_push_frame (kissat *solver, unsigned decision) { PUSH_STACK (solver->frames, frame); } +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/inlineheap.h b/src/sat/kissat/inlineheap.h index 0bc8c122d..cf379b488 100644 --- a/src/sat/kissat/inlineheap.h +++ b/src/sat/kissat/inlineheap.h @@ -5,9 +5,12 @@ #include "internal.h" #include "logging.h" -#define HEAP_CHILD(POS) (assert ((POS) < (1u << 31)), (2 * (POS) + 1)) +#include "global.h" +ABC_NAMESPACE_HEADER_START -#define HEAP_PARENT(POS) (assert ((POS) > 0), (((POS) - 1) / 2)) +#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) { @@ -75,7 +78,7 @@ static inline void kissat_bubble_down (kissat *solver, heap *heap, #define HEAP_IMPORT(IDX) \ do { \ - assert ((IDX) < UINT_MAX - 1); \ + KISSAT_assert ((IDX) < UINT_MAX - 1); \ if (heap->vars <= (IDX)) \ kissat_enlarge_heap (solver, heap, (IDX) + 1); \ } while (0) @@ -85,7 +88,7 @@ static inline void kissat_bubble_down (kissat *solver, heap *heap, static inline void kissat_push_heap (kissat *solver, heap *heap, unsigned idx) { LOG ("push heap %u", idx); - assert (!kissat_heap_contains (heap, idx)); + KISSAT_assert (!kissat_heap_contains (heap, idx)); HEAP_IMPORT (idx); heap->pos[idx] = SIZE_STACK (heap->stack); PUSH_STACK (heap->stack, idx); @@ -95,7 +98,7 @@ static inline void kissat_push_heap (kissat *solver, heap *heap, static inline void kissat_pop_heap (kissat *solver, heap *heap, unsigned idx) { LOG ("pop heap %u", idx); - assert (kissat_heap_contains (heap, idx)); + KISSAT_assert (kissat_heap_contains (heap, idx)); const unsigned last = POP_STACK (heap->stack); heap->pos[last] = DISCONTAIN; if (last == idx) @@ -112,11 +115,11 @@ static inline void kissat_pop_heap (kissat *solver, heap *heap, } static inline unsigned kissat_pop_max_heap (kissat *solver, heap *heap) { - assert (!EMPTY_STACK (heap->stack)); + KISSAT_assert (!EMPTY_STACK (heap->stack)); unsigneds *stack = &heap->stack; unsigned *const begin = BEGIN_STACK (*stack); const unsigned idx = *begin; - assert (!heap->pos[idx]); + KISSAT_assert (!heap->pos[idx]); LOG ("pop max heap %u", idx); const unsigned last = POP_STACK (*stack); unsigned *const pos = heap->pos; @@ -144,7 +147,7 @@ static inline void kissat_adjust_heap (kissat *solver, heap *heap, size_t new_size = old_size ? 2 * old_size : 1; while (idx >= new_size) new_size *= 2; - assert (new_size < DISCONTAIN); + KISSAT_assert (new_size < DISCONTAIN); kissat_resize_heap (solver, heap, new_size); } kissat_enlarge_heap (solver, heap, idx + 1); @@ -173,4 +176,6 @@ static inline void kissat_update_heap (kissat *solver, heap *heap, #endif } +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/inlinequeue.h b/src/sat/kissat/inlinequeue.h index 017522679..3f83dd895 100644 --- a/src/sat/kissat/inlinequeue.h +++ b/src/sat/kissat/inlinequeue.h @@ -4,9 +4,12 @@ #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) { - assert (!DISCONNECTED (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; @@ -16,20 +19,20 @@ static inline void kissat_update_queue (kissat *solver, const links *links, static inline void kissat_enqueue_links (kissat *solver, unsigned i, links *links, queue *queue) { struct links *p = links + i; - assert (DISCONNECTED (p->prev)); - assert (DISCONNECTED (p->next)); + 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; - assert (DISCONNECTED (l->next)); + KISSAT_assert (DISCONNECTED (l->next)); l->next = i; } if (queue->stamp == UINT_MAX) { kissat_reassign_queue_stamps (solver); - assert (p->stamp == queue->stamp); + KISSAT_assert (p->stamp == queue->stamp); } else p->stamp = ++queue->stamp; } @@ -40,25 +43,25 @@ static inline void kissat_dequeue_links (unsigned i, links *links, const unsigned j = l->prev, k = l->next; l->prev = l->next = DISCONNECT; if (DISCONNECTED (j)) { - assert (queue->first == i); + KISSAT_assert (queue->first == i); queue->first = k; } else { struct links *p = links + j; - assert (p->next == i); + KISSAT_assert (p->next == i); p->next = k; } if (DISCONNECTED (k)) { - assert (queue->last == i); + KISSAT_assert (queue->last == i); queue->last = j; } else { struct links *n = links + k; - assert (n->prev == i); + KISSAT_assert (n->prev == i); n->prev = j; } } static inline void kissat_enqueue (kissat *solver, unsigned idx) { - assert (idx < solver->vars); + 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); @@ -69,7 +72,7 @@ static inline void kissat_enqueue (kissat *solver, unsigned idx) { } static inline void kissat_dequeue (kissat *solver, unsigned idx) { - assert (idx < solver->vars); + KISSAT_assert (idx < solver->vars); LOG ("dequeued %s", LOGVAR (idx)); links *links = solver->links; if (solver->queue.search.idx == idx) { @@ -91,10 +94,10 @@ static inline void kissat_move_to_front (kissat *solver, unsigned idx) { queue *queue = &solver->queue; links *links = solver->links; if (idx == queue->last) { - assert (DISCONNECTED (links[idx].next)); + KISSAT_assert (DISCONNECTED (links[idx].next)); return; } - assert (idx < solver->vars); + KISSAT_assert (idx < solver->vars); const value tmp = VALUE (LIT (idx)); if (tmp && queue->search.idx == idx) { unsigned prev = links[idx].prev; @@ -102,7 +105,7 @@ static inline void kissat_move_to_front (kissat *solver, unsigned idx) { kissat_update_queue (solver, links, prev); else { unsigned next = links[idx].next; - assert (!DISCONNECTED (next)); + KISSAT_assert (!DISCONNECTED (next)); kissat_update_queue (solver, links, next); } } @@ -114,4 +117,6 @@ static inline void kissat_move_to_front (kissat *solver, unsigned idx) { kissat_check_queue (solver); } +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/inlinevector.h b/src/sat/kissat/inlinevector.h index b7adbbf7e..d7242c8eb 100644 --- a/src/sat/kissat/inlinevector.h +++ b/src/sat/kissat/inlinevector.h @@ -3,9 +3,12 @@ #include "internal.h" +#include "global.h" +ABC_NAMESPACE_HEADER_START + static inline unsigned *kissat_begin_vector (kissat *solver, vector *vector) { -#ifdef COMPACT +#ifdef KISSAT_COMPACT return BEGIN_STACK (solver->vectors.stack) + vector->offset; #else (void) solver; @@ -14,7 +17,7 @@ static inline unsigned *kissat_begin_vector (kissat *solver, } static inline unsigned *kissat_end_vector (kissat *solver, vector *vector) { -#ifdef COMPACT +#ifdef KISSAT_COMPACT return kissat_begin_vector (solver, vector) + vector->size; #else (void) solver; @@ -24,7 +27,7 @@ static inline unsigned *kissat_end_vector (kissat *solver, vector *vector) { static inline const unsigned * kissat_begin_const_vector (kissat *solver, const vector *vector) { -#ifdef COMPACT +#ifdef KISSAT_COMPACT return BEGIN_STACK (solver->vectors.stack) + vector->offset; #else (void) solver; @@ -34,7 +37,7 @@ kissat_begin_const_vector (kissat *solver, const vector *vector) { static inline const unsigned * kissat_end_const_vector (kissat *solver, const vector *vector) { -#ifdef COMPACT +#ifdef KISSAT_COMPACT return kissat_begin_const_vector (solver, vector) + vector->size; #else (void) solver; @@ -45,7 +48,7 @@ kissat_end_const_vector (kissat *solver, const vector *vector) { #if defined(LOGGING) || defined(TEST_VECTOR) static inline size_t kissat_offset_vector (kissat *solver, vector *vector) { -#ifdef COMPACT +#ifdef KISSAT_COMPACT (void) solver; return vector->offset; #else @@ -58,7 +61,7 @@ static inline size_t kissat_offset_vector (kissat *solver, vector *vector) { #endif static inline size_t kissat_size_vector (const vector *vector) { -#ifdef COMPACT +#ifdef KISSAT_COMPACT return vector->size; #else return vector->end - vector->begin; @@ -66,7 +69,7 @@ static inline size_t kissat_size_vector (const vector *vector) { } static inline bool kissat_empty_vector (vector *vector) { -#ifdef COMPACT +#ifdef KISSAT_COMPACT return !vector->size; #else return vector->end == vector->begin; @@ -74,20 +77,20 @@ static inline bool kissat_empty_vector (vector *vector) { } static inline void kissat_inc_usable (kissat *solver) { - assert (MAX_SECTOR > solver->vectors.usable); + KISSAT_assert (MAX_SECTOR > solver->vectors.usable); solver->vectors.usable++; } static inline void kissat_add_usable (kissat *solver, size_t inc) { - assert (MAX_SECTOR - inc >= solver->vectors.usable); + KISSAT_assert (MAX_SECTOR - inc >= solver->vectors.usable); solver->vectors.usable += inc; } static inline unsigned *kissat_last_vector_pointer (kissat *solver, vector *vector) { - assert (!kissat_empty_vector (vector)); -#ifdef COMPACT - assert (vector->size); + 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 @@ -99,8 +102,8 @@ static inline unsigned *kissat_last_vector_pointer (kissat *solver, #ifdef TEST_VECTOR static inline void kissat_pop_vector (kissat *solver, vector *vector) { - assert (!kissat_empty_vector (vector)); -#ifdef COMPACT + KISSAT_assert (!kissat_empty_vector (vector)); +#ifdef KISSAT_COMPACT unsigned *p = kissat_last_vector_pointer (solver, vector); vector->size--; *p = INVALID_VECTOR_ELEMENT; @@ -118,16 +121,16 @@ static inline void kissat_release_vector (kissat *solver, vector *vector) { } static inline void kissat_dec_usable (kissat *solver) { - assert (solver->vectors.usable > 0); + 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; - assert (e != INVALID_VECTOR_ELEMENT); + KISSAT_assert (e != INVALID_VECTOR_ELEMENT); if ( -#ifdef COMPACT +#ifdef KISSAT_COMPACT !vector->size && !vector->offset #else !vector->begin @@ -137,21 +140,21 @@ static inline void kissat_push_vectors (kissat *solver, vector *vector, PUSH_STACK (*stack, 0); if (FULL_STACK (*stack)) { unsigned *end = kissat_enlarge_vector (solver, vector); - assert (*end == INVALID_VECTOR_ELEMENT); + KISSAT_assert (*end == INVALID_VECTOR_ELEMENT); *end = e; kissat_dec_usable (solver); } else { -#ifdef COMPACT - assert ((uint64_t) SIZE_STACK (*stack) < MAX_VECTORS); +#ifdef KISSAT_COMPACT + KISSAT_assert ((uint64_t) SIZE_STACK (*stack) < MAX_VECTORS); vector->offset = SIZE_STACK (*stack); - assert (vector->offset); + KISSAT_assert (vector->offset); *stack->end++ = e; #else - assert (stack->end < stack->allocated); + KISSAT_assert (stack->end < stack->allocated); *(vector->begin = stack->end++) = e; #endif } -#if !defined(COMPACT) +#if !defined(KISSAT_COMPACT) vector->end = vector->begin; #endif } else { @@ -159,7 +162,7 @@ static inline void kissat_push_vectors (kissat *solver, vector *vector, if (end == END_STACK (*stack)) { if (FULL_STACK (*stack)) { end = kissat_enlarge_vector (solver, vector); - assert (*end == INVALID_VECTOR_ELEMENT); + KISSAT_assert (*end == INVALID_VECTOR_ELEMENT); *end = e; kissat_dec_usable (solver); } else @@ -167,12 +170,12 @@ static inline void kissat_push_vectors (kissat *solver, vector *vector, } else { if (*end != INVALID_VECTOR_ELEMENT) end = kissat_enlarge_vector (solver, vector); - assert (*end == INVALID_VECTOR_ELEMENT); + KISSAT_assert (*end == INVALID_VECTOR_ELEMENT); *end = e; kissat_dec_usable (solver); } } -#ifndef COMPACT +#ifndef KISSAT_COMPACT vector->end++; #else vector->size++; @@ -190,4 +193,6 @@ static inline void kissat_push_vectors (kissat *solver, vector *vector, #endif +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/internal.c b/src/sat/kissat/internal.c index 1c0002019..bf7046159 100644 --- a/src/sat/kissat/internal.c +++ b/src/sat/kissat/internal.c @@ -17,24 +17,26 @@ #include #include +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_calloc (0, 1, sizeof *solver); -#ifndef NOPTIONS + kissat *solver = (kissat*)kissat_calloc (0, 1, sizeof *solver); +#ifndef KISSAT_NOPTIONS kissat_init_options (&solver->options); #else kissat_init_options (); #endif -#ifndef QUIET +#ifndef KISSAT_QUIET kissat_init_profiles (&solver->profiles); #endif START (total); kissat_init_queue (solver); - assert (INTERNAL_MAX_LIT < UINT_MAX); + KISSAT_assert (INTERNAL_MAX_LIT < UINT_MAX); kissat_push_frame (solver, UINT_MAX); solver->watching = true; solver->conflict.size = 2; @@ -42,7 +44,7 @@ kissat *kissat_init (void) { solver->first_reducible = INVALID_REF; solver->last_irredundant = INVALID_REF; kissat_reset_last_learned (solver); -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG kissat_init_checker (solver); #endif solver->prefix = kissat_strdup (solver, "c "); @@ -83,7 +85,7 @@ void kissat_release (kissat *solver) { kissat_release_vectors (solver); kissat_release_phases (solver); - RELEASE_STACK (solver->export); + RELEASE_STACK (solver->export_); RELEASE_STACK (solver->import); DEALLOC_VARIABLE_INDEXED (assigned); @@ -104,7 +106,7 @@ void kissat_release (kissat *solver) { RELEASE_STACK (solver->clause); RELEASE_STACK (solver->shadow); -#if defined(LOGGING) || !defined(NDEBUG) +#if defined(LOGGING) || !defined(KISSAT_NDEBUG) RELEASE_STACK (solver->resolvent); #endif @@ -136,26 +138,26 @@ void kissat_release (kissat *solver) { RELEASE_STACK (solver->gates[1]); RELEASE_STACK (solver->resolvents); -#if !defined(NDEBUG) || !defined(NPROOFS) +#if !defined(KISSAT_NDEBUG) || !defined(KISSAT_NPROOFS) RELEASE_STACK (solver->added); RELEASE_STACK (solver->removed); #endif -#if !defined(NDEBUG) || !defined(NPROOFS) || defined(LOGGING) +#if !defined(KISSAT_NDEBUG) || !defined(KISSAT_NPROOFS) || defined(LOGGING) RELEASE_STACK (solver->original); #endif -#ifndef QUIET +#ifndef KISSAT_QUIET RELEASE_STACK (solver->profiles.stack); #endif kissat_freestr (solver, solver->prefix); -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG kissat_release_checker (solver); #endif -#if !defined(NDEBUG) && defined(METRICS) - uint64_t leaked = solver->statistics.allocated_current; +#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); @@ -182,7 +184,7 @@ void kissat_reserve (kissat *solver, int max_var) { int kissat_get_option (kissat *solver, const char *name) { kissat_require_initialized (solver); kissat_require (name, "name zero pointer"); -#ifndef NOPTIONS +#ifndef KISSAT_NOPTIONS return kissat_options_get (&solver->options, name); #else (void) solver; @@ -191,10 +193,10 @@ int kissat_get_option (kissat *solver, const char *name) { } int kissat_set_option (kissat *solver, const char *name, int new_value) { -#ifndef NOPTIONS +#ifndef KISSAT_NOPTIONS kissat_require_initialized (solver); kissat_require (name, "name zero pointer"); -#ifndef NOPTIONS +#ifndef KISSAT_NOPTIONS return kissat_options_set (&solver->options, name, new_value); #else return kissat_options_set (name, new_value); @@ -209,9 +211,9 @@ 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; + statistics *statistics = &solver->statistics_; limited->decisions = true; - assert (UINT64_MAX - limit >= statistics->decisions); + KISSAT_assert (UINT64_MAX - limit >= statistics->decisions); limits->decisions = statistics->decisions + limit; LOG ("set decision limit to %" PRIu64 " after %u decisions", limits->decisions, limit); @@ -221,16 +223,16 @@ 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; + statistics *statistics = &solver->statistics_; limited->conflicts = true; - assert (UINT64_MAX - limit >= statistics->conflicts); + 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 QUIET +#ifndef KISSAT_QUIET kissat_require_initialized (solver); const int verbosity = kissat_verbosity (solver); if (verbosity < 0) @@ -243,13 +245,13 @@ void kissat_print_statistics (kissat *solver) { kissat_section (solver, "statistics"); const bool verbose = (complete || verbosity > 0); kissat_statistics_print (solver, verbose); -#ifndef NPROOFS +#ifndef KISSAT_NPROOFS if (solver->proof) { kissat_section (solver, "proof"); kissat_print_proof_statistics (solver, verbose); } #endif -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG if (GET_OPTION (check) > 1) { kissat_section (solver, "checker"); kissat_print_checker_statistics (solver, verbose); @@ -266,14 +268,14 @@ void kissat_print_statistics (kissat *solver) { void kissat_add (kissat *solver, int elit) { kissat_require_initialized (solver); kissat_require (!GET (searches), "incremental solving not supported"); -#if !defined(NDEBUG) || !defined(NPROOFS) || defined(LOGGING) +#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(NDEBUG) || !defined(NPROOFS) || defined(LOGGING) +#if !defined(KISSAT_NDEBUG) || !defined(KISSAT_NPROOFS) || defined(LOGGING) if (checking || logging || proving) PUSH_STACK (solver->original, elit); #endif @@ -297,18 +299,18 @@ void kissat_add (kissat *solver, int elit) { } else { MARK (ilit) = 1; MARK (NOT (ilit)) = -1; - assert (SIZE_STACK (solver->clause) < UINT_MAX); + KISSAT_assert (SIZE_STACK (solver->clause) < UINT_MAX); PUSH_STACK (solver->clause, ilit); } } else if (mark < 0) { - assert (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 { - assert (mark > 0); + KISSAT_assert (mark > 0); LOG ("adding duplicated literal %u(%d)", ilit, elit); if (!solver->clause_shrink) { solver->clause_shrink = true; @@ -316,16 +318,16 @@ void kissat_add (kissat *solver, int elit) { } } } else { -#if !defined(NDEBUG) || !defined(NPROOFS) || defined(LOGGING) +#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; - assert (esize <= UINT_MAX); + 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); - assert (isize < (unsigned) INT_MAX); + KISSAT_assert (isize < (unsigned) INT_MAX); if (solver->inconsistent) LOG ("inconsistent thus skipping original clause"); @@ -380,38 +382,38 @@ void kissat_add (kissat *solver, int elit) { assign = true; } else if (u < 0 && k == l) { LOG ("both watches falsified at level @%u", k); - assert (v < 0); - assert (k > 0); + 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); - assert (v < 0); - assert (k > l); - assert (l > 0); + 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); - assert (k <= l); + KISSAT_assert (k <= l); } else if (!u && v > 0) { LOG ("first watch unassigned " "second falsified at level @%u", l); assign = true; } else { - assert (!u); - assert (!v); + KISSAT_assert (!u); + KISSAT_assert (!v); } if (assign) { - assert (solver->level > 0); + KISSAT_assert (solver->level > 0); if (isize == 2) { - assert (res == INVALID_REF); + KISSAT_assert (res == INVALID_REF); kissat_assign_binary (solver, a, b); } else { - assert (res != INVALID_REF); + KISSAT_assert (res != INVALID_REF); clause *c = kissat_dereference_clause (solver, res); kissat_assign_reference (solver, a, res, c); } @@ -419,13 +421,13 @@ void kissat_add (kissat *solver, int elit) { } } -#if !defined(NDEBUG) || !defined(NPROOFS) +#if !defined(KISSAT_NDEBUG) || !defined(KISSAT_NPROOFS) if (solver->clause_satisfied || solver->clause_trivial) { -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG if (checking > 1) kissat_remove_checker_external (solver, esize, elits); #endif -#ifndef NPROOFS +#ifndef KISSAT_NPROOFS if (proving) { if (esize == 1) LOG ("skipping deleting unit from proof"); @@ -434,13 +436,13 @@ void kissat_add (kissat *solver, int elit) { } #endif } else if (!solver->inconsistent && solver->clause_shrink) { -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG if (checking > 1) { kissat_check_and_add_internal (solver, isize, ilits); kissat_remove_checker_external (solver, esize, elits); } #endif -#ifndef NPROOFS +#ifndef KISSAT_NPROOFS if (proving) { kissat_add_lits_to_proof (solver, isize, ilits); kissat_delete_external_from_proof (solver, esize, elits); @@ -449,7 +451,7 @@ void kissat_add (kissat *solver, int elit) { } #endif -#if !defined(NDEBUG) || !defined(NPROOFS) || defined(LOGGING) +#if !defined(KISSAT_NDEBUG) || !defined(KISSAT_NPROOFS) || defined(LOGGING) if (checking) { LOGINTS (esize, elits, "saved original"); PUSH_STACK (solver->original, 0); @@ -483,7 +485,7 @@ int kissat_solve (kissat *solver) { void kissat_terminate (kissat *solver) { kissat_require_initialized (solver); solver->termination.flagged = ~(unsigned) 0; - assert (solver->termination.flagged); + KISSAT_assert (solver->termination.flagged); } void kissat_set_terminate (kissat *solver, void *state, @@ -518,3 +520,9 @@ int kissat_value (kissat *solver, int elit) { tmp = -tmp; return tmp < 0 ? -elit : elit; } + +int kissat_is_inconsistent(kissat *solver) { + return solver->inconsistent; +} + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/internal.h b/src/sat/kissat/internal.h index 8a4b46c80..a3777a961 100644 --- a/src/sat/kissat/internal.h +++ b/src/sat/kissat/internal.h @@ -33,6 +33,9 @@ #include "vector.h" #include "watch.h" +#include "global.h" +ABC_NAMESPACE_HEADER_START + typedef struct datarank datarank; struct datarank { @@ -74,7 +77,7 @@ typedef STACK (watch *) patches; struct kitten; struct kissat { -#if !defined(NDEBUG) || defined(METRICS) +#if !defined(KISSAT_NDEBUG) || defined(METRICS) bool backbone_computing; #endif #ifdef LOGGING @@ -85,11 +88,11 @@ struct kissat { bool iterating; bool preprocessing; bool probing; -#ifndef QUIET +#ifndef KISSAT_QUIET bool sectioned; #endif bool stable; -#if !defined(NDEBUG) || defined(METRICS) +#if !defined(KISSAT_NDEBUG) || defined(METRICS) bool transitive_reducing; bool vivifying; #endif @@ -105,7 +108,7 @@ struct kissat { unsigned active; unsigned randec; - ints export; + ints export_; ints units; imports import; extensions extend; @@ -144,7 +147,7 @@ struct kissat { unsigneds delayed; -#if defined(LOGGING) || !defined(NDEBUG) +#if defined(LOGGING) || !defined(KISSAT_NDEBUG) unsigneds resolvent; #endif unsigned resolvent_size; @@ -197,7 +200,7 @@ struct kissat { uint64_t ticks; - format format; + kormat format; char *prefix; statches antecedents[2]; @@ -215,33 +218,33 @@ struct kissat { bool sweep_incomplete; unsigneds sweep_schedule; -#if !defined(NDEBUG) || !defined(NPROOFS) +#if !defined(KISSAT_NDEBUG) || !defined(KISSAT_NPROOFS) unsigneds added; unsigneds removed; #endif -#if !defined(NDEBUG) || !defined(NPROOFS) || defined(LOGGING) +#if !defined(KISSAT_NDEBUG) || !defined(KISSAT_NPROOFS) || defined(LOGGING) ints original; size_t offset_of_last_original_clause; #endif -#ifndef QUIET +#ifndef KISSAT_QUIET profiles profiles; #endif -#ifndef NOPTIONS +#ifndef KISSAT_NOPTIONS options options; #endif -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG checker *checker; #endif -#ifndef NPROOFS +#ifndef KISSAT_NPROOFS proof *proof; #endif - statistics statistics; + statistics statistics_; }; #define VARS (solver->vars) @@ -259,7 +262,7 @@ struct kissat { #define SCORES (&solver->scores) static inline unsigned kissat_assigned (kissat *solver) { - assert (VARS >= solver->unassigned); + KISSAT_assert (VARS >= solver->unassigned); return VARS - solver->unassigned; } @@ -292,4 +295,6 @@ static inline unsigned kissat_assigned (kissat *solver) { void kissat_reset_last_learned (kissat *solver); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/keatures.h b/src/sat/kissat/keatures.h index d0652be99..e3d4cb912 100644 --- a/src/sat/kissat/keatures.h +++ b/src/sat/kissat/keatures.h @@ -1,6 +1,9 @@ #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 @@ -15,4 +18,6 @@ #define KISSAT_HAS_UNLOCKEDIO #endif +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/kimits.c b/src/sat/kissat/kimits.c index 9fe4dcf05..f5507e098 100644 --- a/src/sat/kissat/kimits.c +++ b/src/sat/kissat/kimits.c @@ -10,29 +10,31 @@ #include #include +ABC_NAMESPACE_IMPL_START + double kissat_logn (uint64_t count) { - assert (count > 0); + KISSAT_assert (count > 0); const double res = log10 (count + 9); - assert (res >= 1); + KISSAT_assert (res >= 1); return res; } double kissat_sqrt (uint64_t count) { - assert (count > 0); + KISSAT_assert (count > 0); const double res = sqrt (count); - assert (res >= 1); + KISSAT_assert (res >= 1); return res; } double kissat_nlogpown (uint64_t count, unsigned exponent) { - assert (count > 0); + KISSAT_assert (count > 0); const double tmp = log10 (count + 9); double factor = 1; while (exponent--) factor *= tmp; - assert (factor >= 1); + KISSAT_assert (factor >= 1); const double res = count * factor; - assert (res >= 1); + KISSAT_assert (res >= 1); return res; } @@ -41,10 +43,10 @@ uint64_t kissat_scale_delta (kissat *solver, const char *pretty, const uint64_t C = BINIRR_CLAUSES; double f = kissat_logn (C + 1) - 5; const double ff = f * f; - assert (ff >= 0); + KISSAT_assert (ff >= 0); const double fff = 4.5 * ff + 25; uint64_t scaled = fff * delta; - assert (delta <= scaled); + KISSAT_assert (delta <= scaled); // clang-format off kissat_very_verbose (solver, "scaled %s delta %" PRIu64 @@ -97,7 +99,7 @@ static void init_enabled (kissat *solver) { } while (0) void kissat_init_limits (kissat *solver) { - assert (solver->statistics.searches == 1); + KISSAT_assert (solver->statistics.searches == 1); init_enabled (solver); @@ -131,7 +133,7 @@ void kissat_init_limits (kissat *solver) { INIT_CONFLICT_LIMIT (probe, true); } -#ifndef QUIET +#ifndef KISSAT_QUIET static const char *delay_description (kissat *solver, delay *delay) { delays *delays = &solver->delays; @@ -142,7 +144,7 @@ static const char *delay_description (kissat *solver, delay *delay) { else if (delay == &delays->sweep) return "sweeping"; else { - assert (delay == &delays->vivifyirr); + KISSAT_assert (delay == &delays->vivifyirr); return "vivifying irredundant clauses"; } } @@ -160,7 +162,7 @@ void kissat_reduce_delay (kissat *solver, delay *delay) { solver, "%s delay interval decreased to %u", delay_description (solver, delay), delay->current); delay->count = delay->current; -#ifdef QUIET +#ifdef KISSAT_QUIET (void) solver; #endif } @@ -171,7 +173,7 @@ void kissat_bump_delay (kissat *solver, delay *delay) { solver, "%s delay interval increased to %u", delay_description (solver, delay), delay->current); delay->count = delay->current; -#ifdef QUIET +#ifdef KISSAT_QUIET (void) solver; #endif } @@ -188,7 +190,9 @@ bool kissat_delaying (kissat *solver, delay *delay) { delay_description (solver, delay)); return false; } -#ifdef QUIET +#ifdef KISSAT_QUIET (void) solver; #endif } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/kimits.h b/src/sat/kissat/kimits.h index 93339b3b5..1696f05ed 100644 --- a/src/sat/kissat/kimits.h +++ b/src/sat/kissat/kimits.h @@ -4,6 +4,9 @@ #include #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + typedef struct bounds bounds; typedef struct changes changes; typedef struct delays delays; @@ -114,12 +117,12 @@ double kissat_logn (uint64_t); do { \ if (solver->inconsistent) \ break; \ - const struct statistics *statistics = &solver->statistics; \ - assert (statistics->COUNT > 0); \ + 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); \ - assert (SCALING >= 1); \ + KISSAT_assert (SCALING >= 1); \ DELTA *= SCALING; \ const uint64_t SCALED = \ !(SCALE_DELTA) ? DELTA \ @@ -135,8 +138,8 @@ double kissat_logn (uint64_t); #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 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; \ @@ -182,4 +185,6 @@ void kissat_reduce_delay (struct kissat *, delay *); #define REDUCE_DELAY(NAME) \ kissat_reduce_delay (solver, &solver->delays.NAME) +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/kissat.h b/src/sat/kissat/kissat.h index eec380566..10fade7ea 100644 --- a/src/sat/kissat/kissat.h +++ b/src/sat/kissat/kissat.h @@ -1,6 +1,9 @@ #ifndef _kissat_h_INCLUDED #define _kissat_h_INCLUDED +#include "global.h" +ABC_NAMESPACE_HEADER_START + typedef struct kissat kissat; // Default (partial) IPASIR interface. @@ -41,4 +44,9 @@ 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 diff --git a/src/sat/kissat/kissatSolver.c b/src/sat/kissat/kissatSolver.c new file mode 100644 index 000000000..8d8cb81cc --- /dev/null +++ b/src/sat/kissat/kissatSolver.c @@ -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 diff --git a/src/sat/kissat/kissatSolver.h b/src/sat/kissat/kissatSolver.h new file mode 100644 index 000000000..aa154dd46 --- /dev/null +++ b/src/sat/kissat/kissatSolver.h @@ -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 /// +//////////////////////////////////////////////////////////////////////// diff --git a/src/sat/kissat/kissatTest.c b/src/sat/kissat/kissatTest.c new file mode 100644 index 000000000..879db8799 --- /dev/null +++ b/src/sat/kissat/kissatTest.c @@ -0,0 +1,133 @@ +/**CFile**************************************************************** + + FileName [kissatTest.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: kissatTest.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "kissatSolver.h" + +ABC_NAMESPACE_IMPL_START + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// +void kissat_solver_test() { + int RetValue; + int Lits[3]; + // test 1 + { + kissat_solver *pSat = kissat_solver_new(); + int a = kissat_solver_addvar(pSat); + int b = kissat_solver_addvar(pSat); + int c = kissat_solver_addvar(pSat); + assert(kissat_solver_nvars(pSat) == 3); + Lits[0] = Abc_Var2Lit(a, 0); + Lits[1] = Abc_Var2Lit(b, 0); + Lits[2] = Abc_Var2Lit(c, 0); + printf("adding (a, b, c)\n"); + RetValue = kissat_solver_addclause(pSat, Lits, Lits + 3); + assert(RetValue); + Lits[0] = Abc_Var2Lit(a, 0); + Lits[1] = Abc_Var2Lit(b, 1); + printf("adding (a, !b)\n"); + RetValue = kissat_solver_addclause(pSat, Lits, Lits + 2); + assert(RetValue); + Lits[0] = Abc_Var2Lit(a, 1); + printf("adding (!a)\n"); + RetValue = kissat_solver_addclause(pSat, Lits, Lits + 1); + assert(RetValue); + RetValue = kissat_solver_solve(pSat, NULL, NULL, 0, 0, 0, 0); + printf("solved: %d\n", RetValue); + assert(RetValue == 1); + int a_val = kissat_solver_get_var_value(pSat, a); + int b_val = kissat_solver_get_var_value(pSat, b); + int c_val = kissat_solver_get_var_value(pSat, c); + printf("a = %d, b = %d, c = %d\n", a_val, b_val, c_val); + assert(a_val == 0); + assert(b_val == 0); + assert(c_val == 1); + kissat_solver_delete(pSat); + printf("test 1 passed\n"); + } + // test 2 + { + kissat_solver *pSat = kissat_solver_new(); + kissat_solver_setnvars(pSat, 2); + assert(kissat_solver_nvars(pSat) == 2); + Lits[0] = Abc_Var2Lit(0, 0); + Lits[1] = Abc_Var2Lit(1, 0); + printf("adding (x0, x1)\n"); + RetValue = kissat_solver_addclause(pSat, Lits, Lits + 2); + assert(RetValue); + Lits[0] = Abc_Var2Lit(0, 0); + Lits[1] = Abc_Var2Lit(1, 1); + printf("adding (x0, !x1)\n"); + RetValue = kissat_solver_addclause(pSat, Lits, Lits + 2); + assert(RetValue); + Lits[0] = Abc_Var2Lit(0, 1); + Lits[1] = Abc_Var2Lit(1, 1); + printf("adding (!x0, !x1)\n"); + RetValue = kissat_solver_addclause(pSat, Lits, Lits + 2); + assert(RetValue); + RetValue = kissat_solver_solve(pSat, NULL, NULL, 0, 0, 0, 0); + printf("solved: %d\n", RetValue); + assert(RetValue == 1); + printf("x0 = %d, x1 = %d\n", kissat_solver_get_var_value(pSat, 0), kissat_solver_get_var_value(pSat, 1)); + assert(kissat_solver_get_var_value(pSat, 0) == 1); + assert(kissat_solver_get_var_value(pSat, 1) == 0); + kissat_solver_delete(pSat); + printf("test 2 passed\n"); + } + // test 3 + { + kissat_solver *pSat = kissat_solver_new(); + kissat_solver_setnvars(pSat, 3); + assert(kissat_solver_nvars(pSat) == 3); + Lits[0] = Abc_Var2Lit(0, 1); + Lits[1] = Abc_Var2Lit(1, 0); + Lits[2] = Abc_Var2Lit(2, 1); + printf("adding (!x0, x1, !x2)\n"); + RetValue = kissat_solver_addclause(pSat, Lits, Lits + 3); + assert(RetValue); + Lits[0] = Abc_Var2Lit(0, 0); + printf("adding (x0)\n"); + RetValue = kissat_solver_addclause(pSat, Lits, Lits + 1); + assert(RetValue); + Lits[0] = Abc_Var2Lit(1, 1); + printf("adding (!x1)\n"); + RetValue = kissat_solver_addclause(pSat, Lits, Lits + 1); + assert(RetValue); + Lits[0] = Abc_Var2Lit(2, 0); + printf("adding (x2)\n"); + RetValue = kissat_solver_addclause(pSat, Lits, Lits + 1); + RetValue = kissat_solver_solve(pSat, NULL, NULL, 0, 0, 0, 0); + printf("solved: %d\n", RetValue); + assert(RetValue == -1); + kissat_solver_delete(pSat); + printf("test 3 passed\n"); + } +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/kitten.c b/src/sat/kissat/kitten.c index 903230f81..ea2e7f360 100644 --- a/src/sat/kissat/kitten.c +++ b/src/sat/kissat/kitten.c @@ -67,9 +67,9 @@ static inline void *kitten_calloc (size_t n, size_t size) { return res; } -#define CALLOC(P, N) \ +#define CALLOC(T, P, N) \ do { \ - (P) = kitten_calloc (N, sizeof *(P)); \ + (P) = (T*) kitten_calloc (N, sizeof *(P)); \ } while (0) #define DEALLOC(P, N) free (P) @@ -77,7 +77,7 @@ static inline void *kitten_calloc (size_t n, size_t size) { #define ENLARGE_STACK(S) \ do { \ - assert (FULL_STACK (S)); \ + KISSAT_assert (FULL_STACK (S)); \ const size_t SIZE = SIZE_STACK (S); \ const size_t OLD_CAPACITY = CAPACITY_STACK (S); \ const size_t NEW_CAPACITY = OLD_CAPACITY ? 2 * OLD_CAPACITY : 1; \ @@ -94,14 +94,14 @@ static inline void *kitten_calloc (size_t n, size_t size) { #define INC(NAME) \ do { \ statistics *statistics = &kitten->statistics; \ - assert (statistics->NAME < UINT64_MAX); \ + KISSAT_assert (statistics->NAME < UINT64_MAX); \ statistics->NAME++; \ } while (0) #define ADD(NAME, DELTA) \ do { \ statistics *statistics = &kitten->statistics; \ - assert (statistics->NAME <= UINT64_MAX - (DELTA)); \ + KISSAT_assert (statistics->NAME <= UINT64_MAX - (DELTA)); \ statistics->NAME += (DELTA); \ } while (0) @@ -116,12 +116,14 @@ static inline void *kitten_calloc (size_t n, size_t size) { #include "internal.h" // Also use 'kissat' statistics if embedded. #include "terminate.h" // For macros defining termination macro. -#define KITTEN_TICKS (solver->statistics.kitten_ticks) +#define KITTEN_TICKS (solver->statistics_.kitten_ticks) /*------------------------------------------------------------------------*/ #endif // STAND_ALONE_KITTEN /*------------------------------------------------------------------------*/ +ABC_NAMESPACE_IMPL_START + #define INVALID UINT_MAX #define MAX_VARS ((1u << 31) - 1) @@ -257,7 +259,7 @@ struct kitten { unsigneds assumptions; unsigneds core; unsigneds eclause; - unsigneds export; + unsigneds export_; unsigneds klause; unsigneds klauses; unsigneds resolved; @@ -288,7 +290,7 @@ static inline void unset_core_klause (klause *c) { c->flags &= ~CORE_FLAG; } static inline klause *dereference_klause (kitten *kitten, unsigned ref) { unsigned *res = BEGIN_STACK (kitten->klauses) + ref; - assert (res < END_STACK (kitten->klauses)); + KISSAT_assert (res < END_STACK (kitten->klauses)); return (klause *) res; } @@ -297,8 +299,8 @@ static inline klause *dereference_klause (kitten *kitten, unsigned ref) { static inline unsigned reference_klause (kitten *kitten, const klause *c) { const unsigned *const begin = BEGIN_STACK (kitten->klauses); const unsigned *p = (const unsigned *) c; - assert (begin <= p); - assert (p < END_STACK (kitten->klauses)); + KISSAT_assert (begin <= p); + KISSAT_assert (p < END_STACK (kitten->klauses)); const unsigned res = p - begin; return res; } @@ -307,7 +309,7 @@ static inline unsigned reference_klause (kitten *kitten, const klause *c) { /*------------------------------------------------------------------------*/ -#define KATCHES(KIT) (kitten->watches[assert ((KIT) < kitten->lits), (KIT)]) +#define KATCHES(KIT) (kitten->watches[KISSAT_assert ((KIT) < kitten->lits), (KIT)]) #define all_klauses(C) \ klause *C = begin_klauses (kitten), *end_##C = end_klauses (kitten); \ @@ -342,7 +344,7 @@ static inline unsigned reference_klause (kitten *kitten, const klause *c) { ++KIT##_PTR #define all_antecedents(REF, C) \ - unsigned REF, *REF##_PTR = antecedents (C), \ + unsigned REF, *REF##_PTR = antecedents_func (C), \ *REF##_END = REF##_PTR + (C)->aux; \ REF##_PTR != REF##_END && ((REF = *REF##_PTR), true); \ ++REF##_PTR @@ -359,7 +361,7 @@ static void log_basic (kitten *, const char *, ...) __attribute__ ((format (printf, 2, 3))); static void log_basic (kitten *kitten, const char *fmt, ...) { - assert (logging); + KISSAT_assert (logging); printf ("c KITTEN %u ", kitten->level); va_list ap; va_start (ap, fmt); @@ -375,7 +377,7 @@ static void log_reference (kitten *, unsigned, const char *, ...) static void log_reference (kitten *kitten, unsigned ref, const char *fmt, ...) { klause *c = dereference_klause (kitten, ref); - assert (logging); + KISSAT_assert (logging); printf ("c KITTEN %u ", kitten->level); va_list ap; va_start (ap, fmt); @@ -435,26 +437,26 @@ static void check_queue (kitten *kitten) { for (unsigned idx = kitten->queue.first, next; idx != INVALID; idx = next) { kink *link = links + idx; - assert (link->prev == prev); - assert (!found || stamp < link->stamp); - assert (link->stamp < kitten->queue.stamp); + KISSAT_assert (link->prev == prev); + KISSAT_assert (!found || stamp < link->stamp); + KISSAT_assert (link->stamp < kitten->queue.stamp); stamp = link->stamp; next = link->next; prev = idx; found++; } - assert (found == vars); + KISSAT_assert (found == vars); unsigned next = INVALID; found = 0; for (unsigned idx = kitten->queue.last, prev; idx != INVALID; idx = prev) { kink *link = links + idx; - assert (link->next == next); + KISSAT_assert (link->next == next); prev = link->prev; next = idx; found++; } - assert (found == vars); + KISSAT_assert (found == vars); value *values = kitten->values; bool first = true; for (unsigned idx = kitten->queue.search, next; idx != INVALID; @@ -462,7 +464,7 @@ static void check_queue (kitten *kitten) { kink *link = links + idx; next = link->next; const unsigned lit = 2 * idx; - assert (first || values[lit]); + KISSAT_assert (first || values[lit]); first = false; } #else @@ -512,8 +514,8 @@ static void dequeue (kitten *kitten, unsigned idx) { static void init_queue (kitten *kitten, size_t old_vars, size_t new_vars) { for (size_t idx = old_vars; idx < new_vars; idx++) { - assert (!kitten->values[2 * idx]); - assert (kitten->unassigned < UINT_MAX); + KISSAT_assert (!kitten->values[2 * idx]); + KISSAT_assert (kitten->unassigned < UINT_MAX); kitten->unassigned++; enqueue (kitten, idx); } @@ -541,35 +543,35 @@ static void clear_kitten (kitten *kitten) { initialize_kitten (kitten); } -#define RESIZE1(P) \ +#define RESIZE1(T, P) \ do { \ void *OLD_PTR = (P); \ - CALLOC ((P), new_size / 2); \ + CALLOC (T, (P), new_size / 2); \ const size_t BYTES = old_vars * sizeof *(P); \ if (BYTES) \ memcpy ((P), OLD_PTR, BYTES); \ void *NEW_PTR = (P); \ - (P) = OLD_PTR; \ + (P) = (T*) OLD_PTR; \ DEALLOC ((P), old_size / 2); \ - (P) = NEW_PTR; \ + (P) = (T*) NEW_PTR; \ } while (0) -#define RESIZE2(P) \ +#define RESIZE2(T, P) \ do { \ void *OLD_PTR = (P); \ - CALLOC ((P), new_size); \ + CALLOC (T, (P), new_size); \ const size_t BYTES = old_lits * sizeof *(P); \ if (BYTES) \ memcpy ((P), OLD_PTR, BYTES); \ void *NEW_PTR = (P); \ - (P) = OLD_PTR; \ + (P) = (T*) OLD_PTR; \ DEALLOC ((P), old_size); \ - (P) = NEW_PTR; \ + (P) = (T*) NEW_PTR; \ } while (0) static void enlarge_internal (kitten *kitten, size_t new_lits) { const size_t old_lits = kitten->lits; - assert (old_lits < new_lits); + KISSAT_assert (old_lits < new_lits); const size_t old_size = kitten->size; const unsigned new_vars = new_lits / 2; const unsigned old_vars = old_lits / 2; @@ -580,13 +582,13 @@ static void enlarge_internal (kitten *kitten, size_t new_lits) { LOG ("internal literals resized to %zu from %zu (requested %zu)", new_size, old_size, new_lits); - RESIZE1 (kitten->marks); - RESIZE1 (kitten->phases); - RESIZE2 (kitten->values); - RESIZE2 (kitten->failed); - RESIZE1 (kitten->vars); - RESIZE1 (kitten->links); - RESIZE2 (kitten->watches); + RESIZE1 (value, kitten->marks); + RESIZE1 (unsigned char, kitten->phases); + RESIZE2 (value, kitten->values); + RESIZE2 (bool, kitten->failed); + RESIZE1 (kar, kitten->vars); + RESIZE1 (kink, kitten->links); + RESIZE2 (katches, kitten->watches); kitten->size = new_size; } @@ -605,7 +607,7 @@ static const char *status_to_string (int status) { case 21: return "formula inconsistent and core computed"; default: - assert (!status); + KISSAT_assert (!status); return "formula unsolved"; } } @@ -652,7 +654,7 @@ static void invalid_api_usage (const char *fun, const char *fmt, ...) { kitten *kitten_init (void) { kitten *kitten; - CALLOC (kitten, 1); + CALLOC (struct kitten, kitten, 1); initialize_kitten (kitten); return kitten; } @@ -667,7 +669,7 @@ kitten *kitten_embedded (struct kissat *kissat) { struct kitten dummy; dummy.kissat = kissat; kitten = &dummy; - CALLOC (kitten, 1); + CALLOC (struct kitten, kitten, 1); kitten->kissat = kissat; initialize_kitten (kitten); return kitten; @@ -827,8 +829,8 @@ void kitten_shuffle_clauses (kitten *kitten) { shuffle_units (kitten); } -static inline unsigned *antecedents (klause *c) { - assert (is_learned_klause (c)); +static inline unsigned *antecedents_func (klause *c) { + KISSAT_assert (is_learned_klause (c)); return c->lits + c->size; } @@ -840,11 +842,11 @@ static inline void watch_klause (kitten *kitten, unsigned lit, klause *c, katch.ref = ref; #ifdef KITTEN_BLIT const unsigned size = c->size; - assert (lit == c->lits[0] || lit == c->lits[1]); + KISSAT_assert (lit == c->lits[0] || lit == c->lits[1]); const unsigned blit = c->lits[0] ^ c->lits[1] ^ lit; const bool binary = size == 2; - assert (size > 1); - assert (ref < (1u << 31)); + KISSAT_assert (size > 1); + KISSAT_assert (ref < (1u << 31)); katch.blit = blit; katch.binary = binary; #else @@ -883,7 +885,7 @@ static unsigned new_reference (kitten *kitten) { #endif } const unsigned res = (unsigned) ref; - assert (res != INVALID); + KISSAT_assert (res != INVALID); INC (kitten_ticks); return res; } @@ -907,7 +909,7 @@ static void new_original_klause (kitten *kitten, unsigned id) { static void enlarge_external (kitten *kitten, size_t eidx) { const size_t old_size = kitten->esize; const unsigned old_evars = kitten->evars; - assert (old_evars <= eidx); + KISSAT_assert (old_evars <= eidx); const unsigned new_evars = eidx + 1; if (old_size <= eidx) { size_t new_size = old_size ? 2 * old_size : 1; @@ -916,7 +918,7 @@ static void enlarge_external (kitten *kitten, size_t eidx) { LOG ("external resizing to %zu variables from %zu (requested %u)", new_size, old_size, new_evars); unsigned *old_import = kitten->import; - CALLOC (kitten->import, new_size); + CALLOC (unsigned, kitten->import, new_size); const size_t bytes = old_evars * sizeof *kitten->import; if (bytes) memcpy (kitten->import, old_import, bytes); @@ -934,16 +936,16 @@ static unsigned import_literal (kitten *kitten, unsigned elit) { unsigned iidx = kitten->import[eidx]; if (!iidx) { - iidx = SIZE_STACK (kitten->export); - PUSH_STACK (kitten->export, eidx); + iidx = SIZE_STACK (kitten->export_); + PUSH_STACK (kitten->export_, eidx); kitten->import[eidx] = iidx + 1; } else iidx--; unsigned ilit = 2 * iidx + (elit & 1); LOG ("imported external literal %u as internal literal %u", elit, ilit); const size_t new_lits = (ilit | 1) + (size_t) 1; - assert (ilit < new_lits); - assert (ilit / 2 < new_lits / 2); + KISSAT_assert (ilit < new_lits); + KISSAT_assert (ilit / 2 < new_lits / 2); if (new_lits > kitten->lits) enlarge_internal (kitten, new_lits); return ilit; @@ -951,8 +953,8 @@ static unsigned import_literal (kitten *kitten, unsigned elit) { static unsigned export_literal (kitten *kitten, unsigned ilit) { const unsigned iidx = ilit / 2; - assert (iidx < SIZE_STACK (kitten->export)); - const unsigned eidx = PEEK_STACK (kitten->export, iidx); + KISSAT_assert (iidx < SIZE_STACK (kitten->export_)); + const unsigned eidx = PEEK_STACK (kitten->export_, iidx); const unsigned elit = 2 * eidx + (ilit & 1); return elit; } @@ -961,10 +963,10 @@ unsigned new_learned_klause (kitten *kitten) { unsigned res = new_reference (kitten); unsigneds *klauses = &kitten->klauses; const size_t size = SIZE_STACK (kitten->klause); - assert (size <= UINT_MAX); + KISSAT_assert (size <= UINT_MAX); const size_t aux = kitten->antecedents ? SIZE_STACK (kitten->resolved) : 0; - assert (aux <= UINT_MAX); + KISSAT_assert (aux <= UINT_MAX); PUSH_STACK (*klauses, (unsigned) aux); PUSH_STACK (*klauses, (unsigned) size); PUSH_STACK (*klauses, LEARNED_FLAG); @@ -984,10 +986,10 @@ unsigned new_learned_klause (kitten *kitten) { void kitten_clear (kitten *kitten) { LOG ("clear kitten of size %zu", kitten->size); - assert (EMPTY_STACK (kitten->analyzed)); - assert (EMPTY_STACK (kitten->klause)); - assert (EMPTY_STACK (kitten->eclause)); - assert (EMPTY_STACK (kitten->resolved)); + KISSAT_assert (EMPTY_STACK (kitten->analyzed)); + KISSAT_assert (EMPTY_STACK (kitten->klause)); + KISSAT_assert (EMPTY_STACK (kitten->eclause)); + KISSAT_assert (EMPTY_STACK (kitten->resolved)); CLEAR_STACK (kitten->assumptions); CLEAR_STACK (kitten->core); @@ -999,15 +1001,15 @@ void kitten_clear (kitten *kitten) { for (all_kits (kit)) CLEAR_STACK (KATCHES (kit)); - while (!EMPTY_STACK (kitten->export)) - kitten->import[POP_STACK (kitten->export)] = 0; + while (!EMPTY_STACK (kitten->export_)) + kitten->import[POP_STACK (kitten->export_)] = 0; const size_t lits = kitten->size; const unsigned vars = lits / 2; -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG for (unsigned i = 0; i < vars; i++) - assert (!kitten->marks[i]); + KISSAT_assert (!kitten->marks[i]); #endif if (vars) { @@ -1028,7 +1030,7 @@ void kitten_release (kitten *kitten) { RELEASE_STACK (kitten->assumptions); RELEASE_STACK (kitten->core); RELEASE_STACK (kitten->eclause); - RELEASE_STACK (kitten->export); + RELEASE_STACK (kitten->export_); RELEASE_STACK (kitten->klause); RELEASE_STACK (kitten->klauses); RELEASE_STACK (kitten->resolved); @@ -1063,7 +1065,7 @@ static inline void move_to_front (kitten *kitten, unsigned idx) { LOG ("move to front variable %u", idx); dequeue (kitten, idx); enqueue (kitten, idx); - assert (kitten->values[2 * idx]); + KISSAT_assert (kitten->values[2 * idx]); } static inline void assign (kitten *kitten, unsigned lit, unsigned reason) { @@ -1075,8 +1077,8 @@ static inline void assign (kitten *kitten, unsigned lit, unsigned reason) { #endif value *values = kitten->values; const unsigned not_lit = lit ^ 1; - assert (!values[lit]); - assert (!values[not_lit]); + KISSAT_assert (!values[lit]); + KISSAT_assert (!values[not_lit]); values[lit] = 1; values[not_lit] = -1; const unsigned idx = lit / 2; @@ -1086,7 +1088,7 @@ static inline void assign (kitten *kitten, unsigned lit, unsigned reason) { kar *v = kitten->vars + idx; v->level = kitten->level; if (!v->level) { - assert (reason != INVALID); + KISSAT_assert (reason != INVALID); klause *c = dereference_klause (kitten, reason); if (c->size > 1) { if (kitten->antecedents) { @@ -1095,7 +1097,7 @@ static inline void assign (kitten *kitten, unsigned lit, unsigned reason) { if (other != lit) { const unsigned other_idx = other / 2; const unsigned other_ref = kitten->vars[other_idx].reason; - assert (other_ref != INVALID); + KISSAT_assert (other_ref != INVALID); PUSH_STACK (kitten->resolved, other_ref); } } @@ -1106,14 +1108,14 @@ static inline void assign (kitten *kitten, unsigned lit, unsigned reason) { } } v->reason = reason; - assert (kitten->unassigned); + KISSAT_assert (kitten->unassigned); kitten->unassigned--; } static inline unsigned propagate_literal (kitten *kitten, unsigned lit) { LOG ("propagating %u", lit); value *values = kitten->values; - assert (values[lit] > 0); + KISSAT_assert (values[lit] > 0); const unsigned not_lit = lit ^ 1; katches *watches = kitten->watches + not_lit; unsigned conflict = INVALID; @@ -1126,7 +1128,7 @@ static inline unsigned propagate_literal (kitten *kitten, unsigned lit) { const unsigned ref = katch.ref; #ifdef KITTEN_BLIT const unsigned blit = katch.blit; - assert (blit != not_lit); + KISSAT_assert (blit != not_lit); const value blit_value = values[blit]; if (blit_value > 0) continue; @@ -1137,14 +1139,14 @@ static inline unsigned propagate_literal (kitten *kitten, unsigned lit) { conflict = ref; break; } else { - assert (!blit_value); + KISSAT_assert (!blit_value); assign (kitten, blit, ref); continue; } } #endif klause *c = dereference_klause (kitten, ref); - assert (c->size > 1); + KISSAT_assert (c->size > 1); unsigned *lits = c->lits; const unsigned other = lits[0] ^ lits[1] ^ not_lit; const value other_value = values[other]; @@ -1166,7 +1168,7 @@ static inline unsigned propagate_literal (kitten *kitten, unsigned lit) { break; } if (replacement_value >= 0) { - assert (replacement != INVALID); + KISSAT_assert (replacement != INVALID); ROG (ref, "unwatching %u in", not_lit); lits[0] = other; lits[1] = replacement; @@ -1179,7 +1181,7 @@ static inline unsigned propagate_literal (kitten *kitten, unsigned lit) { conflict = ref; break; } else { - assert (!other_value); + KISSAT_assert (!other_value); assign (kitten, other, ref); } } @@ -1191,7 +1193,7 @@ static inline unsigned propagate_literal (kitten *kitten, unsigned lit) { } static inline unsigned propagate (kitten *kitten) { - assert (kitten->inconsistent == INVALID); + KISSAT_assert (kitten->inconsistent == INVALID); unsigned propagated = 0; unsigned conflict = INVALID; while (conflict == INVALID && @@ -1216,8 +1218,8 @@ static void bump (kitten *kitten) { static inline void unassign (kitten *kitten, value *values, unsigned lit) { const unsigned not_lit = lit ^ 1; - assert (values[lit]); - assert (values[not_lit]); + KISSAT_assert (values[lit]); + KISSAT_assert (values[not_lit]); const unsigned idx = lit / 2; #ifdef LOGGING kar *var = kitten->vars + idx; @@ -1225,7 +1227,7 @@ static inline void unassign (kitten *kitten, value *values, unsigned lit) { LOG ("unassign %u", lit); #endif values[lit] = values[not_lit] = 0; - assert (kitten->unassigned < kitten->lits / 2); + KISSAT_assert (kitten->unassigned < kitten->lits / 2); kitten->unassigned++; kink *links = kitten->links; kink *link = links + idx; @@ -1235,7 +1237,7 @@ static inline void unassign (kitten *kitten, value *values, unsigned lit) { static void backtrack (kitten *kitten, unsigned jump) { check_queue (kitten); - assert (jump < kitten->level); + KISSAT_assert (jump < kitten->level); LOG ("back%s to level %u", (kitten->level == jump + 1 ? "tracking" : "jumping"), jump); kar *vars = kitten->vars; @@ -1260,11 +1262,11 @@ void completely_backtrack_to_root_level (kitten *kitten) { LOG ("completely backtracking to level 0"); value *values = kitten->values; unsigneds *trail = &kitten->trail; -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG kar *vars = kitten->vars; #endif for (all_stack (unsigned, lit, *trail)) { - assert (vars[lit / 2].level); + KISSAT_assert (vars[lit / 2].level); unassign (kitten, values, lit); } CLEAR_STACK (*trail); @@ -1274,11 +1276,11 @@ void completely_backtrack_to_root_level (kitten *kitten) { } static void analyze (kitten *kitten, unsigned conflict) { - assert (kitten->level); - assert (kitten->inconsistent == INVALID); - assert (EMPTY_STACK (kitten->analyzed)); - assert (EMPTY_STACK (kitten->resolved)); - assert (EMPTY_STACK (kitten->klause)); + KISSAT_assert (kitten->level); + KISSAT_assert (kitten->inconsistent == INVALID); + KISSAT_assert (EMPTY_STACK (kitten->analyzed)); + KISSAT_assert (EMPTY_STACK (kitten->resolved)); + KISSAT_assert (EMPTY_STACK (kitten->klause)); PUSH_STACK (kitten->klause, INVALID); unsigned reason = conflict; value *marks = kitten->marks; @@ -1287,16 +1289,16 @@ static void analyze (kitten *kitten, unsigned conflict) { unsigned const *p = END_STACK (kitten->trail); unsigned open = 0, jump = 0, size = 1, uip; for (;;) { - assert (reason != INVALID); + KISSAT_assert (reason != INVALID); klause *c = dereference_klause (kitten, reason); - assert (c); + KISSAT_assert (c); ROG (reason, "analyzing"); PUSH_STACK (kitten->resolved, reason); for (all_literals_in_klause (lit, c)) { const unsigned idx = lit / 2; if (marks[idx]) continue; - assert (kitten->values[lit] < 0); + KISSAT_assert (kitten->values[lit] < 0); LOG ("analyzed %u", lit); marks[idx] = true; PUSH_STACK (kitten->analyzed, idx); @@ -1318,10 +1320,10 @@ static void analyze (kitten *kitten, unsigned conflict) { } unsigned idx; do { - assert (BEGIN_STACK (kitten->trail) < p); + KISSAT_assert (BEGIN_STACK (kitten->trail) < p); uip = *--p; } while (!marks[idx = uip / 2]); - assert (open); + KISSAT_assert (open); if (!--open) break; reason = vars[idx].reason; @@ -1339,11 +1341,11 @@ static void analyze (kitten *kitten, unsigned conflict) { } static void failing (kitten *kitten) { - assert (kitten->inconsistent == INVALID); - assert (!EMPTY_STACK (kitten->assumptions)); - assert (EMPTY_STACK (kitten->analyzed)); - assert (EMPTY_STACK (kitten->resolved)); - assert (EMPTY_STACK (kitten->klause)); + KISSAT_assert (kitten->inconsistent == INVALID); + KISSAT_assert (!EMPTY_STACK (kitten->assumptions)); + KISSAT_assert (EMPTY_STACK (kitten->analyzed)); + KISSAT_assert (EMPTY_STACK (kitten->resolved)); + KISSAT_assert (EMPTY_STACK (kitten->klause)); LOG ("analyzing failing assumptions"); const value *const values = kitten->values; const kar *const vars = kitten->vars; @@ -1371,7 +1373,7 @@ static void failing (kitten *kitten) { failed = failed_clashing; else failed = first_failed; - assert (failed != INVALID); + KISSAT_assert (failed != INVALID); const unsigned failed_idx = failed / 2; const kar *const failed_var = vars + failed_idx; const unsigned failed_reason = failed_var->reason; @@ -1379,7 +1381,7 @@ static void failing (kitten *kitten) { kitten->failed[failed] = true; if (failed_unit != INVALID) { - assert (dereference_klause (kitten, failed_reason)->size == 1); + KISSAT_assert (dereference_klause (kitten, failed_reason)->size == 1); LOG ("root-level falsified assumption %u", failed); kitten->failing = failed_reason; ROG (kitten->failing, "failing reason"); @@ -1390,19 +1392,19 @@ static void failing (kitten *kitten) { if (failed_clashing != INVALID) { LOG ("clashing with negated assumption %u", not_failed); kitten->failed[not_failed] = true; - assert (kitten->failing == INVALID); + KISSAT_assert (kitten->failing == INVALID); return; } value *marks = kitten->marks; - assert (!marks[failed_idx]); + KISSAT_assert (!marks[failed_idx]); marks[failed_idx] = true; PUSH_STACK (kitten->analyzed, failed_idx); PUSH_STACK (kitten->klause, not_failed); for (size_t next = 0; next < SIZE_STACK (kitten->analyzed); next++) { const unsigned idx = PEEK_STACK (kitten->analyzed, next); - assert (marks[idx]); + KISSAT_assert (marks[idx]); const kar *var = vars + idx; const unsigned reason = var->reason; if (reason == INVALID) { @@ -1410,7 +1412,7 @@ static void failing (kitten *kitten) { if (values[lit] < 0) lit ^= 1; LOG ("failed assumption %u", lit); - assert (!kitten->failed[lit]); + KISSAT_assert (!kitten->failed[lit]); kitten->failed[lit] = true; const unsigned not_lit = lit ^ 1; PUSH_STACK (kitten->klause, not_lit); @@ -1432,11 +1434,11 @@ static void failing (kitten *kitten) { } for (all_stack (unsigned, idx, kitten->analyzed)) - assert (marks[idx]), marks[idx] = 0; + KISSAT_assert (marks[idx]), marks[idx] = 0; CLEAR_STACK (kitten->analyzed); const size_t resolved = SIZE_STACK (kitten->resolved); - assert (resolved); + KISSAT_assert (resolved); if (resolved == 1) { kitten->failing = PEEK_STACK (kitten->resolved, 0); @@ -1453,7 +1455,7 @@ static void failing (kitten *kitten) { static void flush_trail (kitten *kitten) { unsigneds *trail = &kitten->trail; LOG ("flushing %zu root-level literals from trail", SIZE_STACK (*trail)); - assert (!kitten->level); + KISSAT_assert (!kitten->level); kitten->propagated = 0; CLEAR_STACK (*trail); } @@ -1502,7 +1504,7 @@ static int decide (kitten *kitten) { unsigned idx = kitten->queue.search; const kink *const links = kitten->links; for (;;) { - assert (idx != INVALID); + KISSAT_assert (idx != INVALID); if (!values[2 * idx]) break; idx = links[idx].prev; @@ -1519,8 +1521,8 @@ static int decide (kitten *kitten) { } static void inconsistent (kitten *kitten, unsigned ref) { - assert (ref != INVALID); - assert (kitten->inconsistent == INVALID); + KISSAT_assert (ref != INVALID); + KISSAT_assert (kitten->inconsistent == INVALID); if (!kitten->antecedents) { kitten->inconsistent = ref; @@ -1531,25 +1533,25 @@ static void inconsistent (kitten *kitten, unsigned ref) { unsigneds *analyzed = &kitten->analyzed; unsigneds *resolved = &kitten->resolved; - assert (EMPTY_STACK (*analyzed)); - assert (EMPTY_STACK (*resolved)); + KISSAT_assert (EMPTY_STACK (*analyzed)); + KISSAT_assert (EMPTY_STACK (*resolved)); value *marks = kitten->marks; const kar *const vars = kitten->vars; unsigned next = 0; for (;;) { - assert (ref != INVALID); + KISSAT_assert (ref != INVALID); klause *c = dereference_klause (kitten, ref); - assert (c); + KISSAT_assert (c); ROG (ref, "analyzing inconsistent"); PUSH_STACK (*resolved, ref); for (all_literals_in_klause (lit, c)) { const unsigned idx = lit / 2; - assert (!vars[idx].level); + KISSAT_assert (!vars[idx].level); if (marks[idx]) continue; - assert (kitten->values[lit] < 0); + KISSAT_assert (kitten->values[lit] < 0); LOG ("analyzed %u", lit); marks[idx] = true; PUSH_STACK (kitten->analyzed, idx); @@ -1559,10 +1561,10 @@ static void inconsistent (kitten *kitten, unsigned ref) { const unsigned idx = PEEK_STACK (kitten->analyzed, next); next++; const kar *const v = vars + idx; - assert (!v->level); + KISSAT_assert (!v->level); ref = v->reason; } - assert (EMPTY_STACK (kitten->klause)); + KISSAT_assert (EMPTY_STACK (kitten->klause)); ref = new_learned_klause (kitten); ROG (ref, "registering final inconsistent empty"); kitten->inconsistent = ref; @@ -1590,9 +1592,9 @@ static int propagate_units (kitten *kitten) { for (size_t next = 0; next < SIZE_STACK (kitten->units); next++) { const unsigned ref = PEEK_STACK (kitten->units, next); - assert (ref != INVALID); + KISSAT_assert (ref != INVALID); klause *c = dereference_klause (kitten, ref); - assert (c->size == 1); + KISSAT_assert (c->size == 1); ROG (ref, "propagating unit"); const unsigned unit = c->lits[0]; const value value = values[unit]; @@ -1628,8 +1630,8 @@ static klause *end_klauses (kitten *kitten) { } static klause *next_klause (kitten *kitten, klause *c) { - assert (begin_klauses (kitten) <= c); - assert (c < end_klauses (kitten)); + KISSAT_assert (begin_klauses (kitten) <= c); + KISSAT_assert (c < end_klauses (kitten)); unsigned *res = c->lits + c->size; if (kitten->antecedents && is_learned_klause (c)) res += c->aux; @@ -1654,9 +1656,9 @@ static void reset_assumptions (kitten *kitten) { const unsigned assumption = POP_STACK (kitten->assumptions); kitten->failed[assumption] = false; } -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG for (size_t i = 0; i < kitten->size; i++) - assert (!kitten->failed[i]); + KISSAT_assert (!kitten->failed[i]); #endif CLEAR_STACK (kitten->assumptions); if (kitten->failing != INVALID) { @@ -1671,7 +1673,7 @@ static void reset_incremental (kitten *kitten) { if (!EMPTY_STACK (kitten->assumptions)) reset_assumptions (kitten); else - assert (kitten->failing == INVALID); + KISSAT_assert (kitten->failing == INVALID); if (kitten->status == 21) reset_core (kitten); UPDATE_STATUS (0); @@ -1682,7 +1684,7 @@ static void reset_incremental (kitten *kitten) { static bool flip_literal (kitten *kitten, unsigned lit) { INC (kitten_flip); signed char *values = kitten->values; - assert (values[lit]); + KISSAT_assert (values[lit]); if (!kitten->vars[lit / 2].level) { LOG ("can not flip root-level assigned literal %u", lit); return false; @@ -1690,7 +1692,7 @@ static bool flip_literal (kitten *kitten, unsigned lit) { if (values[lit] < 0) lit ^= 1; LOG ("trying to flip value of satisfied literal %u", lit); - assert (values[lit] > 0); + KISSAT_assert (values[lit] > 0); katches *watches = kitten->watches + lit; katch *q = BEGIN_STACK (*watches); const katch *const end_watches = END_STACK (*watches); @@ -1701,7 +1703,7 @@ static bool flip_literal (kitten *kitten, unsigned lit) { const katch katch = *q++ = *p++; #ifdef KITTEN_BLIT const unsigned blit = katch.blit; - assert (blit != lit); + KISSAT_assert (blit != lit); const value blit_value = values[blit]; if (blit_value > 0) continue; @@ -1720,14 +1722,14 @@ static bool flip_literal (kitten *kitten, unsigned lit) { unsigned *r; for (r = lits + 2; r != end_lits; r++) { replacement = *r; - assert (replacement != lit); + KISSAT_assert (replacement != lit); replacement_value = values[replacement]; - assert (replacement_value); + KISSAT_assert (replacement_value); if (replacement_value > 0) break; } if (replacement_value > 0) { - assert (replacement != INVALID); + KISSAT_assert (replacement != INVALID); ROG (ref, "unwatching %u in", lit); lits[0] = other; lits[1] = replacement; @@ -1735,7 +1737,7 @@ static bool flip_literal (kitten *kitten, unsigned lit) { watch_klause (kitten, replacement, c, ref); q--; } else { - assert (replacement_value < 0); + KISSAT_assert (replacement_value < 0); ROG (ref, "single satisfied"); res = false; break; @@ -1774,14 +1776,14 @@ void kitten_clause_with_id_and_exception (kitten *kitten, unsigned id, REQUIRE_INITIALIZED (); if (kitten->status) reset_incremental (kitten); - assert (EMPTY_STACK (kitten->klause)); + KISSAT_assert (EMPTY_STACK (kitten->klause)); const unsigned *const end = elits + size; for (const unsigned *p = elits; p != end; p++) { const unsigned elit = *p; if (elit == except) continue; const unsigned ilit = import_literal (kitten, elit); - assert (ilit < kitten->lits); + KISSAT_assert (ilit < kitten->lits); const unsigned iidx = ilit / 2; if (kitten->marks[iidx]) INVALID_API_USAGE ("variable '%u' of literal '%u' occurs twice", @@ -1877,7 +1879,7 @@ unsigned kitten_compute_clausal_core (kitten *kitten, LOG ("computing clausal core"); unsigneds *resolved = &kitten->resolved; - assert (EMPTY_STACK (*resolved)); + KISSAT_assert (EMPTY_STACK (*resolved)); unsigned original = 0; uint64_t learned = 0; @@ -1885,17 +1887,33 @@ unsigned kitten_compute_clausal_core (kitten *kitten, unsigned reason_ref = kitten->inconsistent; if (reason_ref == INVALID) { - assert (!EMPTY_STACK (kitten->assumptions)); + KISSAT_assert (!EMPTY_STACK (kitten->assumptions)); reason_ref = kitten->failing; if (reason_ref == INVALID) { LOG ("assumptions mutually inconsistent"); - goto DONE; + + + // goto DONE; + if (learned_ptr) + *learned_ptr = learned; + + LOG ("clausal core of %u original clauses", original); + LOG ("clausal core of %" PRIu64 " learned clauses", learned); +#ifdef STAND_ALONE_KITTEN + kitten->statistics.original = original; + kitten->statistics.learned = 0; +#endif + UPDATE_STATUS (21); + + return original; + + } } PUSH_STACK (*resolved, reason_ref); unsigneds *core = &kitten->core; - assert (EMPTY_STACK (*core)); + KISSAT_assert (EMPTY_STACK (*core)); while (!EMPTY_STACK (*resolved)) { const unsigned c_ref = POP_STACK (*resolved); @@ -1904,7 +1922,7 @@ unsigned kitten_compute_clausal_core (kitten *kitten, ROG (d_ref, "core[%zu]", SIZE_STACK (*core)); PUSH_STACK (*core, d_ref); klause *d = dereference_klause (kitten, d_ref); - assert (!is_core_klause (d)); + KISSAT_assert (!is_core_klause (d)); set_core_klause (d); if (is_learned_klause (d)) learned++; @@ -1927,7 +1945,7 @@ unsigned kitten_compute_clausal_core (kitten *kitten, } } -DONE: + //DONE: if (learned_ptr) *learned_ptr = learned; @@ -1952,7 +1970,7 @@ void kitten_traverse_core_ids (kitten *kitten, void *state, unsigned traversed = 0; for (all_original_klauses (c)) { - assert (!is_learned_klause (c)); + KISSAT_assert (!is_learned_klause (c)); if (is_learned_klause (c)) continue; if (!is_core_klause (c)) @@ -1965,7 +1983,7 @@ void kitten_traverse_core_ids (kitten *kitten, void *state, LOG ("traversed %u original core clauses", traversed); (void) traversed; - assert (kitten->status == 21); + KISSAT_assert (kitten->status == 21); } void kitten_traverse_core_clauses (kitten *kitten, void *state, @@ -1979,10 +1997,10 @@ void kitten_traverse_core_clauses (kitten *kitten, void *state, for (all_stack (unsigned, c_ref, kitten->core)) { klause *c = dereference_klause (kitten, c_ref); - assert (is_core_klause (c)); + KISSAT_assert (is_core_klause (c)); const bool learned = is_learned_klause (c); unsigneds *eclause = &kitten->eclause; - assert (EMPTY_STACK (*eclause)); + KISSAT_assert (EMPTY_STACK (*eclause)); for (all_literals_in_klause (ilit, c)) { const unsigned elit = export_literal (kitten, ilit); PUSH_STACK (*eclause, elit); @@ -1998,7 +2016,7 @@ void kitten_traverse_core_clauses (kitten *kitten, void *state, LOG ("traversed %u core clauses", traversed); (void) traversed; - assert (kitten->status == 21); + KISSAT_assert (kitten->status == 21); } void kitten_shrink_to_clausal_core (kitten *kitten) { @@ -2019,7 +2037,7 @@ void kitten_shrink_to_clausal_core (kitten *kitten) { for (all_kits (lit)) CLEAR_STACK (KATCHES (lit)); - assert (kitten->inconsistent != INVALID); + KISSAT_assert (kitten->inconsistent != INVALID); klause *inconsistent = dereference_klause (kitten, kitten->inconsistent); if (is_learned_klause (inconsistent) || inconsistent->size) { ROG (kitten->inconsistent, "resetting inconsistent"); @@ -2036,7 +2054,7 @@ void kitten_shrink_to_clausal_core (kitten *kitten) { #endif for (klause *c = begin, *next; c != end; c = next) { next = next_klause (kitten, c); - assert (!is_learned_klause (c)); + KISSAT_assert (!is_learned_klause (c)); if (is_learned_klause (c)) continue; if (!is_core_klause (c)) @@ -2313,7 +2331,7 @@ static kitten *parse (parser *parser, ints *originals, int *max_var) { } else if (offset > UINT_MAX) ERROR ("too many original literals"); else { - assert (SIZE_STACK (clause) <= UINT_MAX); + KISSAT_assert (SIZE_STACK (clause) <= UINT_MAX); const unsigned size = SIZE_STACK (clause); const unsigned *const lits = BEGIN_STACK (clause); kitten_clause_with_id_and_exception (kitten, offset, size, lits, @@ -2334,7 +2352,7 @@ static kitten *parse (parser *parser, ints *originals, int *max_var) { while (uidx >= new_size_marks) new_size_marks *= 2; signed char *new_marks; - CALLOC (new_marks, new_size_marks); + CALLOC (signed char, new_marks, new_size_marks); if (size_marks) memcpy (new_marks, marks, size_marks); DEALLOC (marks, size_marks); @@ -2393,7 +2411,7 @@ static inline void print_lit (line *line, int lit) { } static void print_witness (kitten *kitten, int max_var) { - assert (max_var >= 0); + KISSAT_assert (max_var >= 0); line line = {.size = 0}; const size_t parsed_lits = 2 * (size_t) max_var; for (size_t ulit = 0; ulit < parsed_lits; ulit += 2) { @@ -2413,14 +2431,14 @@ typedef struct core_writer core_writer; struct core_writer { FILE *file; ints *originals; -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG unsigned written; #endif }; static void write_offset (void *ptr, unsigned offset) { core_writer *writer = ptr; -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG writer->written++; #endif int const *p = &PEEK_STACK (*writer->originals, offset); @@ -2432,19 +2450,19 @@ static void write_offset (void *ptr, unsigned offset) { static void write_core (kitten *kitten, unsigned reduced, ints *originals, FILE *file) { - assert (originals); + KISSAT_assert (originals); fprintf (file, "p cnf %zu %u\n", kitten->evars, reduced); core_writer writer; writer.file = file; writer.originals = originals; -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG writer.written = 0; #endif kitten_traverse_core_ids (kitten, &writer, write_offset); - assert (writer.written == reduced); + KISSAT_assert (writer.written == reduced); } -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG typedef struct lemma_writer lemma_writer; @@ -2460,7 +2478,7 @@ static void write_lemma (void *ptr, bool learned, size_t size, if (!learned) return; const unsigned *const end = lits + size; -#ifdef NDEBUG +#ifdef KISSAT_NDEBUG FILE *file = ptr; #else lemma_writer *writer = ptr; @@ -2471,7 +2489,7 @@ static void write_lemma (void *ptr, bool learned, size_t size, const unsigned ulit = *p; const unsigned idx = ulit / 2; const unsigned sign = ulit & 1; - assert (idx + 1 <= (unsigned) INT_MAX); + KISSAT_assert (idx + 1 <= (unsigned) INT_MAX); int ilit = idx + 1; if (sign) ilit = -ilit; @@ -2482,7 +2500,7 @@ static void write_lemma (void *ptr, bool learned, size_t size, static void write_lemmas (kitten *kitten, uint64_t reduced, FILE *file) { void *state; -#ifdef NDEBUG +#ifdef KISSAT_NDEBUG state = file; (void) reduced; #else @@ -2492,7 +2510,7 @@ static void write_lemmas (kitten *kitten, uint64_t reduced, FILE *file) { state = &writer; #endif kitten_traverse_core_clauses (kitten, state, write_lemma); - assert (writer.written == reduced); + KISSAT_assert (writer.written == reduced); } static void print_statistics (statistics statistics) { @@ -2562,7 +2580,7 @@ static void catch_signal (int sig) { } static void catch_alarm (int sig) { - assert (sig == SIGALRM); + KISSAT_assert (sig == SIGALRM); if (time_limit > 0) time_limit_hit = true; (void) sig; @@ -2757,7 +2775,7 @@ int main (int argc, char **argv) { reset_alarm (); res = kitten_solve (kitten); - assert (res == 20); + KISSAT_assert (res == 20); } FILE *output_file = fopen (output_path, "w"); if (!output_file) @@ -2792,3 +2810,5 @@ int main (int argc, char **argv) { } #endif + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/kitten.h b/src/sat/kissat/kitten.h index e7ead94dc..2ea9d6d36 100644 --- a/src/sat/kissat/kitten.h +++ b/src/sat/kissat/kitten.h @@ -5,6 +5,9 @@ #include #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + typedef struct kitten kitten; kitten *kitten_init (void); @@ -51,4 +54,6 @@ void kitten_traverse_core_clauses (kitten *, void *state, struct kissat; kitten *kitten_embedded (struct kissat *); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/options.c b/src/sat/kissat/kptions.c similarity index 94% rename from src/sat/kissat/options.c rename to src/sat/kissat/kptions.c index cf618905e..8a07b693d 100644 --- a/src/sat/kissat/options.c +++ b/src/sat/kissat/kptions.c @@ -8,7 +8,9 @@ #include #include -#ifdef NOPTIONS +ABC_NAMESPACE_IMPL_START + +#ifdef KISSAT_NOPTIONS static const opt table[] = { #define OPTION(N, V, L, H, D) {#N, (int) (V), D}, @@ -32,7 +34,7 @@ const opt *kissat_options_begin = table; const opt *kissat_options_end = table + size_table; static void check_table_sorted (void) { -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG opt const *p = 0; for (all_options (o)) if (p && strcmp (p->name, o->name) >= 0) @@ -46,7 +48,7 @@ const opt *kissat_options_has (const char *name) { size_t l = 0, m, r = size_table; int tmp; opt const *o; - assert (l < r); + KISSAT_assert (l < r); while (l + 1 < r) { m = l + (r - l) / 2; tmp = strcmp (name, (o = table + m)->name); @@ -148,7 +150,7 @@ bool kissat_parse_option_value (const char *val_str, int *res_ptr) { return false; // '0^0' invalid } else if (ch) return false; - assert (res <= max); + KISSAT_assert (res <= max); if (sign > 0 && res == max) return false; res *= sign; @@ -171,7 +173,7 @@ const char *kissat_parse_option_name (const char *arg, const char *name) { return p + 1; } -#ifdef NOPTIONS +#ifdef KISSAT_NOPTIONS void kissat_init_options (void) { check_table_sorted (); } @@ -182,12 +184,16 @@ int kissat_options_get (const char *name) { #else +ABC_NAMESPACE_IMPL_END + #include "format.h" #include #include #include +ABC_NAMESPACE_IMPL_START + static void kissat_printf_usage (const char *option, const char *fmt, ...) { va_list ap; printf (" %-26s ", option); @@ -217,7 +223,7 @@ static void check_ranges (void) { } static void check_name_length (void) { -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG #define OPTION(N, V, L, H, D) \ if (strlen (#N) + 1 > kissat_options_max_name_buffer_size) \ kissat_fatal ("option '%s' name length %zu " \ @@ -235,8 +241,8 @@ int kissat_options_get (const options *options, const char *name) { } int kissat_options_set_opt (options *options, const opt *o, int value) { - assert (kissat_options_begin <= o); - assert (o < kissat_options_end); + KISSAT_assert (kissat_options_begin <= o); + KISSAT_assert (o < kissat_options_end); int *p = (int *) options + (o - table); int res = *p; if (value == res) @@ -261,8 +267,8 @@ void kissat_init_options (options *options) { check_name_length (); check_table_sorted (); #define OPTION(N, V, L, H, D) \ - assert ((L) <= (V)); \ - assert ((V) <= (H)); \ + KISSAT_assert ((L) <= (V)); \ + KISSAT_assert ((V) <= (H)); \ options->N = (V); OPTIONS #undef OPTION @@ -306,7 +312,7 @@ bool kissat_options_parse_arg (const char *arg, char *buffer, while ((ch = *p) && ch != '=') p++; if (ch) { - assert (ch == '='); + KISSAT_assert (ch == '='); const size_t len = p - name; if (len >= kissat_options_max_name_buffer_size) return false; @@ -333,7 +339,7 @@ bool kissat_options_parse_arg (const char *arg, char *buffer, if (!o || o->high < (value = 1)) return false; } - assert (strlen (name) < kissat_options_max_name_buffer_size); + KISSAT_assert (strlen (name) < kissat_options_max_name_buffer_size); strcpy (buffer, name); *val_ptr = value; } @@ -345,7 +351,7 @@ static bool ignore_embedded_option_for_fuzzing (const char *name) { if (!strcmp (name, "embedded")) return true; #endif -#ifndef QUIET +#ifndef KISSAT_QUIET if (!strcmp (name, "quiet")) return true; #endif @@ -370,7 +376,7 @@ static bool ignore_range_option_for_fuzzing (const char *name) { if (!strcmp (name, "embedded")) return true; #endif -#ifndef QUIET +#ifndef KISSAT_QUIET if (!strcmp (name, "quiet")) return true; #endif @@ -394,3 +400,5 @@ void kissat_print_option_range_list (void) { } #endif + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/krite.c b/src/sat/kissat/krite.c index 85d91d9d9..04c9a810d 100644 --- a/src/sat/kissat/krite.c +++ b/src/sat/kissat/krite.c @@ -5,12 +5,14 @@ #include +ABC_NAMESPACE_IMPL_START + void kissat_write_dimacs (kissat *solver, FILE *file) { size_t imported = SIZE_STACK (solver->import); if (imported) imported--; fprintf (file, "p cnf %zu %" PRIu64 "\n", imported, BINIRR_CLAUSES); - assert (solver->watching); + KISSAT_assert (solver->watching); if (solver->watching) { for (all_literals (ilit)) for (all_binary_blocking_watches (watch, WATCHES (ilit))) @@ -43,3 +45,5 @@ void kissat_write_dimacs (kissat *solver, FILE *file) { fputs ("0\n", file); } } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/krite.h b/src/sat/kissat/krite.h index a8af42c9c..3b6fe6bb4 100644 --- a/src/sat/kissat/krite.h +++ b/src/sat/kissat/krite.h @@ -3,7 +3,12 @@ #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + struct kissat; void kissat_write_dimacs (struct kissat *, FILE *); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/lucky.c b/src/sat/kissat/kucky.c similarity index 89% rename from src/sat/kissat/lucky.c rename to src/sat/kissat/kucky.c index 74219b095..3e3121b2d 100644 --- a/src/sat/kissat/lucky.c +++ b/src/sat/kissat/kucky.c @@ -8,6 +8,8 @@ #include "proprobe.h" #include "report.h" +ABC_NAMESPACE_IMPL_START + static bool no_all_negative_clauses (struct kissat *solver) { clause *last_irredundant = kissat_last_irredundant_clause (solver); for (all_clauses (c)) { @@ -24,7 +26,7 @@ static bool no_all_negative_clauses (struct kissat *solver) { return false; CONTINUE_WITH_NEXT_CLAUSE:; } - assert (solver->watching); + KISSAT_assert (solver->watching); for (all_variables (idx)) { if (!ACTIVE (idx)) continue; @@ -60,7 +62,7 @@ static bool no_all_positive_clauses (struct kissat *solver) { return false; CONTINUE_WITH_NEXT_CLAUSE:; } - assert (solver->watching); + KISSAT_assert (solver->watching); for (all_variables (idx)) { if (!ACTIVE (idx)) continue; @@ -80,8 +82,8 @@ static bool no_all_positive_clauses (struct kissat *solver) { } static int forward_false_satisfiable (struct kissat *solver) { - assert (!solver->level); -#ifndef QUIET + KISSAT_assert (!solver->level); +#ifndef KISSAT_QUIET unsigned conflicts = 0; #endif for (all_stack (import, import, solver->import)) { @@ -100,7 +102,7 @@ static int forward_false_satisfiable (struct kissat *solver) { clause *c = kissat_probing_propagate (solver, 0, true); if (!c) continue; -#ifndef QUIET +#ifndef KISSAT_QUIET conflicts++; #endif if (solver->level > 1) { @@ -118,11 +120,11 @@ static int forward_false_satisfiable (struct kissat *solver) { } else { LOG ("failed literal %s", LOGLIT (not_lit)); kissat_analyze (solver, c); - assert (!solver->level); + KISSAT_assert (!solver->level); clause *d = kissat_probing_propagate (solver, 0, true); if (d) { kissat_analyze (solver, d); - assert (solver->inconsistent); + KISSAT_assert (solver->inconsistent); kissat_verbose (solver, "lucky inconsistency forward assigning to false"); return 20; @@ -135,8 +137,8 @@ static int forward_false_satisfiable (struct kissat *solver) { } static int forward_true_satisfiable (struct kissat *solver) { - assert (!solver->level); -#ifndef QUIET + KISSAT_assert (!solver->level); +#ifndef KISSAT_QUIET unsigned conflicts = 0; #endif for (all_stack (import, import, solver->import)) { @@ -154,7 +156,7 @@ static int forward_true_satisfiable (struct kissat *solver) { clause *c = kissat_probing_propagate (solver, 0, true); if (!c) continue; -#ifndef QUIET +#ifndef KISSAT_QUIET conflicts++; #endif if (solver->level > 1) { @@ -173,11 +175,11 @@ static int forward_true_satisfiable (struct kissat *solver) { } else { LOG ("failed literal %s", LOGLIT (lit)); kissat_analyze (solver, c); - assert (!solver->level); + KISSAT_assert (!solver->level); clause *d = kissat_probing_propagate (solver, 0, true); if (d) { kissat_analyze (solver, d); - assert (solver->inconsistent); + KISSAT_assert (solver->inconsistent); kissat_verbose (solver, "lucky inconsistency forward assigning to true"); return 20; @@ -189,8 +191,8 @@ static int forward_true_satisfiable (struct kissat *solver) { } static int backward_false_satisfiable (struct kissat *solver) { - assert (!solver->level); -#ifndef QUIET + KISSAT_assert (!solver->level); +#ifndef KISSAT_QUIET unsigned conflicts = 0; #endif import *begin = BEGIN_STACK (solver->import); @@ -213,7 +215,7 @@ static int backward_false_satisfiable (struct kissat *solver) { clause *c = kissat_probing_propagate (solver, 0, true); if (!c) continue; -#ifndef QUIET +#ifndef KISSAT_QUIET conflicts++; #endif if (solver->level > 1) { @@ -231,11 +233,11 @@ static int backward_false_satisfiable (struct kissat *solver) { } else { LOG ("failed literal %s", LOGLIT (not_lit)); kissat_analyze (solver, c); - assert (!solver->level); + KISSAT_assert (!solver->level); clause *d = kissat_probing_propagate (solver, 0, true); if (d) { kissat_analyze (solver, d); - assert (solver->inconsistent); + KISSAT_assert (solver->inconsistent); kissat_verbose (solver, "lucky inconsistency backward assigning to false"); return 20; @@ -247,8 +249,8 @@ static int backward_false_satisfiable (struct kissat *solver) { } static int backward_true_satisfiable (struct kissat *solver) { - assert (!solver->level); -#ifndef QUIET + KISSAT_assert (!solver->level); +#ifndef KISSAT_QUIET unsigned conflicts = 0; #endif import *begin = BEGIN_STACK (solver->import); @@ -270,7 +272,7 @@ static int backward_true_satisfiable (struct kissat *solver) { clause *c = kissat_probing_propagate (solver, 0, true); if (!c) continue; -#ifndef QUIET +#ifndef KISSAT_QUIET conflicts++; #endif if (solver->level > 1) { @@ -289,11 +291,11 @@ static int backward_true_satisfiable (struct kissat *solver) { } else { LOG ("failed literal %s", LOGLIT (lit)); kissat_analyze (solver, c); - assert (!solver->level); + KISSAT_assert (!solver->level); clause *d = kissat_probing_propagate (solver, 0, true); if (d) { kissat_analyze (solver, d); - assert (solver->inconsistent); + KISSAT_assert (solver->inconsistent); kissat_verbose (solver, "lucky inconsistency backward assigning to true"); return 20; @@ -313,10 +315,10 @@ int kissat_lucky (struct kissat *solver) { return 0; START (lucky); - assert (!solver->level); - assert (!solver->probing); + KISSAT_assert (!solver->level); + KISSAT_assert (!solver->probing); solver->probing = true; - assert (kissat_propagated (solver)); + KISSAT_assert (kissat_propagated (solver)); int res = 0; @@ -328,15 +330,15 @@ int kissat_lucky (struct kissat *solver) { if (VALUE (lit)) continue; kissat_internal_assume (solver, lit); -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG clause *c = #endif kissat_probing_propagate (solver, 0, true); - assert (!c); + KISSAT_assert (!c); } kissat_verbose (solver, "set all variables to true"); - assert (kissat_propagated (solver)); - assert (!solver->unassigned); + KISSAT_assert (kissat_propagated (solver)); + KISSAT_assert (!solver->unassigned); res = 10; } @@ -349,15 +351,15 @@ int kissat_lucky (struct kissat *solver) { continue; const unsigned not_lit = NOT (lit); kissat_internal_assume (solver, not_lit); -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG clause *c = #endif kissat_probing_propagate (solver, 0, true); - assert (!c); + KISSAT_assert (!c); } kissat_verbose (solver, "set all variables to false"); - assert (kissat_propagated (solver)); - assert (!solver->unassigned); + KISSAT_assert (kissat_propagated (solver)); + KISSAT_assert (!solver->unassigned); res = 10; } @@ -381,13 +383,15 @@ int kissat_lucky (struct kissat *solver) { if (!res && units) kissat_message (solver, "lucky %u units", units); -#ifndef QUIET +#ifndef KISSAT_QUIET bool success = res || units; #endif - assert (solver->probing); + KISSAT_assert (solver->probing); solver->probing = false; REPORT (!success, 'l'); STOP (lucky); return res; } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/learn.c b/src/sat/kissat/learn.c index 36a25be89..401fc0b56 100644 --- a/src/sat/kissat/learn.c +++ b/src/sat/kissat/learn.c @@ -5,8 +5,10 @@ #include +ABC_NAMESPACE_IMPL_START + static unsigned backjump_limit (struct kissat *solver) { -#ifdef NOPTIONS +#ifdef KISSAT_NOPTIONS (void) solver; #endif return GET_OPTION (chrono) ? (unsigned) GET_OPTION (chronolevels) @@ -14,9 +16,9 @@ static unsigned backjump_limit (struct kissat *solver) { } unsigned kissat_determine_new_level (kissat *solver, unsigned jump) { - assert (solver->level); + KISSAT_assert (solver->level); const unsigned back = solver->level - 1; - assert (jump <= back); + KISSAT_assert (jump <= back); const unsigned delta = back - jump; const unsigned limit = backjump_limit (solver); @@ -42,7 +44,7 @@ unsigned kissat_determine_new_level (kissat *solver, unsigned jump) { } static void learn_unit (kissat *solver, unsigned not_uip) { - assert (not_uip == PEEK_STACK (solver->clause, 0)); + KISSAT_assert (not_uip == PEEK_STACK (solver->clause, 0)); LOG ("learned unit clause %s triggers iteration", LOGLIT (not_uip)); const unsigned new_level = kissat_determine_new_level (solver, 0); kissat_backtrack_after_conflict (solver, new_level); @@ -59,11 +61,11 @@ static void learn_binary (kissat *solver, unsigned not_uip) { const unsigned new_level = kissat_determine_new_level (solver, jump_level); kissat_backtrack_after_conflict (solver, new_level); -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG const reference ref = #endif kissat_new_redundant_clause (solver, 1); - assert (ref == INVALID_REF); + KISSAT_assert (ref == INVALID_REF); kissat_assign_binary (solver, not_uip, other); } @@ -80,10 +82,10 @@ static void insert_last_learned (kissat *solver, reference ref) { static reference learn_reference (kissat *solver, unsigned not_uip, unsigned glue) { - assert (solver->level > 1); - assert (SIZE_STACK (solver->clause) > 2); + KISSAT_assert (solver->level > 1); + KISSAT_assert (SIZE_STACK (solver->clause) > 2); unsigned *lits = BEGIN_STACK (solver->clause); - assert (lits[0] == not_uip); + KISSAT_assert (lits[0] == not_uip); unsigned *q = lits + 1; unsigned jump_lit = *q; unsigned jump_level = LEVEL (jump_lit); @@ -105,7 +107,7 @@ static reference learn_reference (kissat *solver, unsigned not_uip, *q = lits[1]; lits[1] = jump_lit; const reference ref = kissat_new_redundant_clause (solver, glue); - assert (ref != INVALID_REF); + KISSAT_assert (ref != INVALID_REF); clause *c = kissat_dereference_clause (solver, ref); c->used = MAX_USED; const unsigned new_level = @@ -116,14 +118,14 @@ static reference learn_reference (kissat *solver, unsigned not_uip, } void kissat_update_learned (kissat *solver, unsigned glue, unsigned size) { - assert (!solver->probing); + KISSAT_assert (!solver->probing); INC (clauses_learned); LOG ("learned[%" PRIu64 "] clause glue %u size %u", GET (clauses_learned), glue, size); if (solver->stable) kissat_tick_reluctant (&solver->reluctant); ADD (literals_learned, size); -#ifndef QUIET +#ifndef KISSAT_QUIET UPDATE_AVERAGE (size, size); #endif UPDATE_AVERAGE (fast_glue, glue); @@ -145,7 +147,7 @@ static void flush_last_learned (kissat *solver) { static void eagerly_subsume_last_learned (kissat *solver) { value *marks = solver->marks; for (all_stack (unsigned, lit, solver->clause)) { - assert (!marks[lit]); + KISSAT_assert (!marks[lit]); marks[lit] = 1; } unsigned clause_size = SIZE_STACK (solver->clause); @@ -191,10 +193,10 @@ void kissat_learn_clause (kissat *solver) { const unsigned not_uip = PEEK_STACK (solver->clause, 0); const unsigned size = SIZE_STACK (solver->clause); const size_t glue = SIZE_STACK (solver->levels); - assert (glue <= UINT_MAX); + KISSAT_assert (glue <= UINT_MAX); if (!solver->probing) kissat_update_learned (solver, glue, size); - assert (size > 0); + KISSAT_assert (size > 0); reference ref = INVALID_REF; if (size == 1) learn_unit (solver, not_uip); @@ -208,3 +210,5 @@ void kissat_learn_clause (kissat *solver) { insert_last_learned (solver, ref); } } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/learn.h b/src/sat/kissat/learn.h index b11923966..42c3bad5e 100644 --- a/src/sat/kissat/learn.h +++ b/src/sat/kissat/learn.h @@ -1,10 +1,15 @@ #ifndef _learn_h_INCLUDED #define _learn_h_INCLUDED +#include "global.h" +ABC_NAMESPACE_HEADER_START + struct kissat; void kissat_learn_clause (struct kissat *); void kissat_update_learned (struct kissat *, unsigned glue, unsigned size); unsigned kissat_determine_new_level (struct kissat *, unsigned jump); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/literal.h b/src/sat/kissat/literal.h index 75d7814c6..9014e5dd4 100644 --- a/src/sat/kissat/literal.h +++ b/src/sat/kissat/literal.h @@ -3,6 +3,9 @@ #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + #define LD_MAX_VAR 30u #define LD_MAX_LIT (1 + LD_MAX_VAR) @@ -23,14 +26,16 @@ ((LIT) && ((LIT) != INT_MIN) && ABS (LIT) <= EXTERNAL_MAX_VAR) #define IDX(LIT) \ - (assert (VALID_INTERNAL_LITERAL (LIT)), (((unsigned) (LIT)) >> 1)) + (KISSAT_assert (VALID_INTERNAL_LITERAL (LIT)), (((unsigned) (LIT)) >> 1)) -#define LIT(IDX) (assert (VALID_INTERNAL_INDEX (IDX)), ((IDX) << 1)) +#define LIT(IDX) (KISSAT_assert (VALID_INTERNAL_INDEX (IDX)), ((IDX) << 1)) -#define NOT(LIT) (assert (VALID_INTERNAL_LITERAL (LIT)), ((LIT) ^ 1u)) +#define NOT(LIT) (KISSAT_assert (VALID_INTERNAL_LITERAL (LIT)), ((LIT) ^ 1u)) -#define NEGATED(LIT) (assert (VALID_INTERNAL_LITERAL (LIT)), ((LIT) & 1u)) +#define NEGATED(LIT) (KISSAT_assert (VALID_INTERNAL_LITERAL (LIT)), ((LIT) & 1u)) -#define STRIP(LIT) (assert (VALID_INTERNAL_LITERAL (LIT)), ((LIT) & ~1u)) +#define STRIP(LIT) (KISSAT_assert (VALID_INTERNAL_LITERAL (LIT)), ((LIT) & ~1u)) + +ABC_NAMESPACE_HEADER_END #endif diff --git a/src/sat/kissat/logging.c b/src/sat/kissat/logging.c index 36abd33ce..6955873fe 100644 --- a/src/sat/kissat/logging.c +++ b/src/sat/kissat/logging.c @@ -1,4 +1,6 @@ -#if defined(LOGGING) && !defined(QUIET) +#include "global.h" + +#if defined(LOGGING) && !defined(KISSAT_QUIET) #include "colors.h" #include "inline.h" @@ -9,7 +11,7 @@ static void begin_logging (kissat *solver, const char *prefix, const char *fmt, va_list *ap) { TERMINAL (stdout, 1); - assert (GET_OPTION (log)); + KISSAT_assert (GET_OPTION (log)); fputs (solver->prefix, stdout); COLOR (MAGENTA); printf ("%s %u ", prefix, solver->level); @@ -52,7 +54,7 @@ static void append_sprintf (char *str, const char *fmt, ...) { const char *kissat_log_repr (kissat *solver, unsigned lit, const unsigned *repr) { - assert (solver); + KISSAT_assert (solver); char *res = kissat_next_format_string (&solver->format); sprintf (res, "%u", lit); if (!solver->compacting && GET_OPTION (log) > 1) @@ -74,7 +76,7 @@ const char *kissat_log_repr (kissat *solver, unsigned lit, append_sprintf (res, "@%u", LEVEL (lit)); } } - assert (strlen (res) < FORMAT_STRING_SIZE); + KISSAT_assert (strlen (res) < FORMAT_STRING_SIZE); return res; } @@ -83,11 +85,11 @@ const char *kissat_log_lit (kissat *solver, unsigned lit) { } const char *kissat_log_var (kissat *solver, unsigned idx) { - assert (solver); + KISSAT_assert (solver); char *res = kissat_next_format_string (&solver->format); const unsigned lit = LIT (idx); sprintf (res, "variable %u (literal %s)", idx, LOGLIT (lit)); - assert (strlen (res) < FORMAT_STRING_SIZE); + KISSAT_assert (strlen (res) < FORMAT_STRING_SIZE); return res; } @@ -301,7 +303,7 @@ void kissat_log_ite_gate (kissat *solver, const char *prefix, size_t id, void kissat_log_extensions (kissat *solver, const char *prefix, size_t size, const extension *const exts, const char *fmt, ...) { - assert (size > 0); + KISSAT_assert (size > 0); va_list ap; va_start (ap, fmt); begin_logging (solver, prefix, fmt, &ap); diff --git a/src/sat/kissat/logging.h b/src/sat/kissat/logging.h index bb2b53218..65f06ef6b 100644 --- a/src/sat/kissat/logging.h +++ b/src/sat/kissat/logging.h @@ -1,8 +1,6 @@ #ifndef _logging_h_INCLUDED #define _logging_h_INCLUDED -#if defined(LOGGING) && !defined(QUIET) - #include "attribute.h" #include "extend.h" #include "reference.h" @@ -10,6 +8,11 @@ #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + +#if defined(LOGGING) && !defined(KISSAT_QUIET) + // clang-format off const char * kissat_log_lit (kissat *, unsigned lit); @@ -461,4 +464,6 @@ ATTRIBUTE_FORMAT (5, 6); LOGLITS (SIZE_STACK (solver->clause), BEGIN_STACK (solver->clause), \ __VA_ARGS__) +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/lucky.h b/src/sat/kissat/lucky.h index ef97c67dc..2e7538ba8 100644 --- a/src/sat/kissat/lucky.h +++ b/src/sat/kissat/lucky.h @@ -1,7 +1,12 @@ #ifndef _lucky_h_INCLUDED #define _lucky_h_INCLUDED +#include "global.h" +ABC_NAMESPACE_HEADER_START + struct kissat; int kissat_lucky (struct kissat *); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/minimize.c b/src/sat/kissat/minimize.c index 94dcb63d5..6739d7c6b 100644 --- a/src/sat/kissat/minimize.c +++ b/src/sat/kissat/minimize.c @@ -1,17 +1,19 @@ #include "minimize.h" #include "inline.h" +ABC_NAMESPACE_IMPL_START + static inline int minimized_index (kissat *solver, bool minimizing, assigned *a, unsigned lit, unsigned idx, unsigned depth) { -#if !defined(LOGGING) && defined(NDEBUG) +#if !defined(LOGGING) && defined(KISSAT_NDEBUG) (void) lit; #endif -#ifdef NDEBUG +#ifdef KISSAT_NDEBUG (void) idx; #endif - assert (IDX (lit) == idx); - assert (solver->assigned + idx == a); + KISSAT_assert (IDX (lit) == idx); + KISSAT_assert (solver->assigned + idx == a); if (!a->level) { LOG2 ("skipping root level literal %s", LOGLIT (lit)); return 1; @@ -20,7 +22,7 @@ static inline int minimized_index (kissat *solver, bool minimizing, LOG2 ("skipping removable literal %s", LOGLIT (lit)); return 1; } - assert (a->reason != UNIT_REASON); + KISSAT_assert (a->reason != UNIT_REASON); if (a->reason == DECISION_REASON) { LOG2 ("can not remove decision literal %s", LOGLIT (lit)); return -1; @@ -81,7 +83,7 @@ static inline bool minimize_binary (kissat *solver, bool minimizing, } unsigned *begin = BEGIN_STACK (solver->minimize) + saved; const unsigned *const end = END_STACK (solver->minimize); - assert (begin <= end); + KISSAT_assert (begin <= end); if (res) for (const unsigned *p = begin; p != end; p++) kissat_push_removable (solver, assigned, *p); @@ -97,9 +99,9 @@ static bool minimize_literal (kissat *solver, bool minimizing, unsigned depth) { LOG ("trying to minimize literal %s at recursion depth %d", LOGLIT (lit), depth); - assert (VALUE (lit) < 0); - assert (depth || EMPTY_STACK (solver->minimize)); - assert (GET_OPTION (minimizedepth) > 0); + KISSAT_assert (VALUE (lit) < 0); + KISSAT_assert (depth || EMPTY_STACK (solver->minimize)); + KISSAT_assert (GET_OPTION (minimizedepth) > 0); if (depth >= (unsigned) GET_OPTION (minimizedepth)) return false; const unsigned idx = IDX (lit); @@ -135,7 +137,7 @@ static bool minimize_literal (kissat *solver, bool minimizing, bool kissat_minimize_literal (kissat *solver, unsigned lit, bool lit_in_clause) { - assert (EMPTY_STACK (solver->minimize)); + KISSAT_assert (EMPTY_STACK (solver->minimize)); return minimize_literal (solver, false, solver->assigned, lit, !lit_in_clause); } @@ -144,9 +146,9 @@ void kissat_reset_poisoned (kissat *solver) { LOG ("reset %zu poisoned variables", SIZE_STACK (solver->poisoned)); assigned *assigned = solver->assigned; for (all_stack (unsigned, idx, solver->poisoned)) { - assert (idx < VARS); + KISSAT_assert (idx < VARS); struct assigned *a = assigned + idx; - assert (a->poisoned); + KISSAT_assert (a->poisoned); a->poisoned = false; } CLEAR_STACK (solver->poisoned); @@ -155,19 +157,19 @@ void kissat_reset_poisoned (kissat *solver) { void kissat_minimize_clause (kissat *solver) { START (minimize); - assert (EMPTY_STACK (solver->minimize)); - assert (EMPTY_STACK (solver->removable)); - assert (EMPTY_STACK (solver->poisoned)); - assert (!EMPTY_STACK (solver->clause)); + KISSAT_assert (EMPTY_STACK (solver->minimize)); + KISSAT_assert (EMPTY_STACK (solver->removable)); + KISSAT_assert (EMPTY_STACK (solver->poisoned)); + KISSAT_assert (!EMPTY_STACK (solver->clause)); unsigned *lits = BEGIN_STACK (solver->clause); unsigned *end = END_STACK (solver->clause); assigned *assigned = solver->assigned; -#ifndef NDEBUG - assert (lits < end); +#ifndef KISSAT_NDEBUG + KISSAT_assert (lits < end); const unsigned not_uip = lits[0]; - assert (assigned[IDX (not_uip)].level == solver->level); + KISSAT_assert (assigned[IDX (not_uip)].level == solver->level); #endif for (const unsigned *p = lits; p != end; p++) kissat_push_removable (solver, assigned, IDX (*p)); @@ -181,7 +183,7 @@ void kissat_minimize_clause (kissat *solver) { for (unsigned *p = end; --p > lits;) { const unsigned lit = *p; - assert (lit != not_uip); + KISSAT_assert (lit != not_uip); if (minimize_literal (solver, true, assigned, lit, 0)) { LOG ("minimized literal %s", LOGLIT (lit)); *p = INVALID_LIT; @@ -196,11 +198,11 @@ void kissat_minimize_clause (kissat *solver) { if (lit != INVALID_LIT) *q++ = lit; } - assert (q + minimized == end); + KISSAT_assert (q + minimized == end); SET_END_OF_STACK (solver->clause, q); LOG ("clause minimization removed %u literals", minimized); - assert (!solver->probing); + KISSAT_assert (!solver->probing); ADD (literals_minimized, minimized); LOGTMP ("minimized learned"); @@ -209,3 +211,5 @@ void kissat_minimize_clause (kissat *solver) { STOP (minimize); } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/minimize.h b/src/sat/kissat/minimize.h index ae06fb9ad..25d2f4d33 100644 --- a/src/sat/kissat/minimize.h +++ b/src/sat/kissat/minimize.h @@ -3,6 +3,9 @@ #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + struct kissat; void kissat_reset_poisoned (struct kissat *); @@ -11,4 +14,6 @@ void kissat_minimize_clause (struct kissat *); bool kissat_minimize_literal (struct kissat *, unsigned, bool lit_in_clause); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/mode.c b/src/sat/kissat/mode.c index b1390eca1..e42027339 100644 --- a/src/sat/kissat/mode.c +++ b/src/sat/kissat/mode.c @@ -8,7 +8,9 @@ #include -#ifndef QUIET +ABC_NAMESPACE_IMPL_START + +#ifndef KISSAT_QUIET static const char *mode_string (kissat *solver) { return solver->stable ? "stable" : "focused"; @@ -20,12 +22,12 @@ void kissat_init_mode_limit (kissat *solver) { limits *limits = &solver->limits; if (GET_OPTION (stable) == 1) { - assert (!solver->stable); + KISSAT_assert (!solver->stable); const uint64_t conflicts_delta = GET_OPTION (modeinit); const uint64_t conflicts_limit = CONFLICTS + conflicts_delta; - assert (conflicts_limit); + KISSAT_assert (conflicts_limit); limits->mode.conflicts = conflicts_limit; limits->mode.ticks = 0; @@ -38,11 +40,11 @@ void kissat_init_mode_limit (kissat *solver) { FORMAT_COUNT (conflicts_limit), FORMAT_COUNT (conflicts_delta)); - solver->mode.ticks = solver->statistics.search_ticks; -#ifndef QUIET + solver->mode.ticks = solver->statistics_.search_ticks; +#ifndef KISSAT_QUIET solver->mode.conflicts = CONFLICTS; #ifdef METRICS - solver->mode.propagations = solver->statistics.search_propagations; + solver->mode.propagations = solver->statistics_.search_propagations; #endif // clang-format off solver->mode.entered = kissat_process_time (); @@ -70,14 +72,14 @@ static void update_mode_limit (kissat *solver, uint64_t delta_ticks) { kissat_init_averages (solver, &AVERAGES); limits *limits = &solver->limits; - statistics *statistics = &solver->statistics; + statistics *statistics = &solver->statistics_; - assert (GET_OPTION (stable) == 1); + KISSAT_assert (GET_OPTION (stable) == 1); if (limits->mode.count & 1) { limits->mode.ticks = statistics->search_ticks + delta_ticks; -#ifndef QUIET - assert (solver->stable); +#ifndef KISSAT_QUIET + KISSAT_assert (solver->stable); kissat_phase (solver, "stable", GET (stable_modes), "new stable mode switching limit of %s " "after %s ticks", @@ -85,13 +87,13 @@ static void update_mode_limit (kissat *solver, uint64_t delta_ticks) { FORMAT_COUNT (delta_ticks)); #endif } else { - assert (limits->mode.ticks); + KISSAT_assert (limits->mode.ticks); const uint64_t interval = GET_OPTION (modeint); const uint64_t count = (statistics->switched + 1) / 2; const uint64_t scaled = interval * kissat_nlogpown (count, 4); limits->mode.conflicts = statistics->conflicts + scaled; -#ifndef QUIET - assert (!solver->stable); +#ifndef KISSAT_QUIET + KISSAT_assert (!solver->stable); kissat_phase (solver, "focused", GET (focused_modes), "new focused mode switching limit of %s " "after %s conflicts", @@ -101,7 +103,7 @@ static void update_mode_limit (kissat *solver, uint64_t delta_ticks) { } solver->mode.ticks = statistics->search_ticks; -#ifndef QUIET +#ifndef KISSAT_QUIET solver->mode.conflicts = statistics->conflicts; #ifdef METRICS solver->mode.propagations = statistics->search_propagations; @@ -111,10 +113,10 @@ static void update_mode_limit (kissat *solver, uint64_t delta_ticks) { static void report_switching_from_mode (kissat *solver, uint64_t *delta_ticks) { - statistics *statistics = &solver->statistics; + statistics *statistics = &solver->statistics_; *delta_ticks = statistics->search_ticks - solver->mode.ticks; -#ifndef QUIET +#ifndef KISSAT_QUIET if (kissat_verbosity (solver) < 2) return; @@ -148,7 +150,7 @@ static void report_switching_from_mode (kissat *solver, } static void switch_to_focused_mode (kissat *solver) { - assert (solver->stable); + KISSAT_assert (solver->stable); uint64_t delta; report_switching_from_mode (solver, &delta); REPORT (0, ']'); @@ -166,7 +168,7 @@ static void switch_to_focused_mode (kissat *solver) { } static void switch_to_stable_mode (kissat *solver) { - assert (!solver->stable); + KISSAT_assert (!solver->stable); uint64_t delta; report_switching_from_mode (solver, &delta); REPORT (0, '}'); @@ -184,13 +186,13 @@ static void switch_to_stable_mode (kissat *solver) { } bool kissat_switching_search_mode (kissat *solver) { - assert (!solver->inconsistent); + KISSAT_assert (!solver->inconsistent); if (GET_OPTION (stable) != 1) return false; limits *limits = &solver->limits; - statistics *statistics = &solver->statistics; + statistics *statistics = &solver->statistics_; if (limits->mode.count & 1) return statistics->search_ticks >= limits->mode.ticks; @@ -199,7 +201,7 @@ bool kissat_switching_search_mode (kissat *solver) { } void kissat_switch_search_mode (kissat *solver) { - assert (kissat_switching_search_mode (solver)); + KISSAT_assert (kissat_switching_search_mode (solver)); INC (switched); solver->limits.mode.count++; @@ -213,3 +215,5 @@ void kissat_switch_search_mode (kissat *solver) { kissat_start_random_sequence (solver); } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/mode.h b/src/sat/kissat/mode.h index 915e746e4..0b658113c 100644 --- a/src/sat/kissat/mode.h +++ b/src/sat/kissat/mode.h @@ -1,13 +1,16 @@ #ifndef _mode_h_INCLUDED #define _mode_h_INCLUDED +#include "global.h" +ABC_NAMESPACE_HEADER_START + struct kissat; typedef struct mode mode; struct mode { uint64_t ticks; -#ifndef QUIET +#ifndef KISSAT_QUIET double entered; uint64_t conflicts; #ifdef METRICS @@ -21,4 +24,6 @@ void kissat_init_mode_limit (struct kissat *); bool kissat_switching_search_mode (struct kissat *); void kissat_switch_search_mode (struct kissat *); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/module.make b/src/sat/kissat/module.make new file mode 100644 index 000000000..e6ca01394 --- /dev/null +++ b/src/sat/kissat/module.make @@ -0,0 +1,91 @@ +SRC += src/sat/kissat/kissatSolver.c \ +src/sat/kissat/kissatTest.c\ +src/sat/kissat/allocate.c \ +src/sat/kissat/analyze.c \ +src/sat/kissat/ands.c \ +src/sat/kissat/arena.c \ +src/sat/kissat/assign.c \ +src/sat/kissat/averages.c \ +src/sat/kissat/backbone.c \ +src/sat/kissat/backtrack.c \ +src/sat/kissat/build.c \ +src/sat/kissat/bump.c \ +src/sat/kissat/check.c \ +src/sat/kissat/classify.c \ +src/sat/kissat/clause.c \ +src/sat/kissat/collect.c \ +src/sat/kissat/colors.c \ +src/sat/kissat/compact.c \ +src/sat/kissat/config.c \ +src/sat/kissat/congruence.c \ +src/sat/kissat/decide.c \ +src/sat/kissat/deduce.c \ +src/sat/kissat/definition.c \ +src/sat/kissat/dense.c \ +src/sat/kissat/dump.c \ +src/sat/kissat/eliminate.c \ +src/sat/kissat/equivalences.c \ +src/sat/kissat/error.c \ +src/sat/kissat/extend.c \ +src/sat/kissat/factor.c \ +src/sat/kissat/fastel.c \ +src/sat/kissat/file.c \ +src/sat/kissat/flags.c \ +src/sat/kissat/format.c \ +src/sat/kissat/forward.c \ +src/sat/kissat/gates.c \ +src/sat/kissat/heap.c \ +src/sat/kissat/ifthenelse.c \ +src/sat/kissat/import.c \ +src/sat/kissat/internal.c \ +src/sat/kissat/kimits.c \ +src/sat/kissat/kitten.c \ +src/sat/kissat/krite.c \ +src/sat/kissat/learn.c \ +src/sat/kissat/logging.c \ +src/sat/kissat/kucky.c \ +src/sat/kissat/minimize.c \ +src/sat/kissat/mode.c \ +src/sat/kissat/kptions.c \ +src/sat/kissat/phases.c \ +src/sat/kissat/preprocess.c \ +src/sat/kissat/print.c \ +src/sat/kissat/probe.c \ +src/sat/kissat/profile.c \ +src/sat/kissat/promote.c \ +src/sat/kissat/proof.c \ +src/sat/kissat/propbeyond.c \ +src/sat/kissat/propdense.c \ +src/sat/kissat/propinitially.c \ +src/sat/kissat/proprobe.c \ +src/sat/kissat/propsearch.c \ +src/sat/kissat/queue.c \ +src/sat/kissat/reduce.c \ +src/sat/kissat/reluctant.c \ +src/sat/kissat/reorder.c \ +src/sat/kissat/rephase.c \ +src/sat/kissat/report.c \ +src/sat/kissat/resize.c \ +src/sat/kissat/resolve.c \ +src/sat/kissat/resources.c \ +src/sat/kissat/restart.c \ +src/sat/kissat/search.c \ +src/sat/kissat/shrink.c \ +src/sat/kissat/smooth.c \ +src/sat/kissat/sort.c \ +src/sat/kissat/stack.c \ +src/sat/kissat/statistics.c \ +src/sat/kissat/strengthen.c \ +src/sat/kissat/substitute.c \ +src/sat/kissat/sweep.c \ +src/sat/kissat/terminate.c \ +src/sat/kissat/tiers.c \ +src/sat/kissat/trail.c \ +src/sat/kissat/transitive.c \ +src/sat/kissat/utilities.c \ +src/sat/kissat/vector.c \ +src/sat/kissat/vivify.c \ +src/sat/kissat/walk.c \ +src/sat/kissat/warmup.c \ +src/sat/kissat/watch.c \ +src/sat/kissat/weaken.c \ diff --git a/src/sat/kissat/options.h b/src/sat/kissat/options.h index 26cd6f066..3746014bd 100644 --- a/src/sat/kissat/options.h +++ b/src/sat/kissat/options.h @@ -4,6 +4,9 @@ #include #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + // clang-format off #define OPTIONS \ @@ -191,19 +194,19 @@ #define STABLE_DEFAULT STABLE_UNSAT #endif -#if defined(LOGGING) && !defined(QUIET) +#if defined(LOGGING) && !defined(KISSAT_QUIET) #define LOGOPT OPTION #else #define LOGOPT(...) /**/ #endif -#ifndef QUIET +#ifndef KISSAT_QUIET #define NQTOPT OPTION #else #define NQTOPT(...) /**/ #endif -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG #define DBGOPT OPTION #else #define DBGOPT(...) /**/ @@ -224,7 +227,7 @@ typedef struct opt opt; struct opt { const char *name; -#ifndef NOPTIONS +#ifndef KISSAT_NOPTIONS int value; const int low; const int high; @@ -245,7 +248,7 @@ extern const opt *kissat_options_end; const char *kissat_parse_option_name (const char *arg, const char *name); bool kissat_parse_option_value (const char *val_str, int *res_ptr); -#ifndef NOPTIONS +#ifndef KISSAT_NOPTIONS void kissat_options_usage (void); @@ -277,8 +280,8 @@ static inline int *kissat_options_ref (const options *options, const opt *o) { if (!o) return 0; - assert (kissat_options_begin <= o); - assert (o < kissat_options_end); + KISSAT_assert (kissat_options_begin <= o); + KISSAT_assert (o < kissat_options_end); return (int *) options + (o - kissat_options_begin); } @@ -296,4 +299,6 @@ OPTIONS #undef OPTION #endif #define GET1K_OPTION(NAME) (((int64_t) 1000) * GET_OPTION (NAME)) +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/parse.h b/src/sat/kissat/parse.h index 665371259..709464648 100644 --- a/src/sat/kissat/parse.h +++ b/src/sat/kissat/parse.h @@ -3,6 +3,9 @@ #include "file.h" +#include "global.h" +ABC_NAMESPACE_HEADER_START + enum strictness { RELAXED_PARSING = 0, NORMAL_PARSING = 1, @@ -16,4 +19,6 @@ struct kissat; const char *kissat_parse_dimacs (struct kissat *, strictness, file *, uint64_t *linenoptr, int *max_var_ptr); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/phases.c b/src/sat/kissat/phases.c index 5fb84c20d..ac1ea70df 100644 --- a/src/sat/kissat/phases.c +++ b/src/sat/kissat/phases.c @@ -4,22 +4,24 @@ #include +ABC_NAMESPACE_IMPL_START + #define realloc_phases(NAME) \ do { \ solver->phases.NAME = \ - kissat_realloc (solver, solver->phases.NAME, old_size, new_size); \ + (value*) kissat_realloc (solver, solver->phases.NAME, old_size, new_size); \ } while (0) #define increase_phases(NAME) \ do { \ - assert (old_size < new_size); \ + KISSAT_assert (old_size < new_size); \ realloc_phases (NAME); \ memset (solver->phases.NAME + old_size, 0, new_size - old_size); \ } while (0) void kissat_increase_phases (kissat *solver, unsigned new_size) { const unsigned old_size = solver->size; - assert (old_size < new_size); + KISSAT_assert (old_size < new_size); LOG ("increasing phases from %u to %u", old_size, new_size); increase_phases (best); increase_phases (saved); @@ -28,7 +30,7 @@ void kissat_increase_phases (kissat *solver, unsigned new_size) { void kissat_decrease_phases (kissat *solver, unsigned new_size) { const unsigned old_size = solver->size; - assert (old_size > new_size); + KISSAT_assert (old_size > new_size); LOG ("decreasing phases from %u to %u", old_size, new_size); realloc_phases (best); realloc_phases (saved); @@ -52,17 +54,19 @@ static void save_phases (kissat *solver, value *phases) { for (value *p = phases, tmp; p != end; p++, v += 2) if ((tmp = *v)) *p = tmp; - assert (v == values + LITS); + KISSAT_assert (v == values + LITS); } void kissat_save_best_phases (kissat *solver) { - assert (sizeof (value) == 1); + KISSAT_assert (sizeof (value) == 1); LOG ("saving %u best values", VARS); save_phases (solver, solver->phases.best); } void kissat_save_target_phases (kissat *solver) { - assert (sizeof (value) == 1); + KISSAT_assert (sizeof (value) == 1); LOG ("saving %u target values", VARS); save_phases (solver, solver->phases.target); } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/phases.h b/src/sat/kissat/phases.h index 4a2456fec..7f852b4e0 100644 --- a/src/sat/kissat/phases.h +++ b/src/sat/kissat/phases.h @@ -3,6 +3,9 @@ #include "value.h" +#include "global.h" +ABC_NAMESPACE_HEADER_START + typedef struct phases phases; struct phases { @@ -12,13 +15,13 @@ struct phases { }; #define BEST(IDX) \ - (solver->phases.best[assert (VALID_INTERNAL_INDEX (IDX)), (IDX)]) + (solver->phases.best[KISSAT_assert (VALID_INTERNAL_INDEX (IDX)), (IDX)]) #define SAVED(IDX) \ - (solver->phases.saved[assert (VALID_INTERNAL_INDEX (IDX)), (IDX)]) + (solver->phases.saved[KISSAT_assert (VALID_INTERNAL_INDEX (IDX)), (IDX)]) #define TARGET(IDX) \ - (solver->phases.target[assert (VALID_INTERNAL_INDEX (IDX)), (IDX)]) + (solver->phases.target[KISSAT_assert (VALID_INTERNAL_INDEX (IDX)), (IDX)]) struct kissat; @@ -29,4 +32,6 @@ void kissat_release_phases (struct kissat *); void kissat_save_best_phases (struct kissat *); void kissat_save_target_phases (struct kissat *); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/preprocess.c b/src/sat/kissat/preprocess.c index 96a0beee0..875b8f49a 100644 --- a/src/sat/kissat/preprocess.c +++ b/src/sat/kissat/preprocess.c @@ -11,33 +11,35 @@ #include +ABC_NAMESPACE_IMPL_START + bool kissat_preprocessing (struct kissat *solver) { - assert (!solver->level); - assert (!solver->inconsistent); + KISSAT_assert (!solver->level); + KISSAT_assert (!solver->inconsistent); if (!GET_OPTION (preprocess)) return false; if (!GET_OPTION (probe)) return false; if (!GET_OPTION (preprocessprobe)) return false; -#if defined(NDEBUG) && defined(NOPTIONS) +#if defined(KISSAT_NDEBUG) && defined(KISSAT_NOPTIONS) (void) solver; #endif return true; } int kissat_preprocess (struct kissat *solver) { - assert (kissat_preprocessing (solver)); + KISSAT_assert (kissat_preprocessing (solver)); if (!kissat_initially_propagate (solver)) { - assert (solver->inconsistent); + KISSAT_assert (solver->inconsistent); return 20; } START (preprocess); - assert (!solver->preprocessing); + KISSAT_assert (!solver->preprocessing); solver->preprocessing = true; REPORT (0, '('); const unsigned max_rounds = GET_OPTION (preprocessrounds); -#ifndef QUIET +#ifndef KISSAT_QUIET const unsigned variables_initially = solver->active; const uint64_t clauses_initially = BINIRR_CLAUSES; const unsigned variables_originally = SIZE_STACK (solver->import); @@ -63,7 +65,7 @@ int kissat_preprocess (struct kissat *solver) { break; const unsigned variables_before = solver->active; const uint64_t clauses_before = BINIRR_CLAUSES; -#ifndef QUIET +#ifndef KISSAT_QUIET kissat_verbose (solver, "[preprocess-%u] started preprocessing round %u", round, round); @@ -74,7 +76,7 @@ int kissat_preprocess (struct kissat *solver) { kissat_fast_variable_elimination (solver); const unsigned variables_after = solver->active; const uint64_t clauses_after = BINIRR_CLAUSES; -#ifndef QUIET +#ifndef KISSAT_QUIET if (variables_after < variables_before) { unsigned removed = variables_before - variables_after; kissat_verbose ( @@ -119,7 +121,7 @@ int kissat_preprocess (struct kissat *solver) { break; round++; } -#ifndef QUIET +#ifndef KISSAT_QUIET const unsigned variables_finally = solver->active; const uint64_t clauses_finally = BINIRR_CLAUSES; kissat_verbose (solver, "[preprocess] finished after %u rounds", round); @@ -171,8 +173,10 @@ int kissat_preprocess (struct kissat *solver) { kissat_percent (clauses_finally, clauses_originally)); #endif REPORT (0, ')'); - assert (solver->preprocessing); + KISSAT_assert (solver->preprocessing); solver->preprocessing = false; STOP (preprocess); return solver->inconsistent ? 20 : 0; } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/preprocess.h b/src/sat/kissat/preprocess.h index 056b5ecde..7826a656e 100644 --- a/src/sat/kissat/preprocess.h +++ b/src/sat/kissat/preprocess.h @@ -3,8 +3,13 @@ #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + struct kissat; bool kissat_preprocessing (struct kissat *); int kissat_preprocess (struct kissat *); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/print.c b/src/sat/kissat/print.c index 454b8f343..3d50141fd 100644 --- a/src/sat/kissat/print.c +++ b/src/sat/kissat/print.c @@ -1,4 +1,6 @@ -#ifndef QUIET +#include "global.h" + +#ifndef KISSAT_QUIET #include "print.h" #include "colors.h" @@ -16,7 +18,7 @@ static inline int verbosity (kissat *solver) { if (GET_OPTION (log)) return 3; #endif -#ifndef QUIET +#ifndef KISSAT_QUIET if (GET_OPTION (quiet)) return -1; return GET_OPTION (verbose); @@ -39,7 +41,7 @@ void kissat_warning (kissat *solver, const char *fmt, ...) { vprintf (fmt, ap); va_end (ap); fputc ('\n', stdout); -#ifdef NOPTIONS +#ifdef KISSAT_NOPTIONS (void) solver; #endif } diff --git a/src/sat/kissat/print.h b/src/sat/kissat/print.h index d6f8a329f..941e94c50 100644 --- a/src/sat/kissat/print.h +++ b/src/sat/kissat/print.h @@ -3,12 +3,15 @@ #ifndef _print_h_INCLUDED #define _print_h_INCLUDED -#ifndef QUIET - #include #include "attribute.h" +#include "global.h" +ABC_NAMESPACE_HEADER_START + +#ifndef KISSAT_QUIET + struct kissat; int kissat_verbosity (struct kissat *); @@ -60,6 +63,8 @@ do { \ kissat_very_verbose (SOLVER, __VA_ARGS__); \ } while (0) +ABC_NAMESPACE_HEADER_END + #endif // clang-format on diff --git a/src/sat/kissat/probe.c b/src/sat/kissat/probe.c index 606710577..f77ba6619 100644 --- a/src/sat/kissat/probe.c +++ b/src/sat/kissat/probe.c @@ -13,10 +13,12 @@ #include +ABC_NAMESPACE_IMPL_START + bool kissat_probing (kissat *solver) { if (!solver->enabled.probe) return false; - statistics *statistics = &solver->statistics; + statistics *statistics = &solver->statistics_; const uint64_t conflicts = statistics->conflicts; if (solver->last.conflicts.reduce == conflicts) return false; @@ -25,7 +27,7 @@ bool kissat_probing (kissat *solver) { static void probe (kissat *solver) { kissat_backtrack_propagate_and_flush_trail (solver); - assert (!solver->inconsistent); + KISSAT_assert (!solver->inconsistent); STOP_SEARCH_AND_START_SIMPLIFIER (probe); kissat_phase (solver, "probe", GET (probings), "probing limit hit after %" PRIu64 " conflicts", @@ -43,8 +45,8 @@ static void probe (kissat *solver) { } static void probe_initially (kissat *solver) { - assert (!solver->level); - assert (!solver->inconsistent); + KISSAT_assert (!solver->level); + KISSAT_assert (!solver->inconsistent); kissat_phase (solver, "probe", GET (probings), "initial probing"); bool substitute_at_the_end = true; if (GET_OPTION (preprocesscongruence)) { @@ -68,9 +70,9 @@ static void probe_initially (kissat *solver) { } int kissat_probe (kissat *solver) { - assert (!solver->inconsistent); + KISSAT_assert (!solver->inconsistent); INC (probings); - assert (!solver->probing); + KISSAT_assert (!solver->probing); solver->probing = true; const unsigned max_rounds = GET_OPTION (proberounds); for (unsigned round = 0; round != max_rounds; round++) { @@ -83,22 +85,24 @@ int kissat_probe (kissat *solver) { } kissat_classify (solver); UPDATE_CONFLICT_LIMIT (probe, probings, NLOGN, true); - solver->last.ticks.probe = solver->statistics.search_ticks; - assert (solver->probing); + solver->last.ticks.probe = solver->statistics_.search_ticks; + KISSAT_assert (solver->probing); solver->probing = false; return solver->inconsistent ? 20 : 0; } int kissat_probe_initially (kissat *solver) { - assert (!solver->level); - assert (!solver->inconsistent); + KISSAT_assert (!solver->level); + KISSAT_assert (!solver->inconsistent); INC (probings); START (probe); - assert (!solver->probing); + KISSAT_assert (!solver->probing); solver->probing = true; probe_initially (solver); - assert (solver->probing); + KISSAT_assert (solver->probing); solver->probing = false; STOP (probe); return solver->inconsistent ? 20 : 0; } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/probe.h b/src/sat/kissat/probe.h index a788918f3..8226325fb 100644 --- a/src/sat/kissat/probe.h +++ b/src/sat/kissat/probe.h @@ -3,10 +3,15 @@ #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + struct kissat; bool kissat_probing (struct kissat *); int kissat_probe (struct kissat *); int kissat_probe_initially (struct kissat *); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/profile.c b/src/sat/kissat/profile.c index 01cd65573..d301e8cbb 100644 --- a/src/sat/kissat/profile.c +++ b/src/sat/kissat/profile.c @@ -1,4 +1,6 @@ -#ifndef QUIET +#include "global.h" + +#ifndef KISSAT_QUIET #include "internal.h" #include "resources.h" @@ -73,7 +75,7 @@ void kissat_start (kissat *solver, profile *profile) { } void kissat_stop (kissat *solver, profile *profile) { - assert (TOP_STACK (solver->profiles.stack) == profile); + KISSAT_assert (TOP_STACK (solver->profiles.stack) == profile); (void) POP_STACK (solver->profiles.stack); const double now = kissat_process_time (); flush_profile (profile, now); @@ -82,23 +84,23 @@ void kissat_stop (kissat *solver, profile *profile) { void kissat_stop_search_and_start_simplifier (kissat *solver, profile *profile) { struct profile *search = &PROFILE (search); - assert (search->level <= GET_OPTION (profile)); + KISSAT_assert (search->level <= GET_OPTION (profile)); const double now = kissat_process_time (); while (TOP_STACK (solver->profiles.stack) != search) { struct profile *mode = POP_STACK (solver->profiles.stack); - assert (search->level <= mode->level); -#ifndef NDEBUG + KISSAT_assert (search->level <= mode->level); +#ifndef KISSAT_NDEBUG if (solver->stable) - assert (mode == &PROFILE (stable)); + KISSAT_assert (mode == &PROFILE (stable)); else - assert (mode == &PROFILE (focused)); + KISSAT_assert (mode == &PROFILE (focused)); #endif flush_profile (mode, now); } (void) POP_STACK (solver->profiles.stack); struct profile *simplify = &PROFILE (simplify); - assert (search->level == simplify->level); - assert (simplify->level <= profile->level); + KISSAT_assert (search->level == simplify->level); + KISSAT_assert (simplify->level <= profile->level); flush_profile (search, now); push_profile (solver, simplify, now); if (profile->level <= GET_OPTION (profile)) @@ -111,28 +113,28 @@ void kissat_stop_simplifier_and_resume_search (kissat *solver, struct profile *top = POP_STACK (solver->profiles.stack); const double now = kissat_process_time (); const double delta = flush_profile (simplify, now); -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG const double entered = now - delta; - assert (solver->mode.entered <= entered); + KISSAT_assert (solver->mode.entered <= entered); #endif solver->mode.entered += delta; if (top == profile) { flush_profile (profile, now); - assert (TOP_STACK (solver->profiles.stack) == simplify); + KISSAT_assert (TOP_STACK (solver->profiles.stack) == simplify); (void) POP_STACK (solver->profiles.stack); } else { - assert (simplify == top); - assert (profile->level > GET_OPTION (profile)); + KISSAT_assert (simplify == top); + KISSAT_assert (profile->level > GET_OPTION (profile)); } -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG struct profile *search = &PROFILE (search); - assert (search->level == simplify->level); + KISSAT_assert (search->level == simplify->level); #endif - assert (simplify->level <= profile->level); + KISSAT_assert (simplify->level <= profile->level); push_profile (solver, &PROFILE (search), now); struct profile *mode = solver->stable ? &PROFILE (stable) : &PROFILE (focused); - assert (search->level <= mode->level); + KISSAT_assert (search->level <= mode->level); if (mode->level <= GET_OPTION (profile)) push_profile (solver, mode, now); } diff --git a/src/sat/kissat/profile.h b/src/sat/kissat/profile.h index 62d03cf71..155724f26 100644 --- a/src/sat/kissat/profile.h +++ b/src/sat/kissat/profile.h @@ -1,10 +1,13 @@ #ifndef _profile_h_INCLUDED #define _profile_h_INCLUDED -#ifndef QUIET - #include "stack.h" +#include "global.h" +ABC_NAMESPACE_HEADER_START + +#ifndef KISSAT_QUIET + typedef struct profile profile; typedef struct profiles profiles; @@ -140,4 +143,6 @@ double kissat_time (struct kissat *); #endif +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/promote.c b/src/sat/kissat/promote.c index 152cfed4c..19d519596 100644 --- a/src/sat/kissat/promote.c +++ b/src/sat/kissat/promote.c @@ -2,35 +2,37 @@ #include "internal.h" #include "logging.h" +ABC_NAMESPACE_IMPL_START + void kissat_promote_clause (kissat *solver, clause *c, unsigned new_glue) { if (!GET_OPTION (promote)) return; - assert (c->redundant); + KISSAT_assert (c->redundant); const unsigned old_glue = c->glue; - assert (new_glue < old_glue); + KISSAT_assert (new_glue < old_glue); const unsigned tier1 = TIER1; const unsigned tier2 = MAX (TIER2, TIER1); if (old_glue <= tier1) { LOGCLS (c, "keeping with new glue %u in tier1", new_glue); INC (clauses_kept1); } else if (new_glue <= tier1) { - assert (tier1 < old_glue); - assert (new_glue <= tier1); + KISSAT_assert (tier1 < old_glue); + KISSAT_assert (new_glue <= tier1); LOGCLS (c, "promoting with new glue %u to tier1", new_glue); INC (clauses_promoted1); } else if (tier2 < old_glue && new_glue <= tier2) { - assert (tier2 < old_glue); - assert (tier1 < new_glue), assert (new_glue <= tier2); + KISSAT_assert (tier2 < old_glue); + KISSAT_assert (tier1 < new_glue), KISSAT_assert (new_glue <= tier2); LOGCLS (c, "promoting with new glue %u to tier2", new_glue); INC (clauses_promoted2); } else if (old_glue <= tier2) { - assert (tier1 < old_glue), assert (old_glue <= tier2); - assert (tier1 < new_glue), assert (new_glue <= tier2); + KISSAT_assert (tier1 < old_glue), KISSAT_assert (old_glue <= tier2); + KISSAT_assert (tier1 < new_glue), KISSAT_assert (new_glue <= tier2); LOGCLS (c, "keeping with new glue %u in tier2", new_glue); INC (clauses_kept2); } else { - assert (tier2 < old_glue); - assert (tier2 < new_glue); + KISSAT_assert (tier2 < old_glue); + KISSAT_assert (tier2 < new_glue); LOGCLS (c, "keeping with new glue %u in tier3", new_glue); INC (clauses_kept3); } @@ -40,3 +42,5 @@ void kissat_promote_clause (kissat *solver, clause *c, unsigned new_glue) { (void) solver; #endif } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/promote.h b/src/sat/kissat/promote.h index 3a6073cf6..0d96577bf 100644 --- a/src/sat/kissat/promote.h +++ b/src/sat/kissat/promote.h @@ -3,15 +3,18 @@ #include "internal.h" +#include "global.h" +ABC_NAMESPACE_HEADER_START + void kissat_promote_clause (struct kissat *, clause *, unsigned new_glue); static inline unsigned kissat_recompute_glue (kissat *solver, clause *c, unsigned limit) { - assert (limit); - assert (EMPTY_STACK (solver->promote)); + KISSAT_assert (limit); + KISSAT_assert (EMPTY_STACK (solver->promote)); unsigned res = 0; for (all_literals_in_clause (lit, c)) { - assert (VALUE (lit)); + KISSAT_assert (VALUE (lit)); const unsigned level = LEVEL (lit); frame *frame = &FRAME (level); if (frame->promote) @@ -23,11 +26,13 @@ static inline unsigned kissat_recompute_glue (kissat *solver, clause *c, } for (all_stack (unsigned, level, solver->promote)) { frame *frame = &FRAME (level); - assert (frame->promote); + KISSAT_assert (frame->promote); frame->promote = false; } CLEAR_STACK (solver->promote); return res; } +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/proof.c b/src/sat/kissat/proof.c index 5c819906b..769655de8 100644 --- a/src/sat/kissat/proof.c +++ b/src/sat/kissat/proof.c @@ -1,13 +1,15 @@ -#ifndef NPROOFS +#include "global.h" + +#ifndef KISSAT_NPROOFS #include "allocate.h" #include "error.h" #include "file.h" #include "inline.h" -#undef NDEBUG +#undef KISSAT_NDEBUG -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG #include #endif @@ -30,12 +32,12 @@ struct proof { uint64_t deleted; uint64_t lines; uint64_t literals; -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG bool empty; char *units; size_t size_units; #endif -#if !defined(NDEBUG) || defined(LOGGING) +#if !defined(KISSAT_NDEBUG) || defined(LOGGING) unsigneds imported; #endif }; @@ -52,8 +54,8 @@ struct proof { __VA_ARGS__) void kissat_init_proof (kissat *solver, file *file, bool binary) { - assert (file); - assert (!solver->proof); + KISSAT_assert (file); + KISSAT_assert (!solver->proof); proof *proof = kissat_calloc (solver, 1, sizeof (struct proof)); proof->binary = binary; proof->file = file; @@ -74,22 +76,22 @@ static void flush_buffer (proof *proof) { void kissat_release_proof (kissat *solver) { proof *proof = solver->proof; - assert (proof); + KISSAT_assert (proof); LOG ("stopping to trace proof"); flush_buffer (proof); kissat_flush (proof->file); RELEASE_STACK (proof->line); -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG kissat_free (solver, proof->units, proof->size_units); #endif -#if !defined(NDEBUG) || defined(LOGGING) +#if !defined(KISSAT_NDEBUG) || defined(LOGGING) RELEASE_STACK (proof->imported); #endif kissat_free (solver, proof, sizeof (struct proof)); solver->proof = 0; } -#ifndef QUIET +#ifndef KISSAT_QUIET #include @@ -138,27 +140,27 @@ static inline void import_internal_proof_literal (kissat *solver, proof *proof, unsigned ilit) { int elit = kissat_export_literal (solver, ilit); - assert (elit); + KISSAT_assert (elit); PUSH_STACK (proof->line, elit); proof->literals++; -#if !defined(NDEBUG) || defined(LOGGING) +#if !defined(KISSAT_NDEBUG) || defined(LOGGING) PUSH_STACK (proof->imported, ilit); #endif } static inline void import_external_proof_literal (kissat *solver, proof *proof, int elit) { - assert (elit); + KISSAT_assert (elit); PUSH_STACK (proof->line, elit); proof->literals++; -#ifndef NDEBUG - assert (EMPTY_STACK (proof->imported)); +#ifndef KISSAT_NDEBUG + KISSAT_assert (EMPTY_STACK (proof->imported)); #endif } static void import_internal_proof_binary (kissat *solver, proof *proof, unsigned a, unsigned b) { - assert (EMPTY_STACK (proof->line)); + KISSAT_assert (EMPTY_STACK (proof->line)); import_internal_proof_literal (solver, proof, a); import_internal_proof_literal (solver, proof, b); } @@ -166,16 +168,16 @@ static void import_internal_proof_binary (kissat *solver, proof *proof, static void import_internal_proof_literals (kissat *solver, proof *proof, size_t size, const unsigned *ilits) { - assert (EMPTY_STACK (proof->line)); - assert (size <= UINT_MAX); + KISSAT_assert (EMPTY_STACK (proof->line)); + KISSAT_assert (size <= UINT_MAX); for (size_t i = 0; i < size; i++) import_internal_proof_literal (solver, proof, ilits[i]); } static void import_external_proof_literals (kissat *solver, proof *proof, size_t size, const int *elits) { - assert (EMPTY_STACK (proof->line)); - assert (size <= UINT_MAX); + KISSAT_assert (EMPTY_STACK (proof->line)); + KISSAT_assert (size <= UINT_MAX); for (size_t i = 0; i < size; i++) import_external_proof_literal (solver, proof, elits[i]); } @@ -186,7 +188,7 @@ static void import_proof_clause (kissat *solver, proof *proof, } static void print_binary_proof_line (proof *proof) { - assert (proof->binary); + KISSAT_assert (proof->binary); for (all_stack (int, elit, proof->line)) { unsigned x = 2u * ABS (elit) + (elit < 0); unsigned char ch; @@ -201,15 +203,15 @@ static void print_binary_proof_line (proof *proof) { } static void print_non_binary_proof_line (proof *proof) { - assert (!proof->binary); + KISSAT_assert (!proof->binary); char buffer[16]; char *end_of_buffer = buffer + sizeof buffer; *--end_of_buffer = 0; for (all_stack (int, elit, proof->line)) { char *p = end_of_buffer; - assert (!*p); - assert (elit); - assert (elit != INT_MIN); + KISSAT_assert (!*p); + KISSAT_assert (elit); + KISSAT_assert (elit != INT_MIN); unsigned eidx; if (elit < 0) { write_char (proof, '-'); @@ -233,10 +235,10 @@ static void print_proof_line (proof *proof) { else print_non_binary_proof_line (proof); CLEAR_STACK (proof->line); -#if !defined(NDEBUG) || defined(LOGGING) +#if !defined(KISSAT_NDEBUG) || defined(LOGGING) CLEAR_STACK (proof->imported); #endif -#ifndef NOPTIONS +#ifndef KISSAT_NOPTIONS kissat *solver = proof->solver; #endif if (GET_OPTION (flushproof)) { @@ -245,11 +247,11 @@ static void print_proof_line (proof *proof) { } } -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG static unsigned external_to_proof_literal (int elit) { - assert (elit); - assert (elit != INT_MIN); + KISSAT_assert (elit); + KISSAT_assert (elit != INT_MIN); return 2u * (abs (elit) - 1) + (elit < 0); } @@ -270,12 +272,12 @@ static void resize_proof_units (proof *proof, unsigned plit) { static void check_repeated_proof_lines (proof *proof) { size_t size = SIZE_STACK (proof->line); if (!size) { - assert (!proof->empty); + KISSAT_assert (!proof->empty); proof->empty = true; } else if (size == 1) { const int eunit = PEEK_STACK (proof->line, 0); const unsigned punit = external_to_proof_literal (eunit); - assert (punit != INVALID_LIT); + KISSAT_assert (punit != INVALID_LIT); if (!proof->size_units || proof->size_units <= punit) resize_proof_units (proof, punit); proof->units[punit] = 1; @@ -288,11 +290,11 @@ static void print_added_proof_line (proof *proof) { proof->added++; #ifdef LOGGING struct kissat *solver = proof->solver; - assert (SIZE_STACK (proof->imported) == SIZE_STACK (proof->line)); + KISSAT_assert (SIZE_STACK (proof->imported) == SIZE_STACK (proof->line)); LOGIMPORTED3 ("added proof line"); LOGLINE3 ("added proof line"); #endif -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG check_repeated_proof_lines (proof); #endif if (proof->binary) @@ -316,37 +318,37 @@ static void print_delete_proof_line (proof *proof) { void kissat_add_binary_to_proof (kissat *solver, unsigned a, unsigned b) { proof *proof = solver->proof; - assert (proof); + KISSAT_assert (proof); import_internal_proof_binary (solver, proof, a, b); print_added_proof_line (proof); } void kissat_add_clause_to_proof (kissat *solver, const clause *c) { proof *proof = solver->proof; - assert (proof); + KISSAT_assert (proof); import_proof_clause (solver, proof, c); print_added_proof_line (proof); } void kissat_add_empty_to_proof (kissat *solver) { proof *proof = solver->proof; - assert (proof); - assert (EMPTY_STACK (proof->line)); + KISSAT_assert (proof); + KISSAT_assert (EMPTY_STACK (proof->line)); print_added_proof_line (proof); } void kissat_add_lits_to_proof (kissat *solver, size_t size, const unsigned *ilits) { proof *proof = solver->proof; - assert (proof); + KISSAT_assert (proof); import_internal_proof_literals (solver, proof, size, ilits); print_added_proof_line (proof); } void kissat_add_unit_to_proof (kissat *solver, unsigned ilit) { proof *proof = solver->proof; - assert (proof); - assert (EMPTY_STACK (proof->line)); + KISSAT_assert (proof); + KISSAT_assert (EMPTY_STACK (proof->line)); import_internal_proof_literal (solver, proof, ilit); print_added_proof_line (proof); } @@ -355,7 +357,7 @@ void kissat_shrink_clause_in_proof (kissat *solver, const clause *c, unsigned remove, unsigned keep) { proof *proof = solver->proof; const value *const values = solver->values; - assert (EMPTY_STACK (proof->line)); + KISSAT_assert (EMPTY_STACK (proof->line)); const unsigned *ilits = c->lits; const unsigned size = c->size; for (unsigned i = 0; i != size; i++) { @@ -374,14 +376,14 @@ void kissat_shrink_clause_in_proof (kissat *solver, const clause *c, void kissat_delete_binary_from_proof (kissat *solver, unsigned a, unsigned b) { proof *proof = solver->proof; - assert (proof); + KISSAT_assert (proof); import_internal_proof_binary (solver, proof, a, b); print_delete_proof_line (proof); } void kissat_delete_clause_from_proof (kissat *solver, const clause *c) { proof *proof = solver->proof; - assert (proof); + KISSAT_assert (proof); import_proof_clause (solver, proof, c); print_delete_proof_line (proof); } @@ -389,7 +391,7 @@ void kissat_delete_clause_from_proof (kissat *solver, const clause *c) { void kissat_delete_external_from_proof (kissat *solver, size_t size, const int *elits) { proof *proof = solver->proof; - assert (proof); + KISSAT_assert (proof); LOGINTS3 (size, elits, "explicitly deleted"); import_external_proof_literals (solver, proof, size, elits); print_delete_proof_line (proof); @@ -398,7 +400,7 @@ void kissat_delete_external_from_proof (kissat *solver, size_t size, void kissat_delete_internal_from_proof (kissat *solver, size_t size, const unsigned *ilits) { proof *proof = solver->proof; - assert (proof); + KISSAT_assert (proof); import_internal_proof_literals (solver, proof, size, ilits); print_delete_proof_line (proof); } diff --git a/src/sat/kissat/proof.h b/src/sat/kissat/proof.h index a87e60de5..d22fedb17 100644 --- a/src/sat/kissat/proof.h +++ b/src/sat/kissat/proof.h @@ -1,11 +1,14 @@ #ifndef _proof_h_INCLUDED #define _proof_h_INCLUDED -#ifndef NPROOFS - #include #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + +#ifndef KISSAT_NPROOFS + typedef struct proof proof; struct clause; @@ -14,7 +17,7 @@ struct file; void kissat_init_proof (struct kissat *, struct file *, bool binary); void kissat_release_proof (struct kissat *); -#ifndef QUIET +#ifndef KISSAT_QUIET void kissat_print_proof_statistics (struct kissat *, bool verbose); #endif @@ -161,4 +164,6 @@ void kissat_delete_internal_from_proof (struct kissat *, size_t, #endif +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/propbeyond.c b/src/sat/kissat/propbeyond.c index b42192b05..8ffeb0432 100644 --- a/src/sat/kissat/propbeyond.c +++ b/src/sat/kissat/propbeyond.c @@ -2,6 +2,8 @@ #include "fastassign.h" #include "trail.h" +ABC_NAMESPACE_IMPL_START + #define PROPAGATE_LITERAL propagate_literal_beyond_conflicts #define CONTINUE_PROPAGATING_AFTER_CONFLICT #define PROPAGATION_TYPE "beyond conflict" @@ -11,7 +13,7 @@ static inline void update_beyond_propagation_statistics (kissat *solver, const unsigned *saved_propagate) { - assert (saved_propagate <= solver->propagate); + KISSAT_assert (saved_propagate <= solver->propagate); const unsigned propagated = solver->propagate - saved_propagate; LOG ("propagated %u literals", propagated); @@ -32,10 +34,10 @@ static void propagate_literals_beyond_conflicts (kissat *solver) { } void kissat_propagate_beyond_conflicts (kissat *solver) { - assert (!solver->probing); - assert (solver->watching); - assert (solver->warming); - assert (!solver->inconsistent); + KISSAT_assert (!solver->probing); + KISSAT_assert (solver->watching); + KISSAT_assert (solver->warming); + KISSAT_assert (!solver->inconsistent); START (propagate); @@ -46,3 +48,5 @@ void kissat_propagate_beyond_conflicts (kissat *solver) { STOP (propagate); } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/propbeyond.h b/src/sat/kissat/propbeyond.h index 09eaf1b4e..85d78d75d 100644 --- a/src/sat/kissat/propbeyond.h +++ b/src/sat/kissat/propbeyond.h @@ -1,9 +1,14 @@ #ifndef _propall_h_INCLUDED #define _propall_h_INCLUDED +#include "global.h" +ABC_NAMESPACE_HEADER_START + struct kissat; struct clause; void kissat_propagate_beyond_conflicts (struct kissat *); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/propdense.c b/src/sat/kissat/propdense.c index 48ccecb4f..18bbb49d6 100644 --- a/src/sat/kissat/propdense.c +++ b/src/sat/kissat/propdense.c @@ -1,11 +1,13 @@ #include "propdense.h" #include "fastassign.h" +ABC_NAMESPACE_IMPL_START + static inline bool non_watching_propagate_literal (kissat *solver, unsigned lit) { - assert (!solver->watching); + KISSAT_assert (!solver->watching); LOG ("propagating %s", LOGLIT (lit)); - assert (VALUE (lit) > 0); + KISSAT_assert (VALUE (lit) > 0); const unsigned not_lit = NOT (lit); watches *watches = &WATCHES (not_lit); @@ -20,7 +22,7 @@ static inline bool non_watching_propagate_literal (kissat *solver, for (all_binary_large_watches (watch, *watches)) { if (watch.type.binary) { const unsigned other = watch.binary.lit; - assert (VALID_INTERNAL_LITERAL (other)); + KISSAT_assert (VALID_INTERNAL_LITERAL (other)); const value other_value = values[other]; if (other_value > 0) continue; @@ -31,15 +33,15 @@ static inline bool non_watching_propagate_literal (kissat *solver, const unsigned other_idx = IDX (other); if (flags[other_idx].eliminated) continue; - assert (!solver->level); + KISSAT_assert (!solver->level); kissat_fast_binary_assign (solver, solver->probing, 0, values, assigned, other, not_lit); } else { const reference ref = watch.large.ref; - assert (ref < SIZE_STACK (solver->arena)); + KISSAT_assert (ref < SIZE_STACK (solver->arena)); clause *c = (clause *) (arena + ref); - assert (c->size > 2); - assert (!c->redundant); + KISSAT_assert (c->size > 2); + KISSAT_assert (!c->redundant); ticks++; if (c->garbage) continue; @@ -49,13 +51,13 @@ static inline bool non_watching_propagate_literal (kissat *solver, for (all_literals_in_clause (other, c)) { if (other == not_lit) continue; - assert (VALID_INTERNAL_LITERAL (other)); + KISSAT_assert (VALID_INTERNAL_LITERAL (other)); const value other_value = values[other]; if (other_value < 0) continue; if (other_value > 0) { satisfied = true; - assert (!solver->level); + KISSAT_assert (!solver->level); LOGCLS (c, "%s satisfied", LOGLIT (other)); kissat_mark_clause_as_garbage (solver, c); break; @@ -84,9 +86,9 @@ static inline bool non_watching_propagate_literal (kissat *solver, } bool kissat_dense_propagate (kissat *solver) { - assert (!solver->level); - assert (!solver->watching); - assert (!solver->inconsistent); + KISSAT_assert (!solver->level); + KISSAT_assert (!solver->watching); + KISSAT_assert (!solver->inconsistent); START (propagate); unsigned *propagate = solver->propagate; bool res = true; @@ -97,7 +99,7 @@ bool kissat_dense_propagate (kissat *solver) { ADD (dense_propagations, propagated); ADD (propagations, propagated); if (!res) { - assert (!solver->inconsistent); + KISSAT_assert (!solver->inconsistent); LOG ("inconsistent root propagation"); CHECK_AND_ADD_EMPTY (); ADD_EMPTY_TO_PROOF (); @@ -106,3 +108,5 @@ bool kissat_dense_propagate (kissat *solver) { STOP (propagate); return res; } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/propdense.h b/src/sat/kissat/propdense.h index adbaae1cd..cdfbc7280 100644 --- a/src/sat/kissat/propdense.h +++ b/src/sat/kissat/propdense.h @@ -4,8 +4,13 @@ #include #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + struct kissat; bool kissat_dense_propagate (struct kissat *); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/propinitially.c b/src/sat/kissat/propinitially.c index 5f66db3d1..d534d0e86 100644 --- a/src/sat/kissat/propinitially.c +++ b/src/sat/kissat/propinitially.c @@ -4,6 +4,8 @@ #include "print.h" #include "trail.h" +ABC_NAMESPACE_IMPL_START + #define PROPAGATE_LITERAL initially_propagate_literal #define PROPAGATION_TYPE "initially" @@ -12,7 +14,7 @@ static inline void update_initial_propagation_statistics (kissat *solver, const unsigned *saved_propagate) { - assert (saved_propagate <= solver->propagate); + KISSAT_assert (saved_propagate <= solver->propagate); const unsigned propagated = solver->propagate - saved_propagate; LOG ("propagated %u literals", propagated); @@ -32,9 +34,9 @@ static clause *initially_propagate (kissat *solver) { } bool kissat_initially_propagate (kissat *solver) { - assert (!solver->probing); - assert (solver->watching); - assert (!solver->inconsistent); + KISSAT_assert (!solver->probing); + KISSAT_assert (solver->watching); + KISSAT_assert (!solver->inconsistent); START (propagate); @@ -45,8 +47,8 @@ bool kissat_initially_propagate (kissat *solver) { kissat_update_conflicts_and_trail (solver, conflict, true); if (conflict) { int res = kissat_analyze (solver, conflict); - assert (solver->inconsistent); - assert (res == 20); + KISSAT_assert (solver->inconsistent); + KISSAT_assert (res == 20); (void) res; } @@ -54,3 +56,5 @@ bool kissat_initially_propagate (kissat *solver) { return !conflict; } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/propinitially.h b/src/sat/kissat/propinitially.h index d53f84c9a..7203cacaf 100644 --- a/src/sat/kissat/propinitially.h +++ b/src/sat/kissat/propinitially.h @@ -3,8 +3,13 @@ #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + struct kissat; bool kissat_initially_propagate (struct kissat *); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/proplit.h b/src/sat/kissat/proplit.h index c8ae9c1cb..be0632d0c 100644 --- a/src/sat/kissat/proplit.h +++ b/src/sat/kissat/proplit.h @@ -1,18 +1,18 @@ static inline void kissat_watch_large_delayed (kissat *solver, watches *all_watches, unsigneds *delayed) { - assert (all_watches == solver->watches); - assert (delayed == &solver->delayed); + KISSAT_assert (all_watches == solver->watches); + KISSAT_assert (delayed == &solver->delayed); const unsigned *const end_delayed = END_STACK (*delayed); unsigned const *d = BEGIN_STACK (*delayed); while (d != end_delayed) { const unsigned lit = *d++; - assert (d != end_delayed); + KISSAT_assert (d != end_delayed); const watch watch = {.raw = *d++}; - assert (!watch.type.binary); - assert (lit < LITS); + KISSAT_assert (!watch.type.binary); + KISSAT_assert (lit < LITS); watches *const lit_watches = all_watches + lit; - assert (d != end_delayed); + KISSAT_assert (d != end_delayed); const reference ref = *d++; const unsigned blocking = watch.blocking.lit; LOGREF3 (ref, "watching %s blocking %s in", LOGLIT (lit), @@ -36,10 +36,10 @@ static inline clause *PROPAGATE_LITERAL (kissat *solver, const clause *const ignore, #endif const unsigned lit) { - assert (solver->watching); + KISSAT_assert (solver->watching); LOG (PROPAGATION_TYPE " propagating %s", LOGLIT (lit)); - assert (VALUE (lit) > 0); - assert (EMPTY_STACK (solver->delayed)); + KISSAT_assert (VALUE (lit) > 0); + KISSAT_assert (EMPTY_STACK (solver->delayed)); watches *const all_watches = solver->watches; ward *const arena = BEGIN_STACK (solver->arena); @@ -48,7 +48,7 @@ static inline clause *PROPAGATE_LITERAL (kissat *solver, const unsigned not_lit = NOT (lit); - assert (not_lit < LITS); + KISSAT_assert (not_lit < LITS); watches *watches = all_watches + not_lit; watch *const begin_watches = BEGIN_WATCHES (*watches); @@ -58,7 +58,7 @@ static inline clause *PROPAGATE_LITERAL (kissat *solver, const watch *p = q; unsigneds *const delayed = &solver->delayed; - assert (EMPTY_STACK (*delayed)); + KISSAT_assert (EMPTY_STACK (*delayed)); const size_t size_watches = SIZE_WATCHES (*watches); uint64_t ticks = 1 + kissat_cache_lines (size_watches, sizeof (watch)); @@ -71,7 +71,7 @@ static inline clause *PROPAGATE_LITERAL (kissat *solver, while (p != end_watches) { const watch head = *q++ = *p++; const unsigned blocking = head.blocking.lit; - assert (VALID_INTERNAL_LITERAL (blocking)); + KISSAT_assert (VALID_INTERNAL_LITERAL (blocking)); const value blocking_value = values[blocking]; const bool binary = head.type.binary; watch tail; @@ -86,14 +86,14 @@ static inline clause *PROPAGATE_LITERAL (kissat *solver, break; #endif } else { - assert (!blocking_value); + KISSAT_assert (!blocking_value); kissat_fast_binary_assign (solver, probing, level, values, assigned, blocking, not_lit); ticks++; } } else { const reference ref = tail.raw; - assert (ref < SIZE_STACK (solver->arena)); + KISSAT_assert (ref < SIZE_STACK (solver->arena)); clause *const c = (clause *) (arena + ref); ticks++; if (c->garbage) { @@ -102,10 +102,10 @@ static inline clause *PROPAGATE_LITERAL (kissat *solver, } unsigned *const lits = BEGIN_LITS (c); const unsigned other = lits[0] ^ lits[1] ^ not_lit; - assert (lits[0] != lits[1]); - assert (VALID_INTERNAL_LITERAL (other)); - assert (not_lit != other); - assert (lit != other); + KISSAT_assert (lits[0] != lits[1]); + KISSAT_assert (VALID_INTERNAL_LITERAL (other)); + KISSAT_assert (not_lit != other); + KISSAT_assert (lit != other); const value other_value = values[other]; if (other_value > 0) { q[-2].blocking.lit = other; @@ -113,13 +113,13 @@ static inline clause *PROPAGATE_LITERAL (kissat *solver, } const unsigned *const end_lits = lits + c->size; unsigned *const searched = lits + c->searched; - assert (c->lits + 2 <= searched); - assert (searched < end_lits); + KISSAT_assert (c->lits + 2 <= searched); + KISSAT_assert (searched < end_lits); unsigned *r, replacement = INVALID_LIT; value replacement_value = -1; for (r = searched; r != end_lits; r++) { replacement = *r; - assert (VALID_INTERNAL_LITERAL (replacement)); + KISSAT_assert (VALID_INTERNAL_LITERAL (replacement)); replacement_value = values[replacement]; if (replacement_value >= 0) break; @@ -127,7 +127,7 @@ static inline clause *PROPAGATE_LITERAL (kissat *solver, if (replacement_value < 0) { for (r = lits + 2; r != searched; r++) { replacement = *r; - assert (VALID_INTERNAL_LITERAL (replacement)); + KISSAT_assert (VALID_INTERNAL_LITERAL (replacement)); replacement_value = values[replacement]; if (replacement_value >= 0) break; @@ -136,20 +136,20 @@ static inline clause *PROPAGATE_LITERAL (kissat *solver, if (replacement_value >= 0) { c->searched = r - lits; - assert (replacement != INVALID_LIT); + KISSAT_assert (replacement != INVALID_LIT); LOGREF3 (ref, "unwatching %s in", LOGLIT (not_lit)); q -= 2; lits[0] = other; lits[1] = replacement; - assert (lits[0] != lits[1]); + KISSAT_assert (lits[0] != lits[1]); *r = not_lit; kissat_delay_watching_large (solver, delayed, replacement, other, ref); ticks++; } else if (other_value) { - assert (replacement_value < 0); - assert (blocking_value < 0); - assert (other_value < 0); + KISSAT_assert (replacement_value < 0); + KISSAT_assert (blocking_value < 0); + KISSAT_assert (other_value < 0); #if defined(PROBING_PROPAGATION) if (c == ignore) { LOGREF (ref, "conflicting but ignored"); @@ -162,7 +162,7 @@ static inline clause *PROPAGATE_LITERAL (kissat *solver, break; #endif } else { - assert (replacement_value < 0); + KISSAT_assert (replacement_value < 0); #if defined(PROBING_PROPAGATION) if (c == ignore) { LOGREF (ref, "forcing %s but ignored", LOGLIT (other)); diff --git a/src/sat/kissat/proprobe.c b/src/sat/kissat/proprobe.c index e95873317..f75799ed4 100644 --- a/src/sat/kissat/proprobe.c +++ b/src/sat/kissat/proprobe.c @@ -2,6 +2,8 @@ #include "fastassign.h" #include "trail.h" +ABC_NAMESPACE_IMPL_START + #define PROPAGATE_LITERAL probing_propagate_literal #define PROPAGATION_TYPE "probing" #define PROBING_PROPAGATION @@ -34,9 +36,9 @@ static void update_probing_propagation_statistics (kissat *solver, clause *kissat_probing_propagate (kissat *solver, clause *ignore, bool flush) { - assert (solver->probing); - assert (solver->watching); - assert (!solver->inconsistent); + KISSAT_assert (solver->probing); + KISSAT_assert (solver->watching); + KISSAT_assert (!solver->inconsistent); START (propagate); @@ -57,3 +59,5 @@ clause *kissat_probing_propagate (kissat *solver, clause *ignore, return conflict; } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/proprobe.h b/src/sat/kissat/proprobe.h index 9fbebe8cc..327c8bd01 100644 --- a/src/sat/kissat/proprobe.h +++ b/src/sat/kissat/proprobe.h @@ -3,10 +3,15 @@ #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + struct kissat; struct clause; struct clause *kissat_probing_propagate (struct kissat *, struct clause *, bool flush); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/propsearch.c b/src/sat/kissat/propsearch.c index c1265301c..301bd02ca 100644 --- a/src/sat/kissat/propsearch.c +++ b/src/sat/kissat/propsearch.c @@ -3,6 +3,8 @@ #include "print.h" #include "trail.h" +ABC_NAMESPACE_IMPL_START + #define PROPAGATE_LITERAL search_propagate_literal #define PROPAGATION_TYPE "search" @@ -11,7 +13,7 @@ static inline void update_search_propagation_statistics (kissat *solver, const unsigned *saved_propagate) { - assert (saved_propagate <= solver->propagate); + KISSAT_assert (saved_propagate <= solver->propagate); const unsigned propagated = solver->propagate - saved_propagate; LOG ("propagated %u literals", propagated); @@ -42,9 +44,9 @@ static clause *search_propagate (kissat *solver) { } clause *kissat_search_propagate (kissat *solver) { - assert (!solver->probing); - assert (solver->watching); - assert (!solver->inconsistent); + KISSAT_assert (!solver->probing); + KISSAT_assert (solver->watching); + KISSAT_assert (!solver->inconsistent); START (propagate); @@ -69,3 +71,5 @@ clause *kissat_search_propagate (kissat *solver) { return conflict; } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/propsearch.h b/src/sat/kissat/propsearch.h index a774d9c5b..c932e66fb 100644 --- a/src/sat/kissat/propsearch.h +++ b/src/sat/kissat/propsearch.h @@ -1,9 +1,14 @@ #ifndef _propsearch_h_INCLUDED #define _propsearch_h_INCLUDED +#include "global.h" +ABC_NAMESPACE_HEADER_START + struct kissat; struct clause; struct clause *kissat_search_propagate (struct kissat *); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/queue.c b/src/sat/kissat/queue.c index f64dfe2a3..14deb0c6f 100644 --- a/src/sat/kissat/queue.c +++ b/src/sat/kissat/queue.c @@ -2,12 +2,14 @@ #include "inlinequeue.h" #include "print.h" +ABC_NAMESPACE_IMPL_START + void kissat_init_queue (kissat *solver) { queue *queue = &solver->queue; queue->first = queue->last = DISCONNECT; - assert (!queue->stamp); + KISSAT_assert (!queue->stamp); queue->search.idx = DISCONNECT; - assert (!queue->search.stamp); + KISSAT_assert (!queue->search.stamp); } void kissat_reset_search_of_queue (kissat *solver) { @@ -15,7 +17,7 @@ void kissat_reset_search_of_queue (kissat *solver) { queue *queue = &solver->queue; links *links = solver->links; const unsigned last = queue->last; - assert (!DISCONNECTED (last)); + KISSAT_assert (!DISCONNECTED (last)); kissat_update_queue (solver, links, last); } @@ -34,7 +36,7 @@ void kissat_reassign_queue_stamps (kissat *solver) { queue->search.stamp = links[queue->search.idx].stamp; } -#if defined(CHECK_QUEUE) && !defined(NDEBUG) +#if defined(CHECK_QUEUE) && !defined(KISSAT_NDEBUG) void kissat_check_queue (kissat *solver) { links *links = solver->links; queue *queue = &solver->queue; @@ -43,13 +45,15 @@ void kissat_check_queue (kissat *solver) { for (unsigned idx = queue->first, prev = DISCONNECT; !DISCONNECTED (idx); idx = links[idx].next) { if (!DISCONNECTED (prev)) - assert (links[prev].stamp < links[idx].stamp); + KISSAT_assert (links[prev].stamp < links[idx].stamp); if (focused && passed_search_idx) - assert (VALUE (LIT (idx))); + KISSAT_assert (VALUE (LIT (idx))); if (idx == queue->search.idx) passed_search_idx = true; } if (!DISCONNECTED (queue->search.idx)) - assert (links[queue->search.idx].stamp == queue->search.stamp); + KISSAT_assert (links[queue->search.idx].stamp == queue->search.stamp); } #endif + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/queue.h b/src/sat/kissat/queue.h index 271e7e567..c6e40ebe1 100644 --- a/src/sat/kissat/queue.h +++ b/src/sat/kissat/queue.h @@ -1,6 +1,9 @@ #ifndef _queue_h_INCLUDED #define _queue_h_INCLUDED +#include "global.h" +ABC_NAMESPACE_HEADER_START + #define DISCONNECT UINT_MAX #define DISCONNECTED(IDX) ((int) (IDX) < 0) @@ -25,9 +28,9 @@ void kissat_init_queue (struct kissat *); void kissat_reset_search_of_queue (struct kissat *); void kissat_reassign_queue_stamps (struct kissat *); -#define LINK(IDX) (solver->links[assert ((IDX) < VARS), (IDX)]) +#define LINK(IDX) (solver->links[KISSAT_assert ((IDX) < VARS), (IDX)]) -#if defined(CHECK_QUEUE) && !defined(NDEBUG) +#if defined(CHECK_QUEUE) && !defined(KISSAT_NDEBUG) void kissat_check_queue (struct kissat *); #else #define kissat_check_queue(...) \ @@ -35,4 +38,6 @@ void kissat_check_queue (struct kissat *); } while (0) #endif +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/random.h b/src/sat/kissat/random.h index 7f00fbf99..5a8057950 100644 --- a/src/sat/kissat/random.h +++ b/src/sat/kissat/random.h @@ -5,6 +5,9 @@ #include #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + typedef uint64_t generator; static inline uint64_t kissat_next_random64 (generator *rng) { @@ -19,17 +22,17 @@ static inline unsigned kissat_next_random32 (generator *rng) { static inline unsigned kissat_pick_random (generator *rng, unsigned l, unsigned r) { - assert (l <= r); + KISSAT_assert (l <= r); if (l == r) return l; const unsigned delta = r - l; const unsigned tmp = kissat_next_random32 (rng); const double fraction = tmp / 4294967296.0; - assert (0 <= fraction), assert (fraction < 1); + KISSAT_assert (0 <= fraction), KISSAT_assert (fraction < 1); const unsigned scaled = delta * fraction; - assert (scaled < delta); + KISSAT_assert (scaled < delta); const unsigned res = l + scaled; - assert (l <= res), assert (res < r); + KISSAT_assert (l <= res), KISSAT_assert (res < r); return res; } @@ -41,4 +44,6 @@ static inline double kissat_pick_double (generator *rng) { return kissat_next_random32 (rng) / 4294967296.0; } +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/rank.h b/src/sat/kissat/rank.h index 283536536..08ac1e8e8 100644 --- a/src/sat/kissat/rank.h +++ b/src/sat/kissat/rank.h @@ -5,17 +5,20 @@ #include -#ifdef NDEBUG +#include "global.h" +ABC_NAMESPACE_HEADER_START + +#ifdef KISSAT_NDEBUG #define CHECK_RANKED(...) \ do { \ } while (0) #else #define CHECK_RANKED(N, A, RANK) \ do { \ - assert (0 < (N)); \ + KISSAT_assert (0 < (N)); \ for (size_t I_CHECK_RANKED = 0; I_CHECK_RANKED < N - 1; \ I_CHECK_RANKED++) \ - assert (RANK (A[I_CHECK_RANKED]) <= RANK (A[I_CHECK_RANKED + 1])); \ + KISSAT_assert (RANK (A[I_CHECK_RANKED]) <= RANK (A[I_CHECK_RANKED + 1])); \ } while (0) #endif @@ -33,7 +36,7 @@ const size_t WIDTH_RADIX = (1 << LENGTH_RADIX); \ const RTYPE MASK_RADIX = WIDTH_RADIX - 1; \ \ - size_t COUNT_RADIX[WIDTH_RADIX]; \ + size_t COUNT_RADIX[256]; \ \ VTYPE *TMP_RADIX = 0; \ const size_t BYTES_TMP_RADIX = N_RADIX * sizeof (VTYPE); \ @@ -100,12 +103,12 @@ } \ \ if (!TMP_RADIX) { \ - assert (C_RADIX == A_RADIX); \ - TMP_RADIX = kissat_malloc (solver, BYTES_TMP_RADIX); \ + KISSAT_assert (C_RADIX == A_RADIX); \ + TMP_RADIX = (VTYPE*)kissat_malloc (solver, BYTES_TMP_RADIX); \ B_RADIX = TMP_RADIX; \ } \ \ - assert (B_RADIX == TMP_RADIX); \ + KISSAT_assert (B_RADIX == TMP_RADIX); \ \ VTYPE *D_RADIX = (C_RADIX == A_RADIX) ? B_RADIX : A_RADIX; \ \ @@ -137,4 +140,6 @@ RADIX_SORT (VTYPE, RTYPE, N_RADIX_STACK, A_RADIX_STACK, RANK); \ } while (0) +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/reduce.c b/src/sat/kissat/reduce.c index 027798520..8d8716cc3 100644 --- a/src/sat/kissat/reduce.c +++ b/src/sat/kissat/reduce.c @@ -11,10 +11,12 @@ #include #include +ABC_NAMESPACE_IMPL_START + bool kissat_reducing (kissat *solver) { if (!GET_OPTION (reduce)) return false; - if (!solver->statistics.clauses_redundant) + if (!solver->statistics_.clauses_redundant) return false; if (CONFLICTS < solver->limits.reduce.conflicts) return false; @@ -36,12 +38,12 @@ typedef STACK (reducible) reducibles; static bool collect_reducibles (kissat *solver, reducibles *reds, reference start_ref) { - assert (start_ref != INVALID_REF); - assert (start_ref <= SIZE_STACK (solver->arena)); + KISSAT_assert (start_ref != INVALID_REF); + KISSAT_assert (start_ref <= SIZE_STACK (solver->arena)); ward *const arena = BEGIN_STACK (solver->arena); clause *start = (clause *) (arena + start_ref); const clause *const end = (clause *) END_STACK (solver->arena); - assert (start < end); + KISSAT_assert (start < end); while (start != end && !start->redundant) start = kissat_next_clause (start); if (start == end) { @@ -61,7 +63,7 @@ static bool collect_reducibles (kissat *solver, reducibles *reds, solver->first_reducible = redundant; const unsigned tier1 = TIER1; const unsigned tier2 = MAX (tier1, TIER2); - assert (tier1 <= tier2); + KISSAT_assert (tier1 <= tier2); for (clause *c = start; c != end; c = kissat_next_clause (c)) { if (!c->redundant) continue; @@ -77,7 +79,7 @@ static bool collect_reducibles (kissat *solver, reducibles *reds, continue; if (glue <= tier2 && used >= MAX_USED - 1) continue; - assert (kissat_clause_in_arena (solver, c)); + KISSAT_assert (kissat_clause_in_arena (solver, c)); reducible red; const uint64_t negative_size = ~c->size; const uint64_t negative_glue = ~c->glue; @@ -101,7 +103,7 @@ static void sort_reducibles (kissat *solver, reducibles *reds) { static void mark_less_useful_clauses_as_garbage (kissat *solver, reducibles *reds) { - statistics *statistics = &solver->statistics; + statistics *statistics = &solver->statistics_; const double high = GET_OPTION (reducehigh) * 0.1; const double low = GET_OPTION (reducelow) * 0.1; double percent; @@ -113,7 +115,7 @@ static void mark_less_useful_clauses_as_garbage (kissat *solver, const double fraction = percent / 100.0; const size_t size = SIZE_STACK (*reds); size_t target = size * fraction; -#ifndef QUIET +#ifndef KISSAT_QUIET const size_t clauses = statistics->clauses_irredundant + statistics->clauses_redundant; kissat_phase (solver, "reduce", GET (reductions), @@ -130,10 +132,10 @@ static void mark_less_useful_clauses_as_garbage (kissat *solver, const unsigned tier2 = TIER2; for (const reducible *p = begin; p != end && target--; p++) { clause *c = (clause *) (arena + p->ref); - assert (kissat_clause_in_arena (solver, c)); - assert (!c->garbage); - assert (!c->reason); - assert (c->redundant); + KISSAT_assert (kissat_clause_in_arena (solver, c)); + KISSAT_assert (!c->garbage); + KISSAT_assert (!c->reason); + KISSAT_assert (c->redundant); LOGCLS (c, "reducing"); kissat_mark_clause_as_garbage (solver, c); reduced++; @@ -160,7 +162,7 @@ int kissat_reduce (kissat *solver) { bool compact = kissat_compacting (solver); reference start = compact ? 0 : solver->first_reducible; if (start != INVALID_REF) { -#ifndef QUIET +#ifndef KISSAT_QUIET size_t arena_size = SIZE_STACK (solver->arena); size_t words_to_sweep = arena_size - start; size_t bytes_to_sweep = sizeof (word) * words_to_sweep; @@ -186,7 +188,7 @@ int kissat_reduce (kissat *solver) { else kissat_unmark_reason_clauses (solver, start); } else - assert (solver->inconsistent); + KISSAT_assert (solver->inconsistent); } else kissat_phase (solver, "reduce", GET (reductions), "nothing to reduce"); kissat_classify (solver); @@ -196,3 +198,5 @@ int kissat_reduce (kissat *solver) { STOP (reduce); return solver->inconsistent ? 20 : 0; } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/reduce.h b/src/sat/kissat/reduce.h index c82c0481d..134e654c3 100644 --- a/src/sat/kissat/reduce.h +++ b/src/sat/kissat/reduce.h @@ -3,9 +3,14 @@ #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + struct kissat; bool kissat_reducing (struct kissat *); int kissat_reduce (struct kissat *); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/reference.h b/src/sat/kissat/reference.h index 028fc4b5f..437ad8642 100644 --- a/src/sat/kissat/reference.h +++ b/src/sat/kissat/reference.h @@ -3,6 +3,9 @@ #include "stack.h" +#include "global.h" +ABC_NAMESPACE_HEADER_START + typedef unsigned reference; #define REFERENCE_FORMAT "u" @@ -16,4 +19,6 @@ typedef unsigned reference; typedef STACK (reference) references; // clang-format on +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/reluctant.c b/src/sat/kissat/reluctant.c index 54b4558e5..ddab37c45 100644 --- a/src/sat/kissat/reluctant.c +++ b/src/sat/kissat/reluctant.c @@ -1,6 +1,8 @@ #include "internal.h" #include "logging.h" +ABC_NAMESPACE_IMPL_START + void kissat_enable_reluctant (reluctant *reluctant, uint64_t period, uint64_t limit) { if (limit && period > limit) @@ -24,7 +26,7 @@ void kissat_tick_reluctant (reluctant *reluctant) { if (reluctant->trigger) return; - assert (reluctant->wait > 0); + KISSAT_assert (reluctant->wait > 0); if (--reluctant->wait) return; @@ -35,12 +37,12 @@ void kissat_tick_reluctant (reluctant *reluctant) { u++; v = 1; } else { - assert (UINT64_MAX / 2 >= v); + KISSAT_assert (UINT64_MAX / 2 >= v); v *= 2; } - assert (v); - assert (UINT64_MAX / v >= reluctant->period); + KISSAT_assert (v); + KISSAT_assert (UINT64_MAX / v >= reluctant->period); uint64_t wait = v * reluctant->period; if (reluctant->limited && wait > reluctant->limit) { @@ -65,3 +67,5 @@ void kissat_init_reluctant (kissat *solver) { kissat_disable_reluctant (&solver->reluctant); } } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/reluctant.h b/src/sat/kissat/reluctant.h index 93513aabe..1ee419f56 100644 --- a/src/sat/kissat/reluctant.h +++ b/src/sat/kissat/reluctant.h @@ -4,6 +4,9 @@ #include #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + typedef struct reluctant reluctant; struct reluctant { @@ -30,4 +33,6 @@ struct kissat; void kissat_init_reluctant (struct kissat *); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/reorder.c b/src/sat/kissat/reorder.c index e1d4fe8c5..fc04d3a9a 100644 --- a/src/sat/kissat/reorder.c +++ b/src/sat/kissat/reorder.c @@ -11,6 +11,8 @@ #include "report.h" #include "sort.h" +ABC_NAMESPACE_IMPL_START + bool kissat_reordering (kissat *solver) { if (!GET_OPTION (reorder)) return false; @@ -22,11 +24,11 @@ bool kissat_reordering (kissat *solver) { } static double *compute_weights (kissat *solver) { - double *weights = kissat_calloc (solver, LITS, sizeof *weights); + double *weights = (double*)kissat_calloc (solver, LITS, sizeof *weights); const unsigned max_size = GET_OPTION (reordermaxsize); LOG ("limiting weight computation to maximum clause size %u", max_size); - assert (2 <= max_size); - double *table = kissat_nalloc (solver, max_size + 1, sizeof *table); + KISSAT_assert (2 <= max_size); + double *table = (double*)kissat_nalloc (solver, max_size + 1, sizeof *table); { double weight = 1; for (unsigned size = 2; size <= max_size; size++) { @@ -35,7 +37,7 @@ static double *compute_weights (kissat *solver) { } } { - assert (!solver->level); + KISSAT_assert (!solver->level); const signed char *const values = solver->values; const clause *last = kissat_last_irredundant_clause (solver); for (all_clauses (c)) { @@ -46,20 +48,25 @@ static double *compute_weights (kissat *solver) { if (c->garbage) continue; unsigned size = 0; + int continue_with_next_clause = 0; for (all_literals_in_clause (lit, c)) { const signed char value = values[lit]; - if (value > 0) - goto CONTINUE_WITH_NEXT_CLAUSE; + if (value > 0) { + continue_with_next_clause = 1; + break; + } if (!value && size < max_size && ++size == max_size) break; } + if(continue_with_next_clause) { + continue; + } const double weight = table[size]; for (all_literals_in_clause (lit, c)) weights[lit] += weight; - CONTINUE_WITH_NEXT_CLAUSE:; } } - assert (solver->watching); + KISSAT_assert (solver->watching); { double weight = table[2]; kissat_dealloc (solver, table, max_size + 1, sizeof *table); @@ -161,13 +168,13 @@ static void sort_active_variables_by_weight (kissat *solver, static void reorder_focused (kissat *solver) { INC (reordered_focused); - assert (!solver->stable); + KISSAT_assert (!solver->stable); double *weights = compute_weights (solver); unsigneds sorted; sort_active_variables_by_weight (solver, &sorted, weights); kissat_dealloc (solver, weights, LITS, sizeof *weights); for (all_stack (unsigned, idx, sorted)) { - assert (ACTIVE (idx)); + KISSAT_assert (ACTIVE (idx)); kissat_move_to_front (solver, idx); } RELEASE_STACK (sorted); @@ -175,7 +182,7 @@ static void reorder_focused (kissat *solver) { static void reorder_stable (kissat *solver) { INC (reordered_stable); - assert (solver->stable); + KISSAT_assert (solver->stable); double *weights = compute_weights (solver); kissat_rescale_scores (solver); unsigneds sorted; @@ -183,7 +190,7 @@ static void reorder_stable (kissat *solver) { heap *scores = SCORES; while (!EMPTY_STACK (sorted)) { unsigned idx = POP_STACK (sorted); - assert (ACTIVE (idx)); + KISSAT_assert (ACTIVE (idx)); const double old_score = kissat_get_heap_score (scores, idx); const double weight = weights[idx]; const double new_score = old_score + weight; @@ -198,7 +205,7 @@ static void reorder_stable (kissat *solver) { void kissat_reorder (kissat *solver) { START (reorder); INC (reordered); - assert (!solver->level); + KISSAT_assert (!solver->level); kissat_phase (solver, "reorder", GET (reordered), "reorder limit %" PRIu64 " hit a after %" PRIu64 " conflicts in %s mode ", @@ -215,3 +222,5 @@ void kissat_reorder (kissat *solver) { REPORT (0, 'o'); STOP (reorder); } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/reorder.h b/src/sat/kissat/reorder.h index 24351927e..d26dd0721 100644 --- a/src/sat/kissat/reorder.h +++ b/src/sat/kissat/reorder.h @@ -3,9 +3,14 @@ #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + struct kissat; bool kissat_reordering (struct kissat *); void kissat_reorder (struct kissat *); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/rephase.c b/src/sat/kissat/rephase.c index 33783f675..00e0dfadb 100644 --- a/src/sat/kissat/rephase.c +++ b/src/sat/kissat/rephase.c @@ -11,6 +11,8 @@ #include #include +ABC_NAMESPACE_IMPL_START + static void kissat_reset_best_assigned (kissat *solver) { if (!solver->best_assigned) return; @@ -75,7 +77,7 @@ static char rephase_inverted (kissat *solver) { } static char rephase_walking (kissat *solver) { - assert (kissat_walking (solver)); + KISSAT_assert (kissat_walking (solver)); STOP (rephase); kissat_walk (solver); START (rephase); @@ -91,7 +93,7 @@ static char (*rephase_schedule[]) (kissat *) = { #define size_rephase_schedule \ (sizeof rephase_schedule / sizeof *rephase_schedule) -#ifndef QUIET +#ifndef KISSAT_QUIET static const char *rephase_type_as_string (char type) { if (type == 'B') @@ -100,7 +102,7 @@ static const char *rephase_type_as_string (char type) { return "inverted"; if (type == 'O') return "original"; - assert (type == 'W'); + KISSAT_assert (type == 'W'); return "walking"; } @@ -108,7 +110,7 @@ static const char *rephase_type_as_string (char type) { static char reset_phases (kissat *solver) { const uint64_t count = GET (rephased); - assert (count > 0); + KISSAT_assert (count > 0); const uint64_t select = (count - 1) % (uint64_t) size_rephase_schedule; const char type = rephase_schedule[select](solver); kissat_phase ( @@ -125,13 +127,15 @@ static char reset_phases (kissat *solver) { void kissat_rephase (kissat *solver) { kissat_backtrack_propagate_and_flush_trail (solver); - assert (!solver->inconsistent); + KISSAT_assert (!solver->inconsistent); START (rephase); INC (rephased); -#ifndef QUIET +#ifndef KISSAT_QUIET const char type = #endif reset_phases (solver); REPORT (0, type); STOP (rephase); } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/rephase.h b/src/sat/kissat/rephase.h index b59382e4e..4ab597866 100644 --- a/src/sat/kissat/rephase.h +++ b/src/sat/kissat/rephase.h @@ -3,9 +3,14 @@ #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + struct kissat; bool kissat_rephasing (struct kissat *); void kissat_rephase (struct kissat *); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/report.c b/src/sat/kissat/report.c index a9fc092b5..820774b96 100644 --- a/src/sat/kissat/report.c +++ b/src/sat/kissat/report.c @@ -1,4 +1,6 @@ -#ifndef QUIET +#include "global.h" + +#ifndef KISSAT_QUIET #include "report.h" #include "colors.h" @@ -58,7 +60,7 @@ void kissat_report (kissat *solver, bool verbose, char type) { REPORTS #undef REP // clang-format on - assert (p < line + sizeof line); + KISSAT_assert (p < line + sizeof line); TERMINAL (stdout, 1); if (!(solver->limits.reports++ % 20)) { #define ROWS 3 @@ -86,9 +88,9 @@ void kissat_report (kissat *solver, bool verbose, char type) { } while (0); REPORTS #undef REP - assert (i == n); + KISSAT_assert (i == n); for (unsigned j = 0; j < ROWS; j++) { - assert (r[j] < rows[j] + sizeof rows[j]); + KISSAT_assert (r[j] < rows[j] + sizeof rows[j]); *r[j] = 0; } if (solver->limits.reports > 1) diff --git a/src/sat/kissat/report.h b/src/sat/kissat/report.h index 744aea32a..9b6207890 100644 --- a/src/sat/kissat/report.h +++ b/src/sat/kissat/report.h @@ -1,7 +1,11 @@ #ifndef _report_h_INCLUDED #define _report_h_INCLUDED -#ifdef QUIET +#include "global.h" + +#ifdef KISSAT_QUIET + +ABC_NAMESPACE_HEADER_START #define REPORT(...) \ do { \ @@ -11,6 +15,8 @@ #include +ABC_NAMESPACE_HEADER_START + struct kissat; void kissat_report (struct kissat *, bool verbose, char type); @@ -19,4 +25,6 @@ void kissat_report (struct kissat *, bool verbose, char type); #endif +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/require.h b/src/sat/kissat/require.h index 9325c9b3f..d938691f3 100644 --- a/src/sat/kissat/require.h +++ b/src/sat/kissat/require.h @@ -1,6 +1,9 @@ #ifndef _require_h_INCLUDED #define _require_h_INCLUDED +#include "global.h" +ABC_NAMESPACE_HEADER_START + #define kissat_require(COND, ...) \ do { \ if ((COND)) \ @@ -24,7 +27,9 @@ kissat_require (TMP_IDX <= EXTERNAL_MAX_VAR, \ "invalid literal '%d' (variable larger than %d)", \ (LIT), EXTERNAL_MAX_VAR); \ - assert (VALID_EXTERNAL_LITERAL (LIT)); \ + KISSAT_assert (VALID_EXTERNAL_LITERAL (LIT)); \ } while (0) +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/resize.c b/src/sat/kissat/resize.c index 593d813c8..83306a772 100644 --- a/src/sat/kissat/resize.c +++ b/src/sat/kissat/resize.c @@ -6,11 +6,13 @@ #include #include +ABC_NAMESPACE_IMPL_START + #define NREALLOC_GENERIC(TYPE, NAME, ELEMENTS_PER_BLOCK) \ do { \ const size_t block_size = sizeof (TYPE); \ solver->NAME = \ - kissat_nrealloc (solver, solver->NAME, old_size, new_size, \ + (TYPE*) kissat_nrealloc (solver, solver->NAME, old_size, new_size, \ ELEMENTS_PER_BLOCK * block_size); \ } while (0) @@ -18,7 +20,7 @@ do { \ const size_t block_size = sizeof (TYPE); \ TYPE *NAME = \ - kissat_calloc (solver, ELEMENTS_PER_BLOCK * new_size, block_size); \ + (TYPE*) kissat_calloc (solver, ELEMENTS_PER_BLOCK * new_size, block_size); \ if (old_size) { \ const size_t bytes = ELEMENTS_PER_BLOCK * old_size * block_size; \ memcpy (NAME, solver->NAME, bytes); \ @@ -43,12 +45,12 @@ static void reallocate_trail (kissat *solver, unsigned old_size, unsigned new_size) { unsigned propagated = solver->propagate - BEGIN_ARRAY (solver->trail); - REALLOCATE_ARRAY (solver->trail, old_size, new_size); + REALLOCATE_ARRAY (unsigned, solver->trail, old_size, new_size); solver->propagate = BEGIN_ARRAY (solver->trail) + propagated; } void kissat_increase_size (kissat *solver, unsigned new_size) { - assert (solver->vars <= new_size); + KISSAT_assert (solver->vars <= new_size); const unsigned old_size = solver->size; if (old_size >= new_size) return; @@ -57,13 +59,13 @@ void kissat_increase_size (kissat *solver, unsigned new_size) { LOG ("%s before increasing size from %u to %u", FORMAT_BYTES (kissat_allocated (solver)), old_size, new_size); #endif - CREALLOC_VARIABLE_INDEXED (assigned, assigned); - CREALLOC_VARIABLE_INDEXED (flags, flags); - NREALLOC_VARIABLE_INDEXED (links, links); + CREALLOC_VARIABLE_INDEXED (struct assigned, assigned); + CREALLOC_VARIABLE_INDEXED (struct flags, flags); + NREALLOC_VARIABLE_INDEXED (struct links, links); CREALLOC_LITERAL_INDEXED (mark, marks); CREALLOC_LITERAL_INDEXED (value, values); - CREALLOC_LITERAL_INDEXED (watches, watches); + CREALLOC_LITERAL_INDEXED (struct vector, watches); reallocate_trail (solver, old_size, new_size); kissat_resize_heap (solver, SCORES, new_size); @@ -109,7 +111,7 @@ void kissat_decrease_size (kissat *solver) { void kissat_enlarge_variables (kissat *solver, unsigned new_vars) { if (solver->vars >= new_vars) return; - assert (new_vars <= INTERNAL_MAX_VAR + 1); + KISSAT_assert (new_vars <= INTERNAL_MAX_VAR + 1); LOG ("enlarging variables from %u to %u", solver->vars, new_vars); const size_t old_size = solver->size; if (old_size < new_vars) { @@ -120,14 +122,14 @@ void kissat_enlarge_variables (kissat *solver, unsigned new_vars) { new_size = new_vars; else { if (kissat_is_power_of_two (old_size)) { - assert (old_size <= UINT_MAX / 2); + KISSAT_assert (old_size <= UINT_MAX / 2); new_size = 2 * old_size; } else { - assert (1 < old_size); + KISSAT_assert (1 < old_size); new_size = 2; } while (new_size < new_vars) { - assert (new_size <= UINT_MAX / 2); + KISSAT_assert (new_size <= UINT_MAX / 2); new_size *= 2; } } @@ -135,3 +137,5 @@ void kissat_enlarge_variables (kissat *solver, unsigned new_vars) { } solver->vars = new_vars; } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/resize.h b/src/sat/kissat/resize.h index 089fe9394..55e578574 100644 --- a/src/sat/kissat/resize.h +++ b/src/sat/kissat/resize.h @@ -1,10 +1,15 @@ #ifndef _resize_h_INCLUDED #define _resize_h_INCLUDED +#include "global.h" +ABC_NAMESPACE_HEADER_START + struct kissat; void kissat_decrease_size (struct kissat *solver); void kissat_increase_size (struct kissat *, unsigned new_size); void kissat_enlarge_variables (struct kissat *, unsigned new_vars); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/resolve.c b/src/sat/kissat/resolve.c index 49567b768..f6b1e6902 100644 --- a/src/sat/kissat/resolve.c +++ b/src/sat/kissat/resolve.c @@ -7,9 +7,11 @@ #include #include +ABC_NAMESPACE_IMPL_START + static inline unsigned occurrences_literal (kissat *solver, unsigned lit, bool *update) { - assert (!solver->watching); + KISSAT_assert (!solver->watching); watches *watches = &WATCHES (lit); #ifdef LOGGING @@ -32,7 +34,7 @@ static inline unsigned occurrences_literal (kissat *solver, unsigned lit, if (head.type.binary) { const unsigned other = head.binary.lit; const value value = values[other]; - assert (value >= 0); + KISSAT_assert (value >= 0); if (value > 0) { kissat_eliminate_binary (solver, lit, other); q--; @@ -40,7 +42,7 @@ static inline unsigned occurrences_literal (kissat *solver, unsigned lit, res++; } else { const reference ref = head.large.ref; - assert (ref < SIZE_STACK (solver->arena)); + KISSAT_assert (ref < SIZE_STACK (solver->arena)); clause *const c = (struct clause *) (arena + ref); if (c->garbage) q--; @@ -76,10 +78,10 @@ static inline clause *watch_to_clause (kissat *solver, ward *const arena, res = tmp; } else { const reference ref = watch.large.ref; - assert (ref < SIZE_STACK (solver->arena)); + KISSAT_assert (ref < SIZE_STACK (solver->arena)); res = (struct clause *) (arena + ref); } -#ifdef NDEBUG +#ifdef KISSAT_NDEBUG (void) solver; #endif return res; @@ -109,7 +111,7 @@ static bool generate_resolvents (kissat *solver, unsigned lit, clause *const c = watch_to_clause (solver, arena, &tmp0, lit, watch0); if (c->garbage) { - assert (c != &tmp0); + KISSAT_assert (c != &tmp0); continue; } @@ -135,7 +137,7 @@ static bool generate_resolvents (kissat *solver, unsigned lit, for (all_literals_in_clause (other, c)) { if (other == lit) continue; - assert (!marks[other]); + KISSAT_assert (!marks[other]); marks[other] = 1; } @@ -144,7 +146,7 @@ static bool generate_resolvents (kissat *solver, unsigned lit, watch_to_clause (solver, arena, &tmp1, not_lit, watch1); if (d->garbage) { - assert (d != &tmp1); + KISSAT_assert (d != &tmp1); continue; } @@ -201,7 +203,7 @@ static bool generate_resolvents (kissat *solver, unsigned lit, if (other == lit) continue; const value value = values[other]; - assert (value <= 0); + KISSAT_assert (value <= 0); if (value < 0) { LOG2 ("dropping falsified literal %s", LOGLIT (other)); continue; @@ -214,7 +216,7 @@ static bool generate_resolvents (kissat *solver, unsigned lit, "resolvent"); if (!size_resolvent) { - assert (!solver->inconsistent); + KISSAT_assert (!solver->inconsistent); solver->inconsistent = true; LOG ("resolved empty clause"); CHECK_AND_ADD_EMPTY (); @@ -248,7 +250,7 @@ static bool generate_resolvents (kissat *solver, unsigned lit, for (all_literals_in_clause (other, c)) { if (other == lit) continue; - assert (marks[other] == 1); + KISSAT_assert (marks[other] == 1); marks[other] = 0; } @@ -368,3 +370,5 @@ bool kissat_generate_resolvents (kissat *solver, unsigned idx, return !failed; } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/resolve.h b/src/sat/kissat/resolve.h index 26bf7a0e9..dfa594ecc 100644 --- a/src/sat/kissat/resolve.h +++ b/src/sat/kissat/resolve.h @@ -3,9 +3,14 @@ #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + struct kissat; bool kissat_generate_resolvents (struct kissat *, unsigned idx, unsigned *lit_ptr); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/resources.c b/src/sat/kissat/resources.c index 31c0378af..82d398a90 100644 --- a/src/sat/kissat/resources.c +++ b/src/sat/kissat/resources.c @@ -1,15 +1,17 @@ #include "resources.h" -#include +//#include -double kissat_wall_clock_time (void) { - struct timeval tv; - if (gettimeofday (&tv, 0)) - return 0; - return 1e-6 * tv.tv_usec + tv.tv_sec; -} +ABC_NAMESPACE_IMPL_START -#ifndef QUIET +/* double kissat_wall_clock_time (void) { */ +/* struct timeval tv; */ +/* if (gettimeofday (&tv, 0)) */ +/* return 0; */ +/* return 1e-6 * tv.tv_usec + tv.tv_sec; */ +/* } */ + +#ifndef KISSAT_QUIET #include "internal.h" #include "statistics.h" @@ -102,3 +104,5 @@ void kissat_print_resources (kissat *solver) { } #endif + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/resources.h b/src/sat/kissat/resources.h index d9bce7853..e12635c52 100644 --- a/src/sat/kissat/resources.h +++ b/src/sat/kissat/resources.h @@ -1,9 +1,12 @@ #ifndef _resources_h_INCLUDED #define _resources_h_INCLUDED +#include "global.h" +ABC_NAMESPACE_HEADER_START + double kissat_wall_clock_time (void); -#ifndef QUIET +#ifndef KISSAT_QUIET #ifndef _resources_h_INLCUDED #define _resources_h_INLCUDED @@ -20,4 +23,6 @@ void kissat_print_resources (struct kissat *); #endif #endif +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/restart.c b/src/sat/kissat/restart.c index dc4edf634..12ce99bf7 100644 --- a/src/sat/kissat/restart.c +++ b/src/sat/kissat/restart.c @@ -11,8 +11,10 @@ #include +ABC_NAMESPACE_IMPL_START + bool kissat_restarting (kissat *solver) { - assert (solver->unassigned); + KISSAT_assert (solver->unassigned); if (!GET_OPTION (restart)) return false; if (!solver->level) @@ -37,9 +39,9 @@ bool kissat_restarting (kissat *solver) { } void kissat_update_focused_restart_limit (kissat *solver) { - assert (!solver->stable); + KISSAT_assert (!solver->stable); limits *limits = &solver->limits; - uint64_t restarts = solver->statistics.restarts; + uint64_t restarts = solver->statistics_.restarts; uint64_t delta = GET_OPTION (restartint); if (restarts) delta += kissat_logn (restarts) - 1; @@ -84,8 +86,8 @@ static unsigned reuse_focused_trail (kissat *solver) { } static unsigned reuse_trail (kissat *solver) { - assert (solver->level); - assert (!EMPTY_STACK (solver->trail)); + KISSAT_assert (solver->level); + KISSAT_assert (!EMPTY_STACK (solver->trail)); if (!GET_OPTION (restartreusetrail)) return 0; @@ -129,3 +131,5 @@ void kissat_restart (kissat *solver) { REPORT (1, 'R'); STOP (restart); } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/restart.h b/src/sat/kissat/restart.h index c17ab6499..7df4d64b5 100644 --- a/src/sat/kissat/restart.h +++ b/src/sat/kissat/restart.h @@ -1,6 +1,9 @@ #ifndef _restart_h_INCLUDED #define _restart_h_INCLUDED +#include "global.h" +ABC_NAMESPACE_HEADER_START + #include struct kissat; @@ -10,4 +13,6 @@ void kissat_restart (struct kissat *); void kissat_update_focused_restart_limit (struct kissat *); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/search.c b/src/sat/kissat/search.c index 77f44ad99..ed283f50a 100644 --- a/src/sat/kissat/search.c +++ b/src/sat/kissat/search.c @@ -24,10 +24,12 @@ #include +ABC_NAMESPACE_IMPL_START + static void init_tiers (kissat *solver) { for (unsigned stable = 0; stable != 2; stable++) { if (!solver->tier1[stable]) { - assert (!solver->tier2[stable]); + KISSAT_assert (!solver->tier2[stable]); solver->tier1[stable] = GET_OPTION (tier1); solver->tier2[stable] = GET_OPTION (tier2); if (solver->tier2[stable] <= solver->tier1[stable]) @@ -70,7 +72,7 @@ static void start_search (kissat *solver) { solver->random = seed; LOG ("initialized random number generator with seed %u", seed); -#ifndef QUIET +#ifndef KISSAT_QUIET limits *limits = &solver->limits; limited *limited = &solver->limited; if (!limited->conflicts && !limited->decisions) @@ -127,7 +129,7 @@ static void stop_search (kissat *solver) { } static void report_search_result (kissat *solver, int res) { -#ifndef QUIET +#ifndef KISSAT_QUIET LOG ("search result %d", res); char type = (res == 10 ? '1' : res == 20 ? '0' : '?'); REPORT (0, type); @@ -137,7 +139,7 @@ static void report_search_result (kissat *solver, int res) { } static void iterate (kissat *solver) { - assert (solver->iterating); + KISSAT_assert (solver->iterating); solver->iterating = false; REPORT (0, 'i'); } @@ -145,22 +147,22 @@ static void iterate (kissat *solver) { static bool conflict_limit_hit (kissat *solver) { if (!solver->limited.conflicts) return false; - if (solver->limits.conflicts > solver->statistics.conflicts) + if (solver->limits.conflicts > solver->statistics_.conflicts) return false; kissat_very_verbose ( solver, "conflict limit %" PRIu64 " hit after %" PRIu64 " conflicts", - solver->limits.conflicts, solver->statistics.conflicts); + solver->limits.conflicts, solver->statistics_.conflicts); return true; } static bool decision_limit_hit (kissat *solver) { if (!solver->limited.decisions) return false; - if (solver->limits.decisions > solver->statistics.decisions) + if (solver->limits.decisions > solver->statistics_.decisions) return false; kissat_very_verbose ( solver, "decision limit %" PRIu64 " hit after %" PRIu64 " decisions", - solver->limits.decisions, solver->statistics.decisions); + solver->limits.decisions, solver->statistics_.decisions); return true; } @@ -227,3 +229,5 @@ int kissat_search (kissat *solver) { report_search_result (solver, res); return res; } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/search.h b/src/sat/kissat/search.h index b7f17f894..33645269e 100644 --- a/src/sat/kissat/search.h +++ b/src/sat/kissat/search.h @@ -1,8 +1,13 @@ #ifndef _search_h_INCLUDED #define _search_h_INCLUDED +#include "global.h" +ABC_NAMESPACE_HEADER_START + struct kissat; int kissat_search (struct kissat *); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/shrink.c b/src/sat/kissat/shrink.c index d0614df97..e368cc8bc 100644 --- a/src/sat/kissat/shrink.c +++ b/src/sat/kissat/shrink.c @@ -3,6 +3,8 @@ #include "inline.h" #include "minimize.h" +ABC_NAMESPACE_IMPL_START + static void reset_shrinkable (kissat *solver) { #ifdef LOGGING size_t reset = 0; @@ -10,7 +12,7 @@ static void reset_shrinkable (kissat *solver) { while (!EMPTY_STACK (solver->shrinkable)) { const unsigned idx = POP_STACK (solver->shrinkable); assigned *a = solver->assigned + idx; - assert (a->shrinkable); + KISSAT_assert (a->shrinkable); a->shrinkable = false; #ifdef LOGGING reset++; @@ -27,9 +29,9 @@ static void mark_shrinkable_as_removable (kissat *solver) { while (!EMPTY_STACK (solver->shrinkable)) { const unsigned idx = POP_STACK (solver->shrinkable); struct assigned *a = assigned + idx; - assert (a->shrinkable); + KISSAT_assert (a->shrinkable); a->shrinkable = false; - assert (!a->poisoned); + KISSAT_assert (!a->poisoned); #ifdef LOGGING reset++; #endif @@ -46,12 +48,12 @@ static void mark_shrinkable_as_removable (kissat *solver) { static inline int shrink_literal (kissat *solver, assigned *assigned, unsigned level, unsigned lit) { - assert (solver->assigned == assigned); - assert (VALUE (lit) < 0); + KISSAT_assert (solver->assigned == assigned); + KISSAT_assert (VALUE (lit) < 0); const unsigned idx = IDX (lit); struct assigned *a = assigned + idx; - assert (a->level <= level); + KISSAT_assert (a->level <= level); if (!a->level) { LOG2 ("skipping root level assigned %s", LOGLIT (lit)); return 0; @@ -84,17 +86,17 @@ static inline int shrink_literal (kissat *solver, assigned *assigned, static inline unsigned shrunken_block (kissat *solver, unsigned level, unsigned *begin_block, unsigned *end_block, unsigned uip) { - assert (uip != INVALID_LIT); + KISSAT_assert (uip != INVALID_LIT); const unsigned not_uip = NOT (uip); LOG ("found unique implication point %s on level %u", LOGLIT (uip), level); - assert (begin_block < end_block); -#if defined(LOGGING) || !defined(NDEBUG) + KISSAT_assert (begin_block < end_block); +#if defined(LOGGING) || !defined(KISSAT_NDEBUG) const size_t tmp = end_block - begin_block; LOG ("shrinking %zu literals on level %u to single literal %s", tmp, level, LOGLIT (not_uip)); - assert (tmp > 1); + KISSAT_assert (tmp > 1); #endif #ifdef LOGGING @@ -116,7 +118,7 @@ static inline unsigned shrunken_block (kissat *solver, unsigned level, block_shrunken++; } *begin_block = not_uip; - assert (block_shrunken); + KISSAT_assert (block_shrunken); block_shrunken--; #ifdef LOGGING if (not_uip_was_in_clause) @@ -143,17 +145,17 @@ static inline void push_literals_of_block (kissat *solver, unsigned *begin_block, unsigned *end_block, unsigned level) { - assert (assigned == solver->assigned); + KISSAT_assert (assigned == solver->assigned); for (const unsigned *p = begin_block; p != end_block; p++) { const unsigned lit = *p; if (lit == INVALID_LIT) continue; -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG int tmp = #endif shrink_literal (solver, assigned, level, lit); - assert (tmp > 0); + KISSAT_assert (tmp > 0); } } @@ -161,7 +163,7 @@ static inline unsigned shrink_along_binary (kissat *solver, assigned *assigned, unsigned level, unsigned uip, unsigned other) { - assert (VALUE (other) < 0); + KISSAT_assert (VALUE (other) < 0); LOGBINARY2 (uip, other, "shrinking along %s reason", LOGLIT (uip)); int tmp = shrink_literal (solver, assigned, level, other); #ifndef LOGGING @@ -181,7 +183,7 @@ shrink_along_large (kissat *solver, assigned *assigned, unsigned level, for (all_literals_in_clause (other, c)) { if (other == uip) continue; - assert (VALUE (other) < 0); + KISSAT_assert (VALUE (other) < 0); int tmp = shrink_literal (solver, assigned, level, other); if (tmp < 0) { *failed_ptr = true; @@ -201,9 +203,9 @@ static inline unsigned shrink_along_reason (kissat *solver, unsigned open = 0; const unsigned uip_idx = IDX (uip); struct assigned *a = assigned + uip_idx; - assert (a->shrinkable); - assert (a->level == level); - assert (a->reason != DECISION_REASON); + KISSAT_assert (a->shrinkable); + KISSAT_assert (a->level == level); + KISSAT_assert (a->reason != DECISION_REASON); if (a->binary) { const unsigned other = a->reason; open = shrink_along_binary (solver, assigned, level, uip, other); @@ -223,7 +225,7 @@ static inline unsigned shrink_along_reason (kissat *solver, static inline unsigned shrink_block (kissat *solver, unsigned *begin_block, unsigned *end_block, unsigned level, unsigned max_trail) { - assert (level < solver->level); + KISSAT_assert (level < solver->level); unsigned open = end_block - begin_block; @@ -234,7 +236,7 @@ static inline unsigned shrink_block (kissat *solver, unsigned *begin_block, push_literals_of_block (solver, assigned, begin_block, end_block, level); - assert (SIZE_STACK (solver->shrinkable) == open); + KISSAT_assert (SIZE_STACK (solver->shrinkable) == open); const unsigned *const begin_trail = BEGIN_ARRAY (solver->trail); @@ -247,14 +249,14 @@ static inline unsigned shrink_block (kissat *solver, unsigned *begin_block, while (!failed) { { do - assert (begin_trail <= t), uip = *t--; + KISSAT_assert (begin_trail <= t), uip = *t--; while (!assigned[IDX (uip)].shrinkable); } if (open == 1) break; open += shrink_along_reason (solver, assigned, level, uip, resolve_large_clauses, &failed); - assert (open > 1); + KISSAT_assert (open > 1); open--; } @@ -280,7 +282,7 @@ static unsigned *next_block (kissat *solver, unsigned *begin_lits, while (begin_lits < begin_block) { const unsigned lit = begin_block[-1]; - assert (lit != INVALID_LIT); + KISSAT_assert (lit != INVALID_LIT); const unsigned idx = IDX (lit); struct assigned *a = assigned + idx; unsigned lit_level = a->level; @@ -288,7 +290,7 @@ static unsigned *next_block (kissat *solver, unsigned *begin_lits, level = lit_level; LOG ("starting to shrink level %u", level); } else { - assert (lit_level >= level); + KISSAT_assert (lit_level >= level); if (lit_level > level) break; } @@ -310,7 +312,7 @@ static unsigned minimize_block (kissat *solver, unsigned *begin_block, for (unsigned *p = begin_block; p != end_block; p++) { const unsigned lit = *p; - assert (lit != INVALID_LIT); + KISSAT_assert (lit != INVALID_LIT); if (!kissat_minimize_literal (solver, lit, true)) continue; LOG ("minimize-shrunken literal %s", LOGLIT (lit)); @@ -325,7 +327,7 @@ static inline unsigned * minimize_and_shrink_block (kissat *solver, unsigned *begin_lits, unsigned *end_block, unsigned *total_shrunken, unsigned *total_minimized) { - assert (EMPTY_STACK (solver->shrinkable)); + KISSAT_assert (EMPTY_STACK (solver->shrinkable)); unsigned level, max_trail; @@ -333,7 +335,7 @@ minimize_and_shrink_block (kissat *solver, unsigned *begin_lits, next_block (solver, begin_lits, end_block, &level, &max_trail); unsigned open = end_block - begin_block; - assert (open > 0); + KISSAT_assert (open > 0); unsigned block_shrunken = 0; unsigned block_minimized = 0; @@ -358,9 +360,9 @@ minimize_and_shrink_block (kissat *solver, unsigned *begin_lits, } void kissat_shrink_clause (kissat *solver) { - assert (GET_OPTION (minimize) > 0); - assert (GET_OPTION (shrink) > 0); - assert (!EMPTY_STACK (solver->clause)); + KISSAT_assert (GET_OPTION (minimize) > 0); + KISSAT_assert (GET_OPTION (shrink) > 0); + KISSAT_assert (!EMPTY_STACK (solver->clause)); START (shrink); @@ -383,7 +385,7 @@ void kissat_shrink_clause (kissat *solver) { } LOG ("clause shrunken by %u literals (including %u minimized)", total_shrunken, total_minimized); - assert (q + total_shrunken == end_lits); + KISSAT_assert (q + total_shrunken == end_lits); SET_END_OF_STACK (solver->clause, q); ADD (literals_shrunken, total_shrunken); ADD (literals_minshrunken, total_minimized); @@ -393,3 +395,5 @@ void kissat_shrink_clause (kissat *solver) { STOP (shrink); } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/shrink.h b/src/sat/kissat/shrink.h index 662df06ee..f50fc911c 100644 --- a/src/sat/kissat/shrink.h +++ b/src/sat/kissat/shrink.h @@ -1,8 +1,13 @@ #ifndef _shrink_h_INCLUDED #define _shrink_h_INCLUDED +#include "global.h" +ABC_NAMESPACE_HEADER_START + struct kissat; void kissat_shrink_clause (struct kissat *); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/smooth.c b/src/sat/kissat/smooth.c index 487680f06..6129a7b83 100644 --- a/src/sat/kissat/smooth.c +++ b/src/sat/kissat/smooth.c @@ -2,16 +2,18 @@ #include "internal.h" #include "logging.h" +ABC_NAMESPACE_IMPL_START + void kissat_init_smooth (kissat *solver, smooth *smooth, int window, const char *name) { - assert (window > 0); + KISSAT_assert (window > 0); const double alpha = 1.0 / window; LOG ("initialized %s EMA alpha %g window %d", name, alpha, window); smooth->value = 0; smooth->biased = 0; smooth->alpha = alpha; smooth->beta = 1.0 - alpha; - assert (smooth->beta > 0); + KISSAT_assert (smooth->beta > 0); smooth->exp = 1.0; #ifdef LOGGING smooth->name = name; @@ -42,7 +44,7 @@ void kissat_update_smooth (kissat *solver, smooth *smooth, double y) { double new_exp, div, new_value; if (old_exp) { new_exp = old_exp * beta; - assert (new_exp < 1); + KISSAT_assert (new_exp < 1); if (new_exp == old_exp) { new_exp = 0; new_value = new_biased; @@ -51,7 +53,7 @@ void kissat_update_smooth (kissat *solver, smooth *smooth, double y) { #endif } else { div = 1 - new_exp; - assert (div > 0); + KISSAT_assert (div > 0); new_value = new_biased / div; } smooth->exp = new_exp; @@ -71,3 +73,5 @@ void kissat_update_smooth (kissat *solver, smooth *smooth, double y) { (void) solver; #endif } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/smooth.h b/src/sat/kissat/smooth.h index 11f2efe9f..2fe4f1464 100644 --- a/src/sat/kissat/smooth.h +++ b/src/sat/kissat/smooth.h @@ -3,6 +3,9 @@ #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + typedef struct smooth smooth; struct smooth { @@ -19,4 +22,6 @@ void kissat_init_smooth (struct kissat *, smooth *, int window, const char *); void kissat_update_smooth (struct kissat *, smooth *, double); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/sort.c b/src/sat/kissat/sort.c index ba1ea32b2..943a67ee4 100644 --- a/src/sat/kissat/sort.c +++ b/src/sat/kissat/sort.c @@ -1,13 +1,15 @@ #include "internal.h" #include "logging.h" +ABC_NAMESPACE_IMPL_START + static inline value move_smallest_literal_to_front (kissat *solver, const value *const values, const assigned *const assigned, bool satisfied_is_enough, unsigned start, unsigned size, unsigned *lits) { - assert (1 < size); - assert (start < size); + KISSAT_assert (1 < size); + KISSAT_assert (start < size); unsigned a = lits[start]; @@ -21,7 +23,7 @@ move_smallest_literal_to_front (kissat *solver, const value *const values, const unsigned i = IDX (a); unsigned k = (u ? assigned[i].level : UINT_MAX); - assert (start < UINT_MAX); + KISSAT_assert (start < UINT_MAX); for (unsigned i = start + 1; i < size; i++) { const unsigned b = lits[i]; const value v = values[b]; @@ -43,12 +45,12 @@ move_smallest_literal_to_front (kissat *solver, const value *const values, else if (u > 0 && v < 0) better = false; else if (u < 0) { - assert (v < 0); + KISSAT_assert (v < 0); better = (k < l); } else { - assert (u > 0); - assert (v > 0); - assert (!satisfied_is_enough); + KISSAT_assert (u > 0); + KISSAT_assert (v > 0); + KISSAT_assert (!satisfied_is_enough); better = (k > l); } @@ -96,3 +98,5 @@ static inline move_smallest_literal_to_front (solver, values, assigned, (u >= 0), 1, size, lits); } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/sort.h b/src/sat/kissat/sort.h index 9e0e6ee94..a21aa4bba 100644 --- a/src/sat/kissat/sort.h +++ b/src/sat/kissat/sort.h @@ -3,6 +3,9 @@ #include "utilities.h" +#include "global.h" +ABC_NAMESPACE_HEADER_START + #define GREATER_SWAP(TYPE, P, Q, LESS) \ do { \ if (LESS (Q, P)) \ @@ -40,8 +43,8 @@ #define QUICK_SORT(TYPE, N, A, LESS) \ do { \ - assert (N); \ - assert (EMPTY_STACK (SORTER)); \ + KISSAT_assert (N); \ + KISSAT_assert (EMPTY_STACK (SORTER)); \ \ size_t L_QUICK_SORT = 0; \ size_t R_QUICK_SORT = N - 1; \ @@ -61,8 +64,8 @@ size_t I_QUICK_SORT; \ \ PARTITION (TYPE, L_QUICK_SORT + 1, R_QUICK_SORT - 1, A, LESS); \ - assert (L_QUICK_SORT < I_QUICK_SORT); \ - assert (I_QUICK_SORT <= R_QUICK_SORT); \ + KISSAT_assert (L_QUICK_SORT < I_QUICK_SORT); \ + KISSAT_assert (I_QUICK_SORT <= R_QUICK_SORT); \ \ size_t LL_QUICK_SORT; \ size_t RR_QUICK_SORT; \ @@ -77,7 +80,7 @@ L_QUICK_SORT = I_QUICK_SORT + 1; \ } \ if (R_QUICK_SORT - L_QUICK_SORT > QUICK_SORT_LIMIT) { \ - assert (RR_QUICK_SORT - LL_QUICK_SORT > QUICK_SORT_LIMIT); \ + KISSAT_assert (RR_QUICK_SORT - LL_QUICK_SORT > QUICK_SORT_LIMIT); \ PUSH_STACK (SORTER, LL_QUICK_SORT); \ PUSH_STACK (SORTER, RR_QUICK_SORT); \ } else if (RR_QUICK_SORT - LL_QUICK_SORT > QUICK_SORT_LIMIT) { \ @@ -116,7 +119,7 @@ } \ } while (0) -#ifdef NDEBUG +#ifdef KISSAT_NDEBUG #define CHECK_SORTED(...) \ do { \ } while (0) @@ -125,7 +128,7 @@ do { \ for (size_t I_CHECK_SORTED = 0; I_CHECK_SORTED < N - 1; \ I_CHECK_SORTED++) \ - assert (!LESS (A[I_CHECK_SORTED + 1], A[I_CHECK_SORTED])); \ + KISSAT_assert (!LESS (A[I_CHECK_SORTED + 1], A[I_CHECK_SORTED])); \ } while (0) #endif @@ -151,4 +154,6 @@ SORT (TYPE, N_SORT_STACK, A_SORT_STACK, LESS); \ } while (0) +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/stack.c b/src/sat/kissat/stack.c index 4fc7f3352..30689adc8 100644 --- a/src/sat/kissat/stack.c +++ b/src/sat/kissat/stack.c @@ -4,10 +4,12 @@ #include +ABC_NAMESPACE_IMPL_START + void kissat_stack_enlarge (struct kissat *solver, chars *s, size_t bytes) { const size_t size = SIZE_STACK (*s); const size_t old_bytes = CAPACITY_STACK (*s); - assert (MAX_SIZE_T / 2 >= old_bytes); + KISSAT_assert (MAX_SIZE_T / 2 >= old_bytes); size_t new_bytes; if (old_bytes) new_bytes = 2 * old_bytes; @@ -16,19 +18,19 @@ void kissat_stack_enlarge (struct kissat *solver, chars *s, size_t bytes) { while (!kissat_aligned_word (new_bytes)) new_bytes <<= 1; } - s->begin = kissat_realloc (solver, s->begin, old_bytes, new_bytes); + s->begin = (char*)kissat_realloc (solver, s->begin, old_bytes, new_bytes); s->allocated = s->begin + new_bytes; s->end = s->begin + size; } void kissat_shrink_stack (struct kissat *solver, chars *s, size_t bytes) { - assert (bytes > 0); + KISSAT_assert (bytes > 0); const size_t old_bytes_capacity = CAPACITY_STACK (*s); - assert (kissat_aligned_word (old_bytes_capacity)); - assert (!(old_bytes_capacity % bytes)); - assert (kissat_is_zero_or_power_of_two (old_bytes_capacity / bytes)); + KISSAT_assert (kissat_aligned_word (old_bytes_capacity)); + KISSAT_assert (!(old_bytes_capacity % bytes)); + KISSAT_assert (kissat_is_zero_or_power_of_two (old_bytes_capacity / bytes)); const size_t old_bytes_size = SIZE_STACK (*s); - assert (!(old_bytes_size % bytes)); + KISSAT_assert (!(old_bytes_size % bytes)); const size_t old_size = old_bytes_size / bytes; size_t new_capacity; if (old_size) { @@ -36,16 +38,18 @@ void kissat_shrink_stack (struct kissat *solver, chars *s, size_t bytes) { new_capacity = ((size_t) 1) << ld_old_size; } else new_capacity = 0; - assert (kissat_is_zero_or_power_of_two (new_capacity)); + KISSAT_assert (kissat_is_zero_or_power_of_two (new_capacity)); size_t new_bytes_capacity = new_capacity * bytes; while (!kissat_aligned_word (new_bytes_capacity)) new_bytes_capacity <<= 1; if (new_bytes_capacity == old_bytes_capacity) return; - assert (new_bytes_capacity < old_bytes_capacity); - s->begin = kissat_realloc (solver, s->begin, old_bytes_capacity, + KISSAT_assert (new_bytes_capacity < old_bytes_capacity); + s->begin = (char*)kissat_realloc (solver, s->begin, old_bytes_capacity, new_bytes_capacity); s->allocated = s->begin + new_bytes_capacity; s->end = s->begin + old_bytes_size; - assert (s->end <= s->allocated); + KISSAT_assert (s->end <= s->allocated); } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/stack.h b/src/sat/kissat/stack.h index 23e07f597..2024f5f3e 100644 --- a/src/sat/kissat/stack.h +++ b/src/sat/kissat/stack.h @@ -3,6 +3,9 @@ #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + #define STACK(TYPE) \ struct { \ TYPE *begin; \ @@ -20,21 +23,21 @@ (S).begin = (S).end = (S).allocated = 0; \ } while (0) -#define TOP_STACK(S) (END_STACK (S)[assert (!EMPTY_STACK (S)), -1]) +#define TOP_STACK(S) (END_STACK (S)[KISSAT_assert (!EMPTY_STACK (S)), -1]) #define PEEK_STACK(S, N) \ - (BEGIN_STACK (S)[assert ((N) < SIZE_STACK (S)), (N)]) + (BEGIN_STACK (S)[KISSAT_assert ((N) < SIZE_STACK (S)), (N)]) #define POKE_STACK(S, N, E) \ do { \ PEEK_STACK (S, N) = (E); \ } while (0) -#define POP_STACK(S) (assert (!EMPTY_STACK (S)), *--(S).end) +#define POP_STACK(S) (KISSAT_assert (!EMPTY_STACK (S)), *--(S).end) #define ENLARGE_STACK(S) \ do { \ - assert (FULL_STACK (S)); \ + KISSAT_assert (FULL_STACK (S)); \ kissat_stack_enlarge (solver, (chars *) &(S), sizeof *(S).begin); \ } while (0) @@ -63,14 +66,14 @@ #define RESIZE_STACK(S, NEW_SIZE) \ do { \ const size_t TMP_NEW_SIZE = (NEW_SIZE); \ - assert (TMP_NEW_SIZE <= SIZE_STACK (S)); \ + KISSAT_assert (TMP_NEW_SIZE <= SIZE_STACK (S)); \ (S).end = (S).begin + TMP_NEW_SIZE; \ } while (0) #define SET_END_OF_STACK(S, P) \ do { \ - assert (BEGIN_STACK (S) <= (P)); \ - assert ((P) <= END_STACK (S)); \ + KISSAT_assert (BEGIN_STACK (S) <= (P)); \ + KISSAT_assert ((P) <= END_STACK (S)); \ if ((P) == END_STACK (S)) \ break; \ (S).end = (P); \ @@ -84,12 +87,12 @@ #define REMOVE_STACK(T, S, E) \ do { \ - assert (!EMPTY_STACK (S)); \ + KISSAT_assert (!EMPTY_STACK (S)); \ T *END_REMOVE_STACK = END_STACK (S); \ T *P_REMOVE_STACK = BEGIN_STACK (S); \ while (*P_REMOVE_STACK != (E)) { \ P_REMOVE_STACK++; \ - assert (P_REMOVE_STACK != END_REMOVE_STACK); \ + KISSAT_assert (P_REMOVE_STACK != END_REMOVE_STACK); \ } \ P_REMOVE_STACK++; \ while (P_REMOVE_STACK != END_REMOVE_STACK) { \ @@ -137,4 +140,6 @@ void kissat_stack_enlarge (struct kissat *, chars *, size_t size_of_element); void kissat_shrink_stack (struct kissat *, chars *, size_t size_of_element); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/statistics.c b/src/sat/kissat/statistics.c index ad4bfa068..3a3c4bd3c 100644 --- a/src/sat/kissat/statistics.c +++ b/src/sat/kissat/statistics.c @@ -1,8 +1,10 @@ -#if !defined(QUIET) || !defined(NDEBUG) +#include "global.h" + +#if !defined(KISSAT_QUIET) || !defined(KISSAT_NDEBUG) #include "internal.h" #endif -#ifndef QUIET +#ifndef KISSAT_QUIET #include "resources.h" #include "tiers.h" @@ -344,13 +346,13 @@ kissat_statistics_print (kissat * solver, bool verbose) // clang-format on -#elif defined(NDEBUG) +#elif defined(KISSAT_NDEBUG) int kissat_statistics_dummy_to_avoid_warning; #endif /*------------------------------------------------------------------------*/ -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG #include "inlinevector.h" @@ -397,15 +399,15 @@ void kissat_check_statistics (kissat *solver) { } } - assert (!(binary & 1)); + KISSAT_assert (!(binary & 1)); binary /= 2; statistics *statistics = &solver->statistics; - assert (statistics->clauses_binary == binary); - assert (statistics->clauses_redundant == redundant); - assert (statistics->clauses_irredundant == irredundant); + KISSAT_assert (statistics->clauses_binary == binary); + KISSAT_assert (statistics->clauses_redundant == redundant); + KISSAT_assert (statistics->clauses_irredundant == irredundant); #ifdef METRICS - assert (statistics->arena_garbage == arena_garbage); + KISSAT_assert (statistics->arena_garbage == arena_garbage); #else (void) arena_garbage; #endif diff --git a/src/sat/kissat/statistics.h b/src/sat/kissat/statistics.h index 8c04f4d33..b0f4e6faf 100644 --- a/src/sat/kissat/statistics.h +++ b/src/sat/kissat/statistics.h @@ -4,6 +4,9 @@ #include #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + // clang-format off #define METRICS_COUNTERS_AND_STATISTICS \ @@ -329,12 +332,12 @@ struct statistics /*------------------------------------------------------------------------*/ #define CLAUSES (IRREDUNDANT_CLAUSES + BINARY_CLAUSES + REDUNDANT_CLAUSES) -#define CONFLICTS (solver->statistics.conflicts) -#define DECISIONS (solver->statistics.decisions) -#define IRREDUNDANT_CLAUSES (solver->statistics.clauses_irredundant) -#define LEARNED_CLAUSES (solver->statistics.learned) -#define REDUNDANT_CLAUSES (solver->statistics.clauses_redundant) -#define BINARY_CLAUSES (solver->statistics.clauses_binary) +#define CONFLICTS (solver->statistics_.conflicts) +#define DECISIONS (solver->statistics_.decisions) +#define IRREDUNDANT_CLAUSES (solver->statistics_.clauses_irredundant) +#define LEARNED_CLAUSES (solver->statistics_.learned) +#define REDUNDANT_CLAUSES (solver->statistics_.clauses_redundant) +#define BINARY_CLAUSES (solver->statistics_.clauses_binary) #define BINIRR_CLAUSES (BINARY_CLAUSES + IRREDUNDANT_CLAUSES) /*------------------------------------------------------------------------*/ @@ -342,24 +345,24 @@ struct statistics #define COUNTER(NAME, VERBOSE, OTHER, UNITS, TYPE) \ \ static inline void kissat_inc_##NAME (statistics *statistics) { \ - assert (statistics->NAME < UINT64_MAX); \ + KISSAT_assert (statistics->NAME < UINT64_MAX); \ statistics->NAME++; \ } \ \ static inline void kissat_dec_##NAME (statistics *statistics) { \ - assert (statistics->NAME); \ + KISSAT_assert (statistics->NAME); \ statistics->NAME--; \ } \ \ static inline void kissat_add_##NAME (statistics *statistics, \ uint64_t n) { \ - assert (UINT64_MAX - n >= statistics->NAME); \ + KISSAT_assert (UINT64_MAX - n >= statistics->NAME); \ statistics->NAME += n; \ } \ \ static inline void kissat_sub_##NAME (statistics *statistics, \ uint64_t n) { \ - assert (n <= statistics->NAME); \ + KISSAT_assert (n <= statistics->NAME); \ statistics->NAME -= n; \ } \ \ @@ -406,14 +409,14 @@ METRICS_COUNTERS_AND_STATISTICS // clang-format on /*------------------------------------------------------------------------*/ -#define INC(NAME) kissat_inc_##NAME (&solver->statistics) -#define DEC(NAME) kissat_dec_##NAME (&solver->statistics) -#define ADD(NAME, N) kissat_add_##NAME (&solver->statistics, (N)) -#define SUB(NAME, N) kissat_sub_##NAME (&solver->statistics, (N)) -#define GET(NAME) kissat_get_##NAME (&solver->statistics) +#define INC(NAME) kissat_inc_##NAME (&solver->statistics_) +#define DEC(NAME) kissat_dec_##NAME (&solver->statistics_) +#define ADD(NAME, N) kissat_add_##NAME (&solver->statistics_, (N)) +#define SUB(NAME, N) kissat_sub_##NAME (&solver->statistics_, (N)) +#define GET(NAME) kissat_get_##NAME (&solver->statistics_) /*------------------------------------------------------------------------*/ -#ifndef QUIET +#ifndef KISSAT_QUIET struct kissat; @@ -451,7 +454,7 @@ void kissat_print_glue_usage (struct kissat *); #endif -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG struct kissat; void kissat_check_statistics (struct kissat *); @@ -464,4 +467,6 @@ void kissat_check_statistics (struct kissat *); #endif +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/strengthen.c b/src/sat/kissat/strengthen.c index d5107d7f5..4d85b0d2a 100644 --- a/src/sat/kissat/strengthen.c +++ b/src/sat/kissat/strengthen.c @@ -3,22 +3,24 @@ #include "inline.h" #include "promote.h" +ABC_NAMESPACE_IMPL_START + static clause *large_on_the_fly_strengthen (kissat *solver, clause *c, unsigned lit) { - assert (solver->antecedent_size > 3); + KISSAT_assert (solver->antecedent_size > 3); LOGCLS (c, "large on-the-fly strengthening " "by removing %s from", LOGLIT (lit)); unsigned *lits = c->lits; - assert (lits[0] == lit || lits[1] == lit); + KISSAT_assert (lits[0] == lit || lits[1] == lit); INC (on_the_fly_strengthened); -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG clause *old_next = kissat_next_clause (c); #endif if (lits[0] == lit) SWAP (unsigned, lits[0], lits[1]); - assert (lits[1] == lit); + KISSAT_assert (lits[1] == lit); const reference ref = kissat_reference_clause (solver, c); kissat_unwatch_blocking (solver, lit, ref); SHRINK_CLAUSE_IN_PROOF (c, lit, lits[0]); @@ -29,14 +31,14 @@ static clause *large_on_the_fly_strengthen (kissat *solver, clause *c, const bool irredundant = !c->redundant; for (unsigned i = 2; i < old_size; i++) { const unsigned other = lits[i]; - assert (VALUE (other) < 0); + KISSAT_assert (VALUE (other) < 0); if (!LEVEL (other)) continue; lits[new_size++] = other; if (irredundant) kissat_mark_added_literal (solver, other); } - assert (new_size > 2); + KISSAT_assert (new_size > 2); c->size = new_size; c->searched = 2; if (c->redundant && c->glue >= new_size) @@ -48,13 +50,13 @@ static clause *large_on_the_fly_strengthen (kissat *solver, clause *c, } LOGCLS (c, "unsorted on-the-fly strengthened"); { - assert (VALUE (lits[1]) < 0); + KISSAT_assert (VALUE (lits[1]) < 0); unsigned highest_pos = 1; unsigned highest_level = LEVEL (lits[1]); const unsigned size = c->size; for (unsigned i = 2; i < size; i++) { const unsigned other = lits[i]; - assert (VALUE (other) < 0); + KISSAT_assert (VALUE (other) < 0); const unsigned level = LEVEL (other); if (level <= highest_level) continue; @@ -68,17 +70,17 @@ static clause *large_on_the_fly_strengthen (kissat *solver, clause *c, } { watches *watches = &WATCHES (lits[0]); -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG const watch *const end_of_watches = END_WATCHES (*watches); #endif watch *p = BEGIN_WATCHES (*watches); - assert (solver->watching); + KISSAT_assert (solver->watching); for (;;) { - assert (p != end_of_watches); + KISSAT_assert (p != end_of_watches); const watch head = *p++; if (head.type.binary) continue; - assert (p != end_of_watches); + KISSAT_assert (p != end_of_watches); const watch tail = *p++; if (tail.large.ref == ref) break; @@ -87,9 +89,9 @@ static clause *large_on_the_fly_strengthen (kissat *solver, clause *c, LOGREF (ref, "updating watching %s now blocking %s in", LOGLIT (lits[0]), LOGLIT (lits[1])); } -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG clause *new_next = kissat_next_clause (c); - assert (old_next == new_next); + KISSAT_assert (old_next == new_next); #endif LOGCLS (c, "conflicting"); return c; @@ -97,38 +99,38 @@ static clause *large_on_the_fly_strengthen (kissat *solver, clause *c, static clause *binary_on_the_fly_strengthen (kissat *solver, clause *c, unsigned lit) { - assert (solver->antecedent_size == 3); + KISSAT_assert (solver->antecedent_size == 3); LOGCLS (c, "binary on-the-fly strengthening " "by removing %s from", LOGLIT (lit)); unsigned first = INVALID_LIT, second = INVALID_LIT; -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG bool found = false; #endif for (all_literals_in_clause (other, c)) { if (other == lit) { -#ifndef NDEBUG - assert (!found); +#ifndef KISSAT_NDEBUG + KISSAT_assert (!found); found = true; #endif continue; } - assert (VALUE (other) < 0); + KISSAT_assert (VALUE (other) < 0); if (!LEVEL (other)) continue; if (first == INVALID_LIT) first = other; else { - assert (second == INVALID_LIT); + KISSAT_assert (second == INVALID_LIT); second = other; -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG break; #endif } } - assert (found); - assert (second != INVALID_LIT); + KISSAT_assert (found); + KISSAT_assert (second != INVALID_LIT); LOGBINARY (first, second, "on-the-fly strengthened"); kissat_new_binary_clause (solver, first, second); const reference ref = kissat_reference_clause (solver, c); @@ -141,8 +143,8 @@ static clause *binary_on_the_fly_strengthen (kissat *solver, clause *c, clause *kissat_on_the_fly_strengthen (kissat *solver, clause *c, unsigned lit) { - assert (!c->garbage); - assert (solver->antecedent_size > 2); + KISSAT_assert (!c->garbage); + KISSAT_assert (solver->antecedent_size > 2); if (!c->redundant) kissat_mark_removed_literal (solver, lit); clause *res; @@ -156,10 +158,10 @@ clause *kissat_on_the_fly_strengthen (kissat *solver, clause *c, void kissat_on_the_fly_subsume (kissat *solver, clause *c, clause *d) { LOGCLS (c, "on-the-fly subsuming"); LOGCLS (d, "on-the-fly subsumed"); - assert (c != d); - assert (!d->garbage); - assert (c->size > 1); - assert (c->size <= d->size); + KISSAT_assert (c != d); + KISSAT_assert (!d->garbage); + KISSAT_assert (c->size > 1); + KISSAT_assert (c->size <= d->size); kissat_mark_clause_as_garbage (solver, d); INC (on_the_fly_subsumed); if (d->redundant) { @@ -174,14 +176,16 @@ void kissat_on_the_fly_subsume (kissat *solver, clause *c, clause *d) { LOGCLS (c, "turned"); kissat_update_last_irredundant (solver, c); } - statistics *statistics = &solver->statistics; + statistics *statistics = &solver->statistics_; if (c->size > 2) { - assert (statistics->clauses_irredundant < UINT64_MAX); + KISSAT_assert (statistics->clauses_irredundant < UINT64_MAX); statistics->clauses_irredundant++; } else { - assert (statistics->clauses_binary < UINT64_MAX); + KISSAT_assert (statistics->clauses_binary < UINT64_MAX); statistics->clauses_binary++; } - assert (statistics->clauses_redundant > 0); + KISSAT_assert (statistics->clauses_redundant > 0); statistics->clauses_redundant--; } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/strengthen.h b/src/sat/kissat/strengthen.h index 1e6a395fc..6624b684a 100644 --- a/src/sat/kissat/strengthen.h +++ b/src/sat/kissat/strengthen.h @@ -3,6 +3,9 @@ #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + struct clause; struct kissat; @@ -14,4 +17,6 @@ void kissat_on_the_fly_subsume (struct kissat *, struct clause *, bool issat_strengthen_clause (struct kissat *, struct clause *, unsigned); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/substitute.c b/src/sat/kissat/substitute.c index f95efe746..76982305c 100644 --- a/src/sat/kissat/substitute.c +++ b/src/sat/kissat/substitute.c @@ -11,6 +11,8 @@ #include +ABC_NAMESPACE_IMPL_START + static void assign_and_propagate_units (kissat *solver, unsigneds *units) { if (EMPTY_STACK (*units)) return; @@ -29,7 +31,7 @@ static void assign_and_propagate_units (kissat *solver, unsigneds *units) { } else { kissat_learned_unit (solver, unit); INC (substitute_units); - assert (!solver->level); + KISSAT_assert (!solver->level); (void) kissat_probing_propagate (solver, 0, false); } } @@ -37,8 +39,8 @@ static void assign_and_propagate_units (kissat *solver, unsigneds *units) { static void determine_representatives (kissat *solver, unsigned *repr) { size_t bytes = LITS * sizeof (unsigned); - unsigned *mark = kissat_calloc (solver, LITS, sizeof *mark); - unsigned *reach = kissat_malloc (solver, LITS * sizeof *reach); + unsigned *mark = (unsigned*)kissat_calloc (solver, LITS, sizeof *mark); + unsigned *reach = (unsigned*)kissat_malloc (solver, LITS * sizeof *reach); watches *all_watches = solver->watches; const flags *const flags = solver->flags; unsigned reached = 0; @@ -61,8 +63,8 @@ static void determine_representatives (kissat *solver, unsigned *repr) { continue; if (!ACTIVE (IDX (root))) continue; - assert (EMPTY_STACK (scc)); - assert (EMPTY_STACK (work)); + KISSAT_assert (EMPTY_STACK (scc)); + KISSAT_assert (EMPTY_STACK (work)); LOG ("substitute root %s", LOGLIT (root)); PUSH_STACK (work, root); bool failed = false; @@ -75,8 +77,8 @@ static void determine_representatives (kissat *solver, unsigned *repr) { const unsigned not_lit = NOT (lit); unsigned reach_lit = reach[lit]; unsigned mark_lit = mark[lit]; - assert (reach_lit == mark_lit); - assert (repr[lit] == INVALID_LIT); + KISSAT_assert (reach_lit == mark_lit); + KISSAT_assert (repr[lit] == INVALID_LIT); watches *watches = all_watches + not_lit; const size_t size_watches = SIZE_WATCHES (*watches); ticks += 1 + kissat_cache_lines (size_watches, sizeof (watch)); @@ -87,7 +89,7 @@ static void determine_representatives (kissat *solver, unsigned *repr) { const unsigned idx_other = IDX (other); if (!flags[idx_other].active) continue; - assert (mark[other]); + KISSAT_assert (mark[other]); unsigned reach_other = reach[other]; if (reach_other < reach_lit) reach_lit = reach_other; @@ -100,7 +102,7 @@ static void determine_representatives (kissat *solver, unsigned *repr) { unsigned *end_scc = END_STACK (scc); unsigned *begin_scc = end_scc; do - assert (begin_scc != BEGIN_STACK (scc)); + KISSAT_assert (begin_scc != BEGIN_STACK (scc)); while (*--begin_scc != lit); SET_END_OF_STACK (scc, begin_scc); const size_t size_scc = end_scc - begin_scc; @@ -121,7 +123,7 @@ static void determine_representatives (kissat *solver, unsigned *repr) { trivial_sccs++; #endif LOG ("trivial size one SCC with %s", LOGLIT (lit)); - assert (min_lit == lit); + KISSAT_assert (min_lit == lit); } for (const unsigned *p = begin_scc; p != end_scc; p++) { const unsigned other = *p; @@ -141,12 +143,12 @@ static void determine_representatives (kissat *solver, unsigned *repr) { inconsistent = true; break; } - assert (NOT (min_lit) == repr_not_other); + KISSAT_assert (NOT (min_lit) == repr_not_other); if (failed) continue; const unsigned mark_not_other = mark[not_other]; - assert (mark_not_other != INVALID_LIT); - assert (mark[root] == mark_root); + KISSAT_assert (mark_not_other != INVALID_LIT); + KISSAT_assert (mark[root] == mark_root); if (mark_root > mark_not_other) continue; LOG ("root %s implies both %s and %s", LOGLIT (root), @@ -193,7 +195,7 @@ static void determine_representatives (kissat *solver, unsigned *repr) { LOG ("found %u trivial SCCs", trivial_sccs); LOG ("found %zu units", SIZE_STACK (units)); assign_and_propagate_units (solver, &units); - assert (!inconsistent || solver->inconsistent); + KISSAT_assert (!inconsistent || solver->inconsistent); RELEASE_STACK (units); kissat_free (solver, reach, bytes); kissat_free (solver, mark, bytes); @@ -206,7 +208,7 @@ static bool *add_representative_equivalences (kissat *solver, unsigned *repr) { if (solver->inconsistent) return 0; - bool *eliminate = kissat_calloc (solver, VARS, sizeof *eliminate); + bool *eliminate = (bool*)kissat_calloc (solver, VARS, sizeof *eliminate); for (all_variables (idx)) { if (!ACTIVE (idx)) continue; @@ -214,7 +216,7 @@ static bool *add_representative_equivalences (kissat *solver, const unsigned other = repr[lit]; if (lit == other) continue; - assert (other < lit); + KISSAT_assert (other < lit); #ifdef CHECKING_OR_PROVING const unsigned not_lit = NOT (lit); const unsigned not_other = NOT (other); @@ -240,14 +242,14 @@ static void remove_representative_equivalences (kissat *solver, if (!eliminate[idx]) continue; - assert (ACTIVE (idx)); + KISSAT_assert (ACTIVE (idx)); const unsigned lit = LIT (idx); const unsigned other = repr[lit]; const unsigned not_lit = NOT (lit); const unsigned not_other = NOT (other); - assert (other < lit); - assert (not_other < not_lit); + KISSAT_assert (other < lit); + KISSAT_assert (not_other < not_lit); REMOVE_CHECKER_BINARY (not_lit, other); DELETE_BINARY_FROM_PROOF (not_lit, other); @@ -276,7 +278,7 @@ static void remove_representative_equivalences (kissat *solver, static void substitute_binaries (kissat *solver, unsigned *repr) { if (solver->inconsistent) return; - assert (sizeof (watch) == sizeof (unsigned)); + KISSAT_assert (sizeof (watch) == sizeof (unsigned)); statches *delayed_watched = (statches *) &solver->delayed; watches *all_watches = solver->watches; #ifdef LOGGING @@ -294,7 +296,7 @@ static void substitute_binaries (kissat *solver, unsigned *repr) { for (all_literals (lit)) { const unsigned repr_lit = repr[lit]; const unsigned not_repr_lit = NOT (repr_lit); - assert (EMPTY_STACK (*delayed_watched)); + KISSAT_assert (EMPTY_STACK (*delayed_watched)); watches *watches = all_watches + lit; watch *begin = BEGIN_WATCHES (*watches), *q = begin; const watch *const end = END_WATCHES (*watches), *p = q; @@ -366,7 +368,7 @@ static void substitute_binaries (kissat *solver, unsigned *repr) { for (all_stack (litwatch, litwatch, delayed_deleted)) { const unsigned lit = litwatch.lit; const watch watch = litwatch.watch; - assert (watch.type.binary); + KISSAT_assert (watch.type.binary); const unsigned other = watch.binary.lit; kissat_delete_binary (solver, lit, other); } @@ -401,7 +403,7 @@ static void substitute_clauses (kissat *solver, unsigned *repr) { if (c->garbage) continue; LOGCLS (c, "substituting"); - assert (EMPTY_STACK (solver->clause)); + KISSAT_assert (EMPTY_STACK (solver->clause)); bool shrink = false; bool satisfied = false; bool substitute = false; @@ -433,7 +435,7 @@ static void substitute_clauses (kissat *solver, unsigned *repr) { break; } if (lit != repr_lit) { - assert (!values[repr_lit]); + KISSAT_assert (!values[repr_lit]); LOG ("substituted literal %s (was %s)", LOGLIT (repr_lit), LOGLIT (lit)); substitute = true; @@ -471,7 +473,7 @@ static void substitute_clauses (kissat *solver, unsigned *repr) { solver->inconsistent = true; break; } else if (size == 1) { - assert (shrink); + KISSAT_assert (shrink); #ifdef LOGGING removed++; #endif @@ -481,7 +483,7 @@ static void substitute_clauses (kissat *solver, unsigned *repr) { const reference ref = kissat_reference_clause (solver, c); PUSH_STACK (delayed_garbage, ref); } else if (size == 2) { - assert (shrink); + KISSAT_assert (shrink); #ifdef LOGGING substituted++; #endif @@ -509,16 +511,16 @@ static void substitute_clauses (kissat *solver, unsigned *repr) { const unsigned old_size = c->size; unsigned *old_lits = c->lits; - assert (new_size <= old_size); + KISSAT_assert (new_size <= old_size); memcpy (old_lits, new_lits, new_size * sizeof *old_lits); - assert (shrink == (new_size < old_size)); + KISSAT_assert (shrink == (new_size < old_size)); if (new_size < old_size) { c->size = new_size; c->searched = 2; if (!c->shrunken) { c->shrunken = true; - assert (c->lits == old_lits); + KISSAT_assert (c->lits == old_lits); old_lits[old_size - 1] = INVALID_LIT; } } @@ -542,10 +544,10 @@ static void substitute_clauses (kissat *solver, unsigned *repr) { } static bool substitute_round (kissat *solver, unsigned round) { - assert (!solver->inconsistent); + KISSAT_assert (!solver->inconsistent); const unsigned active = solver->active; size_t bytes = LITS * sizeof (unsigned); - unsigned *repr = kissat_malloc (solver, bytes); + unsigned *repr = (unsigned*)kissat_malloc (solver, bytes); memset (repr, 0xff, bytes); determine_representatives (solver, repr); bool *eliminate = add_representative_equivalences (solver, repr); @@ -559,7 +561,7 @@ static bool substitute_round (kissat *solver, unsigned round) { kissat_percent (removed, active)); kissat_check_statistics (solver); REPORT (!removed, 'd'); -#ifdef QUIET +#ifdef KISSAT_QUIET (void) round; #endif return !solver->inconsistent && removed; @@ -570,14 +572,14 @@ static void substitute_rounds (kissat *solver, bool complete) { INC (substitutions); const unsigned maxrounds = GET_OPTION (substituterounds); for (unsigned round = 1; round <= maxrounds; round++) { - const uint64_t before = solver->statistics.substitute_ticks; + const uint64_t before = solver->statistics_.substitute_ticks; if (!substitute_round (solver, round)) break; - const uint64_t after = solver->statistics.substitute_ticks; + const uint64_t after = solver->statistics_.substitute_ticks; const uint64_t ticks = after - before; if (!complete) { const uint64_t reference = - solver->statistics.search_ticks - solver->last.ticks.probe; + solver->statistics_.search_ticks - solver->last.ticks.probe; const double fraction = GET_OPTION (substituteeffort) * 1e-3; const uint64_t limit = fraction * reference; if (ticks > limit) { @@ -595,7 +597,7 @@ static void substitute_rounds (kissat *solver, bool complete) { LOG ("now all large clauses are watched after binary clauses"); solver->large_clauses_watched_after_binary_clauses = true; kissat_reset_propagate (solver); - assert (!solver->level); + KISSAT_assert (!solver->level); (void) kissat_probing_propagate (solver, 0, true); } STOP (substitute); @@ -604,9 +606,9 @@ static void substitute_rounds (kissat *solver, bool complete) { void kissat_substitute (kissat *solver, bool complete) { if (solver->inconsistent) return; - assert (solver->probing); - assert (solver->watching); - assert (!solver->level); + KISSAT_assert (solver->probing); + KISSAT_assert (solver->watching); + KISSAT_assert (!solver->level); LOG ("assuming not all large clauses watched after binary clauses"); solver->large_clauses_watched_after_binary_clauses = false; if (!GET_OPTION (substitute)) @@ -615,3 +617,5 @@ void kissat_substitute (kissat *solver, bool complete) { return; substitute_rounds (solver, complete); } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/substitute.h b/src/sat/kissat/substitute.h index 63a464ee9..bf2f39b51 100644 --- a/src/sat/kissat/substitute.h +++ b/src/sat/kissat/substitute.h @@ -3,8 +3,13 @@ #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + struct kissat; void kissat_substitute (struct kissat *, bool complete); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/sweep.c b/src/sat/kissat/sweep.c index 866867112..42420cc54 100644 --- a/src/sat/kissat/sweep.c +++ b/src/sat/kissat/sweep.c @@ -15,6 +15,8 @@ #include #include +ABC_NAMESPACE_IMPL_START + struct sweeper { kissat *solver; unsigned *depths; @@ -53,18 +55,18 @@ static int sweep_solve (sweeper *sweeper) { static void set_kitten_ticks_limit (sweeper *sweeper) { uint64_t remaining = 0; kissat *solver = sweeper->solver; - if (solver->statistics.kitten_ticks < sweeper->limit.ticks) - remaining = sweeper->limit.ticks - solver->statistics.kitten_ticks; + if (solver->statistics_.kitten_ticks < sweeper->limit.ticks) + remaining = sweeper->limit.ticks - solver->statistics_.kitten_ticks; LOG ("'kitten_ticks' remaining %" PRIu64, remaining); kitten_set_ticks_limit (solver->kitten, remaining); } static bool kitten_ticks_limit_hit (sweeper *sweeper, const char *when) { kissat *solver = sweeper->solver; - if (solver->statistics.kitten_ticks >= sweeper->limit.ticks) { + if (solver->statistics_.kitten_ticks >= sweeper->limit.ticks) { LOG ("'kitten_ticks' limit of %" PRIu64 " ticks hit after %" PRIu64 " ticks during %s", - sweeper->limit.ticks, solver->statistics.kitten_ticks, when); + sweeper->limit.ticks, solver->statistics_.kitten_ticks, when); return true; } #ifndef LOGGING @@ -76,19 +78,19 @@ static bool kitten_ticks_limit_hit (sweeper *sweeper, const char *when) { static void init_sweeper (kissat *solver, sweeper *sweeper) { sweeper->solver = solver; sweeper->encoded = 0; - CALLOC (sweeper->depths, VARS); - NALLOC (sweeper->reprs, LITS); + CALLOC (unsigned, sweeper->depths, VARS); + NALLOC (unsigned, sweeper->reprs, LITS); for (all_literals (lit)) sweeper->reprs[lit] = lit; - NALLOC (sweeper->prev, VARS); + NALLOC (unsigned, sweeper->prev, VARS); memset (sweeper->prev, 0xff, VARS * sizeof *sweeper->prev); - NALLOC (sweeper->next, VARS); + NALLOC (unsigned, sweeper->next, VARS); memset (sweeper->next, 0xff, VARS * sizeof *sweeper->next); -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG for (all_variables (idx)) - assert (sweeper->prev[idx] == INVALID_IDX); + KISSAT_assert (sweeper->prev[idx] == INVALID_IDX); for (all_variables (idx)) - assert (sweeper->next[idx] == INVALID_IDX); + KISSAT_assert (sweeper->next[idx] == INVALID_IDX); #endif sweeper->first = sweeper->last = INVALID_IDX; INIT_STACK (sweeper->vars); @@ -98,13 +100,13 @@ static void init_sweeper (kissat *solver, sweeper *sweeper) { INIT_STACK (sweeper->partition); INIT_STACK (sweeper->core[0]); INIT_STACK (sweeper->core[1]); - assert (!solver->kitten); + KISSAT_assert (!solver->kitten); solver->kitten = kitten_embedded (solver); kitten_track_antecedents (solver->kitten); kissat_enter_dense_mode (solver, 0); kissat_connect_irredundant_large_clauses (solver); - unsigned completed = solver->statistics.sweep_completed; + unsigned completed = solver->statistics_.sweep_completed; const unsigned max_completed = 32; if (completed > max_completed) completed = max_completed; @@ -118,7 +120,7 @@ static void init_sweeper (kissat *solver, sweeper *sweeper) { kissat_extremely_verbose (solver, "sweeper variable limit %u", sweeper->limit.vars); - uint64_t depth_limit = solver->statistics.sweep_completed; + uint64_t depth_limit = solver->statistics_.sweep_completed; depth_limit += GET_OPTION (sweepdepth); const unsigned max_depth = GET_OPTION (sweepmaxdepth); if (depth_limit > max_depth) @@ -180,13 +182,13 @@ static void clear_sweeper (sweeper *sweeper) { kitten_clear (solver->kitten); kitten_track_antecedents (solver->kitten); for (all_stack (unsigned, idx, sweeper->vars)) { - assert (sweeper->depths[idx]); + KISSAT_assert (sweeper->depths[idx]); sweeper->depths[idx] = 0; } CLEAR_STACK (sweeper->vars); for (all_stack (reference, ref, sweeper->refs)) { clause *c = kissat_dereference_clause (solver, ref); - assert (c->swept); + KISSAT_assert (c->swept); c->swept = false; } CLEAR_STACK (sweeper->refs); @@ -205,7 +207,7 @@ static unsigned sweep_repr (sweeper *sweeper, unsigned lit) { } if (res == lit) return res; -#if defined(LOGGING) || !defined(NDEBUG) +#if defined(LOGGING) || !defined(KISSAT_NDEBUG) kissat *solver = sweeper->solver; #endif LOG ("sweeping repr[%s] = %s", LOGLIT (lit), LOGLIT (res)); @@ -219,7 +221,7 @@ static unsigned sweep_repr (sweeper *sweeper, unsigned lit) { sweeper->reprs[prev] = res; prev = next; } - assert (sweeper->reprs[NOT (prev)] == not_res); + KISSAT_assert (sweeper->reprs[NOT (prev)] == not_res); } return res; } @@ -233,7 +235,7 @@ static void add_literal_to_environment (sweeper *sweeper, unsigned depth, const unsigned idx = IDX (lit); if (sweeper->depths[idx]) return; - assert (depth < UINT_MAX); + KISSAT_assert (depth < UINT_MAX); sweeper->depths[idx] = depth + 1; PUSH_STACK (sweeper->vars, idx); LOG ("sweeping[%u] adding literal %s", depth, LOGLIT (lit)); @@ -241,7 +243,7 @@ static void add_literal_to_environment (sweeper *sweeper, unsigned depth, static void sweep_clause (sweeper *sweeper, unsigned depth) { kissat *solver = sweeper->solver; - assert (SIZE_STACK (sweeper->clause) > 1); + KISSAT_assert (SIZE_STACK (sweeper->clause) > 1); for (all_stack (unsigned, lit, sweeper->clause)) add_literal_to_environment (sweeper, depth, lit); kitten_clause (solver->kitten, SIZE_STACK (sweeper->clause), @@ -259,7 +261,7 @@ static void sweep_binary (sweeper *sweeper, unsigned depth, unsigned lit, kissat *solver = sweeper->solver; LOGBINARY (lit, other, "sweeping[%u]", depth); value *values = solver->values; - assert (!values[lit]); + KISSAT_assert (!values[lit]); const value other_value = values[other]; if (other_value > 0) { LOGBINARY (lit, other, "skipping satisfied"); @@ -274,8 +276,8 @@ static void sweep_binary (sweeper *sweeper, unsigned depth, unsigned lit, LOGBINARY (lit, other, "skipping depth %u copied", other_depth); return; } - assert (!other_value); - assert (EMPTY_STACK (sweeper->clause)); + KISSAT_assert (!other_value); + KISSAT_assert (EMPTY_STACK (sweeper->clause)); PUSH_STACK (sweeper->clause, lit); PUSH_STACK (sweeper->clause, other); sweep_clause (sweeper, depth); @@ -283,7 +285,7 @@ static void sweep_binary (sweeper *sweeper, unsigned depth, unsigned lit, static void sweep_reference (sweeper *sweeper, unsigned depth, reference ref) { - assert (EMPTY_STACK (sweeper->clause)); + KISSAT_assert (EMPTY_STACK (sweeper->clause)); kissat *solver = sweeper->solver; clause *c = kissat_dereference_clause (solver, ref); if (c->swept) @@ -310,7 +312,7 @@ static void sweep_reference (sweeper *sweeper, unsigned depth, static void save_core_clause (void *state, bool learned, size_t size, const unsigned *lits) { - sweeper *sweeper = state; + sweeper *sweeper = (struct sweeper*)state; kissat *solver = sweeper->solver; if (solver->inconsistent) return; @@ -349,7 +351,7 @@ static void add_core (sweeper *sweeper, unsigned core_idx) { if (solver->inconsistent) return; LOG ("check and add extracted core[%u] lemmas to proof", core_idx); - assert (core_idx == 0 || core_idx == 1); + KISSAT_assert (core_idx == 0 || core_idx == 1); unsigneds *core = sweeper->core + core_idx; const value *const values = solver->values; @@ -400,7 +402,7 @@ static void add_core (sweeper *sweeper, unsigned core_idx) { if (new_size == 1) { q = d; - assert (unit != INVALID_LIT); + KISSAT_assert (unit != INVALID_LIT); LOG ("sweeping produced unit %s", LOGLIT (unit)); CHECK_AND_ADD_UNIT (unit); ADD_UNIT_TO_PROOF (unit); @@ -411,7 +413,7 @@ static void add_core (sweeper *sweeper, unsigned core_idx) { *q++ = INVALID_LIT; - assert (new_size > 1); + KISSAT_assert (new_size > 1); LOGLITS (new_size, d, "adding extracted core[%u] lemma", core_idx); CHECK_AND_ADD_LITS (new_size, d); ADD_LITS_TO_PROOF (new_size, d); @@ -425,8 +427,8 @@ static void add_core (sweeper *sweeper, unsigned core_idx) { static void save_core (sweeper *sweeper, unsigned core) { kissat *solver = sweeper->solver; LOG ("saving extracted core[%u] lemmas", core); - assert (core == 0 || core == 1); - assert (EMPTY_STACK (sweeper->core[core])); + KISSAT_assert (core == 0 || core == 1); + KISSAT_assert (EMPTY_STACK (sweeper->core[core])); sweeper->save = core; kitten_compute_clausal_core (solver->kitten, 0); kitten_traverse_core_clauses (solver->kitten, sweeper, save_core_clause); @@ -436,8 +438,8 @@ static void clear_core (sweeper *sweeper, unsigned core_idx) { kissat *solver = sweeper->solver; if (solver->inconsistent) return; -#if defined(LOGGING) || !defined(NDEBUG) || !defined(NPROOFS) - assert (core_idx == 0 || core_idx == 1); +#if defined(LOGGING) || !defined(KISSAT_NDEBUG) || !defined(KISSAT_NPROOFS) + KISSAT_assert (core_idx == 0 || core_idx == 1); LOG ("clearing core[%u] lemmas", core_idx); #endif unsigneds *core = sweeper->core + core_idx; @@ -449,7 +451,7 @@ static void clear_core (sweeper *sweeper, unsigned core_idx) { while (*p != INVALID_LIT) p++; const size_t size = p - c; - assert (size > 1); + KISSAT_assert (size > 1); REMOVE_CHECKER_LITS (size, c); DELETE_LITS_FROM_PROOF (size, c); } @@ -492,9 +494,9 @@ static void init_backbone_and_partition (sweeper *sweeper) { } static void sweep_empty_clause (sweeper *sweeper) { - assert (!sweeper->solver->inconsistent); + KISSAT_assert (!sweeper->solver->inconsistent); save_add_clear_core (sweeper); - assert (sweeper->solver->inconsistent); + KISSAT_assert (sweeper->solver->inconsistent); } static void sweep_refine_partition (sweeper *sweeper) { @@ -625,7 +627,7 @@ static void flip_backbone_literals (struct sweeper *sweeper) { const unsigned max_rounds = GET_OPTION (sweepfliprounds); if (!max_rounds) return; - assert (!EMPTY_STACK (sweeper->backbone)); + KISSAT_assert (!EMPTY_STACK (sweeper->backbone)); struct kitten *kitten = solver->kitten; if (kitten_status (kitten) != 10) return; @@ -658,7 +660,7 @@ static void flip_backbone_literals (struct sweeper *sweeper) { if (TERMINATED (sweep_terminated_1)) break; - if (solver->statistics.kitten_ticks > sweeper->limit.ticks) + if (solver->statistics_.kitten_ticks > sweeper->limit.ticks) break; } while (flipped && round < max_rounds); LOG ("flipped %u backbone candidates in total in %u rounds", @@ -673,7 +675,7 @@ static bool sweep_backbone_candidate (sweeper *sweeper, unsigned lit) { if (value) { INC (sweep_fixed_backbone); LOG ("literal %s already fixed", LOGLIT (lit)); - assert (value > 0); + KISSAT_assert (value > 0); return false; } @@ -715,37 +717,37 @@ static void add_binary (kissat *solver, unsigned lit, unsigned other) { } static bool scheduled_variable (sweeper *sweeper, unsigned idx) { -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG kissat *const solver = sweeper->solver; - assert (VALID_INTERNAL_INDEX (idx)); + KISSAT_assert (VALID_INTERNAL_INDEX (idx)); #endif return sweeper->prev[idx] != INVALID_IDX || sweeper->first == idx; } static void schedule_inner (sweeper *sweeper, unsigned idx) { kissat *const solver = sweeper->solver; - assert (VALID_INTERNAL_INDEX (idx)); + KISSAT_assert (VALID_INTERNAL_INDEX (idx)); if (!ACTIVE (idx)) return; const unsigned next = sweeper->next[idx]; if (next != INVALID_IDX) { LOG ("rescheduling inner %s as last", LOGVAR (idx)); const unsigned prev = sweeper->prev[idx]; - assert (sweeper->prev[next] == idx); + KISSAT_assert (sweeper->prev[next] == idx); sweeper->prev[next] = prev; if (prev == INVALID_IDX) { - assert (sweeper->first == idx); + KISSAT_assert (sweeper->first == idx); sweeper->first = next; } else { - assert (sweeper->next[prev] == idx); + KISSAT_assert (sweeper->next[prev] == idx); sweeper->next[prev] = next; } const unsigned last = sweeper->last; if (last == INVALID_IDX) { - assert (sweeper->first == INVALID_IDX); + KISSAT_assert (sweeper->first == INVALID_IDX); sweeper->first = idx; } else { - assert (sweeper->next[last] == INVALID_IDX); + KISSAT_assert (sweeper->next[last] == INVALID_IDX); sweeper->next[last] = idx; } sweeper->prev[idx] = last; @@ -755,13 +757,13 @@ static void schedule_inner (sweeper *sweeper, unsigned idx) { LOG ("scheduling inner %s as last", LOGVAR (idx)); const unsigned last = sweeper->last; if (last == INVALID_IDX) { - assert (sweeper->first == INVALID_IDX); + KISSAT_assert (sweeper->first == INVALID_IDX); sweeper->first = idx; } else { - assert (sweeper->next[last] == INVALID_IDX); + KISSAT_assert (sweeper->next[last] == INVALID_IDX); sweeper->next[last] = idx; } - assert (sweeper->next[idx] == INVALID_IDX); + KISSAT_assert (sweeper->next[idx] == INVALID_IDX); sweeper->prev[idx] = last; sweeper->last = idx; } else @@ -769,28 +771,28 @@ static void schedule_inner (sweeper *sweeper, unsigned idx) { } static void schedule_outer (sweeper *sweeper, unsigned idx) { -#if !defined(NDEBUG) || defined(LOGGING) +#if !defined(KISSAT_NDEBUG) || defined(LOGGING) kissat *const solver = sweeper->solver; #endif - assert (VALID_INTERNAL_INDEX (idx)); - assert (!scheduled_variable (sweeper, idx)); - assert (ACTIVE (idx)); + KISSAT_assert (VALID_INTERNAL_INDEX (idx)); + KISSAT_assert (!scheduled_variable (sweeper, idx)); + KISSAT_assert (ACTIVE (idx)); const unsigned first = sweeper->first; if (first == INVALID_IDX) { - assert (sweeper->last == INVALID_IDX); + KISSAT_assert (sweeper->last == INVALID_IDX); sweeper->last = idx; } else { - assert (sweeper->prev[first] == INVALID_IDX); + KISSAT_assert (sweeper->prev[first] == INVALID_IDX); sweeper->prev[first] = idx; } - assert (sweeper->prev[idx] == INVALID_IDX); + KISSAT_assert (sweeper->prev[idx] == INVALID_IDX); sweeper->next[idx] = first; sweeper->first = idx; LOG ("scheduling outer %s as first", LOGVAR (idx)); } static unsigned next_scheduled (sweeper *sweeper) { -#if !defined(NDEBUG) || defined(LOGGING) +#if !defined(KISSAT_NDEBUG) || defined(LOGGING) kissat *const solver = sweeper->solver; #endif unsigned res = sweeper->last; @@ -798,16 +800,16 @@ static unsigned next_scheduled (sweeper *sweeper) { LOG ("no more scheduled variables left"); return INVALID_IDX; } - assert (VALID_INTERNAL_INDEX (res)); + KISSAT_assert (VALID_INTERNAL_INDEX (res)); LOG ("dequeuing next scheduled %s", LOGVAR (res)); const unsigned prev = sweeper->prev[res]; - assert (sweeper->next[res] == INVALID_IDX); + KISSAT_assert (sweeper->next[res] == INVALID_IDX); sweeper->prev[res] = INVALID_IDX; if (prev == INVALID_IDX) { - assert (sweeper->first == res); + KISSAT_assert (sweeper->first == res); sweeper->first = INVALID_IDX; } else { - assert (sweeper->next[prev] == res); + KISSAT_assert (sweeper->next[prev] == res); sweeper->next[prev] = INVALID_IDX; } sweeper->last = prev; @@ -832,17 +834,17 @@ static void substitute_connected_clauses (sweeper *sweeper, unsigned lit, LOG ("substituting %s with %s in all irredundant clauses", LOGLIT (lit), LOGLIT (repr)); - assert (lit != repr); - assert (lit != NOT (repr)); + KISSAT_assert (lit != repr); + KISSAT_assert (lit != NOT (repr)); #ifdef CHECKING_OR_PROVING const bool checking_or_proving = kissat_checking_or_proving (solver); - assert (EMPTY_STACK (solver->added)); - assert (EMPTY_STACK (solver->removed)); + KISSAT_assert (EMPTY_STACK (solver->added)); + KISSAT_assert (EMPTY_STACK (solver->removed)); #endif unsigneds *const delayed = &solver->delayed; - assert (EMPTY_STACK (*delayed)); + KISSAT_assert (EMPTY_STACK (*delayed)); { watches *lit_watches = &WATCHES (lit); @@ -884,7 +886,7 @@ static void substitute_connected_clauses (sweeper *sweeper, unsigned lit, q--; } else { const reference ref = head.large.ref; - assert (EMPTY_STACK (sweeper->clause)); + KISSAT_assert (EMPTY_STACK (sweeper->clause)); clause *c = kissat_dereference_clause (solver, ref); if (c->garbage) continue; @@ -892,21 +894,21 @@ static void substitute_connected_clauses (sweeper *sweeper, unsigned lit, bool satisfied = false; bool repr_already_watched = false; const unsigned not_repr = NOT (repr); -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG bool found = false; #endif for (all_literals_in_clause (other, c)) { if (other == lit) { -#ifndef NDEBUG - assert (!found); +#ifndef KISSAT_NDEBUG + KISSAT_assert (!found); found = true; #endif PUSH_STACK (solver->clause, repr); continue; } - assert (other != NOT (lit)); + KISSAT_assert (other != NOT (lit)); if (other == repr) { - assert (!repr_already_watched); + KISSAT_assert (!repr_already_watched); repr_already_watched = true; continue; } @@ -929,13 +931,13 @@ static void substitute_connected_clauses (sweeper *sweeper, unsigned lit, kissat_mark_clause_as_garbage (solver, c); continue; } - assert (found); + KISSAT_assert (found); const unsigned new_size = SIZE_STACK (solver->clause); if (new_size == 0) { LOGCLS (c, "substituted empty clause"); - assert (!solver->inconsistent); + KISSAT_assert (!solver->inconsistent); solver->inconsistent = true; CHECK_AND_ADD_EMPTY (); ADD_EMPTY_TO_PROOF (); @@ -966,16 +968,16 @@ static void substitute_connected_clauses (sweeper *sweeper, unsigned lit, const unsigned first = POP_STACK (solver->clause); LOGCLS (c, "reduces to binary clause %s %s", LOGLIT (first), LOGLIT (second)); - assert (first == repr || second == repr); + KISSAT_assert (first == repr || second == repr); const unsigned other = first ^ second ^ repr; const watch src = {.raw = head.raw}; watch dst = kissat_binary_watch (repr); watches *other_watches = &WATCHES (other); kissat_substitute_large_watch (solver, other_watches, src, dst); - assert (solver->statistics.clauses_irredundant); - solver->statistics.clauses_irredundant--; - assert (solver->statistics.clauses_binary < UINT64_MAX); - solver->statistics.clauses_binary++; + KISSAT_assert (solver->statistics_.clauses_irredundant); + solver->statistics_.clauses_irredundant--; + KISSAT_assert (solver->statistics_.clauses_binary < UINT64_MAX); + solver->statistics_.clauses_binary++; dst.binary.lit = other; PUSH_STACK (*delayed, dst.raw); const size_t bytes = kissat_actual_bytes_of_clause (c); @@ -985,9 +987,9 @@ static void substitute_connected_clauses (sweeper *sweeper, unsigned lit, continue; } - assert (2 < new_size); + KISSAT_assert (2 < new_size); const unsigned old_size = c->size; - assert (new_size <= old_size); + KISSAT_assert (new_size <= old_size); const unsigned *const begin = BEGIN_STACK (solver->clause); const unsigned *const end = END_STACK (solver->clause); @@ -1045,12 +1047,12 @@ static void substitute_connected_clauses (sweeper *sweeper, unsigned lit, static void sweep_remove (sweeper *sweeper, unsigned lit) { kissat *solver = sweeper->solver; - assert (sweeper->reprs[lit] != lit); + KISSAT_assert (sweeper->reprs[lit] != lit); unsigneds *partition = &sweeper->partition; unsigned *const begin_partition = BEGIN_STACK (*partition), *p; const unsigned *const end_partition = END_STACK (*partition); for (p = begin_partition; *p != lit; p++) - assert (p + 1 != end_partition); + KISSAT_assert (p + 1 != end_partition); unsigned *begin_class = p; while (begin_class != begin_partition && begin_class[-1] != INVALID_LIT) begin_class--; @@ -1060,7 +1062,7 @@ static void sweep_remove (sweeper *sweeper, unsigned lit) { const unsigned size = end_class - begin_class; LOG ("removing non-representative %s from equivalence class of size %u", LOGLIT (lit), size); - assert (size > 1); + KISSAT_assert (size > 1); unsigned *q = begin_class; if (size == 2) { LOG ("completely squashing equivalence class of %s", LOGLIT (lit)); @@ -1082,7 +1084,7 @@ static void flip_partition_literals (struct sweeper *sweeper) { const unsigned max_rounds = GET_OPTION (sweepfliprounds); if (!max_rounds) return; - assert (!EMPTY_STACK (sweeper->partition)); + KISSAT_assert (!EMPTY_STACK (sweeper->partition)); struct kitten *kitten = solver->kitten; if (kitten_status (kitten) != 10) return; @@ -1097,10 +1099,10 @@ static void flip_partition_literals (struct sweeper *sweeper) { const unsigned *const end = END_STACK (sweeper->partition), *src = dst; while (src != end) { const unsigned *end_src = src; - while (assert (end_src != end), *end_src != INVALID_LIT) + while (KISSAT_assert (end_src != end), *end_src != INVALID_LIT) end_src++; unsigned size = end_src - src; - assert (size > 1); + KISSAT_assert (size > 1); unsigned *q = dst; for (const unsigned *p = src; p != end_src; p++) { const unsigned lit = *p; @@ -1128,7 +1130,7 @@ static void flip_partition_literals (struct sweeper *sweeper) { if (TERMINATED (sweep_terminated_2)) break; - if (solver->statistics.kitten_ticks > sweeper->limit.ticks) + if (solver->statistics_.kitten_ticks > sweeper->limit.ticks) break; } while (flipped && round < max_rounds); LOG ("flipped %u equivalence candidates in total in %u rounds", @@ -1145,9 +1147,9 @@ static bool sweep_equivalence_candidates (sweeper *sweeper, unsigned lit, kitten *kitten = solver->kitten; const unsigned *const begin = BEGIN_STACK (sweeper->partition); unsigned *const end = END_STACK (sweeper->partition); - assert (begin + 3 <= end); - assert (end[-3] == lit); - assert (end[-2] == other); + KISSAT_assert (begin + 3 <= end); + KISSAT_assert (end[-3] == lit); + KISSAT_assert (end[-2] == other); const unsigned third = (end - begin == 3) ? INVALID_LIT : end[-4]; const int status = kitten_status (kitten); if (status == 10 && kitten_flip_literal (kitten, lit)) { @@ -1269,22 +1271,22 @@ static bool sweep_equivalence_candidates (sweeper *sweeper, unsigned lit, static const char *sweep_variable (sweeper *sweeper, unsigned idx) { kissat *solver = sweeper->solver; - assert (!solver->inconsistent); + KISSAT_assert (!solver->inconsistent); if (!ACTIVE (idx)) return "inactive variable"; const unsigned start = LIT (idx); if (sweeper->reprs[start] != start) return "non-representative variable"; - assert (EMPTY_STACK (sweeper->vars)); - assert (EMPTY_STACK (sweeper->refs)); - assert (EMPTY_STACK (sweeper->backbone)); - assert (EMPTY_STACK (sweeper->partition)); - assert (!sweeper->encoded); + KISSAT_assert (EMPTY_STACK (sweeper->vars)); + KISSAT_assert (EMPTY_STACK (sweeper->refs)); + KISSAT_assert (EMPTY_STACK (sweeper->backbone)); + KISSAT_assert (EMPTY_STACK (sweeper->partition)); + KISSAT_assert (!sweeper->encoded); INC (sweep_variables); LOG ("sweeping %s", LOGVAR (idx)); - assert (!VALUE (start)); + KISSAT_assert (!VALUE (start)); LOG ("starting sweeping[0]"); add_literal_to_environment (sweeper, 0, start); LOG ("finished sweeping[0]"); @@ -1361,9 +1363,9 @@ static const char *sweep_variable (sweeper *sweeper, unsigned idx) { LOG ("sub-solver returns '%d'", res); if (res == 10) { init_backbone_and_partition (sweeper); -#ifndef QUIET - uint64_t units = solver->statistics.sweep_units; - uint64_t solved = solver->statistics.sweep_solved; +#ifndef KISSAT_QUIET + uint64_t units = solver->statistics_.sweep_units; + uint64_t solved = solver->statistics_.sweep_solved; #endif START (sweepbackbone); while (!EMPTY_STACK (sweeper->backbone)) { @@ -1389,19 +1391,19 @@ static const char *sweep_variable (sweeper *sweeper, unsigned idx) { success = true; } STOP (sweepbackbone); -#ifndef QUIET - units = solver->statistics.sweep_units - units; - solved = solver->statistics.sweep_solved - solved; +#ifndef KISSAT_QUIET + units = solver->statistics_.sweep_units - units; + solved = solver->statistics_.sweep_solved - solved; kissat_extremely_verbose ( solver, "complete swept variable %d backbone with %" PRIu64 " units in %" PRIu64 " solver calls", kissat_export_literal (solver, LIT (idx)), units, solved); #endif - assert (EMPTY_STACK (sweeper->backbone)); -#ifndef QUIET - uint64_t equivalences = solver->statistics.sweep_equivalences; - solved = solver->statistics.sweep_solved; + KISSAT_assert (EMPTY_STACK (sweeper->backbone)); +#ifndef KISSAT_QUIET + uint64_t equivalences = solver->statistics_.sweep_equivalences; + solved = solver->statistics_.sweep_solved; #endif START (sweepequivalences); while (!EMPTY_STACK (sweeper->partition)) { @@ -1422,7 +1424,7 @@ static const char *sweep_variable (sweeper *sweeper, unsigned idx) { break; if (SIZE_STACK (sweeper->partition) > 2) { const unsigned *end = END_STACK (sweeper->partition); - assert (end[-1] == INVALID_LIT); + KISSAT_assert (end[-1] == INVALID_LIT); unsigned lit = end[-3]; unsigned other = end[-2]; if (sweep_equivalence_candidates (sweeper, lit, other)) @@ -1431,9 +1433,9 @@ static const char *sweep_variable (sweeper *sweeper, unsigned idx) { CLEAR_STACK (sweeper->partition); } STOP (sweepequivalences); -#ifndef QUIET - equivalences = solver->statistics.sweep_equivalences - equivalences; - solved = solver->statistics.sweep_solved - solved; +#ifndef KISSAT_QUIET + equivalences = solver->statistics_.sweep_equivalences - equivalences; + solved = solver->statistics_.sweep_solved - solved; if (equivalences) kissat_extremely_verbose ( solver, @@ -1456,7 +1458,7 @@ DONE: return "unsuccessfully without reaching limit"; else if (success && !limit_reached) return "successfully without reaching limit"; - assert (!success && limit_reached); + KISSAT_assert (!success && limit_reached); return "unsuccessfully and reached limit"; } @@ -1520,7 +1522,7 @@ static unsigned schedule_all_other_not_scheduled_yet (sweeper *sweeper) { PUSH_STACK (fresh, cand); } const size_t size = SIZE_STACK (fresh); - assert (size <= UINT_MAX); + KISSAT_assert (size <= UINT_MAX); RADIX_STACK (sweep_candidate, unsigned, fresh, RANK_SWEEP_CANDIDATE); for (all_stack (sweep_candidate, cand, fresh)) schedule_outer (sweeper, cand.idx); @@ -1575,7 +1577,7 @@ static void mark_incomplete (sweeper *sweeper) { marked++; } solver->sweep_incomplete = true; -#ifndef QUIET +#ifndef KISSAT_QUIET kissat_extremely_verbose ( solver, "marked %u scheduled sweeping variables as incomplete", marked); @@ -1590,7 +1592,7 @@ static unsigned schedule_sweeping (sweeper *sweeper) { const unsigned scheduled = fresh + rescheduled; const unsigned incomplete = incomplete_variables (sweeper); kissat *solver = sweeper->solver; -#ifndef QUIET +#ifndef KISSAT_QUIET kissat_phase (solver, "sweep", GET (sweep), "scheduled %u variables %.0f%% " "(%u rescheduled %.0f%%, %u incomplete %.0f%%)", @@ -1600,7 +1602,7 @@ static unsigned schedule_sweeping (sweeper *sweeper) { incomplete, kissat_percent (incomplete, scheduled)); #endif if (incomplete) - assert (solver->sweep_incomplete); + KISSAT_assert (solver->sweep_incomplete); else { if (solver->sweep_incomplete) INC (sweep_completed); @@ -1612,18 +1614,18 @@ static unsigned schedule_sweeping (sweeper *sweeper) { static void unschedule_sweeping (sweeper *sweeper, unsigned swept, unsigned scheduled) { kissat *solver = sweeper->solver; -#ifdef QUIET +#ifdef KISSAT_QUIET (void) scheduled, (void) swept; #endif - assert (EMPTY_STACK (solver->sweep_schedule)); - assert (solver->sweep_incomplete); + KISSAT_assert (EMPTY_STACK (solver->sweep_schedule)); + KISSAT_assert (solver->sweep_incomplete); flags *flags = solver->flags; for (all_scheduled (idx)) if (flags[idx].active) { PUSH_STACK (solver->sweep_schedule, idx); LOG ("untried scheduled %s", LOGVAR (idx)); } -#ifndef QUIET +#ifndef KISSAT_QUIET const unsigned retained = SIZE_STACK (solver->sweep_schedule); kissat_extremely_verbose ( solver, "retained %u variables %.0f%% to be swept next time", @@ -1654,11 +1656,11 @@ bool kissat_sweep (kissat *solver) { return false; if (DELAYING (sweep)) return false; - assert (!solver->level); - assert (!solver->unflushed); + KISSAT_assert (!solver->level); + KISSAT_assert (!solver->unflushed); START (sweep); INC (sweep); - statistics *statistics = &solver->statistics; + statistics *statistics = &solver->statistics_; uint64_t equivalences = statistics->sweep_equivalences; uint64_t units = statistics->sweep_units; sweeper sweeper; @@ -1670,13 +1672,13 @@ bool kissat_sweep (kissat *solver) { break; if (TERMINATED (sweep_terminated_8)) break; - if (solver->statistics.kitten_ticks > sweeper.limit.ticks) + if (solver->statistics_.kitten_ticks > sweeper.limit.ticks) break; unsigned idx = next_scheduled (&sweeper); if (idx == INVALID_IDX) break; FLAGS (idx)->sweep = false; -#ifndef QUIET +#ifndef KISSAT_QUIET const char *res = #endif sweep_variable (&sweeper, idx); @@ -1688,13 +1690,13 @@ bool kissat_sweep (kissat *solver) { "found %" PRIu64 " equivalences and %" PRIu64 " units after sweeping %" PRIu64 " variables ", statistics->sweep_equivalences - equivalences, - solver->statistics.sweep_units - units, swept); + solver->statistics_.sweep_units - units, swept); limit *= 10; } } kissat_very_verbose (solver, "swept %" PRIu64 " variables", swept); equivalences = statistics->sweep_equivalences - equivalences, - units = solver->statistics.sweep_units - units; + units = solver->statistics_.sweep_units - units; kissat_phase (solver, "sweep", GET (sweep), "found %" PRIu64 " equivalences and %" PRIu64 " units", equivalences, units); @@ -1707,8 +1709,8 @@ bool kissat_sweep (kissat *solver) { } uint64_t eliminated = equivalences + units; -#ifndef QUIET - assert (solver->active >= inactive); +#ifndef KISSAT_QUIET + KISSAT_assert (solver->active >= inactive); solver->active -= inactive; REPORT (!eliminated, '='); solver->active += inactive; @@ -1722,3 +1724,5 @@ bool kissat_sweep (kissat *solver) { STOP (sweep); return eliminated; } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/sweep.h b/src/sat/kissat/sweep.h index a0f81b8b0..995c61c79 100644 --- a/src/sat/kissat/sweep.h +++ b/src/sat/kissat/sweep.h @@ -3,7 +3,12 @@ #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + struct kissat; bool kissat_sweep (struct kissat *); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/terminate.c b/src/sat/kissat/terminate.c index c1cfe7549..25b91a866 100644 --- a/src/sat/kissat/terminate.c +++ b/src/sat/kissat/terminate.c @@ -1,7 +1,9 @@ #include "terminate.h" #include "print.h" -#ifndef QUIET +ABC_NAMESPACE_IMPL_START + +#ifndef KISSAT_QUIET void kissat_report_termination (kissat *solver, const char *name, const char *file, long lineno, @@ -13,3 +15,5 @@ void kissat_report_termination (kissat *solver, const char *name, #else int kissat_terminate_dummy_to_avoid_warning; #endif + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/terminate.h b/src/sat/kissat/terminate.h index 731f584b8..853adecd1 100644 --- a/src/sat/kissat/terminate.h +++ b/src/sat/kissat/terminate.h @@ -3,7 +3,10 @@ #include "internal.h" -#ifndef QUIET +#include "global.h" +ABC_NAMESPACE_HEADER_START + +#ifndef KISSAT_QUIET void kissat_report_termination (kissat *, const char *name, const char *file, long lineno, const char *fun); @@ -12,7 +15,7 @@ void kissat_report_termination (kissat *, const char *name, static inline bool kissat_terminated (kissat *solver, int bit, const char *name, const char *file, long lineno, const char *fun) { - assert (0 <= bit), assert (bit < 64); + KISSAT_assert (0 <= bit), KISSAT_assert (bit < 64); #ifdef COVERAGE const uint64_t mask = (uint64_t) 1 << bit; if (!(solver->termination.flagged & mask)) @@ -22,7 +25,7 @@ static inline bool kissat_terminated (kissat *solver, int bit, if (!solver->termination.flagged) return false; #endif -#ifndef QUIET +#ifndef KISSAT_QUIET kissat_report_termination (solver, name, file, lineno, fun); #else (void) file; @@ -30,7 +33,7 @@ static inline bool kissat_terminated (kissat *solver, int bit, (void) lineno; (void) name; #endif -#if !defined(COVERAGE) && defined(NDEBUG) +#if !defined(COVERAGE) && defined(KISSAT_NDEBUG) (void) bit; #endif return true; @@ -83,4 +86,6 @@ static inline bool kissat_terminated (kissat *solver, int bit, #define walk_terminated_1 42 #define warmup_terminated_1 43 +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/tiers.c b/src/sat/kissat/tiers.c index 3fb49e104..3f044d746 100644 --- a/src/sat/kissat/tiers.c +++ b/src/sat/kissat/tiers.c @@ -3,9 +3,11 @@ #include "logging.h" #include "print.h" +ABC_NAMESPACE_IMPL_START + static void compute_tier_limits (kissat *solver, bool stable, unsigned *tier1_ptr, unsigned *tier2_ptr) { - statistics *statistics = &solver->statistics; + statistics *statistics = &solver->statistics_; uint64_t *used_stats = statistics->used[stable].glue; uint64_t total_used = 0; for (unsigned glue = 0; glue <= MAX_GLUE_USED; glue++) @@ -40,8 +42,8 @@ static void compute_tier_limits (kissat *solver, bool stable, tier2 = MAX (GET_OPTION (tier2), tier1); } else if (tier2 < 0) tier2 = tier1; - assert (0 <= tier1); - assert (0 <= tier2); + KISSAT_assert (0 <= tier1); + KISSAT_assert (0 <= tier2); *tier1_ptr = tier1; *tier2_ptr = tier2; LOG ("%s tier1 limit %u", stable ? "stable" : "focused", tier1); @@ -74,16 +76,16 @@ static unsigned decimal_digits (uint64_t i) { void kissat_print_tier_usage_statistics (kissat *solver, bool stable) { unsigned tier1, tier2; compute_tier_limits (solver, stable, &tier1, &tier2); - statistics *statistics = &solver->statistics; + statistics *statistics = &solver->statistics_; uint64_t *used_stats = statistics->used[stable].glue; uint64_t total_used = 0; for (unsigned glue = 0; glue <= MAX_GLUE_USED; glue++) total_used += used_stats[glue]; const char *mode = stable ? "stable" : "focused"; - assert (tier1 <= tier2); + KISSAT_assert (tier1 <= tier2); unsigned span = tier2 - tier1 + 1; const unsigned max_printed = 5; - assert (max_printed & 1), assert (max_printed / 2 > 0); + KISSAT_assert (max_printed & 1), KISSAT_assert (max_printed / 2 > 0); unsigned prefix, suffix; if (span > max_printed) { prefix = tier1 + max_printed / 2 - 1; @@ -159,3 +161,5 @@ void kissat_print_tier_usage_statistics (kissat *solver, bool stable) { break; } } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/tiers.h b/src/sat/kissat/tiers.h index 3b7acb284..c706ccc62 100644 --- a/src/sat/kissat/tiers.h +++ b/src/sat/kissat/tiers.h @@ -3,10 +3,15 @@ #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + struct kissat; void kissat_compute_and_set_tier_limits (struct kissat *); void kissat_print_tier_usage_statistics (struct kissat *solver, bool stable); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/trail.c b/src/sat/kissat/trail.c index 8b1882f53..256da6cfc 100644 --- a/src/sat/kissat/trail.c +++ b/src/sat/kissat/trail.c @@ -3,12 +3,14 @@ #include "inline.h" #include "propsearch.h" +ABC_NAMESPACE_IMPL_START + void kissat_flush_trail (kissat *solver) { - assert (!solver->level); - assert (solver->unflushed); - assert (!solver->inconsistent); - assert (kissat_propagated (solver)); - assert (SIZE_ARRAY (solver->trail) == solver->unflushed); + KISSAT_assert (!solver->level); + KISSAT_assert (solver->unflushed); + KISSAT_assert (!solver->inconsistent); + KISSAT_assert (kissat_propagated (solver)); + KISSAT_assert (SIZE_ARRAY (solver->trail) == solver->unflushed); LOG ("flushed %zu units from trail", SIZE_ARRAY (solver->trail)); CLEAR_ARRAY (solver->trail); kissat_reset_propagate (solver); @@ -18,24 +20,24 @@ void kissat_flush_trail (kissat *solver) { void kissat_mark_reason_clauses (kissat *solver, reference start) { LOG ("starting marking reason clauses at clause[%" REFERENCE_FORMAT "]", start); - assert (!solver->unflushed); + KISSAT_assert (!solver->unflushed); #ifdef LOGGING unsigned reasons = 0; #endif ward *arena = BEGIN_STACK (solver->arena); for (all_stack (unsigned, lit, solver->trail)) { assigned *a = ASSIGNED (lit); - assert (a->level > 0); + KISSAT_assert (a->level > 0); if (a->binary) continue; const reference ref = a->reason; - assert (ref != UNIT_REASON); + KISSAT_assert (ref != UNIT_REASON); if (ref == DECISION_REASON) continue; if (ref < start) continue; clause *c = (clause *) (arena + ref); - assert (kissat_clause_in_arena (solver, c)); + KISSAT_assert (kissat_clause_in_arena (solver, c)); c->reason = true; #ifdef LOGGING reasons++; @@ -46,9 +48,9 @@ void kissat_mark_reason_clauses (kissat *solver, reference start) { bool kissat_flush_and_mark_reason_clauses (kissat *solver, reference start) { - assert (solver->watching); - assert (!solver->inconsistent); - assert (kissat_propagated (solver)); + KISSAT_assert (solver->watching); + KISSAT_assert (!solver->inconsistent); + KISSAT_assert (kissat_propagated (solver)); if (solver->unflushed) { LOG ("need to flush %u units from trail", solver->unflushed); @@ -64,25 +66,25 @@ bool kissat_flush_and_mark_reason_clauses (kissat *solver, void kissat_unmark_reason_clauses (kissat *solver, reference start) { LOG ("starting unmarking reason clauses at clause[%" REFERENCE_FORMAT "]", start); - assert (!solver->unflushed); + KISSAT_assert (!solver->unflushed); #ifdef LOGGING unsigned reasons = 0; #endif ward *arena = BEGIN_STACK (solver->arena); for (all_stack (unsigned, lit, solver->trail)) { assigned *a = ASSIGNED (lit); - assert (a->level > 0); + KISSAT_assert (a->level > 0); if (a->binary) continue; const reference ref = a->reason; - assert (ref != UNIT_REASON); + KISSAT_assert (ref != UNIT_REASON); if (ref == DECISION_REASON) continue; if (ref < start) continue; clause *c = (clause *) (arena + ref); - assert (kissat_clause_in_arena (solver, c)); - assert (c->reason); + KISSAT_assert (kissat_clause_in_arena (solver, c)); + KISSAT_assert (c->reason); c->reason = false; #ifdef LOGGING reasons++; @@ -90,3 +92,5 @@ void kissat_unmark_reason_clauses (kissat *solver, reference start) { } LOG ("unmarked %u reason clauses", reasons); } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/trail.h b/src/sat/kissat/trail.h index ca84203f2..8dcd3c57e 100644 --- a/src/sat/kissat/trail.h +++ b/src/sat/kissat/trail.h @@ -5,6 +5,9 @@ #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + struct kissat; void kissat_flush_trail (struct kissat *); @@ -13,4 +16,6 @@ bool kissat_flush_and_mark_reason_clauses (struct kissat *, void kissat_unmark_reason_clauses (struct kissat *, reference start); void kissat_mark_reason_clauses (struct kissat *, reference start); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/transitive.c b/src/sat/kissat/transitive.c index 2c06ff5e5..3aa58e24e 100644 --- a/src/sat/kissat/transitive.c +++ b/src/sat/kissat/transitive.c @@ -14,12 +14,14 @@ #include +ABC_NAMESPACE_IMPL_START + static void transitive_assign (kissat *solver, unsigned lit) { LOG ("transitive assign %s", LOGLIT (lit)); value *values = solver->values; const unsigned not_lit = NOT (lit); - assert (!values[lit]); - assert (!values[not_lit]); + KISSAT_assert (!values[lit]); + KISSAT_assert (!values[not_lit]); values[lit] = 1; values[not_lit] = -1; PUSH_ARRAY (solver->trail, lit); @@ -29,14 +31,14 @@ static void transitive_backtrack (kissat *solver, unsigned *saved) { value *values = solver->values; unsigned *end_trail = END_ARRAY (solver->trail); - assert (saved <= end_trail); + KISSAT_assert (saved <= end_trail); while (end_trail != saved) { const unsigned lit = *--end_trail; LOG ("transitive unassign %s", LOGLIT (lit)); const unsigned not_lit = NOT (lit); - assert (values[lit] > 0); - assert (values[not_lit] < 0); + KISSAT_assert (values[lit] > 0); + KISSAT_assert (values[not_lit] < 0); values[lit] = values[not_lit] = 0; } @@ -46,12 +48,12 @@ static void transitive_backtrack (kissat *solver, unsigned *saved) { } static void prioritize_binaries (kissat *solver) { - assert (solver->watching); + KISSAT_assert (solver->watching); statches large; INIT_STACK (large); watches *all_watches = solver->watches; for (all_literals (lit)) { - assert (EMPTY_STACK (large)); + KISSAT_assert (EMPTY_STACK (large)); watches *watches = all_watches + lit; watch *begin_watches = BEGIN_WATCHES (*watches), *q = begin_watches; const watch *const end_watches = END_WATCHES (*watches), *p = q; @@ -68,7 +70,7 @@ static void prioritize_binaries (kissat *solver) { watch const *r = BEGIN_STACK (large); while (r != end_large) *q++ = *r++; - assert (q == end_watches); + KISSAT_assert (q == end_watches); CLEAR_STACK (large); } RELEASE_STACK (large); @@ -77,7 +79,7 @@ static void prioritize_binaries (kissat *solver) { static bool transitive_reduce (kissat *solver, unsigned src, uint64_t limit, uint64_t *reduced_ptr, unsigned *units) { bool res = false; - assert (!VALUE (src)); + KISSAT_assert (!VALUE (src)); LOG ("transitive reduce %s", LOGLIT (src)); watches *all_watches = solver->watches; watches *src_watches = all_watches + src; @@ -102,9 +104,9 @@ static bool transitive_reduce (kissat *solver, unsigned src, uint64_t limit, continue; if (VALUE (dst)) continue; - assert (kissat_propagated (solver)); + KISSAT_assert (kissat_propagated (solver)); unsigned *saved = solver->propagate; - assert (!solver->level); + KISSAT_assert (!solver->level); solver->level = 1; transitive_assign (solver, not_src); bool transitive = false; @@ -114,7 +116,7 @@ static bool transitive_reduce (kissat *solver, unsigned src, uint64_t limit, propagate != END_ARRAY (solver->trail)) { const unsigned lit = *propagate++; LOG ("transitive propagate %s", LOGLIT (lit)); - assert (VALUE (lit) > 0); + KISSAT_assert (VALUE (lit) > 0); const unsigned not_lit = NOT (lit); watches *lit_watches = all_watches + not_lit; const watch *const end_lit = END_WATCHES (*lit_watches); @@ -147,9 +149,9 @@ static bool transitive_reduce (kissat *solver, unsigned src, uint64_t limit, } } - assert (solver->probing); + KISSAT_assert (solver->probing); - assert (solver->propagate <= propagate); + KISSAT_assert (solver->propagate <= propagate); const unsigned propagated = propagate - solver->propagate; ADD (transitive_propagations, propagated); @@ -167,7 +169,7 @@ static bool transitive_reduce (kissat *solver, unsigned src, uint64_t limit, INC (transitive_reduced); watches *dst_watches = all_watches + dst; watch dst_watch = src_watch; - assert (dst_watch.binary.lit == dst); + KISSAT_assert (dst_watch.binary.lit == dst); dst_watch.binary.lit = src; REMOVE_WATCHES (*dst_watches, dst_watch); kissat_delete_binary (solver, src, dst); @@ -178,7 +180,7 @@ static bool transitive_reduce (kissat *solver, unsigned src, uint64_t limit, if (failed) break; - if (solver->statistics.transitive_ticks > limit) + if (solver->statistics_.transitive_ticks > limit) break; if (TERMINATED (transitive_terminated_1)) break; @@ -186,8 +188,8 @@ static bool transitive_reduce (kissat *solver, unsigned src, uint64_t limit, if (reduced) { *reduced_ptr += reduced; - assert (begin_src == BEGIN_WATCHES (WATCHES (src))); - assert (end_src == END_WATCHES (WATCHES (src))); + KISSAT_assert (begin_src == BEGIN_WATCHES (WATCHES (src))); + KISSAT_assert (end_src == END_WATCHES (WATCHES (src))); watch *q = begin_src; for (const watch *p = begin_src; p != end_src; p++) { const watch src_watch = *q++ = *p; @@ -198,7 +200,7 @@ static bool transitive_reduce (kissat *solver, unsigned src, uint64_t limit, if (src_watch.binary.lit == ILLEGAL_LIT) q--; } - assert (end_src - q == (ptrdiff_t) reduced); + KISSAT_assert (end_src - q == (ptrdiff_t) reduced); SET_END_OF_WATCHES (*src_watches, q); } @@ -210,7 +212,7 @@ static bool transitive_reduce (kissat *solver, unsigned src, uint64_t limit, kissat_learned_unit (solver, src); - assert (!solver->level); + KISSAT_assert (!solver->level); (void) kissat_probing_propagate (solver, 0, true); } @@ -221,7 +223,7 @@ static inline bool less_stable_transitive (kissat *solver, const flags *const flags, const heap *scores, unsigned a, unsigned b) { -#ifdef NDEBUG +#ifdef KISSAT_NDEBUG (void) solver; #endif const unsigned i = IDX (a); @@ -245,7 +247,7 @@ static inline unsigned less_focused_transitive (kissat *solver, const flags *const flags, const links *links, unsigned a, unsigned b) { -#ifdef NDEBUG +#ifdef KISSAT_NDEBUG (void) solver; #endif const unsigned i = IDX (a); @@ -287,7 +289,7 @@ static void sort_transitive (kissat *solver, unsigneds *probes) { } static void schedule_transitive (kissat *solver, unsigneds *probes) { - assert (EMPTY_STACK (*probes)); + KISSAT_assert (EMPTY_STACK (*probes)); for (all_variables (idx)) if (ACTIVE (idx)) PUSH_STACK (*probes, idx); @@ -299,17 +301,17 @@ static void schedule_transitive (kissat *solver, unsigneds *probes) { void kissat_transitive_reduction (kissat *solver) { if (solver->inconsistent) return; - assert (solver->watching); - assert (solver->probing); - assert (!solver->level); + KISSAT_assert (solver->watching); + KISSAT_assert (solver->probing); + KISSAT_assert (!solver->level); if (!GET_OPTION (transitive)) return; if (TERMINATED (transitive_terminated_2)) return; START (transitive); INC (transitive_reductions); -#if !defined(NDEBUG) || defined(METRICS) - assert (!solver->transitive_reducing); +#if !defined(KISSAT_NDEBUG) || defined(METRICS) + KISSAT_assert (!solver->transitive_reducing); solver->transitive_reducing = true; #endif prioritize_binaries (solver); @@ -319,9 +321,9 @@ void kissat_transitive_reduction (kissat *solver) { SET_EFFORT_LIMIT (limit, transitive, transitive_ticks); -#ifndef QUIET +#ifndef KISSAT_QUIET const unsigned active = solver->active; - const uint64_t old_ticks = solver->statistics.transitive_ticks; + const uint64_t old_ticks = solver->statistics_.transitive_ticks; kissat_extremely_verbose ( solver, "starting with %" PRIu64 " transitive ticks", old_ticks); unsigned probed = 0; @@ -339,14 +341,14 @@ void kissat_transitive_reduction (kissat *solver) { const unsigned lit = 2 * idx + sign; if (solver->values[lit]) continue; -#ifndef QUIET +#ifndef KISSAT_QUIET probed++; #endif if (transitive_reduce (solver, lit, limit, &reduced, &units)) success = true; if (solver->inconsistent) terminate = true; - else if (solver->statistics.transitive_ticks > limit) + else if (solver->statistics_.transitive_ticks > limit) terminate = true; else if (TERMINATED (transitive_terminated_3)) terminate = true; @@ -366,8 +368,8 @@ void kissat_transitive_reduction (kissat *solver) { kissat_very_verbose (solver, "transitive reduction complete"); RELEASE_STACK (probes); -#ifndef QUIET - const uint64_t new_ticks = solver->statistics.transitive_ticks; +#ifndef KISSAT_QUIET + const uint64_t new_ticks = solver->statistics_.transitive_ticks; const uint64_t delta_ticks = new_ticks - old_ticks; kissat_extremely_verbose ( solver, "finished at %" PRIu64 " after %" PRIu64 " transitive ticks", @@ -377,13 +379,15 @@ void kissat_transitive_reduction (kissat *solver) { "probed %u (%.0f%%): reduced %" PRIu64 ", units %u", probed, kissat_percent (probed, 2 * active), reduced, units); -#if !defined(NDEBUG) || defined(METRICS) - assert (solver->transitive_reducing); +#if !defined(KISSAT_NDEBUG) || defined(METRICS) + KISSAT_assert (solver->transitive_reducing); solver->transitive_reducing = false; #endif REPORT (!success, 't'); STOP (transitive); -#ifdef QUIET +#ifdef KISSAT_QUIET (void) success; #endif } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/transitive.h b/src/sat/kissat/transitive.h index ec0011460..214656824 100644 --- a/src/sat/kissat/transitive.h +++ b/src/sat/kissat/transitive.h @@ -1,8 +1,13 @@ #ifndef _transitive_h_INCLUDED #define _transitive_h_INCLUDED +#include "global.h" +ABC_NAMESPACE_HEADER_START + struct kissat; void kissat_transitive_reduction (struct kissat *); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/utilities.c b/src/sat/kissat/utilities.c index 4ea4e0b8f..9a6b08b84 100644 --- a/src/sat/kissat/utilities.c +++ b/src/sat/kissat/utilities.c @@ -2,6 +2,8 @@ #include +ABC_NAMESPACE_IMPL_START + bool kissat_has_suffix (const char *str, const char *suffix) { const char *p = str; while (*p) @@ -14,3 +16,5 @@ bool kissat_has_suffix (const char *str, const char *suffix) { return false; return q == suffix; } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/utilities.h b/src/sat/kissat/utilities.h index 392aaafef..2a9896341 100644 --- a/src/sat/kissat/utilities.h +++ b/src/sat/kissat/utilities.h @@ -6,7 +6,35 @@ #include #include -typedef uintptr_t word; +#ifdef _MSC_VER +#include +static inline int __builtin_clz(unsigned x) { + unsigned long r; + _BitScanReverse(&r, x); + return (int)(r ^ 31); +} + +static inline int __builtin_clzll(unsigned long long x) { +#if defined(_WIN64) + unsigned long r; + _BitScanReverse64(&r, x); + return (int)(r ^ 63); +#else + int l = __builtin_clz((unsigned)x) + 32; + int h = __builtin_clz((unsigned)(x >> 32)); + return !!((unsigned)(x >> 32)) ? h : l; +#endif +} + +static inline int __builtin_clzl(unsigned long x) { + return sizeof(x) == 8 ? __builtin_clzll(x) : __builtin_clz((unsigned)x); +} +#endif + +#include "global.h" +ABC_NAMESPACE_HEADER_START + +//typedef uintptr_t word; typedef uintptr_t w2rd[2]; #define WORD_ALIGNMENT_MASK (sizeof (word) - 1) @@ -21,11 +49,11 @@ typedef uintptr_t w2rd[2]; static inline word kissat_cache_lines (word n, size_t size) { if (!n) return 0; -#ifdef NDEBUG +#ifdef KISSAT_NDEBUG (void) size; #endif - assert (size == 4); - assert (ASSUMED_LD_CACHE_LINE_BYTES > 2); + KISSAT_assert (size == 4); + KISSAT_assert (ASSUMED_LD_CACHE_LINE_BYTES > 2); const unsigned shift = ASSUMED_LD_CACHE_LINE_BYTES - 2u; const word mask = (((word) 1) << shift) - 1; const word masked = n + mask; @@ -131,6 +159,8 @@ static inline unsigned kissat_log2_ceiling_of_uint64 (uint64_t x) { #define MAX(A, B) ((A) < (B) ? (B) : (A)) -#define ABS(A) (assert ((int) (A) != INT_MIN), (A) < 0 ? -(A) : (A)) +#define ABS(A) (KISSAT_assert ((int) (A) != INT_MIN), (A) < 0 ? -(A) : (A)) + +ABC_NAMESPACE_HEADER_END #endif diff --git a/src/sat/kissat/value.h b/src/sat/kissat/value.h index efea7391a..92324ca53 100644 --- a/src/sat/kissat/value.h +++ b/src/sat/kissat/value.h @@ -1,13 +1,18 @@ #ifndef _value_h_INCLUDED #define _value_h_INCLUDED +#include "global.h" +ABC_NAMESPACE_HEADER_START + typedef signed char value; typedef signed char mark; -#define VALUE(LIT) (solver->values[assert ((LIT) < LITS), (LIT)]) +#define VALUE(LIT) (solver->values[KISSAT_assert ((LIT) < LITS), (LIT)]) -#define MARK(LIT) (solver->marks[assert ((LIT) < LITS), (LIT)]) +#define MARK(LIT) (solver->marks[KISSAT_assert ((LIT) < LITS), (LIT)]) #define BOOL_TO_VALUE(B) ((signed char) ((B) ? -1 : 1)) +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/vector.c b/src/sat/kissat/vector.c index 728a66f6d..1383c97c5 100644 --- a/src/sat/kissat/vector.c +++ b/src/sat/kissat/vector.c @@ -9,7 +9,9 @@ #include #include -#ifndef COMPACT +ABC_NAMESPACE_IMPL_START + +#ifndef KISSAT_COMPACT static void fix_vector_pointers_after_moving_stack (kissat *solver, ptrdiff_t moved) { @@ -48,20 +50,20 @@ unsigned *kissat_enlarge_vector (kissat *solver, vector *vector) { LOG2 ("enlarging vector %zu[%zu] at %p", old_offset, old_vector_size, (void *) vector); #endif - assert (old_vector_size < MAX_VECTORS / 2); + KISSAT_assert (old_vector_size < MAX_VECTORS / 2); const size_t new_vector_size = old_vector_size ? 2 * old_vector_size : 1; size_t old_stack_size = SIZE_STACK (*stack); size_t capacity = CAPACITY_STACK (*stack); - assert (kissat_is_power_of_two (MAX_VECTORS)); - assert (capacity <= MAX_VECTORS); + KISSAT_assert (kissat_is_power_of_two (MAX_VECTORS)); + KISSAT_assert (capacity <= MAX_VECTORS); size_t available = capacity - old_stack_size; if (new_vector_size > available) { -#if !defined(QUIET) || !defined(COMPACT) +#if !defined(KISSAT_QUIET) || !defined(KISSAT_COMPACT) unsigned *old_begin_stack = BEGIN_STACK (*stack); #endif unsigned enlarged = 0; do { - assert (kissat_is_zero_or_power_of_two (capacity)); + KISSAT_assert (kissat_is_zero_or_power_of_two (capacity)); if (capacity == MAX_VECTORS) kissat_fatal ("maximum vector stack size " @@ -77,34 +79,34 @@ unsigned *kissat_enlarge_vector (kissat *solver, vector *vector) { if (enlarged) { INC (vectors_enlarged); -#if !defined(QUIET) || !defined(COMPACT) +#if !defined(KISSAT_QUIET) || !defined(KISSAT_COMPACT) unsigned *new_begin_stack = BEGIN_STACK (*stack); const ptrdiff_t moved = (char *) new_begin_stack - (char *) old_begin_stack; #endif -#ifndef QUIET +#ifndef KISSAT_QUIET kissat_phase (solver, "vectors", GET (vectors_enlarged), "enlarged to %s entries %s (%s)", FORMAT_COUNT (capacity), FORMAT_BYTES (capacity * sizeof (unsigned)), (moved ? "moved" : "in place")); #endif -#ifndef COMPACT +#ifndef KISSAT_COMPACT if (moved) fix_vector_pointers_after_moving_stack (solver, moved); #endif } - assert (capacity <= MAX_VECTORS); - assert (new_vector_size <= available); + KISSAT_assert (capacity <= MAX_VECTORS); + KISSAT_assert (new_vector_size <= available); } unsigned *begin_old_vector = kissat_begin_vector (solver, vector); unsigned *begin_new_vector = END_STACK (*stack); unsigned *middle_new_vector = begin_new_vector + old_vector_size; unsigned *end_new_vector = begin_new_vector + new_vector_size; - assert (end_new_vector <= stack->allocated); + KISSAT_assert (end_new_vector <= stack->allocated); const size_t old_bytes = old_vector_size * sizeof (unsigned); const size_t delta_size = new_vector_size - old_vector_size; - assert (MAX_SIZE_T / sizeof (unsigned) >= delta_size); + KISSAT_assert (MAX_SIZE_T / sizeof (unsigned) >= delta_size); const size_t delta_bytes = delta_size * sizeof (unsigned); if (old_bytes) { memcpy (begin_new_vector, begin_old_vector, old_bytes); @@ -114,9 +116,9 @@ unsigned *kissat_enlarge_vector (kissat *solver, vector *vector) { kissat_add_usable (solver, delta_size); if (delta_bytes) memset (middle_new_vector, 0xff, delta_bytes); -#ifdef COMPACT +#ifdef KISSAT_COMPACT const uint64_t offset = SIZE_STACK (*stack); - assert (offset <= MAX_VECTORS); + KISSAT_assert (offset <= MAX_VECTORS); vector->offset = offset; LOG2 ("enlarged vector at %p to %u[%u]", (void *) vector, vector->offset, vector->size); @@ -130,12 +132,12 @@ unsigned *kissat_enlarge_vector (kissat *solver, vector *vector) { #endif #endif stack->end = end_new_vector; - assert (begin_new_vector < end_new_vector); - assert (kissat_size_vector (vector) == old_vector_size); + KISSAT_assert (begin_new_vector < end_new_vector); + KISSAT_assert (kissat_size_vector (vector) == old_vector_size); return middle_new_vector; } -#ifdef COMPACT +#ifdef KISSAT_COMPACT typedef unsigned rank; @@ -167,12 +169,12 @@ void kissat_defrag_vectors (kissat *solver, size_t size_unsorted, LOG ("defragmenting vectors size %zu capacity %zu usable %zu", size_vectors, CAPACITY_STACK (*stack), solver->vectors.usable); size_t bytes = size_unsorted * sizeof (unsigned); - unsigned *sorted = kissat_malloc (solver, bytes); + unsigned *sorted = (unsigned*)kissat_malloc (solver, bytes); unsigned size_sorted = 0; for (unsigned i = 0; i < size_unsorted; i++) { vector *vector = unsorted + i; if (kissat_empty_vector (vector)) -#ifdef COMPACT +#ifdef KISSAT_COMPACT vector->offset = 0; #else vector->begin = vector->end = 0; @@ -188,10 +190,10 @@ void kissat_defrag_vectors (kissat *solver, size_t size_unsorted, vector *vector = unsorted + j; const size_t size = kissat_size_vector (vector); unsigned *new_end_of_vector = p + size; -#ifdef COMPACT +#ifdef KISSAT_COMPACT const unsigned old_offset = vector->offset; const unsigned new_offset = p - old_begin_stack; - assert (new_offset <= old_offset); + KISSAT_assert (new_offset <= old_offset); vector->offset = new_offset; const unsigned *const q = old_begin_stack + old_offset; #else @@ -203,25 +205,25 @@ void kissat_defrag_vectors (kissat *solver, size_t size_unsorted, vector->begin = p; vector->end = new_end_of_vector; #endif - assert (MAX_SIZE_T / sizeof (unsigned) >= size); + KISSAT_assert (MAX_SIZE_T / sizeof (unsigned) >= size); memmove (p, q, size * sizeof (unsigned)); p = new_end_of_vector; } kissat_free (solver, sorted, bytes); -#ifndef QUIET +#ifndef KISSAT_QUIET const size_t freed = END_STACK (*stack) - p; double freed_fraction = kissat_percent (freed, size_vectors); kissat_phase (solver, "defrag", GET (defragmentations), "freed %zu usable entries %.0f%% thus %s", freed, freed_fraction, FORMAT_BYTES (freed * sizeof (unsigned))); - assert (freed == solver->vectors.usable); + KISSAT_assert (freed == solver->vectors.usable); #endif SET_END_OF_STACK (*stack, p); -#ifndef COMPACT - assert (old_begin_stack == BEGIN_STACK (*stack)); +#ifndef KISSAT_COMPACT + KISSAT_assert (old_begin_stack == BEGIN_STACK (*stack)); #endif SHRINK_STACK (*stack); -#ifndef COMPACT +#ifndef KISSAT_COMPACT unsigned *new_begin_stack = BEGIN_STACK (*stack); const ptrdiff_t moved = (char *) new_begin_stack - (char *) old_begin_stack; @@ -237,16 +239,16 @@ void kissat_remove_from_vector (kissat *solver, vector *vector, unsigned remove) { unsigned *begin = kissat_begin_vector (solver, vector), *p = begin; const unsigned *const end = kissat_end_vector (solver, vector); - assert (p != end); + KISSAT_assert (p != end); while (*p != remove) - p++, assert (p != end); + p++, KISSAT_assert (p != end); while (++p != end) p[-1] = *p; p[-1] = INVALID_VECTOR_ELEMENT; -#ifdef COMPACT +#ifdef KISSAT_COMPACT vector->size--; #else - assert (vector->begin < vector->end); + KISSAT_assert (vector->begin < vector->end); vector->end--; #endif kissat_inc_usable (solver); @@ -259,10 +261,10 @@ void kissat_remove_from_vector (kissat *solver, vector *vector, void kissat_resize_vector (kissat *solver, vector *vector, size_t new_size) { const size_t old_size = kissat_size_vector (vector); - assert (new_size <= old_size); + KISSAT_assert (new_size <= old_size); if (new_size == old_size) return; -#ifdef COMPACT +#ifdef KISSAT_COMPACT vector->size = new_size; #else vector->end = vector->begin + new_size; @@ -291,8 +293,8 @@ void kissat_check_vector (kissat *solver, vector *vector) { const unsigned *const end = kissat_end_vector (solver, vector); if (!solver->transitive_reducing) for (const unsigned *p = begin; p != end; p++) - assert (*p != INVALID_VECTOR_ELEMENT); -#ifdef NDEBUG + KISSAT_assert (*p != INVALID_VECTOR_ELEMENT); +#ifdef KISSAT_NDEBUG (void) solver; #endif } @@ -314,7 +316,9 @@ void kissat_check_vectors (kissat *solver) { for (const unsigned *p = begin + 1; p != end; p++) if (*p == INVALID_VECTOR_ELEMENT) invalid++; - assert (invalid == solver->vectors.usable); + KISSAT_assert (invalid == solver->vectors.usable); } #endif + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/vector.h b/src/sat/kissat/vector.h index 55ff2ac1d..5353a2e7b 100644 --- a/src/sat/kissat/vector.h +++ b/src/sat/kissat/vector.h @@ -6,7 +6,10 @@ #include -#ifdef COMPACT +#include "global.h" +ABC_NAMESPACE_HEADER_START + +#ifdef KISSAT_COMPACT #define LD_MAX_VECTORS (sizeof (word) == 8 ? 32u : 28u) #else #define LD_MAX_VECTORS (sizeof (word) == 8 ? 48u : 28u) @@ -27,7 +30,7 @@ struct vectors { }; struct vector { -#ifdef COMPACT +#ifdef KISSAT_COMPACT unsigned offset; unsigned size; #else @@ -52,4 +55,6 @@ void kissat_remove_from_vector (struct kissat *, vector *, unsigned); void kissat_resize_vector (struct kissat *, vector *, size_t); void kissat_release_vectors (struct kissat *); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/vivify.c b/src/sat/kissat/vivify.c index 6627c640e..f1d677e4d 100644 --- a/src/sat/kissat/vivify.c +++ b/src/sat/kissat/vivify.c @@ -21,6 +21,8 @@ #include #include +ABC_NAMESPACE_IMPL_START + static inline bool more_occurrences (unsigned *counts, unsigned a, unsigned b) { const unsigned s = counts[a], t = counts[b]; @@ -57,7 +59,7 @@ static void count_clause (clause *c, unsigned *counts) { static bool simplify_vivification_candidate (kissat *solver, clause *const c) { - assert (!solver->level); + KISSAT_assert (!solver->level); CLEAR_STACK (solver->clause); const value *const values = solver->values; @@ -74,7 +76,7 @@ static bool simplify_vivification_candidate (kissat *solver, } unsigned non_false = SIZE_STACK (solver->clause); - assert (non_false <= c->size); + KISSAT_assert (non_false <= c->size); if (non_false == c->size) return false; @@ -87,7 +89,7 @@ static bool simplify_vivification_candidate (kissat *solver, return true; } - assert (2 < non_false); + KISSAT_assert (2 < non_false); CHECK_AND_ADD_STACK (solver->clause); ADD_STACK_TO_PROOF (solver->clause); @@ -100,14 +102,14 @@ static bool simplify_vivification_candidate (kissat *solver, for (unsigned i = 0; i < old_size; i++) { const unsigned lit = lits[i]; const value value = values[lit]; - assert (value <= 0); + KISSAT_assert (value <= 0); if (!value) lits[new_size++] = lit; } - assert (2 < new_size); - assert (new_size == non_false); - assert (new_size < old_size); + KISSAT_assert (2 < new_size); + KISSAT_assert (new_size == non_false); + KISSAT_assert (new_size < old_size); c->size = new_size; c->searched = 2; @@ -154,7 +156,7 @@ struct vivifier { size_t scheduled, tried, vivified; countrefs countrefs; unsigneds sorted; -#ifndef QUIET +#ifndef KISSAT_QUIET const char *mode; const char *name; char tag; @@ -166,7 +168,7 @@ typedef struct vivifier vivifier; static void init_vivifier (kissat *solver, vivifier *vivifier) { vivifier->solver = solver; - vivifier->counts = kissat_calloc (solver, LITS, sizeof (unsigned)); + vivifier->counts = (unsigned*)kissat_calloc (solver, LITS, sizeof (unsigned)); INIT_STACK (vivifier->schedule); INIT_STACK (vivifier->countrefs); INIT_STACK (vivifier->sorted); @@ -175,7 +177,7 @@ static void init_vivifier (kissat *solver, vivifier *vivifier) { static void set_vivifier_mode (vivifier *vivifier, int tier) { vivifier->tier = tier; -#ifndef QUIET +#ifndef KISSAT_QUIET switch (tier) { case 1: vivifier->mode = "vivify-tier1"; @@ -188,13 +190,13 @@ static void set_vivifier_mode (vivifier *vivifier, int tier) { vivifier->tag = 'v'; break; case 3: - assert (tier == 3); + KISSAT_assert (tier == 3); vivifier->mode = "vivify-tier3"; vivifier->name = "tier3"; vivifier->tag = 'w'; break; default: - assert (tier == 0); + KISSAT_assert (tier == 0); vivifier->mode = "vivify-irredundant"; vivifier->name = "irredundant"; vivifier->tag = 'x'; @@ -235,7 +237,7 @@ static void schedule_vivification_candidates (vivifier *vivifier) { unsigned lower_glue_limit, upper_glue_limit; unsigned tier1 = vivify_tier1_limit (solver); unsigned tier2 = MAX (tier1, vivify_tier2_limit (solver)); - assert (tier1 <= tier2); + KISSAT_assert (tier1 <= tier2); switch (tier) { case 1: lower_glue_limit = 0; @@ -250,12 +252,12 @@ static void schedule_vivification_candidates (vivifier *vivifier) { upper_glue_limit = UINT_MAX; break; default: - assert (tier == 0); + KISSAT_assert (tier == 0); lower_glue_limit = 0; upper_glue_limit = UINT_MAX; break; } - assert (lower_glue_limit <= upper_glue_limit); + KISSAT_assert (lower_glue_limit <= upper_glue_limit); ward *const arena = BEGIN_STACK (solver->arena); size_t prioritized = 0; unsigned *counts = vivifier->counts; @@ -296,7 +298,7 @@ static void schedule_vivification_candidates (vivifier *vivifier) { "prioritizing all %zu scheduled clauses", scheduled); for (all_stack (reference, ref, *schedule)) { clause *c = (clause *) (arena + ref); - assert (kissat_clause_in_arena (solver, c)); + KISSAT_assert (kissat_clause_in_arena (solver, c)); c->vivify = true; } } @@ -339,7 +341,7 @@ static inline bool worse_candidate (kissat *solver, unsigned *counts, if (p == e && q != f) return false; - assert (p == e && q == f); + KISSAT_assert (p == e && q == f); if (a < b) return true; @@ -371,8 +373,8 @@ static void sort_scheduled_candidate_literals (vivifier *vivifier) { static inline void init_countref (countref *cr, clause *c, reference ref, unsigned *counts) { - assert (COUNTREF_COUNTS <= c->size); - assert (c->size <= MAX_COUNTREF_SIZE); + KISSAT_assert (COUNTREF_COUNTS <= c->size); + KISSAT_assert (c->size <= MAX_COUNTREF_SIZE); cr->size = c->size; cr->vivify = c->vivify; cr->ref = ref; @@ -381,19 +383,24 @@ static inline void init_countref (countref *cr, clause *c, reference ref, unsigned best = INVALID_LIT; unsigned best_count = 0; for (all_literals_in_clause (lit, c)) { + int continue_with_next_literal = 0; for (unsigned j = 0; j != i; j++) - if (lits[j] == lit) - goto CONTINUE_WITH_NEXT_LITERAL; + if (lits[j] == lit) { + continue_with_next_literal = 1; + break; + } + if(continue_with_next_literal) { + continue; + } const unsigned lit_count = counts[lit]; - assert (lit_count); + KISSAT_assert (lit_count); if (lit_count <= best_count) continue; best_count = lit_count; best = lit; - CONTINUE_WITH_NEXT_LITERAL:; } - assert (best != INVALID_LIT); - assert (best_count); + KISSAT_assert (best != INVALID_LIT); + KISSAT_assert (best_count); cr->count[i] = best_count; lits[i] = best; } @@ -404,7 +411,7 @@ static void init_countrefs (vivifier *vivifier) { references *schedule = &vivifier->schedule; countrefs *countrefs = &vivifier->countrefs; unsigned *counts = vivifier->counts; - assert (EMPTY_STACK (*countrefs)); + KISSAT_assert (EMPTY_STACK (*countrefs)); for (all_stack (reference, ref, *schedule)) { clause *c = kissat_dereference_clause (solver, ref); countref countref; @@ -433,14 +440,14 @@ static void copy_countrefs (vivifier *vivifier) { kissat *solver = vivifier->solver; references *schedule = &vivifier->schedule; countrefs *countrefs = &vivifier->countrefs; - assert (EMPTY_STACK (*schedule)); + KISSAT_assert (EMPTY_STACK (*schedule)); for (all_stack (countref, cr, *countrefs)) PUSH_STACK (*schedule, cr.ref); RELEASE_STACK (*countrefs); } static void sort_vivification_candidates (vivifier *vivifier) { -#ifndef QUIET +#ifndef KISSAT_QUIET kissat *solver = vivifier->solver; #endif START (vivifysort); @@ -471,35 +478,35 @@ static void vivify_deduce (vivifier *vivifier, clause *candidate, bool redundant = false; bool subsumes = false; - assert (solver->level); - assert (EMPTY_STACK (solver->clause)); - assert (EMPTY_STACK (solver->analyzed)); + KISSAT_assert (solver->level); + KISSAT_assert (EMPTY_STACK (solver->clause)); + KISSAT_assert (EMPTY_STACK (solver->analyzed)); if (implied != INVALID_LIT) { unsigned not_implied = NOT (implied); LOG ("vivify analyzing %s", LOGLIT (not_implied)); assigned *const a = ASSIGNED (not_implied); - assert (a->level); - assert (!a->analyzed); + KISSAT_assert (a->level); + KISSAT_assert (!a->analyzed); a->analyzed = true; PUSH_STACK (solver->analyzed, not_implied); PUSH_STACK (solver->clause, implied); } else { clause *reason = conflict ? conflict : candidate; - assert (reason), assert (!reason->garbage); + KISSAT_assert (reason), KISSAT_assert (!reason->garbage); if (reason->redundant) redundant = true; subsumes = (reason != candidate); for (all_literals_in_clause (other, reason)) { - assert (VALUE (other) < 0); + KISSAT_assert (VALUE (other) < 0); const value value = kissat_fixed (solver, other); if (value < 0) continue; LOG ("vivify analyzing %s", LOGLIT (other)); - assert (!value); + KISSAT_assert (!value); assigned *const a = ASSIGNED (other); - assert (a->level); - assert (!a->analyzed); + KISSAT_assert (a->level); + KISSAT_assert (!a->analyzed); a->analyzed = true; PUSH_STACK (solver->analyzed, other); if (solver->marks[other] <= 0) @@ -520,11 +527,11 @@ static void vivify_deduce (vivifier *vivifier, clause *candidate, while (analyzed < SIZE_STACK (solver->analyzed)) { const unsigned not_lit = PEEK_STACK (solver->analyzed, analyzed); const unsigned lit = NOT (not_lit); - assert (VALUE (lit) > 0); + KISSAT_assert (VALUE (lit) > 0); analyzed++; assigned *a = ASSIGNED (lit); - assert (a->level); - assert (a->analyzed); + KISSAT_assert (a->level); + KISSAT_assert (a->analyzed); if (a->reason == DECISION_REASON) { LOG ("vivify analyzing decision %s", LOGLIT (not_lit)); PUSH_STACK (solver->clause, not_lit); @@ -536,9 +543,9 @@ static void vivify_deduce (vivifier *vivifier, clause *candidate, *subsuming_ptr = kissat_binary_conflict (solver, lit, other); return; } - assert (VALUE (other) < 0); + KISSAT_assert (VALUE (other) < 0); assigned *b = ASSIGNED (other); - assert (b->level); + KISSAT_assert (b->level); if (b->analyzed) continue; LOGBINARY (lit, other, "vivify analyzing %s reason", LOGLIT (lit)); @@ -548,7 +555,7 @@ static void vivify_deduce (vivifier *vivifier, clause *candidate, const reference ref = a->reason; LOGREF (ref, "vivify analyzing %s reason", LOGLIT (lit)); clause *reason = kissat_dereference_clause (solver, ref); - assert (reason != candidate); + KISSAT_assert (reason != candidate); if (reason->redundant) redundant = true; subsumes = true; @@ -557,8 +564,8 @@ static void vivify_deduce (vivifier *vivifier, clause *candidate, subsumes = false; if (other == lit) continue; - assert (other != not_lit); - assert (VALUE (other) < 0); + KISSAT_assert (other != not_lit); + KISSAT_assert (VALUE (other) < 0); assigned *b = ASSIGNED (other); if (!b->level) continue; @@ -600,7 +607,7 @@ static void reset_vivify_analyzed (vivifier *vivifier) { static bool vivify_shrinkable (kissat *solver, unsigneds *sorted, clause *conflict) { - assert (SIZE_STACK (solver->clause) <= SIZE_STACK (*sorted)); + KISSAT_assert (SIZE_STACK (solver->clause) <= SIZE_STACK (*sorted)); if (SIZE_STACK (solver->clause) == SIZE_STACK (*sorted)) return false; const assigned *const assigned = solver->assigned; @@ -623,10 +630,10 @@ static bool vivify_shrinkable (kissat *solver, unsigneds *sorted, return true; } } else { - assert (value < 0); + KISSAT_assert (value < 0); const unsigned idx = IDX (lit); const struct assigned *const a = assigned + idx; - assert (a->level); + KISSAT_assert (a->level); if (!a->analyzed) { LOG ("vivification non-analyzed %s thus shrinking", LOGLIT (lit)); return true; @@ -644,15 +651,15 @@ static bool vivify_shrinkable (kissat *solver, unsigneds *sorted, static void vivify_learn_unit (kissat *solver, clause *c) { LOG ("vivification learns unit clause"); - assert (SIZE_STACK (solver->clause) == 1); + KISSAT_assert (SIZE_STACK (solver->clause) == 1); kissat_backtrack_without_updating_phases (solver, 0); const unsigned unit = PEEK_STACK (solver->clause, 0); kissat_learned_unit (solver, unit); solver->iterating = true; kissat_mark_clause_as_garbage (solver, c); - assert (!solver->level); + KISSAT_assert (!solver->level); clause *conflict = kissat_probing_propagate (solver, 0, true); - assert (!conflict || solver->inconsistent); + KISSAT_assert (!conflict || solver->inconsistent); INC (vivify_units); (void) conflict; } @@ -660,7 +667,7 @@ static void vivify_learn_unit (kissat *solver, clause *c) { static void vivify_learn_binary (kissat *solver, clause *c) { LOG ("vivification learns binary clause"); kissat_backtrack_without_updating_phases (solver, 0); - assert (SIZE_STACK (solver->clause) == 2); + KISSAT_assert (SIZE_STACK (solver->clause) == 2); if (c->redundant) (void) kissat_new_redundant_clause (solver, 1); else @@ -671,7 +678,7 @@ static void vivify_learn_binary (kissat *solver, clause *c) { static void swap_first_literal_with_best_watch (kissat *solver, unsigned *lits, unsigned size) { - assert (size); + KISSAT_assert (size); unsigned *best_ptr = lits; unsigned first = *best_ptr, best = first; signed char value = VALUE (best); @@ -715,7 +722,7 @@ static void vivify_watch_clause (kissat *solver, clause *c) { static void vivify_learn_large (kissat *solver, clause *c, unsigned implied) { - assert (!c->garbage); + KISSAT_assert (!c->garbage); LOG ("vivification learns large clause"); CHECK_AND_ADD_STACK (solver->clause); @@ -736,7 +743,7 @@ static void vivify_learn_large (kissat *solver, clause *c, unsigneds *learned = &solver->clause; const unsigned old_size = c->size; const unsigned new_size = SIZE_STACK (*learned); - assert (new_size <= old_size); + KISSAT_assert (new_size <= old_size); unsigned *lits = c->lits; memcpy (lits, BEGIN_STACK (*learned), new_size * sizeof *lits); @@ -745,7 +752,7 @@ static void vivify_learn_large (kissat *solver, clause *c, for (all_literals_in_clause (lit, c)) kissat_mark_added_literal (solver, lit); - assert (new_size < old_size); + KISSAT_assert (new_size < old_size); if (!c->shrunken) { c->shrunken = true; lits[old_size - 1] = INVALID_LIT; @@ -760,7 +767,7 @@ static void vivify_learn_large (kissat *solver, clause *c, kissat_backtrack_without_updating_phases (solver, new_size - 2); } else { LOGCLS (c, "vivified shrunken after implied"); - assert (solver->level >= new_size - 1); + KISSAT_assert (solver->level >= new_size - 1); } vivify_watch_clause (solver, c); @@ -780,23 +787,23 @@ static void binary_strengthen_after_instantiation (kissat *solver, clause *c, unsigned remove) { LOG ("vivification instantiation yields binary clause"); - assert (solver->level == 3); + KISSAT_assert (solver->level == 3); unsigned first = INVALID_LIT, second = INVALID_LIT; for (all_literals_in_clause (lit, c)) if (lit != remove) { - assert (VALUE (lit) < 0); + KISSAT_assert (VALUE (lit) < 0); if (LEVEL (lit)) { if (first == INVALID_LIT) first = lit; else { - assert (second == INVALID_LIT); + KISSAT_assert (second == INVALID_LIT); second = lit; } } } - assert (first != INVALID_LIT); - assert (second != INVALID_LIT); + KISSAT_assert (first != INVALID_LIT); + KISSAT_assert (second != INVALID_LIT); LOGBINARY (first, second, "vivified strengthened through instantiation"); CLEAR_STACK (solver->clause); PUSH_STACK (solver->clause, first); @@ -813,7 +820,7 @@ static void binary_strengthen_after_instantiation (kissat *solver, static void large_strengthen_after_instantiation (kissat *solver, clause *c, unsigned remove) { LOG ("vivification instantiation yields large clause"); - assert (solver->level > 3); + KISSAT_assert (solver->level > 3); SHRINK_CLAUSE_IN_PROOF (c, remove, INVALID_LIT); CHECK_SHRINK_CLAUSE (c, remove, INVALID_LIT); @@ -822,7 +829,7 @@ static void large_strengthen_after_instantiation (kissat *solver, clause *c, bool irredundant = !c->redundant; const unsigned old_size = c->size; - assert (old_size > 3); + KISSAT_assert (old_size > 3); unsigned new_size = 0, *lits = c->lits; for (unsigned i = 0; i != old_size; i++) { const unsigned lit = lits[i]; @@ -835,8 +842,8 @@ static void large_strengthen_after_instantiation (kissat *solver, clause *c, kissat_mark_added_literal (solver, lit); } } - assert (2 < new_size); - assert (new_size < old_size); + KISSAT_assert (2 < new_size); + KISSAT_assert (new_size < old_size); if (!c->shrunken) { c->shrunken = true; lits[old_size - 1] = INVALID_LIT; @@ -854,9 +861,9 @@ static void large_strengthen_after_instantiation (kissat *solver, clause *c, static void vivify_strengthen_after_instantiation (kissat *solver, clause *c, unsigned remove) { - assert (solver->level >= 3); - assert (VALUE (remove) > 0); - assert (LEVEL (remove) == solver->level); + KISSAT_assert (solver->level >= 3); + KISSAT_assert (VALUE (remove) > 0); + KISSAT_assert (LEVEL (remove) == solver->level); if (solver->level == 3) binary_strengthen_after_instantiation (solver, c, remove); @@ -870,7 +877,7 @@ static void vivify_mark_sorted_literals (vivifier *vivifier) { unsigneds *sorted = &vivifier->sorted; value *marks = solver->marks; for (all_stack (unsigned, lit, *sorted)) - assert (!marks[lit]), marks[lit] = 1, marks[NOT (lit)] = -1; + KISSAT_assert (!marks[lit]), marks[lit] = 1, marks[NOT (lit)] = -1; } static void vivify_unmark_sorted_literals (vivifier *vivifier) { @@ -879,7 +886,7 @@ static void vivify_unmark_sorted_literals (vivifier *vivifier) { unsigneds *sorted = &vivifier->sorted; value *marks = solver->marks; for (all_stack (unsigned, lit, *sorted)) - assert (solver->marks[lit] > 0), assert (marks[NOT (lit)] < 0), + KISSAT_assert (solver->marks[lit] > 0), KISSAT_assert (marks[NOT (lit)] < 0), marks[lit] = marks[NOT (lit)] = 0; } @@ -912,10 +919,10 @@ static void reestablish_watch_invariant_for_candidate (kissat *solver, return; new_level = second_level; } else { - assert (first_val < 0), assert (second_val < 0); + KISSAT_assert (first_val < 0), KISSAT_assert (second_val < 0); new_level = MIN (first_level, second_level); } - assert (new_level); + KISSAT_assert (new_level); LOGCLS (candidate, "reestablish watch invariant by backtracking to %u", new_level - 1); kissat_backtrack_without_updating_phases (solver, new_level - 1); @@ -923,13 +930,13 @@ static void reestablish_watch_invariant_for_candidate (kissat *solver, static bool vivify_clause (vivifier *vivifier, clause *candidate) { - assert (!candidate->garbage); + KISSAT_assert (!candidate->garbage); kissat *solver = vivifier->solver; - assert (solver->probing); - assert (solver->watching); - assert (!solver->inconsistent); + KISSAT_assert (solver->probing); + KISSAT_assert (solver->watching); + KISSAT_assert (!solver->inconsistent); LOGCLS (candidate, "vivifying candidate"); LOGCOUNTEDCLS (candidate, vivifier->counts, @@ -950,12 +957,12 @@ static bool vivify_clause (vivifier *vivifier, clause *candidate) { PUSH_STACK (*sorted, lit); } - assert (!candidate->garbage); + KISSAT_assert (!candidate->garbage); const unsigned non_false = SIZE_STACK (*sorted); - assert (1 < non_false); - assert (non_false <= candidate->size); + KISSAT_assert (1 < non_false); + KISSAT_assert (non_false <= candidate->size); #ifdef LOGGING if (non_false == candidate->size) @@ -980,7 +987,7 @@ static bool vivify_clause (vivifier *vivifier, clause *candidate) { unit = INVALID_LIT; break; } - assert (value > 0); + KISSAT_assert (value > 0); if (unit != INVALID_LIT) { unit = INVALID_LIT; break; @@ -990,7 +997,7 @@ static bool vivify_clause (vivifier *vivifier, clause *candidate) { reference cand_ref = kissat_reference_clause (solver, candidate); if (unit != INVALID_LIT) { assigned *a = ASSIGNED (unit); - assert (a->level); + KISSAT_assert (a->level); if (a->binary) unit = INVALID_LIT; else { @@ -1003,13 +1010,13 @@ static bool vivify_clause (vivifier *vivifier, clause *candidate) { else { LOG ("candidate is the reason of %s", LOGLIT (unit)); const unsigned level = LEVEL (unit); - assert (level > 0); + KISSAT_assert (level > 0); LOG ("forced to backtrack to level %u", level - 1); kissat_backtrack_without_updating_phases (solver, level - 1); } - assert (EMPTY_STACK (solver->analyzed)); - assert (EMPTY_STACK (solver->clause)); + KISSAT_assert (EMPTY_STACK (solver->analyzed)); + KISSAT_assert (EMPTY_STACK (solver->clause)); unsigned *counts = vivifier->counts; vivify_sort_stack_by_counts (solver, sorted, counts); @@ -1038,7 +1045,7 @@ static bool vivify_clause (vivifier *vivifier, clause *candidate) { LOG ("reusing assumption %s", LOGLIT (not_lit)); INC (vivify_reused); INC (vivify_probes); - assert (VALUE (lit) < 0); + KISSAT_assert (VALUE (lit) < 0); continue; } @@ -1047,29 +1054,29 @@ static bool vivify_clause (vivifier *vivifier, clause *candidate) { } const value value = VALUE (lit); - assert (!value || LEVEL (lit) <= level); + KISSAT_assert (!value || LEVEL (lit) <= level); if (value < 0) { - assert (LEVEL (lit)); + KISSAT_assert (LEVEL (lit)); LOG ("literal %s already falsified", LOGLIT (lit)); continue; } if (value > 0) { - assert (LEVEL (lit)); + KISSAT_assert (LEVEL (lit)); LOG ("literal %s already initially satisfied", LOGLIT (lit)); implied = lit; break; } - assert (!value); + KISSAT_assert (!value); LOG ("literal %s unassigned", LOGLIT (lit)); const unsigned not_lit = NOT (lit); INC (vivify_probes); kissat_internal_assume (solver, not_lit); - assert (solver->level >= 1); + KISSAT_assert (solver->level >= 1); const unsigned *p = solver->propagate; conflict = kissat_probing_propagate (solver, candidate, true); @@ -1095,7 +1102,7 @@ EXIT_ASSUMPTION_LOOP:; LOG ("vivification assumptions propagate without conflict nor " "producing an implied literal"); #endif - assert (!conflict || implied == INVALID_LIT); + KISSAT_assert (!conflict || implied == INVALID_LIT); if (implied != INVALID_LIT) { unsigned better_implied = INVALID_LIT; @@ -1117,7 +1124,7 @@ EXIT_ASSUMPTION_LOOP:; } unsigned level_after_assumptions = solver->level; - assert (level_after_assumptions); + KISSAT_assert (level_after_assumptions); clause *subsuming = 0; bool redundant = false; @@ -1129,7 +1136,7 @@ EXIT_ASSUMPTION_LOOP:; bool res; if (subsuming) { - assert (!subsuming->garbage); + KISSAT_assert (!subsuming->garbage); if (candidate->redundant) { LOGCLS (candidate, "vivification subsumed"); kissat_mark_clause_as_garbage (solver, candidate); @@ -1141,22 +1148,22 @@ EXIT_ASSUMPTION_LOOP:; INC (vivified_subsumed); res = true; } else if (!subsuming->redundant) { - assert (!candidate->redundant); + KISSAT_assert (!candidate->redundant); LOGCLS (candidate, "vivification subsumed"); kissat_mark_clause_as_garbage (solver, candidate); INC (vivified_subirr); INC (vivified_subsumed); res = true; } else { - assert (!candidate->redundant); - assert (subsuming->redundant); + KISSAT_assert (!candidate->redundant); + KISSAT_assert (subsuming->redundant); LOGCLS (candidate, "vivification subsumed"); kissat_mark_clause_as_garbage (solver, candidate); subsuming->redundant = false; - assert (solver->statistics.clauses_redundant); - solver->statistics.clauses_redundant--; - assert (solver->statistics.clauses_irredundant < UINT64_MAX); - solver->statistics.clauses_irredundant++; + KISSAT_assert (solver->statistics_.clauses_redundant); + solver->statistics_.clauses_redundant--; + KISSAT_assert (solver->statistics_.clauses_irredundant < UINT64_MAX); + solver->statistics_.clauses_irredundant++; INC (vivified_promoted); LOGCLS (subsuming, "vivification promoted from redundant to"); kissat_update_last_irredundant (solver, subsuming); @@ -1188,20 +1195,20 @@ EXIT_ASSUMPTION_LOOP:; LOGCLS (candidate, "no vivification instantiation with implied literal %s", LOGLIT (implied)); - assert (!candidate->redundant); - assert (redundant); + KISSAT_assert (!candidate->redundant); + KISSAT_assert (redundant); res = false; } else { - assert (solver->level > 2); - assert (solver->level == SIZE_STACK (*sorted)); + KISSAT_assert (solver->level > 2); + KISSAT_assert (solver->level == SIZE_STACK (*sorted)); unsigned lit = TOP_STACK (*sorted); - assert (VALUE (lit) < 0); - assert (LEVEL (lit) == solver->level); + KISSAT_assert (VALUE (lit) < 0); + KISSAT_assert (LEVEL (lit) == solver->level); LOG ("trying vivification instantiation of %s#%u respectively %s#%u", LOGLIT (lit), counts[lit], LOGLIT (NOT (lit)), counts[NOT (lit)]); kissat_backtrack_without_updating_phases (solver, solver->level - 1); conflict = 0; - assert (!VALUE (lit)); + KISSAT_assert (!VALUE (lit)); kissat_internal_assume (solver, lit); LOGCLS (candidate, "vivification instantiation candidate"); conflict = kissat_probing_propagate (solver, candidate, true); @@ -1241,7 +1248,7 @@ EXIT_ASSUMPTION_LOOP:; INC (vivified_tier3); break; default: - assert (vivifier->tier == 0); + KISSAT_assert (vivifier->tier == 0); INC (vivified_irredundant); break; } @@ -1258,9 +1265,9 @@ static void vivify_round (vivifier *vivifier, uint64_t limit) { if (tier && !REDUNDANT_CLAUSES) return; - assert (0 <= tier && tier <= 3); - assert (solver->watching); - assert (solver->probing); + KISSAT_assert (0 <= tier && tier <= 3); + KISSAT_assert (solver->watching); + KISSAT_assert (solver->probing); kissat_flush_large_watches (solver); @@ -1274,8 +1281,8 @@ static void vivify_round (vivifier *vivifier, uint64_t limit) { } kissat_watch_large_clauses (solver); -#ifndef QUIET - uint64_t start = solver->statistics.probing_ticks; +#ifndef KISSAT_QUIET + uint64_t start = solver->statistics_.probing_ticks; uint64_t delta = limit - start; kissat_very_verbose (solver, "vivification %s effort limit %" PRIu64 " = %" PRIu64 @@ -1287,10 +1294,10 @@ static void vivify_round (vivifier *vivifier, uint64_t limit) { "scheduled %zu clauses %.0f%% of %zu", scheduled, kissat_percent (scheduled, total), total); #endif - assert (!vivifier->vivified); - assert (!vivifier->tried); + KISSAT_assert (!vivifier->vivified); + KISSAT_assert (!vivifier->tried); while (!EMPTY_STACK (vivifier->schedule)) { - const uint64_t probing_ticks = solver->statistics.probing_ticks; + const uint64_t probing_ticks = solver->statistics_.probing_ticks; if (probing_ticks > limit) { kissat_extremely_verbose (solver, "vivification %s ticks limit %" PRIu64 @@ -1302,7 +1309,7 @@ static void vivify_round (vivifier *vivifier, uint64_t limit) { break; const reference ref = POP_STACK (vivifier->schedule); clause *candidate = kissat_dereference_clause (solver, ref); - assert (!candidate->garbage); + KISSAT_assert (!candidate->garbage); vivifier->tried++; if (vivify_clause (vivifier, candidate)) vivifier->vivified++; @@ -1312,7 +1319,7 @@ static void vivify_round (vivifier *vivifier, uint64_t limit) { } if (solver->level) kissat_backtrack_without_updating_phases (solver, 0); -#ifndef QUIET +#ifndef KISSAT_QUIET kissat_phase (solver, vivifier->mode, GET (vivifications), "vivified %zu clauses %.0f%% out of %zu tried", vivifier->vivified, @@ -1350,7 +1357,7 @@ static void vivify_round (vivifier *vivifier, uint64_t limit) { } static void vivify_tier1 (vivifier *vivifier, uint64_t limit) { -#ifndef QUIET +#ifndef KISSAT_QUIET kissat *solver = vivifier->solver; #endif START (vivify1); @@ -1360,7 +1367,7 @@ static void vivify_tier1 (vivifier *vivifier, uint64_t limit) { } static void vivify_tier2 (vivifier *vivifier, uint64_t limit) { -#ifndef QUIET +#ifndef KISSAT_QUIET kissat *solver = vivifier->solver; #endif START (vivify2); @@ -1371,7 +1378,7 @@ static void vivify_tier2 (vivifier *vivifier, uint64_t limit) { } static void vivify_tier3 (vivifier *vivifier, uint64_t limit) { -#ifndef QUIET +#ifndef KISSAT_QUIET kissat *solver = vivifier->solver; #endif START (vivify3); @@ -1382,7 +1389,7 @@ static void vivify_tier3 (vivifier *vivifier, uint64_t limit) { } static void vivify_irredundant (vivifier *vivifier, uint64_t limit) { -#ifndef QUIET +#ifndef KISSAT_QUIET kissat *solver = vivifier->solver; #endif START (vivify0); @@ -1395,9 +1402,9 @@ static void vivify_irredundant (vivifier *vivifier, uint64_t limit) { void kissat_vivify (kissat *solver) { if (solver->inconsistent) return; - assert (!solver->level); - assert (solver->probing); - assert (solver->watching); + KISSAT_assert (!solver->level); + KISSAT_assert (solver->probing); + KISSAT_assert (solver->watching); if (!GET_OPTION (vivify)) return; if (TERMINATED (vivify_terminated_2)) @@ -1414,14 +1421,14 @@ void kissat_vivify (kissat *solver) { START (vivify); INC (vivifications); -#if !defined(NDEBUG) || defined(METRICS) - assert (!solver->vivifying); +#if !defined(KISSAT_NDEBUG) || defined(METRICS) + KISSAT_assert (!solver->vivifying); solver->vivifying = true; #endif SET_EFFORT_LIMIT (limit, vivify, probing_ticks); - const uint64_t total = limit - solver->statistics.probing_ticks; - limit = solver->statistics.probing_ticks; + const uint64_t total = limit - solver->statistics_.probing_ticks; + limit = solver->statistics_.probing_ticks; unsigned tier1_limit = vivify_tier1_limit (solver); unsigned tier2_limit = vivify_tier2_limit (solver); if (tier1_budget && tier2_budget && tier1_limit == tier2_limit) { @@ -1459,22 +1466,24 @@ void kissat_vivify (kissat *solver) { release_vivifier (&vivifier); } -#ifndef QUIET - if (solver->statistics.probing_ticks < limit) { - uint64_t delta = limit - solver->statistics.probing_ticks; +#ifndef KISSAT_QUIET + if (solver->statistics_.probing_ticks < limit) { + uint64_t delta = limit - solver->statistics_.probing_ticks; kissat_phase (solver, "vivify-limit", GET (vivifications), "has %" PRIu64 " ticks left %.2f%%", delta, kissat_percent (delta, total)); } else { - uint64_t delta = solver->statistics.probing_ticks - limit; + uint64_t delta = solver->statistics_.probing_ticks - limit; kissat_phase (solver, "vivify-limit", GET (vivifications), "exceeded by %" PRIu64 " ticks %.2f%%", delta, kissat_percent (delta, total)); } #endif -#if !defined(NDEBUG) || defined(METRICS) - assert (solver->vivifying); +#if !defined(KISSAT_NDEBUG) || defined(METRICS) + KISSAT_assert (solver->vivifying); solver->vivifying = false; #endif STOP (vivify); } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/vivify.h b/src/sat/kissat/vivify.h index a83ac9303..42ec2f2c3 100644 --- a/src/sat/kissat/vivify.h +++ b/src/sat/kissat/vivify.h @@ -1,8 +1,13 @@ #ifndef _vivify_h_INCLUDED #define _vivify_h_INCLUDED +#include "global.h" +ABC_NAMESPACE_HEADER_START + struct kissat; void kissat_vivify (struct kissat *); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/walk.c b/src/sat/kissat/walk.c index 88974ee7a..72ce38a6c 100644 --- a/src/sat/kissat/walk.c +++ b/src/sat/kissat/walk.c @@ -12,6 +12,8 @@ #include +ABC_NAMESPACE_IMPL_START + typedef struct tagged tagged; typedef struct counter counter; typedef struct walker walker; @@ -25,8 +27,8 @@ struct tagged { }; static inline tagged make_tagged (bool binary, unsigned ref) { - assert (ref <= MAX_WALK_REF); - tagged res = {.binary = binary, .ref = ref}; + KISSAT_assert (ref <= MAX_WALK_REF); + tagged res = {.ref = ref, .binary = binary}; return res; } @@ -71,7 +73,7 @@ struct walker { uint64_t limit; uint64_t flipped; -#ifndef QUIET +#ifndef KISSAT_QUIET uint64_t start; struct { uint64_t flipped; @@ -83,7 +85,7 @@ struct walker { static const unsigned *dereference_literals (kissat *solver, walker *walker, unsigned counter_ref, unsigned *size_ptr) { - assert (counter_ref < walker->clauses); + KISSAT_assert (counter_ref < walker->clauses); tagged tagged = walker->refs[counter_ref]; unsigned const *lits; if (tagged.binary) { @@ -101,9 +103,9 @@ static const unsigned *dereference_literals (kissat *solver, walker *walker, static void push_unsat (kissat *solver, walker *walker, counter *counters, unsigned counter_ref) { - assert (counter_ref < walker->clauses); + KISSAT_assert (counter_ref < walker->clauses); counter *counter = counters + counter_ref; - assert (SIZE_STACK (walker->unsat) <= UINT_MAX); + KISSAT_assert (SIZE_STACK (walker->unsat) <= UINT_MAX); counter->pos = SIZE_STACK (walker->unsat); PUSH_STACK (walker->unsat, counter_ref); #ifdef LOGGING @@ -116,18 +118,18 @@ static void push_unsat (kissat *solver, walker *walker, counter *counters, static bool pop_unsat (kissat *solver, walker *walker, counter *counters, unsigned counter_ref, unsigned pos) { - assert (walker->current); - assert (counter_ref < walker->clauses); - assert (counters[counter_ref].pos == pos); - assert (walker->current == SIZE_STACK (walker->unsat)); + KISSAT_assert (walker->current); + KISSAT_assert (counter_ref < walker->clauses); + KISSAT_assert (counters[counter_ref].pos == pos); + KISSAT_assert (walker->current == SIZE_STACK (walker->unsat)); const unsigned other_counter_ref = POP_STACK (walker->unsat); walker->current--; bool res = false; if (counter_ref != other_counter_ref) { - assert (other_counter_ref < walker->clauses); + KISSAT_assert (other_counter_ref < walker->clauses); counter *other_counter = counters + other_counter_ref; - assert (other_counter->pos == walker->current); - assert (pos < other_counter->pos); + KISSAT_assert (other_counter->pos == walker->current); + KISSAT_assert (pos < other_counter->pos); other_counter->pos = pos; POKE_STACK (walker->unsat, pos, other_counter_ref); res = true; @@ -155,9 +157,9 @@ static double fit_cbval (double size) { const double x2 = cbvals[i + 1][0], x1 = cbvals[i][0]; const double y2 = cbvals[i + 1][1], y1 = cbvals[i][1]; const double dx = x2 - x1, dy = y2 - y1; - assert (dx); + KISSAT_assert (dx); const double res = dy * (size - x1) / dx + y1; - assert (res > 0); + KISSAT_assert (res > 0); return res; } @@ -172,14 +174,14 @@ static void init_score_table (walker *walker) { for (next = 1; next; next *= base) exponents++; - walker->table = kissat_malloc (solver, exponents * sizeof (double)); + walker->table = (double*)kissat_malloc (solver, exponents * sizeof (double)); unsigned i = 0; double epsilon; for (epsilon = next = 1; next; next = epsilon * base) walker->table[i++] = epsilon = next; - assert (i == exponents); + KISSAT_assert (i == exponents); walker->exponents = exponents; walker->epsilon = epsilon; @@ -198,22 +200,22 @@ static void import_decision_phases (walker *walker) { INC (walk_decisions); const flags *const flags = solver->flags; value *values = solver->values; - walker->best_values = kissat_calloc (solver, VARS, 1); + walker->best_values = (value*)kissat_calloc (solver, VARS, 1); value *best_values = walker->best_values; -#ifndef QUIET +#ifndef KISSAT_QUIET unsigned imported = 0; #endif for (all_variables (idx)) { if (!flags[idx].active) continue; value value = kissat_decide_phase (solver, idx); - assert (value); + KISSAT_assert (value); best_values[idx] = value; const unsigned lit = LIT (idx); const unsigned not_lit = NOT (lit); values[lit] = value; values[not_lit] = -value; -#ifndef QUIET +#ifndef KISSAT_QUIET imported++; #endif LOG ("copied %s decision phase %d", LOGVAR (idx), (int) value); @@ -230,7 +232,7 @@ static unsigned connect_binary_counters (walker *walker) { watches *all_watches = solver->watches; counter *counters = walker->counters; - assert (SIZE_STACK (*walker->binaries) <= UINT_MAX); + KISSAT_assert (SIZE_STACK (*walker->binaries) <= UINT_MAX); const unsigned size = SIZE_STACK (*walker->binaries); litpair *binaries = BEGIN_STACK (*walker->binaries); unsigned unsat = 0, counter_ref = 0; @@ -239,12 +241,12 @@ static unsigned connect_binary_counters (walker *walker) { const litpair *const litpair = binaries + binary_ref; const unsigned first = litpair->lits[0]; const unsigned second = litpair->lits[1]; - assert (first < LITS), assert (second < LITS); + KISSAT_assert (first < LITS), KISSAT_assert (second < LITS); const value first_value = values[first]; const value second_value = values[second]; if (!first_value || !second_value) continue; - assert (counter_ref < walker->clauses); + KISSAT_assert (counter_ref < walker->clauses); refs[counter_ref] = make_tagged (true, binary_ref); watches *first_watches = all_watches + first; watches *second_watches = all_watches + second; @@ -262,7 +264,7 @@ static unsigned connect_binary_counters (walker *walker) { kissat_phase (solver, "walk", GET (walks), "initially %u unsatisfied binary clauses %.0f%% out of %u", unsat, kissat_percent (unsat, counter_ref), counter_ref); -#ifdef QUIET +#ifdef KISSAT_QUIET (void) unsat; #endif walker->size += 2.0 * counter_ref; @@ -271,7 +273,7 @@ static unsigned connect_binary_counters (walker *walker) { static void connect_large_counters (walker *walker, unsigned counter_ref) { kissat *solver = walker->solver; - assert (!solver->level); + KISSAT_assert (!solver->level); const value *const original_values = walker->original_values; const value *const local_search_values = solver->values; ward *const arena = BEGIN_STACK (solver->arena); @@ -297,23 +299,23 @@ static void connect_large_counters (walker *walker, unsigned counter_ref) { continue; LOGCLS (c, "%s satisfied", LOGLIT (lit)); kissat_mark_clause_as_garbage (solver, c); - assert (c->garbage); + KISSAT_assert (c->garbage); continue_with_next_clause = true; break; } if (continue_with_next_clause) continue; large++; - assert (kissat_clause_in_arena (solver, c)); + KISSAT_assert (kissat_clause_in_arena (solver, c)); reference clause_ref = (ward *) c - arena; - assert (clause_ref <= MAX_WALK_REF); - assert (counter_ref < walker->clauses); + KISSAT_assert (clause_ref <= MAX_WALK_REF); + KISSAT_assert (counter_ref < walker->clauses); refs[counter_ref] = make_tagged (false, clause_ref); unsigned count = 0, size = 0; for (all_literals_in_clause (lit, c)) { const value value = local_search_values[lit]; if (!value) { - assert (original_values[lit] < 0); + KISSAT_assert (original_values[lit] < 0); continue; } watches *watches = &WATCHES (lit); @@ -335,13 +337,13 @@ static void connect_large_counters (walker *walker, unsigned counter_ref) { kissat_phase (solver, "walk", GET (walks), "initially %u unsatisfied large clauses %.0f%% out of %u", unsat, kissat_percent (unsat, large), large); -#ifdef QUIET +#ifdef KISSAT_QUIET (void) large; (void) unsat; #endif } -#ifndef QUIET +#ifndef KISSAT_QUIET static void report_initial_minimum (kissat *solver, walker *walker) { walker->report.minimum = walker->minimum; @@ -351,7 +353,7 @@ static void report_initial_minimum (kissat *solver, walker *walker) { static void report_minimum (const char *type, kissat *solver, walker *walker) { - assert (walker->minimum <= walker->report.minimum); + KISSAT_assert (walker->minimum <= walker->report.minimum); kissat_very_verbose (solver, "%s minimum of %u unsatisfied clauses after %" PRIu64 " flipped literals", @@ -370,24 +372,24 @@ static void report_minimum (const char *type, kissat *solver, static void init_walker (kissat *solver, walker *walker, litpairs *binaries) { uint64_t clauses = BINIRR_CLAUSES; - assert (clauses <= MAX_WALK_REF); + KISSAT_assert (clauses <= MAX_WALK_REF); memset (walker, 0, sizeof *walker); walker->solver = solver; walker->clauses = clauses; walker->binaries = binaries; - walker->random = solver->random ^ solver->statistics.walks; + walker->random = solver->random ^ solver->statistics_.walks; walker->original_values = solver->values; - solver->values = kissat_calloc (solver, LITS, 1); + solver->values = (value*)kissat_calloc (solver, LITS, 1); import_decision_phases (walker); - walker->counters = kissat_malloc (solver, clauses * sizeof (counter)); - walker->refs = kissat_malloc (solver, clauses * sizeof (tagged)); + walker->counters = (counter*)kissat_malloc (solver, clauses * sizeof (counter)); + walker->refs = (tagged*)kissat_malloc (solver, clauses * sizeof (tagged)); - assert (!walker->size); + KISSAT_assert (!walker->size); const unsigned counter_ref = connect_binary_counters (walker); connect_large_counters (walker, counter_ref); @@ -413,8 +415,8 @@ static void init_walker_limit (kissat *solver, walker *walker) { SET_EFFORT_LIMIT (limit, walk, walk_steps); walker->limit = limit; walker->flipped = 0; -#ifndef QUIET - walker->start = solver->statistics.walk_steps; +#ifndef KISSAT_QUIET + walker->start = solver->statistics_.walk_steps; walker->report.minimum = UINT_MAX; walker->report.flipped = 0; #endif @@ -438,21 +440,21 @@ static void release_walker (walker *walker) { static unsigned break_value (kissat *solver, walker *walker, value *values, unsigned lit) { - assert (values[lit] < 0); + KISSAT_assert (values[lit] < 0); const unsigned not_lit = NOT (lit); watches *watches = &WATCHES (not_lit); unsigned steps = 1; unsigned res = 0; for (all_binary_large_watches (watch, *watches)) { steps++; - assert (!watch.type.binary); + KISSAT_assert (!watch.type.binary); reference counter_ref = watch.large.ref; - assert (counter_ref < walker->clauses); + KISSAT_assert (counter_ref < walker->clauses); counter *counter = walker->counters + counter_ref; res += (counter->count == 1); } ADD (walk_steps, steps); -#ifdef NDEBUG +#ifdef KISSAT_NDEBUG (void) values; #endif return res; @@ -466,7 +468,7 @@ static double scale_score (walker *walker, unsigned breaks) { } static unsigned pick_literal (kissat *solver, walker *walker) { - assert (walker->current == SIZE_STACK (walker->unsat)); + KISSAT_assert (walker->current == SIZE_STACK (walker->unsat)); const unsigned pos = walker->flipped++ % walker->current; const unsigned counter_ref = PEEK_STACK (walker->unsat, pos); unsigned size; @@ -474,7 +476,7 @@ static unsigned pick_literal (kissat *solver, walker *walker) { dereference_literals (solver, walker, counter_ref, &size); LOGLITS (size, lits, "picked unsatisfied[%u]", pos); - assert (EMPTY_STACK (walker->scores)); + KISSAT_assert (EMPTY_STACK (walker->scores)); value *values = solver->values; @@ -489,21 +491,21 @@ static unsigned pick_literal (kissat *solver, walker *walker) { picked_lit = lit; const unsigned breaks = break_value (solver, walker, values, lit); const double score = scale_score (walker, breaks); - assert (score > 0); + KISSAT_assert (score > 0); LOG ("literal %s breaks %u score %g", LOGLIT (lit), breaks, score); PUSH_STACK (walker->scores, score); sum += score; } - assert (picked_lit != INVALID_LIT); - assert (0 < sum); + KISSAT_assert (picked_lit != INVALID_LIT); + KISSAT_assert (0 < sum); const double random = kissat_pick_double (&walker->random); - assert (0 <= random), assert (random < 1); + KISSAT_assert (0 <= random), KISSAT_assert (random < 1); const double threshold = sum * random; LOG ("score sum %g and random threshold %g", sum, threshold); - // assert (threshold < sum); // NOT TRUE!!!! + // KISSAT_assert (threshold < sum); // NOT TRUE!!!! double *scores = BEGIN_STACK (walker->scores); #ifdef LOGGING @@ -526,7 +528,7 @@ static unsigned pick_literal (kissat *solver, walker *walker) { break; } } - assert (picked_lit != INVALID_LIT); + KISSAT_assert (picked_lit != INVALID_LIT); LOG ("picked literal %s with score %g", LOGLIT (picked_lit), picked_score); @@ -541,7 +543,7 @@ static void break_clauses (kissat *solver, walker *walker, unsigned broken = 0; #endif const unsigned not_flipped = NOT (flipped); - assert (values[not_flipped] < 0); + KISSAT_assert (values[not_flipped] < 0); LOG ("breaking one-satisfied clauses containing negated flipped literal " "%s", LOGLIT (not_flipped)); @@ -550,11 +552,11 @@ static void break_clauses (kissat *solver, walker *walker, unsigned steps = 1; for (all_binary_large_watches (watch, *watches)) { steps++; - assert (!watch.type.binary); + KISSAT_assert (!watch.type.binary); const unsigned counter_ref = watch.large.ref; - assert (counter_ref < walker->clauses); + KISSAT_assert (counter_ref < walker->clauses); counter *counter = counters + counter_ref; - assert (counter->count); + KISSAT_assert (counter->count); if (--counter->count) continue; push_unsat (solver, walker, counters, counter_ref); @@ -566,14 +568,14 @@ static void break_clauses (kissat *solver, walker *walker, "negated flipped literal %s", broken, LOGLIT (not_flipped)); ADD (walk_steps, steps); -#ifdef NDEBUG +#ifdef KISSAT_NDEBUG (void) values; #endif } static void make_clauses (kissat *solver, walker *walker, const value *const values, unsigned flipped) { - assert (values[flipped] > 0); + KISSAT_assert (values[flipped] > 0); LOG ("making unsatisfied clauses containing flipped literal %s", LOGLIT (flipped)); watches *watches = &WATCHES (flipped); @@ -584,11 +586,11 @@ static void make_clauses (kissat *solver, walker *walker, #endif for (all_binary_large_watches (watch, *watches)) { steps++; - assert (!watch.type.binary); + KISSAT_assert (!watch.type.binary); const unsigned counter_ref = watch.large.ref; - assert (counter_ref < walker->clauses); + KISSAT_assert (counter_ref < walker->clauses); counter *counter = counters + counter_ref; - assert (counter->count < UINT_MAX); + KISSAT_assert (counter->count < UINT_MAX); if (counter->count++) continue; if (pop_unsat (solver, walker, counters, counter_ref, counter->pos)) @@ -600,14 +602,14 @@ static void make_clauses (kissat *solver, walker *walker, LOG ("made %u unsatisfied clauses containing flipped literal %s", made, LOGLIT (flipped)); ADD (walk_steps, steps); -#ifdef NDEBUG +#ifdef KISSAT_NDEBUG (void) values; #endif } static void save_all_values (kissat *solver, walker *walker) { - assert (EMPTY_STACK (walker->trail)); - assert (walker->best_trail_pos == INVALID_BEST_TRAIL_POS); + KISSAT_assert (EMPTY_STACK (walker->trail)); + KISSAT_assert (walker->best_trail_pos == INVALID_BEST_TRAIL_POS); LOG ("copying all values as best phases since trail is invalid"); const value *const current_values = solver->values; value *best_values = walker->best_values; @@ -622,11 +624,11 @@ static void save_all_values (kissat *solver, walker *walker) { } static void save_walker_trail (kissat *solver, walker *walker, bool keep) { -#if defined(LOGGING) || !defined(NDEBUG) - assert (walker->best_trail_pos != INVALID_BEST_TRAIL_POS); - assert (SIZE_STACK (walker->trail) <= UINT_MAX); +#if defined(LOGGING) || !defined(KISSAT_NDEBUG) + KISSAT_assert (walker->best_trail_pos != INVALID_BEST_TRAIL_POS); + KISSAT_assert (SIZE_STACK (walker->trail) <= UINT_MAX); const unsigned size_trail = SIZE_STACK (walker->trail); - assert (walker->best_trail_pos <= size_trail); + KISSAT_assert (walker->best_trail_pos <= size_trail); const unsigned kept = size_trail - walker->best_trail_pos; LOG ("saving %u values of flipped literals on trail of size %u", walker->best_trail_pos, size_trail); @@ -652,8 +654,8 @@ static void save_walker_trail (kissat *solver, walker *walker, bool keep) { unsigned *q = begin; for (const unsigned *p = best; p != end; p++) *q++ = *p; - assert ((size_t) (end - q) == walker->best_trail_pos); - assert ((size_t) (q - begin) == kept); + KISSAT_assert ((size_t) (end - q) == walker->best_trail_pos); + KISSAT_assert ((size_t) (q - begin) == kept); SET_END_OF_STACK (walker->trail, q); LOG ("keeping %u literals %.0f%% on trail", kept, kissat_percent (kept, size_trail)); @@ -666,13 +668,13 @@ static void push_flipped (kissat *solver, walker *walker, if (walker->best_trail_pos == INVALID_BEST_TRAIL_POS) { LOG ("not pushing flipped %s to already invalid trail", LOGLIT (flipped)); - assert (EMPTY_STACK (walker->trail)); + KISSAT_assert (EMPTY_STACK (walker->trail)); } else { - assert (SIZE_STACK (walker->trail) <= UINT_MAX); + KISSAT_assert (SIZE_STACK (walker->trail) <= UINT_MAX); const unsigned size_trail = SIZE_STACK (walker->trail); - assert (walker->best_trail_pos <= size_trail); + KISSAT_assert (walker->best_trail_pos <= size_trail); const unsigned limit = VARS / 4 + 1; - assert (limit < INVALID_BEST_TRAIL_POS); + KISSAT_assert (limit < INVALID_BEST_TRAIL_POS); if (size_trail < limit) { PUSH_STACK (walker->trail, flipped); LOG ("pushed flipped %s to trail which now has size %u", @@ -682,7 +684,7 @@ static void push_flipped (kissat *solver, walker *walker, walker->best_trail_pos); save_walker_trail (solver, walker, true); PUSH_STACK (walker->trail, flipped); - assert (SIZE_STACK (walker->trail) <= UINT_MAX); + KISSAT_assert (SIZE_STACK (walker->trail) <= UINT_MAX); LOG ("pushed flipped %s to trail which now has size %zu", LOGLIT (flipped), SIZE_STACK (walker->trail)); } else { @@ -699,7 +701,7 @@ static void flip_literal (kissat *solver, walker *walker, unsigned flip) { LOG ("flipping literal %s", LOGLIT (flip)); value *values = solver->values; const value value = values[flip]; - assert (value < 0); + KISSAT_assert (value < 0); values[flip] = -value; values[NOT (flip)] = value; make_clauses (solver, walker, values, flip); @@ -708,9 +710,9 @@ static void flip_literal (kissat *solver, walker *walker, unsigned flip) { } static void update_best (kissat *solver, walker *walker) { - assert (walker->current < walker->minimum); + KISSAT_assert (walker->current < walker->minimum); walker->minimum = walker->current; -#ifndef QUIET +#ifndef KISSAT_QUIET int verbosity = kissat_verbosity (solver); bool report = (verbosity > 2); if (verbosity == 2) { @@ -730,16 +732,16 @@ static void update_best (kissat *solver, walker *walker) { if (walker->best_trail_pos == INVALID_BEST_TRAIL_POS) save_all_values (solver, walker); else { - assert (SIZE_STACK (walker->trail) < INVALID_BEST_TRAIL_POS); + KISSAT_assert (SIZE_STACK (walker->trail) < INVALID_BEST_TRAIL_POS); walker->best_trail_pos = SIZE_STACK (walker->trail); LOG ("new best trail position %u", walker->best_trail_pos); } } static void local_search_step (kissat *solver, walker *walker) { - assert (walker->current); + KISSAT_assert (walker->current); INC (flipped); - assert (walker->flipped < UINT64_MAX); + KISSAT_assert (walker->flipped < UINT64_MAX); walker->flipped++; LOG ("starting local search flip %" PRIu64 " with %u unsatisfied clauses", GET (flipped), walker->current); @@ -754,18 +756,18 @@ static void local_search_step (kissat *solver, walker *walker) { static void local_search_round (walker *walker) { kissat *solver = walker->solver; -#ifndef QUIET +#ifndef KISSAT_QUIET const unsigned before = walker->minimum; #endif - statistics *statistics = &solver->statistics; + statistics *statistics = &solver->statistics_; while (walker->minimum && walker->limit > statistics->walk_steps) { if (TERMINATED (walk_terminated_1)) break; local_search_step (solver, walker); } -#ifndef QUIET +#ifndef KISSAT_QUIET report_minimum ("last", solver, walker); - assert (statistics->walk_steps >= walker->start); + KISSAT_assert (statistics->walk_steps >= walker->start); const uint64_t steps = statistics->walk_steps - walker->start; // clang-format off kissat_very_verbose (solver, @@ -785,15 +787,15 @@ static void export_best_values (walker *walker) { kissat *const solver = walker->solver; const value *const best = walker->best_values; value *const saved = solver->phases.saved; - assert (sizeof *saved == 1); - assert (sizeof *best == 1); + KISSAT_assert (sizeof *saved == 1); + KISSAT_assert (sizeof *best == 1); memcpy (saved, best, VARS); } static bool save_final_minimum (walker *walker) { kissat *solver = walker->solver; - assert (walker->minimum <= walker->initial); + KISSAT_assert (walker->minimum <= walker->initial); if (walker->minimum == walker->initial) { kissat_phase (solver, "walk", GET (walks), "no improvement thus keeping saved phases"); @@ -823,14 +825,14 @@ static void check_walk (kissat *solver, unsigned expected) { watches *all_watches = solver->watches; const value *const saved = solver->phases.saved; for (all_literals (lit)) { - assert (lit < LITS); + KISSAT_assert (lit < LITS); watches *watches = all_watches + lit; if (kissat_empty_vector (watches)) continue; value value = solver->values[lit]; if (!value) { value = saved[IDX (lit)]; - assert (value); + KISSAT_assert (value); if (NEGATED (lit)) value = -value; } @@ -844,7 +846,7 @@ static void check_walk (kissat *solver, unsigned expected) { value = solver->values[other]; if (!value) { value = saved[IDX (other)]; - assert (value); + KISSAT_assert (value); if (NEGATED (other)) value = -value; } @@ -864,7 +866,7 @@ static void check_walk (kissat *solver, unsigned expected) { value value = solver->values[lit]; if (!value) { value = saved[IDX (lit)]; - assert (value); + KISSAT_assert (value); if (NEGATED (lit)) value = -value; } @@ -878,7 +880,7 @@ static void check_walk (kissat *solver, unsigned expected) { } LOG ("expected %u unsatisfied", expected); LOG ("actually %u unsatisfied", unsatisfied); - assert (expected == unsatisfied); + KISSAT_assert (expected == unsatisfied); } #endif @@ -934,10 +936,10 @@ bool kissat_walking (kissat *solver) { } void kissat_walk (kissat *solver) { - assert (!solver->level); - assert (!solver->inconsistent); - assert (kissat_propagated (solver)); - assert (kissat_walking (solver)); + KISSAT_assert (!solver->level); + KISSAT_assert (!solver->inconsistent); + KISSAT_assert (kissat_propagated (solver)); + KISSAT_assert (kissat_walking (solver)); reference last_irredundant = solver->last_irredundant; if (last_irredundant == INVALID_REF) @@ -964,3 +966,5 @@ void kissat_walk (kissat *solver) { walking_phase (solver); STOP_SIMPLIFIER_AND_RESUME_SEARCH (walking); } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/walk.h b/src/sat/kissat/walk.h index 0acc19193..43e626091 100644 --- a/src/sat/kissat/walk.h +++ b/src/sat/kissat/walk.h @@ -3,9 +3,14 @@ #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + struct kissat; bool kissat_walking (struct kissat *); void kissat_walk (struct kissat *); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/warmup.c b/src/sat/kissat/warmup.c index d9fa9f534..fe7b981f8 100644 --- a/src/sat/kissat/warmup.c +++ b/src/sat/kissat/warmup.c @@ -6,16 +6,18 @@ #include "propbeyond.h" #include "terminate.h" +ABC_NAMESPACE_IMPL_START + void kissat_warmup (kissat *solver) { - assert (!solver->level); - assert (solver->watching); - assert (!solver->inconsistent); - assert (GET_OPTION (warmup)); + KISSAT_assert (!solver->level); + KISSAT_assert (solver->watching); + KISSAT_assert (!solver->inconsistent); + KISSAT_assert (GET_OPTION (warmup)); START (warmup); - assert (!solver->warming); + KISSAT_assert (!solver->warming); solver->warming = true; INC (warmups); -#ifndef QUIET +#ifndef KISSAT_QUIET const statistics *stats = &solver->statistics; uint64_t propagations = stats->warming_propagations; uint64_t decisions = stats->warming_decisions; @@ -26,8 +28,8 @@ void kissat_warmup (kissat *solver) { kissat_decide (solver); kissat_propagate_beyond_conflicts (solver); } - assert (!solver->inconsistent); -#ifndef QUIET + KISSAT_assert (!solver->inconsistent); +#ifndef KISSAT_QUIET decisions = stats->warming_decisions - decisions; propagations = stats->warming_propagations - propagations; @@ -48,7 +50,9 @@ void kissat_warmup (kissat *solver) { solver->level); #endif kissat_backtrack_without_updating_phases (solver, 0); - assert (solver->warming); + KISSAT_assert (solver->warming); solver->warming = false; STOP (warmup); } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/warmup.h b/src/sat/kissat/warmup.h index e0fd47122..23cd6c7a7 100644 --- a/src/sat/kissat/warmup.h +++ b/src/sat/kissat/warmup.h @@ -1,8 +1,13 @@ #ifndef _warmup_h_INCLUDED #define _warmup_h_INCLUDED +#include "global.h" +ABC_NAMESPACE_HEADER_START + struct kissat; void kissat_warmup (struct kissat *); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/watch.c b/src/sat/kissat/watch.c index 39ceace6e..78f9a69ce 100644 --- a/src/sat/kissat/watch.c +++ b/src/sat/kissat/watch.c @@ -3,13 +3,15 @@ #include "inline.h" #include "sort.c" +ABC_NAMESPACE_IMPL_START + void kissat_remove_binary_watch (kissat *solver, watches *watches, unsigned lit) { watch *const begin = BEGIN_WATCHES (*watches); watch *const end = END_WATCHES (*watches); watch *q = begin; watch const *p = q; -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG bool found = false; #endif while (p != end) { @@ -21,34 +23,34 @@ void kissat_remove_binary_watch (kissat *solver, watches *watches, const unsigned other = watch.binary.lit; if (other != lit) continue; -#ifndef NDEBUG - assert (!found); +#ifndef KISSAT_NDEBUG + KISSAT_assert (!found); found = true; #endif q--; } - assert (found); -#ifdef COMPACT + KISSAT_assert (found); +#ifdef KISSAT_COMPACT watches->size -= 1; #else - assert (begin + 1 <= end); + KISSAT_assert (begin + 1 <= end); watches->end -= 1; #endif const watch empty = {.raw = INVALID_VECTOR_ELEMENT}; end[-1] = empty; - assert (solver->vectors.usable < MAX_SECTOR - 1); + KISSAT_assert (solver->vectors.usable < MAX_SECTOR - 1); solver->vectors.usable += 1; kissat_check_vectors (solver); } void kissat_remove_blocking_watch (kissat *solver, watches *watches, reference ref) { - assert (solver->watching); + KISSAT_assert (solver->watching); watch *const begin = BEGIN_WATCHES (*watches); watch *const end = END_WATCHES (*watches); watch *q = begin; watch const *p = q; -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG bool found = false; #endif while (p != end) { @@ -58,49 +60,49 @@ void kissat_remove_blocking_watch (kissat *solver, watches *watches, const watch tail = *q++ = *p++; if (tail.raw != ref) continue; -#ifndef NDEBUG - assert (!found); +#ifndef KISSAT_NDEBUG + KISSAT_assert (!found); found = true; #endif q -= 2; } - assert (found); -#ifdef COMPACT + KISSAT_assert (found); +#ifdef KISSAT_COMPACT watches->size -= 2; #else - assert (begin + 2 <= end); + KISSAT_assert (begin + 2 <= end); watches->end -= 2; #endif const watch empty = {.raw = INVALID_VECTOR_ELEMENT}; end[-2] = end[-1] = empty; - assert (solver->vectors.usable < MAX_SECTOR - 2); + KISSAT_assert (solver->vectors.usable < MAX_SECTOR - 2); solver->vectors.usable += 2; kissat_check_vectors (solver); } void kissat_substitute_large_watch (kissat *solver, watches *watches, watch src, watch dst) { - assert (!solver->watching); + KISSAT_assert (!solver->watching); watch *const begin = BEGIN_WATCHES (*watches); const watch *const end = END_WATCHES (*watches); -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG bool found = false; #endif for (watch *p = begin; p != end; p++) { const watch head = *p; if (head.raw != src.raw) continue; -#ifndef NDEBUG +#ifndef KISSAT_NDEBUG found = true; #endif *p = dst; break; } - assert (found); + KISSAT_assert (found); } void kissat_flush_all_connected (kissat *solver) { - assert (!solver->watching); + KISSAT_assert (!solver->watching); LOG ("flush all connected binaries and clauses"); watches *all_watches = solver->watches; for (all_literals (lit)) @@ -108,7 +110,7 @@ void kissat_flush_all_connected (kissat *solver) { } void kissat_flush_large_watches (kissat *solver) { - assert (solver->watching); + KISSAT_assert (solver->watching); LOG ("flush large clause watches"); watches *all_watches = solver->watches; signed char *marks = solver->marks; @@ -134,7 +136,7 @@ void kissat_flush_large_watches (kissat *solver) { } SET_END_OF_WATCHES (*lit_watches, q); for (p = begin; p != q; p++) { - assert (p->type.binary); + KISSAT_assert (p->type.binary); marks[p->binary.lit] = 0; } } @@ -142,7 +144,7 @@ void kissat_flush_large_watches (kissat *solver) { void kissat_watch_large_clauses (kissat *solver) { LOG ("watching all large clauses"); - assert (solver->watching); + KISSAT_assert (solver->watching); const value *const values = solver->values; const assigned *const assigned = solver->assigned; @@ -167,7 +169,7 @@ void kissat_watch_large_clauses (kissat *solver) { } void kissat_connect_irredundant_large_clauses (kissat *solver) { - assert (!solver->watching); + KISSAT_assert (!solver->watching); LOG ("connecting all large irredundant clauses"); clause *last_irredundant = kissat_last_irredundant_clause (solver); @@ -184,7 +186,7 @@ void kissat_connect_irredundant_large_clauses (kissat *solver) { if (c->garbage) continue; bool satisfied = false; - assert (!solver->level); + KISSAT_assert (!solver->level); for (all_literals_in_clause (lit, c)) { const value value = values[lit]; if (value <= 0) @@ -202,7 +204,7 @@ void kissat_connect_irredundant_large_clauses (kissat *solver) { } void kissat_flush_large_connected (kissat *solver) { - assert (!solver->watching); + KISSAT_assert (!solver->watching); LOG ("flushing large connected clause references"); size_t flushed = 0; for (all_literals (lit)) { @@ -221,3 +223,5 @@ void kissat_flush_large_connected (kissat *solver) { LOG ("flushed %zu large clause references", flushed); (void) flushed; } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/watch.h b/src/sat/kissat/watch.h index 50afdb083..901e489b7 100644 --- a/src/sat/kissat/watch.h +++ b/src/sat/kissat/watch.h @@ -8,6 +8,9 @@ #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + typedef union watch watch; typedef struct binary_tagged_literal watch_type; @@ -77,7 +80,7 @@ static inline watch kissat_binary_watch (unsigned lit) { watch res; res.binary.lit = lit; res.binary.binary = true; - assert (res.type.binary); + KISSAT_assert (res.type.binary); return res; } @@ -85,7 +88,7 @@ static inline watch kissat_large_watch (reference ref) { watch res; res.large.ref = ref; res.large.binary = false; - assert (!res.type.binary); + KISSAT_assert (!res.type.binary); return res; } @@ -93,7 +96,7 @@ static inline watch kissat_blocking_watch (unsigned lit) { watch res; res.blocking.lit = lit; res.blocking.binary = false; - assert (!res.type.binary); + KISSAT_assert (!res.type.binary); return res; } @@ -102,7 +105,7 @@ static inline watch kissat_blocking_watch (unsigned lit) { #define PUSH_WATCHES(W, E) \ do { \ - assert (sizeof (E) == sizeof (unsigned)); \ + KISSAT_assert (sizeof (E) == sizeof (unsigned)); \ kissat_push_vectors (solver, &(W), (E).raw); \ } while (0) @@ -131,13 +134,13 @@ static inline watch kissat_blocking_watch (unsigned lit) { #define REMOVE_WATCHES(W, E) \ kissat_remove_from_vector (solver, &(W), (E).raw) -#define WATCHES(LIT) (solver->watches[assert ((LIT) < LITS), (LIT)]) +#define WATCHES(LIT) (solver->watches[KISSAT_assert ((LIT) < LITS), (LIT)]) // This iterator is currently only used in 'testreferences.c'. // #define all_binary_blocking_watch_ref(WATCH, REF, WATCHES) \ watch WATCH, \ - *WATCH##_PTR = (assert (solver->watching), BEGIN_WATCHES (WATCHES)), \ + *WATCH##_PTR = (KISSAT_assert (solver->watching), BEGIN_WATCHES (WATCHES)), \ *const WATCH##_END = END_WATCHES (WATCHES); \ WATCH##_PTR != WATCH##_END && \ ((WATCH = *WATCH##_PTR), \ @@ -147,7 +150,7 @@ static inline watch kissat_blocking_watch (unsigned lit) { #define all_binary_blocking_watches(WATCH, WATCHES) \ watch WATCH, \ - *WATCH##_PTR = (assert (solver->watching), BEGIN_WATCHES (WATCHES)), \ + *WATCH##_PTR = (KISSAT_assert (solver->watching), BEGIN_WATCHES (WATCHES)), \ *const WATCH##_END = END_WATCHES (WATCHES); \ WATCH##_PTR != WATCH##_END && ((WATCH = *WATCH##_PTR), true); \ WATCH##_PTR += 1u + !WATCH.type.binary @@ -155,7 +158,7 @@ static inline watch kissat_blocking_watch (unsigned lit) { #define all_binary_large_watches(WATCH, WATCHES) \ watch WATCH, \ *WATCH##_PTR = \ - (assert (!solver->watching), BEGIN_WATCHES (WATCHES)), \ + (KISSAT_assert (!solver->watching), BEGIN_WATCHES (WATCHES)), \ *const WATCH##_END = END_WATCHES (WATCHES); \ WATCH##_PTR != WATCH##_END && ((WATCH = *WATCH##_PTR), true); \ ++WATCH##_PTR @@ -173,4 +176,6 @@ void kissat_flush_large_connected (struct kissat *); void kissat_connect_irredundant_large_clauses (struct kissat *); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/weaken.c b/src/sat/kissat/weaken.c index 149616546..5bd06371c 100644 --- a/src/sat/kissat/weaken.c +++ b/src/sat/kissat/weaken.c @@ -1,10 +1,12 @@ #include "weaken.h" #include "inline.h" +ABC_NAMESPACE_IMPL_START + static void push_witness_literal (kissat *solver, unsigned ilit) { - assert (!VALUE (ilit)); + KISSAT_assert (!VALUE (ilit)); int elit = kissat_export_literal (solver, ilit); - assert (elit); + KISSAT_assert (elit); LOG2 ("pushing external witness literal %d on extension stack", elit); const extension ext = kissat_extension (true, elit); PUSH_STACK (solver->extend, ext); @@ -12,14 +14,14 @@ static void push_witness_literal (kissat *solver, unsigned ilit) { static void push_clause_literal (kissat *solver, unsigned ilit) { const value value = VALUE (ilit); - assert (value <= 0); + KISSAT_assert (value <= 0); if (value < 0) LOG ("not pushing internal falsified clause literal %s " "on extension stack", LOGLIT (ilit)); else { int elit = kissat_export_literal (solver, ilit); - assert (elit); + KISSAT_assert (elit); LOG2 ("pushing external clause literal %d on extension stack", elit); const extension ext = kissat_extension (false, elit); PUSH_STACK (solver->extend, ext); @@ -58,3 +60,5 @@ void kissat_weaken_unit (kissat *solver, unsigned lit) { LOGEXT (1, END_STACK (solver->extend) - 1, "pushed witness labelled unit clause at"); } + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/kissat/weaken.h b/src/sat/kissat/weaken.h index beabcb0ce..8cd3dbbd8 100644 --- a/src/sat/kissat/weaken.h +++ b/src/sat/kissat/weaken.h @@ -1,6 +1,9 @@ #ifndef _weaken_h_INCLUDED #define _weaken_h_INCLUDED +#include "global.h" +ABC_NAMESPACE_HEADER_START + struct clause; struct kissat; @@ -8,4 +11,6 @@ void kissat_weaken_unit (struct kissat *, unsigned lit); void kissat_weaken_binary (struct kissat *, unsigned lit, unsigned other); void kissat_weaken_clause (struct kissat *, unsigned lit, struct clause *); +ABC_NAMESPACE_HEADER_END + #endif diff --git a/src/sat/kissat/witness.h b/src/sat/kissat/witness.h index 2b0fdea63..dffeaaabe 100644 --- a/src/sat/kissat/witness.h +++ b/src/sat/kissat/witness.h @@ -3,8 +3,13 @@ #include +#include "global.h" +ABC_NAMESPACE_HEADER_START + struct kissat; void kissat_print_witness (struct kissat *, int max_var, bool partial); +ABC_NAMESPACE_HEADER_END + #endif From 3f6171127a72a9659a56f318eb71e78387df2fd1 Mon Sep 17 00:00:00 2001 From: MyskYko Date: Wed, 5 Mar 2025 04:21:18 -0800 Subject: [PATCH 3/3] add license --- src/sat/kissat/LICENSE | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/sat/kissat/LICENSE diff --git a/src/sat/kissat/LICENSE b/src/sat/kissat/LICENSE new file mode 100644 index 000000000..f26cea22a --- /dev/null +++ b/src/sat/kissat/LICENSE @@ -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.