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