1 /********************* */
4 ** Top contributors (to current version):
5 ** Andrew Reynolds, Tim King, Dejan Jovanovic
6 ** This file is part of the CVC4 project.
7 ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
8 ** in the top-level source directory and their institutional affiliations.
9 ** All rights reserved. See the file COPYING in the top-level source
10 ** directory for licensing information.\endverbatim
12 ** \brief Base for theory interface.
14 ** Base for theory interface.
17 #include "theory/theory.h"
24 #include "base/check.h"
25 #include "expr/node_algorithm.h"
26 #include "options/smt_options.h"
27 #include "options/theory_options.h"
28 #include "smt/smt_statistics_registry.h"
29 #include "theory/ext_theory.h"
30 #include "theory/quantifiers_engine.h"
31 #include "theory/substitutions.h"
32 #include "theory/theory_rewriter.h"
39 /** Default value for the uninterpreted sorts is the UF theory */
40 TheoryId
Theory::s_uninterpretedSortOwner
= THEORY_UF
;
42 std::ostream
& operator<<(std::ostream
& os
, Theory::Effort level
){
44 case Theory::EFFORT_STANDARD
:
45 os
<< "EFFORT_STANDARD"; break;
46 case Theory::EFFORT_FULL
:
47 os
<< "EFFORT_FULL"; break;
48 case Theory::EFFORT_LAST_CALL
:
49 os
<< "EFFORT_LAST_CALL"; break;
54 }/* ostream& operator<<(ostream&, Theory::Effort) */
56 Theory::Theory(TheoryId id
,
57 context::Context
* satContext
,
58 context::UserContext
* userContext
,
61 const LogicInfo
& logicInfo
,
62 ProofNodeManager
* pnm
,
65 d_satContext(satContext
),
66 d_userContext(userContext
),
67 d_logicInfo(logicInfo
),
70 d_factsHead(satContext
, 0),
71 d_sharedTermsIndex(satContext
, 0),
74 d_decManager(nullptr),
76 d_checkTime(getStatsPrefix(id
) + name
+ "::checkTime"),
77 d_computeCareGraphTime(getStatsPrefix(id
) + name
78 + "::computeCareGraphTime"),
79 d_sharedTerms(satContext
),
81 d_valuation(valuation
),
82 d_equalityEngine(nullptr),
83 d_allocEqualityEngine(nullptr),
84 d_theoryState(nullptr),
85 d_inferManager(nullptr)
87 smtStatisticsRegistry()->registerStat(&d_checkTime
);
88 smtStatisticsRegistry()->registerStat(&d_computeCareGraphTime
);
92 smtStatisticsRegistry()->unregisterStat(&d_checkTime
);
93 smtStatisticsRegistry()->unregisterStat(&d_computeCareGraphTime
);
96 bool Theory::needsEqualityEngine(EeSetupInfo
& esi
)
98 // by default, this theory does not use an (official) equality engine
102 void Theory::setEqualityEngine(eq::EqualityEngine
* ee
)
104 // set the equality engine pointer
105 d_equalityEngine
= ee
;
106 if (d_theoryState
!= nullptr)
108 d_theoryState
->setEqualityEngine(ee
);
110 if (d_inferManager
!= nullptr)
112 d_inferManager
->setEqualityEngine(ee
);
116 void Theory::setQuantifiersEngine(QuantifiersEngine
* qe
)
118 Assert(d_quantEngine
== nullptr);
119 // quantifiers engine may be null if not in quantified logic
123 void Theory::setDecisionManager(DecisionManager
* dm
)
125 Assert(d_decManager
== nullptr);
126 Assert(dm
!= nullptr);
130 void Theory::finishInitStandalone()
133 if (needsEqualityEngine(esi
))
135 // always associated with the same SAT context as the theory (d_satContext)
136 d_allocEqualityEngine
.reset(new eq::EqualityEngine(
137 *esi
.d_notify
, d_satContext
, esi
.d_name
, esi
.d_constantsAreTriggers
));
138 // use it as the official equality engine
139 setEqualityEngine(d_allocEqualityEngine
.get());
144 TheoryId
Theory::theoryOf(options::TheoryOfMode mode
, TNode node
)
146 TheoryId tid
= THEORY_BUILTIN
;
148 case options::TheoryOfMode::THEORY_OF_TYPE_BASED
:
149 // Constants, variables, 0-ary constructors
152 if (node
.getKind() == kind::BOOLEAN_TERM_VARIABLE
)
158 tid
= Theory::theoryOf(node
.getType());
161 else if (node
.isConst())
163 tid
= Theory::theoryOf(node
.getType());
165 else if (node
.getKind() == kind::EQUAL
)
167 // Equality is owned by the theory that owns the domain
168 tid
= Theory::theoryOf(node
[0].getType());
172 // Regular nodes are owned by the kind
173 tid
= kindToTheoryId(node
.getKind());
176 case options::TheoryOfMode::THEORY_OF_TERM_BASED
:
180 if (Theory::theoryOf(node
.getType()) != theory::THEORY_BOOL
)
182 // We treat the variables as uninterpreted
183 tid
= s_uninterpretedSortOwner
;
187 if (node
.getKind() == kind::BOOLEAN_TERM_VARIABLE
)
189 // Boolean vars go to UF
194 // Except for the Boolean ones
199 else if (node
.isConst())
201 // Constants go to the theory of the type
202 tid
= Theory::theoryOf(node
.getType());
204 else if (node
.getKind() == kind::EQUAL
)
206 // If one of them is an ITE, it's irelevant, since they will get
207 // replaced out anyhow
208 if (node
[0].getKind() == kind::ITE
)
210 tid
= Theory::theoryOf(node
[0].getType());
212 else if (node
[1].getKind() == kind::ITE
)
214 tid
= Theory::theoryOf(node
[1].getType());
220 TypeNode ltype
= l
.getType();
221 TypeNode rtype
= r
.getType();
224 tid
= Theory::theoryOf(l
.getType());
228 // If both sides belong to the same theory the choice is easy
229 TheoryId T1
= Theory::theoryOf(l
);
230 TheoryId T2
= Theory::theoryOf(r
);
237 TheoryId T3
= Theory::theoryOf(ltype
);
239 // * x*y = f(z) -> UF
241 // * f(x) = read(a, y) -> either UF or ARRAY
242 // at least one of the theories has to be parametric, i.e. theory
243 // of the type is different from the theory of the term
254 // If both are parametric, we take the smaller one (arbitrary)
255 tid
= T1
< T2
? T1
: T2
;
263 // Regular nodes are owned by the kind
264 tid
= kindToTheoryId(node
.getKind());
270 Trace("theory::internal") << "theoryOf(" << mode
<< ", " << node
<< ") -> " << tid
<< std::endl
;
274 void Theory::notifySharedTerm(TNode n
)
276 // TODO (project #39): this will move to addSharedTerm, as every theory with
277 // an equality does this in their notifySharedTerm method.
278 // if we have an equality engine, add the trigger term
279 if (d_equalityEngine
!= nullptr)
281 d_equalityEngine
->addTriggerTerm(n
, d_id
);
285 void Theory::computeCareGraph() {
286 Debug("sharing") << "Theory::computeCareGraph<" << getId() << ">()" << endl
;
287 for (unsigned i
= 0; i
< d_sharedTerms
.size(); ++ i
) {
288 TNode a
= d_sharedTerms
[i
];
289 TypeNode aType
= a
.getType();
290 for (unsigned j
= i
+ 1; j
< d_sharedTerms
.size(); ++ j
) {
291 TNode b
= d_sharedTerms
[j
];
292 if (b
.getType() != aType
) {
293 // We don't care about the terms of different types
296 switch (d_valuation
.getEqualityStatus(a
, b
)) {
297 case EQUALITY_TRUE_AND_PROPAGATED
:
298 case EQUALITY_FALSE_AND_PROPAGATED
:
299 // If we know about it, we should have propagated it, so we can skip
310 void Theory::printFacts(std::ostream
& os
) const {
311 unsigned i
, n
= d_facts
.size();
312 for(i
= 0; i
< n
; i
++){
313 const Assertion
& a_i
= d_facts
[i
];
314 Node assertion
= a_i
;
315 os
<< d_id
<< '[' << i
<< ']' << " " << assertion
<< endl
;
319 void Theory::debugPrintFacts() const{
320 DebugChannel
.getStream() << "Theory::debugPrintFacts()" << endl
;
321 printFacts(DebugChannel
.getStream());
324 bool Theory::isLegalElimination(TNode x
, TNode val
)
327 if (x
.getKind() == kind::BOOLEAN_TERM_VARIABLE
328 || val
.getKind() == kind::BOOLEAN_TERM_VARIABLE
)
332 if (expr::hasSubterm(val
, x
))
336 if (!val
.getType().isSubtypeOf(x
.getType()))
340 if (!options::produceModels())
342 // don't care about the model, we are fine
345 // if there is a model object
346 TheoryModel
* tm
= d_valuation
.getModel();
347 Assert(tm
!= nullptr);
348 return tm
->isLegalElimination(x
, val
);
351 std::unordered_set
<TNode
, TNodeHashFunction
> Theory::currentlySharedTerms() const{
352 std::unordered_set
<TNode
, TNodeHashFunction
> currentlyShared
;
353 for (shared_terms_iterator i
= shared_terms_begin(),
354 i_end
= shared_terms_end(); i
!= i_end
; ++i
) {
355 currentlyShared
.insert (*i
);
357 return currentlyShared
;
360 bool Theory::collectModelInfo(TheoryModel
* m
)
362 // NOTE: the computation of termSet will be moved to model manager
363 // and passed as an argument to collectModelInfo.
364 std::set
<Node
> termSet
;
365 // Compute terms appearing in assertions and shared terms
366 TheoryModel
* tm
= d_valuation
.getModel();
367 Assert(tm
!= nullptr);
368 const std::set
<Kind
>& irrKinds
= tm
->getIrrelevantKinds();
369 computeAssertedTerms(termSet
, irrKinds
, true);
370 // Compute additional relevant terms (theory-specific)
371 computeRelevantTerms(termSet
);
372 // if we are using an equality engine, assert it to the model
373 if (d_equalityEngine
!= nullptr)
375 if (!m
->assertEqualityEngine(d_equalityEngine
, &termSet
))
380 // now, collect theory-specific value assigments
381 return collectModelValues(m
, termSet
);
384 void Theory::collectTerms(TNode n
,
385 const std::set
<Kind
>& irrKinds
,
386 set
<Node
>& termSet
) const
388 if (termSet
.find(n
) != termSet
.end()) {
391 Kind nk
= n
.getKind();
392 if (irrKinds
.find(nk
) == irrKinds
.end())
394 Trace("theory::collectTerms")
395 << "Theory::collectTerms: adding " << n
<< endl
;
398 if (nk
== kind::NOT
|| nk
== kind::EQUAL
|| !isLeaf(n
))
400 for(TNode::iterator child_it
= n
.begin(); child_it
!= n
.end(); ++child_it
) {
401 collectTerms(*child_it
, irrKinds
, termSet
);
406 void Theory::computeAssertedTerms(std::set
<Node
>& termSet
,
407 const std::set
<Kind
>& irrKinds
,
408 bool includeShared
) const
410 // Collect all terms appearing in assertions
411 context::CDList
<Assertion
>::const_iterator assert_it
= facts_begin(),
412 assert_it_end
= facts_end();
413 for (; assert_it
!= assert_it_end
; ++assert_it
)
415 collectTerms(*assert_it
, irrKinds
, termSet
);
422 // Add terms that are shared terms
423 std::set
<Kind
> kempty
;
424 context::CDList
<TNode
>::const_iterator shared_it
= shared_terms_begin(),
425 shared_it_end
= shared_terms_end();
426 for (; shared_it
!= shared_it_end
; ++shared_it
)
428 collectTerms(*shared_it
, kempty
, termSet
);
432 void Theory::computeRelevantTerms(std::set
<Node
>& termSet
)
434 // by default, there are no additional relevant terms
437 bool Theory::collectModelValues(TheoryModel
* m
, const std::set
<Node
>& termSet
)
442 Theory::PPAssertStatus
Theory::ppAssert(TNode in
,
443 SubstitutionMap
& outSubstitutions
)
445 if (in
.getKind() == kind::EQUAL
)
447 // (and (= x t) phi) can be replaced by phi[x/t] if
448 // 1) x is a variable
449 // 2) x is not in the term t
450 // 3) x : T and t : S, then S <: T
451 if (in
[0].isVar() && isLegalElimination(in
[0], in
[1])
452 && in
[0].getKind() != kind::BOOLEAN_TERM_VARIABLE
)
454 outSubstitutions
.addSubstitution(in
[0], in
[1]);
455 return PP_ASSERT_STATUS_SOLVED
;
457 if (in
[1].isVar() && isLegalElimination(in
[1], in
[0])
458 && in
[1].getKind() != kind::BOOLEAN_TERM_VARIABLE
)
460 outSubstitutions
.addSubstitution(in
[1], in
[0]);
461 return PP_ASSERT_STATUS_SOLVED
;
463 if (in
[0].isConst() && in
[1].isConst())
467 return PP_ASSERT_STATUS_CONFLICT
;
472 return PP_ASSERT_STATUS_UNSOLVED
;
475 std::pair
<bool, Node
> Theory::entailmentCheck(TNode lit
)
477 return make_pair(false, Node::null());
480 void Theory::addCarePair(TNode t1
, TNode t2
) {
482 d_careGraph
->insert(CarePair(t1
, t2
, d_id
));
486 void Theory::getCareGraph(CareGraph
* careGraph
) {
487 Assert(careGraph
!= NULL
);
489 Trace("sharing") << "Theory<" << getId() << ">::getCareGraph()" << std::endl
;
490 TimerStat::CodeTimer
computeCareGraphTime(d_computeCareGraphTime
);
491 d_careGraph
= careGraph
;
496 EqualityStatus
Theory::getEqualityStatus(TNode a
, TNode b
)
498 // if not using an equality engine, then by default we don't know the status
499 if (d_equalityEngine
== nullptr)
501 return EQUALITY_UNKNOWN
;
503 Assert(d_equalityEngine
->hasTerm(a
) && d_equalityEngine
->hasTerm(b
));
505 // Check for equality (simplest)
506 if (d_equalityEngine
->areEqual(a
, b
))
508 // The terms are implied to be equal
509 return EQUALITY_TRUE
;
512 // Check for disequality
513 if (d_equalityEngine
->areDisequal(a
, b
, false))
515 // The terms are implied to be dis-equal
516 return EQUALITY_FALSE
;
519 // All other terms are unknown, which is conservative. A theory may override
520 // this method if it knows more information.
521 return EQUALITY_UNKNOWN
;
524 void Theory::check(Effort level
)
526 // see if we are already done (as an optimization)
527 if (done() && level
< EFFORT_FULL
)
531 Assert(d_theoryState
!=nullptr);
532 // standard calls for resource, stats
533 d_out
->spendResource(ResourceManager::Resource::TheoryCheckStep
);
534 TimerStat::CodeTimer
checkTimer(d_checkTime
);
535 // pre-check at level
538 // check aborted for a theory-specific reason
541 // process the pending fact queue
542 while (!done() && !d_theoryState
->isInConflict())
544 // Get the next assertion from the fact queue
545 Assertion assertion
= get();
546 TNode fact
= assertion
.d_assertion
;
547 bool polarity
= fact
.getKind() != kind::NOT
;
548 TNode atom
= polarity
? fact
: fact
[0];
549 // call the pre-notify method
550 if (preNotifyFact(atom
, polarity
, fact
, assertion
.d_isPreregistered
, false))
552 // handled in theory-specific way that doesn't involve equality engine
555 // Theories that don't have an equality engine should always return true
557 Assert(d_equalityEngine
!= nullptr);
558 // assert to the equality engine
559 if (atom
.getKind() == kind::EQUAL
)
561 d_equalityEngine
->assertEquality(atom
, polarity
, fact
);
565 d_equalityEngine
->assertPredicate(atom
, polarity
, fact
);
567 // notify the theory of the new fact, which is not internal
568 notifyFact(atom
, polarity
, fact
, false);
570 // post-check at level
574 bool Theory::preCheck(Effort level
) { return false; }
576 void Theory::postCheck(Effort level
) {}
578 bool Theory::preNotifyFact(
579 TNode atom
, bool polarity
, TNode fact
, bool isPrereg
, bool isInternal
)
584 void Theory::notifyFact(TNode atom
, bool polarity
, TNode fact
, bool isInternal
)
588 void Theory::preRegisterTerm(TNode node
) {}
590 void Theory::addSharedTerm(TNode n
)
592 Debug("sharing") << "Theory::addSharedTerm<" << getId() << ">(" << n
<< ")"
594 Debug("theory::assertions")
595 << "Theory::addSharedTerm<" << getId() << ">(" << n
<< ")" << std::endl
;
596 d_sharedTerms
.push_back(n
);
597 // now call theory-specific method notifySharedTerm
601 eq::EqualityEngine
* Theory::getEqualityEngine()
603 // get the assigned equality engine, which is a pointer stored in this class
604 return d_equalityEngine
;
607 }/* CVC4::theory namespace */
608 }/* CVC4 namespace */