CVC3
|
00001 /*****************************************************************************/ 00002 /*! 00003 *\file dpllt_basic.cpp 00004 *\brief Basic implementation of dpllt module using generic sat solver 00005 * 00006 * Author: Clark Barrett 00007 * 00008 * Created: Mon Dec 12 19:09:43 2005 00009 * 00010 * <hr> 00011 * 00012 * License to use, copy, modify, sell and/or distribute this software 00013 * and its documentation for any purpose is hereby granted without 00014 * royalty, subject to the terms and conditions defined in the \ref 00015 * LICENSE file provided with this distribution. 00016 * 00017 * <hr> 00018 */ 00019 /*****************************************************************************/ 00020 00021 00022 #include "dpllt_basic.h" 00023 #include "cnf.h" 00024 #include "sat_api.h" 00025 #include "exception.h" 00026 00027 00028 using namespace std; 00029 using namespace CVC3; 00030 using namespace SAT; 00031 00032 00033 //int level_ = 0; 00034 00035 static void SATDLevelHook(void *cookie, int change) 00036 { 00037 //cout << "backtrack to: " << level_ << " " << change << endl; 00038 //level_ += change; 00039 // cout<<"decision level called"<<endl; 00040 DPLLTBasic* db = static_cast<DPLLTBasic*>(cookie); 00041 for (; change > 0; change--) { 00042 db->theoryAPI()->push(); 00043 } 00044 for (; change < 0; change++) { 00045 db->theoryAPI()->pop(); 00046 } 00047 } 00048 00049 00050 static SatSolver::Lit SATDecisionHook(void *cookie, bool *done) 00051 { 00052 // cout<<"sat decision called"<<endl; 00053 DPLLTBasic* db = static_cast<DPLLTBasic*>(cookie); 00054 00055 if (db->theoryAPI()->outOfResources()) { 00056 // Tell SAT solver to exit with satisfiable result 00057 *done = true; 00058 return SatSolver::Lit(); 00059 } 00060 00061 if (!db->decider()) { 00062 // Tell SAT solver to make its own choice 00063 if (!*done) return SatSolver::Lit(); 00064 } 00065 else { 00066 Lit lit = db->decider()->makeDecision(); 00067 if (!lit.isNull()) { 00068 //cout << "Split: " << lit.getVar().getIndex() << endl; 00069 // Tell SAT solver which literal to split on 00070 *done = false; 00071 return db->cvc2SAT(lit); 00072 } 00073 } 00074 00075 CNF_Formula_Impl cnf; 00076 DPLLT::ConsistentResult result; 00077 result = db->theoryAPI()->checkConsistent(cnf, true); 00078 00079 if (result == DPLLT::MAYBE_CONSISTENT) { 00080 IF_DEBUG(bool added = ) db->theoryAPI()->getNewClauses(cnf); 00081 DebugAssert(added, "Expected new clauses"); 00082 db->addNewClauses(cnf); 00083 *done = true; 00084 SatSolver::Lit l; 00085 l.id = 0; 00086 return l; 00087 } 00088 else if (result == DPLLT::INCONSISTENT) { 00089 db->addNewClauses(cnf); 00090 } 00091 00092 // Tell SAT solver that we are done 00093 *done = true; 00094 return SatSolver::Lit(); 00095 } 00096 00097 00098 static void SATAssignmentHook(void *cookie, SatSolver::Var var, int value) 00099 { 00100 // cout<<"assignment called"<<endl; 00101 DPLLTBasic* db = static_cast<DPLLTBasic*>(cookie); 00102 TRACE("DPLL Assign", var.id, " := ", value); 00103 if (value == 0) 00104 db->theoryAPI()->assertLit(Lit(db->satSolver()->GetVarIndex(var), false)); 00105 else if (value == 1) 00106 db->theoryAPI()->assertLit(Lit(db->satSolver()->GetVarIndex(var), true)); 00107 else return; 00108 CNF_Formula_Impl cnf; 00109 DPLLT::ConsistentResult result; 00110 result = db->theoryAPI()->checkConsistent(cnf, false); 00111 if (result == DPLLT::INCONSISTENT) { 00112 db->addNewClauses(cnf); 00113 } 00114 } 00115 00116 00117 static void SATDeductionHook(void *cookie) 00118 { 00119 // cout<<"deduction called"<<endl;; 00120 DPLLTBasic* db = static_cast<DPLLTBasic*>(cookie); 00121 Clause c; 00122 CNF_Formula_Impl cnf; 00123 if (db->theoryAPI()->getNewClauses(cnf)) { 00124 db->addNewClauses(cnf); 00125 cnf.reset(); 00126 } 00127 Lit l = db->theoryAPI()->getImplication(); 00128 while (!l.isNull()) { 00129 db->theoryAPI()->getExplanation(l, cnf); 00130 db->addNewClauses(cnf); 00131 cnf.reset(); 00132 l = db->theoryAPI()->getImplication(); 00133 } 00134 } 00135 00136 00137 void DPLLTBasic::createManager() 00138 { 00139 d_mng = SatSolver::Create(); 00140 d_mng->RegisterDLevelHook(SATDLevelHook, this); 00141 d_mng->RegisterDecisionHook(SATDecisionHook, this); 00142 d_mng->RegisterAssignmentHook(SATAssignmentHook, this); 00143 d_mng->RegisterDeductionHook(SATDeductionHook, this); 00144 } 00145 00146 00147 void DPLLTBasic::generate_CDB (CNF_Formula_Impl& cnf) 00148 { 00149 CNF_Formula::const_iterator i, iend; 00150 Clause::const_iterator j, jend; 00151 vector<SatSolver::Lit> clause; 00152 if (cnf.numVars() > unsigned(d_mng->NumVariables())) { 00153 d_mng->AddVariables(cnf.numVars() - d_mng->NumVariables()); 00154 } 00155 cnf.simplify(); 00156 for (i = cnf.end()-1, iend = cnf.begin()-1; i != iend; --i) { 00157 //for (i = cnf.begin(), iend = cnf.end(); i != iend; i++) { 00158 if ((*i).isSatisfied()) continue; 00159 for (j = (*i).begin(), jend = (*i).end(); j != jend; ++j) { 00160 if (!(*j).isFalse()) clause.push_back(cvc2SAT(*j)); 00161 } 00162 if (clause.size() != 0) { 00163 d_mng->AddClause(clause); 00164 clause.clear(); 00165 } 00166 } 00167 } 00168 00169 00170 void DPLLTBasic::handle_result(SatSolver::SATStatus outcome) 00171 { 00172 const char * result = "UNKNOWN"; 00173 switch (outcome) { 00174 case SatSolver::SATISFIABLE: 00175 // if (d_printStats) { 00176 // cout << "Instance satisfiable" << endl; 00177 // for (int i=1, sz = d_mng->NumVariables(); i <= sz; ++i) { 00178 // switch(d_mng->GetVarAssignment(d_mng->GetVar(i))) { 00179 // case -1: 00180 // cout <<"("<< i<<")"; break; 00181 // case 0: 00182 // cout << "-" << i; break; 00183 // case 1: 00184 // cout << i ; break; 00185 // default: 00186 // throw Exception("Unknown variable value state"); 00187 // } 00188 // cout << " "; 00189 // } 00190 // cout << endl; 00191 // } 00192 result = "SAT"; 00193 break; 00194 case SatSolver::UNSATISFIABLE: 00195 result = "UNSAT"; 00196 if (d_printStats) cout << "Instance unsatisfiable" << endl; 00197 break; 00198 case SatSolver::BUDGET_EXCEEDED: 00199 result = "ABORT : TIME OUT"; 00200 cout << "Time out, unable to determine the satisfiablility of the instance"; 00201 cout << endl; 00202 break; 00203 case SatSolver::OUT_OF_MEMORY: 00204 result = "ABORT : MEM OUT"; 00205 cout << "Memory out, unable to determing the satisfiablility of the instance"; 00206 cout << endl; 00207 break; 00208 default: 00209 throw Exception("DPLTBasic::handle_result: Unknown outcome"); 00210 } 00211 if (d_printStats) d_mng->PrintStatistics(); 00212 } 00213 00214 00215 void DPLLTBasic::verify_solution() 00216 { 00217 // Used to check that all clauses are true, but our decision maker 00218 // may ignore some clauses that are no longer relevant, so now we check to 00219 // make sure no clause is false. 00220 for (SatSolver::Clause cl = d_mng->GetFirstClause(); !cl.IsNull(); 00221 cl = d_mng->GetNextClause(cl)) { 00222 vector<SatSolver::Lit> lits; 00223 d_mng->GetClauseLits(cl, &lits); 00224 for (; lits.size() != 0;) { 00225 SatSolver::Lit lit = lits.back(); 00226 SatSolver::Var var = d_mng->GetVarFromLit(lit); 00227 int sign = d_mng->GetPhaseFromLit(lit); 00228 int var_value = d_mng->GetVarAssignment(var); 00229 if( (var_value == 1 && sign == 0) || 00230 (var_value == 0 && sign == 1) || 00231 (var_value == -1) ) break; 00232 lits.pop_back(); 00233 } 00234 DebugAssert(lits.size() != 0, "DPLLTBasic::verify_solution failed"); 00235 } 00236 } 00237 00238 00239 DPLLTBasic::DPLLTBasic(TheoryAPI* theoryAPI, Decider* decider, ContextManager* cm, 00240 bool printStats) 00241 : DPLLT(theoryAPI, decider), d_cm(cm), d_ready(true), 00242 d_printStats(printStats), 00243 d_pushLevel(cm->getCurrentContext(), 0), 00244 d_readyPrev(cm->getCurrentContext(), true), 00245 d_prevStackSize(cm->getCurrentContext(), 0), 00246 d_prevAStackSize(cm->getCurrentContext(), 0) 00247 { 00248 createManager(); 00249 d_cnf = new CNF_Formula_Impl(); 00250 d_assertions = new CD_CNF_Formula(d_cm->getCurrentContext()); 00251 } 00252 00253 00254 DPLLTBasic::~DPLLTBasic() 00255 { 00256 if (d_assertions) delete d_assertions; 00257 if (d_cnf) delete d_cnf; 00258 if (d_mng) delete d_mng; 00259 while (d_assertionsStack.size() > 0) { 00260 d_assertions = d_assertionsStack.back(); 00261 d_assertionsStack.pop_back(); 00262 delete d_assertions; 00263 } 00264 while (d_mngStack.size() > 0) { 00265 d_mng = d_mngStack.back(); 00266 d_mngStack.pop_back(); 00267 delete d_mng; 00268 d_cnf = d_cnfStack.back(); 00269 d_cnfStack.pop_back(); 00270 delete d_cnf; 00271 } 00272 } 00273 00274 00275 void DPLLTBasic::addNewClause(const Clause& c) 00276 { 00277 DebugAssert(c.size() > 0, "Expected non-empty clause"); 00278 DebugAssert(c.getMaxVar() <= unsigned(d_mng->NumVariables()), 00279 "Expected no new variables"); 00280 vector<SatSolver::Lit> lits; 00281 for (Clause::const_iterator i = c.begin(), iend = c.end(); i < iend; ++i) { 00282 if (!(*i).isFalse()) lits.push_back(cvc2SAT(*i)); 00283 } 00284 satSolver()->AddClause(lits); 00285 (*d_cnf) += c; 00286 } 00287 00288 00289 void DPLLTBasic::addNewClauses(CNF_Formula_Impl& cnf) 00290 { 00291 CNF_Formula::const_iterator i, iend; 00292 Clause::const_iterator j, jend; 00293 vector<SatSolver::Lit> clause; 00294 if (cnf.numVars() > unsigned(d_mng->NumVariables())) { 00295 d_mng->AddVariables(cnf.numVars() - d_mng->NumVariables()); 00296 } 00297 cnf.simplify(); 00298 for (i = cnf.end()-1, iend = cnf.begin()-1; i != iend; --i) { 00299 //for (i = cnf.begin(), iend = cnf.end(); i != iend; i++) { 00300 if ((*i).isSatisfied()) continue; 00301 for (j = (*i).begin(), jend = (*i).end(); j != jend; ++j) { 00302 if (!(*j).isFalse()) clause.push_back(cvc2SAT(*j)); 00303 } 00304 if (clause.size() != 0) { 00305 d_mng->AddClause(clause); 00306 clause.clear(); 00307 } 00308 } 00309 generate_CDB(cnf); 00310 (*d_cnf) += cnf; 00311 } 00312 00313 00314 void DPLLTBasic::push() 00315 { 00316 d_theoryAPI->push(); 00317 d_pushLevel = d_pushLevel + 1; 00318 d_prevStackSize = d_mngStack.size(); 00319 d_prevAStackSize = d_assertionsStack.size(); 00320 d_readyPrev = d_ready; 00321 } 00322 00323 00324 void DPLLTBasic::pop() 00325 { 00326 unsigned pushLevel = d_pushLevel; 00327 unsigned prevStackSize = d_prevStackSize; 00328 unsigned prevAStackSize = d_prevAStackSize; 00329 bool readyPrev = d_readyPrev; 00330 00331 while (d_assertionsStack.size() > prevAStackSize) { 00332 delete d_assertions; 00333 d_assertions = d_assertionsStack.back(); 00334 d_assertionsStack.pop_back(); 00335 } 00336 00337 while (d_mngStack.size() > prevStackSize) { 00338 delete d_mng; 00339 delete d_cnf; 00340 d_mng = d_mngStack.back(); 00341 d_mngStack.pop_back(); 00342 d_cnf = d_cnfStack.back(); 00343 d_cnfStack.pop_back(); 00344 DebugAssert(d_mngStack.size() == d_cnfStack.size(), "size mismatch"); 00345 } 00346 00347 if (d_mngStack.size() == 0) { 00348 if (readyPrev && !d_ready) { 00349 delete d_mng; 00350 delete d_cnf; 00351 createManager(); 00352 d_cnf = new CNF_Formula_Impl(); 00353 d_ready = true; 00354 } 00355 else { 00356 DebugAssert(readyPrev == d_ready, "Unexpected ready values"); 00357 } 00358 } 00359 else { 00360 DebugAssert(!d_ready, "Expected ready to be false"); 00361 } 00362 00363 while (d_pushLevel == pushLevel) 00364 d_theoryAPI->pop(); 00365 00366 } 00367 00368 std::vector<SAT::Lit> DPLLTBasic::getCurAssignments(){ 00369 std::vector<SAT::Lit> nothing; 00370 return nothing; 00371 } 00372 00373 std::vector<std::vector<SAT::Lit> > DPLLTBasic::getCurClauses(){ 00374 std::vector<std::vector<SAT::Lit> > nothing; 00375 return nothing; 00376 } 00377 00378 00379 void DPLLTBasic::addAssertion(const CNF_Formula& cnf) 00380 { 00381 // Immediately assert unit clauses 00382 CNF_Formula::const_iterator i, iend; 00383 Clause::const_iterator j, jend; 00384 for (i = cnf.end()-1, iend = cnf.begin()-1; i != iend; --i) { 00385 if ((*i).isUnit()) { 00386 j = (*i).begin(); 00387 d_theoryAPI->assertLit(*j); 00388 } 00389 } 00390 00391 // Accumulate assertions in d_assertions 00392 (*d_assertions) += cnf; 00393 } 00394 00395 00396 QueryResult DPLLTBasic::checkSat(const CNF_Formula& cnf) 00397 { 00398 SatSolver::SATStatus result; 00399 00400 if (!d_ready) { 00401 // Copy current formula 00402 d_cnfStack.push_back(d_cnf); 00403 d_cnf = new CNF_Formula_Impl(*d_cnf); 00404 00405 // make unit clauses for current assignment 00406 int value; 00407 for (int i = 1; i <= d_mng->NumVariables(); ++i) { 00408 value = d_mng->GetVarAssignment(d_mng->GetVar(i)); 00409 if (value == 1) { 00410 d_cnf->newClause(); 00411 d_cnf->addLiteral(Lit(i)); 00412 } 00413 else if (value == 0) { 00414 d_cnf->newClause(); 00415 d_cnf->addLiteral(Lit(i, false)); 00416 } 00417 } 00418 00419 // Create new manager 00420 d_mngStack.push_back(d_mng); 00421 DebugAssert(d_mngStack.size() == d_cnfStack.size(), "size mismatch"); 00422 createManager(); 00423 } 00424 d_ready = false; 00425 00426 if (d_assertions) (*d_cnf) += (*d_assertions); 00427 00428 (*d_cnf) += cnf; 00429 generate_CDB(*d_cnf); 00430 00431 d_theoryAPI->push(); 00432 00433 result = d_mng->Satisfiable(true); 00434 if (result == SatSolver::SATISFIABLE && theoryAPI()->outOfResources()) 00435 result = SatSolver::BUDGET_EXCEEDED; 00436 00437 // Print result 00438 00439 if (result == SatSolver::SATISFIABLE) { 00440 verify_solution(); 00441 if (d_assertions->numClauses() > 0) { 00442 d_assertionsStack.push_back(d_assertions); 00443 d_assertions = new CD_CNF_Formula(d_cm->getCurrentContext()); 00444 } 00445 } 00446 handle_result (result); 00447 00448 if (result == SatSolver::UNSATISFIABLE) { 00449 d_theoryAPI->pop(); 00450 delete d_mng; 00451 delete d_cnf; 00452 if (d_mngStack.size() == 0) { 00453 createManager(); 00454 d_cnf = new CNF_Formula_Impl(); 00455 d_ready = true; 00456 } 00457 else { 00458 d_mng = d_mngStack.back(); 00459 d_mngStack.pop_back(); 00460 d_cnf = d_cnfStack.back(); 00461 d_cnfStack.pop_back(); 00462 DebugAssert(d_mngStack.size() == d_cnfStack.size(), "size mismatch"); 00463 } 00464 } 00465 00466 return (result == SatSolver::UNSATISFIABLE ? UNSATISFIABLE : 00467 result == SatSolver::SATISFIABLE ? SATISFIABLE : 00468 ABORT); 00469 } 00470 00471 00472 QueryResult DPLLTBasic::continueCheck(const CNF_Formula& cnf) 00473 { 00474 SatSolver::SATStatus result; 00475 00476 if (d_ready) { 00477 throw Exception 00478 ("continueCheck should be called after a previous satisfiable result"); 00479 } 00480 if (d_assertions->numClauses() > 0) { 00481 throw Exception 00482 ("a check cannot be continued if new assertions have been made"); 00483 } 00484 CNF_Formula_Impl cnfImpl(cnf); 00485 00486 generate_CDB(cnfImpl); 00487 (*d_cnf) += cnfImpl; 00488 00489 result = d_mng->Continue(); 00490 if (result == SatSolver::SATISFIABLE && theoryAPI()->outOfResources()) 00491 result = SatSolver::BUDGET_EXCEEDED; 00492 00493 // Print result 00494 00495 if (result == SatSolver::SATISFIABLE) 00496 verify_solution(); 00497 handle_result (result); 00498 00499 if (result == SatSolver::UNSATISFIABLE) { 00500 d_theoryAPI->pop(); 00501 delete d_mng; 00502 delete d_cnf; 00503 if (d_mngStack.size() == 0) { 00504 createManager(); 00505 d_cnf = new CNF_Formula_Impl(); 00506 d_ready = true; 00507 } 00508 else { 00509 d_mng = d_mngStack.back(); 00510 d_mngStack.pop_back(); 00511 d_cnf = d_cnfStack.back(); 00512 d_cnfStack.pop_back(); 00513 DebugAssert(d_mngStack.size() == d_cnfStack.size(), "size mismatch"); 00514 } 00515 } 00516 00517 return (result == SatSolver::UNSATISFIABLE ? UNSATISFIABLE : 00518 result == SatSolver::SATISFIABLE ? SATISFIABLE : 00519 ABORT); 00520 } 00521 00522 CVC3::Proof DPLLTBasic::getSatProof(CNF_Manager* cnfManager, CVC3::TheoryCore* core){ 00523 CVC3::Proof temp; 00524 return temp; 00525 } 00526