1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Andrew Reynolds, Dejan Jovanovic, Morgan Deters |
4 |
|
* |
5 |
|
* This file is part of the cvc5 project. |
6 |
|
* |
7 |
|
* Copyright (c) 2009-2021 by the authors listed in the file AUTHORS |
8 |
|
* in the top-level source directory and their institutional affiliations. |
9 |
|
* All rights reserved. See the file COPYING in the top-level source |
10 |
|
* directory for licensing information. |
11 |
|
* **************************************************************************** |
12 |
|
* |
13 |
|
* 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/quantifiers_options.h" |
26 |
|
#include "options/smt_options.h" |
27 |
|
#include "options/theory_options.h" |
28 |
|
#include "printer/printer.h" |
29 |
|
#include "proof/lazy_proof.h" |
30 |
|
#include "proof/proof_checker.h" |
31 |
|
#include "proof/proof_ensure_closed.h" |
32 |
|
#include "prop/prop_engine.h" |
33 |
|
#include "smt/dump.h" |
34 |
|
#include "smt/env.h" |
35 |
|
#include "smt/logic_exception.h" |
36 |
|
#include "smt/output_manager.h" |
37 |
|
#include "theory/combination_care_graph.h" |
38 |
|
#include "theory/decision_manager.h" |
39 |
|
#include "theory/quantifiers/first_order_model.h" |
40 |
|
#include "theory/quantifiers_engine.h" |
41 |
|
#include "theory/relevance_manager.h" |
42 |
|
#include "theory/rewriter.h" |
43 |
|
#include "theory/shared_solver.h" |
44 |
|
#include "theory/theory.h" |
45 |
|
#include "theory/theory_engine_proof_generator.h" |
46 |
|
#include "theory/theory_id.h" |
47 |
|
#include "theory/theory_model.h" |
48 |
|
#include "theory/theory_traits.h" |
49 |
|
#include "theory/uf/equality_engine.h" |
50 |
|
#include "util/resource_manager.h" |
51 |
|
|
52 |
|
using namespace std; |
53 |
|
|
54 |
|
using namespace cvc5::theory; |
55 |
|
|
56 |
|
namespace cvc5 { |
57 |
|
|
58 |
|
/* -------------------------------------------------------------------------- */ |
59 |
|
|
60 |
|
namespace theory { |
61 |
|
|
62 |
|
/** |
63 |
|
* IMPORTANT: The order of the theories is important. For example, strings |
64 |
|
* depends on arith, quantifiers needs to come as the very last. |
65 |
|
* Do not change this order. |
66 |
|
*/ |
67 |
|
|
68 |
|
#define CVC5_FOR_EACH_THEORY \ |
69 |
|
CVC5_FOR_EACH_THEORY_STATEMENT(cvc5::theory::THEORY_BUILTIN) \ |
70 |
|
CVC5_FOR_EACH_THEORY_STATEMENT(cvc5::theory::THEORY_BOOL) \ |
71 |
|
CVC5_FOR_EACH_THEORY_STATEMENT(cvc5::theory::THEORY_UF) \ |
72 |
|
CVC5_FOR_EACH_THEORY_STATEMENT(cvc5::theory::THEORY_ARITH) \ |
73 |
|
CVC5_FOR_EACH_THEORY_STATEMENT(cvc5::theory::THEORY_BV) \ |
74 |
|
CVC5_FOR_EACH_THEORY_STATEMENT(cvc5::theory::THEORY_FP) \ |
75 |
|
CVC5_FOR_EACH_THEORY_STATEMENT(cvc5::theory::THEORY_ARRAYS) \ |
76 |
|
CVC5_FOR_EACH_THEORY_STATEMENT(cvc5::theory::THEORY_DATATYPES) \ |
77 |
|
CVC5_FOR_EACH_THEORY_STATEMENT(cvc5::theory::THEORY_SEP) \ |
78 |
|
CVC5_FOR_EACH_THEORY_STATEMENT(cvc5::theory::THEORY_SETS) \ |
79 |
|
CVC5_FOR_EACH_THEORY_STATEMENT(cvc5::theory::THEORY_BAGS) \ |
80 |
|
CVC5_FOR_EACH_THEORY_STATEMENT(cvc5::theory::THEORY_STRINGS) \ |
81 |
|
CVC5_FOR_EACH_THEORY_STATEMENT(cvc5::theory::THEORY_QUANTIFIERS) |
82 |
|
|
83 |
|
} // namespace theory |
84 |
|
|
85 |
|
/* -------------------------------------------------------------------------- */ |
86 |
|
|
87 |
|
inline void flattenAnd(Node n, std::vector<TNode>& out){ |
88 |
|
Assert(n.getKind() == kind::AND); |
89 |
|
for(Node::iterator i=n.begin(), i_end=n.end(); i != i_end; ++i){ |
90 |
|
Node curr = *i; |
91 |
|
if(curr.getKind() == kind::AND){ |
92 |
|
flattenAnd(curr, out); |
93 |
|
}else{ |
94 |
|
out.push_back(curr); |
95 |
|
} |
96 |
|
} |
97 |
|
} |
98 |
|
|
99 |
|
inline Node flattenAnd(Node n){ |
100 |
|
std::vector<TNode> out; |
101 |
|
flattenAnd(n, out); |
102 |
|
return NodeManager::currentNM()->mkNode(kind::AND, out); |
103 |
|
} |
104 |
|
|
105 |
|
/** |
106 |
|
* Compute the string for a given theory id. In this module, we use |
107 |
|
* THEORY_SAT_SOLVER as an id, which is not a normal id but maps to |
108 |
|
* THEORY_LAST. Thus, we need our own string conversion here. |
109 |
|
* |
110 |
|
* @param id The theory id |
111 |
|
* @return The string corresponding to the theory id |
112 |
|
*/ |
113 |
2031810 |
std::string getTheoryString(theory::TheoryId id) |
114 |
|
{ |
115 |
2031810 |
if (id == theory::THEORY_SAT_SOLVER) |
116 |
|
{ |
117 |
1408318 |
return "THEORY_SAT_SOLVER"; |
118 |
|
} |
119 |
|
else |
120 |
|
{ |
121 |
1246984 |
std::stringstream ss; |
122 |
623492 |
ss << id; |
123 |
623492 |
return ss.str(); |
124 |
|
} |
125 |
|
} |
126 |
|
|
127 |
9917 |
void TheoryEngine::finishInit() |
128 |
|
{ |
129 |
9917 |
Trace("theory") << "Begin TheoryEngine::finishInit" << std::endl; |
130 |
|
// NOTE: This seems to be required since |
131 |
|
// theory::TheoryTraits<THEORY>::isParametric cannot be accessed without |
132 |
|
// using the CVC5_FOR_EACH_THEORY_STATEMENT macro. -AJR |
133 |
19834 |
std::vector<theory::Theory*> paraTheories; |
134 |
|
#ifdef CVC5_FOR_EACH_THEORY_STATEMENT |
135 |
|
#undef CVC5_FOR_EACH_THEORY_STATEMENT |
136 |
|
#endif |
137 |
|
#define CVC5_FOR_EACH_THEORY_STATEMENT(THEORY) \ |
138 |
|
if (theory::TheoryTraits<THEORY>::isParametric \ |
139 |
|
&& d_logicInfo.isTheoryEnabled(THEORY)) \ |
140 |
|
{ \ |
141 |
|
paraTheories.push_back(theoryOf(THEORY)); \ |
142 |
|
} |
143 |
|
// Collect the parametric theories, which are given to the theory combination |
144 |
|
// manager below |
145 |
9917 |
CVC5_FOR_EACH_THEORY; |
146 |
|
|
147 |
|
// Initialize the theory combination architecture |
148 |
9917 |
if (options::tcMode() == options::TcMode::CARE_GRAPH) |
149 |
|
{ |
150 |
9917 |
d_tc.reset(new CombinationCareGraph(*this, d_env, paraTheories, d_pnm)); |
151 |
|
} |
152 |
|
else |
153 |
|
{ |
154 |
|
Unimplemented() << "TheoryEngine::finishInit: theory combination mode " |
155 |
|
<< options::tcMode() << " not supported"; |
156 |
|
} |
157 |
|
// create the relevance filter if any option requires it |
158 |
9917 |
if (options::relevanceFilter() || options::produceDifficulty()) |
159 |
|
{ |
160 |
18 |
d_relManager.reset(new RelevanceManager(userContext(), Valuation(this))); |
161 |
|
} |
162 |
|
|
163 |
|
// initialize the quantifiers engine |
164 |
9917 |
if (d_logicInfo.isQuantified()) |
165 |
|
{ |
166 |
|
// get the quantifiers engine, which is initialized by the quantifiers |
167 |
|
// theory |
168 |
6826 |
d_quantEngine = d_theoryTable[THEORY_QUANTIFIERS]->getQuantifiersEngine(); |
169 |
6826 |
Assert(d_quantEngine != nullptr); |
170 |
|
} |
171 |
|
// finish initializing the quantifiers engine, which must come before |
172 |
|
// initializing theory combination, since quantifiers engine may have a |
173 |
|
// special model builder object |
174 |
9917 |
if (d_logicInfo.isQuantified()) |
175 |
|
{ |
176 |
6826 |
d_quantEngine->finishInit(this); |
177 |
|
} |
178 |
|
// initialize the theory combination manager, which decides and allocates the |
179 |
|
// equality engines to use for all theories. |
180 |
9917 |
d_tc->finishInit(); |
181 |
|
// get pointer to the shared solver |
182 |
9917 |
d_sharedSolver = d_tc->getSharedSolver(); |
183 |
|
|
184 |
|
// finish initializing the theories by linking them with the appropriate |
185 |
|
// utilities and then calling their finishInit method. |
186 |
138838 |
for(TheoryId theoryId = theory::THEORY_FIRST; theoryId != theory::THEORY_LAST; ++ theoryId) { |
187 |
128921 |
Theory* t = d_theoryTable[theoryId]; |
188 |
128921 |
if (t == nullptr) |
189 |
|
{ |
190 |
|
continue; |
191 |
|
} |
192 |
|
// setup the pointers to the utilities |
193 |
128921 |
const EeTheoryInfo* eeti = d_tc->getEeTheoryInfo(theoryId); |
194 |
128921 |
Assert(eeti != nullptr); |
195 |
|
// the theory's official equality engine is the one specified by the |
196 |
|
// equality engine manager |
197 |
128921 |
t->setEqualityEngine(eeti->d_usedEe); |
198 |
|
// set the quantifiers engine |
199 |
128921 |
t->setQuantifiersEngine(d_quantEngine); |
200 |
|
// set the decision manager for the theory |
201 |
128921 |
t->setDecisionManager(d_decManager.get()); |
202 |
|
// finish initializing the theory |
203 |
128921 |
t->finishInit(); |
204 |
|
} |
205 |
9917 |
Trace("theory") << "End TheoryEngine::finishInit" << std::endl; |
206 |
9917 |
} |
207 |
|
|
208 |
|
ProofNodeManager* TheoryEngine::getProofNodeManager() const { return d_pnm; } |
209 |
|
|
210 |
46501 |
context::Context* TheoryEngine::getSatContext() const { return context(); } |
211 |
|
|
212 |
11164 |
context::UserContext* TheoryEngine::getUserContext() const |
213 |
|
{ |
214 |
11164 |
return userContext(); |
215 |
|
} |
216 |
|
|
217 |
9917 |
TheoryEngine::TheoryEngine(Env& env) |
218 |
|
: EnvObj(env), |
219 |
|
d_propEngine(nullptr), |
220 |
9917 |
d_logicInfo(env.getLogicInfo()), |
221 |
9917 |
d_pnm(d_env.isTheoryProofProducing() ? d_env.getProofNodeManager() |
222 |
|
: nullptr), |
223 |
|
d_lazyProof( |
224 |
9917 |
d_pnm != nullptr ? new LazyCDProof( |
225 |
2480 |
d_pnm, nullptr, userContext(), "TheoryEngine::LazyCDProof") |
226 |
|
: nullptr), |
227 |
9917 |
d_tepg(new TheoryEngineProofGenerator(d_pnm, userContext())), |
228 |
|
d_tc(nullptr), |
229 |
|
d_sharedSolver(nullptr), |
230 |
|
d_quantEngine(nullptr), |
231 |
9917 |
d_decManager(new DecisionManager(userContext())), |
232 |
|
d_relManager(nullptr), |
233 |
|
d_inConflict(context(), false), |
234 |
|
d_inSatMode(false), |
235 |
|
d_hasShutDown(false), |
236 |
|
d_incomplete(context(), false), |
237 |
|
d_incompleteTheory(context(), THEORY_BUILTIN), |
238 |
|
d_incompleteId(context(), IncompleteId::UNKNOWN), |
239 |
|
d_propagationMap(context()), |
240 |
|
d_propagationMapTimestamp(context(), 0), |
241 |
|
d_propagatedLiterals(context()), |
242 |
|
d_propagatedLiteralsIndex(context(), 0), |
243 |
|
d_atomRequests(context()), |
244 |
9917 |
d_combineTheoriesTime(statisticsRegistry().registerTimer( |
245 |
19834 |
"TheoryEngine::combineTheoriesTime")), |
246 |
|
d_true(), |
247 |
|
d_false(), |
248 |
|
d_interrupted(false), |
249 |
|
d_inPreregister(false), |
250 |
81816 |
d_factsAsserted(context(), false) |
251 |
|
{ |
252 |
138838 |
for(TheoryId theoryId = theory::THEORY_FIRST; theoryId != theory::THEORY_LAST; |
253 |
|
++ theoryId) |
254 |
|
{ |
255 |
128921 |
d_theoryTable[theoryId] = NULL; |
256 |
128921 |
d_theoryOut[theoryId] = NULL; |
257 |
|
} |
258 |
|
|
259 |
9917 |
if (options::sortInference()) |
260 |
|
{ |
261 |
20 |
d_sortInfer.reset(new SortInference(env)); |
262 |
|
} |
263 |
|
|
264 |
9917 |
d_true = NodeManager::currentNM()->mkConst<bool>(true); |
265 |
9917 |
d_false = NodeManager::currentNM()->mkConst<bool>(false); |
266 |
9917 |
} |
267 |
|
|
268 |
29742 |
TheoryEngine::~TheoryEngine() { |
269 |
9914 |
Assert(d_hasShutDown); |
270 |
|
|
271 |
138796 |
for(TheoryId theoryId = theory::THEORY_FIRST; theoryId != theory::THEORY_LAST; ++ theoryId) { |
272 |
128882 |
if(d_theoryTable[theoryId] != NULL) { |
273 |
128834 |
delete d_theoryTable[theoryId]; |
274 |
128834 |
delete d_theoryOut[theoryId]; |
275 |
|
} |
276 |
|
} |
277 |
19828 |
} |
278 |
|
|
279 |
|
void TheoryEngine::interrupt() { d_interrupted = true; } |
280 |
1083144 |
void TheoryEngine::preRegister(TNode preprocessed) { |
281 |
2166288 |
Debug("theory") << "TheoryEngine::preRegister( " << preprocessed << ")" |
282 |
1083144 |
<< std::endl; |
283 |
1083144 |
d_preregisterQueue.push(preprocessed); |
284 |
|
|
285 |
1083144 |
if (!d_inPreregister) { |
286 |
|
// We're in pre-register |
287 |
1012663 |
d_inPreregister = true; |
288 |
|
|
289 |
|
// Process the pre-registration queue |
290 |
3178943 |
while (!d_preregisterQueue.empty()) { |
291 |
|
// Get the next atom to pre-register |
292 |
1083144 |
preprocessed = d_preregisterQueue.front(); |
293 |
1083144 |
d_preregisterQueue.pop(); |
294 |
|
|
295 |
|
// the atom should not have free variables |
296 |
2166288 |
Debug("theory") << "TheoryEngine::preRegister: " << preprocessed |
297 |
1083144 |
<< std::endl; |
298 |
1083144 |
if (Configuration::isAssertionBuild()) |
299 |
|
{ |
300 |
2166288 |
std::unordered_set<Node> fvs; |
301 |
1083144 |
expr::getFreeVariables(preprocessed, fvs); |
302 |
1083144 |
if (!fvs.empty()) |
303 |
|
{ |
304 |
|
Unhandled() << "Preregistered term with free variable: " |
305 |
|
<< preprocessed << ", fv=" << *fvs.begin(); |
306 |
|
} |
307 |
|
} |
308 |
|
// should not have witness |
309 |
1083144 |
Assert(!expr::hasSubtermKind(kind::WITNESS, preprocessed)); |
310 |
|
|
311 |
|
// pre-register with the shared solver, which handles |
312 |
|
// calling prepregister on individual theories, adding shared terms, |
313 |
|
// and setting up equalities to propagate in the shared term database. |
314 |
1083144 |
Assert(d_sharedSolver != nullptr); |
315 |
1083148 |
d_sharedSolver->preRegister(preprocessed); |
316 |
|
} |
317 |
|
|
318 |
|
// Leaving pre-register |
319 |
1012659 |
d_inPreregister = false; |
320 |
|
} |
321 |
1083140 |
} |
322 |
|
|
323 |
|
void TheoryEngine::printAssertions(const char* tag) { |
324 |
|
if (Trace.isOn(tag)) { |
325 |
|
|
326 |
|
for (TheoryId theoryId = THEORY_FIRST; theoryId < THEORY_LAST; ++theoryId) { |
327 |
|
Theory* theory = d_theoryTable[theoryId]; |
328 |
|
if (theory && d_logicInfo.isTheoryEnabled(theoryId)) { |
329 |
|
Trace(tag) << "--------------------------------------------" << endl; |
330 |
|
Trace(tag) << "Assertions of " << theory->getId() << ": " << endl; |
331 |
|
{ |
332 |
|
context::CDList<Assertion>::const_iterator it = theory->facts_begin(), |
333 |
|
it_end = |
334 |
|
theory->facts_end(); |
335 |
|
for (unsigned i = 0; it != it_end; ++it, ++i) |
336 |
|
{ |
337 |
|
if ((*it).d_isPreregistered) |
338 |
|
{ |
339 |
|
Trace(tag) << "[" << i << "]: "; |
340 |
|
} |
341 |
|
else |
342 |
|
{ |
343 |
|
Trace(tag) << "(" << i << "): "; |
344 |
|
} |
345 |
|
Trace(tag) << (*it).d_assertion << endl; |
346 |
|
} |
347 |
|
} |
348 |
|
|
349 |
|
if (d_logicInfo.isSharingEnabled()) { |
350 |
|
Trace(tag) << "Shared terms of " << theory->getId() << ": " << endl; |
351 |
|
context::CDList<TNode>::const_iterator it = theory->shared_terms_begin(), it_end = theory->shared_terms_end(); |
352 |
|
for (unsigned i = 0; it != it_end; ++ it, ++i) { |
353 |
|
Trace(tag) << "[" << i << "]: " << (*it) << endl; |
354 |
|
} |
355 |
|
} |
356 |
|
} |
357 |
|
} |
358 |
|
} |
359 |
|
} |
360 |
|
|
361 |
|
void TheoryEngine::dumpAssertions(const char* tag) { |
362 |
|
if (Dump.isOn(tag)) { |
363 |
|
const Printer& printer = d_env.getPrinter(); |
364 |
|
std::ostream& out = d_env.getDumpOut(); |
365 |
|
printer.toStreamCmdComment(out, "Starting completeness check"); |
366 |
|
for (TheoryId theoryId = THEORY_FIRST; theoryId < THEORY_LAST; ++theoryId) { |
367 |
|
Theory* theory = d_theoryTable[theoryId]; |
368 |
|
if (theory && d_logicInfo.isTheoryEnabled(theoryId)) { |
369 |
|
printer.toStreamCmdComment(out, "Completeness check"); |
370 |
|
printer.toStreamCmdPush(out); |
371 |
|
|
372 |
|
// Dump the shared terms |
373 |
|
if (d_logicInfo.isSharingEnabled()) { |
374 |
|
printer.toStreamCmdComment(out, "Shared terms"); |
375 |
|
context::CDList<TNode>::const_iterator it = theory->shared_terms_begin(), it_end = theory->shared_terms_end(); |
376 |
|
for (unsigned i = 0; it != it_end; ++ it, ++i) { |
377 |
|
stringstream ss; |
378 |
|
ss << (*it); |
379 |
|
printer.toStreamCmdComment(out, ss.str()); |
380 |
|
} |
381 |
|
} |
382 |
|
|
383 |
|
// Dump the assertions |
384 |
|
printer.toStreamCmdComment(out, "Assertions"); |
385 |
|
context::CDList<Assertion>::const_iterator it = theory->facts_begin(), it_end = theory->facts_end(); |
386 |
|
for (; it != it_end; ++ it) { |
387 |
|
// Get the assertion |
388 |
|
Node assertionNode = (*it).d_assertion; |
389 |
|
// Purify all the terms |
390 |
|
|
391 |
|
if ((*it).d_isPreregistered) |
392 |
|
{ |
393 |
|
printer.toStreamCmdComment(out, "Preregistered"); |
394 |
|
} |
395 |
|
else |
396 |
|
{ |
397 |
|
printer.toStreamCmdComment(out, "Shared assertion"); |
398 |
|
} |
399 |
|
printer.toStreamCmdAssert(out, assertionNode); |
400 |
|
} |
401 |
|
printer.toStreamCmdCheckSat(out); |
402 |
|
|
403 |
|
printer.toStreamCmdPop(out); |
404 |
|
} |
405 |
|
} |
406 |
|
} |
407 |
|
} |
408 |
|
|
409 |
|
/** |
410 |
|
* Check all (currently-active) theories for conflicts. |
411 |
|
* @param effort the effort level to use |
412 |
|
*/ |
413 |
4378287 |
void TheoryEngine::check(Theory::Effort effort) { |
414 |
|
// spendResource(); |
415 |
|
|
416 |
|
// Reset the interrupt flag |
417 |
4378287 |
d_interrupted = false; |
418 |
|
|
419 |
|
#ifdef CVC5_FOR_EACH_THEORY_STATEMENT |
420 |
|
#undef CVC5_FOR_EACH_THEORY_STATEMENT |
421 |
|
#endif |
422 |
|
#define CVC5_FOR_EACH_THEORY_STATEMENT(THEORY) \ |
423 |
|
if (theory::TheoryTraits<THEORY>::hasCheck \ |
424 |
|
&& d_logicInfo.isTheoryEnabled(THEORY)) \ |
425 |
|
{ \ |
426 |
|
theoryOf(THEORY)->check(effort); \ |
427 |
|
if (d_inConflict) \ |
428 |
|
{ \ |
429 |
|
Debug("conflict") << THEORY << " in conflict. " << std::endl; \ |
430 |
|
break; \ |
431 |
|
} \ |
432 |
|
} |
433 |
|
|
434 |
|
// Do the checking |
435 |
|
try { |
436 |
|
|
437 |
|
// Mark the output channel unused (if this is FULL_EFFORT, and nothing |
438 |
|
// is done by the theories, no additional check will be needed) |
439 |
4378287 |
d_outputChannelUsed = false; |
440 |
|
|
441 |
|
// Mark the lemmas flag (no lemmas added) |
442 |
4378287 |
d_lemmasAdded = false; |
443 |
|
|
444 |
4378287 |
Debug("theory") << "TheoryEngine::check(" << effort << "): d_factsAsserted = " << (d_factsAsserted ? "true" : "false") << endl; |
445 |
|
|
446 |
|
// If in full effort, we have a fake new assertion just to jumpstart the checking |
447 |
4378287 |
if (Theory::fullEffort(effort)) { |
448 |
79348 |
d_factsAsserted = true; |
449 |
|
// Reset round for the relevance manager, which notice only sets a flag |
450 |
|
// to indicate that its information must be recomputed. |
451 |
79348 |
if (d_relManager != nullptr) |
452 |
|
{ |
453 |
132 |
d_relManager->resetRound(); |
454 |
|
} |
455 |
79348 |
d_tc->resetRound(); |
456 |
|
} |
457 |
|
|
458 |
|
// Check until done |
459 |
12066375 |
while (d_factsAsserted && !d_inConflict && !d_lemmasAdded) { |
460 |
|
|
461 |
4001843 |
Debug("theory") << "TheoryEngine::check(" << effort << "): running check" << endl; |
462 |
|
|
463 |
4001843 |
Trace("theory::assertions") << endl; |
464 |
4001843 |
if (Trace.isOn("theory::assertions")) { |
465 |
|
printAssertions("theory::assertions"); |
466 |
|
} |
467 |
|
|
468 |
4001843 |
if(Theory::fullEffort(effort)) { |
469 |
88090 |
Trace("theory::assertions::fulleffort") << endl; |
470 |
88090 |
if (Trace.isOn("theory::assertions::fulleffort")) { |
471 |
|
printAssertions("theory::assertions::fulleffort"); |
472 |
|
} |
473 |
|
} |
474 |
|
|
475 |
|
// Note that we've discharged all the facts |
476 |
4001843 |
d_factsAsserted = false; |
477 |
|
|
478 |
|
// Do the checking |
479 |
4001843 |
CVC5_FOR_EACH_THEORY; |
480 |
|
|
481 |
3844044 |
Debug("theory") << "TheoryEngine::check(" << effort << "): running propagation after the initial check" << endl; |
482 |
|
|
483 |
|
// We are still satisfiable, propagate as much as possible |
484 |
3844044 |
propagate(effort); |
485 |
|
|
486 |
|
// We do combination if all has been processed and we are in fullcheck |
487 |
7749084 |
if (Theory::fullEffort(effort) && d_logicInfo.isSharingEnabled() |
488 |
3898353 |
&& !d_factsAsserted && !needCheck() && !d_inConflict) |
489 |
|
{ |
490 |
|
// Do the combination |
491 |
23918 |
Debug("theory") << "TheoryEngine::check(" << effort << "): running combination" << endl; |
492 |
|
{ |
493 |
47836 |
TimerStat::CodeTimer combineTheoriesTimer(d_combineTheoriesTime); |
494 |
23918 |
d_tc->combineTheories(); |
495 |
|
} |
496 |
23918 |
if(d_logicInfo.isQuantified()){ |
497 |
13361 |
d_quantEngine->notifyCombineTheories(); |
498 |
|
} |
499 |
|
} |
500 |
|
} |
501 |
|
|
502 |
|
// Must consult quantifiers theory for last call to ensure sat, or otherwise add a lemma |
503 |
4378283 |
if( Theory::fullEffort(effort) && ! d_inConflict && ! needCheck() ) { |
504 |
20981 |
Trace("theory::assertions-model") << endl; |
505 |
20981 |
if (Trace.isOn("theory::assertions-model")) { |
506 |
|
printAssertions("theory::assertions-model"); |
507 |
|
} |
508 |
|
// reset the model in the combination engine |
509 |
20981 |
d_tc->resetModel(); |
510 |
|
//checks for theories requiring the model go at last call |
511 |
293734 |
for (TheoryId theoryId = THEORY_FIRST; theoryId < THEORY_LAST; ++theoryId) { |
512 |
272753 |
if( theoryId!=THEORY_QUANTIFIERS ){ |
513 |
251772 |
Theory* theory = d_theoryTable[theoryId]; |
514 |
251772 |
if (theory && d_logicInfo.isTheoryEnabled(theoryId)) { |
515 |
131724 |
if( theory->needsCheckLastEffort() ){ |
516 |
9649 |
if (!d_tc->buildModel()) |
517 |
|
{ |
518 |
|
break; |
519 |
|
} |
520 |
9649 |
theory->check(Theory::EFFORT_LAST_CALL); |
521 |
|
} |
522 |
|
} |
523 |
|
} |
524 |
|
} |
525 |
20981 |
if (!d_inConflict) |
526 |
|
{ |
527 |
20981 |
if(d_logicInfo.isQuantified()) { |
528 |
|
// quantifiers engine must check at last call effort |
529 |
14761 |
d_quantEngine->check(Theory::EFFORT_LAST_CALL); |
530 |
|
} |
531 |
|
} |
532 |
|
// notify the relevant manager |
533 |
20971 |
if (d_relManager != nullptr) |
534 |
|
{ |
535 |
111 |
d_relManager->notifyCandidateModel(getModel()); |
536 |
|
} |
537 |
20971 |
if (!d_inConflict && !needCheck()) |
538 |
|
{ |
539 |
|
// We only mark that we are in "SAT mode". We build the model later only |
540 |
|
// if the user asks for it via getBuiltModel. |
541 |
7481 |
d_inSatMode = true; |
542 |
|
} |
543 |
|
} |
544 |
|
|
545 |
4378273 |
Debug("theory") << "TheoryEngine::check(" << effort << "): done, we are " << (d_inConflict ? "unsat" : "sat") << (d_lemmasAdded ? " with new lemmas" : " with no new lemmas"); |
546 |
4378273 |
Debug("theory") << ", need check = " << (needCheck() ? "YES" : "NO") << endl; |
547 |
|
|
548 |
4378273 |
if( Theory::fullEffort(effort) && !d_inConflict && !needCheck()) { |
549 |
|
// Do post-processing of model from the theories (e.g. used for THEORY_SEP |
550 |
|
// to construct heap model) |
551 |
7481 |
d_tc->postProcessModel(d_incomplete.get()); |
552 |
|
} |
553 |
|
} catch(const theory::Interrupted&) { |
554 |
|
Trace("theory") << "TheoryEngine::check() => interrupted" << endl; |
555 |
|
} |
556 |
|
// If fulleffort, check all theories |
557 |
4378273 |
if(Dump.isOn("theory::fullcheck") && Theory::fullEffort(effort)) { |
558 |
|
if (!d_inConflict && !needCheck()) { |
559 |
|
dumpAssertions("theory::fullcheck"); |
560 |
|
} |
561 |
|
} |
562 |
4378273 |
} |
563 |
|
|
564 |
3844044 |
void TheoryEngine::propagate(Theory::Effort effort) |
565 |
|
{ |
566 |
|
// Reset the interrupt flag |
567 |
3844044 |
d_interrupted = false; |
568 |
|
|
569 |
|
// Definition of the statement that is to be run by every theory |
570 |
|
#ifdef CVC5_FOR_EACH_THEORY_STATEMENT |
571 |
|
#undef CVC5_FOR_EACH_THEORY_STATEMENT |
572 |
|
#endif |
573 |
|
#define CVC5_FOR_EACH_THEORY_STATEMENT(THEORY) \ |
574 |
|
if (theory::TheoryTraits<THEORY>::hasPropagate \ |
575 |
|
&& d_logicInfo.isTheoryEnabled(THEORY)) \ |
576 |
|
{ \ |
577 |
|
theoryOf(THEORY)->propagate(effort); \ |
578 |
|
} |
579 |
|
|
580 |
|
// Reset the interrupt flag |
581 |
3844044 |
d_interrupted = false; |
582 |
|
|
583 |
|
// Propagate for each theory using the statement above |
584 |
3844044 |
CVC5_FOR_EACH_THEORY; |
585 |
3844044 |
} |
586 |
|
|
587 |
2937328 |
Node TheoryEngine::getNextDecisionRequest() |
588 |
|
{ |
589 |
2937328 |
return d_decManager->getNextDecisionRequest(); |
590 |
|
} |
591 |
|
|
592 |
132004 |
bool TheoryEngine::properConflict(TNode conflict) const { |
593 |
|
bool value; |
594 |
132004 |
if (conflict.getKind() == kind::AND) { |
595 |
1685225 |
for (unsigned i = 0; i < conflict.getNumChildren(); ++ i) { |
596 |
1553711 |
if (! getPropEngine()->hasValue(conflict[i], value)) { |
597 |
|
Debug("properConflict") << "Bad conflict is due to unassigned atom: " |
598 |
|
<< conflict[i] << endl; |
599 |
|
return false; |
600 |
|
} |
601 |
1553711 |
if (! value) { |
602 |
|
Debug("properConflict") << "Bad conflict is due to false atom: " |
603 |
|
<< conflict[i] << endl; |
604 |
|
return false; |
605 |
|
} |
606 |
1553711 |
if (conflict[i] != Rewriter::rewrite(conflict[i])) { |
607 |
|
Debug("properConflict") << "Bad conflict is due to atom not in normal form: " |
608 |
|
<< conflict[i] << " vs " << Rewriter::rewrite(conflict[i]) << endl; |
609 |
|
return false; |
610 |
|
} |
611 |
|
} |
612 |
|
} else { |
613 |
490 |
if (! getPropEngine()->hasValue(conflict, value)) { |
614 |
|
Debug("properConflict") << "Bad conflict is due to unassigned atom: " |
615 |
|
<< conflict << endl; |
616 |
|
return false; |
617 |
|
} |
618 |
490 |
if(! value) { |
619 |
|
Debug("properConflict") << "Bad conflict is due to false atom: " |
620 |
|
<< conflict << endl; |
621 |
|
return false; |
622 |
|
} |
623 |
490 |
if (conflict != Rewriter::rewrite(conflict)) { |
624 |
|
Debug("properConflict") << "Bad conflict is due to atom not in normal form: " |
625 |
|
<< conflict << " vs " << Rewriter::rewrite(conflict) << endl; |
626 |
|
return false; |
627 |
|
} |
628 |
|
} |
629 |
132004 |
return true; |
630 |
|
} |
631 |
|
|
632 |
7115852 |
TheoryModel* TheoryEngine::getModel() |
633 |
|
{ |
634 |
7115852 |
Assert(d_tc != nullptr); |
635 |
7115852 |
TheoryModel* m = d_tc->getModel(); |
636 |
7115852 |
Assert(m != nullptr); |
637 |
7115852 |
return m; |
638 |
|
} |
639 |
|
|
640 |
4798 |
TheoryModel* TheoryEngine::getBuiltModel() |
641 |
|
{ |
642 |
4798 |
Assert(d_tc != nullptr); |
643 |
|
// If this method was called, we should be in SAT mode, and produceModels |
644 |
|
// should be true. |
645 |
4798 |
AlwaysAssert(options::produceModels()); |
646 |
4798 |
if (!d_inSatMode) |
647 |
|
{ |
648 |
|
// not available, perhaps due to interuption. |
649 |
|
return nullptr; |
650 |
|
} |
651 |
|
// must build model at this point |
652 |
4798 |
if (!d_tc->buildModel()) |
653 |
|
{ |
654 |
|
return nullptr; |
655 |
|
} |
656 |
4797 |
return d_tc->getModel(); |
657 |
|
} |
658 |
|
|
659 |
10347 |
bool TheoryEngine::buildModel() |
660 |
|
{ |
661 |
10347 |
Assert(d_tc != nullptr); |
662 |
10347 |
return d_tc->buildModel(); |
663 |
|
} |
664 |
|
|
665 |
15241 |
bool TheoryEngine::presolve() { |
666 |
|
// Reset the interrupt flag |
667 |
15241 |
d_interrupted = false; |
668 |
|
|
669 |
|
// Reset the decision manager. This clears its decision strategies that are |
670 |
|
// no longer valid in this user context. |
671 |
15241 |
d_decManager->presolve(); |
672 |
|
|
673 |
|
try { |
674 |
|
// Definition of the statement that is to be run by every theory |
675 |
|
#ifdef CVC5_FOR_EACH_THEORY_STATEMENT |
676 |
|
#undef CVC5_FOR_EACH_THEORY_STATEMENT |
677 |
|
#endif |
678 |
|
#define CVC5_FOR_EACH_THEORY_STATEMENT(THEORY) \ |
679 |
|
if (theory::TheoryTraits<THEORY>::hasPresolve) \ |
680 |
|
{ \ |
681 |
|
theoryOf(THEORY)->presolve(); \ |
682 |
|
if (d_inConflict) \ |
683 |
|
{ \ |
684 |
|
return true; \ |
685 |
|
} \ |
686 |
|
} |
687 |
|
|
688 |
|
// Presolve for each theory using the statement above |
689 |
15241 |
CVC5_FOR_EACH_THEORY; |
690 |
|
} catch(const theory::Interrupted&) { |
691 |
|
Trace("theory") << "TheoryEngine::presolve() => interrupted" << endl; |
692 |
|
} |
693 |
|
// return whether we have a conflict |
694 |
15241 |
return false; |
695 |
|
}/* TheoryEngine::presolve() */ |
696 |
|
|
697 |
15225 |
void TheoryEngine::postsolve() { |
698 |
|
// no longer in SAT mode |
699 |
15225 |
d_inSatMode = false; |
700 |
|
// Reset the interrupt flag |
701 |
15225 |
d_interrupted = false; |
702 |
15225 |
CVC5_UNUSED bool wasInConflict = d_inConflict; |
703 |
|
|
704 |
|
try { |
705 |
|
// Definition of the statement that is to be run by every theory |
706 |
|
#ifdef CVC5_FOR_EACH_THEORY_STATEMENT |
707 |
|
#undef CVC5_FOR_EACH_THEORY_STATEMENT |
708 |
|
#endif |
709 |
|
#define CVC5_FOR_EACH_THEORY_STATEMENT(THEORY) \ |
710 |
|
if (theory::TheoryTraits<THEORY>::hasPostsolve) \ |
711 |
|
{ \ |
712 |
|
theoryOf(THEORY)->postsolve(); \ |
713 |
|
Assert(!d_inConflict || wasInConflict) \ |
714 |
|
<< "conflict raised during postsolve()"; \ |
715 |
|
} |
716 |
|
|
717 |
|
// Postsolve for each theory using the statement above |
718 |
|
CVC5_FOR_EACH_THEORY; |
719 |
|
} catch(const theory::Interrupted&) { |
720 |
|
Trace("theory") << "TheoryEngine::postsolve() => interrupted" << endl; |
721 |
|
} |
722 |
15225 |
}/* TheoryEngine::postsolve() */ |
723 |
|
|
724 |
|
|
725 |
2688 |
void TheoryEngine::notifyRestart() { |
726 |
|
// Reset the interrupt flag |
727 |
2688 |
d_interrupted = false; |
728 |
|
|
729 |
|
// Definition of the statement that is to be run by every theory |
730 |
|
#ifdef CVC5_FOR_EACH_THEORY_STATEMENT |
731 |
|
#undef CVC5_FOR_EACH_THEORY_STATEMENT |
732 |
|
#endif |
733 |
|
#define CVC5_FOR_EACH_THEORY_STATEMENT(THEORY) \ |
734 |
|
if (theory::TheoryTraits<THEORY>::hasNotifyRestart \ |
735 |
|
&& d_logicInfo.isTheoryEnabled(THEORY)) \ |
736 |
|
{ \ |
737 |
|
theoryOf(THEORY)->notifyRestart(); \ |
738 |
|
} |
739 |
|
|
740 |
|
// notify each theory using the statement above |
741 |
2688 |
CVC5_FOR_EACH_THEORY; |
742 |
2688 |
} |
743 |
|
|
744 |
105430 |
void TheoryEngine::ppStaticLearn(TNode in, NodeBuilder& learned) |
745 |
|
{ |
746 |
|
// Reset the interrupt flag |
747 |
105430 |
d_interrupted = false; |
748 |
|
|
749 |
|
// Definition of the statement that is to be run by every theory |
750 |
|
#ifdef CVC5_FOR_EACH_THEORY_STATEMENT |
751 |
|
#undef CVC5_FOR_EACH_THEORY_STATEMENT |
752 |
|
#endif |
753 |
|
#define CVC5_FOR_EACH_THEORY_STATEMENT(THEORY) \ |
754 |
|
if (theory::TheoryTraits<THEORY>::hasPpStaticLearn) \ |
755 |
|
{ \ |
756 |
|
theoryOf(THEORY)->ppStaticLearn(in, learned); \ |
757 |
|
} |
758 |
|
|
759 |
|
// static learning for each theory using the statement above |
760 |
105430 |
CVC5_FOR_EACH_THEORY; |
761 |
105430 |
} |
762 |
|
|
763 |
110735 |
bool TheoryEngine::isRelevant(Node lit) const |
764 |
|
{ |
765 |
110735 |
if (d_relManager != nullptr) |
766 |
|
{ |
767 |
2445 |
return d_relManager->isRelevant(lit); |
768 |
|
} |
769 |
|
// otherwise must assume its relevant |
770 |
108290 |
return true; |
771 |
|
} |
772 |
|
|
773 |
9914 |
void TheoryEngine::shutdown() { |
774 |
|
// Set this first; if a Theory shutdown() throws an exception, |
775 |
|
// at least the destruction of the TheoryEngine won't confound |
776 |
|
// matters. |
777 |
9914 |
d_hasShutDown = true; |
778 |
|
|
779 |
|
// Shutdown all the theories |
780 |
138796 |
for(TheoryId theoryId = theory::THEORY_FIRST; theoryId < theory::THEORY_LAST; ++theoryId) { |
781 |
128882 |
if(d_theoryTable[theoryId]) { |
782 |
128834 |
theoryOf(theoryId)->shutdown(); |
783 |
|
} |
784 |
|
} |
785 |
9914 |
} |
786 |
|
|
787 |
113769 |
theory::Theory::PPAssertStatus TheoryEngine::solve( |
788 |
|
TrustNode tliteral, TrustSubstitutionMap& substitutionOut) |
789 |
|
{ |
790 |
|
// Reset the interrupt flag |
791 |
113769 |
d_interrupted = false; |
792 |
|
|
793 |
227538 |
TNode literal = tliteral.getNode(); |
794 |
227538 |
TNode atom = literal.getKind() == kind::NOT ? literal[0] : literal; |
795 |
113769 |
Trace("theory::solve") << "TheoryEngine::solve(" << literal << "): solving with " << theoryOf(atom)->getId() << endl; |
796 |
|
|
797 |
227538 |
if(! d_logicInfo.isTheoryEnabled(Theory::theoryOf(atom)) && |
798 |
113769 |
Theory::theoryOf(atom) != THEORY_SAT_SOLVER) { |
799 |
|
stringstream ss; |
800 |
|
ss << "The logic was specified as " << d_logicInfo.getLogicString() |
801 |
|
<< ", which doesn't include " << Theory::theoryOf(atom) |
802 |
|
<< ", but got a preprocessing-time fact for that theory." << endl |
803 |
|
<< "The fact:" << endl |
804 |
|
<< literal; |
805 |
|
throw LogicException(ss.str()); |
806 |
|
} |
807 |
|
|
808 |
|
Theory::PPAssertStatus solveStatus = |
809 |
113769 |
theoryOf(atom)->ppAssert(tliteral, substitutionOut); |
810 |
113769 |
Trace("theory::solve") << "TheoryEngine::solve(" << literal << ") => " << solveStatus << endl; |
811 |
227538 |
return solveStatus; |
812 |
|
} |
813 |
|
|
814 |
199250 |
TrustNode TheoryEngine::ppRewriteEquality(TNode eq) |
815 |
|
{ |
816 |
199250 |
Assert(eq.getKind() == kind::EQUAL); |
817 |
398500 |
std::vector<SkolemLemma> lems; |
818 |
199250 |
TrustNode trn = theoryOf(eq)->ppRewrite(eq, lems); |
819 |
|
// should never introduce a skolem to eliminate an equality |
820 |
199250 |
Assert(lems.empty()); |
821 |
398500 |
return trn; |
822 |
|
} |
823 |
|
|
824 |
13775 |
void TheoryEngine::notifyPreprocessedAssertions( |
825 |
|
const std::vector<Node>& assertions) { |
826 |
|
// call all the theories |
827 |
192850 |
for (TheoryId theoryId = theory::THEORY_FIRST; theoryId < theory::THEORY_LAST; |
828 |
|
++theoryId) { |
829 |
179075 |
if (d_theoryTable[theoryId]) { |
830 |
179075 |
theoryOf(theoryId)->ppNotifyAssertions(assertions); |
831 |
|
} |
832 |
|
} |
833 |
13775 |
if (d_relManager != nullptr) |
834 |
|
{ |
835 |
18 |
d_relManager->notifyPreprocessedAssertions(assertions); |
836 |
|
} |
837 |
13775 |
} |
838 |
|
|
839 |
35719175 |
bool TheoryEngine::markPropagation(TNode assertion, TNode originalAssertion, theory::TheoryId toTheoryId, theory::TheoryId fromTheoryId) { |
840 |
|
// What and where we are asserting |
841 |
71438350 |
NodeTheoryPair toAssert(assertion, toTheoryId, d_propagationMapTimestamp); |
842 |
|
// What and where it came from |
843 |
71438350 |
NodeTheoryPair toExplain(originalAssertion, fromTheoryId, d_propagationMapTimestamp); |
844 |
|
|
845 |
|
// See if the theory already got this literal |
846 |
35719175 |
PropagationMap::const_iterator find = d_propagationMap.find(toAssert); |
847 |
35719175 |
if (find != d_propagationMap.end()) { |
848 |
|
// The theory already knows this |
849 |
10377483 |
Trace("theory::assertToTheory") << "TheoryEngine::markPropagation(): already there" << endl; |
850 |
10377483 |
return false; |
851 |
|
} |
852 |
|
|
853 |
25341692 |
Trace("theory::assertToTheory") << "TheoryEngine::markPropagation(): marking [" << d_propagationMapTimestamp << "] " << assertion << ", " << toTheoryId << " from " << originalAssertion << ", " << fromTheoryId << endl; |
854 |
|
|
855 |
|
// Mark the propagation |
856 |
25341692 |
d_propagationMap[toAssert] = toExplain; |
857 |
25341692 |
d_propagationMapTimestamp = d_propagationMapTimestamp + 1; |
858 |
|
|
859 |
25341692 |
return true; |
860 |
|
} |
861 |
|
|
862 |
|
|
863 |
41892869 |
void TheoryEngine::assertToTheory(TNode assertion, TNode originalAssertion, theory::TheoryId toTheoryId, theory::TheoryId fromTheoryId) { |
864 |
41892869 |
Trace("theory::assertToTheory") << "TheoryEngine::assertToTheory(" << assertion << ", " << originalAssertion << "," << toTheoryId << ", " << fromTheoryId << ")" << endl; |
865 |
|
|
866 |
41892869 |
Assert(toTheoryId != fromTheoryId); |
867 |
70428394 |
if(toTheoryId != THEORY_SAT_SOLVER && |
868 |
28535525 |
! d_logicInfo.isTheoryEnabled(toTheoryId)) { |
869 |
|
stringstream ss; |
870 |
|
ss << "The logic was specified as " << d_logicInfo.getLogicString() |
871 |
|
<< ", which doesn't include " << toTheoryId |
872 |
|
<< ", but got an asserted fact to that theory." << endl |
873 |
|
<< "The fact:" << endl |
874 |
|
<< assertion; |
875 |
|
throw LogicException(ss.str()); |
876 |
|
} |
877 |
|
|
878 |
41892869 |
if (d_inConflict) { |
879 |
76442 |
return; |
880 |
|
} |
881 |
|
|
882 |
|
// If sharing is disabled, things are easy |
883 |
41816427 |
if (!d_logicInfo.isSharingEnabled()) { |
884 |
6097252 |
Assert(assertion == originalAssertion); |
885 |
6097252 |
if (fromTheoryId == THEORY_SAT_SOLVER) { |
886 |
|
// Send to the apropriate theory |
887 |
4283797 |
theory::Theory* toTheory = theoryOf(toTheoryId); |
888 |
|
// We assert it, and we know it's preregistereed |
889 |
4283797 |
toTheory->assertFact(assertion, true); |
890 |
|
// Mark that we have more information |
891 |
4283797 |
d_factsAsserted = true; |
892 |
|
} else { |
893 |
1813455 |
Assert(toTheoryId == THEORY_SAT_SOLVER); |
894 |
|
// Check for propositional conflict |
895 |
|
bool value; |
896 |
1813455 |
if (d_propEngine->hasValue(assertion, value)) { |
897 |
1135248 |
if (!value) { |
898 |
34194 |
Trace("theory::propagate") << "TheoryEngine::assertToTheory(" << assertion << ", " << toTheoryId << ", " << fromTheoryId << "): conflict (no sharing)" << endl; |
899 |
68388 |
Trace("dtview::conflict") |
900 |
34194 |
<< ":THEORY-CONFLICT: " << assertion << std::endl; |
901 |
34194 |
markInConflict(); |
902 |
|
} else { |
903 |
1101054 |
return; |
904 |
|
} |
905 |
|
} |
906 |
712401 |
d_propagatedLiterals.push_back(assertion); |
907 |
|
} |
908 |
4996198 |
return; |
909 |
|
} |
910 |
|
|
911 |
|
// determine the actual theory that will process/explain the fact, which is |
912 |
|
// THEORY_BUILTIN if the theory uses the central equality engine |
913 |
35719175 |
TheoryId toTheoryIdProp = (Theory::expUsingCentralEqualityEngine(toTheoryId)) |
914 |
35719175 |
? THEORY_BUILTIN |
915 |
35719175 |
: toTheoryId; |
916 |
|
// If sending to the shared solver, it's also simple |
917 |
35719175 |
if (toTheoryId == THEORY_BUILTIN) { |
918 |
11549090 |
if (markPropagation( |
919 |
|
assertion, originalAssertion, toTheoryIdProp, fromTheoryId)) |
920 |
|
{ |
921 |
|
// assert to the shared solver |
922 |
6362367 |
bool polarity = assertion.getKind() != kind::NOT; |
923 |
12724734 |
TNode atom = polarity ? assertion : assertion[0]; |
924 |
6362367 |
d_sharedSolver->assertShared(atom, polarity, assertion); |
925 |
|
} |
926 |
11549090 |
return; |
927 |
|
} |
928 |
|
|
929 |
|
// Things from the SAT solver are already normalized, so they go |
930 |
|
// directly to the apropriate theory |
931 |
24170085 |
if (fromTheoryId == THEORY_SAT_SOLVER) { |
932 |
|
// We know that this is normalized, so just send it off to the theory |
933 |
8794106 |
if (markPropagation( |
934 |
|
assertion, originalAssertion, toTheoryIdProp, fromTheoryId)) |
935 |
|
{ |
936 |
|
// Is it preregistered |
937 |
8679091 |
bool preregistered = d_propEngine->isSatLiteral(assertion) && Theory::theoryOf(assertion) == toTheoryId; |
938 |
|
// We assert it |
939 |
8679091 |
theoryOf(toTheoryId)->assertFact(assertion, preregistered); |
940 |
|
// Mark that we have more information |
941 |
8679091 |
d_factsAsserted = true; |
942 |
|
} |
943 |
8794106 |
return; |
944 |
|
} |
945 |
|
|
946 |
|
// Propagations to the SAT solver are just enqueued for pickup by |
947 |
|
// the SAT solver later |
948 |
15375979 |
if (toTheoryId == THEORY_SAT_SOLVER) { |
949 |
11494862 |
Assert(toTheoryIdProp == toTheoryId); |
950 |
11494862 |
if (markPropagation(assertion, originalAssertion, toTheoryId, fromTheoryId)) { |
951 |
|
// Enqueue for propagation to the SAT solver |
952 |
6923494 |
d_propagatedLiterals.push_back(assertion); |
953 |
|
// Check for propositional conflicts |
954 |
|
bool value; |
955 |
6923494 |
if (d_propEngine->hasValue(assertion, value) && !value) { |
956 |
79248 |
Trace("theory::propagate") |
957 |
39624 |
<< "TheoryEngine::assertToTheory(" << assertion << ", " |
958 |
39624 |
<< toTheoryId << ", " << fromTheoryId << "): conflict (sharing)" |
959 |
39624 |
<< endl; |
960 |
79248 |
Trace("dtview::conflict") |
961 |
39624 |
<< ":THEORY-CONFLICT: " << assertion << std::endl; |
962 |
39624 |
markInConflict(); |
963 |
|
} |
964 |
|
} |
965 |
11494862 |
return; |
966 |
|
} |
967 |
|
|
968 |
3881117 |
Assert(assertion.getKind() == kind::EQUAL |
969 |
|
|| (assertion.getKind() == kind::NOT |
970 |
|
&& assertion[0].getKind() == kind::EQUAL)); |
971 |
|
|
972 |
|
// Normalize |
973 |
7762234 |
Node normalizedLiteral = Rewriter::rewrite(assertion); |
974 |
|
|
975 |
|
// See if it rewrites false directly -> conflict |
976 |
3881117 |
if (normalizedLiteral.isConst()) { |
977 |
22155 |
if (!normalizedLiteral.getConst<bool>()) { |
978 |
|
// Mark the propagation for explanations |
979 |
419 |
if (markPropagation(normalizedLiteral, |
980 |
|
originalAssertion, |
981 |
|
toTheoryIdProp, |
982 |
|
fromTheoryId)) |
983 |
|
{ |
984 |
|
// special case, trust node has no proof generator |
985 |
838 |
TrustNode trnn = TrustNode::mkTrustConflict(normalizedLiteral); |
986 |
|
// Get the explanation (conflict will figure out where it came from) |
987 |
419 |
conflict(trnn, toTheoryId); |
988 |
|
} else { |
989 |
|
Unreachable(); |
990 |
|
} |
991 |
419 |
return; |
992 |
|
} |
993 |
|
} |
994 |
|
|
995 |
|
// Try and assert (note that we assert the non-normalized one) |
996 |
3880698 |
if (markPropagation( |
997 |
|
assertion, originalAssertion, toTheoryIdProp, fromTheoryId)) |
998 |
|
{ |
999 |
|
// Check if has been pre-registered with the theory |
1000 |
3376321 |
bool preregistered = d_propEngine->isSatLiteral(assertion) && Theory::theoryOf(assertion) == toTheoryId; |
1001 |
|
// Assert away |
1002 |
3376321 |
theoryOf(toTheoryId)->assertFact(assertion, preregistered); |
1003 |
3376321 |
d_factsAsserted = true; |
1004 |
|
} |
1005 |
|
|
1006 |
3880698 |
return; |
1007 |
|
} |
1008 |
|
|
1009 |
13044229 |
void TheoryEngine::assertFact(TNode literal) |
1010 |
|
{ |
1011 |
13044229 |
Trace("theory") << "TheoryEngine::assertFact(" << literal << ")" << endl; |
1012 |
|
|
1013 |
|
// spendResource(); |
1014 |
|
|
1015 |
|
// If we're in conflict, nothing to do |
1016 |
13044229 |
if (d_inConflict) { |
1017 |
19105 |
return; |
1018 |
|
} |
1019 |
|
|
1020 |
|
// Get the atom |
1021 |
13025124 |
bool polarity = literal.getKind() != kind::NOT; |
1022 |
26050248 |
TNode atom = polarity ? literal : literal[0]; |
1023 |
|
|
1024 |
13025124 |
if (d_logicInfo.isSharingEnabled()) { |
1025 |
|
// If any shared terms, it's time to do sharing work |
1026 |
8741327 |
d_sharedSolver->preNotifySharedFact(atom); |
1027 |
|
|
1028 |
|
// If it's an equality, assert it to the shared term manager, even though the terms are not |
1029 |
|
// yet shared. As the terms become shared later, the shared terms manager will then add them |
1030 |
|
// to the assert the equality to the interested theories |
1031 |
8741327 |
if (atom.getKind() == kind::EQUAL) { |
1032 |
|
// Assert it to the the owning theory |
1033 |
4659948 |
assertToTheory(literal, literal, /* to */ Theory::theoryOf(atom), /* from */ THEORY_SAT_SOLVER); |
1034 |
|
// Shared terms manager will assert to interested theories directly, as |
1035 |
|
// the terms become shared |
1036 |
4659948 |
assertToTheory(literal, literal, /* to */ THEORY_BUILTIN, /* from */ THEORY_SAT_SOLVER); |
1037 |
|
|
1038 |
|
// Now, let's check for any atom triggers from lemmas |
1039 |
4659948 |
AtomRequests::atom_iterator it = d_atomRequests.getAtomIterator(atom); |
1040 |
4701062 |
while (!it.done()) { |
1041 |
20557 |
const AtomRequests::Request& request = it.get(); |
1042 |
|
Node toAssert = |
1043 |
41114 |
polarity ? (Node)request.d_atom : request.d_atom.notNode(); |
1044 |
41114 |
Debug("theory::atoms") << "TheoryEngine::assertFact(" << literal |
1045 |
20557 |
<< "): sending requested " << toAssert << endl; |
1046 |
20557 |
assertToTheory( |
1047 |
20557 |
toAssert, literal, request.d_toTheory, THEORY_SAT_SOLVER); |
1048 |
20557 |
it.next(); |
1049 |
|
} |
1050 |
|
|
1051 |
|
} else { |
1052 |
|
// Not an equality, just assert to the appropriate theory |
1053 |
4081379 |
assertToTheory(literal, literal, /* to */ Theory::theoryOf(atom), /* from */ THEORY_SAT_SOLVER); |
1054 |
|
} |
1055 |
|
} else { |
1056 |
|
// Assert the fact to the appropriate theory directly |
1057 |
4283797 |
assertToTheory(literal, literal, /* to */ Theory::theoryOf(atom), /* from */ THEORY_SAT_SOLVER); |
1058 |
|
} |
1059 |
|
} |
1060 |
|
|
1061 |
15681500 |
bool TheoryEngine::propagate(TNode literal, theory::TheoryId theory) { |
1062 |
31363000 |
Debug("theory::propagate") |
1063 |
15681500 |
<< "TheoryEngine::propagate(" << literal << ", " << theory << ")" << endl; |
1064 |
|
|
1065 |
31363000 |
Trace("dtview::prop") << std::string(context()->getLevel(), ' ') |
1066 |
15681500 |
<< ":THEORY-PROP: " << literal << endl; |
1067 |
|
|
1068 |
|
// spendResource(); |
1069 |
|
|
1070 |
|
// Get the atom |
1071 |
15681500 |
bool polarity = literal.getKind() != kind::NOT; |
1072 |
31363000 |
TNode atom = polarity ? literal : literal[0]; |
1073 |
|
|
1074 |
15681500 |
if (d_logicInfo.isSharingEnabled() && atom.getKind() == kind::EQUAL) { |
1075 |
11747714 |
if (d_propEngine->isSatLiteral(literal)) { |
1076 |
|
// We propagate SAT literals to SAT |
1077 |
9423558 |
assertToTheory(literal, literal, /* to */ THEORY_SAT_SOLVER, /* from */ theory); |
1078 |
|
} |
1079 |
11747714 |
if (theory != THEORY_BUILTIN) { |
1080 |
|
// Assert to the shared terms database |
1081 |
6912624 |
assertToTheory(literal, literal, /* to */ THEORY_BUILTIN, /* from */ theory); |
1082 |
|
} |
1083 |
|
} else { |
1084 |
|
// Just send off to the SAT solver |
1085 |
3933786 |
Assert(d_propEngine->isSatLiteral(literal)); |
1086 |
3933786 |
assertToTheory(literal, literal, /* to */ THEORY_SAT_SOLVER, /* from */ theory); |
1087 |
|
} |
1088 |
|
|
1089 |
31363000 |
return !d_inConflict; |
1090 |
|
} |
1091 |
|
|
1092 |
39735 |
const LogicInfo& TheoryEngine::getLogicInfo() const { return d_logicInfo; } |
1093 |
|
|
1094 |
1402 |
bool TheoryEngine::getSepHeapTypes(TypeNode& locType, TypeNode& dataType) const |
1095 |
|
{ |
1096 |
1402 |
if (d_sepLocType.isNull()) |
1097 |
|
{ |
1098 |
1381 |
return false; |
1099 |
|
} |
1100 |
21 |
locType = d_sepLocType; |
1101 |
21 |
dataType = d_sepDataType; |
1102 |
21 |
return true; |
1103 |
|
} |
1104 |
|
|
1105 |
121 |
void TheoryEngine::declareSepHeap(TypeNode locT, TypeNode dataT) |
1106 |
|
{ |
1107 |
121 |
Theory* tsep = theoryOf(THEORY_SEP); |
1108 |
121 |
if (tsep == nullptr) |
1109 |
|
{ |
1110 |
|
Assert(false) << "TheoryEngine::declareSepHeap called without the " |
1111 |
|
"separation logic theory enabled"; |
1112 |
|
return; |
1113 |
|
} |
1114 |
|
|
1115 |
|
// Definition of the statement that is to be run by every theory |
1116 |
|
#ifdef CVC5_FOR_EACH_THEORY_STATEMENT |
1117 |
|
#undef CVC5_FOR_EACH_THEORY_STATEMENT |
1118 |
|
#endif |
1119 |
|
#define CVC5_FOR_EACH_THEORY_STATEMENT(THEORY) \ |
1120 |
|
theoryOf(THEORY)->declareSepHeap(locT, dataT); |
1121 |
|
|
1122 |
|
// notify each theory using the statement above |
1123 |
121 |
CVC5_FOR_EACH_THEORY; |
1124 |
|
|
1125 |
|
// remember the types we have set |
1126 |
119 |
d_sepLocType = locT; |
1127 |
119 |
d_sepDataType = dataT; |
1128 |
|
} |
1129 |
|
|
1130 |
1283263 |
theory::EqualityStatus TheoryEngine::getEqualityStatus(TNode a, TNode b) { |
1131 |
1283263 |
Assert(a.getType().isComparableTo(b.getType())); |
1132 |
1283263 |
return d_sharedSolver->getEqualityStatus(a, b); |
1133 |
|
} |
1134 |
|
|
1135 |
|
const std::unordered_set<TNode>& TheoryEngine::getRelevantAssertions( |
1136 |
|
bool& success) |
1137 |
|
{ |
1138 |
|
// if we are not in SAT mode, or there is no relevance manager, we fail |
1139 |
|
if (!d_inSatMode || d_relManager == nullptr) |
1140 |
|
{ |
1141 |
|
success = false; |
1142 |
|
return d_emptyRelevantSet; |
1143 |
|
} |
1144 |
|
return d_relManager->getRelevantAssertions(success); |
1145 |
|
} |
1146 |
|
|
1147 |
|
void TheoryEngine::getDifficultyMap(std::map<Node, Node>& dmap) |
1148 |
|
{ |
1149 |
|
Assert(d_relManager != nullptr); |
1150 |
|
d_relManager->getDifficultyMap(dmap); |
1151 |
|
} |
1152 |
|
|
1153 |
4586 |
Node TheoryEngine::getModelValue(TNode var) { |
1154 |
4586 |
if (var.isConst()) |
1155 |
|
{ |
1156 |
|
// the model value of a constant must be itself |
1157 |
|
return var; |
1158 |
|
} |
1159 |
4586 |
Assert(d_sharedSolver->isShared(var)); |
1160 |
4586 |
return theoryOf(Theory::theoryOf(var.getType()))->getModelValue(var); |
1161 |
|
} |
1162 |
|
|
1163 |
120899 |
TrustNode TheoryEngine::getExplanation(TNode node) |
1164 |
|
{ |
1165 |
241798 |
Debug("theory::explain") << "TheoryEngine::getExplanation(" << node |
1166 |
120899 |
<< "): current propagation index = " |
1167 |
120899 |
<< d_propagationMapTimestamp << endl; |
1168 |
120899 |
bool polarity = node.getKind() != kind::NOT; |
1169 |
241798 |
TNode atom = polarity ? node : node[0]; |
1170 |
|
|
1171 |
|
// If we're not in shared mode, explanations are simple |
1172 |
120899 |
if (!d_logicInfo.isSharingEnabled()) |
1173 |
|
{ |
1174 |
90932 |
Debug("theory::explain") |
1175 |
45466 |
<< "TheoryEngine::getExplanation: sharing is NOT enabled. " |
1176 |
45466 |
<< " Responsible theory is: " << theoryOf(atom)->getId() << std::endl; |
1177 |
|
|
1178 |
90932 |
TrustNode texplanation = theoryOf(atom)->explain(node); |
1179 |
90932 |
Node explanation = texplanation.getNode(); |
1180 |
90932 |
Debug("theory::explain") << "TheoryEngine::getExplanation(" << node |
1181 |
45466 |
<< ") => " << explanation << endl; |
1182 |
45466 |
if (isProofEnabled()) |
1183 |
|
{ |
1184 |
13029 |
texplanation.debugCheckClosed( |
1185 |
|
"te-proof-exp", "texplanation no share", false); |
1186 |
|
// check if no generator, if so, add THEORY_LEMMA |
1187 |
13029 |
if (texplanation.getGenerator() == nullptr) |
1188 |
|
{ |
1189 |
78 |
Node proven = texplanation.getProven(); |
1190 |
39 |
TheoryId tid = theoryOf(atom)->getId(); |
1191 |
78 |
Node tidn = builtin::BuiltinProofRuleChecker::mkTheoryIdNode(tid); |
1192 |
39 |
d_lazyProof->addStep(proven, PfRule::THEORY_LEMMA, {}, {proven, tidn}); |
1193 |
39 |
texplanation = |
1194 |
78 |
TrustNode::mkTrustPropExp(node, explanation, d_lazyProof.get()); |
1195 |
|
} |
1196 |
|
} |
1197 |
45466 |
return texplanation; |
1198 |
|
} |
1199 |
|
|
1200 |
150866 |
Debug("theory::explain") << "TheoryEngine::getExplanation: sharing IS enabled" |
1201 |
75433 |
<< std::endl; |
1202 |
|
|
1203 |
|
// Initial thing to explain |
1204 |
150866 |
NodeTheoryPair toExplain(node, THEORY_SAT_SOLVER, d_propagationMapTimestamp); |
1205 |
75433 |
Assert(d_propagationMap.find(toExplain) != d_propagationMap.end()); |
1206 |
|
|
1207 |
150866 |
NodeTheoryPair nodeExplainerPair = d_propagationMap[toExplain]; |
1208 |
150866 |
Debug("theory::explain") |
1209 |
75433 |
<< "TheoryEngine::getExplanation: explainer for node " |
1210 |
75433 |
<< nodeExplainerPair.d_node |
1211 |
75433 |
<< " is theory: " << nodeExplainerPair.d_theory << std::endl; |
1212 |
|
|
1213 |
|
// Create the workplace for explanations |
1214 |
150866 |
std::vector<NodeTheoryPair> vec{d_propagationMap[toExplain]}; |
1215 |
|
// Process the explanation |
1216 |
150866 |
TrustNode texplanation = getExplanation(vec); |
1217 |
150866 |
Debug("theory::explain") << "TheoryEngine::getExplanation(" << node << ") => " |
1218 |
75433 |
<< texplanation.getNode() << endl; |
1219 |
75433 |
return texplanation; |
1220 |
|
} |
1221 |
|
|
1222 |
80846 |
struct AtomsCollect { |
1223 |
|
|
1224 |
|
std::vector<TNode> d_atoms; |
1225 |
|
std::unordered_set<TNode> d_visited; |
1226 |
|
|
1227 |
|
public: |
1228 |
|
typedef void return_type; |
1229 |
|
|
1230 |
496746 |
bool alreadyVisited(TNode current, TNode parent) { |
1231 |
|
// Check if already visited |
1232 |
496746 |
if (d_visited.find(current) != d_visited.end()) return true; |
1233 |
|
// Don't visit non-boolean |
1234 |
457542 |
if (!current.getType().isBoolean()) return true; |
1235 |
|
// New node |
1236 |
373169 |
return false; |
1237 |
|
} |
1238 |
|
|
1239 |
124796 |
void visit(TNode current, TNode parent) { |
1240 |
124796 |
if (Theory::theoryOf(current) != theory::THEORY_BOOL) { |
1241 |
45169 |
d_atoms.push_back(current); |
1242 |
|
} |
1243 |
124796 |
d_visited.insert(current); |
1244 |
124796 |
} |
1245 |
|
|
1246 |
40423 |
void start(TNode node) {} |
1247 |
40423 |
void done(TNode node) {} |
1248 |
|
|
1249 |
40423 |
std::vector<TNode> getAtoms() const { |
1250 |
40423 |
return d_atoms; |
1251 |
|
} |
1252 |
|
}; |
1253 |
|
|
1254 |
40423 |
void TheoryEngine::ensureLemmaAtoms(TNode n, theory::TheoryId atomsTo) |
1255 |
|
{ |
1256 |
40423 |
Assert(atomsTo != THEORY_LAST); |
1257 |
80846 |
Debug("theory::atoms") << "TheoryEngine::ensureLemmaAtoms(" << n << ", " |
1258 |
40423 |
<< atomsTo << ")" << endl; |
1259 |
80846 |
AtomsCollect collectAtoms; |
1260 |
40423 |
NodeVisitor<AtomsCollect>::run(collectAtoms, n); |
1261 |
40423 |
ensureLemmaAtoms(collectAtoms.getAtoms(), atomsTo); |
1262 |
40423 |
} |
1263 |
|
|
1264 |
40423 |
void TheoryEngine::ensureLemmaAtoms(const std::vector<TNode>& atoms, theory::TheoryId atomsTo) { |
1265 |
85592 |
for (unsigned i = 0; i < atoms.size(); ++ i) { |
1266 |
|
|
1267 |
|
// Non-equality atoms are either owned by theory or they don't make sense |
1268 |
45169 |
if (atoms[i].getKind() != kind::EQUAL) { |
1269 |
45757 |
continue; |
1270 |
|
} |
1271 |
|
|
1272 |
|
// The equality |
1273 |
44581 |
Node eq = atoms[i]; |
1274 |
|
// Simple normalization to not repeat stuff |
1275 |
39204 |
if (eq[0] > eq[1]) { |
1276 |
|
eq = eq[1].eqNode(eq[0]); |
1277 |
|
} |
1278 |
|
|
1279 |
|
// Rewrite the equality |
1280 |
44581 |
Node eqNormalized = Rewriter::rewrite(atoms[i]); |
1281 |
|
|
1282 |
78408 |
Debug("theory::atoms") << "TheoryEngine::ensureLemmaAtoms(): " << eq |
1283 |
39204 |
<< " with nf " << eqNormalized << endl; |
1284 |
|
|
1285 |
|
// If the equality is a boolean constant, we send immediately |
1286 |
39204 |
if (eqNormalized.isConst()) { |
1287 |
|
if (eqNormalized.getConst<bool>()) { |
1288 |
|
assertToTheory(eq, eqNormalized, /** to */ atomsTo, /** Sat solver */ theory::THEORY_SAT_SOLVER); |
1289 |
|
} else { |
1290 |
|
assertToTheory(eq.notNode(), eqNormalized.notNode(), /** to */ atomsTo, /** Sat solver */ theory::THEORY_SAT_SOLVER); |
1291 |
|
} |
1292 |
|
continue; |
1293 |
39204 |
}else if( eqNormalized.getKind() != kind::EQUAL){ |
1294 |
|
Assert(eqNormalized.getKind() == kind::BOOLEAN_TERM_VARIABLE |
1295 |
|
|| (eqNormalized.getKind() == kind::NOT |
1296 |
|
&& eqNormalized[0].getKind() == kind::BOOLEAN_TERM_VARIABLE)); |
1297 |
|
// this happens for Boolean term equalities V = true that are rewritten to V, we should skip |
1298 |
|
// TODO : revisit this |
1299 |
|
continue; |
1300 |
|
} |
1301 |
|
|
1302 |
|
// If the normalization did the just flips, keep the flip |
1303 |
39204 |
if (eqNormalized[0] == eq[1] && eqNormalized[1] == eq[0]) { |
1304 |
1589 |
eq = eqNormalized; |
1305 |
|
} |
1306 |
|
|
1307 |
|
// Check if the equality is already known by the sat solver |
1308 |
39204 |
if (d_propEngine->isSatLiteral(eqNormalized)) { |
1309 |
|
bool value; |
1310 |
34500 |
if (d_propEngine->hasValue(eqNormalized, value)) { |
1311 |
67654 |
if (value) { |
1312 |
33827 |
assertToTheory(eq, eqNormalized, atomsTo, theory::THEORY_SAT_SOLVER); |
1313 |
67654 |
continue; |
1314 |
|
} else { |
1315 |
|
assertToTheory(eq.notNode(), eqNormalized.notNode(), atomsTo, theory::THEORY_SAT_SOLVER); |
1316 |
|
continue; |
1317 |
|
} |
1318 |
|
} |
1319 |
|
} |
1320 |
|
|
1321 |
|
// If the theory is asking about a different form, or the form is ok but if will go to a different theory |
1322 |
|
// then we must figure it out |
1323 |
5377 |
if (eqNormalized != eq || Theory::theoryOf(eq) != atomsTo) { |
1324 |
|
// If you get eqNormalized, send atoms[i] to atomsTo |
1325 |
4438 |
d_atomRequests.add(eqNormalized, eq, atomsTo); |
1326 |
|
} |
1327 |
|
} |
1328 |
40423 |
} |
1329 |
|
|
1330 |
447873 |
void TheoryEngine::lemma(TrustNode tlemma, |
1331 |
|
theory::LemmaProperty p, |
1332 |
|
theory::TheoryId from) |
1333 |
|
{ |
1334 |
|
// For resource-limiting (also does a time check). |
1335 |
|
// spendResource(); |
1336 |
447873 |
Assert(tlemma.getKind() == TrustNodeKind::LEMMA |
1337 |
|
|| tlemma.getKind() == TrustNodeKind::CONFLICT); |
1338 |
|
// get the node |
1339 |
895746 |
Node node = tlemma.getNode(); |
1340 |
895746 |
Node lemma = tlemma.getProven(); |
1341 |
|
|
1342 |
447873 |
Assert(!expr::hasFreeVar(lemma)); |
1343 |
|
|
1344 |
|
// when proofs are enabled, we ensure the trust node has a generator by |
1345 |
|
// adding a trust step to the lazy proof maintained by this class |
1346 |
447873 |
if (isProofEnabled()) |
1347 |
|
{ |
1348 |
|
// ensure proof: set THEORY_LEMMA if no generator is provided |
1349 |
67684 |
if (tlemma.getGenerator() == nullptr) |
1350 |
|
{ |
1351 |
|
// internal lemmas should have generators |
1352 |
7014 |
Assert(from != THEORY_LAST); |
1353 |
|
// add theory lemma step to proof |
1354 |
14028 |
Node tidn = builtin::BuiltinProofRuleChecker::mkTheoryIdNode(from); |
1355 |
7014 |
d_lazyProof->addStep(lemma, PfRule::THEORY_LEMMA, {}, {lemma, tidn}); |
1356 |
|
// update the trust node |
1357 |
7014 |
tlemma = TrustNode::mkTrustLemma(lemma, d_lazyProof.get()); |
1358 |
|
} |
1359 |
|
// ensure closed |
1360 |
67684 |
tlemma.debugCheckClosed("te-proof-debug", "TheoryEngine::lemma_initial"); |
1361 |
|
} |
1362 |
|
|
1363 |
447873 |
if(Dump.isOn("t-lemmas")) { |
1364 |
|
// we dump the negation of the lemma, to show validity of the lemma |
1365 |
|
Node n = lemma.negate(); |
1366 |
|
const Printer& printer = d_env.getPrinter(); |
1367 |
|
std::ostream& out = d_env.getDumpOut(); |
1368 |
|
printer.toStreamCmdComment(out, "theory lemma: expect valid"); |
1369 |
|
printer.toStreamCmdCheckSat(out, n); |
1370 |
|
} |
1371 |
|
|
1372 |
|
// assert the lemma |
1373 |
447875 |
d_propEngine->assertLemma(tlemma, p); |
1374 |
|
|
1375 |
|
// If specified, we must add this lemma to the set of those that need to be |
1376 |
|
// justified, where note we pass all auxiliary lemmas in skAsserts as well, |
1377 |
|
// since these by extension must be justified as well. |
1378 |
447871 |
if (d_relManager != nullptr) |
1379 |
|
{ |
1380 |
1118 |
std::vector<Node> skAsserts; |
1381 |
1118 |
std::vector<Node> sks; |
1382 |
|
Node retLemma = |
1383 |
1118 |
d_propEngine->getPreprocessedTerm(tlemma.getProven(), skAsserts, sks); |
1384 |
559 |
if (isLemmaPropertyNeedsJustify(p)) |
1385 |
|
{ |
1386 |
|
d_relManager->notifyPreprocessedAssertion(retLemma); |
1387 |
|
d_relManager->notifyPreprocessedAssertions(skAsserts); |
1388 |
|
} |
1389 |
559 |
d_relManager->notifyLemma(retLemma); |
1390 |
|
} |
1391 |
|
|
1392 |
|
// Mark that we added some lemmas |
1393 |
447871 |
d_lemmasAdded = true; |
1394 |
447871 |
} |
1395 |
|
|
1396 |
205822 |
void TheoryEngine::markInConflict() |
1397 |
|
{ |
1398 |
|
#ifdef CVC5_FOR_EACH_THEORY_STATEMENT |
1399 |
|
#undef CVC5_FOR_EACH_THEORY_STATEMENT |
1400 |
|
#endif |
1401 |
|
#define CVC5_FOR_EACH_THEORY_STATEMENT(THEORY) \ |
1402 |
|
theoryOf(THEORY)->notifyInConflict(); |
1403 |
205822 |
CVC5_FOR_EACH_THEORY; |
1404 |
205822 |
d_inConflict = true; |
1405 |
205822 |
} |
1406 |
|
|
1407 |
132004 |
void TheoryEngine::conflict(TrustNode tconflict, TheoryId theoryId) |
1408 |
|
{ |
1409 |
132004 |
Assert(tconflict.getKind() == TrustNodeKind::CONFLICT); |
1410 |
|
|
1411 |
264008 |
TNode conflict = tconflict.getNode(); |
1412 |
264008 |
Debug("theory::conflict") << "TheoryEngine::conflict(" << conflict << ", " |
1413 |
132004 |
<< theoryId << ")" << endl; |
1414 |
132004 |
Trace("te-proof-debug") << "Check closed conflict" << std::endl; |
1415 |
|
// doesn't require proof generator, yet, since THEORY_LEMMA is added below |
1416 |
132004 |
tconflict.debugCheckClosed( |
1417 |
|
"te-proof-debug", "TheoryEngine::conflict_initial", false); |
1418 |
|
|
1419 |
132004 |
Trace("dtview::conflict") << ":THEORY-CONFLICT: " << conflict << std::endl; |
1420 |
|
|
1421 |
|
// Mark that we are in conflict |
1422 |
132004 |
markInConflict(); |
1423 |
|
|
1424 |
132004 |
if(Dump.isOn("t-conflicts")) { |
1425 |
|
const Printer& printer = d_env.getPrinter(); |
1426 |
|
std::ostream& out = d_env.getDumpOut(); |
1427 |
|
printer.toStreamCmdComment(out, "theory conflict: expect unsat"); |
1428 |
|
printer.toStreamCmdCheckSat(out, conflict); |
1429 |
|
} |
1430 |
|
|
1431 |
|
// In the multiple-theories case, we need to reconstruct the conflict |
1432 |
132004 |
if (d_logicInfo.isSharingEnabled()) { |
1433 |
|
// Create the workplace for explanations |
1434 |
219946 |
std::vector<NodeTheoryPair> vec; |
1435 |
109973 |
vec.push_back( |
1436 |
219946 |
NodeTheoryPair(conflict, theoryId, d_propagationMapTimestamp)); |
1437 |
|
|
1438 |
|
// Process the explanation |
1439 |
219946 |
TrustNode tncExp = getExplanation(vec); |
1440 |
219946 |
Trace("te-proof-debug") |
1441 |
109973 |
<< "Check closed conflict explained with sharing" << std::endl; |
1442 |
109973 |
tncExp.debugCheckClosed("te-proof-debug", |
1443 |
|
"TheoryEngine::conflict_explained_sharing"); |
1444 |
219946 |
Node fullConflict = tncExp.getNode(); |
1445 |
|
|
1446 |
109973 |
if (isProofEnabled()) |
1447 |
|
{ |
1448 |
14430 |
Trace("te-proof-debug") << "Process conflict: " << conflict << std::endl; |
1449 |
28860 |
Trace("te-proof-debug") << "Conflict " << tconflict << " from " |
1450 |
14430 |
<< tconflict.identifyGenerator() << std::endl; |
1451 |
28860 |
Trace("te-proof-debug") << "Explanation " << tncExp << " from " |
1452 |
14430 |
<< tncExp.identifyGenerator() << std::endl; |
1453 |
14430 |
Assert(d_lazyProof != nullptr); |
1454 |
14430 |
if (tconflict.getGenerator() != nullptr) |
1455 |
|
{ |
1456 |
13986 |
d_lazyProof->addLazyStep(tconflict.getProven(), |
1457 |
|
tconflict.getGenerator()); |
1458 |
|
} |
1459 |
|
else |
1460 |
|
{ |
1461 |
|
// add theory lemma step |
1462 |
888 |
Node tidn = builtin::BuiltinProofRuleChecker::mkTheoryIdNode(theoryId); |
1463 |
888 |
Node conf = tconflict.getProven(); |
1464 |
444 |
d_lazyProof->addStep(conf, PfRule::THEORY_LEMMA, {}, {conf, tidn}); |
1465 |
|
} |
1466 |
|
// store the explicit step, which should come from a different |
1467 |
|
// generator, e.g. d_tepg. |
1468 |
28860 |
Node proven = tncExp.getProven(); |
1469 |
14430 |
Assert(tncExp.getGenerator() != d_lazyProof.get()); |
1470 |
28860 |
Trace("te-proof-debug") << "add lazy step " << tncExp.identifyGenerator() |
1471 |
14430 |
<< " for " << proven << std::endl; |
1472 |
14430 |
d_lazyProof->addLazyStep(proven, tncExp.getGenerator()); |
1473 |
14430 |
pfgEnsureClosed(proven, |
1474 |
14430 |
d_lazyProof.get(), |
1475 |
|
"te-proof-debug", |
1476 |
|
"TheoryEngine::conflict_during"); |
1477 |
28860 |
Node fullConflictNeg = fullConflict.notNode(); |
1478 |
28860 |
std::vector<Node> children; |
1479 |
14430 |
children.push_back(proven); |
1480 |
28860 |
std::vector<Node> args; |
1481 |
14430 |
args.push_back(fullConflictNeg); |
1482 |
14430 |
if (conflict == d_false) |
1483 |
|
{ |
1484 |
120 |
AlwaysAssert(proven == fullConflictNeg); |
1485 |
|
} |
1486 |
|
else |
1487 |
|
{ |
1488 |
14310 |
if (fullConflict != conflict) |
1489 |
|
{ |
1490 |
|
// ------------------------- explained ---------- from theory |
1491 |
|
// fullConflict => conflict ~conflict |
1492 |
|
// ------------------------------------------ MACRO_SR_PRED_TRANSFORM |
1493 |
|
// ~fullConflict |
1494 |
13842 |
children.push_back(conflict.notNode()); |
1495 |
13842 |
args.push_back(mkMethodId(MethodId::SB_LITERAL)); |
1496 |
13842 |
d_lazyProof->addStep( |
1497 |
|
fullConflictNeg, PfRule::MACRO_SR_PRED_TRANSFORM, children, args); |
1498 |
|
} |
1499 |
|
} |
1500 |
|
} |
1501 |
|
// pass the processed trust node |
1502 |
|
TrustNode tconf = |
1503 |
219946 |
TrustNode::mkTrustConflict(fullConflict, d_lazyProof.get()); |
1504 |
219946 |
Debug("theory::conflict") |
1505 |
109973 |
<< "TheoryEngine::conflict(" << conflict << ", " << theoryId |
1506 |
109973 |
<< "): full = " << fullConflict << endl; |
1507 |
109973 |
Assert(properConflict(fullConflict)); |
1508 |
219946 |
Trace("te-proof-debug") |
1509 |
109973 |
<< "Check closed conflict with sharing" << std::endl; |
1510 |
109973 |
tconf.debugCheckClosed("te-proof-debug", "TheoryEngine::conflict:sharing"); |
1511 |
109973 |
lemma(tconf, LemmaProperty::REMOVABLE); |
1512 |
|
} else { |
1513 |
|
// When only one theory, the conflict should need no processing |
1514 |
22031 |
Assert(properConflict(conflict)); |
1515 |
|
// pass the trust node that was sent from the theory |
1516 |
22031 |
lemma(tconflict, LemmaProperty::REMOVABLE, theoryId); |
1517 |
|
} |
1518 |
132004 |
} |
1519 |
|
|
1520 |
2075 |
void TheoryEngine::setIncomplete(theory::TheoryId theory, |
1521 |
|
theory::IncompleteId id) |
1522 |
|
{ |
1523 |
2075 |
d_incomplete = true; |
1524 |
2075 |
d_incompleteTheory = theory; |
1525 |
2075 |
d_incompleteId = id; |
1526 |
2075 |
} |
1527 |
|
|
1528 |
185406 |
TrustNode TheoryEngine::getExplanation( |
1529 |
|
std::vector<NodeTheoryPair>& explanationVector) |
1530 |
|
{ |
1531 |
185406 |
Assert(explanationVector.size() == 1); |
1532 |
370812 |
Node conclusion = explanationVector[0].d_node; |
1533 |
|
// if the theory explains using the central equality engine, we always start |
1534 |
|
// with THEORY_BUILTIN. |
1535 |
185406 |
if (Theory::expUsingCentralEqualityEngine(explanationVector[0].d_theory)) |
1536 |
|
{ |
1537 |
41590 |
explanationVector[0].d_theory = THEORY_BUILTIN; |
1538 |
|
} |
1539 |
370812 |
std::shared_ptr<LazyCDProof> lcp; |
1540 |
185406 |
if (isProofEnabled()) |
1541 |
|
{ |
1542 |
40116 |
Trace("te-proof-exp") << "=== TheoryEngine::getExplanation " << conclusion |
1543 |
20058 |
<< std::endl; |
1544 |
40116 |
lcp.reset(new LazyCDProof( |
1545 |
20058 |
d_pnm, nullptr, nullptr, "TheoryEngine::LazyCDProof::getExplanation")); |
1546 |
|
} |
1547 |
185406 |
unsigned i = 0; // Index of the current literal we are processing |
1548 |
|
|
1549 |
370812 |
std::unique_ptr<std::set<Node>> inputAssertions = nullptr; |
1550 |
|
// the overall explanation |
1551 |
370812 |
std::set<TNode> exp; |
1552 |
|
// vector of trust nodes to explain at the end |
1553 |
370812 |
std::vector<std::pair<TheoryId, TrustNode>> texplains; |
1554 |
|
// cache of nodes we have already explained by some theory |
1555 |
370812 |
std::unordered_map<Node, size_t> cache; |
1556 |
|
|
1557 |
8258226 |
while (i < explanationVector.size()) { |
1558 |
|
// Get the current literal to explain |
1559 |
4389857 |
NodeTheoryPair toExplain = explanationVector[i]; |
1560 |
|
|
1561 |
8072820 |
Debug("theory::explain") |
1562 |
4036410 |
<< "[i=" << i << "] TheoryEngine::explain(): processing [" |
1563 |
4036410 |
<< toExplain.d_timestamp << "] " << toExplain.d_node << " sent from " |
1564 |
4036410 |
<< toExplain.d_theory << endl; |
1565 |
|
|
1566 |
8200014 |
if (cache.find(toExplain.d_node) != cache.end() |
1567 |
4036410 |
&& cache[toExplain.d_node] < toExplain.d_timestamp) |
1568 |
|
{ |
1569 |
127194 |
++i; |
1570 |
127194 |
continue; |
1571 |
|
} |
1572 |
3909216 |
cache[toExplain.d_node] = toExplain.d_timestamp; |
1573 |
|
|
1574 |
|
// If a true constant or a negation of a false constant we can ignore it |
1575 |
7831728 |
if ((toExplain.d_node.isConst() && toExplain.d_node.getConst<bool>()) |
1576 |
11727648 |
|| (toExplain.d_node.getKind() == kind::NOT |
1577 |
4353741 |
&& toExplain.d_node[0].isConst() |
1578 |
3909216 |
&& !toExplain.d_node[0].getConst<bool>())) |
1579 |
|
{ |
1580 |
12877 |
++ i; |
1581 |
|
// if we are building a proof |
1582 |
12877 |
if (lcp != nullptr) |
1583 |
|
{ |
1584 |
2880 |
Trace("te-proof-exp") |
1585 |
1440 |
<< "- explain " << toExplain.d_node << " trivially..." << std::endl; |
1586 |
|
// ------------------MACRO_SR_PRED_INTRO |
1587 |
|
// toExplain.d_node |
1588 |
2880 |
std::vector<Node> children; |
1589 |
2880 |
std::vector<Node> args; |
1590 |
1440 |
args.push_back(toExplain.d_node); |
1591 |
1440 |
lcp->addStep( |
1592 |
|
toExplain.d_node, PfRule::MACRO_SR_PRED_INTRO, children, args); |
1593 |
|
} |
1594 |
12877 |
continue; |
1595 |
|
} |
1596 |
|
|
1597 |
|
// If from the SAT solver, keep it |
1598 |
5280324 |
if (toExplain.d_theory == THEORY_SAT_SOLVER) |
1599 |
|
{ |
1600 |
2767970 |
Debug("theory::explain") |
1601 |
1383985 |
<< "\tLiteral came from THEORY_SAT_SOLVER. Keeping it." << endl; |
1602 |
1383985 |
exp.insert(explanationVector[i++].d_node); |
1603 |
|
// it will be a free assumption in the proof |
1604 |
1383985 |
Trace("te-proof-exp") << "- keep " << toExplain.d_node << std::endl; |
1605 |
1383985 |
continue; |
1606 |
|
} |
1607 |
|
|
1608 |
|
// If an and, expand it |
1609 |
2512354 |
if (toExplain.d_node.getKind() == kind::AND) |
1610 |
|
{ |
1611 |
749378 |
Debug("theory::explain") |
1612 |
374689 |
<< "TheoryEngine::explain(): expanding " << toExplain.d_node |
1613 |
374689 |
<< " got from " << toExplain.d_theory << endl; |
1614 |
374689 |
size_t nchild = toExplain.d_node.getNumChildren(); |
1615 |
2088028 |
for (size_t k = 0; k < nchild; ++k) |
1616 |
|
{ |
1617 |
|
NodeTheoryPair newExplain( |
1618 |
3426678 |
toExplain.d_node[k], toExplain.d_theory, toExplain.d_timestamp); |
1619 |
1713339 |
explanationVector.push_back(newExplain); |
1620 |
|
} |
1621 |
374689 |
if (lcp != nullptr) |
1622 |
|
{ |
1623 |
92084 |
Trace("te-proof-exp") |
1624 |
46042 |
<< "- AND expand " << toExplain.d_node << std::endl; |
1625 |
|
// delay explanation, use a dummy trust node |
1626 |
|
TrustNode tnAndExp = TrustNode::mkTrustPropExp( |
1627 |
92084 |
toExplain.d_node, toExplain.d_node, nullptr); |
1628 |
46042 |
texplains.push_back( |
1629 |
92084 |
std::pair<TheoryId, TrustNode>(THEORY_LAST, tnAndExp)); |
1630 |
|
} |
1631 |
374689 |
++ i; |
1632 |
374689 |
continue; |
1633 |
|
} |
1634 |
|
|
1635 |
|
// See if it was sent to the theory by another theory |
1636 |
2137665 |
PropagationMap::const_iterator find = d_propagationMap.find(toExplain); |
1637 |
2137665 |
if (find != d_propagationMap.end()) { |
1638 |
4063620 |
Debug("theory::explain") |
1639 |
2031810 |
<< "\tTerm was propagated by another theory (theory = " |
1640 |
2031810 |
<< getTheoryString((*find).second.d_theory) << ")" << std::endl; |
1641 |
|
// There is some propagation, check if its a timely one |
1642 |
2031810 |
if ((*find).second.d_timestamp < toExplain.d_timestamp) |
1643 |
|
{ |
1644 |
3568436 |
Debug("theory::explain") |
1645 |
1784218 |
<< "\tRelevant timetsamp, pushing " << (*find).second.d_node |
1646 |
1784218 |
<< "to index = " << explanationVector.size() << std::endl; |
1647 |
1784218 |
explanationVector.push_back((*find).second); |
1648 |
1784218 |
++i; |
1649 |
|
|
1650 |
1784218 |
if (lcp != nullptr) |
1651 |
|
{ |
1652 |
214073 |
if (!CDProof::isSame(toExplain.d_node, (*find).second.d_node)) |
1653 |
|
{ |
1654 |
6708 |
Trace("te-proof-exp") |
1655 |
3354 |
<< "- t-explained cached: " << toExplain.d_node << " by " |
1656 |
3354 |
<< (*find).second.d_node << std::endl; |
1657 |
|
// delay explanation, use a dummy trust node that says that |
1658 |
|
// (*find).second.d_node explains toExplain.d_node. |
1659 |
|
TrustNode tnRewExp = TrustNode::mkTrustPropExp( |
1660 |
6708 |
toExplain.d_node, (*find).second.d_node, nullptr); |
1661 |
3354 |
texplains.push_back( |
1662 |
6708 |
std::pair<TheoryId, TrustNode>(THEORY_LAST, tnRewExp)); |
1663 |
|
} |
1664 |
|
} |
1665 |
1784218 |
continue; |
1666 |
|
} |
1667 |
|
} |
1668 |
|
// It was produced by the theory, so ask for an explanation |
1669 |
|
TrustNode texplanation = |
1670 |
706894 |
d_sharedSolver->explain(toExplain.d_node, toExplain.d_theory); |
1671 |
353447 |
if (lcp != nullptr) |
1672 |
|
{ |
1673 |
44264 |
texplanation.debugCheckClosed("te-proof-exp", "texplanation", false); |
1674 |
88528 |
Trace("te-proof-exp") |
1675 |
44264 |
<< "- t-explained[" << toExplain.d_theory << "]: " << toExplain.d_node |
1676 |
44264 |
<< " by " << texplanation.getNode() << std::endl; |
1677 |
|
// should prove the propagation we asked for |
1678 |
44264 |
Assert(texplanation.getKind() == TrustNodeKind::PROP_EXP |
1679 |
|
&& texplanation.getProven()[1] == toExplain.d_node); |
1680 |
|
// if not a trivial explanation |
1681 |
44264 |
if (!CDProof::isSame(texplanation.getNode(), toExplain.d_node)) |
1682 |
|
{ |
1683 |
|
// We add it to the list of theory explanations, to be processed at |
1684 |
|
// the end of this method. We wait to explain here because it may |
1685 |
|
// be that a later explanation may preempt the need for proving this |
1686 |
|
// step. For instance, if the conclusion lit is later added as an |
1687 |
|
// assumption in the final explanation. This avoids cyclic proofs. |
1688 |
41221 |
texplains.push_back( |
1689 |
82442 |
std::pair<TheoryId, TrustNode>(toExplain.d_theory, texplanation)); |
1690 |
|
} |
1691 |
|
} |
1692 |
706894 |
Node explanation = texplanation.getNode(); |
1693 |
|
|
1694 |
706894 |
Debug("theory::explain") |
1695 |
353447 |
<< "TheoryEngine::explain(): got explanation " << explanation |
1696 |
353447 |
<< " got from " << toExplain.d_theory << endl; |
1697 |
353447 |
Assert(explanation != toExplain.d_node) |
1698 |
|
<< "wasn't sent to you, so why are you explaining it trivially, for " |
1699 |
|
"fact " |
1700 |
|
<< explanation; |
1701 |
|
// Mark the explanation |
1702 |
|
NodeTheoryPair newExplain( |
1703 |
706894 |
explanation, toExplain.d_theory, toExplain.d_timestamp); |
1704 |
353447 |
explanationVector.push_back(newExplain); |
1705 |
|
|
1706 |
353447 |
++ i; |
1707 |
|
} |
1708 |
|
|
1709 |
|
// make the explanation node |
1710 |
370812 |
Node expNode; |
1711 |
185406 |
if (exp.size() == 0) |
1712 |
|
{ |
1713 |
|
// Normalize to true |
1714 |
43 |
expNode = NodeManager::currentNM()->mkConst<bool>(true); |
1715 |
|
} |
1716 |
185363 |
else if (exp.size() == 1) |
1717 |
|
{ |
1718 |
|
// All the same, or just one |
1719 |
6022 |
expNode = *exp.begin(); |
1720 |
|
} |
1721 |
|
else |
1722 |
|
{ |
1723 |
358682 |
NodeBuilder conjunction(kind::AND); |
1724 |
179341 |
std::set<TNode>::const_iterator it = exp.begin(); |
1725 |
179341 |
std::set<TNode>::const_iterator it_end = exp.end(); |
1726 |
2845063 |
while (it != it_end) |
1727 |
|
{ |
1728 |
1332861 |
conjunction << *it; |
1729 |
1332861 |
++it; |
1730 |
|
} |
1731 |
179341 |
expNode = conjunction; |
1732 |
|
} |
1733 |
|
// if we are building a proof, go back through the explanations and |
1734 |
|
// build the proof |
1735 |
185406 |
if (lcp != nullptr) |
1736 |
|
{ |
1737 |
20058 |
if (Trace.isOn("te-proof-exp")) |
1738 |
|
{ |
1739 |
|
Trace("te-proof-exp") << "Explanation is:" << std::endl; |
1740 |
|
for (TNode e : exp) |
1741 |
|
{ |
1742 |
|
Trace("te-proof-exp") << " " << e << std::endl; |
1743 |
|
} |
1744 |
|
Trace("te-proof-exp") << "=== Replay explanations..." << std::endl; |
1745 |
|
} |
1746 |
|
// Now, go back and add the necessary steps of theory explanations, i.e. |
1747 |
|
// add those that prove things that aren't in the final explanation. We |
1748 |
|
// iterate in reverse order so that most recent steps take priority. This |
1749 |
|
// avoids cyclic proofs in the lazy proof we are building (lcp). |
1750 |
90617 |
for (std::vector<std::pair<TheoryId, TrustNode>>::reverse_iterator |
1751 |
20058 |
it = texplains.rbegin(), |
1752 |
20058 |
itEnd = texplains.rend(); |
1753 |
110675 |
it != itEnd; |
1754 |
|
++it) |
1755 |
|
{ |
1756 |
130250 |
TrustNode trn = it->second; |
1757 |
90617 |
Assert(trn.getKind() == TrustNodeKind::PROP_EXP); |
1758 |
130250 |
Node proven = trn.getProven(); |
1759 |
90617 |
Assert(proven.getKind() == kind::IMPLIES); |
1760 |
130250 |
Node tConc = proven[1]; |
1761 |
90617 |
Trace("te-proof-exp") << "- Process " << trn << std::endl; |
1762 |
94475 |
if (exp.find(tConc) != exp.end()) |
1763 |
|
{ |
1764 |
|
// already added to proof |
1765 |
3858 |
Trace("te-proof-exp") << "...already added" << std::endl; |
1766 |
3858 |
continue; |
1767 |
|
} |
1768 |
126392 |
Node symTConc = CDProof::getSymmFact(tConc); |
1769 |
86759 |
if (!symTConc.isNull()) |
1770 |
|
{ |
1771 |
39138 |
if (exp.find(symTConc) != exp.end()) |
1772 |
|
{ |
1773 |
|
// symmetric direction |
1774 |
57 |
Trace("te-proof-exp") << "...already added (SYMM)" << std::endl; |
1775 |
57 |
continue; |
1776 |
|
} |
1777 |
|
} |
1778 |
|
// remember that we've explained this formula, to avoid cycles in lcp |
1779 |
86702 |
exp.insert(tConc); |
1780 |
86702 |
TheoryId ttid = it->first; |
1781 |
126335 |
Node tExp = proven[0]; |
1782 |
86702 |
if (ttid == THEORY_LAST) |
1783 |
|
{ |
1784 |
47069 |
if (tConc == tExp) |
1785 |
|
{ |
1786 |
|
// dummy trust node, do AND expansion |
1787 |
44945 |
Assert(tConc.getKind() == kind::AND); |
1788 |
|
// tConc[0] ... tConc[n] |
1789 |
|
// ---------------------- AND_INTRO |
1790 |
|
// tConc |
1791 |
89890 |
std::vector<Node> pfChildren; |
1792 |
44945 |
pfChildren.insert(pfChildren.end(), tConc.begin(), tConc.end()); |
1793 |
44945 |
lcp->addStep(tConc, PfRule::AND_INTRO, pfChildren, {}); |
1794 |
44945 |
Trace("te-proof-exp") << "...via AND_INTRO" << std::endl; |
1795 |
44945 |
continue; |
1796 |
|
} |
1797 |
|
// otherwise should hold by rewriting |
1798 |
2124 |
Assert(Rewriter::rewrite(tConc) == Rewriter::rewrite(tExp)); |
1799 |
|
// tExp |
1800 |
|
// ---- MACRO_SR_PRED_TRANSFORM |
1801 |
|
// tConc |
1802 |
2124 |
lcp->addStep(tConc, PfRule::MACRO_SR_PRED_TRANSFORM, {tExp}, {tConc}); |
1803 |
2124 |
Trace("te-proof-exp") << "...via MACRO_SR_PRED_TRANSFORM" << std::endl; |
1804 |
2124 |
continue; |
1805 |
|
} |
1806 |
39633 |
if (tExp == tConc) |
1807 |
|
{ |
1808 |
|
// trivial |
1809 |
|
Trace("te-proof-exp") << "...trivial" << std::endl; |
1810 |
|
continue; |
1811 |
|
} |
1812 |
|
// ------------- Via theory |
1813 |
|
// tExp tExp => tConc |
1814 |
|
// ---------------------------------MODUS_PONENS |
1815 |
|
// tConc |
1816 |
39633 |
if (trn.getGenerator() != nullptr) |
1817 |
|
{ |
1818 |
38889 |
Trace("te-proof-exp") << "...via theory generator" << std::endl; |
1819 |
38889 |
lcp->addLazyStep(proven, trn.getGenerator()); |
1820 |
|
} |
1821 |
|
else |
1822 |
|
{ |
1823 |
744 |
Trace("te-proof-exp") << "...via trust THEORY_LEMMA" << std::endl; |
1824 |
|
// otherwise, trusted theory lemma |
1825 |
1488 |
Node tidn = builtin::BuiltinProofRuleChecker::mkTheoryIdNode(it->first); |
1826 |
744 |
lcp->addStep(proven, PfRule::THEORY_LEMMA, {}, {proven, tidn}); |
1827 |
|
} |
1828 |
79266 |
std::vector<Node> pfChildren; |
1829 |
39633 |
pfChildren.push_back(trn.getNode()); |
1830 |
39633 |
pfChildren.push_back(proven); |
1831 |
39633 |
lcp->addStep(tConc, PfRule::MODUS_PONENS, pfChildren, {}); |
1832 |
|
} |
1833 |
|
// store in the proof generator |
1834 |
40116 |
TrustNode trn = d_tepg->mkTrustExplain(conclusion, expNode, lcp); |
1835 |
|
// return the trust node |
1836 |
20058 |
return trn; |
1837 |
|
} |
1838 |
|
|
1839 |
165348 |
return TrustNode::mkTrustPropExp(conclusion, expNode, nullptr); |
1840 |
|
} |
1841 |
|
|
1842 |
788718 |
bool TheoryEngine::isProofEnabled() const { return d_pnm != nullptr; } |
1843 |
|
|
1844 |
2141 |
void TheoryEngine::checkTheoryAssertionsWithModel(bool hardFailure) { |
1845 |
29974 |
for(TheoryId theoryId = THEORY_FIRST; theoryId < THEORY_LAST; ++theoryId) { |
1846 |
27833 |
Theory* theory = d_theoryTable[theoryId]; |
1847 |
27833 |
if(theory && d_logicInfo.isTheoryEnabled(theoryId)) { |
1848 |
113984 |
for(context::CDList<Assertion>::const_iterator it = theory->facts_begin(), |
1849 |
12992 |
it_end = theory->facts_end(); |
1850 |
113984 |
it != it_end; |
1851 |
|
++it) { |
1852 |
201984 |
Node assertion = (*it).d_assertion; |
1853 |
100992 |
if (!isRelevant(assertion)) |
1854 |
|
{ |
1855 |
|
// not relevant, skip |
1856 |
|
continue; |
1857 |
|
} |
1858 |
201984 |
Node val = d_tc->getModel()->getValue(assertion); |
1859 |
100992 |
if (val != d_true) |
1860 |
|
{ |
1861 |
12 |
std::stringstream ss; |
1862 |
12 |
ss << " " << theoryId |
1863 |
12 |
<< " has an asserted fact that the model doesn't satisfy." << endl |
1864 |
12 |
<< "The fact: " << assertion << endl |
1865 |
6 |
<< "Model value: " << val << endl; |
1866 |
6 |
if (hardFailure) |
1867 |
|
{ |
1868 |
6 |
if (val == d_false) |
1869 |
|
{ |
1870 |
|
// Always an error if it is false |
1871 |
|
InternalError() << ss.str(); |
1872 |
|
} |
1873 |
|
else |
1874 |
|
{ |
1875 |
|
// Otherwise just a warning. Notice this case may happen for |
1876 |
|
// assertions with unevaluable operators, e.g. transcendental |
1877 |
|
// functions. It also may happen for separation logic, where |
1878 |
|
// check-model support is limited. |
1879 |
6 |
Warning() << ss.str(); |
1880 |
|
} |
1881 |
|
} |
1882 |
|
} |
1883 |
|
} |
1884 |
|
} |
1885 |
|
} |
1886 |
2141 |
} |
1887 |
|
|
1888 |
8517 |
std::pair<bool, Node> TheoryEngine::entailmentCheck(options::TheoryOfMode mode, |
1889 |
|
TNode lit) |
1890 |
|
{ |
1891 |
17034 |
TNode atom = (lit.getKind() == kind::NOT) ? lit[0] : lit; |
1892 |
8517 |
if( atom.getKind()==kind::AND || atom.getKind()==kind::OR || atom.getKind()==kind::IMPLIES ){ |
1893 |
|
//Boolean connective, recurse |
1894 |
|
std::vector< Node > children; |
1895 |
|
bool pol = (lit.getKind()!=kind::NOT); |
1896 |
|
bool is_conjunction = pol==(lit.getKind()==kind::AND); |
1897 |
|
for( unsigned i=0; i<atom.getNumChildren(); i++ ){ |
1898 |
|
Node ch = atom[i]; |
1899 |
|
if( pol==( lit.getKind()==kind::IMPLIES && i==0 ) ){ |
1900 |
|
ch = atom[i].negate(); |
1901 |
|
} |
1902 |
|
std::pair<bool, Node> chres = entailmentCheck(mode, ch); |
1903 |
|
if( chres.first ){ |
1904 |
|
if( !is_conjunction ){ |
1905 |
|
return chres; |
1906 |
|
}else{ |
1907 |
|
children.push_back( chres.second ); |
1908 |
|
} |
1909 |
|
}else if( !chres.first && is_conjunction ){ |
1910 |
|
return std::pair<bool, Node>(false, Node::null()); |
1911 |
|
} |
1912 |
|
} |
1913 |
|
if( is_conjunction ){ |
1914 |
|
return std::pair<bool, Node>(true, NodeManager::currentNM()->mkNode(kind::AND, children)); |
1915 |
|
}else{ |
1916 |
|
return std::pair<bool, Node>(false, Node::null()); |
1917 |
|
} |
1918 |
8517 |
}else if( atom.getKind()==kind::ITE || ( atom.getKind()==kind::EQUAL && atom[0].getType().isBoolean() ) ){ |
1919 |
|
bool pol = (lit.getKind()!=kind::NOT); |
1920 |
|
for( unsigned r=0; r<2; r++ ){ |
1921 |
|
Node ch = atom[0]; |
1922 |
|
if( r==1 ){ |
1923 |
|
ch = ch.negate(); |
1924 |
|
} |
1925 |
|
std::pair<bool, Node> chres = entailmentCheck(mode, ch); |
1926 |
|
if( chres.first ){ |
1927 |
|
Node ch2 = atom[ atom.getKind()==kind::ITE ? r+1 : 1 ]; |
1928 |
|
if( pol==( atom.getKind()==kind::ITE ? true : r==1 ) ){ |
1929 |
|
ch2 = ch2.negate(); |
1930 |
|
} |
1931 |
|
std::pair<bool, Node> chres2 = entailmentCheck(mode, ch2); |
1932 |
|
if( chres2.first ){ |
1933 |
|
return std::pair<bool, Node>(true, NodeManager::currentNM()->mkNode(kind::AND, chres.second, chres2.second)); |
1934 |
|
}else{ |
1935 |
|
break; |
1936 |
|
} |
1937 |
|
} |
1938 |
|
} |
1939 |
|
return std::pair<bool, Node>(false, Node::null()); |
1940 |
|
}else{ |
1941 |
|
//it is a theory atom |
1942 |
8517 |
theory::TheoryId tid = theory::Theory::theoryOf(mode, atom); |
1943 |
8517 |
theory::Theory* th = theoryOf(tid); |
1944 |
|
|
1945 |
8517 |
Assert(th != NULL); |
1946 |
8517 |
Trace("theory-engine-entc") << "Entailment check : " << lit << std::endl; |
1947 |
|
|
1948 |
17034 |
std::pair<bool, Node> chres = th->entailmentCheck(lit); |
1949 |
8517 |
return chres; |
1950 |
|
} |
1951 |
|
} |
1952 |
|
|
1953 |
7637028 |
bool TheoryEngine::isFiniteType(TypeNode tn) const |
1954 |
|
{ |
1955 |
7637028 |
return isCardinalityClassFinite(tn.getCardinalityClass(), |
1956 |
15274056 |
options::finiteModelFind()); |
1957 |
|
} |
1958 |
|
|
1959 |
9425357 |
void TheoryEngine::spendResource(Resource r) |
1960 |
|
{ |
1961 |
9425357 |
d_env.getResourceManager()->spendResource(r); |
1962 |
9425357 |
} |
1963 |
|
|
1964 |
3783 |
void TheoryEngine::initializeProofChecker(ProofChecker* pc) |
1965 |
|
{ |
1966 |
52962 |
for (theory::TheoryId id = theory::THEORY_FIRST; id < theory::THEORY_LAST; |
1967 |
|
++id) |
1968 |
|
{ |
1969 |
49179 |
ProofRuleChecker* prc = d_theoryTable[id]->getProofChecker(); |
1970 |
49179 |
if (prc) |
1971 |
|
{ |
1972 |
34015 |
prc->registerTo(pc); |
1973 |
|
} |
1974 |
|
} |
1975 |
3783 |
} |
1976 |
|
|
1977 |
128957 |
theory::Rewriter* TheoryEngine::getRewriter() { return d_env.getRewriter(); } |
1978 |
|
|
1979 |
29517 |
} // namespace cvc5 |