/*
* Copyright (C) 2009-2014 University of Freiburg
*
* This file is part of SMTInterpol.
*
* SMTInterpol is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SMTInterpol is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with SMTInterpol. If not, see <http://www.gnu.org/licenses/>.
*/
package de.uni_freiburg.informatik.ultimate.logic;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Map;
import de.uni_freiburg.informatik.ultimate.util.HashUtils;
import de.uni_freiburg.informatik.ultimate.util.datastructures.ScopedHashMap;
import de.uni_freiburg.informatik.ultimate.util.datastructures.UnifyHash;
/**
* The theory is not intended for public use. Please stick to the
* {@link Script} interface and use the functions in {@link Util} to simplify
* logical formulas.
*
* The theory is a container for the function symbols, sort symbols and a
* unifier for all terms created by this theory. Each sort belongs to one
* theory and since every function symbol and every term has a sort, they also
* belong to one theory.
*
* The theory also defines all predefined function symbols required by the
* logic that was set with setLogic(). It allows creating new function and
* sort symbols.
*
* @author Jochen Hoenicke
*/
public class Theory {
/**
* Helper class to set up symbols specific to a solver.
* @author Juergen Christ
*/
public static abstract class SolverSetup {
/**
* Set up symbols needed by this solver. These symbols might depend
* upon the logic, e.g., the diff-symbol needed for quantifier-free
* array interpolation.
* @param theory The theory to be used by the solver.
* @param logic The logic set for this theory
* (@see {@link Theory#getLogic()}).
*/
public abstract void setLogic(Theory theory, Logics logic);
/// *** Delegators ***
protected final void declareInternalSort(
Theory theory, String name, int cardinality, int flags) {
theory.declareInternalSort(name, cardinality, flags);
}
protected final void declareInternalFunction(Theory theory, String name,
Sort[] paramSorts, Sort resultSort, int flags) {
theory.declareInternalFunction(name, paramSorts, resultSort, flags);
}
protected final void declareInternalFunction(Theory theory, String name,
Sort[] paramTypes, TermVariable[] defVars, Term definition,
int flags) {
theory.declareInternalFunction(
name, paramTypes, defVars, definition, flags);
}
protected final void declareInternalPolymorphicFunction(Theory theory,
String name, Sort[] sortParams,
Sort[] paramTypes, Sort resultType, int flags) {
theory.declareInternalPolymorphicFunction(
name, sortParams, paramTypes, resultType, flags);
}
protected final void defineFunction(
Theory theory, FunctionSymbolFactory factory) {
theory.defineFunction(factory);
}
}
private SolverSetup mSolverSetup;
private Logics mLogic;
private Sort mNumericSort, mRealSort, mStringSort, mBooleanSort;
private SortSymbol mBitVecSort, mFloatingPointSort;
private Sort mRoundingModeSort;
private final HashMap<String, FunctionSymbolFactory> mFunFactory =
new HashMap<String, FunctionSymbolFactory>();
private final UnifyHash<FunctionSymbol> mModelValueCache =
new UnifyHash<FunctionSymbol>();
private final ScopedHashMap<String, SortSymbol> mDeclaredSorts =
new ScopedHashMap<String, SortSymbol>();
private final ScopedHashMap<String, FunctionSymbol> mDeclaredFuns =
new ScopedHashMap<String, FunctionSymbol>();
private final UnifyHash<QuantifiedFormula> mQfCache =
new UnifyHash<QuantifiedFormula>();
private final UnifyHash<LetTerm> mLetCache = new UnifyHash<LetTerm>();
private final UnifyHash<Term> mTermCache = new UnifyHash<Term>();
private final UnifyHash<TermVariable> mTvUnify =
new UnifyHash<TermVariable>();
/**
* Cache for bitvector constant function symbols (_ bv123 456).
*/
private UnifyHash<FunctionSymbol> mBitVecConstCache;
public final ApplicationTerm mTrue, mFalse;
public final FunctionSymbol mAnd, mOr, mNot, mImplies, mXor;
public final PolymorphicFunctionSymbol mEquals, mDistinct, mIte;
final static Sort[] EMPTY_SORT_ARRAY = Script.EMPTY_SORT_ARRAY;
final static TermVariable[] EMPTY_TERM_VARIABLE_ARRAY = {};
final static Term[] EMPTY_TERM_ARRAY = Script.EMPTY_TERM_ARRAY;
/**
* Pattern for model value variables '{@literal @}digits'.
*/
private final static String MODEL_VALUE_PATTERN = "@\\d+";
private final static String BITVEC_CONST_PATTERN = "bv\\d+";
private int mTvarCtr = 0;
private int mSkolemCounter = 0;
private boolean mGlobalDecls;
public Theory() {
mTrue = mFalse = null;
mAnd = mOr = mNot = mImplies = mXor = null;
mEquals = mDistinct = mIte = null;
}
public Theory(Logics logic) {
this(logic, null);
}
/**
* Create the term factory. The solver setup should be used to create
* internal function symbols, e.g., to represent proof objects.
* @param logic The logic to use.
* @param solverSetup The solver-specific setup delegate.
*/
public Theory(Logics logic, SolverSetup solverSetup) {
mSolverSetup = solverSetup;
final Sort[] noarg = new Sort[0];
mBooleanSort = declareInternalSort("Bool", 0, 0).getSort(
null, noarg);
final Sort[] generic1 = createSortVariables("A");
final Sort[] bool1 = new Sort[] { mBooleanSort};
final Sort[] bool2 = new Sort[] { mBooleanSort, mBooleanSort};
final Sort[] generic2 = new Sort[] { generic1[0], generic1[0] };
final int leftassoc = FunctionSymbol.LEFTASSOC;
mNot = declareInternalFunction("not", bool1, mBooleanSort, 0);
mAnd = declareInternalFunction("and", bool2, mBooleanSort, leftassoc);
mOr = declareInternalFunction("or", bool2, mBooleanSort, leftassoc);
mImplies = declareInternalFunction(
"=>", bool2, mBooleanSort, FunctionSymbol.RIGHTASSOC);
mEquals = declareInternalPolymorphicFunction("=", generic1, generic2,
mBooleanSort, FunctionSymbol.CHAINABLE);
mDistinct = declareInternalPolymorphicFunction(
"distinct", generic1, generic2,
mBooleanSort, FunctionSymbol.PAIRWISE);
mXor = declareInternalFunction("xor", bool2, mBooleanSort, leftassoc);
mIte = declareInternalPolymorphicFunction(
"ite", generic1,
new Sort[] { mBooleanSort, generic1[0], generic1[0] },
generic1[0],
0);
mTrue = term(declareInternalFunction("true", noarg, mBooleanSort, 0));
mFalse = term(declareInternalFunction("false", noarg, mBooleanSort, 0));
// Finally, declare logic specific functions
setLogic(logic);
}
/******************** LOGICAL OPERATORS *******************************/
private Term simplifyAndOr(FunctionSymbol connector, Term... subforms) {
final Term neutral = (connector == mAnd ? mTrue : mFalse);
final LinkedHashSet<Term> formulas = new LinkedHashSet<Term>();
for (final Term f : subforms) {
if (f == mTrue || f == mFalse) {
if (f == neutral) {
continue;
} else {
return f;
}
}
/* Normalize nested and/ors */
if (f instanceof ApplicationTerm
&& ((ApplicationTerm) f).getFunction() == connector) {
for (final Term subf : ((ApplicationTerm) f).getParameters()) {
formulas.add(subf);
}
} else {
formulas.add(f);
}
}
if (formulas.size() <= 1) { // NOPMD
if (formulas.isEmpty()) {
return neutral;
} else {
return formulas.iterator().next();
}
}
final Term[] arrforms = formulas.toArray(new Term[formulas.size()]);
return term(connector, arrforms);
}
public Term not(Term f) {
if (f == mTrue) {
return mFalse;
}
if (f == mFalse) {
return mTrue;
}
if (f instanceof ApplicationTerm
&& ((ApplicationTerm)f).getFunction() == mNot) {
return ((ApplicationTerm) f).getParameters()[0];
}
return term(mNot, f);
}
public Term and(Term... subforms) {
return simplifyAndOr(mAnd, subforms);
}
public Term or(Term... subforms) {
return simplifyAndOr(mOr, subforms);
}
public Term implies(Term f, Term g) {
if (g == mTrue || f == mTrue) {
return g;
}
if (f == mFalse) {
return mTrue;
}
if (g == mFalse) {
return not(f);
}
if (f == g) {
return mTrue;
}
return term(mImplies, f, g);
}
public Term xor(Term f, Term g) {
if (f == mTrue) {
return not(g);
}
if (g == mTrue) {
return not(f);
}
if (f == mFalse) {
return g;
}
if (g == mFalse) {
return f;
}
if (f == g) {
return mFalse;
}
return term(mXor, f, g);
}
public Term ifthenelse(Term c, Term t, Term e) {
if (c == mTrue) {
return t;
}
if (c == mFalse) {
return e;
}
if (t == e) {
return t;
}
if (t == mTrue && e == mFalse) {
return c;
}
if (t == mFalse && e == mTrue) {
return not(c);
}
if (t == mTrue) {
return term(mOr, c, e);
}
if (t == mFalse) {
return term(mAnd, term(mNot, c), e);
}
if (e == mTrue) {
return term(mImplies, c, t);
}
if (e == mFalse) {
return term(mAnd, c, t);
}
return term(mIte, c, t, e);
}
private Term quantify(int quant, TermVariable[] vars, Term f) {
if (f == mTrue || f == mFalse) {
return f;
}
final int hash = QuantifiedFormula.hashQuantifier(quant, vars, f);
for (final QuantifiedFormula qf : mQfCache.iterateHashCode(hash)) {
if (qf.getQuantifier() == quant && qf.getSubformula() == f
&& Arrays.equals(vars,qf.getVariables())) {
return qf;
}
}
final QuantifiedFormula qf =
new QuantifiedFormula(quant, vars, f, hash);
mQfCache.put(hash,qf);
return qf;
}
public Term exists(TermVariable[] vars, Term f) {
return quantify(QuantifiedFormula.EXISTS, vars, f);
}
public Term forall(TermVariable[] vars, Term f) {
return quantify(QuantifiedFormula.FORALL, vars, f);
}
public Term let(TermVariable[] vars, Term[] values, Term subform) {
assert (vars.length == values.length);
if (vars.length == 0) {
return subform;
}
final int hash = LetTerm.hashLet(vars, values, subform);
for (final LetTerm lt : mLetCache.iterateHashCode(hash)) {
if (lt.getSubTerm() == subform
&& Arrays.equals(lt.getVariables(), vars)
&& Arrays.equals(lt.getValues(), values)) {
return lt;
}
}
final LetTerm lf = new LetTerm(vars, values, subform, hash);
mLetCache.put(hash,lf);
return lf;
}
public Term let(TermVariable var, Term value, Term subform) {
return let(new TermVariable[] {var}, new Term[]{value}, subform);
}
public Term distinct(Term... terms) {
if (terms.length < 2) {
return null;
}
if (terms.length == 2) {
if (terms[0] == terms[1]) {
return mFalse;
}
if (terms[0].getSort() == mBooleanSort) {
if (terms[0] == mFalse) {
return terms[1];
}
if (terms[1] == mFalse) {
return terms[0];
}
if (terms[0] == mTrue) {
return not(terms[1]);
}
if (terms[1] == mTrue) {
return not(terms[0]);
}
}
return term(mDistinct, terms);
}
final HashSet<Term> params = new HashSet<Term>(Arrays.asList(terms));
if (params.size() != terms.length) {
// We had something like (distinct ... a ... a ...)
return mFalse;
}
return term(mDistinct, terms);
}
public Term equals(Term... terms) {
if (terms.length < 2) {
return null;
}
if (terms.length == 2) {
if (terms[0] == terms[1]) {
return mTrue;
}
if (terms[0].getSort() == mBooleanSort) {
if (terms[0] == mTrue) {
return terms[1];
}
if (terms[1] == mTrue) {
return terms[0];
}
if (terms[0] == mFalse) {
return not(terms[1]);
}
if (terms[1] == mFalse) {
return not(terms[0]);
}
}
return term(mEquals, terms);
}
final HashSet<Term> params = new HashSet<Term>(Arrays.asList(terms));
if (params.size() == 1) {
// We had (= a a ... a)
return mTrue;
}
return term(mEquals, terms);
}
/******************** CONSTANTS *************************************/
public Term constant(Object value, Sort sort) {
if (value instanceof Rational) {
if (!sort.isNumericSort()) {
throw new SMTLIBException("Not a numeric sort");
}
final Rational v = (Rational) value;
if (!v.isRational()) {
throw new SMTLIBException("Infinite/NaN value");
}
if (sort.getName().equals("Int") && !v.isIntegral()) {
throw new SMTLIBException(
"Non-integral value with integer sort");
}
}
final int hash = ConstantTerm.hashConstant(value, sort);
for (final Term t : mTermCache.iterateHashCode(hash)) {
if (t instanceof ConstantTerm) {
final ConstantTerm nt = (ConstantTerm)t;
if (nt.getSort() == sort && value.equals(nt.getValue())) {
return nt;
}
}
}
final ConstantTerm nt = new ConstantTerm(value, sort, hash);
mTermCache.put(hash,nt);
return nt;
}
public Term numeral(BigInteger num) {
Term result = constant(num.abs(), mNumericSort);
if (num.signum() < 0) {
final FunctionSymbol neg = getFunction("-", mNumericSort);
result = term(neg, result);
}
return result;
}
public Term numeral(String num) {
return numeral(new BigInteger(num));
}
public Term decimal(BigDecimal value) {
// Fix for 1 vs 1.0: Normalize to .0 for constants.
if (value.scale() == 0) {
value = value.setScale(1);
}
Term result = constant(value.abs(), mRealSort);
if (value.signum() < 0) {
final FunctionSymbol neg = getFunction("-", mRealSort);
result = term(neg, result);
}
return result;
}
public Term decimal(String value) {
return decimal(new BigDecimal(value));
}
/**
* Convert a rational constant to a term of the correct sort.
* The constant must be integral if the sort is integer.
* @param c the constant to convert.
* @param sort the sort; either Real or Int.
* @return an smt term representing constant c.
*/
public Term rational(Rational c, Sort sort) {
// This must not be an infinite or a NAN.
assert c.denominator().signum() == 1;
if (sort == mRealSort) {
return rational(c.numerator(), c.denominator());
} else {
assert c.isIntegral();
return numeral(c.numerator());
}
}
public Term binary(String value) {
assert value.startsWith("#b");
if (mBitVecSort == null) {
return null;
}
final BigInteger bsize = BigInteger.valueOf(value.length() - 2);
final Sort sort = mBitVecSort.getSort(
new BigInteger[] { bsize }, new Sort[0]);
return new ConstantTerm(value, sort,
ConstantTerm.hashConstant(value, sort));
}
public Term hexadecimal(String value) {
assert value.startsWith("#x");
if (mBitVecSort == null) {
return null;
}
final BigInteger bsize = BigInteger.valueOf(4 * (value.length() - 2));// NOCHECKSTYLE
final Sort sort = mBitVecSort.getSort(
new BigInteger[] { bsize }, new Sort[0]);
return new ConstantTerm(value, sort,
ConstantTerm.hashConstant(value, sort));
}
public Term rational(BigInteger num, BigInteger denom) {
BigInteger gcd = num.gcd(denom);
if (denom.signum() * gcd.signum() < 0) {
gcd = gcd.negate();
}
num = num.divide(gcd);
denom = denom.divide(gcd);
if (denom.equals(BigInteger.ONE))
{
return decimal(new BigDecimal(num));// numeral(num);
}
final FunctionSymbol div = getFunction("/", mNumericSort, mNumericSort);
return term(div, decimal(new BigDecimal(num)), decimal(new BigDecimal(denom)));
}
public Term modelRational(Rational rat, Sort sort) {
if (sort == mRealSort) {
final BigInteger num = rat.numerator();
final BigInteger denom = rat.denominator();
if (denom.equals(BigInteger.ONE) && !mLogic.isIRA()) {
return decimal(new BigDecimal(num));
} else {
if (mLogic.isIRA()) {
final FunctionSymbol div = getFunction("/", mRealSort, mRealSort);
final FunctionSymbol toreal = getFunction("to_real", mNumericSort);
Term numeralTerm = term(toreal, numeral(num.abs()));
if (num.signum() < 0) {
numeralTerm = term("-", numeralTerm);
}
return term(div, numeralTerm, term(toreal, numeral(denom)));
} else {
final FunctionSymbol div =
getFunction("/", mNumericSort, mNumericSort);
return term(div, numeral(num), numeral(denom));
}
}
} else {
assert rat.isIntegral();
return numeral(rat.numerator());
}
}
public Term string(String value) {
return constant(new QuotedObject(value), mStringSort);
}
/******************** LOGICS AND THEORIES ********************************/
public Logics getLogic() {
return mLogic;
}
FunctionSymbol declareInternalFunction(String name, Sort[] paramTypes,
Sort resultType, int flags) {
return defineFunction(name, paramTypes, resultType, null, null,
flags | FunctionSymbol.INTERNAL);
}
FunctionSymbol declareInternalFunction(String name, Sort[] paramTypes,
TermVariable[] defVars, Term definition, int flags) {
return defineFunction(name, paramTypes, definition.getSort(),
defVars, definition, flags | FunctionSymbol.INTERNAL);
}
PolymorphicFunctionSymbol declareInternalPolymorphicFunction(
String name, Sort[] sortParams,
Sort[] paramTypes, Sort resultType, int flags) {
assert !mFunFactory.containsKey(name);
final PolymorphicFunctionSymbol f = new PolymorphicFunctionSymbol(
name, sortParams, paramTypes, resultType,
flags | FunctionSymbol.INTERNAL);
defineFunction(f);
return f;
}
class MinusFunctionFactory extends FunctionSymbolFactory {
Sort mSort1, mSort2;
public MinusFunctionFactory(Sort sort1, Sort sort2) {
super("-");
mSort1 = sort1;
mSort2 = sort2;
}
@Override
public int getFlags(
BigInteger[] indices, Sort[] paramSorts, Sort resultSort) {
return paramSorts.length == 1 ? FunctionSymbol.INTERNAL
: FunctionSymbol.LEFTASSOC | FunctionSymbol.INTERNAL;
}
@Override
public Sort getResultSort(BigInteger[] indices, Sort[] paramSorts,
Sort resultSort) {
if (indices != null
|| paramSorts.length == 0 || paramSorts.length > 2
|| resultSort != null
|| (paramSorts[0] != mSort1 && paramSorts[0] != mSort2)) {
return null;
}
if (paramSorts.length == 2 && paramSorts[0] != paramSorts[1]) {
return null;
}
return paramSorts[0];
}
}
class DivisibleFunctionFactory extends FunctionSymbolFactory {
public DivisibleFunctionFactory() {
super("divisible");
}
@Override
public Sort getResultSort(
BigInteger[] indices, Sort[] paramSorts, Sort resultSort) {
return indices != null && indices.length == 1
&& indices[0].signum() > 0
&& paramSorts.length == 1 && paramSorts[0] == mNumericSort
&& resultSort == null ? mBooleanSort : null;
}
}
private void createNumericOperators(final Sort sort, boolean isRational) {
final Sort[] sort1 = new Sort[] { sort };
final Sort[] sort2 = new Sort[] { sort, sort };
declareInternalFunction("+", sort2, sort, FunctionSymbol.LEFTASSOC);
defineFunction(new MinusFunctionFactory(sort, sort));
declareInternalFunction("*", sort2, sort, FunctionSymbol.LEFTASSOC);
if (isRational) {
declareInternalFunction("/", sort2, sort, FunctionSymbol.LEFTASSOC);
} else {
declareInternalFunction(
"div", sort2, sort, FunctionSymbol.LEFTASSOC);
declareInternalFunction("mod", sort2, sort, 0);
defineFunction(new DivisibleFunctionFactory());
}
final Sort sBool = mBooleanSort;
declareInternalFunction(">", sort2, sBool, FunctionSymbol.CHAINABLE);
declareInternalFunction(">=", sort2, sBool, FunctionSymbol.CHAINABLE);
declareInternalFunction("<", sort2, sBool, FunctionSymbol.CHAINABLE);
declareInternalFunction("<=", sort2, sBool, FunctionSymbol.CHAINABLE);
final TermVariable x = createTermVariable("x1", sort);
final Term zero = isRational ? decimal("0.0") : numeral("0");
final Term absx = term("ite", term(">=", x, zero), x, term("-", x));
declareInternalFunction("abs", sort1,
new TermVariable[]{ x }, absx, 0);
}
private void createIRAOperators() {
class BinArithFactory extends FunctionSymbolFactory {
Sort mReturnSort;
int mFlags;
BinArithFactory(String name, Sort returnSort, int flags) {
super(name);
mReturnSort = returnSort;
mFlags = flags | FunctionSymbol.INTERNAL;
}
@Override
public int getFlags(
BigInteger[] indices, Sort[] paramSorts, Sort resultSort) {
return mFlags;
}
@Override
public Sort getResultSort(
BigInteger[] indices, Sort[] paramSorts, Sort resultSort) {
if (indices == null
&& paramSorts.length == 2
&& paramSorts[0] == paramSorts[1]
&& (paramSorts[0] == mNumericSort
|| paramSorts[0] == mRealSort)
&& resultSort == null) {
return mReturnSort == null ? paramSorts[0] : mReturnSort;
} else {
return null;
}
}
}
defineFunction(
new BinArithFactory("+", null, FunctionSymbol.LEFTASSOC));
defineFunction(
new MinusFunctionFactory(mNumericSort, mRealSort));
defineFunction(
new BinArithFactory("*", null, FunctionSymbol.LEFTASSOC));
defineFunction(
new BinArithFactory(
">", mBooleanSort, FunctionSymbol.CHAINABLE));
defineFunction(
new BinArithFactory(
">=", mBooleanSort, FunctionSymbol.CHAINABLE));
defineFunction(
new BinArithFactory(
"<", mBooleanSort, FunctionSymbol.CHAINABLE));
defineFunction(
new BinArithFactory(
"<=", mBooleanSort, FunctionSymbol.CHAINABLE));
final Sort[] int1 = new Sort[] { mNumericSort };
final Sort[] int2 = new Sort[] { mNumericSort, mNumericSort };
final Sort[] real1 = new Sort[] { mRealSort };
final Sort[] real2 = new Sort[] { mRealSort, mRealSort };
declareInternalFunction(
"/", real2, mRealSort, FunctionSymbol.LEFTASSOC);
declareInternalFunction(
"div", int2, mNumericSort, FunctionSymbol.LEFTASSOC);
defineFunction(new DivisibleFunctionFactory());
declareInternalFunction("to_real", int1, mRealSort, 0);
declareInternalFunction("to_int", real1, mNumericSort, 0);
declareInternalFunction("mod", int2, mNumericSort, 0);
final TermVariable xr = createTermVariable("x1", mRealSort);
// isint x: (= x (to_real (to_int x)))
final Term isintx = term("=", xr, term("to_real", term("to_int", xr)));
declareInternalFunction("is_int", real1,
new TermVariable[]{ xr }, isintx, 0);
defineFunction(new FunctionSymbolFactory("abs") {
@Override
public Term getDefinition(TermVariable[] tvs, Sort resultSort) {
final Term zero = (resultSort == mNumericSort) ? numeral("0")
: decimal("0.0");
// abs x: (ite (>= x 0) x (- x))
return term("ite", term(">=", tvs[0], zero),
tvs[0], term("-", tvs[0]));
}
@Override
public Sort getResultSort(
BigInteger[] indices, Sort[] paramSorts, Sort resultSort) {
if (indices == null
&& paramSorts.length == 1
&& (paramSorts[0] == mNumericSort
|| paramSorts[0] == mRealSort)
&& resultSort == null) {
return paramSorts[0];
} else {
return null;
}
}
});
}
private void createArrayOperators() {
final Sort[] generic2 = createSortVariables("X", "Y");
final SortSymbol arraySort =
declareInternalSort("Array", 2, SortSymbol.ARRAY);
final Sort array = arraySort.getSort(null, generic2);
declareInternalPolymorphicFunction(
"select", generic2, new Sort[] { array, generic2[0] },
generic2[1], 0);
declareInternalPolymorphicFunction(
"store", generic2,
new Sort[] { array, generic2[0], generic2[1] }, array, 0);
defineFunction(new FunctionSymbolFactory("const") {
@Override
public Sort getResultSort(BigInteger[] indices, Sort[] paramSorts,
Sort resultSort) {
if (indices != null
|| paramSorts.length != 1 || resultSort == null
|| resultSort.getName() != "Array"
|| ! paramSorts[0].equalsSort(resultSort.getArguments()[1])) {
return null;
}
return resultSort;
}
});
}
private void createBitVecSort() {
mBitVecSort = new SortSymbol(this, "BitVec", 0, null,
SortSymbol.INTERNAL | SortSymbol.INDEXED) {
@Override
public void checkArity(BigInteger[] indices, int arity) {
if (indices == null || indices.length != 1) {
throw new IllegalArgumentException(
"BitVec needs one index");
}
if (indices[0].signum() <= 0) {
throw new IllegalArgumentException(
"BitVec index must be positive");
}
if (arity != 0) {
throw new IllegalArgumentException(
"BitVec has no parameters");
}
}
};
mDeclaredSorts.put("BitVec", mBitVecSort);
}
private void createBitVecOperators() {
class RegularBitVecFunction extends FunctionSymbolFactory {
int mNumArgs;
int mFlags;
Sort mResult;
public RegularBitVecFunction(
String name, int numArgs, Sort result, int flags) {
super(name);
mNumArgs = numArgs;
mResult = result;
mFlags = flags;
}
public RegularBitVecFunction(
String name, int numArgs, Sort result) {
this(name, numArgs, result, FunctionSymbol.INTERNAL);
}
@Override
public int getFlags(BigInteger[] indices, Sort[] paramSorts,
Sort resultSort) {
return mFlags;
}
@Override
public Sort getResultSort(BigInteger[] indices, Sort[] paramSorts,
Sort resultSort) {
if (indices != null
|| paramSorts.length != mNumArgs || resultSort != null
|| paramSorts[0].getName() != "BitVec") {
return null;
}
for (int i = 1; i < mNumArgs; i++) {
if (paramSorts[i] != paramSorts[0]) {
return null;
}
}
return mResult == null ? paramSorts[0] : mResult;
}
}
class ExtendBitVecFunction extends FunctionSymbolFactory {
public ExtendBitVecFunction(String name) {
super(name);
}
@Override
public Sort getResultSort(BigInteger[] indices, Sort[] paramSorts,
Sort resultSort) {
if (indices == null || indices.length != 1
|| paramSorts.length != 1 || resultSort != null
|| paramSorts[0].getName() != "BitVec") {
return null;
}
final BigInteger size = indices[0].add(paramSorts[0].getIndices()[0]);
return mBitVecSort.getSort(
new BigInteger[] { size }, new Sort[0]);
}
}
class RotateBitVecFunction extends FunctionSymbolFactory {
public RotateBitVecFunction(String name) {
super(name);
}
@Override
public Sort getResultSort(BigInteger[] indices, Sort[] paramSorts,
Sort resultSort) {
if (indices == null || indices.length != 1
|| paramSorts.length != 1 || resultSort != null
|| paramSorts[0].getName() != "BitVec") {
return null;
}
return paramSorts[0];
}
}
defineFunction(new FunctionSymbolFactory("concat") {
@Override
public int getFlags(BigInteger[] indices, Sort[] paramSorts,
Sort resultSort) {
return FunctionSymbol.INTERNAL;
}
@Override
public Sort getResultSort(BigInteger[] indices, Sort[] paramSorts,
Sort resultSort) {
if (indices != null
|| paramSorts.length != 2 || resultSort != null
|| paramSorts[0].getName() != "BitVec"
|| paramSorts[1].getName() != "BitVec") {
return null;
}
final BigInteger size = paramSorts[0].getIndices()[0].
add(paramSorts[1].getIndices()[0]);
return mBitVecSort.getSort(
new BigInteger[] { size }, new Sort[0]);
}
});
defineFunction(new FunctionSymbolFactory("extract") {
@Override
public Sort getResultSort(BigInteger[] indices, Sort[] paramSorts,
Sort resultSort) {
if (indices == null || indices.length < 2
|| paramSorts.length != 1 || resultSort != null
|| paramSorts[0].getName() != "BitVec") {
return null;
}
if (indices[0].compareTo(indices[1]) < 0
|| paramSorts[0].getIndices()[0].compareTo(indices[0]) < 0) {
return null;
}
final BigInteger size = indices[0].subtract(indices[1]).
add(BigInteger.ONE);
return mBitVecSort.getSort(
new BigInteger[] { size }, new Sort[0]);
}
});
final Sort bitvec1 = mBitVecSort.
getSort(new BigInteger[] {BigInteger.ONE}, new Sort[0]);
defineFunction(new RegularBitVecFunction("bvnot", 1, null));
defineFunction(new RegularBitVecFunction("bvand", 2, null,
FunctionSymbol.INTERNAL | FunctionSymbol.LEFTASSOC));
defineFunction(new RegularBitVecFunction("bvor", 2, null,
FunctionSymbol.INTERNAL | FunctionSymbol.LEFTASSOC));
defineFunction(new RegularBitVecFunction("bvneg", 1, null));
defineFunction(new RegularBitVecFunction("bvadd", 2, null,
FunctionSymbol.INTERNAL | FunctionSymbol.LEFTASSOC));
defineFunction(new RegularBitVecFunction("bvmul", 2, null,
FunctionSymbol.INTERNAL | FunctionSymbol.LEFTASSOC));
defineFunction(new RegularBitVecFunction("bvudiv", 2, null));
defineFunction(new RegularBitVecFunction("bvurem", 2, null));
defineFunction(new RegularBitVecFunction("bvshl", 2, null));
defineFunction(new RegularBitVecFunction("bvlshr", 2, null));
defineFunction(new RegularBitVecFunction("bvnand", 2, null));
defineFunction(new RegularBitVecFunction("bvnor", 2, null));
defineFunction(new RegularBitVecFunction("bvxor", 2, null,
FunctionSymbol.INTERNAL | FunctionSymbol.LEFTASSOC));
defineFunction(new RegularBitVecFunction("bvxnor", 2, null));
defineFunction(new RegularBitVecFunction("bvcomp", 2, bitvec1));
defineFunction(new RegularBitVecFunction("bvsub", 2, null));
defineFunction(new RegularBitVecFunction("bvsdiv", 2, null));
defineFunction(new RegularBitVecFunction("bvsrem", 2, null));
defineFunction(new RegularBitVecFunction("bvsmod", 2, null));
defineFunction(new RegularBitVecFunction("bvashr", 2, null));
defineFunction(new FunctionSymbolFactory("repeat") {
@Override
public Sort getResultSort(BigInteger[] indices, Sort[] paramSorts,
Sort resultSort) {
if (indices == null || indices.length != 1
|| paramSorts.length != 1 || resultSort != null
|| paramSorts[0].getName() != "BitVec") {
return null;
}
final BigInteger size =
indices[0].multiply(paramSorts[0].getIndices()[0]);
return mBitVecSort.getSort(
new BigInteger[] { size }, new Sort[0]);
}
});
defineFunction(new ExtendBitVecFunction("zero_extend"));
defineFunction(new ExtendBitVecFunction("sign_extend"));
defineFunction(new RotateBitVecFunction("rotate_left"));
defineFunction(new RotateBitVecFunction("rotate_right"));
defineFunction(new RegularBitVecFunction("bvult", 2, mBooleanSort,
FunctionSymbol.INTERNAL | FunctionSymbol.CHAINABLE));
defineFunction(new RegularBitVecFunction("bvule", 2, mBooleanSort,
FunctionSymbol.INTERNAL | FunctionSymbol.CHAINABLE));
defineFunction(new RegularBitVecFunction("bvugt", 2, mBooleanSort,
FunctionSymbol.INTERNAL | FunctionSymbol.CHAINABLE));
defineFunction(new RegularBitVecFunction("bvuge", 2, mBooleanSort,
FunctionSymbol.INTERNAL | FunctionSymbol.CHAINABLE));
defineFunction(new RegularBitVecFunction("bvslt", 2, mBooleanSort,
FunctionSymbol.INTERNAL | FunctionSymbol.CHAINABLE));
defineFunction(new RegularBitVecFunction("bvsle", 2, mBooleanSort,
FunctionSymbol.INTERNAL | FunctionSymbol.CHAINABLE));
defineFunction(new RegularBitVecFunction("bvsgt", 2, mBooleanSort,
FunctionSymbol.INTERNAL | FunctionSymbol.CHAINABLE));
defineFunction(new RegularBitVecFunction("bvsge", 2, mBooleanSort,
FunctionSymbol.INTERNAL | FunctionSymbol.CHAINABLE));
}
private void createFloatingPointOperators() {
mFloatingPointSort = new SortSymbol(this, "FloatingPoint", 0, null,
SortSymbol.INTERNAL | SortSymbol.INDEXED) {
@Override
public void checkArity(BigInteger[] indices, int arity) {
if (indices == null || indices.length != 2) {
throw new IllegalArgumentException(
"Floating Point needs two indices");
}
if (indices[0].signum() <= 0 || indices[1].signum() <= 0) {
throw new IllegalArgumentException(
"FloatingPoint indices must be greater 0");
}
if (arity != 0) {
throw new IllegalArgumentException(
"FloatingPoint has no parameters");
}
}
};
mDeclaredSorts.put("FloatingPoint", mFloatingPointSort);
mRoundingModeSort = declareInternalSort("RoundingMode", 0, 0)
.getSort(null, new Sort[0]);
/*
* Used to create Functions of the Floating Point theory
*/
class RegularFloatingPointFunction extends FunctionSymbolFactory {
int mNumArgs;
Sort mResult;
int mFlags;
int mFirstFloat;
public RegularFloatingPointFunction(
String name, int numArgs, Sort result, int flags) {
super(name);
mNumArgs = numArgs;
mResult = result;
mFlags = flags;
}
@Override
public int getFlags(BigInteger[] indices, Sort[] paramSorts,
Sort resultSort) {
return mFlags;
}
@Override
public Sort getResultSort(BigInteger[] indices, Sort[] paramSorts,
Sort resultSort) {
if (indices != null
|| paramSorts.length != mNumArgs || resultSort != null){
return null;
}
if (paramSorts[0].getName() == ("RoundingMode")) {
mFirstFloat = 1;
} else {
mFirstFloat = 0;
}
for (int i = mFirstFloat; i < mNumArgs; i++) {
if (paramSorts[i].getName() != "FloatingPoint") {
return null;
}
}
return mResult == null ? paramSorts[mFirstFloat] : mResult;
}
}
defineFunction(new FunctionSymbolFactory("fp") {
@Override
public Sort getResultSort(BigInteger[] indices, Sort[] paramSorts,
Sort resultSort) {
if (indices != null
|| paramSorts.length != 3 || resultSort != null
|| paramSorts[0].getName() != "BitVec"
|| !paramSorts[0].getIndices()[0].equals(BigInteger.ONE)
|| paramSorts[1].getName() != "BitVec"
|| paramSorts[2].getName() != "BitVec") {
return null;
}
final BigInteger[] fpIndices = new BigInteger[2];
fpIndices[0] = paramSorts[1].getIndices()[0];
fpIndices[1] = paramSorts[2].getIndices()[0].add(BigInteger.ONE);
return mFloatingPointSort.getSort(fpIndices, new Sort[0] );
}
});
// from BitVec to FP
defineFunction(new FunctionSymbolFactory("to_fp") {
@Override
public Sort getResultSort(BigInteger[] indices, Sort[] paramSorts,
Sort resultSort) {
if (indices == null || indices.length != 2
|| paramSorts == null) {
return null;
}
//from BitVec to FP
if (paramSorts.length == 1 && paramSorts[0].getName() == "BitVec") {
if (!((indices[0].add(indices[1]).equals( paramSorts[0].getIndices()[0])))) {
return null;
}
return mFloatingPointSort.getSort(indices, new Sort[0]);
}
// from FP to FP
if (paramSorts.length == 2 && paramSorts[0].getName() == "RoundingMode"
&& (paramSorts[1].getName() == "FloatingPoint")) {
return mFloatingPointSort.getSort(indices, new Sort[0]);
}
// from real to FP
if (paramSorts.length == 2 && paramSorts[0].getName() == "RoundingMode"
&& paramSorts[1].getName() == "Real") {
return mFloatingPointSort.getSort(indices, new Sort[0]);
}
// from signed machine integer, represented as a 2's complement bit vector to FP
if (paramSorts.length == 2 && paramSorts[0].getName() == "RoundingMode"
&& paramSorts[1].getName() == "BitVec") {
return mFloatingPointSort.getSort(indices, new Sort[0]);
}
return null;
}
});
defineFunction(new FunctionSymbolFactory("to_fp_unsigned") {
@Override
public Sort getResultSort(BigInteger[] indices, Sort[] paramSorts,
Sort resultSort) {
if (indices == null || indices.length != 2
|| paramSorts.length != 2 || resultSort != null
|| paramSorts[0].getName() != "RoundingMode"
|| paramSorts[1].getName() != "BitVec") {
return null;
}
return mFloatingPointSort.getSort(indices, new Sort[0] );
}
});
defineFunction(new FunctionSymbolFactory("fp.to_ubv") {
@Override
public Sort getResultSort(BigInteger[] indices, Sort[] paramSorts,
Sort resultSort) {
if (indices == null || indices.length != 1
|| paramSorts.length != 2 || resultSort != null
|| paramSorts[0].getName() != "RoundingMode"
|| paramSorts[1].getName() != "FloatingPoint") {
return null;
}
return mBitVecSort.getSort(
new BigInteger[] { indices[0] }, new Sort[0]);
}
});
defineFunction(new FunctionSymbolFactory("fp.to_sbv") {
@Override
public Sort getResultSort(BigInteger[] indices, Sort[] paramSorts,
Sort resultSort) {
if (indices == null || indices.length != 1
|| paramSorts.length != 2 || resultSort != null
|| paramSorts[0].getName() != "RoundingMode"
|| paramSorts[1].getName() != "FloatingPoint") {
return null;
}
return mBitVecSort.getSort(
new BigInteger[] { indices[0] }, new Sort[0]);
}
});
/*
* Used to create Constants of the Floating Point theory
*/
class FloatingPointConstant extends FunctionSymbolFactory {
public FloatingPointConstant(String name) {
super(name);
}
@Override
public Sort getResultSort(BigInteger[] indices, Sort[] paramSorts,
Sort resultSort) {
if (indices.length != 2 ||
paramSorts.length != 0 || resultSort != null){
return null;
}
return mFloatingPointSort.getSort(indices, new Sort[0] );
}
}
// +/- infinity
defineFunction(new FloatingPointConstant("+oo"));
defineFunction(new FloatingPointConstant("-oo"));
// +/- zero
defineFunction(new FloatingPointConstant("+zero"));
defineFunction(new FloatingPointConstant("-zero"));
defineFunction(new FloatingPointConstant("NaN"));
//short forms of common floats
defineSort("Float16", 0, mFloatingPointSort.getSort(new BigInteger[]{new BigInteger("5"), new BigInteger("11")}));
defineSort("Float32", 0, mFloatingPointSort.getSort(new BigInteger[]{new BigInteger("8"), new BigInteger("24")}));
defineSort("Float64", 0, mFloatingPointSort.getSort(new BigInteger[]{new BigInteger("11"), new BigInteger("53")}));
defineSort("Float128", 0, mFloatingPointSort.getSort(new BigInteger[]{new BigInteger("15"), new BigInteger("113")}));
//RoundingModes
declareInternalFunction("roundNearestTiesToEven", new Sort[0], mRoundingModeSort, 0);
declareInternalFunction("roundNearestTiesToAway", new Sort[0], mRoundingModeSort, 0);
declareInternalFunction("roundTowardPositive", new Sort[0], mRoundingModeSort, 0);
declareInternalFunction("roundTowardNegative", new Sort[0], mRoundingModeSort, 0);
declareInternalFunction("roundTowardZero", new Sort[0], mRoundingModeSort, 0);
defineFunction("RNE", new Sort[0], mRoundingModeSort, new TermVariable[0],
term("roundNearestTiesToEven"), FunctionSymbol.INTERNAL);
defineFunction("RNA", new Sort[0], mRoundingModeSort, new TermVariable[0],
term("roundNearestTiesToAway"), FunctionSymbol.INTERNAL);
defineFunction("RTP", new Sort[0], mRoundingModeSort, new TermVariable[0],
term("roundTowardPositive"), FunctionSymbol.INTERNAL);
defineFunction("RTN", new Sort[0], mRoundingModeSort, new TermVariable[0],
term("roundTowardNegative"), FunctionSymbol.INTERNAL);
defineFunction("RTZ", new Sort[0], mRoundingModeSort, new TermVariable[0],
term("roundTowardZero"), FunctionSymbol.INTERNAL);
// Operators
defineFunction(new RegularFloatingPointFunction("fp.abs", 1, null, FunctionSymbol.INTERNAL));
defineFunction(new RegularFloatingPointFunction("fp.neg", 1, null, FunctionSymbol.INTERNAL));
defineFunction(new RegularFloatingPointFunction("fp.min", 2, null, FunctionSymbol.INTERNAL));
defineFunction(new RegularFloatingPointFunction("fp.max", 2, null, FunctionSymbol.INTERNAL));
defineFunction(new RegularFloatingPointFunction("fp.rem", 2, null, FunctionSymbol.INTERNAL));
// rounded operators
defineFunction(new RegularFloatingPointFunction("fp.add", 3, null, FunctionSymbol.INTERNAL));
defineFunction(new RegularFloatingPointFunction("fp.sub", 3, null, FunctionSymbol.INTERNAL));
defineFunction(new RegularFloatingPointFunction("fp.mul", 3, null, FunctionSymbol.INTERNAL));
defineFunction(new RegularFloatingPointFunction("fp.div", 3, null, FunctionSymbol.INTERNAL));
defineFunction(new RegularFloatingPointFunction("fp.fma", 4, null, FunctionSymbol.INTERNAL));
defineFunction(new RegularFloatingPointFunction("fp.sqrt", 2, null, FunctionSymbol.INTERNAL));
defineFunction(new RegularFloatingPointFunction("fp.roundToIntegral", 2, null, FunctionSymbol.INTERNAL));
// Comparison Operators
defineFunction(new RegularFloatingPointFunction("fp.leq", 2, mBooleanSort, FunctionSymbol.INTERNAL | FunctionSymbol.CHAINABLE));
defineFunction(new RegularFloatingPointFunction("fp.lt", 2, mBooleanSort, FunctionSymbol.INTERNAL | FunctionSymbol.CHAINABLE));
defineFunction(new RegularFloatingPointFunction("fp.geq", 2, mBooleanSort, FunctionSymbol.INTERNAL | FunctionSymbol.CHAINABLE));
defineFunction(new RegularFloatingPointFunction("fp.gt", 2, mBooleanSort, FunctionSymbol.INTERNAL | FunctionSymbol.CHAINABLE));
defineFunction(new RegularFloatingPointFunction("fp.eq", 2, mBooleanSort, FunctionSymbol.INTERNAL | FunctionSymbol.CHAINABLE));
// Classification of numbers
defineFunction(new RegularFloatingPointFunction("fp.isNormal", 1, mBooleanSort, FunctionSymbol.INTERNAL));
defineFunction(new RegularFloatingPointFunction("fp.isSubnormal", 1, mBooleanSort, FunctionSymbol.INTERNAL));
defineFunction(new RegularFloatingPointFunction("fp.isZero", 1, mBooleanSort, FunctionSymbol.INTERNAL));
defineFunction(new RegularFloatingPointFunction("fp.isInfinite", 1, mBooleanSort, FunctionSymbol.INTERNAL));
defineFunction(new RegularFloatingPointFunction("fp.isNaN", 1, mBooleanSort, FunctionSymbol.INTERNAL));
defineFunction(new RegularFloatingPointFunction("fp.isNegative", 1, mBooleanSort, FunctionSymbol.INTERNAL));
defineFunction(new RegularFloatingPointFunction("fp.isPositive", 1, mBooleanSort, FunctionSymbol.INTERNAL));
// Conversion from FP
defineFunction(new RegularFloatingPointFunction("fp.to_real", 1, mRealSort, FunctionSymbol.INTERNAL));
}
private void setLogic(Logics logic) {
mLogic = logic;
if (logic.isArray()) {
createArrayOperators();
}
if (logic.hasReals() || logic.isFloatingPoint()) {
mRealSort = declareInternalSort("Real", 0,
SortSymbol.NUMERIC).getSort(null, new Sort[0]);
}
if (logic.isArithmetic()) {
if (logic.hasIntegers()) {
mNumericSort = declareInternalSort("Int", 0,
SortSymbol.NUMERIC).getSort(null, new Sort[0]);
} else {
mNumericSort = mRealSort;
}
if (logic.isIRA()) {
createIRAOperators();
} else {
createNumericOperators(mNumericSort, logic.hasReals());
}
}
if (logic.isBitVector() || logic.isFloatingPoint()) {
createBitVecSort();
}
if (logic.isBitVector()) {
createBitVecOperators();
}
if (logic.isFloatingPoint()) {
createFloatingPointOperators();
}
if (mSolverSetup != null) {
mSolverSetup.setLogic(this, logic);
}
}
/******************** SORTS ********************************************/
private SortSymbol defineSort(String name, int paramCount, Sort definition,
int flags) {
if ((flags & FunctionSymbol.INTERNAL) == 0
&& definition == null
&& !mLogic.isUF() && !mLogic.isArray()) {
throw new IllegalArgumentException("Free sorts are not allowed in this logic");
}
SortSymbol sortsym = mDeclaredSorts.get(name);
if (sortsym != null) {
throw new IllegalArgumentException(
"Sort " + name + " already exists.");
}
sortsym = new SortSymbol(this, name, paramCount, definition, flags);
mDeclaredSorts.put(name, sortsym);
return sortsym;
}
public SortSymbol declareSort(String name, int paramCount) {
return defineSort(name, paramCount, null, 0);
}
public SortSymbol defineSort(String name, int paramCount, Sort definition) {
return defineSort(name, paramCount, definition, 0);
}
public Sort[] createSortVariables(String... names) {
final Sort[] sorts = new Sort[names.length];
for (int i = 0; i < names.length; i++) {
sorts[i] = new SortSymbol(
this, names[i], i, null, SortSymbol.TYPEPARAM).
getSort(null, new Sort[0]);
}
return sorts;
}
SortSymbol declareInternalSort(String name, int paramCount, int flags) {
return defineSort(name, paramCount, null, flags | SortSymbol.INTERNAL);
}
/**
* Returns the sort object for a previously declared or defined sort
* with sort arguments.
* @param id The name of the sort.
* @param args The sort arguments.
* @return the sort object.
*/
public Sort getSort(String id, Sort... args) {
return getSort(id, null, args);
}
/**
* Returns the sort object for a previously declared or defined sort
* with sort arguments.
* @param id The name of the sort.
* @param args The sort arguments.
* @return the sort object.
*/
public Sort getSort(String id, BigInteger[] indices, Sort... args) {
SortSymbol symbol;
symbol = mDeclaredSorts.get(id);
if (symbol == null) {
return null;
}
return symbol.getSort(indices, args);
}
/**
* Returns the Boolean sort. This is more efficient but has the same
* effect as calling getSort("Bool").
* @return the Boolean sort.
*/
public Sort getBooleanSort() {
return mBooleanSort;
}
/**
* Get the sort used to construct integers. Note that this returns
* <code>null</code> if the logic does not support integers.
* @return Sort used for integers.
*/
public Sort getNumericSort() {
return mNumericSort;
}
/**
* Get the sort used to construct reals. Note that this returns
* <code>null</code> if the logic does not support reals.
* @return Sort used for reals.
*/
public Sort getRealSort() {
return mRealSort;
}
/**
* Get the sort used to construct strings. Note that this returns
* <code>null</code> if the logic does not support strings.
* @return Sort used for strings.
*/
public Sort getStringSort() {
return mStringSort;
}
/******************** FUNCTIONS SYMBOLS AND FUNCTION TERMS ************/
private void defineFunction(FunctionSymbolFactory factory) {
if (mFunFactory.put(factory.mFuncName, factory) != null) {
throw new AssertionError();
}
}
private FunctionSymbol defineFunction(String name, Sort[] paramTypes,
Sort resultType, TermVariable[] definitionVars, Term definition,
int flags) {
if ((flags & FunctionSymbol.INTERNAL) == 0) {
if (mLogic == null) {
throw new IllegalArgumentException("Call set-logic first!");
}
if (!mLogic.isUF() && paramTypes.length > 0 && definition == null) {
throw new IllegalArgumentException(
"Free functions are not allowed in this logic!");
}
}
if (name.charAt(0) == '@' && name.matches(MODEL_VALUE_PATTERN)) {
throw new IllegalArgumentException(
"Function " + name + " is reserved for internal purposes.");
}
if (mFunFactory.get(name) != null || mDeclaredFuns.get(name) != null) {
throw new IllegalArgumentException(
"Function " + name + " is already defined.");
}
if (paramTypes.length == 0) {
paramTypes = EMPTY_SORT_ARRAY;
}
if (definitionVars != null && definitionVars.length == 0) {
definitionVars = EMPTY_TERM_VARIABLE_ARRAY;
}
final FunctionSymbol f = new FunctionSymbol(name, null, paramTypes,
resultType, definitionVars, definition, flags);
mDeclaredFuns.put(name, f);
return f;
}
/**
* Declare a new function symbol. This corresponds to declare-fun in SMTLIB.
* @param name name of the function.
* @param paramTypes the sorts of the parameters of the function.
* @param resultType the sort of the result type of the function.
* @throws IllegalArgumentException
* if a function with that name is already defined or
* if the sorts are not visible in this scope.
* @return the created function symbol.
*/
public FunctionSymbol declareFunction(
String name, Sort[] paramTypes, Sort resultType) {
return defineFunction(name, paramTypes, resultType, null, null, 0);
}
/**
* Defines a new function symbol. This corresponds to define-fun in SMTLIB.
* @param name name of the function.
* @param definitionVars the variables of the function.
* @param definition the definition of the function.
* @throws IllegalArgumentException
* if a function with that name is already defined or
* if the sorts are not visible in this scope.
* @return the created function symbol.
*/
public FunctionSymbol defineFunction(String name,
TermVariable[] definitionVars, Term definition) {
final Sort[] paramTypes =
definitionVars.length == 0 ? EMPTY_SORT_ARRAY : new Sort[definitionVars.length];
for (int i = 0; i < paramTypes.length; i++) {
paramTypes[i] = definitionVars[i].getSort();
}
final Sort resultType = definition.getSort();
return defineFunction(name, paramTypes, resultType,
definitionVars, definition, 0);
}
public FunctionSymbol getFunction(String name, Sort... paramTypes) {
return getFunctionWithResult(name, null, null, paramTypes);
}
public Map<String, FunctionSymbol> getDeclaredFunctions() {
return mDeclaredFuns;
}
private FunctionSymbol getModelValueSymbol(String name, Sort sort) {
final int hash = HashUtils.hashJenkins(name.hashCode(), sort);
for (final FunctionSymbol symb : mModelValueCache.iterateHashCode(hash)) {
if (symb.getName().equals(name) && symb.getReturnSort() == sort) {
return symb;
}
}
final FunctionSymbol symb = new FunctionSymbol(
name, null, EMPTY_SORT_ARRAY, sort, null, null,
FunctionSymbol.RETURNOVERLOAD | FunctionSymbol.INTERNAL
| FunctionSymbol.MODELVALUE);
mModelValueCache.put(hash,symb);
return symb;
}
public FunctionSymbol getFunctionWithResult(
String name, BigInteger[] indices, Sort resultType,
Sort... paramTypes) {
if (resultType != null && indices == null && paramTypes.length == 0
&& name.matches(MODEL_VALUE_PATTERN)) {
return getModelValueSymbol(name, resultType);
}
final FunctionSymbolFactory factory = mFunFactory.get(name);
if (factory != null) {
FunctionSymbol fsym = factory.getFunctionWithResult(
this, indices, paramTypes, resultType);
if (fsym != null) {
return fsym;
}
if (mLogic.isIRA()) {
fsym = factory.getFunctionWithResult(this, indices,
new Sort[] {mRealSort, mRealSort}, resultType);
if (fsym != null && fsym.typecheck(paramTypes)) {
return fsym;
}
}
return null;
}
final FunctionSymbol fsym = mDeclaredFuns.get(name);
if (fsym != null && indices == null && resultType == null
&& fsym.typecheck(paramTypes)) {
return fsym;
}
if (mBitVecSort != null && name.matches(BITVEC_CONST_PATTERN)
&& indices != null && indices.length == 1
&& resultType == null) {
/* Create bitvector constants */
return getBitVecConstant(name, indices);
}
return null;
}
private FunctionSymbol getBitVecConstant(String name, BigInteger[] indices) {
if (mBitVecConstCache == null) {
mBitVecConstCache = new UnifyHash<FunctionSymbol>();
}
final int hash = HashUtils.hashJenkins(name.hashCode(), (Object[]) indices);
for (final FunctionSymbol symb : mBitVecConstCache.iterateHashCode(hash)) {
if (symb.getName().equals(name) && symb.getIndices()[0].equals(indices[0])) {
return symb;
}
}
final Sort sort = mBitVecSort.getSort(indices);
final FunctionSymbol symb = new FunctionSymbol(
name, indices, EMPTY_SORT_ARRAY, sort, null, null,
FunctionSymbol.INTERNAL);
mBitVecConstCache.put(hash,symb);
return symb;
}
public ApplicationTerm term(
FunctionSymbolFactory factory, Term... parameters) {
final Sort[] sorts =
parameters.length == 0 ? EMPTY_SORT_ARRAY : new Sort[parameters.length];
for (int i = 0; i < parameters.length; i++) {
sorts[i] = parameters[i].getSort();
}
final FunctionSymbol fsym =
factory.getFunctionWithResult(this, null, sorts, null);
if (fsym == null) {
throw new IllegalArgumentException(
"Did not find overload for function " + factory);
}
return term(fsym, parameters);
}
public ApplicationTerm term(String func, Term... parameters) {
final Sort[] paramSorts =
parameters.length == 0 ? EMPTY_SORT_ARRAY : new Sort[parameters.length];
for (int i = 0; i < parameters.length; i++) {
paramSorts[i] = parameters[i].getSort();
}
final FunctionSymbol fsym =
getFunctionWithResult(func, null, null, paramSorts);
if (fsym == null) {
return null;
}
return term(fsym, parameters);
}
public ApplicationTerm term(FunctionSymbol func, Term... parameters) {
if (parameters.length == 0) {
parameters = EMPTY_TERM_ARRAY;
}
final int hash = ApplicationTerm.hashApplication(func, parameters);
for (final Term t : mTermCache.iterateHashCode(hash)) {
if (t instanceof ApplicationTerm) {
final ApplicationTerm app = (ApplicationTerm) t;
if (func == app.getFunction()
&& Arrays.equals(app.getParameters(),parameters)) {
return app;
}
}
}
final ApplicationTerm app = new ApplicationTerm(func, parameters, hash);
mTermCache.put(hash,app);
return app;
}
/******************** TERM VARIABLES AND VARIABLE TERMS *****************/
/**
* Create a fresh term variable that does not clash with any
* existing one.
* @param prefix the prefix of the variable name (without the leading ?).
* @param sort the sort of the variable.
* @return a fresh term variable.
*/
public TermVariable createFreshTermVariable(String prefix, Sort sort) {
final String name = "." + prefix + "." + mTvarCtr++;
return new TermVariable(name, sort,
TermVariable.hashVariable(name, sort));
}
/**
* Create a term variable with the given name and sort.
* @param name the variable name.
* @param sort the sort of the variable.
* @return a term variable.
*/
public TermVariable createTermVariable(String name,Sort sort) {
final int hash = TermVariable.hashVariable(name, sort);
for (final TermVariable tv : mTvUnify.iterateHashCode(hash)) {
if (tv.getSort().equals(sort) && tv.getName().equals(name)) {
return tv;
}
}
final TermVariable tv = new TermVariable(name,sort, hash);
mTvUnify.put(hash,tv);
return tv;
}
public Term term(TermVariable var) {
return var;
}
/******************** ANNOTATED TERMS *********************************/
public Term annotatedTerm(Annotation[] annots, Term sub) {
final int hash = AnnotatedTerm.hashAnnotations(annots, sub);
for (final Term t : mTermCache.iterateHashCode(hash)) {
if (t instanceof AnnotatedTerm) {
final AnnotatedTerm annot = (AnnotatedTerm) t;
if (sub == annot.getSubterm()
&& Arrays.equals(annot.getAnnotations(), annots)) {
return annot;
}
}
}
final AnnotatedTerm annot = new AnnotatedTerm(annots, sub, hash);
mTermCache.put(hash, annot);
return annot;
}
/******************** ASSERTION STACK *********************************/
public void push() {
if (!mGlobalDecls) {
mDeclaredFuns.beginScope();
mDeclaredSorts.beginScope();
}
}
public void pop() {
if (!mGlobalDecls) {
mDeclaredFuns.endScope();
mDeclaredSorts.endScope();
}
}
/******************** SKOLEMIZATION SUPPORT ***************************/
public FunctionSymbol skolemize(TermVariable tv) {
return new FunctionSymbol(
"@" + tv.getName() + "_skolem_" + mSkolemCounter++,null,
EMPTY_SORT_ARRAY,tv.getSort(),null,null,0);
}
public void resetAssertions() {
if (mGlobalDecls) {
return;
}
while (mDeclaredFuns.getActiveScopeNum() > 1) {
mDeclaredFuns.endScope();
}
for (final Iterator<Map.Entry<String, FunctionSymbol>> it = mDeclaredFuns.entrySet().iterator();
it.hasNext(); ) {
final Map.Entry<String, FunctionSymbol> next = it.next();
if (!next.getValue().isIntern()) {
it.remove();
}
}
while (mDeclaredSorts.getActiveScopeNum() > 1) {
mDeclaredSorts.endScope();
}
for (final Iterator<Map.Entry<String, SortSymbol>> it = mDeclaredSorts.entrySet().iterator();
it.hasNext(); ) {
final Map.Entry<String, SortSymbol> next = it.next();
if (!next.getValue().isIntern()) {
it.remove();
}
}
}
public void setGlobalSymbols(boolean globalDecls) {
mGlobalDecls = globalDecls;
}
}