dpllt_basic.cpp

Go to the documentation of this file.
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 /*****************************************************************************/
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   // Used to check that all clauses are true, but our decision maker
00187   // may ignore some clauses that are no longer relevant, so now we check to
00188   // make sure no clause is false.
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     // Copy current formula
00251     d_cnfStack.push_back(d_cnf);
00252     d_cnf = new CNF_Formula_Impl(*d_cnf);
00253 
00254     // make unit clauses for current assignment
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     // Create new manager
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   // Print result
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   // Print result
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 }

Generated on Thu Apr 13 16:57:31 2006 for CVC Lite by  doxygen 1.4.4