search_fast.cpp

Go to the documentation of this file.
00001 ///////////////////////////////////////////////////////////////////////////////
00002 /*!
00003  * \file search_fast.cpp
00004  *
00005  * Author: Mark Zavislak <zavislak@stanford.edu>
00006  *         Undergraduate
00007  *         Stanford University          
00008  *
00009  * Created: Mon Jul 21 23:52:39 UTC 2003
00010  *
00011  * <hr>
00012  * Copyright (C) 2003 by the Board of Trustees of Leland Stanford
00013  * Junior University and by New York University. 
00014  *
00015  * License to use, copy, modify, sell and/or distribute this software
00016  * and its documentation for any purpose is hereby granted without
00017  * royalty, subject to the terms and conditions defined in the \ref
00018  * LICENSE file provided with this distribution.  In particular:
00019  *
00020  * - The above copyright notice and this permission notice must appear
00021  * in all copies of the software and related documentation.
00022  *
00023  * - THE SOFTWARE IS PROVIDED "AS-IS", WITHOUT ANY WARRANTIES,
00024  * EXPRESSED OR IMPLIED.  USE IT AT YOUR OWN RISK.
00025  * 
00026  * <hr>
00027 */
00028 ///////////////////////////////////////////////////////////////////////////////
00029 
00030 #include "search_fast.h"
00031 #include "typecheck_exception.h"
00032 #include "search_rules.h"
00033 #include "command_line_flags.h"
00034 #include "cdmap.h"
00035 #include "decision_engine_dfs.h"
00036 #include "decision_engine_caching.h"
00037 #include "decision_engine_mbtf.h"
00038 #include "expr_transform.h"
00039 
00040 
00041 using namespace CVCL;
00042 using namespace std;
00043 
00044 
00045 //! When set to true, match Chaff behavior as close as possible
00046 #define followChaff false
00047 
00048 
00049 void SearchEngineFast::ConflictClauseManager::setRestorePoint()
00050 {
00051   TRACE("conflict clauses",
00052         "ConflictClauseManager::setRestorePoint(): scope=",
00053             d_se->scopeLevel(), "");
00054   d_se->d_conflictClauseStack.push_back(new deque<ClauseOwner>());
00055   d_se->d_conflictClauses = d_se->d_conflictClauseStack.back();
00056   d_restorePoints.push_back(d_se->scopeLevel());
00057 }
00058 
00059 
00060 void SearchEngineFast::ConflictClauseManager::notify()
00061 {
00062   if (d_restorePoints.size() > 0) {
00063     int scope = d_restorePoints.back();
00064     if (scope > d_se->scopeLevel()) {
00065       TRACE("conflict clauses",
00066             "ConflictClauseManager::notify(): restore to scope ", scope, "");
00067       d_restorePoints.pop_back();
00068       while (d_se->d_conflictClauses->size() > 0)
00069         d_se->d_conflictClauses->pop_back();
00070       delete d_se->d_conflictClauseStack.back();
00071       d_se->d_conflictClauseStack.pop_back();
00072       d_se->d_conflictClauses = d_se->d_conflictClauseStack.back();
00073     }
00074   }
00075 }
00076 
00077 
00078 //! Constructor
00079 SearchEngineFast::SearchEngineFast(TheoryCore* core)
00080   : SearchImplBase(core),
00081     d_name("fast"),
00082     d_unitPropCount(core->getStatistics().counter("unit propagations")),
00083     d_circuitPropCount(core->getStatistics().counter("circuit propagations")),
00084     d_conflictCount(core->getStatistics().counter("conflicts")),
00085     d_conflictClauseCount(core->getStatistics().counter("conflict clauses")),
00086     d_clauses(core->getCM()->getCurrentContext()),
00087     d_unreportedLits(core->getCM()->getCurrentContext()),
00088     d_unreportedLitsHandled(core->getCM()->getCurrentContext()),
00089     d_nonLiterals(core->getCM()->getCurrentContext()),
00090     d_nonLiteralsSaved(core->getCM()->getCurrentContext()),
00091     d_simplifiedThm(core->getCM()->getCurrentContext()),
00092     d_nonlitQueryStart(core->getCM()->getCurrentContext()),
00093     d_nonlitQueryEnd(core->getCM()->getCurrentContext()),
00094     d_clausesQueryStart(core->getCM()->getCurrentContext()),
00095     d_clausesQueryEnd(core->getCM()->getCurrentContext()),
00096     d_conflictClauseManager(core->getCM()->getCurrentContext(), this),
00097     d_literalSet(core->getCM()->getCurrentContext()),
00098     d_useEnqueueFact(false),
00099     d_inCheckSAT(false),
00100     d_litsAlive(core->getCM()->getCurrentContext()),
00101     d_litsMaxScorePos(0),
00102     d_splitterCount(0),
00103     d_litSortCount(0),
00104     d_berkminFlag(core->getFlags()["berkmin"].getBool())
00105 {
00106   if (core->getFlags()["de"].getString() == "caching")
00107     d_decisionEngine = new DecisionEngineCaching(core, this);
00108   else if (core->getFlags()["de"].getString() == "mbtf")
00109     d_decisionEngine = new DecisionEngineMBTF(core, this);
00110   else
00111     d_decisionEngine = new DecisionEngineDFS(core, this);
00112 
00113   IF_DEBUG (
00114     d_nonLiterals.setName("CDList[SearchEngineDefault.d_nonLiterals]");
00115     d_clauses.setName("CDList[SearchEngineDefault.d_clauses]");
00116   )
00117 
00118   d_conflictClauseStack.push_back(new deque<ClauseOwner>());
00119   d_conflictClauses = d_conflictClauseStack.back();
00120 }
00121 
00122 //! Destructor
00123 /*! We own the proof rules (d_rules) and the variable manager (d_vm);
00124   delete them. */
00125 SearchEngineFast::~SearchEngineFast() {
00126   for (unsigned i=0; i < d_circuits.size(); i++)
00127     delete d_circuits[i];
00128   delete d_decisionEngine;
00129   for(size_t i=0, iend=d_conflictClauseStack.size(); i<iend; ++i)
00130     delete d_conflictClauseStack[i];
00131 }
00132 
00133 
00134 /*! @brief Return a ref to the vector of watched literals.  If no
00135   such vector exists, create it. */
00136 /*!  This function is normally used when the value of 'literal'
00137  * becomes false.  The vector contains pointers to all clauses where
00138  * this literal occurs, and therefore, these clauses may cause unit
00139  * propagation.  In any case, the watch pointers in these clauses
00140  * need to be updated.
00141  */
00142 vector<std::pair<Clause, int> >& 
00143 SearchEngineFast::wp(const Literal& literal) {
00144   // return d_wp[literal.getExpr()];
00145   return literal.wp();
00146 }
00147 
00148 #ifdef DEBUG
00149 static void checkAssump(const Theorem& t, const Theorem& orig,
00150                  const CDMap<Expr,Theorem>& assumptions) {
00151   const Assumptions::iterator iend = t.getAssumptions().end();
00152   if(!(!t.isAssump() || assumptions.count(t.getExpr()) > 0))
00153     orig.printDebug();
00154   DebugAssert((!t.isAssump() || assumptions.count(t.getExpr()) > 0), 
00155               "checkAssump: found stray theorem:\n  "
00156               + t.toString());
00157   if(t.isAssump()) return;
00158   for (Assumptions::iterator i = t.getAssumptions().begin(); i != iend; ++i) {
00159     if (!i->isFlagged()) {
00160       i->setFlag();
00161       // comparing only TheoremValue pointers in .find()
00162       checkAssump(*i, orig, assumptions);
00163     }
00164   }
00165 }
00166 
00167 
00168 /*! @brief Check that assumptions in the result of checkValid() are a
00169   subset of assertions */
00170 /*! Only defined in the debug build. 
00171  * \ingroup SE_Default
00172  */
00173 static void
00174 checkAssumpDebug(const Theorem& res,
00175                  const CDMap<Expr,Theorem>& assumptions) {
00176   // FIXME: (jimz) will need to traverse graph
00177 
00178   if(!res.withAssumptions()) return;
00179   if(!res.getAssumptions().isNull()) {
00180     res.clearAllFlags();
00181     checkAssump(res, res, assumptions);
00182   }
00183 }
00184 #endif
00185 
00186 
00187 
00188 
00189 ////////////////////////////
00190 // New Search Engine Code //
00191 ////////////////////////////
00192 
00193 
00194 bool SearchEngineFast::checkSAT()
00195 {
00196   d_inCheckSAT=true;
00197   if (!bcp()) { // run an initial bcp
00198     DebugAssert(d_factQueue.empty(), "checkSAT()");
00199     if (!fixConflict()) {
00200       d_inCheckSAT=false;
00201       return false;
00202     }
00203   }
00204   while (true) {
00205     if (split()) {   // if we were able to split successfully
00206       // Run BCP
00207       while (!bcp()) {  // while bcp finds conflicts
00208         DebugAssert(d_factQueue.empty(), "checkSAT()");
00209         d_decisionEngine->goalSatisfied();
00210 
00211         // Try to fix those conflicts by rolling back contexts and
00212         // adding new conflict clauses to help in the future.
00213         if (!fixConflict()) { // if can't fix conflict
00214           d_inCheckSAT=false;
00215           return false; // UNSAT
00216         }
00217       }
00218     }
00219     // Now we couldn't find a splitter.  This may have been caused by
00220     // other reasons, so we allow them to be processed here.
00221     else {
00222       d_inCheckSAT=false;
00223       return true; // SAT
00224     }
00225   }
00226 }
00227 
00228 
00229 /* There are different heurisitics for splitters available.  We would
00230  * normally try to use the new generic decision class, but initially
00231  * we want this just to work, and so we use a custom decision class
00232  * that knows about this particular search engine.  We can realize
00233  * this same behavior using the existing mechanism by having a
00234  * decision subclass dynamic_cast the received SearchEngine pointer as
00235  * a SearchEngineFast and work from there.  However, as of this time I
00236  * do not plan on supporting the nextClause() and nextNonClause()
00237  * functionality, as they don't make much sense in this kind of modern
00238  * solver.  It may make more sense to have the solver and it's literal
00239  * splitting heuristic tightly connected, but leaving the nonLiteral
00240  * splitting heurisitic separate, since it is generally independent of
00241  * the search mechanism.
00242  *
00243  * By this point we've already guaranteed that we need to split: no
00244  * unit clauses, and no conflicts.  The procedure is as follows.  Ask
00245  * the decision engine for an expression to split on.  The decision
00246  * engine dutifully returns an expression.  We craft an assumption out
00247  * of this and assert it to the core (after making sure d_assumptions
00248  * has a copy).
00249  *
00250  * If no splitters are available, we still have to let the decision
00251  * procedures have a final chance at showing the context is
00252  * inconsistent by calling checkSATcore().  If we get a false out of
00253  * this, we have to continue processing, so the context is left
00254  * unchanged, no splitter is chosen, and we return true to let the
00255  * bcp+conflict processing have another chance.  If we get true, then
00256  * the problem is SAT and we are done, so we return false.
00257  *
00258  * Otherwise, we obtain the splitter, then ship it back off to the
00259  * decision engine for processing.
00260  */
00261 
00262 bool SearchEngineFast::split()
00263 {
00264   TRACE_MSG("search basic", "Choosing splitter");
00265   Expr splitter = findSplitter();
00266   if (splitter.isNull()) {
00267     TRACE_MSG("search basic", "No splitter");
00268     bool res(d_core->inconsistent() || !d_core->checkSATCore());
00269     if(!res) {
00270       d_splitterCount = 0; // Force resorting splitters next time
00271       res = !bcp();
00272     }
00273     return res;
00274   }
00275   Literal l(newLiteral(splitter));
00276   Theorem simp;
00277   if(l.getValue() != 0) {
00278     // The literal is valid at a lower scope than it has been derived,
00279     // and therefore, it was lost after a scope pop.  Reassert it here.
00280     simp = l.deriveTheorem();
00281     d_literals.push_back((l.getValue() == 1)? l : !l);
00282     d_core->addFact(simp);
00283     return true;
00284   }
00285   else {
00286     simp = d_core->simplify(splitter);
00287     const Expr& e = simp.getRHS();
00288     if(e.isBoolConst()) {
00289       IF_DEBUG(debugger.counter("splitter simplified to TRUE or FALSE")++);
00290       if(e.isTrue()) simp = d_commonRules->iffTrueElim(simp);
00291       else {
00292         if(splitter.isNot())
00293           simp = d_commonRules->notNotElim(d_commonRules->iffFalseElim(simp));
00294         else
00295           simp = d_commonRules->iffFalseElim(simp);
00296       }
00297       TRACE("search full", "Simplified candidate: ", splitter.toString(), "");
00298       TRACE("search full", "                  to: ",
00299             simp.getExpr().toString(), "");
00300       // Send this literal to DPs and enqueue it for BCP
00301       d_core->addFact(simp);
00302       addLiteralFact(simp);
00303       DebugAssert(l.getValue()!=0, "SearchFast::split(): l = "+l.toString());
00304       return true;
00305     }
00306   }
00307 
00308   TRACE("search terse", "Asserting splitter: #"
00309         +int2string(d_core->getStatistics().counter("splitters"))+": ",
00310         splitter, "");
00311   d_decisionEngine->pushDecision(splitter);
00312   return true;
00313 }
00314 
00315 //! Total order on literals for the initial sort
00316 /*! Used for debugging, to match Chaff's behavior as close as possible
00317   and track any discrepancies or inefficiencies. */
00318 // static bool compareInitial(const Literal& l1, const Literal& l2) {
00319 //   Expr lit1 = l1.getVar().getExpr();
00320 //   Expr lit2 = l2.getVar().getExpr();
00321 //   if(lit1.hasOp() && lit2.hasOp()) {
00322 //     int i = atoi(&(lit1.getOp().getName().c_str()[2]));
00323 //     int j = atoi(&(lit2.getOp().getName().c_str()[2]));
00324 //     return (i < j);
00325 //   }
00326 //   else
00327 //     return (l1.score() > l2.score());
00328 // }
00329 
00330 //! Ordering on literals, used to sort them by score
00331 static inline bool compareLits(const Literal& l1, 
00332                                const Literal& l2) 
00333 {
00334   return (l1.score() > l2.score());
00335 }
00336 
00337 IF_DEBUG(static string lits2str(const vector<Literal>& lits) {
00338   ostringstream ss;
00339   ss << "\n[";
00340   for(vector<Literal>::const_iterator i=lits.begin(), iend=lits.end();
00341       i!=iend; ++i)
00342     ss << *i << "\n ";
00343   ss << "\n]";
00344   return ss.str();
00345 });
00346 
00347 
00348 /*!
00349  * Recompute the scores for all known literals.  This is a relatively
00350  * expensive procedure, so it should not be called too often.
00351  * Currently, it is called once per 100 splitters.
00352  */
00353 void SearchEngineFast::updateLitScores(bool firstTime)
00354 {
00355   TRACE("search literals", "updateLitScores(size=", d_litsByScores.size(),
00356         ") {");
00357   unsigned count, score;
00358 
00359   if (firstTime && followChaff) {
00360     ::stable_sort(d_litsByScores.begin(), d_litsByScores.end(), compareLits);
00361   }
00362 
00363   for(size_t i=0; i< d_litsByScores.size(); ++i) {
00364     // Reading by value, since we'll be modifying the attributes.
00365     Literal lit = d_litsByScores[i];
00366     // First, clean up the unused literals
00367     while(lit.count()==0 && i+1 < d_litsByScores.size()) {
00368       TRACE("search literals", "Removing lit["+int2string(i)+"] = ", lit,
00369             " from d_litsByScores");
00370       // Remove this literal from the list
00371       lit.added()=false;
00372       lit = d_litsByScores.back();
00373       d_litsByScores[i] = lit;
00374       d_litsByScores.pop_back();
00375     }
00376     // Take care of the last literal in the vector
00377     if(lit.count()==0 && i+1 == d_litsByScores.size()) {
00378       TRACE("search literals", "Removing last lit["+int2string(i)+"] = ", lit,
00379             " from d_litsByScores");
00380       lit.added()=false;
00381       d_litsByScores.pop_back();
00382       break; // Break out of the loop -- no more literals to process
00383     }
00384 
00385     TRACE("search literals", "Updating lit["+int2string(i)+"] = ", lit, " {");
00386 
00387     DebugAssert(lit == d_litsByScores[i], "lit = "+lit.toString());
00388     DebugAssert(lit.added(), "lit = "+lit.toString());
00389     DebugAssert(lit.count()>0, "lit = "+lit.toString());
00390 
00391     count = lit.count();
00392     unsigned& countPrev = lit.countPrev();
00393     int& scoreRef = lit.score();
00394 
00395     score = scoreRef/2 + count - countPrev;
00396     scoreRef = score;
00397     countPrev = count;
00398 
00399     TRACE("search literals", "Updated lit["+int2string(i)+"] = ", lit, " }");
00400 //     Literal neglit(!lit);
00401 
00402 //     count = neglit.count();
00403 //     unsigned& negcountPrev = neglit.countPrev();
00404 //     unsigned& negscoreRef = neglit.score();
00405 
00406 //     negscore = negscoreRef/2 + count - negcountPrev;
00407 //     negscoreRef = negscore;
00408 //     negcountPrev = count;
00409 
00410 //     if(negscore > score) d_litsByScores[i] = neglit;
00411   }
00412   ::stable_sort(d_litsByScores.begin(), d_litsByScores.end(), compareLits);
00413   d_litsMaxScorePos = 0;
00414   d_litSortCount=d_litsByScores.size();
00415   TRACE("search splitters","updateLitScores => ", lits2str(d_litsByScores),"");
00416   TRACE("search literals", "updateLitScores(size=", d_litsByScores.size(),
00417         ") => }");
00418 }
00419 
00420 void SearchEngineFast::updateLitCounts(const Clause& c)
00421 {
00422   TRACE("search literals", "updateLitCounts(", CompactClause(c), ") {");
00423   for(unsigned i=0; i<c.size(); ++i) {
00424     // Assign by value to modify the attributes
00425     Literal lit = c[i];
00426     DebugAssert(lit.getExpr().isAbsLiteral(),"Expected literal");
00427     // Only add the literal if it wasn't added before.  The literal
00428     // counts are taken care of in Clause constructors/destructors.
00429 //     if(!lit.added() || lit.count() != lit.countPrev())
00430     d_litSortCount--;
00431     
00432     if(!lit.added()) {
00433       TRACE("search literals", "adding literal ", lit, " to d_litsByScores");
00434       d_litsByScores.push_back(lit);
00435       lit.added()=true;
00436     }
00437   }
00438   if(d_litSortCount < 0) {
00439     ::stable_sort(d_litsByScores.begin(), d_litsByScores.end(), compareLits);
00440     d_litSortCount=d_litsByScores.size();
00441   }
00442   TRACE("search splitters","updateLitCounts => ", lits2str(d_litsByScores),"");
00443   TRACE_MSG("search literals", "updateLitCounts => }");
00444 }
00445 
00446 Expr SearchEngineFast::findSplitter()
00447 {
00448   TRACE_MSG("splitters", "SearchEngineFast::findSplitter() {");
00449   Expr splitter; // Null by default
00450   unsigned i;
00451 
00452   // if we have a conflict clause, pick the one inside with the
00453   // best ac(z) score (from the most recent conflict clause)
00454   //  if (d_berkminFlag && !d_conflictClauses.empty())
00455   if (d_berkminFlag && !d_conflictClauses->empty())
00456   {
00457     unsigned sCount = 0;
00458     std::deque<ClauseOwner>::reverse_iterator foundUnsat = d_conflictClauses->rend();
00459     for (std::deque<ClauseOwner>::reverse_iterator i = d_conflictClauses->rbegin();
00460          i != d_conflictClauses->rend();
00461          ++i) {
00462       ++sCount;
00463       if (!((Clause)*i).sat(true)) {
00464         foundUnsat = i;
00465         break;
00466       }
00467     }
00468     if (foundUnsat != d_conflictClauses->rend()) {
00469       Clause &topClause = *foundUnsat;
00470       int numLits = topClause.size();
00471       int bestScore = 0;
00472       int bestLit = -1;
00473       unsigned numChoices = 0;
00474       for (int i = 0; i < numLits; ++i) {
00475         const Literal& lit = topClause[i];
00476         if (lit.getValue() != 0) continue;
00477         if (bestLit == -1) bestLit = i;
00478         ++numChoices;
00479         int s = lit.score();
00480         if (s > bestScore) {
00481           bestLit = i;
00482           bestScore = s;
00483         }
00484       }
00485       if (bestLit != -1) {
00486         splitter = topClause[bestLit].getExpr();
00487         IF_DEBUG(debugger.counter("BerkMin heuristic")++); 
00488         TRACE("splitters", "SearchEngineFast::findSplitter()[berkmin] => ",
00489               splitter, " }"); 
00490         return splitter;
00491       }
00492     }
00493   } 
00494 
00495   /*
00496   // Search for DP-specific splitters
00497   for(CDMapOrdered<Splitter,bool>::iterator i=d_dpSplitters.begin(),
00498         iend=d_dpSplitters.end(); i!=iend; ++i) {
00499     Expr e((*i).first.expr);
00500     if(e.isBoolConst() || d_core->find(e).getRHS().isBoolConst())
00501       continue;
00502     return e;
00503   }
00504   */
00505 
00506   for (int i = d_nonLiterals.size()-1; i >= 0; --i) {
00507     const Expr& e = d_nonLiterals[i].get().getExpr();
00508     if (e.isTrue()) continue;
00509     //    if (d_nonLiteralSimplified[thm.getExpr()]) continue;
00510     DebugAssert(!e.isBoolConst(), "Expected non-bool const");
00511     DebugAssert(d_core->simplifyExpr(e) == e,
00512                 "Expected non-literal to be simplified:\n e = "
00513                 +e.toString()+"\n simplify(e) = "
00514                 +d_core->simplifyExpr(e).toString());
00515     splitter = d_decisionEngine->findSplitter(e);
00516     //DebugAssert(!splitter.isNull(),
00517     //            "findSplitter: can't find splitter in non-literal: "
00518     //            + e.toString());
00519     if (splitter.isNull()) continue;
00520     IF_DEBUG(debugger.counter("splitters from non-literals")++);          
00521     TRACE("splitters", "SearchEngineFast::findSplitter()[non-lit] => ",
00522           splitter, " }"); 
00523     return splitter;
00524   }
00525 
00526   // Update the scores: we are about to choose a splitter based on them
00527   if (d_splitterCount <= 0) {
00528     updateLitScores(false);
00529 //     d_splitterCount = d_litsByScores.size();
00530 //     if(d_splitterCount > 100)
00531       d_splitterCount = 0x10;
00532   } else
00533     d_splitterCount--;
00534   // pick splitter based on score
00535   for (i=d_litsMaxScorePos; i<d_litsByScores.size(); ++i) {
00536     const Literal& splitterLit = d_litsByScores[i];
00537     TRACE("search splitters", "d_litsByScores["+int2string(i)+"] = ",
00538           splitterLit,"");
00539     //if (d_core->simplifyExpr(splitter).isBoolConst()) continue;
00540     if(splitterLit.getValue() != 0) continue;
00541     splitter = splitterLit.getExpr();
00542     // Skip auxiliary CNF vars
00543     if(!isGoodSplitter(splitter)) continue;
00544     d_litsMaxScorePos = i+1;
00545     IF_DEBUG(debugger.counter("splitters from literals")++);
00546     TRACE("splitters", "d_litsMaxScorePos: ", d_litsMaxScorePos, "");
00547     TRACE("splitters", "SearchEngineFast::findSplitter()[lit] => ",
00548           splitter, " }"); 
00549     return splitter;
00550   }
00551   TRACE_MSG("splitters",
00552             "SearchEngineFast::findSplitter()[not found] => Null }");
00553   return Expr();
00554 }
00555 
00556 
00557 void SearchEngineFast::recordFact(const Theorem& thm)
00558 {
00559   Literal l(newLiteral(thm.getExpr()));
00560   if(l.getValue() == 0) {
00561     l.setValue(thm, thm.getScope());
00562     IF_DEBUG(debugger.counter("recordFact adds unreported lit")++);
00563     d_unreportedLits.insert(l.getExpr(),thm,thm.getScope());
00564   } else if (l.getValue() == 1 && l.getScope() > thm.getScope()) {
00565     // Cannot do this, it will trigger DebugAssert
00566     // l.setValue(thm,thm.getScope());
00567     IF_DEBUG(debugger.counter("recordFact adds unreported lit")++);
00568     d_unreportedLits.insert(l.getExpr(),thm,thm.getScope());
00569   } else if(l.getValue() < 0) { // Contradiction, bcp will die anyway
00570     if(l.isNegative())
00571       setInconsistent(d_commonRules->contradictionRule(l.deriveTheorem(), thm));
00572     else
00573       setInconsistent(d_commonRules->contradictionRule(thm, l.deriveTheorem()));
00574   }
00575   //else if (thm.getScope() < scopeLevel())
00576   //  d_unreportedLits.insert(l.getExpr(),l,thm.getScope());
00577   
00578 }
00579 
00580 #ifdef DEBUG
00581 void SearchEngineFast::fullCheck()
00582 {
00583   for (unsigned i = 0;
00584        i < d_clauses.size();
00585        ++i) {
00586     if (!((Clause)d_clauses[i]).sat()) {
00587       bool sat = false;
00588       const Clause &theClause = d_clauses[i];
00589       unsigned numLits = theClause.size();
00590       unsigned numChoices = 0;
00591       for (unsigned j = 0; !sat && j < numLits; ++j) {
00592         if (theClause[j].getValue() == 0)
00593           ++numChoices;
00594         else if (theClause[j].getValue() == 1)
00595           sat = true;
00596       }
00597       if (sat) continue;
00598       if (numChoices <= 1 || !theClause.wpCheck()) {
00599         CVCL::debugger.getOS() << CompactClause(theClause) << endl;
00600         CVCL::debugger.getOS() << theClause.toString() << endl;
00601       }
00602       DebugAssert(numChoices > 1, "BCP postcondition violated: unsat or unit clause(s)");
00603       DebugAssert(theClause.wpCheck(), "Watchpointers broken");
00604     }
00605   }
00606 
00607   if (!d_conflictClauses->empty())
00608   {
00609     for (std::deque<ClauseOwner>::reverse_iterator i = d_conflictClauses->rbegin();
00610          i != d_conflictClauses->rend();
00611          ++i) {
00612       if (!((Clause)*i).sat()) {
00613         bool sat = false;
00614         Clause &theClause = *i;
00615         unsigned numLits = theClause.size();
00616         unsigned numChoices = 0;
00617         for (unsigned j = 0; !sat && j < numLits; ++j) {
00618            if (theClause[j].getValue() == 0)
00619             ++numChoices; 
00620            else if (theClause[j].getValue() == 1)
00621              sat = true;
00622         }
00623         if (sat) continue;
00624         if (numChoices <= 1 || !theClause.wpCheck()) {
00625           CVCL::debugger.getOS() << CompactClause(theClause) << endl;
00626           CVCL::debugger.getOS() << theClause.toString() << endl;
00627         }
00628         
00629         DebugAssert(numChoices > 1, "BCP postcondition violated: unsat or unit conflict clause(s)");
00630         DebugAssert(theClause.wpCheck(), "Watchpointers broken");
00631       
00632       }
00633     }
00634   } 
00635 }
00636 #endif
00637 
00638 
00639 void SearchEngineFast::clearLiterals() {
00640   TRACE_MSG("search literals", "clearLiterals()");
00641   d_literals.clear();
00642 }
00643 
00644 
00645 bool SearchEngineFast::bcp()
00646 {
00647   TRACE("search bcp", "bcp@"+int2string(scopeLevel())+"(#lits=",
00648         d_literals.size(), ") {");
00649   IF_DEBUG(TRACE_MSG("search bcp", "literals=[\n");
00650            for(size_t i=0,iend=d_literals.size(); i<iend; i++)
00651            TRACE("search bcp", "          ", d_literals[i], ",");
00652            TRACE_MSG("search bcp", "]"));
00653   DebugAssert(d_factQueue.empty(), "bcp(): start");
00654   bool newInfo = true;
00655   /*
00656   CDMap<Expr,Theorem>::iterator i = d_unreportedLits.begin(),
00657     iend = d_unreportedLits.end();
00658   for (; i != iend; ++i) {
00659     if (d_unreportedLitsHandled[(*i).first])
00660       continue;
00661     Theorem thm((*i).second);
00662     Literal l(newLiteral(thm.getExpr()));
00663     DebugAssert(l.getValue() != -1, "Bad unreported literal: "+l.toString());
00664     if(l.getValue() == 0) l.setValue(thm, scopeLevel());
00665     IF_DEBUG(debugger.counter("re-assert unreported lits")++);
00666     DebugAssert(l.getExpr().isAbsLiteral(),
00667                 "bcp(): pushing non-literal to d_literals:\n "
00668                 +l.getExpr().toString());
00669     // The literal may be set to 1, but not on the list; push it here
00670     // explicitly
00671     d_literals.push_back(l);
00672     //recordFact((*i).second.getTheorem());
00673     enqueueFact(thm);
00674     d_unreportedLitsHandled[(*i).first] = true;
00675   }
00676   */
00677   while (newInfo) {
00678     IF_DEBUG(debugger.counter("BCP: while(newInfo)")++);
00679     TRACE_MSG("search bcp", "while(newInfo) {");
00680     newInfo = false;
00681     while(!d_core->inconsistent() && d_literals.size() > 0) {
00682      for(unsigned i=0; !d_core->inconsistent() && i<d_literals.size(); ++i) {
00683       Literal l = d_literals[i];
00684       TRACE("search props", "Propagating literal: [", l.toString(), "]");
00685       DebugAssert(l.getValue() == 1, "Bad literal is d_literals: "
00686                   +l.toString());
00687       d_litsAlive.push_back(l);
00688       // Use the watch pointers to find more literals to assert.  Repeat
00689       // until conflict.  Once conflict found, call unsatClause() to
00690       // assert the contradiction.
00691       std::vector<std::pair<Clause, int> >& wps = wp(l);
00692       TRACE("search props", "Appears in ", wps.size(), " clauses.");
00693       for(unsigned j=0; j<wps.size(); ++j) {
00694         const Clause& c = wps[j].first;
00695         int k = wps[j].second;
00696         DebugAssert(c.watched(k).getExpr() == (!l).getExpr(),
00697                     "Bad watched literal:\n l = "+l.toString()
00698                     +"\n c[k] = "+c.watched(k).toString());
00699         if(c.deleted()) { // Remove the clause from the list
00700           if(wps.size() > 1) {
00701             wps[j] = wps.back();
00702             --j;
00703           }
00704           wps.pop_back();
00705         } else if(true || !c.sat()) {
00706           // Call BCP to update the watch pointer
00707           bool wpUpdated;
00708           bool conflict = !propagate(c, k, wpUpdated);
00709           // Delete the old watch pointer from the list
00710           if(wpUpdated) {
00711             if(wps.size() > 1) {
00712               wps[j] = wps.back();
00713               --j;
00714             }
00715             wps.pop_back();
00716           }
00717           if (conflict) {
00718             clearFacts();
00719             DebugAssert(d_factQueue.empty(), "bcp(): conflict");
00720             TRACE_MSG("search bcp", "bcp[conflict] => false }}");
00721             return false;
00722           }
00723         }
00724       }
00725 
00726       vector<Circuit*>& cps = d_circuitsByExpr[l.getExpr()];
00727       for (vector<Circuit*>::iterator it = cps.begin(), end = cps.end();
00728            it < end; it++)
00729       {
00730         if (!(*it)->propagate(this)) {
00731           clearFacts();
00732           DebugAssert(d_factQueue.empty(), "bcp(): conflict-2");
00733           TRACE_MSG("search bcp", "bcp[circuit propagate] => false }}");
00734           return false;
00735         }
00736       }
00737      }
00738      // Finished with BCP* (without DPs).
00739      clearLiterals();
00740      // Now, propagate the facts to DPs and repeat ((BCP*); DP) step
00741      if(!d_core->inconsistent()) commitFacts();
00742     }
00743     if (d_core->inconsistent()) {
00744       d_conflictTheorem = d_core->inconsistentThm();
00745       clearFacts();
00746       TRACE_MSG("search bcp", "bcp[DP conflict] => false }}");
00747       return false;
00748     }
00749     else
00750       TRACE("search basic", "Processed ", d_literals.size(), " propagations");
00751     IF_DEBUG(fullCheck());
00752     clearLiterals();
00753 
00754     bool dfs_heuristic = (d_core->getFlags()["de"].getString() == "dfs");
00755     TRACE("search dfs", "DFS is ", (dfs_heuristic? "on" : "off"),
00756           " (de = "+d_core->getFlags()["de"].getString()+") {");
00757     // When DFS heuristic is used, simplify the nonliterals only until
00758     // there is a completely simplified one on top of the stack, or
00759     // all of the non-literals are gone.  Start from the end of the
00760     // list (top of the stack), since that's where the splitter is
00761     // most likely chosen.  This way we are likely to hit something
00762     // that simplifies very soon.
00763 
00764     size_t origSize = d_nonLiterals.size();
00765     bool done(false);
00766     for(int i=origSize-1; !done && !d_core->inconsistent() && i>=0; --i) {
00767       const Theorem& thm = d_nonLiterals[i].get();
00768       const Expr& e = thm.getExpr();
00769       TRACE("search dfs", "Simplifying non-literal", e, "");
00770       if (e.isTrue()) {
00771         //      if (d_nonLiteralSimplified[thm.getExpr()]) {
00772         IF_DEBUG(debugger.counter("BCP: simplified non-literals: skipped [stale]")++);
00773         TRACE_MSG("search bcp", "}[continue]// end of while(newInfo)");
00774         continue;
00775       }
00776       IF_DEBUG(debugger.counter("BCP: simplified non-literals")++);
00777       Theorem simpThm = simplify(thm);
00778       Expr simp = simpThm.getExpr();
00779       if(simp != e) {
00780         IF_DEBUG(debugger.counter("BCP: simplified non-literals: changed")++);
00781         newInfo = true;
00782         //        d_nonLiteralSimplified[thm.getExpr()] = true;
00783         if (!simp.isFalse()) {
00784           while (simp.isExists()) {
00785             simpThm = d_commonRules->skolemize(simpThm);
00786             simp = simpThm.getExpr();
00787           }
00788           if (simp.isAbsLiteral()) {
00789             enqueueFact(simpThm);
00790             commitFacts();
00791           }
00792           d_nonLiterals[i] = simpThm;
00793           if(dfs_heuristic) {
00794             // Something has changed, time to stop this loop.  If we
00795             // also get a new non-literal on top of the stack, and no
00796             // new literals, then stop the entire BCP (since that
00797             // non-literal is guaranteed to be fully simplified).
00798             done = true;
00799             if(d_nonLiterals.size() > origSize && d_literals.empty())
00800               newInfo = false;
00801           }
00802         } else
00803           setInconsistent(simpThm);
00804       } else if (dfs_heuristic) done = true;
00805     }
00806     TRACE("search dfs", "End of non-literal simplification: newInfo = ",
00807           (newInfo? "true" : "false"), " }}");
00808     if (d_core->inconsistent()) {
00809       d_conflictTheorem = d_core->inconsistentThm();
00810       DebugAssert(d_factQueue.empty(), "bcp(): inconsistent (nonLits)");
00811       TRACE_MSG("search bcp", "bcp[nonCNF conflict] => false }}");
00812       return false;
00813     }
00814     TRACE_MSG("search bcp", "}// end of while(newInfo)");
00815   }
00816   IF_DEBUG(fullCheck());
00817   DebugAssert(d_factQueue.empty(), "bcp(): end");
00818   TRACE_MSG("search bcp", "bcp => true }");
00819   return true;
00820 }
00821 
00822 
00823 // True if successfully propagated.  False if conflict.
00824 bool SearchEngineFast::propagate(const Clause &c, int idx, bool& wpUpdated)
00825 {
00826   TRACE("search propagate", "propagate(", CompactClause(c),
00827         ", idx = "+int2string(idx)+") {");
00828   DebugAssert(idx==0 || idx==1, "propagate(): bad index = "+int2string(idx));
00829   // The current watched literal must be set to FALSE, unless the
00830   // clause is of size 1
00831   DebugAssert((c.size() == 1) ||  c.watched(idx).getValue() < 0,
00832               "propagate(): this literal must be FALSE: c.watched("
00833               +int2string(idx)+")\n c = "+c.toString());
00834   wpUpdated = false;
00835   int lit = c.wp(idx), otherLit = c.wp(1-idx);
00836   int dir = c.dir(idx);
00837   int size = c.size();
00838   while(true) {
00839     TRACE_MSG("search propagate", "propagate: lit="+int2string(lit)
00840               +", otherLit="+int2string(otherLit)+", dir="+int2string(dir));
00841     lit += dir;
00842     if(lit < 0 || lit >= size) { // hit the edge
00843       if(dir == c.dir(idx)) {
00844         // Finished first half of the clause, do the other half
00845         lit = c.wp(idx);
00846         dir = -dir;
00847         continue;
00848       }
00849       // All literals are false, except for the other watched literal.
00850       // Check its value.
00851       Literal l(c[otherLit]);
00852       if(l.getValue() < 0) { // a conflict
00853         //Literal ff(newLiteral(d_vcl->getEM()->falseExpr()));
00854         //ff.setValue(1, c, -1);
00855         //d_lastBCPConflict = ff;
00856         vector<Theorem> thms;
00857         for (unsigned i = 0; i < c.size(); ++i)
00858           thms.push_back(c[i].getTheorem());
00859         d_conflictTheorem = d_rules->conflictRule(thms,c.getTheorem());
00860         TRACE("search propagate", "propagate[", CompactClause(c),
00861               "] => false }");
00862         return false;
00863       }
00864       else if(l.getValue() == 0) {
00865         DebugAssert(c.size() > 1 && l.getExpr().isAbsLiteral(), "BCP: Expr should be literal");
00866         d_unitPropCount++;
00867         c.markSat();
00868         // Let's prove the new literal instead of playing assumption games
00869         unitPropagation(c,otherLit);
00870         //l.setValue(1, c, otherLit);
00871         //d_core->addFact(createAssumption(l));
00872         TRACE("search propagate", "propagate[", CompactClause(c),
00873               "] => true }");
00874         return true;
00875       }
00876       else {
00877         c.markSat();
00878         TRACE("search propagate", "propagate[", CompactClause(c),
00879               "] => true }");
00880         return true;
00881       }
00882     }
00883     // If it's the other watched literal, skip it
00884     if(lit == otherLit) continue;
00885 
00886     Literal l(c[lit]);
00887     int val(l.getValue());
00888     // if it is false, keep looking
00889     if(val < 0) continue;
00890     // OPTIMIZATION: if lit is TRUE, mark the clause SAT and give up.
00891     // FIXME: this is different from Chaff.  Make sure it doesn't harm
00892     // the performance.
00893      if(val > 0) {
00894        c.markSat();
00895 //       return true;
00896      }
00897 
00898     // Now the value of 'lit' is unknown.  Set the watch pointer to
00899     // this literal, if it is indeed a literal (it may be any formula
00900     // in a pseudo-clause), and update the direction.
00901     c.wp(idx, lit);
00902     c.dir(idx, dir);
00903     DebugAssert(c.watched(idx).getValue() >= 0,
00904                 "Bad watched literals in clause:\n"
00905                 +CompactClause(c).toString());
00906     // Get the expression of the literal's inverse
00907     Literal inv(!c[lit]);
00908     // If it is indeed a literal, update the watch pointers
00909     DebugAssert(inv.getExpr().isAbsLiteral(), "Expr should be literal: inv = "
00910                 +inv.getExpr().toString());
00911     // Add the new watched literal to the watch pointer list
00912     pair<Clause, int> p(c, idx);
00913     wp(inv).push_back(p);
00914 
00915     // Signal to remove the old watch pointer
00916     wpUpdated = true;
00917     TRACE("search propagate", "propagate[", CompactClause(c),
00918           "] => true }");
00919     return true;
00920   }
00921 }
00922 
00923 void SearchEngineFast::unitPropagation(const Clause &c, unsigned idx)
00924 {  
00925   vector<Theorem> thms;
00926   for (unsigned i = 0; i < c.size(); ++i)
00927     if (i != idx) {
00928       thms.push_back(c[i].getTheorem());
00929       DebugAssert(!thms.back().isNull(),
00930                   "unitPropagation(idx = "+int2string(idx)+", i = "
00931                   +int2string(i)+",\n"+c.toString()+")");
00932     }
00933   Theorem thm(d_rules->unitProp(thms,c.getTheorem(),idx));
00934   enqueueFact(thm); // d_core->addFact(thm);
00935   // recordFact(thm);
00936 
00937   DebugAssert(thm.isAbsLiteral(),
00938               "unitPropagation(): pushing non-literal to d_literals:\n "
00939               +thm.getExpr().toString());
00940   Literal l(newLiteral(thm.getExpr()));
00941   DebugAssert(l.getValue() == 1, "unitPropagation: bad literal: "
00942               +l.toString());
00943   d_literals.push_back(l);
00944 }
00945 
00946 
00947 bool SearchEngineFast::fixConflict()
00948 {
00949   TRACE_MSG("search basic", "FixConflict");
00950   Theorem res, conf;
00951   d_conflictCount++;
00952   TRACE("conflicts", "found conflict # ", d_conflictCount, "");
00953   IF_DEBUG(if(debugger.trace("impl graph verbose")) {
00954     d_conflictTheorem.printDebug();
00955   });
00956 
00957   if (scopeLevel() == d_bottomScope)
00958     return false;
00959   else if(d_conflictTheorem.getScope() <= d_bottomScope) {
00960     d_decisionEngine->popTo(d_bottomScope);
00961     d_litsMaxScorePos = 0; // from decision engine
00962     clearLiterals();
00963     return false;
00964   }
00965 
00966   traceConflict(d_conflictTheorem);
00967   
00968   if (d_lastConflictScope <= d_bottomScope)
00969     return false;
00970 
00971   // If we have unit conflict clauses, then we have to bounce back to
00972   // the original scope and assert them.
00973   if(d_unitConflictClauses.size() > 0) {
00974     TRACE_MSG("search basic", "Found unit conflict clause");
00975     d_decisionEngine->popTo(d_bottomScope);
00976     d_litsMaxScorePos = 0; // from decision engine
00977     clearLiterals();
00978     for (vector<Clause>::reverse_iterator i = d_unitConflictClauses.rbegin();
00979          i != d_unitConflictClauses.rend();
00980          ++i) {
00981       //IF_DEBUG(checkAssumpDebug(i->getTheorem(), d_assumptions));
00982       // The theorem of *i is, most likely, (OR lit); rewrite it to just `lit'
00983       Theorem thm = i->getTheorem();
00984       if(thm.getExpr().isOr())
00985         thm = d_commonRules->iffMP(thm, d_commonRules->rewriteOr(thm.getExpr()));
00986       enqueueFact(thm);
00987       commitFacts(); // Make sure facts propagate to DPs
00988     }
00989     d_unitConflictClauses.clear();
00990     return true; // Let bcp take care of the rest.
00991   }
00992 
00993   // Otherwise, we need to make our failure driven assertion.
00994   DebugAssert(!d_lastConflictClause.isNull(), "");
00995 
00996   // We need to calculate the backtracking level.  We do this by
00997   // examining the decision levels of all the literals involved in the
00998   // last conflict clause.
00999 
01000   Clause &c = d_lastConflictClause;
01001   Literal unit_lit;
01002   unsigned idx=0;
01003   unsigned current_dl = d_lastConflictScope;
01004   unsigned back_dl = d_bottomScope;
01005   for (unsigned i = 0; i < c.size(); ++i) {
01006     unsigned dl = c[i].getVar().getScope();
01007     if (dl < current_dl) {
01008       if (dl > back_dl)
01009         back_dl = dl;
01010     }
01011     else {
01012       DebugAssert(unit_lit.getExpr().isNull(),
01013                   "Only one lit from the current decision level is allowed.\n"
01014                   "current_dl="
01015                   +int2string(current_dl)+", scopeLevel="
01016                   +int2string(scopeLevel())
01017                   +"\n l1 = "
01018                   +unit_lit.toString()
01019                   +"\n l2 = "+c[i].toString()
01020                   +"\nConflict clause: "+c.toString());
01021       unit_lit = c[i];
01022       idx = i;
01023     }
01024   }
01025 
01026 
01027   // Now we have the backtracking decision level.
01028   DebugAssert(!unit_lit.getExpr().isNull(),"Need to have an FDA in "
01029               "conflict clause: "+c.toString());
01030   d_decisionEngine->popTo(back_dl);
01031   d_litsMaxScorePos = 0; // from decision engine
01032   clearLiterals();
01033   unitPropagation(c,idx);
01034   commitFacts(); // Make sure facts propagate to DPs
01035   return true;
01036 }
01037 
01038 
01039 void SearchEngineFast::enqueueFact(const Theorem& thm) {
01040   //  d_core->addFact(thm);
01041   TRACE("search props", "SearchEngineFast::enqueueFact(",
01042         thm.getExpr(), ") {");
01043   if(thm.isAbsLiteral()) {
01044     addLiteralFact(thm);
01045   }
01046   d_factQueue.push_back(thm);
01047   TRACE_MSG("search props", "SearchEngineFast::enqueueFact => }");
01048 }
01049 
01050 
01051 void SearchEngineFast::setInconsistent(const Theorem& thm) {
01052   TRACE_MSG("search props", "SearchEngineFast::setInconsistent()");
01053   d_factQueue.clear();
01054   IF_DEBUG(debugger.counter("conflicts from SAT solver")++);
01055   d_core->setInconsistent(thm);
01056 }
01057 
01058 void SearchEngineFast::commitFacts() {
01059   for(vector<Theorem>::iterator i=d_factQueue.begin(), iend=d_factQueue.end();
01060       i!=iend; ++i) {
01061     TRACE("search props", "commitFacts(", i->getExpr(), ")");
01062     if(d_useEnqueueFact)
01063       d_core->enqueueFact(*i);
01064     else
01065       d_core->addFact(*i);
01066   }
01067   d_factQueue.clear();
01068 }
01069 
01070 
01071 void SearchEngineFast::clearFacts() {
01072   TRACE_MSG("search props", "clearFacts()");
01073   d_factQueue.clear();
01074 }
01075 
01076 
01077 void SearchEngineFast::addNewClause(Clause &c)
01078 {
01079   DebugAssert(c.size() > 1, "New clauses should have size > 1");
01080   d_clauses.push_back(c);
01081   updateLitCounts(c);
01082   // Set up the watch pointers to this clause: find two unassigned
01083   // literals (otherwise we shouldn't even receive it as a clause)
01084   size_t i=0, iend=c.size();
01085   for(; i<iend && c[i].getValue() != 0; ++i);
01086   DebugAssert(i<iend, "SearchEngineFast::addNewClause:\n"
01087               "no unassigned literals in the clause:\nc = "
01088               +CompactClause(c).toString());
01089   c.wp(0,i); ++i;
01090   for(; i<iend && c[i].getValue() != 0; ++i);
01091   DebugAssert(i<iend, "SearchEngineFast::addNewClause:\n"
01092               "Only one unassigned literal in the clause:\nc = "
01093               +CompactClause(c).toString());
01094   c.wp(1,i);
01095   // Add the watched pointers to the appropriate lists
01096   for(int i=0; i<=1; i++) {
01097     Literal l(!c.watched(i));
01098     // Add the pointer to l's list
01099     pair<Clause, int> p(c, i);
01100     wp(l).push_back(p);
01101   }
01102 }
01103 
01104 inline bool TheoremEq(const Theorem& t1, const Theorem& t2) {
01105   DebugAssert(!t1.isNull() && !t2.isNull(),
01106               "analyzeUIPs() Null Theorem found");
01107    return t1.getExpr() == t2.getExpr();
01108 }
01109 
01110 
01111 //! Auxiliary function used in analyzeUIPs()
01112 /*! It processes a node and populates the relevant sets used in the
01113  * algorithm.
01114  * \sa analyzeUIPs() for more detail). 
01115  */
01116 static void processNode(const Theorem& thm, 
01117                         vector<Theorem>& lits,
01118                         vector<Theorem>& gamma,
01119                         vector<Theorem>& fringe,
01120                         int& pending) {
01121   // Decrease the fan-out count
01122   int fanOutCount(thm.getCachedValue() - 1);
01123   thm.setCachedValue(fanOutCount);
01124   bool wasFlagged(thm.isFlagged());
01125   thm.setFlag();
01126   DebugAssert(fanOutCount >= 0, 
01127               "analyzeUIPs(): node visited too many times: "
01128               +thm.toString());
01129   if(fanOutCount == 0) {
01130     if(thm.getExpandFlag()) {
01131       if(wasFlagged) {
01132         TRACE("impl graph", "pending.erase(", thm.getExpr(), ")");
01133         DebugAssert(pending > 0, 
01134                     "analyzeUIPs(): pending set shouldn't be empty here");
01135         pending--;
01136       }
01137       TRACE("impl graph", "fringe.insert(", thm.getExpr(), ")");
01138       fringe.push_back(thm);
01139     } else if(thm.getLitFlag()) {
01140       DebugAssert(thm.isAbsLiteral(), "analyzeUIPs(): bad flag on "
01141                   +thm.toString());
01142       if(wasFlagged) {
01143         TRACE("impl graph", "pending.erase(", thm.getExpr(), ")");
01144         DebugAssert(pending > 0, 
01145                     "analyzeUIPs(): pending set shouldn't be empty here");
01146         pending--;
01147       }
01148       TRACE("impl graph", "lits.insert(", thm.getExpr(), ")");
01149       lits.push_back(thm);
01150     } else {
01151       if(!wasFlagged) {
01152         TRACE("impl graph", "gamma.insert(", thm.getExpr(), ")");
01153         gamma.push_back(thm);
01154       } else {
01155         TRACE("impl graph", "already in gamma: ", thm.getExpr(), "");
01156       }
01157     }
01158   } else { // Fan-out count is non-zero
01159     if(thm.getExpandFlag()) {
01160       // Too early to expand; stash in pending
01161       if(!wasFlagged) {
01162         pending++;
01163         TRACE("impl graph", "pending.insert(", thm.getExpr(), ")");
01164       } else {
01165         TRACE("impl graph", "already in pending: ", thm.getExpr(), "");
01166       }
01167     } else if(thm.getLitFlag()) {
01168       // It's a literal which goes into pending
01169       if(!wasFlagged) {
01170         pending++;
01171         TRACE("impl graph", "pending.insert(", thm.getExpr(), ")");
01172       } else {
01173         TRACE("impl graph", "already in pending: ", thm.getExpr(), "");
01174       }
01175     } else {
01176       if(!wasFlagged) {
01177         TRACE("impl graph", "gamma.insert(", thm.getExpr(), ")");
01178         gamma.push_back(thm);
01179       } else {
01180         TRACE("impl graph", "already in gamma: ", thm.getExpr(), "");
01181       }
01182     }
01183   }
01184   // FIXME: uniquify theorems in lits, gamma, and fringe by
01185   // expression; the smallest scope theorem should supersede all the
01186   // duplicates.  Question: can we do it safely, without breaking the
01187   // UIP algorithm?
01188 }
01189 
01190 /*! 
01191  <strong>Finding UIPs (Unique Implication Pointers)</strong>
01192 
01193  This is basically the same as finding hammocks of the subset of the
01194  implication graph composed of only the nodes from the current scope.
01195  A hammock is a portion of the graph which has a single source and/or
01196  sink such that removing that single node makes the graph
01197  disconnected.
01198 
01199  Conceptually, the algorithm maintains four sets of nodes: literals
01200  (named <em>lits</em>), gamma, fringe, and pending.  Literals are
01201  nodes whose expressions will become literals in the conflict clause
01202  of the current hammock, and the nodes in gamma are assumptions from
01203  which such conflict clause theorem is derived.  Nodes in fringe are
01204  intermediate nodes which are ready to be "expanded" (see the
01205  algorithm description below).  The pending nodes are those which are
01206  not yet ready to be processed (they later become literal or fringe
01207  nodes).
01208 
01209  These sets are maintained as vectors, and are updated in such a way
01210  that the nodes in the vectors never repeat.  The exception is the
01211  pending set, for which only a size counter is maintained.  A node
01212  belongs to the pending set if it has been visited (isFlagged()
01213  method), and its fan-out count is non-zero (stored in the cache,
01214  getCachedValue()).  In other words, pending nodes are those that have
01215  been visited, but not sufficient number of times.
01216 
01217  Also, fringe is maintained as a pair of vectors.  One vector is
01218  always the current fringe, and the other one is built when the
01219  current is processed.  When processing of the current fringe is
01220  finished, it is cleared, and the other vector becomes the current
01221  fringe (that is, they swap roles).
01222 
01223  A node is expanded if it is marked for expansion (getExpandFlag()).
01224  If its fan-out count is not yet zero, it is added to the set of
01225  pending nodes.
01226 
01227  If a node has a literal flag (getLitFlag()), it goes into literals
01228  when its fan-out count reaches zero.  Since this will be the last
01229  time the node is visited, it is added to the vector only once.
01230 
01231  A node neither marked for expansion nor with the literal flag goes
01232  into the gamma set.  It is added the first time the node is visited
01233  (isFlagged() returns false), and therefore, is added to the vector
01234  only once.  This is an important distinction from the other sets,
01235  since a gamma-node may be used by several conflict clauses.
01236 
01237  Clearing the gamma set after each UIP requires both clearing the
01238  vector and resetting all flags (clearAllFlags()).
01239 
01240  <strong>The algorithm</strong>
01241 
01242 <ol>
01243 
01244 <li> Initially, the fringe contains exactly the predecessors of
01245     falseThm from the current scope which are ready to be expanded
01246     (fan-out count is zero).  All the other predecessors of falseThm
01247     go to the appropriate sets of literals, gamma, and pending.
01248 
01249 <li> If fringe.size() <= 1 and the set of pending nodes is empty, then
01250     the element in the fringe (if it's non-empty) is a UIP.  Generate
01251     a conflict clause from the UIP and the literals (using gamma as
01252     the set of assumptions), empty the sets, and continue with the
01253     next step.  Note, that the UIP remains in the fringe, and will be
01254     expanded in the next step.
01255 
01256     The important exception: if the only element in the fringe is
01257     marked for expansion, then this is a false UIP (the SAT solver
01258     doesn't know about this node), and it should not appear in the
01259     conflict clause.  In this case, simply proceed to step 3 as if
01260     nothing happened.
01261 
01262 <li> If fringe.size()==0, stop (the set of pending nodes must also be
01263     empty at this point).  Otherwise, for *every* node in the fringe,
01264     decrement the fan-out for each of its predecessors, and empty the
01265     fringe.  Take the predecessors from the current scope, and add
01266     those to the fringe for which fan-out count is zero, and remove
01267     them from the set of pending nodes.  Add the other predecessors
01268     from the current scope to the set of pending nodes.  Add the
01269     remaining predecessors (not from the current scope) to the
01270     literals or gamma, as appropriate.  Continue with step 2.
01271 
01272 </ol>
01273 */
01274 void SearchEngineFast::analyzeUIPs(const Theorem &falseThm, int conflictScope)
01275 {
01276   TRACE("impl graph", "analyzeUIPs(scope = ", conflictScope, ") {");
01277   vector<Theorem> fringe[2]; // 2-element array of vectors (new & curr. fringe)
01278   unsigned curr(0), next(1);
01279 
01280   int pending(0);
01281   vector<Theorem> lits;
01282   vector<Theorem> gamma;
01283   
01284   Theorem start = falseThm;
01285   d_lastConflictClause = Clause();
01286   d_lastConflictScope = conflictScope;
01287   start.clearAllFlags();
01288 
01289   TRACE("search full", "Analysing UIPs at level: ", conflictScope, "");
01290 
01291   // Initialize all the sets
01292   const Assumptions& a=start.getAssumptionsRef();
01293   for(Assumptions::iterator i=a.begin(), iend=a.end(); i!=iend; ++i) {
01294     processNode(*i, lits, gamma, fringe[curr], pending);
01295   }
01296 
01297   while (true) {
01298     TRACE_MSG("impl graph", "analyzeUIPs(): fringe size = "
01299               +int2string(fringe[curr].size())
01300               +", pending size = "+int2string(pending));
01301     // Wrap up a conflict clause if:
01302     // (1) There are no pending nodes
01303     // (2) The fringe has at most one element
01304     // (3) If fringe is not empty, its node should not be flagged for expansion
01305     if(fringe[curr].size() <= 1 && pending == 0
01306        && (fringe[curr].size() == 0
01307            || !fringe[curr].back().getExpandFlag())) {
01308       // Found UIP or end of graph.  Generate conflict clause.
01309       if(fringe[curr].size() > 0)
01310         lits.push_back(fringe[curr].back());
01311       IF_DEBUG(if(debugger.trace("impl graph")) {
01312         ostream& os = debugger.getOS();
01313         os << "Creating conflict clause:"
01314            << "\n  start: " << start.getExpr()
01315            << "\n  Lits: [\n";
01316         for(size_t i=0; i<lits.size(); i++)
01317           os << "    " << lits[i].getExpr() << "\n";
01318         os << "]\n  Gamma: [\n";
01319         for(size_t i=0; i<gamma.size(); i++)
01320           os << "    " << gamma[i].getExpr() << "\n";
01321         os << "]" << endl;
01322       });
01323       // Derive a theorem for the conflict clause
01324       Theorem clause = d_rules->conflictClause(start, lits, gamma);
01325       d_conflictClauseCount++;
01326       // Generate the actual clause and set it up
01327       Clause c(d_core, d_vm, clause, d_bottomScope, __FILE__, __LINE__);
01328       updateLitCounts(c);
01329       if (c.size() > 1) {
01330         // Set the watched pointers to the two literals with the
01331         // highest scopes
01332         int firstLit = 0;
01333         int secondLit = 1;
01334         int firstDL = c[0].getScope();
01335         int secondDL = c[1].getScope();
01336         // Invariant: firstDL >= secondDL
01337         if(firstDL < secondDL) {
01338           firstLit=1; secondLit=0;
01339           int tmp(secondDL);
01340           secondDL=firstDL; firstDL=tmp;
01341         }
01342         for(unsigned i = 2; i < c.size(); ++i) {
01343           int cur = c[i].getScope();
01344           if(cur >= firstDL) {
01345             secondLit=firstLit; secondDL=firstDL;
01346             firstLit=i; firstDL=cur;
01347           } else if(cur > secondDL) {
01348             secondLit=i; secondDL=cur;
01349           }
01350         }
01351 
01352         c.wp(0, firstLit);
01353         c.wp(1, secondLit);
01354     
01355         // Add the watch pointers to the d_wp lists
01356         for(int i=0; i<=1; i++) {
01357           // Negated watched literal
01358           Literal l(!c.watched(i));
01359           // Add the pointer to l's list
01360           pair<Clause, int> p(c, i);
01361           wp(l).push_back(p);
01362         }
01363       }
01364       TRACE("conflict clauses",
01365             "Conflict clause #"+int2string(d_conflictClauseCount)
01366             +": ", CompactClause(c), "");
01367       if(c.size() == 1) {
01368         // Unit clause: stash it for later unit propagation
01369         TRACE("conflict clauses", "analyzeUIPs(): unit clause: ",
01370               CompactClause(c), "");
01371         d_unitConflictClauses.push_back(c);
01372       }
01373       else {
01374         TRACE("conflict clauses", "analyzeUIPs(): conflict clause ",
01375               CompactClause(c), "");
01376         DebugAssert(c.getScope() <= d_bottomScope,
01377                     "Conflict clause should be at bottom scope.");
01378         d_conflictClauses->push_back(c);
01379         if (d_lastConflictClause.isNull()) {
01380           d_lastConflictClause = c;
01381 //        IF_DEBUG(for(unsigned i=0; i<c.size(); ++i)
01382 //          DebugAssert(c[i].getValue() == -1, "Bad conflict clause: "
01383 //                      +c.toString()));
01384         }
01385       }
01386       if(fringe[curr].size() > 0) {
01387         // This was a UIP.  Leave it in the fringe for later expansion.
01388         IF_DEBUG(debugger.counter("UIPs")++);
01389         start = fringe[curr].back();
01390         lits.clear();
01391         gamma.clear();
01392         start.clearAllFlags();
01393       } else {
01394         // No more conflict clauses, we are done.  This is the only
01395         // way this function can return.
01396         TRACE_MSG("impl graph", "analyzeUIPs => }");
01397         return;
01398       }
01399     }
01400     // Now expand all the nodes in the fringe
01401     for(vector<Theorem>::iterator i=fringe[curr].begin(),
01402           iend=fringe[curr].end();
01403         i!=iend; ++i) {
01404       const Assumptions& a=i->getAssumptionsRef();
01405       for(Assumptions::iterator j=a.begin(), jend=a.end(); j!=jend; ++j) {
01406         processNode(*j, lits, gamma, fringe[next], pending);
01407       }
01408     }
01409     // Swap the current and next fringes
01410     fringe[curr].clear();
01411     curr = 1 - curr;
01412     next = 1 - next;
01413     IF_DEBUG(if(pending > 0 && fringe[curr].size()==0)
01414              falseThm.printDebug());
01415     DebugAssert(pending == 0 || fringe[curr].size() > 0,
01416                 "analyzeUIPs(scope = "
01417                 +int2string(conflictScope)+"): empty fringe");
01418   }
01419 }
01420 
01421 
01422 ////////////////////////////////
01423 // End New Search Engine Code //
01424 ////////////////////////////////
01425 
01426 
01427 //! Redefine the counterexample generation.
01428 /*! FIXME: for now, it just dumps all the assumptions (same as
01429  * getAssumptions()).  Eventually, it will simplify the related
01430  * formulas to TRUE, merge all the generated assumptions into
01431  * d_lastCounterExample, and call the parent's method. */
01432 void SearchEngineFast::getCounterExample(std::vector<Expr>& assertions) {
01433   // This will not add anything, since the counterexample is empty,
01434   // but will check if we are allowed to be called
01435   SearchImplBase::getCounterExample(assertions);
01436   getAssumptions(assertions);
01437 }
01438 
01439 
01440 //! Notify the search engine about a new non-literal fact.
01441 /*! It should be called by TheoryCore::assertFactCore().
01442  *
01443  * If the fact is an AND, we split it into individual conjuncts and
01444  * add them individually.
01445  *
01446  * If the fact is an OR, we check whether it's a CNF clause; that is,
01447  * whether all disjuncts are literals.  If they are, we add it as a
01448  * CNF clause.
01449  *
01450  * Otherwise add the fact to d_nonLiterals as it is.
01451  */
01452 void
01453 SearchEngineFast::addNonLiteralFact(const Theorem& thm) {
01454   TRACE("search", "addNonLiteralFact(", thm, ") {");
01455   TRACE("search", "d_nonLiteralsSaved.size()=",d_nonLiteralsSaved.size(),
01456         "@"+int2string(scopeLevel()));
01457   //IF_DEBUG(checkAssumpDebug(thm, d_assumptions));
01458   const Expr& e(thm.getExpr());
01459   if(d_nonLiteralsSaved.count(e) > 0) {
01460     // We've seen this non-literal before.
01461     TRACE_MSG("search", "addNonLiteralFact[skipping] => }");
01462     IF_DEBUG(debugger.counter("skipped repeated non-literals")++);
01463     return;
01464   }
01465   // Save the non-literal
01466   d_nonLiteralsSaved[e]=thm;
01467   bool isCNFclause(false);
01468   // Split conjunctions into individual assertions and add them to the
01469   // appropriate lists
01470 
01471   int k = e.getKind();
01472   if (k == AND_R || k == IFF_R || k == ITE_R)
01473   {
01474     d_circuits.push_back(new Circuit(this, thm));
01475   }
01476 
01477   else if(e.isAnd()) {
01478     for(int i=0, iend=e.arity(); i<iend; ++i) {
01479       Theorem t_i(d_commonRules->andElim(thm, i));
01480       // Call enqueueFact(), not addFact(), since we are called from
01481       // addFact() here
01482       if(e[i].isAbsLiteral()) {
01483         d_core->enqueueFact(t_i);
01484       }
01485       else addNonLiteralFact(t_i);
01486     }
01487   } else {
01488     int unsetLits(0); // Count the number of unset literals
01489     size_t unitLit(0); // If the #unsetLits==1, this is the only unset literal
01490     vector<Theorem> thms; // collect proofs of !l_i for unit prop.
01491     if(e.isOr()) {
01492       isCNFclause = true;
01493       for(int i=0; isCNFclause && i<e.arity(); ++i) {
01494         isCNFclause=e[i].isAbsLiteral();
01495         if(isCNFclause) {
01496           // Check the value of the literal
01497           Literal l(newLiteral(e[i]));
01498           if(l.getValue() > 0) // The entire clause is true; ignore it
01499             return;
01500           if(l.getValue() == 0) { // Found unset literal
01501             unsetLits++; unitLit = i;
01502           } else // Literal is false, collect the theorem for it
01503             thms.push_back(l.deriveTheorem());
01504         }
01505       }
01506     }
01507     if(isCNFclause) {
01508       DebugAssert(e.arity() > 1, "Clause should have more than one literal");
01509       // Check if clause is unit or unsat
01510       if(unsetLits==0) { // Contradiction
01511         TRACE("search", "contradictory clause:\n",
01512               CompactClause(Clause(d_core, d_vm, thm, scopeLevel())),"");
01513         setInconsistent(d_rules->conflictRule(thms, thm));
01514       } else if(unsetLits==1) { // Unit clause: propagate literal
01515         TRACE("search", "unit clause, unitLit = "+int2string(unitLit)+":\n", 
01516               CompactClause(Clause(d_core, d_vm, thm, scopeLevel())),"");
01517         d_core->enqueueFact(d_rules->unitProp(thms, thm, unitLit));
01518       } else { // Wrap up the clause
01519         Clause c(d_core, d_vm, thm, scopeLevel(), __FILE__, __LINE__);
01520         IF_DEBUG(debugger.counter("CNF clauses added")++);
01521         TRACE("search", "addNonLiteralFact: adding CNF: ", c, "");
01522         addNewClause(c);
01523       }
01524     } else {
01525       TRACE("search", "addNonLiteralFact: adding non-literal: ", thm, "");
01526       IF_DEBUG(debugger.counter("added non-literals")++);
01527       d_nonLiterals.push_back(SmartCDO<Theorem>(d_core->getCM()->getCurrentContext(), thm));
01528       //      d_nonLiteralSimplified[thm.getExpr()] = false;
01529     }
01530   }
01531   TRACE_MSG("search", "addNonLiteralFact => }");
01532 }
01533 
01534 
01535 //! Notify the search engine about a new literal fact.
01536 /*! It should be called by TheoryCore::assertFactCore() */
01537 void
01538 SearchEngineFast::addLiteralFact(const Theorem& thm) {
01539   TRACE("search", "addLiteralFact(", thm, ")");
01540   // Save the value of the flag to restore it later
01541   bool useEF(d_useEnqueueFact);
01542   d_useEnqueueFact=true;
01543 
01544   DebugAssert(thm.isAbsLiteral(),
01545               "addLiteralFact: not a literal: " + thm.toString());
01546   //IF_DEBUG(checkAssumpDebug(thm, d_assumptions));
01547   Literal l(newLiteral(thm.getExpr()));
01548   TRACE("search", "addLiteralFact: literal = ", l, "");
01549   // Only add the literal if it doesn't have any value; otherwise it's
01550   // either a contradiction, or it must already be in the list
01551   // FIXME: why did we need thm.getScope() != 0 ???
01552   if ((l.getValue() == 0 /* && thm.getScope() != 0 */)
01553       /* || (l.getValue() == 1 && l.getScope() > thm.getScope()) */) {
01554     l.setValue(thm, scopeLevel());
01555     DebugAssert(l.getExpr().isAbsLiteral(),
01556                 "addLiteralFact(): pushing non-literal to d_literals:\n "
01557                 +l.getExpr().toString());
01558     DebugAssert(l.getValue() == 1, "addLiteralFact(): l = "+l.toString());
01559     d_literals.push_back(l);
01560     d_literalSet.insert(l.getExpr(),l);
01561     // Immediately propagate the literal with BCP, unless the SAT
01562     // solver is already running
01563     if(!d_inCheckSAT) bcp();
01564 
01565 //     if (thm.getScope() != scopeLevel()) {
01566 //       IF_DEBUG(debugger.counter("addLiteralFact adds unreported lit")++);
01567 //       d_unreportedLits.insert(l.getExpr(),thm,thm.getScope());
01568 //     }
01569   } else if(l.getValue() < 0) { // Contradiction, bcp will die anyway
01570     if(l.isNegative())
01571       setInconsistent(d_commonRules->contradictionRule(l.deriveTheorem(), thm));
01572     else
01573       setInconsistent(d_commonRules->contradictionRule(thm, l.deriveTheorem()));
01574   }
01575   d_useEnqueueFact=useEF;
01576 }
01577 
01578 /*! @brief Redefine newIntAssumption(): we need to add the new theorem
01579  * to the appropriate Literal */
01580 Theorem
01581 SearchEngineFast::newIntAssumption(const Expr& e) {
01582   Theorem thm(SearchImplBase::newIntAssumption(e));
01583   DebugAssert(thm.isAssump(), "Splitter should be an assumption:" + thm.toString());
01584   TRACE("search full", "Splitter: ", thm.toString(), "");
01585   const Expr& expr = thm.getExpr();
01586   Literal l(newLiteral(expr));
01587   if(l.getValue() == 0) {
01588     l.setValue(thm, scopeLevel());
01589     if(l.getExpr().isAbsLiteral()) {
01590       DebugAssert(l.getValue() == 1, "newIntAssumption(): l = "+l.toString());
01591       d_literals.push_back(l);
01592     }
01593     else
01594       d_litsAlive.push_back(l);
01595   }
01596 
01597     
01598   return thm;
01599 }
01600 
01601 bool 
01602 SearchEngineFast::isAssumption(const Expr& e) {
01603   return (SearchImplBase::isAssumption(e)
01604           || (d_nonLiteralsSaved.count(e) > 0));
01605 }
01606 
01607 
01608 void
01609 SearchEngineFast::addSplitter(const Expr& e, int priority) {
01610   // SearchEngine::addSplitter(e, priority);
01611   DebugAssert(e.isAbsLiteral(), "SearchEngineFast::addSplitter("+e.toString()+")");
01612   Literal lit(newLiteral(e));
01613   d_dpSplitters.push_back(Splitter(lit));
01614   if(priority != 0) {
01615     d_litSortCount--;
01616     lit.score() += priority*10;
01617   }
01618   if(!lit.added()) {
01619     TRACE("search literals", "addSplitter(): adding literal ", lit, " to d_litsByScores");
01620     d_litsByScores.push_back(lit);
01621     lit.added()=true;
01622     if(priority == 0) d_litSortCount--;
01623   }
01624   if(d_litSortCount < 0) {
01625     ::stable_sort(d_litsByScores.begin(), d_litsByScores.end(), compareLits);
01626     d_litSortCount=d_litsByScores.size();
01627   }
01628   TRACE("search splitters","addSplitter => ", lits2str(d_litsByScores),"");
01629 }
01630 
01631 
01632 bool SearchEngineFast::checkValidMain(const Expr& e2)
01633 {
01634   // Propagate the literals asserted before checkValid()
01635   for(CDMap<Expr,Literal>::iterator i=d_literalSet.begin(),
01636         iend=d_literalSet.end(); i!=iend; ++i)
01637     d_literals.push_back((*i).second);
01638 
01639   // Run the SAT solver
01640   bool result = checkSAT();
01641 
01642   Theorem res;
01643   if (!result)
01644     res = d_conflictTheorem;
01645   else {
01646     // Set counter-example
01647     vector<Expr> a;
01648     unsigned i;
01649     Theorem thm;
01650 
01651     d_lastCounterExample.clear();
01652     for (i=d_nonlitQueryStart; i < d_nonlitQueryEnd; ++i) {
01653       thm = d_nonLiterals[i].get();
01654       DebugAssert(thm.getExpr().isTrue(),
01655                   "original nonLiteral doesn't simplify to true");
01656       thm.getLeafAssumptions(a);
01657       for (vector<Expr>::iterator i=a.begin(), iend=a.end(); i != iend; ++i) {
01658         d_lastCounterExample[*i] = true;
01659       }
01660       a.clear();
01661     }
01662     for (i=d_clausesQueryStart; i < d_clausesQueryEnd; ++i) {
01663       thm = simplify(((Clause)d_clauses[i]).getTheorem());
01664       DebugAssert(thm.getExpr().isTrue(),
01665                   "original nonLiteral doesn't simplify to true");
01666       thm.getLeafAssumptions(a);
01667       for (vector<Expr>::iterator i=a.begin(), iend=a.end(); i != iend; ++i) {
01668         d_lastCounterExample[*i] = true;
01669       }
01670       a.clear();
01671     }
01672   }
01673 
01674   bool r = processResult(res, e2);
01675 
01676   if (r) {
01677     d_core->getCM()->popto(d_bottomScope);
01678     d_litsMaxScorePos = 0; // from decision engine
01679 
01680     // Clear data structures
01681     d_unitConflictClauses.clear();
01682     clearLiterals();
01683     clearFacts();
01684 
01685     Theorem e_iff_e2(d_commonRules->iffContrapositive(d_simplifiedThm));
01686     d_lastValid =
01687       d_commonRules->iffMP(d_lastValid, d_commonRules->symmetryRule(e_iff_e2));
01688     IF_DEBUG(checkAssumpDebug(d_lastValid, d_assumptions));
01689     TRACE_MSG("search terse", "checkValid => true}");
01690     TRACE("search", "checkValid => true; theorem = ", d_lastValid, "}");
01691     d_core->getCM()->pop();
01692   }
01693   else {
01694     TRACE_MSG("search terse", "checkValid => false}");
01695     TRACE_MSG("search", "checkValid => false; }");
01696     DebugAssert(d_unitConflictClauses.size() == 0, "checkValid(): d_unitConflictClauses postcondition violated");
01697     DebugAssert(d_literals.size() == 0, "checkValid(): d_literals postcondition violated");
01698     DebugAssert(d_factQueue.empty(), "checkValid(): d_factQueue postcondition violated");
01699   }
01700   //IF_DEBUG(debugger.printAll());
01701   return r;
01702 }
01703 
01704 
01705 bool SearchEngineFast::checkValidInternal(const Expr& e)
01706 {
01707   DebugAssert(d_unitConflictClauses.size() == 0, "checkValid(): d_unitConflitClauses precondition violated");
01708   DebugAssert(d_factQueue.empty(), "checkValid(): d_factQueue precondition violated");
01709 
01710   TRACE("search", "checkValid(", e, ") {");
01711   TRACE_MSG("search terse", "checkValid() {");
01712 
01713   if (!e.getType().isBool()) {
01714     throw TypecheckException
01715       ("checking validity of a non-boolean expression:\n\n  "
01716        + e.toString()
01717        + "\n\nwhich has the following type:\n\n  "
01718        + e.getType().toString());
01719   }
01720 
01721   // A successful query should leave the context unchanged
01722   d_core->getCM()->push();
01723   d_conflictClauseManager.setRestorePoint();
01724   d_bottomScope = scopeLevel();
01725 
01726   // First, simplify the NEGATION of the given expression: that's what
01727   // we'll assert
01728   d_simplifiedThm = d_core->getExprTrans()->preprocess(e.negate());
01729   TRACE("search", "checkValid: simplifiedThm = ", d_simplifiedThm, "");
01730 
01731   const Expr& not_e2 = d_simplifiedThm.get().getRHS();
01732   Expr e2 = not_e2.negate();
01733 
01734   // Assert not_e2 if it's not already asserted
01735   TRACE_MSG("search terse", "checkValid: Asserting !e: ");
01736   TRACE("search", "checkValid: Asserting !e: ", not_e2, "");
01737   Theorem not_e2_thm;
01738   d_nonlitQueryStart = d_nonLiterals.size();
01739   d_clausesQueryStart = d_clauses.size();
01740   if(d_assumptions.count(not_e2) == 0) {
01741     not_e2_thm = newUserAssumption(not_e2);
01742   } else {
01743     not_e2_thm = d_assumptions[not_e2];
01744   }
01745   //  d_core->addFact(not_e2_thm);
01746   d_nonlitQueryEnd = d_nonLiterals.size();
01747   d_clausesQueryEnd = d_clauses.size();
01748 
01749   // Reset the splitter counter.  This will force a call to
01750   // updateLitScores() the first time we need to find a splitter, and
01751   // clean out junk from the previous calls to checkValid().
01752   d_splitterCount=0;
01753 
01754   return checkValidMain(e2);
01755 }
01756 
01757 
01758 bool SearchEngineFast::restartInternal(const Expr& e)
01759 {
01760   DebugAssert(d_unitConflictClauses.size() == 0, "restart(): d_unitConflitClauses precondition violated");
01761   DebugAssert(d_factQueue.empty(), "restart(): d_factQueue precondition violated");
01762 
01763   TRACE("search", "restart(", e, ") {");
01764   TRACE_MSG("search terse", "restart() {");
01765 
01766   if (!e.getType().isBool()) {
01767     throw TypecheckException
01768       ("argument to restart is a non-boolean expression:\n\n  "
01769        + e.toString()
01770        + "\n\nwhich has the following type:\n\n  "
01771        + e.getType().toString());
01772   }
01773 
01774   if (d_bottomScope == 0) {
01775     throw Exception("Call to restart with no current query");
01776   }
01777   d_core->getCM()->popto(d_bottomScope);
01778 
01779   Expr e2 = d_simplifiedThm.get().getRHS().negate();
01780 
01781   TRACE_MSG("search terse", "restart: Asserting e: ");
01782   TRACE("search", "restart: Asserting e: ", e, "");
01783   if(d_assumptions.count(e) == 0) {
01784     d_core->addFact(newUserAssumption(e));
01785   }
01786 
01787   return checkValidMain(e2);
01788 }
01789 
01790 /*!
01791  * The purpose of this method is to mark up the assumption graph of
01792  * the FALSE Theorem (conflictThm) for the later UIP analysis.  The
01793  * required flags for each assumption in the graph are:
01794  *
01795  * <strong>ExpandFlag:</strong> whether to "expand" the node or not;
01796  * that is, whether to consider the current node as a final assumption
01797  * (either as a conflict clause literal, or a context assumption from
01798  * \f$\Gamma\f$)
01799  *
01800  * <strong>LitFlag:</strong> the node (actually, its inverse) is a
01801  * literal of the conflict clause
01802  *
01803  * <strong>CachedValue:</strong> the "fanout" count, how many nodes in
01804  * the assumption graph are derived from the current node.
01805  * 
01806  * INVARIANTS (after the method returns):
01807  *
01808  * -# The currect scope is the "true" conflict scope,
01809  *    i.e. scopeLevel() == conflictThm.getScope()
01810  * -# The literals marked with LitFlag (CC literals) are known to the
01811  *    SAT solver, i.e. their Literal class has a value == 1
01812  * -# The only CC literal from the current scope is the latest splitter
01813  *
01814  * ASSUMPTIONS: 
01815  * 
01816  * -# The Theorem scope of an assumption is the same as its Literal scope;
01817  *    i.e. if thm is a splitter, then 
01818  *    thm.getScope() == newLiteral(thm.getExpr()).getScope()
01819  *
01820  * Algorithm:
01821  * 
01822  * First, backtrack to the scope level of the conflict.  Then,
01823  * traverse the implication graph until we either hit a literal known
01824  * to the SAT solver at a lower scope:
01825  * newLiteral(e).getScope()<scopeLevel(), or a splitter (assumption), or a
01826  * fact from the bottom scope.  The literals from the first two
01827  * categories are marked with LitFlag (they'll comprise the conflict
01828  * clause), and the bottom scope facts will be the assumptions in the
01829  * conflict clause's theorem.
01830  *
01831  * The traversed nodes are cached by the .isFlagged() flag, and
01832  * subsequent hits only increase the fanout count of the node.
01833  *
01834  * Notice, that there can only be one literal in the conflict clause
01835  * from the current scope.  Also, even if some intermediate literals
01836  * were delayed by the DPs and reported to the SAT solver at or below
01837  * the conflict scope (which may be below their "true" Theorem scope),
01838  * they will be skipped, and their assumptions will be used.
01839  *
01840  * In other words, it is safe to backtrack to the "true" conflict
01841  * level, since, in the worst case, we traverse the graph all the way
01842  * to the splitters, and make a conflict clause out of those.  The
01843  * hope is, however, that this wouldn't happen too often.
01844  */
01845 void SearchEngineFast::traceConflict(const Theorem& conflictThm) {
01846   TRACE("impl graph", "traceConflict(", conflictThm.getExpr(), ") {");
01847   
01848   // Always process conflict at its true scope or the bottom scope,
01849   // whichever is greater.
01850   DebugAssert(conflictThm.getScope() <= scopeLevel(),
01851               "conflictThm.getScope()="+int2string(conflictThm.getScope())
01852               +", scopeLevel()="+int2string(scopeLevel()));
01853   if(conflictThm.getScope() < scopeLevel()) {
01854     int scope(conflictThm.getScope());
01855     if(scope < d_bottomScope) scope = d_bottomScope;
01856     d_decisionEngine->popTo(scope);
01857   }
01858 
01859   if(scopeLevel() <= d_bottomScope) {
01860     // This is a top-level conflict, nothing to analyze.
01861     TRACE_MSG("impl graph", "traceConflict[bottom scope] => }");
01862     return;
01863   }
01864 
01865   // DFS stack
01866   vector<Theorem> stack;
01867   // Max assumption scope for the contradiction
01868   int maxScope(d_bottomScope);
01869   // Collect potential top-level splitters
01870   IF_DEBUG(vector<Theorem> splitters);
01871   TRACE("impl graph", "traceConflict: maxScope = ", maxScope, "");
01872 
01873   conflictThm.clearAllFlags();
01874   conflictThm.setExpandFlag(true);
01875   conflictThm.setCachedValue(0);
01876 
01877   const Assumptions& assump = conflictThm.getAssumptionsRef();
01878   for(Assumptions::iterator i=assump.begin(),iend=assump.end();i!=iend;++i) {
01879     TRACE("impl graph", "traceConflict: adding ", *i, "");
01880     stack.push_back(*i);
01881   }
01882 
01883   // Do the non-recursive DFS, mark up the assumption graph
01884   IF_DEBUG(Literal maxScopeLit);
01885   while(stack.size() > 0) {
01886     Theorem thm(stack.back());
01887     stack.pop_back();
01888     TRACE("impl graph", "traceConflict: while() { thm = ", thm, "");
01889     if (thm.isFlagged()) {
01890       // We've seen this theorem before.  Update fanout count.
01891       thm.setCachedValue(thm.getCachedValue() + 1);
01892       TRACE("impl graph", "Found again: ", thm.getExpr().toString(), "");
01893       TRACE("impl graph", "With fanout: ", thm.getCachedValue(), "");
01894     }
01895     else {
01896       // This is a new theorem.  Process it.
01897       thm.setCachedValue(1);
01898       thm.setFlag();
01899       thm.setLitFlag(false); // Clear this flag (it may be set later)
01900       bool expand(false);
01901       int scope = thm.getScope();
01902       bool isAssump = thm.isAssump();
01903 
01904       IF_DEBUG({
01905         int s = scope;
01906         if(thm.isAbsLiteral()) {
01907           Literal l(newLiteral(thm.getExpr()));
01908           if(l.getValue() == 1) s = l.getScope();
01909         }
01910         // maxScope will be reset: clear the splitters
01911         if(s > maxScope) splitters.clear();
01912       });
01913 
01914       if(thm.isAbsLiteral()) {
01915         Literal l(newLiteral(thm.getExpr()));
01916         bool isTrue(l.getValue()==1);
01917         if(isTrue) scope = l.getScope();
01918         if(!isAssump && (!isTrue || scope == scopeLevel()))
01919           expand=true;
01920         else if(scope > d_bottomScope) {// Found a literal of a conflict clause
01921           IF_DEBUG(if(scope >= maxScope) splitters.push_back(thm));
01922           thm.setLitFlag(true);
01923         }
01924       } else {
01925         DebugAssert(scope <= d_bottomScope || !isAssump,
01926                     "SearchEngineFast::traceConflict: thm = "
01927                     +thm.toString());
01928         if(!isAssump && scope > d_bottomScope)
01929           expand=true;
01930       }
01931 
01932       if(scope > maxScope) {
01933         maxScope = scope;
01934         IF_DEBUG(maxScopeLit = newLiteral(thm.getExpr()));
01935         TRACE("impl graph", "traceConflict: maxScope = ", maxScope, "");
01936       }
01937 
01938       if(expand) {
01939         DebugAssert(!thm.isAssump(),
01940                     "traceConflict: thm = "+thm.toString());
01941         thm.setExpandFlag(true);
01942         const Assumptions& assump = thm.getAssumptionsRef();
01943         for(Assumptions::iterator i=assump.begin(),iend=assump.end();
01944             i!=iend; ++i) {
01945           TRACE("impl graph", "traceConflict: adding ", *i, "");
01946           stack.push_back(*i);
01947         }
01948       } else
01949         thm.setExpandFlag(false);
01950     }
01951     TRACE_MSG("impl graph", "traceConflict: end of while() }");
01952   }
01953   IF_DEBUG(if(maxScope != scopeLevel()) conflictThm.printDebug());
01954   DebugAssert(maxScope == scopeLevel(), "maxScope="+int2string(maxScope)
01955               +", scopeLevel()="+int2string(scopeLevel())
01956               +"\n maxScopeLit = "+maxScopeLit.toString());
01957   IF_DEBUG(
01958     if(!(maxScope == d_bottomScope || splitters.size() == 1)) {
01959       conflictThm.printDebug();
01960       ostream& os = debugger.getOS();
01961       os << "\n\nsplitters = [";
01962       for(size_t i=0; i<splitters.size(); ++i)
01963         os << splitters[i] << "\n";
01964       os << "]" << endl;
01965     }
01966     );
01967   DebugAssert(maxScope == d_bottomScope || splitters.size() == 1,
01968               "Wrong number of splitters found at maxScope="
01969               +int2string(maxScope)
01970               +": "+int2string(splitters.size())+" splitters.");
01971   d_lastConflictScope = maxScope;
01972   analyzeUIPs(conflictThm, maxScope);
01973   TRACE_MSG("impl graph", "traceConflict => }");
01974 }

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