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