* Skolemizes the given formula, if possible, otherwise returns the result
* of replacing its free variables according to the current replacement environment.
* @see kodkod.ast.visitor.AbstractReplacer#visit(kodkod.ast.QuantifiedFormula)
*/
public final Formula visit(QuantifiedFormula qf) {
Formula ret = lookup(qf);
if (ret!=null) return ret;
final Environment<Expression> oldRepEnv = repEnv;
final Quantifier quant = qf.quantifier();
final Decls decls = qf.decls();
if (skolemDepth>=0 && (negated && quant==ALL || !negated && quant==SOME)) { // skolemizable formula
final List<Formula> rangeConstraints = new LinkedList<Formula>();
final List<Formula> domConstraints = new LinkedList<Formula>();
for(Decl decl : decls) {
final Decl skolemDecl = visit(decl);
final Relation skolem = Relation.nary("$"+ skolemDecl.variable().name(), nonSkolems.size() + skolemDecl.variable().arity());
reporter.skolemizing(decl, skolem, nonSkolemsView);
final Expression skolemExpr = skolemExpr(skolemDecl, skolem);
final Multiplicity mult = decl.multiplicity();
rangeConstraints.add(source(skolemExpr.in(skolemDecl.expression()), decl));
if (mult!=Multiplicity.SET) {
rangeConstraints.add(source(skolemExpr.apply(mult), decl));
}
if (!nonSkolems.isEmpty())
domConstraints.add(source(domainConstraint(skolemDecl, skolem), decl));
repEnv = repEnv.extend(decl.variable(), skolemExpr);
}
ret = source(Formula.and(rangeConstraints), decls).compose(negated ? IMPLIES : AND, qf.formula().accept(this));
if (!domConstraints.isEmpty())
topSkolemConstraints.add(source(Formula.and(domConstraints), decls));
} else { // non-skolemizable formula
final Decls newDecls = visit((Decls)qf.decls());
if (skolemDepth>=nonSkolems.size()+newDecls.size()) { // could skolemize below
for(Decl d: newDecls) { nonSkolems.add(new DeclInfo(d)); }
final Formula formula = qf.formula().accept(this);
ret = ((newDecls==decls && formula==qf.formula()) ? qf : formula.quantify(quant, newDecls));
for(int i = newDecls.size(); i > 0; i--) { nonSkolems.remove(nonSkolems.size()-1); }
} else { // can't skolemize below
final int oldDepth = skolemDepth;
skolemDepth = -1;
final Formula formula = qf.formula().accept(this);
ret = ((newDecls==decls && formula==qf.formula()) ? qf : formula.quantify(quant, newDecls));
skolemDepth = oldDepth;
}
}
repEnv = oldRepEnv;