Branch data Line data Source code
1 : : /****************************************************************************** 2 : : * Top contributors (to current version): 3 : : * Andrew Reynolds, Gereon Kremer, Morgan Deters 4 : : * 5 : : * This file is part of the cvc5 project. 6 : : * 7 : : * Copyright (c) 2009-2025 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. 11 : : * **************************************************************************** 12 : : * 13 : : * An additional layer between commands and invoking them. 14 : : */ 15 : : 16 : : #include "main/command_executor.h" 17 : : 18 : : #ifndef __WIN32__ 19 : : # include <sys/resource.h> 20 : : #endif /* ! __WIN32__ */ 21 : : 22 : : #include <cvc5/cvc5_parser.h> 23 : : 24 : : #include <iomanip> 25 : : #include <iostream> 26 : : #include <memory> 27 : : #include <string> 28 : : #include <vector> 29 : : 30 : : #include "base/output.h" 31 : : #include "main/main.h" 32 : : #include "parser/commands.h" 33 : : #include "smt/solver_engine.h" 34 : : 35 : : using namespace cvc5::parser; 36 : : 37 : : namespace cvc5::main { 38 : : 39 : : // Function to cancel any (externally-imposed) limit on CPU time. 40 : : // This is used for competitions while a solution (proof or model) 41 : : // is being dumped (so that we don't give "sat" or "unsat" then get 42 : : // interrupted partway through outputting a proof!). 43 : 0 : void setNoLimitCPU() { 44 : : // Windows doesn't have these things, just ignore 45 : : #ifndef __WIN32__ 46 : : struct rlimit rlc; 47 : 0 : int st = getrlimit(RLIMIT_CPU, &rlc); 48 [ - - ]: 0 : if(st == 0) { 49 : 0 : rlc.rlim_cur = rlc.rlim_max; 50 : 0 : setrlimit(RLIMIT_CPU, &rlc); 51 : : } 52 : : #endif /* ! __WIN32__ */ 53 : 0 : } 54 : : 55 : 27489 : CommandExecutor::CommandExecutor(std::unique_ptr<cvc5::Solver>& solver) 56 : : : d_solver(solver), 57 : 27489 : d_symman(new SymbolManager(d_solver->getTermManager())), 58 : : d_result(), 59 : 54978 : d_parseOnly(false) 60 : : { 61 : 27489 : } 62 : 54978 : CommandExecutor::~CommandExecutor() 63 : : { 64 : 54978 : } 65 : : 66 : 23615 : void CommandExecutor::storeOptionsAsOriginal() 67 : : { 68 : 23615 : d_solver->d_originalOptions->copyValues(d_solver->d_slv->getOptions()); 69 : : // cache the value of parse-only, which is set by the command line only 70 : : // and thus will not change in a run. 71 : 23615 : d_parseOnly = d_solver->getOptionInfo("parse-only").boolValue(); 72 : 23615 : } 73 : : 74 : 89345 : void CommandExecutor::setOptionInternal(const std::string& key, 75 : : const std::string& value) 76 : : { 77 : : // set option, marked not from user. 78 : 89345 : d_solver->d_slv->setOption(key, value, false); 79 : 89345 : } 80 : : 81 : 23567 : void CommandExecutor::printStatistics(std::ostream& out) const 82 : : { 83 [ - + ]: 23567 : if (d_solver->getOptionInfo("stats").boolValue()) 84 : : { 85 : : { 86 : 0 : const auto& stats = d_solver->getStatistics(); 87 : : auto it = 88 : 0 : stats.begin(d_solver->getOptionInfo("stats-internal").boolValue(), 89 : 0 : d_solver->getOptionInfo("stats-all").boolValue()); 90 [ - - ]: 0 : for (; it != stats.end(); ++it) 91 : : { 92 : 0 : out << it->first << " = " << it->second << std::endl; 93 : : } 94 : : } 95 : : { 96 : 0 : const auto& stats = d_solver->getTermManager().getStatistics(); 97 : : auto it = 98 : 0 : stats.begin(d_solver->getOptionInfo("stats-internal").boolValue(), 99 : 0 : d_solver->getOptionInfo("stats-all").boolValue()); 100 [ - - ]: 0 : for (; it != stats.end(); ++it) 101 : : { 102 : 0 : out << it->first << " = " << it->second << std::endl; 103 : : } 104 : : } 105 : : } 106 : 23567 : } 107 : : 108 : 0 : void CommandExecutor::printStatisticsSafe(int fd) const 109 : : { 110 [ - - ]: 0 : if (d_solver->getOptionInfo("stats").boolValue()) 111 : : { 112 : 0 : d_solver->getTermManager().printStatisticsSafe(fd); 113 : 0 : d_solver->printStatisticsSafe(fd); 114 : : } 115 : 0 : } 116 : : 117 : 701037 : bool CommandExecutor::doCommand(Command* cmd) 118 : : { 119 : : // formerly was guarded by verbosity > 2 120 [ + - ]: 701037 : Trace("cmd-exec") << "Invoking: " << *cmd << std::endl; 121 : 701037 : return doCommandSingleton(cmd->d_cmd.get()); 122 : : } 123 : : 124 : 0 : void CommandExecutor::reset() 125 : : { 126 : 0 : printStatistics(d_solver->getDriverOptions().err()); 127 : 0 : Cmd::resetSolver(d_solver.get()); 128 : 0 : } 129 : : 130 : 705659 : bool CommandExecutor::doCommandSingleton(Cmd* cmd) 131 : : { 132 : 705659 : bool status = solverInvoke(d_solver.get(), 133 : : d_symman->toSymManager(), 134 : : cmd, 135 : 705661 : d_solver->getDriverOptions().out()); 136 : : 137 : 1411310 : cvc5::Result res; 138 : 705657 : bool hasResult = false; 139 [ + - ]: 705657 : const CheckSatCommand* cs = dynamic_cast<const CheckSatCommand*>(cmd); 140 [ + + ]: 705657 : if (cs != nullptr) 141 : : { 142 : 26961 : d_result = res = cs->getResult(); 143 : 26961 : hasResult = true; 144 : : } 145 : : const CheckSatAssumingCommand* csa = 146 [ + - ]: 705657 : dynamic_cast<const CheckSatAssumingCommand*>(cmd); 147 [ + + ]: 705657 : if (csa != nullptr) 148 : : { 149 : 4453 : d_result = res = csa->getResult(); 150 : 4453 : hasResult = true; 151 : : } 152 : : 153 : : // if we didnt set a result, return the status 154 [ + + ]: 705657 : if (!hasResult) 155 : : { 156 : 674243 : return status; 157 : : } 158 : : 159 : : // dump the model/proof/unsat core if option is set 160 [ + + ]: 31414 : if (status) { 161 : 31367 : bool isResultUnsat = res.isUnsat(); 162 : 31367 : bool isResultSat = res.isSat(); 163 : 62734 : std::vector<std::unique_ptr<Cmd> > getterCommands; 164 : 62734 : if (d_solver->getOptionInfo("dump-models").boolValue() 165 [ + + ][ + + ]: 62744 : && (isResultSat [ + - ] 166 [ - + ]: 10 : || (res.isUnknown() 167 [ - - ]: 0 : && res.getUnknownExplanation() 168 : : == cvc5::UnknownExplanation::INCOMPLETE))) 169 : : { 170 : 10 : getterCommands.emplace_back(new GetModelCommand()); 171 : : } 172 : 31367 : if (d_solver->getOptionInfo("dump-proofs").boolValue() && isResultUnsat) 173 : : { 174 : 4582 : getterCommands.emplace_back(new GetProofCommand()); 175 : : } 176 : : 177 : 62734 : if ((d_solver->getOptionInfo("dump-instantiations").boolValue() 178 : 62710 : || d_solver->getOptionInfo("dump-instantiations-debug").boolValue()) 179 [ + + ][ + + ]: 94077 : && GetInstantiationsCommand::isEnabled(d_solver.get(), res)) [ + + ] 180 : : { 181 : 14 : getterCommands.emplace_back(new GetInstantiationsCommand()); 182 : : } 183 : : 184 : 62734 : if (d_solver->getOptionInfo("dump-unsat-cores").boolValue() 185 [ + + ][ + + ]: 62734 : && isResultUnsat) [ + - ] 186 : : { 187 : 4 : getterCommands.emplace_back(new GetUnsatCoreCommand()); 188 : : } 189 : : 190 : 62734 : if (d_solver->getOptionInfo("dump-unsat-cores-lemmas").boolValue() 191 [ - + ][ - - ]: 62734 : && isResultUnsat) [ + - ] 192 : : { 193 : 0 : getterCommands.emplace_back(new GetUnsatCoreLemmasCommand()); 194 : : } 195 : : 196 : 62734 : if (d_solver->getOptionInfo("dump-difficulty").boolValue() 197 [ + + ][ + + ]: 62734 : && (isResultUnsat || isResultSat || res.isUnknown())) [ + + ][ - + ] [ + - ] 198 : : { 199 : 12 : getterCommands.emplace_back(new GetDifficultyCommand()); 200 : : } 201 : : 202 [ + + ]: 31367 : if (!getterCommands.empty()) { 203 : : // set no time limit during dumping if applicable 204 [ - + ]: 4622 : if (d_solver->getOptionInfo("force-no-limit-cpu-while-dump").boolValue()) 205 : : { 206 : 0 : setNoLimitCPU(); 207 : : } 208 [ + + ]: 9244 : for (const auto& getterCommand : getterCommands) { 209 : 4622 : status = doCommandSingleton(getterCommand.get()); 210 [ - + ]: 4622 : if (!status) 211 : : { 212 : 0 : break; 213 : : } 214 : : } 215 : : } 216 : : } 217 : 31414 : return status; 218 : : } 219 : : 220 : 705659 : bool CommandExecutor::solverInvoke(cvc5::Solver* solver, 221 : : SymManager* sm, 222 : : Cmd* cmd, 223 : : std::ostream& out) 224 : : { 225 : : // print output for -o raw-benchmark 226 [ + + ]: 705659 : if (solver->isOutputOn("raw-benchmark")) 227 : : { 228 : 135252 : solver->getOutput("raw-benchmark") << cmd->toString() << std::endl; 229 : : } 230 : : 231 : : // In parse-only mode, we do not invoke any of the commands except define-* 232 : : // declare-*, set-logic, and reset commands. We invoke define-* and declare-* 233 : : // commands because they add function names to the symbol table. 234 [ + - ][ + + ]: 270436 : if (d_parseOnly && dynamic_cast<SetBenchmarkLogicCommand*>(cmd) == nullptr 235 [ + - ][ + + ]: 262644 : && dynamic_cast<ResetCommand*>(cmd) == nullptr 236 [ + - ][ + + ]: 262609 : && dynamic_cast<DeclarationDefinitionCommand*>(cmd) == nullptr 237 [ + - ][ + + ]: 98108 : && dynamic_cast<DatatypeDeclarationCommand*>(cmd) == nullptr 238 [ + + ][ + - ]: 976095 : && dynamic_cast<DefineFunctionRecCommand*>(cmd) == nullptr) [ + + ][ + + ] 239 : : { 240 : 96726 : return true; 241 : : } 242 : : 243 : 608933 : cmd->invoke(solver, sm, out); 244 : 608931 : return !cmd->fail(); 245 : : } 246 : : 247 : 23567 : void CommandExecutor::flushOutputStreams() { 248 : 23567 : printStatistics(d_solver->getDriverOptions().err()); 249 : : 250 : : // make sure out and err streams are flushed too 251 : 23567 : d_solver->getDriverOptions().out() << std::flush; 252 : 23567 : d_solver->getDriverOptions().err() << std::flush; 253 : 23567 : } 254 : : 255 : : } // namespace cvc5::main