Branch data Line data Source code
1 : : /******************************************************************************
2 : : * This file is part of the cvc5 project.
3 : : *
4 : : * Copyright (c) 2009-2026 by the authors listed in the file AUTHORS
5 : : * in the top-level source directory and their institutional affiliations.
6 : : * All rights reserved. See the file COPYING in the top-level source
7 : : * directory for licensing information.
8 : : * ****************************************************************************
9 : : *
10 : : * The theory engine.
11 : : */
12 : :
13 : : #include "theory/theory_engine.h"
14 : :
15 : : #include <sstream>
16 : :
17 : : #include "base/map_util.h"
18 : : #include "decision/decision_engine.h"
19 : : #include "expr/attribute.h"
20 : : #include "expr/node_builder.h"
21 : : #include "expr/node_visitor.h"
22 : : #include "options/parallel_options.h"
23 : : #include "options/quantifiers_options.h"
24 : : #include "options/smt_options.h"
25 : : #include "options/theory_options.h"
26 : : #include "printer/printer.h"
27 : : #include "proof/lazy_proof.h"
28 : : #include "proof/proof_checker.h"
29 : : #include "proof/proof_ensure_closed.h"
30 : : #include "prop/prop_engine.h"
31 : : #include "smt/env.h"
32 : : #include "smt/logic_exception.h"
33 : : #include "smt/solver_engine_state.h"
34 : : #include "theory/combination_care_graph.h"
35 : : #include "theory/conflict_processor.h"
36 : : #include "theory/decision_manager.h"
37 : : #include "theory/ee_manager_central.h"
38 : : #include "theory/partition_generator.h"
39 : : #include "theory/plugin_module.h"
40 : : #include "theory/quantifiers/first_order_model.h"
41 : : #include "theory/quantifiers_engine.h"
42 : : #include "theory/relevance_manager.h"
43 : : #include "theory/rewriter.h"
44 : : #include "theory/shared_solver.h"
45 : : #include "theory/theory.h"
46 : : #include "theory/theory_engine_proof_generator.h"
47 : : #include "theory/theory_id.h"
48 : : #include "theory/theory_model.h"
49 : : #include "theory/theory_traits.h"
50 : : #include "theory/uf/equality_engine.h"
51 : : #include "util/resource_manager.h"
52 : :
53 : : using namespace std;
54 : :
55 : : using namespace cvc5::internal::theory;
56 : :
57 : : namespace cvc5::internal {
58 : :
59 : : /* -------------------------------------------------------------------------- */
60 : :
61 : : namespace theory {
62 : :
63 : : /**
64 : : * IMPORTANT: The order of the theories is important. For example, strings
65 : : * depends on arith, quantifiers needs to come as the very last.
66 : : * Do not change this order.
67 : : */
68 : :
69 : : #define CVC5_FOR_EACH_THEORY \
70 : : CVC5_FOR_EACH_THEORY_STATEMENT(cvc5::internal::theory::THEORY_BUILTIN) \
71 : : CVC5_FOR_EACH_THEORY_STATEMENT(cvc5::internal::theory::THEORY_BOOL) \
72 : : CVC5_FOR_EACH_THEORY_STATEMENT(cvc5::internal::theory::THEORY_UF) \
73 : : CVC5_FOR_EACH_THEORY_STATEMENT(cvc5::internal::theory::THEORY_ARITH) \
74 : : CVC5_FOR_EACH_THEORY_STATEMENT(cvc5::internal::theory::THEORY_BV) \
75 : : CVC5_FOR_EACH_THEORY_STATEMENT(cvc5::internal::theory::THEORY_FF) \
76 : : CVC5_FOR_EACH_THEORY_STATEMENT(cvc5::internal::theory::THEORY_FP) \
77 : : CVC5_FOR_EACH_THEORY_STATEMENT(cvc5::internal::theory::THEORY_ARRAYS) \
78 : : CVC5_FOR_EACH_THEORY_STATEMENT(cvc5::internal::theory::THEORY_DATATYPES) \
79 : : CVC5_FOR_EACH_THEORY_STATEMENT(cvc5::internal::theory::THEORY_SEP) \
80 : : CVC5_FOR_EACH_THEORY_STATEMENT(cvc5::internal::theory::THEORY_SETS) \
81 : : CVC5_FOR_EACH_THEORY_STATEMENT(cvc5::internal::theory::THEORY_BAGS) \
82 : : CVC5_FOR_EACH_THEORY_STATEMENT(cvc5::internal::theory::THEORY_STRINGS) \
83 : : CVC5_FOR_EACH_THEORY_STATEMENT(cvc5::internal::theory::THEORY_QUANTIFIERS)
84 : :
85 : : } // namespace theory
86 : :
87 : : /* -------------------------------------------------------------------------- */
88 : :
89 : : /**
90 : : * Compute the string for a given theory id. In this module, we use
91 : : * THEORY_SAT_SOLVER as an id, which is not a normal id but maps to
92 : : * THEORY_LAST. Thus, we need our own string conversion here.
93 : : *
94 : : * @param id The theory id
95 : : * @return The string corresponding to the theory id
96 : : */
97 : 0 : std::string getTheoryString(theory::TheoryId id)
98 : : {
99 [ - - ]: 0 : if (id == theory::THEORY_SAT_SOLVER)
100 : : {
101 : 0 : return "THEORY_SAT_SOLVER";
102 : : }
103 : : else
104 : : {
105 : 0 : std::stringstream ss;
106 : 0 : ss << id;
107 : 0 : return ss.str();
108 : 0 : }
109 : : }
110 : :
111 : 51364 : void TheoryEngine::finishInit()
112 : : {
113 : 51364 : d_modules.clear();
114 [ + - ]: 51364 : Trace("theory") << "Begin TheoryEngine::finishInit" << std::endl;
115 : : // NOTE: This seems to be required since
116 : : // theory::TheoryTraits<THEORY>::isParametric cannot be accessed without
117 : : // using the CVC5_FOR_EACH_THEORY_STATEMENT macro. -AJR
118 : 51364 : std::vector<theory::Theory*> paraTheories;
119 : : #ifdef CVC5_FOR_EACH_THEORY_STATEMENT
120 : : #undef CVC5_FOR_EACH_THEORY_STATEMENT
121 : : #endif
122 : : #define CVC5_FOR_EACH_THEORY_STATEMENT(THEORY) \
123 : : if (theory::TheoryTraits<THEORY>::isParametric && isTheoryEnabled(THEORY)) \
124 : : { \
125 : : paraTheories.push_back(theoryOf(THEORY)); \
126 : : }
127 : : // Collect the parametric theories, which are given to the theory combination
128 : : // manager below
129 [ + + ][ + + ]: 51364 : CVC5_FOR_EACH_THEORY;
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
130 : :
131 : : // Initialize the theory combination architecture
132 [ + - ]: 51364 : if (options().theory.tcMode == options::TcMode::CARE_GRAPH)
133 : : {
134 : 51364 : d_tc.reset(new CombinationCareGraph(d_env, *this, paraTheories));
135 : : }
136 : : else
137 : : {
138 : 0 : Unimplemented() << "TheoryEngine::finishInit: theory combination mode "
139 : 0 : << options().theory.tcMode << " not supported";
140 : : }
141 : : // create the relevance filter if any option requires it
142 [ + + ][ + + ]: 51364 : if (options().theory.relevanceFilter || options().smt.produceDifficulty)
[ + + ]
143 : : {
144 : 486 : d_relManager.reset(new RelevanceManager(d_env, this));
145 : 486 : d_modules.push_back(d_relManager.get());
146 : : }
147 : :
148 : : // initialize the quantifiers engine
149 [ + + ]: 51364 : if (logicInfo().isQuantified())
150 : : {
151 : : // get the quantifiers engine, which is initialized by the quantifiers
152 : : // theory
153 : 44518 : d_quantEngine = d_theoryTable[THEORY_QUANTIFIERS]->getQuantifiersEngine();
154 [ - + ][ - + ]: 44518 : Assert(d_quantEngine != nullptr);
[ - - ]
155 : : }
156 : : // finish initializing the quantifiers engine, which must come before
157 : : // initializing theory combination, since quantifiers engine may have a
158 : : // special model builder object
159 [ + + ]: 51364 : if (logicInfo().isQuantified())
160 : : {
161 : 44518 : d_quantEngine->finishInit(this);
162 : : }
163 : : // initialize the theory combination manager, which decides and allocates the
164 : : // equality engines to use for all theories.
165 : 51364 : d_tc->finishInit();
166 : : // get pointer to the shared solver
167 : 51364 : d_sharedSolver = d_tc->getSharedSolver();
168 : :
169 : : // finish initializing the theories by linking them with the appropriate
170 : : // utilities and then calling their finishInit method.
171 : 51364 : for (TheoryId theoryId = theory::THEORY_FIRST;
172 [ + + ]: 770460 : theoryId != theory::THEORY_LAST;
173 : 719096 : ++theoryId)
174 : : {
175 : 719096 : Theory* t = d_theoryTable[theoryId];
176 [ - + ]: 719096 : if (t == nullptr)
177 : : {
178 : 0 : continue;
179 : : }
180 : : // setup the pointers to the utilities
181 : 719096 : const EeTheoryInfo* eeti = d_tc->getEeTheoryInfo(theoryId);
182 [ - + ][ - + ]: 719096 : Assert(eeti != nullptr);
[ - - ]
183 : : // the theory's official equality engine is the one specified by the
184 : : // equality engine manager
185 : 719096 : t->setEqualityEngine(eeti->d_usedEe);
186 : : // set the quantifiers engine
187 : 719096 : t->setQuantifiersEngine(d_quantEngine);
188 : : // set the decision manager for the theory
189 : 719096 : t->setDecisionManager(d_decManager.get());
190 : : // finish initializing the theory
191 : 719096 : t->finishInit();
192 : : }
193 : :
194 [ - + ]: 51364 : if (options().parallel.computePartitions > 1)
195 : : {
196 : : d_partitionGen =
197 : 0 : std::make_unique<PartitionGenerator>(d_env, this, getPropEngine());
198 : 0 : d_modules.push_back(d_partitionGen.get());
199 : : }
200 : :
201 : : // add user-provided plugins
202 : 51364 : const std::vector<Plugin*> plugins = d_env.getPlugins();
203 [ + - ]: 102728 : Trace("theory") << "initialize with " << plugins.size()
204 : 51364 : << " user-provided plugins" << std::endl;
205 [ + + ]: 51392 : for (Plugin* p : plugins)
206 : : {
207 : 28 : d_userPlugins.push_back(
208 : 56 : std::unique_ptr<PluginModule>(new PluginModule(d_env, this, p)));
209 : 28 : d_modules.push_back(d_userPlugins.back().get());
210 : : }
211 [ + - ]: 51364 : Trace("theory") << "End TheoryEngine::finishInit" << std::endl;
212 : 51364 : }
213 : :
214 : 51364 : TheoryEngine::TheoryEngine(Env& env)
215 : : : EnvObj(env),
216 : 51364 : d_propEngine(nullptr),
217 : 62251 : d_lazyProof(
218 [ + + ]: 51364 : env.isTheoryProofProducing()
219 : : ? new LazyCDProof(
220 : 21774 : env, nullptr, userContext(), "TheoryEngine::LazyCDProof")
221 : : : nullptr),
222 : 51364 : d_tepg(new TheoryEngineProofGenerator(env, userContext())),
223 : 51364 : d_tc(nullptr),
224 : 51364 : d_sharedSolver(nullptr),
225 : 51364 : d_quantEngine(nullptr),
226 : 51364 : d_decManager(new DecisionManager(userContext())),
227 : 51364 : d_relManager(nullptr),
228 : 51364 : d_inConflict(context(), false),
229 : 51364 : d_modelUnsound(context(), false),
230 : 51364 : d_modelUnsoundTheory(context(), THEORY_BUILTIN),
231 : 51364 : d_modelUnsoundId(context(), IncompleteId::UNKNOWN),
232 : 51364 : d_refutationUnsound(userContext(), false),
233 : 51364 : d_refutationUnsoundTheory(userContext(), THEORY_BUILTIN),
234 : 51364 : d_refutationUnsoundId(userContext(), IncompleteId::UNKNOWN),
235 : 51364 : d_propagationMap(context()),
236 : 51364 : d_propagationMapTimestamp(context(), 0),
237 : 51364 : d_propagatedLiterals(context()),
238 : 51364 : d_propagatedLiteralsIndex(context(), 0),
239 : 51364 : d_atomRequests(context()),
240 : 51364 : d_stats(statisticsRegistry()),
241 : 51364 : d_true(),
242 : 51364 : d_false(),
243 : 51364 : d_interrupted(false),
244 : 51364 : d_inPreregister(false),
245 : 51364 : d_factsAsserted(context(), false),
246 : 205456 : d_cp(nullptr)
247 : : {
248 : 51364 : for (TheoryId theoryId = theory::THEORY_FIRST;
249 [ + + ]: 770460 : theoryId != theory::THEORY_LAST;
250 : 719096 : ++theoryId)
251 : : {
252 : 719096 : d_theoryTable[theoryId] = nullptr;
253 : 719096 : d_theoryOut[theoryId] = nullptr;
254 : : }
255 : :
256 [ + + ]: 51364 : if (options().smt.sortInference)
257 : : {
258 : 45 : d_sortInfer.reset(new SortInference(env));
259 : : }
260 : 51364 : if (options().theory.conflictProcessMode
261 [ + + ]: 51364 : != options::ConflictProcessMode::NONE)
262 : : {
263 : 7 : bool useExtRewriter = (options().theory.conflictProcessMode
264 : 7 : == options::ConflictProcessMode::MINIMIZE_EXT);
265 : 7 : d_cp.reset(new ConflictProcessor(env, useExtRewriter));
266 : : }
267 : :
268 : 51364 : d_true = nodeManager()->mkConst<bool>(true);
269 : 51364 : d_false = nodeManager()->mkConst<bool>(false);
270 : 51364 : }
271 : :
272 : 102032 : TheoryEngine::~TheoryEngine()
273 : : {
274 : 51016 : for (TheoryId theoryId = theory::THEORY_FIRST;
275 [ + + ]: 765240 : theoryId != theory::THEORY_LAST;
276 : 714224 : ++theoryId)
277 : : {
278 [ + + ]: 714224 : if (d_theoryTable[theoryId] != nullptr)
279 : : {
280 [ + - ]: 714197 : delete d_theoryTable[theoryId];
281 [ + - ]: 714197 : delete d_theoryOut[theoryId];
282 : : }
283 : : }
284 : 102032 : }
285 : :
286 : 315129 : void TheoryEngine::interrupt() { d_interrupted = true; }
287 : 2228782 : void TheoryEngine::preRegister(TNode preprocessed)
288 : : {
289 [ + - ]: 4457564 : Trace("theory") << "TheoryEngine::preRegister( " << preprocessed << ")"
290 : 2228782 : << std::endl;
291 : 2228782 : d_preregisterQueue.push(preprocessed);
292 : :
293 [ + + ]: 2228782 : if (!d_inPreregister)
294 : : {
295 : : // We're in pre-register
296 : 2076496 : d_inPreregister = true;
297 : :
298 : : // Process the pre-registration queue
299 [ + + ]: 4305262 : while (!d_preregisterQueue.empty())
300 : : {
301 : : // Get the next atom to pre-register
302 : 2228782 : preprocessed = d_preregisterQueue.front();
303 : 2228782 : d_preregisterQueue.pop();
304 : :
305 : : // the atom should not have free variables
306 [ + - ]: 4457564 : Trace("theory") << "TheoryEngine::preRegister: " << preprocessed
307 : 2228782 : << std::endl;
308 [ + - ]: 2228782 : if (Configuration::isAssertionBuild())
309 : : {
310 : 2228782 : std::unordered_set<Node> fvs;
311 : 2228782 : expr::getFreeVariables(preprocessed, fvs);
312 [ - + ]: 2228782 : if (!fvs.empty())
313 : : {
314 : 0 : Unhandled() << "Preregistered term with free variable: "
315 : 0 : << preprocessed << ", fv=" << *fvs.begin();
316 : : }
317 : 2228782 : }
318 : : // should not have witness
319 [ - + ][ - + ]: 2228782 : Assert(!expr::hasSubtermKind(Kind::WITNESS, preprocessed));
[ - - ]
320 : :
321 : : // pre-register with the shared solver, which handles
322 : : // calling prepregister on individual theories, adding shared terms,
323 : : // and setting up equalities to propagate in the shared term database.
324 [ - + ][ - + ]: 2228782 : Assert(d_sharedSolver != nullptr);
[ - - ]
325 : 2228782 : d_sharedSolver->preRegister(preprocessed);
326 : : }
327 : :
328 : : // Leaving pre-register
329 : 2076480 : d_inPreregister = false;
330 : : }
331 : 2228766 : }
332 : :
333 : 0 : void TheoryEngine::printAssertions(const char* tag)
334 : : {
335 [ - - ]: 0 : if (TraceIsOn(tag))
336 : : {
337 [ - - ]: 0 : for (TheoryId theoryId = THEORY_FIRST; theoryId < THEORY_LAST; ++theoryId)
338 : : {
339 : 0 : Theory* theory = d_theoryTable[theoryId];
340 : 0 : if (theory && isTheoryEnabled(theoryId))
341 : : {
342 [ - - ]: 0 : Trace(tag) << "--------------------------------------------" << endl;
343 [ - - ]: 0 : Trace(tag) << "Assertions of " << theory->getId() << ": " << endl;
344 : : {
345 : 0 : context::CDList<Assertion>::const_iterator it = theory->facts_begin(),
346 : : it_end =
347 : 0 : theory->facts_end();
348 [ - - ]: 0 : for (unsigned i = 0; it != it_end; ++it, ++i)
349 : : {
350 [ - - ]: 0 : if ((*it).d_isPreregistered)
351 : : {
352 [ - - ]: 0 : Trace(tag) << "[" << i << "]: ";
353 : : }
354 : : else
355 : : {
356 [ - - ]: 0 : Trace(tag) << "(" << i << "): ";
357 : : }
358 [ - - ]: 0 : Trace(tag) << (*it).d_assertion << endl;
359 : : }
360 : : }
361 : :
362 [ - - ]: 0 : if (logicInfo().isSharingEnabled())
363 : : {
364 : 0 : TheoryState* state = theory->getTheoryState();
365 [ - - ]: 0 : if (state != nullptr)
366 : : {
367 [ - - ]: 0 : Trace(tag) << "Shared terms of " << theory->getId() << ": " << endl;
368 : : context::CDList<TNode>::const_iterator
369 : 0 : it = state->shared_terms_begin(),
370 : 0 : it_end = state->shared_terms_end();
371 [ - - ]: 0 : for (unsigned i = 0; it != it_end; ++it, ++i)
372 : : {
373 [ - - ]: 0 : Trace(tag) << "[" << i << "]: " << (*it) << endl;
374 : : }
375 : : }
376 : : }
377 : : }
378 : : }
379 : : }
380 : 0 : }
381 : :
382 : : /**
383 : : * Check all (currently-active) theories for conflicts.
384 : : * @param effort the effort level to use
385 : : */
386 : 11199270 : void TheoryEngine::check(Theory::Effort effort)
387 : : {
388 : : // spendResource();
389 : :
390 : : // Reset the interrupt flag
391 : 11199270 : d_interrupted = false;
392 : :
393 : : #ifdef CVC5_FOR_EACH_THEORY_STATEMENT
394 : : #undef CVC5_FOR_EACH_THEORY_STATEMENT
395 : : #endif
396 : : #define CVC5_FOR_EACH_THEORY_STATEMENT(THEORY) \
397 : : if (theory::TheoryTraits<THEORY>::hasCheck && isTheoryEnabled(THEORY)) \
398 : : { \
399 : : theoryOf(THEORY)->check(effort); \
400 : : if (d_inConflict) \
401 : : { \
402 : : Trace("conflict") << THEORY << " in conflict. " << std::endl; \
403 : : break; \
404 : : } \
405 : : if (rm->out()) \
406 : : { \
407 : : interrupt(); \
408 : : return; \
409 : : } \
410 : : }
411 : :
412 : : // Do the checking
413 : : try
414 : : {
415 : : // Mark the output channel unused (if this is FULL_EFFORT, and nothing
416 : : // is done by the theories, no additional check will be needed)
417 : 11199270 : d_outputChannelUsed = false;
418 : :
419 : : // Mark the lemmas flag (no lemmas added)
420 : 11199270 : d_lemmasAdded = false;
421 : :
422 [ + - ]: 22398540 : Trace("theory") << "TheoryEngine::check(" << effort
423 : 0 : << "): d_factsAsserted = "
424 [ - - ]: 11199270 : << (d_factsAsserted ? "true" : "false") << endl;
425 : :
426 : : // If in full effort, we have a fake new assertion just to jumpstart the
427 : : // checking
428 [ + + ]: 11199270 : if (Theory::fullEffort(effort))
429 : : {
430 : 175209 : spendResource(Resource::TheoryFullCheckStep);
431 : 175209 : d_factsAsserted = true;
432 : 175209 : d_tc->resetRound();
433 : : }
434 : :
435 : : // check with the theory modules
436 [ + + ]: 11201053 : for (TheoryEngineModule* tem : d_modules)
437 : : {
438 : 1783 : tem->check(effort);
439 : : }
440 : :
441 : 11199270 : auto rm = d_env.getResourceManager();
442 : :
443 : : // Check until done
444 [ + + ][ + + ]: 20019735 : while (d_factsAsserted && !d_inConflict && !d_lemmasAdded)
[ + + ][ + + ]
445 : : {
446 [ + - ]: 18224064 : Trace("theory") << "TheoryEngine::check(" << effort << "): running check"
447 : 9112032 : << endl;
448 : :
449 [ + - ]: 9112032 : Trace("theory::assertions") << endl;
450 [ - + ]: 9112032 : if (TraceIsOn("theory::assertions"))
451 : : {
452 : 0 : printAssertions("theory::assertions");
453 : : }
454 : :
455 [ + + ]: 9112032 : if (Theory::fullEffort(effort))
456 : : {
457 [ + - ]: 189977 : Trace("theory::assertions::fulleffort") << endl;
458 [ - + ]: 189977 : if (TraceIsOn("theory::assertions::fulleffort"))
459 : : {
460 : 0 : printAssertions("theory::assertions::fulleffort");
461 : : }
462 : : }
463 : :
464 : : // Note that we've discharged all the facts
465 : 9112032 : d_factsAsserted = false;
466 : :
467 : : // Do the checking
468 [ + + ][ + + ]: 9112032 : CVC5_FOR_EACH_THEORY;
[ + - ][ + + ]
[ + + ][ + + ]
[ + - ][ + + ]
[ + + ][ + + ]
[ + - ][ - + ]
[ + + ][ + + ]
[ + - ][ + + ]
[ + + ][ + + ]
[ + - ][ - + ]
[ + + ][ + + ]
[ + - ][ - + ]
[ + + ][ + + ]
[ + - ][ + + ]
[ + + ][ + + ]
[ + - ][ - + ]
[ + + ][ + + ]
[ + - ][ - + ]
[ + + ][ + + ]
[ + - ][ + + ]
[ + + ][ + + ]
[ + - ][ - + ]
[ + + ][ - + ]
[ - - ][ - + ]
469 : :
470 [ + - ]: 17640930 : Trace("theory") << "TheoryEngine::check(" << effort
471 : 0 : << "): running propagation after the initial check"
472 : 8820465 : << endl;
473 : :
474 : : // We are still satisfiable, propagate as much as possible
475 : 8820465 : propagate(effort);
476 : :
477 : : // Interrupt in case we reached a resource limit.
478 [ - + ]: 8820465 : if (rm->out())
479 : : {
480 : 0 : interrupt();
481 : 0 : return;
482 : : }
483 : :
484 [ + + ]: 8820465 : if (Theory::fullEffort(effort))
485 : : {
486 : 145267 : d_stats.d_fullEffortChecks++;
487 : : // We do combination if all has been processed and we are in fullcheck
488 [ + + ][ + + ]: 281404 : if (logicInfo().isSharingEnabled() && !d_factsAsserted && !needCheck()
489 [ + + ][ + - ]: 281404 : && !d_inConflict)
[ + + ]
490 : : {
491 : 69279 : d_stats.d_combineTheoriesCalls++;
492 : : // Do the combination
493 [ + - ]: 138558 : Trace("theory") << "TheoryEngine::check(" << effort
494 : 69279 : << "): running combination" << endl;
495 : : {
496 : : TimerStat::CodeTimer combineTheoriesTimer(
497 : 69279 : d_stats.d_combineTheoriesTime);
498 : 69279 : d_tc->combineTheories();
499 : 69279 : }
500 [ + + ]: 69279 : if (logicInfo().isQuantified())
501 : : {
502 : 50616 : d_quantEngine->notifyCombineTheories();
503 : : }
504 : : }
505 : : }
506 : : else
507 : : {
508 [ - + ][ - + ]: 8675198 : Assert(effort == Theory::EFFORT_STANDARD);
[ - - ]
509 : 8675198 : d_stats.d_stdEffortChecks++;
510 : : }
511 : :
512 : : // Interrupt in case we reached a resource limit.
513 [ - + ]: 8820465 : if (rm->out())
514 : : {
515 : 0 : interrupt();
516 : 0 : return;
517 : : }
518 : : }
519 : :
520 : : // Must consult quantifiers theory for last call to ensure sat, or otherwise
521 : : // add a lemma
522 [ + + ][ + + ]: 11199176 : if (Theory::fullEffort(effort) && !d_inConflict && !needCheck())
[ + + ][ + + ]
523 : : {
524 : 60507 : d_stats.d_lcEffortChecks++;
525 [ + - ]: 60507 : Trace("theory::assertions-model") << endl;
526 [ - + ]: 60507 : if (TraceIsOn("theory::assertions-model"))
527 : : {
528 : 0 : printAssertions("theory::assertions-model");
529 : : }
530 : : // reset the model in the combination engine
531 : 60507 : d_tc->resetModel();
532 : : // checks for theories requiring the model go at last call
533 [ + + ]: 907605 : for (TheoryId theoryId = THEORY_FIRST; theoryId < THEORY_LAST; ++theoryId)
534 : : {
535 [ + + ]: 847098 : if (theoryId != THEORY_QUANTIFIERS)
536 : : {
537 : 786591 : Theory* theory = d_theoryTable[theoryId];
538 [ + - ][ + + ]: 786591 : if (theory && isTheoryEnabled(theoryId))
[ + + ]
539 : : {
540 [ + + ]: 493505 : if (theory->needsCheckLastEffort())
541 : : {
542 [ + + ]: 23170 : if (!d_tc->buildModel())
543 : : {
544 : : // We don't check if the model building fails, but for
545 : : // uniformity ask all theories needsCheckLastEffort method.
546 : 393 : continue;
547 : : }
548 : 22777 : theory->check(Theory::EFFORT_LAST_CALL);
549 : : }
550 : : }
551 : : }
552 : : }
553 [ + - ]: 60507 : if (!d_inConflict)
554 : : {
555 [ + + ]: 60507 : if (logicInfo().isQuantified())
556 : : {
557 : : // quantifiers engine must check at last call effort
558 : 51096 : d_quantEngine->check(Theory::EFFORT_LAST_CALL);
559 : : }
560 : : // notify the theory modules of the model
561 [ + + ]: 60903 : for (TheoryEngineModule* tem : d_modules)
562 : : {
563 [ + + ]: 415 : if (!tem->needsCandidateModel())
564 : : {
565 : : // module does not need candidate model
566 : 391 : continue;
567 : : }
568 [ - + ]: 24 : if (!d_tc->buildModel())
569 : : {
570 : : // model failed to build, we are done
571 : 0 : break;
572 : : }
573 : 24 : tem->notifyCandidateModel(getModel());
574 : : }
575 : : }
576 : : }
577 : :
578 [ + - ]: 22398314 : Trace("theory") << "TheoryEngine::check(" << effort << "): done, we are "
579 [ - - ]: 0 : << (d_inConflict ? "unsat" : "sat")
580 [ - - ]: 11199157 : << (d_lemmasAdded ? " with new lemmas"
581 : 11199157 : : " with no new lemmas");
582 [ + - ][ - - ]: 22398314 : Trace("theory") << ", need check = " << (needCheck() ? "YES" : "NO")
583 : 11199157 : << endl;
584 : :
585 : : // post check with the theory modules
586 [ + + ]: 11200940 : for (TheoryEngineModule* tem : d_modules)
587 : : {
588 : 1783 : tem->postCheck(effort);
589 : : }
590 [ + + ]: 11199157 : if (Theory::fullEffort(effort))
591 : : {
592 [ + + ][ + + ]: 175183 : if (!d_inConflict && !needCheck())
[ + + ]
593 : : {
594 : : // if some theory believes there is a conflict, but it is was not
595 : : // processed, we mark incomplete.
596 [ + + ]: 372030 : for (TheoryId theoryId = THEORY_FIRST; theoryId < THEORY_LAST;
597 : 347228 : ++theoryId)
598 : : {
599 : 347228 : Theory* theory = d_theoryTable[theoryId];
600 [ + - ][ + + ]: 347228 : if (theory && theory->getTheoryState() != nullptr)
[ + + ]
601 : : {
602 [ - + ]: 322426 : if (theory->getTheoryState()->isInConflict())
603 : : {
604 : 0 : setModelUnsound(theoryId,
605 : : IncompleteId::UNPROCESSED_THEORY_CONFLICT);
606 : 0 : DebugUnhandled()
607 : 0 : << "Unprocessed theory conflict from " << theoryId;
608 : : break;
609 : : }
610 : : }
611 : : }
612 : : // Do post-processing of model from the theories (e.g. used for
613 : : // THEORY_SEP to construct heap model)
614 : 24802 : d_tc->postProcessModel(d_modelUnsound.get());
615 : : }
616 : : }
617 : : }
618 [ - + ]: 12 : catch (const theory::Interrupted&)
619 : : {
620 [ + - ]: 12 : Trace("theory") << "TheoryEngine::check() => interrupted" << endl;
621 : 12 : }
622 : : }
623 : :
624 : 8820465 : void TheoryEngine::propagate(Theory::Effort effort)
625 : : {
626 : : // Reset the interrupt flag
627 : 8820465 : d_interrupted = false;
628 : :
629 : : // Definition of the statement that is to be run by every theory
630 : : #ifdef CVC5_FOR_EACH_THEORY_STATEMENT
631 : : #undef CVC5_FOR_EACH_THEORY_STATEMENT
632 : : #endif
633 : : #define CVC5_FOR_EACH_THEORY_STATEMENT(THEORY) \
634 : : if (theory::TheoryTraits<THEORY>::hasPropagate && isTheoryEnabled(THEORY)) \
635 : : { \
636 : : theoryOf(THEORY)->propagate(effort); \
637 : : }
638 : :
639 : : // Reset the interrupt flag
640 : 8820465 : d_interrupted = false;
641 : :
642 : : // Propagate for each theory using the statement above
643 [ + + ][ + + ]: 8820465 : CVC5_FOR_EACH_THEORY;
644 : 8820465 : }
645 : :
646 : 7363917 : Node TheoryEngine::getNextDecisionRequest()
647 : : {
648 : 7363917 : return d_decManager->getNextDecisionRequest();
649 : : }
650 : :
651 : 198211 : bool TheoryEngine::properConflict(TNode conflict) const
652 : : {
653 : : bool value;
654 [ + + ]: 198211 : if (conflict.getKind() == Kind::AND)
655 : : {
656 [ + + ]: 2231952 : for (unsigned i = 0; i < conflict.getNumChildren(); ++i)
657 : : {
658 [ - + ]: 2035178 : if (!getPropEngine()->hasValue(conflict[i], value))
659 : : {
660 [ - - ]: 0 : Trace("properConflict")
661 : 0 : << "Bad conflict is due to unassigned atom: " << conflict[i]
662 : 0 : << endl;
663 : 0 : return false;
664 : : }
665 [ - + ]: 2035178 : if (!value)
666 : : {
667 [ - - ]: 0 : Trace("properConflict")
668 : 0 : << "Bad conflict is due to false atom: " << conflict[i] << endl;
669 : 0 : return false;
670 : : }
671 [ - + ]: 2035178 : if (conflict[i] != rewrite(conflict[i]))
672 : : {
673 [ - - ]: 0 : Trace("properConflict")
674 [ - - ]: 0 : << "Bad conflict is due to atom not in normal form: " << conflict[i]
675 : 0 : << " vs " << rewrite(conflict[i]) << endl;
676 : 0 : return false;
677 : : }
678 : : }
679 : : }
680 : : else
681 : : {
682 [ - + ]: 1437 : if (!getPropEngine()->hasValue(conflict, value))
683 : : {
684 [ - - ]: 0 : Trace("properConflict")
685 : 0 : << "Bad conflict is due to unassigned atom: " << conflict << endl;
686 : 0 : return false;
687 : : }
688 [ - + ]: 1437 : if (!value)
689 : : {
690 [ - - ]: 0 : Trace("properConflict")
691 : 0 : << "Bad conflict is due to false atom: " << conflict << endl;
692 : 0 : return false;
693 : : }
694 [ - + ]: 1437 : if (conflict != rewrite(conflict))
695 : : {
696 [ - - ]: 0 : Trace("properConflict")
697 : 0 : << "Bad conflict is due to atom not in normal form: " << conflict
698 : 0 : << " vs " << rewrite(conflict) << endl;
699 : 0 : return false;
700 : : }
701 : : }
702 : 198211 : return true;
703 : : }
704 : :
705 : 1897173 : TheoryModel* TheoryEngine::getModel()
706 : : {
707 [ - + ][ - + ]: 1897173 : Assert(d_tc != nullptr);
[ - - ]
708 : 1897173 : TheoryModel* m = d_tc->getModel();
709 [ - + ][ - + ]: 1897173 : Assert(m != nullptr);
[ - - ]
710 : 1897173 : return m;
711 : : }
712 : :
713 : 24746 : TheoryModel* TheoryEngine::getBuiltModel()
714 : : {
715 [ - + ][ - + ]: 24746 : Assert(d_tc != nullptr);
[ - - ]
716 : : // If this method was called, produceModels should be true.
717 [ - + ][ - + ]: 24746 : AlwaysAssert(options().smt.produceModels);
[ - - ]
718 : : // we must build model at this point
719 [ - + ]: 24746 : if (!d_tc->buildModel())
720 : : {
721 : 0 : return nullptr;
722 : : }
723 : 24746 : return d_tc->getModel();
724 : : }
725 : :
726 : 25545 : bool TheoryEngine::buildModel()
727 : : {
728 [ - + ][ - + ]: 25545 : Assert(d_tc != nullptr);
[ - - ]
729 : 25545 : return d_tc->buildModel();
730 : : }
731 : :
732 : 197190925 : bool TheoryEngine::isTheoryEnabled(theory::TheoryId theoryId) const
733 : : {
734 : 197190925 : return logicInfo().isTheoryEnabled(theoryId);
735 : : }
736 : :
737 : 70185589 : theory::TheoryId TheoryEngine::theoryExpPropagation(theory::TheoryId tid) const
738 : : {
739 [ + + ]: 70185589 : if (options().theory.eeMode == options::EqEngineMode::CENTRAL)
740 : : {
741 : 32955 : if (EqEngineManagerCentral::usesCentralEqualityEngine(options(), tid)
742 [ + + ][ + + ]: 32955 : && Theory::expUsingCentralEqualityEngine(tid))
[ + + ]
743 : : {
744 : 12762 : return THEORY_BUILTIN;
745 : : }
746 : : }
747 : 70172827 : return tid;
748 : : }
749 : :
750 : 50795 : bool TheoryEngine::presolve()
751 : : {
752 : : // Reset the interrupt flag
753 : 50795 : d_interrupted = false;
754 : :
755 : : // Reset the decision manager. This clears its decision strategies that are
756 : : // no longer valid in this user context.
757 : 50795 : d_decManager->presolve();
758 : :
759 : : try
760 : : {
761 : : // Definition of the statement that is to be run by every theory
762 : : #ifdef CVC5_FOR_EACH_THEORY_STATEMENT
763 : : #undef CVC5_FOR_EACH_THEORY_STATEMENT
764 : : #endif
765 : : #define CVC5_FOR_EACH_THEORY_STATEMENT(THEORY) \
766 : : if (theory::TheoryTraits<THEORY>::hasPresolve) \
767 : : { \
768 : : theoryOf(THEORY)->presolve(); \
769 : : if (d_inConflict) \
770 : : { \
771 : : return true; \
772 : : } \
773 : : }
774 : :
775 : : // Presolve for each theory using the statement above
776 [ + + ][ - + ]: 50795 : CVC5_FOR_EACH_THEORY;
[ - + ][ - + ]
[ - + ][ - + ]
[ - + ][ - + ]
[ - + ]
777 : : }
778 [ - - ]: 0 : catch (const theory::Interrupted&)
779 : : {
780 [ - - ]: 0 : Trace("theory") << "TheoryEngine::presolve() => interrupted" << endl;
781 : 0 : }
782 : : // presolve with the theory engine modules as well
783 [ + + ]: 51304 : for (TheoryEngineModule* tem : d_modules)
784 : : {
785 : 511 : tem->presolve();
786 : : }
787 : :
788 : : // return whether we have a conflict
789 : 50793 : return false;
790 : : } /* TheoryEngine::presolve() */
791 : :
792 : 50779 : void TheoryEngine::postsolve(prop::SatValue result)
793 : : {
794 : : // postsolve with the theory engine modules as well
795 [ + + ]: 51290 : for (TheoryEngineModule* tem : d_modules)
796 : : {
797 : 511 : tem->postsolve(result);
798 : : }
799 : :
800 : : // Reset the interrupt flag
801 : 50779 : d_interrupted = false;
802 : 50779 : }
803 : :
804 : 4953 : void TheoryEngine::notifyRestart()
805 : : {
806 : : // Reset the interrupt flag
807 : 4953 : d_interrupted = false;
808 : :
809 : : // Definition of the statement that is to be run by every theory
810 : : #ifdef CVC5_FOR_EACH_THEORY_STATEMENT
811 : : #undef CVC5_FOR_EACH_THEORY_STATEMENT
812 : : #endif
813 : : #define CVC5_FOR_EACH_THEORY_STATEMENT(THEORY) \
814 : : if (theory::TheoryTraits<THEORY>::hasNotifyRestart \
815 : : && isTheoryEnabled(THEORY)) \
816 : : { \
817 : : theoryOf(THEORY)->notifyRestart(); \
818 : : }
819 : :
820 : : // notify each theory using the statement above
821 [ + + ]: 4953 : CVC5_FOR_EACH_THEORY;
822 : 4953 : }
823 : :
824 : 346565 : void TheoryEngine::ppStaticLearn(TNode in, std::vector<TrustNode>& learned)
825 : : {
826 : : // Reset the interrupt flag
827 : 346565 : d_interrupted = false;
828 : :
829 : : // Definition of the statement that is to be run by every theory
830 : : #ifdef CVC5_FOR_EACH_THEORY_STATEMENT
831 : : #undef CVC5_FOR_EACH_THEORY_STATEMENT
832 : : #endif
833 : : #define CVC5_FOR_EACH_THEORY_STATEMENT(THEORY) \
834 : : if (theory::TheoryTraits<THEORY>::hasPpStaticLearn) \
835 : : { \
836 : : theoryOf(THEORY)->ppStaticLearn(in, learned); \
837 : : }
838 : :
839 : : // static learning for each theory using the statement above
840 : 346565 : CVC5_FOR_EACH_THEORY;
841 : 346565 : }
842 : :
843 : 326819 : bool TheoryEngine::hasSatValue(TNode n, bool& value) const
844 : : {
845 [ + + ]: 326819 : if (d_propEngine->isSatLiteral(n))
846 : : {
847 : 326706 : return d_propEngine->hasValue(n, value);
848 : : }
849 : 113 : return false;
850 : : }
851 : :
852 : 1909989 : bool TheoryEngine::hasSatValue(TNode n) const
853 : : {
854 [ + + ]: 1909989 : if (d_propEngine->isSatLiteral(n))
855 : : {
856 : : bool value;
857 : 1909053 : return d_propEngine->hasValue(n, value);
858 : : }
859 : 936 : return false;
860 : : }
861 : :
862 : 1726 : bool TheoryEngine::isRelevant(Node lit) const
863 : : {
864 [ + - ]: 1726 : if (d_relManager != nullptr)
865 : : {
866 : 1726 : return d_relManager->isRelevant(lit);
867 : : }
868 : : // otherwise must assume its relevant
869 : 0 : return true;
870 : : }
871 : :
872 : 53751 : bool TheoryEngine::isLegalElimination(TNode x, TNode val)
873 : : {
874 [ - + ][ - + ]: 53751 : Assert(x.isVar());
[ - - ]
875 [ + + ]: 53751 : if (expr::hasSubterm(val, x))
876 : : {
877 : 13121 : return false;
878 : : }
879 [ - + ]: 121890 : if (!CVC5_EQUAL(val.getType(), x.getType()))
880 : : {
881 : 0 : return false;
882 : : }
883 [ + + ][ + + ]: 40630 : if (!options().smt.produceModels || options().smt.modelVarElimUneval)
[ + + ]
884 : : {
885 : : // Don't care about the model, or we allow variables to be eliminated by
886 : : // unevaluatable terms, we can eliminate. Notice that when
887 : : // options().smt.modelVarElimUneval is true, val may contain unevaluatable
888 : : // kinds. This means that e.g. a Boolean variable may be eliminated based on
889 : : // an equality (= b (forall ((x)) (P x))), where its model value is (forall
890 : : // ((x)) (P x)).
891 : 40626 : return true;
892 : : }
893 : : // If models are enabled, then it depends on whether the term contains any
894 : : // unevaluable operators like FORALL, SINE, etc. Having such operators makes
895 : : // model construction contain non-constant values for variables, which is
896 : : // not ideal from a user perspective.
897 : : // We also insist on this check since the term to eliminate should never
898 : : // contain quantifiers, or else variable shadowing issues may arise.
899 : : // there should be a model object
900 : 4 : TheoryModel* tm = getModel();
901 [ - + ][ - + ]: 4 : Assert(tm != nullptr);
[ - - ]
902 : 4 : return tm->isLegalElimination(val);
903 : : }
904 : :
905 : 215569 : bool TheoryEngine::solve(TrustNode tliteral,
906 : : TrustSubstitutionMap& substitutionOut)
907 : : {
908 [ - + ][ - + ]: 215569 : Assert(tliteral.getKind() == TrustNodeKind::LEMMA);
[ - - ]
909 : : // Reset the interrupt flag
910 : 215569 : d_interrupted = false;
911 : :
912 : 215569 : TNode literal = tliteral.getNode();
913 [ + + ]: 215569 : TNode atom = literal.getKind() == Kind::NOT ? literal[0] : literal;
914 [ + - ]: 431138 : Trace("theory::solve") << "TheoryEngine::solve(" << literal
915 [ - + ][ - - ]: 215569 : << "): solving with " << theoryOf(atom)->getId()
916 : 215569 : << endl;
917 : :
918 : 215569 : TheoryId tid = d_env.theoryOf(atom);
919 : : // Note that ppAssert is called before ppRewrite.
920 [ + + ][ + - ]: 215569 : if (!isTheoryEnabled(tid) && tid != THEORY_SAT_SOLVER)
[ + + ]
921 : : {
922 : : // don't throw an exception yet
923 : : // Instead ppStaticRewrite will be called on atom, which may throw an
924 : : // exception if the term is not rewritten.
925 : 12 : return false;
926 : : }
927 : :
928 : 215557 : bool solveStatus = d_theoryTable[tid]->ppAssert(tliteral, substitutionOut);
929 [ + - ]: 431114 : Trace("theory::solve") << "TheoryEngine::solve(" << literal << ") => "
930 : 215557 : << solveStatus << endl;
931 : 215557 : return solveStatus;
932 : 215569 : }
933 : :
934 : 4767450 : TrustNode TheoryEngine::ppRewrite(TNode term,
935 : : std::vector<theory::SkolemLemma>& lems)
936 : : {
937 [ - + ][ - + ]: 4767450 : Assert(lems.empty());
[ - - ]
938 : 4767450 : TheoryId tid = d_env.theoryOf(term);
939 : : // We check whether the theory is enabled here (instead of only during solve),
940 : : // since there are corner cases where facts may involve terms that belong
941 : : // to other theories, e.g. equalities between variables belong to UF when
942 : : // theoryof-mode is `term`.
943 [ - + ][ - - ]: 4767450 : if (!isTheoryEnabled(tid) && tid != THEORY_SAT_SOLVER)
[ - + ]
944 : : {
945 : 0 : stringstream ss;
946 : 0 : ss << "The logic was specified as " << logicInfo().getLogicString()
947 : 0 : << ", which doesn't include " << tid
948 : 0 : << ", but got a term for that theory during solving." << std::endl
949 : 0 : << "The term:" << std::endl
950 : 0 : << term;
951 : 0 : throw LogicException(ss.str());
952 : 0 : }
953 : 4767459 : TrustNode trn = d_theoryTable[tid]->ppRewrite(term, lems);
954 : : // should never introduce a skolem to eliminate an equality
955 [ + + ][ + - ]: 4767441 : Assert(lems.empty() || term.getKind() != Kind::EQUAL);
[ - + ][ - + ]
[ - - ]
956 [ + + ]: 4767441 : if (!isProofEnabled())
957 : : {
958 : 2715814 : return trn;
959 : : }
960 [ - + ][ - + ]: 2051627 : Assert(d_lazyProof != nullptr);
[ - - ]
961 : : // if proofs are enabled, must ensure we have proofs for all the skolem lemmas
962 [ + + ]: 2054879 : for (SkolemLemma& skl : lems)
963 : : {
964 : 3252 : TrustNode tskl = skl.d_lemma;
965 [ - + ][ - + ]: 3252 : Assert(tskl.getKind() == TrustNodeKind::LEMMA);
[ - - ]
966 [ + + ]: 3252 : if (tskl.getGenerator() == nullptr)
967 : : {
968 : 1016 : Node proven = tskl.getProven();
969 : : Node tidn =
970 : 1016 : builtin::BuiltinProofRuleChecker::mkTheoryIdNode(nodeManager(), tid);
971 : 2032 : d_lazyProof->addTrustedStep(
972 : : proven, TrustId::THEORY_PREPROCESS_LEMMA, {}, {tidn});
973 [ + - ]: 1016 : skl.d_lemma = TrustNode::mkTrustLemma(proven, d_lazyProof.get());
974 : 1016 : }
975 : 3252 : }
976 : : // notice that we don't ensure proofs are processed for the returned (rewrite)
977 : : // trust node, this is the responsibility of the caller, i.e. theory
978 : : // preprocessor.
979 : 2051627 : return trn;
980 : 0 : }
981 : :
982 : 3692868 : TrustNode TheoryEngine::ppStaticRewrite(TNode term)
983 : : {
984 : 3692868 : TheoryId tid = d_env.theoryOf(term);
985 [ + + ][ + - ]: 3692868 : if (!isTheoryEnabled(tid) && tid != THEORY_SAT_SOLVER)
[ + + ]
986 : : {
987 : : // If the theory is not enabled, then we require eliminating the term
988 : : // here.
989 : 11 : TrustNode tret = d_theoryTable[THEORY_BUILTIN]->ppStaticRewrite(term);
990 [ + + ]: 11 : if (!tret.isNull())
991 : : {
992 : 8 : return tret;
993 : : }
994 : 3 : stringstream ss;
995 : 3 : ss << "The logic was specified as " << logicInfo().getLogicString()
996 : 6 : << ", which doesn't include " << tid
997 : 3 : << ", but got a preprocessing-time term for that theory." << std::endl
998 : 3 : << "The term:" << std::endl
999 : 3 : << term;
1000 : 3 : throw LogicException(ss.str());
1001 : 14 : }
1002 : 3692857 : return d_theoryTable[tid]->ppStaticRewrite(term);
1003 : : }
1004 : :
1005 : 65951 : void TheoryEngine::notifyPreprocessedAssertions(
1006 : : const std::vector<Node>& assertions)
1007 : : {
1008 : : // call all the theories
1009 [ + + ]: 989265 : for (TheoryId theoryId = theory::THEORY_FIRST; theoryId < theory::THEORY_LAST;
1010 : 923314 : ++theoryId)
1011 : : {
1012 [ + - ]: 923314 : if (d_theoryTable[theoryId])
1013 : : {
1014 : 923314 : theoryOf(theoryId)->ppNotifyAssertions(assertions);
1015 : : }
1016 : : }
1017 [ + + ]: 65951 : if (d_relManager != nullptr)
1018 : : {
1019 : 483 : d_relManager->notifyPreprocessedAssertions(assertions, true);
1020 : : }
1021 : 65951 : }
1022 : :
1023 : 69856302 : bool TheoryEngine::markPropagation(TNode assertion,
1024 : : TNode originalAssertion,
1025 : : theory::TheoryId toTheoryId,
1026 : : theory::TheoryId fromTheoryId)
1027 : : {
1028 : : // What and where we are asserting
1029 : 69856302 : NodeTheoryPair toAssert(assertion, toTheoryId, d_propagationMapTimestamp);
1030 : : // What and where it came from
1031 : : NodeTheoryPair toExplain(
1032 : 69856302 : originalAssertion, fromTheoryId, d_propagationMapTimestamp);
1033 : :
1034 : : // See if the theory already got this literal
1035 : 69856302 : PropagationMap::const_iterator find = d_propagationMap.find(toAssert);
1036 [ + + ]: 69856302 : if (find != d_propagationMap.end())
1037 : : {
1038 : : // The theory already knows this
1039 [ + - ]: 39326430 : Trace("theory::assertToTheory")
1040 : 19663215 : << "TheoryEngine::markPropagation(): already there" << endl;
1041 : 19663215 : return false;
1042 : : }
1043 : :
1044 [ + - ]: 100386174 : Trace("theory::assertToTheory")
1045 : 0 : << "TheoryEngine::markPropagation(): marking ["
1046 : 0 : << d_propagationMapTimestamp << "] " << assertion << ", " << toTheoryId
1047 : 50193087 : << " from " << originalAssertion << ", " << fromTheoryId << endl;
1048 : :
1049 : : // Mark the propagation
1050 : 50193087 : d_propagationMap[toAssert] = toExplain;
1051 : 50193087 : d_propagationMapTimestamp = d_propagationMapTimestamp + 1;
1052 : :
1053 : 50193087 : return true;
1054 : 69856302 : }
1055 : :
1056 : 85824543 : void TheoryEngine::assertToTheory(TNode assertion,
1057 : : TNode originalAssertion,
1058 : : theory::TheoryId toTheoryId,
1059 : : theory::TheoryId fromTheoryId)
1060 : : {
1061 [ + - ]: 171649086 : Trace("theory::assertToTheory")
1062 : 0 : << "TheoryEngine::assertToTheory(" << assertion << ", "
1063 : 0 : << originalAssertion << "," << toTheoryId << ", " << fromTheoryId << ")"
1064 : 85824543 : << endl;
1065 : :
1066 [ - + ][ - + ]: 85824543 : Assert(toTheoryId != fromTheoryId);
[ - - ]
1067 [ + + ][ - + ]: 85824543 : if (toTheoryId != THEORY_SAT_SOLVER && !isTheoryEnabled(toTheoryId))
[ - + ]
1068 : : {
1069 : 0 : stringstream ss;
1070 : 0 : ss << "The logic was specified as " << logicInfo().getLogicString()
1071 : 0 : << ", which doesn't include " << toTheoryId
1072 : 0 : << ", but got an asserted fact to that theory." << endl
1073 : 0 : << "The fact:" << endl
1074 : 0 : << assertion;
1075 : 0 : throw LogicException(ss.str());
1076 : 0 : }
1077 : :
1078 [ + + ]: 85824543 : if (d_inConflict)
1079 : : {
1080 : 183887 : return;
1081 : : }
1082 : :
1083 : : // If sharing is disabled, things are easy
1084 [ + + ]: 85640656 : if (!logicInfo().isSharingEnabled())
1085 : : {
1086 [ - + ][ - + ]: 15784354 : Assert(assertion == originalAssertion);
[ - - ]
1087 [ + + ]: 15784354 : if (fromTheoryId == THEORY_SAT_SOLVER)
1088 : : {
1089 : : // Send to the apropriate theory
1090 : 11409867 : theory::Theory* toTheory = theoryOf(toTheoryId);
1091 : : // We assert it, and we know it's preregistereed
1092 : 11409867 : toTheory->assertFact(assertion, true);
1093 : : // Mark that we have more information
1094 : 11409867 : d_factsAsserted = true;
1095 : : }
1096 : : else
1097 : : {
1098 [ - + ][ - + ]: 4374487 : Assert(toTheoryId == THEORY_SAT_SOLVER);
[ - - ]
1099 : : // Check for propositional conflict
1100 : : bool value;
1101 [ + + ]: 4374487 : if (d_propEngine->hasValue(assertion, value))
1102 : : {
1103 [ + + ]: 3173989 : if (!value)
1104 : : {
1105 [ + - ]: 131978 : Trace("theory::propagate")
1106 : 0 : << "TheoryEngine::assertToTheory(" << assertion << ", "
1107 : 0 : << toTheoryId << ", " << fromTheoryId
1108 : 65989 : << "): conflict (no sharing)" << endl;
1109 [ + - ]: 131978 : Trace("dtview::conflict")
1110 : 65989 : << ":THEORY-CONFLICT: " << assertion << std::endl;
1111 : 65989 : markInConflict();
1112 : : }
1113 : : else
1114 : : {
1115 : 3108000 : return;
1116 : : }
1117 : : }
1118 : 1266487 : d_propagatedLiterals.push_back(assertion);
1119 : : }
1120 : 12676354 : return;
1121 : : }
1122 : :
1123 : : // determine the actual theory that will process/explain the fact, which is
1124 : : // THEORY_BUILTIN if the theory uses the central equality engine
1125 : 69856302 : TheoryId toTheoryIdProp = theoryExpPropagation(toTheoryId);
1126 : : // If sending to the shared solver, it's also simple
1127 [ + + ]: 69856302 : if (toTheoryId == THEORY_BUILTIN)
1128 : : {
1129 [ + + ]: 22741691 : if (markPropagation(
1130 : : assertion, originalAssertion, toTheoryIdProp, fromTheoryId))
1131 : : {
1132 : : // assert to the shared solver
1133 : 12653554 : bool polarity = assertion.getKind() != Kind::NOT;
1134 [ + + ]: 12653554 : TNode atom = polarity ? assertion : assertion[0];
1135 : 12653554 : d_sharedSolver->assertShared(atom, polarity, assertion);
1136 : 12653554 : }
1137 : 22741691 : return;
1138 : : }
1139 : :
1140 : : // Things from the SAT solver are already normalized, so they go
1141 : : // directly to the apropriate theory
1142 [ + + ]: 47114611 : if (fromTheoryId == THEORY_SAT_SOLVER)
1143 : : {
1144 : : // We know that this is normalized, so just send it off to the theory
1145 [ + + ]: 17094919 : if (markPropagation(
1146 : : assertion, originalAssertion, toTheoryIdProp, fromTheoryId))
1147 : : {
1148 : : // Is it preregistered
1149 [ - - ]: 16960504 : bool preregistered = d_propEngine->isSatLiteral(assertion)
1150 [ + + ][ + + ]: 16960504 : && d_env.theoryOf(assertion) == toTheoryId;
[ + + ][ + - ]
[ - - ]
1151 : : // We assert it
1152 : 16960504 : theoryOf(toTheoryId)->assertFact(assertion, preregistered);
1153 : : // Mark that we have more information
1154 : 16960504 : d_factsAsserted = true;
1155 : : }
1156 : 17094919 : return;
1157 : : }
1158 : :
1159 : : // Propagations to the SAT solver are just enqueued for pickup by
1160 : : // the SAT solver later
1161 [ + + ]: 30019692 : if (toTheoryId == THEORY_SAT_SOLVER)
1162 : : {
1163 [ - + ][ - + ]: 22735965 : Assert(toTheoryIdProp == toTheoryId);
[ - - ]
1164 [ + + ]: 22735965 : if (markPropagation(assertion, originalAssertion, toTheoryId, fromTheoryId))
1165 : : {
1166 : : // Enqueue for propagation to the SAT solver
1167 : 13936646 : d_propagatedLiterals.push_back(assertion);
1168 : : // Check for propositional conflicts
1169 : : bool value;
1170 [ + + ][ + + ]: 13936646 : if (d_propEngine->hasValue(assertion, value) && !value)
[ + - ][ + + ]
[ - - ]
1171 : : {
1172 [ + - ]: 208690 : Trace("theory::propagate")
1173 : 0 : << "TheoryEngine::assertToTheory(" << assertion << ", "
1174 : 0 : << toTheoryId << ", " << fromTheoryId << "): conflict (sharing)"
1175 : 104345 : << endl;
1176 [ + - ]: 208690 : Trace("dtview::conflict")
1177 : 104345 : << ":THEORY-CONFLICT: " << assertion << std::endl;
1178 : 104345 : markInConflict();
1179 : : }
1180 : : }
1181 : 22735965 : return;
1182 : : }
1183 : :
1184 : 7283727 : Assert(assertion.getKind() == Kind::EQUAL
1185 : : || (assertion.getKind() == Kind::NOT
1186 : : && assertion[0].getKind() == Kind::EQUAL));
1187 : :
1188 : : // Normalize
1189 : 7283727 : Node normalizedLiteral = rewrite(assertion);
1190 : :
1191 : : // See if it rewrites false directly -> conflict
1192 [ + + ]: 7283727 : if (normalizedLiteral.isConst())
1193 : : {
1194 [ + + ]: 47271 : if (!normalizedLiteral.getConst<bool>())
1195 : : {
1196 : : // Mark the propagation for explanations
1197 [ + - ]: 1037 : if (markPropagation(normalizedLiteral,
1198 : : originalAssertion,
1199 : : toTheoryIdProp,
1200 : : fromTheoryId))
1201 : : {
1202 : : // special case, trust node has no proof generator
1203 : 1037 : TrustNode trnn = TrustNode::mkTrustConflict(normalizedLiteral);
1204 : : // Get the explanation (conflict will figure out where it came from)
1205 : 1037 : conflict(trnn, InferenceId::CONFLICT_REWRITE_LIT, toTheoryId);
1206 : 1037 : }
1207 : : else
1208 : : {
1209 : 0 : Unreachable();
1210 : : }
1211 : 1037 : return;
1212 : : }
1213 : : }
1214 : :
1215 : : // Try and assert (note that we assert the non-normalized one)
1216 [ + + ]: 7282690 : if (markPropagation(
1217 : : assertion, originalAssertion, toTheoryIdProp, fromTheoryId))
1218 : : {
1219 : : // Check if has been pre-registered with the theory
1220 [ - - ]: 6641346 : bool preregistered = d_propEngine->isSatLiteral(assertion)
1221 [ + + ][ + + ]: 6641346 : && d_env.theoryOf(assertion) == toTheoryId;
[ + + ][ + - ]
[ - - ]
1222 : : // Assert away
1223 : 6641346 : theoryOf(toTheoryId)->assertFact(assertion, preregistered);
1224 : 6641346 : d_factsAsserted = true;
1225 : : }
1226 : :
1227 : 7282690 : return;
1228 : 7283727 : }
1229 : :
1230 : 28438843 : void TheoryEngine::assertFact(TNode literal)
1231 : : {
1232 [ + - ]: 28438843 : Trace("theory") << "TheoryEngine::assertFact(" << literal << ")" << endl;
1233 : :
1234 : : // spendResource();
1235 : :
1236 : : // If we're in conflict, nothing to do
1237 [ + + ]: 28438843 : if (d_inConflict)
1238 : : {
1239 : 40419 : return;
1240 : : }
1241 : :
1242 : : // Get the atom
1243 : 28398424 : bool polarity = literal.getKind() != Kind::NOT;
1244 [ + + ]: 28398424 : TNode atom = polarity ? literal : literal[0];
1245 : :
1246 [ + + ]: 28398424 : if (logicInfo().isSharingEnabled())
1247 : : {
1248 : : // If any shared terms, it's time to do sharing work
1249 : 16988558 : d_sharedSolver->preNotifySharedFact(atom);
1250 : :
1251 : : // If it's an equality, assert it to the shared term manager, even though
1252 : : // the terms are not yet shared. As the terms become shared later, the
1253 : : // shared terms manager will then add them to the assert the equality to the
1254 : : // interested theories
1255 [ + + ]: 16988556 : if (atom.getKind() == Kind::EQUAL)
1256 : : {
1257 : : // Assert it to the the owning theory
1258 : 9184853 : assertToTheory(literal,
1259 : : literal,
1260 : 9184853 : /* to */ d_env.theoryOf(atom),
1261 : : /* from */ THEORY_SAT_SOLVER);
1262 : : // Shared terms manager will assert to interested theories directly, as
1263 : : // the terms become shared
1264 : 9184853 : assertToTheory(literal,
1265 : : literal,
1266 : : /* to */ THEORY_BUILTIN,
1267 : : /* from */ THEORY_SAT_SOLVER);
1268 : :
1269 : : // Now, let's check for any atom triggers from lemmas
1270 : 9184853 : AtomRequests::atom_iterator it = d_atomRequests.getAtomIterator(atom);
1271 [ + + ]: 9227351 : while (!it.done())
1272 : : {
1273 : 42498 : const AtomRequests::Request& request = it.get();
1274 : : Node toAssert =
1275 [ + + ]: 42498 : polarity ? (Node)request.d_atom : request.d_atom.notNode();
1276 [ + - ]: 84996 : Trace("theory::atoms") << "TheoryEngine::assertFact(" << literal
1277 : 42498 : << "): sending requested " << toAssert << endl;
1278 : 42498 : assertToTheory(
1279 : 42498 : toAssert, literal, request.d_toTheory, THEORY_SAT_SOLVER);
1280 [ + + ]: 42498 : if (options().theory.eeMode == options::EqEngineMode::CENTRAL)
1281 : : {
1282 : : // Also send to THEORY_BUILTIN, similar to above
1283 : 48 : assertToTheory(toAssert,
1284 : : literal,
1285 : : /* to */ THEORY_BUILTIN,
1286 : : /* from */ THEORY_SAT_SOLVER);
1287 : : }
1288 : 42498 : it.next();
1289 : 42498 : }
1290 : : }
1291 : : else
1292 : : {
1293 : : // Not an equality, just assert to the appropriate theory
1294 : 7803703 : assertToTheory(literal,
1295 : : literal,
1296 : 7803703 : /* to */ d_env.theoryOf(atom),
1297 : : /* from */ THEORY_SAT_SOLVER);
1298 : : }
1299 : : }
1300 : : else
1301 : : {
1302 : : // Assert the fact to the appropriate theory directly
1303 : 11409867 : assertToTheory(literal,
1304 : : literal,
1305 : 11409867 : /* to */ d_env.theoryOf(atom),
1306 : : /* from */ THEORY_SAT_SOLVER);
1307 : : }
1308 : 28398424 : }
1309 : :
1310 : 31959055 : bool TheoryEngine::propagate(TNode literal, theory::TheoryId theory)
1311 : : {
1312 [ + - ]: 63918110 : Trace("theory::propagate")
1313 : 31959055 : << "TheoryEngine::propagate(" << literal << ", " << theory << ")" << endl;
1314 : :
1315 : 63918110 : Trace("dtview::prop") << std::string(context()->getLevel(), ' ')
1316 : 31959055 : << ":THEORY-PROP: " << literal << endl;
1317 : :
1318 : : // spendResource();
1319 : :
1320 : : // Get the atom
1321 : 31959055 : bool polarity = literal.getKind() != Kind::NOT;
1322 [ + + ]: 31959055 : TNode atom = polarity ? literal : literal[0];
1323 : :
1324 [ + + ][ + + ]: 31959055 : if (logicInfo().isSharingEnabled() && atom.getKind() == Kind::EQUAL)
[ + + ]
1325 : : {
1326 [ + + ]: 23240880 : if (d_propEngine->isSatLiteral(literal))
1327 : : {
1328 : : // We propagate SAT literals to SAT
1329 : 18488530 : assertToTheory(
1330 : : literal, literal, /* to */ THEORY_SAT_SOLVER, /* from */ theory);
1331 : : }
1332 [ + + ]: 23240880 : if (theory != THEORY_BUILTIN)
1333 : : {
1334 : : // Assert to the shared terms database
1335 : 13635333 : assertToTheory(
1336 : : literal, literal, /* to */ THEORY_BUILTIN, /* from */ theory);
1337 : : }
1338 : : }
1339 : : else
1340 : : {
1341 : : // Just send off to the SAT solver
1342 [ - + ][ - + ]: 8718175 : Assert(d_propEngine->isSatLiteral(literal));
[ - - ]
1343 : 8718175 : assertToTheory(
1344 : : literal, literal, /* to */ THEORY_SAT_SOLVER, /* from */ theory);
1345 : : }
1346 : :
1347 : 63918110 : return !d_inConflict;
1348 : 31959055 : }
1349 : :
1350 : 2160243 : theory::EqualityStatus TheoryEngine::getEqualityStatus(TNode a, TNode b)
1351 : : {
1352 [ - + ][ - + ]: 6480729 : AssertEqual(a.getType(), b.getType());
[ - - ]
1353 : 2160243 : return d_sharedSolver->getEqualityStatus(a, b);
1354 : : }
1355 : :
1356 : 454 : void TheoryEngine::getDifficultyMap(std::map<Node, Node>& dmap,
1357 : : bool includeLemmas)
1358 : : {
1359 [ - + ][ - + ]: 454 : Assert(d_relManager != nullptr);
[ - - ]
1360 : 454 : d_relManager->getDifficultyMap(dmap, includeLemmas);
1361 : 454 : }
1362 : :
1363 : 1765 : theory::IncompleteId TheoryEngine::getModelUnsoundId() const
1364 : : {
1365 : 1765 : return d_modelUnsoundId.get();
1366 : : }
1367 : 23 : theory::IncompleteId TheoryEngine::getRefutationUnsoundId() const
1368 : : {
1369 : 23 : return d_refutationUnsoundId.get();
1370 : : }
1371 : :
1372 : 12493 : Node TheoryEngine::getCandidateModelValue(TNode var)
1373 : : {
1374 [ + + ]: 12493 : if (var.isConst())
1375 : : {
1376 : : // the model value of a constant must be itself
1377 : 18 : return var;
1378 : : }
1379 [ - + ][ - - ]: 24950 : Assert(d_sharedSolver->isShared(var))
1380 [ - + ][ - + ]: 12475 : << "node " << var << " is not shared" << std::endl;
[ - - ]
1381 : 12475 : return theoryOf(d_env.theoryOf(var.getType()))->getCandidateModelValue(var);
1382 : : }
1383 : :
1384 : 0 : std::unordered_set<TNode> TheoryEngine::getRelevantAssertions(bool& success)
1385 : : {
1386 : : // if there is no relevance manager, we fail
1387 [ - - ]: 0 : if (d_relManager == nullptr)
1388 : : {
1389 : 0 : success = false;
1390 : : // return empty set
1391 : 0 : return std::unordered_set<TNode>();
1392 : : }
1393 : 0 : return d_relManager->getRelevantAssertions(success);
1394 : : }
1395 : :
1396 : 251983 : TrustNode TheoryEngine::getExplanation(TNode node)
1397 : : {
1398 [ + - ]: 503966 : Trace("theory::explain") << "TheoryEngine::getExplanation(" << node
1399 : 0 : << "): current propagation index = "
1400 : 251983 : << d_propagationMapTimestamp << endl;
1401 : 251983 : bool polarity = node.getKind() != Kind::NOT;
1402 [ + + ]: 251983 : TNode atom = polarity ? node : node[0];
1403 : :
1404 : : // If we're not in shared mode, explanations are simple
1405 : 251983 : TrustNode texplanation;
1406 [ + + ]: 251983 : if (!logicInfo().isSharingEnabled())
1407 : : {
1408 [ + - ]: 171360 : Trace("theory::explain")
1409 : 0 : << "TheoryEngine::getExplanation: sharing is NOT enabled. "
1410 [ - + ][ - - ]: 85680 : << " Responsible theory is: " << theoryOf(atom)->getId() << std::endl;
1411 : :
1412 : 85680 : texplanation = theoryOf(atom)->explain(node);
1413 : 85680 : Node explanation = texplanation.getNode();
1414 [ + - ]: 171360 : Trace("theory::explain") << "TheoryEngine::getExplanation(" << node
1415 : 85680 : << ") => " << explanation << endl;
1416 [ + + ]: 85680 : if (isProofEnabled())
1417 : : {
1418 : 40162 : texplanation.debugCheckClosed(
1419 : : options(), "te-proof-exp", "texplanation no share", false);
1420 : : // check if no generator, if so, add THEORY_LEMMA
1421 [ - + ]: 40162 : if (texplanation.getGenerator() == nullptr)
1422 : : {
1423 : 0 : Node proven = texplanation.getProven();
1424 : 0 : TheoryId tid = theoryOf(atom)->getId();
1425 : : Node tidn = builtin::BuiltinProofRuleChecker::mkTheoryIdNode(
1426 : 0 : nodeManager(), tid);
1427 : 0 : d_lazyProof->addTrustedStep(proven, TrustId::THEORY_LEMMA, {}, {tidn});
1428 : : texplanation =
1429 [ - - ]: 0 : TrustNode::mkTrustPropExp(node, explanation, d_lazyProof.get());
1430 : 0 : }
1431 : : }
1432 : 85680 : }
1433 : : else
1434 : : {
1435 [ + - ]: 332606 : Trace("theory::explain")
1436 : 166303 : << "TheoryEngine::getExplanation: sharing IS enabled" << std::endl;
1437 : :
1438 : : // Initial thing to explain
1439 : : NodeTheoryPair toExplain(
1440 : 166303 : node, THEORY_SAT_SOLVER, d_propagationMapTimestamp);
1441 [ - + ][ - + ]: 166303 : Assert(d_propagationMap.find(toExplain) != d_propagationMap.end());
[ - - ]
1442 : :
1443 : 166303 : NodeTheoryPair nodeExplainerPair = d_propagationMap[toExplain];
1444 [ + - ]: 332606 : Trace("theory::explain")
1445 : 0 : << "TheoryEngine::getExplanation: explainer for node "
1446 : 0 : << nodeExplainerPair.d_node
1447 : 166303 : << " is theory: " << nodeExplainerPair.d_theory << std::endl;
1448 : :
1449 : : // Create the workplace for explanations
1450 : 498909 : std::vector<NodeTheoryPair> vec{d_propagationMap[toExplain]};
1451 : : // Process the explanation
1452 : 166303 : texplanation = getExplanation(vec);
1453 [ + - ]: 332606 : Trace("theory::explain") << "TheoryEngine::getExplanation(" << node
1454 [ - + ][ - - ]: 166303 : << ") => " << texplanation.getNode() << endl;
1455 : 166303 : }
1456 : : // notify the conflict as a lemma
1457 [ + + ]: 252019 : for (TheoryEngineModule* tem : d_modules)
1458 : : {
1459 : 36 : tem->notifyLemma(texplanation.getProven(),
1460 : : InferenceId::EXPLAINED_PROPAGATION,
1461 : : LemmaProperty::NONE,
1462 : : {},
1463 : : {});
1464 : : }
1465 : 503966 : return texplanation;
1466 : 251983 : }
1467 : :
1468 : : struct AtomsCollect
1469 : : {
1470 : : std::vector<TNode> d_atoms;
1471 : : std::unordered_set<TNode> d_visited;
1472 : :
1473 : : public:
1474 : : typedef void return_type;
1475 : :
1476 : 1013408 : bool alreadyVisited(TNode current, CVC5_UNUSED TNode parent)
1477 : : {
1478 : : // Check if already visited
1479 [ + + ]: 1013408 : if (d_visited.find(current) != d_visited.end()) return true;
1480 : : // Don't visit non-boolean
1481 [ + + ]: 930452 : if (!current.getType().isBoolean()) return true;
1482 : : // New node
1483 : 760718 : return false;
1484 : : }
1485 : :
1486 : 254010 : void visit(TNode current, CVC5_UNUSED TNode parent)
1487 : : {
1488 [ + + ]: 254010 : if (Theory::theoryOf(current) != theory::THEORY_BOOL)
1489 : : {
1490 : 86780 : d_atoms.push_back(current);
1491 : : }
1492 : 254010 : d_visited.insert(current);
1493 : 254010 : }
1494 : :
1495 : 84268 : void start(CVC5_UNUSED TNode node) {}
1496 : 84268 : void done(CVC5_UNUSED TNode node) {}
1497 : :
1498 : 84268 : std::vector<TNode> getAtoms() const { return d_atoms; }
1499 : : };
1500 : :
1501 : 84268 : void TheoryEngine::ensureLemmaAtoms(TNode n, theory::TheoryId atomsTo)
1502 : : {
1503 [ - + ][ - + ]: 84268 : Assert(atomsTo != THEORY_LAST);
[ - - ]
1504 [ + - ]: 168536 : Trace("theory::atoms") << "TheoryEngine::ensureLemmaAtoms(" << n << ", "
1505 : 84268 : << atomsTo << ")" << endl;
1506 : 84268 : AtomsCollect collectAtoms;
1507 : 84268 : NodeVisitor<AtomsCollect>::run(collectAtoms, n);
1508 : 84268 : ensureLemmaAtoms(collectAtoms.getAtoms(), atomsTo);
1509 : 84268 : }
1510 : :
1511 : 84268 : void TheoryEngine::ensureLemmaAtoms(const std::vector<TNode>& atoms,
1512 : : theory::TheoryId atomsTo)
1513 : : {
1514 [ + + ]: 171048 : for (unsigned i = 0; i < atoms.size(); ++i)
1515 : : {
1516 : : // Non-equality atoms are either owned by theory or they don't make sense
1517 [ + + ]: 86780 : if (atoms[i].getKind() != Kind::EQUAL)
1518 : : {
1519 : 71167 : continue;
1520 : : }
1521 : :
1522 : : // The equality
1523 : 82954 : Node eq = atoms[i];
1524 : : // Simple normalization to not repeat stuff
1525 [ - + ]: 82954 : if (eq[0] > eq[1])
1526 : : {
1527 : 0 : eq = eq[1].eqNode(eq[0]);
1528 : : }
1529 : :
1530 : : // Rewrite the equality
1531 : 82954 : Node eqNormalized = rewrite(atoms[i]);
1532 : :
1533 [ + - ]: 165908 : Trace("theory::atoms") << "TheoryEngine::ensureLemmaAtoms(): " << eq
1534 : 82954 : << " with nf " << eqNormalized << endl;
1535 : :
1536 : : // If the equality is a boolean constant, we send immediately
1537 [ + + ]: 82954 : if (eqNormalized.isConst())
1538 : : {
1539 [ - + ]: 2 : if (eqNormalized.getConst<bool>())
1540 : : {
1541 : 0 : assertToTheory(eq,
1542 : : eqNormalized,
1543 : : /** to */ atomsTo,
1544 : : /** Sat solver */ theory::THEORY_SAT_SOLVER);
1545 : : }
1546 : : else
1547 : : {
1548 : : // Use notEq and notEqNormalized to ensure deterministic node ID
1549 : : // assignments
1550 : 2 : Node notEq = eq.notNode();
1551 : 2 : Node notEqNormalized = eqNormalized.notNode();
1552 : 2 : assertToTheory(notEq,
1553 : : notEqNormalized,
1554 : : /** to */ atomsTo,
1555 : : /** Sat solver */ theory::THEORY_SAT_SOLVER);
1556 : 2 : }
1557 : 2 : continue;
1558 : 2 : }
1559 [ - + ]: 82952 : else if (eqNormalized.getKind() != Kind::EQUAL)
1560 : : {
1561 : 0 : Assert(eqNormalized.getKind() == Kind::SKOLEM
1562 : : || (eqNormalized.getKind() == Kind::NOT
1563 : : && eqNormalized[0].getKind() == Kind::SKOLEM));
1564 : : // this happens for Boolean term equalities V = true that are rewritten to
1565 : : // V, we should skip
1566 : : // TODO : revisit this
1567 : 0 : continue;
1568 : : }
1569 : :
1570 : : // If the normalization did the just flips, keep the flip
1571 : 82952 : if (eqNormalized[0] == eq[1] && eqNormalized[1] == eq[0])
1572 : : {
1573 : 1619 : eq = eqNormalized;
1574 : : }
1575 : :
1576 : : // Check if the equality is already known by the sat solver
1577 [ + + ]: 82952 : if (d_propEngine->isSatLiteral(eqNormalized))
1578 : : {
1579 : : bool value;
1580 [ + + ]: 69606 : if (d_propEngine->hasValue(eqNormalized, value))
1581 : : {
1582 [ + + ]: 67339 : if (value)
1583 : : {
1584 : 66534 : assertToTheory(eq, eqNormalized, atomsTo, theory::THEORY_SAT_SOLVER);
1585 : 67339 : continue;
1586 : : }
1587 : : else
1588 : : {
1589 : : // Use notEq and notEqNormalized to ensure deterministic node ID
1590 : : // assignments
1591 : 805 : Node notEq = eq.notNode();
1592 : 805 : Node notEqNormalized = eqNormalized.notNode();
1593 : 805 : assertToTheory(
1594 : : notEq, notEqNormalized, atomsTo, theory::THEORY_SAT_SOLVER);
1595 : 805 : continue;
1596 : 805 : }
1597 : : }
1598 : : }
1599 : :
1600 : : // If the theory is asking about a different form, or the form is ok but if
1601 : : // will go to a different theory then we must figure it out
1602 [ + + ][ + + ]: 15613 : if (eqNormalized != eq || d_env.theoryOf(eq) != atomsTo)
[ + + ][ + + ]
[ - - ]
1603 : : {
1604 : : // If you get eqNormalized, send atoms[i] to atomsTo
1605 : 12923 : d_atomRequests.add(eqNormalized, eq, atomsTo);
1606 : : }
1607 [ + + ][ + + ]: 150295 : }
1608 : 84268 : }
1609 : :
1610 : 911559 : void TheoryEngine::lemma(TrustNode tlemma,
1611 : : InferenceId id,
1612 : : LemmaProperty p,
1613 : : TheoryId from)
1614 : : {
1615 : : // For resource-limiting (also does a time check).
1616 : : // spendResource();
1617 [ + + ][ + - ]: 911559 : Assert(tlemma.getKind() == TrustNodeKind::LEMMA
[ - + ][ - + ]
[ - - ]
1618 : : || tlemma.getKind() == TrustNodeKind::CONFLICT);
1619 : :
1620 : : // minimize or generalize conflict
1621 [ + + ]: 911559 : if (d_cp)
1622 : : {
1623 : 135 : TrustNode tproc = d_cp->processLemma(tlemma);
1624 [ + + ]: 135 : if (!tproc.isNull())
1625 : : {
1626 : 7 : tlemma = tproc;
1627 : : }
1628 : 135 : }
1629 : :
1630 : : // get the node
1631 : 911559 : Node node = tlemma.getNode();
1632 : 911559 : Node lemma = tlemma.getProven();
1633 : :
1634 : : // must rewrite when checking here since we may have shadowing in rare cases,
1635 : : // e.g. lazy lambda lifting lemmas
1636 [ - + ][ - - ]: 1823118 : Assert(!expr::hasFreeVar(rewrite(lemma)))
1637 [ - + ][ - + ]: 911559 : << "Lemma " << lemma << " from " << from << " has a free variable";
[ - - ]
1638 : :
1639 : : // when proofs are enabled, we ensure the trust node has a generator by
1640 : : // adding a trust step to the lazy proof maintained by this class
1641 [ + + ]: 911559 : if (isProofEnabled())
1642 : : {
1643 : : // ensure proof: set THEORY_LEMMA if no generator is provided
1644 [ + + ]: 392955 : if (tlemma.getGenerator() == nullptr)
1645 : : {
1646 : : // add theory lemma step to proof
1647 : : Node tidn =
1648 : 46473 : builtin::BuiltinProofRuleChecker::mkTheoryIdNode(nodeManager(), from);
1649 : 92946 : d_lazyProof->addTrustedStep(lemma, TrustId::THEORY_LEMMA, {}, {tidn});
1650 : : // update the trust node
1651 [ + - ]: 46473 : tlemma = TrustNode::mkTrustLemma(lemma, d_lazyProof.get());
1652 : 46473 : }
1653 : : // ensure closed
1654 : 392955 : tlemma.debugCheckClosed(
1655 : : options(), "te-proof-debug", "TheoryEngine::lemma_initial");
1656 : : }
1657 : :
1658 : : // assert the lemma
1659 : 911560 : d_propEngine->assertLemma(id, tlemma, p);
1660 : :
1661 : : // If specified, we must add this lemma to the set of those that need to be
1662 : : // justified, where note we pass all auxiliary lemmas in skAsserts as well,
1663 : : // since these by extension must be justified as well.
1664 [ + + ]: 911558 : if (!d_modules.empty())
1665 : : {
1666 : 945 : std::vector<Node> skAsserts;
1667 : 945 : std::vector<Node> sks;
1668 : : Node retLemma =
1669 : 1890 : d_propEngine->getPreprocessedTerm(tlemma.getProven(), skAsserts, sks);
1670 : :
1671 : : // notify the modules of the lemma
1672 [ + + ]: 1890 : for (TheoryEngineModule* tem : d_modules)
1673 : : {
1674 : : // don't notify theory modules of their own lemmas
1675 [ + + ]: 945 : if (tem->getId() != from)
1676 : : {
1677 : 932 : tem->notifyLemma(retLemma, id, p, skAsserts, sks);
1678 : : }
1679 : : }
1680 : 945 : }
1681 : :
1682 : : // Mark that we added some lemmas
1683 : 911558 : d_lemmasAdded = true;
1684 : 911560 : }
1685 : :
1686 : 368545 : void TheoryEngine::markInConflict()
1687 : : {
1688 : : #ifdef CVC5_FOR_EACH_THEORY_STATEMENT
1689 : : #undef CVC5_FOR_EACH_THEORY_STATEMENT
1690 : : #endif
1691 : : #define CVC5_FOR_EACH_THEORY_STATEMENT(THEORY) \
1692 : : theoryOf(THEORY)->notifyInConflict();
1693 : 368545 : CVC5_FOR_EACH_THEORY;
1694 : 368545 : d_inConflict = true;
1695 : 368545 : }
1696 : :
1697 : 198211 : void TheoryEngine::conflict(TrustNode tconflict,
1698 : : InferenceId id,
1699 : : TheoryId theoryId)
1700 : : {
1701 [ - + ][ - + ]: 198211 : Assert(tconflict.getKind() == TrustNodeKind::CONFLICT);
[ - - ]
1702 : :
1703 : 198211 : TNode conflict = tconflict.getNode();
1704 [ + - ]: 396422 : Trace("theory::conflict") << "TheoryEngine::conflict(" << conflict << ", "
1705 : 198211 : << id << ", " << theoryId << ")" << endl;
1706 [ + - ]: 198211 : Trace("te-proof-debug") << "Check closed conflict" << std::endl;
1707 : : // doesn't require proof generator, yet, since THEORY_LEMMA is added below
1708 : 198211 : tconflict.debugCheckClosed(
1709 : : options(), "te-proof-debug", "TheoryEngine::conflict_initial", false);
1710 : :
1711 [ + - ]: 198211 : Trace("dtview::conflict") << ":THEORY-CONFLICT: " << conflict << std::endl;
1712 : :
1713 : : // Mark that we are in conflict
1714 : 198211 : markInConflict();
1715 : :
1716 : : // In the multiple-theories case, we need to reconstruct the conflict
1717 [ + + ]: 198211 : if (logicInfo().isSharingEnabled())
1718 : : {
1719 : : // Create the workplace for explanations
1720 : 162984 : std::vector<NodeTheoryPair> vec;
1721 : 162984 : vec.push_back(
1722 : 325968 : NodeTheoryPair(conflict, theoryId, d_propagationMapTimestamp));
1723 : :
1724 : : // Process the explanation
1725 : 162984 : TrustNode tncExp = getExplanation(vec);
1726 : 162984 : Node fullConflict = tncExp.getNode();
1727 : :
1728 [ + + ]: 162984 : if (isProofEnabled())
1729 : : {
1730 [ + - ]: 139884 : Trace("te-proof-debug")
1731 : 69942 : << "Check closed conflict explained with sharing" << std::endl;
1732 : 69942 : tncExp.debugCheckClosed(options(),
1733 : : "te-proof-debug",
1734 : : "TheoryEngine::conflict_explained_sharing");
1735 [ + - ]: 69942 : Trace("te-proof-debug") << "Process conflict: " << conflict << std::endl;
1736 [ + - ]: 139884 : Trace("te-proof-debug") << "Conflict " << tconflict << " from "
1737 [ - + ][ - - ]: 69942 : << tconflict.identifyGenerator() << std::endl;
1738 [ + - ]: 139884 : Trace("te-proof-debug") << "Explanation " << tncExp << " from "
1739 [ - + ][ - - ]: 69942 : << tncExp.identifyGenerator() << std::endl;
1740 [ - + ][ - + ]: 69942 : Assert(d_lazyProof != nullptr);
[ - - ]
1741 [ + + ]: 69942 : if (tconflict.getGenerator() != nullptr)
1742 : : {
1743 : 68620 : d_lazyProof->addLazyStep(tconflict.getProven(),
1744 : : tconflict.getGenerator());
1745 : : }
1746 : : else
1747 : : {
1748 : : // add theory lemma step
1749 : : Node tidn = builtin::BuiltinProofRuleChecker::mkTheoryIdNode(
1750 : 1322 : nodeManager(), theoryId);
1751 : 1322 : Node conf = tconflict.getProven();
1752 : 2644 : d_lazyProof->addTrustedStep(conf, TrustId::THEORY_LEMMA, {}, {tidn});
1753 : 1322 : }
1754 : : // store the explicit step, which should come from a different
1755 : : // generator, e.g. d_tepg.
1756 : 69942 : Node proven = tncExp.getProven();
1757 [ + - ][ - + ]: 69942 : Assert(tncExp.getGenerator() != d_lazyProof.get());
[ - + ][ - - ]
1758 [ + - ][ - + ]: 139884 : Trace("te-proof-debug") << "add lazy step " << tncExp.identifyGenerator()
[ - - ]
1759 : 69942 : << " for " << proven << std::endl;
1760 : 69942 : d_lazyProof->addLazyStep(proven, tncExp.getGenerator());
1761 [ + - ]: 69942 : pfgEnsureClosed(options(),
1762 : : proven,
1763 : 69942 : d_lazyProof.get(),
1764 : : "te-proof-debug",
1765 : : "TheoryEngine::conflict_during");
1766 : 69942 : Node fullConflictNeg = fullConflict.notNode();
1767 : 69942 : std::vector<Node> children;
1768 : 69942 : children.push_back(proven);
1769 : 69942 : std::vector<Node> args;
1770 : 69942 : args.push_back(fullConflictNeg);
1771 [ + + ]: 69942 : if (conflict == d_false)
1772 : : {
1773 [ - + ][ - + ]: 598 : AlwaysAssert(proven == fullConflictNeg);
[ - - ]
1774 : : }
1775 : : else
1776 : : {
1777 [ + + ]: 69344 : if (!CDProof::isSame(fullConflict, conflict))
1778 : : {
1779 : : // ------------------------- explained
1780 : : // fullConflict => conflict
1781 : : // ------------------------- IMPLIES_ELIM ---------- from theory
1782 : : // ~fullConflict V conflict ~conflict
1783 : : // -------------------------------------------------- RESOLUTION
1784 : : // ~fullConflict
1785 : : Node provenOr =
1786 : 131072 : nodeManager()->mkNode(Kind::OR, proven[0].notNode(), proven[1]);
1787 : 131072 : d_lazyProof->addStep(provenOr, ProofRule::IMPLIES_ELIM, {proven}, {});
1788 : 393216 : d_lazyProof->addStep(fullConflictNeg,
1789 : : ProofRule::RESOLUTION,
1790 : : {provenOr, conflict.notNode()},
1791 : 65536 : {d_true, conflict});
1792 : 65536 : }
1793 : : }
1794 : 69942 : }
1795 : : // pass the processed trust node
1796 : : TrustNode tconf =
1797 [ + + ]: 162984 : TrustNode::mkTrustConflict(fullConflict, d_lazyProof.get());
1798 [ + - ]: 325968 : Trace("theory::conflict")
1799 : 0 : << "TheoryEngine::conflict(" << conflict << ", " << theoryId
1800 : 162984 : << "): full = " << fullConflict << endl;
1801 [ - + ][ - + ]: 162984 : Assert(properConflict(fullConflict));
[ - - ]
1802 [ + - ]: 325968 : Trace("te-proof-debug")
1803 : 162984 : << "Check closed conflict with sharing" << std::endl;
1804 [ + + ]: 162984 : if (isProofEnabled())
1805 : : {
1806 : 69942 : tconf.debugCheckClosed(
1807 : : options(), "te-proof-debug", "TheoryEngine::conflict:sharing");
1808 : : }
1809 : 162984 : lemma(tconf, id, LemmaProperty::NONE, theoryId);
1810 : 162984 : }
1811 : : else
1812 : : {
1813 : : // When only one theory, the conflict should need no processing
1814 [ - + ][ - + ]: 35227 : Assert(properConflict(conflict));
[ - - ]
1815 : : // pass the trust node that was sent from the theory
1816 : 35227 : lemma(tconflict, id, LemmaProperty::NONE, theoryId);
1817 : : }
1818 : 198211 : }
1819 : :
1820 : 0 : void TheoryEngine::setModelUnsound(theory::IncompleteId id)
1821 : : {
1822 : 0 : setModelUnsound(TheoryId::THEORY_NONE, id);
1823 : 0 : }
1824 : :
1825 : 43 : void TheoryEngine::setRefutationUnsound(theory::IncompleteId id)
1826 : : {
1827 : 43 : setRefutationUnsound(TheoryId::THEORY_NONE, id);
1828 : 43 : }
1829 : :
1830 : 3421 : void TheoryEngine::setModelUnsound(theory::TheoryId theory,
1831 : : theory::IncompleteId id)
1832 : : {
1833 : 3421 : d_modelUnsound = true;
1834 : 3421 : d_modelUnsoundTheory = theory;
1835 : 3421 : d_modelUnsoundId = id;
1836 : 3421 : }
1837 : :
1838 : 176 : void TheoryEngine::setRefutationUnsound(theory::TheoryId theory,
1839 : : theory::IncompleteId id)
1840 : : {
1841 : 176 : d_refutationUnsound = true;
1842 : 176 : d_refutationUnsoundTheory = theory;
1843 : 176 : d_refutationUnsoundId = id;
1844 : 176 : }
1845 : :
1846 : 329287 : TrustNode TheoryEngine::getExplanation(
1847 : : std::vector<NodeTheoryPair>& explanationVector)
1848 : : {
1849 [ - + ][ - + ]: 329287 : Assert(explanationVector.size() == 1);
[ - - ]
1850 : 329287 : Node conclusion = explanationVector[0].d_node;
1851 : : // if the theory explains using the central equality engine, we always start
1852 : : // with THEORY_BUILTIN.
1853 : 658574 : explanationVector[0].d_theory =
1854 : 329287 : theoryExpPropagation(explanationVector[0].d_theory);
1855 : 329287 : std::shared_ptr<LazyCDProof> lcp;
1856 [ + + ]: 329287 : if (isProofEnabled())
1857 : : {
1858 [ + - ]: 241032 : Trace("te-proof-exp") << "=== TheoryEngine::getExplanation " << conclusion
1859 : 120516 : << std::endl;
1860 : : // We do not use auto-symmetry in this proof, since in very rare cases, it
1861 : : // is possible that the proof of explanations is cyclic when considering
1862 : : // (dis)equalities modulo symmetry, where such a proof looks like:
1863 : : // x = y
1864 : : // -----
1865 : : // A ...
1866 : : // ----------
1867 : : // y = x
1868 : : // Notice that this complication arises since propagations consider
1869 : : // equalities that are not in rewritten form. This complication would not
1870 : : // exist otherwise. It is the shared term database that introduces these
1871 : : // unrewritten equalities; it must do so since theory combination requires
1872 : : // communicating arrangements between shared terms, and the rewriter
1873 : : // for arithmetic equalities does not preserve terms, e.g. x=y may become
1874 : : // x+-1*y=0.
1875 : 241032 : lcp.reset(new LazyCDProof(d_env,
1876 : : nullptr,
1877 : : nullptr,
1878 : : "TheoryEngine::LazyCDProof::getExplanation",
1879 : 120516 : false));
1880 : : }
1881 : 329287 : unsigned i = 0; // Index of the current literal we are processing
1882 : :
1883 : 329287 : std::unique_ptr<std::set<Node>> inputAssertions = nullptr;
1884 : : // the overall explanation
1885 : 329287 : std::set<TNode> exp;
1886 : : // vector of trust nodes to explain at the end
1887 : 329287 : std::vector<std::pair<TheoryId, TrustNode>> texplains;
1888 : : // cache of nodes we have already explained by some theory
1889 : 329287 : std::unordered_map<Node, size_t> cache;
1890 : :
1891 [ + + ]: 8539280 : while (i < explanationVector.size())
1892 : : {
1893 : : // Get the current literal to explain
1894 : 8209993 : NodeTheoryPair toExplain = explanationVector[i];
1895 : :
1896 [ + - ]: 16419986 : Trace("theory::explain")
1897 : 0 : << "[i=" << i << "] TheoryEngine::explain(): processing ["
1898 : 0 : << toExplain.d_timestamp << "] " << toExplain.d_node << " sent from "
1899 : 8209993 : << toExplain.d_theory << endl;
1900 : :
1901 : 8209993 : if (cache.find(toExplain.d_node) != cache.end()
1902 [ + + ][ + + ]: 8209993 : && cache[toExplain.d_node] < toExplain.d_timestamp)
[ + + ]
1903 : : {
1904 : 258868 : ++i;
1905 : 258868 : continue;
1906 : : }
1907 : 7951125 : cache[toExplain.d_node] = toExplain.d_timestamp;
1908 : :
1909 : : // If a true constant or a negation of a false constant we can ignore it
1910 [ + + ]: 30947 : if ((toExplain.d_node.isConst() && toExplain.d_node.getConst<bool>())
1911 [ + + ][ + + ]: 8658762 : || (toExplain.d_node.getKind() == Kind::NOT
1912 [ - + ][ + + ]: 8627815 : && toExplain.d_node[0].isConst()
[ - - ]
1913 [ - - ][ - + ]: 7951125 : && !toExplain.d_node[0].getConst<bool>()))
[ + + ][ - - ]
1914 : : {
1915 : 29910 : ++i;
1916 : : // if we are building a proof
1917 [ + + ]: 29910 : if (lcp != nullptr)
1918 : : {
1919 [ + - ]: 6422 : Trace("te-proof-exp")
1920 : 3211 : << "- explain " << toExplain.d_node << " trivially..." << std::endl;
1921 : : // ------------------MACRO_SR_PRED_INTRO
1922 : : // toExplain.d_node
1923 : 3211 : std::vector<Node> children;
1924 : 3211 : std::vector<Node> args;
1925 : 3211 : args.push_back(toExplain.d_node);
1926 : 3211 : lcp->addStep(
1927 : : toExplain.d_node, ProofRule::MACRO_SR_PRED_INTRO, children, args);
1928 : 3211 : }
1929 : 29910 : continue;
1930 : 29910 : }
1931 : :
1932 : : // If from the SAT solver, keep it
1933 [ + + ]: 7921215 : if (toExplain.d_theory == THEORY_SAT_SOLVER)
1934 : : {
1935 [ + - ]: 5816036 : Trace("theory::explain")
1936 : 2908018 : << "\tLiteral came from THEORY_SAT_SOLVER. Keeping it." << endl;
1937 : 2908018 : exp.insert(explanationVector[i++].d_node);
1938 : : // it will be a free assumption in the proof
1939 [ + - ]: 2908018 : Trace("te-proof-exp") << "- keep " << toExplain.d_node << std::endl;
1940 : 2908018 : continue;
1941 : : }
1942 : :
1943 : : // If an and, expand it
1944 [ + + ]: 5013197 : if (toExplain.d_node.getKind() == Kind::AND)
1945 : : {
1946 [ + - ]: 1366204 : Trace("theory::explain")
1947 : 0 : << "TheoryEngine::explain(): expanding " << toExplain.d_node
1948 : 683102 : << " got from " << toExplain.d_theory << endl;
1949 : 683102 : size_t nchild = toExplain.d_node.getNumChildren();
1950 [ + + ]: 4233713 : for (size_t k = 0; k < nchild; ++k)
1951 : : {
1952 : : NodeTheoryPair newExplain(
1953 : 7101222 : toExplain.d_node[k], toExplain.d_theory, toExplain.d_timestamp);
1954 : 3550611 : explanationVector.push_back(newExplain);
1955 : 3550611 : }
1956 [ + + ]: 683102 : if (lcp != nullptr)
1957 : : {
1958 [ + - ]: 536906 : Trace("te-proof-exp")
1959 : 268453 : << "- AND expand " << toExplain.d_node << std::endl;
1960 : : // delay explanation, use a dummy trust node
1961 : : TrustNode tnAndExp = TrustNode::mkTrustPropExp(
1962 : 536906 : toExplain.d_node, toExplain.d_node, nullptr);
1963 : 268453 : texplains.push_back(
1964 : 536906 : std::pair<TheoryId, TrustNode>(THEORY_LAST, tnAndExp));
1965 : 268453 : }
1966 : 683102 : ++i;
1967 : 683102 : continue;
1968 : 683102 : }
1969 : :
1970 : : // See if it was sent to the theory by another theory
1971 : 4330095 : PropagationMap::const_iterator find = d_propagationMap.find(toExplain);
1972 [ + + ]: 4330095 : if (find != d_propagationMap.end())
1973 : : {
1974 [ + - ]: 8216314 : Trace("theory::explain")
1975 : 0 : << "\tTerm was propagated by another theory (theory = "
1976 [ - + ][ - - ]: 4108157 : << getTheoryString((*find).second.d_theory) << ")" << std::endl;
1977 : : // There is some propagation, check if its a timely one
1978 [ + + ]: 4108157 : if ((*find).second.d_timestamp < toExplain.d_timestamp)
1979 : : {
1980 [ + - ]: 7373300 : Trace("theory::explain")
1981 : 0 : << "\tRelevant timetsamp, pushing " << (*find).second.d_node
1982 : 3686650 : << "to index = " << explanationVector.size() << std::endl;
1983 : 3686650 : explanationVector.push_back((*find).second);
1984 : 3686650 : ++i;
1985 : :
1986 [ + + ]: 3686650 : if (lcp != nullptr)
1987 : : {
1988 [ + + ]: 1465433 : if (toExplain.d_node != (*find).second.d_node)
1989 : : {
1990 [ + - ]: 22714 : Trace("te-proof-exp")
1991 : 0 : << "- t-explained cached: " << toExplain.d_node << " by "
1992 : 11357 : << (*find).second.d_node << std::endl;
1993 : : // delay explanation, use a dummy trust node that says that
1994 : : // (*find).second.d_node explains toExplain.d_node.
1995 : : TrustNode tnRewExp = TrustNode::mkTrustPropExp(
1996 : 22714 : toExplain.d_node, (*find).second.d_node, nullptr);
1997 : 11357 : texplains.push_back(
1998 : 22714 : std::pair<TheoryId, TrustNode>(THEORY_LAST, tnRewExp));
1999 : 11357 : }
2000 : : }
2001 : 3686650 : continue;
2002 : 3686650 : }
2003 : : }
2004 : : // It was produced by the theory, so ask for an explanation
2005 : : TrustNode texplanation =
2006 : 643445 : d_sharedSolver->explain(toExplain.d_node, toExplain.d_theory);
2007 [ + + ]: 643445 : if (lcp != nullptr)
2008 : : {
2009 : 255067 : texplanation.debugCheckClosed(
2010 : : options(), "te-proof-exp", "texplanation", false);
2011 [ + - ]: 510134 : Trace("te-proof-exp")
2012 : 0 : << "- t-explained[" << toExplain.d_theory << "]: " << toExplain.d_node
2013 [ - + ][ - - ]: 255067 : << " by " << texplanation.getNode() << std::endl;
2014 : : // should prove the propagation we asked for
2015 : 255067 : Assert(texplanation.getKind() == TrustNodeKind::PROP_EXP
2016 : : && texplanation.getProven()[1] == toExplain.d_node);
2017 : : // We add it to the list of theory explanations, to be processed at
2018 : : // the end of this method. We wait to explain here because it may
2019 : : // be that a later explanation may preempt the need for proving this
2020 : : // step. For instance, if the conclusion lit is later added as an
2021 : : // assumption in the final explanation. This avoids cyclic proofs.
2022 : 255067 : texplains.push_back(
2023 : 510134 : std::pair<TheoryId, TrustNode>(toExplain.d_theory, texplanation));
2024 : : }
2025 : 643445 : Node explanation = texplanation.getNode();
2026 : :
2027 [ + - ]: 1286890 : Trace("theory::explain")
2028 : 0 : << "TheoryEngine::explain(): got explanation " << explanation
2029 : 643445 : << " got from " << toExplain.d_theory << endl;
2030 : 643445 : Assert(explanation != toExplain.d_node)
2031 : : << "wasn't sent to you, so why are you explaining it trivially, for "
2032 : 0 : "fact "
2033 : : << explanation;
2034 : : // Mark the explanation
2035 : : NodeTheoryPair newExplain(
2036 : 643445 : explanation, toExplain.d_theory, toExplain.d_timestamp);
2037 : 643445 : explanationVector.push_back(newExplain);
2038 : :
2039 : 643445 : ++i;
2040 [ + + ]: 8209993 : }
2041 : :
2042 : : // make the explanation node
2043 : 329287 : Node expNode;
2044 [ + + ]: 329287 : if (exp.size() == 0)
2045 : : {
2046 : : // Normalize to true
2047 : 72 : expNode = nodeManager()->mkConst<bool>(true);
2048 : : }
2049 [ + + ]: 329215 : else if (exp.size() == 1)
2050 : : {
2051 : : // All the same, or just one
2052 : 12249 : expNode = *exp.begin();
2053 : : }
2054 : : else
2055 : : {
2056 : 316966 : NodeBuilder conjunction(nodeManager(), Kind::AND);
2057 : 316966 : std::set<TNode>::const_iterator it = exp.begin();
2058 : 316966 : std::set<TNode>::const_iterator it_end = exp.end();
2059 [ + + ]: 3132385 : while (it != it_end)
2060 : : {
2061 : 2815419 : conjunction << *it;
2062 : 2815419 : ++it;
2063 : : }
2064 : 316966 : expNode = conjunction;
2065 : 316966 : }
2066 : : // if we are building a proof, go back through the explanations and
2067 : : // build the proof
2068 [ + + ]: 329287 : if (lcp != nullptr)
2069 : : {
2070 [ - + ]: 120516 : if (TraceIsOn("te-proof-exp"))
2071 : : {
2072 [ - - ]: 0 : Trace("te-proof-exp") << "Explanation is:" << std::endl;
2073 [ - - ]: 0 : for (TNode e : exp)
2074 : : {
2075 [ - - ]: 0 : Trace("te-proof-exp") << " " << e << std::endl;
2076 : 0 : }
2077 [ - - ]: 0 : Trace("te-proof-exp") << "=== Replay explanations..." << std::endl;
2078 : : }
2079 : : // Now, go back and add the necessary steps of theory explanations, i.e.
2080 : : // add those that prove things that aren't in the final explanation. We
2081 : : // iterate in reverse order so that most recent steps take priority. This
2082 : : // avoids cyclic proofs in the lazy proof we are building (lcp).
2083 : 120516 : for (std::vector<std::pair<TheoryId, TrustNode>>::reverse_iterator
2084 : 120516 : it = texplains.rbegin(),
2085 : 120516 : itEnd = texplains.rend();
2086 [ + + ]: 655393 : it != itEnd;
2087 : 534877 : ++it)
2088 : : {
2089 : 534877 : TrustNode trn = it->second;
2090 [ - + ][ - + ]: 534877 : Assert(trn.getKind() == TrustNodeKind::PROP_EXP);
[ - - ]
2091 : 534877 : Node proven = trn.getProven();
2092 [ - + ][ - + ]: 534877 : Assert(proven.getKind() == Kind::IMPLIES);
[ - - ]
2093 : 534877 : Node tConc = proven[1];
2094 [ + - ]: 534877 : Trace("te-proof-exp") << "- Process " << trn << std::endl;
2095 [ + + ]: 534877 : if (exp.find(tConc) != exp.end())
2096 : : {
2097 : : // already added to proof
2098 [ + - ]: 20249 : Trace("te-proof-exp") << "...already added" << std::endl;
2099 : 20249 : continue;
2100 : : }
2101 : : // remember that we've explained this formula, to avoid cycles in lcp
2102 : 514628 : exp.insert(tConc);
2103 : 514628 : TheoryId ttid = it->first;
2104 : 514628 : Node tExp = proven[0];
2105 [ + + ]: 514628 : if (ttid == THEORY_LAST)
2106 : : {
2107 [ + + ]: 269193 : if (tConc == tExp)
2108 : : {
2109 : : // dummy trust node, do AND expansion
2110 [ - + ][ - + ]: 261424 : Assert(tConc.getKind() == Kind::AND);
[ - - ]
2111 : : // tConc[0] ... tConc[n]
2112 : : // ---------------------- AND_INTRO
2113 : : // tConc
2114 : 261424 : std::vector<Node> pfChildren;
2115 : 261424 : pfChildren.insert(pfChildren.end(), tConc.begin(), tConc.end());
2116 : 261424 : lcp->addStep(tConc, ProofRule::AND_INTRO, pfChildren, {});
2117 [ + - ]: 261424 : Trace("te-proof-exp") << "...via AND_INTRO" << std::endl;
2118 : 261424 : continue;
2119 : 261424 : }
2120 : : // otherwise should hold by rewriting
2121 [ - + ][ - + ]: 38845 : AssertEqual(rewrite(tConc), rewrite(tExp));
[ - - ]
2122 : : // tExp
2123 : : // ---- MACRO_SR_PRED_TRANSFORM
2124 : : // tConc
2125 : 23307 : lcp->addStep(
2126 : : tConc, ProofRule::MACRO_SR_PRED_TRANSFORM, {tExp}, {tConc});
2127 [ + - ]: 7769 : Trace("te-proof-exp") << "...via MACRO_SR_PRED_TRANSFORM" << std::endl;
2128 : 7769 : continue;
2129 : 7769 : }
2130 [ - + ]: 245435 : if (tExp == tConc)
2131 : : {
2132 : : // trivial
2133 [ - - ]: 0 : Trace("te-proof-exp") << "...trivial" << std::endl;
2134 : 0 : continue;
2135 : : }
2136 : : // ------------- Via theory
2137 : : // tExp tExp => tConc
2138 : : // ---------------------------------MODUS_PONENS
2139 : : // tConc
2140 [ + - ]: 245435 : if (trn.getGenerator() != nullptr)
2141 : : {
2142 [ + - ]: 245435 : Trace("te-proof-exp") << "...via theory generator" << std::endl;
2143 : 245435 : lcp->addLazyStep(proven, trn.getGenerator());
2144 : : }
2145 : : else
2146 : : {
2147 [ - - ]: 0 : Trace("te-proof-exp") << "...via trust THEORY_LEMMA" << std::endl;
2148 : : // otherwise, trusted theory lemma
2149 : : Node tidn = builtin::BuiltinProofRuleChecker::mkTheoryIdNode(
2150 : 0 : nodeManager(), ttid);
2151 : 0 : lcp->addTrustedStep(proven, TrustId::THEORY_LEMMA, {}, {tidn});
2152 : 0 : }
2153 : 245435 : std::vector<Node> pfChildren;
2154 : 245435 : pfChildren.push_back(trn.getNode());
2155 : 245435 : pfChildren.push_back(proven);
2156 : 245435 : lcp->addStep(tConc, ProofRule::MODUS_PONENS, pfChildren, {});
2157 [ + + ][ + + ]: 1382954 : }
[ + + ][ + + ]
2158 : : // If we don't have a step and the conclusion is not part of the
2159 : : // explanation (for unit T-conflicts), it must be by symmetry. We must do
2160 : : // this manually since lcp does not have auto-symmetry enabled due to the
2161 : : // complication mentioned above.
2162 : 120516 : if (!lcp->hasStep(conclusion) && exp.find(conclusion) == exp.end())
2163 : : {
2164 : 0 : Node sconc = CDProof::getSymmFact(conclusion);
2165 [ - - ]: 0 : if (!sconc.isNull())
2166 : : {
2167 : 0 : lcp->addStep(conclusion, ProofRule::SYMM, {sconc}, {});
2168 : : }
2169 : : else
2170 : : {
2171 : 0 : DebugUnhandled()
2172 : 0 : << "TheoryEngine::getExplanation: no step found for conclusion "
2173 : : << conclusion;
2174 : : }
2175 : 0 : }
2176 : : // store in the proof generator
2177 : 241032 : TrustNode trn = d_tepg->mkTrustExplain(conclusion, expNode, lcp);
2178 : : // return the trust node
2179 : 120516 : return trn;
2180 : 120516 : }
2181 : :
2182 : 208771 : return TrustNode::mkTrustPropExp(conclusion, expNode, nullptr);
2183 : 329287 : }
2184 : :
2185 : 6419935 : bool TheoryEngine::isProofEnabled() const
2186 : : {
2187 : 6419935 : return d_env.isTheoryProofProducing();
2188 : : }
2189 : :
2190 : 2898 : void TheoryEngine::checkTheoryAssertionsWithModel(bool hardFailure)
2191 : : {
2192 : 2898 : bool hasFailure = false;
2193 : 2898 : std::stringstream serror;
2194 : : // If possible, get the list of relevant assertions. Those that are not
2195 : : // relevant will be skipped.
2196 : 2898 : std::unordered_set<TNode> relevantAssertions;
2197 : 2898 : bool hasRelevantAssertions = false;
2198 [ + + ]: 2898 : if (d_relManager != nullptr)
2199 : : {
2200 : : relevantAssertions =
2201 : 11 : d_relManager->getRelevantAssertions(hasRelevantAssertions);
2202 : : }
2203 [ + + ]: 43470 : for (TheoryId theoryId = THEORY_FIRST; theoryId < THEORY_LAST; ++theoryId)
2204 : : {
2205 : 40572 : Theory* theory = d_theoryTable[theoryId];
2206 [ + - ][ + + ]: 40572 : if (theory && isTheoryEnabled(theoryId))
[ + + ]
2207 : : {
2208 : 21238 : for (context::CDList<Assertion>::const_iterator
2209 : 21238 : it = theory->facts_begin(),
2210 : 21238 : it_end = theory->facts_end();
2211 [ + + ]: 157779 : it != it_end;
2212 : 136541 : ++it)
2213 : : {
2214 : 136541 : Node assertion = (*it).d_assertion;
2215 : 136776 : if (hasRelevantAssertions
2216 [ + + ][ + + ]: 136541 : && relevantAssertions.find(assertion) == relevantAssertions.end())
[ + + ][ + + ]
[ - - ]
2217 : : {
2218 : : // not relevant, skip
2219 : 235 : continue;
2220 : : }
2221 : 136306 : Node val = d_tc->getModel()->getValue(assertion);
2222 [ + + ]: 136306 : if (val != d_true)
2223 : : {
2224 : 357 : std::stringstream ss;
2225 [ + + ]: 930 : for (Node child : assertion)
2226 : : {
2227 : 573 : Node value = d_tc->getModel()->getValue(child);
2228 : 573 : ss << "getValue(" << child << "): " << value << std::endl;
2229 : 573 : }
2230 : 357 : ss << " " << theoryId << " has an asserted fact that";
2231 [ - + ]: 357 : if (val == d_false)
2232 : : {
2233 : 0 : ss << " the model doesn't satisfy." << std::endl;
2234 : : }
2235 : : else
2236 : : {
2237 : 357 : ss << " the model may not satisfy." << std::endl;
2238 : : }
2239 : 357 : ss << "The fact: " << assertion << std::endl
2240 : 357 : << "Model value: " << val << std::endl;
2241 [ + - ]: 357 : if (hardFailure)
2242 : : {
2243 [ - + ]: 357 : if (val == d_false)
2244 : : {
2245 : : // Always an error if it is false
2246 : 0 : hasFailure = true;
2247 : 0 : serror << ss.str();
2248 : : }
2249 : : else
2250 : : {
2251 : : // Otherwise just a warning. Notice this case may happen for
2252 : : // assertions with unevaluable operators, e.g. transcendental
2253 : : // functions. It also may happen for separation logic, where
2254 : : // check-model support is limited.
2255 : 357 : warning() << ss.str();
2256 : : }
2257 : : }
2258 : 357 : }
2259 [ + + ]: 136541 : }
2260 : : }
2261 : : }
2262 [ - + ]: 2898 : if (hasFailure)
2263 : : {
2264 : 0 : InternalError() << serror.str();
2265 : : }
2266 : 2898 : }
2267 : :
2268 : 11517 : std::pair<bool, Node> TheoryEngine::entailmentCheck(options::TheoryOfMode mode,
2269 : : TNode lit)
2270 : : {
2271 [ + + ]: 11517 : TNode atom = (lit.getKind() == Kind::NOT) ? lit[0] : lit;
2272 [ + + ]: 23030 : if (atom.getKind() == Kind::AND || atom.getKind() == Kind::OR
2273 [ + + ][ + + ]: 23030 : || atom.getKind() == Kind::IMPLIES)
[ + + ]
2274 : : {
2275 : : // Boolean connective, recurse
2276 : 18 : std::vector<Node> children;
2277 : 18 : bool pol = (lit.getKind() != Kind::NOT);
2278 : 18 : bool is_conjunction = pol == (lit.getKind() == Kind::AND);
2279 [ + - ]: 18 : for (unsigned i = 0; i < atom.getNumChildren(); i++)
2280 : : {
2281 : 18 : Node ch = atom[i];
2282 [ - + ][ - - ]: 18 : if (pol == (lit.getKind() == Kind::IMPLIES && i == 0))
[ + - ]
2283 : : {
2284 : 18 : ch = atom[i].negate();
2285 : : }
2286 : 18 : std::pair<bool, Node> chres = entailmentCheck(mode, ch);
2287 [ - + ]: 18 : if (chres.first)
2288 : : {
2289 [ - - ]: 0 : if (!is_conjunction)
2290 : : {
2291 : 0 : return chres;
2292 : : }
2293 : : else
2294 : : {
2295 : 0 : children.push_back(chres.second);
2296 : : }
2297 : : }
2298 [ + - ][ + - ]: 18 : else if (!chres.first && is_conjunction)
2299 : : {
2300 : 18 : return std::pair<bool, Node>(false, Node::null());
2301 : : }
2302 [ - + ][ - + ]: 36 : }
2303 [ - - ]: 0 : if (is_conjunction)
2304 : : {
2305 : : return std::pair<bool, Node>(true,
2306 : 0 : nodeManager()->mkNode(Kind::AND, children));
2307 : : }
2308 : : else
2309 : : {
2310 : 0 : return std::pair<bool, Node>(false, Node::null());
2311 : : }
2312 : 18 : }
2313 : 34497 : else if (atom.getKind() == Kind::ITE
2314 : 11499 : || (atom.getKind() == Kind::EQUAL && atom[0].getType().isBoolean()))
2315 : : {
2316 : 0 : bool pol = (lit.getKind() != Kind::NOT);
2317 [ - - ]: 0 : for (unsigned r = 0; r < 2; r++)
2318 : : {
2319 : 0 : Node ch = atom[0];
2320 [ - - ]: 0 : if (r == 1)
2321 : : {
2322 : 0 : ch = ch.negate();
2323 : : }
2324 : 0 : std::pair<bool, Node> chres = entailmentCheck(mode, ch);
2325 [ - - ]: 0 : if (chres.first)
2326 : : {
2327 [ - - ]: 0 : Node ch2 = atom[atom.getKind() == Kind::ITE ? r + 1 : 1];
2328 : 0 : if (pol == (atom.getKind() == Kind::ITE ? true : r == 1))
2329 : : {
2330 : 0 : ch2 = ch2.negate();
2331 : : }
2332 : 0 : std::pair<bool, Node> chres2 = entailmentCheck(mode, ch2);
2333 [ - - ]: 0 : if (chres2.first)
2334 : : {
2335 : : return std::pair<bool, Node>(
2336 : : true,
2337 : 0 : NodeManager::mkNode(Kind::AND, chres.second, chres2.second));
2338 : : }
2339 : : else
2340 : : {
2341 : 0 : break;
2342 : : }
2343 [ - - ][ - - ]: 0 : }
2344 [ - - ][ - - ]: 0 : }
[ - - ]
2345 : 0 : return std::pair<bool, Node>(false, Node::null());
2346 : : }
2347 : : else
2348 : : {
2349 : : // it is a theory atom
2350 : 11499 : theory::TheoryId tid = Theory::theoryOf(atom, mode);
2351 : 11499 : theory::Theory* th = theoryOf(tid);
2352 : :
2353 [ - + ][ - + ]: 11499 : Assert(th != nullptr);
[ - - ]
2354 [ + - ]: 11499 : Trace("theory-engine-entc") << "Entailment check : " << lit << std::endl;
2355 : :
2356 : 11499 : std::pair<bool, Node> chres = th->entailmentCheck(lit);
2357 : 11499 : return chres;
2358 : 11499 : }
2359 : 11517 : }
2360 : :
2361 : 22369364 : void TheoryEngine::spendResource(Resource r)
2362 : : {
2363 : 22369364 : d_env.getResourceManager()->spendResource(r);
2364 : 22369364 : }
2365 : :
2366 : 20031 : void TheoryEngine::initializeProofChecker(ProofChecker* pc)
2367 : : {
2368 [ + + ]: 300465 : for (theory::TheoryId id = theory::THEORY_FIRST; id < theory::THEORY_LAST;
2369 : 280434 : ++id)
2370 : : {
2371 : 280434 : ProofRuleChecker* prc = d_theoryTable[id]->getProofChecker();
2372 [ + + ]: 280434 : if (prc)
2373 : : {
2374 : 200310 : prc->registerTo(pc);
2375 : : }
2376 : : }
2377 : 20031 : }
2378 : :
2379 : 719114 : theory::Rewriter* TheoryEngine::getRewriter() { return d_env.getRewriter(); }
2380 : :
2381 : : } // namespace cvc5::internal
|