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

📄 solver.cpp

📁 最快速的可满足性分析工具软件
💻 CPP
📖 第 1 页 / 共 2 页
字号:
      }//end if else relate==0,1,-1
      
    }
    
    //reset various fields.
    reason[v] = NULL;
    level[v] = 0;
    status[v] = 0;
    //put the variable back in the variable heap.
    undo(my_m->var_order_heap,v);      
  }//end main while loop
  
  my_m->assign_top = stack;
  my_m->decision_level = dest-1; //restore the decision level so that the next decision is made at level dest.  
}//end function backtrack

/*
 * Apply unit propagation to all literals currently on the assignment stack.
 * This function is intended to be called after we finish reading the input file.
 *
 * Return 1 iff a conflict is found.
 */
char process_unit_literal_queue()
{
  //check the implication queue to see if there is any enqueued implication.
  my_var v = dequeue(my_m->imp);

  if(v!=0){
    //if there is, call bcp.
    my_m->simplify_orig_kb = 1;
    my_m->simplify_learned_kb = 1;
    my_m->stack_offset--;
    int res = bcp(my_m->status[v]);    
    my_m->stack_offset = 0;
    return res;
  }
  
  //no enqueued implication, return 1.
  return 1;
}//end function process unit literal queue

/*
 * Perform unit propagation starting at the assignment of literal l.
 * Return 1 if no conflict arises, otherwise return 0.
 *
 * In case of conflict, call analyze_conflict before returning.
 */
char bcp(my_lit l)
{
  //last points to the most recent implication on the assignment stack.
  my_lit* last = my_m->assign_top;//第一次BCP之前始终为0,之后再是最近的
  int* level = my_m->level;
  my_lit* status = my_m->status;
  my_clause** reason = my_m->reason;
  my_clause*** watched = my_m->watched;
  int* watched_size = my_m->watched_size;  
  int slevel = level[var(l)];
  implication_queue* q = my_m->imp;
  
  //put this literal (l) into the priority queue 
  undo(q,var(l));

  *(last++) = l;

  status[var(l)] = l;
  
  //usually, stack_offset is 0. It could be > 0 only at the first call 
  //to bcp when we implications enqueued in the assignment stack (see process_unit_literal_queue).
  //stack_offset has compensated for *(last++) above
  last += my_m->stack_offset;

  my_var v;
  
  //keep dequeuing variable from the implication queue
  while((v=dequeue(q))!=0){//到680
    my_lit lit = status[v];
    my_lit neg_lit = neg(lit);
    int wi = watched_index(neg_lit); //wi is the array index of neg_lit
    //since neg_lit is now false, we need to traverse its watched list.
    
    //the watched list of neg_lit
    my_clause** watched_list = watched[wi];
    my_clause** pointer = watched_list;
    my_clause** end = watched_list+watched_size[wi];
    
    //for each clause in the watched list of neg_lit
    //find a new literal to watch
    while(watched_list<end){//到676

      my_clause* clause = *(watched_list++);
      my_lit* lits = clause->lits;

      my_lit first_lit = lits[1];
      
      //make sure that neg_lit is in the second position in the array,只对前两个lit进行监视
      if(first_lit!=neg_lit){
	lits[1] = lits[0];
	lits[0] = first_lit;		
      }
      
      if(set(lits[0])){//这个子句早就成立 了
	//this clause is already satisfied, skip it
	//put it in the same watched list (even though this current literal is already falsified!)	为什么不删除?    
	
	*(pointer++) = clause;
	continue;
      }
      
      int clause_size = clause->size;
	  
      //search for an un-falsified literal in lits[2...n]
      //note that if clause_size==2, then there is nothing to search.
      //the current clause is guaranteed to be either unit or empty.
      if(clause_size>2){//到617
	
	char found = 0;
	my_lit temp = lits[1];
	    
	int k = 2;
	for(;k<clause_size;k++){
	  my_lit temp2 = lits[k];
	  if(unresolved(temp2)){//统一只能前两个lit 监视出子句		
	    lits[1] = temp2;
	    lits[k] = temp;
	    //add this current clause to the watched list of the new found literal.
	    add_watched_clause(temp2,clause);//把这个clause移到temp2上去了
	    
	    found = 1;
	    break;
	  }
	}//end for k

	if(found){
	  //done with this clause, move on to the next clause
	  continue;
	}
	
      }//end if clause_size > 2
      
      //at this point, we know we could not find a new unresolved literal from lits[2..n]
      //(this is because alls of them are resolved or none of them even exits)
      //all we have to do now is check whether there is a conflict or not
      //basically, if lit[0] is free, we have a unit clause
      //if lit[0] is falsified, we have a contradiction!
	
      my_lit other_lit = lits[0];
      if(status[var(other_lit)]==neg(other_lit)){//到654
	
	//here, we must pop everything out of the queue
	//move stack_top to last
	//because every literal on the stack has a chance of participating in the conflict
	//[even if it is not yet processed]
	
	while((v=dequeue(q))!=0){
	}
	
	my_m->assign_top = last;
	
	//move the rest of neg_list watched clauses into their appropriate positions
	*(pointer++) = clause;
	while(watched_list<end){
	  *(pointer++) = *(watched_list++);
	}
	      
	watched_size[wi] -= watched_list-pointer;	//总数减去被别人监视的子句的所有子句包括已成立、有错误的、还unit子句
	
	//set the conflicting clause to this clause so
	//that we can later perform conflict analysis correctly.
	my_m->conflicting_clause = clause;

	assert(last==my_m->assign_top);	      
	
	return 0;	
      }else{//674
	
	//we have a unit implication in this case
	my_lit unit_lit = other_lit;
	my_var unit_var = var(unit_lit);
	    
	if(status[unit_var]==0) {
	  //this literal is implied for the first time
	  
	  reason[unit_var] = clause;	  
	  status[unit_var] = unit_lit;
	  level[unit_var] = slevel;

	  //put this unit variable into the implication queue
	  undo(q,unit_var);
	  *(last++) = unit_lit;
	  
	}//end if else unit for the first time
	    
	*(pointer++) = clause;
      }//end if else
	  
    }//end while more clauses in watched list of neg_lit		
    
    watched_size[wi] -= watched_list-pointer;//总数减去被别人监视的子句的所有子句包括已成立、有错误的、还unit子句

  }//end while more literal to process
  
  my_m->assign_top = last;
  return 1;
}//end function bcp

/*
 * Add the current conflict clause to the knowledge base
 * and apply unit propagation (call bcp) on it.
 * Return 0 iff unit propagation derives a conflict.
 *
 */
char assert_conflict_clause()
{
  if(my_m->vc>VC_THRESHOLD && my_m->decision_level<my_m->decision_lit_size/4){
    half_decision_lit_len();
  }
  
  my_clause* conflict_clause = my_m->conflict_clause;
  int size = conflict_clause->size;
  
  if(size>1){
    //Add this conflict clause to the knowledge base only if it is not unit.
    add_conflict_clause();
  }

  my_lit fuip = conflict_clause->lits[0];
  my_var fuip_var = var(fuip);
  my_m->level[fuip_var] = my_m->assertion_level;
  
  my_m->reason[fuip_var] = (size>1?conflict_clause:NULL);
  
  if(size==1){
    free(conflict_clause->lits);
    free(conflict_clause);
    my_m->conflict_clause = NULL;
    my_m->simplify_orig_kb = 1;
    my_m->simplify_learned_kb = 1;
  }

  my_m->score_inc *= my_m->score_inc_factor;
  my_m->clause_score_inc *= CLAUSE_SCORE_INC_FACTOR;    

  return bcp(fuip);
}//end function assert conflict clause

/*
 * Set literal l to true. Set this literal to be the decision literal of the level.
 * Propagate its effects (by calling bcp).
 * Returns 0 iff bcp can derive a conflict.
 *
 */
char set_decision(my_lit l) 
{
  if(my_m->decision_level > my_m->max_decision_level) {
    my_m->max_decision_level = my_m->decision_level;
  }

  int level = ++(my_m->decision_level);
  ++(my_m->decisions);  
  
  my_var v = var(l);
  my_m->level[v] = level;
  my_m->reason[v] = NULL;
  
  if(level>=my_m->decision_lit_size){
    double_decision_lit_len();
  }

  my_m->decision_lit[level] = my_m->assign_top;  

  return bcp(l);
}//end function set decision

/*
 * Return the free variable with the highest score.
 * Return 0 if no free variable remains.
 *
 */
my_var select_variable()
{

#if(USE_RANDOM_ORDER)
  double random_var_freq = 0.2;
  
  double r = (double)rand()/RAND_MAX;

  if(r < random_var_freq){
    my_var next = my_m->vc*((double)rand()/RAND_MAX)+1;
    if(my_m->level[next]==0){
      return next;
    }//end inner if
  }//end if
#endif

  heap* h = my_m->var_order_heap;

  while(!empty(h)){
    my_var next = get_min_element(h);   //this takes care of restructuring heap
    if(my_m->level[next]==0){
      //if this variable is free, return it
      
      return next;
    }//end if
  }//end while

  //no more free variable:SAT
  return 0;
}//end function select variable

/*
 * The main solving function.
 * Solve the SAT problem stored in the manager my_m.
 * Return 1 if SAT, 0 if UNSAT, and -1 if UNKNOWN (timeout).
 *
 * The idea is to keep making decisions until either a solution 
 * or a conflict is found. 
 * 
 * If a solution is found, return.
 * If a conflict is found, perform conflict analysis, backtrack, 
 * and apply bcp to the new cluase. This is repeated until no
 * conflict remains. Then the solver continue to the loop.
 * 
 */
int solve()
{
  start_time = clock();
  
  my_m->previous_decision_count = 0;
  my_m->previous_conflicts = 0;
  my_m->previous_reduce_kb_count = 0;
  my_m->previous_simplify_kb_count = 0;
  
  //we use the value of result to determine when to return from this function
  //result==-2 means that we have not found a solution.
  int result = -2;
    
  //this is the main loop. Each iteration is 1 decision
  while(1){        

    if(result==0){
      //UNSAT, break and return.
      break;
    }


    /******************************************
     *
     * Loop invariant: 
     * At this point of the loop, the 
     * solver state is closed under
     * unit resolution and is 1-consistent.
     * In other words, unit propagation
     * cannot derive any implication at
     * this point, and there is no 
     * conflict.
     * 
     * 
     * The next thing we do is to check whether 
     * it is time to restart or not, then we
     * check if it is time to manage the knowledge 
     * base or not (simplify, delete,...).
     * After all these, we pick a decision variable
     * and make a decision on it.
     *
     *******************************************/

#if(TIME_OUT)
    //rough implementation of timeout
    if(my_m->decisions%2000==0 && time_out>0){
      double elapsed = get_cpu_time();
      if(elapsed > time_out){
	backtrack(2);
	return -1;
      }
    }
#endif//endif time out

    if(my_m->conflicts>=my_m->next_restart_conflict){	
      //time to restart
      //note how we do not change the value of result (-2).
	
      print_progress();

      backtrack(2);

      my_m->restart++;

      int restart = my_m->restart;
      my_m->restart_conflict_incr = get_luby(restart+1);
      my_m->next_restart_conflict = my_m->conflicts + (int)my_m->restart_conflict_incr;
	
      simplify_original_kb();
    }//endif meet restart criteria

    if(my_m->simplify_learned_kb && my_m->decision_level==1 && my_m->conflicts >= my_m->num_conflicts_for_next_simplify){
      simplify_kb();
    }

    int num_assigned = (my_m->assign_top - my_m->assign);
      
    if(my_m->cur_cdc_count >= my_m->max_learned_clauses + num_assigned){
      reduce_kb();
    }

    /*****************************************************
     *
     * End checking restarting criteria and managing KB.
     *
     *****************************************************/
    
    //Jump directly to the label "pre_decision" if you want a clean way of bypassing the call to select_variable
    
    my_lit literal;
      
    //select a variable as the decision variable
    my_var dec_var = select_variable();
    
    if(dec_var==0){      
      //solution found!!
      result = 1;      	
      print_progress();
      
#if(VERIFY_SOLUTION)
      save_solution();
#endif
      print_progress_footer();
	
      if(my_m->print_mode==2){
	print_solution();
      }
	
      backtrack(2);
      break;
    }//endif solution found      
    
    //decide which phase of dec_var to try first
    if(my_m->saved[dec_var]==0 || !my_m->save_progress){	
      literal = nlit(dec_var);
    }else{	
      literal = my_m->saved[dec_var];
    }//end if else use saved phase or not
      
    //literal must be already set at this point!
    //pre_decision: //currently, this label is not used

    //make the decision
    char res = set_decision(literal);                
    //res is 1 if everything was okay, 0 if there was a conflict

    //deal with conflict, if any.
    while(res!=1){//948
      //at this point, the current state of the solver has a conflict.
      
      //analyze the conflict (derive conflict clause).
      analyze_conflict(my_m->conflicting_clause,my_m->decision_level);

      if(my_m->assertion_level==0){
	//UNSAT!
	result = 0;
	break;
      }
      
      //backtrack to the assertion level (erase upto assertion level+1)
      backtrack((my_m->assertion_level)+1);
      //assert the conflict clause
      res = assert_conflict_clause();
      //at this point of the program, we are done with the assertion (may have resulted in success or another conflict)
    }//end while conflict
      
    //at this point, we do not have a contradiction
    //in the current state.
      
  }//end while not time to restart or solution found
    
  //at this point, result is either 0 or 1.
  return result;

}//end function solve

⌨️ 快捷键说明

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