Branch data Line data Source code
1 : : /****************************************************************************** 2 : : * This file is part of the cvc5 project. 3 : : * 4 : : * Copyright (c) 2009-2026 by the authors listed in the file AUTHORS 5 : : * in the top-level source directory and their institutional affiliations. 6 : : * All rights reserved. See the file COPYING in the top-level source 7 : : * directory for licensing information. 8 : : * **************************************************************************** 9 : : * 10 : : * The solver for SMT queries in an SolverEngine. 11 : : */ 12 : : 13 : : #include "smt/smt_solver.h" 14 : : 15 : : #include "options/arith_options.h" 16 : : #include "options/arrays_options.h" 17 : : #include "options/bags_options.h" 18 : : #include "options/base_options.h" 19 : : #include "options/datatypes_options.h" 20 : : #include "options/ff_options.h" 21 : : #include "options/fp_options.h" 22 : : #include "options/main_options.h" 23 : : #include "options/sets_options.h" 24 : : #include "options/smt_options.h" 25 : : #include "preprocessing/assertion_pipeline.h" 26 : : #include "prop/prop_engine.h" 27 : : #include "smt/assertions.h" 28 : : #include "smt/env.h" 29 : : #include "smt/logic_exception.h" 30 : : #include "smt/preprocessor.h" 31 : : #include "smt/proof_manager.h" 32 : : #include "smt/solver_engine_stats.h" 33 : : #include "theory/logic_info.h" 34 : : #include "theory/theory_engine.h" 35 : : #include "theory/theory_traits.h" 36 : : 37 : : using namespace std; 38 : : 39 : : namespace cvc5::internal { 40 : : namespace smt { 41 : : 42 : 76237 : SmtSolver::SmtSolver(Env& env, SolverEngineStatistics& stats) 43 : : : EnvObj(env), 44 : 76237 : d_pp(env, stats), 45 : 76237 : d_asserts(env), 46 : 76237 : d_stats(stats), 47 : 76237 : d_theoryEngine(nullptr), 48 : 76237 : d_propEngine(nullptr), 49 : 76237 : d_ppAssertions(userContext()), 50 : 152474 : d_ppSkolemMap(userContext()) 51 : : { 52 : 76237 : } 53 : : 54 : 142300 : SmtSolver::~SmtSolver() {} 55 : : 56 : 51330 : void SmtSolver::finishInit() 57 : : { 58 : : // We have mutual dependency here, so we add the prop engine to the theory 59 : : // engine later (it is non-essential there) 60 : 51330 : d_theoryEngine.reset(new TheoryEngine(d_env)); 61 : : 62 : : // Add the theories 63 [ + + ]: 769950 : for (theory::TheoryId id = theory::THEORY_FIRST; id < theory::THEORY_LAST; 64 : 718620 : ++id) 65 : : { 66 : 718620 : theory::TheoryConstructor::addTheory(d_theoryEngine.get(), id); 67 : : } 68 : : // Add the proof checkers for each theory 69 : 51330 : ProofNodeManager* pnm = d_env.getProofNodeManager(); 70 [ + + ]: 51330 : if (pnm) 71 : : { 72 : : // reset the rule checkers 73 : 20032 : pnm->getChecker()->reset(); 74 : : // add rule checkers from the theory engine 75 : 20032 : d_theoryEngine->initializeProofChecker(pnm->getChecker()); 76 : : } 77 [ + - ]: 51330 : Trace("smt-debug") << "Making prop engine..." << std::endl; 78 : : /* force destruction of referenced PropEngine to enforce that statistics 79 : : * are unregistered by the obsolete PropEngine object before registered 80 : : * again by the new PropEngine object */ 81 : 51330 : d_propEngine.reset(nullptr); 82 : 51330 : d_propEngine.reset(new prop::PropEngine(d_env, d_theoryEngine.get())); 83 : : 84 [ + - ]: 51330 : Trace("smt-debug") << "Setting up theory engine..." << std::endl; 85 : 51330 : d_theoryEngine->setPropEngine(getPropEngine()); 86 [ + - ]: 51330 : Trace("smt-debug") << "Finishing init for theory engine..." << std::endl; 87 : 51330 : d_theoryEngine->finishInit(); 88 : 51330 : d_propEngine->finishInit(); 89 : 51330 : finishInitPreprocessor(); 90 : : 91 [ - + ]: 51330 : if (options().proof.proofLog) 92 : : { 93 : 0 : smt::PfManager* pm = d_env.getProofManager(); 94 [ - - ]: 0 : if (pm != nullptr) 95 : : { 96 : : // Logs proofs on the base output stream of the solver 97 : 0 : pm->startProofLogging(options().base.out, d_asserts); 98 : : } 99 : : } 100 : 51330 : } 101 : : 102 : 689 : void SmtSolver::resetAssertions() 103 : : { 104 : : /* Create new PropEngine. 105 : : * First force destruction of referenced PropEngine to enforce that 106 : : * statistics are unregistered by the obsolete PropEngine object before 107 : : * registered again by the new PropEngine object */ 108 : 689 : d_propEngine.reset(nullptr); 109 : 689 : d_propEngine.reset(new prop::PropEngine(d_env, d_theoryEngine.get())); 110 : 689 : d_theoryEngine->setPropEngine(getPropEngine()); 111 : : // Notice that we do not reset TheoryEngine, nor does it require calling 112 : : // finishInit again. In particular, TheoryEngine::finishInit does not 113 : : // depend on knowing the associated PropEngine. 114 : 689 : d_propEngine->finishInit(); 115 : : // must reset the preprocessor as well 116 : 689 : finishInitPreprocessor(); 117 : 689 : } 118 : : 119 : 312214 : void SmtSolver::interrupt() 120 : : { 121 [ + - ]: 312214 : if (d_propEngine != nullptr) 122 : : { 123 : 312214 : d_propEngine->interrupt(); 124 : : } 125 [ + - ]: 312214 : if (d_theoryEngine != nullptr) 126 : : { 127 : 312214 : d_theoryEngine->interrupt(); 128 : : } 129 : 312214 : } 130 : : 131 : 50761 : Result SmtSolver::checkSatInternal() 132 : : { 133 : : // call the prop engine to check sat 134 : 50761 : return d_propEngine->checkSat(); 135 : : } 136 : : 137 : 65948 : void SmtSolver::preprocess(preprocessing::AssertionPipeline& ap) 138 : : { 139 : 65948 : TimerStat::CodeTimer paTimer(d_stats.d_processAssertionsTime); 140 : 65948 : d_env.getResourceManager()->spendResource(Resource::PreprocessStep); 141 : : 142 : : // process the assertions with the preprocessor 143 : 65948 : d_pp.process(ap); 144 : : 145 : : // end: INVARIANT to maintain: no reordering of assertions or 146 : : // introducing new ones 147 : 65948 : } 148 : : 149 : 65917 : void SmtSolver::assertToInternal(preprocessing::AssertionPipeline& ap) 150 : : { 151 : : // carry information about soundness to the theory engine we are sending to 152 [ + + ]: 65917 : if (ap.isRefutationUnsound()) 153 : : { 154 : 43 : d_theoryEngine->setRefutationUnsound(theory::IncompleteId::PREPROCESSING); 155 : : } 156 [ - + ]: 65917 : if (ap.isModelUnsound()) 157 : : { 158 : 0 : d_theoryEngine->setModelUnsound(theory::IncompleteId::PREPROCESSING); 159 : : } 160 : : // get the assertions 161 : 65917 : const std::vector<Node>& assertions = ap.ref(); 162 : 65917 : preprocessing::IteSkolemMap& ism = ap.getIteSkolemMap(); 163 : : // assert to prop engine, which will convert to CNF 164 : 65917 : d_env.verbose(2) << "converting to CNF..." << endl; 165 : 65917 : d_propEngine->assertInputFormulas(assertions, ism); 166 : : 167 : : // It is important to distinguish the input assertions from the skolem 168 : : // definitions, as the decision justification heuristic treates the latter 169 : : // specially. Note that we don't pass the preprocess learned literals 170 : : // d_pp.getLearnedLiterals() here, since they may not exactly correspond 171 : : // to the actual preprocessed learned literals, as the input may have 172 : : // undergone further preprocessing. 173 : : // if we can deep restart, we always remember the preprocessed formulas, 174 : : // which are the basis for the next check-sat. 175 [ + + ]: 65901 : if (trackPreprocessedAssertions()) 176 : : { 177 : : // incompatible with global negation 178 [ - + ][ - + ]: 26996 : Assert(!options().quantifiers.globalNegate); [ - - ] 179 : 26996 : theory::SubstitutionMap& sm = d_env.getTopLevelSubstitutions().get(); 180 : 26996 : size_t startIndex = d_ppAssertions.size(); 181 : : // remember the assertions and Skolem mapping 182 [ + + ]: 297755 : for (const Node& a : assertions) 183 : : { 184 : 270759 : d_ppAssertions.push_back(a); 185 : : } 186 [ + + ]: 44102 : for (const std::pair<const size_t, Node>& k : ism) 187 : : { 188 : : // optimization: skip skolems that were eliminated in preprocessing 189 [ - + ]: 17106 : if (sm.hasSubstitution(k.second)) 190 : : { 191 : 0 : continue; 192 : : } 193 : 17106 : size_t newIndex = k.first + startIndex; 194 : 17106 : d_ppSkolemMap[newIndex] = k.second; 195 : : } 196 : : } 197 : 65901 : } 198 : : 199 : 695 : const context::CDList<Node>& SmtSolver::getPreprocessedAssertions() const 200 : : { 201 : 695 : return d_ppAssertions; 202 : : } 203 : : 204 : 683 : const context::CDHashMap<size_t, Node>& SmtSolver::getPreprocessedSkolemMap() 205 : : const 206 : : { 207 : 683 : return d_ppSkolemMap; 208 : : } 209 : : 210 : 65901 : bool SmtSolver::trackPreprocessedAssertions() const 211 : : { 212 : 65901 : return options().smt.deepRestartMode != options::DeepRestartMode::NONE 213 [ + + ][ + + ]: 65901 : || options().smt.produceProofs; 214 : : } 215 : : 216 : 27248 : TheoryEngine* SmtSolver::getTheoryEngine() { return d_theoryEngine.get(); } 217 : : 218 : 126904 : prop::PropEngine* SmtSolver::getPropEngine() { return d_propEngine.get(); } 219 : : 220 : 3434 : theory::QuantifiersEngine* SmtSolver::getQuantifiersEngine() 221 : : { 222 [ - + ][ - + ]: 3434 : Assert(d_theoryEngine != nullptr); [ - - ] 223 : 3434 : return d_theoryEngine->getQuantifiersEngine(); 224 : : } 225 : : 226 : 147762 : Preprocessor* SmtSolver::getPreprocessor() { return &d_pp; } 227 : : 228 : 409256 : Assertions& SmtSolver::getAssertions() { return d_asserts; } 229 : : 230 : 8227 : void SmtSolver::pushPropContext() 231 : : { 232 : 8227 : TimerStat::CodeTimer pushPopTimer(d_stats.d_pushPopTime); 233 [ - + ][ - + ]: 8227 : Assert(d_propEngine != nullptr); [ - - ] 234 : 8227 : d_propEngine->push(); 235 : 8227 : } 236 : : 237 : 8220 : void SmtSolver::popPropContext() 238 : : { 239 : 8220 : TimerStat::CodeTimer pushPopTimer(d_stats.d_pushPopTime); 240 [ - + ][ - + ]: 8220 : Assert(d_propEngine != nullptr); [ - - ] 241 : 8220 : d_propEngine->pop(); 242 : 8220 : } 243 : : 244 : 49865 : void SmtSolver::resetTrail() 245 : : { 246 [ - + ][ - + ]: 49865 : Assert(d_propEngine != nullptr); [ - - ] 247 : 49865 : d_propEngine->resetTrail(); 248 : 49865 : } 249 : : 250 : 52019 : void SmtSolver::finishInitPreprocessor() 251 : : { 252 : : // determine if we are assigning a preprocess proof generator here 253 : 52019 : smt::PfManager* pm = d_env.getProofManager(); 254 : 52019 : smt::PreprocessProofGenerator* pppg = nullptr; 255 [ + + ]: 52019 : if (pm != nullptr) 256 : : { 257 : 20274 : pppg = pm->getPreprocessProofGenerator(); 258 : : } 259 : 52019 : d_pp.finishInit(d_theoryEngine.get(), d_propEngine.get(), pppg); 260 : 52019 : } 261 : : 262 : : } // namespace smt 263 : : } // namespace cvc5::internal