/** * Author: Georg Hofferek <georg.hofferek@iaik.tugraz.at> */ package at.iaik.suraq.smtlib.formula; import java.io.BufferedWriter; import java.io.IOException; import java.io.Serializable; import java.io.Writer; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; import at.iaik.suraq.exceptions.SuraqException; import at.iaik.suraq.sexp.SExpression; import at.iaik.suraq.sexp.Token; import at.iaik.suraq.smtlib.SMTLibObject; import at.iaik.suraq.util.HashTagContainer; import at.iaik.suraq.util.IdGenerator; /** * This abstract class represents terms. Terms can be domain terms, array terms, * or "propositional terms". Strictly following the grammar, the latter would be * formulas, but treating them like terms eases handling of (in)equalities and * if-then-else constructs. * * @author Georg Hofferek <georg.hofferek@iaik.tugraz.at> * */ public abstract class Term implements Serializable, SMTLibObject { /** * */ private static final long serialVersionUID = -5654824580231056142L; public static final Class<?> domainTermClass = (DomainVariable.create("")) .getClass().getSuperclass(); public static final Class<?> arrayTermClass = (ArrayVariable.create("")) .getClass().getSuperclass(); public static final Class<?> propositionalTermClass = (PropositionalVariable .create("")).getClass().getSuperclass(); public final static int GLOBAL_PARTITION = -1; private final long id = IdGenerator.getId(); /** * The assert-partitions */ protected int assertPartition = Term.GLOBAL_PARTITION; /** * Checks whether all terms in the given list are compatible for * (dis)equality operations. If so, the type is returned. * * @param terms * the list of terms to check. * @return the type of the terms in <code>termList</code> or * <code>null</code> if there are multiple incompatible types. */ public static Class<?> checkTypeCompatibility( Collection<? extends Term> terms) { if (terms.size() < 1) return null; Class<?> type = null; Term firstTerm = terms.iterator().next(); if (Term.domainTermClass.isInstance(firstTerm)) type = Term.domainTermClass; if (Term.arrayTermClass.isInstance(firstTerm)) type = Term.arrayTermClass; if (Term.propositionalTermClass.isInstance(firstTerm)) type = Term.propositionalTermClass; boolean allOk = true; for (Term term : terms) { if (!type.isInstance(term)) allOk = false; } if (allOk) return type; else return null; } /** * Returns the type of this term. * * @return the type of this term. */ public abstract SExpression getType(); /** * Returns a deep copy of this term. * * @return a deep copy of this term. */ public abstract Term deepTermCopy(); /** * Returns a new term that is a version of this term, with the substitutions * given by the given map applied. E.g., the local term of a function * macro's body is converted to the (more) global term of the macro's * instance. Terms which are not found in the map are returned unchanged. * * @param paramMap * the map to convert local terms to the caller's scope * @return a (new) term, converted according to the given map. */ public abstract Term substituteTerm(Map<Token, ? extends Term> paramMap, Map<SMTLibObject, SMTLibObject> done); @Override public abstract Term substituteUninterpretedFunction( Map<Token, UninterpretedFunction> substitutions, Map<SMTLibObject, SMTLibObject> done); /** * Computes the index set of this term. I.e., if it is an array read, its * index term is returned (as a singleton). For other term types, an empty * set is returned. * * @return the index set. * @throws SuraqException * if the term is an array write expressions, or computation * otherwise fails. */ public abstract Set<DomainTerm> getIndexSet() throws SuraqException; /** * Converts this term into an s-expression compatible with SMTLIBv2. Only * the term itself is converted. No variable/function/macro declarations are * included. * * @return this term as an SMTLIBv2 s-expression. */ @Override public abstract SExpression toSmtlibV2(); /** * Reduces all array properties in this formula to finite conjunctions over * the given index set. The index set must already include the special * variable lambda. * * @param indexSet * the index set. */ public abstract Term arrayPropertiesToFiniteConjunctionsTerm( Set<DomainTerm> indexSet); /** * Replaces all array equalities in this formula by equivalent array * properties. */ public abstract Term removeArrayEqualitiesTerm(); /** * Recursively replaces all array writes by applying the write axiom. * * @param topLevelFormula * The top-level formula on which the recursion started. (Needed * to determine fresh variable names.) * @param constraints * A set to which constraints coming from write-axiom application * will be added. * @param noDependenceVars A set of variables on * which the controller may not depend. Newly created variables * on which the controller may not depend are added to this set * during recursion. */ public abstract Term removeArrayWritesTerm(Formula topLevelFormula, Set<Formula> constraints, Set<Token> noDependenceVars); /** * Replaces all array-read expressions with uninterpreted function instances * of the same name. * * @param noDependenceVars * the variables on which the controller may not depend. New such * variables are added to this set during recursion. * */ public abstract Term arrayReadsToUninterpretedFunctionsTerm( Set<Token> noDependenceVars); /** * @see at.iaik.suraq.smtlib.formula.Formula#substituteUninterpretedFunction(Token, * at.iaik.suraq.smtlib.formula.UninterpretedFunction) */ /** * * @see java.lang.Object#toString() */ @Override public String toString() { return this.toSmtlibV2().toString(); } /** * @see at.iaik.suraq.smtlib.formula.Formula#flatten() */ public abstract Term flatten(); /** * @param topLevelFormula * TODO * @param noDependenceVars * TODO * @see at.iaik.suraq.smtlib.formula.Formula#makeArrayReadsSimple(Formula, * at.iaik.suraq.smtlib.formula.Formula, Set) */ public abstract Term makeArrayReadsSimpleTerm(Formula topLevelFormula, Set<Formula> constraints, Set<Token> noDependenceVars); /** * Returns the elements assert-partition. * * @return assert-partition of the element. */ @Override public abstract Set<Integer> getPartitionsFromSymbols(); /** * Replaces instances of uninterpreted predicates in formula with auxiliary * boolean variables. * * @param topLeveFormula * the top level formula (for finding fresh variable names). * * @param predicateInstances * map containing mapping from predicate names to boolean * auxiliary variables. * * @param instanceParameters * map containing mapping from boolean auxiliary variables to * predicate instance parameters. * * @return a new formula with uninterpreted predicates replaced by boolean * auxiliary variables. */ public abstract Term uninterpretedPredicatesToAuxiliaryVariablesTerm( Formula topLeveFormula, Map<String, List<PropositionalVariable>> predicateInstances, Map<PropositionalVariable, List<DomainTerm>> instanceParameters, Set<Token> noDependenceVars); /** * Replaces instances of uninterpreted functions in formula with auxiliary * variables. * * * @param topLeveFormula * the top level formula (for finding fresh variable names). * * @param functionInstances * map containing mapping from function names to auxiliary * variables. * * @param instanceParameters * map containing mapping from auxiliary variables to function * instance parameters. * * @return a new formula with uninterpreted predicates replaced by auxiliary * variables. */ public abstract Term uninterpretedFunctionsToAuxiliaryVariablesTerm( Formula topLeveFormula, Map<String, List<DomainVariable>> functionInstances, Map<DomainVariable, List<DomainTerm>> instanceParameters, Set<Token> noDependenceVars); /** * A new <code>Term</code> where DomainITEs have been replaced with new * variables. * * @param topLevelFormula * @param noDependenceVars * @param andPreList * @return */ public abstract Term removeDomainITE(Formula topLevelFormula, Set<Token> noDependenceVars, List<Formula> andPreList); /** * @param topLevelFormula * @param noDependenceVars * @param constraints * @return */ public abstract Term removeArrayITE(Formula topLevelFormula, Set<Token> noDependenceVars, Collection<Formula> constraints); /** * @param writer * @param tagContainer * @param handleThisWithTagContainer */ public abstract void writeOut(BufferedWriter writer, HashTagContainer tagContainer) throws IOException; /** * Writes the term to the given writer. Essentially, this should write the * same thing as would be produced by <code>toString</code>. * * @param writer * @throws IOException */ public abstract void writeTo(Writer writer) throws IOException; /** * @see java.lang.Comparable#compareTo(java.lang.Object) */ @Override public final int compareTo(SMTLibObject o) { long otherId = o.getId(); if (this.id < otherId) return -1; if (this.id == otherId) return 0; if (this.id > otherId) return 1; throw new RuntimeException("Something is TERRIBLY wrong!!"); } /** * * @see at.iaik.suraq.smtlib.SMTLibObject#getId() */ @Override public final long getId() { return id; } }