#include "allocate.h" #include "backtrack.h" #include "error.h" #include "search.h" #include "import.h" #include "inline.h" #include "print.h" #include "propsearch.h" #include "require.h" #include "resize.h" #include "resources.h" #include #include #include #include #include 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); solver->importedClause = cvec_init(); solver->exportedClause = cvec_init(); kissat_init_queue (&solver->queue); kissat_push_frame (solver, INVALID_LIT); solver->nconflict = 0; solver->share_dps = 0; solver->share_dps_period = 10000; solver->watching = true; solver->conflict.size = 2; solver->conflict.keep = true; solver->scinc = 1.0; solver->first_reducible = INVALID_REF; solver->last_irredundant = INVALID_REF; // CHB solver->step_dec_chb = 0.000001; solver->step_min_chb = 0.06; // MAB solver->mab_heuristics = 2; solver-> mab_decisions = 0; solver-> mab_chosen_tot = 0; solver-> reseting = 0; #ifndef NDEBUG kissat_init_checker (solver); #endif solver->step_chb = 0.1*GET_OPTION(stepchb); solver->heuristic = GET_OPTION(heuristic); solver->mab = GET_OPTION(mab); if(solver->mab) { for (unsigned i=0;imab_heuristics;i++) { solver->mab_reward[i] = 0; solver->mab_select[i] = 0; } solver->mabc = GET_OPTION(mabcint)+0.1*GET_OPTION(mabcdecimal); solver->mab_select[solver->heuristic]++; } return solver; } #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, &solver->scores); // CHB kissat_release_heap (solver, &solver->scores_chb); DEALLOC_VARIABLE_INDEXED (conflicted_chb); kissat_release_heap (solver, &solver->schedule); kissat_release_clueue (solver, &solver->clueue); RELEASE_STACK (solver->exportk); RELEASE_STACK (solver->import); DEALLOC_VARIABLE_INDEXED (assigned); DEALLOC_VARIABLE_INDEXED (flags); DEALLOC_VARIABLE_INDEXED (links); DEALLOC_VARIABLE_INDEXED (phases); 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->vectors.stack); RELEASE_STACK (solver->delayed); RELEASE_STACK (solver->clause.lits); #if defined(LOGGING) || !defined(NDEBUG) RELEASE_STACK (solver->resolvent_lits); #endif RELEASE_STACK (solver->arena); RELEASE_STACK (solver->units); RELEASE_STACK (solver->frames); RELEASE_STACK (solver->sorter); RELEASE_STACK (solver->trail); 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->xorted[0]); RELEASE_STACK (solver->xorted[1]); RELEASE_STACK (solver->bump); 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 #ifndef NDEBUG kissat_release_checker (solver); #endif #if !defined(NDEBUG) && !defined(NMETRICS) 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); int seed = GET_OPTION(order_reset); if (seed != -1) { // srand(solver->order_reset); int *id; id = (int *)malloc(sizeof(int) * (max_var + 1)); for (int i = 1; i <= max_var; i++) id[i] = i; for (int i = 1; i <= max_var; i++) { int j = (rand_r(&seed) % max_var) + 1; int x = id[i]; id[i] = id[j]; id[j] = x; } // printf("c mxavar is %d, first is %d, tenth is %d\n", max_var, id[1], id[10]); for (int i = 1; i <= max_var; i++) kissat_activate_literal(solver, kissat_import_literal(solver, id[i])); free(id); } else { for (int i = 1; i <= max_var; i++) kissat_import_literal(solver, i); } } 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); if(solver->mab) { printf("c MAB stats : "); for (unsigned i=0;imab_heuristics;i++) printf("%d ",solver->mab_select[i]); printf("\n"); } #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, "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.lits) < UINT_MAX); PUSH_STACK (solver->clause.lits, 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.lits); unsigned *ilits = BEGIN_STACK (solver->clause.lits); 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.lits); if (solver->clause.shrink) LOGUNARY (unit, "original clause shrinks to"); else LOGUNARY (unit, "found original"); kissat_assign_unit (solver, unit); if (!solver->level) { clause *conflict = kissat_search_propagate (solver); if (conflict) { LOG ("propagation of root level unit failed"); solver->inconsistent = true; CHECK_AND_ADD_EMPTY (); ADD_EMPTY_TO_PROOF (); } } } 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 (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, false, 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) kissat_delete_external_from_proof (solver, esize, elits); #endif } else if (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.lits)) MARK (lit) = MARK (NOT (lit)) = 0; CLEAR_STACK (solver->clause.lits); solver->clause.satisfied = false; solver->clause.trivial = false; solver->clause.shrink = 0; } } int kissat_solve (kissat * solver) { kissat_require_initialized (solver); kissat_require (EMPTY_STACK (solver->clause.lits), "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->terminate = ~(unsigned) 0; assert (solver->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 *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; }