2023-04-28 17:15:37 +08:00

2832 lines
94 KiB
C++
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/***************************************************************************************[Solver.cc]
MiniSat -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
Copyright (c) 2007-2010, Niklas Sorensson
Chanseok Oh's MiniSat Patch Series -- Copyright (c) 2015, Chanseok Oh
Maple_LCM, Based on MapleCOMSPS_DRUP -- Copyright (c) 2017, Mao Luo, Chu-Min LI, Fan Xiao: implementing a learnt clause minimisation approach
Reference: M. Luo, C.-M. Li, F. Xiao, F. Manya, and Z. L. , “An effective learnt clause minimization approach for cdcl sat solvers,” in IJCAI-2017, 2017, pp. toappear.
Maple_LCM_Dist, Based on Maple_LCM -- Copyright (c) 2017, Fan Xiao, Chu-Min LI, Mao Luo: using a new branching heuristic called Distance at the beginning of search
MapleLCMDistChronoBT, based on Maple_LCM_Dist -- Copyright (c), Alexander Nadel, Vadim Ryvchin: "Chronological Backtracking" in SAT-2018, pp. 111-121.
MapleLCMDistChronoBT-DL, based on MapleLCMDistChronoBT -- Copyright (c), Stepan Kochemazov, Oleg Zaikin, Victor Kondratiev, Alexander Semenov: The solver was augmented with heuristic that moves duplicate learnt clauses into the core/tier2 tiers depending on a number of parameters.
lstech, Relaxed_newTech -- Copyright (c) 2019-2021, Xindi Zhang, Shaowei Cai
Reference: Shaowei Cai, Xindi Zhang: Deep Cooperation of CDCL and Local Search for SAT.
Xindi Zhang, Shaowei Cai: Relaxed Backtracking with Rephasing.
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.
**************************************************************************************************/
#include <math.h>
#include <algorithm>
#include <signal.h>
#include <unistd.h>
#include <fstream>
#include "mtl/Sort.h"
#include "core/Solver.h"
#include "utils/ccnr.h"
#include "utils/System.h"
using namespace Minisat;
//#define PRINT_OUT
#ifdef BIN_DRUP
int Solver::buf_len = 0;
unsigned char Solver::drup_buf[2 * 1024 * 1024];
unsigned char* Solver::buf_ptr = drup_buf;
#endif
//=================================================================================================
// Options:
static const char* _cat = "CORE";
static DoubleOption opt_step_size (_cat, "step-size", "Initial step size", 0.40, DoubleRange(0, false, 1, false));
static DoubleOption opt_step_size_dec (_cat, "step-size-dec","Step size decrement", 0.000001, DoubleRange(0, false, 1, false));
static DoubleOption opt_min_step_size (_cat, "min-step-size","Minimal step size", 0.06, DoubleRange(0, false, 1, false));
static DoubleOption opt_var_decay (_cat, "var-decay", "The variable activity decay factor", 0.80, DoubleRange(0, false, 1, false));
static DoubleOption opt_clause_decay (_cat, "cla-decay", "The clause activity decay factor", 0.999, DoubleRange(0, false, 1, false));
static DoubleOption opt_random_var_freq (_cat, "rnd-freq", "The frequency with which the decision heuristic tries to choose a random variable", 0, DoubleRange(0, true, 1, true));
static DoubleOption opt_random_seed (_cat, "rnd-seed", "Used by the random variable selection", 91648253, DoubleRange(0, false, HUGE_VAL, false));
static IntOption opt_ccmin_mode (_cat, "ccmin-mode", "Controls conflict clause minimization (0=none, 1=basic, 2=deep)", 2, IntRange(0, 2));
static IntOption opt_phase_saving (_cat, "phase-saving", "Controls the level of phase saving (0=none, 1=limited, 2=full)", 2, IntRange(0, 2));
static BoolOption opt_rnd_init_act (_cat, "rnd-init", "Randomize the initial activity", false);
static IntOption opt_restart_first (_cat, "rfirst", "The base restart interval", 100, IntRange(1, INT32_MAX));
static DoubleOption opt_restart_inc (_cat, "rinc", "Restart interval increase factor", 2, DoubleRange(1, false, HUGE_VAL, false));
static DoubleOption opt_garbage_frac (_cat, "gc-frac", "The fraction of wasted memory allowed before a garbage collection is triggered", 0.20, DoubleRange(0, false, HUGE_VAL, false));
static IntOption opt_chrono (_cat, "chrono", "Controls if to perform chrono backtrack", 100, IntRange(-1, INT32_MAX));
static IntOption opt_conf_to_chrono (_cat, "confl-to-chrono", "Controls number of conflicts to perform chrono backtrack", 4000, IntRange(-1, INT32_MAX));
static IntOption opt_max_lbd_dup ("DUP-LEARNTS", "lbd-limit", "specifies the maximum lbd of learnts to be screened for duplicates.", 14, IntRange(0, INT32_MAX));
static IntOption opt_min_dupl_app ("DUP-LEARNTS", "min-dup-app", "specifies the minimum number of learnts to be included into db.", 2, IntRange(2, INT32_MAX));
static IntOption opt_dupl_db_init_size ("DUP-LEARNTS", "dupdb-init", "specifies the initial maximal duplicates DB size.", 1000000, IntRange(1, INT32_MAX));
//=================================================================================================
// Constructor/Destructor:
Solver::Solver() :
// Parameters (user settable):
//
worker_index (-1)
, worker_number (-1)
, worker_seed (-1)
, drup_file (NULL)
, verbosity (0)
, step_size (opt_step_size)
, step_size_dec (opt_step_size_dec)
, min_step_size (opt_min_step_size)
, timer (5000)
, var_decay (opt_var_decay)
, clause_decay (opt_clause_decay)
, random_var_freq (opt_random_var_freq)
, random_seed (opt_random_seed)
, VSIDS (false)
, ccmin_mode (opt_ccmin_mode)
, phase_saving (opt_phase_saving)
, rnd_pol (false)
, rnd_init_act (opt_rnd_init_act)
, garbage_frac (opt_garbage_frac)
, restart_first (opt_restart_first)
, restart_inc (opt_restart_inc)
, min_number_of_learnts_copies(opt_min_dupl_app)
, max_lbd_dup(opt_max_lbd_dup)
, dupl_db_init_size(opt_dupl_db_init_size)
// Parameters (the rest):
//
, learntsize_factor((double)1/(double)3), learntsize_inc(1.1)
// Parameters (experimental):
//
, learntsize_adjust_start_confl (100)
, learntsize_adjust_inc (1.5)
// Statistics: (formerly in 'SolverStats')
//
, solves(0), starts(0), decisions(0), rnd_decisions(0), propagations(0), conflicts(0), conflicts_VSIDS(0)
, dec_vars(0), clauses_literals(0), learnts_literals(0), max_literals(0), tot_literals(0)
, chrono_backtrack(0), non_chrono_backtrack(0)
, ok (true)
, cla_inc (1)
, var_inc (1)
, watches_bin (WatcherDeleted(ca))
, watches (WatcherDeleted(ca))
, qhead (0)
, simpDB_assigns (-1)
, simpDB_props (0)
, order_heap_CHB (VarOrderLt(activity_CHB))
, order_heap_VSIDS (VarOrderLt(activity_VSIDS))
, progress_estimate (0)
, remove_satisfied (true)
, core_lbd_cut (2)
, global_lbd_sum (0)
, lbd_queue (50)
, next_T2_reduce (10000)
, next_L_reduce (15000)
, confl_to_chrono (opt_conf_to_chrono)
, chrono (opt_chrono)
, counter (0)
// Resource constraints:
//
, conflict_budget (-1)
, propagation_budget (-1)
, asynch_interrupt (false)
// simplfiy
, nbSimplifyAll(0)
, s_propagations(0)
// simplifyAll adjust occasion
, curSimplify(1)
, nbconfbeforesimplify(1000)
, incSimplify(1000)
{}
Solver::~Solver()
{
}
// simplify All
//
CRef Solver::simplePropagate()
{
CRef confl = CRef_Undef;
int num_props = 0;
watches.cleanAll();
watches_bin.cleanAll();
while (qhead < trail.size())
{
Lit p = trail[qhead++]; // 'p' is enqueued fact to propagate.
vec<Watcher>& ws = watches[p];
Watcher *i, *j, *end;
num_props++;
// First, Propagate binary clauses
vec<Watcher>& wbin = watches_bin[p];
for (int k = 0; k<wbin.size(); k++)
{
Lit imp = wbin[k].blocker;
if (value(imp) == l_False)
{
return wbin[k].cref;
}
if (value(imp) == l_Undef)
{
simpleUncheckEnqueue(imp, wbin[k].cref);
}
}
for (i = j = (Watcher*)ws, end = i + ws.size(); i != end;)
{
// Try to avoid inspecting the clause:
Lit blocker = i->blocker;
if (value(blocker) == l_True)
{
*j++ = *i++; continue;
}
// Make sure the false literal is data[1]:
CRef cr = i->cref;
Clause& c = ca[cr];
Lit false_lit = ~p;
if (c[0] == false_lit)
c[0] = c[1], c[1] = false_lit;
assert(c[1] == false_lit);
// i++;
// If 0th watch is true, then clause is already satisfied.
// However, 0th watch is not the blocker, make it blocker using a new watcher w
// why not simply do i->blocker=first in this case?
Lit first = c[0];
// Watcher w = Watcher(cr, first);
if (first != blocker && value(first) == l_True)
{
i->blocker = first;
*j++ = *i++; continue;
}
// Look for new watch:
//if (incremental)
//{ // ----------------- INCREMENTAL MODE
// int choosenPos = -1;
// for (int k = 2; k < c.size(); k++)
// {
// if (value(c[k]) != l_False)
// {
// if (decisionLevel()>assumptions.size())
// {
// choosenPos = k;
// break;
// }
// else
// {
// choosenPos = k;
// if (value(c[k]) == l_True || !isSelector(var(c[k]))) {
// break;
// }
// }
// }
// }
// if (choosenPos != -1)
// {
// // watcher i is abandonned using i++, because cr watches now ~c[k] instead of p
// // the blocker is first in the watcher. However,
// // the blocker in the corresponding watcher in ~first is not c[1]
// Watcher w = Watcher(cr, first); i++;
// c[1] = c[choosenPos]; c[choosenPos] = false_lit;
// watches[~c[1]].push(w);
// goto NextClause;
// }
//}
else
{ // ----------------- DEFAULT MODE (NOT INCREMENTAL)
for (int k = 2; k < c.size(); k++)
{
if (value(c[k]) != l_False)
{
// watcher i is abandonned using i++, because cr watches now ~c[k] instead of p
// the blocker is first in the watcher. However,
// the blocker in the corresponding watcher in ~first is not c[1]
Watcher w = Watcher(cr, first); i++;
c[1] = c[k]; c[k] = false_lit;
watches[~c[1]].push(w);
goto NextClause;
}
}
}
// Did not find watch -- clause is unit under assignment:
i->blocker = first;
*j++ = *i++;
if (value(first) == l_False)
{
confl = cr;
qhead = trail.size();
// Copy the remaining watches:
while (i < end)
*j++ = *i++;
}
else
{
simpleUncheckEnqueue(first, cr);
}
NextClause:;
}
ws.shrink(i - j);
}
s_propagations += num_props;
return confl;
}
void Solver::simpleUncheckEnqueue(Lit p, CRef from){
assert(value(p) == l_Undef);
assigns[var(p)] = lbool(!sign(p)); // this makes a lbool object whose value is sign(p)
vardata[var(p)].reason = from;
trail.push_(p);
}
void Solver::cancelUntilTrailRecord()
{
for (int c = trail.size() - 1; c >= trailRecord; c--)
{
Var x = var(trail[c]);
assigns[x] = l_Undef;
}
qhead = trailRecord;
trail.shrink(trail.size() - trailRecord);
}
void Solver::litsEnqueue(int cutP, Clause& c)
{
for (int i = cutP; i < c.size(); i++)
{
simpleUncheckEnqueue(~c[i]);
}
}
bool Solver::removed(CRef cr) {
return ca[cr].mark() == 1;
}
void Solver::simpleAnalyze(CRef confl, vec<Lit>& out_learnt, vec<CRef>& reason_clause, bool True_confl)
{
int pathC = 0;
Lit p = lit_Undef;
int index = trail.size() - 1;
do{
if (confl != CRef_Undef){
reason_clause.push(confl);
Clause& c = ca[confl];
// Special case for binary clauses
// The first one has to be SAT
if (p != lit_Undef && c.size() == 2 && value(c[0]) == l_False) {
assert(value(c[1]) == l_True);
Lit tmp = c[0];
c[0] = c[1], c[1] = tmp;
}
// if True_confl==true, then choose p begin with the 1th index of c;
for (int j = (p == lit_Undef && True_confl == false) ? 0 : 1; j < c.size(); j++){
Lit q = c[j];
if (!seen[var(q)]){
seen[var(q)] = 1;
pathC++;
}
}
}
else if (confl == CRef_Undef){
out_learnt.push(~p);
}
// if not break, while() will come to the index of trail blow 0, and fatal error occur;
if (pathC == 0) break;
// Select next clause to look at:
while (!seen[var(trail[index--])]);
// if the reason cr from the 0-level assigned var, we must break avoid move forth further;
// but attention that maybe seen[x]=1 and never be clear. However makes no matter;
if (trailRecord > index + 1) break;
p = trail[index + 1];
confl = reason(var(p));
seen[var(p)] = 0;
pathC--;
} while (pathC >= 0);
}
void Solver::simplifyLearnt(Clause& c)
{
////
original_length_record += c.size();
trailRecord = trail.size();// record the start pointer
vec<Lit> falseLit;
falseLit.clear();
//sort(&c[0], c.size(), VarOrderLevelLt(vardata));
bool True_confl = false;
int beforeSize, afterSize;
beforeSize = c.size();
int i, j;
CRef confl;
for (i = 0, j = 0; i < c.size(); i++){
if (value(c[i]) == l_Undef){
//printf("///@@@ uncheckedEnqueue:index = %d. l_Undef\n", i);
simpleUncheckEnqueue(~c[i]);
c[j++] = c[i];
confl = simplePropagate();
if (confl != CRef_Undef){
break;
}
}
else{
if (value(c[i]) == l_True){
//printf("///@@@ uncheckedEnqueue:index = %d. l_True\n", i);
c[j++] = c[i];
True_confl = true;
confl = reason(var(c[i]));
break;
}
else{
//printf("///@@@ uncheckedEnqueue:index = %d. l_False\n", i);
falseLit.push(c[i]);
}
}
}
c.shrink(c.size() - j);
afterSize = c.size();
//printf("\nbefore : %d, after : %d ", beforeSize, afterSize);
if (confl != CRef_Undef || True_confl == true){
simp_learnt_clause.clear();
simp_reason_clause.clear();
if (True_confl == true){
simp_learnt_clause.push(c.last());
}
simpleAnalyze(confl, simp_learnt_clause, simp_reason_clause, True_confl);
if (simp_learnt_clause.size() < c.size()){
for (i = 0; i < simp_learnt_clause.size(); i++){
c[i] = simp_learnt_clause[i];
}
c.shrink(c.size() - i);
}
}
cancelUntilTrailRecord();
////
simplified_length_record += c.size();
}
bool Solver::simplifyLearnt_x(vec<CRef>& learnts_x)
{
int beforeSize, afterSize;
int learnts_x_size_before = learnts_x.size();
int ci, cj, li, lj;
bool sat, false_lit;
unsigned int nblevels;
////
//printf("learnts_x size : %d\n", learnts_x.size());
////
int nbSimplified = 0;
int nbSimplifing = 0;
for (ci = 0, cj = 0; ci < learnts_x.size(); ci++){
CRef cr = learnts_x[ci];
Clause& c = ca[cr];
if (removed(cr)) continue;
else if (c.simplified()){
learnts_x[cj++] = learnts_x[ci];
////
nbSimplified++;
}
else{
////
nbSimplifing++;
sat = false_lit = false;
for (int i = 0; i < c.size(); i++){
if (value(c[i]) == l_True){
sat = true;
break;
}
else if (value(c[i]) == l_False){
false_lit = true;
}
}
if (sat){
removeClause(cr);
}
else{
detachClause(cr, true);
if (false_lit){
for (li = lj = 0; li < c.size(); li++){
if (value(c[li]) != l_False){
c[lj++] = c[li];
}
}
c.shrink(li - lj);
}
beforeSize = c.size();
assert(c.size() > 1);
// simplify a learnt clause c
simplifyLearnt(c);
assert(c.size() > 0);
afterSize = c.size();
//printf("beforeSize: %2d, afterSize: %2d\n", beforeSize, afterSize);
if (c.size() == 1){
// when unit clause occur, enqueue and propagate
uncheckedEnqueue(c[0]);
if (propagate() != CRef_Undef){
ok = false;
return false;
}
// delete the clause memory in logic
c.mark(1);
ca.free(cr);
}
else{
attachClause(cr);
learnts_x[cj++] = learnts_x[ci];
nblevels = computeLBD(c);
if (nblevels < c.lbd()){
//printf("lbd-before: %d, lbd-after: %d\n", c.lbd(), nblevels);
c.set_lbd(nblevels);
}
if (c.mark() != CORE){
if (c.lbd() <= core_lbd_cut){
//if (c.mark() == LOCAL) local_learnts_dirty = true;
//else tier2_learnts_dirty = true;
cj--;
learnts_core.push(cr);
c.mark(CORE);
}
else if (c.mark() == LOCAL && c.lbd() <= 6){
//local_learnts_dirty = true;
cj--;
learnts_tier2.push(cr);
c.mark(TIER2);
}
}
c.setSimplified(true);
}
}
}
}
learnts_x.shrink(ci - cj);
// printf("c nbLearnts_x %d / %d, nbSimplified: %d, nbSimplifing: %d\n",
// learnts_x_size_before, learnts_x.size(), nbSimplified, nbSimplifing);
return true;
}
bool Solver::simplifyLearnt_core()
{
int beforeSize, afterSize;
int learnts_core_size_before = learnts_core.size();
int ci, cj, li, lj;
bool sat, false_lit;
unsigned int nblevels;
////
//printf("learnts_x size : %d\n", learnts_x.size());
////
int nbSimplified = 0;
int nbSimplifing = 0;
for (ci = 0, cj = 0; ci < learnts_core.size(); ci++){
CRef cr = learnts_core[ci];
Clause& c = ca[cr];
if (removed(cr)) continue;
else if (c.simplified()){
learnts_core[cj++] = learnts_core[ci];
////
nbSimplified++;
}
else{
int saved_size=c.size();
// if (drup_file){
// add_oc.clear();
// for (int i = 0; i < c.size(); i++) add_oc.push(c[i]); }
////
nbSimplifing++;
sat = false_lit = false;
for (int i = 0; i < c.size(); i++){
if (value(c[i]) == l_True){
sat = true;
break;
}
else if (value(c[i]) == l_False){
false_lit = true;
}
}
if (sat){
removeClause(cr);
}
else{
detachClause(cr, true);
if (false_lit){
for (li = lj = 0; li < c.size(); li++){
if (value(c[li]) != l_False){
c[lj++] = c[li];
}
}
c.shrink(li - lj);
}
beforeSize = c.size();
assert(c.size() > 1);
// simplify a learnt clause c
simplifyLearnt(c);
assert(c.size() > 0);
afterSize = c.size();
if(drup_file && saved_size !=c.size()){
#ifdef BIN_DRUP
binDRUP('a', c , drup_file);
// binDRUP('d', add_oc, drup_file);
#else
for (int i = 0; i < c.size(); i++)
fprintf(drup_file, "%i ", (var(c[i]) + 1) * (-2 * sign(c[i]) + 1));
fprintf(drup_file, "0\n");
// fprintf(drup_file, "d ");
// for (int i = 0; i < add_oc.size(); i++)
// fprintf(drup_file, "%i ", (var(add_oc[i]) + 1) * (-2 * sign(add_oc[i]) + 1));
// fprintf(drup_file, "0\n");
#endif
}
//printf("beforeSize: %2d, afterSize: %2d\n", beforeSize, afterSize);
if (c.size() == 1){
// when unit clause occur, enqueue and propagate
uncheckedEnqueue(c[0]);
if (propagate() != CRef_Undef){
ok = false;
return false;
}
// delete the clause memory in logic
c.mark(1);
ca.free(cr);
//#ifdef BIN_DRUP
// binDRUP('d', c, drup_file);
//#else
// fprintf(drup_file, "d ");
// for (int i = 0; i < c.size(); i++)
// fprintf(drup_file, "%i ", (var(c[i]) + 1) * (-2 * sign(c[i]) + 1));
// fprintf(drup_file, "0\n");
//#endif
}
else{
attachClause(cr);
learnts_core[cj++] = learnts_core[ci];
nblevels = computeLBD(c);
if (nblevels < c.lbd()){
//printf("lbd-before: %d, lbd-after: %d\n", c.lbd(), nblevels);
c.set_lbd(nblevels);
}
c.setSimplified(true);
}
}
}
}
learnts_core.shrink(ci - cj);
// printf("c nbLearnts_core %d / %d, nbSimplified: %d, nbSimplifing: %d\n",
// learnts_core_size_before, learnts_core.size(), nbSimplified, nbSimplifing);
return true;
}
int Solver::is_duplicate(std::vector<uint32_t>&c){
auto time_point_0 = std::chrono::high_resolution_clock::now();
dupl_db_size++;
int res = 0;
int sz = c.size();
std::vector<uint32_t> tmp(c);
sort(tmp.begin(),tmp.end());
uint64_t hash = 0;
for (int i =0; i<sz; i++) {
hash ^= tmp[i] + 0x9e3779b9 + (hash << 6) + (hash>> 2);
}
int32_t head = tmp[0];
auto it0 = ht.find(head);
if (it0 != ht.end()){
auto it1=ht[head].find(sz);
if (it1 != ht[head].end()){
auto it2 = ht[head][sz].find(hash);
if (it2 != ht[head][sz].end()){
it2->second++;
res = it2->second;
}
else{
ht[head][sz][hash]=1;
}
}
else{
ht[head][sz][hash]=1;
}
}else{
ht[head][sz][hash]=1;
}
auto time_point_1 = std::chrono::high_resolution_clock::now();
duptime += std::chrono::duration_cast<std::chrono::microseconds>(time_point_1-time_point_0);
return res;
}
bool Solver::simplifyLearnt_tier2()
{
int beforeSize, afterSize;
int learnts_tier2_size_before = learnts_tier2.size();
int ci, cj, li, lj;
bool sat, false_lit;
unsigned int nblevels;
////
//printf("learnts_x size : %d\n", learnts_x.size());
////
int nbSimplified = 0;
int nbSimplifing = 0;
for (ci = 0, cj = 0; ci < learnts_tier2.size(); ci++){
CRef cr = learnts_tier2[ci];
Clause& c = ca[cr];
if (removed(cr)) continue;
else if (c.simplified()){
learnts_tier2[cj++] = learnts_tier2[ci];
////
nbSimplified++;
}
else{
int saved_size=c.size();
// if (drup_file){
// add_oc.clear();
// for (int i = 0; i < c.size(); i++) add_oc.push(c[i]); }
////
nbSimplifing++;
sat = false_lit = false;
for (int i = 0; i < c.size(); i++){
if (value(c[i]) == l_True){
sat = true;
break;
}
else if (value(c[i]) == l_False){
false_lit = true;
}
}
if (sat){
removeClause(cr);
}
else{
detachClause(cr, true);
if (false_lit){
for (li = lj = 0; li < c.size(); li++){
if (value(c[li]) != l_False){
c[lj++] = c[li];
}
}
c.shrink(li - lj);
}
beforeSize = c.size();
assert(c.size() > 1);
// simplify a learnt clause c
simplifyLearnt(c);
assert(c.size() > 0);
afterSize = c.size();
if(drup_file && saved_size!=c.size()){
#ifdef BIN_DRUP
binDRUP('a', c , drup_file);
// binDRUP('d', add_oc, drup_file);
#else
for (int i = 0; i < c.size(); i++)
fprintf(drup_file, "%i ", (var(c[i]) + 1) * (-2 * sign(c[i]) + 1));
fprintf(drup_file, "0\n");
// fprintf(drup_file, "d ");
// for (int i = 0; i < add_oc.size(); i++)
// fprintf(drup_file, "%i ", (var(add_oc[i]) + 1) * (-2 * sign(add_oc[i]) + 1));
// fprintf(drup_file, "0\n");
#endif
}
//printf("beforeSize: %2d, afterSize: %2d\n", beforeSize, afterSize);
if (c.size() == 1){
// when unit clause occur, enqueue and propagate
uncheckedEnqueue(c[0]);
if (propagate() != CRef_Undef){
ok = false;
return false;
}
// delete the clause memory in logic
c.mark(1);
ca.free(cr);
//#ifdef BIN_DRUP
// binDRUP('d', c, drup_file);
//#else
// fprintf(drup_file, "d ");
// for (int i = 0; i < c.size(); i++)
// fprintf(drup_file, "%i ", (var(c[i]) + 1) * (-2 * sign(c[i]) + 1));
// fprintf(drup_file, "0\n");
//#endif
}
else{
nblevels = computeLBD(c);
if (nblevels < c.lbd()){
//printf("lbd-before: %d, lbd-after: %d\n", c.lbd(), nblevels);
c.set_lbd(nblevels);
}
//duplicate learnts
int id = 0;
std::vector<uint32_t> tmp;
for (int i = 0; i < c.size(); i++)
tmp.push_back(c[i].x);
id = is_duplicate(tmp);
//duplicate learnts
if (id < min_number_of_learnts_copies+2){
attachClause(cr);
learnts_tier2[cj++] = learnts_tier2[ci];
if (id == min_number_of_learnts_copies+1){
duplicates_added_minimization++;
}
if ((c.lbd() <= core_lbd_cut)||(id == min_number_of_learnts_copies+1)){
//if (id == min_number_of_learnts_copies+1){
cj--;
learnts_core.push(cr);
c.mark(CORE);
}
c.setSimplified(true);
}
}
}
}
}
learnts_tier2.shrink(ci - cj);
// printf("c nbLearnts_tier2 %d / %d, nbSimplified: %d, nbSimplifing: %d\n",
// learnts_tier2_size_before, learnts_tier2.size(), nbSimplified, nbSimplifing);
return true;
}
bool Solver::simplifyAll()
{
////
simplified_length_record = original_length_record = 0;
if (!ok || propagate() != CRef_Undef)
return ok = false;
//// cleanLearnts(also can delete these code), here just for analyzing
//if (local_learnts_dirty) cleanLearnts(learnts_local, LOCAL);
//if (tier2_learnts_dirty) cleanLearnts(learnts_tier2, TIER2);
//local_learnts_dirty = tier2_learnts_dirty = false;
if (!simplifyLearnt_core()) return ok = false;
if (!simplifyLearnt_tier2()) return ok = false;
//if (!simplifyLearnt_x(learnts_local)) return ok = false;
checkGarbage();
////
// printf("c size_reduce_ratio : %4.2f%%\n",
// original_length_record == 0 ? 0 : (original_length_record - simplified_length_record) * 100 / (double)original_length_record);
return true;
}
//=================================================================================================
// Minor methods:
// Creates a new SAT variable in the solver. If 'decision' is cleared, variable will not be
// used as a decision variable (NOTE! This has effects on the meaning of a SATISFIABLE result).
//
Var Solver::newVar(bool sign, bool dvar)
{
int v = nVars();
// printf("%d %d %d\n", v, sign, dvar);
watches_bin.init(mkLit(v, false));
watches_bin.init(mkLit(v, true ));
watches .init(mkLit(v, false));
watches .init(mkLit(v, true ));
assigns .push(l_Undef);
vardata .push(mkVarData(CRef_Undef, 0));
activity_CHB .push(0);
activity_VSIDS.push(rnd_init_act ? drand(random_seed) * 0.00001 : 0);
picked.push(0);
conflicted.push(0);
almost_conflicted.push(0);
#ifdef ANTI_EXPLORATION
canceled.push(0);
#endif
seen .push(0);
seen2 .push(0);
polarity .push(sign);
decision .push();
trail .capacity(v+1);
setDecisionVar(v, dvar);
return v;
}
bool Solver::addClause_(vec<Lit>& ps)
{
assert(decisionLevel() == 0);
if (!ok) return false;
// Check if clause is satisfied and remove false/duplicate literals:
sort(ps);
Lit p; int i, j;
if (drup_file){
add_oc.clear();
for (int i = 0; i < ps.size(); i++) add_oc.push(ps[i]); }
for (i = j = 0, p = lit_Undef; i < ps.size(); i++)
if (value(ps[i]) == l_True || ps[i] == ~p)
return true;
else if (value(ps[i]) != l_False && ps[i] != p)
ps[j++] = p = ps[i];
ps.shrink(i - j);
if (drup_file && i != j){
#ifdef BIN_DRUP
binDRUP('a', ps, drup_file);
binDRUP('d', add_oc, drup_file);
#else
for (int i = 0; i < ps.size(); i++)
fprintf(drup_file, "%i ", (var(ps[i]) + 1) * (-2 * sign(ps[i]) + 1));
fprintf(drup_file, "0\n");
fprintf(drup_file, "d ");
for (int i = 0; i < add_oc.size(); i++)
fprintf(drup_file, "%i ", (var(add_oc[i]) + 1) * (-2 * sign(add_oc[i]) + 1));
fprintf(drup_file, "0\n");
#endif
}
if (ps.size() == 0)
return ok = false;
else if (ps.size() == 1){
uncheckedEnqueue(ps[0]);
return ok = (propagate() == CRef_Undef);
}else{
CRef cr = ca.alloc(ps, false);
clauses.push(cr);
attachClause(cr);
}
return true;
}
bool Solver::importClauses() {
assert(decisionLevel() == 0);
if (cbkImportClause == NULL)
return true;
int lbd, k, l;
bool alreadySat;
while (cbkImportClause(issuer, &lbd, importedClause)) {
// fflush(stdout);
alreadySat = false;
// Simplify clause before add
for (k = l = 0; k < importedClause.size(); k++) {
if (value(importedClause[k]) == l_True) {
alreadySat = true;
break;
} else if (value(importedClause[k]) == l_Undef) {
importedClause[l++] = importedClause[k];
}
}
importedClause.shrink(k - l);
if (alreadySat) {
importedClause.clear();
continue;
}
if (importedClause.size() == 0) {
return false;
} else if (importedClause.size() == 1) {
uncheckedEnqueue(importedClause[0]);
} else {
CRef cr = ca.alloc(importedClause, true);
lbd = importedClause.size();
ca[cr].set_lbd(lbd);
if (lbd <= core_lbd_cut) {
learnts_core.push(cr);
ca[cr].mark(CORE);
} else if (lbd <= 6) {
learnts_tier2.push(cr);
ca[cr].mark(TIER2);
ca[cr].touched() = conflicts;
} else {
learnts_local.push(cr);
claBumpActivity(ca[cr]);
}
attachClause(cr);
}
importedClause.clear();
}
return true;
}
void Solver::attachClause(CRef cr) {
const Clause& c = ca[cr];
assert(c.size() > 1);
OccLists<Lit, vec<Watcher>, WatcherDeleted>& ws = c.size() == 2 ? watches_bin : watches;
ws[~c[0]].push(Watcher(cr, c[1]));
ws[~c[1]].push(Watcher(cr, c[0]));
if (c.learnt()) learnts_literals += c.size();
else clauses_literals += c.size(); }
void Solver::detachClause(CRef cr, bool strict) {
const Clause& c = ca[cr];
assert(c.size() > 1);
OccLists<Lit, vec<Watcher>, WatcherDeleted>& ws = c.size() == 2 ? watches_bin : watches;
if (strict){
remove(ws[~c[0]], Watcher(cr, c[1]));
remove(ws[~c[1]], Watcher(cr, c[0]));
}else{
// Lazy detaching: (NOTE! Must clean all watcher lists before garbage collecting this clause)
ws.smudge(~c[0]);
ws.smudge(~c[1]);
}
if (c.learnt()) learnts_literals -= c.size();
else clauses_literals -= c.size(); }
void Solver::removeClause(CRef cr) {
Clause& c = ca[cr];
if (drup_file){
if (c.mark() != 1){
#ifdef BIN_DRUP
binDRUP('d', c, drup_file);
#else
fprintf(drup_file, "d ");
for (int i = 0; i < c.size(); i++)
fprintf(drup_file, "%i ", (var(c[i]) + 1) * (-2 * sign(c[i]) + 1));
fprintf(drup_file, "0\n");
#endif
}else
printf("c Bug. I don't expect this to happen.\n");
}
detachClause(cr);
// Don't leave pointers to free'd memory!
if (locked(c)){
Lit implied = c.size() != 2 ? c[0] : (value(c[0]) == l_True ? c[0] : c[1]);
vardata[var(implied)].reason = CRef_Undef; }
c.mark(1);
ca.free(cr);
}
bool Solver::satisfied(const Clause& c) const {
for (int i = 0; i < c.size(); i++)
if (value(c[i]) == l_True)
return true;
return false; }
// Revert to the state at given level (keeping all assignment at 'level' but not beyond).
//
void Solver::cancelUntil(int bLevel) {
if (decisionLevel() > bLevel){
#ifdef PRINT_OUT
std::cout << "bt " << bLevel << "\n";
#endif
add_tmp.clear();
for (int c = trail.size()-1; c >= trail_lim[bLevel]; c--)
{
Var x = var(trail[c]);
if (level(x) <= bLevel)
{
add_tmp.push(trail[c]);
}
else
{
if (!VSIDS){
uint32_t age = conflicts - picked[x];
if (age > 0){
double adjusted_reward = ((double) (conflicted[x] + almost_conflicted[x])) / ((double) age);
double old_activity = activity_CHB[x];
activity_CHB[x] = step_size * adjusted_reward + ((1 - step_size) * old_activity);
if (order_heap_CHB.inHeap(x)){
if (activity_CHB[x] > old_activity)
order_heap_CHB.decrease(x);
else
order_heap_CHB.increase(x);
}
}
#ifdef ANTI_EXPLORATION
canceled[x] = conflicts;
#endif
}
assigns [x] = l_Undef;
#ifdef PRINT_OUT
std::cout << "undo " << x << "\n";
#endif
if (phase_saving > 1 || (phase_saving == 1) && c > trail_lim.last()){
polarity[x] = sign(trail[c]);
}
insertVarOrder(x);
}
}
qhead = trail_lim[bLevel];
trail.shrink(trail.size() - trail_lim[bLevel]);
trail_lim.shrink(trail_lim.size() - bLevel);
for (int nLitId = add_tmp.size() - 1; nLitId >= 0; --nLitId)
{
trail.push_(add_tmp[nLitId]);
}
add_tmp.clear();
} }
//=================================================================================================
// Major methods:
Lit Solver::pickBranchLit()
{
Var next = var_Undef;
// Heap<VarOrderLt>& order_heap = VSIDS ? order_heap_VSIDS : order_heap_CHB;
Heap<VarOrderLt>& order_heap = ((!VSIDS)? order_heap_CHB:order_heap_VSIDS);
// Random decision:
/*if (drand(random_seed) < random_var_freq && !order_heap.empty()){
next = order_heap[irand(random_seed,order_heap.size())];
if (value(next) == l_Undef && decision[next])
rnd_decisions++; }*/
// Activity based decision:
while (next == var_Undef || value(next) != l_Undef || !decision[next])
if (order_heap.empty())
return lit_Undef;
else{
#ifdef ANTI_EXPLORATION
if (!VSIDS){
Var v = order_heap_CHB[0];
uint32_t age = conflicts - canceled[v];
while (age > 0){
double decay = pow(0.95, age);
activity_CHB[v] *= decay;
if (order_heap_CHB.inHeap(v))
order_heap_CHB.increase(v);
canceled[v] = conflicts;
v = order_heap_CHB[0];
age = conflicts - canceled[v];
}
}
#endif
next = order_heap.removeMin();
}
return mkLit(next, polarity[next]);
}
inline Solver::ConflictData Solver::FindConflictLevel(CRef cind)
{
ConflictData data;
Clause& conflCls = ca[cind];
data.nHighestLevel = level(var(conflCls[0]));
if (data.nHighestLevel == decisionLevel() && level(var(conflCls[1])) == decisionLevel())
{
return data;
}
int highestId = 0;
data.bOnlyOneLitFromHighest = true;
// find the largest decision level in the clause
for (int nLitId = 1; nLitId < conflCls.size(); ++nLitId)
{
int nLevel = level(var(conflCls[nLitId]));
if (nLevel > data.nHighestLevel)
{
highestId = nLitId;
data.nHighestLevel = nLevel;
data.bOnlyOneLitFromHighest = true;
}
else if (nLevel == data.nHighestLevel && data.bOnlyOneLitFromHighest == true)
{
data.bOnlyOneLitFromHighest = false;
}
}
if (highestId != 0)
{
std::swap(conflCls[0], conflCls[highestId]);
if (highestId > 1)
{
OccLists<Lit, vec<Watcher>, WatcherDeleted>& ws = conflCls.size() == 2 ? watches_bin : watches;
//ws.smudge(~conflCls[highestId]);
remove(ws[~conflCls[highestId]], Watcher(cind, conflCls[1]));
ws[~conflCls[0]].push(Watcher(cind, conflCls[1]));
}
}
return data;
}
/*_________________________________________________________________________________________________
|
| analyze : (confl : Clause*) (out_learnt : vec<Lit>&) (out_btlevel : int&) -> [void]
|
| Description:
| Analyze conflict and produce a reason clause.
|
| Pre-conditions:
| * 'out_learnt' is assumed to be cleared.
| * Current decision level must be greater than root level.
|
| Post-conditions:
| * 'out_learnt[0]' is the asserting literal at level 'out_btlevel'.
| * If out_learnt.size() > 1 then 'out_learnt[1]' has the greatest decision level of the
| rest of literals. There may be others from the same level though.
|
|________________________________________________________________________________________________@*/
void Solver::analyze(CRef confl, vec<Lit>& out_learnt, int& out_btlevel, int& out_lbd)
{
int pathC = 0;
Lit p = lit_Undef;
// Generate conflict clause:
//
out_learnt.push(); // (leave room for the asserting literal)
int index = trail.size() - 1;
int nDecisionLevel = level(var(ca[confl][0]));
assert(nDecisionLevel == level(var(ca[confl][0])));
do{
assert(confl != CRef_Undef); // (otherwise should be UIP)
Clause& c = ca[confl];
// For binary clauses, we don't rearrange literals in propagate(), so check and make sure the first is an implied lit.
if (p != lit_Undef && c.size() == 2 && value(c[0]) == l_False){
assert(value(c[1]) == l_True);
Lit tmp = c[0];
c[0] = c[1], c[1] = tmp; }
// Update LBD if improved.
if (c.learnt() && c.mark() != CORE){
int lbd = computeLBD(c);
if (lbd < c.lbd()){
if (c.lbd() <= 30) c.removable(false); // Protect once from reduction.
c.set_lbd(lbd);
if (lbd <= core_lbd_cut){
learnts_core.push(confl);
c.mark(CORE);
}else if (lbd <= 6 && c.mark() == LOCAL){
// Bug: 'cr' may already be in 'learnts_tier2', e.g., if 'cr' was demoted from TIER2
// to LOCAL previously and if that 'cr' is not cleaned from 'learnts_tier2' yet.
learnts_tier2.push(confl);
c.mark(TIER2); }
}
if (c.mark() == TIER2)
c.touched() = conflicts;
else if (c.mark() == LOCAL)
claBumpActivity(c);
}
for (int j = (p == lit_Undef) ? 0 : 1; j < c.size(); j++){
Lit q = c[j];
if (!seen[var(q)] && level(var(q)) > 0){
if (VSIDS){
varBumpActivity(var(q), .5);
add_tmp.push(q);
}else
conflicted[var(q)]++;
seen[var(q)] = 1;
if (level(var(q)) >= nDecisionLevel){
pathC++;
}else
out_learnt.push(q);
}
}
// Select next clause to look at:
do {
while (!seen[var(trail[index--])]);
p = trail[index+1];
} while (level(var(p)) < nDecisionLevel);
confl = reason(var(p));
seen[var(p)] = 0;
pathC--;
}while (pathC > 0);
out_learnt[0] = ~p;
// Simplify conflict clause:
//
int i, j;
out_learnt.copyTo(analyze_toclear);
if (ccmin_mode == 2){
uint32_t abstract_level = 0;
for (i = 1; i < out_learnt.size(); i++)
abstract_level |= abstractLevel(var(out_learnt[i])); // (maintain an abstraction of levels involved in conflict)
for (i = j = 1; i < out_learnt.size(); i++)
if (reason(var(out_learnt[i])) == CRef_Undef || !litRedundant(out_learnt[i], abstract_level))
out_learnt[j++] = out_learnt[i];
}else if (ccmin_mode == 1){
for (i = j = 1; i < out_learnt.size(); i++){
Var x = var(out_learnt[i]);
if (reason(x) == CRef_Undef)
out_learnt[j++] = out_learnt[i];
else{
Clause& c = ca[reason(var(out_learnt[i]))];
for (int k = c.size() == 2 ? 0 : 1; k < c.size(); k++)
if (!seen[var(c[k])] && level(var(c[k])) > 0){
out_learnt[j++] = out_learnt[i];
break; }
}
}
}else
i = j = out_learnt.size();
max_literals += out_learnt.size();
out_learnt.shrink(i - j);
tot_literals += out_learnt.size();
out_lbd = computeLBD(out_learnt);
if (out_lbd <= 6 && out_learnt.size() <= 30) // Try further minimization?
if (binResMinimize(out_learnt))
out_lbd = computeLBD(out_learnt); // Recompute LBD if minimized.
// Find correct backtrack level:
//
if (out_learnt.size() == 1)
out_btlevel = 0;
else{
int max_i = 1;
// Find the first literal assigned at the next-highest level:
for (int i = 2; i < out_learnt.size(); i++)
if (level(var(out_learnt[i])) > level(var(out_learnt[max_i])))
max_i = i;
// Swap-in this literal at index 1:
Lit p = out_learnt[max_i];
out_learnt[max_i] = out_learnt[1];
out_learnt[1] = p;
out_btlevel = level(var(p));
}
if (VSIDS){
for (int i = 0; i < add_tmp.size(); i++){
Var v = var(add_tmp[i]);
if (level(v) >= out_btlevel - 1)
varBumpActivity(v, 1);
}
add_tmp.clear();
}else{
seen[var(p)] = true;
for(int i = out_learnt.size() - 1; i >= 0; i--){
Var v = var(out_learnt[i]);
CRef rea = reason(v);
if (rea != CRef_Undef){
const Clause& reaC = ca[rea];
for (int i = 0; i < reaC.size(); i++){
Lit l = reaC[i];
if (!seen[var(l)]){
seen[var(l)] = true;
almost_conflicted[var(l)]++;
analyze_toclear.push(l); } } } } }
for (int j = 0; j < analyze_toclear.size(); j++) seen[var(analyze_toclear[j])] = 0; // ('seen[]' is now cleared)
}
// Try further learnt clause minimization by means of binary clause resolution.
bool Solver::binResMinimize(vec<Lit>& out_learnt)
{
// Preparation: remember which false variables we have in 'out_learnt'.
counter++;
for (int i = 1; i < out_learnt.size(); i++)
seen2[var(out_learnt[i])] = counter;
// Get the list of binary clauses containing 'out_learnt[0]'.
const vec<Watcher>& ws = watches_bin[~out_learnt[0]];
int to_remove = 0;
for (int i = 0; i < ws.size(); i++){
Lit the_other = ws[i].blocker;
// Does 'the_other' appear negatively in 'out_learnt'?
if (seen2[var(the_other)] == counter && value(the_other) == l_True){
to_remove++;
seen2[var(the_other)] = counter - 1; // Remember to remove this variable.
}
}
// Shrink.
if (to_remove > 0){
int last = out_learnt.size() - 1;
for (int i = 1; i < out_learnt.size() - to_remove; i++)
if (seen2[var(out_learnt[i])] != counter)
out_learnt[i--] = out_learnt[last--];
out_learnt.shrink(to_remove);
}
return to_remove != 0;
}
// Check if 'p' can be removed. 'abstract_levels' is used to abort early if the algorithm is
// visiting literals at levels that cannot be removed later.
bool Solver::litRedundant(Lit p, uint32_t abstract_levels)
{
analyze_stack.clear(); analyze_stack.push(p);
int top = analyze_toclear.size();
while (analyze_stack.size() > 0){
assert(reason(var(analyze_stack.last())) != CRef_Undef);
Clause& c = ca[reason(var(analyze_stack.last()))]; analyze_stack.pop();
// Special handling for binary clauses like in 'analyze()'.
if (c.size() == 2 && value(c[0]) == l_False){
assert(value(c[1]) == l_True);
Lit tmp = c[0];
c[0] = c[1], c[1] = tmp; }
for (int i = 1; i < c.size(); i++){
Lit p = c[i];
if (!seen[var(p)] && level(var(p)) > 0){
if (reason(var(p)) != CRef_Undef && (abstractLevel(var(p)) & abstract_levels) != 0){
seen[var(p)] = 1;
analyze_stack.push(p);
analyze_toclear.push(p);
}else{
for (int j = top; j < analyze_toclear.size(); j++)
seen[var(analyze_toclear[j])] = 0;
analyze_toclear.shrink(analyze_toclear.size() - top);
return false;
}
}
}
}
return true;
}
/*_________________________________________________________________________________________________
|
| analyzeFinal : (p : Lit) -> [void]
|
| Description:
| Specialized analysis procedure to express the final conflict in terms of assumptions.
| Calculates the (possibly empty) set of assumptions that led to the assignment of 'p', and
| stores the result in 'out_conflict'.
|________________________________________________________________________________________________@*/
void Solver::analyzeFinal(Lit p, vec<Lit>& out_conflict)
{
out_conflict.clear();
out_conflict.push(p);
if (decisionLevel() == 0)
return;
seen[var(p)] = 1;
for (int i = trail.size()-1; i >= trail_lim[0]; i--){
Var x = var(trail[i]);
if (seen[x]){
if (reason(x) == CRef_Undef){
assert(level(x) > 0);
out_conflict.push(~trail[i]);
}else{
Clause& c = ca[reason(x)];
for (int j = c.size() == 2 ? 0 : 1; j < c.size(); j++)
if (level(var(c[j])) > 0)
seen[var(c[j])] = 1;
}
seen[x] = 0;
}
}
seen[var(p)] = 0;
}
void Solver::uncheckedEnqueue(Lit p, int level, CRef from)
{
assert(value(p) == l_Undef);
Var x = var(p);
if (!VSIDS){
picked[x] = conflicts;
conflicted[x] = 0;
almost_conflicted[x] = 0;
#ifdef ANTI_EXPLORATION
uint32_t age = conflicts - canceled[var(p)];
if (age > 0){
double decay = pow(0.95, age);
activity_CHB[var(p)] *= decay;
if (order_heap_CHB.inHeap(var(p)))
order_heap_CHB.increase(var(p));
}
#endif
}
assigns[x] = lbool(!sign(p));
vardata[x] = mkVarData(from, level);
trail.push_(p);
}
/*_________________________________________________________________________________________________
|
| propagate : [void] -> [Clause*]
|
| Description:
| Propagates all enqueued facts. If a conflict arises, the conflicting clause is returned,
| otherwise CRef_Undef.
|
| Post-conditions:
| * the propagation queue is empty, even if there was a conflict.
|________________________________________________________________________________________________@*/
CRef Solver::propagate()
{
CRef confl = CRef_Undef;
int num_props = 0;
watches.cleanAll();
watches_bin.cleanAll();
while (qhead < trail.size()){
Lit p = trail[qhead++]; // 'p' is enqueued fact to propagate.
int currLevel = level(var(p));
vec<Watcher>& ws = watches[p];
Watcher *i, *j, *end;
num_props++;
vec<Watcher>& ws_bin = watches_bin[p]; // Propagate binary clauses first.
for (int k = 0; k < ws_bin.size(); k++){
Lit the_other = ws_bin[k].blocker;
if (value(the_other) == l_False){
confl = ws_bin[k].cref;
#ifdef LOOSE_PROP_STAT
return confl;
#else
goto ExitProp;
#endif
}else if(value(the_other) == l_Undef)
{
uncheckedEnqueue(the_other, currLevel, ws_bin[k].cref);
#ifdef PRINT_OUT
std::cout << "i " << the_other << " l " << currLevel << "\n";
#endif
}
}
for (i = j = (Watcher*)ws, end = i + ws.size(); i != end;){
// Try to avoid inspecting the clause:
Lit blocker = i->blocker;
if (value(blocker) == l_True){
*j++ = *i++; continue; }
// Make sure the false literal is data[1]:
CRef cr = i->cref;
Clause& c = ca[cr];
Lit false_lit = ~p;
if (c[0] == false_lit)
c[0] = c[1], c[1] = false_lit;
assert(c[1] == false_lit);
i++;
// If 0th watch is true, then clause is already satisfied.
Lit first = c[0];
Watcher w = Watcher(cr, first);
if (first != blocker && value(first) == l_True){
*j++ = w; continue; }
// Look for new watch:
for (int k = 2; k < c.size(); k++)
if (value(c[k]) != l_False){
c[1] = c[k]; c[k] = false_lit;
watches[~c[1]].push(w);
goto NextClause; }
// Did not find watch -- clause is unit under assignment:
*j++ = w;
if (value(first) == l_False){
confl = cr;
qhead = trail.size();
// Copy the remaining watches:
while (i < end)
*j++ = *i++;
}else
{
if (currLevel == decisionLevel())
{
uncheckedEnqueue(first, currLevel, cr);
#ifdef PRINT_OUT
std::cout << "i " << first << " l " << currLevel << "\n";
#endif
}
else
{
int nMaxLevel = currLevel;
int nMaxInd = 1;
// pass over all the literals in the clause and find the one with the biggest level
for (int nInd = 2; nInd < c.size(); ++nInd)
{
int nLevel = level(var(c[nInd]));
if (nLevel > nMaxLevel)
{
nMaxLevel = nLevel;
nMaxInd = nInd;
}
}
if (nMaxInd != 1)
{
std::swap(c[1], c[nMaxInd]);
*j--; // undo last watch
watches[~c[1]].push(w);
}
uncheckedEnqueue(first, nMaxLevel, cr);
#ifdef PRINT_OUT
std::cout << "i " << first << " l " << nMaxLevel << "\n";
#endif
}
}
NextClause:;
}
ws.shrink(i - j);
}
ExitProp:;
propagations += num_props;
simpDB_props -= num_props;
return confl;
}
/*_________________________________________________________________________________________________
|
| reduceDB : () -> [void]
|
| Description:
| Remove half of the learnt clauses, minus the clauses locked by the current assignment. Locked
| clauses are clauses that are reason to some assignment. Binary clauses are never removed.
|________________________________________________________________________________________________@*/
struct reduceDB_lt {
ClauseAllocator& ca;
reduceDB_lt(ClauseAllocator& ca_) : ca(ca_) {}
bool operator () (CRef x, CRef y) const { return ca[x].activity() < ca[y].activity(); }
};
void Solver::reduceDB()
{
int i, j;
//if (local_learnts_dirty) cleanLearnts(learnts_local, LOCAL);
//local_learnts_dirty = false;
sort(learnts_local, reduceDB_lt(ca));
int limit = learnts_local.size() / 2;
for (i = j = 0; i < learnts_local.size(); i++){
Clause& c = ca[learnts_local[i]];
if (c.mark() == LOCAL)
if (c.removable() && !locked(c) && i < limit)
removeClause(learnts_local[i]);
else{
if (!c.removable()) limit++;
c.removable(true);
learnts_local[j++] = learnts_local[i]; }
}
learnts_local.shrink(i - j);
checkGarbage();
}
void Solver::reduceDB_Tier2()
{
int i, j;
for (i = j = 0; i < learnts_tier2.size(); i++){
Clause& c = ca[learnts_tier2[i]];
if (c.mark() == TIER2)
if (!locked(c) && c.touched() + 30000 < conflicts){
learnts_local.push(learnts_tier2[i]);
c.mark(LOCAL);
//c.removable(true);
c.activity() = 0;
claBumpActivity(c);
}else
learnts_tier2[j++] = learnts_tier2[i];
}
learnts_tier2.shrink(i - j);
}
void Solver::removeSatisfied(vec<CRef>& cs)
{
int i, j;
for (i = j = 0; i < cs.size(); i++){
Clause& c = ca[cs[i]];
if (satisfied(c))
removeClause(cs[i]);
else
cs[j++] = cs[i];
}
cs.shrink(i - j);
}
void Solver::safeRemoveSatisfied(vec<CRef>& cs, unsigned valid_mark)
{
int i, j;
for (i = j = 0; i < cs.size(); i++){
Clause& c = ca[cs[i]];
if (c.mark() == valid_mark)
if (satisfied(c))
removeClause(cs[i]);
else
cs[j++] = cs[i];
}
cs.shrink(i - j);
}
void Solver::rebuildOrderHeap()
{
vec<Var> vs;
for (Var v = 0; v < nVars(); v++)
if (decision[v] && value(v) == l_Undef)
vs.push(v);
order_heap_CHB .build(vs);
order_heap_VSIDS.build(vs);
}
/*_________________________________________________________________________________________________
|
| simplify : [void] -> [bool]
|
| Description:
| Simplify the clause database according to the current top-level assigment. Currently, the only
| thing done here is the removal of satisfied clauses, but more things can be put here.
|________________________________________________________________________________________________@*/
bool Solver::simplify()
{
assert(decisionLevel() == 0);
if (!ok || propagate() != CRef_Undef)
return ok = false;
if (nAssigns() == simpDB_assigns || (simpDB_props > 0))
return true;
// Remove satisfied clauses:
removeSatisfied(learnts_core); // Should clean core first.
safeRemoveSatisfied(learnts_tier2, TIER2);
safeRemoveSatisfied(learnts_local, LOCAL);
if (remove_satisfied) // Can be turned off.
removeSatisfied(clauses);
checkGarbage();
rebuildOrderHeap();
simpDB_assigns = nAssigns();
simpDB_props = clauses_literals + learnts_literals; // (shouldn't depend on stats really, but it will do for now)
return true;
}
/*_________________________________________________________________________________________________
|
| search : (nof_conflicts : int) (params : const SearchParams&) -> [lbool]
|
| Description:
| Search for a model the specified number of conflicts.
|
| Output:
| 'l_True' if a partial assigment that is consistent with respect to the clauseset is found. If
| all variables are decision variables, this means that the clause set is satisfiable. 'l_False'
| if the clause set is unsatisfiable. 'l_Undef' if the bound on number of conflicts is reached.
|________________________________________________________________________________________________@*/
void Solver::info_based_rephase(){
int var_nums = nVars();
for(int i=0;i<var_nums;++i) polarity[i] = !ls_mediation_soln[i];
for(int i=0;i<lssolver->in_conflict_sz;++i){
int v = lssolver->in_conflict[i];
if(VSIDS){
varBumpActivity(v-1,lssolver->conflict_ct[v]);
}else{
conflicted[v-1] += lssolver->conflict_ct[v];
}
}
}
void Solver::rand_based_rephase(){
int var_nums = nVars();
int pick_rand = rand()%1000;
//local search
if ((pick_rand-=100)<0){
for(int i=0;i<var_nums;++i) polarity[i] = !ls_best_soln[i];
}else if((pick_rand-=300)<0){
for(int i=0;i<var_nums;++i) polarity[i] = !ls_mediation_soln[i];
// mediation_used = true;
}
//top_trail 200
else if((pick_rand-=300)<0){
for(int i=0;i<var_nums;++i) polarity[i] = !top_trail_soln[i];
}
//reverse
else if((pick_rand-=50)<0){
for(int i=0;i<var_nums;++i) polarity[i] = !polarity[i];
}else if((pick_rand-=25)<0){
for(int i=0;i<var_nums;++i) polarity[i] = ls_best_soln[i];
}else if((pick_rand-=25)<0){
for(int i=0;i<var_nums;++i) polarity[i] = top_trail_soln[i];
}
//150
else if((pick_rand-=140)<0){
for(int i=0;i<var_nums;++i) polarity[i] = rand()%2==0?1:0;
}
else if((pick_rand-=5)<0){
for(int i=0;i<var_nums;++i) polarity[i] = 1;
}else if((pick_rand-=5)<0){
for(int i=0;i<var_nums;++i) polarity[i] = 0;
}
//50
else{
//do nothing
}
}
lbool Solver::search(int& nof_conflicts)
{
assert(ok);
int backtrack_level;
int lbd;
vec<Lit> learnt_clause;
bool cached = false;
starts++;
freeze_ls_restart_num--;
bool can_call_ls = true;
if(freeze_ls_restart_num<1){
bool res = call_ls(top_trail_UP);
if(res){
solved_by_ls = true;
return l_True;
}
}
// if(ls_call_num>1){
if(rand()%100<50) info_based_rephase();
else rand_based_rephase();
// }
// simplify
//
if (conflicts >= curSimplify * nbconfbeforesimplify){
// printf("c ### simplifyAll on conflict : %lld\n", conflicts);
//printf("nbClauses: %d, nbLearnts_core: %d, nbLearnts_tier2: %d, nbLearnts_local: %d, nbLearnts: %d\n",
// clauses.size(), learnts_core.size(), learnts_tier2.size(), learnts_local.size(),
// learnts_core.size() + learnts_tier2.size() + learnts_local.size());
nbSimplifyAll++;
if (!simplifyAll()){
return l_False;
}
curSimplify = (conflicts / nbconfbeforesimplify) + 1;
nbconfbeforesimplify += incSimplify;
}
for (;;){
if (decisionLevel() == 0) { // We import clauses
if (!importClauses()) return l_False;
}
CRef confl = propagate();
if (confl != CRef_Undef){
// CONFLICT
if (VSIDS){
if (--timer == 0 && var_decay < 0.95) timer = 5000, var_decay += 0.01;
}else
if (step_size > min_step_size) step_size -= step_size_dec;
conflicts++; nof_conflicts--;
//if (conflicts == 100000 && learnts_core.size() < 100) core_lbd_cut = 5;
ConflictData data = FindConflictLevel(confl);
if (data.nHighestLevel == 0) return l_False;
if (data.bOnlyOneLitFromHighest)
{
cancelUntil(data.nHighestLevel - 1);
continue;
}
learnt_clause.clear();
analyze(confl, learnt_clause, backtrack_level, lbd);
if (cbkExportClause != NULL)
cbkExportClause(issuer, lbd, learnt_clause);
// check chrono backtrack condition
if ((confl_to_chrono < 0 || confl_to_chrono <= conflicts) && chrono > -1 && (decisionLevel() - backtrack_level) >= chrono)
{
++chrono_backtrack;
cancelUntil(data.nHighestLevel -1);
}
else // default behavior
{
++non_chrono_backtrack;
cancelUntil(backtrack_level);
}
lbd--;
if (VSIDS){
cached = false;
conflicts_VSIDS++;
lbd_queue.push(lbd);
global_lbd_sum += (lbd > 50 ? 50 : lbd); }
if (learnt_clause.size() == 1){
uncheckedEnqueue(learnt_clause[0]);
}else{
CRef cr = ca.alloc(learnt_clause, true);
ca[cr].set_lbd(lbd);
//duplicate learnts
int id = 0;
if (lbd <= max_lbd_dup){
std::vector<uint32_t> tmp;
for (int i = 0; i < learnt_clause.size(); i++)
tmp.push_back(learnt_clause[i].x);
id = is_duplicate(tmp);
if (id == min_number_of_learnts_copies +1){
duplicates_added_conflicts++;
}
if (id == min_number_of_learnts_copies){
duplicates_added_tier2++;
}
}
//duplicate learnts
if ((lbd <= core_lbd_cut) || (id == min_number_of_learnts_copies+1)){
learnts_core.push(cr);
ca[cr].mark(CORE);
}else if ((lbd <= 6)||(id == min_number_of_learnts_copies)){
learnts_tier2.push(cr);
ca[cr].mark(TIER2);
ca[cr].touched() = conflicts;
}else{
learnts_local.push(cr);
claBumpActivity(ca[cr]); }
attachClause(cr);
uncheckedEnqueue(learnt_clause[0], backtrack_level, cr);
#ifdef PRINT_OUT
std::cout << "new " << ca[cr] << "\n";
std::cout << "ci " << learnt_clause[0] << " l " << backtrack_level << "\n";
#endif
}
if (drup_file){
#ifdef BIN_DRUP
binDRUP('a', learnt_clause, drup_file);
#else
for (int i = 0; i < learnt_clause.size(); i++)
fprintf(drup_file, "%i ", (var(learnt_clause[i]) + 1) * (-2 * sign(learnt_clause[i]) + 1));
fprintf(drup_file, "0\n");
#endif
}
if (VSIDS) varDecayActivity();
claDecayActivity();
/*if (--learntsize_adjust_cnt == 0){
learntsize_adjust_confl *= learntsize_adjust_inc;
learntsize_adjust_cnt = (int)learntsize_adjust_confl;
max_learnts *= learntsize_inc;
if (verbosity >= 1)
printf("c | %9d | %7d %8d %8d | %8d %8d %6.0f | %6.3f %% |\n",
(int)conflicts,
(int)dec_vars - (trail_lim.size() == 0 ? trail.size() : trail_lim[0]), nClauses(), (int)clauses_literals,
(int)max_learnts, nLearnts(), (double)learnts_literals/nLearnts(), progressEstimate()*100);
}*/
// the top_trail_soln should be update after each conflict
if(trail.size() > max_trail){
max_trail = trail.size();
build_soln_with_UP();
int var_nums = nVars();
for(int i=0;i<var_nums;++i){top_trail_soln[i]=tmp_up_build_soln[i];}
// for(int idx_i=0; idx_i<var_nums; ++idx_i){
// lbool value_i = value(idx_i);
// if(value_i==l_Undef) top_trail_soln[idx_i] = !polarity[idx_i];
// else{
// top_trail_soln[idx_i] = value_i==l_True?1:0;
// }
// }
}
}else{
// NO_CONFLICT
// if( can_call_ls && freeze_ls_restart_num < 1 && mediation_used \
// && (trail.size() > (int)(conflict_ratio * nVars()) || trail.size() > (int)(percent_ratio * max_trail) )\
// //&& up_time_ratio * search_start_cpu_time > ls_used_time
// ){
// can_call_ls = false;
// mediation_used = false;
// freeze_ls_restart_num = restarts_gap;
// bool res = call_ls(current_UP);
// if(res){
// solved_by_ls = true;
// return l_True;
// }
// }
bool restart = false;
if (!VSIDS)
restart = nof_conflicts <= 0;
else if (!cached){
restart = lbd_queue.full() && (lbd_queue.avg() * 0.8 > global_lbd_sum / conflicts_VSIDS);
cached = true;
}
if (restart || !withinBudget()){
lbd_queue.clear();
cached = false;
// Reached bound on number of conflicts:
progress_estimate = progressEstimate();
cancelUntil(0);
return l_Undef; }
// Simplify the set of problem clauses:
if (decisionLevel() == 0 && !simplify())
return l_False;
if (conflicts >= next_T2_reduce){
next_T2_reduce = conflicts + 10000;
reduceDB_Tier2(); }
if (conflicts >= next_L_reduce){
next_L_reduce = conflicts + 15000;
reduceDB(); }
Lit next = lit_Undef;
/*while (decisionLevel() < assumptions.size()){
// Perform user provided assumption:
Lit p = assumptions[decisionLevel()];
if (value(p) == l_True){
// Dummy decision level:
newDecisionLevel();
}else if (value(p) == l_False){
analyzeFinal(~p, conflict);
return l_False;
}else{
next = p;
break;
}
}
if (next == lit_Undef)*/{
// New variable decision:
decisions++;
next = pickBranchLit();
if (next == lit_Undef)
// Model found:
return l_True;
}
// Increase decision level and enqueue 'next'
newDecisionLevel();
uncheckedEnqueue(next, decisionLevel());
#ifdef PRINT_OUT
std::cout << "d " << next << " l " << decisionLevel() << "\n";
#endif
}
}
}
double Solver::progressEstimate() const
{
double progress = 0;
double F = 1.0 / nVars();
for (int i = 0; i <= decisionLevel(); i++){
int beg = i == 0 ? 0 : trail_lim[i - 1];
int end = i == decisionLevel() ? trail.size() : trail_lim[i];
progress += pow(F, i) * (end - beg);
}
return progress / nVars();
}
/*
Finite subsequences of the Luby-sequence:
0: 1
1: 1 1 2
2: 1 1 2 1 1 2 4
3: 1 1 2 1 1 2 4 1 1 2 1 1 2 4 8
...
*/
static double luby(double y, int x){
// Find the finite subsequence that contains index 'x', and the
// size of that subsequence:
int size, seq;
for (size = 1, seq = 0; size < x+1; seq++, size = 2*size+1);
while (size-1 != x){
size = (size-1)>>1;
seq--;
x = x % size;
}
return pow(y, seq);
}
static bool switch_mode = false;
static void SIGALRM_switch(int signum) { switch_mode = true; }
// NOTE: assumptions passed in member-variable 'assumptions'.
lbool Solver::solve_()
{
// signal(SIGALRM, SIGALRM_switch);
// alarm(2500);
restarts_gap = 300;
restarts_basic = 300;
// if trail.size() over c*nVars or p*max_trail, call ls.
// float conflict_ratio = 0.4;
// float percent_ratio = 0.9;
// // control ls time total use.
// float up_time_ratio = 0.2;
// control ls memory use per call.
ls_mems_num = 50*1000*1000;
// whether the mediation_soln is used as rephase, if not
// bool mediation_used = false;
switch_heristic_mod = 500;//starts
last_switch_conflicts;
//informations
// bool lssolver_constructed = false;
freeze_ls_restart_num = 0;
ls_used_time = 0;
ls_call_num = 0;
ls_best_unsat_num = INT_MAX;
solved_by_ls = false;
max_trail = 0;
max_trail_improved = false;
up_build_num = 0;
up_build_time = 0.0;
ccanr_has_constructed=false;
model.clear();
conflict.clear();
if (!ok) return l_False;
solves++;
max_learnts = nClauses() * learntsize_factor;
learntsize_adjust_confl = learntsize_adjust_start_confl;
learntsize_adjust_cnt = (int)learntsize_adjust_confl;
lbool status = l_Undef;
ls_mediation_soln = new char[nVars()+2];
ls_best_soln = new char[nVars()+2];
top_trail_soln = new char[nVars()+2];
tmp_up_build_soln = new char[nVars()+2];
if (verbosity >= 1){
printf("c ============================[ Search Statistics ]==============================\n");
printf("c | Conflicts | ORIGINAL | LEARNT | Progress |\n");
printf("c | | Vars Clauses Literals | Limit Clauses Lit/Cl | |\n");
printf("c ===============================================================================\n");
}
add_tmp.clear();
lssolver = (CCAnr*)malloc(sizeof(CCAnr)*1);
int fls_res = call_ls(current_UP);
if(fls_res){
status = l_True;
}
for(int i=0;i<nVars();++i) top_trail_soln[i] = ls_best_soln[i];
VSIDS = true;
int init = 10000;
while (status == l_Undef && init > 0 && withinBudget())
status = search(init);
VSIDS = false;
duplicates_added_conflicts = 0;
duplicates_added_minimization=0;
duplicates_added_tier2 =0;
dupl_db_size=0;
size_t dupl_db_size_limit = dupl_db_init_size;
// Search:
int curr_restarts = 0;
last_switch_conflicts = starts;
while (status == l_Undef && withinBudget()){
if (dupl_db_size >= dupl_db_size_limit){
// printf("c Duplicate learnts added (Minimization) %i.\n",duplicates_added_minimization);
// printf("c Duplicate learnts added (conflicts) %i.\n",duplicates_added_conflicts);
// printf("c Duplicate learnts added (tier2) %i.\n",duplicates_added_tier2);
// printf("c Duptime: %i\n",duptime.count());
// printf("c Number of conflicts: %i\n",conflicts);
// printf("c Core size: %i\n",learnts_core.size());
uint32_t removed_duplicates = 0;
std::vector<std::vector<uint64_t>> tmp;
//std::map<int32_t,std::map<uint32_t,std::unordered_map<uint64_t,uint32_t>>> ht;
for (auto & outer_mp: ht){//variables
for (auto &inner_mp:outer_mp.second){//sizes
for (auto &in_in_mp: inner_mp.second){
if (in_in_mp.second >= min_number_of_learnts_copies){
tmp.push_back({outer_mp.first,inner_mp.first,in_in_mp.first,in_in_mp.second});
}
}
}
}
removed_duplicates = dupl_db_size-tmp.size();
ht.clear();
for (auto i=0;i<tmp.size();i++){
ht[tmp[i][0]][tmp[i][1]][tmp[i][2]]=tmp[i][3];
}
//ht_old.clear();
dupl_db_size_limit*=1.1;
dupl_db_size -= removed_duplicates;
// printf("c removed duplicate db entries %i\n",removed_duplicates);
}
if (VSIDS){
int weighted = INT32_MAX;
status = search(weighted);
}else{
int nof_conflicts = luby(restart_inc, curr_restarts) * restart_first;
curr_restarts++;
status = search(nof_conflicts);
}
if(starts-last_switch_conflicts > switch_heristic_mod){
if(VSIDS){
VSIDS = false;
}else{
VSIDS = true;
// picked.clear();
// conflicted.clear();
// almost_conflicted.clear();
// #ifdef ANTI_EXPLORATION
// canceled.clear();
// #endif
}
last_switch_conflicts = starts;
// cout<<"c Swith"<<VSIDS<<endl;
}
// if (!VSIDS && switch_mode){
// VSIDS = true;
// printf("c Switched to VSIDS.\n");
// fflush(stdout);
// picked.clear();
// conflicted.clear();
// almost_conflicted.clear();
// #ifdef ANTI_EXPLORATION
// canceled.clear();
// #endif
// }
}
if (verbosity >= 1)
printf("c ===============================================================================\n");
#ifdef BIN_DRUP
if (drup_file && status == l_False) binDRUP_flush(drup_file);
#endif
if (status == l_True){
// Extend & copy model:
model.growTo(nVars());
if(solved_by_ls)
for (int i = 0; i < nVars(); i++) model[i] = ls_mediation_soln[i]?l_True:l_False;
else
for (int i = 0; i < nVars(); i++) model[i] = value(i);
}else if (status == l_False && conflict.size() == 0)
ok = false;
cancelUntil(0);
delete [] ls_mediation_soln;
delete [] ls_best_soln;
delete [] top_trail_soln;
delete [] tmp_up_build_soln;
if (lssolver) {
free_memory(lssolver);
free(lssolver);
}
lssolver = NULL;
return status;
}
//=================================================================================================
// Writing CNF to DIMACS:
//
// FIXME: this needs to be rewritten completely.
static Var mapVar(Var x, vec<Var>& map, Var& max)
{
if (map.size() <= x || map[x] == -1){
map.growTo(x+1, -1);
map[x] = max++;
}
return map[x];
}
void Solver::toDimacs(FILE* f, Clause& c, vec<Var>& map, Var& max)
{
if (satisfied(c)) return;
for (int i = 0; i < c.size(); i++)
if (value(c[i]) != l_False)
fprintf(f, "%s%d ", sign(c[i]) ? "-" : "", mapVar(var(c[i]), map, max)+1);
fprintf(f, "0\n");
}
void Solver::toDimacs(const char *file, const vec<Lit>& assumps)
{
FILE* f = fopen(file, "wr");
if (f == NULL)
fprintf(stderr, "could not open file %s\n", file), exit(1);
toDimacs(f, assumps);
fclose(f);
}
void Solver::toDimacs(FILE* f, const vec<Lit>& assumps)
{
// Handle case when solver is in contradictory state:
if (!ok){
fprintf(f, "p cnf 1 2\n1 0\n-1 0\n");
return; }
vec<Var> map; Var max = 0;
// Cannot use removeClauses here because it is not safe
// to deallocate them at this point. Could be improved.
int cnt = 0;
for (int i = 0; i < clauses.size(); i++)
if (!satisfied(ca[clauses[i]]))
cnt++;
for (int i = 0; i < clauses.size(); i++)
if (!satisfied(ca[clauses[i]])){
Clause& c = ca[clauses[i]];
for (int j = 0; j < c.size(); j++)
if (value(c[j]) != l_False)
mapVar(var(c[j]), map, max);
}
// Assumptions are added as unit clauses:
cnt += assumptions.size();
fprintf(f, "p cnf %d %d\n", max, cnt);
for (int i = 0; i < assumptions.size(); i++){
assert(value(assumptions[i]) != l_False);
fprintf(f, "%s%d 0\n", sign(assumptions[i]) ? "-" : "", mapVar(var(assumptions[i]), map, max)+1);
}
for (int i = 0; i < clauses.size(); i++)
toDimacs(f, ca[clauses[i]], map, max);
if (verbosity > 0)
printf("c Wrote %d clauses with %d variables.\n", cnt, max);
}
//=================================================================================================
// Garbage Collection methods:
void Solver::relocAll(ClauseAllocator& to)
{
// All watchers:
//
// for (int i = 0; i < watches.size(); i++)
watches.cleanAll();
watches_bin.cleanAll();
for (int v = 0; v < nVars(); v++)
for (int s = 0; s < 2; s++){
Lit p = mkLit(v, s);
// printf(" >>> RELOCING: %s%d\n", sign(p)?"-":"", var(p)+1);
vec<Watcher>& ws = watches[p];
for (int j = 0; j < ws.size(); j++)
ca.reloc(ws[j].cref, to);
vec<Watcher>& ws_bin = watches_bin[p];
for (int j = 0; j < ws_bin.size(); j++)
ca.reloc(ws_bin[j].cref, to);
}
// All reasons:
//
for (int i = 0; i < trail.size(); i++){
Var v = var(trail[i]);
if (reason(v) != CRef_Undef && (ca[reason(v)].reloced() || locked(ca[reason(v)])))
ca.reloc(vardata[v].reason, to);
}
// All learnt:
//
for (int i = 0; i < learnts_core.size(); i++)
ca.reloc(learnts_core[i], to);
for (int i = 0; i < learnts_tier2.size(); i++)
ca.reloc(learnts_tier2[i], to);
for (int i = 0; i < learnts_local.size(); i++)
ca.reloc(learnts_local[i], to);
// All original:
//
int i, j;
for (i = j = 0; i < clauses.size(); i++)
if (ca[clauses[i]].mark() != 1){
ca.reloc(clauses[i], to);
clauses[j++] = clauses[i]; }
clauses.shrink(i - j);
}
void Solver::garbageCollect()
{
// Initialize the next region to a size corresponding to the estimated utilization degree. This
// is not precise but should avoid some unnecessary reallocations for the new region:
ClauseAllocator to(ca.size() - ca.wasted());
relocAll(to);
if (verbosity >= 2)
printf("c | Garbage collection: %12d bytes => %12d bytes |\n",
ca.size()*ClauseAllocator::Unit_Size, to.size()*ClauseAllocator::Unit_Size);
to.moveTo(ca);
}
void Solver::load_ls_data(){
using namespace std;
int ls_var_nums = nVars();
int ls_cls_nums = nClauses()+learnts_core.size()+learnts_tier2.size();
int ls_trail_sz;
if(trail_lim.size()>0) ls_trail_sz = trail_lim[0];
else ls_trail_sz = trail.size();
ls_cls_nums += ls_trail_sz;
lssolver->num_vars = ls_var_nums;
lssolver->num_clauses = ls_cls_nums;
lssolver->mems_left = (long long) ls_mems_num;
lssolver->ratio = (lssolver->num_clauses+0.0)/lssolver->num_vars;
alloc_memory(lssolver);
for (int c = 0; c < lssolver->num_clauses; c++)
lssolver->clause_lit_count[c] = lssolver->clause_delete[c] = 0;
for (int v=1; v<=lssolver->num_vars; ++v)
lssolver->var_lit_count[v] = lssolver->fix[v] = 0;
lssolver->max_clause_len = 0;
lssolver->min_clause_len = lssolver->num_vars;
using namespace std;
int cls_ct = 0;
for(int idx=0;idx<3;++idx){
vec<CRef> &vs = (idx==0)?clauses:(idx==1?learnts_core:(idx==2?learnts_tier2:learnts_local));
int vs_sz = vs.size();
for(int j=0;j<vs_sz;j++){
CRef &cr = vs[j];
Clause &c = ca[cr];
lssolver->clause_lit_count[cls_ct] = c.size();
lssolver->clause_lit[cls_ct] = (lit*)malloc(sizeof(lit)*(lssolver->clause_lit_count[cls_ct]+1));
int i=0;
for(;i<lssolver->clause_lit_count[cls_ct];i++){
int cur_lit = toFormal(c[i]);
lssolver->clause_lit[cls_ct][i].clause_num = cls_ct;
lssolver->clause_lit[cls_ct][i].var_num = abs(cur_lit);
if (cur_lit > 0) lssolver->clause_lit[cls_ct][i].sense = 1;
else lssolver->clause_lit[cls_ct][i].sense = 0;
lssolver->var_lit_count[lssolver->clause_lit[cls_ct][i].var_num]++;
}
lssolver->clause_lit[cls_ct][i].var_num=0;
lssolver->clause_lit[cls_ct][i].clause_num = -1;
//unit clause
if(lssolver->clause_lit_count[cls_ct]==1){
lssolver->unitclause_queue[lssolver->unitclause_queue_end_pointer++] = lssolver->clause_lit[cls_ct][0];
lssolver->clause_delete[cls_ct]=1;
lssolver->clause_lit_count[cls_ct]=0;
}
if(lssolver->clause_lit_count[cls_ct] > lssolver->max_clause_len)
lssolver->max_clause_len = lssolver->clause_lit_count[cls_ct];
else if(lssolver->clause_lit_count[cls_ct] < lssolver->min_clause_len)
lssolver->min_clause_len = lssolver->clause_lit_count[cls_ct];
lssolver->formula_len += lssolver->clause_lit_count[cls_ct];
cls_ct++;
}
}
for(int j=0;j<ls_trail_sz;++j){
int cur_lit = toFormal(trail[j]);
lssolver->clause_lit_count[cls_ct] = 1;
lssolver->clause_lit[cls_ct] = (lit*)malloc(sizeof(lit)*(2));
lssolver->clause_lit[cls_ct][0].clause_num = cls_ct;
lssolver->clause_lit[cls_ct][0].var_num = abs(cur_lit);
if (cur_lit > 0) lssolver->clause_lit[cls_ct][0].sense = 1;
else lssolver->clause_lit[cls_ct][0].sense = 0;
lssolver->var_lit_count[lssolver->clause_lit[cls_ct][0].var_num]++;
lssolver->clause_lit[cls_ct][1].var_num=0;
lssolver->clause_lit[cls_ct][1].clause_num=-1;
lssolver->unitclause_queue[lssolver->unitclause_queue_end_pointer++] = lssolver->clause_lit[cls_ct][0];
lssolver->clause_delete[cls_ct]=1;
lssolver->clause_lit_count[cls_ct]=0;
if(lssolver->min_clause_len > 1)lssolver->min_clause_len = 1;
lssolver->formula_len += 1;
cls_ct++;
}
for (int c = 0; c < lssolver->num_clauses; ++c)
{
if(lssolver->clause_delete[c]==1) {
continue;
}
for(int i=0; i<lssolver->clause_lit_count[c]; ++i)
{
int v = lssolver->clause_lit[c][i].var_num;
if (v > 0 && v <= lssolver->num_vars);
else {
printf("\n111wrong v %d clause id: %d\n", v, c);
for(int ii=0; ii<lssolver->clause_lit_count[c]; ++ii)
printf("%d ", lssolver->clause_lit[c][ii].var_num);
puts("");
}
if (lssolver->var_lit_count[v] >= 0 && lssolver->var_lit_count[v] <= lssolver->num_clauses);
else printf("111wrong var_lit_count[v] %d\n", lssolver->var_lit_count[v]);
}
}
// printf("finish check 1\n");
// ofstream fout("test.txt");
// for (int c = 0; c < lssolver->num_clauses; ++c)
// {
// if(lssolver->clause_delete[c]==1) {
// continue;
// }
// fout << c << ": ";
// for(int i=0; i<lssolver->clause_lit_count[c]; ++i)
// {
// int v = lssolver->clause_lit[c][i].var_num;
// int p = lssolver->clause_lit[c][i].sense;
// fout << (p==1 ? v:-v) << " ";
// }
// fout << endl;
// }
// fout.close();
update_after_build(lssolver);
for (int c = 0; c < lssolver->num_clauses; ++c)
{
if(lssolver->clause_delete[c]==1) {
continue;
}
for(int i=0; i<lssolver->clause_lit_count[c]; ++i)
{
int v = lssolver->clause_lit[c][i].var_num;
if (v > 0 && v <= lssolver->num_vars);
else {
printf("\n333wrong v %d clause id: %d\n", v, c);
for(int ii=0; ii<lssolver->clause_lit_count[c]; ++ii)
printf("%d ", lssolver->clause_lit[c][ii].var_num);
puts("");
}
if (lssolver->var_lit_count[v] >= 0 && lssolver->var_lit_count[v] <= lssolver->num_clauses);
else printf("333wrong var_lit_count[v] %d\n", lssolver->var_lit_count[v]);
}
}
// printf("finish check 3\n");
}
void Solver::build_soln_with_UP(){
#include <vector>
using std::vector;
double start_time = cpuTime();
int var_nums = nVars();
int trl_sz = trail.size();
int trl_loc = qhead;
Lit* trl = new Lit[var_nums+1];
int undef_vars_sz = 0;
int* undef_vars = new int[var_nums+1];
int* idx_in_undef_vars = new int[var_nums+1];
// -1 undef, 0 false, 1 true
for(int i=0;i<trl_sz;++i) trl[i]=trail[i];
for(int i=0;i<var_nums;++i) {
if(value(i) == l_Undef){
undef_vars[undef_vars_sz] = i;
idx_in_undef_vars[i] = undef_vars_sz++;
tmp_up_build_soln[i] = -1;
}else{
tmp_up_build_soln[i] = (value(i) == l_True) ? 1 : 0;
}
}
// do UP
while(undef_vars_sz>0){
while(trl_loc<trl_sz && undef_vars_sz>0){
Lit &p = trl[trl_loc++];
// watch binary codes
vec<Watcher>& ws_bin = watches_bin[p];
int ws_bin_sz = ws_bin.size();
for(int k=0;k<ws_bin_sz;++k){
Lit the_other = ws_bin[k].blocker;
Var the_other_var = var(the_other);
if(tmp_up_build_soln[the_other_var]==-1){
tmp_up_build_soln[the_other_var] = sign(the_other)?0:1;
trl[trl_sz++] = the_other;
int end_var = undef_vars[--undef_vars_sz];
int idx_end_var = idx_in_undef_vars[the_other_var];
undef_vars[idx_end_var] = end_var;
idx_in_undef_vars[end_var] = idx_end_var;
if(undef_vars_sz==0) break;
}
}
if(undef_vars_sz==0) break;
// not binary codes
vec<Watcher>& ws = watches[p];
Watcher *i,*j,*end;
for(i=j=(Watcher*)ws,end=i+ws.size();i!=end;){
Lit blocker = i->blocker;
// the clause is already SAT
if(tmp_up_build_soln[var(blocker)]==!sign(blocker)){*j++ = *i++;continue;}
CRef cr = i->cref;
Clause& c = ca[cr];
// make sure c[1] is the false_lit to swap
Lit false_lit = ~p;
if(c[0]==false_lit) c[0]=c[1],c[1]=false_lit;
i++;
// judge if the first lit is l_true
Lit first = c[0];
Var first_var = var(first);
Watcher w = Watcher(cr,first);
if(first!=blocker && tmp_up_build_soln[first_var]==!sign(first)){*j++ = w; continue;}
// first is l_false or l_undef
// then find another !l_false lit
int c_sz = c.size();
bool should_goto_next_cls = false;
for(int k=2;k<c_sz;++k){
Lit tmp_lit = c[k];
Var tmp_var = var(tmp_lit);
if(tmp_up_build_soln[tmp_var]!=sign(tmp_lit)){
c[1] = c[k];
c[k] = false_lit;
watches[~c[1]].push(w);
should_goto_next_cls=true;break;
}
}if(should_goto_next_cls) continue;
// all lit except c[0] in this cls is l_false.
*j++ = w;
if(tmp_up_build_soln[first_var]==-1){ // is unit cls
tmp_up_build_soln[first_var] = !sign(first);
trl[trl_sz++] = mkLit(first_var,sign(first));
int end_var = undef_vars[--undef_vars_sz];
int idx_end_var = idx_in_undef_vars[first_var];
undef_vars[idx_end_var] = end_var;
idx_in_undef_vars[end_var] = idx_end_var;
if(undef_vars_sz==0){while (i < end) *j++=*i++; break;}
}
}
ws.shrink(i-j);
}
if(undef_vars_sz==0) break;
// up cannot continue, random pick a var and assign.
int add_var = undef_vars[rand()%undef_vars_sz];
trl[trl_sz++] = mkLit(add_var,polarity[add_var]);
tmp_up_build_soln[add_var] = !polarity[add_var];
int end_var = undef_vars[--undef_vars_sz];
int idx_end_var = idx_in_undef_vars[add_var];
undef_vars[idx_end_var] = end_var;
idx_in_undef_vars[end_var] = idx_end_var;
}
delete[] trl,undef_vars,idx_in_undef_vars;
double tmp_time = cpuTime()-start_time;
up_build_time += tmp_time;
up_build_num++;
}
bool Solver::call_ls(build_type type){
// double start_time = cpuTime();
if(ccanr_has_constructed)reinit_CCAnr(lssolver);
else init_CCAnr(lssolver),ccanr_has_constructed=true;
load_ls_data();
bool res = false;
int init_ls_unsat_ct;
if(type == current_UP){
build_soln_with_UP();
settings(lssolver,tmp_up_build_soln);
}else if(type == top_trail_UP){settings(lssolver,top_trail_soln);}
else if(type == random_build){settings(lssolver,NULL);}
init_ls_unsat_ct = lssolver->unsat_stack_fill_pointer;
// double construct_time = cpuTime()-start_time;
res = local_search(lssolver);
confl_trans(lssolver);
int ls_var_nums=nVars();
for(int i=0;i<ls_var_nums;++i)ls_mediation_soln[i] = lssolver->best_soln[i+1];
if(lssolver->best_cost <= ls_best_unsat_num){
restarts_gap-=restarts_basic;
if(restarts_gap<restarts_basic) restarts_gap = restarts_basic;
ls_best_unsat_num = lssolver->best_cost;
for(int i=0;i<ls_var_nums;++i) ls_best_soln[i] = ls_mediation_soln[i];
}else{restarts_gap += restarts_basic;}
freeze_ls_restart_num = restarts_gap;
max_trail = max_trail*0.9;
if(res==true) solved_by_ls = true;
// double this_ls_time = cpuTime()-start_time;
// using std::to_string;
// std::cout <<"c LS_res("<<to_string(++ls_call_num)+")="+to_string((int)res)
// <<",(cr="<<((trail.size()+0.0)/nVars())<<",pr="<<((trail.size()+0.0)/max_trail)<<")"
// <<",(fix"<<to_string(lssolver->fix_var_ct)+"v,del"+to_string(lssolver->del_cls_ct)+"c)"
// <<",(v="<<to_string(lssolver->num_vars)+",c="+to_string(lssolver->num_clauses)+")"
// <<",(unsat:"<<to_string(init_ls_unsat_ct)<<"->"<<to_string(lssolver->best_cost)+")"
// <<",("<<to_string(conflicts)<<"c,"<<to_string(starts)<<"r,"<<to_string(lssolver->step)<<"s)"
// <<",["<<to_string(max_trail)<<"trl,"<<to_string(up_build_num)<<"n,"<<to_string(up_build_time)<<"t]"
// <<","<<to_string(construct_time)<<","<<to_string(this_ls_time)
// <<std::endl;
return res;
}