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 |
1706620 |
std::string getTheoryString(theory::TheoryId id) |
114 |
|
{ |
115 |
1706620 |
if (id == theory::THEORY_SAT_SOLVER) |
116 |
|
{ |
117 |
1184331 |
return "THEORY_SAT_SOLVER"; |
118 |
|
} |
119 |
|
else |
120 |
|
{ |
121 |
1044578 |
std::stringstream ss; |
122 |
522289 |
ss << id; |
123 |
522289 |
return ss.str(); |
124 |
|
} |
125 |
|
} |
126 |
|
|
127 |
9854 |
void TheoryEngine::finishInit() |
128 |
|
{ |
129 |
9854 |
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 |
19708 |
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 |
9854 |
CVC5_FOR_EACH_THEORY; |
146 |
|
|
147 |
|
// Initialize the theory combination architecture |
148 |
9854 |
if (options::tcMode() == options::TcMode::CARE_GRAPH) |
149 |
|
{ |
150 |
9854 |
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 |
9854 |
if (options::relevanceFilter()) |
159 |
|
{ |
160 |
50 |
d_relManager.reset( |
161 |
50 |
new RelevanceManager(d_env.getUserContext(), theory::Valuation(this))); |
162 |
|
} |
163 |
|
|
164 |
|
// initialize the quantifiers engine |
165 |
9854 |
if (d_logicInfo.isQuantified()) |
166 |
|
{ |
167 |
|
// get the quantifiers engine, which is initialized by the quantifiers |
168 |
|
// theory |
169 |
6766 |
d_quantEngine = d_theoryTable[THEORY_QUANTIFIERS]->getQuantifiersEngine(); |
170 |
6766 |
Assert(d_quantEngine != nullptr); |
171 |
|
} |
172 |
|
// finish initializing the quantifiers engine, which must come before |
173 |
|
// initializing theory combination, since quantifiers engine may have a |
174 |
|
// special model builder object |
175 |
9854 |
if (d_logicInfo.isQuantified()) |
176 |
|
{ |
177 |
6766 |
d_quantEngine->finishInit(this); |
178 |
|
} |
179 |
|
// initialize the theory combination manager, which decides and allocates the |
180 |
|
// equality engines to use for all theories. |
181 |
9854 |
d_tc->finishInit(); |
182 |
|
// get pointer to the shared solver |
183 |
9854 |
d_sharedSolver = d_tc->getSharedSolver(); |
184 |
|
|
185 |
|
// finish initializing the theories by linking them with the appropriate |
186 |
|
// utilities and then calling their finishInit method. |
187 |
137956 |
for(TheoryId theoryId = theory::THEORY_FIRST; theoryId != theory::THEORY_LAST; ++ theoryId) { |
188 |
128102 |
Theory* t = d_theoryTable[theoryId]; |
189 |
128102 |
if (t == nullptr) |
190 |
|
{ |
191 |
|
continue; |
192 |
|
} |
193 |
|
// setup the pointers to the utilities |
194 |
128102 |
const EeTheoryInfo* eeti = d_tc->getEeTheoryInfo(theoryId); |
195 |
128102 |
Assert(eeti != nullptr); |
196 |
|
// the theory's official equality engine is the one specified by the |
197 |
|
// equality engine manager |
198 |
128102 |
t->setEqualityEngine(eeti->d_usedEe); |
199 |
|
// set the quantifiers engine |
200 |
128102 |
t->setQuantifiersEngine(d_quantEngine); |
201 |
|
// set the decision manager for the theory |
202 |
128102 |
t->setDecisionManager(d_decManager.get()); |
203 |
|
// finish initializing the theory |
204 |
128102 |
t->finishInit(); |
205 |
|
} |
206 |
9854 |
Trace("theory") << "End TheoryEngine::finishInit" << std::endl; |
207 |
9854 |
} |
208 |
|
|
209 |
|
ProofNodeManager* TheoryEngine::getProofNodeManager() const { return d_pnm; } |
210 |
|
|
211 |
46189 |
context::Context* TheoryEngine::getSatContext() const |
212 |
|
{ |
213 |
46189 |
return d_env.getContext(); |
214 |
|
} |
215 |
|
|
216 |
11107 |
context::UserContext* TheoryEngine::getUserContext() const |
217 |
|
{ |
218 |
11107 |
return d_env.getUserContext(); |
219 |
|
} |
220 |
|
|
221 |
9854 |
TheoryEngine::TheoryEngine(Env& env) |
222 |
|
: d_propEngine(nullptr), |
223 |
|
d_env(env), |
224 |
9854 |
d_logicInfo(env.getLogicInfo()), |
225 |
9854 |
d_pnm(d_env.isTheoryProofProducing() ? d_env.getProofNodeManager() |
226 |
|
: nullptr), |
227 |
9854 |
d_lazyProof(d_pnm != nullptr |
228 |
|
? new LazyCDProof(d_pnm, |
229 |
|
nullptr, |
230 |
1246 |
d_env.getUserContext(), |
231 |
1246 |
"TheoryEngine::LazyCDProof") |
232 |
|
: nullptr), |
233 |
9854 |
d_tepg(new TheoryEngineProofGenerator(d_pnm, d_env.getUserContext())), |
234 |
|
d_tc(nullptr), |
235 |
|
d_sharedSolver(nullptr), |
236 |
|
d_quantEngine(nullptr), |
237 |
9854 |
d_decManager(new DecisionManager(d_env.getUserContext())), |
238 |
|
d_relManager(nullptr), |
239 |
|
d_eager_model_building(false), |
240 |
9854 |
d_inConflict(d_env.getContext(), false), |
241 |
|
d_inSatMode(false), |
242 |
|
d_hasShutDown(false), |
243 |
9854 |
d_incomplete(d_env.getContext(), false), |
244 |
9854 |
d_incompleteTheory(d_env.getContext(), THEORY_BUILTIN), |
245 |
9854 |
d_incompleteId(d_env.getContext(), IncompleteId::UNKNOWN), |
246 |
9854 |
d_propagationMap(d_env.getContext()), |
247 |
9854 |
d_propagationMapTimestamp(d_env.getContext(), 0), |
248 |
9854 |
d_propagatedLiterals(d_env.getContext()), |
249 |
9854 |
d_propagatedLiteralsIndex(d_env.getContext(), 0), |
250 |
9854 |
d_atomRequests(d_env.getContext()), |
251 |
9854 |
d_combineTheoriesTime(smtStatisticsRegistry().registerTimer( |
252 |
19708 |
"TheoryEngine::combineTheoriesTime")), |
253 |
|
d_true(), |
254 |
|
d_false(), |
255 |
|
d_interrupted(false), |
256 |
|
d_inPreregister(false), |
257 |
9854 |
d_factsAsserted(d_env.getContext(), false), |
258 |
179864 |
d_attr_handle() |
259 |
|
{ |
260 |
137956 |
for(TheoryId theoryId = theory::THEORY_FIRST; theoryId != theory::THEORY_LAST; |
261 |
|
++ theoryId) |
262 |
|
{ |
263 |
128102 |
d_theoryTable[theoryId] = NULL; |
264 |
128102 |
d_theoryOut[theoryId] = NULL; |
265 |
|
} |
266 |
|
|
267 |
9854 |
if (options::sortInference()) |
268 |
|
{ |
269 |
20 |
d_sortInfer.reset(new SortInference); |
270 |
|
} |
271 |
|
|
272 |
9854 |
d_true = NodeManager::currentNM()->mkConst<bool>(true); |
273 |
9854 |
d_false = NodeManager::currentNM()->mkConst<bool>(false); |
274 |
9854 |
} |
275 |
|
|
276 |
19708 |
TheoryEngine::~TheoryEngine() { |
277 |
9854 |
Assert(d_hasShutDown); |
278 |
|
|
279 |
137956 |
for(TheoryId theoryId = theory::THEORY_FIRST; theoryId != theory::THEORY_LAST; ++ theoryId) { |
280 |
128102 |
if(d_theoryTable[theoryId] != NULL) { |
281 |
128054 |
delete d_theoryTable[theoryId]; |
282 |
128054 |
delete d_theoryOut[theoryId]; |
283 |
|
} |
284 |
|
} |
285 |
9854 |
} |
286 |
|
|
287 |
|
void TheoryEngine::interrupt() { d_interrupted = true; } |
288 |
1042548 |
void TheoryEngine::preRegister(TNode preprocessed) { |
289 |
2085096 |
Debug("theory") << "TheoryEngine::preRegister( " << preprocessed << ")" |
290 |
1042548 |
<< std::endl; |
291 |
1042548 |
d_preregisterQueue.push(preprocessed); |
292 |
|
|
293 |
1042548 |
if (!d_inPreregister) { |
294 |
|
// We're in pre-register |
295 |
976941 |
d_inPreregister = true; |
296 |
|
|
297 |
|
// Process the pre-registration queue |
298 |
3062029 |
while (!d_preregisterQueue.empty()) { |
299 |
|
// Get the next atom to pre-register |
300 |
1042548 |
preprocessed = d_preregisterQueue.front(); |
301 |
1042548 |
d_preregisterQueue.pop(); |
302 |
|
|
303 |
|
// the atom should not have free variables |
304 |
2085096 |
Debug("theory") << "TheoryEngine::preRegister: " << preprocessed |
305 |
1042548 |
<< std::endl; |
306 |
1042548 |
Assert(!expr::hasFreeVar(preprocessed)); |
307 |
|
// should not have witness |
308 |
1042548 |
Assert(!expr::hasSubtermKind(kind::WITNESS, preprocessed)); |
309 |
|
|
310 |
|
// pre-register with the shared solver, which handles |
311 |
|
// calling prepregister on individual theories, adding shared terms, |
312 |
|
// and setting up equalities to propagate in the shared term database. |
313 |
1042548 |
Assert(d_sharedSolver != nullptr); |
314 |
1042552 |
d_sharedSolver->preRegister(preprocessed); |
315 |
|
} |
316 |
|
|
317 |
|
// Leaving pre-register |
318 |
976937 |
d_inPreregister = false; |
319 |
|
} |
320 |
1042544 |
} |
321 |
|
|
322 |
|
void TheoryEngine::printAssertions(const char* tag) { |
323 |
|
if (Trace.isOn(tag)) { |
324 |
|
|
325 |
|
for (TheoryId theoryId = THEORY_FIRST; theoryId < THEORY_LAST; ++theoryId) { |
326 |
|
Theory* theory = d_theoryTable[theoryId]; |
327 |
|
if (theory && d_logicInfo.isTheoryEnabled(theoryId)) { |
328 |
|
Trace(tag) << "--------------------------------------------" << endl; |
329 |
|
Trace(tag) << "Assertions of " << theory->getId() << ": " << endl; |
330 |
|
{ |
331 |
|
context::CDList<Assertion>::const_iterator it = theory->facts_begin(), |
332 |
|
it_end = |
333 |
|
theory->facts_end(); |
334 |
|
for (unsigned i = 0; it != it_end; ++it, ++i) |
335 |
|
{ |
336 |
|
if ((*it).d_isPreregistered) |
337 |
|
{ |
338 |
|
Trace(tag) << "[" << i << "]: "; |
339 |
|
} |
340 |
|
else |
341 |
|
{ |
342 |
|
Trace(tag) << "(" << i << "): "; |
343 |
|
} |
344 |
|
Trace(tag) << (*it).d_assertion << endl; |
345 |
|
} |
346 |
|
} |
347 |
|
|
348 |
|
if (d_logicInfo.isSharingEnabled()) { |
349 |
|
Trace(tag) << "Shared terms of " << theory->getId() << ": " << endl; |
350 |
|
context::CDList<TNode>::const_iterator it = theory->shared_terms_begin(), it_end = theory->shared_terms_end(); |
351 |
|
for (unsigned i = 0; it != it_end; ++ it, ++i) { |
352 |
|
Trace(tag) << "[" << i << "]: " << (*it) << endl; |
353 |
|
} |
354 |
|
} |
355 |
|
} |
356 |
|
} |
357 |
|
} |
358 |
|
} |
359 |
|
|
360 |
|
void TheoryEngine::dumpAssertions(const char* tag) { |
361 |
|
if (Dump.isOn(tag)) { |
362 |
|
const Printer& printer = d_env.getPrinter(); |
363 |
|
std::ostream& out = d_env.getDumpOut(); |
364 |
|
printer.toStreamCmdComment(out, "Starting completeness check"); |
365 |
|
for (TheoryId theoryId = THEORY_FIRST; theoryId < THEORY_LAST; ++theoryId) { |
366 |
|
Theory* theory = d_theoryTable[theoryId]; |
367 |
|
if (theory && d_logicInfo.isTheoryEnabled(theoryId)) { |
368 |
|
printer.toStreamCmdComment(out, "Completeness check"); |
369 |
|
printer.toStreamCmdPush(out); |
370 |
|
|
371 |
|
// Dump the shared terms |
372 |
|
if (d_logicInfo.isSharingEnabled()) { |
373 |
|
printer.toStreamCmdComment(out, "Shared terms"); |
374 |
|
context::CDList<TNode>::const_iterator it = theory->shared_terms_begin(), it_end = theory->shared_terms_end(); |
375 |
|
for (unsigned i = 0; it != it_end; ++ it, ++i) { |
376 |
|
stringstream ss; |
377 |
|
ss << (*it); |
378 |
|
printer.toStreamCmdComment(out, ss.str()); |
379 |
|
} |
380 |
|
} |
381 |
|
|
382 |
|
// Dump the assertions |
383 |
|
printer.toStreamCmdComment(out, "Assertions"); |
384 |
|
context::CDList<Assertion>::const_iterator it = theory->facts_begin(), it_end = theory->facts_end(); |
385 |
|
for (; it != it_end; ++ it) { |
386 |
|
// Get the assertion |
387 |
|
Node assertionNode = (*it).d_assertion; |
388 |
|
// Purify all the terms |
389 |
|
|
390 |
|
if ((*it).d_isPreregistered) |
391 |
|
{ |
392 |
|
printer.toStreamCmdComment(out, "Preregistered"); |
393 |
|
} |
394 |
|
else |
395 |
|
{ |
396 |
|
printer.toStreamCmdComment(out, "Shared assertion"); |
397 |
|
} |
398 |
|
printer.toStreamCmdAssert(out, assertionNode); |
399 |
|
} |
400 |
|
printer.toStreamCmdCheckSat(out); |
401 |
|
|
402 |
|
printer.toStreamCmdPop(out); |
403 |
|
} |
404 |
|
} |
405 |
|
} |
406 |
|
} |
407 |
|
|
408 |
|
/** |
409 |
|
* Check all (currently-active) theories for conflicts. |
410 |
|
* @param effort the effort level to use |
411 |
|
*/ |
412 |
3990979 |
void TheoryEngine::check(Theory::Effort effort) { |
413 |
|
// spendResource(); |
414 |
|
|
415 |
|
// Reset the interrupt flag |
416 |
3990979 |
d_interrupted = false; |
417 |
|
|
418 |
|
#ifdef CVC5_FOR_EACH_THEORY_STATEMENT |
419 |
|
#undef CVC5_FOR_EACH_THEORY_STATEMENT |
420 |
|
#endif |
421 |
|
#define CVC5_FOR_EACH_THEORY_STATEMENT(THEORY) \ |
422 |
|
if (theory::TheoryTraits<THEORY>::hasCheck \ |
423 |
|
&& d_logicInfo.isTheoryEnabled(THEORY)) \ |
424 |
|
{ \ |
425 |
|
theoryOf(THEORY)->check(effort); \ |
426 |
|
if (d_inConflict) \ |
427 |
|
{ \ |
428 |
|
Debug("conflict") << THEORY << " in conflict. " << std::endl; \ |
429 |
|
break; \ |
430 |
|
} \ |
431 |
|
} |
432 |
|
|
433 |
|
// Do the checking |
434 |
|
try { |
435 |
|
|
436 |
|
// Mark the output channel unused (if this is FULL_EFFORT, and nothing |
437 |
|
// is done by the theories, no additional check will be needed) |
438 |
3990979 |
d_outputChannelUsed = false; |
439 |
|
|
440 |
|
// Mark the lemmas flag (no lemmas added) |
441 |
3990979 |
d_lemmasAdded = false; |
442 |
|
|
443 |
3990979 |
Debug("theory") << "TheoryEngine::check(" << effort << "): d_factsAsserted = " << (d_factsAsserted ? "true" : "false") << endl; |
444 |
|
|
445 |
|
// If in full effort, we have a fake new assertion just to jumpstart the checking |
446 |
3990979 |
if (Theory::fullEffort(effort)) { |
447 |
75195 |
d_factsAsserted = true; |
448 |
|
// Reset round for the relevance manager, which notice only sets a flag |
449 |
|
// to indicate that its information must be recomputed. |
450 |
75195 |
if (d_relManager != nullptr) |
451 |
|
{ |
452 |
143 |
d_relManager->resetRound(); |
453 |
|
} |
454 |
75195 |
d_tc->resetRound(); |
455 |
|
} |
456 |
|
|
457 |
|
// Check until done |
458 |
10864617 |
while (d_factsAsserted && !d_inConflict && !d_lemmasAdded) { |
459 |
|
|
460 |
3583091 |
Debug("theory") << "TheoryEngine::check(" << effort << "): running check" << endl; |
461 |
|
|
462 |
3583091 |
Trace("theory::assertions") << endl; |
463 |
3583091 |
if (Trace.isOn("theory::assertions")) { |
464 |
|
printAssertions("theory::assertions"); |
465 |
|
} |
466 |
|
|
467 |
3583091 |
if(Theory::fullEffort(effort)) { |
468 |
81885 |
Trace("theory::assertions::fulleffort") << endl; |
469 |
81885 |
if (Trace.isOn("theory::assertions::fulleffort")) { |
470 |
|
printAssertions("theory::assertions::fulleffort"); |
471 |
|
} |
472 |
|
} |
473 |
|
|
474 |
|
// Note that we've discharged all the facts |
475 |
3583091 |
d_factsAsserted = false; |
476 |
|
|
477 |
|
// Do the checking |
478 |
3583091 |
CVC5_FOR_EACH_THEORY; |
479 |
|
|
480 |
3436819 |
Debug("theory") << "TheoryEngine::check(" << effort << "): running propagation after the initial check" << endl; |
481 |
|
|
482 |
|
// We are still satisfiable, propagate as much as possible |
483 |
3436819 |
propagate(effort); |
484 |
|
|
485 |
|
// We do combination if all has been processed and we are in fullcheck |
486 |
6930924 |
if (Theory::fullEffort(effort) && d_logicInfo.isSharingEnabled() |
487 |
3487397 |
&& !d_factsAsserted && !needCheck() && !d_inConflict) |
488 |
|
{ |
489 |
|
// Do the combination |
490 |
21921 |
Debug("theory") << "TheoryEngine::check(" << effort << "): running combination" << endl; |
491 |
|
{ |
492 |
43842 |
TimerStat::CodeTimer combineTheoriesTimer(d_combineTheoriesTime); |
493 |
21921 |
d_tc->combineTheories(); |
494 |
|
} |
495 |
21921 |
if(d_logicInfo.isQuantified()){ |
496 |
13518 |
d_quantEngine->notifyCombineTheories(); |
497 |
|
} |
498 |
|
} |
499 |
|
} |
500 |
|
|
501 |
|
// Must consult quantifiers theory for last call to ensure sat, or otherwise add a lemma |
502 |
3990975 |
if( Theory::fullEffort(effort) && ! d_inConflict && ! needCheck() ) { |
503 |
21068 |
Trace("theory::assertions-model") << endl; |
504 |
21068 |
if (Trace.isOn("theory::assertions-model")) { |
505 |
|
printAssertions("theory::assertions-model"); |
506 |
|
} |
507 |
|
// reset the model in the combination engine |
508 |
21068 |
d_tc->resetModel(); |
509 |
|
//checks for theories requiring the model go at last call |
510 |
294932 |
for (TheoryId theoryId = THEORY_FIRST; theoryId < THEORY_LAST; ++theoryId) { |
511 |
273866 |
if( theoryId!=THEORY_QUANTIFIERS ){ |
512 |
252800 |
Theory* theory = d_theoryTable[theoryId]; |
513 |
252800 |
if (theory && d_logicInfo.isTheoryEnabled(theoryId)) { |
514 |
133669 |
if( theory->needsCheckLastEffort() ){ |
515 |
9566 |
if (!d_tc->buildModel()) |
516 |
|
{ |
517 |
2 |
break; |
518 |
|
} |
519 |
9564 |
theory->check(Theory::EFFORT_LAST_CALL); |
520 |
|
} |
521 |
|
} |
522 |
|
} |
523 |
|
} |
524 |
21068 |
if (!d_inConflict) |
525 |
|
{ |
526 |
21068 |
if(d_logicInfo.isQuantified()) { |
527 |
|
// quantifiers engine must check at last call effort |
528 |
14918 |
d_quantEngine->check(Theory::EFFORT_LAST_CALL); |
529 |
|
} |
530 |
|
} |
531 |
21058 |
if (!d_inConflict && !needCheck()) |
532 |
|
{ |
533 |
|
// If d_eager_model_building is false, then we only mark that we |
534 |
|
// are in "SAT mode". We build the model later only if the user asks |
535 |
|
// for it via getBuiltModel. |
536 |
7482 |
d_inSatMode = true; |
537 |
7482 |
if (d_eager_model_building) |
538 |
|
{ |
539 |
4 |
d_tc->buildModel(); |
540 |
|
} |
541 |
|
} |
542 |
|
} |
543 |
|
|
544 |
3990965 |
Debug("theory") << "TheoryEngine::check(" << effort << "): done, we are " << (d_inConflict ? "unsat" : "sat") << (d_lemmasAdded ? " with new lemmas" : " with no new lemmas"); |
545 |
3990965 |
Debug("theory") << ", need check = " << (needCheck() ? "YES" : "NO") << endl; |
546 |
|
|
547 |
3990965 |
if( Theory::fullEffort(effort) && !d_inConflict && !needCheck()) { |
548 |
|
// Do post-processing of model from the theories (e.g. used for THEORY_SEP |
549 |
|
// to construct heap model) |
550 |
7482 |
d_tc->postProcessModel(d_incomplete.get()); |
551 |
|
} |
552 |
|
} catch(const theory::Interrupted&) { |
553 |
|
Trace("theory") << "TheoryEngine::check() => interrupted" << endl; |
554 |
|
} |
555 |
|
// If fulleffort, check all theories |
556 |
3990965 |
if(Dump.isOn("theory::fullcheck") && Theory::fullEffort(effort)) { |
557 |
|
if (!d_inConflict && !needCheck()) { |
558 |
|
dumpAssertions("theory::fullcheck"); |
559 |
|
} |
560 |
|
} |
561 |
3990965 |
} |
562 |
|
|
563 |
3436819 |
void TheoryEngine::propagate(Theory::Effort effort) |
564 |
|
{ |
565 |
|
// Reset the interrupt flag |
566 |
3436819 |
d_interrupted = false; |
567 |
|
|
568 |
|
// Definition of the statement that is to be run by every theory |
569 |
|
#ifdef CVC5_FOR_EACH_THEORY_STATEMENT |
570 |
|
#undef CVC5_FOR_EACH_THEORY_STATEMENT |
571 |
|
#endif |
572 |
|
#define CVC5_FOR_EACH_THEORY_STATEMENT(THEORY) \ |
573 |
|
if (theory::TheoryTraits<THEORY>::hasPropagate \ |
574 |
|
&& d_logicInfo.isTheoryEnabled(THEORY)) \ |
575 |
|
{ \ |
576 |
|
theoryOf(THEORY)->propagate(effort); \ |
577 |
|
} |
578 |
|
|
579 |
|
// Reset the interrupt flag |
580 |
3436819 |
d_interrupted = false; |
581 |
|
|
582 |
|
// Propagate for each theory using the statement above |
583 |
3436819 |
CVC5_FOR_EACH_THEORY; |
584 |
3436819 |
} |
585 |
|
|
586 |
2682620 |
Node TheoryEngine::getNextDecisionRequest() |
587 |
|
{ |
588 |
2682620 |
return d_decManager->getNextDecisionRequest(); |
589 |
|
} |
590 |
|
|
591 |
116140 |
bool TheoryEngine::properConflict(TNode conflict) const { |
592 |
|
bool value; |
593 |
116140 |
if (conflict.getKind() == kind::AND) { |
594 |
1504017 |
for (unsigned i = 0; i < conflict.getNumChildren(); ++ i) { |
595 |
1388370 |
if (! getPropEngine()->hasValue(conflict[i], value)) { |
596 |
|
Debug("properConflict") << "Bad conflict is due to unassigned atom: " |
597 |
|
<< conflict[i] << endl; |
598 |
|
return false; |
599 |
|
} |
600 |
1388370 |
if (! value) { |
601 |
|
Debug("properConflict") << "Bad conflict is due to false atom: " |
602 |
|
<< conflict[i] << endl; |
603 |
|
return false; |
604 |
|
} |
605 |
1388370 |
if (conflict[i] != Rewriter::rewrite(conflict[i])) { |
606 |
|
Debug("properConflict") << "Bad conflict is due to atom not in normal form: " |
607 |
|
<< conflict[i] << " vs " << Rewriter::rewrite(conflict[i]) << endl; |
608 |
|
return false; |
609 |
|
} |
610 |
|
} |
611 |
|
} else { |
612 |
493 |
if (! getPropEngine()->hasValue(conflict, value)) { |
613 |
|
Debug("properConflict") << "Bad conflict is due to unassigned atom: " |
614 |
|
<< conflict << endl; |
615 |
|
return false; |
616 |
|
} |
617 |
493 |
if(! value) { |
618 |
|
Debug("properConflict") << "Bad conflict is due to false atom: " |
619 |
|
<< conflict << endl; |
620 |
|
return false; |
621 |
|
} |
622 |
493 |
if (conflict != Rewriter::rewrite(conflict)) { |
623 |
|
Debug("properConflict") << "Bad conflict is due to atom not in normal form: " |
624 |
|
<< conflict << " vs " << Rewriter::rewrite(conflict) << endl; |
625 |
|
return false; |
626 |
|
} |
627 |
|
} |
628 |
116140 |
return true; |
629 |
|
} |
630 |
|
|
631 |
3016027 |
TheoryModel* TheoryEngine::getModel() |
632 |
|
{ |
633 |
3016027 |
Assert(d_tc != nullptr); |
634 |
3016027 |
TheoryModel* m = d_tc->getModel(); |
635 |
3016027 |
Assert(m != nullptr); |
636 |
3016027 |
return m; |
637 |
|
} |
638 |
|
|
639 |
5173 |
TheoryModel* TheoryEngine::getBuiltModel() |
640 |
|
{ |
641 |
5173 |
Assert(d_tc != nullptr); |
642 |
|
// If this method was called, we should be in SAT mode, and produceModels |
643 |
|
// should be true. |
644 |
5173 |
AlwaysAssert(options::produceModels()); |
645 |
5173 |
if (!d_inSatMode) |
646 |
|
{ |
647 |
|
// not available, perhaps due to interuption. |
648 |
|
return nullptr; |
649 |
|
} |
650 |
|
// must build model at this point |
651 |
5173 |
if (!d_tc->buildModel()) |
652 |
|
{ |
653 |
|
return nullptr; |
654 |
|
} |
655 |
5172 |
return d_tc->getModel(); |
656 |
|
} |
657 |
|
|
658 |
10688 |
bool TheoryEngine::buildModel() |
659 |
|
{ |
660 |
10688 |
Assert(d_tc != nullptr); |
661 |
10688 |
return d_tc->buildModel(); |
662 |
|
} |
663 |
|
|
664 |
15205 |
bool TheoryEngine::presolve() { |
665 |
|
// Reset the interrupt flag |
666 |
15205 |
d_interrupted = false; |
667 |
|
|
668 |
|
// Reset the decision manager. This clears its decision strategies that are |
669 |
|
// no longer valid in this user context. |
670 |
15205 |
d_decManager->presolve(); |
671 |
|
|
672 |
|
try { |
673 |
|
// Definition of the statement that is to be run by every theory |
674 |
|
#ifdef CVC5_FOR_EACH_THEORY_STATEMENT |
675 |
|
#undef CVC5_FOR_EACH_THEORY_STATEMENT |
676 |
|
#endif |
677 |
|
#define CVC5_FOR_EACH_THEORY_STATEMENT(THEORY) \ |
678 |
|
if (theory::TheoryTraits<THEORY>::hasPresolve) \ |
679 |
|
{ \ |
680 |
|
theoryOf(THEORY)->presolve(); \ |
681 |
|
if (d_inConflict) \ |
682 |
|
{ \ |
683 |
|
return true; \ |
684 |
|
} \ |
685 |
|
} |
686 |
|
|
687 |
|
// Presolve for each theory using the statement above |
688 |
15205 |
CVC5_FOR_EACH_THEORY; |
689 |
|
} catch(const theory::Interrupted&) { |
690 |
|
Trace("theory") << "TheoryEngine::presolve() => interrupted" << endl; |
691 |
|
} |
692 |
|
// return whether we have a conflict |
693 |
15205 |
return false; |
694 |
|
}/* TheoryEngine::presolve() */ |
695 |
|
|
696 |
15189 |
void TheoryEngine::postsolve() { |
697 |
|
// no longer in SAT mode |
698 |
15189 |
d_inSatMode = false; |
699 |
|
// Reset the interrupt flag |
700 |
15189 |
d_interrupted = false; |
701 |
15189 |
bool CVC5_UNUSED wasInConflict = d_inConflict; |
702 |
|
|
703 |
|
try { |
704 |
|
// Definition of the statement that is to be run by every theory |
705 |
|
#ifdef CVC5_FOR_EACH_THEORY_STATEMENT |
706 |
|
#undef CVC5_FOR_EACH_THEORY_STATEMENT |
707 |
|
#endif |
708 |
|
#define CVC5_FOR_EACH_THEORY_STATEMENT(THEORY) \ |
709 |
|
if (theory::TheoryTraits<THEORY>::hasPostsolve) \ |
710 |
|
{ \ |
711 |
|
theoryOf(THEORY)->postsolve(); \ |
712 |
|
Assert(!d_inConflict || wasInConflict) \ |
713 |
|
<< "conflict raised during postsolve()"; \ |
714 |
|
} |
715 |
|
|
716 |
|
// Postsolve for each theory using the statement above |
717 |
|
CVC5_FOR_EACH_THEORY; |
718 |
|
} catch(const theory::Interrupted&) { |
719 |
|
Trace("theory") << "TheoryEngine::postsolve() => interrupted" << endl; |
720 |
|
} |
721 |
15189 |
}/* TheoryEngine::postsolve() */ |
722 |
|
|
723 |
|
|
724 |
2672 |
void TheoryEngine::notifyRestart() { |
725 |
|
// Reset the interrupt flag |
726 |
2672 |
d_interrupted = false; |
727 |
|
|
728 |
|
// Definition of the statement that is to be run by every theory |
729 |
|
#ifdef CVC5_FOR_EACH_THEORY_STATEMENT |
730 |
|
#undef CVC5_FOR_EACH_THEORY_STATEMENT |
731 |
|
#endif |
732 |
|
#define CVC5_FOR_EACH_THEORY_STATEMENT(THEORY) \ |
733 |
|
if (theory::TheoryTraits<THEORY>::hasNotifyRestart \ |
734 |
|
&& d_logicInfo.isTheoryEnabled(THEORY)) \ |
735 |
|
{ \ |
736 |
|
theoryOf(THEORY)->notifyRestart(); \ |
737 |
|
} |
738 |
|
|
739 |
|
// notify each theory using the statement above |
740 |
2672 |
CVC5_FOR_EACH_THEORY; |
741 |
2672 |
} |
742 |
|
|
743 |
105239 |
void TheoryEngine::ppStaticLearn(TNode in, NodeBuilder& learned) |
744 |
|
{ |
745 |
|
// Reset the interrupt flag |
746 |
105239 |
d_interrupted = false; |
747 |
|
|
748 |
|
// Definition of the statement that is to be run by every theory |
749 |
|
#ifdef CVC5_FOR_EACH_THEORY_STATEMENT |
750 |
|
#undef CVC5_FOR_EACH_THEORY_STATEMENT |
751 |
|
#endif |
752 |
|
#define CVC5_FOR_EACH_THEORY_STATEMENT(THEORY) \ |
753 |
|
if (theory::TheoryTraits<THEORY>::hasPpStaticLearn) \ |
754 |
|
{ \ |
755 |
|
theoryOf(THEORY)->ppStaticLearn(in, learned); \ |
756 |
|
} |
757 |
|
|
758 |
|
// static learning for each theory using the statement above |
759 |
105239 |
CVC5_FOR_EACH_THEORY; |
760 |
105239 |
} |
761 |
|
|
762 |
104481 |
bool TheoryEngine::isRelevant(Node lit) const |
763 |
|
{ |
764 |
104481 |
if (d_relManager != nullptr) |
765 |
|
{ |
766 |
1995 |
return d_relManager->isRelevant(lit); |
767 |
|
} |
768 |
|
// otherwise must assume its relevant |
769 |
102486 |
return true; |
770 |
|
} |
771 |
|
|
772 |
9854 |
void TheoryEngine::shutdown() { |
773 |
|
// Set this first; if a Theory shutdown() throws an exception, |
774 |
|
// at least the destruction of the TheoryEngine won't confound |
775 |
|
// matters. |
776 |
9854 |
d_hasShutDown = true; |
777 |
|
|
778 |
|
// Shutdown all the theories |
779 |
137956 |
for(TheoryId theoryId = theory::THEORY_FIRST; theoryId < theory::THEORY_LAST; ++theoryId) { |
780 |
128102 |
if(d_theoryTable[theoryId]) { |
781 |
128054 |
theoryOf(theoryId)->shutdown(); |
782 |
|
} |
783 |
|
} |
784 |
9854 |
} |
785 |
|
|
786 |
113489 |
theory::Theory::PPAssertStatus TheoryEngine::solve( |
787 |
|
TrustNode tliteral, TrustSubstitutionMap& substitutionOut) |
788 |
|
{ |
789 |
|
// Reset the interrupt flag |
790 |
113489 |
d_interrupted = false; |
791 |
|
|
792 |
226978 |
TNode literal = tliteral.getNode(); |
793 |
226978 |
TNode atom = literal.getKind() == kind::NOT ? literal[0] : literal; |
794 |
113489 |
Trace("theory::solve") << "TheoryEngine::solve(" << literal << "): solving with " << theoryOf(atom)->getId() << endl; |
795 |
|
|
796 |
226978 |
if(! d_logicInfo.isTheoryEnabled(Theory::theoryOf(atom)) && |
797 |
113489 |
Theory::theoryOf(atom) != THEORY_SAT_SOLVER) { |
798 |
|
stringstream ss; |
799 |
|
ss << "The logic was specified as " << d_logicInfo.getLogicString() |
800 |
|
<< ", which doesn't include " << Theory::theoryOf(atom) |
801 |
|
<< ", but got a preprocessing-time fact for that theory." << endl |
802 |
|
<< "The fact:" << endl |
803 |
|
<< literal; |
804 |
|
throw LogicException(ss.str()); |
805 |
|
} |
806 |
|
|
807 |
|
Theory::PPAssertStatus solveStatus = |
808 |
113489 |
theoryOf(atom)->ppAssert(tliteral, substitutionOut); |
809 |
113489 |
Trace("theory::solve") << "TheoryEngine::solve(" << literal << ") => " << solveStatus << endl; |
810 |
226978 |
return solveStatus; |
811 |
|
} |
812 |
|
|
813 |
202030 |
TrustNode TheoryEngine::ppRewriteEquality(TNode eq) |
814 |
|
{ |
815 |
202030 |
Assert(eq.getKind() == kind::EQUAL); |
816 |
404060 |
std::vector<SkolemLemma> lems; |
817 |
202030 |
TrustNode trn = theoryOf(eq)->ppRewrite(eq, lems); |
818 |
|
// should never introduce a skolem to eliminate an equality |
819 |
202030 |
Assert(lems.empty()); |
820 |
404060 |
return trn; |
821 |
|
} |
822 |
|
|
823 |
13741 |
void TheoryEngine::notifyPreprocessedAssertions( |
824 |
|
const std::vector<Node>& assertions) { |
825 |
|
// call all the theories |
826 |
192374 |
for (TheoryId theoryId = theory::THEORY_FIRST; theoryId < theory::THEORY_LAST; |
827 |
|
++theoryId) { |
828 |
178633 |
if (d_theoryTable[theoryId]) { |
829 |
178633 |
theoryOf(theoryId)->ppNotifyAssertions(assertions); |
830 |
|
} |
831 |
|
} |
832 |
13741 |
if (d_relManager != nullptr) |
833 |
|
{ |
834 |
25 |
d_relManager->notifyPreprocessedAssertions(assertions); |
835 |
|
} |
836 |
13741 |
} |
837 |
|
|
838 |
29731459 |
bool TheoryEngine::markPropagation(TNode assertion, TNode originalAssertion, theory::TheoryId toTheoryId, theory::TheoryId fromTheoryId) { |
839 |
|
// What and where we are asserting |
840 |
59462918 |
NodeTheoryPair toAssert(assertion, toTheoryId, d_propagationMapTimestamp); |
841 |
|
// What and where it came from |
842 |
59462918 |
NodeTheoryPair toExplain(originalAssertion, fromTheoryId, d_propagationMapTimestamp); |
843 |
|
|
844 |
|
// See if the theory already got this literal |
845 |
29731459 |
PropagationMap::const_iterator find = d_propagationMap.find(toAssert); |
846 |
29731459 |
if (find != d_propagationMap.end()) { |
847 |
|
// The theory already knows this |
848 |
8766248 |
Trace("theory::assertToTheory") << "TheoryEngine::markPropagation(): already there" << endl; |
849 |
8766248 |
return false; |
850 |
|
} |
851 |
|
|
852 |
20965211 |
Trace("theory::assertToTheory") << "TheoryEngine::markPropagation(): marking [" << d_propagationMapTimestamp << "] " << assertion << ", " << toTheoryId << " from " << originalAssertion << ", " << fromTheoryId << endl; |
853 |
|
|
854 |
|
// Mark the propagation |
855 |
20965211 |
d_propagationMap[toAssert] = toExplain; |
856 |
20965211 |
d_propagationMapTimestamp = d_propagationMapTimestamp + 1; |
857 |
|
|
858 |
20965211 |
return true; |
859 |
|
} |
860 |
|
|
861 |
|
|
862 |
36168063 |
void TheoryEngine::assertToTheory(TNode assertion, TNode originalAssertion, theory::TheoryId toTheoryId, theory::TheoryId fromTheoryId) { |
863 |
36168063 |
Trace("theory::assertToTheory") << "TheoryEngine::assertToTheory(" << assertion << ", " << originalAssertion << "," << toTheoryId << ", " << fromTheoryId << ")" << endl; |
864 |
|
|
865 |
36168063 |
Assert(toTheoryId != fromTheoryId); |
866 |
61020870 |
if(toTheoryId != THEORY_SAT_SOLVER && |
867 |
24852807 |
! d_logicInfo.isTheoryEnabled(toTheoryId)) { |
868 |
|
stringstream ss; |
869 |
|
ss << "The logic was specified as " << d_logicInfo.getLogicString() |
870 |
|
<< ", which doesn't include " << toTheoryId |
871 |
|
<< ", but got an asserted fact to that theory." << endl |
872 |
|
<< "The fact:" << endl |
873 |
|
<< assertion; |
874 |
|
throw LogicException(ss.str()); |
875 |
|
} |
876 |
|
|
877 |
36168063 |
if (d_inConflict) { |
878 |
71437 |
return; |
879 |
|
} |
880 |
|
|
881 |
|
// If sharing is disabled, things are easy |
882 |
36096626 |
if (!d_logicInfo.isSharingEnabled()) { |
883 |
6365167 |
Assert(assertion == originalAssertion); |
884 |
6365167 |
if (fromTheoryId == THEORY_SAT_SOLVER) { |
885 |
|
// Send to the apropriate theory |
886 |
4574963 |
theory::Theory* toTheory = theoryOf(toTheoryId); |
887 |
|
// We assert it, and we know it's preregistereed |
888 |
4574963 |
toTheory->assertFact(assertion, true); |
889 |
|
// Mark that we have more information |
890 |
4574963 |
d_factsAsserted = true; |
891 |
|
} else { |
892 |
1790204 |
Assert(toTheoryId == THEORY_SAT_SOLVER); |
893 |
|
// Check for propositional conflict |
894 |
|
bool value; |
895 |
1790204 |
if (d_propEngine->hasValue(assertion, value)) { |
896 |
1110982 |
if (!value) { |
897 |
34194 |
Trace("theory::propagate") << "TheoryEngine::assertToTheory(" << assertion << ", " << toTheoryId << ", " << fromTheoryId << "): conflict (no sharing)" << endl; |
898 |
68388 |
Trace("dtview::conflict") |
899 |
34194 |
<< ":THEORY-CONFLICT: " << assertion << std::endl; |
900 |
34194 |
markInConflict(); |
901 |
|
} else { |
902 |
1076788 |
return; |
903 |
|
} |
904 |
|
} |
905 |
713416 |
d_propagatedLiterals.push_back(assertion); |
906 |
|
} |
907 |
5288379 |
return; |
908 |
|
} |
909 |
|
|
910 |
|
// determine the actual theory that will process/explain the fact, which is |
911 |
|
// THEORY_BUILTIN if the theory uses the central equality engine |
912 |
29731459 |
TheoryId toTheoryIdProp = (Theory::expUsingCentralEqualityEngine(toTheoryId)) |
913 |
29731459 |
? THEORY_BUILTIN |
914 |
29731459 |
: toTheoryId; |
915 |
|
// If sending to the shared solver, it's also simple |
916 |
29731459 |
if (toTheoryId == THEORY_BUILTIN) { |
917 |
9896072 |
if (markPropagation( |
918 |
|
assertion, originalAssertion, toTheoryIdProp, fromTheoryId)) |
919 |
|
{ |
920 |
|
// assert to the shared solver |
921 |
5472821 |
bool polarity = assertion.getKind() != kind::NOT; |
922 |
10945642 |
TNode atom = polarity ? assertion : assertion[0]; |
923 |
5472821 |
d_sharedSolver->assertShared(atom, polarity, assertion); |
924 |
|
} |
925 |
9896072 |
return; |
926 |
|
} |
927 |
|
|
928 |
|
// Things from the SAT solver are already normalized, so they go |
929 |
|
// directly to the apropriate theory |
930 |
19835387 |
if (fromTheoryId == THEORY_SAT_SOLVER) { |
931 |
|
// We know that this is normalized, so just send it off to the theory |
932 |
7107637 |
if (markPropagation( |
933 |
|
assertion, originalAssertion, toTheoryIdProp, fromTheoryId)) |
934 |
|
{ |
935 |
|
// Is it preregistered |
936 |
7014373 |
bool preregistered = d_propEngine->isSatLiteral(assertion) && Theory::theoryOf(assertion) == toTheoryId; |
937 |
|
// We assert it |
938 |
7014373 |
theoryOf(toTheoryId)->assertFact(assertion, preregistered); |
939 |
|
// Mark that we have more information |
940 |
7014373 |
d_factsAsserted = true; |
941 |
|
} |
942 |
7107637 |
return; |
943 |
|
} |
944 |
|
|
945 |
|
// Propagations to the SAT solver are just enqueued for pickup by |
946 |
|
// the SAT solver later |
947 |
12727750 |
if (toTheoryId == THEORY_SAT_SOLVER) { |
948 |
9480052 |
Assert(toTheoryIdProp == toTheoryId); |
949 |
9480052 |
if (markPropagation(assertion, originalAssertion, toTheoryId, fromTheoryId)) { |
950 |
|
// Enqueue for propagation to the SAT solver |
951 |
5623029 |
d_propagatedLiterals.push_back(assertion); |
952 |
|
// Check for propositional conflicts |
953 |
|
bool value; |
954 |
5623029 |
if (d_propEngine->hasValue(assertion, value) && !value) { |
955 |
74612 |
Trace("theory::propagate") |
956 |
37306 |
<< "TheoryEngine::assertToTheory(" << assertion << ", " |
957 |
37306 |
<< toTheoryId << ", " << fromTheoryId << "): conflict (sharing)" |
958 |
37306 |
<< endl; |
959 |
74612 |
Trace("dtview::conflict") |
960 |
37306 |
<< ":THEORY-CONFLICT: " << assertion << std::endl; |
961 |
37306 |
markInConflict(); |
962 |
|
} |
963 |
|
} |
964 |
9480052 |
return; |
965 |
|
} |
966 |
|
|
967 |
3247698 |
Assert(assertion.getKind() == kind::EQUAL |
968 |
|
|| (assertion.getKind() == kind::NOT |
969 |
|
&& assertion[0].getKind() == kind::EQUAL)); |
970 |
|
|
971 |
|
// Normalize |
972 |
6495396 |
Node normalizedLiteral = Rewriter::rewrite(assertion); |
973 |
|
|
974 |
|
// See if it rewrites false directly -> conflict |
975 |
3247698 |
if (normalizedLiteral.isConst()) { |
976 |
21164 |
if (!normalizedLiteral.getConst<bool>()) { |
977 |
|
// Mark the propagation for explanations |
978 |
406 |
if (markPropagation(normalizedLiteral, |
979 |
|
originalAssertion, |
980 |
|
toTheoryIdProp, |
981 |
|
fromTheoryId)) |
982 |
|
{ |
983 |
|
// special case, trust node has no proof generator |
984 |
812 |
TrustNode trnn = TrustNode::mkTrustConflict(normalizedLiteral); |
985 |
|
// Get the explanation (conflict will figure out where it came from) |
986 |
406 |
conflict(trnn, toTheoryId); |
987 |
|
} else { |
988 |
|
Unreachable(); |
989 |
|
} |
990 |
406 |
return; |
991 |
|
} |
992 |
|
} |
993 |
|
|
994 |
|
// Try and assert (note that we assert the non-normalized one) |
995 |
3247292 |
if (markPropagation( |
996 |
|
assertion, originalAssertion, toTheoryIdProp, fromTheoryId)) |
997 |
|
{ |
998 |
|
// Check if has been pre-registered with the theory |
999 |
2854582 |
bool preregistered = d_propEngine->isSatLiteral(assertion) && Theory::theoryOf(assertion) == toTheoryId; |
1000 |
|
// Assert away |
1001 |
2854582 |
theoryOf(toTheoryId)->assertFact(assertion, preregistered); |
1002 |
2854582 |
d_factsAsserted = true; |
1003 |
|
} |
1004 |
|
|
1005 |
3247292 |
return; |
1006 |
|
} |
1007 |
|
|
1008 |
11656366 |
void TheoryEngine::assertFact(TNode literal) |
1009 |
|
{ |
1010 |
11656366 |
Trace("theory") << "TheoryEngine::assertFact(" << literal << ")" << endl; |
1011 |
|
|
1012 |
|
// spendResource(); |
1013 |
|
|
1014 |
|
// If we're in conflict, nothing to do |
1015 |
11656366 |
if (d_inConflict) { |
1016 |
17925 |
return; |
1017 |
|
} |
1018 |
|
|
1019 |
|
// Get the atom |
1020 |
11638441 |
bool polarity = literal.getKind() != kind::NOT; |
1021 |
23276882 |
TNode atom = polarity ? literal : literal[0]; |
1022 |
|
|
1023 |
11638441 |
if (d_logicInfo.isSharingEnabled()) { |
1024 |
|
// If any shared terms, it's time to do sharing work |
1025 |
7063478 |
d_sharedSolver->preNotifySharedFact(atom); |
1026 |
|
|
1027 |
|
// If it's an equality, assert it to the shared term manager, even though the terms are not |
1028 |
|
// yet shared. As the terms become shared later, the shared terms manager will then add them |
1029 |
|
// to the assert the equality to the interested theories |
1030 |
7063478 |
if (atom.getKind() == kind::EQUAL) { |
1031 |
|
// Assert it to the the owning theory |
1032 |
4013235 |
assertToTheory(literal, literal, /* to */ Theory::theoryOf(atom), /* from */ THEORY_SAT_SOLVER); |
1033 |
|
// Shared terms manager will assert to interested theories directly, as |
1034 |
|
// the terms become shared |
1035 |
4013235 |
assertToTheory(literal, literal, /* to */ THEORY_BUILTIN, /* from */ THEORY_SAT_SOLVER); |
1036 |
|
|
1037 |
|
// Now, let's check for any atom triggers from lemmas |
1038 |
4013235 |
AtomRequests::atom_iterator it = d_atomRequests.getAtomIterator(atom); |
1039 |
4055361 |
while (!it.done()) { |
1040 |
21063 |
const AtomRequests::Request& request = it.get(); |
1041 |
|
Node toAssert = |
1042 |
42126 |
polarity ? (Node)request.d_atom : request.d_atom.notNode(); |
1043 |
42126 |
Debug("theory::atoms") << "TheoryEngine::assertFact(" << literal |
1044 |
21063 |
<< "): sending requested " << toAssert << endl; |
1045 |
21063 |
assertToTheory( |
1046 |
21063 |
toAssert, literal, request.d_toTheory, THEORY_SAT_SOLVER); |
1047 |
21063 |
it.next(); |
1048 |
|
} |
1049 |
|
|
1050 |
|
} else { |
1051 |
|
// Not an equality, just assert to the appropriate theory |
1052 |
3050243 |
assertToTheory(literal, literal, /* to */ Theory::theoryOf(atom), /* from */ THEORY_SAT_SOLVER); |
1053 |
|
} |
1054 |
|
} else { |
1055 |
|
// Assert the fact to the appropriate theory directly |
1056 |
4574963 |
assertToTheory(literal, literal, /* to */ Theory::theoryOf(atom), /* from */ THEORY_SAT_SOLVER); |
1057 |
|
} |
1058 |
|
} |
1059 |
|
|
1060 |
13349247 |
bool TheoryEngine::propagate(TNode literal, theory::TheoryId theory) { |
1061 |
26698494 |
Debug("theory::propagate") |
1062 |
13349247 |
<< "TheoryEngine::propagate(" << literal << ", " << theory << ")" << endl; |
1063 |
|
|
1064 |
26698494 |
Trace("dtview::prop") << std::string(d_env.getContext()->getLevel(), ' ') |
1065 |
13349247 |
<< ":THEORY-PROP: " << literal << endl; |
1066 |
|
|
1067 |
|
// spendResource(); |
1068 |
|
|
1069 |
|
// Get the atom |
1070 |
13349247 |
bool polarity = literal.getKind() != kind::NOT; |
1071 |
26698494 |
TNode atom = polarity ? literal : literal[0]; |
1072 |
|
|
1073 |
13349247 |
if (d_logicInfo.isSharingEnabled() && atom.getKind() == kind::EQUAL) { |
1074 |
10094325 |
if (d_propEngine->isSatLiteral(literal)) { |
1075 |
|
// We propagate SAT literals to SAT |
1076 |
8060334 |
assertToTheory(literal, literal, /* to */ THEORY_SAT_SOLVER, /* from */ theory); |
1077 |
|
} |
1078 |
10094325 |
if (theory != THEORY_BUILTIN) { |
1079 |
|
// Assert to the shared terms database |
1080 |
5905527 |
assertToTheory(literal, literal, /* to */ THEORY_BUILTIN, /* from */ theory); |
1081 |
|
} |
1082 |
|
} else { |
1083 |
|
// Just send off to the SAT solver |
1084 |
3254922 |
Assert(d_propEngine->isSatLiteral(literal)); |
1085 |
3254922 |
assertToTheory(literal, literal, /* to */ THEORY_SAT_SOLVER, /* from */ theory); |
1086 |
|
} |
1087 |
|
|
1088 |
26698494 |
return !d_inConflict; |
1089 |
|
} |
1090 |
|
|
1091 |
39485 |
const LogicInfo& TheoryEngine::getLogicInfo() const { return d_logicInfo; } |
1092 |
|
|
1093 |
1368 |
bool TheoryEngine::getSepHeapTypes(TypeNode& locType, TypeNode& dataType) const |
1094 |
|
{ |
1095 |
1368 |
if (d_sepLocType.isNull()) |
1096 |
|
{ |
1097 |
1347 |
return false; |
1098 |
|
} |
1099 |
21 |
locType = d_sepLocType; |
1100 |
21 |
dataType = d_sepDataType; |
1101 |
21 |
return true; |
1102 |
|
} |
1103 |
|
|
1104 |
121 |
void TheoryEngine::declareSepHeap(TypeNode locT, TypeNode dataT) |
1105 |
|
{ |
1106 |
121 |
Theory* tsep = theoryOf(THEORY_SEP); |
1107 |
121 |
if (tsep == nullptr) |
1108 |
|
{ |
1109 |
|
Assert(false) << "TheoryEngine::declareSepHeap called without the " |
1110 |
|
"separation logic theory enabled"; |
1111 |
|
return; |
1112 |
|
} |
1113 |
|
|
1114 |
|
// Definition of the statement that is to be run by every theory |
1115 |
|
#ifdef CVC5_FOR_EACH_THEORY_STATEMENT |
1116 |
|
#undef CVC5_FOR_EACH_THEORY_STATEMENT |
1117 |
|
#endif |
1118 |
|
#define CVC5_FOR_EACH_THEORY_STATEMENT(THEORY) \ |
1119 |
|
theoryOf(THEORY)->declareSepHeap(locT, dataT); |
1120 |
|
|
1121 |
|
// notify each theory using the statement above |
1122 |
121 |
CVC5_FOR_EACH_THEORY; |
1123 |
|
|
1124 |
|
// remember the types we have set |
1125 |
119 |
d_sepLocType = locT; |
1126 |
119 |
d_sepDataType = dataT; |
1127 |
|
} |
1128 |
|
|
1129 |
1132164 |
theory::EqualityStatus TheoryEngine::getEqualityStatus(TNode a, TNode b) { |
1130 |
1132164 |
Assert(a.getType().isComparableTo(b.getType())); |
1131 |
1132164 |
return d_sharedSolver->getEqualityStatus(a, b); |
1132 |
|
} |
1133 |
|
|
1134 |
|
const std::unordered_set<TNode>& TheoryEngine::getRelevantAssertions( |
1135 |
|
bool& success) |
1136 |
|
{ |
1137 |
|
// if we are not in SAT mode, or there is no relevance manager, we fail |
1138 |
|
if (!d_inSatMode || d_relManager == nullptr) |
1139 |
|
{ |
1140 |
|
success = false; |
1141 |
|
return d_emptyRelevantSet; |
1142 |
|
} |
1143 |
|
return d_relManager->getRelevantAssertions(success); |
1144 |
|
} |
1145 |
|
|
1146 |
4316 |
Node TheoryEngine::getModelValue(TNode var) { |
1147 |
4316 |
if (var.isConst()) |
1148 |
|
{ |
1149 |
|
// the model value of a constant must be itself |
1150 |
|
return var; |
1151 |
|
} |
1152 |
4316 |
Assert(d_sharedSolver->isShared(var)); |
1153 |
4316 |
return theoryOf(Theory::theoryOf(var.getType()))->getModelValue(var); |
1154 |
|
} |
1155 |
|
|
1156 |
110648 |
TrustNode TheoryEngine::getExplanation(TNode node) |
1157 |
|
{ |
1158 |
221296 |
Debug("theory::explain") << "TheoryEngine::getExplanation(" << node |
1159 |
110648 |
<< "): current propagation index = " |
1160 |
110648 |
<< d_propagationMapTimestamp << endl; |
1161 |
110648 |
bool polarity = node.getKind() != kind::NOT; |
1162 |
221296 |
TNode atom = polarity ? node : node[0]; |
1163 |
|
|
1164 |
|
// If we're not in shared mode, explanations are simple |
1165 |
110648 |
if (!d_logicInfo.isSharingEnabled()) |
1166 |
|
{ |
1167 |
90968 |
Debug("theory::explain") |
1168 |
45484 |
<< "TheoryEngine::getExplanation: sharing is NOT enabled. " |
1169 |
45484 |
<< " Responsible theory is: " << theoryOf(atom)->getId() << std::endl; |
1170 |
|
|
1171 |
90968 |
TrustNode texplanation = theoryOf(atom)->explain(node); |
1172 |
90968 |
Node explanation = texplanation.getNode(); |
1173 |
90968 |
Debug("theory::explain") << "TheoryEngine::getExplanation(" << node |
1174 |
45484 |
<< ") => " << explanation << endl; |
1175 |
45484 |
if (isProofEnabled()) |
1176 |
|
{ |
1177 |
13029 |
texplanation.debugCheckClosed( |
1178 |
|
"te-proof-exp", "texplanation no share", false); |
1179 |
|
// check if no generator, if so, add THEORY_LEMMA |
1180 |
13029 |
if (texplanation.getGenerator() == nullptr) |
1181 |
|
{ |
1182 |
78 |
Node proven = texplanation.getProven(); |
1183 |
39 |
TheoryId tid = theoryOf(atom)->getId(); |
1184 |
78 |
Node tidn = builtin::BuiltinProofRuleChecker::mkTheoryIdNode(tid); |
1185 |
39 |
d_lazyProof->addStep(proven, PfRule::THEORY_LEMMA, {}, {proven, tidn}); |
1186 |
39 |
texplanation = |
1187 |
78 |
TrustNode::mkTrustPropExp(node, explanation, d_lazyProof.get()); |
1188 |
|
} |
1189 |
|
} |
1190 |
45484 |
return texplanation; |
1191 |
|
} |
1192 |
|
|
1193 |
130328 |
Debug("theory::explain") << "TheoryEngine::getExplanation: sharing IS enabled" |
1194 |
65164 |
<< std::endl; |
1195 |
|
|
1196 |
|
// Initial thing to explain |
1197 |
130328 |
NodeTheoryPair toExplain(node, THEORY_SAT_SOLVER, d_propagationMapTimestamp); |
1198 |
65164 |
Assert(d_propagationMap.find(toExplain) != d_propagationMap.end()); |
1199 |
|
|
1200 |
130328 |
NodeTheoryPair nodeExplainerPair = d_propagationMap[toExplain]; |
1201 |
130328 |
Debug("theory::explain") |
1202 |
65164 |
<< "TheoryEngine::getExplanation: explainer for node " |
1203 |
65164 |
<< nodeExplainerPair.d_node |
1204 |
65164 |
<< " is theory: " << nodeExplainerPair.d_theory << std::endl; |
1205 |
|
|
1206 |
|
// Create the workplace for explanations |
1207 |
130328 |
std::vector<NodeTheoryPair> vec{d_propagationMap[toExplain]}; |
1208 |
|
// Process the explanation |
1209 |
130328 |
TrustNode texplanation = getExplanation(vec); |
1210 |
130328 |
Debug("theory::explain") << "TheoryEngine::getExplanation(" << node << ") => " |
1211 |
65164 |
<< texplanation.getNode() << endl; |
1212 |
65164 |
return texplanation; |
1213 |
|
} |
1214 |
|
|
1215 |
62618 |
struct AtomsCollect { |
1216 |
|
|
1217 |
|
std::vector<TNode> d_atoms; |
1218 |
|
std::unordered_set<TNode> d_visited; |
1219 |
|
|
1220 |
|
public: |
1221 |
|
typedef void return_type; |
1222 |
|
|
1223 |
386586 |
bool alreadyVisited(TNode current, TNode parent) { |
1224 |
|
// Check if already visited |
1225 |
386586 |
if (d_visited.find(current) != d_visited.end()) return true; |
1226 |
|
// Don't visit non-boolean |
1227 |
356462 |
if (!current.getType().isBoolean()) return true; |
1228 |
|
// New node |
1229 |
290532 |
return false; |
1230 |
|
} |
1231 |
|
|
1232 |
97239 |
void visit(TNode current, TNode parent) { |
1233 |
97239 |
if (Theory::theoryOf(current) != theory::THEORY_BOOL) { |
1234 |
35806 |
d_atoms.push_back(current); |
1235 |
|
} |
1236 |
97239 |
d_visited.insert(current); |
1237 |
97239 |
} |
1238 |
|
|
1239 |
31309 |
void start(TNode node) {} |
1240 |
31309 |
void done(TNode node) {} |
1241 |
|
|
1242 |
31309 |
std::vector<TNode> getAtoms() const { |
1243 |
31309 |
return d_atoms; |
1244 |
|
} |
1245 |
|
}; |
1246 |
|
|
1247 |
31309 |
void TheoryEngine::ensureLemmaAtoms(TNode n, theory::TheoryId atomsTo) |
1248 |
|
{ |
1249 |
31309 |
Assert(atomsTo != THEORY_LAST); |
1250 |
62618 |
Debug("theory::atoms") << "TheoryEngine::ensureLemmaAtoms(" << n << ", " |
1251 |
31309 |
<< atomsTo << ")" << endl; |
1252 |
62618 |
AtomsCollect collectAtoms; |
1253 |
31309 |
NodeVisitor<AtomsCollect>::run(collectAtoms, n); |
1254 |
31309 |
ensureLemmaAtoms(collectAtoms.getAtoms(), atomsTo); |
1255 |
31309 |
} |
1256 |
|
|
1257 |
31309 |
void TheoryEngine::ensureLemmaAtoms(const std::vector<TNode>& atoms, theory::TheoryId atomsTo) { |
1258 |
67115 |
for (unsigned i = 0; i < atoms.size(); ++ i) { |
1259 |
|
|
1260 |
|
// Non-equality atoms are either owned by theory or they don't make sense |
1261 |
35806 |
if (atoms[i].getKind() != kind::EQUAL) { |
1262 |
36030 |
continue; |
1263 |
|
} |
1264 |
|
|
1265 |
|
// The equality |
1266 |
35582 |
Node eq = atoms[i]; |
1267 |
|
// Simple normalization to not repeat stuff |
1268 |
30124 |
if (eq[0] > eq[1]) { |
1269 |
|
eq = eq[1].eqNode(eq[0]); |
1270 |
|
} |
1271 |
|
|
1272 |
|
// Rewrite the equality |
1273 |
35582 |
Node eqNormalized = Rewriter::rewrite(atoms[i]); |
1274 |
|
|
1275 |
60248 |
Debug("theory::atoms") << "TheoryEngine::ensureLemmaAtoms(): " << eq |
1276 |
30124 |
<< " with nf " << eqNormalized << endl; |
1277 |
|
|
1278 |
|
// If the equality is a boolean constant, we send immediately |
1279 |
30124 |
if (eqNormalized.isConst()) { |
1280 |
|
if (eqNormalized.getConst<bool>()) { |
1281 |
|
assertToTheory(eq, eqNormalized, /** to */ atomsTo, /** Sat solver */ theory::THEORY_SAT_SOLVER); |
1282 |
|
} else { |
1283 |
|
assertToTheory(eq.notNode(), eqNormalized.notNode(), /** to */ atomsTo, /** Sat solver */ theory::THEORY_SAT_SOLVER); |
1284 |
|
} |
1285 |
|
continue; |
1286 |
30124 |
}else if( eqNormalized.getKind() != kind::EQUAL){ |
1287 |
|
Assert(eqNormalized.getKind() == kind::BOOLEAN_TERM_VARIABLE |
1288 |
|
|| (eqNormalized.getKind() == kind::NOT |
1289 |
|
&& eqNormalized[0].getKind() == kind::BOOLEAN_TERM_VARIABLE)); |
1290 |
|
// this happens for Boolean term equalities V = true that are rewritten to V, we should skip |
1291 |
|
// TODO : revisit this |
1292 |
|
continue; |
1293 |
|
} |
1294 |
|
|
1295 |
|
// If the normalization did the just flips, keep the flip |
1296 |
30124 |
if (eqNormalized[0] == eq[1] && eqNormalized[1] == eq[0]) { |
1297 |
1687 |
eq = eqNormalized; |
1298 |
|
} |
1299 |
|
|
1300 |
|
// Check if the equality is already known by the sat solver |
1301 |
30124 |
if (d_propEngine->isSatLiteral(eqNormalized)) { |
1302 |
|
bool value; |
1303 |
25298 |
if (d_propEngine->hasValue(eqNormalized, value)) { |
1304 |
49332 |
if (value) { |
1305 |
24666 |
assertToTheory(eq, eqNormalized, atomsTo, theory::THEORY_SAT_SOLVER); |
1306 |
49332 |
continue; |
1307 |
|
} else { |
1308 |
|
assertToTheory(eq.notNode(), eqNormalized.notNode(), atomsTo, theory::THEORY_SAT_SOLVER); |
1309 |
|
continue; |
1310 |
|
} |
1311 |
|
} |
1312 |
|
} |
1313 |
|
|
1314 |
|
// If the theory is asking about a different form, or the form is ok but if will go to a different theory |
1315 |
|
// then we must figure it out |
1316 |
5458 |
if (eqNormalized != eq || Theory::theoryOf(eq) != atomsTo) { |
1317 |
|
// If you get eqNormalized, send atoms[i] to atomsTo |
1318 |
4551 |
d_atomRequests.add(eqNormalized, eq, atomsTo); |
1319 |
|
} |
1320 |
|
} |
1321 |
31309 |
} |
1322 |
|
|
1323 |
422885 |
void TheoryEngine::lemma(TrustNode tlemma, |
1324 |
|
theory::LemmaProperty p, |
1325 |
|
theory::TheoryId from) |
1326 |
|
{ |
1327 |
|
// For resource-limiting (also does a time check). |
1328 |
|
// spendResource(); |
1329 |
422885 |
Assert(tlemma.getKind() == TrustNodeKind::LEMMA |
1330 |
|
|| tlemma.getKind() == TrustNodeKind::CONFLICT); |
1331 |
|
// get the node |
1332 |
845770 |
Node node = tlemma.getNode(); |
1333 |
845770 |
Node lemma = tlemma.getProven(); |
1334 |
|
|
1335 |
422885 |
Assert(!expr::hasFreeVar(lemma)); |
1336 |
|
|
1337 |
|
// when proofs are enabled, we ensure the trust node has a generator by |
1338 |
|
// adding a trust step to the lazy proof maintained by this class |
1339 |
422885 |
if (isProofEnabled()) |
1340 |
|
{ |
1341 |
|
// ensure proof: set THEORY_LEMMA if no generator is provided |
1342 |
62188 |
if (tlemma.getGenerator() == nullptr) |
1343 |
|
{ |
1344 |
|
// internal lemmas should have generators |
1345 |
6918 |
Assert(from != THEORY_LAST); |
1346 |
|
// add theory lemma step to proof |
1347 |
13836 |
Node tidn = builtin::BuiltinProofRuleChecker::mkTheoryIdNode(from); |
1348 |
6918 |
d_lazyProof->addStep(lemma, PfRule::THEORY_LEMMA, {}, {lemma, tidn}); |
1349 |
|
// update the trust node |
1350 |
6918 |
tlemma = TrustNode::mkTrustLemma(lemma, d_lazyProof.get()); |
1351 |
|
} |
1352 |
|
// ensure closed |
1353 |
62188 |
tlemma.debugCheckClosed("te-proof-debug", "TheoryEngine::lemma_initial"); |
1354 |
|
} |
1355 |
|
|
1356 |
422885 |
if(Dump.isOn("t-lemmas")) { |
1357 |
|
// we dump the negation of the lemma, to show validity of the lemma |
1358 |
|
Node n = lemma.negate(); |
1359 |
|
const Printer& printer = d_env.getPrinter(); |
1360 |
|
std::ostream& out = d_env.getDumpOut(); |
1361 |
|
printer.toStreamCmdComment(out, "theory lemma: expect valid"); |
1362 |
|
printer.toStreamCmdCheckSat(out, n); |
1363 |
|
} |
1364 |
|
|
1365 |
|
// assert the lemma |
1366 |
422887 |
d_propEngine->assertLemma(tlemma, p); |
1367 |
|
|
1368 |
|
// If specified, we must add this lemma to the set of those that need to be |
1369 |
|
// justified, where note we pass all auxiliary lemmas in skAsserts as well, |
1370 |
|
// since these by extension must be justified as well. |
1371 |
422883 |
if (d_relManager != nullptr && isLemmaPropertyNeedsJustify(p)) |
1372 |
|
{ |
1373 |
|
std::vector<Node> skAsserts; |
1374 |
|
std::vector<Node> sks; |
1375 |
|
Node retLemma = |
1376 |
|
d_propEngine->getPreprocessedTerm(tlemma.getProven(), skAsserts, sks); |
1377 |
|
d_relManager->notifyPreprocessedAssertion(retLemma); |
1378 |
|
d_relManager->notifyPreprocessedAssertions(skAsserts); |
1379 |
|
} |
1380 |
|
|
1381 |
|
// Mark that we added some lemmas |
1382 |
422883 |
d_lemmasAdded = true; |
1383 |
422883 |
} |
1384 |
|
|
1385 |
187640 |
void TheoryEngine::markInConflict() |
1386 |
|
{ |
1387 |
|
#ifdef CVC5_FOR_EACH_THEORY_STATEMENT |
1388 |
|
#undef CVC5_FOR_EACH_THEORY_STATEMENT |
1389 |
|
#endif |
1390 |
|
#define CVC5_FOR_EACH_THEORY_STATEMENT(THEORY) \ |
1391 |
|
theoryOf(THEORY)->notifyInConflict(); |
1392 |
187640 |
CVC5_FOR_EACH_THEORY; |
1393 |
187640 |
d_inConflict = true; |
1394 |
187640 |
} |
1395 |
|
|
1396 |
116140 |
void TheoryEngine::conflict(TrustNode tconflict, TheoryId theoryId) |
1397 |
|
{ |
1398 |
116140 |
Assert(tconflict.getKind() == TrustNodeKind::CONFLICT); |
1399 |
|
|
1400 |
232280 |
TNode conflict = tconflict.getNode(); |
1401 |
232280 |
Debug("theory::conflict") << "TheoryEngine::conflict(" << conflict << ", " |
1402 |
116140 |
<< theoryId << ")" << endl; |
1403 |
116140 |
Trace("te-proof-debug") << "Check closed conflict" << std::endl; |
1404 |
|
// doesn't require proof generator, yet, since THEORY_LEMMA is added below |
1405 |
116140 |
tconflict.debugCheckClosed( |
1406 |
|
"te-proof-debug", "TheoryEngine::conflict_initial", false); |
1407 |
|
|
1408 |
116140 |
Trace("dtview::conflict") << ":THEORY-CONFLICT: " << conflict << std::endl; |
1409 |
|
|
1410 |
|
// Mark that we are in conflict |
1411 |
116140 |
markInConflict(); |
1412 |
|
|
1413 |
116140 |
if(Dump.isOn("t-conflicts")) { |
1414 |
|
const Printer& printer = d_env.getPrinter(); |
1415 |
|
std::ostream& out = d_env.getDumpOut(); |
1416 |
|
printer.toStreamCmdComment(out, "theory conflict: expect unsat"); |
1417 |
|
printer.toStreamCmdCheckSat(out, conflict); |
1418 |
|
} |
1419 |
|
|
1420 |
|
// In the multiple-theories case, we need to reconstruct the conflict |
1421 |
116140 |
if (d_logicInfo.isSharingEnabled()) { |
1422 |
|
// Create the workplace for explanations |
1423 |
187916 |
std::vector<NodeTheoryPair> vec; |
1424 |
93958 |
vec.push_back( |
1425 |
187916 |
NodeTheoryPair(conflict, theoryId, d_propagationMapTimestamp)); |
1426 |
|
|
1427 |
|
// Process the explanation |
1428 |
187916 |
TrustNode tncExp = getExplanation(vec); |
1429 |
187916 |
Trace("te-proof-debug") |
1430 |
93958 |
<< "Check closed conflict explained with sharing" << std::endl; |
1431 |
93958 |
tncExp.debugCheckClosed("te-proof-debug", |
1432 |
|
"TheoryEngine::conflict_explained_sharing"); |
1433 |
187916 |
Node fullConflict = tncExp.getNode(); |
1434 |
|
|
1435 |
93958 |
if (isProofEnabled()) |
1436 |
|
{ |
1437 |
12848 |
Trace("te-proof-debug") << "Process conflict: " << conflict << std::endl; |
1438 |
25696 |
Trace("te-proof-debug") << "Conflict " << tconflict << " from " |
1439 |
12848 |
<< tconflict.identifyGenerator() << std::endl; |
1440 |
25696 |
Trace("te-proof-debug") << "Explanation " << tncExp << " from " |
1441 |
12848 |
<< tncExp.identifyGenerator() << std::endl; |
1442 |
12848 |
Assert(d_lazyProof != nullptr); |
1443 |
12848 |
if (tconflict.getGenerator() != nullptr) |
1444 |
|
{ |
1445 |
12408 |
d_lazyProof->addLazyStep(tconflict.getProven(), |
1446 |
|
tconflict.getGenerator()); |
1447 |
|
} |
1448 |
|
else |
1449 |
|
{ |
1450 |
|
// add theory lemma step |
1451 |
880 |
Node tidn = builtin::BuiltinProofRuleChecker::mkTheoryIdNode(theoryId); |
1452 |
880 |
Node conf = tconflict.getProven(); |
1453 |
440 |
d_lazyProof->addStep(conf, PfRule::THEORY_LEMMA, {}, {conf, tidn}); |
1454 |
|
} |
1455 |
|
// store the explicit step, which should come from a different |
1456 |
|
// generator, e.g. d_tepg. |
1457 |
25696 |
Node proven = tncExp.getProven(); |
1458 |
12848 |
Assert(tncExp.getGenerator() != d_lazyProof.get()); |
1459 |
25696 |
Trace("te-proof-debug") << "add lazy step " << tncExp.identifyGenerator() |
1460 |
12848 |
<< " for " << proven << std::endl; |
1461 |
12848 |
d_lazyProof->addLazyStep(proven, tncExp.getGenerator()); |
1462 |
12848 |
pfgEnsureClosed(proven, |
1463 |
12848 |
d_lazyProof.get(), |
1464 |
|
"te-proof-debug", |
1465 |
|
"TheoryEngine::conflict_during"); |
1466 |
25696 |
Node fullConflictNeg = fullConflict.notNode(); |
1467 |
25696 |
std::vector<Node> children; |
1468 |
12848 |
children.push_back(proven); |
1469 |
25696 |
std::vector<Node> args; |
1470 |
12848 |
args.push_back(fullConflictNeg); |
1471 |
12848 |
if (conflict == d_false) |
1472 |
|
{ |
1473 |
118 |
AlwaysAssert(proven == fullConflictNeg); |
1474 |
|
} |
1475 |
|
else |
1476 |
|
{ |
1477 |
12730 |
if (fullConflict != conflict) |
1478 |
|
{ |
1479 |
|
// ------------------------- explained ---------- from theory |
1480 |
|
// fullConflict => conflict ~conflict |
1481 |
|
// ------------------------------------------ MACRO_SR_PRED_TRANSFORM |
1482 |
|
// ~fullConflict |
1483 |
12281 |
children.push_back(conflict.notNode()); |
1484 |
12281 |
args.push_back(mkMethodId(MethodId::SB_LITERAL)); |
1485 |
12281 |
d_lazyProof->addStep( |
1486 |
|
fullConflictNeg, PfRule::MACRO_SR_PRED_TRANSFORM, children, args); |
1487 |
|
} |
1488 |
|
} |
1489 |
|
} |
1490 |
|
// pass the processed trust node |
1491 |
|
TrustNode tconf = |
1492 |
187916 |
TrustNode::mkTrustConflict(fullConflict, d_lazyProof.get()); |
1493 |
187916 |
Debug("theory::conflict") |
1494 |
93958 |
<< "TheoryEngine::conflict(" << conflict << ", " << theoryId |
1495 |
93958 |
<< "): full = " << fullConflict << endl; |
1496 |
93958 |
Assert(properConflict(fullConflict)); |
1497 |
187916 |
Trace("te-proof-debug") |
1498 |
93958 |
<< "Check closed conflict with sharing" << std::endl; |
1499 |
93958 |
tconf.debugCheckClosed("te-proof-debug", "TheoryEngine::conflict:sharing"); |
1500 |
93958 |
lemma(tconf, LemmaProperty::REMOVABLE); |
1501 |
|
} else { |
1502 |
|
// When only one theory, the conflict should need no processing |
1503 |
22182 |
Assert(properConflict(conflict)); |
1504 |
|
// pass the trust node that was sent from the theory |
1505 |
22182 |
lemma(tconflict, LemmaProperty::REMOVABLE, theoryId); |
1506 |
|
} |
1507 |
116140 |
} |
1508 |
|
|
1509 |
2150 |
void TheoryEngine::setIncomplete(theory::TheoryId theory, |
1510 |
|
theory::IncompleteId id) |
1511 |
|
{ |
1512 |
2150 |
d_incomplete = true; |
1513 |
2150 |
d_incompleteTheory = theory; |
1514 |
2150 |
d_incompleteId = id; |
1515 |
2150 |
} |
1516 |
|
|
1517 |
159122 |
TrustNode TheoryEngine::getExplanation( |
1518 |
|
std::vector<NodeTheoryPair>& explanationVector) |
1519 |
|
{ |
1520 |
159122 |
Assert(explanationVector.size() == 1); |
1521 |
318244 |
Node conclusion = explanationVector[0].d_node; |
1522 |
|
// if the theory explains using the central equality engine, we always start |
1523 |
|
// with THEORY_BUILTIN. |
1524 |
159122 |
if (Theory::expUsingCentralEqualityEngine(explanationVector[0].d_theory)) |
1525 |
|
{ |
1526 |
39186 |
explanationVector[0].d_theory = THEORY_BUILTIN; |
1527 |
|
} |
1528 |
318244 |
std::shared_ptr<LazyCDProof> lcp; |
1529 |
159122 |
if (isProofEnabled()) |
1530 |
|
{ |
1531 |
36270 |
Trace("te-proof-exp") << "=== TheoryEngine::getExplanation " << conclusion |
1532 |
18135 |
<< std::endl; |
1533 |
36270 |
lcp.reset(new LazyCDProof( |
1534 |
18135 |
d_pnm, nullptr, nullptr, "TheoryEngine::LazyCDProof::getExplanation")); |
1535 |
|
} |
1536 |
159122 |
unsigned i = 0; // Index of the current literal we are processing |
1537 |
|
|
1538 |
318244 |
std::unique_ptr<std::set<Node>> inputAssertions = nullptr; |
1539 |
|
// the overall explanation |
1540 |
318244 |
std::set<TNode> exp; |
1541 |
|
// vector of trust nodes to explain at the end |
1542 |
318244 |
std::vector<std::pair<TheoryId, TrustNode>> texplains; |
1543 |
|
// cache of nodes we have already explained by some theory |
1544 |
318244 |
std::unordered_map<Node, size_t> cache; |
1545 |
|
|
1546 |
6972824 |
while (i < explanationVector.size()) { |
1547 |
|
// Get the current literal to explain |
1548 |
3706233 |
NodeTheoryPair toExplain = explanationVector[i]; |
1549 |
|
|
1550 |
6813702 |
Debug("theory::explain") |
1551 |
3406851 |
<< "[i=" << i << "] TheoryEngine::explain(): processing [" |
1552 |
3406851 |
<< toExplain.d_timestamp << "] " << toExplain.d_node << " sent from " |
1553 |
3406851 |
<< toExplain.d_theory << endl; |
1554 |
|
|
1555 |
6924943 |
if (cache.find(toExplain.d_node) != cache.end() |
1556 |
3406851 |
&& cache[toExplain.d_node] < toExplain.d_timestamp) |
1557 |
|
{ |
1558 |
111241 |
++i; |
1559 |
111241 |
continue; |
1560 |
|
} |
1561 |
3295610 |
cache[toExplain.d_node] = toExplain.d_timestamp; |
1562 |
|
|
1563 |
|
// If a true constant or a negation of a false constant we can ignore it |
1564 |
6604890 |
if ((toExplain.d_node.isConst() && toExplain.d_node.getConst<bool>()) |
1565 |
9886830 |
|| (toExplain.d_node.getKind() == kind::NOT |
1566 |
3626116 |
&& toExplain.d_node[0].isConst() |
1567 |
3295610 |
&& !toExplain.d_node[0].getConst<bool>())) |
1568 |
|
{ |
1569 |
13264 |
++ i; |
1570 |
|
// if we are building a proof |
1571 |
13264 |
if (lcp != nullptr) |
1572 |
|
{ |
1573 |
2932 |
Trace("te-proof-exp") |
1574 |
1466 |
<< "- explain " << toExplain.d_node << " trivially..." << std::endl; |
1575 |
|
// ------------------MACRO_SR_PRED_INTRO |
1576 |
|
// toExplain.d_node |
1577 |
2932 |
std::vector<Node> children; |
1578 |
2932 |
std::vector<Node> args; |
1579 |
1466 |
args.push_back(toExplain.d_node); |
1580 |
1466 |
lcp->addStep( |
1581 |
|
toExplain.d_node, PfRule::MACRO_SR_PRED_INTRO, children, args); |
1582 |
|
} |
1583 |
13264 |
continue; |
1584 |
|
} |
1585 |
|
|
1586 |
|
// If from the SAT solver, keep it |
1587 |
4448989 |
if (toExplain.d_theory == THEORY_SAT_SOLVER) |
1588 |
|
{ |
1589 |
2333286 |
Debug("theory::explain") |
1590 |
1166643 |
<< "\tLiteral came from THEORY_SAT_SOLVER. Keeping it." << endl; |
1591 |
1166643 |
exp.insert(explanationVector[i++].d_node); |
1592 |
|
// it will be a free assumption in the proof |
1593 |
1166643 |
Trace("te-proof-exp") << "- keep " << toExplain.d_node << std::endl; |
1594 |
1166643 |
continue; |
1595 |
|
} |
1596 |
|
|
1597 |
|
// If an and, expand it |
1598 |
2115703 |
if (toExplain.d_node.getKind() == kind::AND) |
1599 |
|
{ |
1600 |
633562 |
Debug("theory::explain") |
1601 |
316781 |
<< "TheoryEngine::explain(): expanding " << toExplain.d_node |
1602 |
316781 |
<< " got from " << toExplain.d_theory << endl; |
1603 |
316781 |
size_t nchild = toExplain.d_node.getNumChildren(); |
1604 |
1765588 |
for (size_t k = 0; k < nchild; ++k) |
1605 |
|
{ |
1606 |
|
NodeTheoryPair newExplain( |
1607 |
2897614 |
toExplain.d_node[k], toExplain.d_theory, toExplain.d_timestamp); |
1608 |
1448807 |
explanationVector.push_back(newExplain); |
1609 |
|
} |
1610 |
316781 |
if (lcp != nullptr) |
1611 |
|
{ |
1612 |
83484 |
Trace("te-proof-exp") |
1613 |
41742 |
<< "- AND expand " << toExplain.d_node << std::endl; |
1614 |
|
// delay explanation, use a dummy trust node |
1615 |
|
TrustNode tnAndExp = TrustNode::mkTrustPropExp( |
1616 |
83484 |
toExplain.d_node, toExplain.d_node, nullptr); |
1617 |
41742 |
texplains.push_back( |
1618 |
83484 |
std::pair<TheoryId, TrustNode>(THEORY_LAST, tnAndExp)); |
1619 |
|
} |
1620 |
316781 |
++ i; |
1621 |
316781 |
continue; |
1622 |
|
} |
1623 |
|
|
1624 |
|
// See if it was sent to the theory by another theory |
1625 |
1798922 |
PropagationMap::const_iterator find = d_propagationMap.find(toExplain); |
1626 |
1798922 |
if (find != d_propagationMap.end()) { |
1627 |
3413240 |
Debug("theory::explain") |
1628 |
1706620 |
<< "\tTerm was propagated by another theory (theory = " |
1629 |
1706620 |
<< getTheoryString((*find).second.d_theory) << ")" << std::endl; |
1630 |
|
// There is some propagation, check if its a timely one |
1631 |
1706620 |
if ((*find).second.d_timestamp < toExplain.d_timestamp) |
1632 |
|
{ |
1633 |
2999080 |
Debug("theory::explain") |
1634 |
1499540 |
<< "\tRelevant timetsamp, pushing " << (*find).second.d_node |
1635 |
1499540 |
<< "to index = " << explanationVector.size() << std::endl; |
1636 |
1499540 |
explanationVector.push_back((*find).second); |
1637 |
1499540 |
++i; |
1638 |
|
|
1639 |
1499540 |
if (lcp != nullptr) |
1640 |
|
{ |
1641 |
193777 |
if (!CDProof::isSame(toExplain.d_node, (*find).second.d_node)) |
1642 |
|
{ |
1643 |
6706 |
Trace("te-proof-exp") |
1644 |
3353 |
<< "- t-explained cached: " << toExplain.d_node << " by " |
1645 |
3353 |
<< (*find).second.d_node << std::endl; |
1646 |
|
// delay explanation, use a dummy trust node that says that |
1647 |
|
// (*find).second.d_node explains toExplain.d_node. |
1648 |
|
TrustNode tnRewExp = TrustNode::mkTrustPropExp( |
1649 |
6706 |
toExplain.d_node, (*find).second.d_node, nullptr); |
1650 |
3353 |
texplains.push_back( |
1651 |
6706 |
std::pair<TheoryId, TrustNode>(THEORY_LAST, tnRewExp)); |
1652 |
|
} |
1653 |
|
} |
1654 |
1499540 |
continue; |
1655 |
|
} |
1656 |
|
} |
1657 |
|
// It was produced by the theory, so ask for an explanation |
1658 |
|
TrustNode texplanation = |
1659 |
598764 |
d_sharedSolver->explain(toExplain.d_node, toExplain.d_theory); |
1660 |
299382 |
if (lcp != nullptr) |
1661 |
|
{ |
1662 |
40291 |
texplanation.debugCheckClosed("te-proof-exp", "texplanation", false); |
1663 |
80582 |
Trace("te-proof-exp") |
1664 |
40291 |
<< "- t-explained[" << toExplain.d_theory << "]: " << toExplain.d_node |
1665 |
40291 |
<< " by " << texplanation.getNode() << std::endl; |
1666 |
|
// should prove the propagation we asked for |
1667 |
40291 |
Assert(texplanation.getKind() == TrustNodeKind::PROP_EXP |
1668 |
|
&& texplanation.getProven()[1] == toExplain.d_node); |
1669 |
|
// if not a trivial explanation |
1670 |
40291 |
if (!CDProof::isSame(texplanation.getNode(), toExplain.d_node)) |
1671 |
|
{ |
1672 |
|
// We add it to the list of theory explanations, to be processed at |
1673 |
|
// the end of this method. We wait to explain here because it may |
1674 |
|
// be that a later explanation may preempt the need for proving this |
1675 |
|
// step. For instance, if the conclusion lit is later added as an |
1676 |
|
// assumption in the final explanation. This avoids cyclic proofs. |
1677 |
37908 |
texplains.push_back( |
1678 |
75816 |
std::pair<TheoryId, TrustNode>(toExplain.d_theory, texplanation)); |
1679 |
|
} |
1680 |
|
} |
1681 |
598764 |
Node explanation = texplanation.getNode(); |
1682 |
|
|
1683 |
598764 |
Debug("theory::explain") |
1684 |
299382 |
<< "TheoryEngine::explain(): got explanation " << explanation |
1685 |
299382 |
<< " got from " << toExplain.d_theory << endl; |
1686 |
299382 |
Assert(explanation != toExplain.d_node) |
1687 |
|
<< "wasn't sent to you, so why are you explaining it trivially, for " |
1688 |
|
"fact " |
1689 |
|
<< explanation; |
1690 |
|
// Mark the explanation |
1691 |
|
NodeTheoryPair newExplain( |
1692 |
598764 |
explanation, toExplain.d_theory, toExplain.d_timestamp); |
1693 |
299382 |
explanationVector.push_back(newExplain); |
1694 |
|
|
1695 |
299382 |
++ i; |
1696 |
|
} |
1697 |
|
|
1698 |
|
// make the explanation node |
1699 |
318244 |
Node expNode; |
1700 |
159122 |
if (exp.size() == 0) |
1701 |
|
{ |
1702 |
|
// Normalize to true |
1703 |
39 |
expNode = NodeManager::currentNM()->mkConst<bool>(true); |
1704 |
|
} |
1705 |
159083 |
else if (exp.size() == 1) |
1706 |
|
{ |
1707 |
|
// All the same, or just one |
1708 |
5446 |
expNode = *exp.begin(); |
1709 |
|
} |
1710 |
|
else |
1711 |
|
{ |
1712 |
307274 |
NodeBuilder conjunction(kind::AND); |
1713 |
153637 |
std::set<TNode>::const_iterator it = exp.begin(); |
1714 |
153637 |
std::set<TNode>::const_iterator it_end = exp.end(); |
1715 |
2392889 |
while (it != it_end) |
1716 |
|
{ |
1717 |
1119626 |
conjunction << *it; |
1718 |
1119626 |
++it; |
1719 |
|
} |
1720 |
153637 |
expNode = conjunction; |
1721 |
|
} |
1722 |
|
// if we are building a proof, go back through the explanations and |
1723 |
|
// build the proof |
1724 |
159122 |
if (lcp != nullptr) |
1725 |
|
{ |
1726 |
18135 |
if (Trace.isOn("te-proof-exp")) |
1727 |
|
{ |
1728 |
|
Trace("te-proof-exp") << "Explanation is:" << std::endl; |
1729 |
|
for (TNode e : exp) |
1730 |
|
{ |
1731 |
|
Trace("te-proof-exp") << " " << e << std::endl; |
1732 |
|
} |
1733 |
|
Trace("te-proof-exp") << "=== Replay explanations..." << std::endl; |
1734 |
|
} |
1735 |
|
// Now, go back and add the necessary steps of theory explanations, i.e. |
1736 |
|
// add those that prove things that aren't in the final explanation. We |
1737 |
|
// iterate in reverse order so that most recent steps take priority. This |
1738 |
|
// avoids cyclic proofs in the lazy proof we are building (lcp). |
1739 |
83003 |
for (std::vector<std::pair<TheoryId, TrustNode>>::reverse_iterator |
1740 |
18135 |
it = texplains.rbegin(), |
1741 |
18135 |
itEnd = texplains.rend(); |
1742 |
101138 |
it != itEnd; |
1743 |
|
++it) |
1744 |
|
{ |
1745 |
119460 |
TrustNode trn = it->second; |
1746 |
83003 |
Assert(trn.getKind() == TrustNodeKind::PROP_EXP); |
1747 |
119460 |
Node proven = trn.getProven(); |
1748 |
83003 |
Assert(proven.getKind() == kind::IMPLIES); |
1749 |
119460 |
Node tConc = proven[1]; |
1750 |
83003 |
Trace("te-proof-exp") << "- Process " << trn << std::endl; |
1751 |
86662 |
if (exp.find(tConc) != exp.end()) |
1752 |
|
{ |
1753 |
|
// already added to proof |
1754 |
3659 |
Trace("te-proof-exp") << "...already added" << std::endl; |
1755 |
3659 |
continue; |
1756 |
|
} |
1757 |
115801 |
Node symTConc = CDProof::getSymmFact(tConc); |
1758 |
79344 |
if (!symTConc.isNull()) |
1759 |
|
{ |
1760 |
35995 |
if (exp.find(symTConc) != exp.end()) |
1761 |
|
{ |
1762 |
|
// symmetric direction |
1763 |
46 |
Trace("te-proof-exp") << "...already added (SYMM)" << std::endl; |
1764 |
46 |
continue; |
1765 |
|
} |
1766 |
|
} |
1767 |
|
// remember that we've explained this formula, to avoid cycles in lcp |
1768 |
79298 |
exp.insert(tConc); |
1769 |
79298 |
TheoryId ttid = it->first; |
1770 |
115755 |
Node tExp = proven[0]; |
1771 |
79298 |
if (ttid == THEORY_LAST) |
1772 |
|
{ |
1773 |
42841 |
if (tConc == tExp) |
1774 |
|
{ |
1775 |
|
// dummy trust node, do AND expansion |
1776 |
40718 |
Assert(tConc.getKind() == kind::AND); |
1777 |
|
// tConc[0] ... tConc[n] |
1778 |
|
// ---------------------- AND_INTRO |
1779 |
|
// tConc |
1780 |
81436 |
std::vector<Node> pfChildren; |
1781 |
40718 |
pfChildren.insert(pfChildren.end(), tConc.begin(), tConc.end()); |
1782 |
40718 |
lcp->addStep(tConc, PfRule::AND_INTRO, pfChildren, {}); |
1783 |
40718 |
Trace("te-proof-exp") << "...via AND_INTRO" << std::endl; |
1784 |
40718 |
continue; |
1785 |
|
} |
1786 |
|
// otherwise should hold by rewriting |
1787 |
2123 |
Assert(Rewriter::rewrite(tConc) == Rewriter::rewrite(tExp)); |
1788 |
|
// tExp |
1789 |
|
// ---- MACRO_SR_PRED_TRANSFORM |
1790 |
|
// tConc |
1791 |
2123 |
lcp->addStep(tConc, PfRule::MACRO_SR_PRED_TRANSFORM, {tExp}, {tConc}); |
1792 |
2123 |
Trace("te-proof-exp") << "...via MACRO_SR_PRED_TRANSFORM" << std::endl; |
1793 |
2123 |
continue; |
1794 |
|
} |
1795 |
36457 |
if (tExp == tConc) |
1796 |
|
{ |
1797 |
|
// trivial |
1798 |
|
Trace("te-proof-exp") << "...trivial" << std::endl; |
1799 |
|
continue; |
1800 |
|
} |
1801 |
|
// ------------- Via theory |
1802 |
|
// tExp tExp => tConc |
1803 |
|
// ---------------------------------MODUS_PONENS |
1804 |
|
// tConc |
1805 |
36457 |
if (trn.getGenerator() != nullptr) |
1806 |
|
{ |
1807 |
35713 |
Trace("te-proof-exp") << "...via theory generator" << std::endl; |
1808 |
35713 |
lcp->addLazyStep(proven, trn.getGenerator()); |
1809 |
|
} |
1810 |
|
else |
1811 |
|
{ |
1812 |
744 |
Trace("te-proof-exp") << "...via trust THEORY_LEMMA" << std::endl; |
1813 |
|
// otherwise, trusted theory lemma |
1814 |
1488 |
Node tidn = builtin::BuiltinProofRuleChecker::mkTheoryIdNode(it->first); |
1815 |
744 |
lcp->addStep(proven, PfRule::THEORY_LEMMA, {}, {proven, tidn}); |
1816 |
|
} |
1817 |
72914 |
std::vector<Node> pfChildren; |
1818 |
36457 |
pfChildren.push_back(trn.getNode()); |
1819 |
36457 |
pfChildren.push_back(proven); |
1820 |
36457 |
lcp->addStep(tConc, PfRule::MODUS_PONENS, pfChildren, {}); |
1821 |
|
} |
1822 |
|
// store in the proof generator |
1823 |
36270 |
TrustNode trn = d_tepg->mkTrustExplain(conclusion, expNode, lcp); |
1824 |
|
// return the trust node |
1825 |
18135 |
return trn; |
1826 |
|
} |
1827 |
|
|
1828 |
140987 |
return TrustNode::mkTrustPropExp(conclusion, expNode, nullptr); |
1829 |
|
} |
1830 |
|
|
1831 |
721449 |
bool TheoryEngine::isProofEnabled() const { return d_pnm != nullptr; } |
1832 |
|
|
1833 |
241 |
void TheoryEngine::setUserAttribute(const std::string& attr, |
1834 |
|
Node n, |
1835 |
|
const std::vector<Node>& node_values, |
1836 |
|
const std::string& str_value) |
1837 |
|
{ |
1838 |
241 |
Trace("te-attr") << "set user attribute " << attr << " " << n << endl; |
1839 |
241 |
if( d_attr_handle.find( attr )!=d_attr_handle.end() ){ |
1840 |
482 |
for( size_t i=0; i<d_attr_handle[attr].size(); i++ ){ |
1841 |
241 |
d_attr_handle[attr][i]->setUserAttribute(attr, n, node_values, str_value); |
1842 |
|
} |
1843 |
|
} else { |
1844 |
|
//unhandled exception? |
1845 |
|
} |
1846 |
241 |
} |
1847 |
|
|
1848 |
49270 |
void TheoryEngine::handleUserAttribute(const char* attr, Theory* t) { |
1849 |
49270 |
Trace("te-attr") << "Handle user attribute " << attr << " " << t << endl; |
1850 |
98540 |
std::string str( attr ); |
1851 |
49270 |
d_attr_handle[ str ].push_back( t ); |
1852 |
49270 |
} |
1853 |
|
|
1854 |
2137 |
void TheoryEngine::checkTheoryAssertionsWithModel(bool hardFailure) { |
1855 |
29918 |
for(TheoryId theoryId = THEORY_FIRST; theoryId < THEORY_LAST; ++theoryId) { |
1856 |
27781 |
Theory* theory = d_theoryTable[theoryId]; |
1857 |
27781 |
if(theory && d_logicInfo.isTheoryEnabled(theoryId)) { |
1858 |
109498 |
for(context::CDList<Assertion>::const_iterator it = theory->facts_begin(), |
1859 |
12947 |
it_end = theory->facts_end(); |
1860 |
109498 |
it != it_end; |
1861 |
|
++it) { |
1862 |
193102 |
Node assertion = (*it).d_assertion; |
1863 |
96551 |
if (!isRelevant(assertion)) |
1864 |
|
{ |
1865 |
|
// not relevant, skip |
1866 |
|
continue; |
1867 |
|
} |
1868 |
193102 |
Node val = d_tc->getModel()->getValue(assertion); |
1869 |
96551 |
if (val != d_true) |
1870 |
|
{ |
1871 |
12 |
std::stringstream ss; |
1872 |
12 |
ss << " " << theoryId |
1873 |
12 |
<< " has an asserted fact that the model doesn't satisfy." << endl |
1874 |
12 |
<< "The fact: " << assertion << endl |
1875 |
6 |
<< "Model value: " << val << endl; |
1876 |
6 |
if (hardFailure) |
1877 |
|
{ |
1878 |
6 |
if (val == d_false) |
1879 |
|
{ |
1880 |
|
// Always an error if it is false |
1881 |
|
InternalError() << ss.str(); |
1882 |
|
} |
1883 |
|
else |
1884 |
|
{ |
1885 |
|
// Otherwise just a warning. Notice this case may happen for |
1886 |
|
// assertions with unevaluable operators, e.g. transcendental |
1887 |
|
// functions. It also may happen for separation logic, where |
1888 |
|
// check-model support is limited. |
1889 |
6 |
Warning() << ss.str(); |
1890 |
|
} |
1891 |
|
} |
1892 |
|
} |
1893 |
|
} |
1894 |
|
} |
1895 |
|
} |
1896 |
2137 |
} |
1897 |
|
|
1898 |
6591 |
std::pair<bool, Node> TheoryEngine::entailmentCheck(options::TheoryOfMode mode, |
1899 |
|
TNode lit) |
1900 |
|
{ |
1901 |
13182 |
TNode atom = (lit.getKind() == kind::NOT) ? lit[0] : lit; |
1902 |
6591 |
if( atom.getKind()==kind::AND || atom.getKind()==kind::OR || atom.getKind()==kind::IMPLIES ){ |
1903 |
|
//Boolean connective, recurse |
1904 |
|
std::vector< Node > children; |
1905 |
|
bool pol = (lit.getKind()!=kind::NOT); |
1906 |
|
bool is_conjunction = pol==(lit.getKind()==kind::AND); |
1907 |
|
for( unsigned i=0; i<atom.getNumChildren(); i++ ){ |
1908 |
|
Node ch = atom[i]; |
1909 |
|
if( pol==( lit.getKind()==kind::IMPLIES && i==0 ) ){ |
1910 |
|
ch = atom[i].negate(); |
1911 |
|
} |
1912 |
|
std::pair<bool, Node> chres = entailmentCheck(mode, ch); |
1913 |
|
if( chres.first ){ |
1914 |
|
if( !is_conjunction ){ |
1915 |
|
return chres; |
1916 |
|
}else{ |
1917 |
|
children.push_back( chres.second ); |
1918 |
|
} |
1919 |
|
}else if( !chres.first && is_conjunction ){ |
1920 |
|
return std::pair<bool, Node>(false, Node::null()); |
1921 |
|
} |
1922 |
|
} |
1923 |
|
if( is_conjunction ){ |
1924 |
|
return std::pair<bool, Node>(true, NodeManager::currentNM()->mkNode(kind::AND, children)); |
1925 |
|
}else{ |
1926 |
|
return std::pair<bool, Node>(false, Node::null()); |
1927 |
|
} |
1928 |
6591 |
}else if( atom.getKind()==kind::ITE || ( atom.getKind()==kind::EQUAL && atom[0].getType().isBoolean() ) ){ |
1929 |
|
bool pol = (lit.getKind()!=kind::NOT); |
1930 |
|
for( unsigned r=0; r<2; r++ ){ |
1931 |
|
Node ch = atom[0]; |
1932 |
|
if( r==1 ){ |
1933 |
|
ch = ch.negate(); |
1934 |
|
} |
1935 |
|
std::pair<bool, Node> chres = entailmentCheck(mode, ch); |
1936 |
|
if( chres.first ){ |
1937 |
|
Node ch2 = atom[ atom.getKind()==kind::ITE ? r+1 : 1 ]; |
1938 |
|
if( pol==( atom.getKind()==kind::ITE ? true : r==1 ) ){ |
1939 |
|
ch2 = ch2.negate(); |
1940 |
|
} |
1941 |
|
std::pair<bool, Node> chres2 = entailmentCheck(mode, ch2); |
1942 |
|
if( chres2.first ){ |
1943 |
|
return std::pair<bool, Node>(true, NodeManager::currentNM()->mkNode(kind::AND, chres.second, chres2.second)); |
1944 |
|
}else{ |
1945 |
|
break; |
1946 |
|
} |
1947 |
|
} |
1948 |
|
} |
1949 |
|
return std::pair<bool, Node>(false, Node::null()); |
1950 |
|
}else{ |
1951 |
|
//it is a theory atom |
1952 |
6591 |
theory::TheoryId tid = theory::Theory::theoryOf(mode, atom); |
1953 |
6591 |
theory::Theory* th = theoryOf(tid); |
1954 |
|
|
1955 |
6591 |
Assert(th != NULL); |
1956 |
6591 |
Trace("theory-engine-entc") << "Entailment check : " << lit << std::endl; |
1957 |
|
|
1958 |
13182 |
std::pair<bool, Node> chres = th->entailmentCheck(lit); |
1959 |
6591 |
return chres; |
1960 |
|
} |
1961 |
|
} |
1962 |
|
|
1963 |
7260298 |
bool TheoryEngine::isFiniteType(TypeNode tn) const |
1964 |
|
{ |
1965 |
7260298 |
return isCardinalityClassFinite(tn.getCardinalityClass(), |
1966 |
14520596 |
options::finiteModelFind()); |
1967 |
|
} |
1968 |
|
|
1969 |
8583159 |
void TheoryEngine::spendResource(Resource r) |
1970 |
|
{ |
1971 |
8583159 |
d_env.getResourceManager()->spendResource(r); |
1972 |
8583159 |
} |
1973 |
|
|
1974 |
3769 |
void TheoryEngine::initializeProofChecker(ProofChecker* pc) |
1975 |
|
{ |
1976 |
52766 |
for (theory::TheoryId id = theory::THEORY_FIRST; id < theory::THEORY_LAST; |
1977 |
|
++id) |
1978 |
|
{ |
1979 |
48997 |
ProofRuleChecker* prc = d_theoryTable[id]->getProofChecker(); |
1980 |
48997 |
if (prc) |
1981 |
|
{ |
1982 |
33890 |
prc->registerTo(pc); |
1983 |
|
} |
1984 |
|
} |
1985 |
3769 |
} |
1986 |
|
|
1987 |
29349 |
} // namespace cvc5 |