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