00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include "dpllt_basic.h"
00014 #include "cnf.h"
00015 #include "sat_api.h"
00016 #include "exception.h"
00017
00018
00019 using namespace std;
00020 using namespace CVCL;
00021 using namespace SAT;
00022
00023
00024 static void SATDLevelHook(void *cookie, int change)
00025 {
00026 DPLLTBasic* db = static_cast<DPLLTBasic*>(cookie);
00027 if (!db->popScopes()) return;
00028 for (; change > 0; change--) {
00029 db->theoryAPI()->push();
00030 }
00031 for (; change < 0; change++) {
00032 db->theoryAPI()->pop();
00033 }
00034 }
00035
00036
00037 static SatSolver::Lit SATDecisionHook(void *cookie, bool *done)
00038 {
00039 DPLLTBasic* db = static_cast<DPLLTBasic*>(cookie);
00040
00041 if (!db->decider()) {
00042 *done = true;
00043 return SatSolver::Lit();
00044 }
00045
00046 Lit lit = db->decider()->makeDecision();
00047 if (!lit.isNull()) {
00048 *done = false;
00049 return db->cvcl2SAT(lit);
00050 }
00051
00052 *done = true;
00053 Clause c;
00054 DPLLT::ConsistentResult result;
00055 result = db->theoryAPI()->checkConsistent(c, true);
00056
00057 while (result == DPLLT::MAYBE_CONSISTENT) {
00058 CNF_Formula_Impl cnf;
00059 bool added = db->theoryAPI()->getNewClauses(cnf);
00060 if (added) {
00061 db->addNewClauses(cnf);
00062 return SatSolver::Lit();
00063 }
00064 result = db->theoryAPI()->checkConsistent(c, true);
00065 }
00066 if (result == DPLLT::INCONSISTENT) {
00067 db->addNewClause(c);
00068 }
00069
00070 return SatSolver::Lit();
00071 }
00072
00073
00074 static void SATAssignmentHook(void *cookie, SatSolver::Var var, int value)
00075 {
00076 DPLLTBasic* db = static_cast<DPLLTBasic*>(cookie);
00077 if (value == 0)
00078 db->theoryAPI()->assertLit(Lit(db->satSolver()->GetVarIndex(var), false));
00079 else if (value == 1)
00080 db->theoryAPI()->assertLit(Lit(db->satSolver()->GetVarIndex(var), true));
00081 else return;
00082 Clause c;
00083 DPLLT::ConsistentResult result;
00084 result = db->theoryAPI()->checkConsistent(c, false);
00085 if (result == DPLLT::INCONSISTENT) {
00086 db->addNewClause(c);
00087 }
00088 }
00089
00090
00091 static void SATDeductionHook(void *cookie)
00092 {
00093 DPLLTBasic* db = static_cast<DPLLTBasic*>(cookie);
00094 Clause c;
00095 CNF_Formula_Impl cnf;
00096 if (db->theoryAPI()->getNewClauses(cnf)) db->addNewClauses(cnf);
00097 Lit l = db->theoryAPI()->getImplication();
00098 while (!l.isNull()) {
00099 db->theoryAPI()->getExplanation(l, c);
00100 db->addNewClause(c);
00101 c.clear();
00102 l = db->theoryAPI()->getImplication();
00103 }
00104 }
00105
00106
00107 void DPLLTBasic::createManager()
00108 {
00109 d_mng = SatSolver::Create();
00110 d_mng->RegisterDLevelHook(SATDLevelHook, this);
00111 d_mng->RegisterDecisionHook(SATDecisionHook, this);
00112 d_mng->RegisterAssignmentHook(SATAssignmentHook, this);
00113 d_mng->RegisterDeductionHook(SATDeductionHook, this);
00114 }
00115
00116
00117 void DPLLTBasic::generate_CDB (CNF_Formula_Impl& cnf)
00118 {
00119 CNF_Formula::const_iterator i, iend;
00120 Clause::const_iterator j, jend;
00121 vector<SatSolver::Lit> clause;
00122 if (cnf.numVars() > unsigned(d_mng->NumVariables())) {
00123 d_mng->AddVariables(cnf.numVars() - d_mng->NumVariables());
00124 }
00125 cnf.simplify();
00126 for (i = cnf.end()-1, iend = cnf.begin()-1; i != iend; --i) {
00127 if ((*i).isSatisfied()) continue;
00128 for (j = (*i).begin(), jend = (*i).end(); j != jend; ++j) {
00129 if (!(*j).isFalse()) clause.push_back(cvcl2SAT(*j));
00130 }
00131 if (clause.size() != 0) {
00132 d_mng->AddClause(clause);
00133 clause.clear();
00134 }
00135 }
00136 }
00137
00138
00139 void DPLLTBasic::handle_result(SatSolver::SATStatus outcome)
00140 {
00141 char * result = "UNKNOWN";
00142 switch (outcome) {
00143 case SatSolver::SATISFIABLE:
00144 if (d_printStats) {
00145 cout << "Instance satisfiable" << endl;
00146 for (int i=1, sz = d_mng->NumVariables(); i <= sz; ++i) {
00147 switch(d_mng->GetVarAssignment(d_mng->GetVar(i))) {
00148 case -1:
00149 cout <<"("<< i<<")"; break;
00150 case 0:
00151 cout << "-" << i; break;
00152 case 1:
00153 cout << i ; break;
00154 default:
00155 throw Exception("Unknown variable value state");
00156 }
00157 cout << " ";
00158 }
00159 cout << endl;
00160 }
00161 result = "SAT";
00162 break;
00163 case SatSolver::UNSATISFIABLE:
00164 result = "UNSAT";
00165 if (d_printStats) cout << "Instance unsatisfiable" << endl;
00166 break;
00167 case SatSolver::BUDGET_EXCEEDED:
00168 result = "ABORT : TIME OUT";
00169 cout << "Time out, unable to determine the satisfiablility of the instance";
00170 cout << endl;
00171 break;
00172 case SatSolver::OUT_OF_MEMORY:
00173 result = "ABORT : MEM OUT";
00174 cout << "Memory out, unable to determing the satisfiablility of the instance";
00175 cout << endl;
00176 break;
00177 default:
00178 throw Exception("DPLTBasic::handle_result: Unknown outcome");
00179 }
00180 if (d_printStats) d_mng->PrintStatistics();
00181 }
00182
00183
00184 void DPLLTBasic::verify_solution()
00185 {
00186
00187
00188
00189 for (SatSolver::Clause cl = d_mng->GetFirstClause(); !cl.IsNull();
00190 cl = d_mng->GetNextClause(cl)) {
00191 vector<SatSolver::Lit> lits;
00192 d_mng->GetClauseLits(cl, &lits);
00193 for (; lits.size() != 0;) {
00194 SatSolver::Lit lit = lits.back();
00195 SatSolver::Var var = d_mng->GetVarFromLit(lit);
00196 int sign = d_mng->GetPhaseFromLit(lit);
00197 int var_value = d_mng->GetVarAssignment(var);
00198 if( (var_value == 1 && sign == 0) ||
00199 (var_value == 0 && sign == 1) ||
00200 (var_value == -1) ) break;
00201 lits.pop_back();
00202 }
00203 DebugAssert(lits.size() != 0, "DPLLTBasic::verify_solution failed");
00204 }
00205 }
00206
00207
00208 DPLLTBasic::DPLLTBasic(TheoryAPI* theoryAPI, Decider* decider, bool printStats)
00209 : DPLLT(theoryAPI, decider), d_ready(true), d_popScopes(true),
00210 d_printStats(printStats)
00211 {
00212 createManager();
00213 d_cnf = new CNF_Formula_Impl();
00214 }
00215
00216
00217 DPLLTBasic::~DPLLTBasic()
00218 {
00219 if (d_cnf) delete d_cnf;
00220 if (d_mng) delete d_mng;
00221 }
00222
00223
00224 void DPLLTBasic::addNewClause(const Clause& c)
00225 {
00226 DebugAssert(c.size() > 0, "Expected non-empty clause");
00227 DebugAssert(c.getMaxVar() <= unsigned(d_mng->NumVariables()),
00228 "Expected no new variables");
00229 vector<SatSolver::Lit> lits;
00230 for (Clause::const_iterator i = c.begin(), iend = c.end(); i < iend; ++i) {
00231 if (!(*i).isFalse()) lits.push_back(cvcl2SAT(*i));
00232 }
00233 satSolver()->AddClause(lits);
00234 (*d_cnf) += c;
00235 }
00236
00237
00238 void DPLLTBasic::addNewClauses(CNF_Formula_Impl& cnf)
00239 {
00240 generate_CDB(cnf);
00241 (*d_cnf) += cnf;
00242 }
00243
00244
00245 DPLLTBasic::Result DPLLTBasic::checkSat(const CNF_Formula& cnf)
00246 {
00247 SatSolver::SATStatus result;
00248
00249 if (!d_ready) {
00250
00251 d_cnfStack.push_back(d_cnf);
00252 d_cnf = new CNF_Formula_Impl(*d_cnf);
00253
00254
00255 int value;
00256 for (int i = 1; i <= d_mng->NumVariables(); ++i) {
00257 value = d_mng->GetVarAssignment(d_mng->GetVar(i));
00258 if (value == 1) {
00259 d_cnf->newClause();
00260 d_cnf->addLiteral(Lit(i));
00261 }
00262 else if (value == 0) {
00263 d_cnf->newClause();
00264 d_cnf->addLiteral(Lit(i, false));
00265 }
00266 }
00267
00268
00269 d_mngStack.push_back(d_mng);
00270 createManager();
00271 }
00272 d_ready = false;
00273
00274 (*d_cnf) += cnf;
00275 generate_CDB(*d_cnf);
00276
00277 d_theoryAPI->push();
00278
00279 result = d_mng->Satisfiable(true);
00280
00281
00282
00283 if (result == SatSolver::SATISFIABLE)
00284 verify_solution();
00285 handle_result (result);
00286
00287 if (result != SatSolver::SATISFIABLE) {
00288 d_theoryAPI->pop();
00289 delete d_mng;
00290 delete d_cnf;
00291 if (d_mngStack.size() == 0) {
00292 createManager();
00293 d_cnf = new CNF_Formula_Impl();
00294 d_ready = true;
00295 }
00296 else {
00297 d_mng = d_mngStack.back();
00298 d_mngStack.pop_back();
00299 d_cnf = d_cnfStack.back();
00300 d_cnfStack.pop_back();
00301 }
00302 }
00303
00304 return (result == SatSolver::UNSATISFIABLE ? UNSAT :
00305 result == SatSolver::SATISFIABLE ? SATISFIABLE :
00306 ABORT);
00307 }
00308
00309
00310 DPLLTBasic::Result DPLLTBasic::continueCheck(const CNF_Formula& cnf)
00311 {
00312 SatSolver::SATStatus result;
00313
00314 if (d_ready) {
00315 throw Exception
00316 ("continueCheck should be called after a previous satisfiable result");
00317 }
00318 CNF_Formula_Impl cnfImpl(cnf);
00319
00320 generate_CDB(cnfImpl);
00321 (*d_cnf) += cnfImpl;
00322
00323 result = d_mng->Continue();
00324
00325
00326
00327 if (result == SatSolver::SATISFIABLE)
00328 verify_solution();
00329 handle_result (result);
00330
00331 if (result != SatSolver::SATISFIABLE) {
00332 d_theoryAPI->pop();
00333 delete d_mng;
00334 delete d_cnf;
00335 if (d_mngStack.size() == 0) {
00336 createManager();
00337 d_cnf = new CNF_Formula_Impl();
00338 d_ready = true;
00339 }
00340 else {
00341 d_mng = d_mngStack.back();
00342 d_mngStack.pop_back();
00343 d_cnf = d_cnfStack.back();
00344 d_cnfStack.pop_back();
00345 }
00346 }
00347
00348 return (result == SatSolver::UNSATISFIABLE ? UNSAT :
00349 result == SatSolver::SATISFIABLE ? SATISFIABLE :
00350 ABORT);
00351 }
00352
00353
00354 void DPLLTBasic::returnFromSat()
00355 {
00356 d_popScopes = false;
00357 delete d_mng;
00358 d_popScopes = true;
00359 delete d_cnf;
00360 if (d_mngStack.size() == 0) {
00361 if (d_ready) {
00362 throw Exception
00363 ("returnFromSat requires previous SATISFIABLE checkSat call");
00364 }
00365 createManager();
00366 d_cnf = new CNF_Formula_Impl();
00367 d_ready = true;
00368 }
00369 else {
00370 DebugAssert(!d_ready, "Expected ready to be false");
00371 d_mng = d_mngStack.back();
00372 d_mngStack.pop_back();
00373 d_cnf = d_cnfStack.back();
00374 d_cnfStack.pop_back();
00375 }
00376 }