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/lazy_proof.h" |
24 |
|
#include "expr/node_builder.h" |
25 |
|
#include "expr/node_visitor.h" |
26 |
|
#include "expr/proof_checker.h" |
27 |
|
#include "expr/proof_ensure_closed.h" |
28 |
|
#include "options/quantifiers_options.h" |
29 |
|
#include "options/smt_options.h" |
30 |
|
#include "options/theory_options.h" |
31 |
|
#include "printer/printer.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 |
1823834 |
std::string getTheoryString(theory::TheoryId id) |
114 |
|
{ |
115 |
1823834 |
if (id == theory::THEORY_SAT_SOLVER) |
116 |
|
{ |
117 |
1250368 |
return "THEORY_SAT_SOLVER"; |
118 |
|
} |
119 |
|
else |
120 |
|
{ |
121 |
1146932 |
std::stringstream ss; |
122 |
573466 |
ss << id; |
123 |
573466 |
return ss.str(); |
124 |
|
} |
125 |
|
} |
126 |
|
|
127 |
9459 |
void TheoryEngine::finishInit() |
128 |
|
{ |
129 |
|
// NOTE: This seems to be required since |
130 |
|
// theory::TheoryTraits<THEORY>::isParametric cannot be accessed without |
131 |
|
// using the CVC5_FOR_EACH_THEORY_STATEMENT macro. -AJR |
132 |
18918 |
std::vector<theory::Theory*> paraTheories; |
133 |
|
#ifdef CVC5_FOR_EACH_THEORY_STATEMENT |
134 |
|
#undef CVC5_FOR_EACH_THEORY_STATEMENT |
135 |
|
#endif |
136 |
|
#define CVC5_FOR_EACH_THEORY_STATEMENT(THEORY) \ |
137 |
|
if (theory::TheoryTraits<THEORY>::isParametric \ |
138 |
|
&& d_logicInfo.isTheoryEnabled(THEORY)) \ |
139 |
|
{ \ |
140 |
|
paraTheories.push_back(theoryOf(THEORY)); \ |
141 |
|
} |
142 |
|
// Collect the parametric theories, which are given to the theory combination |
143 |
|
// manager below |
144 |
9459 |
CVC5_FOR_EACH_THEORY; |
145 |
|
|
146 |
|
// Initialize the theory combination architecture |
147 |
18918 |
if (options::tcMode() == options::TcMode::CARE_GRAPH) |
148 |
|
{ |
149 |
9459 |
d_tc.reset(new CombinationCareGraph(*this, d_env, paraTheories, d_pnm)); |
150 |
|
} |
151 |
|
else |
152 |
|
{ |
153 |
|
Unimplemented() << "TheoryEngine::finishInit: theory combination mode " |
154 |
|
<< options::tcMode() << " not supported"; |
155 |
|
} |
156 |
|
// create the relevance filter if any option requires it |
157 |
9459 |
if (options::relevanceFilter()) |
158 |
|
{ |
159 |
50 |
d_relManager.reset( |
160 |
50 |
new RelevanceManager(d_env.getUserContext(), theory::Valuation(this))); |
161 |
|
} |
162 |
|
|
163 |
|
// initialize the quantifiers engine |
164 |
9459 |
if (d_logicInfo.isQuantified()) |
165 |
|
{ |
166 |
|
// get the quantifiers engine, which is initialized by the quantifiers |
167 |
|
// theory |
168 |
6413 |
d_quantEngine = d_theoryTable[THEORY_QUANTIFIERS]->getQuantifiersEngine(); |
169 |
6413 |
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 |
9459 |
if (d_logicInfo.isQuantified()) |
175 |
|
{ |
176 |
6413 |
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 |
9459 |
d_tc->finishInit(); |
181 |
|
// get pointer to the shared solver |
182 |
9459 |
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 |
132426 |
for(TheoryId theoryId = theory::THEORY_FIRST; theoryId != theory::THEORY_LAST; ++ theoryId) { |
187 |
122967 |
Theory* t = d_theoryTable[theoryId]; |
188 |
122967 |
if (t == nullptr) |
189 |
|
{ |
190 |
|
continue; |
191 |
|
} |
192 |
|
// setup the pointers to the utilities |
193 |
122967 |
const EeTheoryInfo* eeti = d_tc->getEeTheoryInfo(theoryId); |
194 |
122967 |
Assert(eeti != nullptr); |
195 |
|
// the theory's official equality engine is the one specified by the |
196 |
|
// equality engine manager |
197 |
122967 |
t->setEqualityEngine(eeti->d_usedEe); |
198 |
|
// set the quantifiers engine |
199 |
122967 |
t->setQuantifiersEngine(d_quantEngine); |
200 |
|
// set the decision manager for the theory |
201 |
122967 |
t->setDecisionManager(d_decManager.get()); |
202 |
|
// finish initializing the theory |
203 |
122967 |
t->finishInit(); |
204 |
|
} |
205 |
9459 |
} |
206 |
|
|
207 |
|
ProofNodeManager* TheoryEngine::getProofNodeManager() const { return d_pnm; } |
208 |
|
|
209 |
167252 |
context::Context* TheoryEngine::getSatContext() const |
210 |
|
{ |
211 |
167252 |
return d_env.getContext(); |
212 |
|
} |
213 |
|
|
214 |
133654 |
context::UserContext* TheoryEngine::getUserContext() const |
215 |
|
{ |
216 |
133654 |
return d_env.getUserContext(); |
217 |
|
} |
218 |
|
|
219 |
9459 |
TheoryEngine::TheoryEngine(Env& env, |
220 |
|
OutputManager& outMgr, |
221 |
9459 |
ProofNodeManager* pnm) |
222 |
|
: d_propEngine(nullptr), |
223 |
|
d_env(env), |
224 |
9459 |
d_logicInfo(env.getLogicInfo()), |
225 |
|
d_outMgr(outMgr), |
226 |
|
d_pnm(pnm), |
227 |
9459 |
d_lazyProof(d_pnm != nullptr |
228 |
|
? new LazyCDProof(d_pnm, |
229 |
|
nullptr, |
230 |
1192 |
d_env.getUserContext(), |
231 |
1192 |
"TheoryEngine::LazyCDProof") |
232 |
|
: nullptr), |
233 |
9459 |
d_tepg(new TheoryEngineProofGenerator(d_pnm, d_env.getUserContext())), |
234 |
|
d_tc(nullptr), |
235 |
|
d_sharedSolver(nullptr), |
236 |
|
d_quantEngine(nullptr), |
237 |
9459 |
d_decManager(new DecisionManager(d_env.getUserContext())), |
238 |
|
d_relManager(nullptr), |
239 |
|
d_eager_model_building(false), |
240 |
9459 |
d_inConflict(d_env.getContext(), false), |
241 |
|
d_inSatMode(false), |
242 |
|
d_hasShutDown(false), |
243 |
9459 |
d_incomplete(d_env.getContext(), false), |
244 |
9459 |
d_incompleteTheory(d_env.getContext(), THEORY_BUILTIN), |
245 |
9459 |
d_incompleteId(d_env.getContext(), IncompleteId::UNKNOWN), |
246 |
9459 |
d_propagationMap(d_env.getContext()), |
247 |
9459 |
d_propagationMapTimestamp(d_env.getContext(), 0), |
248 |
9459 |
d_propagatedLiterals(d_env.getContext()), |
249 |
9459 |
d_propagatedLiteralsIndex(d_env.getContext(), 0), |
250 |
9459 |
d_atomRequests(d_env.getContext()), |
251 |
9459 |
d_combineTheoriesTime(smtStatisticsRegistry().registerTimer( |
252 |
18918 |
"TheoryEngine::combineTheoriesTime")), |
253 |
|
d_true(), |
254 |
|
d_false(), |
255 |
|
d_interrupted(false), |
256 |
|
d_inPreregister(false), |
257 |
9459 |
d_factsAsserted(d_env.getContext(), false), |
258 |
163187 |
d_attr_handle() |
259 |
|
{ |
260 |
132426 |
for(TheoryId theoryId = theory::THEORY_FIRST; theoryId != theory::THEORY_LAST; |
261 |
|
++ theoryId) |
262 |
|
{ |
263 |
122967 |
d_theoryTable[theoryId] = NULL; |
264 |
122967 |
d_theoryOut[theoryId] = NULL; |
265 |
|
} |
266 |
|
|
267 |
9459 |
if (options::sortInference()) |
268 |
|
{ |
269 |
20 |
d_sortInfer.reset(new SortInference); |
270 |
|
} |
271 |
|
|
272 |
9459 |
d_true = NodeManager::currentNM()->mkConst<bool>(true); |
273 |
9459 |
d_false = NodeManager::currentNM()->mkConst<bool>(false); |
274 |
9459 |
} |
275 |
|
|
276 |
18918 |
TheoryEngine::~TheoryEngine() { |
277 |
9459 |
Assert(d_hasShutDown); |
278 |
|
|
279 |
132426 |
for(TheoryId theoryId = theory::THEORY_FIRST; theoryId != theory::THEORY_LAST; ++ theoryId) { |
280 |
122967 |
if(d_theoryTable[theoryId] != NULL) { |
281 |
122919 |
delete d_theoryTable[theoryId]; |
282 |
122919 |
delete d_theoryOut[theoryId]; |
283 |
|
} |
284 |
|
} |
285 |
9459 |
} |
286 |
|
|
287 |
|
void TheoryEngine::interrupt() { d_interrupted = true; } |
288 |
889297 |
void TheoryEngine::preRegister(TNode preprocessed) { |
289 |
1778594 |
Debug("theory") << "TheoryEngine::preRegister( " << preprocessed << ")" |
290 |
889297 |
<< std::endl; |
291 |
889297 |
d_preregisterQueue.push(preprocessed); |
292 |
|
|
293 |
889297 |
if (!d_inPreregister) { |
294 |
|
// We're in pre-register |
295 |
836334 |
d_inPreregister = true; |
296 |
|
|
297 |
|
// Process the pre-registration queue |
298 |
2614920 |
while (!d_preregisterQueue.empty()) { |
299 |
|
// Get the next atom to pre-register |
300 |
889297 |
preprocessed = d_preregisterQueue.front(); |
301 |
889297 |
d_preregisterQueue.pop(); |
302 |
|
|
303 |
|
// the atom should not have free variables |
304 |
1778594 |
Debug("theory") << "TheoryEngine::preRegister: " << preprocessed |
305 |
889297 |
<< std::endl; |
306 |
889297 |
Assert(!expr::hasFreeVar(preprocessed)); |
307 |
|
// should not have witness |
308 |
889297 |
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 |
889297 |
Assert(d_sharedSolver != nullptr); |
314 |
889301 |
d_sharedSolver->preRegister(preprocessed); |
315 |
|
} |
316 |
|
|
317 |
|
// Leaving pre-register |
318 |
836330 |
d_inPreregister = false; |
319 |
|
} |
320 |
889293 |
} |
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_outMgr.getPrinter(); |
363 |
|
std::ostream& out = d_outMgr.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 |
3075758 |
void TheoryEngine::check(Theory::Effort effort) { |
413 |
|
// spendResource(); |
414 |
|
|
415 |
|
// Reset the interrupt flag |
416 |
3075758 |
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 |
3075758 |
d_outputChannelUsed = false; |
439 |
|
|
440 |
|
// Mark the lemmas flag (no lemmas added) |
441 |
3075758 |
d_lemmasAdded = false; |
442 |
|
|
443 |
3075758 |
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 |
3075758 |
if (Theory::fullEffort(effort)) { |
447 |
61722 |
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 |
61722 |
if (d_relManager != nullptr) |
451 |
|
{ |
452 |
143 |
d_relManager->resetRound(); |
453 |
|
} |
454 |
61722 |
d_tc->resetRound(); |
455 |
|
} |
456 |
|
|
457 |
|
// Check until done |
458 |
8093264 |
while (d_factsAsserted && !d_inConflict && !d_lemmasAdded) { |
459 |
|
|
460 |
2652762 |
Debug("theory") << "TheoryEngine::check(" << effort << "): running check" << endl; |
461 |
|
|
462 |
2652762 |
Trace("theory::assertions") << endl; |
463 |
2652762 |
if (Trace.isOn("theory::assertions")) { |
464 |
|
printAssertions("theory::assertions"); |
465 |
|
} |
466 |
|
|
467 |
2652762 |
if(Theory::fullEffort(effort)) { |
468 |
62425 |
Trace("theory::assertions::fulleffort") << endl; |
469 |
62425 |
if (Trace.isOn("theory::assertions::fulleffort")) { |
470 |
|
printAssertions("theory::assertions::fulleffort"); |
471 |
|
} |
472 |
|
} |
473 |
|
|
474 |
|
// Note that we've discharged all the facts |
475 |
2652762 |
d_factsAsserted = false; |
476 |
|
|
477 |
|
// Do the checking |
478 |
2652762 |
CVC5_FOR_EACH_THEORY; |
479 |
|
|
480 |
2508753 |
Debug("theory") << "TheoryEngine::check(" << effort << "): running propagation after the initial check" << endl; |
481 |
|
|
482 |
|
// We are still satisfiable, propagate as much as possible |
483 |
2508753 |
propagate(effort); |
484 |
|
|
485 |
|
// We do combination if all has been processed and we are in fullcheck |
486 |
5067719 |
if (Theory::fullEffort(effort) && d_logicInfo.isSharingEnabled() |
487 |
2552823 |
&& !d_factsAsserted && !needCheck() && !d_inConflict) |
488 |
|
{ |
489 |
|
// Do the combination |
490 |
20889 |
Debug("theory") << "TheoryEngine::check(" << effort << "): running combination" << endl; |
491 |
|
{ |
492 |
41778 |
TimerStat::CodeTimer combineTheoriesTimer(d_combineTheoriesTime); |
493 |
20889 |
d_tc->combineTheories(); |
494 |
|
} |
495 |
20889 |
if(d_logicInfo.isQuantified()){ |
496 |
12483 |
d_quantEngine->notifyCombineTheories(); |
497 |
|
} |
498 |
|
} |
499 |
|
} |
500 |
|
|
501 |
|
// Must consult quantifiers theory for last call to ensure sat, or otherwise add a lemma |
502 |
3075754 |
if( Theory::fullEffort(effort) && ! d_inConflict && ! needCheck() ) { |
503 |
19608 |
Trace("theory::assertions-model") << endl; |
504 |
19608 |
if (Trace.isOn("theory::assertions-model")) { |
505 |
|
printAssertions("theory::assertions-model"); |
506 |
|
} |
507 |
|
// reset the model in the combination engine |
508 |
19608 |
d_tc->resetModel(); |
509 |
|
//checks for theories requiring the model go at last call |
510 |
274492 |
for (TheoryId theoryId = THEORY_FIRST; theoryId < THEORY_LAST; ++theoryId) { |
511 |
254886 |
if( theoryId!=THEORY_QUANTIFIERS ){ |
512 |
235280 |
Theory* theory = d_theoryTable[theoryId]; |
513 |
235280 |
if (theory && d_logicInfo.isTheoryEnabled(theoryId)) { |
514 |
124296 |
if( theory->needsCheckLastEffort() ){ |
515 |
9624 |
if (!d_tc->buildModel()) |
516 |
|
{ |
517 |
2 |
break; |
518 |
|
} |
519 |
9622 |
theory->check(Theory::EFFORT_LAST_CALL); |
520 |
|
} |
521 |
|
} |
522 |
|
} |
523 |
|
} |
524 |
19608 |
if (!d_inConflict) |
525 |
|
{ |
526 |
19608 |
if(d_logicInfo.isQuantified()) { |
527 |
|
// quantifiers engine must check at last call effort |
528 |
13482 |
d_quantEngine->check(Theory::EFFORT_LAST_CALL); |
529 |
|
} |
530 |
|
} |
531 |
19598 |
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 |
6994 |
d_inSatMode = true; |
537 |
6994 |
if (d_eager_model_building) |
538 |
|
{ |
539 |
4 |
d_tc->buildModel(); |
540 |
|
} |
541 |
|
} |
542 |
|
} |
543 |
|
|
544 |
3075744 |
Debug("theory") << "TheoryEngine::check(" << effort << "): done, we are " << (d_inConflict ? "unsat" : "sat") << (d_lemmasAdded ? " with new lemmas" : " with no new lemmas"); |
545 |
3075744 |
Debug("theory") << ", need check = " << (needCheck() ? "YES" : "NO") << endl; |
546 |
|
|
547 |
3075744 |
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 |
6994 |
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 |
3075744 |
if(Dump.isOn("theory::fullcheck") && Theory::fullEffort(effort)) { |
557 |
|
if (!d_inConflict && !needCheck()) { |
558 |
|
dumpAssertions("theory::fullcheck"); |
559 |
|
} |
560 |
|
} |
561 |
3075744 |
} |
562 |
|
|
563 |
2508753 |
void TheoryEngine::propagate(Theory::Effort effort) |
564 |
|
{ |
565 |
|
// Reset the interrupt flag |
566 |
2508753 |
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 |
2508753 |
d_interrupted = false; |
581 |
|
|
582 |
|
// Propagate for each theory using the statement above |
583 |
2508753 |
CVC5_FOR_EACH_THEORY; |
584 |
2508753 |
} |
585 |
|
|
586 |
2010617 |
Node TheoryEngine::getNextDecisionRequest() |
587 |
|
{ |
588 |
2010617 |
return d_decManager->getNextDecisionRequest(); |
589 |
|
} |
590 |
|
|
591 |
115152 |
bool TheoryEngine::properConflict(TNode conflict) const { |
592 |
|
bool value; |
593 |
115152 |
if (conflict.getKind() == kind::AND) { |
594 |
1583545 |
for (unsigned i = 0; i < conflict.getNumChildren(); ++ i) { |
595 |
1468960 |
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 |
1468960 |
if (! value) { |
601 |
|
Debug("properConflict") << "Bad conflict is due to false atom: " |
602 |
|
<< conflict[i] << endl; |
603 |
|
return false; |
604 |
|
} |
605 |
1468960 |
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 |
567 |
if (! getPropEngine()->hasValue(conflict, value)) { |
613 |
|
Debug("properConflict") << "Bad conflict is due to unassigned atom: " |
614 |
|
<< conflict << endl; |
615 |
|
return false; |
616 |
|
} |
617 |
567 |
if(! value) { |
618 |
|
Debug("properConflict") << "Bad conflict is due to false atom: " |
619 |
|
<< conflict << endl; |
620 |
|
return false; |
621 |
|
} |
622 |
567 |
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 |
115152 |
return true; |
629 |
|
} |
630 |
|
|
631 |
171984 |
TheoryModel* TheoryEngine::getModel() |
632 |
|
{ |
633 |
171984 |
Assert(d_tc != nullptr); |
634 |
171984 |
TheoryModel* m = d_tc->getModel(); |
635 |
171984 |
Assert(m != nullptr); |
636 |
171984 |
return m; |
637 |
|
} |
638 |
|
|
639 |
4194 |
TheoryModel* TheoryEngine::getBuiltModel() |
640 |
|
{ |
641 |
4194 |
Assert(d_tc != nullptr); |
642 |
|
// If this method was called, we should be in SAT mode, and produceModels |
643 |
|
// should be true. |
644 |
4194 |
AlwaysAssert(options::produceModels()); |
645 |
4194 |
if (!d_inSatMode) |
646 |
|
{ |
647 |
|
// not available, perhaps due to interuption. |
648 |
|
return nullptr; |
649 |
|
} |
650 |
|
// must build model at this point |
651 |
4194 |
if (!d_tc->buildModel()) |
652 |
|
{ |
653 |
|
return nullptr; |
654 |
|
} |
655 |
4193 |
return d_tc->getModel(); |
656 |
|
} |
657 |
|
|
658 |
9760 |
bool TheoryEngine::buildModel() |
659 |
|
{ |
660 |
9760 |
Assert(d_tc != nullptr); |
661 |
9760 |
return d_tc->buildModel(); |
662 |
|
} |
663 |
|
|
664 |
14310 |
bool TheoryEngine::presolve() { |
665 |
|
// Reset the interrupt flag |
666 |
14310 |
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 |
14310 |
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 |
14310 |
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 |
14306 |
return false; |
694 |
|
}/* TheoryEngine::presolve() */ |
695 |
|
|
696 |
14294 |
void TheoryEngine::postsolve() { |
697 |
|
// no longer in SAT mode |
698 |
14294 |
d_inSatMode = false; |
699 |
|
// Reset the interrupt flag |
700 |
14294 |
d_interrupted = false; |
701 |
14294 |
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 |
14294 |
}/* TheoryEngine::postsolve() */ |
722 |
|
|
723 |
|
|
724 |
2527 |
void TheoryEngine::notifyRestart() { |
725 |
|
// Reset the interrupt flag |
726 |
2527 |
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 |
2527 |
CVC5_FOR_EACH_THEORY; |
741 |
2527 |
} |
742 |
|
|
743 |
104072 |
void TheoryEngine::ppStaticLearn(TNode in, NodeBuilder& learned) |
744 |
|
{ |
745 |
|
// Reset the interrupt flag |
746 |
104072 |
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 |
104072 |
CVC5_FOR_EACH_THEORY; |
760 |
104072 |
} |
761 |
|
|
762 |
103214 |
bool TheoryEngine::isRelevant(Node lit) const |
763 |
|
{ |
764 |
103214 |
if (d_relManager != nullptr) |
765 |
|
{ |
766 |
1995 |
return d_relManager->isRelevant(lit); |
767 |
|
} |
768 |
|
// otherwise must assume its relevant |
769 |
101219 |
return true; |
770 |
|
} |
771 |
|
|
772 |
9459 |
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 |
9459 |
d_hasShutDown = true; |
777 |
|
|
778 |
|
// Shutdown all the theories |
779 |
132426 |
for(TheoryId theoryId = theory::THEORY_FIRST; theoryId < theory::THEORY_LAST; ++theoryId) { |
780 |
122967 |
if(d_theoryTable[theoryId]) { |
781 |
122919 |
theoryOf(theoryId)->shutdown(); |
782 |
|
} |
783 |
|
} |
784 |
9459 |
} |
785 |
|
|
786 |
112897 |
theory::Theory::PPAssertStatus TheoryEngine::solve( |
787 |
|
TrustNode tliteral, TrustSubstitutionMap& substitutionOut) |
788 |
|
{ |
789 |
|
// Reset the interrupt flag |
790 |
112897 |
d_interrupted = false; |
791 |
|
|
792 |
225794 |
TNode literal = tliteral.getNode(); |
793 |
225794 |
TNode atom = literal.getKind() == kind::NOT ? literal[0] : literal; |
794 |
112897 |
Trace("theory::solve") << "TheoryEngine::solve(" << literal << "): solving with " << theoryOf(atom)->getId() << endl; |
795 |
|
|
796 |
225794 |
if(! d_logicInfo.isTheoryEnabled(Theory::theoryOf(atom)) && |
797 |
112897 |
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 |
112897 |
theoryOf(atom)->ppAssert(tliteral, substitutionOut); |
809 |
112897 |
Trace("theory::solve") << "TheoryEngine::solve(" << literal << ") => " << solveStatus << endl; |
810 |
225794 |
return solveStatus; |
811 |
|
} |
812 |
|
|
813 |
203525 |
theory::TrustNode TheoryEngine::ppRewriteEquality(TNode eq) |
814 |
|
{ |
815 |
203525 |
Assert(eq.getKind() == kind::EQUAL); |
816 |
407050 |
std::vector<SkolemLemma> lems; |
817 |
203525 |
TrustNode trn = theoryOf(eq)->ppRewrite(eq, lems); |
818 |
|
// should never introduce a skolem to eliminate an equality |
819 |
203525 |
Assert(lems.empty()); |
820 |
407050 |
return trn; |
821 |
|
} |
822 |
|
|
823 |
12874 |
void TheoryEngine::notifyPreprocessedAssertions( |
824 |
|
const std::vector<Node>& assertions) { |
825 |
|
// call all the theories |
826 |
180236 |
for (TheoryId theoryId = theory::THEORY_FIRST; theoryId < theory::THEORY_LAST; |
827 |
|
++theoryId) { |
828 |
167362 |
if (d_theoryTable[theoryId]) { |
829 |
167362 |
theoryOf(theoryId)->ppNotifyAssertions(assertions); |
830 |
|
} |
831 |
|
} |
832 |
12874 |
if (d_relManager != nullptr) |
833 |
|
{ |
834 |
25 |
d_relManager->notifyPreprocessedAssertions(assertions); |
835 |
|
} |
836 |
12874 |
} |
837 |
|
|
838 |
26576713 |
bool TheoryEngine::markPropagation(TNode assertion, TNode originalAssertion, theory::TheoryId toTheoryId, theory::TheoryId fromTheoryId) { |
839 |
|
|
840 |
|
// What and where we are asserting |
841 |
53153426 |
NodeTheoryPair toAssert(assertion, toTheoryId, d_propagationMapTimestamp); |
842 |
|
// What and where it came from |
843 |
53153426 |
NodeTheoryPair toExplain(originalAssertion, fromTheoryId, d_propagationMapTimestamp); |
844 |
|
|
845 |
|
// See if the theory already got this literal |
846 |
26576713 |
PropagationMap::const_iterator find = d_propagationMap.find(toAssert); |
847 |
26576713 |
if (find != d_propagationMap.end()) { |
848 |
|
// The theory already knows this |
849 |
7751233 |
Trace("theory::assertToTheory") << "TheoryEngine::markPropagation(): already there" << endl; |
850 |
7751233 |
return false; |
851 |
|
} |
852 |
|
|
853 |
18825480 |
Trace("theory::assertToTheory") << "TheoryEngine::markPropagation(): marking [" << d_propagationMapTimestamp << "] " << assertion << ", " << toTheoryId << " from " << originalAssertion << ", " << fromTheoryId << endl; |
854 |
|
|
855 |
|
// Mark the propagation |
856 |
18825480 |
d_propagationMap[toAssert] = toExplain; |
857 |
18825480 |
d_propagationMapTimestamp = d_propagationMapTimestamp + 1; |
858 |
|
|
859 |
18825480 |
return true; |
860 |
|
} |
861 |
|
|
862 |
|
|
863 |
32294972 |
void TheoryEngine::assertToTheory(TNode assertion, TNode originalAssertion, theory::TheoryId toTheoryId, theory::TheoryId fromTheoryId) { |
864 |
|
|
865 |
32294972 |
Trace("theory::assertToTheory") << "TheoryEngine::assertToTheory(" << assertion << ", " << originalAssertion << "," << toTheoryId << ", " << fromTheoryId << ")" << endl; |
866 |
|
|
867 |
32294972 |
Assert(toTheoryId != fromTheoryId); |
868 |
53883440 |
if(toTheoryId != THEORY_SAT_SOLVER && |
869 |
21588468 |
! d_logicInfo.isTheoryEnabled(toTheoryId)) { |
870 |
|
stringstream ss; |
871 |
|
ss << "The logic was specified as " << d_logicInfo.getLogicString() |
872 |
|
<< ", which doesn't include " << toTheoryId |
873 |
|
<< ", but got an asserted fact to that theory." << endl |
874 |
|
<< "The fact:" << endl |
875 |
|
<< assertion; |
876 |
|
throw LogicException(ss.str()); |
877 |
|
} |
878 |
|
|
879 |
32294972 |
if (d_inConflict) { |
880 |
66303 |
return; |
881 |
|
} |
882 |
|
|
883 |
|
// If sharing is disabled, things are easy |
884 |
32228669 |
if (!d_logicInfo.isSharingEnabled()) { |
885 |
5651956 |
Assert(assertion == originalAssertion); |
886 |
5651956 |
if (fromTheoryId == THEORY_SAT_SOLVER) { |
887 |
|
// Send to the apropriate theory |
888 |
3670892 |
theory::Theory* toTheory = theoryOf(toTheoryId); |
889 |
|
// We assert it, and we know it's preregistereed |
890 |
3670892 |
toTheory->assertFact(assertion, true); |
891 |
|
// Mark that we have more information |
892 |
3670892 |
d_factsAsserted = true; |
893 |
|
} else { |
894 |
1981064 |
Assert(toTheoryId == THEORY_SAT_SOLVER); |
895 |
|
// Check for propositional conflict |
896 |
|
bool value; |
897 |
1981064 |
if (d_propEngine->hasValue(assertion, value)) { |
898 |
863210 |
if (!value) { |
899 |
34067 |
Trace("theory::propagate") << "TheoryEngine::assertToTheory(" << assertion << ", " << toTheoryId << ", " << fromTheoryId << "): conflict (no sharing)" << endl; |
900 |
68134 |
Trace("dtview::conflict") |
901 |
34067 |
<< ":THEORY-CONFLICT: " << assertion << std::endl; |
902 |
34067 |
d_inConflict = true; |
903 |
|
} else { |
904 |
829143 |
return; |
905 |
|
} |
906 |
|
} |
907 |
1151921 |
d_propagatedLiterals.push_back(assertion); |
908 |
|
} |
909 |
4822813 |
return; |
910 |
|
} |
911 |
|
|
912 |
|
// If sending to the shared terms database, it's also simple |
913 |
26576713 |
if (toTheoryId == THEORY_BUILTIN) { |
914 |
17344002 |
Assert(assertion.getKind() == kind::EQUAL |
915 |
|
|| (assertion.getKind() == kind::NOT |
916 |
|
&& assertion[0].getKind() == kind::EQUAL)) |
917 |
8672001 |
<< "atom should be an EQUALity, not `" << assertion << "'"; |
918 |
8672001 |
if (markPropagation(assertion, originalAssertion, toTheoryId, fromTheoryId)) { |
919 |
|
// assert to the shared solver |
920 |
4817915 |
bool polarity = assertion.getKind() != kind::NOT; |
921 |
9635830 |
TNode atom = polarity ? assertion : assertion[0]; |
922 |
4817915 |
d_sharedSolver->assertSharedEquality(atom, polarity, assertion); |
923 |
|
} |
924 |
8672001 |
return; |
925 |
|
} |
926 |
|
|
927 |
|
// Things from the SAT solver are already normalized, so they go |
928 |
|
// directly to the apropriate theory |
929 |
17904712 |
if (fromTheoryId == THEORY_SAT_SOLVER) { |
930 |
|
// We know that this is normalized, so just send it off to the theory |
931 |
6505193 |
if (markPropagation(assertion, originalAssertion, toTheoryId, fromTheoryId)) { |
932 |
|
// Is it preregistered |
933 |
6433517 |
bool preregistered = d_propEngine->isSatLiteral(assertion) && Theory::theoryOf(assertion) == toTheoryId; |
934 |
|
// We assert it |
935 |
6433517 |
theoryOf(toTheoryId)->assertFact(assertion, preregistered); |
936 |
|
// Mark that we have more information |
937 |
6433517 |
d_factsAsserted = true; |
938 |
|
} |
939 |
6505193 |
return; |
940 |
|
} |
941 |
|
|
942 |
|
// Propagations to the SAT solver are just enqueued for pickup by |
943 |
|
// the SAT solver later |
944 |
11399519 |
if (toTheoryId == THEORY_SAT_SOLVER) { |
945 |
8682068 |
if (markPropagation(assertion, originalAssertion, toTheoryId, fromTheoryId)) { |
946 |
|
// Enqueue for propagation to the SAT solver |
947 |
5219815 |
d_propagatedLiterals.push_back(assertion); |
948 |
|
// Check for propositional conflicts |
949 |
|
bool value; |
950 |
5219815 |
if (d_propEngine->hasValue(assertion, value) && !value) { |
951 |
69234 |
Trace("theory::propagate") |
952 |
34617 |
<< "TheoryEngine::assertToTheory(" << assertion << ", " |
953 |
34617 |
<< toTheoryId << ", " << fromTheoryId << "): conflict (sharing)" |
954 |
34617 |
<< endl; |
955 |
69234 |
Trace("dtview::conflict") |
956 |
34617 |
<< ":THEORY-CONFLICT: " << assertion << std::endl; |
957 |
34617 |
d_inConflict = true; |
958 |
|
} |
959 |
|
} |
960 |
8682068 |
return; |
961 |
|
} |
962 |
|
|
963 |
2717451 |
Assert(assertion.getKind() == kind::EQUAL |
964 |
|
|| (assertion.getKind() == kind::NOT |
965 |
|
&& assertion[0].getKind() == kind::EQUAL)); |
966 |
|
|
967 |
|
// Normalize |
968 |
5434902 |
Node normalizedLiteral = Rewriter::rewrite(assertion); |
969 |
|
|
970 |
|
// See if it rewrites false directly -> conflict |
971 |
2717451 |
if (normalizedLiteral.isConst()) { |
972 |
20438 |
if (!normalizedLiteral.getConst<bool>()) { |
973 |
|
// Mark the propagation for explanations |
974 |
482 |
if (markPropagation(normalizedLiteral, originalAssertion, toTheoryId, fromTheoryId)) { |
975 |
|
// special case, trust node has no proof generator |
976 |
964 |
TrustNode trnn = TrustNode::mkTrustConflict(normalizedLiteral); |
977 |
|
// Get the explanation (conflict will figure out where it came from) |
978 |
482 |
conflict(trnn, toTheoryId); |
979 |
|
} else { |
980 |
|
Unreachable(); |
981 |
|
} |
982 |
482 |
return; |
983 |
|
} |
984 |
|
} |
985 |
|
|
986 |
|
// Try and assert (note that we assert the non-normalized one) |
987 |
2716969 |
if (markPropagation(assertion, originalAssertion, toTheoryId, fromTheoryId)) { |
988 |
|
// Check if has been pre-registered with the theory |
989 |
2353751 |
bool preregistered = d_propEngine->isSatLiteral(assertion) && Theory::theoryOf(assertion) == toTheoryId; |
990 |
|
// Assert away |
991 |
2353751 |
theoryOf(toTheoryId)->assertFact(assertion, preregistered); |
992 |
2353751 |
d_factsAsserted = true; |
993 |
|
} |
994 |
|
|
995 |
2716969 |
return; |
996 |
|
} |
997 |
|
|
998 |
10168896 |
void TheoryEngine::assertFact(TNode literal) |
999 |
|
{ |
1000 |
10168896 |
Trace("theory") << "TheoryEngine::assertFact(" << literal << ")" << endl; |
1001 |
|
|
1002 |
|
// spendResource(); |
1003 |
|
|
1004 |
|
// If we're in conflict, nothing to do |
1005 |
10168896 |
if (d_inConflict) { |
1006 |
22268 |
return; |
1007 |
|
} |
1008 |
|
|
1009 |
|
// Get the atom |
1010 |
10146628 |
bool polarity = literal.getKind() != kind::NOT; |
1011 |
20293256 |
TNode atom = polarity ? literal : literal[0]; |
1012 |
|
|
1013 |
10146628 |
if (d_logicInfo.isSharingEnabled()) { |
1014 |
|
// If any shared terms, it's time to do sharing work |
1015 |
6475736 |
d_sharedSolver->preNotifySharedFact(atom); |
1016 |
|
|
1017 |
|
// If it's an equality, assert it to the shared term manager, even though the terms are not |
1018 |
|
// yet shared. As the terms become shared later, the shared terms manager will then add them |
1019 |
|
// to the assert the equality to the interested theories |
1020 |
6475736 |
if (atom.getKind() == kind::EQUAL) { |
1021 |
|
// Assert it to the the owning theory |
1022 |
3576609 |
assertToTheory(literal, literal, /* to */ Theory::theoryOf(atom), /* from */ THEORY_SAT_SOLVER); |
1023 |
|
// Shared terms manager will assert to interested theories directly, as |
1024 |
|
// the terms become shared |
1025 |
3576609 |
assertToTheory(literal, literal, /* to */ THEORY_BUILTIN, /* from */ THEORY_SAT_SOLVER); |
1026 |
|
|
1027 |
|
// Now, let's check for any atom triggers from lemmas |
1028 |
3576609 |
AtomRequests::atom_iterator it = d_atomRequests.getAtomIterator(atom); |
1029 |
3587159 |
while (!it.done()) { |
1030 |
5275 |
const AtomRequests::Request& request = it.get(); |
1031 |
|
Node toAssert = |
1032 |
10550 |
polarity ? (Node)request.d_atom : request.d_atom.notNode(); |
1033 |
5275 |
Debug("theory::atoms") << "TheoryEngine::assertFact(" << literal << "): sending requested " << toAssert << endl; |
1034 |
5275 |
assertToTheory( |
1035 |
5275 |
toAssert, literal, request.d_toTheory, THEORY_SAT_SOLVER); |
1036 |
5275 |
it.next(); |
1037 |
|
} |
1038 |
|
|
1039 |
|
} else { |
1040 |
|
// Not an equality, just assert to the appropriate theory |
1041 |
2899127 |
assertToTheory(literal, literal, /* to */ Theory::theoryOf(atom), /* from */ THEORY_SAT_SOLVER); |
1042 |
|
} |
1043 |
|
} else { |
1044 |
|
// Assert the fact to the appropriate theory directly |
1045 |
3670892 |
assertToTheory(literal, literal, /* to */ Theory::theoryOf(atom), /* from */ THEORY_SAT_SOLVER); |
1046 |
|
} |
1047 |
|
} |
1048 |
|
|
1049 |
12336908 |
bool TheoryEngine::propagate(TNode literal, theory::TheoryId theory) { |
1050 |
12336908 |
Debug("theory::propagate") << "TheoryEngine::propagate(" << literal << ", " << theory << ")" << endl; |
1051 |
|
|
1052 |
24673816 |
Trace("dtview::prop") << std::string(d_env.getContext()->getLevel(), ' ') |
1053 |
12336908 |
<< ":THEORY-PROP: " << literal << endl; |
1054 |
|
|
1055 |
|
// spendResource(); |
1056 |
|
|
1057 |
|
// Get the atom |
1058 |
12336908 |
bool polarity = literal.getKind() != kind::NOT; |
1059 |
24673816 |
TNode atom = polarity ? literal : literal[0]; |
1060 |
|
|
1061 |
12336908 |
if (d_logicInfo.isSharingEnabled() && atom.getKind() == kind::EQUAL) { |
1062 |
8842001 |
if (d_propEngine->isSatLiteral(literal)) { |
1063 |
|
// We propagate SAT literals to SAT |
1064 |
7211597 |
assertToTheory(literal, literal, /* to */ THEORY_SAT_SOLVER, /* from */ theory); |
1065 |
|
} |
1066 |
8842001 |
if (theory != THEORY_BUILTIN) { |
1067 |
|
// Assert to the shared terms database |
1068 |
5115895 |
assertToTheory(literal, literal, /* to */ THEORY_BUILTIN, /* from */ theory); |
1069 |
|
} |
1070 |
|
} else { |
1071 |
|
// Just send off to the SAT solver |
1072 |
3494907 |
Assert(d_propEngine->isSatLiteral(literal)); |
1073 |
3494907 |
assertToTheory(literal, literal, /* to */ THEORY_SAT_SOLVER, /* from */ theory); |
1074 |
|
} |
1075 |
|
|
1076 |
24673816 |
return !d_inConflict; |
1077 |
|
} |
1078 |
|
|
1079 |
37873 |
const LogicInfo& TheoryEngine::getLogicInfo() const { return d_logicInfo; } |
1080 |
|
|
1081 |
1310 |
bool TheoryEngine::getSepHeapTypes(TypeNode& locType, TypeNode& dataType) const |
1082 |
|
{ |
1083 |
1310 |
if (d_sepLocType.isNull()) |
1084 |
|
{ |
1085 |
1289 |
return false; |
1086 |
|
} |
1087 |
21 |
locType = d_sepLocType; |
1088 |
21 |
dataType = d_sepDataType; |
1089 |
21 |
return true; |
1090 |
|
} |
1091 |
|
|
1092 |
121 |
void TheoryEngine::declareSepHeap(TypeNode locT, TypeNode dataT) |
1093 |
|
{ |
1094 |
121 |
Theory* tsep = theoryOf(THEORY_SEP); |
1095 |
121 |
if (tsep == nullptr) |
1096 |
|
{ |
1097 |
|
Assert(false) << "TheoryEngine::declareSepHeap called without the " |
1098 |
|
"separation logic theory enabled"; |
1099 |
|
return; |
1100 |
|
} |
1101 |
|
|
1102 |
|
// Definition of the statement that is to be run by every theory |
1103 |
|
#ifdef CVC5_FOR_EACH_THEORY_STATEMENT |
1104 |
|
#undef CVC5_FOR_EACH_THEORY_STATEMENT |
1105 |
|
#endif |
1106 |
|
#define CVC5_FOR_EACH_THEORY_STATEMENT(THEORY) \ |
1107 |
|
theoryOf(THEORY)->declareSepHeap(locT, dataT); |
1108 |
|
|
1109 |
|
// notify each theory using the statement above |
1110 |
121 |
CVC5_FOR_EACH_THEORY; |
1111 |
|
|
1112 |
|
// remember the types we have set |
1113 |
119 |
d_sepLocType = locT; |
1114 |
119 |
d_sepDataType = dataT; |
1115 |
|
} |
1116 |
|
|
1117 |
1197756 |
theory::EqualityStatus TheoryEngine::getEqualityStatus(TNode a, TNode b) { |
1118 |
1197756 |
Assert(a.getType().isComparableTo(b.getType())); |
1119 |
1197756 |
return d_sharedSolver->getEqualityStatus(a, b); |
1120 |
|
} |
1121 |
|
|
1122 |
|
const std::unordered_set<TNode>& TheoryEngine::getRelevantAssertions( |
1123 |
|
bool& success) |
1124 |
|
{ |
1125 |
|
// if we are not in SAT mode, or there is no relevance manager, we fail |
1126 |
|
if (!d_inSatMode || d_relManager == nullptr) |
1127 |
|
{ |
1128 |
|
success = false; |
1129 |
|
return d_emptyRelevantSet; |
1130 |
|
} |
1131 |
|
return d_relManager->getRelevantAssertions(success); |
1132 |
|
} |
1133 |
|
|
1134 |
4602 |
Node TheoryEngine::getModelValue(TNode var) { |
1135 |
4602 |
if (var.isConst()) |
1136 |
|
{ |
1137 |
|
// the model value of a constant must be itself |
1138 |
|
return var; |
1139 |
|
} |
1140 |
4602 |
Assert(d_sharedSolver->isShared(var)); |
1141 |
4602 |
return theoryOf(Theory::theoryOf(var.getType()))->getModelValue(var); |
1142 |
|
} |
1143 |
|
|
1144 |
122918 |
TrustNode TheoryEngine::getExplanation(TNode node) |
1145 |
|
{ |
1146 |
245836 |
Debug("theory::explain") << "TheoryEngine::getExplanation(" << node |
1147 |
122918 |
<< "): current propagation index = " |
1148 |
122918 |
<< d_propagationMapTimestamp << endl; |
1149 |
122918 |
bool polarity = node.getKind() != kind::NOT; |
1150 |
245836 |
TNode atom = polarity ? node : node[0]; |
1151 |
|
|
1152 |
|
// If we're not in shared mode, explanations are simple |
1153 |
122918 |
if (!d_logicInfo.isSharingEnabled()) |
1154 |
|
{ |
1155 |
107912 |
Debug("theory::explain") |
1156 |
53956 |
<< "TheoryEngine::getExplanation: sharing is NOT enabled. " |
1157 |
53956 |
<< " Responsible theory is: " << theoryOf(atom)->getId() << std::endl; |
1158 |
|
|
1159 |
107912 |
TrustNode texplanation = theoryOf(atom)->explain(node); |
1160 |
107912 |
Node explanation = texplanation.getNode(); |
1161 |
107912 |
Debug("theory::explain") << "TheoryEngine::getExplanation(" << node |
1162 |
53956 |
<< ") => " << explanation << endl; |
1163 |
53956 |
if (isProofEnabled()) |
1164 |
|
{ |
1165 |
14829 |
texplanation.debugCheckClosed( |
1166 |
|
"te-proof-exp", "texplanation no share", false); |
1167 |
|
// check if no generator, if so, add THEORY_LEMMA |
1168 |
14829 |
if (texplanation.getGenerator() == nullptr) |
1169 |
|
{ |
1170 |
3672 |
Node proven = texplanation.getProven(); |
1171 |
1836 |
TheoryId tid = theoryOf(atom)->getId(); |
1172 |
3672 |
Node tidn = builtin::BuiltinProofRuleChecker::mkTheoryIdNode(tid); |
1173 |
1836 |
d_lazyProof->addStep(proven, PfRule::THEORY_LEMMA, {}, {proven, tidn}); |
1174 |
1836 |
texplanation = |
1175 |
3672 |
TrustNode::mkTrustPropExp(node, explanation, d_lazyProof.get()); |
1176 |
|
} |
1177 |
|
} |
1178 |
53956 |
return texplanation; |
1179 |
|
} |
1180 |
|
|
1181 |
137924 |
Debug("theory::explain") << "TheoryEngine::getExplanation: sharing IS enabled" |
1182 |
68962 |
<< std::endl; |
1183 |
|
|
1184 |
|
// Initial thing to explain |
1185 |
137924 |
NodeTheoryPair toExplain(node, THEORY_SAT_SOLVER, d_propagationMapTimestamp); |
1186 |
68962 |
Assert(d_propagationMap.find(toExplain) != d_propagationMap.end()); |
1187 |
|
|
1188 |
137924 |
NodeTheoryPair nodeExplainerPair = d_propagationMap[toExplain]; |
1189 |
137924 |
Debug("theory::explain") |
1190 |
68962 |
<< "TheoryEngine::getExplanation: explainer for node " |
1191 |
68962 |
<< nodeExplainerPair.d_node |
1192 |
68962 |
<< " is theory: " << nodeExplainerPair.d_theory << std::endl; |
1193 |
|
|
1194 |
|
// Create the workplace for explanations |
1195 |
137924 |
std::vector<NodeTheoryPair> vec{d_propagationMap[toExplain]}; |
1196 |
|
// Process the explanation |
1197 |
137924 |
TrustNode texplanation = getExplanation(vec); |
1198 |
137924 |
Debug("theory::explain") << "TheoryEngine::getExplanation(" << node << ") => " |
1199 |
68962 |
<< texplanation.getNode() << endl; |
1200 |
68962 |
return texplanation; |
1201 |
|
} |
1202 |
|
|
1203 |
60902 |
struct AtomsCollect { |
1204 |
|
|
1205 |
|
std::vector<TNode> d_atoms; |
1206 |
|
std::unordered_set<TNode> d_visited; |
1207 |
|
|
1208 |
|
public: |
1209 |
|
typedef void return_type; |
1210 |
|
|
1211 |
375688 |
bool alreadyVisited(TNode current, TNode parent) { |
1212 |
|
// Check if already visited |
1213 |
375688 |
if (d_visited.find(current) != d_visited.end()) return true; |
1214 |
|
// Don't visit non-boolean |
1215 |
346319 |
if (!current.getType().isBoolean()) return true; |
1216 |
|
// New node |
1217 |
282307 |
return false; |
1218 |
|
} |
1219 |
|
|
1220 |
94463 |
void visit(TNode current, TNode parent) { |
1221 |
94463 |
if (Theory::theoryOf(current) != theory::THEORY_BOOL) { |
1222 |
34643 |
d_atoms.push_back(current); |
1223 |
|
} |
1224 |
94463 |
d_visited.insert(current); |
1225 |
94463 |
} |
1226 |
|
|
1227 |
30451 |
void start(TNode node) {} |
1228 |
30451 |
void done(TNode node) {} |
1229 |
|
|
1230 |
30451 |
std::vector<TNode> getAtoms() const { |
1231 |
30451 |
return d_atoms; |
1232 |
|
} |
1233 |
|
}; |
1234 |
|
|
1235 |
30451 |
void TheoryEngine::ensureLemmaAtoms(const std::vector<TNode>& atoms, theory::TheoryId atomsTo) { |
1236 |
65094 |
for (unsigned i = 0; i < atoms.size(); ++ i) { |
1237 |
|
|
1238 |
|
// Non-equality atoms are either owned by theory or they don't make sense |
1239 |
34643 |
if (atoms[i].getKind() != kind::EQUAL) { |
1240 |
35330 |
continue; |
1241 |
|
} |
1242 |
|
|
1243 |
|
// The equality |
1244 |
33956 |
Node eq = atoms[i]; |
1245 |
|
// Simple normalization to not repeat stuff |
1246 |
29369 |
if (eq[0] > eq[1]) { |
1247 |
|
eq = eq[1].eqNode(eq[0]); |
1248 |
|
} |
1249 |
|
|
1250 |
|
// Rewrite the equality |
1251 |
33956 |
Node eqNormalized = Rewriter::rewrite(atoms[i]); |
1252 |
|
|
1253 |
29369 |
Debug("theory::atoms") << "TheoryEngine::ensureLemmaAtoms(): " << eq << " with nf " << eqNormalized << endl; |
1254 |
|
|
1255 |
|
// If the equality is a boolean constant, we send immediately |
1256 |
29369 |
if (eqNormalized.isConst()) { |
1257 |
|
if (eqNormalized.getConst<bool>()) { |
1258 |
|
assertToTheory(eq, eqNormalized, /** to */ atomsTo, /** Sat solver */ theory::THEORY_SAT_SOLVER); |
1259 |
|
} else { |
1260 |
|
assertToTheory(eq.notNode(), eqNormalized.notNode(), /** to */ atomsTo, /** Sat solver */ theory::THEORY_SAT_SOLVER); |
1261 |
|
} |
1262 |
|
continue; |
1263 |
29369 |
}else if( eqNormalized.getKind() != kind::EQUAL){ |
1264 |
|
Assert(eqNormalized.getKind() == kind::BOOLEAN_TERM_VARIABLE |
1265 |
|
|| (eqNormalized.getKind() == kind::NOT |
1266 |
|
&& eqNormalized[0].getKind() == kind::BOOLEAN_TERM_VARIABLE)); |
1267 |
|
// this happens for Boolean term equalities V = true that are rewritten to V, we should skip |
1268 |
|
// TODO : revisit this |
1269 |
|
continue; |
1270 |
|
} |
1271 |
|
|
1272 |
|
// If the normalization did the just flips, keep the flip |
1273 |
29369 |
if (eqNormalized[0] == eq[1] && eqNormalized[1] == eq[0]) { |
1274 |
1085 |
eq = eqNormalized; |
1275 |
|
} |
1276 |
|
|
1277 |
|
// Check if the equality is already known by the sat solver |
1278 |
29369 |
if (d_propEngine->isSatLiteral(eqNormalized)) { |
1279 |
|
bool value; |
1280 |
25315 |
if (d_propEngine->hasValue(eqNormalized, value)) { |
1281 |
49564 |
if (value) { |
1282 |
24782 |
assertToTheory(eq, eqNormalized, atomsTo, theory::THEORY_SAT_SOLVER); |
1283 |
49564 |
continue; |
1284 |
|
} else { |
1285 |
|
assertToTheory(eq.notNode(), eqNormalized.notNode(), atomsTo, theory::THEORY_SAT_SOLVER); |
1286 |
|
continue; |
1287 |
|
} |
1288 |
|
} |
1289 |
|
} |
1290 |
|
|
1291 |
|
// If the theory is asking about a different form, or the form is ok but if will go to a different theory |
1292 |
|
// then we must figure it out |
1293 |
4587 |
if (eqNormalized != eq || Theory::theoryOf(eq) != atomsTo) { |
1294 |
|
// If you get eqNormalized, send atoms[i] to atomsTo |
1295 |
3694 |
d_atomRequests.add(eqNormalized, eq, atomsTo); |
1296 |
|
} |
1297 |
|
} |
1298 |
30451 |
} |
1299 |
|
|
1300 |
414663 |
void TheoryEngine::lemma(theory::TrustNode tlemma, |
1301 |
|
theory::LemmaProperty p, |
1302 |
|
theory::TheoryId atomsTo, |
1303 |
|
theory::TheoryId from) |
1304 |
|
{ |
1305 |
|
// For resource-limiting (also does a time check). |
1306 |
|
// spendResource(); |
1307 |
414663 |
Assert(tlemma.getKind() == TrustNodeKind::LEMMA |
1308 |
|
|| tlemma.getKind() == TrustNodeKind::CONFLICT); |
1309 |
|
// get the node |
1310 |
829326 |
Node node = tlemma.getNode(); |
1311 |
829326 |
Node lemma = tlemma.getProven(); |
1312 |
|
|
1313 |
414663 |
Assert(!expr::hasFreeVar(lemma)); |
1314 |
|
|
1315 |
|
// when proofs are enabled, we ensure the trust node has a generator by |
1316 |
|
// adding a trust step to the lazy proof maintained by this class |
1317 |
414663 |
if (isProofEnabled()) |
1318 |
|
{ |
1319 |
|
// ensure proof: set THEORY_LEMMA if no generator is provided |
1320 |
68184 |
if (tlemma.getGenerator() == nullptr) |
1321 |
|
{ |
1322 |
|
// internal lemmas should have generators |
1323 |
8266 |
Assert(from != THEORY_LAST); |
1324 |
|
// add theory lemma step to proof |
1325 |
16532 |
Node tidn = builtin::BuiltinProofRuleChecker::mkTheoryIdNode(from); |
1326 |
8266 |
d_lazyProof->addStep(lemma, PfRule::THEORY_LEMMA, {}, {lemma, tidn}); |
1327 |
|
// update the trust node |
1328 |
8266 |
tlemma = TrustNode::mkTrustLemma(lemma, d_lazyProof.get()); |
1329 |
|
} |
1330 |
|
// ensure closed |
1331 |
68184 |
tlemma.debugCheckClosed("te-proof-debug", "TheoryEngine::lemma_initial"); |
1332 |
|
} |
1333 |
|
|
1334 |
|
// Do we need to check atoms |
1335 |
414663 |
if (atomsTo != theory::THEORY_LAST) { |
1336 |
30451 |
Debug("theory::atoms") << "TheoryEngine::lemma(" << node << ", " << atomsTo << ")" << endl; |
1337 |
60902 |
AtomsCollect collectAtoms; |
1338 |
30451 |
NodeVisitor<AtomsCollect>::run(collectAtoms, node); |
1339 |
30451 |
ensureLemmaAtoms(collectAtoms.getAtoms(), atomsTo); |
1340 |
|
} |
1341 |
|
|
1342 |
414663 |
if(Dump.isOn("t-lemmas")) { |
1343 |
|
// we dump the negation of the lemma, to show validity of the lemma |
1344 |
|
Node n = lemma.negate(); |
1345 |
|
const Printer& printer = d_outMgr.getPrinter(); |
1346 |
|
std::ostream& out = d_outMgr.getDumpOut(); |
1347 |
|
printer.toStreamCmdComment(out, "theory lemma: expect valid"); |
1348 |
|
printer.toStreamCmdCheckSat(out, n); |
1349 |
|
} |
1350 |
|
|
1351 |
|
// assert the lemma |
1352 |
414665 |
d_propEngine->assertLemma(tlemma, p); |
1353 |
|
|
1354 |
|
// If specified, we must add this lemma to the set of those that need to be |
1355 |
|
// justified, where note we pass all auxiliary lemmas in skAsserts as well, |
1356 |
|
// since these by extension must be justified as well. |
1357 |
414661 |
if (d_relManager != nullptr && isLemmaPropertyNeedsJustify(p)) |
1358 |
|
{ |
1359 |
|
std::vector<Node> skAsserts; |
1360 |
|
std::vector<Node> sks; |
1361 |
|
Node retLemma = |
1362 |
|
d_propEngine->getPreprocessedTerm(tlemma.getProven(), skAsserts, sks); |
1363 |
|
d_relManager->notifyPreprocessedAssertion(retLemma); |
1364 |
|
d_relManager->notifyPreprocessedAssertions(skAsserts); |
1365 |
|
} |
1366 |
|
|
1367 |
|
// Mark that we added some lemmas |
1368 |
414661 |
d_lemmasAdded = true; |
1369 |
414661 |
} |
1370 |
|
|
1371 |
115152 |
void TheoryEngine::conflict(theory::TrustNode tconflict, TheoryId theoryId) |
1372 |
|
{ |
1373 |
115152 |
Assert(tconflict.getKind() == TrustNodeKind::CONFLICT); |
1374 |
230304 |
TNode conflict = tconflict.getNode(); |
1375 |
230304 |
Trace("theory::conflict") << "TheoryEngine::conflict(" << conflict << ", " |
1376 |
115152 |
<< theoryId << ")" << endl; |
1377 |
115152 |
Trace("te-proof-debug") << "Check closed conflict" << std::endl; |
1378 |
|
// doesn't require proof generator, yet, since THEORY_LEMMA is added below |
1379 |
115152 |
tconflict.debugCheckClosed( |
1380 |
|
"te-proof-debug", "TheoryEngine::conflict_initial", false); |
1381 |
|
|
1382 |
115152 |
Trace("dtview::conflict") << ":THEORY-CONFLICT: " << conflict << std::endl; |
1383 |
|
|
1384 |
|
// Mark that we are in conflict |
1385 |
115152 |
d_inConflict = true; |
1386 |
|
|
1387 |
115152 |
if(Dump.isOn("t-conflicts")) { |
1388 |
|
const Printer& printer = d_outMgr.getPrinter(); |
1389 |
|
std::ostream& out = d_outMgr.getDumpOut(); |
1390 |
|
printer.toStreamCmdComment(out, "theory conflict: expect unsat"); |
1391 |
|
printer.toStreamCmdCheckSat(out, conflict); |
1392 |
|
} |
1393 |
|
|
1394 |
|
// In the multiple-theories case, we need to reconstruct the conflict |
1395 |
115152 |
if (d_logicInfo.isSharingEnabled()) { |
1396 |
|
// Create the workplace for explanations |
1397 |
178532 |
std::vector<NodeTheoryPair> vec; |
1398 |
89266 |
vec.push_back( |
1399 |
178532 |
NodeTheoryPair(conflict, theoryId, d_propagationMapTimestamp)); |
1400 |
|
|
1401 |
|
// Process the explanation |
1402 |
178532 |
TrustNode tncExp = getExplanation(vec); |
1403 |
178532 |
Trace("te-proof-debug") |
1404 |
89266 |
<< "Check closed conflict explained with sharing" << std::endl; |
1405 |
89266 |
tncExp.debugCheckClosed("te-proof-debug", |
1406 |
|
"TheoryEngine::conflict_explained_sharing"); |
1407 |
178532 |
Node fullConflict = tncExp.getNode(); |
1408 |
|
|
1409 |
89266 |
if (isProofEnabled()) |
1410 |
|
{ |
1411 |
14317 |
Trace("te-proof-debug") << "Process conflict: " << conflict << std::endl; |
1412 |
28634 |
Trace("te-proof-debug") << "Conflict " << tconflict << " from " |
1413 |
14317 |
<< tconflict.identifyGenerator() << std::endl; |
1414 |
28634 |
Trace("te-proof-debug") << "Explanation " << tncExp << " from " |
1415 |
14317 |
<< tncExp.identifyGenerator() << std::endl; |
1416 |
14317 |
Assert(d_lazyProof != nullptr); |
1417 |
14317 |
if (tconflict.getGenerator() != nullptr) |
1418 |
|
{ |
1419 |
12898 |
d_lazyProof->addLazyStep(tconflict.getProven(), |
1420 |
|
tconflict.getGenerator()); |
1421 |
|
} |
1422 |
|
else |
1423 |
|
{ |
1424 |
|
// add theory lemma step |
1425 |
2838 |
Node tidn = builtin::BuiltinProofRuleChecker::mkTheoryIdNode(theoryId); |
1426 |
2838 |
Node conf = tconflict.getProven(); |
1427 |
1419 |
d_lazyProof->addStep(conf, PfRule::THEORY_LEMMA, {}, {conf, tidn}); |
1428 |
|
} |
1429 |
|
// store the explicit step, which should come from a different |
1430 |
|
// generator, e.g. d_tepg. |
1431 |
28634 |
Node proven = tncExp.getProven(); |
1432 |
14317 |
Assert(tncExp.getGenerator() != d_lazyProof.get()); |
1433 |
28634 |
Trace("te-proof-debug") << "add lazy step " << tncExp.identifyGenerator() |
1434 |
14317 |
<< " for " << proven << std::endl; |
1435 |
14317 |
d_lazyProof->addLazyStep(proven, tncExp.getGenerator()); |
1436 |
14317 |
pfgEnsureClosed(proven, |
1437 |
14317 |
d_lazyProof.get(), |
1438 |
|
"te-proof-debug", |
1439 |
|
"TheoryEngine::conflict_during"); |
1440 |
28634 |
Node fullConflictNeg = fullConflict.notNode(); |
1441 |
28634 |
std::vector<Node> children; |
1442 |
14317 |
children.push_back(proven); |
1443 |
28634 |
std::vector<Node> args; |
1444 |
14317 |
args.push_back(fullConflictNeg); |
1445 |
14317 |
if (conflict == d_false) |
1446 |
|
{ |
1447 |
111 |
AlwaysAssert(proven == fullConflictNeg); |
1448 |
|
} |
1449 |
|
else |
1450 |
|
{ |
1451 |
14206 |
if (fullConflict != conflict) |
1452 |
|
{ |
1453 |
|
// ------------------------- explained ---------- from theory |
1454 |
|
// fullConflict => conflict ~conflict |
1455 |
|
// ------------------------------------------ MACRO_SR_PRED_TRANSFORM |
1456 |
|
// ~fullConflict |
1457 |
13641 |
children.push_back(conflict.notNode()); |
1458 |
13641 |
args.push_back(mkMethodId(MethodId::SB_LITERAL)); |
1459 |
13641 |
d_lazyProof->addStep( |
1460 |
|
fullConflictNeg, PfRule::MACRO_SR_PRED_TRANSFORM, children, args); |
1461 |
|
} |
1462 |
|
} |
1463 |
|
} |
1464 |
|
// pass the processed trust node |
1465 |
|
TrustNode tconf = |
1466 |
178532 |
TrustNode::mkTrustConflict(fullConflict, d_lazyProof.get()); |
1467 |
89266 |
Debug("theory::conflict") << "TheoryEngine::conflict(" << conflict << ", " << theoryId << "): full = " << fullConflict << endl; |
1468 |
89266 |
Assert(properConflict(fullConflict)); |
1469 |
178532 |
Trace("te-proof-debug") |
1470 |
89266 |
<< "Check closed conflict with sharing" << std::endl; |
1471 |
89266 |
tconf.debugCheckClosed("te-proof-debug", "TheoryEngine::conflict:sharing"); |
1472 |
89266 |
lemma(tconf, LemmaProperty::REMOVABLE); |
1473 |
|
} else { |
1474 |
|
// When only one theory, the conflict should need no processing |
1475 |
25886 |
Assert(properConflict(conflict)); |
1476 |
|
// pass the trust node that was sent from the theory |
1477 |
25886 |
lemma(tconflict, LemmaProperty::REMOVABLE, THEORY_LAST, theoryId); |
1478 |
|
} |
1479 |
115152 |
} |
1480 |
|
|
1481 |
2095 |
void TheoryEngine::setIncomplete(theory::TheoryId theory, |
1482 |
|
theory::IncompleteId id) |
1483 |
|
{ |
1484 |
2095 |
d_incomplete = true; |
1485 |
2095 |
d_incompleteTheory = theory; |
1486 |
2095 |
d_incompleteId = id; |
1487 |
2095 |
} |
1488 |
|
|
1489 |
158228 |
theory::TrustNode TheoryEngine::getExplanation( |
1490 |
|
std::vector<NodeTheoryPair>& explanationVector) |
1491 |
|
{ |
1492 |
158228 |
Assert(explanationVector.size() == 1); |
1493 |
316456 |
Node conclusion = explanationVector[0].d_node; |
1494 |
316456 |
std::shared_ptr<LazyCDProof> lcp; |
1495 |
158228 |
if (isProofEnabled()) |
1496 |
|
{ |
1497 |
41874 |
Trace("te-proof-exp") << "=== TheoryEngine::getExplanation " << conclusion |
1498 |
20937 |
<< std::endl; |
1499 |
41874 |
lcp.reset(new LazyCDProof( |
1500 |
20937 |
d_pnm, nullptr, nullptr, "TheoryEngine::LazyCDProof::getExplanation")); |
1501 |
|
} |
1502 |
158228 |
unsigned i = 0; // Index of the current literal we are processing |
1503 |
|
|
1504 |
316456 |
std::unique_ptr<std::set<Node>> inputAssertions = nullptr; |
1505 |
|
// the overall explanation |
1506 |
316456 |
std::set<TNode> exp; |
1507 |
|
// vector of trust nodes to explain at the end |
1508 |
316456 |
std::vector<std::pair<TheoryId, TrustNode>> texplains; |
1509 |
|
// cache of nodes we have already explained by some theory |
1510 |
316456 |
std::unordered_map<Node, size_t> cache; |
1511 |
|
|
1512 |
7584880 |
while (i < explanationVector.size()) { |
1513 |
|
// Get the current literal to explain |
1514 |
4052638 |
NodeTheoryPair toExplain = explanationVector[i]; |
1515 |
|
|
1516 |
7426652 |
Debug("theory::explain") |
1517 |
3713326 |
<< "[i=" << i << "] TheoryEngine::explain(): processing [" |
1518 |
3713326 |
<< toExplain.d_timestamp << "] " << toExplain.d_node << " sent from " |
1519 |
3713326 |
<< toExplain.d_theory << endl; |
1520 |
|
|
1521 |
7605028 |
if (cache.find(toExplain.d_node) != cache.end() |
1522 |
3713326 |
&& cache[toExplain.d_node] < toExplain.d_timestamp) |
1523 |
|
{ |
1524 |
178376 |
++i; |
1525 |
178376 |
continue; |
1526 |
|
} |
1527 |
3534950 |
cache[toExplain.d_node] = toExplain.d_timestamp; |
1528 |
|
|
1529 |
|
// If a true constant or a negation of a false constant we can ignore it |
1530 |
7085489 |
if ((toExplain.d_node.isConst() && toExplain.d_node.getConst<bool>()) |
1531 |
10604850 |
|| (toExplain.d_node.getKind() == kind::NOT |
1532 |
3877596 |
&& toExplain.d_node[0].isConst() |
1533 |
3534950 |
&& !toExplain.d_node[0].getConst<bool>())) |
1534 |
|
{ |
1535 |
15107 |
++ i; |
1536 |
|
// if we are building a proof |
1537 |
15107 |
if (lcp != nullptr) |
1538 |
|
{ |
1539 |
1600 |
Trace("te-proof-exp") |
1540 |
800 |
<< "- explain " << toExplain.d_node << " trivially..." << std::endl; |
1541 |
|
// ------------------MACRO_SR_PRED_INTRO |
1542 |
|
// toExplain.d_node |
1543 |
1600 |
std::vector<Node> children; |
1544 |
1600 |
std::vector<Node> args; |
1545 |
800 |
args.push_back(toExplain.d_node); |
1546 |
800 |
lcp->addStep( |
1547 |
|
toExplain.d_node, PfRule::MACRO_SR_PRED_INTRO, children, args); |
1548 |
|
} |
1549 |
15107 |
continue; |
1550 |
|
} |
1551 |
|
|
1552 |
|
// If from the SAT solver, keep it |
1553 |
4752162 |
if (toExplain.d_theory == THEORY_SAT_SOLVER) |
1554 |
|
{ |
1555 |
1232319 |
Debug("theory::explain") << "\tLiteral came from THEORY_SAT_SOLVER. Kepping it." << endl; |
1556 |
1232319 |
exp.insert(explanationVector[i++].d_node); |
1557 |
|
// it will be a free assumption in the proof |
1558 |
1232319 |
Trace("te-proof-exp") << "- keep " << toExplain.d_node << std::endl; |
1559 |
1232319 |
continue; |
1560 |
|
} |
1561 |
|
|
1562 |
|
// If an and, expand it |
1563 |
2287524 |
if (toExplain.d_node.getKind() == kind::AND) |
1564 |
|
{ |
1565 |
700206 |
Debug("theory::explain") |
1566 |
350103 |
<< "TheoryEngine::explain(): expanding " << toExplain.d_node |
1567 |
350103 |
<< " got from " << toExplain.d_theory << endl; |
1568 |
350103 |
size_t nchild = toExplain.d_node.getNumChildren(); |
1569 |
1967780 |
for (size_t k = 0; k < nchild; ++k) |
1570 |
|
{ |
1571 |
|
NodeTheoryPair newExplain( |
1572 |
3235354 |
toExplain.d_node[k], toExplain.d_theory, toExplain.d_timestamp); |
1573 |
1617677 |
explanationVector.push_back(newExplain); |
1574 |
|
} |
1575 |
350103 |
if (lcp != nullptr) |
1576 |
|
{ |
1577 |
114922 |
Trace("te-proof-exp") |
1578 |
57461 |
<< "- AND expand " << toExplain.d_node << std::endl; |
1579 |
|
// delay explanation, use a dummy trust node |
1580 |
|
TrustNode tnAndExp = TrustNode::mkTrustPropExp( |
1581 |
114922 |
toExplain.d_node, toExplain.d_node, nullptr); |
1582 |
57461 |
texplains.push_back( |
1583 |
114922 |
std::pair<TheoryId, TrustNode>(THEORY_LAST, tnAndExp)); |
1584 |
|
} |
1585 |
350103 |
++ i; |
1586 |
350103 |
continue; |
1587 |
|
} |
1588 |
|
|
1589 |
|
// See if it was sent to the theory by another theory |
1590 |
1937421 |
PropagationMap::const_iterator find = d_propagationMap.find(toExplain); |
1591 |
1937421 |
if (find != d_propagationMap.end()) { |
1592 |
3647668 |
Debug("theory::explain") |
1593 |
1823834 |
<< "\tTerm was propagated by another theory (theory = " |
1594 |
1823834 |
<< getTheoryString((*find).second.d_theory) << ")" << std::endl; |
1595 |
|
// There is some propagation, check if its a timely one |
1596 |
1823834 |
if ((*find).second.d_timestamp < toExplain.d_timestamp) |
1597 |
|
{ |
1598 |
3196218 |
Debug("theory::explain") |
1599 |
1598109 |
<< "\tRelevant timetsamp, pushing " << (*find).second.d_node |
1600 |
1598109 |
<< "to index = " << explanationVector.size() << std::endl; |
1601 |
1598109 |
explanationVector.push_back((*find).second); |
1602 |
1598109 |
++i; |
1603 |
|
|
1604 |
1598109 |
if (lcp != nullptr) |
1605 |
|
{ |
1606 |
248167 |
if (!CDProof::isSame(toExplain.d_node, (*find).second.d_node)) |
1607 |
|
{ |
1608 |
6736 |
Trace("te-proof-exp") |
1609 |
3368 |
<< "- t-explained cached: " << toExplain.d_node << " by " |
1610 |
3368 |
<< (*find).second.d_node << std::endl; |
1611 |
|
// delay explanation, use a dummy trust node that says that |
1612 |
|
// (*find).second.d_node explains toExplain.d_node. |
1613 |
|
TrustNode tnRewExp = TrustNode::mkTrustPropExp( |
1614 |
6736 |
toExplain.d_node, (*find).second.d_node, nullptr); |
1615 |
3368 |
texplains.push_back( |
1616 |
6736 |
std::pair<TheoryId, TrustNode>(THEORY_LAST, tnRewExp)); |
1617 |
|
} |
1618 |
|
} |
1619 |
1598109 |
continue; |
1620 |
|
} |
1621 |
|
} |
1622 |
|
// It was produced by the theory, so ask for an explanation |
1623 |
|
TrustNode texplanation = |
1624 |
678624 |
d_sharedSolver->explain(toExplain.d_node, toExplain.d_theory); |
1625 |
339312 |
if (lcp != nullptr) |
1626 |
|
{ |
1627 |
58933 |
texplanation.debugCheckClosed("te-proof-exp", "texplanation", false); |
1628 |
117866 |
Trace("te-proof-exp") |
1629 |
58933 |
<< "- t-explained[" << toExplain.d_theory << "]: " << toExplain.d_node |
1630 |
58933 |
<< " by " << texplanation.getNode() << std::endl; |
1631 |
|
// should prove the propagation we asked for |
1632 |
58933 |
Assert(texplanation.getKind() == TrustNodeKind::PROP_EXP |
1633 |
|
&& texplanation.getProven()[1] == toExplain.d_node); |
1634 |
|
// if not a trivial explanation |
1635 |
58933 |
if (!CDProof::isSame(texplanation.getNode(), toExplain.d_node)) |
1636 |
|
{ |
1637 |
|
// We add it to the list of theory explanations, to be processed at |
1638 |
|
// the end of this method. We wait to explain here because it may |
1639 |
|
// be that a later explanation may preempt the need for proving this |
1640 |
|
// step. For instance, if the conclusion lit is later added as an |
1641 |
|
// assumption in the final explanation. This avoids cyclic proofs. |
1642 |
52734 |
texplains.push_back( |
1643 |
105468 |
std::pair<TheoryId, TrustNode>(toExplain.d_theory, texplanation)); |
1644 |
|
} |
1645 |
|
} |
1646 |
678624 |
Node explanation = texplanation.getNode(); |
1647 |
|
|
1648 |
678624 |
Debug("theory::explain") |
1649 |
339312 |
<< "TheoryEngine::explain(): got explanation " << explanation |
1650 |
339312 |
<< " got from " << toExplain.d_theory << endl; |
1651 |
339312 |
Assert(explanation != toExplain.d_node) |
1652 |
|
<< "wasn't sent to you, so why are you explaining it trivially"; |
1653 |
|
// Mark the explanation |
1654 |
|
NodeTheoryPair newExplain( |
1655 |
678624 |
explanation, toExplain.d_theory, toExplain.d_timestamp); |
1656 |
339312 |
explanationVector.push_back(newExplain); |
1657 |
|
|
1658 |
339312 |
++ i; |
1659 |
|
} |
1660 |
|
|
1661 |
|
// make the explanation node |
1662 |
316456 |
Node expNode; |
1663 |
158228 |
if (exp.size() == 0) |
1664 |
|
{ |
1665 |
|
// Normalize to true |
1666 |
38 |
expNode = NodeManager::currentNM()->mkConst<bool>(true); |
1667 |
|
} |
1668 |
158190 |
else if (exp.size() == 1) |
1669 |
|
{ |
1670 |
|
// All the same, or just one |
1671 |
5087 |
expNode = *exp.begin(); |
1672 |
|
} |
1673 |
|
else |
1674 |
|
{ |
1675 |
306206 |
NodeBuilder conjunction(kind::AND); |
1676 |
153103 |
std::set<TNode>::const_iterator it = exp.begin(); |
1677 |
153103 |
std::set<TNode>::const_iterator it_end = exp.end(); |
1678 |
2529579 |
while (it != it_end) |
1679 |
|
{ |
1680 |
1188238 |
conjunction << *it; |
1681 |
1188238 |
++it; |
1682 |
|
} |
1683 |
153103 |
expNode = conjunction; |
1684 |
|
} |
1685 |
|
// if we are building a proof, go back through the explanations and |
1686 |
|
// build the proof |
1687 |
158228 |
if (lcp != nullptr) |
1688 |
|
{ |
1689 |
20937 |
if (Trace.isOn("te-proof-exp")) |
1690 |
|
{ |
1691 |
|
Trace("te-proof-exp") << "Explanation is:" << std::endl; |
1692 |
|
for (TNode e : exp) |
1693 |
|
{ |
1694 |
|
Trace("te-proof-exp") << " " << e << std::endl; |
1695 |
|
} |
1696 |
|
Trace("te-proof-exp") << "=== Replay explanations..." << std::endl; |
1697 |
|
} |
1698 |
|
// Now, go back and add the necessary steps of theory explanations, i.e. |
1699 |
|
// add those that prove things that aren't in the final explanation. We |
1700 |
|
// iterate in reverse order so that most recent steps take priority. This |
1701 |
|
// avoids cyclic proofs in the lazy proof we are building (lcp). |
1702 |
113563 |
for (std::vector<std::pair<TheoryId, TrustNode>>::reverse_iterator |
1703 |
20937 |
it = texplains.rbegin(), |
1704 |
20937 |
itEnd = texplains.rend(); |
1705 |
134500 |
it != itEnd; |
1706 |
|
++it) |
1707 |
|
{ |
1708 |
164485 |
TrustNode trn = it->second; |
1709 |
113563 |
Assert(trn.getKind() == TrustNodeKind::PROP_EXP); |
1710 |
164485 |
Node proven = trn.getProven(); |
1711 |
113563 |
Assert(proven.getKind() == kind::IMPLIES); |
1712 |
164485 |
Node tConc = proven[1]; |
1713 |
113563 |
Trace("te-proof-exp") << "- Process " << trn << std::endl; |
1714 |
118243 |
if (exp.find(tConc) != exp.end()) |
1715 |
|
{ |
1716 |
|
// already added to proof |
1717 |
4680 |
Trace("te-proof-exp") << "...already added" << std::endl; |
1718 |
4680 |
continue; |
1719 |
|
} |
1720 |
159805 |
Node symTConc = CDProof::getSymmFact(tConc); |
1721 |
108883 |
if (!symTConc.isNull()) |
1722 |
|
{ |
1723 |
51311 |
if (exp.find(symTConc) != exp.end()) |
1724 |
|
{ |
1725 |
|
// symmetric direction |
1726 |
24 |
Trace("te-proof-exp") << "...already added (SYMM)" << std::endl; |
1727 |
24 |
continue; |
1728 |
|
} |
1729 |
|
} |
1730 |
|
// remember that we've explained this formula, to avoid cycles in lcp |
1731 |
108859 |
exp.insert(tConc); |
1732 |
108859 |
TheoryId ttid = it->first; |
1733 |
159781 |
Node tExp = proven[0]; |
1734 |
108859 |
if (ttid == THEORY_LAST) |
1735 |
|
{ |
1736 |
57937 |
if (tConc == tExp) |
1737 |
|
{ |
1738 |
|
// dummy trust node, do AND expansion |
1739 |
55803 |
Assert(tConc.getKind() == kind::AND); |
1740 |
|
// tConc[0] ... tConc[n] |
1741 |
|
// ---------------------- AND_INTRO |
1742 |
|
// tConc |
1743 |
111606 |
std::vector<Node> pfChildren; |
1744 |
55803 |
pfChildren.insert(pfChildren.end(), tConc.begin(), tConc.end()); |
1745 |
55803 |
lcp->addStep(tConc, PfRule::AND_INTRO, pfChildren, {}); |
1746 |
55803 |
Trace("te-proof-exp") << "...via AND_INTRO" << std::endl; |
1747 |
55803 |
continue; |
1748 |
|
} |
1749 |
|
// otherwise should hold by rewriting |
1750 |
2134 |
Assert(Rewriter::rewrite(tConc) == Rewriter::rewrite(tExp)); |
1751 |
|
// tExp |
1752 |
|
// ---- MACRO_SR_PRED_TRANSFORM |
1753 |
|
// tConc |
1754 |
2134 |
lcp->addStep(tConc, PfRule::MACRO_SR_PRED_TRANSFORM, {tExp}, {tConc}); |
1755 |
2134 |
Trace("te-proof-exp") << "...via MACRO_SR_PRED_TRANSFORM" << std::endl; |
1756 |
2134 |
continue; |
1757 |
|
} |
1758 |
50922 |
if (tExp == tConc) |
1759 |
|
{ |
1760 |
|
// trivial |
1761 |
|
Trace("te-proof-exp") << "...trivial" << std::endl; |
1762 |
|
continue; |
1763 |
|
} |
1764 |
|
// ------------- Via theory |
1765 |
|
// tExp tExp => tConc |
1766 |
|
// ---------------------------------MODUS_PONENS |
1767 |
|
// tConc |
1768 |
50922 |
if (trn.getGenerator() != nullptr) |
1769 |
|
{ |
1770 |
48018 |
Trace("te-proof-exp") << "...via theory generator" << std::endl; |
1771 |
48018 |
lcp->addLazyStep(proven, trn.getGenerator()); |
1772 |
|
} |
1773 |
|
else |
1774 |
|
{ |
1775 |
2904 |
Trace("te-proof-exp") << "...via trust THEORY_LEMMA" << std::endl; |
1776 |
|
// otherwise, trusted theory lemma |
1777 |
5808 |
Node tidn = builtin::BuiltinProofRuleChecker::mkTheoryIdNode(it->first); |
1778 |
2904 |
lcp->addStep(proven, PfRule::THEORY_LEMMA, {}, {proven, tidn}); |
1779 |
|
} |
1780 |
101844 |
std::vector<Node> pfChildren; |
1781 |
50922 |
pfChildren.push_back(trn.getNode()); |
1782 |
50922 |
pfChildren.push_back(proven); |
1783 |
50922 |
lcp->addStep(tConc, PfRule::MODUS_PONENS, pfChildren, {}); |
1784 |
|
} |
1785 |
|
// store in the proof generator |
1786 |
41874 |
TrustNode trn = d_tepg->mkTrustExplain(conclusion, expNode, lcp); |
1787 |
|
// return the trust node |
1788 |
20937 |
return trn; |
1789 |
|
} |
1790 |
|
|
1791 |
137291 |
return theory::TrustNode::mkTrustPropExp(conclusion, expNode, nullptr); |
1792 |
|
} |
1793 |
|
|
1794 |
716113 |
bool TheoryEngine::isProofEnabled() const { return d_pnm != nullptr; } |
1795 |
|
|
1796 |
232 |
void TheoryEngine::setUserAttribute(const std::string& attr, |
1797 |
|
Node n, |
1798 |
|
const std::vector<Node>& node_values, |
1799 |
|
const std::string& str_value) |
1800 |
|
{ |
1801 |
232 |
Trace("te-attr") << "set user attribute " << attr << " " << n << endl; |
1802 |
232 |
if( d_attr_handle.find( attr )!=d_attr_handle.end() ){ |
1803 |
464 |
for( size_t i=0; i<d_attr_handle[attr].size(); i++ ){ |
1804 |
232 |
d_attr_handle[attr][i]->setUserAttribute(attr, n, node_values, str_value); |
1805 |
|
} |
1806 |
|
} else { |
1807 |
|
//unhandled exception? |
1808 |
|
} |
1809 |
232 |
} |
1810 |
|
|
1811 |
47295 |
void TheoryEngine::handleUserAttribute(const char* attr, Theory* t) { |
1812 |
47295 |
Trace("te-attr") << "Handle user attribute " << attr << " " << t << endl; |
1813 |
94590 |
std::string str( attr ); |
1814 |
47295 |
d_attr_handle[ str ].push_back( t ); |
1815 |
47295 |
} |
1816 |
|
|
1817 |
2064 |
void TheoryEngine::checkTheoryAssertionsWithModel(bool hardFailure) { |
1818 |
28896 |
for(TheoryId theoryId = THEORY_FIRST; theoryId < THEORY_LAST; ++theoryId) { |
1819 |
26832 |
Theory* theory = d_theoryTable[theoryId]; |
1820 |
26832 |
if(theory && d_logicInfo.isTheoryEnabled(theoryId)) { |
1821 |
104179 |
for(context::CDList<Assertion>::const_iterator it = theory->facts_begin(), |
1822 |
12433 |
it_end = theory->facts_end(); |
1823 |
104179 |
it != it_end; |
1824 |
|
++it) { |
1825 |
183492 |
Node assertion = (*it).d_assertion; |
1826 |
91746 |
if (!isRelevant(assertion)) |
1827 |
|
{ |
1828 |
|
// not relevant, skip |
1829 |
|
continue; |
1830 |
|
} |
1831 |
183492 |
Node val = d_tc->getModel()->getValue(assertion); |
1832 |
91746 |
if (val != d_true) |
1833 |
|
{ |
1834 |
12 |
std::stringstream ss; |
1835 |
12 |
ss << " " << theoryId |
1836 |
12 |
<< " has an asserted fact that the model doesn't satisfy." << endl |
1837 |
12 |
<< "The fact: " << assertion << endl |
1838 |
6 |
<< "Model value: " << val << endl; |
1839 |
6 |
if (hardFailure) |
1840 |
|
{ |
1841 |
6 |
if (val == d_false) |
1842 |
|
{ |
1843 |
|
// Always an error if it is false |
1844 |
|
InternalError() << ss.str(); |
1845 |
|
} |
1846 |
|
else |
1847 |
|
{ |
1848 |
|
// Otherwise just a warning. Notice this case may happen for |
1849 |
|
// assertions with unevaluable operators, e.g. transcendental |
1850 |
|
// functions. It also may happen for separation logic, where |
1851 |
|
// check-model support is limited. |
1852 |
6 |
Warning() << ss.str(); |
1853 |
|
} |
1854 |
|
} |
1855 |
|
} |
1856 |
|
} |
1857 |
|
} |
1858 |
|
} |
1859 |
2064 |
} |
1860 |
|
|
1861 |
4830 |
std::pair<bool, Node> TheoryEngine::entailmentCheck(options::TheoryOfMode mode, |
1862 |
|
TNode lit) |
1863 |
|
{ |
1864 |
9660 |
TNode atom = (lit.getKind() == kind::NOT) ? lit[0] : lit; |
1865 |
4830 |
if( atom.getKind()==kind::AND || atom.getKind()==kind::OR || atom.getKind()==kind::IMPLIES ){ |
1866 |
|
//Boolean connective, recurse |
1867 |
|
std::vector< Node > children; |
1868 |
|
bool pol = (lit.getKind()!=kind::NOT); |
1869 |
|
bool is_conjunction = pol==(lit.getKind()==kind::AND); |
1870 |
|
for( unsigned i=0; i<atom.getNumChildren(); i++ ){ |
1871 |
|
Node ch = atom[i]; |
1872 |
|
if( pol==( lit.getKind()==kind::IMPLIES && i==0 ) ){ |
1873 |
|
ch = atom[i].negate(); |
1874 |
|
} |
1875 |
|
std::pair<bool, Node> chres = entailmentCheck(mode, ch); |
1876 |
|
if( chres.first ){ |
1877 |
|
if( !is_conjunction ){ |
1878 |
|
return chres; |
1879 |
|
}else{ |
1880 |
|
children.push_back( chres.second ); |
1881 |
|
} |
1882 |
|
}else if( !chres.first && is_conjunction ){ |
1883 |
|
return std::pair<bool, Node>(false, Node::null()); |
1884 |
|
} |
1885 |
|
} |
1886 |
|
if( is_conjunction ){ |
1887 |
|
return std::pair<bool, Node>(true, NodeManager::currentNM()->mkNode(kind::AND, children)); |
1888 |
|
}else{ |
1889 |
|
return std::pair<bool, Node>(false, Node::null()); |
1890 |
|
} |
1891 |
4830 |
}else if( atom.getKind()==kind::ITE || ( atom.getKind()==kind::EQUAL && atom[0].getType().isBoolean() ) ){ |
1892 |
|
bool pol = (lit.getKind()!=kind::NOT); |
1893 |
|
for( unsigned r=0; r<2; r++ ){ |
1894 |
|
Node ch = atom[0]; |
1895 |
|
if( r==1 ){ |
1896 |
|
ch = ch.negate(); |
1897 |
|
} |
1898 |
|
std::pair<bool, Node> chres = entailmentCheck(mode, ch); |
1899 |
|
if( chres.first ){ |
1900 |
|
Node ch2 = atom[ atom.getKind()==kind::ITE ? r+1 : 1 ]; |
1901 |
|
if( pol==( atom.getKind()==kind::ITE ? true : r==1 ) ){ |
1902 |
|
ch2 = ch2.negate(); |
1903 |
|
} |
1904 |
|
std::pair<bool, Node> chres2 = entailmentCheck(mode, ch2); |
1905 |
|
if( chres2.first ){ |
1906 |
|
return std::pair<bool, Node>(true, NodeManager::currentNM()->mkNode(kind::AND, chres.second, chres2.second)); |
1907 |
|
}else{ |
1908 |
|
break; |
1909 |
|
} |
1910 |
|
} |
1911 |
|
} |
1912 |
|
return std::pair<bool, Node>(false, Node::null()); |
1913 |
|
}else{ |
1914 |
|
//it is a theory atom |
1915 |
4830 |
theory::TheoryId tid = theory::Theory::theoryOf(mode, atom); |
1916 |
4830 |
theory::Theory* th = theoryOf(tid); |
1917 |
|
|
1918 |
4830 |
Assert(th != NULL); |
1919 |
4830 |
Trace("theory-engine-entc") << "Entailment check : " << lit << std::endl; |
1920 |
|
|
1921 |
9660 |
std::pair<bool, Node> chres = th->entailmentCheck(lit); |
1922 |
4830 |
return chres; |
1923 |
|
} |
1924 |
|
} |
1925 |
|
|
1926 |
6960196 |
bool TheoryEngine::isFiniteType(TypeNode tn) const |
1927 |
|
{ |
1928 |
6960196 |
return isCardinalityClassFinite(tn.getCardinalityClass(), |
1929 |
13920392 |
options::finiteModelFind()); |
1930 |
|
} |
1931 |
|
|
1932 |
29380200 |
void TheoryEngine::spendResource(Resource r) |
1933 |
|
{ |
1934 |
29380200 |
d_env.getResourceManager()->spendResource(r); |
1935 |
29380200 |
} |
1936 |
|
|
1937 |
3600 |
void TheoryEngine::initializeProofChecker(ProofChecker* pc) |
1938 |
|
{ |
1939 |
50400 |
for (theory::TheoryId id = theory::THEORY_FIRST; id < theory::THEORY_LAST; |
1940 |
|
++id) |
1941 |
|
{ |
1942 |
46800 |
ProofRuleChecker* prc = d_theoryTable[id]->getProofChecker(); |
1943 |
46800 |
if (prc) |
1944 |
|
{ |
1945 |
28803 |
prc->registerTo(pc); |
1946 |
|
} |
1947 |
|
} |
1948 |
3600 |
} |
1949 |
|
|
1950 |
28191 |
} // namespace cvc5 |