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