⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 solver.cpp

📁 最快速的可满足性分析工具软件
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/* 
 * solver.cpp: The file that contains all the core functions for a SAT solver.
 * We intend to make this file as self-contained as possible including any 
 * low-level function that are unnecessary to the main execution flow.
 * 
 * The following functions are in this file:
 * - solve (the main solving function)
 * - select_variable
 * - set_decision
 * - bcp (unit propagation)
 * - backtrack
 * - analyze_conflict 
 * - derive_conflict_clause
 * - removable (helper for derive_conflict_clause)
 * - assert_conflict_clause
 * - get_luby (for restarting)
 * - process_unit_literal_queue
 *
 */
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <assert.h>
#include <math.h>

#include "flags.h"
#include "structures.h"
#include "constants.h"

extern my_manager* my_m;
clock_t start_time,end_time;

#if(TIME_OUT)
extern double time_out;  //time out limit
extern clock_t start_t;  //the starting time of the solver
#endif

/*
 * Return the ith number of the luby sequence.
 * This function is called to determine the restarting schedule.
 *
 */
int get_luby(int i)
{
  if(i==1){return my_m->luby_unit;}  
  double k = log2(i+1);
  
  if(k==round(k)){
    return (int)(pow(2,k-1))*my_m->luby_unit;
  }else{
    k = (int)floor(k);
    return get_luby(i-(int)pow(2,k)+1);
  }
}//end function get luby

/*
 * Helper function for derive_conflict_clause.
 * Used to perform conflict clause minimization.
 * Return 1 if literal l can be removed from the current
 * conflict clause (in cdc) without introducing any new
 * literal.
 *
 * minl is a simple hash function which could quickly tell
 * us that l cannot be removed.
 * 
 *
 * stack contains the literals yet to be resolved away.
 * save contains the indices of variables on the stack.
 *
 * The main idea for this function is the keep resolving away literals 
 * on the stack until none is left. If at the end of the process,
 * no new literal is introduced, the literal can be removed.
 * Otherwise, the literal cannot be removed.
 *
 * This process of conflict minimization is really a partial implementation
 * of the AllUIP approach. We perform additional resolutions on all literals 
 * at lower level of see if the contribution from each level can be represented
 * with fewer literals or not.
 */
inline char removable(my_lit l,unsigned int minl)
{  
  //this seen array currently contains a 1-flag for each literal in the conflict clause.
  char* seen = my_m->seen;
  my_lit* stack = my_m->stack;
  int stack_index = 0;
  int stack_size = my_m->stack_size;
  int* save = my_m->save;
  int save_size = my_m->save_size;
  int size = 0;
  my_clause** reasons = my_m->reason;
  int* levels = my_m->level;
  
  //initially, the stack contains only the literal in question
  stack[stack_index++] = l;
  
  //main while loop
  //loop until all literals on the stack have been resolved away.
  while(stack_index>0){
    stack_index--;
    
    //pop a literal from the stack
    my_lit cur = stack[stack_index];
    my_var cur_v = var(cur);
    //inspect its reason
    my_clause* reason = reasons[cur_v];

    my_lit* lits = reason->lits;
    int rsize = reason->size;    
    int begin = 1;//是否因为第一个是要考察的literal 本身?

    //for each literal in the reason
    for(int i=begin;i<rsize;i++){     
      my_lit cur_lit = lits[i];
      my_var index = var(cur_lit); //the variable index of this literal
      int level = levels[index];

      //if seen[index]==1, this literal already involved in the conflict analysis. 
      //if seen[index]==0, this literal is not in the conflict. But, perhaps, all its antecedents are involved. We need to keep on looking.

      if(!seen[index]&& level != 1){

	//At this point, we know this literal is not directly in the conflict analysis (because seen is 0).
	//Here we check if this literal's antecedents are all be involved in the conflict analysis.
	//if this literal is a decision literal (the else case below), too bad. It does not even have any antecedent. Return false.
	//if (1<< (this literal's level)) & minl == 0 (also the else case), it means (guarantees) no literal of the level were present in the conflict analysis.
	//this just implies that this current literal (cur_lit) can never satisfy the condition above, return false.	
	//otherwise, this literal MAY have all antecedent present in the conflict analysis, push it on the stack for further inspection.
	if( (reasons[index]!=NULL) && ((1<< (level)) & minl)){
	  //this literal is promising, push it on the stack and remember it in save array.
	  seen[index] = 1;
	  
	  if(stack_index>=stack_size){
	    double_stack_len();
	    stack_size = my_m->stack_size;
	    stack = my_m->stack;
	  }

	  if(size>=save_size){
	    double_save_len();
	    save_size = my_m->save_size;
	    save = my_m->save;
	  }

	  stack[stack_index++] = cur_lit;
	  save[size++] = index;
	}else{
	  //this literal, l, is NOT removable
	  //since l is not removable, we need to clean up all the seen entries
	  //that we set in this function call.
	  for(int j=0;j<size;j++){
	    seen[save[j]] = 0;
	  }

	  return 0;
	}//end if else

      }//end if !seen
    }//end for i
  }//end while
  
  //at this point, the literal l can be removed from the conflict clause.
  //Note how we do not clean up the seen array in this case. This is because
  //we know all those set entries have antecedents that meet the removing criteria.
  //We can simply remember this information so that future calls to this function
  //have a chance to do less work.

  return 1;
}//end function removable

/*
 * Derive an asserting conflict clause.
 * conf is the conflicting clause.
 * clevel is the level of the conflict.
 * *alevel must be set to the assertion level upon return.
 *
 * The idea is to keep resolving literals (at clevel) that are involved in 
 * the conflict by their reasons until we only have 1 literal 
 * at the level of the conflict left.
 *
 */
int derive_conflict_clause(my_clause* conf,int clevel,int* alevel)
{
  //number of literals at clevel.
  int num_lits_at_clevel = 0;
  my_lit next_lit = 0;
  my_lit* next_on_stack = my_m->assign_top;
  
  my_m->seen = (char*)calloc(my_m->vc+1,sizeof(char));//记录已经分析过的变量
  char* seen = my_m->seen;

  int assertion_level = 1;
  my_m->assertion_level = 1;
  
  my_m->cdc_index = 0;  
  my_lit* cdc = my_m->cdc;
  int cdc_size = my_m->cdc_size;
  
  int* levels = my_m->level;
  my_clause** reasons = my_m->reason;

  //save a place for the asserted literal. We will fill this spot later.
  cdc[my_m->cdc_index++] = 0;
  
  if(clevel<=1){
    //conflict is fatal, because it occurs at level 1 (top)    
    cdc[0] = 0;
    cdc[1] = 0;
    free(my_m->seen);
    my_m->seen = NULL;

    *alevel = 0;

    return 0;
  }

  //as long as we have more literals to resolve
  do{//到311 num_lits_at_clevel>0

    //debugging code
    if(conf==NULL){      
      print_location();
      printf("Inside derive conflict clause [%"i64d"]\n",my_m->conflicts);
      printf("Reason of literal [%d] is NULL\n",lit_index(next_lit));
      printf("Decision literal of level %d is [%d], # lits at clevel = %d\n",clevel,lit_index(*(my_m->decision_lit[clevel])),num_lits_at_clevel);
      exit(0);
    }
    
    int size = conf->size;			
    my_lit* lits = conf->lits;    
    int begin = (next_lit==0?0:1);
    
    //usually, we want to skip the first literal in the clause because
    //it is the literal we are resolving on. The only exception is the very first clause.
    for(int i=begin;i<size;i++){//到274
    
      //for each literal in clause conf
      //inspect each literal and decide whether
      //1) to put it in the learned clause OR
      //2) to resolve on it in the future
      my_lit cur_lit = lits[i];      
      int index = var(cur_lit); //variable index of the current literal
      int level = levels[index];
      
      //we can skip this literal if
      // 1) we have seen it before
      // 2) it is falsified at level 1 (we can always resolve away such literal by our top-level implication)
      if(!seen[index] && (level > 1)){//274
	//if we have not seen this variable
	//mark it seen and increase its score
	seen[index] = 1;
	increment_literal_score(cur_lit);  //increase scores of those involve in the conflict
	
	//there are 2 possible actions here
	// 1) if the literal is falsified at clevel, we must keep on resolving it.
	//    In this case, just increment num_lits_at_clevel is enough.
	// 2) if the literal is falsified at a lower level, we must add it to the conflict clause.
	if(level==clevel){
	  //this literal's value was set at clevel
	  num_lits_at_clevel++;

	}else{
	  //this literal's value was set before clevel
	  //add it to the conflict clause	
	  if(my_m->cdc_index>=cdc_size){
	    double_cdc_len();
	    cdc_size = my_m->cdc_size;
	    cdc = my_m->cdc;
	  }
	  
	  //put it in the cdc array
	  cdc[my_m->cdc_index++] = cur_lit;
	  
	}//end if else
      }//end if seen
    }//end for i
    //finish inspecting the current clause
    
    //now, we must find the next variable on stack that is involved in this conflict.
    //a variable is involved if it's seen entry is set to 1.
    while(1){
      next_on_stack--;
      assert(next_on_stack>=my_m->assign);

      int index = var(*next_on_stack);
      
      if(seen[index]){
	break;
      }
    }//end while 1
    
    next_lit = *next_on_stack;      //next_lit is now the next literal in the stack that is involved in the conflict
    my_var next_var = var(next_lit);
    seen[next_var] = 0;  //mark next_lit not seen, because we exclude it from the learned clause
    num_lits_at_clevel--; //coz we just expanded on next_lit
        
    //set conf to be the reason of next_lit
    if(reasons[next_var]!=NULL){
      conf = reasons[next_var];

      if(conf->index>=0){
	//only bump the activity of those clauses learned
	increment_clause_score(conf);
      }

    }else{
      //this should happen only if num_lits_at_clevel==0
      //we should be out of the loop next
      conf = NULL;
    }

  }while(num_lits_at_clevel>0);

  //now, we can put the asserted literal in the first position of the conflict clause.
  cdc[0] = neg(next_lit);
  seen[var(next_lit)] = 1;

  //end main conflict clause derivation
  
  
  //begin conflict clause mininimization
  int size = my_m->cdc_index;
  int i=size,j=size;

  unsigned int minl = 0;

  //first, compute a hash value for the literals in the cdc array
  //The ith bit of minl is 1 if some literal in the cdc array is falsified
  //at a level L such that l%32 == i.
  for (i = 1; i<size; i++){
    my_lit cur = cdc[i];
    int level = levels[var(cur)];
    minl |= 1 << (level & 31);       
  } 

  int start = 1;
  
  for (i = j = start; i < size; i++){
    my_lit cur = cdc[i];
    my_var cur_v = var(cur);
    
    //only retain this literal if either it is a decision literal or if it cannot be removed.
    //otherwise, we skip it (nothing to do in this case).
    if((reasons[cur_v]==NULL) || !removable(cur,minl)){
      int level = levels[cur_v];
      
      if(level>assertion_level){ 
	assertion_level = level; 
      }
      
      cdc[j++] = cdc[i];
    }
  }//end for i=j=X

  *alevel = assertion_level;  

  int final_size = size-(i-j);
  
  free(seen);
  my_m->seen = NULL;

  //i-j is the number of literals in the conflict clause skipped by the minimization step
  return final_size; //return the size of the conflict clause

}//end derive_conflict_clause

/*
 * Analyze the current conflict (from conflicting_clause) at clevel.
 * At the end, set my_m->conflict_clause to the derived conflict clause
 * and set my_m->assertion_level to the corresponding assertion level 
 * and set my_m->conflict_level to be clevel.
 * 
 * Another side-effect of this is to determine whether to turn progress saving
 * on or off. This is determined based on the value of my_m->next_sp_switch.
 */
void analyze_conflict(my_clause* conflicting_clause,int clevel)
{
  //control progress saving here.
  if(my_m->conflicts>=my_m->next_sp_switch){
    //flip the status of save_progress
    my_m->save_progress = 1-my_m->save_progress;
        
    //update threshold values
    int inc = 0;
    if(my_m->save_progress){
      //OFF==>ON
      my_m->on_th += my_m->on_th_inc;    
      inc = my_m->off_th;
    }else{
      //ON==>OFF
      my_m->off_th += my_m->off_th_inc;
      inc = my_m->on_th;
    }
    
    //schedule the next switch
    my_m->next_sp_switch += inc;
  }
  //done switching progress saving

  //begin conflict analysis
  
  my_m->conflict_level = clevel;
  ++my_m->conflicts;

  int assertion_level = 0;
  
  //derive an asserting conflict clause
  int size = derive_conflict_clause(conflicting_clause,clevel,&assertion_level);
  my_m->assertion_level = assertion_level;

  if(size>0){
    //a normal conflict clause
    //put it in a clause structure, initialize it and return.
    my_clause* conflict_clause = (my_clause*)calloc(1,sizeof(my_clause));
    my_lit* lits = (my_lit*)calloc(size,sizeof(my_lit));
    my_lit* cdc = my_m->cdc;
    
      
    for(int i=0;i<size;i++){
      lits[i] = cdc[i];
    }
    
    conflict_clause->size = size;
    conflict_clause->index = 1;
    conflict_clause->lits = lits;
    
    my_m->conflict_clause = conflict_clause;           
  }else{
    //size==0, this problem is UNSAT.
    //set assertion level to 0, the main solving function will take care of this.
    my_m->assertion_level=0;
    my_m->conflict_clause = NULL;
  }
  
}//end function analyze_conflict

/* 
 * Undo all literals at level above and including level.
 * After returning from this function, the decision level 
 * should be dest-1. Hence, the subsequent decision will be
 * made at level dest--the last level erased.
 * 
 */
void backtrack(int dest)
{
  //check this, otherwise, erase level will erase assignments of previous levels
  if(my_m->decision_level<dest){
    //this may happen if the solver tries to restart while at level 1 (top).
    return;
  }
  
  my_lit* target = my_m->decision_lit[dest];
  my_lit* stack = my_m->assign_top;
  int* level = my_m->level;
  my_lit* status = my_m->status;
  my_clause** reason = my_m->reason;
  my_lit* saved = my_m->saved;
  
  //for each assignment on the stack down to level dest.
  while(stack>target){

    stack--;
    my_lit l = *(stack);   
    my_var v = var(l);
    
    if(my_m->save_progress==1){
      //consider saving progress
      char relate = 0; 
      //even though by default, we save all assignments,
      //it is possible to be more selective in what we save.
      
      if(relate==0){
	//save progress
	saved[v] = l;
	
      }else if(relate==1){
	saved[v] = 0;
	
      }else if(relate==-1){
	//flip
	saved[v] = neg(l);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -