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