/* * Copyright (C) 2009-2012 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.BigInteger; /** * Represents a function symbol. Each function symbol has a name, a sort and * zero or more parameter sorts. A constant symbol is represented as a function * symbols with zero parameters. * * For parametric functions we create a different FunctionSymbol for every * instantiation. * * @author hoenicke */ public class FunctionSymbol { public static final int INTERNAL = 1; public static final int LEFTASSOC = (1) << 1; public static final int RIGHTASSOC = (2) << 1; public static final int CHAINABLE = (3) << 1;// NOCHECKSTYLE public static final int PAIRWISE = (4) << 1;// NOCHECKSTYLE public static final int ASSOCMASK = (7) << 1;// NOCHECKSTYLE public static final int RETURNOVERLOAD = 16; public static final int MODELVALUE = 32; final String mName; final BigInteger[] mIndices; final Sort[] mParamSort; final Sort mReturnSort; final int mFlags; final TermVariable[] mDefinitionVars; final Term mDefinition; FunctionSymbol(String n, BigInteger[] i, Sort[] params, Sort result, TermVariable[] definitionVars, Term definition, int flags) { mName = n; mIndices = i; mParamSort = params; mReturnSort = result; mFlags = flags; mDefinition = definition; mDefinitionVars = definitionVars; if (isLeftAssoc() && (params.length != 2 || !params[0].equalsSort(result))) { throw new IllegalArgumentException( "Wrong sorts for left-associative symbol"); } if (isRightAssoc() && (params.length != 2 || !params[1].equalsSort(result))) { throw new IllegalArgumentException( "Wrong sorts for right-associative symbol"); } if ((isChainable() || isPairwise()) && (params.length != 2 || !params[0].equalsSort(params[1]) || !result.equalsSort(getTheory().getBooleanSort()))) { throw new IllegalArgumentException( "Wrong sorts for chainable symbol"); } } @Override public int hashCode() { return mName.hashCode(); } /** * Get the name of the function. This is the name as used in an SMTLIB * script. It can also contain symbols not allowed by the SMTLIB standard. * In that case the string representation uses <code>|</code> to quote * the name. The name may not contain <code>|</code> symbols. * @return the name of the function. */ public String getName() { return mName; } public BigInteger[] getIndices() { return mIndices; } /** * Check whether this function symbol is created by the solver. Symbols * created by the solver are assumed to be special symbols like * <code>+</code>, <code>-</code>, or internal symbols only used by the * solver. * @return true if and only if the function symbol was flagged as internal. */ public boolean isIntern() { return (mFlags & INTERNAL) != 0; } public boolean isModelValue() { return (mFlags & MODELVALUE) != 0; } public Theory getTheory() { return mReturnSort.mSymbol.mTheory; } /** * @deprecated use getParameterSorts().length * @return the number of parameters this function takes. */ @Deprecated public int getParameterCount() { return mParamSort.length; } /** * @deprecated use getParameterSorts()[i]. * @param i the parameter number. * @return the sort of the ith parameter. */ @Deprecated public Sort getParameterSort(int i) { return mParamSort[i]; } /** * Retrieve the variables used in the definition of this function symbol. * A definition only exists if the function symbol is a macro created by the * {@link Script#defineFun(String, TermVariable[], Sort, Term) define-fun} * command or a <code>:named</code> annotation. * @return The variables used in the definition of this function symbol or * <code>null</code> if this function symbol is not a macro. */ public TermVariable[] getDefinitionVars() { return mDefinitionVars; } /** * Retrieve the definition of this function symbol. A definition only * exists if the function symbol is a macro created by the * {@link Script#defineFun(String, TermVariable[], Sort, Term) define-fun} * command or a <code>:named</code> annotation. * @return The definition of this function symbol or <code>null</code> if * this function symbol is not a macro. */ public Term getDefinition() { return mDefinition; } /** * Get the return sort of this function. * @return the return sort. */ public Sort getReturnSort() { return mReturnSort; } /** * Get the sort of the parameters for this function. * @return An array with the parameter sorts. Never write to this array! */ public Sort[] getParameterSorts() { return mParamSort; } private final void checkSort(Term arg, Sort sort, boolean mixRealInt) { final Sort argSort = arg.getSort(); if (!sort.equalsSort(argSort)) { if (argSort.toString().equals(sort.toString())) { throw new SMTLIBException( "Argument " + arg + " comes from wrong theory."); } else if (!mixRealInt || !argSort.getName().equals("Int")) { throw new SMTLIBException( "Argument " + arg + " has type " + argSort + " but function " + mName + " expects " + sort); } } } /** * Check if this function symbol can be called on the given argument terms. * This throws an exception if the type check fails. * @param params the arguments for the function symbols. */ public void typecheck(Term[] params) throws SMTLIBException { boolean mixRealInt = false; if (getTheory().getLogic() != null && getTheory().getLogic().isIRA() && mParamSort.length == 2 && mParamSort[0] == mParamSort[1] && mParamSort[0] == getTheory().getSort("Real")) { mixRealInt = true; } if ((mFlags & (ASSOCMASK)) != 0) { // NOPMD // All arguments should have the same type. if (params.length < 2) { throw new SMTLIBException( "Function " + mName + " expects at least two arguments."); } checkSort(params[0], mParamSort[0], mixRealInt); checkSort(params[params.length - 1], mParamSort[1], mixRealInt); final Sort otherSort = isLeftAssoc() ? mParamSort[1] : mParamSort[0]; for (int i = 1; i < params.length - 1; i++) { checkSort(params[i], otherSort, mixRealInt); } } else { if (params.length != mParamSort.length) { throw new SMTLIBException( "Function " + mName + " expects " + mParamSort.length + " arguments."); } for (int i = 0; i < mParamSort.length; i++) { checkSort(params[i], mParamSort[i], mixRealInt); } } } /** * Check if this function symbol can be called on terms with the given sort. * @param params the sort of the arguments for the function symbols. * @return true if the type check succeeds, false otherwise. */ public boolean typecheck(Sort[] params) { boolean mixRealInt = false; if (getTheory().getLogic().isIRA() && mParamSort.length == 2 && mParamSort[0] == mParamSort[1] && mParamSort[0].getName().equals("Real")) { mixRealInt = true; } if ((mFlags & (ASSOCMASK)) != 0) { // NOPMD assert (mParamSort.length == 2); if (params.length < 2) { return false; } if (!params[0].equalsSort(mParamSort[0]) && (!mixRealInt || params[0] != getTheory().getSort("Int"))) { return false; } if (!params[params.length - 1].equalsSort(mParamSort[1]) && (!mixRealInt || params[params.length - 1] != getTheory().getSort("Int"))) { return false; } final Sort otherSort = isLeftAssoc() ? mParamSort[1] : mParamSort[0]; for (int i = 1; i < params.length - 1; i++) { if (!params[i].equalsSort(otherSort) && (!mixRealInt || params[i] != getTheory().getSort("Int"))) { return false; } } } else { if (params.length != mParamSort.length) { return false; } for (int i = 0; i < mParamSort.length; i++) { if (!params[i].equalsSort(mParamSort[i]) && (!mixRealInt || params[i] != getTheory().getSort("Int"))) { return false; } } } return true; } /** * Returns a string representation of this object. This is a SMTLIB * like representation of the following form: * <pre>(name paramsort1 ... paramsortn returnsort)</pre> * where name is the (possibly indexed and quoted) function name. */ @Override public String toString() { final StringBuffer sb = new StringBuffer(); final String name = PrintTerm.quoteIdentifier(mName); sb.append('('); if (mIndices == null) { sb.append(name); } else { sb.append("(_ ").append(name); for (final BigInteger i : mIndices) { sb.append(' ').append(i); } sb.append(')'); } for (final Sort s : mParamSort) { sb.append(' ').append(s); } sb.append(' ').append(mReturnSort); sb.append(')'); return sb.toString(); } /** * Checks if this function symbol was declared as chainable. * This should only be true for the internal equality function. * @return true if the function symbol is chainable. */ public final boolean isChainable() { return (mFlags & ASSOCMASK) == CHAINABLE; } /** * Checks if this function symbol was declared as pairwise. * This should only be true for the internal distinct function. * @return true if the function symbol is pairwise. */ public final boolean isPairwise() { return (mFlags & ASSOCMASK) == PAIRWISE; } /** * Checks if this function symbol was declared as left associative. * This should only be true for internal function symbols. * @return true if the function symbol is left associative. */ public final boolean isLeftAssoc() { return (mFlags & ASSOCMASK) == LEFTASSOC; } /** * Checks if this function symbol was declared as right associative. * This should only be true for internal function symbols. * @return true if the function symbol is right associative. */ public final boolean isRightAssoc() { return (mFlags & ASSOCMASK) == RIGHTASSOC; } /** * Checks if this function symbol was created with the SMTLIB * syntax <code>(as name sort)</code> to give it a different result * sort. * @return true if the sort was explicitly given, false if it is implicit. */ public final boolean isReturnOverload() { return (mFlags & RETURNOVERLOAD) != 0; } /** * Get the string representation of this function symbol as it would * be used to build an application term. * @return the string representation. */ public String getApplicationString() { final String name = PrintTerm.quoteIdentifier(mName); if (mIndices == null && !isReturnOverload()) { return name; } final StringBuffer sb = new StringBuffer(); if (isReturnOverload()) { sb.append("(as "); } if (mIndices != null) { sb.append("(_ "); } sb.append(name); if (mIndices != null) { for (final BigInteger i : mIndices) { sb.append(' ').append(i); } sb.append(')'); } if (isReturnOverload()) { sb.append(' ').append(getReturnSort()).append(')'); } return sb.toString(); } /** * Check whether this function symbol is an internal symbol that has a fixed * semantic. * @return true if and only if the symbol is an internal symbol with a fixed * semantic. */ public boolean isInterpreted() { return isModelValue() || (isIntern() && (mName.charAt(0) != '@' || !mName.endsWith("0"))); } }