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