#include "Lib/Environment.hpp"
#include "Clause.hpp"
#include "FormulaUnit.hpp"
#include "Signature.hpp"
#include "OperatorType.hpp"
#include "SubformulaIterator.hpp"
#include "Term.hpp"
#include "TermIterators.hpp"
#include "Substitution.hpp"
#include "SubstHelper.hpp"
#include "SortHelper.hpp"
using namespace std;
using namespace Kernel;
enum CollectWhat {
COLLECT_TERM,
COLLECT_TERMLIST,
COLLECT_SPECIALTERM,
COLLECT_FORMULA,
BIND,
UNBIND,
};
struct CollectTask {
CollectTask(CollectWhat what) : fncTag(what) {}
CollectWhat fncTag;
union {
TermList ts;
Term* t; Formula* f;
VList* vars; };
TermList contextSort; };
static OperatorType* getType(Term const* t)
{
if (t->isLiteral())
return env.signature->getPredicate(t->functor())->predType();
if (t->isSort())
return env.signature->getTypeCon(t->functor())->typeConType();
return env.signature->getFunction(t->functor())->fnType();
}
bool SortHelper::getTypeSub(const Term* t, Substitution& subst)
{
OperatorType* ot = getType(t);
unsigned typeArgsArity = ot->numTypeArguments();
bool resultShared = true;
auto *typeArg = const_cast<TermList *>(t->args());
for(unsigned i = 0; i < typeArgsArity; i++){
TermList var = ot->quantifiedVar(i);
ASS_REP(var.isVar(), t->toString());
if (typeArg->isSpecialVar() || (typeArg->isTerm() && !typeArg->term()->shared()))
resultShared = false;
subst.bindUnbound(var.var(), *typeArg);
typeArg = typeArg->next();
}
return resultShared;
}
TermList SortHelper::getResultSort(const Term* t)
{
ASS(!t->isSpecial());
ASS(!t->isLiteral());
if(t->isSort()){
return TermList(AtomicSort::superSort());
}
Substitution subst;
bool shared = getTypeSub(t, subst);
Signature::Symbol* sym = env.signature->getFunction(t->functor());
TermList result = sym->fnType()->result();
ASS(
!subst.isEmpty() ||
(result.isTerm() && (result.term()->isSuper() || result.term()->ground()))
)
return SubstHelper::apply(result, subst, !shared);
}
TermList SortHelper::getResultSortMono(const Term* t)
{
ASS(!t->isSpecial());
ASS(!t->isLiteral());
Signature::Symbol* sym = env.signature->getFunction(t->functor());
return sym->fnType()->result();
}
bool SortHelper::tryGetResultSort(const Term* t, TermList& result)
{
ASS(!t->isLiteral());
TermList masterVar;
return getResultSortOrMasterVariable(t, result, masterVar);
}
bool SortHelper::tryGetResultSort(const TermList t, TermList& result)
{
if (t.isVar()) {
return false;
}
return tryGetResultSort(t.term(), result);
}
TermList SortHelper::getResultSort(TermList t, DHMap<unsigned,TermList>& varSorts)
{
TermList res;
TermList masterVar;
if (!getResultSortOrMasterVariable(t, res, masterVar)) {
ASS(masterVar.isOrdinaryVar());
res = varSorts.get(masterVar.var());
}
return res;
}
bool SortHelper::getResultSortOrMasterVariable(const Term* t, TermList& resultSort, TermList& resultVar)
{
if(t->isSort()){
resultSort = AtomicSort::superSort();
return true;
}
if (!t->isSpecial()) {
resultSort = getResultSort(t);
return true;
}
switch(t->specialFunctor()) {
case SpecialFunctor::LET:
case SpecialFunctor::ITE:
case SpecialFunctor::MATCH:
resultSort = t->getSpecialData()->getSort();
return true;
case SpecialFunctor::FORMULA:
resultSort = AtomicSort::boolSort();
return true;
case SpecialFunctor::LAMBDA: {
resultSort = t->getSpecialData()->getSort();
return true;
}
}
ASSERTION_VIOLATION
}
bool SortHelper::getResultSortOrMasterVariable(const TermList t, TermList& resultSort, TermList& resultVar)
{
if (t.isVar()) {
resultVar = t;
return false;
}
return getResultSortOrMasterVariable(t.term(), resultSort, resultVar);
}
TermList SortHelper::getArgSort(Term const* t, unsigned argIndex)
{
ASS_L(argIndex, t->arity());
if(t->isSort()){
return AtomicSort::superSort();
}
if (t->isLiteral() && static_cast<Literal const*>(t)->isEquality()) {
return getEqualityArgumentSort(static_cast<Literal const*>(t));
}
Substitution subst;
OperatorType* ot = getType(t);
if(argIndex < ot->numTypeArguments()){
return AtomicSort::superSort();
}
bool shared = getTypeSub(t, subst);
return SubstHelper::apply(ot->arg(argIndex), subst, !shared);
}
TermList SortHelper::getTermArgSort(Term const* t, unsigned n)
{ return getArgSort(t, n + t->numTypeArguments()); }
TermList SortHelper::getEqualityArgumentSort(const Literal* lit)
{
ASS(lit->isEquality());
if (lit->isTwoVarEquality()) {
return lit->twoVarEqSort();
}
TermList arg1 = *lit->nthArgument(0);
TermList srt1;
if (tryGetResultSort(arg1, srt1)) {
return srt1;
}
TermList arg2 = *lit->nthArgument(1);
TermList srt2;
ALWAYS(tryGetResultSort(arg2, srt2));
return srt2;
}
TermList SortHelper::getVariableSort(TermList var, Term* t)
{
TermList res;
ALWAYS(tryGetVariableSortTerm(var, t, res, true));
return res;
}
bool SortHelper::tryGetVariableSort(unsigned var, Formula* f, TermList& res)
{
TermList varTerm(var, false);
SubformulaIterator sfit(f);
while (sfit.hasNext()) {
Formula* sf = sfit.next();
if (sf->connective() == LITERAL){
Literal* lit = sf->literal();
if(lit->isEquality()){
TermList* left = lit->nthArgument(0);
TermList* right = lit->nthArgument(1);
if((left->isVar() && left->var()==var) ||
(right->isVar() && right->var()==var)){
res = getEqualityArgumentSort(lit);
return true;
}
if (lit->isTwoVarEquality()) {
TermList sort = lit->twoVarEqSort();
if (sort.containsSubterm(varTerm)) {
res = AtomicSort::superSort();
return true;
}
}
}
if(tryGetVariableSortTerm(varTerm, lit, res, false)){
return true;
}
}
if(sf->connective() == BOOL_TERM){
TermList stt = sf->getBooleanTerm();
if(stt.isVar() && stt.var()==var){
res = AtomicSort::boolSort();
return true;
}
if(stt.isTerm()){
Term* st = stt.term();
if(tryGetVariableSortTerm(varTerm,st,res, false)){
return true;
}
}
}
}
return false;
}
static void collectVariableSortsIter(CollectTask task, DHMap<unsigned,TermList>& map, bool ignoreBound = false)
{
Stack<CollectTask> todo;
ZIArray<unsigned> bound;
todo.push(task);
while (todo.isNonEmpty()) {
CollectTask task = todo.pop();
switch(task.fncTag) {
case COLLECT_TERM: {
Term* term = task.t;
unsigned position = 0;
for (TermList* ts = term->args(); ts->isNonEmpty(); ts = ts->next()) {
CollectTask newTask(COLLECT_TERMLIST);
newTask.ts = *ts;
newTask.contextSort = SortHelper::getArgSort(term, position++);
todo.push(newTask);
}
} break;
case COLLECT_TERMLIST: {
TermList ts = task.ts;
if (ts.isTerm()) {
Term* term = ts.term();
CollectTask newTask(term->isSpecial() ? COLLECT_SPECIALTERM : COLLECT_TERM);
newTask.t = term;
newTask.contextSort = task.contextSort;
todo.push(newTask);
} else if (ts.isOrdinaryVar()) {
unsigned var = ts.var();
if (!ignoreBound || !bound.get(var)) {
if (!map.insert(var, task.contextSort)) {
ASS_EQ(task.contextSort, map.get(var));
}
}
}
} break;
case COLLECT_SPECIALTERM: {
Term* term = task.t;
ASS(term->isSpecial());
Term::SpecialTermData* sd = term->getSpecialData();
switch (term->specialFunctor()) {
case SpecialFunctor::ITE: {
CollectTask newTask(COLLECT_TERMLIST);
newTask.contextSort = sd->getSort();
newTask.ts = *term->nthArgument(0);
todo.push(newTask);
newTask.ts = *term->nthArgument(1);
todo.push(newTask);
newTask.fncTag = COLLECT_FORMULA;
newTask.f = sd->getITECondition();
todo.push(newTask);
break;
}
case SpecialFunctor::LET: {
CollectTask newTask(COLLECT_FORMULA);
newTask.f = sd->getLetBinding();
todo.push(newTask);
newTask.fncTag = COLLECT_TERMLIST;
newTask.contextSort = sd->getSort();
newTask.ts = *term->nthArgument(0);
todo.push(newTask);
break;
}
case SpecialFunctor::FORMULA: {
CollectTask newTask(COLLECT_FORMULA);
newTask.f = sd->getFormula();
todo.push(newTask);
} break;
case SpecialFunctor::LAMBDA: {
CollectTask newTask(COLLECT_TERMLIST);
newTask.contextSort = sd->getLambdaExpSort();
newTask.ts = sd->getLambdaExp();
todo.push(newTask);
} break;
case SpecialFunctor::MATCH: {
CollectTask newTask(COLLECT_TERMLIST);
auto matchedSort = term->getSpecialData()->getMatchedSort();
newTask.ts = *term->nthArgument(0);
newTask.contextSort = matchedSort;
todo.push(newTask);
for (unsigned int i = 1; i < term->arity(); i += 2) {
newTask.ts = *term->nthArgument(i);
newTask.contextSort = matchedSort;
todo.push(newTask);
newTask.ts = *term->nthArgument(i + 1);
newTask.contextSort = sd->getSort();
todo.push(newTask);
}
break;
}
}
} break;
case COLLECT_FORMULA: {
Formula* f = task.f;
switch (f->connective()) {
case LITERAL: {
Literal* lit = f->literal();
if(lit->isTwoVarEquality()){
CollectTask newTask(COLLECT_TERMLIST);
newTask.ts = lit->twoVarEqSort();
newTask.contextSort = AtomicSort::superSort();
todo.push(newTask);
}
CollectTask newTask(COLLECT_TERM);
newTask.t = lit;
todo.push(newTask);
break;
}
case BOOL_TERM: {
TermList ts = f->getBooleanTerm();
if (ts.isVar()) {
if (!ignoreBound || !bound.get(ts.var())) {
if (!map.insert(ts.var(), AtomicSort::boolSort())) {
ASS_EQ(AtomicSort::boolSort(), map.get(ts.var()));
}
}
} else {
ASS(ts.isTerm());
CollectTask newTask(ts.term()->isSpecial() ? COLLECT_SPECIALTERM : COLLECT_TERM);
newTask.t = ts.term();
newTask.contextSort = AtomicSort::boolSort();
todo.push(newTask);
}
break;
}
case EXISTS:
case FORALL: {
if (ignoreBound) {
CollectTask unbindTask(UNBIND);
unbindTask.vars = f->vars();
todo.push(unbindTask);
}
CollectTask newTask(COLLECT_FORMULA);
newTask.f = f->qarg();
todo.push(newTask);
if (ignoreBound) {
CollectTask bindTask(BIND);
bindTask.vars = f->vars();
todo.push(bindTask);
}
break;
}
case AND:
case OR: {
FormulaList::Iterator argIt(f->args());
while (argIt.hasNext()) {
CollectTask newTask(COLLECT_FORMULA);
newTask.f = argIt.next();
todo.push(newTask);
}
break;
}
case IMP:
case IFF:
case XOR: {
CollectTask leftTask(COLLECT_FORMULA);
leftTask.f = f->left();
todo.push(leftTask);
CollectTask rightTask(COLLECT_FORMULA);
rightTask.f = f->right();
todo.push(rightTask);
break;
}
case NOT: {
CollectTask newTask(COLLECT_FORMULA);
newTask.f = f->uarg();
todo.push(newTask);
break;
}
default:
continue;
}
} break;
case BIND: {
VList::Iterator vit(task.vars);
while (vit.hasNext()) {
bound[vit.next()]++;
}
} break;
case UNBIND: {
VList::Iterator vit(task.vars);
while (vit.hasNext()) {
bound[vit.next()]--;
}
} break;
}
}
}
void SortHelper::collectVariableSorts(Term* term, DHMap<unsigned,TermList>& map)
{
CollectTask t(term->isSpecial() ? COLLECT_SPECIALTERM : COLLECT_TERM);
t.t = term;
collectVariableSortsIter(t,map);
}
void SortHelper::collectVariableSorts(Formula* f, DHMap<unsigned,TermList>& map, bool ignoreBound)
{
CollectTask task(COLLECT_FORMULA);
task.f = f;
collectVariableSortsIter(task,map,ignoreBound);
}
void SortHelper::collectVariableSorts(Unit* u, DHMap<unsigned,TermList>& map)
{
if (!u->isClause()) {
FormulaUnit* fu = static_cast<FormulaUnit*>(u);
CollectTask task(COLLECT_FORMULA);
task.f = fu->formula();
collectVariableSortsIter(task,map);
return;
}
Clause* cl = static_cast<Clause*>(u);
for (Literal* l : cl->iterLits()) {
CollectTask task(COLLECT_TERM);
task.t = l;
collectVariableSortsIter(task,map);
}
}
void SortHelper::normaliseArgSorts(VList* qVars, TermStack& argSorts)
{
Substitution subst;
unsigned i = 0;
while(qVars){
unsigned var = qVars->head();
subst.bindUnbound(var, TermList(i++, false));
qVars = qVars->tail();
}
for(unsigned i = 0; i < argSorts.size(); i++){
argSorts[i] = SubstHelper::apply(argSorts[i], subst);
}
}
void SortHelper::normaliseSort(VList* qVars, TermList& sort)
{
Substitution subst;
unsigned i = 0;
while(qVars){
unsigned var = qVars->head();
subst.bindUnbound(var, TermList(i++, false));
qVars = qVars->tail();
}
sort = SubstHelper::apply(sort, subst);
}
void SortHelper::normaliseArgSorts(const TermStack& qVars, TermStack& argSorts)
{
Substitution subst;
for(unsigned i = 0; i < qVars.size(); i++){
subst.bindUnbound(qVars[i].var(), TermList(i, false));
}
for(unsigned i = 0; i < argSorts.size(); i++){
argSorts[i] = SubstHelper::apply(argSorts[i], subst);
}
}
void SortHelper::normaliseSort(TermStack qVars, TermList& sort)
{
Substitution subst;
for(unsigned i = 0; i < qVars.size(); i++){
subst.bindUnbound(qVars[i].var(), TermList(i, false));
}
sort = SubstHelper::apply(sort, subst);
}
bool SortHelper::tryGetVariableSortTerm(TermList var, Term* t0, TermList& result, bool recurseToSubformulas)
{
ASS(var.isVar());
NonVariableIterator sit(t0,true);
while (sit.hasNext()) {
Term* t = sit.next().term();
if(t->isLet()){
if (recurseToSubformulas) {
Formula* binding = t->getSpecialData()->getLetBinding();
if (tryGetVariableSort(var.var(), binding, result)){
return true;
}
}
ASS_EQ(t->arity(),1);
if (*t->nthArgument(0) == var) {
result = t->getSpecialData()->getSort();
return true;
}
continue;
}
if (t->isITE()) {
if (recurseToSubformulas) {
Formula* f = t->getSpecialData()->getITECondition();
if(tryGetVariableSort(var.var(), f, result)){
return true;
}
}
ASS_EQ(t->arity(),2);
if (*t->nthArgument(0) == var || *t->nthArgument(1) == var) {
result = t->getSpecialData()->getSort();
return true;
}
continue;
}
if(t->isFormula() && recurseToSubformulas){
Formula* f = t->getSpecialData()->getFormula();
if(tryGetVariableSort(var.var(), f, result)){
return true;
}
}
if (t->isLambda()) {
TermList sort = t->getSpecialData()->getLambdaExpSort();
TermList lambdaTerm = t->getSpecialData()->getLambdaExp();
if(lambdaTerm.isTerm()){
if(tryGetVariableSortTerm(var, lambdaTerm.term(),result,recurseToSubformulas)){
return true;
}
} else {
if(lambdaTerm == var){
result = sort;
return true;
}
}
continue;
}
if (t->isMatch()) {
for (unsigned int i = 0; i < t->arity(); i++) {
auto arg = t->nthArgument(i);
if (*arg == var && tryGetResultSort(*arg, result)) {
return true;
}
}
continue;
}
if (t->shared() && t->ground()) {
sit.right();
continue;
}
int idx = 0;
TermList* args = t->args();
while (!args->isEmpty()) {
if (*args==var) {
result = getArgSort(t, idx);
return true;
}
idx++;
args=args->next();
}
}
return false;
}
bool SortHelper::areImmediateSortsValidPoly(Term* t)
{
ASS(!t->isSuper());
if (t->isLiteral() && static_cast<Literal*>(t)->isEquality()) {
Literal* lit = static_cast<Literal*>(t);
TermList eqSrt = getEqualityArgumentSort(lit);
for (unsigned i=0; i<2; i++) {
TermList arg = *t->nthArgument(i);
if (!arg.isTerm()) { continue; }
Term* ta = arg.term();
TermList argSort = getResultSort(ta);
if (eqSrt != argSort) {
return false;
}
}
return true;
}
OperatorType* type = getType(t);
unsigned arity = t->arity();
Substitution subst;
getTypeSub(t, subst);
for (unsigned i = 0; i < arity; i++) {
TermList arg = *t->nthArgument(i);
if (!arg.isTerm()) { continue; }
Term* ta = arg.term();
TermList argSort = getResultSort(ta);
TermList instantiatedTypeSort = SubstHelper::apply(type->arg(i), subst);
if (instantiatedTypeSort != argSort) {
return false;
}
}
return true;
}
bool SortHelper::areImmediateSortsValidMono(Term* t)
{
ASS(!t->isSuper());
if (t->isLiteral() && static_cast<Literal*>(t)->isEquality()) {
Literal* lit = static_cast<Literal*>(t);
TermList eqSrt = getEqualityArgumentSort(lit);
for (unsigned i=0; i<2; i++) {
TermList arg = *t->nthArgument(i);
if (!arg.isTerm()) { continue; }
Term* ta = arg.term();
TermList argSort = getResultSortMono(ta);
if (eqSrt != argSort) {
return false;
}
}
return true;
}
OperatorType* type = getType(t);
unsigned arity = t->arity();
for (unsigned i=0; i<arity; i++) {
TermList arg = *t->nthArgument(i);
if (!arg.isTerm()) { continue; }
Term* ta = arg.term();
TermList argSort = getResultSortMono(ta);
if (type->arg(i) != argSort) {
return false;
}
}
return true;
}
bool SortHelper::allTopLevelArgsAreSorts(AtomicSort* sort)
{
for(unsigned i = 0; i < sort->arity(); i++){
TermList arg = *sort->nthArgument(i);
if(arg.isVar()){
continue;
}
if(!arg.term()->isSort()){
return false;
}
}
return true;
}
TermList SortHelper::getIndexSort(TermList arraySort)
{
ASS(arraySort.isArraySort());
return *arraySort.term()->nthArgument(0);
}
TermList SortHelper::getInnerSort(TermList arraySort)
{
ASS(arraySort.isArraySort());
return *arraySort.term()->nthArgument(1);
}
bool SortHelper::areSortsValid(Clause* cl)
{
static DHMap<unsigned,TermList> varSorts;
varSorts.reset();
unsigned clen = cl->length();
for (unsigned i=0; i<clen; i++) {
if (!areSortsValid((*cl)[i], varSorts)) {
return false;
}
}
return true;
}
bool SortHelper::areSortsValid(Term* t0)
{
DHMap<unsigned,TermList> varSorts;
return areSortsValid(t0, varSorts);
}
bool SortHelper::areSortsValid(Term* t0, DHMap<unsigned,TermList>& varSorts)
{
NonVariableIterator sit(t0,true);
while (sit.hasNext()) {
Term* t = sit.next().term();
int idx = 0;
TermList* args = t->args();
while (!args->isEmpty()) {
TermList argSrt = getArgSort(t,idx);
TermList arg = *args;
if (arg.isVar()) {
TermList varSrt;
if (!varSorts.findOrInsert(arg.var(), varSrt, argSrt)) {
if (varSrt != argSrt) {
return false;
}
}
} else {
if (argSrt != getResultSort(arg.term())) {
return false;
}
}
idx++;
args=args->next();
}
}
return true;
}