| //===--- solver.c -----------------------------------------------------------=== |
| // |
| // 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_clause.h" |
| #include "act_var.h" |
| #include "solver.h" |
| #include "utils/heap.h" |
| #include "utils/mem.h" |
| #include "utils/sort.h" |
| |
| #include "misc/util/abc_global.h" |
| ABC_NAMESPACE_IMPL_START |
| |
| //===------------------------------------------------------------------------=== |
| // Lit funtions |
| //===------------------------------------------------------------------------=== |
| /** |
| * A literal is said to be redundant in a given clause if and only if all |
| * variables in its reason are either present in that clause or (recursevely) |
| * redundant. |
| */ |
| static inline int lit_is_removable(solver_t* s, unsigned lit, unsigned min_level) |
| { |
| unsigned top = vec_uint_size(s->tagged); |
| |
| assert(lit_reason(s, lit) != UNDEF); |
| vec_uint_clear(s->stack); |
| vec_uint_push_back(s->stack, lit2var(lit)); |
| while (vec_uint_size(s->stack)) { |
| unsigned i; |
| unsigned var = vec_uint_pop_back(s->stack); |
| struct clause *c = clause_fetch(s, var_reason(s, var)); |
| unsigned *lits = &(c->data[0].lit); |
| |
| assert(var_reason(s, var) != UNDEF); |
| if (c->size == 2 && lit_value(s, lits[0]) == SATOKO_LIT_FALSE) { |
| assert(lit_value(s, lits[1]) == SATOKO_LIT_TRUE); |
| stk_swap(unsigned, lits[0], lits[1]); |
| } |
| |
| /* Check scan the literals of the reason clause. |
| * The first literal is skiped because is the literal itself. */ |
| for (i = 1; i < c->size; i++) { |
| var = lit2var(lits[i]); |
| |
| /* Check if the variable has already been seen or if it |
| * was assinged a value at the decision level 0. In a |
| * positive case, there is no need to look any further */ |
| if (vec_char_at(s->seen, var) || var_dlevel(s, var) == 0) |
| continue; |
| |
| /* If the variable has a reason clause and if it was |
| * assingned at a 'possible' level, then we need to |
| * check if it is recursively redundant, otherwise the |
| * literal being checked is not redundant */ |
| if (var_reason(s, var) != UNDEF && ((1 << (var_dlevel(s, var) & 31)) & min_level)) { |
| vec_uint_push_back(s->stack, var); |
| vec_uint_push_back(s->tagged, var); |
| vec_char_assign(s->seen, var, 1); |
| } else { |
| vec_uint_foreach_start(s->tagged, var, i, top) |
| vec_char_assign(s->seen, var, 0); |
| vec_uint_shrink(s->tagged, top); |
| return 0; |
| } |
| } |
| } |
| return 1; |
| } |
| |
| //===------------------------------------------------------------------------=== |
| // Clause functions |
| //===------------------------------------------------------------------------=== |
| /* Calculate clause LBD (Literal Block Distance): |
| * - It's the number of variables in the final conflict clause that come from |
| * different decision levels |
| */ |
| static inline unsigned clause_clac_lbd(solver_t *s, unsigned *lits, unsigned size) |
| { |
| unsigned i; |
| unsigned lbd = 0; |
| |
| s->cur_stamp++; |
| for (i = 0; i < size; i++) { |
| unsigned level = lit_dlevel(s, lits[i]); |
| if (vec_uint_at(s->stamps, level) != s->cur_stamp) { |
| vec_uint_assign(s->stamps, level, s->cur_stamp); |
| lbd++; |
| } |
| } |
| return lbd; |
| } |
| |
| static inline void clause_bin_resolution(solver_t *s, vec_uint_t *clause_lits) |
| { |
| unsigned *lits = vec_uint_data(clause_lits); |
| unsigned counter, sz, i; |
| unsigned lit; |
| unsigned neg_lit = lit_compl(lits[0]); |
| struct watcher *w; |
| |
| s->cur_stamp++; |
| vec_uint_foreach(clause_lits, lit, i) |
| vec_uint_assign(s->stamps, lit2var(lit), s->cur_stamp); |
| |
| counter = 0; |
| watch_list_foreach_bin(s->watches, w, neg_lit) { |
| unsigned imp_lit = w->blocker; |
| if (vec_uint_at(s->stamps, lit2var(imp_lit)) == s->cur_stamp && |
| lit_value(s, imp_lit) == SATOKO_LIT_TRUE) { |
| counter++; |
| vec_uint_assign(s->stamps, lit2var(imp_lit), (s->cur_stamp - 1)); |
| } |
| } |
| if (counter > 0) { |
| sz = vec_uint_size(clause_lits) - 1; |
| for (i = 1; i < vec_uint_size(clause_lits) - counter; i++) |
| if (vec_uint_at(s->stamps, lit2var(lits[i])) != s->cur_stamp) { |
| stk_swap(unsigned, lits[i], lits[sz]); |
| i--; |
| sz--; |
| } |
| vec_uint_shrink(clause_lits, vec_uint_size(clause_lits) - counter); |
| } |
| } |
| |
| static inline void clause_minimize(solver_t *s, vec_uint_t *clause_lits) |
| { |
| unsigned i, j; |
| unsigned *lits = vec_uint_data(clause_lits); |
| unsigned min_level = 0; |
| unsigned clause_size; |
| |
| for (i = 1; i < vec_uint_size(clause_lits); i++) { |
| unsigned level = lit_dlevel(s, lits[i]); |
| min_level |= 1 << (level & 31); |
| } |
| |
| /* Remove reduntant literals */ |
| vec_uint_foreach(clause_lits, i, j) |
| vec_uint_push_back(s->tagged, lit2var(i)); |
| for (i = j = 1; i < vec_uint_size(clause_lits); i++) |
| if (lit_reason(s, lits[i]) == UNDEF || !lit_is_removable(s, lits[i], min_level)) |
| lits[j++] = lits[i]; |
| vec_uint_shrink(clause_lits, j); |
| |
| /* Binary Resolution */ |
| clause_size = vec_uint_size(clause_lits); |
| if (clause_size <= s->opts.clause_max_sz_bin_resol && |
| clause_clac_lbd(s, lits, clause_size) <= s->opts.clause_min_lbd_bin_resol) |
| clause_bin_resolution(s, clause_lits); |
| } |
| |
| static inline void clause_realloc(struct cdb *dest, struct cdb *src, unsigned *cref) |
| { |
| unsigned new_cref; |
| struct clause *new_clause; |
| struct clause *old_clause = cdb_handler(src, *cref); |
| |
| if (old_clause->f_reallocd) { |
| *cref = (unsigned) old_clause->size; |
| return; |
| } |
| new_cref = cdb_append(dest, 3 + old_clause->f_learnt + old_clause->size); |
| new_clause = cdb_handler(dest, new_cref); |
| memcpy(new_clause, old_clause, (3 + old_clause->f_learnt + old_clause->size) * 4); |
| old_clause->f_reallocd = 1; |
| old_clause->size = (unsigned) new_cref; |
| *cref = new_cref; |
| } |
| |
| //===------------------------------------------------------------------------=== |
| // Solver internal functions |
| //===------------------------------------------------------------------------=== |
| static inline unsigned solver_decide(solver_t *s) |
| { |
| unsigned next_var = UNDEF; |
| |
| while (next_var == UNDEF || var_value(s, next_var) != SATOKO_VAR_UNASSING) { |
| if (heap_size(s->var_order) == 0) { |
| next_var = UNDEF; |
| return UNDEF; |
| } |
| next_var = heap_remove_min(s->var_order); |
| if (solver_has_marks(s) && !var_mark(s, next_var)) |
| next_var = UNDEF; |
| } |
| return var2lit(next_var, satoko_var_polarity(s, next_var)); |
| } |
| |
| static inline void solver_new_decision(solver_t *s, unsigned lit) |
| { |
| if (solver_has_marks(s) && !var_mark(s, lit2var(lit))) |
| return; |
| assert(var_value(s, lit2var(lit)) == SATOKO_VAR_UNASSING); |
| vec_uint_push_back(s->trail_lim, vec_uint_size(s->trail)); |
| solver_enqueue(s, lit, UNDEF); |
| } |
| |
| /* Calculate Backtrack Level from the learnt clause */ |
| static inline unsigned solver_calc_bt_level(solver_t *s, vec_uint_t *learnt) |
| { |
| unsigned i, tmp; |
| unsigned i_max = 1; |
| unsigned *lits = vec_uint_data(learnt); |
| unsigned max = lit_dlevel(s, lits[1]); |
| |
| if (vec_uint_size(learnt) == 1) |
| return 0; |
| for (i = 2; i < vec_uint_size(learnt); i++) { |
| if (lit_dlevel(s, lits[i]) > max) { |
| max = lit_dlevel(s, lits[i]); |
| i_max = i; |
| } |
| } |
| tmp = lits[1]; |
| lits[1] = lits[i_max]; |
| lits[i_max] = tmp; |
| return lit_dlevel(s, lits[1]); |
| } |
| |
| /** |
| * Most books and papers explain conflict analysis and the calculation of the |
| * 1UIP (first Unique Implication Point) using an implication graph. This |
| * function, however, do not explicity constructs the graph! It inspects the |
| * trail in reverse and figure out which literals should be added to the |
| * to-be-learnt clause using the reasons of each assignment. |
| * |
| * cur_lit: current literal being analyzed. |
| * n_paths: number of unprocessed paths from conlfict node to the current |
| * literal being analyzed (cur_lit). |
| * |
| * This functions performs a backward BFS (breadth-first search) for 1UIP node. |
| * The trail works as the BFS queue. The counter of unprocessed but seen |
| * variables (n_paths) allows us to identify when 'cur_lit' is the closest |
| * cause of conflict. |
| * |
| * When 'n_paths' reaches zero it means there are no unprocessed reverse paths |
| * back from the conflict node to 'cur_lit' - meaning it is the 1UIP decision |
| * variable. |
| * |
| */ |
| static inline void solver_analyze(solver_t *s, unsigned cref, vec_uint_t *learnt, |
| unsigned *bt_level, unsigned *lbd) |
| { |
| unsigned i; |
| unsigned *trail = vec_uint_data(s->trail); |
| unsigned idx = vec_uint_size(s->trail) - 1; |
| unsigned n_paths = 0; |
| unsigned p = UNDEF; |
| unsigned var; |
| |
| vec_uint_push_back(learnt, UNDEF); |
| do { |
| struct clause *clause; |
| unsigned *lits; |
| unsigned j; |
| |
| assert(cref != UNDEF); |
| clause = clause_fetch(s, cref); |
| lits = &(clause->data[0].lit); |
| |
| if (p != UNDEF && clause->size == 2 && lit_value(s, lits[0]) == SATOKO_LIT_FALSE) { |
| assert(lit_value(s, lits[1]) == SATOKO_LIT_TRUE); |
| stk_swap(unsigned, lits[0], lits[1] ); |
| } |
| |
| if (clause->f_learnt) |
| clause_act_bump(s, clause); |
| |
| if (clause->f_learnt && clause->lbd > 2) { |
| unsigned n_levels = clause_clac_lbd(s, lits, clause->size); |
| if (n_levels + 1 < clause->lbd) { |
| if (clause->lbd <= s->opts.lbd_freeze_clause) |
| clause->f_deletable = 0; |
| clause->lbd = n_levels; |
| } |
| } |
| |
| for (j = (p == UNDEF ? 0 : 1); j < clause->size; j++) { |
| var = lit2var(lits[j]); |
| if (vec_char_at(s->seen, var) || var_dlevel(s, var) == 0) |
| continue; |
| vec_char_assign(s->seen, var, 1); |
| var_act_bump(s, var); |
| if (var_dlevel(s, var) == solver_dlevel(s)) { |
| n_paths++; |
| if (var_reason(s, var) != UNDEF && clause_fetch(s, var_reason(s, var))->f_learnt) |
| vec_uint_push_back(s->last_dlevel, var); |
| } else |
| vec_uint_push_back(learnt, lits[j]); |
| } |
| |
| while (!vec_char_at(s->seen, lit2var(trail[idx--]))); |
| |
| p = trail[idx + 1]; |
| cref = lit_reason(s, p); |
| vec_char_assign(s->seen, lit2var(p), 0); |
| n_paths--; |
| } while (n_paths > 0); |
| |
| vec_uint_data(learnt)[0] = lit_compl(p); |
| clause_minimize(s, learnt); |
| *bt_level = solver_calc_bt_level(s, learnt); |
| *lbd = clause_clac_lbd(s, vec_uint_data(learnt), vec_uint_size(learnt)); |
| |
| if (vec_uint_size(s->last_dlevel) > 0) { |
| vec_uint_foreach(s->last_dlevel, var, i) { |
| if (clause_fetch(s, var_reason(s, var))->lbd < *lbd) |
| var_act_bump(s, var); |
| } |
| vec_uint_clear(s->last_dlevel); |
| } |
| vec_uint_foreach(s->tagged, var, i) |
| vec_char_assign(s->seen, var, 0); |
| vec_uint_clear(s->tagged); |
| } |
| |
| static inline int solver_rst(solver_t *s) |
| { |
| return b_queue_is_valid(s->bq_lbd) && |
| (((long)b_queue_avg(s->bq_lbd) * s->opts.f_rst) > (s->sum_lbd / s->stats.n_conflicts)); |
| } |
| |
| static inline int solver_block_rst(solver_t *s) |
| { |
| return s->stats.n_conflicts > (int)s->opts.fst_block_rst && |
| b_queue_is_valid(s->bq_lbd) && |
| ((long)vec_uint_size(s->trail) > (s->opts.b_rst * (long)b_queue_avg(s->bq_trail))); |
| } |
| |
| static inline void solver_handle_conflict(solver_t *s, unsigned confl_cref) |
| { |
| unsigned bt_level; |
| unsigned lbd; |
| unsigned cref; |
| |
| vec_uint_clear(s->temp_lits); |
| solver_analyze(s, confl_cref, s->temp_lits, &bt_level, &lbd); |
| s->sum_lbd += lbd; |
| b_queue_push(s->bq_lbd, lbd); |
| solver_cancel_until(s, bt_level); |
| cref = UNDEF; |
| if (vec_uint_size(s->temp_lits) > 1) { |
| cref = solver_clause_create(s, s->temp_lits, 1); |
| clause_watch(s, cref); |
| } |
| solver_enqueue(s, vec_uint_at(s->temp_lits, 0), cref); |
| var_act_decay(s); |
| clause_act_decay(s); |
| } |
| |
| static inline void solver_analyze_final(solver_t *s, unsigned lit) |
| { |
| unsigned i; |
| |
| // printf("[Satoko] Analize final..\n"); |
| // printf("[Satoko] Conflicting lit: %d\n", lit); |
| vec_uint_clear(s->final_conflict); |
| vec_uint_push_back(s->final_conflict, lit); |
| if (solver_dlevel(s) == 0) |
| return; |
| vec_char_assign(s->seen, lit2var(lit), 1); |
| for (i = vec_uint_size(s->trail); i --> vec_uint_at(s->trail_lim, 0);) { |
| unsigned var = lit2var(vec_uint_at(s->trail, i)); |
| |
| if (vec_char_at(s->seen, var)) { |
| unsigned reason = var_reason(s, var); |
| if (reason == UNDEF) { |
| assert(var_dlevel(s, var) > 0); |
| vec_uint_push_back(s->final_conflict, lit_compl(vec_uint_at(s->trail, i))); |
| } else { |
| unsigned j; |
| struct clause *clause = clause_fetch(s, reason); |
| for (j = (clause->size == 2 ? 0 : 1); j < clause->size; j++) { |
| if (lit_dlevel(s, clause->data[j].lit) > 0) |
| vec_char_assign(s->seen, lit2var(clause->data[j].lit), 1); |
| } |
| } |
| vec_char_assign(s->seen, var, 0); |
| } |
| } |
| vec_char_assign(s->seen, lit2var(lit), 0); |
| // solver_debug_check_unsat(s); |
| } |
| |
| static inline void solver_garbage_collect(solver_t *s) |
| { |
| unsigned i; |
| unsigned *array; |
| struct cdb *new_cdb = cdb_alloc(cdb_capacity(s->all_clauses) - cdb_wasted(s->all_clauses)); |
| |
| if (s->book_cdb) |
| s->book_cdb = 0; |
| |
| for (i = 0; i < 2 * vec_char_size(s->assigns); i++) { |
| struct watcher *w; |
| watch_list_foreach(s->watches, w, i) |
| clause_realloc(new_cdb, s->all_clauses, &(w->cref)); |
| } |
| |
| /* Update CREFS */ |
| for (i = 0; i < vec_uint_size(s->trail); i++) |
| if (lit_reason(s, vec_uint_at(s->trail, i)) != UNDEF) |
| clause_realloc(new_cdb, s->all_clauses, &(vec_uint_data(s->reasons)[lit2var(vec_uint_at(s->trail, i))])); |
| |
| array = vec_uint_data(s->learnts); |
| for (i = 0; i < vec_uint_size(s->learnts); i++) |
| clause_realloc(new_cdb, s->all_clauses, &(array[i])); |
| |
| array = vec_uint_data(s->originals); |
| for (i = 0; i < vec_uint_size(s->originals); i++) |
| clause_realloc(new_cdb, s->all_clauses, &(array[i])); |
| |
| cdb_free(s->all_clauses); |
| s->all_clauses = new_cdb; |
| } |
| |
| static inline void solver_reduce_cdb(solver_t *s) |
| { |
| unsigned i, limit; |
| unsigned n_learnts = vec_uint_size(s->learnts); |
| unsigned cref; |
| struct clause *clause; |
| struct clause **learnts_cls; |
| |
| learnts_cls = satoko_alloc(struct clause *, n_learnts); |
| vec_uint_foreach_start(s->learnts, cref, i, s->book_cl_lrnt) |
| learnts_cls[i] = clause_fetch(s, cref); |
| |
| limit = (unsigned)(n_learnts * s->opts.learnt_ratio); |
| |
| satoko_sort((void **)learnts_cls, n_learnts, |
| (int (*)(const void *, const void *)) clause_compare); |
| |
| if (learnts_cls[n_learnts / 2]->lbd <= 3) |
| s->RC2 += s->opts.inc_special_reduce; |
| if (learnts_cls[n_learnts - 1]->lbd <= 6) |
| s->RC2 += s->opts.inc_special_reduce; |
| |
| vec_uint_clear(s->learnts); |
| for (i = 0; i < n_learnts; i++) { |
| clause = learnts_cls[i]; |
| cref = cdb_cref(s->all_clauses, (unsigned *)clause); |
| assert(clause->f_mark == 0); |
| if (clause->f_deletable && clause->lbd > 2 && clause->size > 2 && lit_reason(s, clause->data[0].lit) != cref && (i < limit)) { |
| clause->f_mark = 1; |
| s->stats.n_learnt_lits -= clause->size; |
| clause_unwatch(s, cref); |
| cdb_remove(s->all_clauses, clause); |
| } else { |
| if (!clause->f_deletable) |
| limit++; |
| clause->f_deletable = 1; |
| vec_uint_push_back(s->learnts, cref); |
| } |
| } |
| satoko_free(learnts_cls); |
| |
| if (s->opts.verbose) { |
| printf("reduceDB: Keeping %7d out of %7d clauses (%5.2f %%) \n", |
| vec_uint_size(s->learnts), n_learnts, |
| 100.0 * vec_uint_size(s->learnts) / n_learnts); |
| fflush(stdout); |
| } |
| if (cdb_wasted(s->all_clauses) > cdb_size(s->all_clauses) * s->opts.garbage_max_ratio) |
| solver_garbage_collect(s); |
| } |
| |
| //===------------------------------------------------------------------------=== |
| // Solver external functions |
| //===------------------------------------------------------------------------=== |
| unsigned solver_clause_create(solver_t *s, vec_uint_t *lits, unsigned f_learnt) |
| { |
| struct clause *clause; |
| unsigned cref; |
| unsigned n_words; |
| |
| assert(vec_uint_size(lits) > 1); |
| assert(f_learnt == 0 || f_learnt == 1); |
| |
| n_words = 3 + f_learnt + vec_uint_size(lits); |
| cref = cdb_append(s->all_clauses, n_words); |
| clause = clause_fetch(s, cref); |
| clause->f_learnt = f_learnt; |
| clause->f_mark = 0; |
| clause->f_reallocd = 0; |
| clause->f_deletable = f_learnt; |
| clause->size = vec_uint_size(lits); |
| memcpy(&(clause->data[0].lit), vec_uint_data(lits), sizeof(unsigned) * vec_uint_size(lits)); |
| |
| if (f_learnt) { |
| vec_uint_push_back(s->learnts, cref); |
| clause->lbd = clause_clac_lbd(s, vec_uint_data(lits), vec_uint_size(lits)); |
| clause->data[clause->size].act = 0; |
| s->stats.n_learnt_lits += vec_uint_size(lits); |
| clause_act_bump(s, clause); |
| } else { |
| vec_uint_push_back(s->originals, cref); |
| s->stats.n_original_lits += vec_uint_size(lits); |
| } |
| return cref; |
| } |
| |
| void solver_cancel_until(solver_t *s, unsigned level) |
| { |
| unsigned i; |
| |
| if (solver_dlevel(s) <= level) |
| return; |
| for (i = vec_uint_size(s->trail); i --> vec_uint_at(s->trail_lim, level);) { |
| unsigned var = lit2var(vec_uint_at(s->trail, i)); |
| |
| vec_char_assign(s->assigns, var, SATOKO_VAR_UNASSING); |
| vec_uint_assign(s->reasons, var, UNDEF); |
| if (!heap_in_heap(s->var_order, var)) |
| heap_insert(s->var_order, var); |
| } |
| s->i_qhead = vec_uint_at(s->trail_lim, level); |
| vec_uint_shrink(s->trail, vec_uint_at(s->trail_lim, level)); |
| vec_uint_shrink(s->trail_lim, level); |
| } |
| |
| unsigned solver_propagate(solver_t *s) |
| { |
| unsigned conf_cref = UNDEF; |
| unsigned *lits; |
| unsigned neg_lit; |
| unsigned n_propagations = 0; |
| |
| while (s->i_qhead < vec_uint_size(s->trail)) { |
| unsigned p = vec_uint_at(s->trail, s->i_qhead++); |
| struct watch_list *ws; |
| struct watcher *begin; |
| struct watcher *end; |
| struct watcher *i, *j; |
| |
| n_propagations++; |
| watch_list_foreach_bin(s->watches, i, p) { |
| if (solver_has_marks(s) && !var_mark(s, lit2var(i->blocker))) |
| continue; |
| if (var_value(s, lit2var(i->blocker)) == SATOKO_VAR_UNASSING) |
| solver_enqueue(s, i->blocker, i->cref); |
| else if (lit_value(s, i->blocker) == SATOKO_LIT_FALSE) |
| return i->cref; |
| } |
| |
| ws = vec_wl_at(s->watches, p); |
| begin = watch_list_array(ws); |
| end = begin + watch_list_size(ws); |
| for (i = j = begin + ws->n_bin; i < end;) { |
| struct clause *clause; |
| struct watcher w; |
| |
| if (solver_has_marks(s) && !var_mark(s, lit2var(i->blocker))) { |
| *j++ = *i++; |
| continue; |
| } |
| if (lit_value(s, i->blocker) == SATOKO_LIT_TRUE) { |
| *j++ = *i++; |
| continue; |
| } |
| |
| clause = clause_fetch(s, i->cref); |
| lits = &(clause->data[0].lit); |
| |
| // Make sure the false literal is data[1]: |
| neg_lit = lit_compl(p); |
| if (lits[0] == neg_lit) |
| stk_swap(unsigned, lits[0], lits[1]); |
| assert(lits[1] == neg_lit); |
| |
| w.cref = i->cref; |
| w.blocker = lits[0]; |
| |
| /* If 0th watch is true, then clause is already satisfied. */ |
| if (lits[0] != i->blocker && lit_value(s, lits[0]) == SATOKO_LIT_TRUE) |
| *j++ = w; |
| else { |
| /* Look for new watch */ |
| unsigned k; |
| for (k = 2; k < clause->size; k++) { |
| if (lit_value(s, lits[k]) != SATOKO_LIT_FALSE) { |
| lits[1] = lits[k]; |
| lits[k] = neg_lit; |
| watch_list_push(vec_wl_at(s->watches, lit_compl(lits[1])), w, 0); |
| goto next; |
| } |
| } |
| |
| *j++ = w; |
| |
| /* Clause becomes unit under this assignment */ |
| if (lit_value(s, lits[0]) == SATOKO_LIT_FALSE) { |
| conf_cref = i->cref; |
| s->i_qhead = vec_uint_size(s->trail); |
| i++; |
| // Copy the remaining watches: |
| while (i < end) |
| *j++ = *i++; |
| } else |
| solver_enqueue(s, lits[0], i->cref); |
| } |
| next: |
| i++; |
| } |
| |
| s->stats.n_inspects += j - watch_list_array(ws); |
| watch_list_shrink(ws, j - watch_list_array(ws)); |
| } |
| s->stats.n_propagations += n_propagations; |
| s->stats.n_propagations_all += n_propagations; |
| s->n_props_simplify -= n_propagations; |
| return conf_cref; |
| } |
| |
| char solver_search(solver_t *s) |
| { |
| s->stats.n_starts++; |
| while (1) { |
| unsigned confl_cref = solver_propagate(s); |
| if (confl_cref != UNDEF) { |
| s->stats.n_conflicts++; |
| s->stats.n_conflicts_all++; |
| if (solver_dlevel(s) == 0) |
| return SATOKO_UNSAT; |
| /* Restart heuristic */ |
| b_queue_push(s->bq_trail, vec_uint_size(s->trail)); |
| if (solver_block_rst(s)) |
| b_queue_clean(s->bq_lbd); |
| solver_handle_conflict(s, confl_cref); |
| } else { |
| // solver_debug_check_clauses(s); |
| /* No conflict */ |
| unsigned next_lit; |
| |
| if (solver_rst(s) || solver_check_limits(s) == 0 || solver_stop(s) || |
| (s->nRuntimeLimit && (s->stats.n_conflicts & 63) == 0 && Abc_Clock() > s->nRuntimeLimit)) { |
| b_queue_clean(s->bq_lbd); |
| solver_cancel_until(s, 0); |
| return SATOKO_UNDEC; |
| } |
| if (!s->opts.no_simplify && solver_dlevel(s) == 0) |
| satoko_simplify(s); |
| |
| /* Reduce the set of learnt clauses */ |
| if (s->opts.learnt_ratio && vec_uint_size(s->learnts) > 100 && |
| s->stats.n_conflicts >= s->n_confl_bfr_reduce) { |
| s->RC1 = (s->stats.n_conflicts / s->RC2) + 1; |
| solver_reduce_cdb(s); |
| s->RC2 += s->opts.inc_reduce; |
| s->n_confl_bfr_reduce = s->RC1 * s->RC2; |
| } |
| |
| /* Make decisions based on user assumptions */ |
| next_lit = UNDEF; |
| while (solver_dlevel(s) < vec_uint_size(s->assumptions)) { |
| unsigned lit = vec_uint_at(s->assumptions, solver_dlevel(s)); |
| if (lit_value(s, lit) == SATOKO_LIT_TRUE) { |
| vec_uint_push_back(s->trail_lim, vec_uint_size(s->trail)); |
| } else if (lit_value(s, lit) == SATOKO_LIT_FALSE) { |
| solver_analyze_final(s, lit_compl(lit)); |
| return SATOKO_UNSAT; |
| } else { |
| next_lit = lit; |
| break; |
| } |
| |
| } |
| if (next_lit == UNDEF) { |
| s->stats.n_decisions++; |
| next_lit = solver_decide(s); |
| if (next_lit == UNDEF) { |
| // solver_debug_check(s, SATOKO_SAT); |
| return SATOKO_SAT; |
| } |
| } |
| solver_new_decision(s, next_lit); |
| } |
| } |
| } |
| |
| //===------------------------------------------------------------------------=== |
| // Debug procedures |
| //===------------------------------------------------------------------------=== |
| void solver_debug_check_trail(solver_t *s) |
| { |
| unsigned i; |
| unsigned *array; |
| vec_uint_t *trail_dup = vec_uint_alloc(0); |
| fprintf(stdout, "[Satoko] Checking for trail(%u) inconsistencies...\n", vec_uint_size(s->trail)); |
| vec_uint_duplicate(trail_dup, s->trail); |
| vec_uint_sort(trail_dup, 1); |
| array = vec_uint_data(trail_dup); |
| for (i = 1; i < vec_uint_size(trail_dup); i++) { |
| if (array[i - 1] == lit_compl(array[i])) { |
| fprintf(stdout, "[Satoko] Inconsistent trail: %u %u\n", array[i - 1], array[i]); |
| assert(0); |
| return; |
| } |
| } |
| for (i = 0; i < vec_uint_size(trail_dup); i++) { |
| if (var_value(s, lit2var(array[i])) != lit_polarity(array[i])) { |
| fprintf(stdout, "[Satoko] Inconsistent trail assignment: %u, %u\n", vec_char_at(s->assigns, lit2var(array[i])), array[i]); |
| assert(0); |
| return; |
| } |
| } |
| fprintf(stdout, "[Satoko] Trail OK.\n"); |
| vec_uint_print(trail_dup); |
| vec_uint_free(trail_dup); |
| |
| } |
| |
| void solver_debug_check_clauses(solver_t *s) |
| { |
| unsigned cref, i; |
| |
| fprintf(stdout, "[Satoko] Checking clauses (%d)...\n", vec_uint_size(s->originals)); |
| vec_uint_foreach(s->originals, cref, i) { |
| unsigned j; |
| struct clause *clause = clause_fetch(s, cref); |
| for (j = 0; j < clause->size; j++) { |
| if (vec_uint_find(s->trail, lit_compl(clause->data[j].lit))) { |
| continue; |
| } |
| break; |
| } |
| if (j == clause->size) { |
| vec_uint_print(s->trail); |
| fprintf(stdout, "[Satoko] FOUND UNSAT CLAUSE]: (%d) ", i); |
| clause_print(clause); |
| assert(0); |
| } |
| } |
| fprintf(stdout, "[Satoko] All SAT - OK\n"); |
| } |
| |
| void solver_debug_check(solver_t *s, int result) |
| { |
| unsigned cref, i; |
| solver_debug_check_trail(s); |
| fprintf(stdout, "[Satoko] Checking clauses (%d)... \n", vec_uint_size(s->originals)); |
| vec_uint_foreach(s->originals, cref, i) { |
| unsigned j; |
| struct clause *clause = clause_fetch(s, cref); |
| for (j = 0; j < clause->size; j++) { |
| if (vec_uint_find(s->trail, clause->data[j].lit)) { |
| break; |
| } |
| } |
| if (result == SATOKO_SAT && j == clause->size) { |
| fprintf(stdout, "[Satoko] FOUND UNSAT CLAUSE: (%d) ", i); |
| clause_print(clause); |
| assert(0); |
| } |
| } |
| fprintf(stdout, "[Satoko] All SAT - OK\n"); |
| } |
| |
| ABC_NAMESPACE_IMPL_END |