#include <iostream>
#include <ostream>
#if VZ3
#include "z3++.h"
#endif
#include "Debug/TimeProfiling.hpp"
#include "Lib/Exception.hpp"
#include "Lib/Environment.hpp"
#include "Lib/Random.hpp"
#include "Lib/Timer.hpp"
#include "Lib/List.hpp"
#include "Lib/System.hpp"
#include "Lib/StringUtils.hpp"
#include "Lib/Sys/Multiprocessing.hpp"
#include "Lib/Int.hpp"
#include "Kernel/Clause.hpp"
#include "Kernel/Formula.hpp"
#include "Kernel/FormulaUnit.hpp"
#include "Kernel/Problem.hpp"
#include "Kernel/Signature.hpp"
#include "Kernel/Term.hpp"
#include "Inferences/InferenceEngine.hpp"
#include "Inferences/TautologyDeletionISE.hpp"
#include "CASC/PortfolioMode.hpp"
#include "Shell/CommandLine.hpp"
#include "Shell/Normalisation.hpp"
#include "Shell/Options.hpp"
#include "Shell/Property.hpp"
#include "Saturation/ProvingHelper.hpp"
#include "Shell/Preprocess.hpp"
#include "Shell/TheoryFinder.hpp"
#include "Shell/TPTPPrinter.hpp"
#include "Parse/TPTP.hpp"
#include "Shell/FOOLElimination.hpp"
#include "Shell/Statistics.hpp"
#include "Shell/UIHelper.hpp"
#include "Shell/SineUtils.hpp"
#include "Saturation/SaturationAlgorithm.hpp"
#include "FMB/ModelCheck.hpp"
using namespace std;
int vampireReturnValue = VAMP_RESULT_STATUS_UNKNOWN;
[[nodiscard]]
Problem* preprocessProblem(Problem* prb)
{
if (env.options->randomSeed() != 0) {
Lib::Random::setSeed(env.options->randomSeed());
} else {
Lib::Random::resetSeed();
}
TIME_TRACE(TimeTrace::PREPROCESSING);
if (env.options->mode() != Options::Mode::SPIDER) {
env.options->checkProblemOptionConstraints(prb->getProperty(), true);
}
Shell::Preprocess prepro(*env.options);
prepro.preprocess(*prb);
return prb;
}
void explainException(Exception& exception)
{
exception.cry(std::cout);
}
[[nodiscard]]
Problem *doProving(Problem* problem)
{
if (env.options->showPropDict()) {
cout << "% Prop: " << problem->getProperty()->toDict() << endl;
}
if (!env.options->strategySamplerFilename().empty()) {
env.options->sampleStrategy(env.options->strategySamplerFilename(),
problem->getProperty()->toDict());
}
env.options->setForcedOptionValues();
env.options->checkGlobalOptionConstraints();
Problem *prb = preprocessProblem(problem);
if (env.options->mode() != Options::Mode::SPIDER) {
env.options->checkProblemOptionConstraints(prb->getProperty(), false);
}
ProvingHelper::runVampireSaturation(*prb, *env.options);
return prb;
}
void profileMode(Problem* problem)
{
ScopedPtr<Problem> prb(problem);
Property* property = prb->getProperty();
Normalisation().normalise(*prb);
TheoryFinder(prb->units(), property).search();
std::cout << property->categoryString() << ' ' << property->props() << ' '
<< property->atoms() << "\n";
vampireReturnValue = VAMP_RESULT_STATUS_SUCCESS;
}
void preprocessMode(Problem* problem, bool theory)
{
ScopedPtr<Problem> prb(problem);
TIME_TRACE(TimeTrace::PREPROCESSING);
Shell::Preprocess prepro(*env.options);
prepro.turnClausifierOff();
if(env.options->mode() == Options::Mode::PREPROCESS2){
prepro.keepSimplifyStep();
}
prepro.preprocess(*prb);
UIHelper::outputSymbolDeclarations(std::cout);
UnitList::Iterator units(prb->units());
while (units.hasNext()) {
Unit* u = units.next();
if (!env.options->showFOOL()) {
if (u->inference().rule() == InferenceRule::FOOL_AXIOM_TRUE_NEQ_FALSE || u->inference().rule() == InferenceRule::FOOL_AXIOM_ALL_IS_TRUE_OR_FALSE) {
continue;
}
}
if (theory) {
Formula* f = u->getFormula();
if (u->inference().inputType() == UnitInputType::CONJECTURE) {
u->inference().setInputType(UnitInputType::NEGATED_CONJECTURE);
}
FormulaUnit* fu = new FormulaUnit(f,u->inference()); std::cout << TPTPPrinter::toString(fu) << "\n";
} else {
std::cout << TPTPPrinter::toString(u) << "\n";
}
}
vampireReturnValue = VAMP_RESULT_STATUS_SUCCESS;
}
void modelCheckMode(Problem* problem)
{
ScopedPtr<Problem> prb(problem);
if(env.getMainProblem()->hasPolymorphicSym() || env.getMainProblem()->isHigherOrder()){
USER_ERROR("Polymorphic Vampire is not yet compatible with theory reasoning");
}
FMB::ModelCheck::doCheck(prb->units());
}
void outputMode(Problem* problem)
{
ScopedPtr<Problem> prb(problem);
UIHelper::outputSymbolDeclarations(std::cout);
UnitList::Iterator units(prb->units());
while (units.hasNext()) {
Unit* u = units.next();
std::cout << TPTPPrinter::toString(u) << "\n";
}
vampireReturnValue = VAMP_RESULT_STATUS_SUCCESS;
}
void vampireMode(Problem* problem)
{
if (env.options->mode() == Options::Mode::CONSEQUENCE_ELIMINATION) {
env.options->setUnusedPredicateDefinitionRemoval(false);
}
ScopedPtr<Problem> prb(doProving(problem));
UIHelper::outputResult(std::cout);
if (env.statistics->terminationReason == TerminationReason::REFUTATION
|| env.statistics->terminationReason == TerminationReason::SATISFIABLE) {
vampireReturnValue = VAMP_RESULT_STATUS_SUCCESS;
}
}
void spiderMode(Problem* problem)
{
env.options->setBadOptionChoice(Options::BadOption::HARD);
env.options->setOutputMode(Options::Output::SPIDER);
env.options->setNormalize(true);
Exception* exception = 0;
#if VZ3
z3::exception* z3_exception = 0;
#endif
bool exceptionRaised = false;
ScopedPtr<Problem> prb;
try {
prb = doProving(problem);
} catch (Exception& e) {
exception = &e;
exceptionRaised = true;
#if VZ3
} catch(z3::exception& e){
z3_exception = &e;
exceptionRaised = true;
#endif
} catch (...) {
exceptionRaised = true;
}
if (!exceptionRaised) {
switch (env.statistics->terminationReason) {
case TerminationReason::REFUTATION:
reportSpiderStatus('+');
vampireReturnValue = VAMP_RESULT_STATUS_SUCCESS;
break;
case TerminationReason::TIME_LIMIT:
reportSpiderStatus('t');
break;
case TerminationReason::MEMORY_LIMIT:
reportSpiderStatus('m');
break;
case TerminationReason::UNKNOWN:
case TerminationReason::INAPPROPRIATE:
reportSpiderStatus('u');
break;
case TerminationReason::REFUTATION_NOT_FOUND:
if (env.statistics->discardedNonRedundantClauses > 0) {
reportSpiderStatus('n');
}
else{
reportSpiderStatus('i');
}
break;
case TerminationReason::SATISFIABLE:
reportSpiderStatus('-');
vampireReturnValue = VAMP_RESULT_STATUS_SUCCESS;
break;
default:
ASSERTION_VIOLATION;
}
return;
}
vampireReturnValue = VAMP_RESULT_STATUS_UNHANDLED_EXCEPTION;
#if VZ3
if (z3_exception) {
if (strcmp(z3_exception->msg(),"out of memory\n")) {
reportSpiderStatus('m');
}
else {
reportSpiderFail();
}
return;
}
#endif
reportSpiderFail();
ASS(exception);
explainException(*exception);
}
void clausifyMode(Problem* problem, bool theory)
{
CompositeISE simplifier;
simplifier.addFront(new TrivialInequalitiesRemovalISE());
simplifier.addFront(new TautologyDeletionISE());
simplifier.addFront(new DuplicateLiteralRemovalISE());
if (!env.options->strategySamplerFilename().empty()) {
env.options->sampleStrategy(env.options->strategySamplerFilename(),
problem->getProperty()->toDict());
}
ScopedPtr<Problem> prb(preprocessProblem(problem));
UIHelper::outputSymbolDeclarations(std::cout);
ClauseIterator cit = prb->clauseIterator();
bool printed_conjecture = false;
while (cit.hasNext()) {
Clause* cl = cit.next();
cl = simplifier.simplify(cl);
if (!cl) {
continue;
}
printed_conjecture |= cl->inputType() == UnitInputType::CONJECTURE || cl->inputType() == UnitInputType::NEGATED_CONJECTURE;
if (theory) {
Formula* f = Formula::fromClause(cl);
if (cl->inference().inputType() == UnitInputType::CONJECTURE) {
cl->inference().setInputType(UnitInputType::NEGATED_CONJECTURE);
}
FormulaUnit* fu = new FormulaUnit(f,cl->inference()); fu->overwriteNumber(cl->number()); std::cout << TPTPPrinter::toString(fu) << "\n";
} else {
std::cout << TPTPPrinter::toString(cl) << "\n";
}
}
if(!printed_conjecture && UIHelper::haveConjecture()){
unsigned p = env.signature->addFreshPredicate(0,"p");
auto c = Clause::fromLiterals({
Literal::create(p, true , {}),
Literal::create(p, false, {})
},
NonspecificInference0(UnitInputType::NEGATED_CONJECTURE,InferenceRule::INPUT));
std::cout << TPTPPrinter::toString(c) << "\n";
}
vampireReturnValue = VAMP_RESULT_STATUS_SUCCESS;
}
void axiomSelectionMode(Problem* problem)
{
ScopedPtr<Problem> prb(problem);
env.options->setSineSelection(Options::SineSelection::AXIOMS);
if (prb->hasFOOL()) {
FOOLElimination().apply(*prb);
}
if (env.options->normalize()) {
env.statistics->phase = ExecutionPhase::NORMALIZATION;
Normalisation norm;
norm.normalise(*prb);
}
env.statistics->phase = ExecutionPhase::SINE_SELECTION;
Shell::SineSelector(*env.options).perform(*prb);
env.statistics->phase = ExecutionPhase::FINALIZATION;
UnitList::Iterator uit(prb->units());
while (uit.hasNext()) {
Unit* u = uit.next();
std::cout << TPTPPrinter::toString(u) << "\n";
}
vampireReturnValue = VAMP_RESULT_STATUS_SUCCESS;
}
void dispatchByMode(Problem* problem)
{
switch (env.options->mode())
{
case Options::Mode::AXIOM_SELECTION:
axiomSelectionMode(problem);
break;
case Options::Mode::SPIDER:
spiderMode(problem);
break;
case Options::Mode::CONSEQUENCE_ELIMINATION:
case Options::Mode::VAMPIRE:
vampireMode(problem);
break;
case Options::Mode::CASC:
env.options->setIgnoreMissing(Options::IgnoreMissing::WARN);
if (env.options->intent() == Options::Intent::UNSAT) {
env.options->setSchedule(Options::Schedule::CASC);
} else {
env.options->setSchedule(Options::Schedule::CASC_SAT);
}
env.options->setInputSyntax(Options::InputSyntax::TPTP);
env.options->setOutputMode(Options::Output::SZS);
env.options->setProof(Options::Proof::TPTP);
env.options->setOutputAxiomNames(true);
if (CASC::PortfolioMode::perform(problem)) {
vampireReturnValue = VAMP_RESULT_STATUS_SUCCESS;
}
break;
case Options::Mode::SMTCOMP:
env.options->setIgnoreMissing(Options::IgnoreMissing::OFF);
env.options->setInputSyntax(Options::InputSyntax::SMTLIB2);
if(env.options->outputMode() != Options::Output::UCORE){
env.options->setOutputMode(Options::Output::SMTCOMP);
}
env.options->setSchedule(Options::Schedule::SMTCOMP);
env.options->setProof(Options::Proof::OFF);
env.options->setNormalize(true);
env.options->setRandomizeSeedForPortfolioWorkers(false);
env.options->setMulticore(0); env.options->setTimeLimitInSeconds(1800);
env.options->setStatistics(Options::Statistics::NONE);
env.options->setTimeLimitInSeconds(100000);
if (CASC::PortfolioMode::perform(problem)){
vampireReturnValue = VAMP_RESULT_STATUS_SUCCESS;
}
else {
cout << "unknown" << endl;
}
break;
case Options::Mode::PORTFOLIO:
env.options->setIgnoreMissing(Options::IgnoreMissing::WARN);
if (CASC::PortfolioMode::perform(problem)) {
vampireReturnValue = VAMP_RESULT_STATUS_SUCCESS;
}
break;
case Options::Mode::MODEL_CHECK:
modelCheckMode(problem);
break;
case Options::Mode::CLAUSIFY:
clausifyMode(problem,false);
break;
case Options::Mode::TCLAUSIFY:
clausifyMode(problem,true);
break;
case Options::Mode::OUTPUT:
outputMode(problem);
break;
case Options::Mode::PROFILE:
profileMode(problem);
break;
case Options::Mode::PREPROCESS:
case Options::Mode::PREPROCESS2:
preprocessMode(problem,false);
break;
case Options::Mode::TPREPROCESS:
preprocessMode(problem,true);
break;
}
}
void interactiveMetamode()
{
Options& opts = *env.options;
opts.setInteractive(false);
ScopedPtr<Problem> prb;
if (!opts.inputFile().empty()) {
UIHelper::parseFile(opts.inputFile(),opts.inputSyntax(),true);
opts.resetInputFile();
} prb = UIHelper::getInputProblem();
while (true) {
std::string line;
if (!getline(cin, line) || line.rfind("exit",0) == 0) {
cout << "Bye." << endl;
break;
} else if (line.rfind("run",0) == 0) {
pid_t process = Lib::Sys::Multiprocessing::instance()->fork();
ASS_NEQ(process, -1);
if(process == 0) {
UIHelper::unsetExpecting();
Stack<std::string> pieces;
StringUtils::splitStr(line.c_str(),' ',pieces);
StringUtils::dropEmpty(pieces);
Stack<const char*> argv(pieces.size());
for(auto it = pieces.iterFifo(); it.hasNext();) {
argv.push(it.next().c_str());
}
Shell::CommandLine cl(argv.size(), argv.begin());
cl.interpret(opts);
Timer::reinitialise();
if (!opts.inputFile().empty()) {
UIHelper::parseFile(opts.inputFile(),opts.inputSyntax(),true);
prb = UIHelper::getInputProblem();
}
dispatchByMode(prb.ptr());
exit(vampireReturnValue);
}
} else if (line.rfind("load",0) == 0) {
Stack<std::string> pieces;
StringUtils::splitStr(line.c_str(),' ',pieces);
StringUtils::dropEmpty(pieces);
auto it = pieces.iterFifo();
ALWAYS(it.next() == "load");
while (it.hasNext()) {
UIHelper::parseFile(it.next(),opts.inputSyntax(),true);
}
prb = UIHelper::getInputProblem();
} else if (line.rfind("tptp ",0) == 0) {
try {
UIHelper::parseSingleLine(line.substr(5),Options::InputSyntax::TPTP);
prb = UIHelper::getInputProblem();
} catch (ParsingRelatedException& exception) {
explainException(exception);
}
} else if (line.rfind("smt2 ",0) == 0) {
try {
UIHelper::parseSingleLine(line.substr(5),Options::InputSyntax::SMTLIB2);
prb = UIHelper::getInputProblem();
} catch (ParsingRelatedException& exception) {
explainException(exception);
}
} else if (line.rfind("list",0) == 0) {
UIHelper::listLoadedPieces(cout);
} else if (line.rfind("pop",0) == 0) {
Stack<std::string> pieces;
StringUtils::splitStr(line.c_str(),' ',pieces);
StringUtils::dropEmpty(pieces);
int numPops = 1;
if (pieces.size() > 1) {
Int::stringToInt(pieces[1],numPops);
}
UIHelper::popLoadedPiece(numPops);
prb = UIHelper::getInputProblem();
} else {
cout << "Unreconginzed command! Try 'run [options] [filename_to_load]', 'load <filenames>', 'tptp <one_line_input_in_tptp>',\n"
"'smt2 <one_line_input_in_smt2>' 'pop [how_many_levels] (one is default)', 'list', or 'exit'." << endl;
}
}
}
int main(int argc, char* argv[])
{
System::setSignalHandlers();
try {
Options& opts = *env.options;
Shell::CommandLine cl(argc, argv);
cl.interpret(opts);
#if VDEBUG
std::cerr << "% WARNING: debug build, do not use in anger\n";
#endif
if(opts.encodeStrategy()){
cout << opts.generateEncodedOptions() << "\n";
}
#if VTIME_PROFILING
TimeTrace::instance().setEnabled(opts.timeStatistics());
#endif
if (opts.showHelp() || opts.showOptions() || opts.showExperimentalOptions() ||
!opts.explainOption().empty() || opts.printAllTheoryAxioms()) {
opts.output(std::cout);
exit(0);
}
Lib::setMemoryLimit(env.options->memoryLimit() * 1048576ul);
if (opts.mode() == Options::Mode::MODEL_CHECK) {
opts.setOutputAxiomNames(true);
}
if (opts.interactive()) {
interactiveMetamode();
} else {
Timer::reinitialise();
#if VAMPIRE_PERF_EXISTS
unsigned saveInstrLimit = env.options->instructionLimit();
if (env.options->parsingDoesNotCount()) {
env.options->setInstructionLimit(0);
}
#endif
if (opts.inputFile().empty()) {
UIHelper::parseStandardInput(opts.inputSyntax());
} else {
UIHelper::parseFile(opts.inputFile(),opts.inputSyntax(),
opts.mode() != Options::Mode::SPIDER && opts.mode() != Options::Mode::PROFILE);
}
#if VAMPIRE_PERF_EXISTS
if (env.options->parsingDoesNotCount()) {
Timer::updateInstructionCount();
unsigned burnedParsing = Timer::elapsedMegaInstructions();
addCommentSignForSZS(std::cout);
std::cout << "Instructions burned parsing: " << burnedParsing << " (million)" << endl;
env.options->setInstructionLimit(saveInstrLimit+burnedParsing);
}
#endif
dispatchByMode(UIHelper::getInputProblem());
}
#if CHECK_LEAKS
delete env.signature;
env.signature = 0;
#endif
}
#if VZ3
catch (z3::exception& exception) {
vampireReturnValue = VAMP_RESULT_STATUS_UNHANDLED_EXCEPTION;
if (outputAllowed()) {
cout << "Z3 exception:\n" << exception.msg() << endl;
}
reportSpiderFail();
}
#endif
catch (UserErrorException& exception) {
vampireReturnValue = VAMP_RESULT_STATUS_UNHANDLED_EXCEPTION;
reportSpiderFail();
explainException(exception);
}
catch (Parse::TPTP::ParseErrorException& exception) {
vampireReturnValue = VAMP_RESULT_STATUS_UNHANDLED_EXCEPTION;
reportSpiderFail();
explainException(exception);
}
catch (Exception& exception) {
vampireReturnValue = VAMP_RESULT_STATUS_UNHANDLED_EXCEPTION;
reportSpiderFail();
explainException(exception);
} catch (std::bad_alloc& _) {
vampireReturnValue = VAMP_RESULT_STATUS_UNHANDLED_EXCEPTION;
reportSpiderFail();
std::cout << "Insufficient system memory" << '\n';
}
return vampireReturnValue;
}