/* * FIXME in lazy version, we need to consider the clauses that would be * activated and becoming unsat if the variable is flipped. The dcost computed * by the current code is an underestimate */ void cost_flip_unfixed_variable(samp_table_t *table, int32_t var, int32_t *dcost) { rule_inst_table_t *rule_inst_table = &table->rule_inst_table; atom_table_t *atom_table = &table->atom_table; samp_literal_t plit, nlit; uint32_t i; if (assigned_true(atom_table->assignment[var])) { nlit = neg_lit(var); plit = pos_lit(var); } else { nlit = pos_lit(var); plit = neg_lit(var); } *dcost = 0; samp_clause_t *ptr; samp_clause_t *cls; /* add the number of the watched clauses that will be flipped */ for (ptr = rule_inst_table->watched[plit].head; ptr != rule_inst_table->watched[plit].tail; ptr = next_clause_ptr(ptr)) { cls = ptr->link; i = 0; while (i < cls->num_lits && (cls->disjunct[i] == plit || assigned_false_lit(atom_table->assignment, cls->disjunct[i]))) { i++; } if (i == cls->num_lits) { *dcost += 1; } } /* subtract the number of the unsatisfied clauses that can be flipped */ for (ptr = rule_inst_table->unsat_clauses.head; ptr != rule_inst_table->unsat_clauses.tail; ptr = next_clause_ptr(ptr)) { cls = ptr->link; i = 0; while (i < cls->num_lits && cls->disjunct[i] != nlit) { assert(cls->disjunct[i] != plit); i++; } if (i < cls->num_lits) { *dcost -= 1; } } }
void init_live_clauses(samp_table_t *table) { rule_inst_table_t *rule_inst_table = &table->rule_inst_table; atom_table_t *atom_table = &table->atom_table; int32_t i, j; for (i = 0; i < atom_table->num_vars; i++) { empty_clause_list(&rule_inst_table->watched[pos_lit(i)]); empty_clause_list(&rule_inst_table->watched[neg_lit(i)]); } for (i = 0; i < rule_inst_table->num_rule_insts; i++) empty_clause_list(&rule_inst_table->rule_watched[i]); empty_clause_list(&rule_inst_table->sat_clauses); empty_clause_list(&rule_inst_table->unsat_clauses); empty_clause_list(&rule_inst_table->live_clauses); for (i = 0; i < rule_inst_table->num_rule_insts; i++) { if (assigned_true(rule_inst_table->assignment[i])) { rule_inst_t *rinst = rule_inst_table->rule_insts[i]; for (j = 0; j < rinst->num_clauses; j++) { clause_list_insert_tail(rinst->conjunct[j], &rule_inst_table->live_clauses); } } } }
/* * Try to set the value of an atom. * * If the atom has a non-fixed value and is set to a fixed value, run * unit_propagation...; * If the atom has a non-fixed value and is set to the opposite non-fixed value, * just change the value (and change the state of the relavent clauses?) */ static int32_t update_atom_tval(int32_t var, samp_truth_value_t tval, samp_table_t *table) { pred_table_t *pred_table = &table->pred_table; atom_table_t *atom_table = &table->atom_table; samp_atom_t *atom = atom_table->atom[var]; pred_entry_t *pred_entry = get_pred_entry(pred_table, atom->pred); /* * Case 0: If the atom has been fixed, check if consistent: if it is * assigned to the opposite value, return inconsistency; otherwise do * nothing; */ samp_truth_value_t old_tval = atom_table->assignment[var]; if (!unfixed_tval(old_tval)) { if ((assigned_true(old_tval) && assigned_false(tval)) || (assigned_false(old_tval) && assigned_true(tval))) { mcsat_err("[update_atom_tval] Assigning a conflict truth value. No model exists.\n"); return -1; } else { return 0; } } #if USE_PTHREADS /* Internally, this is now theoretically protected with a mutex, but do we really want a multithreaded mcmc to be waiting for mutexes? */ #else /* Something's still bad here. For now, we ignore this code block if we are compiled for pthreads */ char *var_str = var_string(var, table); cprintf(3, "[update_atom_tval] Setting the value of %s to %s\n", var_str, samp_truth_value_string(tval)); free(var_str); #endif /* Not case 0: update the value */ atom_table->assignment[var] = tval; if (fixed_tval(tval)) { /* If fixed, this can break a later assertion that there are no fixed vars. Why? */ atom_table->num_unfixed_vars--; } /* Case 1: If the value just gets fixed but not changed, we are done. */ if (old_tval == unfix_tval(tval)) { return 0; } /* Case 2: the value has changed */ if (assigned_true(tval)) { link_propagate(table, neg_lit(var)); } else { link_propagate(table, pos_lit(var)); } //assert(valid_table(table)); /* If the atom is inactive AND the value is non-default, activate the atom. */ if (lazy_mcsat() && !atom_table->active[var] && assigned_false(tval) == pred_default_value(pred_entry)) { activate_atom(table, var); } //assert(valid_table(table)); samp_truth_value_t new_tval = atom_table->assignment[var]; assert(new_tval == tval || (fixed_tval(new_tval) && tval == unfix_tval(negate_tval(new_tval)))); /* * WARNING: in lazy mcsat, when we activate a new clause, it may force the * value of the atom being activated to be the nagation of the value we * intend to assign. E.g., when we want to set p(A) to v_true, and * activated (and kept alive of) the clause ~p(A) or q(B), where q(B) is * fixed to false (either by database or unit propagation), then p(A) has * to change back to v_fixed_false. */ if (new_tval != tval) return -1; return 0; }
/* * Validate all the lists in the clause table */ bool valid_rule_inst_table(rule_inst_table_t *rule_inst_table, atom_table_t *atom_table){ samp_clause_t *ptr; samp_clause_t *cls; int32_t lit, i; assert(rule_inst_table->size >= 0); assert(rule_inst_table->num_rule_insts >= 0); assert(rule_inst_table->num_rule_insts <= rule_inst_table->size); if (rule_inst_table->size < 0) return false; if (rule_inst_table->num_rule_insts < 0 || rule_inst_table->num_rule_insts > rule_inst_table->size) return false; /* check that every clause in the unsat list is unsat */ valid_clause_list(&rule_inst_table->unsat_clauses); for (ptr = rule_inst_table->unsat_clauses.head; ptr != rule_inst_table->unsat_clauses.tail; ptr = next_clause_ptr(ptr)) { cls = ptr->link; assert(eval_clause(atom_table->assignment, cls) == -1); if (eval_clause(atom_table->assignment, cls) != -1) return false; } ///* check negative_or_unit_clauses */ //valid_clause_list(&rule_inst_table->negative_or_unit_clauses); //for (ptr = rule_inst_table->negative_or_unit_clauses.head; // ptr != rule_inst_table->negative_or_unit_clauses.tail; // ptr = next_clause_ptr(ptr)) { // cls = ptr->link; // assert(cls->weight < 0 || cls->numlits == 1); // if (cls->weight >= 0 && cls->numlits != 1) // return false; //} ///* check dead_negative_or_unit_clauses */ //valid_clause_list(&rule_inst_table->dead_negative_or_unit_clauses); //for (ptr = rule_inst_table->dead_negative_or_unit_clauses.head; // ptr != rule_inst_table->dead_negative_or_unit_clauses.tail; // ptr = next_clause_ptr(ptr)) { // cls = ptr->link; // assert(cls->weight < 0 || cls->numlits == 1); // if (cls->weight >= 0 && cls->numlits != 1) // return false; //} /* check that every watched clause is satisfied */ for (i = 0; i < atom_table->num_vars; i++) { lit = pos_lit(i); valid_watched_lit(rule_inst_table, lit, atom_table); lit = neg_lit(i); valid_watched_lit(rule_inst_table, lit, atom_table); } /* check the sat_clauses to see if the first disjunct is fixed true */ valid_clause_list(&rule_inst_table->sat_clauses); for (ptr = rule_inst_table->sat_clauses.head; ptr != rule_inst_table->sat_clauses.tail; ptr = next_clause_ptr(ptr)) { cls = ptr->link; assert(clause_contains_fixed_true_lit(cls, atom_table->assignment)); if (!clause_contains_fixed_true_lit(cls, atom_table->assignment)) return false; } /* check the live_clauses */ valid_clause_list(&rule_inst_table->sat_clauses); /* check all the clauses to see if they are properly indexed */ rule_inst_t *rinst; for (i = 0; i < rule_inst_table->num_rule_insts; i++){ rinst = rule_inst_table->rule_insts[i]; assert(rinst->num_clauses >= 0); if (rinst->num_clauses < 0) return false; //for (j = 0; j < clause->numlits; j++){ // assert(var_of(clause->disjunct[j]) >= 0); // assert(var_of(clause->disjunct[j]) < atom_table->num_vars); // if (var_of(clause->disjunct[j]) < 0 || // var_of(clause->disjunct[j]) >= atom_table->num_vars) // return false; //} } return true; }