1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Andrew Reynolds, Morgan Deters, Dejan Jovanovic |
4 |
|
* |
5 |
|
* This file is part of the cvc5 project. |
6 |
|
* |
7 |
|
* Copyright (c) 2009-2021 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. |
11 |
|
* **************************************************************************** |
12 |
|
* |
13 |
|
* Base of the theory interface. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "cvc5_private.h" |
17 |
|
|
18 |
|
#ifndef CVC5__THEORY__THEORY_H |
19 |
|
#define CVC5__THEORY__THEORY_H |
20 |
|
|
21 |
|
#include <iosfwd> |
22 |
|
#include <set> |
23 |
|
#include <string> |
24 |
|
#include <unordered_set> |
25 |
|
|
26 |
|
#include "context/cdlist.h" |
27 |
|
#include "context/cdo.h" |
28 |
|
#include "context/context.h" |
29 |
|
#include "expr/node.h" |
30 |
|
#include "options/theory_options.h" |
31 |
|
#include "proof/trust_node.h" |
32 |
|
#include "smt/env.h" |
33 |
|
#include "smt/env_obj.h" |
34 |
|
#include "theory/assertion.h" |
35 |
|
#include "theory/care_graph.h" |
36 |
|
#include "theory/logic_info.h" |
37 |
|
#include "theory/skolem_lemma.h" |
38 |
|
#include "theory/theory_id.h" |
39 |
|
#include "theory/valuation.h" |
40 |
|
#include "util/statistics_stats.h" |
41 |
|
|
42 |
|
namespace cvc5 { |
43 |
|
|
44 |
|
class ProofNodeManager; |
45 |
|
class TheoryEngine; |
46 |
|
class ProofRuleChecker; |
47 |
|
|
48 |
|
namespace theory { |
49 |
|
|
50 |
|
class DecisionManager; |
51 |
|
struct EeSetupInfo; |
52 |
|
class OutputChannel; |
53 |
|
class QuantifiersEngine; |
54 |
|
class TheoryInferenceManager; |
55 |
|
class TheoryModel; |
56 |
|
class TheoryRewriter; |
57 |
|
class TheoryState; |
58 |
|
class TrustSubstitutionMap; |
59 |
|
|
60 |
|
namespace eq { |
61 |
|
class EqualityEngine; |
62 |
|
} // namespace eq |
63 |
|
|
64 |
|
/** |
65 |
|
* Base class for T-solvers. Abstract DPLL(T). |
66 |
|
* |
67 |
|
* This is essentially an interface class. The TheoryEngine has |
68 |
|
* pointers to Theory. Note that only one specific Theory type (e.g., |
69 |
|
* TheoryUF) can exist per NodeManager, because of how the |
70 |
|
* RegisteredAttr works. (If you need multiple instances of the same |
71 |
|
* theory, you'll have to write a multiplexed theory that dispatches |
72 |
|
* all calls to them.) |
73 |
|
* |
74 |
|
* NOTE: A Theory has a special way of being initialized. The owner of a Theory |
75 |
|
* is either: |
76 |
|
* |
77 |
|
* (A) Using Theory as a standalone object, not associated with a TheoryEngine. |
78 |
|
* In this case, simply call the public initialization method |
79 |
|
* (Theory::finishInitStandalone). |
80 |
|
* |
81 |
|
* (B) TheoryEngine, which determines how the Theory acts in accordance with |
82 |
|
* its theory combination policy. We require the following steps in order: |
83 |
|
* (B.1) Get information about whether the theory wishes to use an equality |
84 |
|
* eninge, and more specifically which equality engine notifications the Theory |
85 |
|
* would like to be notified of (Theory::needsEqualityEngine). |
86 |
|
* (B.2) Set the equality engine of the theory (Theory::setEqualityEngine), |
87 |
|
* which we refer to as the "official equality engine" of this Theory. The |
88 |
|
* equality engine passed to the theory must respect the contract(s) specified |
89 |
|
* by the equality engine setup information (EeSetupInfo) returned in the |
90 |
|
* previous step. |
91 |
|
* (B.3) Set the other required utilities including setQuantifiersEngine and |
92 |
|
* setDecisionManager. |
93 |
|
* (B.4) Call the private initialization method (Theory::finishInit). |
94 |
|
* |
95 |
|
* Initialization of the second form happens during TheoryEngine::finishInit, |
96 |
|
* after the quantifiers engine and model objects have been set up. |
97 |
|
*/ |
98 |
|
class Theory : protected EnvObj |
99 |
|
{ |
100 |
|
friend class ::cvc5::TheoryEngine; |
101 |
|
|
102 |
|
private: |
103 |
|
// Disallow default construction, copy, assignment. |
104 |
|
Theory() = delete; |
105 |
|
Theory(const Theory&) = delete; |
106 |
|
Theory& operator=(const Theory&) = delete; |
107 |
|
|
108 |
|
/** An integer identifying the type of the theory. */ |
109 |
|
TheoryId d_id; |
110 |
|
|
111 |
|
/** |
112 |
|
* The assertFact() queue. |
113 |
|
* |
114 |
|
* These can not be TNodes as some atoms (such as equalities) are sent |
115 |
|
* across theories without being stored in a global map. |
116 |
|
*/ |
117 |
|
context::CDList<Assertion> d_facts; |
118 |
|
|
119 |
|
/** Index into the head of the facts list */ |
120 |
|
context::CDO<unsigned> d_factsHead; |
121 |
|
|
122 |
|
/** Indices for splitting on the shared terms. */ |
123 |
|
context::CDO<unsigned> d_sharedTermsIndex; |
124 |
|
|
125 |
|
/** The care graph the theory will use during combination. */ |
126 |
|
CareGraph* d_careGraph; |
127 |
|
|
128 |
|
/** Pointer to the decision manager. */ |
129 |
|
DecisionManager* d_decManager; |
130 |
|
|
131 |
|
protected: |
132 |
|
/** Name of this theory instance. Along with the TheoryId this should |
133 |
|
* provide an unique string identifier for each instance of a Theory class. |
134 |
|
* We need this to ensure unique statistics names over multiple theory |
135 |
|
* instances. */ |
136 |
|
std::string d_instanceName; |
137 |
|
|
138 |
|
// === STATISTICS === |
139 |
|
/** time spent in check calls */ |
140 |
|
TimerStat d_checkTime; |
141 |
|
/** time spent in theory combination */ |
142 |
|
TimerStat d_computeCareGraphTime; |
143 |
|
|
144 |
|
/** |
145 |
|
* The only method to add suff to the care graph. |
146 |
|
*/ |
147 |
|
void addCarePair(TNode t1, TNode t2); |
148 |
|
|
149 |
|
/** |
150 |
|
* The function should compute the care graph over the shared terms. |
151 |
|
* The default function returns all the pairs among the shared variables. |
152 |
|
*/ |
153 |
|
virtual void computeCareGraph(); |
154 |
|
|
155 |
|
/** |
156 |
|
* A list of shared terms that the theory has. |
157 |
|
*/ |
158 |
|
context::CDList<TNode> d_sharedTerms; |
159 |
|
|
160 |
|
/** |
161 |
|
* Construct a Theory. |
162 |
|
* |
163 |
|
* The pair <id, instance> is assumed to uniquely identify this Theory |
164 |
|
* w.r.t. the SmtEngine. |
165 |
|
*/ |
166 |
|
Theory(TheoryId id, |
167 |
|
Env& env, |
168 |
|
OutputChannel& out, |
169 |
|
Valuation valuation, |
170 |
|
std::string instance = ""); // taking : No default. |
171 |
|
|
172 |
|
/** |
173 |
|
* This is called at shutdown time by the TheoryEngine, just before |
174 |
|
* destruction. It is important because there are destruction |
175 |
|
* ordering issues between PropEngine and Theory (based on what |
176 |
|
* hard-links to Nodes are outstanding). As the fact queue might be |
177 |
|
* nonempty, we ensure here that it's clear. If you overload this, |
178 |
|
* you must make an explicit call here to this->Theory::shutdown() |
179 |
|
* too. |
180 |
|
*/ |
181 |
79294 |
virtual void shutdown() {} |
182 |
|
|
183 |
|
/** |
184 |
|
* The output channel for the Theory. |
185 |
|
*/ |
186 |
|
OutputChannel* d_out; |
187 |
|
|
188 |
|
/** |
189 |
|
* The valuation proxy for the Theory to communicate back with the |
190 |
|
* theory engine (and other theories). |
191 |
|
*/ |
192 |
|
Valuation d_valuation; |
193 |
|
/** |
194 |
|
* Pointer to the official equality engine of this theory, which is owned by |
195 |
|
* the equality engine manager of TheoryEngine. |
196 |
|
*/ |
197 |
|
eq::EqualityEngine* d_equalityEngine; |
198 |
|
/** |
199 |
|
* The official equality engine, if we allocated it. |
200 |
|
*/ |
201 |
|
std::unique_ptr<eq::EqualityEngine> d_allocEqualityEngine; |
202 |
|
/** |
203 |
|
* The theory state, which contains contexts, valuation, and equality |
204 |
|
* engine. Notice the theory is responsible for memory management of this |
205 |
|
* class. |
206 |
|
*/ |
207 |
|
TheoryState* d_theoryState; |
208 |
|
/** |
209 |
|
* The theory inference manager. This is a wrapper around the equality |
210 |
|
* engine and the output channel. It ensures that the output channel and |
211 |
|
* the equality engine are used properly. |
212 |
|
*/ |
213 |
|
TheoryInferenceManager* d_inferManager; |
214 |
|
|
215 |
|
/** |
216 |
|
* Pointer to the quantifiers engine (or NULL, if quantifiers are not |
217 |
|
* supported or not enabled). Not owned by the theory. |
218 |
|
*/ |
219 |
|
QuantifiersEngine* d_quantEngine; |
220 |
|
|
221 |
|
/** Pointer to proof node manager */ |
222 |
|
ProofNodeManager* d_pnm; |
223 |
|
/** |
224 |
|
* Are proofs enabled? |
225 |
|
* |
226 |
|
* They are considered enabled if the ProofNodeManager is non-null. |
227 |
|
*/ |
228 |
|
bool proofsEnabled() const; |
229 |
|
|
230 |
|
/** |
231 |
|
* Returns the next assertion in the assertFact() queue. |
232 |
|
* |
233 |
|
* @return the next assertion in the assertFact() queue |
234 |
|
*/ |
235 |
|
inline Assertion get(); |
236 |
|
|
237 |
|
/** |
238 |
|
* Set separation logic heap. This is called when the location and data |
239 |
|
* types for separation logic are determined. This should be called at |
240 |
|
* most once, before solving. |
241 |
|
* |
242 |
|
* This currently should be overridden by the separation logic theory only. |
243 |
|
*/ |
244 |
1444 |
virtual void declareSepHeap(TypeNode locT, TypeNode dataT) {} |
245 |
|
|
246 |
|
/** |
247 |
|
* The theory that owns the uninterpreted sort. |
248 |
|
*/ |
249 |
|
static TheoryId s_uninterpretedSortOwner; |
250 |
|
|
251 |
|
void printFacts(std::ostream& os) const; |
252 |
|
void debugPrintFacts() const; |
253 |
|
|
254 |
|
/** is legal elimination |
255 |
|
* |
256 |
|
* Returns true if x -> val is a legal elimination of variable x. This is |
257 |
|
* useful for ppAssert, when x = val is an entailed equality. This function |
258 |
|
* determines whether indeed x can be eliminated from the problem via the |
259 |
|
* substituion x -> val. |
260 |
|
* |
261 |
|
* The following criteria imply that x -> val is *not* a legal elimination: |
262 |
|
* (1) If x is contained in val, |
263 |
|
* (2) If the type of val is not a subtype of the type of x, |
264 |
|
* (3) If val contains an operator that cannot be evaluated, and |
265 |
|
* produceModels is true. For example, x -> sqrt(2) is not a legal |
266 |
|
* elimination if we are producing models. This is because we care about the |
267 |
|
* value of x, and its value must be computed (approximated) by the |
268 |
|
* non-linear solver. |
269 |
|
*/ |
270 |
|
bool isLegalElimination(TNode x, TNode val); |
271 |
|
//--------------------------------- private initialization |
272 |
|
/** |
273 |
|
* Called to set the official equality engine. This should be done by |
274 |
|
* TheoryEngine only. |
275 |
|
*/ |
276 |
|
void setEqualityEngine(eq::EqualityEngine* ee); |
277 |
|
/** Called to set the quantifiers engine. */ |
278 |
|
void setQuantifiersEngine(QuantifiersEngine* qe); |
279 |
|
/** Called to set the decision manager. */ |
280 |
|
void setDecisionManager(DecisionManager* dm); |
281 |
|
/** |
282 |
|
* Finish theory initialization. At this point, options and the logic |
283 |
|
* setting are final, the master equality engine and quantifiers |
284 |
|
* engine (if any) are initialized, and the official equality engine of this |
285 |
|
* theory has been assigned. This base class implementation |
286 |
|
* does nothing. This should be called by TheoryEngine only. |
287 |
|
*/ |
288 |
9917 |
virtual void finishInit() {} |
289 |
|
//--------------------------------- end private initialization |
290 |
|
|
291 |
|
/** |
292 |
|
* This method is called to notify a theory that the node n should |
293 |
|
* be considered a "shared term" by this theory. This does anything |
294 |
|
* theory-specific concerning the fact that n is now marked as a shared |
295 |
|
* term, which is done in addition to explicitly storing n as a shared |
296 |
|
* term and adding it as a trigger term in the equality engine of this |
297 |
|
* class (see addSharedTerm). |
298 |
|
*/ |
299 |
|
virtual void notifySharedTerm(TNode n); |
300 |
|
/** |
301 |
|
* Notify in conflict, called when a conflict clause is added to |
302 |
|
* TheoryEngine by any theory (not necessarily this one). This signals that |
303 |
|
* the theory should suspend what it is currently doing and wait for |
304 |
|
* backtracking. |
305 |
|
*/ |
306 |
|
virtual void notifyInConflict(); |
307 |
|
|
308 |
|
public: |
309 |
|
//--------------------------------- initialization |
310 |
|
/** |
311 |
|
* @return The theory rewriter associated with this theory. |
312 |
|
*/ |
313 |
|
virtual TheoryRewriter* getTheoryRewriter() = 0; |
314 |
|
/** |
315 |
|
* @return The proof checker associated with this theory. |
316 |
|
*/ |
317 |
|
virtual ProofRuleChecker* getProofChecker() = 0; |
318 |
|
/** |
319 |
|
* Returns true if this theory needs an equality engine for checking |
320 |
|
* satisfiability. |
321 |
|
* |
322 |
|
* If this method returns true, then the equality engine manager will |
323 |
|
* initialize its equality engine field via setEqualityEngine above during |
324 |
|
* TheoryEngine::finishInit, prior to calling finishInit for this theory. |
325 |
|
* |
326 |
|
* Additionally, if this method returns true, then this method is required |
327 |
|
* to update the argument esi with instructions for initializing and setting |
328 |
|
* up notifications from its equality engine, which is commonly done with a |
329 |
|
* notifications class (eq::EqualityEngineNotify). |
330 |
|
*/ |
331 |
|
virtual bool needsEqualityEngine(EeSetupInfo& esi); |
332 |
|
/** |
333 |
|
* Finish theory initialization, standalone version. This is used to |
334 |
|
* initialize this class if it is not associated with a theory engine. |
335 |
|
* This allocates the official equality engine of this Theory and then |
336 |
|
* calls the finishInit method above. |
337 |
|
*/ |
338 |
|
void finishInitStandalone(); |
339 |
|
//--------------------------------- end initialization |
340 |
|
|
341 |
|
/** |
342 |
|
* Return the ID of the theory responsible for the given type. |
343 |
|
*/ |
344 |
56720294 |
static inline TheoryId theoryOf(TypeNode typeNode) |
345 |
|
{ |
346 |
56720294 |
Trace("theory::internal") << "theoryOf(" << typeNode << ")" << std::endl; |
347 |
|
TheoryId id; |
348 |
56720294 |
if (typeNode.getKind() == kind::TYPE_CONSTANT) |
349 |
|
{ |
350 |
41926544 |
id = typeConstantToTheoryId(typeNode.getConst<TypeConstant>()); |
351 |
|
} |
352 |
|
else |
353 |
|
{ |
354 |
14793750 |
id = kindToTheoryId(typeNode.getKind()); |
355 |
|
} |
356 |
56720294 |
if (id == THEORY_BUILTIN) |
357 |
|
{ |
358 |
5161364 |
Trace("theory::internal") |
359 |
2580682 |
<< "theoryOf(" << typeNode << ") == " << s_uninterpretedSortOwner |
360 |
2580682 |
<< std::endl; |
361 |
2580682 |
return s_uninterpretedSortOwner; |
362 |
|
} |
363 |
54139612 |
return id; |
364 |
|
} |
365 |
|
|
366 |
|
/** |
367 |
|
* Returns the ID of the theory responsible for the given node. |
368 |
|
*/ |
369 |
|
static TheoryId theoryOf(options::TheoryOfMode mode, TNode node); |
370 |
|
|
371 |
|
/** |
372 |
|
* Returns the ID of the theory responsible for the given node. |
373 |
|
*/ |
374 |
192610908 |
static inline TheoryId theoryOf(TNode node) |
375 |
|
{ |
376 |
192610908 |
return theoryOf(options::theoryOfMode(), node); |
377 |
|
} |
378 |
|
|
379 |
|
/** |
380 |
|
* Set the owner of the uninterpreted sort. |
381 |
|
*/ |
382 |
9917 |
static void setUninterpretedSortOwner(TheoryId theory) |
383 |
|
{ |
384 |
9917 |
s_uninterpretedSortOwner = theory; |
385 |
9917 |
} |
386 |
|
|
387 |
|
/** |
388 |
|
* Get the owner of the uninterpreted sort. |
389 |
|
*/ |
390 |
|
static TheoryId getUninterpretedSortOwner() |
391 |
|
{ |
392 |
|
return s_uninterpretedSortOwner; |
393 |
|
} |
394 |
|
|
395 |
|
/** |
396 |
|
* Checks if the node is a leaf node of this theory |
397 |
|
*/ |
398 |
392436 |
inline bool isLeaf(TNode node) const |
399 |
|
{ |
400 |
392436 |
return node.getNumChildren() == 0 || theoryOf(node) != d_id; |
401 |
|
} |
402 |
|
|
403 |
|
/** |
404 |
|
* Checks if the node is a leaf node of a theory. |
405 |
|
*/ |
406 |
222919618 |
inline static bool isLeafOf(TNode node, TheoryId theoryId) |
407 |
|
{ |
408 |
222919618 |
return node.getNumChildren() == 0 || theoryOf(node) != theoryId; |
409 |
|
} |
410 |
|
|
411 |
|
/** Returns true if the assertFact queue is empty*/ |
412 |
54465707 |
bool done() const { return d_factsHead == d_facts.size(); } |
413 |
|
/** |
414 |
|
* Destructs a Theory. |
415 |
|
*/ |
416 |
|
virtual ~Theory(); |
417 |
|
|
418 |
|
/** |
419 |
|
* Subclasses of Theory may add additional efforts. DO NOT CHECK |
420 |
|
* equality with one of these values (e.g. if STANDARD xxx) but |
421 |
|
* rather use range checks (or use the helper functions below). |
422 |
|
* Normally we call QUICK_CHECK or STANDARD; at the leaves we call |
423 |
|
* with FULL_EFFORT. |
424 |
|
*/ |
425 |
|
enum Effort |
426 |
|
{ |
427 |
|
/** |
428 |
|
* Standard effort where theory need not do anything |
429 |
|
*/ |
430 |
|
EFFORT_STANDARD = 50, |
431 |
|
/** |
432 |
|
* Full effort requires the theory make sure its assertions are |
433 |
|
* satisfiable or not |
434 |
|
*/ |
435 |
|
EFFORT_FULL = 100, |
436 |
|
/** |
437 |
|
* Last call effort, called after theory combination has completed with |
438 |
|
* no lemmas and a model is available. |
439 |
|
*/ |
440 |
|
EFFORT_LAST_CALL = 200 |
441 |
|
}; /* enum Effort */ |
442 |
|
|
443 |
37293950 |
static bool fullEffort(Effort e) { return e == EFFORT_FULL; } |
444 |
|
|
445 |
|
/** |
446 |
|
* Get the id for this Theory. |
447 |
|
*/ |
448 |
20720286 |
TheoryId getId() const { return d_id; } |
449 |
|
|
450 |
|
/** |
451 |
|
* Get the output channel associated to this theory. |
452 |
|
*/ |
453 |
124698 |
OutputChannel& getOutputChannel() { return *d_out; } |
454 |
|
|
455 |
|
/** |
456 |
|
* Get the valuation associated to this theory. |
457 |
|
*/ |
458 |
39037 |
Valuation& getValuation() { return d_valuation; } |
459 |
|
|
460 |
|
/** Get the equality engine being used by this theory. */ |
461 |
|
eq::EqualityEngine* getEqualityEngine(); |
462 |
|
|
463 |
|
/** |
464 |
|
* Get the quantifiers engine associated to this theory. |
465 |
|
*/ |
466 |
271284 |
QuantifiersEngine* getQuantifiersEngine() { return d_quantEngine; } |
467 |
|
|
468 |
|
/** |
469 |
|
* @return The theory state associated with this theory. |
470 |
|
*/ |
471 |
|
TheoryState* getTheoryState() { return d_theoryState; } |
472 |
|
|
473 |
|
/** |
474 |
|
* @return The theory inference manager associated with this theory. |
475 |
|
*/ |
476 |
9917 |
TheoryInferenceManager* getInferenceManager() { return d_inferManager; } |
477 |
|
|
478 |
|
/** |
479 |
|
* Pre-register a term. Done one time for a Node per SAT context level. |
480 |
|
*/ |
481 |
|
virtual void preRegisterTerm(TNode); |
482 |
|
|
483 |
|
/** |
484 |
|
* Assert a fact in the current context. |
485 |
|
*/ |
486 |
16340928 |
void assertFact(TNode assertion, bool isPreregistered) |
487 |
|
{ |
488 |
32681856 |
Trace("theory") << "Theory<" << getId() << ">::assertFact[" |
489 |
32681856 |
<< context()->getLevel() << "](" << assertion << ", " |
490 |
16340928 |
<< (isPreregistered ? "true" : "false") << ")" << std::endl; |
491 |
16340928 |
d_facts.push_back(Assertion(assertion, isPreregistered)); |
492 |
16340928 |
} |
493 |
|
|
494 |
|
/** Add shared term to the theory. */ |
495 |
|
void addSharedTerm(TNode node); |
496 |
|
|
497 |
|
/** |
498 |
|
* Return the current theory care graph. Theories should overload |
499 |
|
* computeCareGraph to do the actual computation, and use addCarePair to add |
500 |
|
* pairs to the care graph. |
501 |
|
*/ |
502 |
|
void getCareGraph(CareGraph* careGraph); |
503 |
|
|
504 |
|
/** |
505 |
|
* Return the status of two terms in the current context. Should be |
506 |
|
* implemented in sub-theories to enable more efficient theory-combination. |
507 |
|
*/ |
508 |
|
virtual EqualityStatus getEqualityStatus(TNode a, TNode b); |
509 |
|
|
510 |
|
/** |
511 |
|
* Return the model value of the give shared term (or null if not |
512 |
|
* available). |
513 |
|
* |
514 |
|
* TODO (project #39): this method is likely to become deprecated. |
515 |
|
*/ |
516 |
1625 |
virtual Node getModelValue(TNode var) { return Node::null(); } |
517 |
|
|
518 |
|
/** T-propagate new literal assignments in the current context. */ |
519 |
|
virtual void propagate(Effort level = EFFORT_FULL) {} |
520 |
|
|
521 |
|
/** |
522 |
|
* Return an explanation for the literal represented by parameter n |
523 |
|
* (which was previously propagated by this theory). |
524 |
|
*/ |
525 |
|
virtual TrustNode explain(TNode n) |
526 |
|
{ |
527 |
|
Unimplemented() << "Theory " << identify() |
528 |
|
<< " propagated a node but doesn't implement the " |
529 |
|
"Theory::explain() interface!"; |
530 |
|
return TrustNode::null(); |
531 |
|
} |
532 |
|
|
533 |
|
//--------------------------------- check |
534 |
|
/** |
535 |
|
* Does this theory wish to be called to check at last call effort? This is |
536 |
|
* the case for any theory that wishes to run when a model is available. |
537 |
|
*/ |
538 |
59914 |
virtual bool needsCheckLastEffort() { return false; } |
539 |
|
/** |
540 |
|
* Check the current assignment's consistency. |
541 |
|
* |
542 |
|
* An implementation of check() is required to either: |
543 |
|
* - return a conflict on the output channel, |
544 |
|
* - be interrupted, |
545 |
|
* - throw an exception |
546 |
|
* - or call get() until done() is true. |
547 |
|
* |
548 |
|
* The standard method for check consists of a loop that processes the |
549 |
|
* entire fact queue when preCheck returns false. It makes four |
550 |
|
* theory-specific callbacks, (preCheck, postCheck, preNotifyFact, |
551 |
|
* notifyFact) as described below. It asserts each fact to the official |
552 |
|
* equality engine when preNotifyFact returns false. |
553 |
|
* |
554 |
|
* Theories that use this check method must use an official theory |
555 |
|
* state object (d_theoryState). |
556 |
|
*/ |
557 |
|
void check(Effort level = EFFORT_FULL); |
558 |
|
/** |
559 |
|
* Pre-check, called before the fact queue of the theory is processed. |
560 |
|
* If this method returns false, then the theory will process its fact |
561 |
|
* queue. If this method returns true, then the theory has indicated |
562 |
|
* its check method should finish immediately. |
563 |
|
*/ |
564 |
|
virtual bool preCheck(Effort level = EFFORT_FULL); |
565 |
|
/** |
566 |
|
* Post-check, called after the fact queue of the theory is processed. |
567 |
|
*/ |
568 |
|
virtual void postCheck(Effort level = EFFORT_FULL); |
569 |
|
/** |
570 |
|
* Pre-notify fact, return true if the theory processed it. If this |
571 |
|
* method returns false, then the atom will be added to the equality engine |
572 |
|
* of the theory and notifyFact will be called with isInternal=false. |
573 |
|
* |
574 |
|
* Theories that implement check but do not use official equality |
575 |
|
* engines should always return true for this method. |
576 |
|
* |
577 |
|
* @param atom The atom |
578 |
|
* @param polarity Its polarity |
579 |
|
* @param fact The original literal that was asserted |
580 |
|
* @param isPrereg Whether the assertion is preregistered |
581 |
|
* @param isInternal Whether the origin of the fact was internal. If this |
582 |
|
* is false, the fact was asserted via the fact queue of the theory. |
583 |
|
* @return true if the theory completely processed this fact, i.e. it does |
584 |
|
* not need to assert the fact to its equality engine. |
585 |
|
*/ |
586 |
|
virtual bool preNotifyFact( |
587 |
|
TNode atom, bool pol, TNode fact, bool isPrereg, bool isInternal); |
588 |
|
/** |
589 |
|
* Notify fact, called immediately after the fact was pushed into the |
590 |
|
* equality engine. |
591 |
|
* |
592 |
|
* @param atom The atom |
593 |
|
* @param polarity Its polarity |
594 |
|
* @param fact The original literal that was asserted. |
595 |
|
* @param isInternal Whether the origin of the fact was internal. If this |
596 |
|
* is false, the fact was asserted via the fact queue of the theory. |
597 |
|
*/ |
598 |
|
virtual void notifyFact(TNode atom, bool pol, TNode fact, bool isInternal); |
599 |
|
//--------------------------------- end check |
600 |
|
|
601 |
|
//--------------------------------- collect model info |
602 |
|
/** |
603 |
|
* Get all relevant information in this theory regarding the current |
604 |
|
* model. This should be called after a call to check( FULL_EFFORT ) |
605 |
|
* for all theories with no conflicts and no lemmas added. |
606 |
|
* |
607 |
|
* This method returns true if and only if the equality engine of m is |
608 |
|
* consistent as a result of this call. |
609 |
|
* |
610 |
|
* The standard method for collectModelInfo computes the relevant terms, |
611 |
|
* asserts the theory's equality engine to the model (if necessary) and |
612 |
|
* then calls computeModelValues. |
613 |
|
* |
614 |
|
* TODO (project #39): this method should be non-virtual, once all theories |
615 |
|
* conform to the new standard, delete, move to model manager distributed. |
616 |
|
*/ |
617 |
|
virtual bool collectModelInfo(TheoryModel* m, const std::set<Node>& termSet); |
618 |
|
/** |
619 |
|
* Compute terms that are not necessarily part of the assertions or |
620 |
|
* shared terms that should be considered relevant, add them to termSet. |
621 |
|
*/ |
622 |
|
virtual void computeRelevantTerms(std::set<Node>& termSet); |
623 |
|
/** |
624 |
|
* Collect asserted terms for this theory and add them to termSet. |
625 |
|
* |
626 |
|
* @param termSet The set to add terms to |
627 |
|
* @param includeShared Whether to include the shared terms of the theory |
628 |
|
*/ |
629 |
|
void collectAssertedTerms(std::set<Node>& termSet, |
630 |
|
bool includeShared = true) const; |
631 |
|
/** |
632 |
|
* Helper function for collectAssertedTerms, adds all subterms |
633 |
|
* belonging to this theory to termSet. |
634 |
|
*/ |
635 |
|
void collectTerms(TNode n, std::set<Node>& termSet) const; |
636 |
|
/** |
637 |
|
* Collect model values, after equality information is added to the model. |
638 |
|
* The argument termSet is the set of relevant terms returned by |
639 |
|
* computeRelevantTerms. |
640 |
|
*/ |
641 |
|
virtual bool collectModelValues(TheoryModel* m, |
642 |
|
const std::set<Node>& termSet); |
643 |
|
/** if theories want to do something with model after building, do it here |
644 |
|
*/ |
645 |
7548 |
virtual void postProcessModel(TheoryModel* m) {} |
646 |
|
//--------------------------------- end collect model info |
647 |
|
|
648 |
|
//--------------------------------- preprocessing |
649 |
|
/** |
650 |
|
* Statically learn from assertion "in," which has been asserted |
651 |
|
* true at the top level. The theory should only add (via |
652 |
|
* ::operator<< or ::append()) to the "learned" builder---it should |
653 |
|
* *never* clear it. It is a conjunction to add to the formula at |
654 |
|
* the top-level and may contain other theories' contributions. |
655 |
|
*/ |
656 |
|
virtual void ppStaticLearn(TNode in, NodeBuilder& learned) {} |
657 |
|
|
658 |
|
enum PPAssertStatus |
659 |
|
{ |
660 |
|
/** Atom has been solved */ |
661 |
|
PP_ASSERT_STATUS_SOLVED, |
662 |
|
/** Atom has not been solved */ |
663 |
|
PP_ASSERT_STATUS_UNSOLVED, |
664 |
|
/** Atom is inconsistent */ |
665 |
|
PP_ASSERT_STATUS_CONFLICT |
666 |
|
}; |
667 |
|
|
668 |
|
/** |
669 |
|
* Given a literal and its proof generator (encapsulated by trust node tin), |
670 |
|
* add the solved substitutions to the map, if any. The method should return |
671 |
|
* true if the literal can be safely removed from the input problem. |
672 |
|
* |
673 |
|
* Note that tin has trust node kind LEMMA. Its proof generator should be |
674 |
|
* taken into account when adding a substitution to outSubstitutions when |
675 |
|
* proofs are enabled. |
676 |
|
*/ |
677 |
|
virtual PPAssertStatus ppAssert(TrustNode tin, |
678 |
|
TrustSubstitutionMap& outSubstitutions); |
679 |
|
|
680 |
|
/** |
681 |
|
* Given a term of the theory coming from the input formula or |
682 |
|
* from a lemma generated during solving, this method can be overridden in a |
683 |
|
* theory implementation to rewrite the term into an equivalent form. |
684 |
|
* |
685 |
|
* This method returns a TrustNode of kind TrustNodeKind::REWRITE, which |
686 |
|
* carries information about the proof generator for the rewrite, which can |
687 |
|
* be the null TrustNode if n is unchanged. |
688 |
|
* |
689 |
|
* Notice this method is used both in the "theory rewrite equalities" |
690 |
|
* preprocessing pass, where n is an equality from the input formula, |
691 |
|
* and in theory preprocessing, where n is a (non-equality) term occurring |
692 |
|
* in the input or generated in a lemma. |
693 |
|
* |
694 |
|
* @param n the node to preprocess-rewrite. |
695 |
|
* @param lems a set of lemmas that should be added as a consequence of |
696 |
|
* preprocessing n. These are in the form of "skolem lemmas". For example, |
697 |
|
* calling this method on (div x n), we return a trust node proving: |
698 |
|
* (= (div x n) k_div) |
699 |
|
* for fresh skolem k, and add the skolem lemma for k that indicates that |
700 |
|
* it is the division of x and n. |
701 |
|
* |
702 |
|
* Note that ppRewrite should not return WITNESS terms, since the internal |
703 |
|
* calculus works in "original forms" and not "witness forms". |
704 |
|
*/ |
705 |
116052 |
virtual TrustNode ppRewrite(TNode n, std::vector<SkolemLemma>& lems) |
706 |
|
{ |
707 |
116052 |
return TrustNode::null(); |
708 |
|
} |
709 |
|
|
710 |
|
/** |
711 |
|
* Notify preprocessed assertions. Called on new assertions after |
712 |
|
* preprocessing before they are asserted to theory engine. |
713 |
|
*/ |
714 |
151525 |
virtual void ppNotifyAssertions(const std::vector<Node>& assertions) {} |
715 |
|
//--------------------------------- end preprocessing |
716 |
|
|
717 |
|
/** |
718 |
|
* A Theory is called with presolve exactly one time per user |
719 |
|
* check-sat. presolve() is called after preregistration, |
720 |
|
* rewriting, and Boolean propagation, (other theories' |
721 |
|
* propagation?), but the notified Theory has not yet had its |
722 |
|
* check() or propagate() method called. A Theory may empty its |
723 |
|
* assertFact() queue using get(). A Theory can raise conflicts, |
724 |
|
* add lemmas, and propagate literals during presolve(). |
725 |
|
* |
726 |
|
* NOTE: The presolve property must be added to the kinds file for |
727 |
|
* the theory. |
728 |
|
*/ |
729 |
|
virtual void presolve() {} |
730 |
|
|
731 |
|
/** |
732 |
|
* A Theory is called with postsolve exactly one time per user |
733 |
|
* check-sat. postsolve() is called after the query has completed |
734 |
|
* (regardless of whether sat, unsat, or unknown), and after any |
735 |
|
* model-querying related to the query has been performed. |
736 |
|
* After this call, the theory will not get another check() or |
737 |
|
* propagate() call until presolve() is called again. A Theory |
738 |
|
* cannot raise conflicts, add lemmas, or propagate literals during |
739 |
|
* postsolve(). |
740 |
|
*/ |
741 |
|
virtual void postsolve() {} |
742 |
|
|
743 |
|
/** |
744 |
|
* Notification sent to the theory wheneven the search restarts. |
745 |
|
* Serves as a good time to do some clean-up work, and you can |
746 |
|
* assume you're at DL 0 for the purposes of Contexts. This function |
747 |
|
* should not use the output channel. |
748 |
|
*/ |
749 |
|
virtual void notifyRestart() {} |
750 |
|
|
751 |
|
/** |
752 |
|
* Identify this theory (for debugging, dynamic configuration, |
753 |
|
* etc..) |
754 |
|
*/ |
755 |
|
virtual std::string identify() const = 0; |
756 |
|
|
757 |
|
typedef context::CDList<Assertion>::const_iterator assertions_iterator; |
758 |
|
|
759 |
|
/** |
760 |
|
* Provides access to the facts queue, primarily intended for theory |
761 |
|
* debugging purposes. |
762 |
|
* |
763 |
|
* @return the iterator to the beginning of the fact queue |
764 |
|
*/ |
765 |
164305 |
assertions_iterator facts_begin() const { return d_facts.begin(); } |
766 |
|
|
767 |
|
/** |
768 |
|
* Provides access to the facts queue, primarily intended for theory |
769 |
|
* debugging purposes. |
770 |
|
* |
771 |
|
* @return the iterator to the end of the fact queue |
772 |
|
*/ |
773 |
1247810 |
assertions_iterator facts_end() const { return d_facts.end(); } |
774 |
|
/** |
775 |
|
* Whether facts have been asserted to this theory. |
776 |
|
* |
777 |
|
* @return true iff facts have been asserted to this theory. |
778 |
|
*/ |
779 |
5711 |
bool hasFacts() { return !d_facts.empty(); } |
780 |
|
|
781 |
|
/** Return total number of facts asserted to this theory */ |
782 |
4433 |
size_t numAssertions() { return d_facts.size(); } |
783 |
|
|
784 |
|
typedef context::CDList<TNode>::const_iterator shared_terms_iterator; |
785 |
|
|
786 |
|
/** |
787 |
|
* Provides access to the shared terms, primarily intended for theory |
788 |
|
* debugging purposes. |
789 |
|
* |
790 |
|
* @return the iterator to the beginning of the shared terms list |
791 |
|
*/ |
792 |
196589 |
shared_terms_iterator shared_terms_begin() const |
793 |
|
{ |
794 |
196589 |
return d_sharedTerms.begin(); |
795 |
|
} |
796 |
|
|
797 |
|
/** |
798 |
|
* Provides access to the facts queue, primarily intended for theory |
799 |
|
* debugging purposes. |
800 |
|
* |
801 |
|
* @return the iterator to the end of the shared terms list |
802 |
|
*/ |
803 |
245775 |
shared_terms_iterator shared_terms_end() const { return d_sharedTerms.end(); } |
804 |
|
|
805 |
|
/** |
806 |
|
* This is a utility function for constructing a copy of the currently |
807 |
|
* shared terms in a queriable form. As this is |
808 |
|
*/ |
809 |
|
std::unordered_set<TNode> currentlySharedTerms() const; |
810 |
|
|
811 |
|
/** |
812 |
|
* This allows the theory to be queried for whether a literal, lit, is |
813 |
|
* entailed by the theory. This returns a pair of a Boolean and a node E. |
814 |
|
* |
815 |
|
* If the Boolean is true, then E is a formula that entails lit and E is |
816 |
|
* propositionally entailed by the assertions to the theory. |
817 |
|
* |
818 |
|
* If the Boolean is false, it is "unknown" if lit is entailed and E may be |
819 |
|
* any node. |
820 |
|
* |
821 |
|
* The literal lit is either an atom a or (not a), which must belong to the |
822 |
|
* theory: There is some TheoryOfMode m s.t. Theory::theoryOf(m, a) == |
823 |
|
* this->getId(). |
824 |
|
* |
825 |
|
* There are NO assumptions that a or the subterms of a have been |
826 |
|
* preprocessed in any form. This includes ppRewrite, rewriting, |
827 |
|
* preregistering, registering, definition expansion or ITE removal! |
828 |
|
* |
829 |
|
* Theories are free to limit the amount of effort they use and so may |
830 |
|
* always opt to return "unknown". Both "unknown" and "not entailed", |
831 |
|
* may return for E a non-boolean Node (e.g. Node::null()). (There is no |
832 |
|
* explicit output for the negation of lit is entailed.) |
833 |
|
* |
834 |
|
* If lit is theory valid, the return result may be the Boolean constant |
835 |
|
* true for E. |
836 |
|
* |
837 |
|
* If lit is entailed by multiple assertions on the theory's getFact() |
838 |
|
* queue, a_1, a_2, ... and a_k, this may return E=(and a_1 a_2 ... a_k) or |
839 |
|
* another theory entailed explanation E=(and (and a_1 a_2) (and a3 a_4) ... |
840 |
|
* a_k) |
841 |
|
* |
842 |
|
* If lit is entailed by a single assertion on the theory's getFact() |
843 |
|
* queue, say a, this may return E=a. |
844 |
|
* |
845 |
|
* The theory may always return false! |
846 |
|
* |
847 |
|
* Theories may not touch their output stream during an entailment check. |
848 |
|
* |
849 |
|
* @param lit a literal belonging to the theory. |
850 |
|
* @return a pair <b,E> s.t. if b is true, then a formula E such |
851 |
|
* that E |= lit in the theory. |
852 |
|
*/ |
853 |
|
virtual std::pair<bool, Node> entailmentCheck(TNode lit); |
854 |
|
|
855 |
|
/** Return true if this theory uses central equality engine */ |
856 |
|
bool usesCentralEqualityEngine() const; |
857 |
|
/** uses central equality engine (static) */ |
858 |
|
static bool usesCentralEqualityEngine(TheoryId id); |
859 |
|
/** Explains/propagates via central equality engine only */ |
860 |
|
static bool expUsingCentralEqualityEngine(TheoryId id); |
861 |
|
}; /* class Theory */ |
862 |
|
|
863 |
|
std::ostream& operator<<(std::ostream& os, theory::Theory::Effort level); |
864 |
|
|
865 |
|
|
866 |
15955150 |
inline theory::Assertion Theory::get() { |
867 |
15955150 |
Assert(!done()) << "Theory::get() called with assertion queue empty!"; |
868 |
|
|
869 |
|
// Get the assertion |
870 |
15955150 |
Assertion fact = d_facts[d_factsHead]; |
871 |
15955150 |
d_factsHead = d_factsHead + 1; |
872 |
|
|
873 |
15955150 |
Trace("theory") << "Theory::get() => " << fact << " (" << d_facts.size() - d_factsHead << " left)" << std::endl; |
874 |
|
|
875 |
15955150 |
return fact; |
876 |
|
} |
877 |
|
|
878 |
|
inline std::ostream& operator<<(std::ostream& out, |
879 |
|
const cvc5::theory::Theory& theory) |
880 |
|
{ |
881 |
|
return out << theory.identify(); |
882 |
|
} |
883 |
|
|
884 |
|
inline std::ostream& operator << (std::ostream& out, theory::Theory::PPAssertStatus status) { |
885 |
|
switch (status) { |
886 |
|
case theory::Theory::PP_ASSERT_STATUS_SOLVED: |
887 |
|
out << "SOLVE_STATUS_SOLVED"; break; |
888 |
|
case theory::Theory::PP_ASSERT_STATUS_UNSOLVED: |
889 |
|
out << "SOLVE_STATUS_UNSOLVED"; break; |
890 |
|
case theory::Theory::PP_ASSERT_STATUS_CONFLICT: |
891 |
|
out << "SOLVE_STATUS_CONFLICT"; break; |
892 |
|
default: |
893 |
|
Unhandled(); |
894 |
|
} |
895 |
|
return out; |
896 |
|
} |
897 |
|
|
898 |
|
} // namespace theory |
899 |
|
} // namespace cvc5 |
900 |
|
|
901 |
|
#endif /* CVC5__THEORY__THEORY_H */ |