Fix ackermannize preprocessing pass. (#1904)
[cvc5.git] / src / smt / smt_engine.cpp
1 /********************* */
2 /*! \file smt_engine.cpp
3 ** \verbatim
4 ** Top contributors (to current version):
5 ** Morgan Deters, Andrew Reynolds, Tim King
6 ** This file is part of the CVC4 project.
7 ** Copyright (c) 2009-2018 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.\endverbatim
11 **
12 ** \brief The main entry point into the CVC4 library's SMT interface
13 **
14 ** The main entry point into the CVC4 library's SMT interface.
15 **/
16
17 #include "smt/smt_engine.h"
18
19 #include <algorithm>
20 #include <cctype>
21 #include <iterator>
22 #include <memory>
23 #include <sstream>
24 #include <stack>
25 #include <string>
26 #include <unordered_map>
27 #include <unordered_set>
28 #include <utility>
29 #include <vector>
30
31 #include "base/configuration.h"
32 #include "base/configuration_private.h"
33 #include "base/exception.h"
34 #include "base/listener.h"
35 #include "base/modal_exception.h"
36 #include "base/output.h"
37 #include "context/cdhashmap.h"
38 #include "context/cdhashset.h"
39 #include "context/cdlist.h"
40 #include "context/context.h"
41 #include "decision/decision_engine.h"
42 #include "expr/attribute.h"
43 #include "expr/expr.h"
44 #include "expr/kind.h"
45 #include "expr/metakind.h"
46 #include "expr/node.h"
47 #include "expr/node_builder.h"
48 #include "expr/node_self_iterator.h"
49 #include "options/arith_options.h"
50 #include "options/arrays_options.h"
51 #include "options/base_options.h"
52 #include "options/booleans_options.h"
53 #include "options/bv_options.h"
54 #include "options/datatypes_options.h"
55 #include "options/decision_mode.h"
56 #include "options/decision_options.h"
57 #include "options/language.h"
58 #include "options/main_options.h"
59 #include "options/open_ostream.h"
60 #include "options/option_exception.h"
61 #include "options/printer_options.h"
62 #include "options/proof_options.h"
63 #include "options/prop_options.h"
64 #include "options/quantifiers_options.h"
65 #include "options/sep_options.h"
66 #include "options/set_language.h"
67 #include "options/smt_options.h"
68 #include "options/strings_options.h"
69 #include "options/theory_options.h"
70 #include "options/uf_options.h"
71 #include "preprocessing/passes/bool_to_bv.h"
72 #include "preprocessing/passes/bv_abstraction.h"
73 #include "preprocessing/passes/bv_ackermann.h"
74 #include "preprocessing/passes/bv_gauss.h"
75 #include "preprocessing/passes/bv_intro_pow2.h"
76 #include "preprocessing/passes/bv_to_bool.h"
77 #include "preprocessing/passes/int_to_bv.h"
78 #include "preprocessing/passes/pseudo_boolean_processor.h"
79 #include "preprocessing/passes/real_to_int.h"
80 #include "preprocessing/passes/symmetry_breaker.h"
81 #include "preprocessing/passes/symmetry_detect.h"
82 #include "preprocessing/preprocessing_pass.h"
83 #include "preprocessing/preprocessing_pass_context.h"
84 #include "preprocessing/preprocessing_pass_registry.h"
85 #include "printer/printer.h"
86 #include "proof/proof.h"
87 #include "proof/proof_manager.h"
88 #include "proof/theory_proof.h"
89 #include "proof/unsat_core.h"
90 #include "prop/prop_engine.h"
91 #include "smt/command.h"
92 #include "smt/command_list.h"
93 #include "smt/logic_request.h"
94 #include "smt/managed_ostreams.h"
95 #include "smt/smt_engine_scope.h"
96 #include "smt/term_formula_removal.h"
97 #include "smt/update_ostream.h"
98 #include "smt_util/boolean_simplification.h"
99 #include "smt_util/nary_builder.h"
100 #include "smt_util/node_visitor.h"
101 #include "theory/booleans/circuit_propagator.h"
102 #include "theory/bv/theory_bv_rewriter.h"
103 #include "theory/logic_info.h"
104 #include "theory/quantifiers/fun_def_process.h"
105 #include "theory/quantifiers/global_negate.h"
106 #include "theory/quantifiers/macros.h"
107 #include "theory/quantifiers/quantifiers_rewriter.h"
108 #include "theory/quantifiers/single_inv_partition.h"
109 #include "theory/quantifiers/sygus/ce_guided_instantiation.h"
110 #include "theory/quantifiers/sygus_inference.h"
111 #include "theory/quantifiers/term_util.h"
112 #include "theory/sort_inference.h"
113 #include "theory/strings/theory_strings.h"
114 #include "theory/substitutions.h"
115 #include "theory/theory_engine.h"
116 #include "theory/theory_model.h"
117 #include "theory/theory_traits.h"
118 #include "util/hash.h"
119 #include "util/proof.h"
120 #include "util/random.h"
121 #include "util/resource_manager.h"
122
123 using namespace std;
124 using namespace CVC4;
125 using namespace CVC4::smt;
126 using namespace CVC4::preprocessing;
127 using namespace CVC4::preprocessing::passes;
128 using namespace CVC4::prop;
129 using namespace CVC4::context;
130 using namespace CVC4::theory;
131
132 namespace CVC4 {
133 namespace smt {
134
135 struct DeleteCommandFunction : public std::unary_function<const Command*, void>
136 {
137 void operator()(const Command* command) { delete command; }
138 };
139
140 void DeleteAndClearCommandVector(std::vector<Command*>& commands) {
141 std::for_each(commands.begin(), commands.end(), DeleteCommandFunction());
142 commands.clear();
143 }
144
145 /** Useful for counting the number of recursive calls. */
146 class ScopeCounter {
147 private:
148 unsigned& d_depth;
149 public:
150 ScopeCounter(unsigned& d) : d_depth(d) {
151 ++d_depth;
152 }
153 ~ScopeCounter(){
154 --d_depth;
155 }
156 };
157
158 /**
159 * Representation of a defined function. We keep these around in
160 * SmtEngine to permit expanding definitions late (and lazily), to
161 * support getValue() over defined functions, to support user output
162 * in terms of defined functions, etc.
163 */
164 class DefinedFunction {
165 Node d_func;
166 vector<Node> d_formals;
167 Node d_formula;
168 public:
169 DefinedFunction() {}
170 DefinedFunction(Node func, vector<Node> formals, Node formula) :
171 d_func(func),
172 d_formals(formals),
173 d_formula(formula) {
174 }
175 Node getFunction() const { return d_func; }
176 vector<Node> getFormals() const { return d_formals; }
177 Node getFormula() const { return d_formula; }
178 };/* class DefinedFunction */
179
180 struct SmtEngineStatistics {
181 /** time spent in gaussian elimination */
182 TimerStat d_gaussElimTime;
183 /** time spent in definition-expansion */
184 TimerStat d_definitionExpansionTime;
185 /** time spent in non-clausal simplification */
186 TimerStat d_nonclausalSimplificationTime;
187 /** time spent in miplib pass */
188 TimerStat d_miplibPassTime;
189 /** number of assertions removed by miplib pass */
190 IntStat d_numMiplibAssertionsRemoved;
191 /** number of constant propagations found during nonclausal simp */
192 IntStat d_numConstantProps;
193 /** time spent in static learning */
194 TimerStat d_staticLearningTime;
195 /** time spent in simplifying ITEs */
196 TimerStat d_simpITETime;
197 /** time spent in simplifying ITEs */
198 TimerStat d_unconstrainedSimpTime;
199 /** time spent removing ITEs */
200 TimerStat d_iteRemovalTime;
201 /** time spent in theory preprocessing */
202 TimerStat d_theoryPreprocessTime;
203 /** time spent in theory preprocessing */
204 TimerStat d_rewriteApplyToConstTime;
205 /** time spent converting to CNF */
206 TimerStat d_cnfConversionTime;
207 /** Num of assertions before ite removal */
208 IntStat d_numAssertionsPre;
209 /** Num of assertions after ite removal */
210 IntStat d_numAssertionsPost;
211 /** time spent in checkModel() */
212 TimerStat d_checkModelTime;
213 /** time spent in checkProof() */
214 TimerStat d_checkProofTime;
215 /** time spent in checkUnsatCore() */
216 TimerStat d_checkUnsatCoreTime;
217 /** time spent in PropEngine::checkSat() */
218 TimerStat d_solveTime;
219 /** time spent in pushing/popping */
220 TimerStat d_pushPopTime;
221 /** time spent in processAssertions() */
222 TimerStat d_processAssertionsTime;
223
224 /** Has something simplified to false? */
225 IntStat d_simplifiedToFalse;
226 /** Number of resource units spent. */
227 ReferenceStat<uint64_t> d_resourceUnitsUsed;
228
229 SmtEngineStatistics() :
230 d_gaussElimTime("smt::SmtEngine::gaussElimTime"),
231 d_definitionExpansionTime("smt::SmtEngine::definitionExpansionTime"),
232 d_nonclausalSimplificationTime("smt::SmtEngine::nonclausalSimplificationTime"),
233 d_miplibPassTime("smt::SmtEngine::miplibPassTime"),
234 d_numMiplibAssertionsRemoved("smt::SmtEngine::numMiplibAssertionsRemoved", 0),
235 d_numConstantProps("smt::SmtEngine::numConstantProps", 0),
236 d_staticLearningTime("smt::SmtEngine::staticLearningTime"),
237 d_simpITETime("smt::SmtEngine::simpITETime"),
238 d_unconstrainedSimpTime("smt::SmtEngine::unconstrainedSimpTime"),
239 d_iteRemovalTime("smt::SmtEngine::iteRemovalTime"),
240 d_theoryPreprocessTime("smt::SmtEngine::theoryPreprocessTime"),
241 d_rewriteApplyToConstTime("smt::SmtEngine::rewriteApplyToConstTime"),
242 d_cnfConversionTime("smt::SmtEngine::cnfConversionTime"),
243 d_numAssertionsPre("smt::SmtEngine::numAssertionsPreITERemoval", 0),
244 d_numAssertionsPost("smt::SmtEngine::numAssertionsPostITERemoval", 0),
245 d_checkModelTime("smt::SmtEngine::checkModelTime"),
246 d_checkProofTime("smt::SmtEngine::checkProofTime"),
247 d_checkUnsatCoreTime("smt::SmtEngine::checkUnsatCoreTime"),
248 d_solveTime("smt::SmtEngine::solveTime"),
249 d_pushPopTime("smt::SmtEngine::pushPopTime"),
250 d_processAssertionsTime("smt::SmtEngine::processAssertionsTime"),
251 d_simplifiedToFalse("smt::SmtEngine::simplifiedToFalse", 0),
252 d_resourceUnitsUsed("smt::SmtEngine::resourceUnitsUsed")
253 {
254
255 smtStatisticsRegistry()->registerStat(&d_gaussElimTime);
256 smtStatisticsRegistry()->registerStat(&d_definitionExpansionTime);
257 smtStatisticsRegistry()->registerStat(&d_nonclausalSimplificationTime);
258 smtStatisticsRegistry()->registerStat(&d_miplibPassTime);
259 smtStatisticsRegistry()->registerStat(&d_numMiplibAssertionsRemoved);
260 smtStatisticsRegistry()->registerStat(&d_numConstantProps);
261 smtStatisticsRegistry()->registerStat(&d_staticLearningTime);
262 smtStatisticsRegistry()->registerStat(&d_simpITETime);
263 smtStatisticsRegistry()->registerStat(&d_unconstrainedSimpTime);
264 smtStatisticsRegistry()->registerStat(&d_iteRemovalTime);
265 smtStatisticsRegistry()->registerStat(&d_theoryPreprocessTime);
266 smtStatisticsRegistry()->registerStat(&d_rewriteApplyToConstTime);
267 smtStatisticsRegistry()->registerStat(&d_cnfConversionTime);
268 smtStatisticsRegistry()->registerStat(&d_numAssertionsPre);
269 smtStatisticsRegistry()->registerStat(&d_numAssertionsPost);
270 smtStatisticsRegistry()->registerStat(&d_checkModelTime);
271 smtStatisticsRegistry()->registerStat(&d_checkProofTime);
272 smtStatisticsRegistry()->registerStat(&d_checkUnsatCoreTime);
273 smtStatisticsRegistry()->registerStat(&d_solveTime);
274 smtStatisticsRegistry()->registerStat(&d_pushPopTime);
275 smtStatisticsRegistry()->registerStat(&d_processAssertionsTime);
276 smtStatisticsRegistry()->registerStat(&d_simplifiedToFalse);
277 smtStatisticsRegistry()->registerStat(&d_resourceUnitsUsed);
278 }
279
280 ~SmtEngineStatistics() {
281 smtStatisticsRegistry()->unregisterStat(&d_gaussElimTime);
282 smtStatisticsRegistry()->unregisterStat(&d_definitionExpansionTime);
283 smtStatisticsRegistry()->unregisterStat(&d_nonclausalSimplificationTime);
284 smtStatisticsRegistry()->unregisterStat(&d_miplibPassTime);
285 smtStatisticsRegistry()->unregisterStat(&d_numMiplibAssertionsRemoved);
286 smtStatisticsRegistry()->unregisterStat(&d_numConstantProps);
287 smtStatisticsRegistry()->unregisterStat(&d_staticLearningTime);
288 smtStatisticsRegistry()->unregisterStat(&d_simpITETime);
289 smtStatisticsRegistry()->unregisterStat(&d_unconstrainedSimpTime);
290 smtStatisticsRegistry()->unregisterStat(&d_iteRemovalTime);
291 smtStatisticsRegistry()->unregisterStat(&d_theoryPreprocessTime);
292 smtStatisticsRegistry()->unregisterStat(&d_rewriteApplyToConstTime);
293 smtStatisticsRegistry()->unregisterStat(&d_cnfConversionTime);
294 smtStatisticsRegistry()->unregisterStat(&d_numAssertionsPre);
295 smtStatisticsRegistry()->unregisterStat(&d_numAssertionsPost);
296 smtStatisticsRegistry()->unregisterStat(&d_checkModelTime);
297 smtStatisticsRegistry()->unregisterStat(&d_checkProofTime);
298 smtStatisticsRegistry()->unregisterStat(&d_checkUnsatCoreTime);
299 smtStatisticsRegistry()->unregisterStat(&d_solveTime);
300 smtStatisticsRegistry()->unregisterStat(&d_pushPopTime);
301 smtStatisticsRegistry()->unregisterStat(&d_processAssertionsTime);
302 smtStatisticsRegistry()->unregisterStat(&d_simplifiedToFalse);
303 smtStatisticsRegistry()->unregisterStat(&d_resourceUnitsUsed);
304 }
305 };/* struct SmtEngineStatistics */
306
307
308 class SoftResourceOutListener : public Listener {
309 public:
310 SoftResourceOutListener(SmtEngine& smt) : d_smt(&smt) {}
311 void notify() override
312 {
313 SmtScope scope(d_smt);
314 Assert(smt::smtEngineInScope());
315 d_smt->interrupt();
316 }
317 private:
318 SmtEngine* d_smt;
319 }; /* class SoftResourceOutListener */
320
321
322 class HardResourceOutListener : public Listener {
323 public:
324 HardResourceOutListener(SmtEngine& smt) : d_smt(&smt) {}
325 void notify() override
326 {
327 SmtScope scope(d_smt);
328 theory::Rewriter::clearCaches();
329 }
330 private:
331 SmtEngine* d_smt;
332 }; /* class HardResourceOutListener */
333
334 class SetLogicListener : public Listener {
335 public:
336 SetLogicListener(SmtEngine& smt) : d_smt(&smt) {}
337 void notify() override
338 {
339 LogicInfo inOptions(options::forceLogicString());
340 d_smt->setLogic(inOptions);
341 }
342 private:
343 SmtEngine* d_smt;
344 }; /* class SetLogicListener */
345
346 class BeforeSearchListener : public Listener {
347 public:
348 BeforeSearchListener(SmtEngine& smt) : d_smt(&smt) {}
349 void notify() override { d_smt->beforeSearch(); }
350
351 private:
352 SmtEngine* d_smt;
353 }; /* class BeforeSearchListener */
354
355 class UseTheoryListListener : public Listener {
356 public:
357 UseTheoryListListener(TheoryEngine* theoryEngine)
358 : d_theoryEngine(theoryEngine)
359 {}
360
361 void notify() override
362 {
363 std::stringstream commaList(options::useTheoryList());
364 std::string token;
365
366 Debug("UseTheoryListListener") << "UseTheoryListListener::notify() "
367 << options::useTheoryList() << std::endl;
368
369 while(std::getline(commaList, token, ',')){
370 if(token == "help") {
371 puts(theory::useTheoryHelp);
372 exit(1);
373 }
374 if(theory::useTheoryValidate(token)) {
375 d_theoryEngine->enableTheoryAlternative(token);
376 } else {
377 throw OptionException(
378 std::string("unknown option for --use-theory : `") + token +
379 "'. Try --use-theory=help.");
380 }
381 }
382 }
383
384 private:
385 TheoryEngine* d_theoryEngine;
386 }; /* class UseTheoryListListener */
387
388
389 class SetDefaultExprDepthListener : public Listener {
390 public:
391 void notify() override
392 {
393 int depth = options::defaultExprDepth();
394 Debug.getStream() << expr::ExprSetDepth(depth);
395 Trace.getStream() << expr::ExprSetDepth(depth);
396 Notice.getStream() << expr::ExprSetDepth(depth);
397 Chat.getStream() << expr::ExprSetDepth(depth);
398 Message.getStream() << expr::ExprSetDepth(depth);
399 Warning.getStream() << expr::ExprSetDepth(depth);
400 // intentionally exclude Dump stream from this list
401 }
402 };
403
404 class SetDefaultExprDagListener : public Listener {
405 public:
406 void notify() override
407 {
408 int dag = options::defaultDagThresh();
409 Debug.getStream() << expr::ExprDag(dag);
410 Trace.getStream() << expr::ExprDag(dag);
411 Notice.getStream() << expr::ExprDag(dag);
412 Chat.getStream() << expr::ExprDag(dag);
413 Message.getStream() << expr::ExprDag(dag);
414 Warning.getStream() << expr::ExprDag(dag);
415 Dump.getStream() << expr::ExprDag(dag);
416 }
417 };
418
419 class SetPrintExprTypesListener : public Listener {
420 public:
421 void notify() override
422 {
423 bool value = options::printExprTypes();
424 Debug.getStream() << expr::ExprPrintTypes(value);
425 Trace.getStream() << expr::ExprPrintTypes(value);
426 Notice.getStream() << expr::ExprPrintTypes(value);
427 Chat.getStream() << expr::ExprPrintTypes(value);
428 Message.getStream() << expr::ExprPrintTypes(value);
429 Warning.getStream() << expr::ExprPrintTypes(value);
430 // intentionally exclude Dump stream from this list
431 }
432 };
433
434 class DumpModeListener : public Listener {
435 public:
436 void notify() override
437 {
438 const std::string& value = options::dumpModeString();
439 Dump.setDumpFromString(value);
440 }
441 };
442
443 class PrintSuccessListener : public Listener {
444 public:
445 void notify() override
446 {
447 bool value = options::printSuccess();
448 Debug.getStream() << Command::printsuccess(value);
449 Trace.getStream() << Command::printsuccess(value);
450 Notice.getStream() << Command::printsuccess(value);
451 Chat.getStream() << Command::printsuccess(value);
452 Message.getStream() << Command::printsuccess(value);
453 Warning.getStream() << Command::printsuccess(value);
454 *options::out() << Command::printsuccess(value);
455 }
456 };
457
458
459
460 /**
461 * This is an inelegant solution, but for the present, it will work.
462 * The point of this is to separate the public and private portions of
463 * the SmtEngine class, so that smt_engine.h doesn't
464 * include "expr/node.h", which is a private CVC4 header (and can lead
465 * to linking errors due to the improper inlining of non-visible symbols
466 * into user code!).
467 *
468 * The "real" solution (that which is usually implemented) is to move
469 * ALL the implementation to SmtEnginePrivate and maintain a
470 * heap-allocated instance of it in SmtEngine. SmtEngine (the public
471 * one) becomes an "interface shell" which simply acts as a forwarder
472 * of method calls.
473 */
474 class SmtEnginePrivate : public NodeManagerListener {
475 SmtEngine& d_smt;
476
477 typedef unordered_map<Node, Node, NodeHashFunction> NodeToNodeHashMap;
478 typedef unordered_map<Node, bool, NodeHashFunction> NodeToBoolHashMap;
479
480 /**
481 * Manager for limiting time and abstract resource usage.
482 */
483 ResourceManager* d_resourceManager;
484
485 /** Manager for the memory of regular-output-channel. */
486 ManagedRegularOutputChannel d_managedRegularChannel;
487
488 /** Manager for the memory of diagnostic-output-channel. */
489 ManagedDiagnosticOutputChannel d_managedDiagnosticChannel;
490
491 /** Manager for the memory of --dump-to. */
492 ManagedDumpOStream d_managedDumpChannel;
493
494 /** Manager for --replay-log. */
495 ManagedReplayLogOstream d_managedReplayLog;
496
497 /**
498 * This list contains:
499 * softResourceOut
500 * hardResourceOut
501 * setForceLogic
502 * beforeSearchListener
503 * UseTheoryListListener
504 *
505 * This needs to be deleted before both NodeManager's Options,
506 * SmtEngine, d_resourceManager, and TheoryEngine.
507 */
508 ListenerRegistrationList* d_listenerRegistrations;
509
510 /** Learned literals */
511 vector<Node> d_nonClausalLearnedLiterals;
512
513 /** Size of assertions array when preprocessing starts */
514 unsigned d_realAssertionsEnd;
515
516 /** A circuit propagator for non-clausal propositional deduction */
517 booleans::CircuitPropagator d_propagator;
518 bool d_propagatorNeedsFinish;
519 std::vector<Node> d_boolVars;
520
521 /** Assertions in the preprocessing pipeline */
522 AssertionPipeline d_assertions;
523
524 /** Whether any assertions have been processed */
525 CDO<bool> d_assertionsProcessed;
526
527 /** Index for where to store substitutions */
528 CDO<unsigned> d_substitutionsIndex;
529
530 // Cached true value
531 Node d_true;
532
533 /**
534 * A context that never pushes/pops, for use by CD structures (like
535 * SubstitutionMaps) that should be "global".
536 */
537 context::Context d_fakeContext;
538
539 /**
540 * A map of AbsractValues to their actual constants. Only used if
541 * options::abstractValues() is on.
542 */
543 SubstitutionMap d_abstractValueMap;
544
545 /**
546 * A mapping of all abstract values (actual value |-> abstract) that
547 * we've handed out. This is necessary to ensure that we give the
548 * same AbstractValues for the same real constants. Only used if
549 * options::abstractValues() is on.
550 */
551 NodeToNodeHashMap d_abstractValues;
552
553 /** Number of calls of simplify assertions active.
554 */
555 unsigned d_simplifyAssertionsDepth;
556
557 /** TODO: whether certain preprocess steps are necessary */
558 //bool d_needsExpandDefs;
559
560 //------------------------------- expression names
561 /** mapping from expressions to name */
562 context::CDHashMap< Node, std::string, NodeHashFunction > d_exprNames;
563 //------------------------------- end expression names
564 public:
565 /**
566 * Map from skolem variables to index in d_assertions containing
567 * corresponding introduced Boolean ite
568 */
569 IteSkolemMap d_iteSkolemMap;
570
571 /** Instance of the ITE remover */
572 RemoveTermFormulas d_iteRemover;
573
574 /* Finishes the initialization of the private portion of SMTEngine. */
575 void finishInit();
576
577 private:
578 std::unique_ptr<PreprocessingPassContext> d_preprocessingPassContext;
579 PreprocessingPassRegistry d_preprocessingPassRegistry;
580
581 /** The top level substitutions */
582 SubstitutionMap d_topLevelSubstitutions;
583
584 static const bool d_doConstantProp = true;
585
586 /**
587 * Runs the nonclausal solver and tries to solve all the assigned
588 * theory literals.
589 *
590 * Returns false if the formula simplifies to "false"
591 */
592 bool nonClausalSimplify();
593
594 /**
595 * Performs static learning on the assertions.
596 */
597 void staticLearning();
598
599 /**
600 * Remove ITEs from the assertions.
601 */
602 void removeITEs();
603
604 Node realToInt(TNode n, NodeToNodeHashMap& cache, std::vector< Node >& var_eq);
605 Node purifyNlTerms(TNode n, NodeToNodeHashMap& cache, NodeToNodeHashMap& bcache, std::vector< Node >& var_eq, bool beneathMult = false);
606
607 /**
608 * Helper function to fix up assertion list to restore invariants needed after
609 * ite removal.
610 */
611 void collectSkolems(TNode n, set<TNode>& skolemSet, NodeToBoolHashMap& cache);
612
613 /**
614 * Helper function to fix up assertion list to restore invariants needed after
615 * ite removal.
616 */
617 bool checkForBadSkolems(TNode n, TNode skolem, NodeToBoolHashMap& cache);
618
619 // Simplify ITE structure
620 bool simpITE();
621
622 // Simplify based on unconstrained values
623 void unconstrainedSimp();
624
625 /**
626 * Ensures the assertions asserted after before now effectively come before
627 * d_realAssertionsEnd.
628 */
629 void compressBeforeRealAssertions(size_t before);
630
631 /**
632 * Trace nodes back to their assertions using CircuitPropagator's
633 * BackEdgesMap.
634 */
635 void traceBackToAssertions(const std::vector<Node>& nodes,
636 std::vector<TNode>& assertions);
637
638 /**
639 * Remove conjuncts in toRemove from conjunction n. Return # of removed
640 * conjuncts.
641 */
642 size_t removeFromConjunction(Node& n,
643 const std::unordered_set<unsigned long>& toRemove);
644
645 /** Scrub miplib encodings. */
646 void doMiplibTrick();
647
648 /**
649 * Perform non-clausal simplification of a Node. This involves
650 * Theory implementations, but does NOT involve the SAT solver in
651 * any way.
652 *
653 * Returns false if the formula simplifies to "false"
654 */
655 bool simplifyAssertions();
656
657 public:
658
659 SmtEnginePrivate(SmtEngine& smt) :
660 d_smt(smt),
661 d_managedRegularChannel(),
662 d_managedDiagnosticChannel(),
663 d_managedDumpChannel(),
664 d_managedReplayLog(),
665 d_listenerRegistrations(new ListenerRegistrationList()),
666 d_nonClausalLearnedLiterals(),
667 d_realAssertionsEnd(0),
668 d_propagator(d_nonClausalLearnedLiterals, true, true),
669 d_propagatorNeedsFinish(false),
670 d_assertions(),
671 d_assertionsProcessed(smt.d_userContext, false),
672 d_substitutionsIndex(smt.d_userContext, 0),
673 d_fakeContext(),
674 d_abstractValueMap(&d_fakeContext),
675 d_abstractValues(),
676 d_simplifyAssertionsDepth(0),
677 //d_needsExpandDefs(true), //TODO?
678 d_exprNames(smt.d_userContext),
679 d_iteSkolemMap(),
680 d_iteRemover(smt.d_userContext),
681 d_topLevelSubstitutions(smt.d_userContext)
682 {
683 d_smt.d_nodeManager->subscribeEvents(this);
684 d_true = NodeManager::currentNM()->mkConst(true);
685 d_resourceManager = NodeManager::currentResourceManager();
686
687 d_listenerRegistrations->add(d_resourceManager->registerSoftListener(
688 new SoftResourceOutListener(d_smt)));
689
690 d_listenerRegistrations->add(d_resourceManager->registerHardListener(
691 new HardResourceOutListener(d_smt)));
692
693 Options& nodeManagerOptions = NodeManager::currentNM()->getOptions();
694 d_listenerRegistrations->add(
695 nodeManagerOptions.registerForceLogicListener(
696 new SetLogicListener(d_smt), true));
697
698 // Multiple options reuse BeforeSearchListener so registration requires an
699 // extra bit of care.
700 // We can safely not call notify on this before search listener at
701 // registration time. This d_smt cannot be beforeSearch at construction
702 // time. Therefore the BeforeSearchListener is a no-op. Therefore it does
703 // not have to be called.
704 d_listenerRegistrations->add(
705 nodeManagerOptions.registerBeforeSearchListener(
706 new BeforeSearchListener(d_smt)));
707
708 // These do need registration calls.
709 d_listenerRegistrations->add(
710 nodeManagerOptions.registerSetDefaultExprDepthListener(
711 new SetDefaultExprDepthListener(), true));
712 d_listenerRegistrations->add(
713 nodeManagerOptions.registerSetDefaultExprDagListener(
714 new SetDefaultExprDagListener(), true));
715 d_listenerRegistrations->add(
716 nodeManagerOptions.registerSetPrintExprTypesListener(
717 new SetPrintExprTypesListener(), true));
718 d_listenerRegistrations->add(
719 nodeManagerOptions.registerSetDumpModeListener(
720 new DumpModeListener(), true));
721 d_listenerRegistrations->add(
722 nodeManagerOptions.registerSetPrintSuccessListener(
723 new PrintSuccessListener(), true));
724 d_listenerRegistrations->add(
725 nodeManagerOptions.registerSetRegularOutputChannelListener(
726 new SetToDefaultSourceListener(&d_managedRegularChannel), true));
727 d_listenerRegistrations->add(
728 nodeManagerOptions.registerSetDiagnosticOutputChannelListener(
729 new SetToDefaultSourceListener(&d_managedDiagnosticChannel), true));
730 d_listenerRegistrations->add(
731 nodeManagerOptions.registerDumpToFileNameListener(
732 new SetToDefaultSourceListener(&d_managedDumpChannel), true));
733 d_listenerRegistrations->add(
734 nodeManagerOptions.registerSetReplayLogFilename(
735 new SetToDefaultSourceListener(&d_managedReplayLog), true));
736 }
737
738 ~SmtEnginePrivate()
739 {
740 delete d_listenerRegistrations;
741
742 if(d_propagatorNeedsFinish) {
743 d_propagator.finish();
744 d_propagatorNeedsFinish = false;
745 }
746 d_smt.d_nodeManager->unsubscribeEvents(this);
747 }
748
749 void unregisterPreprocessingPasses()
750 {
751 d_preprocessingPassRegistry.unregisterPasses();
752 }
753
754 ResourceManager* getResourceManager() { return d_resourceManager; }
755 void spendResource(unsigned amount)
756 {
757 d_resourceManager->spendResource(amount);
758 }
759
760 void nmNotifyNewSort(TypeNode tn, uint32_t flags) override
761 {
762 DeclareTypeCommand c(tn.getAttribute(expr::VarNameAttr()),
763 0,
764 tn.toType());
765 if((flags & ExprManager::SORT_FLAG_PLACEHOLDER) == 0) {
766 d_smt.addToModelCommandAndDump(c, flags);
767 }
768 }
769
770 void nmNotifyNewSortConstructor(TypeNode tn) override
771 {
772 DeclareTypeCommand c(tn.getAttribute(expr::VarNameAttr()),
773 tn.getAttribute(expr::SortArityAttr()),
774 tn.toType());
775 d_smt.addToModelCommandAndDump(c);
776 }
777
778 void nmNotifyNewDatatypes(const std::vector<DatatypeType>& dtts) override
779 {
780 DatatypeDeclarationCommand c(dtts);
781 d_smt.addToModelCommandAndDump(c);
782 }
783
784 void nmNotifyNewVar(TNode n, uint32_t flags) override
785 {
786 DeclareFunctionCommand c(n.getAttribute(expr::VarNameAttr()),
787 n.toExpr(),
788 n.getType().toType());
789 if((flags & ExprManager::VAR_FLAG_DEFINED) == 0) {
790 d_smt.addToModelCommandAndDump(c, flags);
791 }
792 if(n.getType().isBoolean() && !options::incrementalSolving()) {
793 d_boolVars.push_back(n);
794 }
795 }
796
797 void nmNotifyNewSkolem(TNode n,
798 const std::string& comment,
799 uint32_t flags) override
800 {
801 string id = n.getAttribute(expr::VarNameAttr());
802 DeclareFunctionCommand c(id, n.toExpr(), n.getType().toType());
803 if(Dump.isOn("skolems") && comment != "") {
804 Dump("skolems") << CommentCommand(id + " is " + comment);
805 }
806 if((flags & ExprManager::VAR_FLAG_DEFINED) == 0) {
807 d_smt.addToModelCommandAndDump(c, flags, false, "skolems");
808 }
809 if(n.getType().isBoolean() && !options::incrementalSolving()) {
810 d_boolVars.push_back(n);
811 }
812 }
813
814 void nmNotifyDeleteNode(TNode n) override {}
815
816 Node applySubstitutions(TNode node) const {
817 return Rewriter::rewrite(d_topLevelSubstitutions.apply(node));
818 }
819
820 /**
821 * Apply the substitutions in d_topLevelAssertions and the rewriter to each of
822 * the assertions in d_assertions, and store the result back in d_assertions.
823 */
824 void applySubstitutionsToAssertions();
825
826 /**
827 * Process the assertions that have been asserted.
828 */
829 void processAssertions();
830
831 /** Process a user push.
832 */
833 void notifyPush() {
834
835 }
836
837 /**
838 * Process a user pop. Clears out the non-context-dependent stuff in this
839 * SmtEnginePrivate. Necessary to clear out our assertion vectors in case
840 * someone does a push-assert-pop without a check-sat. It also pops the
841 * last map of expression names from notifyPush.
842 */
843 void notifyPop() {
844 d_assertions.clear();
845 d_nonClausalLearnedLiterals.clear();
846 d_realAssertionsEnd = 0;
847 d_iteSkolemMap.clear();
848 }
849
850 /**
851 * Adds a formula to the current context. Action here depends on
852 * the SimplificationMode (in the current Options scope); the
853 * formula might be pushed out to the propositional layer
854 * immediately, or it might be simplified and kept, or it might not
855 * even be simplified.
856 * the 2nd and 3rd arguments added for bookkeeping for proofs
857 */
858 void addFormula(TNode n, bool inUnsatCore, bool inInput = true);
859
860 /** Expand definitions in n. */
861 Node expandDefinitions(TNode n,
862 NodeToNodeHashMap& cache,
863 bool expandOnly = false);
864
865 /**
866 * Simplify node "in" by expanding definitions and applying any
867 * substitutions learned from preprocessing.
868 */
869 Node simplify(TNode in) {
870 // Substitute out any abstract values in ex.
871 // Expand definitions.
872 NodeToNodeHashMap cache;
873 Node n = expandDefinitions(in, cache).toExpr();
874 // Make sure we've done all preprocessing, etc.
875 Assert(d_assertions.size() == 0);
876 return applySubstitutions(n).toExpr();
877 }
878
879 /**
880 * Substitute away all AbstractValues in a node.
881 */
882 Node substituteAbstractValues(TNode n) {
883 // We need to do this even if options::abstractValues() is off,
884 // since the setting might have changed after we already gave out
885 // some abstract values.
886 return d_abstractValueMap.apply(n);
887 }
888
889 /**
890 * Make a new (or return an existing) abstract value for a node.
891 * Can only use this if options::abstractValues() is on.
892 */
893 Node mkAbstractValue(TNode n) {
894 Assert(options::abstractValues());
895 Node& val = d_abstractValues[n];
896 if(val.isNull()) {
897 val = d_smt.d_nodeManager->mkAbstractValue(n.getType());
898 d_abstractValueMap.addSubstitution(val, n);
899 }
900 // We are supposed to ascribe types to all abstract values that go out.
901 NodeManager* current = d_smt.d_nodeManager;
902 Node ascription = current->mkConst(AscriptionType(n.getType().toType()));
903 Node retval = current->mkNode(kind::APPLY_TYPE_ASCRIPTION, ascription, val);
904 return retval;
905 }
906
907 NodeToNodeHashMap d_rewriteApplyToConstCache;
908 Node rewriteApplyToConst(TNode n) {
909 Trace("rewriteApplyToConst") << "rewriteApplyToConst :: " << n << std::endl;
910
911 if(n.getMetaKind() == kind::metakind::CONSTANT ||
912 n.getMetaKind() == kind::metakind::VARIABLE ||
913 n.getMetaKind() == kind::metakind::NULLARY_OPERATOR)
914 {
915 return n;
916 }
917
918 if(d_rewriteApplyToConstCache.find(n) != d_rewriteApplyToConstCache.end()) {
919 Trace("rewriteApplyToConst") << "in cache :: "
920 << d_rewriteApplyToConstCache[n]
921 << std::endl;
922 return d_rewriteApplyToConstCache[n];
923 }
924
925 if(n.getKind() == kind::APPLY_UF) {
926 if(n.getNumChildren() == 1 && n[0].isConst() &&
927 n[0].getType().isInteger())
928 {
929 stringstream ss;
930 ss << n.getOperator() << "_";
931 if(n[0].getConst<Rational>() < 0) {
932 ss << "m" << -n[0].getConst<Rational>();
933 } else {
934 ss << n[0];
935 }
936 Node newvar = NodeManager::currentNM()->mkSkolem(
937 ss.str(), n.getType(), "rewriteApplyToConst skolem",
938 NodeManager::SKOLEM_EXACT_NAME);
939 d_rewriteApplyToConstCache[n] = newvar;
940 Trace("rewriteApplyToConst") << "made :: " << newvar << std::endl;
941 return newvar;
942 } else {
943 stringstream ss;
944 ss << "The rewrite-apply-to-const preprocessor is currently limited;"
945 << std::endl
946 << "it only works if all function symbols are unary and with Integer"
947 << std::endl
948 << "domain, and all applications are to integer values." << std::endl
949 << "Found application: " << n;
950 Unhandled(ss.str());
951 }
952 }
953
954 NodeBuilder<> builder(n.getKind());
955 if(n.getMetaKind() == kind::metakind::PARAMETERIZED) {
956 builder << n.getOperator();
957 }
958 for(unsigned i = 0; i < n.getNumChildren(); ++i) {
959 builder << rewriteApplyToConst(n[i]);
960 }
961 Node rewr = builder;
962 d_rewriteApplyToConstCache[n] = rewr;
963 Trace("rewriteApplyToConst") << "built :: " << rewr << std::endl;
964 return rewr;
965 }
966
967 void addUseTheoryListListener(TheoryEngine* theoryEngine){
968 Options& nodeManagerOptions = NodeManager::currentNM()->getOptions();
969 d_listenerRegistrations->add(
970 nodeManagerOptions.registerUseTheoryListListener(
971 new UseTheoryListListener(theoryEngine), true));
972 }
973
974 std::ostream* getReplayLog() const {
975 return d_managedReplayLog.getReplayLog();
976 }
977
978 //------------------------------- expression names
979 // implements setExpressionName, as described in smt_engine.h
980 void setExpressionName(Expr e, std::string name) {
981 d_exprNames[Node::fromExpr(e)] = name;
982 }
983
984 // implements getExpressionName, as described in smt_engine.h
985 bool getExpressionName(Expr e, std::string& name) const {
986 context::CDHashMap< Node, std::string, NodeHashFunction >::const_iterator it = d_exprNames.find(e);
987 if(it!=d_exprNames.end()) {
988 name = (*it).second;
989 return true;
990 }else{
991 return false;
992 }
993 }
994 //------------------------------- end expression names
995
996 };/* class SmtEnginePrivate */
997
998 }/* namespace CVC4::smt */
999
1000 SmtEngine::SmtEngine(ExprManager* em)
1001 : d_context(new Context()),
1002 d_userLevels(),
1003 d_userContext(new UserContext()),
1004 d_exprManager(em),
1005 d_nodeManager(d_exprManager->getNodeManager()),
1006 d_decisionEngine(NULL),
1007 d_theoryEngine(NULL),
1008 d_propEngine(NULL),
1009 d_proofManager(NULL),
1010 d_definedFunctions(NULL),
1011 d_fmfRecFunctionsDefined(NULL),
1012 d_assertionList(NULL),
1013 d_assignments(NULL),
1014 d_modelGlobalCommands(),
1015 d_modelCommands(NULL),
1016 d_dumpCommands(),
1017 d_defineCommands(),
1018 d_logic(),
1019 d_originalOptions(),
1020 d_pendingPops(0),
1021 d_fullyInited(false),
1022 d_problemExtended(false),
1023 d_queryMade(false),
1024 d_needPostsolve(false),
1025 d_earlyTheoryPP(true),
1026 d_globalNegation(false),
1027 d_status(),
1028 d_replayStream(NULL),
1029 d_private(NULL),
1030 d_statisticsRegistry(NULL),
1031 d_stats(NULL),
1032 d_channels(new LemmaChannels())
1033 {
1034 SmtScope smts(this);
1035 d_originalOptions.copyValues(em->getOptions());
1036 d_private = new smt::SmtEnginePrivate(*this);
1037 d_statisticsRegistry = new StatisticsRegistry();
1038 d_stats = new SmtEngineStatistics();
1039 d_stats->d_resourceUnitsUsed.setData(
1040 d_private->getResourceManager()->getResourceUsage());
1041
1042 // The ProofManager is constructed before any other proof objects such as
1043 // SatProof and TheoryProofs. The TheoryProofEngine and the SatProof are
1044 // initialized in TheoryEngine and PropEngine respectively.
1045 Assert(d_proofManager == NULL);
1046
1047 // d_proofManager must be created before Options has been finished
1048 // being parsed from the input file. Because of this, we cannot trust
1049 // that options::proof() is set correctly yet.
1050 #ifdef CVC4_PROOF
1051 d_proofManager = new ProofManager(d_userContext);
1052 #endif
1053
1054 // We have mutual dependency here, so we add the prop engine to the theory
1055 // engine later (it is non-essential there)
1056 d_theoryEngine = new TheoryEngine(d_context, d_userContext,
1057 d_private->d_iteRemover,
1058 const_cast<const LogicInfo&>(d_logic),
1059 d_channels);
1060
1061 // Add the theories
1062 for(TheoryId id = theory::THEORY_FIRST; id < theory::THEORY_LAST; ++id) {
1063 TheoryConstructor::addTheory(d_theoryEngine, id);
1064 //register with proof engine if applicable
1065 #ifdef CVC4_PROOF
1066 ProofManager::currentPM()->getTheoryProofEngine()->registerTheory(d_theoryEngine->theoryOf(id));
1067 #endif
1068 }
1069
1070 d_private->addUseTheoryListListener(d_theoryEngine);
1071
1072 // global push/pop around everything, to ensure proper destruction
1073 // of context-dependent data structures
1074 d_userContext->push();
1075 d_context->push();
1076
1077 d_definedFunctions = new(true) DefinedFunctionMap(d_userContext);
1078 d_fmfRecFunctionsDefined = new(true) NodeList(d_userContext);
1079 d_modelCommands = new(true) smt::CommandList(d_userContext);
1080 }
1081
1082 void SmtEngine::finishInit() {
1083 Trace("smt-debug") << "SmtEngine::finishInit" << std::endl;
1084 // ensure that our heuristics are properly set up
1085 setDefaults();
1086
1087 Trace("smt-debug") << "Making decision engine..." << std::endl;
1088
1089 d_decisionEngine = new DecisionEngine(d_context, d_userContext);
1090 d_decisionEngine->init(); // enable appropriate strategies
1091
1092 Trace("smt-debug") << "Making prop engine..." << std::endl;
1093 d_propEngine = new PropEngine(d_theoryEngine, d_decisionEngine, d_context,
1094 d_userContext, d_private->getReplayLog(),
1095 d_replayStream, d_channels);
1096
1097 Trace("smt-debug") << "Setting up theory engine..." << std::endl;
1098 d_theoryEngine->setPropEngine(d_propEngine);
1099 d_theoryEngine->setDecisionEngine(d_decisionEngine);
1100 Trace("smt-debug") << "Finishing init for theory engine..." << std::endl;
1101 d_theoryEngine->finishInit();
1102
1103 Trace("smt-debug") << "Set up assertion list..." << std::endl;
1104 // [MGD 10/20/2011] keep around in incremental mode, due to a
1105 // cleanup ordering issue and Nodes/TNodes. If SAT is popped
1106 // first, some user-context-dependent TNodes might still exist
1107 // with rc == 0.
1108 if(options::produceAssertions() ||
1109 options::incrementalSolving()) {
1110 // In the case of incremental solving, we appear to need these to
1111 // ensure the relevant Nodes remain live.
1112 d_assertionList = new(true) AssertionList(d_userContext);
1113 }
1114
1115 // dump out a set-logic command
1116 if(Dump.isOn("benchmark")) {
1117 if (Dump.isOn("raw-benchmark")) {
1118 Dump("raw-benchmark") << SetBenchmarkLogicCommand(d_logic.getLogicString());
1119 } else {
1120 LogicInfo everything;
1121 everything.lock();
1122 Dump("benchmark") << CommentCommand("CVC4 always dumps the most general, all-supported logic (below), as some internals might require the use of a logic more general than the input.")
1123 << SetBenchmarkLogicCommand(everything.getLogicString());
1124 }
1125 }
1126
1127 Trace("smt-debug") << "Dump declaration commands..." << std::endl;
1128 // dump out any pending declaration commands
1129 for(unsigned i = 0; i < d_dumpCommands.size(); ++i) {
1130 Dump("declarations") << *d_dumpCommands[i];
1131 delete d_dumpCommands[i];
1132 }
1133 d_dumpCommands.clear();
1134
1135 PROOF( ProofManager::currentPM()->setLogic(d_logic); );
1136 PROOF({
1137 for(TheoryId id = theory::THEORY_FIRST; id < theory::THEORY_LAST; ++id) {
1138 ProofManager::currentPM()->getTheoryProofEngine()->
1139 finishRegisterTheory(d_theoryEngine->theoryOf(id));
1140 }
1141 });
1142 d_private->finishInit();
1143 Trace("smt-debug") << "SmtEngine::finishInit done" << std::endl;
1144 }
1145
1146 void SmtEngine::finalOptionsAreSet() {
1147 if(d_fullyInited) {
1148 return;
1149 }
1150
1151 if(! d_logic.isLocked()) {
1152 setLogicInternal();
1153 }
1154
1155 // finish initialization, create the prop engine, etc.
1156 finishInit();
1157
1158 AlwaysAssert( d_propEngine->getAssertionLevel() == 0,
1159 "The PropEngine has pushed but the SmtEngine "
1160 "hasn't finished initializing!" );
1161
1162 d_fullyInited = true;
1163 Assert(d_logic.isLocked());
1164
1165 d_propEngine->assertFormula(NodeManager::currentNM()->mkConst<bool>(true));
1166 d_propEngine->assertFormula(NodeManager::currentNM()->mkConst<bool>(false).notNode());
1167 }
1168
1169 void SmtEngine::shutdown() {
1170 doPendingPops();
1171
1172 while(options::incrementalSolving() && d_userContext->getLevel() > 1) {
1173 internalPop(true);
1174 }
1175
1176 // check to see if a postsolve() is pending
1177 if(d_needPostsolve) {
1178 d_theoryEngine->postsolve();
1179 d_needPostsolve = false;
1180 }
1181
1182 if(d_propEngine != NULL) {
1183 d_propEngine->shutdown();
1184 }
1185 if(d_theoryEngine != NULL) {
1186 d_theoryEngine->shutdown();
1187 }
1188 if(d_decisionEngine != NULL) {
1189 d_decisionEngine->shutdown();
1190 }
1191 }
1192
1193 SmtEngine::~SmtEngine()
1194 {
1195 SmtScope smts(this);
1196
1197 try {
1198 shutdown();
1199
1200 // global push/pop around everything, to ensure proper destruction
1201 // of context-dependent data structures
1202 d_context->popto(0);
1203 d_userContext->popto(0);
1204
1205 if(d_assignments != NULL) {
1206 d_assignments->deleteSelf();
1207 }
1208
1209 if(d_assertionList != NULL) {
1210 d_assertionList->deleteSelf();
1211 }
1212
1213 for(unsigned i = 0; i < d_dumpCommands.size(); ++i) {
1214 delete d_dumpCommands[i];
1215 d_dumpCommands[i] = NULL;
1216 }
1217 d_dumpCommands.clear();
1218
1219 DeleteAndClearCommandVector(d_modelGlobalCommands);
1220
1221 if(d_modelCommands != NULL) {
1222 d_modelCommands->deleteSelf();
1223 }
1224
1225 d_definedFunctions->deleteSelf();
1226 d_fmfRecFunctionsDefined->deleteSelf();
1227
1228 //destroy all passes before destroying things that they refer to
1229 d_private->unregisterPreprocessingPasses();
1230
1231 delete d_theoryEngine;
1232 d_theoryEngine = NULL;
1233 delete d_propEngine;
1234 d_propEngine = NULL;
1235 delete d_decisionEngine;
1236 d_decisionEngine = NULL;
1237
1238
1239 // d_proofManager is always created when proofs are enabled at configure time.
1240 // Becuase of this, this code should not be wrapped in PROOF() which
1241 // additionally checks flags such as options::proof().
1242 #ifdef CVC4_PROOF
1243 delete d_proofManager;
1244 d_proofManager = NULL;
1245 #endif
1246
1247 delete d_stats;
1248 d_stats = NULL;
1249 delete d_statisticsRegistry;
1250 d_statisticsRegistry = NULL;
1251
1252 delete d_private;
1253 d_private = NULL;
1254
1255 delete d_userContext;
1256 d_userContext = NULL;
1257 delete d_context;
1258 d_context = NULL;
1259
1260 delete d_channels;
1261 d_channels = NULL;
1262
1263 } catch(Exception& e) {
1264 Warning() << "CVC4 threw an exception during cleanup." << endl
1265 << e << endl;
1266 }
1267 }
1268
1269 void SmtEngine::setLogic(const LogicInfo& logic)
1270 {
1271 SmtScope smts(this);
1272 if(d_fullyInited) {
1273 throw ModalException("Cannot set logic in SmtEngine after the engine has "
1274 "finished initializing.");
1275 }
1276 d_logic = logic;
1277 setLogicInternal();
1278 }
1279
1280 void SmtEngine::setLogic(const std::string& s)
1281 {
1282 SmtScope smts(this);
1283 try {
1284 setLogic(LogicInfo(s));
1285 } catch(IllegalArgumentException& e) {
1286 throw LogicException(e.what());
1287 }
1288 }
1289
1290 void SmtEngine::setLogic(const char* logic) { setLogic(string(logic)); }
1291 LogicInfo SmtEngine::getLogicInfo() const {
1292 return d_logic;
1293 }
1294 void SmtEngine::setLogicInternal()
1295 {
1296 Assert(!d_fullyInited, "setting logic in SmtEngine but the engine has already"
1297 " finished initializing for this run");
1298 d_logic.lock();
1299 }
1300
1301 void SmtEngine::setDefaults() {
1302 Random::getRandom().setSeed(options::seed());
1303 // Language-based defaults
1304 if (!options::bitvectorDivByZeroConst.wasSetByUser())
1305 {
1306 options::bitvectorDivByZeroConst.set(
1307 language::isInputLang_smt2_6(options::inputLanguage()));
1308 }
1309 if (options::inputLanguage() == language::input::LANG_SYGUS)
1310 {
1311 if (!options::ceGuidedInst.wasSetByUser())
1312 {
1313 options::ceGuidedInst.set(true);
1314 }
1315 // must use Ferrante/Rackoff for real arithmetic
1316 if (!options::cbqiMidpoint.wasSetByUser())
1317 {
1318 options::cbqiMidpoint.set(true);
1319 }
1320 }
1321 else
1322 {
1323 // cannot use sygus repair constants
1324 options::sygusRepairConst.set(false);
1325 }
1326
1327 if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER)
1328 {
1329 if (options::incrementalSolving())
1330 {
1331 if (options::incrementalSolving.wasSetByUser())
1332 {
1333 throw OptionException(std::string(
1334 "Eager bit-blasting does not currently support incremental mode. "
1335 "Try --bitblast=lazy"));
1336 }
1337 Notice() << "SmtEngine: turning off incremental to support eager "
1338 << "bit-blasting" << endl;
1339 setOption("incremental", SExpr("false"));
1340 }
1341 if (options::produceModels()
1342 && (d_logic.isTheoryEnabled(THEORY_ARRAYS)
1343 || d_logic.isTheoryEnabled(THEORY_UF)))
1344 {
1345 if (options::bitblastMode.wasSetByUser()
1346 || options::produceModels.wasSetByUser())
1347 {
1348 throw OptionException(std::string(
1349 "Eager bit-blasting currently does not support model generation "
1350 "for the combination of bit-vectors with arrays or uinterpreted "
1351 "functions. Try --bitblast=lazy"));
1352 }
1353 Notice() << "SmtEngine: setting bit-blast mode to lazy to support model"
1354 << "generation" << endl;
1355 setOption("bitblastMode", SExpr("lazy"));
1356 }
1357 }
1358
1359 if(options::forceLogicString.wasSetByUser()) {
1360 d_logic = LogicInfo(options::forceLogicString());
1361 }else if (options::solveIntAsBV() > 0) {
1362 d_logic = LogicInfo("QF_BV");
1363 }else if (d_logic.getLogicString() == "QF_NRA" && options::solveRealAsInt()) {
1364 d_logic = LogicInfo("QF_NIA");
1365 } else if ((d_logic.getLogicString() == "QF_UFBV" ||
1366 d_logic.getLogicString() == "QF_ABV") &&
1367 options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER) {
1368 d_logic = LogicInfo("QF_BV");
1369 }
1370
1371 // set strings-exp
1372 /* - disabled for 1.4 release [MGD 2014.06.25]
1373 if(!d_logic.hasEverything() && d_logic.isTheoryEnabled(THEORY_STRINGS) ) {
1374 if(! options::stringExp.wasSetByUser()) {
1375 options::stringExp.set( true );
1376 Trace("smt") << "turning on strings-exp, for the theory of strings" << std::endl;
1377 }
1378 }
1379 */
1380 // for strings
1381 if(options::stringExp()) {
1382 if( !d_logic.isQuantified() ) {
1383 d_logic = d_logic.getUnlockedCopy();
1384 d_logic.enableQuantifiers();
1385 d_logic.lock();
1386 Trace("smt") << "turning on quantifier logic, for strings-exp"
1387 << std::endl;
1388 }
1389 if(! options::fmfBound.wasSetByUser()) {
1390 options::fmfBound.set( true );
1391 Trace("smt") << "turning on fmf-bound-int, for strings-exp" << std::endl;
1392 }
1393 if(! options::fmfInstEngine.wasSetByUser()) {
1394 options::fmfInstEngine.set( true );
1395 Trace("smt") << "turning on fmf-inst-engine, for strings-exp" << std::endl;
1396 }
1397 /*
1398 if(! options::rewriteDivk.wasSetByUser()) {
1399 options::rewriteDivk.set( true );
1400 Trace("smt") << "turning on rewrite-divk, for strings-exp" << std::endl;
1401 }*/
1402 /*
1403 if(! options::stringFMF.wasSetByUser()) {
1404 options::stringFMF.set( true );
1405 Trace("smt") << "turning on strings-fmf, for strings-exp" << std::endl;
1406 }
1407 */
1408 }
1409
1410 // sygus inference may require datatypes
1411 if (options::sygusInference())
1412 {
1413 d_logic = d_logic.getUnlockedCopy();
1414 d_logic.enableTheory(THEORY_DATATYPES);
1415 d_logic.lock();
1416 }
1417
1418 if ((options::checkModels() || options::checkSynthSol())
1419 && !options::produceAssertions())
1420 {
1421 Notice() << "SmtEngine: turning on produce-assertions to support "
1422 << "check-models or check-synth-sol." << endl;
1423 setOption("produce-assertions", SExpr("true"));
1424 }
1425
1426 if(options::unsatCores()) {
1427 if(options::simplificationMode() != SIMPLIFICATION_MODE_NONE) {
1428 if(options::simplificationMode.wasSetByUser()) {
1429 throw OptionException("simplification not supported with unsat cores");
1430 }
1431 Notice() << "SmtEngine: turning off simplification to support unsat-cores"
1432 << endl;
1433 options::simplificationMode.set(SIMPLIFICATION_MODE_NONE);
1434 }
1435
1436 if(options::unconstrainedSimp()) {
1437 if(options::unconstrainedSimp.wasSetByUser()) {
1438 throw OptionException("unconstrained simplification not supported with unsat cores");
1439 }
1440 Notice() << "SmtEngine: turning off unconstrained simplification to support unsat-cores" << endl;
1441 options::unconstrainedSimp.set(false);
1442 }
1443
1444 if(options::pbRewrites()) {
1445 if(options::pbRewrites.wasSetByUser()) {
1446 throw OptionException("pseudoboolean rewrites not supported with unsat cores");
1447 }
1448 Notice() << "SmtEngine: turning off pseudoboolean rewrites to support unsat-cores" << endl;
1449 setOption("pb-rewrites", false);
1450 }
1451
1452 if(options::sortInference()) {
1453 if(options::sortInference.wasSetByUser()) {
1454 throw OptionException("sort inference not supported with unsat cores");
1455 }
1456 Notice() << "SmtEngine: turning off sort inference to support unsat-cores" << endl;
1457 options::sortInference.set(false);
1458 }
1459
1460 if(options::preSkolemQuant()) {
1461 if(options::preSkolemQuant.wasSetByUser()) {
1462 throw OptionException("pre-skolemization not supported with unsat cores");
1463 }
1464 Notice() << "SmtEngine: turning off pre-skolemization to support unsat-cores" << endl;
1465 options::preSkolemQuant.set(false);
1466 }
1467
1468 if(options::bitvectorToBool()) {
1469 if(options::bitvectorToBool.wasSetByUser()) {
1470 throw OptionException("bv-to-bool not supported with unsat cores");
1471 }
1472 Notice() << "SmtEngine: turning off bitvector-to-bool to support unsat-cores" << endl;
1473 options::bitvectorToBool.set(false);
1474 }
1475
1476 if(options::boolToBitvector()) {
1477 if(options::boolToBitvector.wasSetByUser()) {
1478 throw OptionException("bool-to-bv not supported with unsat cores");
1479 }
1480 Notice() << "SmtEngine: turning off bool-to-bitvector to support unsat-cores" << endl;
1481 options::boolToBitvector.set(false);
1482 }
1483
1484 if(options::bvIntroducePow2()) {
1485 if(options::bvIntroducePow2.wasSetByUser()) {
1486 throw OptionException("bv-intro-pow2 not supported with unsat cores");
1487 }
1488 Notice() << "SmtEngine: turning off bv-intro-pow2 to support unsat-cores" << endl;
1489 setOption("bv-intro-pow2", false);
1490 }
1491
1492 if(options::repeatSimp()) {
1493 if(options::repeatSimp.wasSetByUser()) {
1494 throw OptionException("repeat-simp not supported with unsat cores");
1495 }
1496 Notice() << "SmtEngine: turning off repeat-simp to support unsat-cores" << endl;
1497 setOption("repeat-simp", false);
1498 }
1499
1500 if (options::globalNegate())
1501 {
1502 if (options::globalNegate.wasSetByUser())
1503 {
1504 throw OptionException("global-negate not supported with unsat cores");
1505 }
1506 Notice() << "SmtEngine: turning off global-negate to support unsat-cores"
1507 << endl;
1508 setOption("global-negate", false);
1509 }
1510 }
1511
1512 if (options::cbqiBv() && d_logic.isQuantified())
1513 {
1514 if(options::boolToBitvector.wasSetByUser()) {
1515 throw OptionException(
1516 "bool-to-bv not supported with CBQI BV for quantified logics");
1517 }
1518 Notice() << "SmtEngine: turning off bool-to-bitvector to support CBQI BV"
1519 << endl;
1520 options::boolToBitvector.set(false);
1521 }
1522
1523 // cases where we need produce models
1524 if (!options::produceModels()
1525 && (options::produceAssignments() || options::sygusRewSynthCheck()
1526 || options::sygusRepairConst()))
1527 {
1528 Notice() << "SmtEngine: turning on produce-models" << endl;
1529 setOption("produce-models", SExpr("true"));
1530 }
1531
1532 // Set the options for the theoryOf
1533 if(!options::theoryOfMode.wasSetByUser()) {
1534 if(d_logic.isSharingEnabled() &&
1535 !d_logic.isTheoryEnabled(THEORY_BV) &&
1536 !d_logic.isTheoryEnabled(THEORY_STRINGS) &&
1537 !d_logic.isTheoryEnabled(THEORY_SETS) ) {
1538 Trace("smt") << "setting theoryof-mode to term-based" << endl;
1539 options::theoryOfMode.set(THEORY_OF_TERM_BASED);
1540 }
1541 }
1542
1543 // strings require LIA, UF; widen the logic
1544 if(d_logic.isTheoryEnabled(THEORY_STRINGS)) {
1545 LogicInfo log(d_logic.getUnlockedCopy());
1546 // Strings requires arith for length constraints, and also UF
1547 if(!d_logic.isTheoryEnabled(THEORY_UF)) {
1548 Trace("smt") << "because strings are enabled, also enabling UF" << endl;
1549 log.enableTheory(THEORY_UF);
1550 }
1551 if(!d_logic.isTheoryEnabled(THEORY_ARITH) || d_logic.isDifferenceLogic() || !d_logic.areIntegersUsed()) {
1552 Trace("smt") << "because strings are enabled, also enabling linear integer arithmetic" << endl;
1553 log.enableTheory(THEORY_ARITH);
1554 log.enableIntegers();
1555 log.arithOnlyLinear();
1556 }
1557 d_logic = log;
1558 d_logic.lock();
1559 }
1560 if(d_logic.isTheoryEnabled(THEORY_ARRAYS) || d_logic.isTheoryEnabled(THEORY_DATATYPES) || d_logic.isTheoryEnabled(THEORY_SETS)) {
1561 if(!d_logic.isTheoryEnabled(THEORY_UF)) {
1562 LogicInfo log(d_logic.getUnlockedCopy());
1563 Trace("smt") << "because a theory that permits Boolean terms is enabled, also enabling UF" << endl;
1564 log.enableTheory(THEORY_UF);
1565 d_logic = log;
1566 d_logic.lock();
1567 }
1568 }
1569
1570 // by default, symmetry breaker is on only for QF_UF
1571 if(! options::ufSymmetryBreaker.wasSetByUser()) {
1572 bool qf_uf = d_logic.isPure(THEORY_UF) && !d_logic.isQuantified() && !options::proof();
1573 Trace("smt") << "setting uf symmetry breaker to " << qf_uf << endl;
1574 options::ufSymmetryBreaker.set(qf_uf);
1575 }
1576 // by default, nonclausal simplification is off for QF_SAT
1577 if(! options::simplificationMode.wasSetByUser()) {
1578 bool qf_sat = d_logic.isPure(THEORY_BOOL) && !d_logic.isQuantified();
1579 Trace("smt") << "setting simplification mode to <" << d_logic.getLogicString() << "> " << (!qf_sat) << endl;
1580 //simplification=none works better for SMT LIB benchmarks with quantifiers, not others
1581 //options::simplificationMode.set(qf_sat || quantifiers ? SIMPLIFICATION_MODE_NONE : SIMPLIFICATION_MODE_BATCH);
1582 options::simplificationMode.set(qf_sat ? SIMPLIFICATION_MODE_NONE : SIMPLIFICATION_MODE_BATCH);
1583 }
1584
1585 // If in arrays, set the UF handler to arrays
1586 if(d_logic.isTheoryEnabled(THEORY_ARRAYS) && ( !d_logic.isQuantified() ||
1587 (d_logic.isQuantified() && !d_logic.isTheoryEnabled(THEORY_UF)))) {
1588 Theory::setUninterpretedSortOwner(THEORY_ARRAYS);
1589 } else {
1590 Theory::setUninterpretedSortOwner(THEORY_UF);
1591 }
1592
1593 // Turn on ite simplification for QF_LIA and QF_AUFBV
1594 // WARNING: These checks match much more than just QF_AUFBV and
1595 // QF_LIA logics. --K [2014/10/15]
1596 if(! options::doITESimp.wasSetByUser()) {
1597 bool qf_aufbv = !d_logic.isQuantified() &&
1598 d_logic.isTheoryEnabled(THEORY_ARRAYS) &&
1599 d_logic.isTheoryEnabled(THEORY_UF) &&
1600 d_logic.isTheoryEnabled(THEORY_BV);
1601 bool qf_lia = !d_logic.isQuantified() &&
1602 d_logic.isPure(THEORY_ARITH) &&
1603 d_logic.isLinear() &&
1604 !d_logic.isDifferenceLogic() &&
1605 !d_logic.areRealsUsed();
1606
1607 bool iteSimp = (qf_aufbv || qf_lia);
1608 Trace("smt") << "setting ite simplification to " << iteSimp << endl;
1609 options::doITESimp.set(iteSimp);
1610 }
1611 if(! options::compressItes.wasSetByUser() ){
1612 bool qf_lia = !d_logic.isQuantified() &&
1613 d_logic.isPure(THEORY_ARITH) &&
1614 d_logic.isLinear() &&
1615 !d_logic.isDifferenceLogic() &&
1616 !d_logic.areRealsUsed();
1617
1618 bool compressIte = qf_lia;
1619 Trace("smt") << "setting ite compression to " << compressIte << endl;
1620 options::compressItes.set(compressIte);
1621 }
1622 if(! options::simplifyWithCareEnabled.wasSetByUser() ){
1623 bool qf_aufbv = !d_logic.isQuantified() &&
1624 d_logic.isTheoryEnabled(THEORY_ARRAYS) &&
1625 d_logic.isTheoryEnabled(THEORY_UF) &&
1626 d_logic.isTheoryEnabled(THEORY_BV);
1627
1628 bool withCare = qf_aufbv;
1629 Trace("smt") << "setting ite simplify with care to " << withCare << endl;
1630 options::simplifyWithCareEnabled.set(withCare);
1631 }
1632 // Turn off array eager index splitting for QF_AUFLIA
1633 if(! options::arraysEagerIndexSplitting.wasSetByUser()) {
1634 if (not d_logic.isQuantified() &&
1635 d_logic.isTheoryEnabled(THEORY_ARRAYS) &&
1636 d_logic.isTheoryEnabled(THEORY_UF) &&
1637 d_logic.isTheoryEnabled(THEORY_ARITH)) {
1638 Trace("smt") << "setting array eager index splitting to false" << endl;
1639 options::arraysEagerIndexSplitting.set(false);
1640 }
1641 }
1642 // Turn on model-based arrays for QF_AX (unless models are enabled)
1643 // if(! options::arraysModelBased.wasSetByUser()) {
1644 // if (not d_logic.isQuantified() &&
1645 // d_logic.isTheoryEnabled(THEORY_ARRAYS) &&
1646 // d_logic.isPure(THEORY_ARRAYS) &&
1647 // !options::produceModels() &&
1648 // !options::checkModels()) {
1649 // Trace("smt") << "turning on model-based array solver" << endl;
1650 // options::arraysModelBased.set(true);
1651 // }
1652 // }
1653 // Turn on multiple-pass non-clausal simplification for QF_AUFBV
1654 if(! options::repeatSimp.wasSetByUser()) {
1655 bool repeatSimp = !d_logic.isQuantified() &&
1656 (d_logic.isTheoryEnabled(THEORY_ARRAYS) &&
1657 d_logic.isTheoryEnabled(THEORY_UF) &&
1658 d_logic.isTheoryEnabled(THEORY_BV)) &&
1659 !options::unsatCores();
1660 Trace("smt") << "setting repeat simplification to " << repeatSimp << endl;
1661 options::repeatSimp.set(repeatSimp);
1662 }
1663 // Turn on unconstrained simplification for QF_AUFBV
1664 if(!options::unconstrainedSimp.wasSetByUser() ||
1665 options::incrementalSolving()) {
1666 // bool qf_sat = d_logic.isPure(THEORY_BOOL) && !d_logic.isQuantified();
1667 // bool uncSimp = false && !qf_sat && !options::incrementalSolving();
1668 bool uncSimp = !options::incrementalSolving() &&
1669 !d_logic.isQuantified() &&
1670 !options::produceModels() &&
1671 !options::produceAssignments() &&
1672 !options::checkModels() &&
1673 !options::unsatCores() &&
1674 (d_logic.isTheoryEnabled(THEORY_ARRAYS) && d_logic.isTheoryEnabled(THEORY_BV));
1675 Trace("smt") << "setting unconstrained simplification to " << uncSimp << endl;
1676 options::unconstrainedSimp.set(uncSimp);
1677 }
1678 // Unconstrained simp currently does *not* support model generation
1679 if (options::unconstrainedSimp.wasSetByUser() && options::unconstrainedSimp()) {
1680 if (options::produceModels()) {
1681 if (options::produceModels.wasSetByUser()) {
1682 throw OptionException("Cannot use unconstrained-simp with model generation.");
1683 }
1684 Notice() << "SmtEngine: turning off produce-models to support unconstrainedSimp" << endl;
1685 setOption("produce-models", SExpr("false"));
1686 }
1687 if (options::produceAssignments()) {
1688 if (options::produceAssignments.wasSetByUser()) {
1689 throw OptionException("Cannot use unconstrained-simp with model generation (produce-assignments).");
1690 }
1691 Notice() << "SmtEngine: turning off produce-assignments to support unconstrainedSimp" << endl;
1692 setOption("produce-assignments", SExpr("false"));
1693 }
1694 if (options::checkModels()) {
1695 if (options::checkModels.wasSetByUser()) {
1696 throw OptionException("Cannot use unconstrained-simp with model generation (check-models).");
1697 }
1698 Notice() << "SmtEngine: turning off check-models to support unconstrainedSimp" << endl;
1699 setOption("check-models", SExpr("false"));
1700 }
1701 }
1702
1703 if (! options::bvEagerExplanations.wasSetByUser() &&
1704 d_logic.isTheoryEnabled(THEORY_ARRAYS) &&
1705 d_logic.isTheoryEnabled(THEORY_BV)) {
1706 Trace("smt") << "enabling eager bit-vector explanations " << endl;
1707 options::bvEagerExplanations.set(true);
1708 }
1709
1710 if( !options::bitvectorEqualitySolver() ){
1711 Trace("smt") << "disabling bvLazyRewriteExtf since equality solver is disabled" << endl;
1712 options::bvLazyRewriteExtf.set(false);
1713 }
1714
1715 // Turn on arith rewrite equalities only for pure arithmetic
1716 if(! options::arithRewriteEq.wasSetByUser()) {
1717 bool arithRewriteEq = d_logic.isPure(THEORY_ARITH) && d_logic.isLinear() && !d_logic.isQuantified();
1718 Trace("smt") << "setting arith rewrite equalities " << arithRewriteEq << endl;
1719 options::arithRewriteEq.set(arithRewriteEq);
1720 }
1721 if(! options::arithHeuristicPivots.wasSetByUser()) {
1722 int16_t heuristicPivots = 5;
1723 if(d_logic.isPure(THEORY_ARITH) && !d_logic.isQuantified()) {
1724 if(d_logic.isDifferenceLogic()) {
1725 heuristicPivots = -1;
1726 } else if(!d_logic.areIntegersUsed()) {
1727 heuristicPivots = 0;
1728 }
1729 }
1730 Trace("smt") << "setting arithHeuristicPivots " << heuristicPivots << endl;
1731 options::arithHeuristicPivots.set(heuristicPivots);
1732 }
1733 if(! options::arithPivotThreshold.wasSetByUser()){
1734 uint16_t pivotThreshold = 2;
1735 if(d_logic.isPure(THEORY_ARITH) && !d_logic.isQuantified()){
1736 if(d_logic.isDifferenceLogic()){
1737 pivotThreshold = 16;
1738 }
1739 }
1740 Trace("smt") << "setting arith arithPivotThreshold " << pivotThreshold << endl;
1741 options::arithPivotThreshold.set(pivotThreshold);
1742 }
1743 if(! options::arithStandardCheckVarOrderPivots.wasSetByUser()){
1744 int16_t varOrderPivots = -1;
1745 if(d_logic.isPure(THEORY_ARITH) && !d_logic.isQuantified()){
1746 varOrderPivots = 200;
1747 }
1748 Trace("smt") << "setting arithStandardCheckVarOrderPivots " << varOrderPivots << endl;
1749 options::arithStandardCheckVarOrderPivots.set(varOrderPivots);
1750 }
1751 // Turn off early theory preprocessing if arithRewriteEq is on
1752 if (options::arithRewriteEq()) {
1753 d_earlyTheoryPP = false;
1754 }
1755 if (d_logic.isPure(THEORY_ARITH) && !d_logic.areRealsUsed())
1756 {
1757 if (!options::nlExtTangentPlanesInterleave.wasSetByUser())
1758 {
1759 Trace("smt") << "setting nlExtTangentPlanesInterleave to true" << endl;
1760 options::nlExtTangentPlanesInterleave.set(true);
1761 }
1762 }
1763
1764 // Set decision mode based on logic (if not set by user)
1765 if(!options::decisionMode.wasSetByUser()) {
1766 decision::DecisionMode decMode =
1767 // ALL
1768 d_logic.hasEverything() ? decision::DECISION_STRATEGY_JUSTIFICATION :
1769 ( // QF_BV
1770 (not d_logic.isQuantified() &&
1771 d_logic.isPure(THEORY_BV)
1772 ) ||
1773 // QF_AUFBV or QF_ABV or QF_UFBV
1774 (not d_logic.isQuantified() &&
1775 (d_logic.isTheoryEnabled(THEORY_ARRAYS) ||
1776 d_logic.isTheoryEnabled(THEORY_UF)) &&
1777 d_logic.isTheoryEnabled(THEORY_BV)
1778 ) ||
1779 // QF_AUFLIA (and may be ends up enabling QF_AUFLRA?)
1780 (not d_logic.isQuantified() &&
1781 d_logic.isTheoryEnabled(THEORY_ARRAYS) &&
1782 d_logic.isTheoryEnabled(THEORY_UF) &&
1783 d_logic.isTheoryEnabled(THEORY_ARITH)
1784 ) ||
1785 // QF_LRA
1786 (not d_logic.isQuantified() &&
1787 d_logic.isPure(THEORY_ARITH) && d_logic.isLinear() && !d_logic.isDifferenceLogic() && !d_logic.areIntegersUsed()
1788 ) ||
1789 // Quantifiers
1790 d_logic.isQuantified() ||
1791 // Strings
1792 d_logic.isTheoryEnabled(THEORY_STRINGS)
1793 ? decision::DECISION_STRATEGY_JUSTIFICATION
1794 : decision::DECISION_STRATEGY_INTERNAL
1795 );
1796
1797 bool stoponly =
1798 // ALL
1799 d_logic.hasEverything() || d_logic.isTheoryEnabled(THEORY_STRINGS) ? false :
1800 ( // QF_AUFLIA
1801 (not d_logic.isQuantified() &&
1802 d_logic.isTheoryEnabled(THEORY_ARRAYS) &&
1803 d_logic.isTheoryEnabled(THEORY_UF) &&
1804 d_logic.isTheoryEnabled(THEORY_ARITH)
1805 ) ||
1806 // QF_LRA
1807 (not d_logic.isQuantified() &&
1808 d_logic.isPure(THEORY_ARITH) && d_logic.isLinear() && !d_logic.isDifferenceLogic() && !d_logic.areIntegersUsed()
1809 )
1810 ? true : false
1811 );
1812
1813 Trace("smt") << "setting decision mode to " << decMode << endl;
1814 options::decisionMode.set(decMode);
1815 options::decisionStopOnly.set(stoponly);
1816 }
1817 if( options::incrementalSolving() ){
1818 //disable modes not supported by incremental
1819 options::sortInference.set( false );
1820 options::ufssFairnessMonotone.set( false );
1821 options::quantEpr.set( false );
1822 options::globalNegate.set(false);
1823 }
1824 if( d_logic.hasCardinalityConstraints() ){
1825 //must have finite model finding on
1826 options::finiteModelFind.set( true );
1827 }
1828
1829 //if it contains a theory with non-termination, do not strictly enforce that quantifiers and theory combination must be interleaved
1830 if( d_logic.isTheoryEnabled(THEORY_STRINGS) || (d_logic.isTheoryEnabled(THEORY_ARITH) && !d_logic.isLinear()) ){
1831 if( !options::instWhenStrictInterleave.wasSetByUser() ){
1832 options::instWhenStrictInterleave.set( false );
1833 }
1834 }
1835
1836 //local theory extensions
1837 if( options::localTheoryExt() ){
1838 if( !options::instMaxLevel.wasSetByUser() ){
1839 options::instMaxLevel.set( 0 );
1840 }
1841 }
1842 if( options::instMaxLevel()!=-1 ){
1843 Notice() << "SmtEngine: turning off cbqi to support instMaxLevel" << endl;
1844 options::cbqi.set(false);
1845 }
1846 //track instantiations?
1847 if( options::cbqiNestedQE() || ( options::proof() && !options::trackInstLemmas.wasSetByUser() ) ){
1848 options::trackInstLemmas.set( true );
1849 }
1850
1851 if( ( options::fmfBoundLazy.wasSetByUser() && options::fmfBoundLazy() ) ||
1852 ( options::fmfBoundInt.wasSetByUser() && options::fmfBoundInt() ) ) {
1853 options::fmfBound.set( true );
1854 }
1855 //now have determined whether fmfBoundInt is on/off
1856 //apply fmfBoundInt options
1857 if( options::fmfBound() ){
1858 //must have finite model finding on
1859 options::finiteModelFind.set( true );
1860 if( ! options::mbqiMode.wasSetByUser() ||
1861 ( options::mbqiMode()!=quantifiers::MBQI_NONE &&
1862 options::mbqiMode()!=quantifiers::MBQI_FMC &&
1863 options::mbqiMode()!=quantifiers::MBQI_FMC_INTERVAL ) ){
1864 //if bounded integers are set, use no MBQI by default
1865 options::mbqiMode.set( quantifiers::MBQI_NONE );
1866 }
1867 if( ! options::prenexQuant.wasSetByUser() ){
1868 options::prenexQuant.set( quantifiers::PRENEX_QUANT_NONE );
1869 }
1870 }
1871 if( options::ufHo() ){
1872 //if higher-order, then current variants of model-based instantiation cannot be used
1873 if( options::mbqiMode()!=quantifiers::MBQI_NONE ){
1874 options::mbqiMode.set( quantifiers::MBQI_NONE );
1875 }
1876 }
1877 if( options::mbqiMode()==quantifiers::MBQI_ABS ){
1878 if( !d_logic.isPure(THEORY_UF) ){
1879 //MBQI_ABS is only supported in pure quantified UF
1880 options::mbqiMode.set( quantifiers::MBQI_FMC );
1881 }
1882 }
1883 if( options::fmfFunWellDefinedRelevant() ){
1884 if( !options::fmfFunWellDefined.wasSetByUser() ){
1885 options::fmfFunWellDefined.set( true );
1886 }
1887 }
1888 if( options::fmfFunWellDefined() ){
1889 if( !options::finiteModelFind.wasSetByUser() ){
1890 options::finiteModelFind.set( true );
1891 }
1892 }
1893 //EPR
1894 if( options::quantEpr() ){
1895 if( !options::preSkolemQuant.wasSetByUser() ){
1896 options::preSkolemQuant.set( true );
1897 }
1898 }
1899
1900 //now, have determined whether finite model find is on/off
1901 //apply finite model finding options
1902 if( options::finiteModelFind() ){
1903 //apply conservative quantifiers splitting
1904 if( !options::quantDynamicSplit.wasSetByUser() ){
1905 options::quantDynamicSplit.set( quantifiers::QUANT_DSPLIT_MODE_DEFAULT );
1906 }
1907 //do not eliminate extended arithmetic symbols from quantified formulas
1908 if( !options::elimExtArithQuant.wasSetByUser() ){
1909 options::elimExtArithQuant.set( false );
1910 }
1911 if( !options::eMatching.wasSetByUser() ){
1912 options::eMatching.set( options::fmfInstEngine() );
1913 }
1914 if( !options::instWhenMode.wasSetByUser() ){
1915 //instantiate only on last call
1916 if( options::eMatching() ){
1917 options::instWhenMode.set( quantifiers::INST_WHEN_LAST_CALL );
1918 }
1919 }
1920 if( options::mbqiMode()==quantifiers::MBQI_ABS ){
1921 if( !options::preSkolemQuant.wasSetByUser() ){
1922 options::preSkolemQuant.set( true );
1923 }
1924 if( !options::preSkolemQuantNested.wasSetByUser() ){
1925 options::preSkolemQuantNested.set( true );
1926 }
1927 if( !options::fmfOneInstPerRound.wasSetByUser() ){
1928 options::fmfOneInstPerRound.set( true );
1929 }
1930 }
1931 }
1932
1933 //apply counterexample guided instantiation options
1934 // if we are attempting to rewrite everything to SyGuS, use ceGuidedInst
1935 if (options::sygusInference())
1936 {
1937 if (!options::ceGuidedInst.wasSetByUser())
1938 {
1939 options::ceGuidedInst.set(true);
1940 }
1941 // optimization: apply preskolemization, makes it succeed more often
1942 if (!options::preSkolemQuant.wasSetByUser())
1943 {
1944 options::preSkolemQuant.set(true);
1945 }
1946 if (!options::preSkolemQuantNested.wasSetByUser())
1947 {
1948 options::preSkolemQuantNested.set(true);
1949 }
1950 }
1951 if( options::cegqiSingleInvMode()!=quantifiers::CEGQI_SI_MODE_NONE ){
1952 if( !options::ceGuidedInst.wasSetByUser() ){
1953 options::ceGuidedInst.set( true );
1954 }
1955 }
1956 if( options::ceGuidedInst() ){
1957 //counterexample-guided instantiation for sygus
1958 if( !options::cegqiSingleInvMode.wasSetByUser() ){
1959 options::cegqiSingleInvMode.set( quantifiers::CEGQI_SI_MODE_USE );
1960 }
1961 if( !options::quantConflictFind.wasSetByUser() ){
1962 options::quantConflictFind.set( false );
1963 }
1964 if( !options::instNoEntail.wasSetByUser() ){
1965 options::instNoEntail.set( false );
1966 }
1967 if (options::sygusRew())
1968 {
1969 options::sygusRewSynth.set(true);
1970 options::sygusRewVerify.set(true);
1971 }
1972 if (options::sygusRewSynth() || options::sygusRewVerify())
1973 {
1974 // rewrite rule synthesis implies that sygus stream must be true
1975 options::sygusStream.set(true);
1976 }
1977 if (options::sygusStream())
1978 {
1979 // PBE and streaming modes are incompatible
1980 if (!options::sygusSymBreakPbe.wasSetByUser())
1981 {
1982 options::sygusSymBreakPbe.set(false);
1983 }
1984 if (!options::sygusUnifPbe.wasSetByUser())
1985 {
1986 options::sygusUnifPbe.set(false);
1987 }
1988 }
1989 //do not allow partial functions
1990 if( !options::bitvectorDivByZeroConst.wasSetByUser() ){
1991 options::bitvectorDivByZeroConst.set( true );
1992 }
1993 if( !options::dtRewriteErrorSel.wasSetByUser() ){
1994 options::dtRewriteErrorSel.set( true );
1995 }
1996 //do not miniscope
1997 if( !options::miniscopeQuant.wasSetByUser() ){
1998 options::miniscopeQuant.set( false );
1999 }
2000 if( !options::miniscopeQuantFreeVar.wasSetByUser() ){
2001 options::miniscopeQuantFreeVar.set( false );
2002 }
2003 //rewrite divk
2004 if( !options::rewriteDivk.wasSetByUser()) {
2005 options::rewriteDivk.set( true );
2006 }
2007 //do not do macros
2008 if( !options::macrosQuant.wasSetByUser()) {
2009 options::macrosQuant.set( false );
2010 }
2011 if( !options::cbqiPreRegInst.wasSetByUser()) {
2012 options::cbqiPreRegInst.set( true );
2013 }
2014 }
2015 //counterexample-guided instantiation for non-sygus
2016 // enable if any possible quantifiers with arithmetic, datatypes or bitvectors
2017 if( d_logic.isQuantified() &&
2018 ( ( options::decisionMode()!=decision::DECISION_STRATEGY_INTERNAL &&
2019 ( d_logic.isTheoryEnabled(THEORY_ARITH) || d_logic.isTheoryEnabled(THEORY_DATATYPES) || d_logic.isTheoryEnabled(THEORY_BV) ) ) ||
2020 d_logic.isPure(THEORY_ARITH) || d_logic.isPure(THEORY_BV) ||
2021 options::cbqiAll() ) ){
2022 if( !options::cbqi.wasSetByUser() ){
2023 options::cbqi.set( true );
2024 }
2025 // check whether we should apply full cbqi
2026 if (d_logic.isPure(THEORY_BV))
2027 {
2028 if (!options::cbqiFullEffort.wasSetByUser())
2029 {
2030 options::cbqiFullEffort.set(true);
2031 }
2032 }
2033 }
2034 if( options::cbqi() ){
2035 //must rewrite divk
2036 if( !options::rewriteDivk.wasSetByUser()) {
2037 options::rewriteDivk.set( true );
2038 }
2039 if (d_logic.isPure(THEORY_ARITH) || d_logic.isPure(THEORY_BV))
2040 {
2041 options::cbqiAll.set( false );
2042 if( !options::quantConflictFind.wasSetByUser() ){
2043 options::quantConflictFind.set( false );
2044 }
2045 if( !options::instNoEntail.wasSetByUser() ){
2046 options::instNoEntail.set( false );
2047 }
2048 if( !options::instWhenMode.wasSetByUser() && options::cbqiModel() ){
2049 //only instantiation should happen at last call when model is avaiable
2050 options::instWhenMode.set( quantifiers::INST_WHEN_LAST_CALL );
2051 }
2052 }else{
2053 // only supported in pure arithmetic or pure BV
2054 options::cbqiNestedQE.set(false);
2055 }
2056 // prenexing
2057 if (options::cbqiNestedQE()
2058 || options::decisionMode() == decision::DECISION_STRATEGY_INTERNAL)
2059 {
2060 // only complete with prenex = disj_normal or normal
2061 if (options::prenexQuant() <= quantifiers::PRENEX_QUANT_DISJ_NORMAL)
2062 {
2063 options::prenexQuant.set(quantifiers::PRENEX_QUANT_DISJ_NORMAL);
2064 }
2065 }
2066 else if (options::globalNegate())
2067 {
2068 if (!options::prenexQuant.wasSetByUser())
2069 {
2070 options::prenexQuant.set(quantifiers::PRENEX_QUANT_NONE);
2071 }
2072 }
2073 }
2074 //implied options...
2075 if( options::strictTriggers() ){
2076 if( !options::userPatternsQuant.wasSetByUser() ){
2077 options::userPatternsQuant.set( quantifiers::USER_PAT_MODE_TRUST );
2078 }
2079 }
2080 if( options::qcfMode.wasSetByUser() || options::qcfTConstraint() ){
2081 options::quantConflictFind.set( true );
2082 }
2083 if( options::cbqiNestedQE() ){
2084 options::prenexQuantUser.set( true );
2085 if( !options::preSkolemQuant.wasSetByUser() ){
2086 options::preSkolemQuant.set( true );
2087 }
2088 }
2089 //for induction techniques
2090 if( options::quantInduction() ){
2091 if( !options::dtStcInduction.wasSetByUser() ){
2092 options::dtStcInduction.set( true );
2093 }
2094 if( !options::intWfInduction.wasSetByUser() ){
2095 options::intWfInduction.set( true );
2096 }
2097 }
2098 if( options::dtStcInduction() ){
2099 //try to remove ITEs from quantified formulas
2100 if( !options::iteDtTesterSplitQuant.wasSetByUser() ){
2101 options::iteDtTesterSplitQuant.set( true );
2102 }
2103 if( !options::iteLiftQuant.wasSetByUser() ){
2104 options::iteLiftQuant.set( quantifiers::ITE_LIFT_QUANT_MODE_ALL );
2105 }
2106 }
2107 if( options::intWfInduction() ){
2108 if( !options::purifyTriggers.wasSetByUser() ){
2109 options::purifyTriggers.set( true );
2110 }
2111 }
2112 if( options::conjectureNoFilter() ){
2113 if( !options::conjectureFilterActiveTerms.wasSetByUser() ){
2114 options::conjectureFilterActiveTerms.set( false );
2115 }
2116 if( !options::conjectureFilterCanonical.wasSetByUser() ){
2117 options::conjectureFilterCanonical.set( false );
2118 }
2119 if( !options::conjectureFilterModel.wasSetByUser() ){
2120 options::conjectureFilterModel.set( false );
2121 }
2122 }
2123 if( options::conjectureGenPerRound.wasSetByUser() ){
2124 if( options::conjectureGenPerRound()>0 ){
2125 options::conjectureGen.set( true );
2126 }else{
2127 options::conjectureGen.set( false );
2128 }
2129 }
2130 //can't pre-skolemize nested quantifiers without UF theory
2131 if( !d_logic.isTheoryEnabled(THEORY_UF) && options::preSkolemQuant() ){
2132 if( !options::preSkolemQuantNested.wasSetByUser() ){
2133 options::preSkolemQuantNested.set( false );
2134 }
2135 }
2136 if( !d_logic.isTheoryEnabled(THEORY_DATATYPES) ){
2137 options::quantDynamicSplit.set( quantifiers::QUANT_DSPLIT_MODE_NONE );
2138 }
2139
2140 //until bugs 371,431 are fixed
2141 if( ! options::minisatUseElim.wasSetByUser()){
2142 //AJR: cannot use minisat elim for new implementation of sets TODO: why?
2143 if( d_logic.isTheoryEnabled(THEORY_SETS) || d_logic.isQuantified() || options::produceModels() || options::produceAssignments() || options::checkModels() ){
2144 options::minisatUseElim.set( false );
2145 }
2146 }
2147 else if (options::minisatUseElim()) {
2148 if (options::produceModels()) {
2149 Notice() << "SmtEngine: turning off produce-models to support minisatUseElim" << endl;
2150 setOption("produce-models", SExpr("false"));
2151 }
2152 if (options::produceAssignments()) {
2153 Notice() << "SmtEngine: turning off produce-assignments to support minisatUseElim" << endl;
2154 setOption("produce-assignments", SExpr("false"));
2155 }
2156 if (options::checkModels()) {
2157 Notice() << "SmtEngine: turning off check-models to support minisatUseElim" << endl;
2158 setOption("check-models", SExpr("false"));
2159 }
2160 }
2161
2162 // For now, these array theory optimizations do not support model-building
2163 if (options::produceModels() || options::produceAssignments() || options::checkModels()) {
2164 options::arraysOptimizeLinear.set(false);
2165 options::arraysLazyRIntro1.set(false);
2166 }
2167
2168 // Non-linear arithmetic does not support models unless nlExt is enabled
2169 if ((d_logic.isTheoryEnabled(THEORY_ARITH) && !d_logic.isLinear()
2170 && !options::nlExt())
2171 || options::globalNegate())
2172 {
2173 std::string reason =
2174 options::globalNegate() ? "--global-negate" : "nonlinear arithmetic";
2175 if (options::produceModels()) {
2176 if(options::produceModels.wasSetByUser()) {
2177 throw OptionException(
2178 std::string("produce-model not supported with " + reason));
2179 }
2180 Warning()
2181 << "SmtEngine: turning off produce-models because unsupported for "
2182 << reason << endl;
2183 setOption("produce-models", SExpr("false"));
2184 }
2185 if (options::produceAssignments()) {
2186 if(options::produceAssignments.wasSetByUser()) {
2187 throw OptionException(
2188 std::string("produce-assignments not supported with " + reason));
2189 }
2190 Warning() << "SmtEngine: turning off produce-assignments because "
2191 "unsupported for "
2192 << reason << endl;
2193 setOption("produce-assignments", SExpr("false"));
2194 }
2195 if (options::checkModels()) {
2196 if(options::checkModels.wasSetByUser()) {
2197 throw OptionException(
2198 std::string("check-models not supported with " + reason));
2199 }
2200 Warning()
2201 << "SmtEngine: turning off check-models because unsupported for "
2202 << reason << endl;
2203 setOption("check-models", SExpr("false"));
2204 }
2205 }
2206
2207 if(options::incrementalSolving() && options::proof()) {
2208 Warning() << "SmtEngine: turning off incremental solving mode (not yet supported with --proof, try --tear-down-incremental instead)" << endl;
2209 setOption("incremental", SExpr("false"));
2210 }
2211
2212 if (options::proof())
2213 {
2214 if (options::bitvectorAlgebraicSolver())
2215 {
2216 if (options::bitvectorAlgebraicSolver.wasSetByUser())
2217 {
2218 throw OptionException(
2219 "--bv-algebraic-solver is not supported with proofs");
2220 }
2221 Notice() << "SmtEngine: turning off bv algebraic solver to support proofs"
2222 << std::endl;
2223 options::bitvectorAlgebraicSolver.set(false);
2224 }
2225 if (options::bitvectorEqualitySolver())
2226 {
2227 if (options::bitvectorEqualitySolver.wasSetByUser())
2228 {
2229 throw OptionException("--bv-eq-solver is not supported with proofs");
2230 }
2231 Notice() << "SmtEngine: turning off bv eq solver to support proofs"
2232 << std::endl;
2233 options::bitvectorEqualitySolver.set(false);
2234 }
2235 if (options::bitvectorInequalitySolver())
2236 {
2237 if (options::bitvectorInequalitySolver.wasSetByUser())
2238 {
2239 throw OptionException(
2240 "--bv-inequality-solver is not supported with proofs");
2241 }
2242 Notice() << "SmtEngine: turning off bv ineq solver to support proofs"
2243 << std::endl;
2244 options::bitvectorInequalitySolver.set(false);
2245 }
2246 }
2247 }
2248
2249 void SmtEngine::setProblemExtended(bool value)
2250 {
2251 d_problemExtended = value;
2252 if (value) { d_assumptions.clear(); }
2253 }
2254
2255 void SmtEngine::setInfo(const std::string& key, const CVC4::SExpr& value)
2256 {
2257 SmtScope smts(this);
2258
2259 Trace("smt") << "SMT setInfo(" << key << ", " << value << ")" << endl;
2260
2261 if(Dump.isOn("benchmark")) {
2262 if(key == "status") {
2263 string s = value.getValue();
2264 BenchmarkStatus status =
2265 (s == "sat") ? SMT_SATISFIABLE :
2266 ((s == "unsat") ? SMT_UNSATISFIABLE : SMT_UNKNOWN);
2267 Dump("benchmark") << SetBenchmarkStatusCommand(status);
2268 } else {
2269 Dump("benchmark") << SetInfoCommand(key, value);
2270 }
2271 }
2272
2273 // Check for CVC4-specific info keys (prefixed with "cvc4-" or "cvc4_")
2274 if(key.length() > 5) {
2275 string prefix = key.substr(0, 5);
2276 if(prefix == "cvc4-" || prefix == "cvc4_") {
2277 string cvc4key = key.substr(5);
2278 if(cvc4key == "logic") {
2279 if(! value.isAtom()) {
2280 throw OptionException("argument to (set-info :cvc4-logic ..) must be a string");
2281 }
2282 SmtScope smts(this);
2283 d_logic = value.getValue();
2284 setLogicInternal();
2285 return;
2286 } else {
2287 throw UnrecognizedOptionException();
2288 }
2289 }
2290 }
2291
2292 // Check for standard info keys (SMT-LIB v1, SMT-LIB v2, ...)
2293 if(key == "source" ||
2294 key == "category" ||
2295 key == "difficulty" ||
2296 key == "notes") {
2297 // ignore these
2298 return;
2299 } else if(key == "name") {
2300 d_filename = value.getValue();
2301 return;
2302 } else if(key == "smt-lib-version") {
2303 language::input::Language ilang = language::input::LANG_AUTO;
2304 if( (value.isInteger() && value.getIntegerValue() == Integer(2)) ||
2305 (value.isRational() && value.getRationalValue() == Rational(2)) ||
2306 value.getValue() == "2" ||
2307 value.getValue() == "2.0" ) {
2308 ilang = language::input::LANG_SMTLIB_V2_0;
2309 } else if( (value.isRational() && value.getRationalValue() == Rational(5, 2)) ||
2310 value.getValue() == "2.5" ) {
2311 ilang = language::input::LANG_SMTLIB_V2_5;
2312 } else if( (value.isRational() && value.getRationalValue() == Rational(13, 5)) ||
2313 value.getValue() == "2.6" ) {
2314 ilang = language::input::LANG_SMTLIB_V2_6;
2315 }
2316 else if (value.getValue() == "2.6.1")
2317 {
2318 ilang = language::input::LANG_SMTLIB_V2_6_1;
2319 }
2320 else
2321 {
2322 Warning() << "Warning: unsupported smt-lib-version: " << value << endl;
2323 throw UnrecognizedOptionException();
2324 }
2325 options::inputLanguage.set(ilang);
2326 // also update the output language
2327 if (!options::outputLanguage.wasSetByUser())
2328 {
2329 language::output::Language olang = language::toOutputLanguage(ilang);
2330 if (options::outputLanguage() != olang)
2331 {
2332 options::outputLanguage.set(olang);
2333 *options::out() << language::SetLanguage(olang);
2334 }
2335 }
2336 return;
2337 } else if(key == "status") {
2338 string s;
2339 if(value.isAtom()) {
2340 s = value.getValue();
2341 }
2342 if(s != "sat" && s != "unsat" && s != "unknown") {
2343 throw OptionException("argument to (set-info :status ..) must be "
2344 "`sat' or `unsat' or `unknown'");
2345 }
2346 d_status = Result(s, d_filename);
2347 return;
2348 }
2349 throw UnrecognizedOptionException();
2350 }
2351
2352 CVC4::SExpr SmtEngine::getInfo(const std::string& key) const {
2353
2354 SmtScope smts(this);
2355
2356 Trace("smt") << "SMT getInfo(" << key << ")" << endl;
2357 if(key == "all-statistics") {
2358 vector<SExpr> stats;
2359 for(StatisticsRegistry::const_iterator i = NodeManager::fromExprManager(d_exprManager)->getStatisticsRegistry()->begin();
2360 i != NodeManager::fromExprManager(d_exprManager)->getStatisticsRegistry()->end();
2361 ++i) {
2362 vector<SExpr> v;
2363 v.push_back((*i).first);
2364 v.push_back((*i).second);
2365 stats.push_back(v);
2366 }
2367 for(StatisticsRegistry::const_iterator i = d_statisticsRegistry->begin();
2368 i != d_statisticsRegistry->end();
2369 ++i) {
2370 vector<SExpr> v;
2371 v.push_back((*i).first);
2372 v.push_back((*i).second);
2373 stats.push_back(v);
2374 }
2375 return SExpr(stats);
2376 } else if(key == "error-behavior") {
2377 // immediate-exit | continued-execution
2378 if( options::continuedExecution() || options::interactive() ) {
2379 return SExpr(SExpr::Keyword("continued-execution"));
2380 } else {
2381 return SExpr(SExpr::Keyword("immediate-exit"));
2382 }
2383 } else if(key == "name") {
2384 return SExpr(Configuration::getName());
2385 } else if(key == "version") {
2386 return SExpr(Configuration::getVersionString());
2387 } else if(key == "authors") {
2388 return SExpr(Configuration::about());
2389 } else if(key == "status") {
2390 // sat | unsat | unknown
2391 switch(d_status.asSatisfiabilityResult().isSat()) {
2392 case Result::SAT:
2393 return SExpr(SExpr::Keyword("sat"));
2394 case Result::UNSAT:
2395 return SExpr(SExpr::Keyword("unsat"));
2396 default:
2397 return SExpr(SExpr::Keyword("unknown"));
2398 }
2399 } else if(key == "reason-unknown") {
2400 if(!d_status.isNull() && d_status.isUnknown()) {
2401 stringstream ss;
2402 ss << d_status.whyUnknown();
2403 string s = ss.str();
2404 transform(s.begin(), s.end(), s.begin(), ::tolower);
2405 return SExpr(SExpr::Keyword(s));
2406 } else {
2407 throw ModalException("Can't get-info :reason-unknown when the "
2408 "last result wasn't unknown!");
2409 }
2410 } else if(key == "assertion-stack-levels") {
2411 AlwaysAssert(d_userLevels.size() <=
2412 std::numeric_limits<unsigned long int>::max());
2413 return SExpr(static_cast<unsigned long int>(d_userLevels.size()));
2414 } else if(key == "all-options") {
2415 // get the options, like all-statistics
2416 std::vector< std::vector<std::string> > current_options =
2417 Options::current()->getOptions();
2418 return SExpr::parseListOfListOfAtoms(current_options);
2419 } else {
2420 throw UnrecognizedOptionException();
2421 }
2422 }
2423
2424 void SmtEngine::debugCheckFormals(const std::vector<Expr>& formals, Expr func)
2425 {
2426 for(std::vector<Expr>::const_iterator i = formals.begin(); i != formals.end(); ++i) {
2427 if((*i).getKind() != kind::BOUND_VARIABLE) {
2428 stringstream ss;
2429 ss << "All formal arguments to defined functions must be BOUND_VARIABLEs, but in the\n"
2430 << "definition of function " << func << ", formal\n"
2431 << " " << *i << "\n"
2432 << "has kind " << (*i).getKind();
2433 throw TypeCheckingException(func, ss.str());
2434 }
2435 }
2436 }
2437
2438 void SmtEngine::debugCheckFunctionBody(Expr formula,
2439 const std::vector<Expr>& formals,
2440 Expr func)
2441 {
2442 Type formulaType = formula.getType(options::typeChecking());
2443 Type funcType = func.getType();
2444 // We distinguish here between definitions of constants and functions,
2445 // because the type checking for them is subtly different. Perhaps we
2446 // should instead have SmtEngine::defineFunction() and
2447 // SmtEngine::defineConstant() for better clarity, although then that
2448 // doesn't match the SMT-LIBv2 standard...
2449 if(formals.size() > 0) {
2450 Type rangeType = FunctionType(funcType).getRangeType();
2451 if(! formulaType.isComparableTo(rangeType)) {
2452 stringstream ss;
2453 ss << "Type of defined function does not match its declaration\n"
2454 << "The function : " << func << "\n"
2455 << "Declared type : " << rangeType << "\n"
2456 << "The body : " << formula << "\n"
2457 << "Body type : " << formulaType;
2458 throw TypeCheckingException(func, ss.str());
2459 }
2460 } else {
2461 if(! formulaType.isComparableTo(funcType)) {
2462 stringstream ss;
2463 ss << "Declared type of defined constant does not match its definition\n"
2464 << "The constant : " << func << "\n"
2465 << "Declared type : " << funcType << " " << Type::getTypeNode(funcType)->getId() << "\n"
2466 << "The definition : " << formula << "\n"
2467 << "Definition type: " << formulaType << " " << Type::getTypeNode(formulaType)->getId();
2468 throw TypeCheckingException(func, ss.str());
2469 }
2470 }
2471 }
2472
2473 void SmtEngine::defineFunction(Expr func,
2474 const std::vector<Expr>& formals,
2475 Expr formula)
2476 {
2477 SmtScope smts(this);
2478 doPendingPops();
2479 Trace("smt") << "SMT defineFunction(" << func << ")" << endl;
2480 debugCheckFormals(formals, func);
2481
2482 stringstream ss;
2483 ss << language::SetLanguage(
2484 language::SetLanguage::getLanguage(Dump.getStream()))
2485 << func;
2486 DefineFunctionCommand c(ss.str(), func, formals, formula);
2487 addToModelCommandAndDump(
2488 c, ExprManager::VAR_FLAG_DEFINED, true, "declarations");
2489
2490 PROOF(if (options::checkUnsatCores()) {
2491 d_defineCommands.push_back(c.clone());
2492 });
2493
2494 // type check body
2495 debugCheckFunctionBody(formula, formals, func);
2496
2497 // Substitute out any abstract values in formula
2498 Expr form =
2499 d_private->substituteAbstractValues(Node::fromExpr(formula)).toExpr();
2500
2501 TNode funcNode = func.getTNode();
2502 vector<Node> formalsNodes;
2503 for(vector<Expr>::const_iterator i = formals.begin(),
2504 iend = formals.end();
2505 i != iend;
2506 ++i) {
2507 formalsNodes.push_back((*i).getNode());
2508 }
2509 TNode formNode = form.getTNode();
2510 DefinedFunction def(funcNode, formalsNodes, formNode);
2511 // Permit (check-sat) (define-fun ...) (get-value ...) sequences.
2512 // Otherwise, (check-sat) (get-value ((! foo :named bar))) breaks
2513 // d_haveAdditions = true;
2514 Debug("smt") << "definedFunctions insert " << funcNode << " " << formNode << endl;
2515 d_definedFunctions->insert(funcNode, def);
2516 }
2517
2518 void SmtEngine::defineFunctionsRec(
2519 const std::vector<Expr>& funcs,
2520 const std::vector<std::vector<Expr> >& formals,
2521 const std::vector<Expr>& formulas)
2522 {
2523 SmtScope smts(this);
2524 finalOptionsAreSet();
2525 doPendingPops();
2526 Trace("smt") << "SMT defineFunctionsRec(...)" << endl;
2527
2528 if (funcs.size() != formals.size() && funcs.size() != formulas.size())
2529 {
2530 stringstream ss;
2531 ss << "Number of functions, formals, and function bodies passed to "
2532 "defineFunctionsRec do not match:"
2533 << "\n"
2534 << " #functions : " << funcs.size() << "\n"
2535 << " #arg lists : " << formals.size() << "\n"
2536 << " #function bodies : " << formulas.size() << "\n";
2537 throw ModalException(ss.str());
2538 }
2539 for (unsigned i = 0, size = funcs.size(); i < size; i++)
2540 {
2541 // check formal argument list
2542 debugCheckFormals(formals[i], funcs[i]);
2543 // type check body
2544 debugCheckFunctionBody(formulas[i], formals[i], funcs[i]);
2545 }
2546
2547 if (Dump.isOn("raw-benchmark"))
2548 {
2549 Dump("raw-benchmark") << DefineFunctionRecCommand(funcs, formals, formulas);
2550 }
2551
2552 ExprManager* em = getExprManager();
2553 for (unsigned i = 0, size = funcs.size(); i < size; i++)
2554 {
2555 // we assert a quantified formula
2556 Expr func_app;
2557 // make the function application
2558 if (formals[i].empty())
2559 {
2560 // it has no arguments
2561 func_app = funcs[i];
2562 }
2563 else
2564 {
2565 std::vector<Expr> children;
2566 children.push_back(funcs[i]);
2567 children.insert(children.end(), formals[i].begin(), formals[i].end());
2568 func_app = em->mkExpr(kind::APPLY_UF, children);
2569 }
2570 Expr lem = em->mkExpr(kind::EQUAL, func_app, formulas[i]);
2571 if (!formals[i].empty())
2572 {
2573 // set the attribute to denote this is a function definition
2574 std::string attr_name("fun-def");
2575 Expr aexpr = em->mkExpr(kind::INST_ATTRIBUTE, func_app);
2576 aexpr = em->mkExpr(kind::INST_PATTERN_LIST, aexpr);
2577 std::vector<Expr> expr_values;
2578 std::string str_value;
2579 setUserAttribute(attr_name, func_app, expr_values, str_value);
2580 // make the quantified formula
2581 Expr boundVars = em->mkExpr(kind::BOUND_VAR_LIST, formals[i]);
2582 lem = em->mkExpr(kind::FORALL, boundVars, lem, aexpr);
2583 }
2584 // assert the quantified formula
2585 // notice we don't call assertFormula directly, since this would
2586 // duplicate the output on raw-benchmark.
2587 Expr e = d_private->substituteAbstractValues(Node::fromExpr(lem)).toExpr();
2588 if (d_assertionList != NULL)
2589 {
2590 d_assertionList->push_back(e);
2591 }
2592 d_private->addFormula(e.getNode(), false);
2593 }
2594 }
2595
2596 void SmtEngine::defineFunctionRec(Expr func,
2597 const std::vector<Expr>& formals,
2598 Expr formula)
2599 {
2600 std::vector<Expr> funcs;
2601 funcs.push_back(func);
2602 std::vector<std::vector<Expr> > formals_multi;
2603 formals_multi.push_back(formals);
2604 std::vector<Expr> formulas;
2605 formulas.push_back(formula);
2606 defineFunctionsRec(funcs, formals_multi, formulas);
2607 }
2608
2609 bool SmtEngine::isDefinedFunction( Expr func ){
2610 Node nf = Node::fromExpr( func );
2611 Debug("smt") << "isDefined function " << nf << "?" << std::endl;
2612 return d_definedFunctions->find(nf) != d_definedFunctions->end();
2613 }
2614
2615 void SmtEnginePrivate::finishInit() {
2616 d_preprocessingPassContext.reset(new PreprocessingPassContext(&d_smt));
2617 // TODO: register passes here (this will likely change when we add support for
2618 // actually assembling preprocessing pipelines).
2619 std::unique_ptr<BoolToBV> boolToBv(
2620 new BoolToBV(d_preprocessingPassContext.get()));
2621 std::unique_ptr<BVAckermann> bvAckermann(
2622 new BVAckermann(d_preprocessingPassContext.get()));
2623 std::unique_ptr<BvAbstraction> bvAbstract(
2624 new BvAbstraction(d_preprocessingPassContext.get()));
2625 std::unique_ptr<BVGauss> bvGauss(
2626 new BVGauss(d_preprocessingPassContext.get()));
2627 std::unique_ptr<BvIntroPow2> bvIntroPow2(
2628 new BvIntroPow2(d_preprocessingPassContext.get()));
2629 std::unique_ptr<BVToBool> bvToBool(
2630 new BVToBool(d_preprocessingPassContext.get()));
2631 std::unique_ptr<IntToBV> intToBV(
2632 new IntToBV(d_preprocessingPassContext.get()));
2633 std::unique_ptr<PseudoBooleanProcessor> pbProc(
2634 new PseudoBooleanProcessor(d_preprocessingPassContext.get()));
2635 std::unique_ptr<RealToInt> realToInt(
2636 new RealToInt(d_preprocessingPassContext.get()));
2637 std::unique_ptr<SymBreakerPass> sbProc(
2638 new SymBreakerPass(d_preprocessingPassContext.get()));
2639 d_preprocessingPassRegistry.registerPass("bool-to-bv", std::move(boolToBv));
2640 d_preprocessingPassRegistry.registerPass("bv-abstraction",
2641 std::move(bvAbstract));
2642 d_preprocessingPassRegistry.registerPass("bv-ackermann",
2643 std::move(bvAckermann));
2644 d_preprocessingPassRegistry.registerPass("bv-gauss", std::move(bvGauss));
2645 d_preprocessingPassRegistry.registerPass("bv-intro-pow2",
2646 std::move(bvIntroPow2));
2647 d_preprocessingPassRegistry.registerPass("bv-to-bool", std::move(bvToBool));
2648 d_preprocessingPassRegistry.registerPass("int-to-bv", std::move(intToBV));
2649 d_preprocessingPassRegistry.registerPass("pseudo-boolean-processor",
2650 std::move(pbProc));
2651 d_preprocessingPassRegistry.registerPass("real-to-int", std::move(realToInt));
2652 d_preprocessingPassRegistry.registerPass("sym-break", std::move(sbProc));
2653 }
2654
2655 Node SmtEnginePrivate::expandDefinitions(TNode n, unordered_map<Node, Node, NodeHashFunction>& cache, bool expandOnly)
2656 {
2657 stack< triple<Node, Node, bool> > worklist;
2658 stack<Node> result;
2659 worklist.push(make_triple(Node(n), Node(n), false));
2660 // The worklist is made of triples, each is input / original node then the output / rewritten node
2661 // and finally a flag tracking whether the children have been explored (i.e. if this is a downward
2662 // or upward pass).
2663
2664 do {
2665 spendResource(options::preprocessStep());
2666 n = worklist.top().first; // n is the input / original
2667 Node node = worklist.top().second; // node is the output / result
2668 bool childrenPushed = worklist.top().third;
2669 worklist.pop();
2670
2671 // Working downwards
2672 if(!childrenPushed) {
2673 Kind k = n.getKind();
2674
2675 // we can short circuit (variable) leaves
2676 if(n.isVar()) {
2677 SmtEngine::DefinedFunctionMap::const_iterator i = d_smt.d_definedFunctions->find(n);
2678 if(i != d_smt.d_definedFunctions->end()) {
2679 // replacement must be closed
2680 if((*i).second.getFormals().size() > 0) {
2681 result.push(d_smt.d_nodeManager->mkNode(kind::LAMBDA, d_smt.d_nodeManager->mkNode(kind::BOUND_VAR_LIST, (*i).second.getFormals()), (*i).second.getFormula()));
2682 continue;
2683 }
2684 // don't bother putting in the cache
2685 result.push((*i).second.getFormula());
2686 continue;
2687 }
2688 // don't bother putting in the cache
2689 result.push(n);
2690 continue;
2691 }
2692
2693 // maybe it's in the cache
2694 unordered_map<Node, Node, NodeHashFunction>::iterator cacheHit = cache.find(n);
2695 if(cacheHit != cache.end()) {
2696 TNode ret = (*cacheHit).second;
2697 result.push(ret.isNull() ? n : ret);
2698 continue;
2699 }
2700
2701 // otherwise expand it
2702 bool doExpand = k == kind::APPLY;
2703 if( !doExpand ){
2704 if( options::macrosQuant() ){
2705 //expand if we have inferred an operator corresponds to a defined function
2706 doExpand = k==kind::APPLY_UF && d_smt.isDefinedFunction( n.getOperator().toExpr() );
2707 }
2708 }
2709 if (doExpand) {
2710 vector<Node> formals;
2711 TNode fm;
2712 if( n.getOperator().getKind() == kind::LAMBDA ){
2713 TNode op = n.getOperator();
2714 // lambda
2715 for( unsigned i=0; i<op[0].getNumChildren(); i++ ){
2716 formals.push_back( op[0][i] );
2717 }
2718 fm = op[1];
2719 }else{
2720 // application of a user-defined symbol
2721 TNode func = n.getOperator();
2722 SmtEngine::DefinedFunctionMap::const_iterator i = d_smt.d_definedFunctions->find(func);
2723 if(i == d_smt.d_definedFunctions->end()) {
2724 throw TypeCheckingException(n.toExpr(), string("Undefined function: `") + func.toString() + "'");
2725 }
2726 DefinedFunction def = (*i).second;
2727 formals = def.getFormals();
2728
2729 if(Debug.isOn("expand")) {
2730 Debug("expand") << "found: " << n << endl;
2731 Debug("expand") << " func: " << func << endl;
2732 string name = func.getAttribute(expr::VarNameAttr());
2733 Debug("expand") << " : \"" << name << "\"" << endl;
2734 }
2735 if(Debug.isOn("expand")) {
2736 Debug("expand") << " defn: " << def.getFunction() << endl
2737 << " [";
2738 if(formals.size() > 0) {
2739 copy( formals.begin(), formals.end() - 1,
2740 ostream_iterator<Node>(Debug("expand"), ", ") );
2741 Debug("expand") << formals.back();
2742 }
2743 Debug("expand") << "]" << endl
2744 << " " << def.getFunction().getType() << endl
2745 << " " << def.getFormula() << endl;
2746 }
2747
2748 fm = def.getFormula();
2749 }
2750
2751 Node instance = fm.substitute(formals.begin(),
2752 formals.end(),
2753 n.begin(),
2754 n.begin() + formals.size());
2755 Debug("expand") << "made : " << instance << endl;
2756
2757 Node expanded = expandDefinitions(instance, cache, expandOnly);
2758 cache[n] = (n == expanded ? Node::null() : expanded);
2759 result.push(expanded);
2760 continue;
2761
2762 } else if(! expandOnly) {
2763 // do not do any theory stuff if expandOnly is true
2764
2765 theory::Theory* t = d_smt.d_theoryEngine->theoryOf(node);
2766
2767 Assert(t != NULL);
2768 LogicRequest req(d_smt);
2769 node = t->expandDefinition(req, n);
2770 }
2771
2772 // the partial functions can fall through, in which case we still
2773 // consider their children
2774 worklist.push(make_triple(Node(n), node, true)); // Original and rewritten result
2775
2776 for(size_t i = 0; i < node.getNumChildren(); ++i) {
2777 worklist.push(make_triple(node[i], node[i], false)); // Rewrite the children of the result only
2778 }
2779
2780 } else {
2781 // Working upwards
2782 // Reconstruct the node from it's (now rewritten) children on the stack
2783
2784 Debug("expand") << "cons : " << node << endl;
2785 if(node.getNumChildren()>0) {
2786 //cout << "cons : " << node << endl;
2787 NodeBuilder<> nb(node.getKind());
2788 if(node.getMetaKind() == kind::metakind::PARAMETERIZED) {
2789 Debug("expand") << "op : " << node.getOperator() << endl;
2790 //cout << "op : " << node.getOperator() << endl;
2791 nb << node.getOperator();
2792 }
2793 for(size_t i = 0; i < node.getNumChildren(); ++i) {
2794 Assert(!result.empty());
2795 Node expanded = result.top();
2796 result.pop();
2797 //cout << "exchld : " << expanded << endl;
2798 Debug("expand") << "exchld : " << expanded << endl;
2799 nb << expanded;
2800 }
2801 node = nb;
2802 }
2803 cache[n] = n == node ? Node::null() : node; // Only cache once all subterms are expanded
2804 result.push(node);
2805 }
2806 } while(!worklist.empty());
2807
2808 AlwaysAssert(result.size() == 1);
2809
2810 return result.top();
2811 }
2812
2813 typedef std::unordered_map<Node, Node, NodeHashFunction> NodeMap;
2814
2815 Node SmtEnginePrivate::purifyNlTerms(TNode n, NodeMap& cache, NodeMap& bcache, std::vector< Node >& var_eq, bool beneathMult) {
2816 if( beneathMult ){
2817 NodeMap::iterator find = bcache.find(n);
2818 if (find != bcache.end()) {
2819 return (*find).second;
2820 }
2821 }else{
2822 NodeMap::iterator find = cache.find(n);
2823 if (find != cache.end()) {
2824 return (*find).second;
2825 }
2826 }
2827 Node ret = n;
2828 if( n.getNumChildren()>0 ){
2829 if( beneathMult && n.getKind()!=kind::MULT ){
2830 //new variable
2831 ret = NodeManager::currentNM()->mkSkolem("__purifyNl_var", n.getType(), "Variable introduced in purifyNl pass");
2832 Node np = purifyNlTerms( n, cache, bcache, var_eq, false );
2833 var_eq.push_back( np.eqNode( ret ) );
2834 }else{
2835 bool beneathMultNew = beneathMult || n.getKind()==kind::MULT;
2836 bool childChanged = false;
2837 std::vector< Node > children;
2838 for( unsigned i=0; i<n.getNumChildren(); i++ ){
2839 Node nc = purifyNlTerms( n[i], cache, bcache, var_eq, beneathMultNew );
2840 childChanged = childChanged || nc!=n[i];
2841 children.push_back( nc );
2842 }
2843 if( childChanged ){
2844 ret = NodeManager::currentNM()->mkNode( n.getKind(), children );
2845 }
2846 }
2847 }
2848 if( beneathMult ){
2849 bcache[n] = ret;
2850 }else{
2851 cache[n] = ret;
2852 }
2853 return ret;
2854 }
2855
2856 void SmtEnginePrivate::removeITEs() {
2857 d_smt.finalOptionsAreSet();
2858 spendResource(options::preprocessStep());
2859 Trace("simplify") << "SmtEnginePrivate::removeITEs()" << endl;
2860
2861 // Remove all of the ITE occurrences and normalize
2862 d_iteRemover.run(d_assertions.ref(), d_iteSkolemMap, true);
2863 for (unsigned i = 0; i < d_assertions.size(); ++ i) {
2864 d_assertions.replace(i, Rewriter::rewrite(d_assertions[i]));
2865 }
2866 }
2867
2868 void SmtEnginePrivate::staticLearning() {
2869 d_smt.finalOptionsAreSet();
2870 spendResource(options::preprocessStep());
2871
2872 TimerStat::CodeTimer staticLearningTimer(d_smt.d_stats->d_staticLearningTime);
2873
2874 Trace("simplify") << "SmtEnginePrivate::staticLearning()" << endl;
2875
2876 for (unsigned i = 0; i < d_assertions.size(); ++ i) {
2877
2878 NodeBuilder<> learned(kind::AND);
2879 learned << d_assertions[i];
2880 d_smt.d_theoryEngine->ppStaticLearn(d_assertions[i], learned);
2881 if(learned.getNumChildren() == 1) {
2882 learned.clear();
2883 } else {
2884 d_assertions.replace(i, learned);
2885 }
2886 }
2887 }
2888
2889 // do dumping (before/after any preprocessing pass)
2890 static void dumpAssertions(const char* key,
2891 const AssertionPipeline& assertionList) {
2892 if( Dump.isOn("assertions") &&
2893 Dump.isOn(string("assertions:") + key) ) {
2894 // Push the simplified assertions to the dump output stream
2895 for(unsigned i = 0; i < assertionList.size(); ++ i) {
2896 TNode n = assertionList[i];
2897 Dump("assertions") << AssertCommand(Expr(n.toExpr()));
2898 }
2899 }
2900 }
2901
2902 // returns false if it learns a conflict
2903 bool SmtEnginePrivate::nonClausalSimplify() {
2904 spendResource(options::preprocessStep());
2905 d_smt.finalOptionsAreSet();
2906
2907 if(options::unsatCores() || options::fewerPreprocessingHoles()) {
2908 return true;
2909 }
2910
2911 TimerStat::CodeTimer nonclausalTimer(d_smt.d_stats->d_nonclausalSimplificationTime);
2912
2913 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify()" << endl;
2914 for (unsigned i = 0; i < d_assertions.size(); ++ i) {
2915 Trace("simplify") << "Assertion #" << i << " : " << d_assertions[i] << std::endl;
2916 }
2917
2918 if(d_propagatorNeedsFinish) {
2919 d_propagator.finish();
2920 d_propagatorNeedsFinish = false;
2921 }
2922 d_propagator.initialize();
2923
2924 // Assert all the assertions to the propagator
2925 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
2926 << "asserting to propagator" << endl;
2927 for (unsigned i = 0; i < d_assertions.size(); ++ i) {
2928 Assert(Rewriter::rewrite(d_assertions[i]) == d_assertions[i]);
2929 // Don't reprocess substitutions
2930 if (d_substitutionsIndex > 0 && i == d_substitutionsIndex) {
2931 continue;
2932 }
2933 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): asserting " << d_assertions[i] << endl;
2934 Debug("cores") << "d_propagator assertTrue: " << d_assertions[i] << std::endl;
2935 d_propagator.assertTrue(d_assertions[i]);
2936 }
2937
2938 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
2939 << "propagating" << endl;
2940 if (d_propagator.propagate()) {
2941 // If in conflict, just return false
2942 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
2943 << "conflict in non-clausal propagation" << endl;
2944 Node falseNode = NodeManager::currentNM()->mkConst<bool>(false);
2945 Assert(!options::unsatCores() && !options::fewerPreprocessingHoles());
2946 d_assertions.clear();
2947 addFormula(falseNode, false, false);
2948 d_propagatorNeedsFinish = true;
2949 return false;
2950 }
2951
2952
2953 Trace("simplify") << "Iterate through " << d_nonClausalLearnedLiterals.size() << " learned literals." << std::endl;
2954 // No conflict, go through the literals and solve them
2955 SubstitutionMap constantPropagations(d_smt.d_context);
2956 SubstitutionMap newSubstitutions(d_smt.d_context);
2957 SubstitutionMap::iterator pos;
2958 unsigned j = 0;
2959 for(unsigned i = 0, i_end = d_nonClausalLearnedLiterals.size(); i < i_end; ++ i) {
2960 // Simplify the literal we learned wrt previous substitutions
2961 Node learnedLiteral = d_nonClausalLearnedLiterals[i];
2962 Assert(Rewriter::rewrite(learnedLiteral) == learnedLiteral);
2963 Assert(d_topLevelSubstitutions.apply(learnedLiteral) == learnedLiteral);
2964 Trace("simplify") << "Process learnedLiteral : " << learnedLiteral << std::endl;
2965 Node learnedLiteralNew = newSubstitutions.apply(learnedLiteral);
2966 if (learnedLiteral != learnedLiteralNew) {
2967 learnedLiteral = Rewriter::rewrite(learnedLiteralNew);
2968 }
2969 Trace("simplify") << "Process learnedLiteral, after newSubs : " << learnedLiteral << std::endl;
2970 for (;;) {
2971 learnedLiteralNew = constantPropagations.apply(learnedLiteral);
2972 if (learnedLiteralNew == learnedLiteral) {
2973 break;
2974 }
2975 ++d_smt.d_stats->d_numConstantProps;
2976 learnedLiteral = Rewriter::rewrite(learnedLiteralNew);
2977 }
2978 Trace("simplify") << "Process learnedLiteral, after constProp : " << learnedLiteral << std::endl;
2979 // It might just simplify to a constant
2980 if (learnedLiteral.isConst()) {
2981 if (learnedLiteral.getConst<bool>()) {
2982 // If the learned literal simplifies to true, it's redundant
2983 continue;
2984 } else {
2985 // If the learned literal simplifies to false, we're in conflict
2986 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
2987 << "conflict with "
2988 << d_nonClausalLearnedLiterals[i] << endl;
2989 Assert(!options::unsatCores());
2990 d_assertions.clear();
2991 addFormula(NodeManager::currentNM()->mkConst<bool>(false), false, false);
2992 d_propagatorNeedsFinish = true;
2993 return false;
2994 }
2995 }
2996
2997 // Solve it with the corresponding theory, possibly adding new
2998 // substitutions to newSubstitutions
2999 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
3000 << "solving " << learnedLiteral << endl;
3001
3002 Theory::PPAssertStatus solveStatus =
3003 d_smt.d_theoryEngine->solve(learnedLiteral, newSubstitutions);
3004
3005 switch (solveStatus) {
3006 case Theory::PP_ASSERT_STATUS_SOLVED: {
3007 // The literal should rewrite to true
3008 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
3009 << "solved " << learnedLiteral << endl;
3010 Assert(Rewriter::rewrite(newSubstitutions.apply(learnedLiteral)).isConst());
3011 // vector<pair<Node, Node> > equations;
3012 // constantPropagations.simplifyLHS(d_topLevelSubstitutions, equations, true);
3013 // if (equations.empty()) {
3014 // break;
3015 // }
3016 // Assert(equations[0].first.isConst() && equations[0].second.isConst() && equations[0].first != equations[0].second);
3017 // else fall through
3018 break;
3019 }
3020 case Theory::PP_ASSERT_STATUS_CONFLICT:
3021 // If in conflict, we return false
3022 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
3023 << "conflict while solving "
3024 << learnedLiteral << endl;
3025 Assert(!options::unsatCores());
3026 d_assertions.clear();
3027 addFormula(NodeManager::currentNM()->mkConst<bool>(false), false, false);
3028 d_propagatorNeedsFinish = true;
3029 return false;
3030 default:
3031 if (d_doConstantProp && learnedLiteral.getKind() == kind::EQUAL && (learnedLiteral[0].isConst() || learnedLiteral[1].isConst())) {
3032 // constant propagation
3033 TNode t;
3034 TNode c;
3035 if (learnedLiteral[0].isConst()) {
3036 t = learnedLiteral[1];
3037 c = learnedLiteral[0];
3038 }
3039 else {
3040 t = learnedLiteral[0];
3041 c = learnedLiteral[1];
3042 }
3043 Assert(!t.isConst());
3044 Assert(constantPropagations.apply(t) == t);
3045 Assert(d_topLevelSubstitutions.apply(t) == t);
3046 Assert(newSubstitutions.apply(t) == t);
3047 constantPropagations.addSubstitution(t, c);
3048 // vector<pair<Node,Node> > equations;
3049 // constantPropagations.simplifyLHS(t, c, equations, true);
3050 // if (!equations.empty()) {
3051 // Assert(equations[0].first.isConst() && equations[0].second.isConst() && equations[0].first != equations[0].second);
3052 // d_assertions.clear();
3053 // addFormula(NodeManager::currentNM()->mkConst<bool>(false), false, false);
3054 // return;
3055 // }
3056 // d_topLevelSubstitutions.simplifyRHS(constantPropagations);
3057 }
3058 else {
3059 // Keep the literal
3060 d_nonClausalLearnedLiterals[j++] = d_nonClausalLearnedLiterals[i];
3061 }
3062 break;
3063 }
3064 }
3065
3066 #ifdef CVC4_ASSERTIONS
3067 // NOTE: When debugging this code, consider moving this check inside of the
3068 // loop over d_nonClausalLearnedLiterals. This check has been moved outside
3069 // because it is costly for certain inputs (see bug 508).
3070 //
3071 // Check data structure invariants:
3072 // 1. for each lhs of d_topLevelSubstitutions, does not appear anywhere in rhs of d_topLevelSubstitutions or anywhere in constantPropagations
3073 // 2. each lhs of constantPropagations rewrites to itself
3074 // 3. if l -> r is a constant propagation and l is a subterm of l' with l' -> r' another constant propagation, then l'[l/r] -> r' should be a
3075 // constant propagation too
3076 // 4. each lhs of constantPropagations is different from each rhs
3077 for (pos = newSubstitutions.begin(); pos != newSubstitutions.end(); ++pos) {
3078 Assert((*pos).first.isVar());
3079 Assert(d_topLevelSubstitutions.apply((*pos).first) == (*pos).first);
3080 Assert(d_topLevelSubstitutions.apply((*pos).second) == (*pos).second);
3081 Assert(newSubstitutions.apply(newSubstitutions.apply((*pos).second)) == newSubstitutions.apply((*pos).second));
3082 }
3083 for (pos = constantPropagations.begin(); pos != constantPropagations.end(); ++pos) {
3084 Assert((*pos).second.isConst());
3085 Assert(Rewriter::rewrite((*pos).first) == (*pos).first);
3086 // Node newLeft = d_topLevelSubstitutions.apply((*pos).first);
3087 // if (newLeft != (*pos).first) {
3088 // newLeft = Rewriter::rewrite(newLeft);
3089 // Assert(newLeft == (*pos).second ||
3090 // (constantPropagations.hasSubstitution(newLeft) && constantPropagations.apply(newLeft) == (*pos).second));
3091 // }
3092 // newLeft = constantPropagations.apply((*pos).first);
3093 // if (newLeft != (*pos).first) {
3094 // newLeft = Rewriter::rewrite(newLeft);
3095 // Assert(newLeft == (*pos).second ||
3096 // (constantPropagations.hasSubstitution(newLeft) && constantPropagations.apply(newLeft) == (*pos).second));
3097 // }
3098 Assert(constantPropagations.apply((*pos).second) == (*pos).second);
3099 }
3100 #endif /* CVC4_ASSERTIONS */
3101
3102 // Resize the learnt
3103 Trace("simplify") << "Resize non-clausal learned literals to " << j << std::endl;
3104 d_nonClausalLearnedLiterals.resize(j);
3105
3106 unordered_set<TNode, TNodeHashFunction> s;
3107 Trace("debugging") << "NonClausal simplify pre-preprocess\n";
3108 for (unsigned i = 0; i < d_assertions.size(); ++ i) {
3109 Node assertion = d_assertions[i];
3110 Node assertionNew = newSubstitutions.apply(assertion);
3111 Trace("debugging") << "assertion = " << assertion << endl;
3112 Trace("debugging") << "assertionNew = " << assertionNew << endl;
3113 if (assertion != assertionNew) {
3114 assertion = Rewriter::rewrite(assertionNew);
3115 Trace("debugging") << "rewrite(assertion) = " << assertion << endl;
3116 }
3117 Assert(Rewriter::rewrite(assertion) == assertion);
3118 for (;;) {
3119 assertionNew = constantPropagations.apply(assertion);
3120 if (assertionNew == assertion) {
3121 break;
3122 }
3123 ++d_smt.d_stats->d_numConstantProps;
3124 Trace("debugging") << "assertionNew = " << assertionNew << endl;
3125 assertion = Rewriter::rewrite(assertionNew);
3126 Trace("debugging") << "assertionNew = " << assertionNew << endl;
3127 }
3128 Trace("debugging") << "\n";
3129 s.insert(assertion);
3130 d_assertions.replace(i, assertion);
3131 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
3132 << "non-clausal preprocessed: "
3133 << assertion << endl;
3134 }
3135
3136 // If in incremental mode, add substitutions to the list of assertions
3137 if (d_substitutionsIndex > 0) {
3138 NodeBuilder<> substitutionsBuilder(kind::AND);
3139 substitutionsBuilder << d_assertions[d_substitutionsIndex];
3140 pos = newSubstitutions.begin();
3141 for (; pos != newSubstitutions.end(); ++pos) {
3142 // Add back this substitution as an assertion
3143 TNode lhs = (*pos).first, rhs = newSubstitutions.apply((*pos).second);
3144 Node n = NodeManager::currentNM()->mkNode(kind::EQUAL, lhs, rhs);
3145 substitutionsBuilder << n;
3146 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): will notify SAT layer of substitution: " << n << endl;
3147 }
3148 if (substitutionsBuilder.getNumChildren() > 1) {
3149 d_assertions.replace(d_substitutionsIndex,
3150 Rewriter::rewrite(Node(substitutionsBuilder)));
3151 }
3152 } else {
3153 // If not in incremental mode, must add substitutions to model
3154 TheoryModel* m = d_smt.d_theoryEngine->getModel();
3155 if(m != NULL) {
3156 for(pos = newSubstitutions.begin(); pos != newSubstitutions.end(); ++pos) {
3157 Node n = (*pos).first;
3158 Node v = newSubstitutions.apply((*pos).second);
3159 Trace("model") << "Add substitution : " << n << " " << v << endl;
3160 m->addSubstitution( n, v );
3161 }
3162 }
3163 }
3164
3165 NodeBuilder<> learnedBuilder(kind::AND);
3166 Assert(d_realAssertionsEnd <= d_assertions.size());
3167 learnedBuilder << d_assertions[d_realAssertionsEnd - 1];
3168
3169 for (unsigned i = 0; i < d_nonClausalLearnedLiterals.size(); ++ i) {
3170 Node learned = d_nonClausalLearnedLiterals[i];
3171 Assert(d_topLevelSubstitutions.apply(learned) == learned);
3172 Node learnedNew = newSubstitutions.apply(learned);
3173 if (learned != learnedNew) {
3174 learned = Rewriter::rewrite(learnedNew);
3175 }
3176 Assert(Rewriter::rewrite(learned) == learned);
3177 for (;;) {
3178 learnedNew = constantPropagations.apply(learned);
3179 if (learnedNew == learned) {
3180 break;
3181 }
3182 ++d_smt.d_stats->d_numConstantProps;
3183 learned = Rewriter::rewrite(learnedNew);
3184 }
3185 if (s.find(learned) != s.end()) {
3186 continue;
3187 }
3188 s.insert(learned);
3189 learnedBuilder << learned;
3190 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
3191 << "non-clausal learned : "
3192 << learned << endl;
3193 }
3194 d_nonClausalLearnedLiterals.clear();
3195
3196 for (pos = constantPropagations.begin(); pos != constantPropagations.end(); ++pos) {
3197 Node cProp = (*pos).first.eqNode((*pos).second);
3198 Assert(d_topLevelSubstitutions.apply(cProp) == cProp);
3199 Node cPropNew = newSubstitutions.apply(cProp);
3200 if (cProp != cPropNew) {
3201 cProp = Rewriter::rewrite(cPropNew);
3202 Assert(Rewriter::rewrite(cProp) == cProp);
3203 }
3204 if (s.find(cProp) != s.end()) {
3205 continue;
3206 }
3207 s.insert(cProp);
3208 learnedBuilder << cProp;
3209 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
3210 << "non-clausal constant propagation : "
3211 << cProp << endl;
3212 }
3213
3214 // Add new substitutions to topLevelSubstitutions
3215 // Note that we don't have to keep rhs's in full solved form
3216 // because SubstitutionMap::apply does a fixed-point iteration when substituting
3217 d_topLevelSubstitutions.addSubstitutions(newSubstitutions);
3218
3219 if(learnedBuilder.getNumChildren() > 1) {
3220 d_assertions.replace(d_realAssertionsEnd - 1,
3221 Rewriter::rewrite(Node(learnedBuilder)));
3222 }
3223
3224 d_propagatorNeedsFinish = true;
3225 return true;
3226 }
3227
3228 bool SmtEnginePrivate::simpITE() {
3229 TimerStat::CodeTimer simpITETimer(d_smt.d_stats->d_simpITETime);
3230
3231 spendResource(options::preprocessStep());
3232
3233 Trace("simplify") << "SmtEnginePrivate::simpITE()" << endl;
3234
3235 unsigned numAssertionOnEntry = d_assertions.size();
3236 for (unsigned i = 0; i < d_assertions.size(); ++i) {
3237 spendResource(options::preprocessStep());
3238 Node result = d_smt.d_theoryEngine->ppSimpITE(d_assertions[i]);
3239 d_assertions.replace(i, result);
3240 if(result.isConst() && !result.getConst<bool>()){
3241 return false;
3242 }
3243 }
3244 bool result = d_smt.d_theoryEngine->donePPSimpITE(d_assertions.ref());
3245 if(numAssertionOnEntry < d_assertions.size()){
3246 compressBeforeRealAssertions(numAssertionOnEntry);
3247 }
3248 return result;
3249 }
3250
3251 void SmtEnginePrivate::compressBeforeRealAssertions(size_t before){
3252 size_t curr = d_assertions.size();
3253 if(before >= curr ||
3254 d_realAssertionsEnd <= 0 ||
3255 d_realAssertionsEnd >= curr){
3256 return;
3257 }
3258
3259 // assertions
3260 // original: [0 ... d_realAssertionsEnd)
3261 // can be modified
3262 // ites skolems [d_realAssertionsEnd, before)
3263 // cannot be moved
3264 // added [before, curr)
3265 // can be modified
3266 Assert(0 < d_realAssertionsEnd);
3267 Assert(d_realAssertionsEnd <= before);
3268 Assert(before < curr);
3269
3270 std::vector<Node> intoConjunction;
3271 for(size_t i = before; i<curr; ++i){
3272 intoConjunction.push_back(d_assertions[i]);
3273 }
3274 d_assertions.resize(before);
3275 size_t lastBeforeItes = d_realAssertionsEnd - 1;
3276 intoConjunction.push_back(d_assertions[lastBeforeItes]);
3277 Node newLast = util::NaryBuilder::mkAssoc(kind::AND, intoConjunction);
3278 d_assertions.replace(lastBeforeItes, newLast);
3279 Assert(d_assertions.size() == before);
3280 }
3281
3282 void SmtEnginePrivate::unconstrainedSimp() {
3283 TimerStat::CodeTimer unconstrainedSimpTimer(d_smt.d_stats->d_unconstrainedSimpTime);
3284 spendResource(options::preprocessStep());
3285 Trace("simplify") << "SmtEnginePrivate::unconstrainedSimp()" << endl;
3286 d_smt.d_theoryEngine->ppUnconstrainedSimp(d_assertions.ref());
3287 }
3288
3289 void SmtEnginePrivate::traceBackToAssertions(const std::vector<Node>& nodes, std::vector<TNode>& assertions) {
3290 const booleans::CircuitPropagator::BackEdgesMap& backEdges = d_propagator.getBackEdges();
3291 for(vector<Node>::const_iterator i = nodes.begin(); i != nodes.end(); ++i) {
3292 booleans::CircuitPropagator::BackEdgesMap::const_iterator j = backEdges.find(*i);
3293 // term must appear in map, otherwise how did we get here?!
3294 Assert(j != backEdges.end());
3295 // if term maps to empty, that means it's a top-level assertion
3296 if(!(*j).second.empty()) {
3297 traceBackToAssertions((*j).second, assertions);
3298 } else {
3299 assertions.push_back(*i);
3300 }
3301 }
3302 }
3303
3304 size_t SmtEnginePrivate::removeFromConjunction(Node& n, const std::unordered_set<unsigned long>& toRemove) {
3305 Assert(n.getKind() == kind::AND);
3306 size_t removals = 0;
3307 for(Node::iterator j = n.begin(); j != n.end(); ++j) {
3308 size_t subremovals = 0;
3309 Node sub = *j;
3310 if(toRemove.find(sub.getId()) != toRemove.end() ||
3311 (sub.getKind() == kind::AND && (subremovals = removeFromConjunction(sub, toRemove)) > 0)) {
3312 NodeBuilder<> b(kind::AND);
3313 b.append(n.begin(), j);
3314 if(subremovals > 0) {
3315 removals += subremovals;
3316 b << sub;
3317 } else {
3318 ++removals;
3319 }
3320 for(++j; j != n.end(); ++j) {
3321 if(toRemove.find((*j).getId()) != toRemove.end()) {
3322 ++removals;
3323 } else if((*j).getKind() == kind::AND) {
3324 sub = *j;
3325 if((subremovals = removeFromConjunction(sub, toRemove)) > 0) {
3326 removals += subremovals;
3327 b << sub;
3328 } else {
3329 b << *j;
3330 }
3331 } else {
3332 b << *j;
3333 }
3334 }
3335 if(b.getNumChildren() == 0) {
3336 n = d_true;
3337 b.clear();
3338 } else if(b.getNumChildren() == 1) {
3339 n = b[0];
3340 b.clear();
3341 } else {
3342 n = b;
3343 }
3344 n = Rewriter::rewrite(n);
3345 return removals;
3346 }
3347 }
3348
3349 Assert(removals == 0);
3350 return 0;
3351 }
3352
3353 void SmtEnginePrivate::doMiplibTrick() {
3354 Assert(d_realAssertionsEnd == d_assertions.size());
3355 Assert(!options::incrementalSolving());
3356
3357 const booleans::CircuitPropagator::BackEdgesMap& backEdges = d_propagator.getBackEdges();
3358 unordered_set<unsigned long> removeAssertions;
3359
3360 NodeManager* nm = NodeManager::currentNM();
3361 Node zero = nm->mkConst(Rational(0)), one = nm->mkConst(Rational(1));
3362
3363 unordered_map<TNode, Node, TNodeHashFunction> intVars;
3364 for(vector<Node>::const_iterator i = d_boolVars.begin(); i != d_boolVars.end(); ++i) {
3365 if(d_propagator.isAssigned(*i)) {
3366 Debug("miplib") << "ineligible: " << *i << " because assigned " << d_propagator.getAssignment(*i) << endl;
3367 continue;
3368 }
3369
3370 vector<TNode> assertions;
3371 booleans::CircuitPropagator::BackEdgesMap::const_iterator j = backEdges.find(*i);
3372 // if not in back edges map, the bool var is unconstrained, showing up in no assertions.
3373 // if maps to an empty vector, that means the bool var was asserted itself.
3374 if(j != backEdges.end()) {
3375 if(!(*j).second.empty()) {
3376 traceBackToAssertions((*j).second, assertions);
3377 } else {
3378 assertions.push_back(*i);
3379 }
3380 }
3381 Debug("miplib") << "for " << *i << endl;
3382 bool eligible = true;
3383 map<pair<Node, Node>, uint64_t> marks;
3384 map<pair<Node, Node>, vector<Rational> > coef;
3385 map<pair<Node, Node>, vector<Rational> > checks;
3386 map<pair<Node, Node>, vector<TNode> > asserts;
3387 for(vector<TNode>::const_iterator j = assertions.begin(); j != assertions.end(); ++j) {
3388 Debug("miplib") << " found: " << *j << endl;
3389 if((*j).getKind() != kind::IMPLIES) {
3390 eligible = false;
3391 Debug("miplib") << " -- INELIGIBLE -- (not =>)" << endl;
3392 break;
3393 }
3394 Node conj = BooleanSimplification::simplify((*j)[0]);
3395 if(conj.getKind() == kind::AND && conj.getNumChildren() > 6) {
3396 eligible = false;
3397 Debug("miplib") << " -- INELIGIBLE -- (N-ary /\\ too big)" << endl;
3398 break;
3399 }
3400 if(conj.getKind() != kind::AND && !conj.isVar() && !(conj.getKind() == kind::NOT && conj[0].isVar())) {
3401 eligible = false;
3402 Debug("miplib") << " -- INELIGIBLE -- (not /\\ or literal)" << endl;
3403 break;
3404 }
3405 if((*j)[1].getKind() != kind::EQUAL ||
3406 !( ( (*j)[1][0].isVar() &&
3407 (*j)[1][1].getKind() == kind::CONST_RATIONAL ) ||
3408 ( (*j)[1][0].getKind() == kind::CONST_RATIONAL &&
3409 (*j)[1][1].isVar() ) )) {
3410 eligible = false;
3411 Debug("miplib") << " -- INELIGIBLE -- (=> (and X X) X)" << endl;
3412 break;
3413 }
3414 if(conj.getKind() == kind::AND) {
3415 vector<Node> posv;
3416 bool found_x = false;
3417 map<TNode, bool> neg;
3418 for(Node::iterator ii = conj.begin(); ii != conj.end(); ++ii) {
3419 if((*ii).isVar()) {
3420 posv.push_back(*ii);
3421 neg[*ii] = false;
3422 found_x = found_x || *i == *ii;
3423 } else if((*ii).getKind() == kind::NOT && (*ii)[0].isVar()) {
3424 posv.push_back((*ii)[0]);
3425 neg[(*ii)[0]] = true;
3426 found_x = found_x || *i == (*ii)[0];
3427 } else {
3428 eligible = false;
3429 Debug("miplib") << " -- INELIGIBLE -- (non-var: " << *ii << ")" << endl;
3430 break;
3431 }
3432 if(d_propagator.isAssigned(posv.back())) {
3433 eligible = false;
3434 Debug("miplib") << " -- INELIGIBLE -- (" << posv.back() << " asserted)" << endl;
3435 break;
3436 }
3437 }
3438 if(!eligible) {
3439 break;
3440 }
3441 if(!found_x) {
3442 eligible = false;
3443 Debug("miplib") << " --INELIGIBLE -- (couldn't find " << *i << " in conjunction)" << endl;
3444 break;
3445 }
3446 sort(posv.begin(), posv.end());
3447 const Node pos = NodeManager::currentNM()->mkNode(kind::AND, posv);
3448 const TNode var = ((*j)[1][0].getKind() == kind::CONST_RATIONAL) ? (*j)[1][1] : (*j)[1][0];
3449 const pair<Node, Node> pos_var(pos, var);
3450 const Rational& constant = ((*j)[1][0].getKind() == kind::CONST_RATIONAL) ? (*j)[1][0].getConst<Rational>() : (*j)[1][1].getConst<Rational>();
3451 uint64_t mark = 0;
3452 unsigned countneg = 0, thepos = 0;
3453 for(unsigned ii = 0; ii < pos.getNumChildren(); ++ii) {
3454 if(neg[pos[ii]]) {
3455 ++countneg;
3456 } else {
3457 thepos = ii;
3458 mark |= (0x1 << ii);
3459 }
3460 }
3461 if((marks[pos_var] & (1lu << mark)) != 0) {
3462 eligible = false;
3463 Debug("miplib") << " -- INELIGIBLE -- (remarked)" << endl;
3464 break;
3465 }
3466 Debug("miplib") << "mark is " << mark << " -- " << (1lu << mark) << endl;
3467 marks[pos_var] |= (1lu << mark);
3468 Debug("miplib") << "marks[" << pos << "," << var << "] now " << marks[pos_var] << endl;
3469 if(countneg == pos.getNumChildren()) {
3470 if(constant != 0) {
3471 eligible = false;
3472 Debug("miplib") << " -- INELIGIBLE -- (nonzero constant)" << endl;
3473 break;
3474 }
3475 } else if(countneg == pos.getNumChildren() - 1) {
3476 Assert(coef[pos_var].size() <= 6 && thepos < 6);
3477 if(coef[pos_var].size() <= thepos) {
3478 coef[pos_var].resize(thepos + 1);
3479 }
3480 coef[pos_var][thepos] = constant;
3481 } else {
3482 if(checks[pos_var].size() <= mark) {
3483 checks[pos_var].resize(mark + 1);
3484 }
3485 checks[pos_var][mark] = constant;
3486 }
3487 asserts[pos_var].push_back(*j);
3488 } else {
3489 TNode x = conj;
3490 if(x != *i && x != (*i).notNode()) {
3491 eligible = false;
3492 Debug("miplib") << " -- INELIGIBLE -- (x not present where I expect it)" << endl;
3493 break;
3494 }
3495 const bool xneg = (x.getKind() == kind::NOT);
3496 x = xneg ? x[0] : x;
3497 Debug("miplib") << " x:" << x << " " << xneg << endl;
3498 const TNode var = ((*j)[1][0].getKind() == kind::CONST_RATIONAL) ? (*j)[1][1] : (*j)[1][0];
3499 const pair<Node, Node> x_var(x, var);
3500 const Rational& constant = ((*j)[1][0].getKind() == kind::CONST_RATIONAL) ? (*j)[1][0].getConst<Rational>() : (*j)[1][1].getConst<Rational>();
3501 unsigned mark = (xneg ? 0 : 1);
3502 if((marks[x_var] & (1u << mark)) != 0) {
3503 eligible = false;
3504 Debug("miplib") << " -- INELIGIBLE -- (remarked)" << endl;
3505 break;
3506 }
3507 marks[x_var] |= (1u << mark);
3508 if(xneg) {
3509 if(constant != 0) {
3510 eligible = false;
3511 Debug("miplib") << " -- INELIGIBLE -- (nonzero constant)" << endl;
3512 break;
3513 }
3514 } else {
3515 Assert(coef[x_var].size() <= 6);
3516 coef[x_var].resize(6);
3517 coef[x_var][0] = constant;
3518 }
3519 asserts[x_var].push_back(*j);
3520 }
3521 }
3522 if(eligible) {
3523 for(map<pair<Node, Node>, uint64_t>::const_iterator j = marks.begin(); j != marks.end(); ++j) {
3524 const TNode pos = (*j).first.first;
3525 const TNode var = (*j).first.second;
3526 const pair<Node, Node>& pos_var = (*j).first;
3527 const uint64_t mark = (*j).second;
3528 const unsigned numVars = pos.getKind() == kind::AND ? pos.getNumChildren() : 1;
3529 uint64_t expected = (uint64_t(1) << (1 << numVars)) - 1;
3530 expected = (expected == 0) ? -1 : expected; // fix for overflow
3531 Debug("miplib") << "[" << pos << "] => " << hex << mark << " expect " << expected << dec << endl;
3532 Assert(pos.getKind() == kind::AND || pos.isVar());
3533 if(mark != expected) {
3534 Debug("miplib") << " -- INELIGIBLE " << pos << " -- (insufficiently marked, got " << mark << " for " << numVars << " vars, expected " << expected << endl;
3535 } else {
3536 if(mark != 3) { // exclude single-var case; nothing to check there
3537 uint64_t sz = (uint64_t(1) << checks[pos_var].size()) - 1;
3538 sz = (sz == 0) ? -1 : sz; // fix for overflow
3539 Assert(sz == mark, "expected size %u == mark %u", sz, mark);
3540 for(size_t k = 0; k < checks[pos_var].size(); ++k) {
3541 if((k & (k - 1)) != 0) {
3542 Rational sum = 0;
3543 Debug("miplib") << k << " => " << checks[pos_var][k] << endl;
3544 for(size_t v = 1, kk = k; kk != 0; ++v, kk >>= 1) {
3545 if((kk & 0x1) == 1) {
3546 Assert(pos.getKind() == kind::AND);
3547 Debug("miplib") << "var " << v << " : " << pos[v - 1] << " coef:" << coef[pos_var][v - 1] << endl;
3548 sum += coef[pos_var][v - 1];
3549 }
3550 }
3551 Debug("miplib") << "checkSum is " << sum << " input says " << checks[pos_var][k] << endl;
3552 if(sum != checks[pos_var][k]) {
3553 eligible = false;
3554 Debug("miplib") << " -- INELIGIBLE " << pos << " -- (nonlinear combination)" << endl;
3555 break;
3556 }
3557 } else {
3558 Assert(checks[pos_var][k] == 0, "checks[(%s,%s)][%u] should be 0, but it's %s", pos.toString().c_str(), var.toString().c_str(), k, checks[pos_var][k].toString().c_str()); // we never set for single-positive-var
3559 }
3560 }
3561 }
3562 if(!eligible) {
3563 eligible = true; // next is still eligible
3564 continue;
3565 }
3566
3567 Debug("miplib") << " -- ELIGIBLE " << *i << " , " << pos << " --" << endl;
3568 vector<Node> newVars;
3569 expr::NodeSelfIterator ii, iiend;
3570 if(pos.getKind() == kind::AND) {
3571 ii = pos.begin();
3572 iiend = pos.end();
3573 } else {
3574 ii = expr::NodeSelfIterator::self(pos);
3575 iiend = expr::NodeSelfIterator::selfEnd(pos);
3576 }
3577 for(; ii != iiend; ++ii) {
3578 Node& varRef = intVars[*ii];
3579 if(varRef.isNull()) {
3580 stringstream ss;
3581 ss << "mipvar_" << *ii;
3582 Node newVar = nm->mkSkolem(ss.str(), nm->integerType(), "a variable introduced due to scrubbing a miplib encoding", NodeManager::SKOLEM_EXACT_NAME);
3583 Node geq = Rewriter::rewrite(nm->mkNode(kind::GEQ, newVar, zero));
3584 Node leq = Rewriter::rewrite(nm->mkNode(kind::LEQ, newVar, one));
3585 addFormula(Rewriter::rewrite(geq.andNode(leq)), false, false);
3586 SubstitutionMap nullMap(&d_fakeContext);
3587 Theory::PPAssertStatus status CVC4_UNUSED; // just for assertions
3588 status = d_smt.d_theoryEngine->solve(geq, nullMap);
3589 Assert(status == Theory::PP_ASSERT_STATUS_UNSOLVED,
3590 "unexpected solution from arith's ppAssert()");
3591 Assert(nullMap.empty(),
3592 "unexpected substitution from arith's ppAssert()");
3593 status = d_smt.d_theoryEngine->solve(leq, nullMap);
3594 Assert(status == Theory::PP_ASSERT_STATUS_UNSOLVED,
3595 "unexpected solution from arith's ppAssert()");
3596 Assert(nullMap.empty(),
3597 "unexpected substitution from arith's ppAssert()");
3598 d_smt.d_theoryEngine->getModel()->addSubstitution(*ii, newVar.eqNode(one));
3599 newVars.push_back(newVar);
3600 varRef = newVar;
3601 } else {
3602 newVars.push_back(varRef);
3603 }
3604 if(!d_smt.d_logic.areIntegersUsed()) {
3605 d_smt.d_logic = d_smt.d_logic.getUnlockedCopy();
3606 d_smt.d_logic.enableIntegers();
3607 d_smt.d_logic.lock();
3608 }
3609 }
3610 Node sum;
3611 if(pos.getKind() == kind::AND) {
3612 NodeBuilder<> sumb(kind::PLUS);
3613 for(size_t ii = 0; ii < pos.getNumChildren(); ++ii) {
3614 sumb << nm->mkNode(kind::MULT, nm->mkConst(coef[pos_var][ii]), newVars[ii]);
3615 }
3616 sum = sumb;
3617 } else {
3618 sum = nm->mkNode(kind::MULT, nm->mkConst(coef[pos_var][0]), newVars[0]);
3619 }
3620 Debug("miplib") << "vars[] " << var << endl
3621 << " eq " << Rewriter::rewrite(sum) << endl;
3622 Node newAssertion = var.eqNode(Rewriter::rewrite(sum));
3623 if(d_topLevelSubstitutions.hasSubstitution(newAssertion[0])) {
3624 //Warning() << "RE-SUBSTITUTION " << newAssertion[0] << endl;
3625 //Warning() << "REPLACE " << newAssertion[1] << endl;
3626 //Warning() << "ORIG " << d_topLevelSubstitutions.getSubstitution(newAssertion[0]) << endl;
3627 Assert(d_topLevelSubstitutions.getSubstitution(newAssertion[0]) == newAssertion[1]);
3628 } else if(pos.getNumChildren() <= options::arithMLTrickSubstitutions()) {
3629 d_topLevelSubstitutions.addSubstitution(newAssertion[0], newAssertion[1]);
3630 Debug("miplib") << "addSubs: " << newAssertion[0] << " to " << newAssertion[1] << endl;
3631 } else {
3632 Debug("miplib") << "skipSubs: " << newAssertion[0] << " to " << newAssertion[1] << " (threshold is " << options::arithMLTrickSubstitutions() << ")" << endl;
3633 }
3634 newAssertion = Rewriter::rewrite(newAssertion);
3635 Debug("miplib") << " " << newAssertion << endl;
3636 addFormula(newAssertion, false, false);
3637 Debug("miplib") << " assertions to remove: " << endl;
3638 for(vector<TNode>::const_iterator k = asserts[pos_var].begin(), k_end = asserts[pos_var].end(); k != k_end; ++k) {
3639 Debug("miplib") << " " << *k << endl;
3640 removeAssertions.insert((*k).getId());
3641 }
3642 }
3643 }
3644 }
3645 }
3646 if(!removeAssertions.empty()) {
3647 Debug("miplib") << "SmtEnginePrivate::simplify(): scrubbing miplib encoding..." << endl;
3648 for(size_t i = 0; i < d_realAssertionsEnd; ++i) {
3649 if(removeAssertions.find(d_assertions[i].getId()) != removeAssertions.end()) {
3650 Debug("miplib") << "SmtEnginePrivate::simplify(): - removing " << d_assertions[i] << endl;
3651 d_assertions[i] = d_true;
3652 ++d_smt.d_stats->d_numMiplibAssertionsRemoved;
3653 } else if(d_assertions[i].getKind() == kind::AND) {
3654 size_t removals = removeFromConjunction(d_assertions[i], removeAssertions);
3655 if(removals > 0) {
3656 Debug("miplib") << "SmtEnginePrivate::simplify(): - reduced " << d_assertions[i] << endl;
3657 Debug("miplib") << "SmtEnginePrivate::simplify(): - by " << removals << " conjuncts" << endl;
3658 d_smt.d_stats->d_numMiplibAssertionsRemoved += removals;
3659 }
3660 }
3661 Debug("miplib") << "had: " << d_assertions[i] << endl;
3662 d_assertions[i] = Rewriter::rewrite(d_topLevelSubstitutions.apply(d_assertions[i]));
3663 Debug("miplib") << "now: " << d_assertions[i] << endl;
3664 }
3665 } else {
3666 Debug("miplib") << "SmtEnginePrivate::simplify(): miplib pass found nothing." << endl;
3667 }
3668 d_realAssertionsEnd = d_assertions.size();
3669 }
3670
3671
3672 // returns false if simplification led to "false"
3673 bool SmtEnginePrivate::simplifyAssertions()
3674 {
3675 spendResource(options::preprocessStep());
3676 Assert(d_smt.d_pendingPops == 0);
3677 try {
3678 ScopeCounter depth(d_simplifyAssertionsDepth);
3679
3680 Trace("simplify") << "SmtEnginePrivate::simplify()" << endl;
3681
3682 dumpAssertions("pre-nonclausal", d_assertions);
3683
3684 if(options::simplificationMode() != SIMPLIFICATION_MODE_NONE) {
3685 // Perform non-clausal simplification
3686 Chat() << "...performing nonclausal simplification..." << endl;
3687 Trace("simplify") << "SmtEnginePrivate::simplify(): "
3688 << "performing non-clausal simplification" << endl;
3689 bool noConflict = nonClausalSimplify();
3690 if(!noConflict) {
3691 return false;
3692 }
3693
3694 // We piggy-back off of the BackEdgesMap in the CircuitPropagator to
3695 // do the miplib trick.
3696 if( // check that option is on
3697 options::arithMLTrick() &&
3698 // miplib rewrites aren't safe in incremental mode
3699 ! options::incrementalSolving() &&
3700 // only useful in arith
3701 d_smt.d_logic.isTheoryEnabled(THEORY_ARITH) &&
3702 // we add new assertions and need this (in practice, this
3703 // restriction only disables miplib processing during
3704 // re-simplification, which we don't expect to be useful anyway)
3705 d_realAssertionsEnd == d_assertions.size() ) {
3706 Chat() << "...fixing miplib encodings..." << endl;
3707 Trace("simplify") << "SmtEnginePrivate::simplify(): "
3708 << "looking for miplib pseudobooleans..." << endl;
3709
3710 TimerStat::CodeTimer miplibTimer(d_smt.d_stats->d_miplibPassTime);
3711
3712 doMiplibTrick();
3713 } else {
3714 Trace("simplify") << "SmtEnginePrivate::simplify(): "
3715 << "skipping miplib pseudobooleans pass (either incrementalSolving is on, or miplib pbs are turned off)..." << endl;
3716 }
3717 }
3718
3719 dumpAssertions("post-nonclausal", d_assertions);
3720 Trace("smt") << "POST nonClausalSimplify" << endl;
3721 Debug("smt") << " d_assertions : " << d_assertions.size() << endl;
3722
3723 // before ppRewrite check if only core theory for BV theory
3724 d_smt.d_theoryEngine->staticInitializeBVOptions(d_assertions.ref());
3725
3726 dumpAssertions("pre-theorypp", d_assertions);
3727
3728 // Theory preprocessing
3729 if (d_smt.d_earlyTheoryPP) {
3730 Chat() << "...doing early theory preprocessing..." << endl;
3731 TimerStat::CodeTimer codeTimer(d_smt.d_stats->d_theoryPreprocessTime);
3732 // Call the theory preprocessors
3733 d_smt.d_theoryEngine->preprocessStart();
3734 for (unsigned i = 0; i < d_assertions.size(); ++ i) {
3735 Assert(Rewriter::rewrite(d_assertions[i]) == d_assertions[i]);
3736 d_assertions.replace(i, d_smt.d_theoryEngine->preprocess(d_assertions[i]));
3737 Assert(Rewriter::rewrite(d_assertions[i]) == d_assertions[i]);
3738 }
3739 }
3740
3741 dumpAssertions("post-theorypp", d_assertions);
3742 Trace("smt") << "POST theoryPP" << endl;
3743 Debug("smt") << " d_assertions : " << d_assertions.size() << endl;
3744
3745 // ITE simplification
3746 if(options::doITESimp() &&
3747 (d_simplifyAssertionsDepth <= 1 || options::doITESimpOnRepeat())) {
3748 Chat() << "...doing ITE simplification..." << endl;
3749 bool noConflict = simpITE();
3750 if(!noConflict){
3751 Chat() << "...ITE simplification found unsat..." << endl;
3752 return false;
3753 }
3754 }
3755
3756 dumpAssertions("post-itesimp", d_assertions);
3757 Trace("smt") << "POST iteSimp" << endl;
3758 Debug("smt") << " d_assertions : " << d_assertions.size() << endl;
3759
3760 // Unconstrained simplification
3761 if(options::unconstrainedSimp()) {
3762 Chat() << "...doing unconstrained simplification..." << endl;
3763 unconstrainedSimp();
3764 }
3765
3766 dumpAssertions("post-unconstrained", d_assertions);
3767 Trace("smt") << "POST unconstrainedSimp" << endl;
3768 Debug("smt") << " d_assertions : " << d_assertions.size() << endl;
3769
3770 if(options::repeatSimp() && options::simplificationMode() != SIMPLIFICATION_MODE_NONE) {
3771 Chat() << "...doing another round of nonclausal simplification..." << endl;
3772 Trace("simplify") << "SmtEnginePrivate::simplify(): "
3773 << " doing repeated simplification" << endl;
3774 bool noConflict = nonClausalSimplify();
3775 if(!noConflict) {
3776 return false;
3777 }
3778 }
3779
3780 dumpAssertions("post-repeatsimp", d_assertions);
3781 Trace("smt") << "POST repeatSimp" << endl;
3782 Debug("smt") << " d_assertions : " << d_assertions.size() << endl;
3783
3784 } catch(TypeCheckingExceptionPrivate& tcep) {
3785 // Calls to this function should have already weeded out any
3786 // typechecking exceptions via (e.g.) ensureBoolean(). But a
3787 // theory could still create a new expression that isn't
3788 // well-typed, and we don't want the C++ runtime to abort our
3789 // process without any error notice.
3790 stringstream ss;
3791 ss << "A bad expression was produced. Original exception follows:\n"
3792 << tcep;
3793 InternalError(ss.str().c_str());
3794 }
3795 return true;
3796 }
3797
3798 Result SmtEngine::check() {
3799 Assert(d_fullyInited);
3800 Assert(d_pendingPops == 0);
3801
3802 Trace("smt") << "SmtEngine::check()" << endl;
3803
3804 ResourceManager* resourceManager = d_private->getResourceManager();
3805
3806 resourceManager->beginCall();
3807
3808 // Only way we can be out of resource is if cumulative budget is on
3809 if (resourceManager->cumulativeLimitOn() &&
3810 resourceManager->out()) {
3811 Result::UnknownExplanation why = resourceManager->outOfResources() ?
3812 Result::RESOURCEOUT : Result::TIMEOUT;
3813 return Result(Result::VALIDITY_UNKNOWN, why, d_filename);
3814 }
3815
3816 // Make sure the prop layer has all of the assertions
3817 Trace("smt") << "SmtEngine::check(): processing assertions" << endl;
3818 d_private->processAssertions();
3819 Trace("smt") << "SmtEngine::check(): done processing assertions" << endl;
3820
3821 // Turn off stop only for QF_LRA
3822 // TODO: Bring up in a meeting where to put this
3823 if(options::decisionStopOnly() && !options::decisionMode.wasSetByUser() ){
3824 if( // QF_LRA
3825 (not d_logic.isQuantified() &&
3826 d_logic.isPure(THEORY_ARITH) && d_logic.isLinear() && !d_logic.isDifferenceLogic() && !d_logic.areIntegersUsed()
3827 )){
3828 if(d_private->d_iteSkolemMap.empty()){
3829 options::decisionStopOnly.set(false);
3830 d_decisionEngine->clearStrategies();
3831 Trace("smt") << "SmtEngine::check(): turning off stop only" << endl;
3832 }
3833 }
3834 }
3835
3836 TimerStat::CodeTimer solveTimer(d_stats->d_solveTime);
3837
3838 Chat() << "solving..." << endl;
3839 Trace("smt") << "SmtEngine::check(): running check" << endl;
3840 Result result = d_propEngine->checkSat();
3841
3842 resourceManager->endCall();
3843 Trace("limit") << "SmtEngine::check(): cumulative millis " << resourceManager->getTimeUsage()
3844 << ", resources " << resourceManager->getResourceUsage() << endl;
3845
3846
3847 return Result(result, d_filename);
3848 }
3849
3850 Result SmtEngine::quickCheck() {
3851 Assert(d_fullyInited);
3852 Trace("smt") << "SMT quickCheck()" << endl;
3853 return Result(Result::VALIDITY_UNKNOWN, Result::REQUIRES_FULL_CHECK, d_filename);
3854 }
3855
3856
3857 void SmtEnginePrivate::collectSkolems(TNode n, set<TNode>& skolemSet, unordered_map<Node, bool, NodeHashFunction>& cache)
3858 {
3859 unordered_map<Node, bool, NodeHashFunction>::iterator it;
3860 it = cache.find(n);
3861 if (it != cache.end()) {
3862 return;
3863 }
3864
3865 size_t sz = n.getNumChildren();
3866 if (sz == 0) {
3867 IteSkolemMap::iterator it = d_iteSkolemMap.find(n);
3868 if (it != d_iteSkolemMap.end()) {
3869 skolemSet.insert(n);
3870 }
3871 cache[n] = true;
3872 return;
3873 }
3874
3875 size_t k = 0;
3876 for (; k < sz; ++k) {
3877 collectSkolems(n[k], skolemSet, cache);
3878 }
3879 cache[n] = true;
3880 }
3881
3882
3883 bool SmtEnginePrivate::checkForBadSkolems(TNode n, TNode skolem, unordered_map<Node, bool, NodeHashFunction>& cache)
3884 {
3885 unordered_map<Node, bool, NodeHashFunction>::iterator it;
3886 it = cache.find(n);
3887 if (it != cache.end()) {
3888 return (*it).second;
3889 }
3890
3891 size_t sz = n.getNumChildren();
3892 if (sz == 0) {
3893 IteSkolemMap::iterator it = d_iteSkolemMap.find(n);
3894 bool bad = false;
3895 if (it != d_iteSkolemMap.end()) {
3896 if (!((*it).first < n)) {
3897 bad = true;
3898 }
3899 }
3900 cache[n] = bad;
3901 return bad;
3902 }
3903
3904 size_t k = 0;
3905 for (; k < sz; ++k) {
3906 if (checkForBadSkolems(n[k], skolem, cache)) {
3907 cache[n] = true;
3908 return true;
3909 }
3910 }
3911
3912 cache[n] = false;
3913 return false;
3914 }
3915
3916 void SmtEnginePrivate::applySubstitutionsToAssertions() {
3917 if(!options::unsatCores()) {
3918 Chat() << "applying substitutions..." << endl;
3919 Trace("simplify") << "SmtEnginePrivate::processAssertions(): "
3920 << "applying substitutions" << endl;
3921 // TODO(b/1255): Substitutions in incremental mode should be managed with a
3922 // proper data structure.
3923
3924 // When solving incrementally, all substitutions are piled into the
3925 // assertion at d_substitutionsIndex: we don't want to apply substitutions
3926 // to this assertion or information will be lost.
3927 unsigned substitutionAssertion = d_substitutionsIndex > 0 ? d_substitutionsIndex : d_assertions.size();
3928 for (unsigned i = 0; i < d_assertions.size(); ++ i) {
3929 if (i == substitutionAssertion) {
3930 continue;
3931 }
3932 Trace("simplify") << "applying to " << d_assertions[i] << endl;
3933 spendResource(options::preprocessStep());
3934 d_assertions.replace(i, Rewriter::rewrite(d_topLevelSubstitutions.apply(d_assertions[i])));
3935 Trace("simplify") << " got " << d_assertions[i] << endl;
3936 }
3937 }
3938 }
3939
3940 void SmtEnginePrivate::processAssertions() {
3941 TimerStat::CodeTimer paTimer(d_smt.d_stats->d_processAssertionsTime);
3942 spendResource(options::preprocessStep());
3943 Assert(d_smt.d_fullyInited);
3944 Assert(d_smt.d_pendingPops == 0);
3945
3946 // Dump the assertions
3947 dumpAssertions("pre-everything", d_assertions);
3948
3949 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() begin" << endl;
3950 Trace("smt") << "SmtEnginePrivate::processAssertions()" << endl;
3951
3952 Debug("smt") << " d_assertions : " << d_assertions.size() << endl;
3953
3954 if (d_assertions.size() == 0) {
3955 // nothing to do
3956 return;
3957 }
3958
3959 if (options::bvGaussElim())
3960 {
3961 TimerStat::CodeTimer gaussElimTimer(d_smt.d_stats->d_gaussElimTime);
3962 d_preprocessingPassRegistry.getPass("bv-gauss")->apply(&d_assertions);
3963 }
3964
3965 if (d_assertionsProcessed && options::incrementalSolving()) {
3966 // TODO(b/1255): Substitutions in incremental mode should be managed with a
3967 // proper data structure.
3968
3969 // Placeholder for storing substitutions
3970 d_substitutionsIndex = d_assertions.size();
3971 d_assertions.push_back(NodeManager::currentNM()->mkConst<bool>(true));
3972 }
3973
3974 // Add dummy assertion in last position - to be used as a
3975 // placeholder for any new assertions to get added
3976 d_assertions.push_back(NodeManager::currentNM()->mkConst<bool>(true));
3977 // any assertions added beyond realAssertionsEnd must NOT affect the
3978 // equisatisfiability
3979 d_realAssertionsEnd = d_assertions.size();
3980
3981 // Assertions are NOT guaranteed to be rewritten by this point
3982
3983 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : pre-definition-expansion" << endl;
3984 dumpAssertions("pre-definition-expansion", d_assertions);
3985 {
3986 Chat() << "expanding definitions..." << endl;
3987 Trace("simplify") << "SmtEnginePrivate::simplify(): expanding definitions" << endl;
3988 TimerStat::CodeTimer codeTimer(d_smt.d_stats->d_definitionExpansionTime);
3989 unordered_map<Node, Node, NodeHashFunction> cache;
3990 for(unsigned i = 0; i < d_assertions.size(); ++ i) {
3991 d_assertions.replace(i, expandDefinitions(d_assertions[i], cache));
3992 }
3993 }
3994 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : post-definition-expansion" << endl;
3995 dumpAssertions("post-definition-expansion", d_assertions);
3996
3997 // save the assertions now
3998 THEORY_PROOF
3999 (
4000 for (unsigned i = 0; i < d_assertions.size(); ++i) {
4001 ProofManager::currentPM()->addAssertion(d_assertions[i].toExpr());
4002 }
4003 );
4004
4005 Debug("smt") << " d_assertions : " << d_assertions.size() << endl;
4006
4007 if (options::sygusInference())
4008 {
4009 // try recast as sygus
4010 quantifiers::SygusInference si;
4011 if (si.simplify(d_assertions.ref()))
4012 {
4013 Trace("smt-proc") << "...converted to sygus conjecture." << std::endl;
4014 d_smt.d_globalNegation = !d_smt.d_globalNegation;
4015 }
4016 }
4017 else if (options::globalNegate())
4018 {
4019 // global negation of the formula
4020 quantifiers::GlobalNegate gn;
4021 gn.simplify(d_assertions.ref());
4022 d_smt.d_globalNegation = !d_smt.d_globalNegation;
4023 }
4024
4025 if( options::nlExtPurify() ){
4026 unordered_map<Node, Node, NodeHashFunction> cache;
4027 unordered_map<Node, Node, NodeHashFunction> bcache;
4028 std::vector< Node > var_eq;
4029 for (unsigned i = 0; i < d_assertions.size(); ++ i) {
4030 d_assertions.replace(i, purifyNlTerms(d_assertions[i], cache, bcache, var_eq));
4031 }
4032 if( !var_eq.empty() ){
4033 unsigned lastIndex = d_assertions.size()-1;
4034 var_eq.insert( var_eq.begin(), d_assertions[lastIndex] );
4035 d_assertions.replace(lastIndex, NodeManager::currentNM()->mkNode( kind::AND, var_eq ) );
4036 }
4037 }
4038
4039 if( options::ceGuidedInst() ){
4040 //register sygus conjecture pre-rewrite (motivated by solution reconstruction)
4041 for (unsigned i = 0; i < d_assertions.size(); ++ i) {
4042 d_smt.d_theoryEngine->getQuantifiersEngine()->getCegInstantiation()->preregisterAssertion( d_assertions[i] );
4043 }
4044 }
4045
4046 if (options::solveRealAsInt()) {
4047 d_preprocessingPassRegistry.getPass("real-to-int")->apply(&d_assertions);
4048 }
4049
4050 if (options::solveIntAsBV() > 0)
4051 {
4052 d_preprocessingPassRegistry.getPass("int-to-bv")->apply(&d_assertions);
4053 }
4054
4055 if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER &&
4056 !d_smt.d_logic.isPure(THEORY_BV) &&
4057 d_smt.d_logic.getLogicString() != "QF_UFBV" &&
4058 d_smt.d_logic.getLogicString() != "QF_ABV") {
4059 throw ModalException("Eager bit-blasting does not currently support theory combination. "
4060 "Note that in a QF_BV problem UF symbols can be introduced for division. "
4061 "Try --bv-div-zero-const to interpret division by zero as a constant.");
4062 }
4063
4064 if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER)
4065 {
4066 d_preprocessingPassRegistry.getPass("bv-ackermann")->apply(&d_assertions);
4067 }
4068
4069 if (options::bvAbstraction() && !options::incrementalSolving())
4070 {
4071 d_preprocessingPassRegistry.getPass("bv-abstraction")->apply(&d_assertions);
4072 }
4073
4074 Debug("smt") << " d_assertions : " << d_assertions.size() << endl;
4075
4076 bool noConflict = true;
4077
4078 if (options::extRewPrep())
4079 {
4080 theory::quantifiers::ExtendedRewriter extr(options::extRewPrepAgg());
4081 for (unsigned i = 0; i < d_assertions.size(); ++i)
4082 {
4083 Node a = d_assertions[i];
4084 d_assertions.replace(i, extr.extendedRewrite(a));
4085 }
4086 }
4087
4088 // Unconstrained simplification
4089 if(options::unconstrainedSimp()) {
4090 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : pre-unconstrained-simp" << endl;
4091 dumpAssertions("pre-unconstrained-simp", d_assertions);
4092 Chat() << "...doing unconstrained simplification..." << endl;
4093 for (unsigned i = 0; i < d_assertions.size(); ++ i) {
4094 d_assertions.replace(i, Rewriter::rewrite(d_assertions[i]));
4095 }
4096 unconstrainedSimp();
4097 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : post-unconstrained-simp" << endl;
4098 dumpAssertions("post-unconstrained-simp", d_assertions);
4099 }
4100
4101 if(options::bvIntroducePow2())
4102 {
4103 d_preprocessingPassRegistry.getPass("bv-intro-pow2")->apply(&d_assertions);
4104 }
4105
4106 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : pre-substitution" << endl;
4107 dumpAssertions("pre-substitution", d_assertions);
4108
4109 if(options::unsatCores()) {
4110 // special rewriting pass for unsat cores, since many of the passes below are skipped
4111 for (unsigned i = 0; i < d_assertions.size(); ++ i) {
4112 d_assertions.replace(i, Rewriter::rewrite(d_assertions[i]));
4113 }
4114 } else {
4115 applySubstitutionsToAssertions();
4116 }
4117 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : post-substitution" << endl;
4118 dumpAssertions("post-substitution", d_assertions);
4119
4120 // Assertions ARE guaranteed to be rewritten by this point
4121 #ifdef CVC4_ASSERTIONS
4122 for (unsigned i = 0; i < d_assertions.size(); ++i)
4123 {
4124 Assert(Rewriter::rewrite(d_assertions[i]) == d_assertions[i]);
4125 }
4126 #endif
4127
4128 // Lift bit-vectors of size 1 to bool
4129 if(options::bitvectorToBool()) {
4130 dumpAssertions("pre-bv-to-bool", d_assertions);
4131 Chat() << "...doing bvToBool..." << endl;
4132 d_preprocessingPassRegistry.getPass("bv-to-bool")->apply(&d_assertions);
4133 dumpAssertions("post-bv-to-bool", d_assertions);
4134 Trace("smt") << "POST bvToBool" << endl;
4135 }
4136 // Convert non-top-level Booleans to bit-vectors of size 1
4137 if(options::boolToBitvector()) {
4138 dumpAssertions("pre-bool-to-bv", d_assertions);
4139 Chat() << "...doing boolToBv..." << endl;
4140 d_preprocessingPassRegistry.getPass("bool-to-bv")->apply(&d_assertions);
4141 dumpAssertions("post-bool-to-bv", d_assertions);
4142 Trace("smt") << "POST boolToBv" << endl;
4143 }
4144 if(options::sepPreSkolemEmp()) {
4145 for (unsigned i = 0; i < d_assertions.size(); ++ i) {
4146 Node prev = d_assertions[i];
4147 Node next = sep::TheorySepRewriter::preprocess( prev );
4148 if( next!=prev ){
4149 d_assertions.replace( i, Rewriter::rewrite( next ) );
4150 Trace("sep-preprocess") << "*** Preprocess sep " << prev << endl;
4151 Trace("sep-preprocess") << " ...got " << d_assertions[i] << endl;
4152 }
4153 }
4154 }
4155
4156 if( d_smt.d_logic.isQuantified() ){
4157 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : pre-quant-preprocess" << endl;
4158
4159 dumpAssertions("pre-skolem-quant", d_assertions);
4160 //remove rewrite rules, apply pre-skolemization to existential quantifiers
4161 for (unsigned i = 0; i < d_assertions.size(); ++ i) {
4162 Node prev = d_assertions[i];
4163 Node next = quantifiers::QuantifiersRewriter::preprocess( prev );
4164 if( next!=prev ){
4165 d_assertions.replace( i, Rewriter::rewrite( next ) );
4166 Trace("quantifiers-preprocess") << "*** Pre-skolemize " << prev << endl;
4167 Trace("quantifiers-preprocess") << " ...got " << d_assertions[i] << endl;
4168 }
4169 }
4170 dumpAssertions("post-skolem-quant", d_assertions);
4171 if( options::macrosQuant() ){
4172 //quantifiers macro expansion
4173 quantifiers::QuantifierMacros qm( d_smt.d_theoryEngine->getQuantifiersEngine() );
4174 bool success;
4175 do{
4176 success = qm.simplify( d_assertions.ref(), true );
4177 }while( success );
4178 //finalize the definitions
4179 qm.finalizeDefinitions();
4180 }
4181
4182 //fmf-fun : assume admissible functions, applying preprocessing reduction to FMF
4183 if( options::fmfFunWellDefined() ){
4184 quantifiers::FunDefFmf fdf;
4185 Assert( d_smt.d_fmfRecFunctionsDefined!=NULL );
4186 //must carry over current definitions (for incremental)
4187 for( context::CDList<Node>::const_iterator fit = d_smt.d_fmfRecFunctionsDefined->begin();
4188 fit != d_smt.d_fmfRecFunctionsDefined->end(); ++fit ) {
4189 Node f = (*fit);
4190 Assert( d_smt.d_fmfRecFunctionsAbs.find( f )!=d_smt.d_fmfRecFunctionsAbs.end() );
4191 TypeNode ft = d_smt.d_fmfRecFunctionsAbs[f];
4192 fdf.d_sorts[f] = ft;
4193 std::map< Node, std::vector< Node > >::iterator fcit = d_smt.d_fmfRecFunctionsConcrete.find( f );
4194 Assert( fcit!=d_smt.d_fmfRecFunctionsConcrete.end() );
4195 for( unsigned j=0; j<fcit->second.size(); j++ ){
4196 fdf.d_input_arg_inj[f].push_back( fcit->second[j] );
4197 }
4198 }
4199 fdf.simplify( d_assertions.ref() );
4200 //must store new definitions (for incremental)
4201 for( unsigned i=0; i<fdf.d_funcs.size(); i++ ){
4202 Node f = fdf.d_funcs[i];
4203 d_smt.d_fmfRecFunctionsAbs[f] = fdf.d_sorts[f];
4204 d_smt.d_fmfRecFunctionsConcrete[f].clear();
4205 for( unsigned j=0; j<fdf.d_input_arg_inj[f].size(); j++ ){
4206 d_smt.d_fmfRecFunctionsConcrete[f].push_back( fdf.d_input_arg_inj[f][j] );
4207 }
4208 d_smt.d_fmfRecFunctionsDefined->push_back( f );
4209 }
4210 }
4211 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : post-quant-preprocess" << endl;
4212 }
4213
4214 if( options::sortInference() || options::ufssFairnessMonotone() ){
4215 //sort inference technique
4216 SortInference * si = d_smt.d_theoryEngine->getSortInference();
4217 si->simplify( d_assertions.ref(), options::sortInference(), options::ufssFairnessMonotone() );
4218 for( std::map< Node, Node >::iterator it = si->d_model_replace_f.begin(); it != si->d_model_replace_f.end(); ++it ){
4219 d_smt.setPrintFuncInModel( it->first.toExpr(), false );
4220 d_smt.setPrintFuncInModel( it->second.toExpr(), true );
4221 }
4222 }
4223
4224 if( options::pbRewrites() ){
4225 d_preprocessingPassRegistry.getPass("pseudo-boolean-processor")
4226 ->apply(&d_assertions);
4227 }
4228
4229 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : pre-simplify" << endl;
4230 dumpAssertions("pre-simplify", d_assertions);
4231 Chat() << "simplifying assertions..." << endl;
4232 noConflict = simplifyAssertions();
4233 if(!noConflict){
4234 ++(d_smt.d_stats->d_simplifiedToFalse);
4235 }
4236 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : post-simplify" << endl;
4237 dumpAssertions("post-simplify", d_assertions);
4238
4239 if (options::symmetryBreakerExp())
4240 {
4241 // apply symmetry breaking
4242 d_preprocessingPassRegistry.getPass("sym-break")->apply(&d_assertions);
4243 }
4244
4245 dumpAssertions("pre-static-learning", d_assertions);
4246 if(options::doStaticLearning()) {
4247 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : pre-static-learning" << endl;
4248 // Perform static learning
4249 Chat() << "doing static learning..." << endl;
4250 Trace("simplify") << "SmtEnginePrivate::simplify(): "
4251 << "performing static learning" << endl;
4252 staticLearning();
4253 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : post-static-learning" << endl;
4254 }
4255 dumpAssertions("post-static-learning", d_assertions);
4256
4257 Debug("smt") << " d_assertions : " << d_assertions.size() << endl;
4258
4259
4260 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : pre-ite-removal" << endl;
4261 dumpAssertions("pre-ite-removal", d_assertions);
4262 {
4263 Chat() << "removing term ITEs..." << endl;
4264 TimerStat::CodeTimer codeTimer(d_smt.d_stats->d_iteRemovalTime);
4265 // Remove ITEs, updating d_iteSkolemMap
4266 d_smt.d_stats->d_numAssertionsPre += d_assertions.size();
4267 removeITEs();
4268 // This is needed because when solving incrementally, removeITEs may introduce
4269 // skolems that were solved for earlier and thus appear in the substitution
4270 // map.
4271 applySubstitutionsToAssertions();
4272 d_smt.d_stats->d_numAssertionsPost += d_assertions.size();
4273 }
4274 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : post-ite-removal" << endl;
4275 dumpAssertions("post-ite-removal", d_assertions);
4276
4277 dumpAssertions("pre-repeat-simplify", d_assertions);
4278 if(options::repeatSimp()) {
4279 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : pre-repeat-simplify" << endl;
4280 Chat() << "re-simplifying assertions..." << endl;
4281 ScopeCounter depth(d_simplifyAssertionsDepth);
4282 noConflict &= simplifyAssertions();
4283 if (noConflict) {
4284 // Need to fix up assertion list to maintain invariants:
4285 // Let Sk be the set of Skolem variables introduced by ITE's. Let <_sk be the order in which these variables were introduced
4286 // during ite removal.
4287 // For each skolem variable sk, let iteExpr = iteMap(sk) be the ite expr mapped to by sk.
4288
4289 // cache for expression traversal
4290 unordered_map<Node, bool, NodeHashFunction> cache;
4291
4292 // First, find all skolems that appear in the substitution map - their associated iteExpr will need
4293 // to be moved to the main assertion set
4294 set<TNode> skolemSet;
4295 SubstitutionMap::iterator pos = d_topLevelSubstitutions.begin();
4296 for (; pos != d_topLevelSubstitutions.end(); ++pos) {
4297 collectSkolems((*pos).first, skolemSet, cache);
4298 collectSkolems((*pos).second, skolemSet, cache);
4299 }
4300
4301 // We need to ensure:
4302 // 1. iteExpr has the form (ite cond (sk = t) (sk = e))
4303 // 2. if some sk' in Sk appears in cond, t, or e, then sk' <_sk sk
4304 // If either of these is violated, we must add iteExpr as a proper assertion
4305 IteSkolemMap::iterator it = d_iteSkolemMap.begin();
4306 IteSkolemMap::iterator iend = d_iteSkolemMap.end();
4307 NodeBuilder<> builder(kind::AND);
4308 builder << d_assertions[d_realAssertionsEnd - 1];
4309 vector<TNode> toErase;
4310 for (; it != iend; ++it) {
4311 if (skolemSet.find((*it).first) == skolemSet.end()) {
4312 TNode iteExpr = d_assertions[(*it).second];
4313 if (iteExpr.getKind() == kind::ITE &&
4314 iteExpr[1].getKind() == kind::EQUAL &&
4315 iteExpr[1][0] == (*it).first &&
4316 iteExpr[2].getKind() == kind::EQUAL &&
4317 iteExpr[2][0] == (*it).first) {
4318 cache.clear();
4319 bool bad = checkForBadSkolems(iteExpr[0], (*it).first, cache);
4320 bad = bad || checkForBadSkolems(iteExpr[1][1], (*it).first, cache);
4321 bad = bad || checkForBadSkolems(iteExpr[2][1], (*it).first, cache);
4322 if (!bad) {
4323 continue;
4324 }
4325 }
4326 }
4327 // Move this iteExpr into the main assertions
4328 builder << d_assertions[(*it).second];
4329 d_assertions[(*it).second] = NodeManager::currentNM()->mkConst<bool>(true);
4330 toErase.push_back((*it).first);
4331 }
4332 if(builder.getNumChildren() > 1) {
4333 while (!toErase.empty()) {
4334 d_iteSkolemMap.erase(toErase.back());
4335 toErase.pop_back();
4336 }
4337 d_assertions[d_realAssertionsEnd - 1] = Rewriter::rewrite(Node(builder));
4338 }
4339 // TODO(b/1256): For some reason this is needed for some benchmarks, such as
4340 // QF_AUFBV/dwp_formulas/try5_small_difret_functions_dwp_tac.re_node_set_remove_at.il.dwp.smt2
4341 removeITEs();
4342 applySubstitutionsToAssertions();
4343 // Assert(iteRewriteAssertionsEnd == d_assertions.size());
4344 }
4345 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : post-repeat-simplify" << endl;
4346 }
4347 dumpAssertions("post-repeat-simplify", d_assertions);
4348
4349 dumpAssertions("pre-rewrite-apply-to-const", d_assertions);
4350 if(options::rewriteApplyToConst()) {
4351 Chat() << "Rewriting applies to constants..." << endl;
4352 TimerStat::CodeTimer codeTimer(d_smt.d_stats->d_rewriteApplyToConstTime);
4353 for (unsigned i = 0; i < d_assertions.size(); ++ i) {
4354 d_assertions[i] = Rewriter::rewrite(rewriteApplyToConst(d_assertions[i]));
4355 }
4356 }
4357 dumpAssertions("post-rewrite-apply-to-const", d_assertions);
4358
4359 // begin: INVARIANT to maintain: no reordering of assertions or
4360 // introducing new ones
4361 #ifdef CVC4_ASSERTIONS
4362 unsigned iteRewriteAssertionsEnd = d_assertions.size();
4363 #endif
4364
4365 Debug("smt") << " d_assertions : " << d_assertions.size() << endl;
4366
4367 Debug("smt") << "SmtEnginePrivate::processAssertions() POST SIMPLIFICATION" << endl;
4368 Debug("smt") << " d_assertions : " << d_assertions.size() << endl;
4369
4370 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : pre-theory-preprocessing" << endl;
4371 dumpAssertions("pre-theory-preprocessing", d_assertions);
4372 {
4373 Chat() << "theory preprocessing..." << endl;
4374 TimerStat::CodeTimer codeTimer(d_smt.d_stats->d_theoryPreprocessTime);
4375 // Call the theory preprocessors
4376 d_smt.d_theoryEngine->preprocessStart();
4377 for (unsigned i = 0; i < d_assertions.size(); ++ i) {
4378 d_assertions.replace(i, d_smt.d_theoryEngine->preprocess(d_assertions[i]));
4379 }
4380 }
4381 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : post-theory-preprocessing" << endl;
4382 dumpAssertions("post-theory-preprocessing", d_assertions);
4383
4384 // If we are using eager bit-blasting wrap assertions in fake atom so that
4385 // everything gets bit-blasted to internal SAT solver
4386 if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER) {
4387 for (unsigned i = 0; i < d_assertions.size(); ++i) {
4388 TNode atom = d_assertions[i];
4389 Node eager_atom = NodeManager::currentNM()->mkNode(kind::BITVECTOR_EAGER_ATOM, atom);
4390 d_assertions.replace(i, eager_atom);
4391 TheoryModel* m = d_smt.d_theoryEngine->getModel();
4392 m->addSubstitution(eager_atom, atom);
4393 }
4394 }
4395
4396 //notify theory engine new preprocessed assertions
4397 d_smt.d_theoryEngine->notifyPreprocessedAssertions( d_assertions.ref() );
4398
4399 // Push the formula to decision engine
4400 if(noConflict) {
4401 Chat() << "pushing to decision engine..." << endl;
4402 Assert(iteRewriteAssertionsEnd == d_assertions.size());
4403 d_smt.d_decisionEngine->addAssertions
4404 (d_assertions.ref(), d_realAssertionsEnd, d_iteSkolemMap);
4405 }
4406
4407 // end: INVARIANT to maintain: no reordering of assertions or
4408 // introducing new ones
4409
4410 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() end" << endl;
4411 dumpAssertions("post-everything", d_assertions);
4412
4413 // Push the formula to SAT
4414 {
4415 Chat() << "converting to CNF..." << endl;
4416 TimerStat::CodeTimer codeTimer(d_smt.d_stats->d_cnfConversionTime);
4417 for (unsigned i = 0; i < d_assertions.size(); ++ i) {
4418 Chat() << "+ " << d_assertions[i] << std::endl;
4419 d_smt.d_propEngine->assertFormula(d_assertions[i]);
4420 }
4421 }
4422
4423 d_assertionsProcessed = true;
4424
4425 d_assertions.clear();
4426 d_iteSkolemMap.clear();
4427 }
4428
4429 void SmtEnginePrivate::addFormula(TNode n, bool inUnsatCore, bool inInput)
4430 {
4431 if (n == d_true) {
4432 // nothing to do
4433 return;
4434 }
4435
4436 Trace("smt") << "SmtEnginePrivate::addFormula(" << n << "), inUnsatCore = " << inUnsatCore << ", inInput = " << inInput << endl;
4437
4438 // Give it to proof manager
4439 PROOF(
4440 if( inInput ){
4441 // n is an input assertion
4442 if (inUnsatCore || options::unsatCores() || options::dumpUnsatCores() || options::checkUnsatCores() || options::fewerPreprocessingHoles()) {
4443
4444 ProofManager::currentPM()->addCoreAssertion(n.toExpr());
4445 }
4446 }else{
4447 // n is the result of an unknown preprocessing step, add it to dependency map to null
4448 ProofManager::currentPM()->addDependence(n, Node::null());
4449 }
4450 // rewrite rules are by default in the unsat core because
4451 // they need to be applied until saturation
4452 if(options::unsatCores() &&
4453 n.getKind() == kind::REWRITE_RULE ){
4454 ProofManager::currentPM()->addUnsatCore(n.toExpr());
4455 }
4456 );
4457
4458 // Add the normalized formula to the queue
4459 d_assertions.push_back(n);
4460 //d_assertions.push_back(Rewriter::rewrite(n));
4461 }
4462
4463 void SmtEngine::ensureBoolean(const Expr& e)
4464 {
4465 Type type = e.getType(options::typeChecking());
4466 Type boolType = d_exprManager->booleanType();
4467 if(type != boolType) {
4468 stringstream ss;
4469 ss << "Expected " << boolType << "\n"
4470 << "The assertion : " << e << "\n"
4471 << "Its type : " << type;
4472 throw TypeCheckingException(e, ss.str());
4473 }
4474 }
4475
4476 Result SmtEngine::checkSat(const Expr& assumption, bool inUnsatCore)
4477 {
4478 return checkSatisfiability(assumption, inUnsatCore, false);
4479 }
4480
4481 Result SmtEngine::checkSat(const vector<Expr>& assumptions, bool inUnsatCore)
4482 {
4483 return checkSatisfiability(assumptions, inUnsatCore, false);
4484 }
4485
4486 Result SmtEngine::query(const Expr& assumption, bool inUnsatCore)
4487 {
4488 Assert(!assumption.isNull());
4489 return checkSatisfiability(assumption, inUnsatCore, true);
4490 }
4491
4492 Result SmtEngine::query(const vector<Expr>& assumptions, bool inUnsatCore)
4493 {
4494 return checkSatisfiability(assumptions, inUnsatCore, true);
4495 }
4496
4497 Result SmtEngine::checkSatisfiability(const Expr& expr,
4498 bool inUnsatCore,
4499 bool isQuery)
4500 {
4501 return checkSatisfiability(
4502 expr.isNull() ? vector<Expr>() : vector<Expr>{expr},
4503 inUnsatCore,
4504 isQuery);
4505 }
4506
4507 Result SmtEngine::checkSatisfiability(const vector<Expr>& assumptions,
4508 bool inUnsatCore,
4509 bool isQuery)
4510 {
4511 try
4512 {
4513 SmtScope smts(this);
4514 finalOptionsAreSet();
4515 doPendingPops();
4516
4517 Trace("smt") << "SmtEngine::" << (isQuery ? "query" : "checkSat") << "("
4518 << assumptions << ")" << endl;
4519
4520 if(d_queryMade && !options::incrementalSolving()) {
4521 throw ModalException("Cannot make multiple queries unless "
4522 "incremental solving is enabled "
4523 "(try --incremental)");
4524 }
4525
4526 // check to see if a postsolve() is pending
4527 if(d_needPostsolve) {
4528 d_theoryEngine->postsolve();
4529 d_needPostsolve = false;
4530 }
4531 // Note that a query has been made
4532 d_queryMade = true;
4533 // reset global negation
4534 d_globalNegation = false;
4535
4536 bool didInternalPush = false;
4537
4538 setProblemExtended(true);
4539
4540 if (isQuery)
4541 {
4542 size_t size = assumptions.size();
4543 if (size > 1)
4544 {
4545 /* Assume: not (BIGAND assumptions) */
4546 d_assumptions.push_back(
4547 d_exprManager->mkExpr(kind::AND, assumptions).notExpr());
4548 }
4549 else if (size == 1)
4550 {
4551 /* Assume: not expr */
4552 d_assumptions.push_back(assumptions[0].notExpr());
4553 }
4554 }
4555 else
4556 {
4557 /* Assume: BIGAND assumptions */
4558 d_assumptions = assumptions;
4559 }
4560
4561 if (!d_assumptions.empty())
4562 {
4563 internalPush();
4564 didInternalPush = true;
4565 }
4566
4567 Result r(Result::SAT_UNKNOWN, Result::UNKNOWN_REASON);
4568 for (Expr e : d_assumptions)
4569 {
4570 // Substitute out any abstract values in ex.
4571 e = d_private->substituteAbstractValues(Node::fromExpr(e)).toExpr();
4572 Assert(e.getExprManager() == d_exprManager);
4573 // Ensure expr is type-checked at this point.
4574 ensureBoolean(e);
4575
4576 /* Add assumption */
4577 if (d_assertionList != NULL)
4578 {
4579 d_assertionList->push_back(e);
4580 }
4581 d_private->addFormula(e.getNode(), inUnsatCore);
4582 }
4583
4584 r = isQuery ? check().asValidityResult() : check().asSatisfiabilityResult();
4585
4586 if ((options::solveRealAsInt() || options::solveIntAsBV() > 0)
4587 && r.asSatisfiabilityResult().isSat() == Result::UNSAT)
4588 {
4589 r = Result(Result::SAT_UNKNOWN, Result::UNKNOWN_REASON);
4590 }
4591 // flipped if we did a global negation
4592 if (d_globalNegation)
4593 {
4594 Trace("smt") << "SmtEngine::process global negate " << r << std::endl;
4595 if (r.asSatisfiabilityResult().isSat() == Result::UNSAT)
4596 {
4597 r = Result(Result::SAT);
4598 }
4599 else if (r.asSatisfiabilityResult().isSat() == Result::SAT)
4600 {
4601 // only if satisfaction complete
4602 if (d_logic.isPure(THEORY_ARITH) || d_logic.isPure(THEORY_BV))
4603 {
4604 r = Result(Result::UNSAT);
4605 }
4606 else
4607 {
4608 r = Result(Result::SAT_UNKNOWN, Result::UNKNOWN_REASON);
4609 }
4610 }
4611 Trace("smt") << "SmtEngine::global negate returned " << r << std::endl;
4612 }
4613
4614 d_needPostsolve = true;
4615
4616 // Dump the query if requested
4617 if (Dump.isOn("benchmark"))
4618 {
4619 size_t size = assumptions.size();
4620 // the expr already got dumped out if assertion-dumping is on
4621 if (isQuery && size == 1)
4622 {
4623 Dump("benchmark") << QueryCommand(assumptions[0]);
4624 }
4625 else if (size == 0)
4626 {
4627 Dump("benchmark") << CheckSatCommand();
4628 }
4629 else
4630 {
4631 Dump("benchmark") << CheckSatAssumingCommand(d_assumptions,
4632 inUnsatCore);
4633 }
4634 }
4635
4636 // Pop the context
4637 if (didInternalPush)
4638 {
4639 internalPop();
4640 }
4641
4642 // Remember the status
4643 d_status = r;
4644
4645 setProblemExtended(false);
4646
4647 Trace("smt") << "SmtEngine::" << (isQuery ? "query" : "checkSat") << "("
4648 << assumptions << ") => " << r << endl;
4649
4650 // Check that SAT results generate a model correctly.
4651 if(options::checkModels()) {
4652 // TODO (#1693) check model when unknown result?
4653 if (r.asSatisfiabilityResult().isSat() == Result::SAT)
4654 {
4655 checkModel();
4656 }
4657 }
4658 // Check that UNSAT results generate a proof correctly.
4659 if(options::checkProofs()) {
4660 if(r.asSatisfiabilityResult().isSat() == Result::UNSAT) {
4661 TimerStat::CodeTimer checkProofTimer(d_stats->d_checkProofTime);
4662 checkProof();
4663 }
4664 }
4665 // Check that UNSAT results generate an unsat core correctly.
4666 if(options::checkUnsatCores()) {
4667 if(r.asSatisfiabilityResult().isSat() == Result::UNSAT) {
4668 TimerStat::CodeTimer checkUnsatCoreTimer(d_stats->d_checkUnsatCoreTime);
4669 checkUnsatCore();
4670 }
4671 }
4672 // Check that synthesis solutions satisfy the conjecture
4673 if (options::checkSynthSol()
4674 && r.asSatisfiabilityResult().isSat() == Result::UNSAT)
4675 {
4676 checkSynthSolution();
4677 }
4678
4679 return r;
4680 } catch (UnsafeInterruptException& e) {
4681 AlwaysAssert(d_private->getResourceManager()->out());
4682 Result::UnknownExplanation why = d_private->getResourceManager()->outOfResources() ?
4683 Result::RESOURCEOUT : Result::TIMEOUT;
4684 return Result(Result::SAT_UNKNOWN, why, d_filename);
4685 }
4686 }
4687
4688 vector<Expr> SmtEngine::getUnsatAssumptions(void)
4689 {
4690 Trace("smt") << "SMT getUnsatAssumptions()" << endl;
4691 SmtScope smts(this);
4692 if (!options::unsatAssumptions())
4693 {
4694 throw ModalException(
4695 "Cannot get unsat assumptions when produce-unsat-assumptions option "
4696 "is off.");
4697 }
4698 if (d_status.isNull()
4699 || d_status.asSatisfiabilityResult() != Result::UNSAT
4700 || d_problemExtended)
4701 {
4702 throw RecoverableModalException(
4703 "Cannot get unsat assumptions unless immediately preceded by "
4704 "UNSAT/VALID response.");
4705 }
4706 finalOptionsAreSet();
4707 if (Dump.isOn("benchmark"))
4708 {
4709 Dump("benchmark") << GetUnsatCoreCommand();
4710 }
4711 UnsatCore core = getUnsatCore();
4712 vector<Expr> res;
4713 for (const Expr& e : d_assumptions)
4714 {
4715 if (find(core.begin(), core.end(), e) != core.end()) { res.push_back(e); }
4716 }
4717 return res;
4718 }
4719
4720 Result SmtEngine::checkSynth(const Expr& e)
4721 {
4722 SmtScope smts(this);
4723 Trace("smt") << "Check synth: " << e << std::endl;
4724 Trace("smt-synth") << "Check synthesis conjecture: " << e << std::endl;
4725 Expr e_check = e;
4726 if (options::sygusQePreproc())
4727 {
4728 // the following does quantifier elimination as a preprocess step
4729 // for "non-ground single invocation synthesis conjectures":
4730 // exists f. forall xy. P[ f(x), x, y ]
4731 // We run quantifier elimination:
4732 // exists y. P[ z, x, y ] ----> Q[ z, x ]
4733 // Where we replace the original conjecture with:
4734 // exists f. forall x. Q[ f(x), x ]
4735 // For more details, see Example 6 of Reynolds et al. SYNT 2017.
4736 Node conj = Node::fromExpr(e);
4737 if (conj.getKind() == kind::FORALL && conj[1].getKind() == kind::EXISTS)
4738 {
4739 Node conj_se = Node::fromExpr(expandDefinitions(conj[1][1].toExpr()));
4740
4741 Trace("smt-synth") << "Compute single invocation for " << conj_se << "..."
4742 << std::endl;
4743 quantifiers::SingleInvocationPartition sip;
4744 std::vector<Node> funcs;
4745 funcs.insert(funcs.end(), conj[0].begin(), conj[0].end());
4746 sip.init(funcs, conj_se.negate());
4747 Trace("smt-synth") << "...finished, got:" << std::endl;
4748 sip.debugPrint("smt-synth");
4749
4750 if (!sip.isPurelySingleInvocation() && sip.isNonGroundSingleInvocation())
4751 {
4752 // create new smt engine to do quantifier elimination
4753 SmtEngine smt_qe(d_exprManager);
4754 smt_qe.setLogic(getLogicInfo());
4755 Trace("smt-synth") << "Property is non-ground single invocation, run "
4756 "QE to obtain single invocation."
4757 << std::endl;
4758 NodeManager* nm = NodeManager::currentNM();
4759 // partition variables
4760 std::vector<Node> all_vars;
4761 sip.getAllVariables(all_vars);
4762 std::vector<Node> si_vars;
4763 sip.getSingleInvocationVariables(si_vars);
4764 std::vector<Node> qe_vars;
4765 std::vector<Node> nqe_vars;
4766 for (unsigned i = 0, size = all_vars.size(); i < size; i++)
4767 {
4768 Node v = all_vars[i];
4769 if (std::find(si_vars.begin(), si_vars.end(), v) == si_vars.end())
4770 {
4771 qe_vars.push_back(v);
4772 }
4773 else
4774 {
4775 nqe_vars.push_back(v);
4776 }
4777 }
4778 std::vector<Node> orig;
4779 std::vector<Node> subs;
4780 // skolemize non-qe variables
4781 for (unsigned i = 0; i < nqe_vars.size(); i++)
4782 {
4783 Node k = nm->mkSkolem("k",
4784 nqe_vars[i].getType(),
4785 "qe for non-ground single invocation");
4786 orig.push_back(nqe_vars[i]);
4787 subs.push_back(k);
4788 Trace("smt-synth") << " subs : " << nqe_vars[i] << " -> " << k
4789 << std::endl;
4790 }
4791 std::vector<Node> funcs;
4792 sip.getFunctions(funcs);
4793 for (unsigned i = 0, size = funcs.size(); i < size; i++)
4794 {
4795 Node f = funcs[i];
4796 Node fi = sip.getFunctionInvocationFor(f);
4797 Node fv = sip.getFirstOrderVariableForFunction(f);
4798 Assert(!fi.isNull());
4799 orig.push_back(fi);
4800 Node k =
4801 nm->mkSkolem("k",
4802 fv.getType(),
4803 "qe for function in non-ground single invocation");
4804 subs.push_back(k);
4805 Trace("smt-synth") << " subs : " << fi << " -> " << k << std::endl;
4806 }
4807 Node conj_se_ngsi = sip.getFullSpecification();
4808 Trace("smt-synth") << "Full specification is " << conj_se_ngsi
4809 << std::endl;
4810 Node conj_se_ngsi_subs = conj_se_ngsi.substitute(
4811 orig.begin(), orig.end(), subs.begin(), subs.end());
4812 Assert(!qe_vars.empty());
4813 conj_se_ngsi_subs =
4814 nm->mkNode(kind::EXISTS,
4815 nm->mkNode(kind::BOUND_VAR_LIST, qe_vars),
4816 conj_se_ngsi_subs.negate());
4817
4818 Trace("smt-synth") << "Run quantifier elimination on "
4819 << conj_se_ngsi_subs << std::endl;
4820 Expr qe_res = smt_qe.doQuantifierElimination(
4821 conj_se_ngsi_subs.toExpr(), true, false);
4822 Trace("smt-synth") << "Result : " << qe_res << std::endl;
4823
4824 // create single invocation conjecture
4825 Node qe_res_n = Node::fromExpr(qe_res);
4826 qe_res_n = qe_res_n.substitute(
4827 subs.begin(), subs.end(), orig.begin(), orig.end());
4828 if (!nqe_vars.empty())
4829 {
4830 qe_res_n = nm->mkNode(kind::EXISTS,
4831 nm->mkNode(kind::BOUND_VAR_LIST, nqe_vars),
4832 qe_res_n);
4833 }
4834 Assert(conj.getNumChildren() == 3);
4835 qe_res_n = nm->mkNode(kind::FORALL, conj[0], qe_res_n, conj[2]);
4836 Trace("smt-synth") << "Converted conjecture after QE : " << qe_res_n
4837 << std::endl;
4838 e_check = qe_res_n.toExpr();
4839 }
4840 }
4841 }
4842
4843 return checkSatisfiability( e_check, true, false );
4844 }
4845
4846 Result SmtEngine::assertFormula(const Expr& ex, bool inUnsatCore)
4847 {
4848 Assert(ex.getExprManager() == d_exprManager);
4849 SmtScope smts(this);
4850 finalOptionsAreSet();
4851 doPendingPops();
4852
4853 Trace("smt") << "SmtEngine::assertFormula(" << ex << ")" << endl;
4854
4855 if (Dump.isOn("raw-benchmark")) {
4856 Dump("raw-benchmark") << AssertCommand(ex);
4857 }
4858
4859 // Substitute out any abstract values in ex
4860 Expr e = d_private->substituteAbstractValues(Node::fromExpr(ex)).toExpr();
4861
4862 ensureBoolean(e);
4863 if(d_assertionList != NULL) {
4864 d_assertionList->push_back(e);
4865 }
4866 d_private->addFormula(e.getNode(), inUnsatCore);
4867 return quickCheck().asValidityResult();
4868 }/* SmtEngine::assertFormula() */
4869
4870 Node SmtEngine::postprocess(TNode node, TypeNode expectedType) const {
4871 return node;
4872 }
4873
4874 Expr SmtEngine::simplify(const Expr& ex)
4875 {
4876 Assert(ex.getExprManager() == d_exprManager);
4877 SmtScope smts(this);
4878 finalOptionsAreSet();
4879 doPendingPops();
4880 Trace("smt") << "SMT simplify(" << ex << ")" << endl;
4881
4882 if(Dump.isOn("benchmark")) {
4883 Dump("benchmark") << SimplifyCommand(ex);
4884 }
4885
4886 Expr e = d_private->substituteAbstractValues(Node::fromExpr(ex)).toExpr();
4887 if( options::typeChecking() ) {
4888 e.getType(true); // ensure expr is type-checked at this point
4889 }
4890
4891 // Make sure all preprocessing is done
4892 d_private->processAssertions();
4893 Node n = d_private->simplify(Node::fromExpr(e));
4894 n = postprocess(n, TypeNode::fromType(e.getType()));
4895 return n.toExpr();
4896 }
4897
4898 Expr SmtEngine::expandDefinitions(const Expr& ex)
4899 {
4900 d_private->spendResource(options::preprocessStep());
4901
4902 Assert(ex.getExprManager() == d_exprManager);
4903 SmtScope smts(this);
4904 finalOptionsAreSet();
4905 doPendingPops();
4906 Trace("smt") << "SMT expandDefinitions(" << ex << ")" << endl;
4907
4908 // Substitute out any abstract values in ex.
4909 Expr e = d_private->substituteAbstractValues(Node::fromExpr(ex)).toExpr();
4910 if(options::typeChecking()) {
4911 // Ensure expr is type-checked at this point.
4912 e.getType(true);
4913 }
4914 if(Dump.isOn("benchmark")) {
4915 Dump("benchmark") << ExpandDefinitionsCommand(e);
4916 }
4917 unordered_map<Node, Node, NodeHashFunction> cache;
4918 Node n = d_private->expandDefinitions(Node::fromExpr(e), cache, /* expandOnly = */ true);
4919 n = postprocess(n, TypeNode::fromType(e.getType()));
4920
4921 return n.toExpr();
4922 }
4923
4924 // TODO(#1108): Simplify the error reporting of this method.
4925 Expr SmtEngine::getValue(const Expr& ex) const
4926 {
4927 Assert(ex.getExprManager() == d_exprManager);
4928 SmtScope smts(this);
4929
4930 Trace("smt") << "SMT getValue(" << ex << ")" << endl;
4931 if(Dump.isOn("benchmark")) {
4932 Dump("benchmark") << GetValueCommand(ex);
4933 }
4934
4935 if(!options::produceModels()) {
4936 const char* msg =
4937 "Cannot get value when produce-models options is off.";
4938 throw ModalException(msg);
4939 }
4940 if(d_status.isNull() ||
4941 d_status.asSatisfiabilityResult() == Result::UNSAT ||
4942 d_problemExtended) {
4943 const char* msg =
4944 "Cannot get value unless immediately preceded by SAT/INVALID or UNKNOWN response.";
4945 throw RecoverableModalException(msg);
4946 }
4947
4948 // Substitute out any abstract values in ex.
4949 Expr e = d_private->substituteAbstractValues(Node::fromExpr(ex)).toExpr();
4950
4951 // Ensure expr is type-checked at this point.
4952 e.getType(options::typeChecking());
4953
4954 // do not need to apply preprocessing substitutions (should be recorded
4955 // in model already)
4956
4957 Node n = Node::fromExpr(e);
4958 Trace("smt") << "--- getting value of " << n << endl;
4959 TypeNode expectedType = n.getType();
4960
4961 // Expand, then normalize
4962 unordered_map<Node, Node, NodeHashFunction> cache;
4963 n = d_private->expandDefinitions(n, cache);
4964 // There are two ways model values for terms are computed (for historical
4965 // reasons). One way is that used in check-model; the other is that
4966 // used by the Model classes. It's not clear to me exactly how these
4967 // two are different, but they need to be unified. This ugly hack here
4968 // is to fix bug 554 until we can revamp boolean-terms and models [MGD]
4969
4970 //AJR : necessary?
4971 if(!n.getType().isFunction()) {
4972 n = Rewriter::rewrite(n);
4973 }
4974
4975 Trace("smt") << "--- getting value of " << n << endl;
4976 TheoryModel* m = d_theoryEngine->getModel();
4977 Node resultNode;
4978 if(m != NULL) {
4979 resultNode = m->getValue(n);
4980 }
4981 Trace("smt") << "--- got value " << n << " = " << resultNode << endl;
4982 resultNode = postprocess(resultNode, expectedType);
4983 Trace("smt") << "--- model-post returned " << resultNode << endl;
4984 Trace("smt") << "--- model-post returned " << resultNode.getType() << endl;
4985 Trace("smt") << "--- model-post expected " << expectedType << endl;
4986
4987 // type-check the result we got
4988 Assert(resultNode.isNull() || resultNode.getType().isSubtypeOf(expectedType),
4989 "Run with -t smt for details.");
4990
4991 // ensure it's a constant
4992 Assert(resultNode.getKind() == kind::LAMBDA || resultNode.isConst());
4993
4994 if(options::abstractValues() && resultNode.getType().isArray()) {
4995 resultNode = d_private->mkAbstractValue(resultNode);
4996 Trace("smt") << "--- abstract value >> " << resultNode << endl;
4997 }
4998
4999 return resultNode.toExpr();
5000 }
5001
5002 bool SmtEngine::addToAssignment(const Expr& ex) {
5003 SmtScope smts(this);
5004 finalOptionsAreSet();
5005 doPendingPops();
5006 // Substitute out any abstract values in ex
5007 Expr e = d_private->substituteAbstractValues(Node::fromExpr(ex)).toExpr();
5008 Type type = e.getType(options::typeChecking());
5009 // must be Boolean
5010 PrettyCheckArgument(
5011 type.isBoolean(), e,
5012 "expected Boolean-typed variable or function application "
5013 "in addToAssignment()" );
5014 Node n = e.getNode();
5015 // must be an APPLY of a zero-ary defined function, or a variable
5016 PrettyCheckArgument(
5017 ( ( n.getKind() == kind::APPLY &&
5018 ( d_definedFunctions->find(n.getOperator()) !=
5019 d_definedFunctions->end() ) &&
5020 n.getNumChildren() == 0 ) ||
5021 n.isVar() ), e,
5022 "expected variable or defined-function application "
5023 "in addToAssignment(),\ngot %s", e.toString().c_str() );
5024 if(!options::produceAssignments()) {
5025 return false;
5026 }
5027 if(d_assignments == NULL) {
5028 d_assignments = new(true) AssignmentSet(d_context);
5029 }
5030 d_assignments->insert(n);
5031
5032 return true;
5033 }
5034
5035 // TODO(#1108): Simplify the error reporting of this method.
5036 vector<pair<Expr, Expr>> SmtEngine::getAssignment()
5037 {
5038 Trace("smt") << "SMT getAssignment()" << endl;
5039 SmtScope smts(this);
5040 finalOptionsAreSet();
5041 if(Dump.isOn("benchmark")) {
5042 Dump("benchmark") << GetAssignmentCommand();
5043 }
5044 if(!options::produceAssignments()) {
5045 const char* msg =
5046 "Cannot get the current assignment when "
5047 "produce-assignments option is off.";
5048 throw ModalException(msg);
5049 }
5050 if(d_status.isNull() ||
5051 d_status.asSatisfiabilityResult() == Result::UNSAT ||
5052 d_problemExtended) {
5053 const char* msg =
5054 "Cannot get the current assignment unless immediately "
5055 "preceded by SAT/INVALID or UNKNOWN response.";
5056 throw RecoverableModalException(msg);
5057 }
5058
5059 vector<pair<Expr,Expr>> res;
5060 if (d_assignments != nullptr)
5061 {
5062 TypeNode boolType = d_nodeManager->booleanType();
5063 TheoryModel* m = d_theoryEngine->getModel();
5064 for (AssignmentSet::key_iterator i = d_assignments->key_begin(),
5065 iend = d_assignments->key_end();
5066 i != iend;
5067 ++i)
5068 {
5069 Node as = *i;
5070 Assert(as.getType() == boolType);
5071
5072 Trace("smt") << "--- getting value of " << as << endl;
5073
5074 // Expand, then normalize
5075 unordered_map<Node, Node, NodeHashFunction> cache;
5076 Node n = d_private->expandDefinitions(as, cache);
5077 n = Rewriter::rewrite(n);
5078
5079 Trace("smt") << "--- getting value of " << n << endl;
5080 Node resultNode;
5081 if (m != nullptr)
5082 {
5083 resultNode = m->getValue(n);
5084 }
5085
5086 // type-check the result we got
5087 Assert(resultNode.isNull() || resultNode.getType() == boolType);
5088
5089 // ensure it's a constant
5090 Assert(resultNode.isConst());
5091
5092 Assert(as.getKind() == kind::APPLY || as.isVar());
5093 Assert(as.getKind() != kind::APPLY || as.getNumChildren() == 0);
5094 res.emplace_back(as.toExpr(), resultNode.toExpr());
5095 }
5096 }
5097 return res;
5098 }
5099
5100 void SmtEngine::addToModelCommandAndDump(const Command& c, uint32_t flags, bool userVisible, const char* dumpTag) {
5101 Trace("smt") << "SMT addToModelCommandAndDump(" << c << ")" << endl;
5102 SmtScope smts(this);
5103 // If we aren't yet fully inited, the user might still turn on
5104 // produce-models. So let's keep any commands around just in
5105 // case. This is useful in two cases: (1) SMT-LIBv1 auto-declares
5106 // sort "U" in QF_UF before setLogic() is run and we still want to
5107 // support finding card(U) with --finite-model-find, and (2) to
5108 // decouple SmtEngine and ExprManager if the user does a few
5109 // ExprManager::mkSort() before SmtEngine::setOption("produce-models")
5110 // and expects to find their cardinalities in the model.
5111 if(/* userVisible && */
5112 (!d_fullyInited || options::produceModels()) &&
5113 (flags & ExprManager::VAR_FLAG_DEFINED) == 0) {
5114 doPendingPops();
5115 if(flags & ExprManager::VAR_FLAG_GLOBAL) {
5116 d_modelGlobalCommands.push_back(c.clone());
5117 } else {
5118 d_modelCommands->push_back(c.clone());
5119 }
5120 }
5121 if(Dump.isOn(dumpTag)) {
5122 if(d_fullyInited) {
5123 Dump(dumpTag) << c;
5124 } else {
5125 d_dumpCommands.push_back(c.clone());
5126 }
5127 }
5128 }
5129
5130 // TODO(#1108): Simplify the error reporting of this method.
5131 Model* SmtEngine::getModel() {
5132 Trace("smt") << "SMT getModel()" << endl;
5133 SmtScope smts(this);
5134
5135 finalOptionsAreSet();
5136
5137 if(Dump.isOn("benchmark")) {
5138 Dump("benchmark") << GetModelCommand();
5139 }
5140
5141 if(d_status.isNull() ||
5142 d_status.asSatisfiabilityResult() == Result::UNSAT ||
5143 d_problemExtended) {
5144 const char* msg =
5145 "Cannot get the current model unless immediately "
5146 "preceded by SAT/INVALID or UNKNOWN response.";
5147 throw RecoverableModalException(msg);
5148 }
5149 if(!options::produceModels()) {
5150 const char* msg =
5151 "Cannot get model when produce-models options is off.";
5152 throw ModalException(msg);
5153 }
5154 TheoryModel* m = d_theoryEngine->getModel();
5155 m->d_inputName = d_filename;
5156 return m;
5157 }
5158
5159 void SmtEngine::checkUnsatCore() {
5160 Assert(options::unsatCores(), "cannot check unsat core if unsat cores are turned off");
5161
5162 Notice() << "SmtEngine::checkUnsatCore(): generating unsat core" << endl;
5163 UnsatCore core = getUnsatCore();
5164
5165 SmtEngine coreChecker(d_exprManager);
5166 coreChecker.setLogic(getLogicInfo());
5167
5168 PROOF(
5169 std::vector<Command*>::const_iterator itg = d_defineCommands.begin();
5170 for (; itg != d_defineCommands.end(); ++itg) {
5171 (*itg)->invoke(&coreChecker);
5172 }
5173 );
5174
5175 Notice() << "SmtEngine::checkUnsatCore(): pushing core assertions (size == " << core.size() << ")" << endl;
5176 for(UnsatCore::iterator i = core.begin(); i != core.end(); ++i) {
5177 Notice() << "SmtEngine::checkUnsatCore(): pushing core member " << *i << endl;
5178 coreChecker.assertFormula(*i);
5179 }
5180 const bool checkUnsatCores = options::checkUnsatCores();
5181 Result r;
5182 try {
5183 options::checkUnsatCores.set(false);
5184 options::checkProofs.set(false);
5185 r = coreChecker.checkSat();
5186 } catch(...) {
5187 options::checkUnsatCores.set(checkUnsatCores);
5188 throw;
5189 }
5190 Notice() << "SmtEngine::checkUnsatCore(): result is " << r << endl;
5191 if(r.asSatisfiabilityResult().isUnknown()) {
5192 InternalError("SmtEngine::checkUnsatCore(): could not check core result unknown.");
5193 }
5194
5195 if(r.asSatisfiabilityResult().isSat()) {
5196 InternalError("SmtEngine::checkUnsatCore(): produced core was satisfiable.");
5197 }
5198 }
5199
5200 void SmtEngine::checkModel(bool hardFailure) {
5201 // --check-model implies --produce-assertions, which enables the
5202 // assertion list, so we should be ok.
5203 Assert(d_assertionList != NULL, "don't have an assertion list to check in SmtEngine::checkModel()");
5204
5205 TimerStat::CodeTimer checkModelTimer(d_stats->d_checkModelTime);
5206
5207 // Throughout, we use Notice() to give diagnostic output.
5208 //
5209 // If this function is running, the user gave --check-model (or equivalent),
5210 // and if Notice() is on, the user gave --verbose (or equivalent).
5211
5212 Notice() << "SmtEngine::checkModel(): generating model" << endl;
5213 TheoryModel* m = d_theoryEngine->getModel();
5214
5215 // check-model is not guaranteed to succeed if approximate values were used
5216 if (m->hasApproximations())
5217 {
5218 Warning()
5219 << "WARNING: running check-model on a model with approximate values..."
5220 << endl;
5221 }
5222
5223 // Check individual theory assertions
5224 d_theoryEngine->checkTheoryAssertionsWithModel(hardFailure);
5225
5226 // Output the model
5227 Notice() << *m;
5228
5229 // We have a "fake context" for the substitution map (we don't need it
5230 // to be context-dependent)
5231 context::Context fakeContext;
5232 SubstitutionMap substitutions(&fakeContext, /* substituteUnderQuantifiers = */ false);
5233
5234 for(size_t k = 0; k < m->getNumCommands(); ++k) {
5235 const DeclareFunctionCommand* c = dynamic_cast<const DeclareFunctionCommand*>(m->getCommand(k));
5236 Notice() << "SmtEngine::checkModel(): model command " << k << " : " << m->getCommand(k) << endl;
5237 if(c == NULL) {
5238 // we don't care about DECLARE-DATATYPES, DECLARE-SORT, ...
5239 Notice() << "SmtEngine::checkModel(): skipping..." << endl;
5240 } else {
5241 // We have a DECLARE-FUN:
5242 //
5243 // We'll first do some checks, then add to our substitution map
5244 // the mapping: function symbol |-> value
5245
5246 Expr func = c->getFunction();
5247 Node val = m->getValue(func);
5248
5249 Notice() << "SmtEngine::checkModel(): adding substitution: " << func << " |-> " << val << endl;
5250
5251 // (1) if the value is a lambda, ensure the lambda doesn't contain the
5252 // function symbol (since then the definition is recursive)
5253 if (val.getKind() == kind::LAMBDA) {
5254 // first apply the model substitutions we have so far
5255 Debug("boolean-terms") << "applying subses to " << val[1] << endl;
5256 Node n = substitutions.apply(val[1]);
5257 Debug("boolean-terms") << "++ got " << n << endl;
5258 // now check if n contains func by doing a substitution
5259 // [func->func2] and checking equality of the Nodes.
5260 // (this just a way to check if func is in n.)
5261 SubstitutionMap subs(&fakeContext);
5262 Node func2 = NodeManager::currentNM()->mkSkolem("", TypeNode::fromType(func.getType()), "", NodeManager::SKOLEM_NO_NOTIFY);
5263 subs.addSubstitution(func, func2);
5264 if(subs.apply(n) != n) {
5265 Notice() << "SmtEngine::checkModel(): *** PROBLEM: MODEL VALUE DEFINED IN TERMS OF ITSELF ***" << endl;
5266 stringstream ss;
5267 ss << "SmtEngine::checkModel(): ERRORS SATISFYING ASSERTIONS WITH MODEL:" << endl
5268 << "considering model value for " << func << endl
5269 << "body of lambda is: " << val << endl;
5270 if(n != val[1]) {
5271 ss << "body substitutes to: " << n << endl;
5272 }
5273 ss << "so " << func << " is defined in terms of itself." << endl
5274 << "Run with `--check-models -v' for additional diagnostics.";
5275 InternalError(ss.str());
5276 }
5277 }
5278
5279 // (2) check that the value is actually a value
5280 else if (!val.isConst()) {
5281 Notice() << "SmtEngine::checkModel(): *** PROBLEM: MODEL VALUE NOT A CONSTANT ***" << endl;
5282 stringstream ss;
5283 ss << "SmtEngine::checkModel(): ERRORS SATISFYING ASSERTIONS WITH MODEL:" << endl
5284 << "model value for " << func << endl
5285 << " is " << val << endl
5286 << "and that is not a constant (.isConst() == false)." << endl
5287 << "Run with `--check-models -v' for additional diagnostics.";
5288 InternalError(ss.str());
5289 }
5290
5291 // (3) check that it's the correct (sub)type
5292 // This was intended to be a more general check, but for now we can't do that because
5293 // e.g. "1" is an INT, which isn't a subrange type [1..10] (etc.).
5294 else if(func.getType().isInteger() && !val.getType().isInteger()) {
5295 Notice() << "SmtEngine::checkModel(): *** PROBLEM: MODEL VALUE NOT CORRECT TYPE ***" << endl;
5296 stringstream ss;
5297 ss << "SmtEngine::checkModel(): ERRORS SATISFYING ASSERTIONS WITH MODEL:" << endl
5298 << "model value for " << func << endl
5299 << " is " << val << endl
5300 << "value type is " << val.getType() << endl
5301 << "should be of type " << func.getType() << endl
5302 << "Run with `--check-models -v' for additional diagnostics.";
5303 InternalError(ss.str());
5304 }
5305
5306 // (4) checks complete, add the substitution
5307 Debug("boolean-terms") << "cm: adding subs " << func << " :=> " << val << endl;
5308 substitutions.addSubstitution(func, val);
5309 }
5310 }
5311
5312 // Now go through all our user assertions checking if they're satisfied.
5313 for(AssertionList::const_iterator i = d_assertionList->begin(); i != d_assertionList->end(); ++i) {
5314 Notice() << "SmtEngine::checkModel(): checking assertion " << *i << endl;
5315 Node n = Node::fromExpr(*i);
5316
5317 // Apply any define-funs from the problem.
5318 {
5319 unordered_map<Node, Node, NodeHashFunction> cache;
5320 n = d_private->expandDefinitions(n, cache);
5321 }
5322 Notice() << "SmtEngine::checkModel(): -- expands to " << n << endl;
5323
5324 // Apply our model value substitutions.
5325 Debug("boolean-terms") << "applying subses to " << n << endl;
5326 n = substitutions.apply(n);
5327 Debug("boolean-terms") << "++ got " << n << endl;
5328 Notice() << "SmtEngine::checkModel(): -- substitutes to " << n << endl;
5329
5330 if( n.getKind() != kind::REWRITE_RULE ){
5331 // In case it's a quantifier (or contains one), look up its value before
5332 // simplifying, or the quantifier might be irreparably altered.
5333 n = m->getValue(n);
5334 Notice() << "SmtEngine::checkModel(): -- get value : " << n << std::endl;
5335 } else {
5336 // Note this "skip" is done here, rather than above. This is
5337 // because (1) the quantifier could in principle simplify to false,
5338 // which should be reported, and (2) checking for the quantifier
5339 // above, before simplification, doesn't catch buried quantifiers
5340 // anyway (those not at the top-level).
5341 Notice() << "SmtEngine::checkModel(): -- skipping rewrite-rules assertion"
5342 << endl;
5343 continue;
5344 }
5345
5346 // Simplify the result.
5347 n = d_private->simplify(n);
5348 Notice() << "SmtEngine::checkModel(): -- simplifies to " << n << endl;
5349
5350 // Replace the already-known ITEs (this is important for ground ITEs under quantifiers).
5351 n = d_private->d_iteRemover.replace(n);
5352 Notice() << "SmtEngine::checkModel(): -- ite replacement gives " << n << endl;
5353
5354 // Apply our model value substitutions (again), as things may have been simplified.
5355 Debug("boolean-terms") << "applying subses to " << n << endl;
5356 n = substitutions.apply(n);
5357 Debug("boolean-terms") << "++ got " << n << endl;
5358 Notice() << "SmtEngine::checkModel(): -- re-substitutes to " << n << endl;
5359
5360 // As a last-ditch effort, ask model to simplify it.
5361 // Presently, this is only an issue for quantifiers, which can have a value
5362 // but don't show up in our substitution map above.
5363 n = m->getValue(n);
5364 Notice() << "SmtEngine::checkModel(): -- model-substitutes to " << n << endl;
5365
5366 if( d_logic.isQuantified() ){
5367 // AJR: since quantified formulas are not checkable, we assign them to true/false based on the satisfying assignment.
5368 // however, quantified formulas can be modified during preprocess, so they may not correspond to those in the satisfying assignment.
5369 // hence we use a relaxed version of check model here.
5370 // this is necessary until preprocessing passes explicitly record how they rewrite quantified formulas
5371 if( hardFailure && !n.isConst() && n.getKind() != kind::LAMBDA ){
5372 Notice() << "SmtEngine::checkModel(): -- relax check model wrt quantified formulas..." << endl;
5373 AlwaysAssert( quantifiers::QuantifiersRewriter::containsQuantifiers( n ) );
5374 Warning() << "Warning : SmtEngine::checkModel(): cannot check simplified assertion : " << n << endl;
5375 continue;
5376 }
5377 }else{
5378 AlwaysAssert(!hardFailure || n.isConst() || n.getKind() == kind::LAMBDA);
5379 }
5380 // The result should be == true.
5381 if(n != NodeManager::currentNM()->mkConst(true)) {
5382 Notice() << "SmtEngine::checkModel(): *** PROBLEM: EXPECTED `TRUE' ***"
5383 << endl;
5384 stringstream ss;
5385 ss << "SmtEngine::checkModel(): "
5386 << "ERRORS SATISFYING ASSERTIONS WITH MODEL:" << endl
5387 << "assertion: " << *i << endl
5388 << "simplifies to: " << n << endl
5389 << "expected `true'." << endl
5390 << "Run with `--check-models -v' for additional diagnostics.";
5391 if(hardFailure) {
5392 InternalError(ss.str());
5393 } else {
5394 Warning() << ss.str() << endl;
5395 }
5396 }
5397 }
5398 Notice() << "SmtEngine::checkModel(): all assertions checked out OK !" << endl;
5399 }
5400
5401 void SmtEngine::checkSynthSolution()
5402 {
5403 NodeManager* nm = NodeManager::currentNM();
5404 Notice() << "SmtEngine::checkSynthSolution(): checking synthesis solution" << endl;
5405 map<Node, Node> sol_map;
5406 /* Get solutions and build auxiliary vectors for substituting */
5407 d_theoryEngine->getSynthSolutions(sol_map);
5408 if (sol_map.empty())
5409 {
5410 Trace("check-synth-sol") << "No solution to check!\n";
5411 return;
5412 }
5413 Trace("check-synth-sol") << "Got solution map:\n";
5414 std::vector<Node> function_vars, function_sols;
5415 for (const auto& pair : sol_map)
5416 {
5417 Trace("check-synth-sol") << pair.first << " --> " << pair.second << "\n";
5418 function_vars.push_back(pair.first);
5419 function_sols.push_back(pair.second);
5420 }
5421 Trace("check-synth-sol") << "Starting new SMT Engine\n";
5422 /* Start new SMT engine to check solutions */
5423 SmtEngine solChecker(d_exprManager);
5424 solChecker.setLogic(getLogicInfo());
5425 setOption("check-synth-sol", SExpr("false"));
5426
5427 Trace("check-synth-sol") << "Retrieving assertions\n";
5428 // Build conjecture from original assertions
5429 if (d_assertionList == NULL)
5430 {
5431 Trace("check-synth-sol") << "No assertions to check\n";
5432 return;
5433 }
5434 for (AssertionList::const_iterator i = d_assertionList->begin();
5435 i != d_assertionList->end();
5436 ++i)
5437 {
5438 Notice() << "SmtEngine::checkSynthSolution(): checking assertion " << *i << endl;
5439 Trace("check-synth-sol") << "Retrieving assertion " << *i << "\n";
5440 Node conj = Node::fromExpr(*i);
5441 // Apply any define-funs from the problem.
5442 {
5443 unordered_map<Node, Node, NodeHashFunction> cache;
5444 conj = d_private->expandDefinitions(conj, cache);
5445 }
5446 Notice() << "SmtEngine::checkSynthSolution(): -- expands to " << conj << endl;
5447 Trace("check-synth-sol") << "Expanded assertion " << conj << "\n";
5448
5449 // Apply solution map to conjecture body
5450 Node conjBody;
5451 /* Whether property is quantifier free */
5452 if (conj[1].getKind() != kind::EXISTS)
5453 {
5454 conjBody = conj[1].substitute(function_vars.begin(),
5455 function_vars.end(),
5456 function_sols.begin(),
5457 function_sols.end());
5458 }
5459 else
5460 {
5461 conjBody = conj[1][1].substitute(function_vars.begin(),
5462 function_vars.end(),
5463 function_sols.begin(),
5464 function_sols.end());
5465
5466 /* Skolemize property */
5467 std::vector<Node> vars, skos;
5468 for (unsigned j = 0, size = conj[1][0].getNumChildren(); j < size; ++j)
5469 {
5470 vars.push_back(conj[1][0][j]);
5471 std::stringstream ss;
5472 ss << "sk_" << j;
5473 skos.push_back(nm->mkSkolem(ss.str(), conj[1][0][j].getType()));
5474 Trace("check-synth-sol") << "\tSkolemizing " << conj[1][0][j] << " to "
5475 << skos.back() << "\n";
5476 }
5477 conjBody = conjBody.substitute(
5478 vars.begin(), vars.end(), skos.begin(), skos.end());
5479 }
5480 Notice() << "SmtEngine::checkSynthSolution(): -- body substitutes to "
5481 << conjBody << endl;
5482 Trace("check-synth-sol") << "Substituted body of assertion to " << conjBody
5483 << "\n";
5484 solChecker.assertFormula(conjBody.toExpr());
5485 Result r = solChecker.checkSat();
5486 Notice() << "SmtEngine::checkSynthSolution(): result is " << r << endl;
5487 Trace("check-synth-sol") << "Satsifiability check: " << r << "\n";
5488 if (r.asSatisfiabilityResult().isUnknown())
5489 {
5490 InternalError(
5491 "SmtEngine::checkSynthSolution(): could not check solution, result "
5492 "unknown.");
5493 }
5494 else if (r.asSatisfiabilityResult().isSat())
5495 {
5496 InternalError(
5497 "SmtEngine::checkSynthSolution(): produced solution leads to "
5498 "satisfiable negated conjecture.");
5499 }
5500 solChecker.resetAssertions();
5501 }
5502 }
5503
5504 // TODO(#1108): Simplify the error reporting of this method.
5505 UnsatCore SmtEngine::getUnsatCore() {
5506 Trace("smt") << "SMT getUnsatCore()" << endl;
5507 SmtScope smts(this);
5508 finalOptionsAreSet();
5509 if(Dump.isOn("benchmark")) {
5510 Dump("benchmark") << GetUnsatCoreCommand();
5511 }
5512 #if IS_PROOFS_BUILD
5513 if(!options::unsatCores()) {
5514 throw ModalException("Cannot get an unsat core when produce-unsat-cores option is off.");
5515 }
5516 if(d_status.isNull() ||
5517 d_status.asSatisfiabilityResult() != Result::UNSAT ||
5518 d_problemExtended) {
5519 throw RecoverableModalException(
5520 "Cannot get an unsat core unless immediately preceded by UNSAT/VALID "
5521 "response.");
5522 }
5523
5524 d_proofManager->traceUnsatCore();// just to trigger core creation
5525 return UnsatCore(this, d_proofManager->extractUnsatCore());
5526 #else /* IS_PROOFS_BUILD */
5527 throw ModalException("This build of CVC4 doesn't have proof support (required for unsat cores).");
5528 #endif /* IS_PROOFS_BUILD */
5529 }
5530
5531 // TODO(#1108): Simplify the error reporting of this method.
5532 const Proof& SmtEngine::getProof()
5533 {
5534 Trace("smt") << "SMT getProof()" << endl;
5535 SmtScope smts(this);
5536 finalOptionsAreSet();
5537 if(Dump.isOn("benchmark")) {
5538 Dump("benchmark") << GetProofCommand();
5539 }
5540 #if IS_PROOFS_BUILD
5541 if(!options::proof()) {
5542 throw ModalException("Cannot get a proof when produce-proofs option is off.");
5543 }
5544 if(d_status.isNull() ||
5545 d_status.asSatisfiabilityResult() != Result::UNSAT ||
5546 d_problemExtended) {
5547 throw RecoverableModalException(
5548 "Cannot get a proof unless immediately preceded by UNSAT/VALID "
5549 "response.");
5550 }
5551
5552 return ProofManager::getProof(this);
5553 #else /* IS_PROOFS_BUILD */
5554 throw ModalException("This build of CVC4 doesn't have proof support.");
5555 #endif /* IS_PROOFS_BUILD */
5556 }
5557
5558 void SmtEngine::printInstantiations( std::ostream& out ) {
5559 SmtScope smts(this);
5560 if( options::instFormatMode()==INST_FORMAT_MODE_SZS ){
5561 out << "% SZS output start Proof for " << d_filename.c_str() << std::endl;
5562 }
5563 if( d_theoryEngine ){
5564 d_theoryEngine->printInstantiations( out );
5565 }else{
5566 Assert( false );
5567 }
5568 if( options::instFormatMode()==INST_FORMAT_MODE_SZS ){
5569 out << "% SZS output end Proof for " << d_filename.c_str() << std::endl;
5570 }
5571 }
5572
5573 void SmtEngine::printSynthSolution( std::ostream& out ) {
5574 SmtScope smts(this);
5575 if( d_theoryEngine ){
5576 d_theoryEngine->printSynthSolution( out );
5577 }else{
5578 Assert( false );
5579 }
5580 }
5581
5582 Expr SmtEngine::doQuantifierElimination(const Expr& e, bool doFull, bool strict)
5583 {
5584 SmtScope smts(this);
5585 if(!d_logic.isPure(THEORY_ARITH) && strict){
5586 Warning() << "Unexpected logic for quantifier elimination " << d_logic << endl;
5587 }
5588 Trace("smt-qe") << "Do quantifier elimination " << e << std::endl;
5589 Node n_e = Node::fromExpr( e );
5590 if (n_e.getKind() != kind::EXISTS && n_e.getKind() != kind::FORALL)
5591 {
5592 throw ModalException(
5593 "Expecting a quantified formula as argument to get-qe.");
5594 }
5595 //tag the quantified formula with the quant-elim attribute
5596 TypeNode t = NodeManager::currentNM()->booleanType();
5597 Node n_attr = NodeManager::currentNM()->mkSkolem("qe", t, "Auxiliary variable for qe attr.");
5598 std::vector< Node > node_values;
5599 d_theoryEngine->setUserAttribute( doFull ? "quant-elim" : "quant-elim-partial", n_attr, node_values, "");
5600 n_attr = NodeManager::currentNM()->mkNode(kind::INST_ATTRIBUTE, n_attr);
5601 n_attr = NodeManager::currentNM()->mkNode(kind::INST_PATTERN_LIST, n_attr);
5602 std::vector< Node > e_children;
5603 e_children.push_back( n_e[0] );
5604 e_children.push_back(n_e.getKind() == kind::EXISTS ? n_e[1]
5605 : n_e[1].negate());
5606 e_children.push_back( n_attr );
5607 Node nn_e = NodeManager::currentNM()->mkNode( kind::EXISTS, e_children );
5608 Trace("smt-qe-debug") << "Query for quantifier elimination : " << nn_e << std::endl;
5609 Assert( nn_e.getNumChildren()==3 );
5610 Result r = checkSatisfiability(nn_e.toExpr(), true, true);
5611 Trace("smt-qe") << "Query returned " << r << std::endl;
5612 if(r.asSatisfiabilityResult().isSat() != Result::UNSAT ) {
5613 if( r.asSatisfiabilityResult().isSat() != Result::SAT && doFull ){
5614 stringstream ss;
5615 ss << "While performing quantifier elimination, unexpected result : " << r << " for query.";
5616 InternalError(ss.str().c_str());
5617 }
5618 std::vector< Node > inst_qs;
5619 d_theoryEngine->getInstantiatedQuantifiedFormulas( inst_qs );
5620 Assert( inst_qs.size()<=1 );
5621 Node ret_n;
5622 if( inst_qs.size()==1 ){
5623 Node top_q = inst_qs[0];
5624 //Node top_q = Rewriter::rewrite( nn_e ).negate();
5625 Assert( top_q.getKind()==kind::FORALL );
5626 Trace("smt-qe") << "Get qe for " << top_q << std::endl;
5627 ret_n = d_theoryEngine->getInstantiatedConjunction( top_q );
5628 Trace("smt-qe") << "Returned : " << ret_n << std::endl;
5629 if (n_e.getKind() == kind::EXISTS)
5630 {
5631 ret_n = Rewriter::rewrite(ret_n.negate());
5632 }
5633 }else{
5634 ret_n = NodeManager::currentNM()->mkConst(n_e.getKind() != kind::EXISTS);
5635 }
5636 return ret_n.toExpr();
5637 }else {
5638 return NodeManager::currentNM()
5639 ->mkConst(n_e.getKind() == kind::EXISTS)
5640 .toExpr();
5641 }
5642 }
5643
5644 void SmtEngine::getInstantiatedQuantifiedFormulas( std::vector< Expr >& qs ) {
5645 SmtScope smts(this);
5646 if( d_theoryEngine ){
5647 std::vector< Node > qs_n;
5648 d_theoryEngine->getInstantiatedQuantifiedFormulas( qs_n );
5649 for( unsigned i=0; i<qs_n.size(); i++ ){
5650 qs.push_back( qs_n[i].toExpr() );
5651 }
5652 }else{
5653 Assert( false );
5654 }
5655 }
5656
5657 void SmtEngine::getInstantiations( Expr q, std::vector< Expr >& insts ) {
5658 SmtScope smts(this);
5659 if( d_theoryEngine ){
5660 std::vector< Node > insts_n;
5661 d_theoryEngine->getInstantiations( Node::fromExpr( q ), insts_n );
5662 for( unsigned i=0; i<insts_n.size(); i++ ){
5663 insts.push_back( insts_n[i].toExpr() );
5664 }
5665 }else{
5666 Assert( false );
5667 }
5668 }
5669
5670 void SmtEngine::getInstantiationTermVectors( Expr q, std::vector< std::vector< Expr > >& tvecs ) {
5671 SmtScope smts(this);
5672 Assert(options::trackInstLemmas());
5673 if( d_theoryEngine ){
5674 std::vector< std::vector< Node > > tvecs_n;
5675 d_theoryEngine->getInstantiationTermVectors( Node::fromExpr( q ), tvecs_n );
5676 for( unsigned i=0; i<tvecs_n.size(); i++ ){
5677 std::vector< Expr > tvec;
5678 for( unsigned j=0; j<tvecs_n[i].size(); j++ ){
5679 tvec.push_back( tvecs_n[i][j].toExpr() );
5680 }
5681 tvecs.push_back( tvec );
5682 }
5683 }else{
5684 Assert( false );
5685 }
5686 }
5687
5688 vector<Expr> SmtEngine::getAssertions() {
5689 SmtScope smts(this);
5690 finalOptionsAreSet();
5691 doPendingPops();
5692 if(Dump.isOn("benchmark")) {
5693 Dump("benchmark") << GetAssertionsCommand();
5694 }
5695 Trace("smt") << "SMT getAssertions()" << endl;
5696 if(!options::produceAssertions()) {
5697 const char* msg =
5698 "Cannot query the current assertion list when not in produce-assertions mode.";
5699 throw ModalException(msg);
5700 }
5701 Assert(d_assertionList != NULL);
5702 // copy the result out
5703 return vector<Expr>(d_assertionList->begin(), d_assertionList->end());
5704 }
5705
5706 void SmtEngine::push()
5707 {
5708 SmtScope smts(this);
5709 finalOptionsAreSet();
5710 doPendingPops();
5711 Trace("smt") << "SMT push()" << endl;
5712 d_private->notifyPush();
5713 d_private->processAssertions();
5714 if(Dump.isOn("benchmark")) {
5715 Dump("benchmark") << PushCommand();
5716 }
5717 if(!options::incrementalSolving()) {
5718 throw ModalException("Cannot push when not solving incrementally (use --incremental)");
5719 }
5720
5721 // check to see if a postsolve() is pending
5722 if(d_needPostsolve) {
5723 d_theoryEngine->postsolve();
5724 d_needPostsolve = false;
5725 }
5726
5727 // The problem isn't really "extended" yet, but this disallows
5728 // get-model after a push, simplifying our lives somewhat and
5729 // staying symmtric with pop.
5730 setProblemExtended(true);
5731
5732 d_userLevels.push_back(d_userContext->getLevel());
5733 internalPush();
5734 Trace("userpushpop") << "SmtEngine: pushed to level "
5735 << d_userContext->getLevel() << endl;
5736 }
5737
5738 void SmtEngine::pop() {
5739 SmtScope smts(this);
5740 finalOptionsAreSet();
5741 Trace("smt") << "SMT pop()" << endl;
5742 if(Dump.isOn("benchmark")) {
5743 Dump("benchmark") << PopCommand();
5744 }
5745 if(!options::incrementalSolving()) {
5746 throw ModalException("Cannot pop when not solving incrementally (use --incremental)");
5747 }
5748 if(d_userLevels.size() == 0) {
5749 throw ModalException("Cannot pop beyond the first user frame");
5750 }
5751
5752 // check to see if a postsolve() is pending
5753 if(d_needPostsolve) {
5754 d_theoryEngine->postsolve();
5755 d_needPostsolve = false;
5756 }
5757
5758 // The problem isn't really "extended" yet, but this disallows
5759 // get-model after a pop, simplifying our lives somewhat. It might
5760 // not be strictly necessary to do so, since the pops occur lazily,
5761 // but also it would be weird to have a legally-executed (get-model)
5762 // that only returns a subset of the assignment (because the rest
5763 // is no longer in scope!).
5764 setProblemExtended(true);
5765
5766 AlwaysAssert(d_userContext->getLevel() > 0);
5767 AlwaysAssert(d_userLevels.back() < d_userContext->getLevel());
5768 while (d_userLevels.back() < d_userContext->getLevel()) {
5769 internalPop(true);
5770 }
5771 d_userLevels.pop_back();
5772
5773 // Clear out assertion queues etc., in case anything is still in there
5774 d_private->notifyPop();
5775
5776 Trace("userpushpop") << "SmtEngine: popped to level "
5777 << d_userContext->getLevel() << endl;
5778 // FIXME: should we reset d_status here?
5779 // SMT-LIBv2 spec seems to imply no, but it would make sense to..
5780 }
5781
5782 void SmtEngine::internalPush() {
5783 Assert(d_fullyInited);
5784 Trace("smt") << "SmtEngine::internalPush()" << endl;
5785 doPendingPops();
5786 if(options::incrementalSolving()) {
5787 d_private->processAssertions();
5788 TimerStat::CodeTimer pushPopTimer(d_stats->d_pushPopTime);
5789 d_userContext->push();
5790 // the d_context push is done inside of the SAT solver
5791 d_propEngine->push();
5792 }
5793 }
5794
5795 void SmtEngine::internalPop(bool immediate) {
5796 Assert(d_fullyInited);
5797 Trace("smt") << "SmtEngine::internalPop()" << endl;
5798 if(options::incrementalSolving()) {
5799 ++d_pendingPops;
5800 }
5801 if(immediate) {
5802 doPendingPops();
5803 }
5804 }
5805
5806 void SmtEngine::doPendingPops() {
5807 Assert(d_pendingPops == 0 || options::incrementalSolving());
5808 while(d_pendingPops > 0) {
5809 TimerStat::CodeTimer pushPopTimer(d_stats->d_pushPopTime);
5810 d_propEngine->pop();
5811 // the d_context pop is done inside of the SAT solver
5812 d_userContext->pop();
5813 --d_pendingPops;
5814 }
5815 }
5816
5817 void SmtEngine::reset()
5818 {
5819 SmtScope smts(this);
5820 ExprManager *em = d_exprManager;
5821 Trace("smt") << "SMT reset()" << endl;
5822 if(Dump.isOn("benchmark")) {
5823 Dump("benchmark") << ResetCommand();
5824 }
5825 Options opts;
5826 opts.copyValues(d_originalOptions);
5827 this->~SmtEngine();
5828 NodeManager::fromExprManager(em)->getOptions().copyValues(opts);
5829 new(this) SmtEngine(em);
5830 }
5831
5832 void SmtEngine::resetAssertions()
5833 {
5834 SmtScope smts(this);
5835 doPendingPops();
5836
5837 Trace("smt") << "SMT resetAssertions()" << endl;
5838 if(Dump.isOn("benchmark")) {
5839 Dump("benchmark") << ResetAssertionsCommand();
5840 }
5841
5842 while(!d_userLevels.empty()) {
5843 pop();
5844 }
5845
5846 // Also remember the global push/pop around everything.
5847 Assert(d_userLevels.size() == 0 && d_userContext->getLevel() == 1);
5848 d_context->popto(0);
5849 d_userContext->popto(0);
5850 DeleteAndClearCommandVector(d_modelGlobalCommands);
5851 d_userContext->push();
5852 d_context->push();
5853 }
5854
5855 void SmtEngine::interrupt()
5856 {
5857 if(!d_fullyInited) {
5858 return;
5859 }
5860 d_propEngine->interrupt();
5861 d_theoryEngine->interrupt();
5862 }
5863
5864 void SmtEngine::setResourceLimit(unsigned long units, bool cumulative) {
5865 d_private->getResourceManager()->setResourceLimit(units, cumulative);
5866 }
5867 void SmtEngine::setTimeLimit(unsigned long milis, bool cumulative) {
5868 d_private->getResourceManager()->setTimeLimit(milis, cumulative);
5869 }
5870
5871 unsigned long SmtEngine::getResourceUsage() const {
5872 return d_private->getResourceManager()->getResourceUsage();
5873 }
5874
5875 unsigned long SmtEngine::getTimeUsage() const {
5876 return d_private->getResourceManager()->getTimeUsage();
5877 }
5878
5879 unsigned long SmtEngine::getResourceRemaining() const
5880 {
5881 return d_private->getResourceManager()->getResourceRemaining();
5882 }
5883
5884 unsigned long SmtEngine::getTimeRemaining() const
5885 {
5886 return d_private->getResourceManager()->getTimeRemaining();
5887 }
5888
5889 Statistics SmtEngine::getStatistics() const
5890 {
5891 return Statistics(*d_statisticsRegistry);
5892 }
5893
5894 SExpr SmtEngine::getStatistic(std::string name) const
5895 {
5896 return d_statisticsRegistry->getStatistic(name);
5897 }
5898
5899 void SmtEngine::safeFlushStatistics(int fd) const {
5900 d_statisticsRegistry->safeFlushInformation(fd);
5901 }
5902
5903 void SmtEngine::setUserAttribute(const std::string& attr,
5904 Expr expr,
5905 const std::vector<Expr>& expr_values,
5906 const std::string& str_value)
5907 {
5908 SmtScope smts(this);
5909 std::vector<Node> node_values;
5910 for( unsigned i=0; i<expr_values.size(); i++ ){
5911 node_values.push_back( expr_values[i].getNode() );
5912 }
5913 d_theoryEngine->setUserAttribute(attr, expr.getNode(), node_values, str_value);
5914 }
5915
5916 void SmtEngine::setPrintFuncInModel(Expr f, bool p) {
5917 Trace("setp-model") << "Set printInModel " << f << " to " << p << std::endl;
5918 for( unsigned i=0; i<d_modelGlobalCommands.size(); i++ ){
5919 Command * c = d_modelGlobalCommands[i];
5920 DeclareFunctionCommand* dfc = dynamic_cast<DeclareFunctionCommand*>(c);
5921 if(dfc != NULL) {
5922 if( dfc->getFunction()==f ){
5923 dfc->setPrintInModel( p );
5924 }
5925 }
5926 }
5927 for( unsigned i=0; i<d_modelCommands->size(); i++ ){
5928 Command * c = (*d_modelCommands)[i];
5929 DeclareFunctionCommand* dfc = dynamic_cast<DeclareFunctionCommand*>(c);
5930 if(dfc != NULL) {
5931 if( dfc->getFunction()==f ){
5932 dfc->setPrintInModel( p );
5933 }
5934 }
5935 }
5936 }
5937
5938 void SmtEngine::beforeSearch()
5939 {
5940 if(d_fullyInited) {
5941 throw ModalException(
5942 "SmtEngine::beforeSearch called after initialization.");
5943 }
5944 }
5945
5946
5947 void SmtEngine::setOption(const std::string& key, const CVC4::SExpr& value)
5948 {
5949 NodeManagerScope nms(d_nodeManager);
5950 Trace("smt") << "SMT setOption(" << key << ", " << value << ")" << endl;
5951
5952 if(Dump.isOn("benchmark")) {
5953 Dump("benchmark") << SetOptionCommand(key, value);
5954 }
5955
5956 if(key == "command-verbosity") {
5957 if(!value.isAtom()) {
5958 const vector<SExpr>& cs = value.getChildren();
5959 if(cs.size() == 2 &&
5960 (cs[0].isKeyword() || cs[0].isString()) &&
5961 cs[1].isInteger()) {
5962 string c = cs[0].getValue();
5963 const Integer& v = cs[1].getIntegerValue();
5964 if(v < 0 || v > 2) {
5965 throw OptionException("command-verbosity must be 0, 1, or 2");
5966 }
5967 d_commandVerbosity[c] = v;
5968 return;
5969 }
5970 }
5971 throw OptionException("command-verbosity value must be a tuple (command-name, integer)");
5972 }
5973
5974 if(!value.isAtom()) {
5975 throw OptionException("bad value for :" + key);
5976 }
5977
5978 string optionarg = value.getValue();
5979 Options& nodeManagerOptions = NodeManager::currentNM()->getOptions();
5980 nodeManagerOptions.setOption(key, optionarg);
5981 }
5982
5983 CVC4::SExpr SmtEngine::getOption(const std::string& key) const
5984 {
5985 NodeManagerScope nms(d_nodeManager);
5986
5987 Trace("smt") << "SMT getOption(" << key << ")" << endl;
5988
5989 if(key.length() >= 18 &&
5990 key.compare(0, 18, "command-verbosity:") == 0) {
5991 map<string, Integer>::const_iterator i = d_commandVerbosity.find(key.c_str() + 18);
5992 if(i != d_commandVerbosity.end()) {
5993 return SExpr((*i).second);
5994 }
5995 i = d_commandVerbosity.find("*");
5996 if(i != d_commandVerbosity.end()) {
5997 return SExpr((*i).second);
5998 }
5999 return SExpr(Integer(2));
6000 }
6001
6002 if(Dump.isOn("benchmark")) {
6003 Dump("benchmark") << GetOptionCommand(key);
6004 }
6005
6006 if(key == "command-verbosity") {
6007 vector<SExpr> result;
6008 SExpr defaultVerbosity;
6009 for(map<string, Integer>::const_iterator i = d_commandVerbosity.begin();
6010 i != d_commandVerbosity.end();
6011 ++i) {
6012 vector<SExpr> v;
6013 v.push_back(SExpr((*i).first));
6014 v.push_back(SExpr((*i).second));
6015 if((*i).first == "*") {
6016 // put the default at the end of the SExpr
6017 defaultVerbosity = SExpr(v);
6018 } else {
6019 result.push_back(SExpr(v));
6020 }
6021 }
6022 // put the default at the end of the SExpr
6023 if(!defaultVerbosity.isAtom()) {
6024 result.push_back(defaultVerbosity);
6025 } else {
6026 // ensure the default is always listed
6027 vector<SExpr> v;
6028 v.push_back(SExpr("*"));
6029 v.push_back(SExpr(Integer(2)));
6030 result.push_back(SExpr(v));
6031 }
6032 return SExpr(result);
6033 }
6034
6035 Options& nodeManagerOptions = NodeManager::currentNM()->getOptions();
6036 return SExpr::parseAtom(nodeManagerOptions.getOption(key));
6037 }
6038
6039 void SmtEngine::setReplayStream(ExprStream* replayStream) {
6040 AlwaysAssert(!d_fullyInited,
6041 "Cannot set replay stream once fully initialized");
6042 d_replayStream = replayStream;
6043 }
6044
6045 bool SmtEngine::getExpressionName(Expr e, std::string& name) const {
6046 return d_private->getExpressionName(e, name);
6047 }
6048
6049 void SmtEngine::setExpressionName(Expr e, const std::string& name) {
6050 Trace("smt-debug") << "Set expression name " << e << " to " << name << std::endl;
6051 d_private->setExpressionName(e,name);
6052 }
6053
6054 }/* CVC4 namespace */