#include <array>
#include <unordered_set>
#include "Debug/Assertion.hpp"
#include "Inferences/EqualityResolution.hpp"
#include "Inferences/Factoring.hpp"
#include "Inferences/Superposition.hpp"
#include "Kernel/Theory.hpp"
#include "Lib/Exception.hpp"
#include "SMTCheck.hpp"
#include "Inferences/ALASCA/BinInf.hpp"
#include "Inferences/ALASCA/FourierMotzkin.hpp"
#include "Inferences/ALASCA/Superposition.hpp"
#include "Inferences/BinaryResolution.hpp"
#include "Kernel/EqHelper.hpp"
#include "Kernel/RobSubstitution.hpp"
#include "Kernel/SortHelper.hpp"
#include "Kernel/SubstHelper.hpp"
#include "Lib/SharedSet.hpp"
#include "Saturation/Splitter.hpp"
#include "SATSubsumption/SATSubsumptionAndResolution.hpp"
using namespace Kernel;
using Indexing::Splitter;
using SortMap = DHMap<unsigned, TermList>;
template <unsigned N, typename T>
std::array<T *, N> getParents(T *unit)
{
std::array<T *, N> parents;
UnitIterator it = unit->getParents();
for (unsigned i = 0; i < N; i++) {
ALWAYS(it.hasNext())
parents[i] = static_cast<T *>(it.next());
}
ALWAYS(!it.hasNext())
return parents;
}
template<bool real>
struct SMTNumeral {
const IntegerConstantType &constant;
};
template<bool real>
static std::ostream &operator<<(std::ostream &out, SMTNumeral<real> num) {
if(num.constant.sign() == Sign::Neg)
return out << "(- " << num.constant.abs() << (real ? ".0" : "") << ")";
else
return out << num.constant << (real ? ".0" : "");
}
struct Escaped {
const char *name;
};
static std::ostream &operator<<(std::ostream &out, Escaped escaped) {
out << "|_";
for(const char *c = escaped.name; *c; c++)
if(*c == '|')
out << '#';
else
out << *c;
return out << '|';
}
struct FunctionName {
FunctionName(Signature::Symbol *symbol) : symbol(symbol) {}
FunctionName(Term *t) : FunctionName(env.signature->getFunction(t->functor())) {}
Signature::Symbol *symbol;
};
static std::ostream &operator<<(std::ostream &out, FunctionName name) {
auto f = name.symbol;
if(!f->interpreted())
return out << Escaped {f->name().c_str()};
if(f->integerConstant())
return out << SMTNumeral<false> {f->integerValue()};
if(f->rationalConstant() || f->realConstant()) {
auto rat = f->rationalConstant() ? f->rationalValue() : f->realValue();
return out << "(/ " << SMTNumeral<true> {rat.numerator()} << ' ' << SMTNumeral<true> {rat.denominator()} << ")";
}
auto *interpreted = static_cast<Signature::InterpretedSymbol *>(f);
switch(interpreted->getInterpretation()) {
case Theory::EQUAL:
case Theory::INT_IS_INT:
case Theory::INT_IS_RAT:
case Theory::INT_IS_REAL:
case Theory::INT_GREATER:
case Theory::INT_GREATER_EQUAL:
case Theory::INT_LESS:
case Theory::INT_LESS_EQUAL:
case Theory::INT_DIVIDES:
case Theory::RAT_IS_INT:
case Theory::RAT_IS_RAT:
case Theory::RAT_IS_REAL:
case Theory::RAT_GREATER:
case Theory::RAT_GREATER_EQUAL:
case Theory::RAT_LESS:
case Theory::RAT_LESS_EQUAL:
case Theory::REAL_IS_INT:
case Theory::REAL_IS_RAT:
case Theory::REAL_IS_REAL:
case Theory::REAL_GREATER:
case Theory::REAL_GREATER_EQUAL:
case Theory::REAL_LESS:
case Theory::REAL_LESS_EQUAL:
ASSERTION_VIOLATION
case Theory::INT_SUCCESSOR:
NOT_IMPLEMENTED;
case Theory::INT_UNARY_MINUS:
case Theory::RAT_UNARY_MINUS:
case Theory::REAL_UNARY_MINUS:
return out << '-';
case Theory::INT_PLUS:
case Theory::RAT_PLUS:
case Theory::REAL_PLUS:
return out << '+';
case Theory::INT_MINUS:
case Theory::RAT_MINUS:
case Theory::REAL_MINUS:
return out << '-';
case Theory::INT_MULTIPLY:
case Theory::RAT_MULTIPLY:
case Theory::REAL_MULTIPLY:
return out << '*';
case Theory::INT_QUOTIENT_E:
case Theory::RAT_QUOTIENT:
case Theory::REAL_QUOTIENT:
return out << '/';
case Theory::INT_QUOTIENT_T:
case Theory::INT_QUOTIENT_F:
case Theory::RAT_QUOTIENT_E:
case Theory::RAT_QUOTIENT_T:
case Theory::RAT_QUOTIENT_F:
case Theory::REAL_QUOTIENT_E:
case Theory::REAL_QUOTIENT_T:
case Theory::REAL_QUOTIENT_F:
NOT_IMPLEMENTED;
case Theory::INT_REMAINDER_E:
return out << "mod";
case Theory::INT_REMAINDER_T:
case Theory::INT_REMAINDER_F:
case Theory::RAT_REMAINDER_E:
case Theory::RAT_REMAINDER_T:
case Theory::RAT_REMAINDER_F:
case Theory::REAL_REMAINDER_E:
case Theory::REAL_REMAINDER_T:
case Theory::REAL_REMAINDER_F:
NOT_IMPLEMENTED;
case Theory::INT_TRUNCATE:
case Theory::RAT_TRUNCATE:
case Theory::REAL_TRUNCATE:
NOT_IMPLEMENTED;
case Theory::INT_ROUND:
case Theory::RAT_ROUND:
case Theory::REAL_ROUND:
NOT_IMPLEMENTED;
case Theory::INT_ABS:
NOT_IMPLEMENTED;
case Theory::RAT_TO_INT:
case Theory::REAL_TO_INT:
return out << "to_int";
case Theory::INT_TO_RAT:
case Theory::INT_TO_REAL:
return out << "to_real";
case Theory::INT_TO_INT:
case Theory::RAT_TO_RAT:
case Theory::RAT_TO_REAL:
case Theory::REAL_TO_RAT:
case Theory::REAL_TO_REAL:
case Theory::RAT_FLOOR:
case Theory::REAL_FLOOR:
case Theory::RAT_CEILING:
case Theory::REAL_CEILING:
ASSERTION_VIOLATION
case Theory::INT_FLOOR:
case Theory::INT_CEILING:
ASSERTION_VIOLATION
case Theory::ARRAY_SELECT:
case Theory::ARRAY_BOOL_SELECT:
case Theory::ARRAY_STORE:
NOT_IMPLEMENTED;
case Theory::INVALID_INTERPRETATION:
ASSERTION_VIOLATION
}
return out;
}
struct PredicateName {
PredicateName(Signature::Symbol *symbol) : symbol(symbol) {}
PredicateName(Literal *l) : PredicateName(env.signature->getPredicate(l->functor())) {}
Signature::Symbol *symbol;
};
static std::ostream &operator<<(std::ostream &out, PredicateName name) {
auto p = name.symbol;
if(!p->interpreted())
return out << Escaped {p->name().c_str()};
auto *interpreted = static_cast<Signature::InterpretedSymbol *>(p);
switch(interpreted->getInterpretation()) {
case Theory::EQUAL:
return out << '=';
case Theory::RAT_IS_INT:
case Theory::REAL_IS_INT:
return out << "is_int";
case Theory::REAL_IS_RAT:
return out << "is_rat";
case Theory::INT_IS_INT:
case Theory::INT_IS_RAT:
case Theory::RAT_IS_RAT:
case Theory::INT_IS_REAL:
case Theory::RAT_IS_REAL:
case Theory::REAL_IS_REAL:
ASSERTION_VIOLATION
case Theory::INT_GREATER:
case Theory::RAT_GREATER:
case Theory::REAL_GREATER:
return out << '>';
case Theory::INT_GREATER_EQUAL:
case Theory::RAT_GREATER_EQUAL:
case Theory::REAL_GREATER_EQUAL:
return out << ">=";
case Theory::INT_LESS:
case Theory::RAT_LESS:
case Theory::REAL_LESS:
return out << '<';
case Theory::INT_LESS_EQUAL:
case Theory::RAT_LESS_EQUAL:
case Theory::REAL_LESS_EQUAL:
return out << "<=";
case Theory::INT_DIVIDES:
NOT_IMPLEMENTED;
case Theory::INT_SUCCESSOR:
case Theory::INT_UNARY_MINUS:
case Theory::INT_PLUS:
case Theory::INT_MINUS:
case Theory::INT_MULTIPLY:
case Theory::INT_QUOTIENT_E:
case Theory::INT_QUOTIENT_T:
case Theory::INT_QUOTIENT_F:
case Theory::INT_REMAINDER_E:
case Theory::INT_REMAINDER_T:
case Theory::INT_REMAINDER_F:
case Theory::INT_FLOOR:
case Theory::INT_CEILING:
case Theory::INT_TRUNCATE:
case Theory::INT_ROUND:
case Theory::INT_ABS:
case Theory::RAT_UNARY_MINUS:
case Theory::RAT_PLUS:
case Theory::RAT_MINUS:
case Theory::RAT_MULTIPLY:
case Theory::RAT_QUOTIENT:
case Theory::RAT_QUOTIENT_E:
case Theory::RAT_QUOTIENT_T:
case Theory::RAT_QUOTIENT_F:
case Theory::RAT_REMAINDER_E:
case Theory::RAT_REMAINDER_T:
case Theory::RAT_REMAINDER_F:
case Theory::RAT_FLOOR:
case Theory::RAT_CEILING:
case Theory::RAT_TRUNCATE:
case Theory::RAT_ROUND:
case Theory::REAL_UNARY_MINUS:
case Theory::REAL_PLUS:
case Theory::REAL_MINUS:
case Theory::REAL_MULTIPLY:
case Theory::REAL_QUOTIENT:
case Theory::REAL_QUOTIENT_E:
case Theory::REAL_QUOTIENT_T:
case Theory::REAL_QUOTIENT_F:
case Theory::REAL_REMAINDER_E:
case Theory::REAL_REMAINDER_T:
case Theory::REAL_REMAINDER_F:
case Theory::REAL_FLOOR:
case Theory::REAL_CEILING:
case Theory::REAL_TRUNCATE:
case Theory::REAL_ROUND:
case Theory::INT_TO_INT:
case Theory::INT_TO_RAT:
case Theory::INT_TO_REAL:
case Theory::RAT_TO_INT:
case Theory::RAT_TO_RAT:
case Theory::RAT_TO_REAL:
case Theory::REAL_TO_INT:
case Theory::REAL_TO_RAT:
case Theory::REAL_TO_REAL:
case Theory::ARRAY_SELECT:
case Theory::ARRAY_BOOL_SELECT:
case Theory::ARRAY_STORE:
ASSERTION_VIOLATION
case Theory::INVALID_INTERPRETATION:
ASSERTION_VIOLATION
}
return out;
}
struct Blank {};
static std::ostream &operator<<(std::ostream &out, Blank) { return out; }
struct Inhabit {};
static std::ostream &operator<<(std::ostream &out, Inhabit) { return out << "inhabit_"; }
template<typename Prefix = Blank>
struct SortName {
SortName(unsigned functor) : functor(functor) {}
SortName(AtomicSort *s) : functor(s->functor()) {}
unsigned functor;
};
template<typename Prefix>
static std::ostream &operator<<(std::ostream &out, SortName<Prefix> name) {
Prefix prefix;
switch(name.functor) {
case Signature::DEFAULT_SORT_CON:
return out << prefix << "iota";
case Signature::BOOL_SRT_CON:
return out << prefix << "Bool";
case Signature::INTEGER_SRT_CON:
return out << prefix << "Int";
case Signature::RATIONAL_SRT_CON:
case Signature::REAL_SRT_CON:
return out << prefix << "Real";
}
return out << '|' << prefix << '_' << env.signature->getTypeCon(name.functor)->name() << '|';
}
struct Args {
TermList *start;
SortMap &conclSorts;
SortMap &otherSorts;
};
static std::ostream &operator<<(std::ostream &out, Args args)
{
if (args.start->isEmpty())
return out;
Stack<TermList *> todo;
TermList empty;
TermList *current = args.start;
while (true) {
out << " ";
if (current->isVar()) {
unsigned var = current->var();
if (args.conclSorts.findPtr(var))
out << "v" << var;
else
out << SortName<Inhabit>(static_cast<AtomicSort *>(args.otherSorts.get(var).term()));
current = current->next();
}
else if (current->isTerm()) {
Term *term = current->term();
FunctionName name(term);
if (term->arity()) {
if(name.symbol->interpreted()) {
auto interpreted = static_cast<Signature::InterpretedSymbol *>(name.symbol);
switch(interpreted->getInterpretation()) {
case Theory::INT_TO_INT:
case Theory::RAT_TO_RAT:
case Theory::RAT_TO_REAL:
case Theory::REAL_TO_RAT:
case Theory::REAL_TO_REAL:
out << Args { term->args(), args.conclSorts, args.otherSorts };
current = current->next();
goto carry_on;
case Theory::RAT_FLOOR:
case Theory::REAL_FLOOR:
out << "(to_real (to_int";
todo.push(current->next());
todo.push(&empty);
break;
case Theory::RAT_CEILING:
case Theory::REAL_CEILING:
out << "(- (to_real (to_int (-";
todo.push(current->next());
todo.push(&empty);
todo.push(&empty);
todo.push(&empty);
break;
default:
out << "(" << name;
todo.push(current->next());
break;
}
}
else if(name.symbol->linMul()) {
out << "(* ";
if(auto attempt = env.signature->tryLinMul<IntegerConstantType>(term->functor()); attempt.isSome()) {
auto factor = SMTNumeral<false> {attempt.unwrap()};
out << factor;
}
else if(auto attempt = env.signature->tryLinMul<RationalConstantType>(term->functor()); attempt.isSome()) {
auto factor = attempt.unwrap();
out << "(/ " << SMTNumeral<true> {factor.numerator()} << " " << SMTNumeral<true> {factor.denominator()} << ")";
}
else if(auto attempt = env.signature->tryLinMul<RealConstantType>(term->functor()); attempt.isSome()) {
auto factor = attempt.unwrap();
out << "(/ " << SMTNumeral<true> {factor.numerator()} << " " << SMTNumeral<true> {factor.denominator()} << ")";
}
else
ASSERTION_VIOLATION
todo.push(current->next());
}
else {
out << "(" << name;
todo.push(current->next());
}
current = term->args();
}
else {
if(env.signature->isFoolConstantSymbol(false, term->functor()))
out << "false";
else if(env.signature->isFoolConstantSymbol(true, term->functor()))
out << "true";
else
out << name;
current = current->next();
}
}
carry_on:
while (current->isEmpty()) {
if (todo.isEmpty())
return out;
current = todo.pop();
out << ")";
}
}
}
struct Lit {
Literal *literal;
SortMap &conclSorts;
SortMap &otherSorts;
};
static std::ostream &operator<<(std::ostream &out, Lit lit)
{
Literal *literal = lit.literal;
PredicateName name(literal);
if (!literal->polarity())
out << "(not ";
if (literal->arity())
out << "(";
if(name.symbol->interpreted()) {
auto interpreted = static_cast<Signature::InterpretedSymbol *>(name.symbol);
switch(interpreted->getInterpretation()) {
case Theory::INT_IS_INT:
case Theory::INT_IS_RAT:
case Theory::INT_IS_REAL:
case Theory::RAT_IS_RAT:
case Theory::RAT_IS_REAL:
case Theory::REAL_IS_REAL:
out << "true";
goto finish;
default:
break;
}
}
out << name << Args{literal->args(), lit.conclSorts, lit.otherSorts};
if (literal->arity())
out << ")";
finish:
if (!literal->polarity())
out << ")";
return out;
}
struct Sort {
TermList sort;
};
static std::ostream &operator<<(std::ostream &out, Sort print) {
AtomicSort *sort = static_cast<AtomicSort *>(print.sort.term());
ASS_EQ(sort->arity(), 0)
return out << SortName(sort);
}
template <bool flip = false>
struct Split {
unsigned level;
Split(unsigned level) : level(level) {}
};
template <bool flip>
static std::ostream &operator<<(std::ostream &out, Split<flip> split)
{
SATLiteral sat = Splitter::getLiteralFromName(split.level);
return out
<< (flip == sat.positive() ? "(not " : "")
<< "sp" << sat.var()
<< (flip == sat.positive() ? ")" : "");
}
struct Identity {
Literal *operator()(Literal *l) { return l; }
};
struct DoSubst {
Substitution &subst;
DoSubst(Substitution &subst) : subst(subst) {}
Literal *operator()(Literal *l) { return SubstHelper::apply(l, subst); }
};
template <unsigned bank>
struct DoRobSubst {
const RobSubstitution &subst;
DoRobSubst(const RobSubstitution &subst) : subst(subst) {}
Literal *operator()(Literal *l) { return subst.apply(l, bank); }
};
template <typename Transform = Identity>
static void outputPremise(std::ostream &out, SortMap &conclSorts, Clause *cl, Transform transform = Transform{})
{
out << "(assert (or";
for (Literal *l : *cl) {
l = transform(l);
SortMap otherSorts;
SortHelper::collectVariableSorts(l, otherSorts);
out << " " << Lit{l, conclSorts, otherSorts};
}
if (cl->splits()) {
SplitSet &clSplits = *cl->splits();
for (unsigned i = 0; i < clSplits.size(); i++) {
out << " " << Split<true>(clSplits[i]);
}
}
out << "))\n";
}
static void outputConclusion(std::ostream &out, SortMap &conclSorts, Clause *cl)
{
SortMap otherSorts;
for (Literal *l : *cl)
out << "(assert " << Lit{Literal::complementaryLiteral(l), conclSorts, otherSorts} << ")\n";
if (cl->splits()) {
SplitSet &clSplits = *cl->splits();
for (unsigned i = 0; i < clSplits.size(); i++)
out << "(assert " << Split(clSplits[i]) << ")\n";
}
}
static void trivial(std::ostream &out, SortMap &conclSorts, Clause *concl)
{
UnitIterator parents = concl->getParents();
while (parents.hasNext()) {
Unit *parent = parents.next();
ASS(parent->isClause())
outputPremise(out, conclSorts, parent->asClause());
}
outputConclusion(out, conclSorts, concl->asClause());
}
static void resolution(std::ostream &out, SortMap &conclSorts, Clause *concl)
{
auto [left, right] = getParents<2>(concl);
const auto &br = env.proofExtra.get<Inferences::BinaryResolutionExtra>(concl);
auto uwa = AbstractingUnifier::empty(AbstractionOracle(env.options->unificationWithAbstraction()));
Literal *selectedLeft = br.selectedLiteral.selectedLiteral;
Literal *selectedRight = br.otherLiteral;
for(unsigned i = 0; i < selectedLeft->arity(); i++)
ALWAYS(uwa.unify((*selectedLeft)[i], 0, (*selectedRight)[i], 1))
ASS_NEQ(selectedLeft->polarity(), selectedRight->polarity())
RobSubstitution &subst = uwa.subs();
for (unsigned i = 0; i < left->length(); i++)
if ((*left)[i] != selectedLeft)
subst.apply((*left)[i], 0);
for (unsigned i = 0; i < right->length(); i++)
if ((*right)[i] != selectedRight)
subst.apply((*right)[i], 1);
outputPremise(out, conclSorts, left->asClause(), DoRobSubst<0>(subst));
outputPremise(out, conclSorts, right->asClause(), DoRobSubst<1>(subst));
outputConclusion(out, conclSorts, concl->asClause());
}
static void subsumptionResolution(std::ostream &out, SortMap &conclSorts, Clause *concl)
{
auto [left, right] = getParents<2>(concl);
auto sr = env.proofExtra.get<Inferences::LiteralInferenceExtra>(concl);
Literal *m = sr.selectedLiteral;
SATSubsumption::SATSubsumptionAndResolution satSR;
ALWAYS(satSR.checkSubsumptionResolutionWithLiteral(right, left, left->getLiteralPosition(m)))
auto subst = satSR.getBindingsForSubsumptionResolutionWithLiteral();
outputPremise(out, conclSorts, left->asClause());
outputPremise(out, conclSorts, right->asClause(), DoSubst(subst));
outputConclusion(out, conclSorts, concl->asClause());
}
static void factoring(std::ostream &out, SortMap &conclSorts, Clause *concl) {
auto [premise] = getParents<1>(concl);
const auto &fact = env.proofExtra.get<Inferences::FactoringExtra>(concl);
RobSubstitution subst;
Literal *selected = fact.selectedLiteral.selectedLiteral;
Literal *other = fact.otherLiteral;
ASS_EQ(selected->polarity(), other->polarity())
ASS_EQ(selected->functor(), other->functor())
ALWAYS(subst.unify(TermList(selected), 0, TermList(other), 0));
for (unsigned i = 0; i < premise->length(); i++)
if ((*premise)[i] != other)
subst.apply((*premise)[i], 0);
outputPremise(out, conclSorts, premise->asClause(), DoRobSubst<0>(subst));
outputConclusion(out, conclSorts, concl->asClause());
}
static void equalityResolution(std::ostream &out, SortMap &conclSorts, Clause *concl) {
auto [premise] = getParents<1>(concl);
const auto &res = env.proofExtra.get<Inferences::EqualityResolutionExtra>(concl);
RobSubstitution subst;
Literal *selected = res.selectedLiteral;
ASS(selected->isEquality())
ASS(selected->isNegative())
TermList s = selected->termArg(0), t = selected->termArg(1);
ALWAYS(subst.unify(s, 0, t, 0));
for (unsigned i = 0; i < premise->length(); i++)
if ((*premise)[i] != selected)
subst.apply((*premise)[i], 0);
outputPremise(out, conclSorts, premise->asClause(), DoRobSubst<0>(subst));
outputConclusion(out, conclSorts, concl->asClause());
}
static void superposition(std::ostream &out, SortMap &conclSorts, Clause *concl)
{
auto [left, right] = getParents<2>(concl);
auto sup = env.proofExtra.get<Inferences::SuperpositionExtra>(concl);
RobSubstitution subst;
Literal *leftSelected = sup.selected.selectedLiteral.selectedLiteral;
Literal *rightSelected = sup.selected.otherLiteral;
TermList from = sup.rewrite.lhs;
TermList to = EqHelper::getOtherEqualitySide(rightSelected, from);
TermList target = sup.rewrite.rewritten;
ASS(rightSelected->isEquality())
ASS(rightSelected->isPositive())
ASS(rightSelected->termArg(0) == from || rightSelected->termArg(1) == from)
ALWAYS(subst.unify(target, 0, from, 1))
subst.apply(to, 1);
subst.apply(leftSelected, 0);
subst.apply(target, 0);
subst.apply(from, 1);
for (unsigned i = 0; i < left->length(); i++)
if ((*left)[i] != leftSelected)
subst.apply((*left)[i], 0);
for (unsigned i = 0; i < right->length(); i++)
if ((*right)[i] != rightSelected)
subst.apply((*right)[i], 1);
outputPremise(out, conclSorts, left->asClause(), DoRobSubst<0>(subst));
outputPremise(out, conclSorts, right->asClause(), DoRobSubst<1>(subst));
outputConclusion(out, conclSorts, concl->asClause());
}
static bool isL2RDemodulatorFor(Literal *demodulator, Clause *rewritten, TermList target, Clause *result)
{
ASS(demodulator->isEquality())
ASS(demodulator->isPositive())
Substitution subst;
if (!MatchingUtils::matchTerms(demodulator->termArg(0), target, subst))
return false;
TermList rhsSubst = SubstHelper::apply(demodulator->termArg(1), subst);
for (Literal *l : rewritten->iterLits())
if (!result->contains(l) && !result->contains(EqHelper::replace(l, target, rhsSubst)))
return false;
return true;
}
static void demodulation(std::ostream &out, SortMap &conclSorts, Clause *concl)
{
auto [left, right] = getParents<2>(concl);
auto rw = env.proofExtra.get<Inferences::RewriteInferenceExtra>(concl);
Substitution subst;
Literal *rightLit = (*right)[0];
TermList target = rw.rewritten;
TermList from = rightLit->termArg(!isL2RDemodulatorFor(rightLit, left, target, concl));
ASS(rightLit->isEquality())
ASS(rightLit->isPositive())
ASS(rightLit->termArg(0) == from || rightLit->termArg(1) == from)
ALWAYS(MatchingUtils::matchTerms(from, target, subst))
outputPremise(out, conclSorts, left->asClause());
outputPremise(out, conclSorts, right->asClause(), DoSubst(subst));
outputConclusion(out, conclSorts, concl->asClause());
}
static void splitClause(std::ostream &out, SortMap &conclSorts, Unit *concl)
{
ASS(conclSorts.isEmpty())
SATClause *sat = env.proofExtra.get<Indexing::SATClauseExtra>(concl).clause;
std::unordered_set<unsigned> seen;
for(SATLiteral l : sat->iter())
if(seen.insert(l.var()).second)
out << "(declare-const sp" << l.var() << " Bool)\n";
auto parents = concl->getParents();
ALWAYS(parents.hasNext())
Clause *split = parents.next()->asClause();
outputPremise(out, conclSorts, split);
for (Unit *u : iterTraits(std::move(parents))) {
Clause *component = env.proofExtra.get<Indexing::SplitDefinitionExtra>(u).component;
SortMap otherSorts;
SortHelper::collectVariableSorts(component, otherSorts);
out << "(assert (= " << Split {component->splits()->sval()} << " (or";
for(Literal *l : *component)
out << ' ' << Lit {l, conclSorts, otherSorts};
out << ")))\n";
}
for(SATLiteral l : sat->iter())
out
<< "(assert "
<< (l.positive() ? "(not " : "")
<< "sp" << l.var()
<< (l.positive() ? ")" : "")
<< ")\n";
}
static void satRefutation(std::ostream &out, SortMap &conclSorts, Unit *concl) {
std::unordered_set<unsigned> seen;
for(Unit *u : iterTraits(concl->getParents()))
for(SATLiteral l : env.proofExtra.get<Indexing::SATClauseExtra>(u).clause->iter())
if(seen.insert(l.var()).second)
out << "(declare-const sp" << l.var() << " Bool)\n";
for(Unit *u : iterTraits(concl->getParents())) {
out << "(assert (or";
for(SATLiteral l : env.proofExtra.get<Indexing::SATClauseExtra>(u).clause->iter())
out
<< ' ' << (l.positive() ? "" : "(not ")
<< "sp" << l.var()
<< (l.positive() ? "" : ")");
out << "))\n";
}
}
template<class Rule>
static void alascaBinInf(std::ostream &out, SortMap &conclSorts, Clause *concl) {
auto [left, right] = getParents<2>(concl);
const auto &fm = env.proofExtra.get<ALASCA::BinInfExtra<Rule>>(concl);
auto uwa = AbstractingUnifier::empty(AbstractionOracle(env.options->unificationWithAbstraction()));
ALWAYS(uwa.unify(fm.left.key(), 0, fm.right.key(), 1))
RobSubstitution &subst = uwa.subs();
subst.apply(fm.left.literal(), 0);
subst.apply(fm.right.literal(), 1);
for (unsigned i = 0; i < left->length(); i++)
subst.apply((*left)[i], 0);
for (unsigned i = 0; i < right->length(); i++)
subst.apply((*right)[i], 1);
outputPremise(out, conclSorts, left->asClause(), DoRobSubst<0>(subst));
outputPremise(out, conclSorts, right->asClause(), DoRobSubst<1>(subst));
outputConclusion(out, conclSorts, concl->asClause());
}
static SortMap outputSkolemsAndGetSorts(std::ostream &out, Unit *u)
{
SortMap sorts;
SortHelper::collectVariableSorts(u, sorts);
auto it = sorts.items();
while (it.hasNext()) {
auto [var, sort] = it.next();
out << "(declare-const v" << var << " " << Sort {sort} << ")\n";
}
return sorts;
}
static void outputSplits(std::ostream &out, Unit *u)
{
if (!u->isClause())
return;
Clause *cl = u->asClause();
if (!cl->splits())
return;
SplitSet &clSplits = *cl->splits();
std::unordered_set<unsigned> splits;
for (unsigned i = 0; i < clSplits.size(); i++)
splits.insert(clSplits[i]);
UnitIterator parents = u->getParents();
while (parents.hasNext()) {
Unit *parent = parents.next();
if (!parent->isClause())
continue;
Clause *cl = parent->asClause();
if (!cl->splits())
continue;
SplitSet &clSplits = *cl->splits();
for (unsigned i = 0; i < clSplits.size(); i++)
splits.insert(clSplits[i]);
}
for (unsigned split : splits)
out << "(declare-const sp" << Splitter::getLiteralFromName(split).var() << " Bool)\n";
}
namespace Shell {
namespace SMTCheck {
void outputSignature(std::ostream &out)
{
out << "(set-logic ALL)\n";
out << "(declare-sort iota 0)\n";
out << "(declare-const inhabit_iota iota)\n";
out << "(declare-const inhabit_Int Int)\n";
out << "(declare-const inhabit_Real Real)\n";
out << "(declare-const inhabit_Bool Bool)\n";
out << "(declare-fun is_rat (Real) Bool)\n";
Signature &sig = *env.signature;
for(unsigned i = Signature::FIRST_USER_CON; i < sig.typeCons(); i++) {
out << "(declare-sort " << SortName(i);
#if VDEBUG
Signature::Symbol *type = sig.getTypeCon(i);
OperatorType *typeType = type->typeConType();
ASS_EQ(typeType->numTypeArguments(), 0)
#endif
out << " 0)\n";
out << "(declare-const " << SortName<Inhabit>(i) << ' ' << SortName(i) << ")\n";
}
for(unsigned i = 0; i < sig.functions(); i++) {
Signature::Symbol *fun = sig.getFunction(i);
if(fun->interpreted() || fun->linMul())
continue;
out << "(declare-fun " << FunctionName(fun);
OperatorType *type = fun->fnType();
TermList range = type->result();
ASS_EQ(type->numTypeArguments(), 0)
out << " (";
for (unsigned i = 0; i < type->arity(); i++)
out << (i == 0 ? "" : " ") << Sort {type->arg(i)};
out << ") " << Sort {range} << ")\n";
}
for(unsigned i = 1; i < sig.predicates(); i++) {
Signature::Symbol *pred = sig.getPredicate(i);
if(pred->interpreted())
continue;
out << "(declare-fun " << PredicateName(pred);
OperatorType *type = pred->predType();
ASS_EQ(type->numTypeArguments(), 0)
out << " (";
for (unsigned i = 0; i < type->arity(); i++)
out << (i == 0 ? "" : " ") << Sort {type->arg(i)};
out << ") Bool)\n";
}
}
void outputStep(std::ostream &out, Unit *u)
{
InferenceRule rule = u->inference().rule();
if (
rule == InferenceRule::INPUT || rule == InferenceRule::NEGATED_CONJECTURE
|| rule == InferenceRule::SKOLEM_SYMBOL_INTRODUCTION
|| rule == InferenceRule::DISTINCTNESS_AXIOM
|| rule == InferenceRule::AVATAR_DEFINITION || rule == InferenceRule::AVATAR_COMPONENT
|| rule == InferenceRule::AVATAR_CONTRADICTION_CLAUSE)
return;
out << "\n; step " << u->number() << "\n";
out << "(push)\n";
bool sorry = false;
auto conclSorts = outputSkolemsAndGetSorts(out, u);
outputSplits(out, u);
switch (rule) {
case InferenceRule::REMOVE_DUPLICATE_LITERALS:
case InferenceRule::TRIVIAL_INEQUALITY_REMOVAL:
case InferenceRule::EVALUATION:
case InferenceRule::ALASCA_NORMALIZATION:
case InferenceRule::THA_COMMUTATIVITY:
case InferenceRule::THA_ASSOCIATIVITY:
case InferenceRule::THA_RIGHT_IDENTITY:
case InferenceRule::THA_LEFT_IDENTITY:
case InferenceRule::THA_INVERSE_OP_OP_INVERSES:
case InferenceRule::THA_INVERSE_OP_UNIT:
case InferenceRule::THA_INVERSE_ASSOC:
case InferenceRule::THA_NONREFLEX:
case InferenceRule::THA_TRANSITIVITY:
case InferenceRule::THA_ORDER_TOTALITY:
case InferenceRule::THA_ORDER_MONOTONICITY:
case InferenceRule::THA_ALASCA:
case InferenceRule::THA_PLUS_ONE_GREATER:
case InferenceRule::THA_ORDER_PLUS_ONE_DICHOTOMY:
case InferenceRule::THA_MINUS_MINUS_X:
case InferenceRule::THA_TIMES_ZERO:
case InferenceRule::THA_DISTRIBUTIVITY:
case InferenceRule::THA_DIVISIBILITY:
case InferenceRule::THA_MODULO_MULTIPLY:
case InferenceRule::THA_MODULO_POSITIVE:
case InferenceRule::THA_MODULO_SMALL:
case InferenceRule::THA_DIVIDES_MULTIPLY:
case InferenceRule::THA_NONDIVIDES_SKOLEM:
case InferenceRule::THA_ABS_EQUALS:
case InferenceRule::THA_ABS_MINUS_EQUALS:
case InferenceRule::THA_QUOTIENT_NON_ZERO:
case InferenceRule::THA_QUOTIENT_MULTIPLY:
case InferenceRule::THA_EXTRA_INTEGER_ORDERING:
case InferenceRule::THA_FLOOR_SMALL:
case InferenceRule::THA_FLOOR_BIG:
case InferenceRule::THA_CEILING_BIG:
case InferenceRule::THA_CEILING_SMALL:
case InferenceRule::THA_TRUNC1:
case InferenceRule::THA_TRUNC2:
case InferenceRule::THA_TRUNC3:
case InferenceRule::THA_TRUNC4:
case InferenceRule::THA_ARRAY_EXTENSIONALITY:
case InferenceRule::THA_BOOLEAN_ARRAY_EXTENSIONALITY:
case InferenceRule::THA_BOOLEAN_ARRAY_WRITE1:
case InferenceRule::THA_BOOLEAN_ARRAY_WRITE2:
case InferenceRule::THA_ARRAY_WRITE1:
case InferenceRule::THA_ARRAY_WRITE2:
case InferenceRule::TERM_ALGEBRA_ACYCLICITY_AXIOM:
case InferenceRule::TERM_ALGEBRA_DIRECT_SUBTERMS_AXIOM:
case InferenceRule::TERM_ALGEBRA_SUBTERMS_TRANSITIVE_AXIOM:
case InferenceRule::TERM_ALGEBRA_DISCRIMINATION_AXIOM:
case InferenceRule::TERM_ALGEBRA_DISTINCTNESS_AXIOM:
case InferenceRule::TERM_ALGEBRA_EXHAUSTIVENESS_AXIOM:
case InferenceRule::TERM_ALGEBRA_INJECTIVITY_AXIOM:
case InferenceRule::FOOL_AXIOM_TRUE_NEQ_FALSE:
case InferenceRule::FOOL_AXIOM_ALL_IS_TRUE_OR_FALSE:
trivial(out, conclSorts, u->asClause());
break;
case InferenceRule::RESOLUTION:
resolution(out, conclSorts, u->asClause());
break;
case InferenceRule::FORWARD_SUBSUMPTION_RESOLUTION:
case InferenceRule::BACKWARD_SUBSUMPTION_RESOLUTION:
subsumptionResolution(out, conclSorts, u->asClause());
break;
case InferenceRule::FACTORING:
factoring(out, conclSorts, u->asClause());
break;
case InferenceRule::EQUALITY_RESOLUTION:
equalityResolution(out, conclSorts, u->asClause());
break;
case InferenceRule::SUPERPOSITION:
superposition(out, conclSorts, u->asClause());
break;
case InferenceRule::FORWARD_DEMODULATION:
case InferenceRule::BACKWARD_DEMODULATION:
demodulation(out, conclSorts, u->asClause());
break;
case InferenceRule::AVATAR_SPLIT_CLAUSE:
splitClause(out, conclSorts, u);
break;
case InferenceRule::AVATAR_REFUTATION:
satRefutation(out, conclSorts, u);
break;
case InferenceRule::ALASCA_FOURIER_MOTZKIN:
alascaBinInf<ALASCA::FourierMotzkinConf>(out, conclSorts, u->asClause());
break;
case InferenceRule::ALASCA_SUPERPOSITION:
alascaBinInf<ALASCA::SuperpositionConf>(out, conclSorts, u->asClause());
break;
default:
sorry = true;
out << "(echo \"sorry: " << ruleName(rule) << "\")\n";
}
if (!sorry) {
out << "(set-info :status unsat)\n";
out << "(check-sat)\n";
}
out << "(pop)\n";
}
} }