//frees the SatState void sat_state_free(SatState* sat_state) { for (c2dSize i = 1; i <= sat_var_count(sat_state); i++) { Var* var = sat_index2var(i, sat_state); vector_free(&var->mentions); vector_free(&var->mentions_lc); free(var); free(sat_index2literal(i, sat_state)); free(sat_index2literal(-i, sat_state)); } for (c2dSize i = 1; i <= sat_clause_count(sat_state); i++) { Clause* clause = sat_index2clause(i, sat_state); vector_free(&clause->lits); free(clause); } vector_free(&sat_state->vars); vector_free(&sat_state->plits); vector_free(&sat_state->nlits); vector_free(&sat_state->kb); vector_free(&sat_state->lc); vector_free(&sat_state->ds); vector_free(&sat_state->il); vector_free(&sat_state->q); vector_free(&sat_state->s); free(sat_state); }
/****************************************************************************** Two literal watch algorithm for unit resolution The algorithm taken from the Class Notes for CS264A, UCLA ******************************************************************************/ BOOLEAN two_literal_watch(SatState* sat_state, Lit** literals_list, unsigned long num_elements, unsigned long type){ // Once I entered here I must have elements in the decision array assert(sat_state->num_literals_in_decision > 0); // initialize the list of watched clauses already initialized in ParseDIMACS // if(!INIT_LITERAL_WATCH) // intitialize_watching_clauses(sat_state); BOOLEAN contradiction_flag = 0; //TODO: Due to recursion of pending list we may need to consider more than one decided literal then we need a list that captures all literals of last decision //loop on all decided literals // Lit** literals_in_decision = literals_list; // unsigned long max_size_decision_list = capacity; // unsigned long num_decision_lit = num_elements; // Create pending literal list Lit** pending_list = (Lit**)malloc(sizeof(Lit*)); unsigned long max_size_pending_list = 1; unsigned long num_pending_lit = 0; unsigned long initial_num_elements = num_elements; for(unsigned long i =0; i< num_elements; i++){ #ifdef DEBUG printf("--------------------------------------\n"); printf("Decision list now in two literal watch: "); for(unsigned long j =0; j< num_elements;j++){ printf("%ld\t", literals_list[j]->sindex ); } printf("\n"); #endif if(type == CASE1 && (sat_state->decisions[i]->decision_level != sat_state->current_decision_level)){ continue; // don't re-evaluate this literal }else if(type == CASE2 && sat_state->decisions[i]->decision_level != sat_state->current_decision_level){ continue; }else if(type == CASE2 && sat_state->decisions[i]->decision_level == sat_state->current_decision_level && i < initial_num_elements-1){ continue; } else{ //Lit* decided_literal = sat_state->decisions[sat_state->num_literals_in_decision -1]; Lit* decided_literal = literals_list[i]; Lit* resolved_literal = get_resolved_lit(decided_literal, sat_state); #ifdef DEBUG printf("Resolved Literal: %ld\n", resolved_literal->sindex); #endif //Update clauses state based on the decided literal sat_update_clauses_state(decided_literal , sat_state); //If no watching clauses on the resolved literal then do nothing and record the decision if(resolved_literal->num_watched_clauses == 0){ // The decided literal is already in the decision list so no need to record it again #ifdef DEBUG printf("Number of watching clause on literal %ld is %ld\n",resolved_literal->sindex,resolved_literal->num_watched_clauses ); #endif //wait for a new decision continue; } else{ //Get the watched clauses for the resolved literal for(unsigned long k = 0; k < resolved_literal->num_watched_clauses && contradiction_flag == 0; k++){ //check dirty flag if(resolved_literal->list_of_dirty_watched_clauses[k] == 0) continue; Clause* wclause = sat_index2clause( resolved_literal->list_of_watched_clauses[k], sat_state); //TODO: Check if this actually works to skip the subsumed clauses //TODO: Enhance: we can only get the watched clauses that are not subsumed to speed it up and to avoid checking the unit clause if(wclause->is_subsumed) continue; unsigned long num_free_literals = 0; // I have to check the other watched literal Lit* the_other_watched_literal = NULL; if(resolved_literal->sindex == wclause->L1->sindex) the_other_watched_literal = wclause->L2; else if(resolved_literal->sindex == wclause->L2->sindex) the_other_watched_literal = wclause->L1; // FIXME the_other_watched_literal is not always set by this point // but is being dereferenced in the loop below #ifdef DEBUG printf("Current watching clause = %ld\n", wclause->cindex); //printf("Before assertion, resolved literal %ld, wcluase 1 index=%ld, wclause 2 idx =%ld \n", resolved_literal->sindex, wclause->L1->sindex, wclause->L2->sindex ); //print_all_clauses(sat_state); #endif assert(the_other_watched_literal!=NULL); for(unsigned long l = 0; l < wclause->num_literals_in_clause; l++){ //check for not resolved literal = free or asserted if( !sat_is_resolved_literal(wclause->literals[l]) && wclause->literals[l]->sindex != the_other_watched_literal->sindex ) { num_free_literals++; } } if (num_free_literals == 0){ //3cases //contradiction --> everything is resolved //subsumed clause --> do nothing //implication --> free literal if(sat_is_resolved_literal(the_other_watched_literal)){ // all literal of the clause are resolved --> contradiction contradiction_flag = 1; #ifdef DEBUG printf("-------------Contradiction happens with clause: %ld in level: %ld\n",wclause->cindex, sat_state->current_decision_level); #endif sat_state->conflict_clause = wclause; break; //break from loop of watched clauses over this decided literal } else if(sat_is_asserted_literal(the_other_watched_literal)){ // we do nothing since this clause is subsumed wclause->is_subsumed = 1; contradiction_flag = 0; // just checking if I have to reassign the value in order to avoid the compilation optimization continue; } else if (the_other_watched_literal->LitState == 0){ // implication if(sat_literal_var(the_other_watched_literal)->antecedent == 0){ sat_literal_var(the_other_watched_literal)->antecedent = wclause->cindex; // remember the decision list is updated with the pending list so that's ok #ifdef DEBUG printf("free literal %ld\n",the_other_watched_literal->sindex); //print_clause(wclause); printf("Antecedent: \n"); print_clause(sat_index2clause(sat_literal_var(the_other_watched_literal)->antecedent, sat_state)); #endif add_literal_to_list(&pending_list, the_other_watched_literal , &max_size_pending_list, &num_pending_lit); #ifdef DEBUG printf("Add the free literal %ld to the pending list with antecedent %ld\n",the_other_watched_literal->sindex, (sat_literal_var(the_other_watched_literal)->antecedent) ); #endif continue; // go to the next clause } else { //this means I implied the opposite (contradiction) or the same literal again(redundancy) in another clause //TODO: first check if pending list contains the same literal, if yes then just continue to the next clause else contradiction BOOLEAN lit_is_already_in_pending = 0; for(unsigned long pendelem =0; pendelem<num_pending_lit; pendelem ++){ if (pending_list[pendelem]->sindex == the_other_watched_literal->sindex) lit_is_already_in_pending =1; } if(lit_is_already_in_pending == 1) continue; //go to the next clause else{ contradiction_flag= 1; #ifdef DEBUG printf("free literal %ld\n",the_other_watched_literal->sindex); printf("-------------Contradiction(opposite implication) happens with clause: %ld\n",wclause->cindex); #endif sat_state->conflict_clause = wclause; break; //break from loop of watched clauses over this decided literal } } } //end of the implication case } // end of the three cases else if (num_free_literals > 0) { // find another literal to watch that is free for(unsigned long z = 0; z < wclause->num_literals_in_clause; z++){ if((!sat_is_resolved_literal(wclause->literals[z])) && wclause->literals[z] != wclause->L1 && wclause->literals[z] != wclause->L2){ Lit* new_watched_lit = wclause->literals[z]; //remove_watching_clause(k, resolved_literal); resolved_literal->list_of_dirty_watched_clauses[k] = 0; //add the watching clause to the free literal add_watching_clause(wclause, new_watched_lit); assert(resolved_literal->sindex == wclause->L1->sindex || resolved_literal->sindex == wclause->L2->sindex ); // remove the resolved literal from the watch and update the clause watch list if(resolved_literal->sindex == wclause->L1->sindex) wclause->L1 = new_watched_lit; else if (resolved_literal->sindex == wclause->L2->sindex) wclause->L2 = new_watched_lit; break; } } } //end of else number of free literals > 0 } //end of for for watched clauses over this decided literal //SALMA removed and the contradiction !=1 if(num_pending_lit >0){ // Pass over the pending list and add the literals to the decision while maintaining the level for(unsigned long i =0; i < num_pending_lit; i++){ //evaluate the pending list to make sure we didn't miss a chance of contraction // if the contradiction flag is raised then the conflict clause is already set in this function //BOOLEAN fails = evaluate_delta(sat_state, pending_list, i+1); //up till this pending literal // pending literal was an already watched clause so the associated list of watching clauses is already handled // fix values of pending literal before putting in decision Lit* pending_lit = pending_list[i]; //TODO: the decision level should be the same as the max level of the antecedent not the current level. //pending_lit->decision_level = sat_state->current_decision_level; // this is so wrong ... this will affect the UIP learning at contradiction because of stopping condition unsigned long pending_lit_decision =0; Var* pending_var = sat_literal_var(pending_lit); Clause* pending_antecedent = sat_index2clause(pending_var->antecedent, sat_state); for(unsigned long indxant =0; indxant < pending_antecedent->num_literals_in_clause; indxant++ ){ Var* current_var = sat_literal_var(pending_antecedent->literals[indxant]); if(current_var->index == pending_var->index) continue; //skip the var else if(pending_antecedent->literals[indxant]->decision_level > pending_lit_decision) pending_lit_decision = pending_antecedent->literals[indxant]->decision_level; } pending_lit->decision_level = pending_lit_decision; //TODO: this part is already done in evaluate delta if(pending_lit->sindex <0){ pending_lit->LitValue = 0; pending_lit->LitState = 1; Lit* opposite_lit = sat_literal_var(pending_lit)->posLit; opposite_lit->LitValue = 0; opposite_lit->LitState = 1; opposite_lit->decision_level = pending_lit->decision_level; } else if(pending_lit->sindex >0){ pending_lit->LitValue = 1; pending_lit->LitState = 1; Lit* opposite_lit = sat_literal_var(pending_lit)->negLit; opposite_lit->LitValue = 1; opposite_lit->LitState = 1; opposite_lit->decision_level = pending_lit->decision_level; } // for(unsigned long i = 0; i< sat_literal_var(pending_lit)->num_of_clauses_of_variables; i++){ // Clause* clause = sat_literal_var(pending_lit)->list_clause_of_variables[i]; // // } //update the decision list sat_state->decisions[sat_state->num_literals_in_decision++] = pending_lit; //update list of literals in last decision because this is the main loop literals_list[num_elements++] = pending_lit; // if (fails == 1){ // contradiction_flag = 1; // break; // } } // //free pending list for the next round // if(pending_list != NULL && num_pending_lit != 0) // FREE(pending_list); } // pending_list > 1 }//Get the watched clauses for the resolved literal //free pending list for the next round //--> pending list is related to each decided literal. so before taking a new decision clear the pending list //double free or corruption (out): if(pending_list != NULL && num_pending_lit != 0){ //FREE(pending_list); // TODO: free pending list num_pending_lit = 0; } if(contradiction_flag == 1) // no need to go for another literal in the decided literal list break; }//end of for for decide literal } //TODO: This is so bad ... need to figure out why this sentence is executed even if I have a return when the contradiction happens //TODO: needs to find a way to clear the literals in last_decision // if(literals_in_last_decision != NULL && num_last_decision_lit !=0) // FREE(literals_in_last_decision); if(contradiction_flag == 1) return 0; else return 1; }
static BOOLEAN evaluate_current_assignment(SatState* sat_state, Lit** pending_list, unsigned long num_pending_lit){ #ifdef DEBUG printf("Evaluate the current assignment\n"); #endif BOOLEAN fails = 0; // just for the sake of this function but will be reset if contradiction happens for(unsigned long i =0; i<num_pending_lit; i++){ Lit* pending_lit = pending_list[i]; if(pending_lit->sindex <0){ pending_lit->LitValue = 0; pending_lit->LitState = 1; } else if(pending_lit->sindex >0){ pending_lit->LitValue = 1; pending_lit->LitState = 1; } } Lit** decisions = sat_state->decisions; //now I have the current decision and the pending list // instead of merging the two list in one list just pass by each one for(unsigned long i =0; i<sat_state->num_literals_in_decision; i++){ #ifdef DEBUG printf("In the decision literals loop: current literal %ld \n", decisions[i]->sindex); #endif Var* corresponding_var = sat_literal_var(decisions[i]); unsigned long* decision_clause_list = corresponding_var->list_clause_of_variables; for(unsigned long j=0; j<corresponding_var->num_of_clauses_of_variables; j++){ Clause* clause = sat_index2clause(decision_clause_list[j], sat_state); //check clause for(unsigned long k = 0; k<clause->num_literals_in_clause;k++){ //check if the literal is asserted or not yet set if(sat_is_asserted_literal(clause->literals[k]) || (!sat_implied_literal(clause->literals[k]) )){ break; //don't check the other literals of the clause } else if(k== clause->num_literals_in_clause-1){ // I reached the end of the loop with no break (contradicted clause) fails = 1; sat_state->conflict_clause = clause; // reset the pending list for(unsigned long i =0; i<num_pending_lit; i++){ Lit* pending_lit = pending_list[i]; pending_lit->LitValue = 'u'; pending_lit->LitState = 0; } return fails; } } // for all literals in a clause } // for all clauses for this variable }// for all variables in decision list //repeat the same for pending list for(unsigned long i =0; i< num_pending_lit; i++){ #ifdef DEBUG printf("In the pending literals loop: current literal %ld \n", pending_list[i]->sindex); #endif Var* corresponding_var = sat_literal_var(pending_list[i]); unsigned long* pending_clause_list = corresponding_var->list_clause_of_variables; for(unsigned long j=0; j<corresponding_var->num_of_clauses_of_variables; j++){ Clause* clause = sat_index2clause(pending_clause_list[j], sat_state); //check clause for(unsigned long k = 0; k<clause->num_literals_in_clause;k++){ //check if the literal is asserted or not yet set if(sat_is_asserted_literal(clause->literals[k]) || (!sat_implied_literal(clause->literals[k]) )){ break; //don't check the other literals of the clause } else if(k== clause->num_literals_in_clause-1){ // I reached the end of the loop with no break (contradicted clause) fails = 1; sat_state->conflict_clause = clause; // reset the pending list for(unsigned long i =0; i<num_pending_lit; i++){ Lit* pending_lit = pending_list[i]; pending_lit->LitValue = 'u'; pending_lit->LitState = 0; } return fails; } } // for all literals in a clause } // for all clauses for this variable }// for all variables in pending list //TODO: check do i have to unset all the literals in the pending list #ifdef DEBUG if(fails == 1){ printf("Contradiction happens in evaluating clauses in the pending list\n"); } #endif return fails; }
//constructs a SatState from an input cnf file SatState* sat_state_new(const char* file_name) { FILE *file; if (!(file = fopen(file_name, "r"))) return NULL; SatState *sat_state = malloc(sizeof(SatState)); while (!feof(file)) { if (fgetc(file) == 'p') break; while (fgetc(file) != '\n') continue; } fscanf(file, " cnf %lu %lu", &sat_state->varnum, &sat_state->clausenum); vector_init(&sat_state->vars); vector_init(&sat_state->plits); vector_init(&sat_state->nlits); vector_init(&sat_state->kb); vector_init(&sat_state->lc); vector_init(&sat_state->ds); vector_init(&sat_state->il); vector_init(&sat_state->q); vector_init(&sat_state->s); sat_state->ac = NULL; for (c2dSize i = 1; i <= sat_var_count(sat_state); i++) { Var* var = malloc(sizeof(Var)); var->index = i; var->mark = 0; vector_init(&var->mentions); vector_init(&var->mentions_lc); Lit* plit = malloc(sizeof(Lit)); plit->index = i; plit->implied = 0; plit->var = var; Lit* nlit = malloc(sizeof(Lit)); nlit->index = -i; nlit->implied = 0; nlit->var = var; vector_push(&sat_state->plits, plit); vector_push(&sat_state->nlits, nlit); var->plit = plit; var->nlit = nlit; vector_push(&sat_state->vars, var); } for (c2dSize i = 1; i <= sat_clause_count(sat_state); i++) { Clause* clause = malloc(sizeof(Clause)); clause->index = i; clause->subsumed = 0; clause->mark = 0; vector_init(&clause->lits); while (1) { c2dLiteral index; while (!fscanf(file, "%ld", &index) || (index == 0 && vector_size(&clause->lits) == 0)) { while (fgetc(file) != '\n') continue; } if (index == 0) break; vector_push(&clause->lits, sat_index2literal(index, sat_state)); } vector_push(&sat_state->kb, clause); vector_push(&sat_state->q, clause); } for (c2dSize i = 1; i <= sat_clause_count(sat_state); i++) { Clause* clause = sat_index2clause(i, sat_state); for (c2dSize j = 0; j < sat_clause_size(clause); j++) { Lit* lit = vector_get(&clause->lits, j); Var* var = sat_literal_var(lit); if (vector_size(&var->mentions) == 0 || vector_top(&var->mentions) != clause) vector_push(&var->mentions, clause); } } fclose(file); return sat_state; }
//applies unit resolution to the cnf of sat state //returns 1 if unit resolution succeeds, 0 if it finds a contradiction BOOLEAN sat_unit_resolution(SatState* sat_state) { Lit* ret_lit; Var* var; c2dLiteral tmp_value; Clause* conflict_clause = NULL; c2dSize f = 0, r = 0; Lit** tmp_lit_list = sat_state->tmp_lit_list; // Push the new decided literal if (sat_state->unit_resolution_s == UNIT_RESOLUTION_AFTER_DECIDING_LITERAL) { if (sat_state->num_decided_literals > 0) { tmp_lit_list[++r] = sat_state->decided_literals[sat_state->num_decided_literals-1]; } if (sat_state->num_implied_literals > 0) { c2dSize i = sat_state->num_implied_literals - 1; while (sat_state->implied_literals[i]->decision_level == sat_state->cur_level) { tmp_lit_list[++r] = sat_state->implied_literals[i]; if (i == 0) break; i--; } } } // Check whether has unit clause c2dSize start_clauses = 1; if (sat_state->unit_resolution_s == UNIT_RESOLUTION_AFTER_ASSERTING_CLAUSE) start_clauses = sat_state->num_cnf_clauses + sat_state->num_learned_clauses; if (sat_state->unit_resolution_s == UNIT_RESOLUTION_AFTER_DECIDING_LITERAL) start_clauses = sat_state->num_cnf_clauses + sat_state->num_learned_clauses + 1; for (c2dSize i = start_clauses; i <= sat_state->num_cnf_clauses + sat_state->num_learned_clauses; i++) { Clause* clause = sat_index2clause(i, sat_state); tmp_value = check_clause(clause, &ret_lit); if (tmp_value == -1) { conflict_clause = clause; break; } if (tmp_value == 2) { instantiate_literal(ret_lit, sat_state->cur_level, clause); sat_state->implied_literals[sat_state->num_implied_literals++] = ret_lit; tmp_lit_list[++r] = ret_lit; } } if (conflict_clause == NULL) { // BFS, expands the implied literals while (f < r) { var = sat_literal_var(tmp_lit_list[++f]); for (c2dSize i = 0; i < var->num_clauses; i++) { tmp_value = check_clause(var->clauses[i], &ret_lit); if (tmp_value == -1) { conflict_clause = var->clauses[i]; break; } if (tmp_value == 2) { instantiate_literal(ret_lit, sat_state->cur_level, var->clauses[i]); sat_state->implied_literals[sat_state->num_implied_literals++] = ret_lit; tmp_lit_list[++r] = ret_lit; } } } } if (conflict_clause == NULL) { // No conflict sat_state->asserted_clause = NULL; return 1; } // Has conflict, derives asserted clause // // It follows the algorithm: // // In implication graph, if the contradition happended at node n. // then // { {n} if n is root // C(n) = { // { ePa(n) \union \union_{m \in Pa(n)} C(m) // where Pa(n) are the parents of node n which are set at the same level as n // ePa(n) are the parents of ndoe n set at earlier levels // BOOLEAN* seen = sat_state->seen; for (c2dSize i = 1; i <= sat_state->num_vars; i++) seen[i] = 0; Lit** lit_list = sat_state->lit_list; c2dSize lit_list_sz = 0; f = 0, r = 0; for (c2dSize i = 0; i < conflict_clause->size; i++) { if (!seen[conflict_clause->literals[i]->var->index]) { tmp_lit_list[++r] = conflict_clause->literals[i]->op_lit; seen[conflict_clause->literals[i]->var->index] = 1; } } c2dSize assertion_level = 1; c2dSize dl; while (f < r) { Lit* lit = tmp_lit_list[++f]; if (lit->decision_level < sat_state->cur_level || lit->decision_clause == NULL) { lit_list[lit_list_sz++] = lit->op_lit; dl = lit->decision_level; if (dl < sat_state->cur_level && dl > assertion_level) { assertion_level = dl; } } else { for (c2dSize i = 0; i < lit->decision_clause->size; i++) { if (!seen[lit->decision_clause->literals[i]->var->index]) { tmp_lit_list[++r] = lit->decision_clause->literals[i]->op_lit; seen[lit->decision_clause->literals[i]->var->index] = 1; } } } } sat_state->asserted_clause = new_clause(0, lit_list_sz, lit_list); sat_state->asserted_clause->assertion_level = assertion_level; return 0; }