blob: 0193b1c32bb34279772e67d6eb43fa47b820ec14 [file] [log] [blame]
//===--- solver_api.h -------------------------------------------------------===
//
// satoko: Satisfiability solver
//
// This file is distributed under the BSD 2-Clause License.
// See LICENSE for details.
//
//===------------------------------------------------------------------------===
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <math.h>
#include "act_var.h"
#include "solver.h"
#include "utils/misc.h"
#include "misc/util/abc_global.h"
ABC_NAMESPACE_IMPL_START
//===------------------------------------------------------------------------===
// Satoko internal functions
//===------------------------------------------------------------------------===
static inline void solver_rebuild_order(solver_t *s)
{
unsigned var;
vec_uint_t *vars = vec_uint_alloc(vec_char_size(s->assigns));
for (var = 0; var < vec_char_size(s->assigns); var++)
if (var_value(s, var) == SATOKO_VAR_UNASSING)
vec_uint_push_back(vars, var);
heap_build(s->var_order, vars);
vec_uint_free(vars);
}
static inline int clause_is_satisfied(solver_t *s, struct clause *clause)
{
unsigned i;
unsigned *lits = &(clause->data[0].lit);
for (i = 0; i < clause->size; i++)
if (lit_value(s, lits[i]) == SATOKO_LIT_TRUE)
return SATOKO_OK;
return SATOKO_ERR;
}
static inline void solver_clean_stats(solver_t *s)
{
long n_conflicts_all = s->stats.n_conflicts_all;
long n_propagations_all = s->stats.n_propagations_all;
memset(&(s->stats), 0, sizeof(struct satoko_stats));
s->stats.n_conflicts_all = n_conflicts_all;
s->stats.n_propagations_all = n_propagations_all;
}
static inline void print_opts(solver_t *s)
{
printf( "+-[ BLACK MAGIC - PARAMETERS ]-+\n");
printf( "| |\n");
printf( "|--> Restarts heuristic |\n");
printf( "| * LBD Queue = %6d |\n", s->opts.sz_lbd_bqueue);
printf( "| * Trail Queue = %6d |\n", s->opts.sz_trail_bqueue);
printf( "| * f_rst = %6.2f |\n", s->opts.f_rst);
printf( "| * b_rst = %6.2f |\n", s->opts.b_rst);
printf( "| |\n");
printf( "|--> Clause DB reduction: |\n");
printf( "| * First = %6d |\n", s->opts.n_conf_fst_reduce);
printf( "| * Inc = %6d |\n", s->opts.inc_reduce);
printf( "| * Special Inc = %6d |\n", s->opts.inc_special_reduce);
printf( "| * Protected (LBD) < %2d |\n", s->opts.lbd_freeze_clause);
printf( "| |\n");
printf( "|--> Binary resolution: |\n");
printf( "| * Clause size < %3d |\n", s->opts.clause_max_sz_bin_resol);
printf( "| * Clause lbd < %3d |\n", s->opts.clause_min_lbd_bin_resol);
printf( "+------------------------------+\n\n");
}
static inline void print_stats(solver_t *s)
{
printf("starts : %10d\n", s->stats.n_starts);
printf("conflicts : %10ld\n", s->stats.n_conflicts);
printf("decisions : %10ld\n", s->stats.n_decisions);
printf("propagations : %10ld\n", s->stats.n_propagations);
}
//===------------------------------------------------------------------------===
// Satoko external functions
//===------------------------------------------------------------------------===
solver_t * satoko_create()
{
solver_t *s = satoko_calloc(solver_t, 1);
satoko_default_opts(&s->opts);
s->status = SATOKO_OK;
/* User data */
s->assumptions = vec_uint_alloc(0);
s->final_conflict = vec_uint_alloc(0);
/* Clauses Database */
s->all_clauses = cdb_alloc(0);
s->originals = vec_uint_alloc(0);
s->learnts = vec_uint_alloc(0);
s->watches = vec_wl_alloc(0);
/* Activity heuristic */
s->var_act_inc = VAR_ACT_INIT_INC;
s->clause_act_inc = CLAUSE_ACT_INIT_INC;
/* Variable Information */
s->activity = vec_act_alloc(0);
s->var_order = heap_alloc(s->activity);
s->levels = vec_uint_alloc(0);
s->reasons = vec_uint_alloc(0);
s->assigns = vec_char_alloc(0);
s->polarity = vec_char_alloc(0);
/* Assignments */
s->trail = vec_uint_alloc(0);
s->trail_lim = vec_uint_alloc(0);
/* Temporary data used by Search method */
s->bq_trail = b_queue_alloc(s->opts.sz_trail_bqueue);
s->bq_lbd = b_queue_alloc(s->opts.sz_lbd_bqueue);
s->n_confl_bfr_reduce = s->opts.n_conf_fst_reduce;
s->RC1 = 1;
s->RC2 = s->opts.n_conf_fst_reduce;
/* Temporary data used by Analyze */
s->temp_lits = vec_uint_alloc(0);
s->seen = vec_char_alloc(0);
s->tagged = vec_uint_alloc(0);
s->stack = vec_uint_alloc(0);
s->last_dlevel = vec_uint_alloc(0);
/* Misc temporary */
s->stamps = vec_uint_alloc(0);
return s;
}
void satoko_destroy(solver_t *s)
{
vec_uint_free(s->assumptions);
vec_uint_free(s->final_conflict);
cdb_free(s->all_clauses);
vec_uint_free(s->originals);
vec_uint_free(s->learnts);
vec_wl_free(s->watches);
vec_act_free(s->activity);
heap_free(s->var_order);
vec_uint_free(s->levels);
vec_uint_free(s->reasons);
vec_char_free(s->assigns);
vec_char_free(s->polarity);
vec_uint_free(s->trail);
vec_uint_free(s->trail_lim);
b_queue_free(s->bq_lbd);
b_queue_free(s->bq_trail);
vec_uint_free(s->temp_lits);
vec_char_free(s->seen);
vec_uint_free(s->tagged);
vec_uint_free(s->stack);
vec_uint_free(s->last_dlevel);
vec_uint_free(s->stamps);
if (s->marks)
vec_char_free(s->marks);
satoko_free(s);
}
void satoko_default_opts(satoko_opts_t *opts)
{
memset(opts, 0, sizeof(satoko_opts_t));
opts->verbose = 0;
opts->no_simplify = 0;
/* Limits */
opts->conf_limit = 0;
opts->prop_limit = 0;
/* Constants used for restart heuristic */
opts->f_rst = 0.8;
opts->b_rst = 1.4;
opts->fst_block_rst = 10000;
opts->sz_lbd_bqueue = 50;
opts->sz_trail_bqueue = 5000;
/* Constants used for clause database reduction heuristic */
opts->n_conf_fst_reduce = 2000;
opts->inc_reduce = 300;
opts->inc_special_reduce = 1000;
opts->lbd_freeze_clause = 30;
opts->learnt_ratio = 0.5;
/* VSIDS heuristic */
opts->var_act_limit = VAR_ACT_LIMIT;
opts->var_act_rescale = VAR_ACT_RESCALE;
opts->var_decay = 0.95;
opts->clause_decay = (clause_act_t) 0.995;
/* Binary resolution */
opts->clause_max_sz_bin_resol = 30;
opts->clause_min_lbd_bin_resol = 6;
opts->garbage_max_ratio = (float) 0.3;
}
/**
* TODO: sanity check on configuration options
*/
void satoko_configure(satoko_t *s, satoko_opts_t *user_opts)
{
assert(user_opts);
memcpy(&s->opts, user_opts, sizeof(satoko_opts_t));
}
int satoko_simplify(solver_t * s)
{
unsigned i, j = 0;
unsigned cref;
assert(solver_dlevel(s) == 0);
if (solver_propagate(s) != UNDEF)
return SATOKO_ERR;
if (s->n_assigns_simplify == vec_uint_size(s->trail) || s->n_props_simplify > 0)
return SATOKO_OK;
vec_uint_foreach(s->originals, cref, i) {
struct clause *clause = clause_fetch(s, cref);
if (clause_is_satisfied(s, clause)) {
clause->f_mark = 1;
s->stats.n_original_lits -= clause->size;
clause_unwatch(s, cref);
} else
vec_uint_assign(s->originals, j++, cref);
}
vec_uint_shrink(s->originals, j);
solver_rebuild_order(s);
s->n_assigns_simplify = vec_uint_size(s->trail);
s->n_props_simplify = s->stats.n_original_lits + s->stats.n_learnt_lits;
return SATOKO_OK;
}
void satoko_setnvars(solver_t *s, int nvars)
{
int i;
for (i = satoko_varnum(s); i < nvars; i++)
satoko_add_variable(s, 0);
}
int satoko_add_variable(solver_t *s, char sign)
{
unsigned var = vec_act_size(s->activity);
vec_wl_push(s->watches);
vec_wl_push(s->watches);
vec_act_push_back(s->activity, 0);
vec_uint_push_back(s->levels, 0);
vec_char_push_back(s->assigns, SATOKO_VAR_UNASSING);
vec_char_push_back(s->polarity, sign);
vec_uint_push_back(s->reasons, UNDEF);
vec_uint_push_back(s->stamps, 0);
vec_char_push_back(s->seen, 0);
heap_insert(s->var_order, var);
if (s->marks)
vec_char_push_back(s->marks, 0);
return var;
}
int satoko_add_clause(solver_t *s, int *lits, int size)
{
unsigned i, j;
unsigned prev_lit;
unsigned max_var;
unsigned cref;
qsort((void *) lits, size, sizeof(unsigned), stk_uint_compare);
max_var = lit2var(lits[size - 1]);
while (max_var >= vec_act_size(s->activity))
satoko_add_variable(s, SATOKO_LIT_FALSE);
vec_uint_clear(s->temp_lits);
j = 0;
prev_lit = UNDEF;
for (i = 0; i < (unsigned)size; i++) {
if ((unsigned)lits[i] == lit_compl(prev_lit) || lit_value(s, lits[i]) == SATOKO_LIT_TRUE)
return SATOKO_OK;
else if ((unsigned)lits[i] != prev_lit && var_value(s, lit2var(lits[i])) == SATOKO_VAR_UNASSING) {
prev_lit = lits[i];
vec_uint_push_back(s->temp_lits, lits[i]);
}
}
if (vec_uint_size(s->temp_lits) == 0) {
s->status = SATOKO_ERR;
return SATOKO_ERR;
} if (vec_uint_size(s->temp_lits) == 1) {
solver_enqueue(s, vec_uint_at(s->temp_lits, 0), UNDEF);
return (s->status = (solver_propagate(s) == UNDEF));
}
if ( 0 ) {
for ( i = 0; i < vec_uint_size(s->temp_lits); i++ ) {
int lit = vec_uint_at(s->temp_lits, i);
printf( "%s%d ", lit&1 ? "!":"", lit>>1 );
}
printf( "\n" );
}
cref = solver_clause_create(s, s->temp_lits, 0);
clause_watch(s, cref);
return SATOKO_OK;
}
void satoko_assump_push(solver_t *s, int lit)
{
assert(lit2var(lit) < (unsigned)satoko_varnum(s));
// printf("[Satoko] Push assumption: %d\n", lit);
vec_uint_push_back(s->assumptions, lit);
vec_char_assign(s->polarity, lit2var(lit), lit_polarity(lit));
}
void satoko_assump_pop(solver_t *s)
{
assert(vec_uint_size(s->assumptions) > 0);
// printf("[Satoko] Pop assumption: %d\n", vec_uint_pop_back(s->assumptions));
vec_uint_pop_back(s->assumptions);
solver_cancel_until(s, vec_uint_size(s->assumptions));
}
int satoko_solve(solver_t *s)
{
int status = SATOKO_UNDEC;
assert(s);
solver_clean_stats(s);
//if (s->opts.verbose)
// print_opts(s);
if (s->status == SATOKO_ERR) {
printf("Satoko in inconsistent state\n");
return SATOKO_UNDEC;
}
if (!s->opts.no_simplify)
if (satoko_simplify(s) != SATOKO_OK)
return SATOKO_UNDEC;
while (status == SATOKO_UNDEC) {
status = solver_search(s);
if (solver_check_limits(s) == 0 || solver_stop(s))
break;
if (s->nRuntimeLimit && Abc_Clock() > s->nRuntimeLimit)
break;
if (s->pFuncStop && s->pFuncStop(s->RunId))
break;
}
if (s->opts.verbose)
print_stats(s);
solver_cancel_until(s, vec_uint_size(s->assumptions));
return status;
}
int satoko_solve_assumptions(solver_t *s, int * plits, int nlits)
{
int i, status;
// printf("\n[Satoko] Solve with assumptions.. (%d)\n", vec_uint_size(s->assumptions));
// printf("[Satoko] + Variables: %d\n", satoko_varnum(s));
// printf("[Satoko] + Clauses: %d\n", satoko_clausenum(s));
// printf("[Satoko] + Trail size: %d\n", vec_uint_size(s->trail));
// printf("[Satoko] + Queue head: %d\n", s->i_qhead);
// solver_debug_check_trail(s);
for ( i = 0; i < nlits; i++ )
satoko_assump_push( s, plits[i] );
status = satoko_solve( s );
for ( i = 0; i < nlits; i++ )
satoko_assump_pop( s );
return status;
}
int satoko_solve_assumptions_limit(satoko_t *s, int * plits, int nlits, int nconflim)
{
int temp = s->opts.conf_limit, status;
s->opts.conf_limit = nconflim ? s->stats.n_conflicts + nconflim : 0;
status = satoko_solve_assumptions(s, plits, nlits);
s->opts.conf_limit = temp;
return status;
}
int satoko_minimize_assumptions(satoko_t * s, int * plits, int nlits, int nconflim)
{
int i, nlitsL, nlitsR, nresL, nresR, status;
if ( nlits == 1 )
{
// since the problem is UNSAT, we try to solve it without assuming the last literal
// if the result is UNSAT, the last literal can be dropped; otherwise, it is needed
status = satoko_solve_assumptions_limit( s, NULL, 0, nconflim );
return (int)(status != SATOKO_UNSAT); // return 1 if the problem is not UNSAT
}
assert( nlits >= 2 );
nlitsL = nlits / 2;
nlitsR = nlits - nlitsL;
// assume the left lits
for ( i = 0; i < nlitsL; i++ )
satoko_assump_push(s, plits[i]);
// solve with these assumptions
status = satoko_solve_assumptions_limit( s, NULL, 0, nconflim );
if ( status == SATOKO_UNSAT ) // these are enough
{
for ( i = 0; i < nlitsL; i++ )
satoko_assump_pop(s);
return satoko_minimize_assumptions( s, plits, nlitsL, nconflim );
}
// these are not enoguh
// solve for the right lits
nresL = nlitsR == 1 ? 1 : satoko_minimize_assumptions( s, plits + nlitsL, nlitsR, nconflim );
for ( i = 0; i < nlitsL; i++ )
satoko_assump_pop(s);
// swap literals
vec_uint_clear(s->temp_lits);
for ( i = 0; i < nlitsL; i++ )
vec_uint_push_back(s->temp_lits, plits[i]);
for ( i = 0; i < nresL; i++ )
plits[i] = plits[nlitsL+i];
for ( i = 0; i < nlitsL; i++ )
plits[nresL+i] = vec_uint_at(s->temp_lits, i);
// assume the right lits
for ( i = 0; i < nresL; i++ )
satoko_assump_push(s, plits[i]);
// solve with these assumptions
status = satoko_solve_assumptions_limit( s, NULL, 0, nconflim );
if ( status == SATOKO_UNSAT ) // these are enough
{
for ( i = 0; i < nresL; i++ )
satoko_assump_pop(s);
return nresL;
}
// solve for the left lits
nresR = nlitsL == 1 ? 1 : satoko_minimize_assumptions( s, plits + nresL, nlitsL, nconflim );
for ( i = 0; i < nresL; i++ )
satoko_assump_pop(s);
return nresL + nresR;
}
int satoko_final_conflict(solver_t *s, int **out)
{
*out = (int *)vec_uint_data(s->final_conflict);
return vec_uint_size(s->final_conflict);
}
satoko_stats_t * satoko_stats(satoko_t *s)
{
return &s->stats;
}
satoko_opts_t * satoko_options(satoko_t *s)
{
return &s->opts;
}
void satoko_bookmark(satoko_t *s)
{
// printf("[Satoko] Bookmark.\n");
assert(s->status == SATOKO_OK);
assert(solver_dlevel(s) == 0);
s->book_cl_orig = vec_uint_size(s->originals);
s->book_cl_lrnt = vec_uint_size(s->learnts);
s->book_vars = vec_char_size(s->assigns);
s->book_trail = vec_uint_size(s->trail);
// s->book_qhead = s->i_qhead;
s->opts.no_simplify = 1;
}
void satoko_unbookmark(satoko_t *s)
{
// printf("[Satoko] Unbookmark.\n");
assert(s->status == SATOKO_OK);
s->book_cl_orig = 0;
s->book_cl_lrnt = 0;
s->book_cdb = 0;
s->book_vars = 0;
s->book_trail = 0;
// s->book_qhead = 0;
s->opts.no_simplify = 0;
}
void satoko_reset(satoko_t *s)
{
// printf("[Satoko] Reset.\n");
vec_uint_clear(s->assumptions);
vec_uint_clear(s->final_conflict);
cdb_clear(s->all_clauses);
vec_uint_clear(s->originals);
vec_uint_clear(s->learnts);
vec_wl_clean(s->watches);
vec_act_clear(s->activity);
heap_clear(s->var_order);
vec_uint_clear(s->levels);
vec_uint_clear(s->reasons);
vec_char_clear(s->assigns);
vec_char_clear(s->polarity);
vec_uint_clear(s->trail);
vec_uint_clear(s->trail_lim);
b_queue_clean(s->bq_lbd);
b_queue_clean(s->bq_trail);
vec_uint_clear(s->temp_lits);
vec_char_clear(s->seen);
vec_uint_clear(s->tagged);
vec_uint_clear(s->stack);
vec_uint_clear(s->last_dlevel);
vec_uint_clear(s->stamps);
s->status = SATOKO_OK;
s->var_act_inc = VAR_ACT_INIT_INC;
s->clause_act_inc = CLAUSE_ACT_INIT_INC;
s->n_confl_bfr_reduce = s->opts.n_conf_fst_reduce;
s->RC1 = 1;
s->RC2 = s->opts.n_conf_fst_reduce;
s->book_cl_orig = 0;
s->book_cl_lrnt = 0;
s->book_cdb = 0;
s->book_vars = 0;
s->book_trail = 0;
s->i_qhead = 0;
}
void satoko_rollback(satoko_t *s)
{
unsigned i, cref;
unsigned n_originals = vec_uint_size(s->originals) - s->book_cl_orig;
unsigned n_learnts = vec_uint_size(s->learnts) - s->book_cl_lrnt;
struct clause **cl_to_remove;
// printf("[Satoko] rollback.\n");
assert(s->status == SATOKO_OK);
assert(solver_dlevel(s) == 0);
if (!s->book_vars) {
satoko_reset(s);
return;
}
cl_to_remove = satoko_alloc(struct clause *, n_originals + n_learnts);
/* Mark clauses */
vec_uint_foreach_start(s->originals, cref, i, s->book_cl_orig)
cl_to_remove[i] = clause_fetch(s, cref);
vec_uint_foreach_start(s->learnts, cref, i, s->book_cl_lrnt)
cl_to_remove[n_originals + i] = clause_fetch(s, cref);
for (i = 0; i < n_originals + n_learnts; i++) {
clause_unwatch(s, cdb_cref(s->all_clauses, (unsigned *)cl_to_remove[i]));
cl_to_remove[i]->f_mark = 1;
}
satoko_free(cl_to_remove);
vec_uint_shrink(s->originals, s->book_cl_orig);
vec_uint_shrink(s->learnts, s->book_cl_lrnt);
/* Shrink variable related vectors */
for (i = s->book_vars; i < 2 * vec_char_size(s->assigns); i++) {
vec_wl_at(s->watches, i)->size = 0;
vec_wl_at(s->watches, i)->n_bin = 0;
}
// s->i_qhead = s->book_qhead;
s->watches->size = s->book_vars;
vec_act_shrink(s->activity, s->book_vars);
vec_uint_shrink(s->levels, s->book_vars);
vec_uint_shrink(s->reasons, s->book_vars);
vec_uint_shrink(s->stamps, s->book_vars);
vec_char_shrink(s->assigns, s->book_vars);
vec_char_shrink(s->seen, s->book_vars);
vec_char_shrink(s->polarity, s->book_vars);
solver_rebuild_order(s);
/* Rewind solver and cancel level 0 assignments to the trail */
solver_cancel_until(s, 0);
vec_uint_shrink(s->trail, s->book_trail);
if (s->book_cdb)
s->all_clauses->size = s->book_cdb;
s->book_cl_orig = 0;
s->book_cl_lrnt = 0;
s->book_vars = 0;
s->book_trail = 0;
// s->book_qhead = 0;
}
void satoko_mark_cone(satoko_t *s, int * pvars, int n_vars)
{
int i;
if (!solver_has_marks(s))
s->marks = vec_char_init(satoko_varnum(s), 0);
for (i = 0; i < n_vars; i++) {
var_set_mark(s, pvars[i]);
vec_sdbl_assign(s->activity, pvars[i], 0);
if (!heap_in_heap(s->var_order, pvars[i]))
heap_insert(s->var_order, pvars[i]);
}
}
void satoko_unmark_cone(satoko_t *s, int *pvars, int n_vars)
{
int i;
assert(solver_has_marks(s));
for (i = 0; i < n_vars; i++)
var_clean_mark(s, pvars[i]);
}
void satoko_write_dimacs(satoko_t *s, char *fname, int wrt_lrnt, int zero_var)
{
FILE *file;
unsigned i;
unsigned n_vars = vec_act_size(s->activity);
unsigned n_orig = vec_uint_size(s->originals) + vec_uint_size(s->trail);
unsigned n_lrnts = vec_uint_size(s->learnts);
unsigned *array;
assert(wrt_lrnt == 0 || wrt_lrnt == 1);
assert(zero_var == 0 || zero_var == 1);
if (fname != NULL)
file = fopen(fname, "w");
else
file = stdout;
if (file == NULL) {
printf( "Error: Cannot open output file.\n");
return;
}
fprintf(file, "p cnf %d %d\n", n_vars, wrt_lrnt ? n_orig + n_lrnts : n_orig);
for (i = 0; i < vec_char_size(s->assigns); i++) {
if ( var_value(s, i) != SATOKO_VAR_UNASSING ) {
if (zero_var)
fprintf(file, "%d\n", var_value(s, i) == SATOKO_LIT_FALSE ? -(int)(i) : i);
else
fprintf(file, "%d 0\n", var_value(s, i) == SATOKO_LIT_FALSE ? -(int)(i + 1) : i + 1);
}
}
array = vec_uint_data(s->originals);
for (i = 0; i < vec_uint_size(s->originals); i++)
clause_dump(file, clause_fetch(s, array[i]), !zero_var);
if (wrt_lrnt) {
array = vec_uint_data(s->learnts);
for (i = 0; i < n_lrnts; i++)
clause_dump(file, clause_fetch(s, array[i]), !zero_var);
}
fclose(file);
}
int satoko_varnum(satoko_t *s)
{
return vec_char_size(s->assigns);
}
int satoko_clausenum(satoko_t *s)
{
return vec_uint_size(s->originals);
}
int satoko_learntnum(satoko_t *s)
{
return vec_uint_size(s->learnts);
}
int satoko_conflictnum(satoko_t *s)
{
return satoko_stats(s)->n_conflicts_all;
}
void satoko_set_stop(satoko_t *s, int * pstop)
{
s->pstop = pstop;
}
void satoko_set_stop_func(satoko_t *s, int (*fnct)(int))
{
s->pFuncStop = fnct;
}
void satoko_set_runid(satoko_t *s, int id)
{
s->RunId = id;
}
int satoko_read_cex_varvalue(satoko_t *s, int ivar)
{
return satoko_var_polarity(s, ivar) == SATOKO_LIT_TRUE;
}
abctime satoko_set_runtime_limit(satoko_t* s, abctime Limit)
{
abctime nRuntimeLimit = s->nRuntimeLimit;
s->nRuntimeLimit = Limit;
return nRuntimeLimit;
}
char satoko_var_polarity(satoko_t *s, unsigned var)
{
return vec_char_at(s->polarity, var);
}
ABC_NAMESPACE_IMPL_END