/* =========FOR INTERNAL USE ONLY. NO DISTRIBUTION PLEASE ========== */
/*********************************************************************
Copyright 2000-2001, Princeton University. All rights reserved.
By using this software the USER indicates that he or she has read,
understood and will comply with the following:
--- Princeton University hereby grants USER nonexclusive permission
to use, copy and/or modify this software for internal, noncommercial,
research purposes only. Any distribution, including commercial sale
or license, of this software, copies of the software, its associated
documentation and/or modifications of either is strictly prohibited
without the prior consent of Princeton University. Title to copyright
to this software and its associated documentation shall at all times
remain with Princeton University. Appropriate copyright notice shall
be placed on all software copies, and a complete copy of this notice
shall be included in all copies of the associated documentation.
No right is granted to use in advertising, publicity or otherwise
any trademark, service mark, or the name of Princeton University.
--- This software and any associated documentation is provided "as is"
PRINCETON UNIVERSITY MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS
OR IMPLIED, INCLUDING THOSE OF MERCHANTABILITY OR FITNESS FOR A
PARTICULAR PURPOSE, OR THAT USE OF THE SOFTWARE, MODIFICATIONS, OR
ASSOCIATED DOCUMENTATION WILL NOT INFRINGE ANY PATENTS, COPYRIGHTS,
TRADEMARKS OR OTHER INTELLECTUAL PROPERTY RIGHTS OF A THIRD PARTY.
Princeton University shall not be liable under any circumstances for
any direct, indirect, special, incidental, or consequential damages
with respect to any claim by USER or any third party on account of
or arising from the use, or inability to use, this software or its
associated documentation, even if Princeton University has been advised
of the possibility of those damages.
*********************************************************************/
#include "xchaff_solver.h"
#include <algorithm>
CSolver::CSolver(void)
{
dlevel()=0;
_params.time_limit = 3600 * 48; //2 days
_params.decision_strategy = 0;
_params.preprocess_strategy = 0;
_params.allow_clause_deletion = true ;
_params.clause_deletion_interval = 5000;
_params.max_unrelevance = 20;
_params.min_num_clause_lits_for_delete = 100;
_params.max_conflict_clause_length = 5000;
_params.bubble_init_step = 32;
_params.randomness = 0;
_params.verbosity = 0;
_params.back_track_complete = true;
_params.allow_multiple_conflict = false;
_params.allow_multiple_conflict_clause = false;
_params.allow_restart = true;
_params.next_restart_time = 50; //this set the first restart time (in seconds)
_params.restart_time_increment = 0;
_params.restart_time_incr_incr = 0;
_params.next_restart_backtrack= 0;
_params.restart_backtrack_incr= 40000;
_params.restart_backtrack_incr_incr = 100;
_params.restart_randomness = 0;
_params.base_randomness = 0;
_params.randomness = 0;
_stats.is_solver_started = false;
_stats.outcome = UNKNOWN;
_stats.is_mem_out = false;
_stats.start_cpu_time = 0;
_stats.finish_cpu_time = 0;
_stats.last_cpu_time = 0;
_stats.start_world_time = 0;
_stats.finish_world_time = 0;
_stats.num_decisions = 0;
_stats.num_backtracks = 0;
_stats.max_dlevel = 0;
_stats.num_implications = 0;
_num_marked = 0;
_dlevel = 0;
_stats.total_bubble_move = 0;
_dlevel_hook = NULL;
_decision_hook = NULL;
_assignment_hook = NULL;
_deduction_hook = NULL;
}
CSolver::~CSolver()
{
if (_stats.is_solver_started) {
for (unsigned i=0; i<variables().size(); ++i)
delete _assignment_stack[i];
}
}
void CSolver::run_periodic_functions(void)
{
//a. clause deletion
if ( _params.allow_clause_deletion &&
_stats.num_backtracks % _params.clause_deletion_interval == 0)
delete_unrelevant_clauses();
//b. restart
if (_params.allow_restart && _stats.num_backtracks > _params.next_restart_backtrack) {
_params.next_restart_backtrack += _params.restart_backtrack_incr;
_params.restart_backtrack_incr += _params.restart_backtrack_incr_incr;
float current = current_cpu_time()/1000;
if (current > _params.next_restart_time) {
if (_params.verbosity > 1) cout << "restart..." << endl;
_params.next_restart_time = current + _params.restart_time_increment;
_params.restart_time_increment += _params.restart_time_incr_incr;
_params.randomness = _params.restart_randomness;
restart();
}
}
//c. update var stats for decision
if ((_stats.num_decisions % 0xff)==0)
update_var_stats();
//d. run hook functions
for (unsigned i=0; i< _hooks.size(); ++i) {
pair<int,pair<HookFunPtrT, int> > & hook = _hooks[i];
if (_stats.num_decisions >= hook.first) {
hook.first += hook.second.second;
hook.second.first((void *) this);
}
}
}
void CSolver::init(void)
{
CDatabase::init();
_stats.is_solver_started = true;
_stats.start_cpu_time = current_cpu_time();
_stats.start_world_time = current_world_time();
_stats.num_free_variables = num_variables();
for (unsigned i=0; i<variables().size(); ++i)
_assignment_stack.push_back(new vector<int>);
_var_order.resize( num_variables());
_last_var_lits_count[0].resize(variables().size());
_last_var_lits_count[1].resize(variables().size());
CHECK(dump());
}
int CSolver::add_variables(int new_vars)
{
int old_num_vars = variables().size();
int num_vars = old_num_vars + new_vars;
variables().resize(num_vars) ;
if (_stats.is_solver_started) {
_stats.num_free_variables += new_vars;
for (int i=old_num_vars; i<num_vars; ++i) {
_assignment_stack.push_back(new vector<int>);
_var_order.push_back(pair<int, int>(i,0));
}
_last_var_lits_count[0].resize(num_vars);
_last_var_lits_count[1].resize(num_vars);
}
return old_num_vars;
}
ClauseIdx CSolver::add_clause(vector<long>& lits, bool addConflicts) {
int new_cl;
int n_lits = lits.size();
//a. do we need to enlarge lits pool?
while (lit_pool_free_space() <= n_lits + 1) {
if (enlarge_lit_pool()==false)
return -1; //mem out, can't enlarge lit pool, because
//ClauseIdx can't be -1, so it shows error.
}
//b. get a free cl index;
if (_unused_clause_idx_queue.empty()) {
new_cl = _clauses.size();
_clauses.resize(new_cl + 1);
}
else {
new_cl = _unused_clause_idx_queue.front();
_unused_clause_idx_queue.pop();
}
//c. add the clause lits to lits pool
clause(new_cl).init(lit_pool_end(), n_lits);
//I want to verify added clauses are either all free or all 0
bool satisfied = false, is_unit = false, is_conflict = false;
int num_unknown = 0;
for (int i=0; i< n_lits; ++i){
int var_idx = lits[i]>>1;
if ((unsigned)var_idx >= variables().size()) {
assert(false);
}
int var_sign = lits[i]&0x1;
lit_pool_push_back( ((var_idx<<1) + var_sign) << 2);
++variable(var_idx).lits_count(var_sign);
int lit_value = literal_value(clause(new_cl).literal(i));
if (lit_value == 1) {
satisfied = true;
}
else if (lit_value != 0) {
++num_unknown;
}
}
is_conflict = !satisfied && (num_unknown == 0);
is_unit = !satisfied && (num_unknown == 1);
assert(_stats.is_solver_started || num_unknown == n_lits);
lit_pool_push_back(-new_cl); //push in the clause idx in the end
//d. set the head/tail pointers
if (clause(new_cl).num_lits() > 1) {
//add the ht. note: ht must be the last free var
int max_idx = -1, max_dl = -1;
CClause & cl = clause(new_cl);
int i, sz = cl.num_lits();
int other_ht_idx;
for (i=0; i< sz; ++i) {
int v_idx = cl.literals()[i].var_index();
if (variable(v_idx).value()==UNKNOWN) {
int v_sign = cl.literals()[i].var_sign();
variable(v_idx).ht_ptr(v_sign).push_back( & cl.literals()[i]);
cl.literals()[i].set_ht(1);
other_ht_idx = i;
break;
}
else {
if (variable(v_idx).dlevel() > max_dl) {
max_dl = variable(v_idx).dlevel();
max_idx = i;
}
}
}
if (i >= sz) {
//no unknown literals. so use the max dl literal
int v_idx = cl.literals()[max_idx].var_index();
int v_sign = cl.literals()[max_idx].var_sign();
variable(v_idx).ht_ptr(v_sign).push_back( & cl.literals()[max_idx]);
cl.literals()[max_idx].set_ht(1);
other_ht_idx = max_idx;
}
max_idx = -1; max_dl = -1;
for (i=sz-1; i>=0; --i) {
if (i==other_ht_idx ) continue;
int v_idx = cl.literals()[i].var_index();
if (variable(v_idx).value()==UNKNOWN) {
int v_sign = cl.literals()[i].var_sign();
variable(v_idx).ht_ptr(v_sign).push_back( & cl.literals()[i]);
cl.literals()[i].set_ht(-1);
break;
}
else {
if (variable(v_idx).dlevel() > max_dl) {
max_dl = variable(v_idx).dlevel();
max_idx = i;
}
}
}
if (i < 0) {
int v_idx = cl.literals()[max_idx].var_index();
int v_sign = cl.literals()[max_idx].var_sign();
CLitPoolElement * lit_ptr = & cl.literals()[max_idx];
variable(v_idx).ht_ptr(v_sign).push_back(lit_ptr);
cl.literals()[max_idx].set_ht(-1);
}
}
//update some statistics
++CDatabase::_stats.num_added_clauses;
CDatabase::_stats.num_added_literals += n_lits;
if (is_unit && _stats.is_solver_started) {
if (n_lits == 1) _addedUnitClauses.push_back(new_cl);
int lit = find_unit_literal(new_cl);
assert(lit);
queue_implication(lit, new_cl);
}
else if (addConflicts && is_conflict) {
_conflicts.push_back(new_cl);
}
return new_cl;
}
void CSolver::set_var_value(int v, int value, ClauseIdx ante, int dl)
{
assert (value == 0 || value == 1);
CHECK_FULL(dump());
CHECK(verify_integrity());
CHECK (cout << "Setting\t" << (value>0?"+":"-") << v
<< " at " << dl << " because " << ante<< endl;);
++_stats.num_implications ;
--num_free_variables();
if (_assignment_hook) {
(*_assignment_hook)(_assignment_hook_cookie, v, value);
}
CVariable & var = _variables[v];
assert (var.value() == UNKNOWN);
var.dlevel() = dl;
var.value() = value;
var.set_antecedence(ante);
vector<CLitPoolElement *> & ht_ptrs = var.ht_ptr(value);
if (dl == dlevel())
set_var_value_with_current_dl(v, ht_ptrs);
else
set_var_value_not_current_dl(v, ht_ptrs);
}
void CSolver::set_var_value_with_current_dl(int v, vector<CLitPoolElement *> & ht_ptrs)
{
ClauseIdx cl_idx;
CLitPoolElement * ht_ptr, * other_ht_ptr = NULL, * ptr;
int dir;
for (vector <CLitPoolElement *>::iterator itr = ht_ptrs.begin(); itr != ht_ptrs.end(); ++itr) {
ht_ptr = *itr;
dir = ht_ptr->direction();
ptr = ht_ptr;
while(1) {
ptr += dir;
if (ptr->val() <= 0) {
if (dir == 1)
cl_idx = - ptr->val();
if (dir == ht_ptr->direction()) {
ptr = ht_ptr;
dir = -dir;
continue;
}
int the_value = literal_value (*other_ht_ptr);
if (the_value == 0) //a conflict
_conflicts.push_back(cl_idx);
else if ( the_value != 1) //e.g. unknown
queue_implication (other_ht_ptr->s_var(), cl_idx);
break;
}
if (ptr->is_ht()) {
other_ht_ptr = ptr;
continue;
}
if (literal_value(*ptr) == 0)
continue;
//now it's value is either 1 or unknown
int v1 = ptr->var_index();
int sign = ptr->var_sign();
variable(v1).ht_ptr(sign).push_back(ptr);
ht_ptr->unset_ht();
ptr->set_ht(dir);
*itr = ht_ptrs.back();
ht_ptrs.pop_back();
--itr;
break;
}
}
}
void CSolver::set_var_value_not_current_dl(int v, vector<CLitPoolElement *> & ht_ptrs)
{
ClauseIdx cl_idx;
CLitPoolElement * ht_ptr, * other_ht_ptr = NULL, * ptr, * max_ptr = NULL;
int dir,max_dl;
for (vector <CLitPoolElement *>::iterator itr = ht_ptrs.begin();
itr != ht_ptrs.end(); ++itr) {
max_dl = -1;
ht_ptr = *itr;
dir = ht_ptr->direction();
ptr = ht_ptr;
while(1) {
ptr += dir;
if (ptr->val() <= 0) {
if (dir == 1)
cl_idx = - ptr->val();
if (dir == ht_ptr->direction()) {
ptr = ht_ptr;
dir = -dir;
continue;
}
if (variable(ht_ptr->var_index()).dlevel() < max_dl) {
int v1 = max_ptr->var_index();
int sign = max_ptr->var_sign();
variable(v1).ht_ptr(sign).push_back(max_ptr);
ht_ptr->unset_ht();
max_ptr->set_ht(dir);
*itr = ht_ptrs.back();
ht_ptrs.pop_back();
--itr;
}
int the_value = literal_value (*other_ht_ptr);
if (the_value == 0) //a conflict
_conflicts.push_back(cl_idx);
else if ( the_value != 1) //e.g. unknown
queue_implication (other_ht_ptr->s_var(), cl_idx);
break;
}
if (ptr->is_ht()) {
other_ht_ptr = ptr;
continue;
}
if (literal_value(*ptr) == 0) {
if (variable(ptr->var_index()).dlevel() > max_dl) {
max_dl = variable(ptr->var_index()).dlevel();
max_ptr = ptr;
}
continue;
}
//now it's value is either 1 or unknown
int v1 = ptr->var_index();
int sign = ptr->var_sign();
variable(v1).ht_ptr(sign).push_back(ptr);
ht_ptr->unset_ht();
ptr->set_ht(dir);
*itr = ht_ptrs.back();
ht_ptrs.pop_back();
--itr;
break;
}
}
}
void CSolver::unset_var_value(int v)
{
CHECK(cout <<"Unset var " << (variable(v).value()?"+":"-") << v << endl;);
CVariable & var = variable(v);
if (var.var_score_pos() < _max_score_pos)
_max_score_pos = var.var_score_pos();
var.value() = UNKNOWN;
var.set_antecedence(NULL_CLAUSE);
var.dlevel() = -1;
if (_assignment_hook) {
(*_assignment_hook)(_assignment_hook_cookie, v, -1);
}
}
int CSolver::find_max_clause_dlevel(ClauseIdx cl)
{
//if cl has single literal, then dlevel should be 0
int max_level = 0;
if (cl == NULL_CLAUSE || cl == FLIPPED)
return dlevel();
for (int i=0, sz= clause(cl).num_lits(); i<sz; ++i) {
int var_idx =((clause(cl).literals())[i]).var_index();
if (_variables[var_idx].value() != UNKNOWN) {
if (max_level < _variables[var_idx].dlevel())
max_level = _variables[var_idx].dlevel();
}
}
return max_level;
}
void CSolver::dump_assignment_stack(ostream & os) {
cout << "Assignment Stack: ";
for (int i=0; i<= dlevel(); ++i) {
if ((*_assignment_stack[i]).size() > 0)
if (variable( (*_assignment_stack[i])[0]>>1).get_antecedence()==FLIPPED)
cout << "*" ;
cout << "(" <<i << ":";
for (unsigned j=0; j<(*_assignment_stack[i]).size(); ++j )
cout << ((*_assignment_stack[i])[j]&0x1?"-":"+")
<< ((*_assignment_stack[i])[j] >> 1) << " ";
cout << ") " << endl;
}
cout << endl;
}
bool CDatabase::is_conflict(ClauseIdx cl)
{
CLitPoolElement * lits = clause(cl).literals();
for (int i=0, sz= clause(cl).num_lits(); i<sz; ++i)
if (literal_value(lits[i]) != 0)
return false;
return true;
}
bool CDatabase::is_satisfied(ClauseIdx cl)
{
CLitPoolElement * lits = clause(cl).literals();
for (int i=0, sz= clause(cl).num_lits(); i<sz; ++i)
if (literal_value(lits[i]) == 1)
return true;
return false;
}
int CDatabase::find_unit_literal(ClauseIdx cl)
{
//if it's not unit, return 0.
int unassigned = 0;
for (int i=0, sz= clause(cl).num_lits(); i<sz; ++i) {
int var_idx =((clause(cl).literals())[i]).var_index();
if (_variables[var_idx].value() == UNKNOWN) {
if (unassigned == 0)
unassigned = clause(cl).literals()[i].s_var();
else //more than one unassigned
return 0;
}
}
return unassigned;
}
void CSolver::delete_unrelevant_clauses(void)
{
CHECK_FULL (dump());
int original_num_deleted = num_deleted_clauses();
if (CDatabase::_stats.mem_used_up) {
CDatabase::_stats.mem_used_up = false;
if (++CDatabase::_stats.mem_used_up_counts < 5) {
_params.max_unrelevance = (int) (_params.max_unrelevance * 0.8);
if (_params.max_unrelevance < 4)
_params.max_unrelevance = 4;
_params.min_num_clause_lits_for_delete = (int) (_params.min_num_clause_lits_for_delete* 0.8);
if (_params.min_num_clause_lits_for_delete < 10)
_params.min_num_clause_lits_for_delete = 10;
_params.max_conflict_clause_length = (int) (_params.max_conflict_clause_length*0.8);
if (_params.max_conflict_clause_length < 50 )
_params.max_conflict_clause_length = 50;
CHECK(
cout << "Forced to reduce unrelevance in clause deletion. " << endl;
cout <<"MaxUnrel: " << _params.max_unrelevance
<< " MinLenDel: " << _params.min_num_clause_lits_for_delete
<< " MaxLenCL : " << _params.max_conflict_clause_length << endl;
);
}
}
//first find out the clause to delete and mark them
for (vector<CClause>::iterator itr = clauses().begin() + init_num_clauses();
itr != clauses().end(); ++itr) {
CClause & cl = * itr;
if (!cl.in_use() || cl.num_lits() < _params.min_num_clause_lits_for_delete ) continue;
int val_0_lits = 0, val_1_lits = 0, unknown_lits = 0;
for (int i=0; i< cl.num_lits(); ++i) {
int lit_value = literal_value (cl.literal(i));
if (lit_value == 0 ) ++val_0_lits;
else if (lit_value == 1) ++val_1_lits;
else ++unknown_lits;
if (unknown_lits + val_1_lits > _params.max_unrelevance) {
mark_clause_deleted(cl);
_unused_clause_idx_queue.push(itr - clauses().begin());
CHECK (cout << "Deleting Unrelevant clause: " << cl << endl;);
break;
}
if (cl.num_lits() > _params.max_conflict_clause_length &&
(unknown_lits+val_1_lits > 1) ) { //to make sure it's not generating an implication
//and it's not an antecedence for other var assignment
mark_clause_deleted(cl);
CHECK (cout << "Deleting too large clause: " << cl << endl;);
_unused_clause_idx_queue.push(itr - clauses().begin());
break;
}
}
}
//now delete the index from variables
if (original_num_deleted == num_deleted_clauses())
return ; //didn't delete anything
for (vector<CVariable>::iterator itr = variables().begin();
itr != variables().end(); ++ itr) {
for (int i=0; i<2; ++i) { //for each phase
//delete the h_t index from the vars
vector<CLitPoolElement *> & ht_ptr = (*itr).ht_ptr(i);
for (vector<CLitPoolElement *>::iterator my_itr = ht_ptr.begin();
my_itr != ht_ptr.end(); ++my_itr) {
if ( (*my_itr)->val() <= 0) {
*my_itr = ht_ptr.back();
ht_ptr.pop_back();
--my_itr;
}
}
}
}
CHECK(cout << "Deleting " << num_deleted_clauses() - original_num_deleted << " Clause ";
cout << " and " << num_deleted_literals() - original_del_lits << " Literals " << endl;);
CHECK_FULL (dump());
}
//============================================================================================
bool CSolver::time_out(void)
{
if ( (current_cpu_time() - _stats.start_cpu_time)/1000.0 > _params.time_limit )
return true;
return false;
}
inline bool compare_var_stat(const pair<int, int> & v1,
const pair<int, int> & v2)
{
if (v1.second > v2.second) return true;
return false;
}
void CSolver::update_var_stats(void)
{
for(unsigned i=1; i< variables().size(); ++i) {
CVariable & var = variable(i);
var.score(0) = var.score(0)/2 + var.lits_count(0) - _last_var_lits_count[0][i];
var.score(1) = var.score(1)/2 + var.lits_count(1) - _last_var_lits_count[1][i];
_last_var_lits_count[0][i] = var.lits_count(0);
_last_var_lits_count[1][i] = var.lits_count(1);
_var_order[i-1] = pair<int, int>(i, var.score());
}
::stable_sort(_var_order.begin(), _var_order.end(), compare_var_stat);
for (unsigned i=0; i<_var_order.size(); ++i)
variable(_var_order[i].first).var_score_pos() = i;
_max_score_pos = 0;
}
bool CSolver::decide_next_branch(void)
{
++_stats.num_decisions;
if (!_implication_queue.empty()) {
//some hook function did a decision, so skip my own decision making.
//if the front of implication queue is 0, that means it's finished
//because var index start from 1, so 2 *vid + sign won't be 0.
//else it's a valid decision.
_max_score_pos = 0; //reset the max_score_position.
return _implication_queue.front().first;
}
int s_var = 0, s_var2;
bool done = false;
unsigned i, var_idx, sign;
CVariable * ptr;
for (i=_max_score_pos; i<_var_order.size(); ++i) {
var_idx = _var_order[i].first;
ptr = &(variables()[var_idx]);
if (ptr->value()==UNKNOWN) {
//move th max score position pointer
_max_score_pos = i;
//make some randomness happen
if (--_params.randomness < _params.base_randomness)
_params.randomness = _params.base_randomness;
int randomness = _params.randomness;
if (randomness >= num_free_variables())
randomness = num_free_variables() - 1;
int skip =random()%(1+randomness);
int index = i;
while (skip > 0) {
++index;
var_idx = _var_order[index].first;
ptr = &(variables()[var_idx]);
if (ptr->value()==UNKNOWN)
--skip;
}
assert (ptr->value() == UNKNOWN);
sign = ptr->score(0) > ptr->score(1) ? 0 : 1;
s_var = var_idx + var_idx + sign;
break;
}
}
if (s_var < 2) done = true;
if (_decision_hook) {
s_var2 = (*_decision_hook)(_decision_hook_cookie, &done);
if (done || s_var2 >= 2)
s_var = s_var2;
}
if (s_var<2) //no more free vars, solution found, quit
return false;
++dlevel();
if (_dlevel_hook) {
(*_dlevel_hook)(_dlevel_hook_cookie, 1);
}
if (dlevel() > _stats.max_dlevel) _stats.max_dlevel = dlevel();
CHECK (cout << "**Decision at Level " << dlevel() ;
cout <<": " << s_var << "\te.g. " << (s_var&0x1?"-":" ") ;
cout <<(s_var>>1) << endl; );
queue_implication(s_var, NULL_CLAUSE);
return true;
}
int CSolver::preprocess(bool allowNewClauses)
{
//1. detect all the unused variables
if (!allowNewClauses) {
vector<int> un_used;
for (int i=1, sz=variables().size(); i<sz; ++i) {
CVariable & v = variable(i);
if (v.lits_count(0) == 0 && v.lits_count(1) == 0) {
un_used.push_back(i);
v.value() = 1;
v.dlevel() = -1;
}
}
num_free_variables() -= un_used.size();
if (_params.verbosity>1 && un_used.size() > 0) {
cout << un_used.size()<< " Variables are defined but not used " << endl;
if (_params.verbosity > 2) {
for (unsigned i=0; i< un_used.size(); ++i)
cout << un_used[i] << " ";
cout << endl;
}
}
//2. detect all variables with only one phase occuring
vector<int> uni_phased;
for (int i=1, sz=variables().size(); i<sz; ++i) {
CVariable & v = variable(i);
if (v.value() != UNKNOWN)
continue;
if (v.lits_count(0) == 0){ //no positive phased lits.
queue_implication( i+i+1, NULL_CLAUSE);
uni_phased.push_back(-i);
}
else if (v.lits_count(1) == 0){ //no negative phased lits.
queue_implication( i+i, NULL_CLAUSE);
uni_phased.push_back(i);
}
}
if (_params.verbosity>1 && uni_phased.size() > 0) {
cout << uni_phased.size()<< " Variables only appear in one phase." << endl;
if (_params.verbosity > 2) {
for (unsigned i=0; i< uni_phased.size(); ++i)
cout << uni_phased[i] << " ";
cout <<endl;
}
}
}
//3. detect all the unit clauses
for (ClauseIdx i=0, sz=clauses().size(); i<sz; ++i) {
if (clause(i).num_lits() == 1){ //unit clause
queue_implication(find_unit_literal(i), i);
}
}
if(deduce()==CONFLICT) return CONFLICT;
return NO_CONFLICT;
}
void CSolver::real_solve(void)
{
while(1) {
run_periodic_functions();
if (decide_next_branch() || !_implication_queue.empty() ||
_conflicts.size() != 0) {
while (deduce()==CONFLICT) {
int blevel = analyze_conflicts();
if (blevel <= 0) {
_stats.outcome = UNSATISFIABLE;
return;
}
else if (_addedUnitClauses.size()) {
// reassert added unit clauses
unsigned idx = _addedUnitClauses.size()-1;
ClauseIdx cl = _addedUnitClauses.back();
int lit = find_unit_literal(cl);
while (lit != 0) {
queue_implication(lit, cl);
if (idx == 0) break;
cl = _addedUnitClauses[--idx];
lit = find_unit_literal(cl);
}
}
}
}
else {
_stats.outcome = SATISFIABLE;
return;
}
if (time_out()) {
_stats.outcome = TIME_OUT;
return;
}
if (_stats.is_mem_out) {
_stats.outcome = MEM_OUT;
return;
}
}
}
int CSolver::solve(bool allowNewClauses)
{
init();
//preprocess
if(preprocess(allowNewClauses)==CONFLICT) {
_stats.outcome = UNSATISFIABLE;
}
else { //the real search
if (_dlevel_hook) {
(*_dlevel_hook)(_dlevel_hook_cookie, 1);
}
real_solve();
}
_stats.finish_cpu_time = current_cpu_time();
_stats.finish_world_time = current_world_time();
return _stats.outcome;
}
int CSolver::continueCheck()
{
real_solve();
_stats.finish_cpu_time = current_cpu_time();
_stats.finish_world_time = current_world_time();
return _stats.outcome;
}
void CSolver::back_track(int blevel)
{
CHECK (cout << "Back track to " << blevel <<" ,currently in "<< dlevel() << " level" << endl;);
CHECK_FULL (dump());
CHECK(verify_integrity());
assert(blevel <= dlevel());
for (int i=dlevel(); i>= blevel; --i) {
vector<int> & assignments = *_assignment_stack[i];
for (int j=assignments.size()-1 ; j>=0; --j)
unset_var_value(assignments[j]>>1);
num_free_variables() += assignments.size();
assignments.clear();
if (_dlevel_hook) {
(*_dlevel_hook)(_dlevel_hook_cookie, -1);
}
}
dlevel() = blevel - 1;
++_stats.num_backtracks;
CHECK_FULL (dump());
CHECK(verify_integrity());
}
int CSolver::deduce(void)
{
restart:
while (!_implication_queue.empty() && _conflicts.size()==0) {
int literal = _implication_queue.front().first;
int variable_index = literal>>1;
ClauseIdx cl = _implication_queue.front().second;
_implication_queue.pop();
CVariable * the_var = &(variables()[variable_index]);
if ( the_var->value() == UNKNOWN) { // an implication
int dl;
if (_params.back_track_complete)
dl = dlevel();
else
dl = find_max_clause_dlevel(cl);
set_var_value(variable_index, !(literal&0x1), cl, dl);
the_var = &(variables()[variable_index]);
_assignment_stack[dl]->push_back(literal);
CHECK(verify_integrity());
}
else if (the_var->value() == (literal&0x1) ) { //a conflict
//note: literal & 0x1 == 1 means the literal is in negative phase
_conflicts.push_back(cl);
}
}
if (!_conflicts.size() && _deduction_hook) {
(*_deduction_hook)(_deduction_hook_cookie);
if (!_implication_queue.empty()) goto restart;
}
while(!_implication_queue.empty()) _implication_queue.pop();
return (_conflicts.size()?CONFLICT:NO_CONFLICT);
}
void CSolver::verify_integrity(void)
{
}
void CSolver::mark_vars_at_level(ClauseIdx cl, int var_idx, int dl)
{
for (CLitPoolElement * itr = clause(cl).literals(); (*itr).val() > 0 ; ++ itr) {
int v = (*itr).var_index();
if (v == var_idx)
continue;
else if (variable(v).dlevel() == dl) {
if (!variable(v).is_marked()) {
variable(v).set_marked();
++ _num_marked;
}
}
else {
assert (variable(v).dlevel() < dl);
if (variable(v).in_new_cl() == -1){ //it's not in the new cl
variable(v).set_in_new_cl((*itr).var_sign());
_conflict_lits.push_back((*itr).s_var());
}
}
}
}
int CSolver::analyze_conflicts(void) {
return conflict_analysis_zchaff();
}
int CSolver::conflict_analysis_zchaff (void)
{
assert (_conflicts.size());
assert (_implication_queue.empty());
assert (_num_marked == 0);
int back_level = 0;
ClauseIdx conflict_cl;
vector<ClauseIdx> added_conflict_clauses;
for (int i=0, sz=_conflicts.size(); i<sz; ++i) {
ClauseIdx cl = _conflicts[i];
if (!is_conflict(cl)) continue;
back_level = 0; // reset it
while (_conflict_lits.size()) {
CVariable & var = variable(_conflict_lits.back() >> 1);
_conflict_lits.pop_back();
assert (var.in_new_cl() != -1);
var.set_in_new_cl(-1);
}
int max_dlevel = find_max_clause_dlevel(cl); // find the max level, which is the back track level
bool first_time = true; //its the beginning
bool prev_is_uip = false;
mark_vars_at_level (cl, -1 /*var*/, max_dlevel);
vector <int> & assignments = *_assignment_stack[max_dlevel];
for (int j = assignments.size() - 1; j >= 0; --j ) { //now add conflict lits, and unassign vars
int assigned = assignments[j];
if (variable(assigned>>1).is_marked()) {
variable(assigned>>1).clear_marked();
-- _num_marked;
ClauseIdx ante_cl = variables()[assigned>>1].get_antecedence();
if ( (_num_marked == 0 &&
(!first_time) &&
(prev_is_uip == false))
|| ante_cl==NULL_CLAUSE) { //conclude add clause
assert (variable(assigned>>1).in_new_cl()==-1);
_conflict_lits.push_back(assigned^0x1); // add this assignment's reverse, e.g. UIP
int conflict_cl = add_clause(_conflict_lits, false);
if (conflict_cl < 0 ) {
_stats.is_mem_out = true;
_conflicts.clear();
assert (_implication_queue.empty());
return 1;
}
_conflict_lits.pop_back(); // remove for continue use of _conflict_lits
added_conflict_clauses.push_back(conflict_cl);
CHECK(cout <<"Conflict clause: " << cl << " : " << clause(cl) << endl;
cout << "**Add Clause " <<conflict_cl<< " : "<<clause(conflict_cl) << endl;
);
prev_is_uip = true;
break; //if do this, only one clause will be added.
}
else prev_is_uip = false;
if ( ante_cl != NULL_CLAUSE )
mark_vars_at_level(ante_cl, assigned>>1/*var*/, max_dlevel);
else
assert (j == 0);
first_time = false;
}
}
back_level = max_dlevel;
back_track(max_dlevel);
}
assert (_num_marked == 0);
if (back_level==0) //there are nothing to be done
return back_level;
if (_params.back_track_complete) {
for (unsigned i=0; i< added_conflict_clauses.size(); ++i) {
ClauseIdx cl = added_conflict_clauses[i];
if (find_unit_literal(cl)) { //i.e. if it's a unit clause
int dl = find_max_clause_dlevel(cl);
if (dl < dlevel()) { //thus make sure implied vars are at current dl.
back_track(dl+1);
}
}
}
}
for (int i=0, sz=added_conflict_clauses.size(); i<sz; ++i) {
conflict_cl = added_conflict_clauses[i];
int lit = find_unit_literal(conflict_cl);
if (lit) {
queue_implication(lit, conflict_cl);
}
}
_conflicts.clear();
while (_conflict_lits.size()) {
CVariable & var = variable(_conflict_lits.back() >> 1);
_conflict_lits.pop_back();
assert (var.in_new_cl() != -1);
var.set_in_new_cl(-1);
}
CHECK( dump_assignment_stack(););
CHECK(cout << "Conflict Analasis: conflict at level: " << back_level;
cout << " Assertion Clause is " << conflict_cl<< endl; );
return back_level;
}
syntax highlighted by Code2HTML, v. 0.9.1