/*****************************************************************************/
/*!
*\file minisat_derivation.cpp
*\brief MiniSat proof logging
*
* Author: Alexander Fuchs
*
* Created: Sun Dec 07 11:09:00 2007
*
*
*
* License to use, copy, modify, sell and/or distribute this software
* and its documentation for any purpose is hereby granted without
* royalty, subject to the terms and conditions defined in the \ref
* LICENSE file provided with this distribution.
*
*
*/
/*****************************************************************************/
#include "minisat_derivation.h"
#include "minisat_solver.h"
#include
#include
using namespace MiniSat;
using namespace std;
std::string Inference::toString() const {
ostringstream buffer;
buffer << getStart();
for (Inference::TSteps::const_iterator step = d_steps.begin(); step != d_steps.end(); ++step) {
buffer << " " << step->first.toString() << " " << step->second;
}
return buffer.str();
}
Derivation::~Derivation() {
// deallocate generated unit clauses
for (TClauses::iterator i = d_unitClauses.begin(); i != d_unitClauses.end(); ++i) {
xfree(i->second);
}
// deallocate removed clauses
for (std::deque::iterator i = d_removedClauses.begin(); i != d_removedClauses.end(); ++i) {
xfree(*i);
}
// deallocate inferences
for (TInferences::iterator i = d_inferences.begin(); i != d_inferences.end(); ++i) {
delete i->second;
}
}
int Derivation::computeRootReason(Lit implied, Solver* solver) {
Clause* reason = solver->getReason(implied);
DebugAssert(reason != NULL, "MiniSat::Derivation::computeRootReason: implied reason is NULL");
DebugAssert(reason != Clause::Decision(), "MiniSat::Derivation::computeRootReason: implied is a decision");
DebugAssert((*reason)[0] == implied, "MiniSat::Derivation::computeRootReason: implied is not in its reason");
IF_DEBUG (
DebugAssert(solver->getValue((*reason)[0]) == l_True,
"MiniSat::Derivation::computeRootReason: literal not implied (TRUE)");
for (int i = 1; i < reason->size(); ++i) {
DebugAssert(solver->getValue((*reason)[i]) == l_False,
"MiniSat::Derivation::computeRootReason: literal not implied (FALSE)");
}
)
// already a unit clause, so done
if (reason->size() == 1) {
return reason->id();
}
// already derived the unit clause internally
TClauses::const_iterator iter = d_unitClauses.find(implied.index());
if (iter != d_unitClauses.end()) {
return iter->second->id();
}
// otherwise resolve the reason ...
Inference* inference = new Inference(reason->id());
for (int i = 1; i < reason->size(); ++i) {
Lit lit((*reason)[i]);
inference->add(lit, computeRootReason(~lit, solver));
}
// and create the new unit clause
// (after resolve, so that clause ids are chronological wrt. inference)
vector literals;
literals.push_back(implied);
Clause* unit = Clause_new(literals, solver->nextClauseID());
d_unitClauses[implied.index()] = unit;
registerClause(unit);
registerInference(unit->id(), inference);
return unit->id();
}
void Derivation::finish(Clause* clause, Solver* solver) {
DebugAssert(clause != NULL, "MiniSat::derivation:finish:");
// already the empty clause
if (clause->size() == 0) {
d_emptyClause = clause;
}
// derive the empty clause
else {
Inference* inference = new Inference(clause->id());
for (int i = 0; i < clause->size(); ++i) {
Lit lit((*clause)[i]);
inference->add(lit, computeRootReason(~lit, solver));
}
vector literals;
Clause* empty = Clause_new(literals, solver->nextClauseID());
removedClause(empty);
d_emptyClause = empty;
registerClause(empty);
registerInference(empty->id(), inference);
}
// cout << "PROOF_START" << endl;
// printProof();
// cout << "PROOF_END" << endl;
};
void Derivation::printProof() {
DebugAssert(d_emptyClause != NULL, "MiniSat::Derivation:printProof: no empty clause");
printProof(d_emptyClause);
}
void Derivation::printProof(Clause* clause) {
// find all relevant clauses
// - relevant: set clauses used in derivation
// - regress: relevant clauses whose antecedents have to be checked
std::set relevant;
std::set regress;
regress.insert(clause->id());
while (!regress.empty()) {
// pick next clause to derive - start from bottom, i.e. latest derived clause
int clauseID = *(regress.rbegin());
regress.erase(clauseID);
// move to clauses relevant for the derivation
DebugAssert(relevant.count(clauseID) == 0, "Solver::printProof: already in relevant");
relevant.insert(clauseID);
// process antecedents
TInferences::const_iterator iter = d_inferences.find(clauseID);
// input clause
if (iter == d_inferences.end()) {
DebugAssert(d_inputClauses.contains(clauseID),
"Solver::printProof: clause without antecedents is not marked as input clause");
}
else {
Inference* inference = iter->second;
regress.insert(inference->getStart());
const Inference::TSteps& steps = inference->getSteps();
for (Inference::TSteps::const_iterator step = steps.begin(); step != steps.end(); ++step) {
regress.insert(step->second);
}
}
}
// print proof
for (std::set::iterator i = relevant.begin(); i != relevant.end(); ++i) {
int clauseID = *i;
DebugAssert(d_clauses.contains(clauseID), "Solver::printProof: clause id in proof is not in clauses");
Clause* clause = d_clauses.find(clauseID)->second;
Inference* inference = NULL;
TInferences::const_iterator j = d_inferences.find(clauseID);
if (j != d_inferences.end()) {
inference = j->second;
}
// ID D : L1 ... Ln : C1 K1 C2 K2 ... Cm
cout << clauseID;
// input clause or derived clause?
if (d_inputClauses.contains(clauseID)) {
cout << " I ";
} else {
cout << " D ";
}
cout << ": " << clause->toString() << " : ";
if (inference != NULL) cout << inference->toString();
cout << endl;
}
}
void Derivation::push(int clauseID) {
}
void Derivation::pop(int clauseID) {
// remove all popped clauses
TClauses::iterator i = d_clauses.begin();
while (i != d_clauses.end()) {
if ((*i).second->pushID() > clauseID) {
int id = (*i).first;
++i;
d_clauses.erase(id);
d_unitClauses.erase(id);
d_inferences.erase(id);
}
else {
++i;
}
}
// undo conflicting clause
if (d_emptyClause != NULL && d_emptyClause->pushID() > clauseID)
d_emptyClause = NULL;
// delete popped and removed clauses
std::deque::iterator j = d_removedClauses.begin();
while (j != d_removedClauses.end()) {
if ((*j)->pushID() > clauseID) {
xfree(*j);
j = d_removedClauses.erase(j);
} else {
++j;
}
}
}