1 /********************* */
4 ** Original author: mdeters
5 ** Major contributors: dejan
6 ** Minor contributors (to current version): taking, barrett
7 ** This file is part of the CVC4 prototype.
8 ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys)
9 ** Courant Institute of Mathematical Sciences
10 ** New York University
11 ** See the file COPYING in the top-level source directory for licensing
12 ** information.\endverbatim
14 ** \brief Base of the theory interface.
16 ** Base of the theory interface.
19 #include "cvc4_private.h"
21 #ifndef __CVC4__THEORY__THEORY_H
22 #define __CVC4__THEORY__THEORY_H
24 #include "expr/node.h"
25 #include "expr/attribute.h"
26 #include "expr/command.h"
27 #include "theory/valuation.h"
28 #include "theory/substitutions.h"
29 #include "theory/output_channel.h"
30 #include "context/context.h"
31 #include "context/cdlist.h"
32 #include "context/cdo.h"
33 #include "util/options.h"
34 #include "util/dump.h"
46 * Information about an assertion for the theories.
52 /** Has this assertion been preregistered with this theory */
55 Assertion(TNode assertion
, bool isPreregistered
)
56 : assertion(assertion
), isPreregistered(isPreregistered
) {}
59 * Convert the assertion to a TNode.
61 operator TNode () const {
66 * Convert the assertion to a Node.
68 operator Node () const {
74 * A pair of terms a theory cares about.
79 CarePair(TNode a
, TNode b
, TheoryId theory
)
80 : a(a
), b(b
), theory(theory
) {}
84 * A set of care pairs.
86 typedef std::vector
<CarePair
> CareGraph
;
89 * Base class for T-solvers. Abstract DPLL(T).
91 * This is essentially an interface class. The TheoryEngine has
92 * pointers to Theory. Note that only one specific Theory type (e.g.,
93 * TheoryUF) can exist per NodeManager, because of how the
94 * RegisteredAttr works. (If you need multiple instances of the same
95 * theory, you'll have to write a multiplexed theory that dispatches
101 friend class ::CVC4::TheoryEngine
;
103 // Disallow default construction, copy, assignment.
104 Theory() CVC4_UNUSED
;
105 Theory(const Theory
&) CVC4_UNUSED
;
106 Theory
& operator=(const Theory
&) CVC4_UNUSED
;
109 * An integer identifying the type of the theory
114 * The context for the Theory.
116 context::Context
* d_context
;
119 * The user context for the Theory.
121 context::UserContext
* d_userContext
;
124 * The assertFact() queue.
126 * These can not be TNodes as some atoms (such as equalities) are sent
127 * across theories without being stored in a global map.
129 context::CDList
<Assertion
> d_facts
;
131 /** Index into the head of the facts list */
132 context::CDO
<unsigned> d_factsHead
;
135 * Add shared term to the theory.
137 void addSharedTermInternal(TNode node
);
140 * Indices for splitting on the shared terms.
142 context::CDO
<unsigned> d_sharedTermsIndex
;
147 * A list of shared terms that the theory has.
149 context::CDList
<TNode
> d_sharedTerms
;
152 * Construct a Theory.
154 Theory(TheoryId id
, context::Context
* context
, context::UserContext
* userContext
,
155 OutputChannel
& out
, Valuation valuation
) throw() :
158 d_userContext(userContext
),
160 d_factsHead(context
, 0),
161 d_sharedTermsIndex(context
, 0),
162 d_sharedTerms(context
),
164 d_valuation(valuation
)
169 * This is called at shutdown time by the TheoryEngine, just before
170 * destruction. It is important because there are destruction
171 * ordering issues between PropEngine and Theory (based on what
172 * hard-links to Nodes are outstanding). As the fact queue might be
173 * nonempty, we ensure here that it's clear. If you overload this,
174 * you must make an explicit call here to this->Theory::shutdown()
177 virtual void shutdown() { }
180 * The output channel for the Theory.
182 OutputChannel
* d_out
;
185 * The valuation proxy for the Theory to communicate back with the
186 * theory engine (and other theories).
188 Valuation d_valuation
;
191 * Returns the next assertion in the assertFact() queue.
193 * @return the next assertion in the assertFact() queue
196 Assert( !done(), "Theory`() called with assertion queue empty!" );
199 Assertion fact
= d_facts
[d_factsHead
];
200 d_factsHead
= d_factsHead
+ 1;
201 Trace("theory") << "Theory::get() => " << fact
<< " (" << d_facts
.size() - d_factsHead
<< " left)" << std::endl
;
202 if(Dump
.isOn("state")) {
203 Dump("state") << AssertCommand(fact
.assertion
.toExpr());
210 * The theory that owns the uninterpreted sort.
212 static TheoryId s_uninterpretedSortOwner
;
214 void printFacts(std::ostream
& os
) const;
220 * Return the ID of the theory responsible for the given type.
222 static inline TheoryId
theoryOf(TypeNode typeNode
) {
223 Trace("theory") << "theoryOf(" << typeNode
<< ")" << std::endl
;
225 while (typeNode
.isPredicateSubtype()) {
226 typeNode
= typeNode
.getSubtypeBaseType();
228 if (typeNode
.getKind() == kind::TYPE_CONSTANT
) {
229 id
= typeConstantToTheoryId(typeNode
.getConst
<TypeConstant
>());
231 id
= kindToTheoryId(typeNode
.getKind());
233 if (id
== THEORY_BUILTIN
) {
234 Trace("theory") << "theoryOf(" << typeNode
<< ") == " << s_uninterpretedSortOwner
<< std::endl
;
235 return s_uninterpretedSortOwner
;
242 * Returns the ID of the theory responsible for the given node.
244 static inline TheoryId
theoryOf(TNode node
) {
245 Trace("theory::internal") << "theoryOf(" << node
<< ")" << std::endl
;
246 // Constants, variables, 0-ary constructors
247 if (node
.getMetaKind() == kind::metakind::VARIABLE
|| node
.getMetaKind() == kind::metakind::CONSTANT
) {
248 return theoryOf(node
.getType());
250 // Equality is owned by the theory that owns the domain
251 if (node
.getKind() == kind::EQUAL
) {
252 return theoryOf(node
[0].getType());
254 // Regular nodes are owned by the kind
255 return kindToTheoryId(node
.getKind());
259 * Set the owner of the uninterpreted sort.
261 static void setUninterpretedSortOwner(TheoryId theory
) {
262 s_uninterpretedSortOwner
= theory
;
266 * Checks if the node is a leaf node of this theory
268 inline bool isLeaf(TNode node
) const {
269 return node
.getNumChildren() == 0 || theoryOf(node
) != d_id
;
273 * Checks if the node is a leaf node of a theory.
275 inline static bool isLeafOf(TNode node
, TheoryId theoryId
) {
276 return node
.getNumChildren() == 0 || theoryOf(node
) != theoryId
;
280 * Returns true if the assertFact queue is empty
282 bool done() throw() {
283 return d_factsHead
== d_facts
.size();
287 * Destructs a Theory. This implementation does nothing, but we
288 * need a virtual destructor for safety in case subclasses have a
295 * Subclasses of Theory may add additional efforts. DO NOT CHECK
296 * equality with one of these values (e.g. if STANDARD xxx) but
297 * rather use range checks (or use the helper functions below).
298 * Normally we call QUICK_CHECK or STANDARD; at the leaves we call
303 * Standard effort where theory need not do anything
305 EFFORT_STANDARD
= 50,
307 * Full effort requires the theory make sure its assertions are satisfiable or not
311 * Combination effort means that the individual theories are already satisfied, and
312 * it is time to put some effort into propagation of shared term equalities
314 EFFORT_COMBINATION
= 150
317 static inline bool standardEffortOrMore(Effort e
) CVC4_CONST_FUNCTION
318 { return e
>= EFFORT_STANDARD
; }
319 static inline bool standardEffortOnly(Effort e
) CVC4_CONST_FUNCTION
320 { return e
>= EFFORT_STANDARD
&& e
< EFFORT_FULL
; }
321 static inline bool fullEffort(Effort e
) CVC4_CONST_FUNCTION
322 { return e
== EFFORT_FULL
; }
323 static inline bool combination(Effort e
) CVC4_CONST_FUNCTION
324 { return e
== EFFORT_COMBINATION
; }
327 * Get the id for this Theory.
329 TheoryId
getId() const {
334 * Get the context associated to this Theory.
336 context::Context
* getContext() const {
341 * Get the context associated to this Theory.
343 context::UserContext
* getUserContext() const {
344 return d_userContext
;
348 * Set the output channel associated to this theory.
350 void setOutputChannel(OutputChannel
& out
) {
355 * Get the output channel associated to this theory.
357 OutputChannel
& getOutputChannel() {
362 * Pre-register a term. Done one time for a Node, ever.
364 virtual void preRegisterTerm(TNode
) { }
367 * Assert a fact in the current context.
369 void assertFact(TNode assertion
, bool isPreregistered
) {
370 Trace("theory") << "Theory<" << getId() << ">::assertFact[" << d_context
->getLevel() << "](" << assertion
<< ", " << (isPreregistered
? "true" : "false") << ")" << std::endl
;
371 d_facts
.push_back(Assertion(assertion
, isPreregistered
));
375 * This method is called to notify a theory that the node n should
376 * be considered a "shared term" by this theory
378 virtual void addSharedTerm(TNode n
) { }
381 * The function should compute the care graph over the shared terms.
382 * The default function returns all the pairs among the shared variables.
384 virtual void computeCareGraph(CareGraph
& careGraph
);
387 * Return the status of two terms in the current context. Should be implemented in
388 * sub-theories to enable more efficient theory-combination.
390 virtual EqualityStatus
getEqualityStatus(TNode a
, TNode b
) { return EQUALITY_UNKNOWN
; }
393 * This method is called by the shared term manager when a shared
394 * term lhs which this theory cares about (either because it
395 * received a previous addSharedTerm call with lhs or because it
396 * received a previous notifyEq call with lhs as the second
397 * argument) becomes equal to another shared term rhs. This call
398 * also serves as notice to the theory that the shared term manager
399 * now considers rhs the representative for this equivalence class
400 * of shared terms, so future notifications for this class will be
401 * based on rhs not lhs.
403 virtual void notifyEq(TNode lhs
, TNode rhs
) { }
406 * Check the current assignment's consistency.
408 * An implementation of check() is required to either:
409 * - return a conflict on the output channel,
411 * - throw an exception
412 * - or call get() until done() is true.
414 virtual void check(Effort level
= EFFORT_FULL
) { }
417 * T-propagate new literal assignments in the current context.
419 virtual void propagate(Effort level
= EFFORT_FULL
) { }
422 * Return an explanation for the literal represented by parameter n
423 * (which was previously propagated by this theory).
425 virtual Node
explain(TNode n
) {
426 Unimplemented("Theory %s propagated a node but doesn't implement the "
427 "Theory::explain() interface!", identify().c_str());
431 * Return the value of a node (typically used after a ). If the
432 * theory supports model generation but has no value for this node,
433 * it should return Node::null(). If the theory doesn't support
434 * model generation at all, or usually would but doesn't in its
435 * current state, it should throw an exception saying so.
437 * The TheoryEngine is passed in so that you can recursively request
438 * values for the Node's children. This is important because the
439 * TheoryEngine takes care of simple cases (metakind CONSTANT,
440 * Boolean-valued VARIABLES, ...) and can dispatch to other theories
441 * if that's necessary. Only call your own getValue() recursively
442 * if you *know* that you are responsible handle the Node you're
443 * asking for; other theories can use your types, so be careful
444 * here! To be safe, it's best to delegate back to the
445 * TheoryEngine (by way of the Valuation proxy object, which avoids
446 * direct dependence on TheoryEngine).
448 * Usually, you need to handle at least the two cases of EQUAL and
449 * VARIABLE---EQUAL in case a value of yours is on the LHS of an
450 * EQUAL, and VARIABLE for variables of your types. You also need
451 * to support any operators that can survive your rewriter. You
452 * don't need to handle constants, as they are handled by the
455 * There are some gotchas here. The user may be requesting the
456 * value of an expression that wasn't part of the satisfiable
457 * assertion, or has been declared since. If you don't have a value
458 * and suspect this situation is the case, return Node::null()
459 * rather than throwing an exception.
461 virtual Node
getValue(TNode n
) {
462 Unimplemented("Theory %s doesn't support Theory::getValue interface",
468 * Statically learn from assertion "in," which has been asserted
469 * true at the top level. The theory should only add (via
470 * ::operator<< or ::append()) to the "learned" builder---it should
471 * *never* clear it. It is a conjunction to add to the formula at
472 * the top-level and may contain other theories' contributions.
474 virtual void ppStaticLearn(TNode in
, NodeBuilder
<>& learned
) { }
476 enum PPAssertStatus
{
477 /** Atom has been solved */
478 PP_ASSERT_STATUS_SOLVED
,
479 /** Atom has not been solved */
480 PP_ASSERT_STATUS_UNSOLVED
,
481 /** Atom is inconsistent */
482 PP_ASSERT_STATUS_CONFLICT
486 * Given a literal, add the solved substitutions to the map, if any.
487 * The method should return true if the literal can be safely removed.
489 virtual PPAssertStatus
ppAssert(TNode in
, SubstitutionMap
& outSubstitutions
) {
490 if (in
.getKind() == kind::EQUAL
) {
491 if (in
[0].getMetaKind() == kind::metakind::VARIABLE
&& !in
[1].hasSubterm(in
[0])) {
492 outSubstitutions
.addSubstitution(in
[0], in
[1]);
493 return PP_ASSERT_STATUS_SOLVED
;
495 if (in
[1].getMetaKind() == kind::metakind::VARIABLE
&& !in
[0].hasSubterm(in
[1])) {
496 outSubstitutions
.addSubstitution(in
[1], in
[0]);
497 return PP_ASSERT_STATUS_SOLVED
;
499 if (in
[0].getMetaKind() == kind::metakind::CONSTANT
&& in
[1].getMetaKind() == kind::metakind::CONSTANT
) {
500 if (in
[0] != in
[1]) {
501 return PP_ASSERT_STATUS_CONFLICT
;
506 return PP_ASSERT_STATUS_UNSOLVED
;
510 * Given an atom of the theory coming from the input formula, this
511 * method can be overridden in a theory implementation to rewrite
512 * the atom into an equivalent form. This is only called just
513 * before an input atom to the engine.
515 virtual Node
ppRewrite(TNode atom
) { return atom
; }
518 * A Theory is called with presolve exactly one time per user
519 * check-sat. presolve() is called after preregistration,
520 * rewriting, and Boolean propagation, (other theories'
521 * propagation?), but the notified Theory has not yet had its
522 * check() or propagate() method called. A Theory may empty its
523 * assertFact() queue using get(). A Theory can raise conflicts,
524 * add lemmas, and propagate literals during presolve().
526 virtual void presolve() { }
529 * A Theory is called with postsolve exactly one time per user
530 * check-sat. postsolve() is called after the query has completed
531 * (regardless of whether sat, unsat, or unknown), and after any
532 * model-querying related to the query has been performed.
533 * After this call, the theory will not get another check() or
534 * propagate() call until presolve() is called again. A Theory
535 * cannot raise conflicts, add lemmas, or propagate literals during
538 virtual void postsolve() { }
541 * Notification sent to the theory wheneven the search restarts.
542 * Serves as a good time to do some clean-up work, and you can
543 * assume you're at DL 0 for the purposes of Contexts. This function
544 * should not use the output channel.
546 virtual void notifyRestart() { }
549 * Identify this theory (for debugging, dynamic configuration,
552 virtual std::string
identify() const = 0;
554 /** A set of theories */
555 typedef uint32_t Set
;
557 /** A set of all theories */
558 static const Set AllTheories
= (1 << theory::THEORY_LAST
) - 1;
560 /** Add the theory to the set. If no set specified, just returns a singleton set */
561 static inline Set
setInsert(TheoryId theory
, Set set
= 0) {
562 return set
| (1 << theory
);
565 /** Check if the set contains the theory */
566 static inline bool setContains(TheoryId theory
, Set set
) {
567 return set
& (1 << theory
);
570 static inline Set
setComplement(Set a
) {
571 return (~a
) & AllTheories
;
574 static inline Set
setIntersection(Set a
, Set b
) {
578 static inline Set
setUnion(Set a
, Set b
) {
583 static inline Set
setDifference(Set a
, Set b
) {
584 return ((~b
) & AllTheories
) & a
;
587 static inline std::string
setToString(theory::Theory::Set theorySet
) {
588 std::stringstream ss
;
590 for(unsigned theoryId
= 0; theoryId
< theory::THEORY_LAST
; ++theoryId
) {
591 if (theory::Theory::setContains((theory::TheoryId
)theoryId
, theorySet
)) {
592 ss
<< (theory::TheoryId
) theoryId
<< " ";
600 * Provides access to the facts queue, primarily intended for theory
601 * debugging purposes.
603 * @return the iterator to the beginning of the fact queue
605 context::CDList
<Assertion
>::const_iterator
facts_begin() const {
606 return d_facts
.begin();
610 * Provides access to the facts queue, primarily intended for theory
611 * debugging purposes.
613 * @return the iterator to the end of the fact queue
615 context::CDList
<Assertion
>::const_iterator
facts_end() const {
616 return d_facts
.end();
620 * Provides access to the shared terms, primarily intended for theory
621 * debugging purposes.
623 * @return the iterator to the beginning of the shared terms list
625 context::CDList
<TNode
>::const_iterator
shared_terms_begin() const {
626 return d_sharedTerms
.begin();
630 * Provides access to the facts queue, primarily intended for theory
631 * debugging purposes.
633 * @return the iterator to the end of the shared terms list
635 context::CDList
<TNode
>::const_iterator
shared_terms_end() const {
636 return d_sharedTerms
.end();
641 std::ostream
& operator<<(std::ostream
& os
, Theory::Effort level
);
643 }/* CVC4::theory namespace */
645 inline std::ostream
& operator<<(std::ostream
& out
,
646 const CVC4::theory::Theory
& theory
) {
647 return out
<< theory
.identify();
650 inline std::ostream
& operator << (std::ostream
& out
, theory::Theory::PPAssertStatus status
) {
652 case theory::Theory::PP_ASSERT_STATUS_SOLVED
:
653 out
<< "SOLVE_STATUS_SOLVED"; break;
654 case theory::Theory::PP_ASSERT_STATUS_UNSOLVED
:
655 out
<< "SOLVE_STATUS_UNSOLVED"; break;
656 case theory::Theory::PP_ASSERT_STATUS_CONFLICT
:
657 out
<< "SOLVE_STATUS_CONFLICT"; break;
664 }/* CVC4 namespace */
666 #endif /* __CVC4__THEORY__THEORY_H */