/*****************************************************************************/
/*!
*\file search_sat.h
*\brief Search engine that uses an external SAT engine
*
* Author: Clark Barrett
*
* Created: Mon Dec 5 17:52:05 2005
*
*
*
* License to use, copy, modify, sell and/or distribute this software
* and its documentation for any purpose is hereby granted without
* royalty, subject to the terms and conditions defined in the \ref
* LICENSE file provided with this distribution.
*
*
*
*/
/*****************************************************************************/
#ifndef _cvc3__include__search_sat_h_
#define _cvc3__include__search_sat_h_
#include
#include
#include "search.h"
#include "smartcdo.h"
#include "cdlist.h"
#include "cnf_manager.h"
#include "expr.h"
#include "dpllt.h"
#include "theory_core.h"
namespace CVC3 {
//! Search engine that connects to a generic SAT reasoning module
/*! \ingroup SE */
class SearchSat :public SearchEngine {
//! Name of search engine
std::string d_name;
//! Bottom scope for current query
CDO d_bottomScope;
//! Last expr checked for validity
CDO d_lastCheck;
/*! @brief Theorem from the last successful checkValid call. It is
used by getProof and getAssumptions. */
CDO d_lastValid;
//! List of all user assumptions
CDList d_userAssumptions;
//! List of all internal assumptions
CDList d_intAssumptions;
//! Index to where unprocessed assumptions start
CDO d_idxUserAssump;
TheoryCore::CoreSatAPI* d_coreSatAPI;
//! Pointer to DPLLT implementation
SAT::DPLLT* d_dpllt;
//! Implementation of TheoryAPI for DPLLT
SAT::DPLLT::TheoryAPI* d_theoryAPI;
//! Implementation of Decider for DPLLT
SAT::DPLLT::Decider* d_decider;
//! Store of theorems for expressions sent to DPLLT
CDMap d_theorems;
//! Manages CNF formula and its relationship to original Exprs and Theorems
SAT::CNF_Manager *d_cnfManager;
//! Callback for CNF_Manager
SAT::CNF_Manager::CNFCallback *d_cnfCallback;
//! Cached values of variables
std::vector d_vars;
//! Whether we are currently in a call to dpllt->checkSat
bool d_inCheckSat;
//! CNF Formula used for theory lemmas
SAT::CD_CNF_Formula d_lemmas;
//! Lemmas waiting to be translated since last call to getNewClauses()
std::vector > d_pendingLemmas;
//! Backtracking size of d_pendingLemmas
CDO d_pendingLemmasSize;
//! Backtracking next item in d_pendingLemmas
CDO d_pendingLemmasNext;
//! Current position in d_lemmas
CDO d_lemmasNext;
//! List for backtracking var values
std::vector d_varsUndoList;
//! Backtracking size of d_varsUndoList
CDO d_varsUndoListSize;
public:
//! Pair of Lit and priority of this Lit
class LitPriorityPair {
SAT::Lit d_lit;
int d_priority;
LitPriorityPair() {}
public:
LitPriorityPair(SAT::Lit lit, int priority)
: d_lit(lit), d_priority(priority) {}
SAT::Lit getLit() const { return d_lit; }
int getPriority() const { return d_priority; }
friend bool operator<(const LitPriorityPair& p1,
const LitPriorityPair& p2);
};
private:
//! Used to determine order to find splitters
std::set d_prioritySet;
//! Current position in prioritySet
CDO::const_iterator> d_prioritySetStart;
//! Backtracking size of priority set entries
CDO d_prioritySetEntriesSize;
//! Entries in priority set in insertion order (so set can be backtracked)
std::vector::iterator> d_prioritySetEntries;
//! Backtracking size of priority set entries at bottom scope
std::vector d_prioritySetBottomEntriesSizeStack;
//! Current size of bottom entries
unsigned d_prioritySetBottomEntriesSize;
//! Entries in priority set in insertion order (so set can be backtracked)
std::vector::iterator> d_prioritySetBottomEntries;
//! Last Var registered with core theory
CDO d_lastRegisteredVar;
//! Whether it's OK to call DPLLT solver from the current scope
CDO d_dplltReady;
CDO d_nextImpliedLiteral;
//! Helper class for resetting DPLLT engine
/*! We need to be notified when the scope goes below the scope from
* which the last invalid call to checkValid originated. This helper class
* ensures that this happens.
*/
friend class Restorer;
class Restorer :public ContextNotifyObj {
SearchSat* d_ss;
public:
Restorer(Context* context, SearchSat* ss)
: ContextNotifyObj(context), d_ss(ss) {}
void notifyPre() { d_ss->restorePre(); }
void notify() { d_ss->restore(); }
};
//! Instance of Restorer class
Restorer d_restorer;
private:
//! Get rid of bottom scope entries in prioritySet
void restorePre();
//! Get rid of entries in prioritySet and pendingLemmas added since last push
void restore();
//! Helper for addLemma and check
bool recordNewRootLit(SAT::Lit lit, int priority = 0, bool atBottomScope = false);
friend class SearchSatCoreSatAPI;
friend class SearchSatCNFCallback;
//! Core theory callback which adds a new lemma from the core theory
void addLemma(const Theorem& thm, int priority = 0);
//! Core theory callback which asks for the bottom scope for current query
int getBottomScope() { return d_bottomScope; }
//! Core theory callback which suggests a splitter
void addSplitter(const Expr& e, int priority);
friend class SearchSatTheoryAPI;
//! DPLLT callback to inform theory that a literal has been assigned
void assertLit(SAT::Lit l);
//! DPLLT callback to ask if theory has detected inconsistency.
SAT::DPLLT::ConsistentResult checkConsistent(SAT::Clause& c,bool fullEffort);
//! DPLLT callback to get theory propagations.
SAT::Lit getImplication();
//! DPLLT callback to explain a theory propagation.
void getExplanation(SAT::Lit l, SAT::Clause& c);
//! DPLLT callback to get more general theory clauses.
bool getNewClauses(SAT::CNF_Formula& cnf);
friend class SearchSatDecider;
//! DPLLT callback to decide which literal to split on next
SAT::Lit makeDecision();
//! Recursively traverse DAG looking for a splitter
/*! Returns true if a splitter is found, false otherwise. The splitter is
* returned in lit (lit should be set to true). Nodes whose current value is
* fully justified are marked by calling setFlag to avoid searching them in
* the future.
*/
bool findSplitterRec(SAT::Lit lit, SAT::Var::Val value,
SAT::Lit* litDecision);
//! Get the value of a CNF Literal
SAT::Var::Val getValue(SAT::Lit c) {
DebugAssert(!c.isVar() || unsigned(c.getVar()) < d_vars.size(),
"Lit out of bounds in getValue");
return c.isFalse() ? SAT::Var::FALSE_VAL : c.isTrue() ? SAT::Var::TRUE_VAL :
c.isInverted() ? SAT::Var::invertValue(d_vars[c.getVar()]) :
d_vars[c.getVar()]; }
//! Set the value of a variable
void setValue(SAT::Var v, SAT::Var::Val val) {
DebugAssert(!v.isNull(), "expected non-null Var");
DebugAssert(unsigned(v) < d_vars.size(), "Var out of bounds in getValue");
DebugAssert(d_vars[v] == SAT::Var::UNKNOWN, "Expected unknown");
DebugAssert(val != SAT::Var::UNKNOWN, "Expected set to non-unknown");
d_vars[v] = val;
DebugAssert(d_varsUndoListSize == d_varsUndoList.size(), "Size mismatch");
d_varsUndoList.push_back(unsigned(v));
d_varsUndoListSize = d_varsUndoListSize + 1;
}
//! Check whether this variable's value is justified
bool checkJustified(SAT::Var v)
{ return d_cnfManager->concreteLit(SAT::Lit(v)).isJustified(); }
//! Mark this variable as justified
void setJustified(SAT::Var v)
{ d_cnfManager->concreteLit(SAT::Lit(v)).setJustified(); }
//! Main checking procedure shared by checkValid and restart
QueryResult check(const Expr& e, Theorem& result, bool isRestart = false);
//! Helper for newUserAssumption
Theorem newUserAssumptionInt(const Expr& e, SAT::CNF_Formula_Impl& cnf,
bool atBottomScope);
public:
//! Constructor
//! name is the name of the dpllt engine to use, as returned by getName()
SearchSat(TheoryCore* core, const std::string& name);
//! Destructor
virtual ~SearchSat();
// Implementation of virtual SearchEngine methods
virtual const std::string& getName() { return d_name; }
virtual void registerAtom(const Expr& e);
virtual Theorem getImpliedLiteral();
virtual void push() { d_dpllt->push(); }
virtual void pop() { d_dpllt->pop(); }
virtual QueryResult checkValid(const Expr& e, Theorem& result)
{ return check(e, result); }
virtual QueryResult restart(const Expr& e, Theorem& result)
{ return check(e, result, true); }
virtual void returnFromCheck();
virtual Theorem lastThm() { return d_lastValid; }
virtual Theorem newUserAssumption(const Expr& e);
virtual void getUserAssumptions(std::vector& assumptions);
virtual void getInternalAssumptions(std::vector& assumptions);
virtual void getAssumptions(std::vector& assumptions);
virtual bool isAssumption(const Expr& e);
virtual void getCounterExample(std::vector& assertions,
bool inOrder = true);
virtual Proof getProof();
};
inline bool operator<(const SearchSat::LitPriorityPair& p1,
const SearchSat::LitPriorityPair& p2)
{
if (p1.d_priority > p2.d_priority) return true;
if (p1.d_priority < p2.d_priority) return false;
return p1.d_lit.getVar() < p2.d_lit.getVar() ||
(p1.d_lit.getVar() == p2.d_lit.getVar() &&
p1.d_lit.isPositive() && !p2.d_lit.isPositive());
}
}
#endif