/** * Author: Georg Hofferek <georg.hofferek@iaik.tugraz.at> */ package at.iaik.suraq.smtlib.formula; import java.io.IOException; import java.io.Writer; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; 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.SExpressionConstants; import at.iaik.suraq.sexp.Token; import at.iaik.suraq.smtlib.SMTLibObject; import at.iaik.suraq.util.FormulaCache; import at.iaik.suraq.util.Util; /** * An if-then-else-style array term. * * @author Georg Hofferek <georg.hofferek@iaik.tugraz.at> * */ public class ArrayIte extends ArrayTerm { /** * */ private static final long serialVersionUID = 4245403417842028322L; /** * The condition. */ private final Formula condition; /** * The then-branch. */ private final ArrayTerm thenBranch; /** * The else-branch */ private final ArrayTerm elseBranch; /** * * Constructs a new <code>ArrayIte</code>. * * @param condition * the condition * @param thenBranch * the value of the then-branch * @param elseBranch * the value of the else-branch */ private ArrayIte(Formula condition, ArrayTerm thenBranch, ArrayTerm elseBranch) { if (condition instanceof FormulaTerm) this.condition = ((FormulaTerm) condition).getFormula(); else this.condition = condition; this.thenBranch = thenBranch; this.elseBranch = elseBranch; } public static ArrayIte create(Formula condition, ArrayTerm thenBranch, ArrayTerm elseBranch) { return (ArrayIte) FormulaCache.term.put(new ArrayIte(condition, thenBranch, elseBranch)); } /** * Returns the condition. * * @return the <code>condition</code> */ public Formula getCondition() { return condition; } /** * Returns the then branch. * * @return the <code>thenBranch</code> */ public ArrayTerm getThenBranch() { return thenBranch; } /** * Returns the else branch. * * @return the <code>elseBranch</code> */ public ArrayTerm getElseBranch() { return elseBranch; } /** * @see at.iaik.suraq.smtlib.formula.Term#deepTermCopy() */ @Override public Term deepTermCopy() { return this; // experimental // return new ArrayIte(condition.deepFormulaCopy(), // (ArrayTerm) thenBranch.deepTermCopy(), // (ArrayTerm) elseBranch.deepTermCopy()); } /** * @see at.iaik.suraq.smtlib.formula.Term#getArrayVariables() */ @Override public void getArrayVariables(Set<ArrayVariable> result, Set<SMTLibObject> done) { if (done.contains(this)) return; thenBranch.getArrayVariables(result, done); elseBranch.getArrayVariables(result, done); condition.getArrayVariables(result, done); done.add(this); } /** * @see at.iaik.suraq.smtlib.formula.Term#getDomainVariables() */ @Override public void getDomainVariables(Set<DomainVariable> result, Set<SMTLibObject> done) { if (done.contains(this)) return; thenBranch.getDomainVariables(result, done); elseBranch.getDomainVariables(result, done); condition.getDomainVariables(result, done); done.add(this); } /** * @see at.iaik.suraq.smtlib.formula.Term#getPropositionalVariables() */ @Override public void getPropositionalVariables(Set<PropositionalVariable> result, Set<SMTLibObject> done) { if (done.contains(this)) return; thenBranch.getPropositionalVariables(result, done); elseBranch.getPropositionalVariables(result, done); condition.getPropositionalVariables(result, done); done.add(this); } /** * @see at.iaik.suraq.smtlib.formula.Term#getFunctionMacroNames() */ @Override public void getFunctionMacroNames(Set<String> result, Set<SMTLibObject> done) { if (done.contains(this)) return; thenBranch.getFunctionMacroNames(result, done); elseBranch.getFunctionMacroNames(result, done); condition.getFunctionMacroNames(result, done); done.add(this); } /** * @see at.iaik.suraq.smtlib.formula.Term#getFunctionMacros() */ @Override public void getFunctionMacros(Set<FunctionMacro> result, Set<SMTLibObject> done) { if (done.contains(this)) return; thenBranch.getFunctionMacros(result, done); elseBranch.getFunctionMacros(result, done); condition.getFunctionMacros(result, done); done.add(this); } /** * @see at.iaik.suraq.smtlib.formula.Term#getUninterpretedFunctionNames() */ @Override public void getUninterpretedFunctionNames(Set<String> result, Set<SMTLibObject> done) { if (done.contains(this)) return; thenBranch.getUninterpretedFunctionNames(result, done); elseBranch.getUninterpretedFunctionNames(result, done); condition.getUninterpretedFunctionNames(result, done); done.add(this); } /** * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (!(obj instanceof ArrayIte)) return false; if (this.hashCode() != obj.hashCode()) return false; return ((ArrayIte) obj).thenBranch.equals(thenBranch) && ((ArrayIte) obj).elseBranch.equals(elseBranch) && ((ArrayIte) obj).condition.equals(condition); } /** * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return condition.hashCode() * 31 * 31 + thenBranch.hashCode() * 31 + elseBranch.hashCode(); } /** * @see at.iaik.suraq.smtlib.formula.Term#getIndexSet() */ @Override public Set<DomainTerm> getIndexSet() throws SuraqException { Set<DomainTerm> result = new HashSet<DomainTerm>(); result.addAll(thenBranch.getIndexSet()); result.addAll(elseBranch.getIndexSet()); result.addAll(condition.getIndexSet()); return result; } /** * @see at.iaik.suraq.smtlib.formula.Term#substituteTerm(Map) */ @Override public Term substituteTerm(Map<Token, ? extends Term> paramMap, Map<SMTLibObject, SMTLibObject> done) { if (done.containsKey(this)) { assert (done.get(this) != null); assert (done.get(this) instanceof Term); return (Term) done.get(this); } ArrayTerm convertedThenBranch = (ArrayTerm) thenBranch.substituteTerm( paramMap, done); ArrayTerm convertedElseBranch = (ArrayTerm) elseBranch.substituteTerm( paramMap, done); Formula convertedCondition = condition .substituteFormula(paramMap, done); Term result = ArrayIte.create(convertedCondition, convertedThenBranch, convertedElseBranch); assert (result != null); done.put(this, result); return result; } /** * Simplifies this term by first simplifying the condition, and subsequently * simplifying the ite, if the condition is a constant. * * @return a <code>ArrayIte</code> term, which is simplified. Unchanged * parts are not copied. */ public ArrayTerm simplify() { Formula simplifiedCondition = condition.simplify(); if (simplifiedCondition instanceof PropositionalConstant) if (((PropositionalConstant) simplifiedCondition).getValue()) return thenBranch; else return elseBranch; if (thenBranch.equals(elseBranch)) return thenBranch; return ArrayIte.create(simplifiedCondition, thenBranch, elseBranch); } /** * @return a flattened copy of this term. */ @Override public ArrayTerm flatten() { return ArrayIte.create(condition.flatten(), (ArrayTerm) thenBranch.flatten(), (ArrayTerm) elseBranch.flatten()); } /** * @see at.iaik.suraq.smtlib.formula.Term#toSmtlibV2() */ @Override public SExpression toSmtlibV2() { SExpression[] expr = new SExpression[4]; expr[0] = SExpressionConstants.ITE; expr[1] = condition.toSmtlibV2(); expr[2] = thenBranch.toSmtlibV2(); expr[3] = elseBranch.toSmtlibV2(); return new SExpression(expr); } /** * @see at.iaik.suraq.smtlib.formula.Term#arrayPropertiesToFiniteConjunctions(java.util.Set) */ @Override public Term arrayPropertiesToFiniteConjunctionsTerm(Set<DomainTerm> indexSet) { Formula condition = this.condition; ArrayTerm thenBranch = this.thenBranch; ArrayTerm elseBranch = this.elseBranch; condition = condition.arrayPropertiesToFiniteConjunctions(indexSet); thenBranch = (ArrayTerm) thenBranch .arrayPropertiesToFiniteConjunctionsTerm(indexSet); elseBranch = (ArrayTerm) elseBranch .arrayPropertiesToFiniteConjunctionsTerm(indexSet); return ArrayIte.create(condition, thenBranch, elseBranch); } /** * @see at.iaik.suraq.smtlib.formula.Term#removeArrayEqualitiesTerm() */ @Override public Term removeArrayEqualitiesTerm() { Formula condition = this.condition; ArrayTerm thenBranch = this.thenBranch; ArrayTerm elseBranch = this.elseBranch; condition = condition.removeArrayEqualities(); thenBranch = (ArrayTerm) thenBranch.removeArrayEqualitiesTerm(); elseBranch = (ArrayTerm) elseBranch.removeArrayEqualitiesTerm(); return ArrayIte.create(condition, thenBranch, elseBranch); } /** * @see at.iaik.suraq.smtlib.formula.Term#removeArrayWrites(at.iaik.suraq.smtlib.formula.Formula) */ @Override public Term removeArrayWritesTerm(Formula topLevelFormula, Set<Formula> constraints, Set<Token> noDependenceVars) { Formula condition = this.condition; ArrayTerm thenBranch = this.thenBranch; ArrayTerm elseBranch = this.elseBranch; condition = condition.removeArrayWrites(topLevelFormula, constraints, noDependenceVars); if (thenBranch instanceof ArrayWrite) thenBranch = ((ArrayWrite) thenBranch).applyWriteAxiom( topLevelFormula, constraints, noDependenceVars); else thenBranch = (ArrayTerm) thenBranch.removeArrayWritesTerm( topLevelFormula, constraints, noDependenceVars); if (elseBranch instanceof ArrayWrite) elseBranch = ((ArrayWrite) elseBranch).applyWriteAxiom( topLevelFormula, constraints, noDependenceVars); else elseBranch = (ArrayTerm) elseBranch.removeArrayWritesTerm( topLevelFormula, constraints, noDependenceVars); return ArrayIte.create(condition, thenBranch, elseBranch); } /** * @see at.iaik.suraq.smtlib.formula.Term#arrayReadsToUninterpretedFunctions() */ @Override public Term arrayReadsToUninterpretedFunctionsTerm( Set<Token> noDependenceVars) { Formula condition = this.condition; ArrayTerm thenBranch = this.thenBranch; ArrayTerm elseBranch = this.elseBranch; condition = condition .arrayReadsToUninterpretedFunctions(noDependenceVars); thenBranch = (ArrayTerm) thenBranch .arrayReadsToUninterpretedFunctionsTerm(noDependenceVars); elseBranch = (ArrayTerm) elseBranch .arrayReadsToUninterpretedFunctionsTerm(noDependenceVars); return new ArrayIte(condition, thenBranch, elseBranch); } /** * @see at.iaik.suraq.smtlib.formula.Term#getUninterpretedFunctions() */ @Override public void getUninterpretedFunctions(Set<UninterpretedFunction> result, Set<SMTLibObject> done) { if (done.contains(this)) return; thenBranch.getUninterpretedFunctions(result, done); elseBranch.getUninterpretedFunctions(result, done); condition.getUninterpretedFunctions(result, done); done.add(this); } /** * @see at.iaik.suraq.smtlib.formula.Term#substituteUninterpretedFunction(Token, * at.iaik.suraq.smtlib.formula.UninterpretedFunction) */ @Override public Term substituteUninterpretedFunction( Map<Token, UninterpretedFunction> substitutions, Map<SMTLibObject, SMTLibObject> done) { if (done.get(this) != null) { assert (done.get(this) instanceof Term); return (Term) done.get(this); } Formula condition = this.condition; ArrayTerm thenBranch = this.thenBranch; ArrayTerm elseBranch = this.elseBranch; condition = condition.substituteUninterpretedFunction(substitutions, done); thenBranch = (ArrayTerm) thenBranch.substituteUninterpretedFunction( substitutions, done); elseBranch = (ArrayTerm) elseBranch.substituteUninterpretedFunction( substitutions, done); Term result = ArrayIte.create(condition, thenBranch, elseBranch); done.put(this, result); return result; } /** * @see at.iaik.suraq.smtlib.formula.Term#makeArrayReadsSimple(Formula, * java.util.Set, Set) */ @Override public Term makeArrayReadsSimpleTerm(Formula topLevelFormula, Set<Formula> constraints, Set<Token> noDependenceVars) { Formula condition = this.condition; ArrayTerm thenBranch = this.thenBranch; ArrayTerm elseBranch = this.elseBranch; condition = condition.makeArrayReadsSimple(topLevelFormula, constraints, noDependenceVars); thenBranch = (ArrayTerm) thenBranch.makeArrayReadsSimpleTerm( topLevelFormula, constraints, noDependenceVars); elseBranch = (ArrayTerm) elseBranch.makeArrayReadsSimpleTerm( topLevelFormula, constraints, noDependenceVars); return new ArrayIte(condition, thenBranch, elseBranch); } /** * @see at.iaik.suraq.smtlib.formula.Term#uninterpretedPredicatesToAuxiliaryVariables(at.iaik.suraq.smtlib.formula.Formula, * java.util.Set, java.util.Set) */ /* * @Override public ArrayIte uninterpretedPredicatesToAuxiliaryVariables( * Formula topLeveFormula, Set<Formula> constraints, Set<Token> * noDependenceVars) { return new ArrayIte( * condition.uninterpretedPredicatesToAuxiliaryVariables( topLeveFormula, * constraints, noDependenceVars), * thenBranch.uninterpretedPredicatesToAuxiliaryVariables( topLeveFormula, * constraints, noDependenceVars), * elseBranch.uninterpretedPredicatesToAuxiliaryVariables( topLeveFormula, * constraints, noDependenceVars)); } */ /** * Returns the elements assert-partition. * * @return assert-partition of the element. */ @Override public Set<Integer> getPartitionsFromSymbols() { Set<Integer> partitions = condition.getPartitionsFromSymbols(); partitions.addAll(thenBranch.getPartitionsFromSymbols()); partitions.addAll(elseBranch.getPartitionsFromSymbols()); return partitions; } /** * @see at.iaik.suraq.formula.Term#uninterpretedPredicatesToAuxiliaryVariables(at.iaik.suraq.formula.Formula, * java.util.Map, java.util.Map) */ @Override public Term uninterpretedPredicatesToAuxiliaryVariablesTerm( Formula topLeveFormula, Map<String, List<PropositionalVariable>> predicateInstances, Map<PropositionalVariable, List<DomainTerm>> instanceParameters, Set<Token> noDependenceVars) { throw new RuntimeException( "uninterpretedPredicatesToAuxiliaryVariables cannot be called on an ArrayIte."); /* * if (condition instanceof UninterpretedPredicateInstance) condition = * ((UninterpretedPredicateInstance) * condition).applyReplaceUninterpretedPredicates(topLeveFormula, * predicateInstances, instanceParameters,noDependenceVars); else * condition.uninterpretedPredicatesToAuxiliaryVariables( * topLeveFormula, predicateInstances, instanceParameters, * noDependenceVars); * * thenBranch.uninterpretedPredicatesToAuxiliaryVariables( * topLeveFormula, predicateInstances, instanceParameters, * noDependenceVars); * * elseBranch.uninterpretedPredicatesToAuxiliaryVariables( * topLeveFormula, predicateInstances, instanceParameters, * noDependenceVars); */ } /** * @see at.iaik.suraq.formula.Term#uninterpretedFunctionsToAuxiliaryVariables(at.iaik.suraq.formula.Formula, * java.util.Map, java.util.Map) */ @Override public Term uninterpretedFunctionsToAuxiliaryVariablesTerm( Formula topLeveFormula, Map<String, List<DomainVariable>> functionInstances, Map<DomainVariable, List<DomainTerm>> instanceParameters, Set<Token> noDependenceVars) { throw new RuntimeException( "uninterpretedFunctionsToAuxiliaryVariables cannot be called on an ArrayIte."); /* * condition.uninterpretedFunctionsToAuxiliaryVariables( topLeveFormula, * functionInstances, instanceParameters, noDependenceVars); * thenBranch.uninterpretedFunctionsToAuxiliaryVariables( * topLeveFormula, functionInstances, instanceParameters, * noDependenceVars); * elseBranch.uninterpretedFunctionsToAuxiliaryVariables( * topLeveFormula, functionInstances, instanceParameters, * noDependenceVars); */ } /** * @see at.iaik.suraq.smtlib.formula.ArrayTerm#uninterpretedFunctionsBackToArrayReads(java.util.Set) */ @Override public ArrayTerm uninterpretedFunctionsBackToArrayReads( Set<ArrayVariable> arrayVars, Map<SMTLibObject, SMTLibObject> done) { if (done.get(this) != null) return (ArrayTerm) done.get(this); ArrayTerm result = ArrayIte.create((Formula) condition .uninterpretedFunctionsBackToArrayReads(arrayVars, done), (ArrayTerm) thenBranch.uninterpretedFunctionsBackToArrayReads( arrayVars, done), (ArrayTerm) elseBranch.uninterpretedFunctionsBackToArrayReads( arrayVars, done)); done.put(this, result); return result; } /** * @see at.iaik.suraq.smtlib.formula.Term#removeDomainITE(at.iaik.suraq.smtlib.formula.Formula, * java.util.Set, java.util.List) */ @Override public ArrayTerm removeDomainITE(Formula topLevelFormula, Set<Token> noDependenceVars, List<Formula> andPreList) { Formula newCondition = condition.removeDomainITE(topLevelFormula, noDependenceVars, andPreList); ArrayTerm newThenBranch = thenBranch.removeDomainITE(topLevelFormula, noDependenceVars, andPreList); ArrayTerm newElseBranch = elseBranch.removeDomainITE(topLevelFormula, noDependenceVars, andPreList); return ArrayIte.create(newCondition, newThenBranch, newElseBranch); } /** * @see at.iaik.suraq.smtlib.formula.ArrayTerm#removeArrayITE(at.iaik.suraq.smtlib.formula.Formula, * java.util.Set, java.util.Collection) */ @Override public ArrayVariable removeArrayITE(Formula topLevelFormula, Set<Token> noDependenceVars, Collection<Formula> constraints) { Token newToken = Token.generate(Util.freshVarNameCached( topLevelFormula, "array_itev")); ArrayVariable newVar = ArrayVariable.create(newToken); List<ArrayTerm> termsThen = new ArrayList<ArrayTerm>(2); List<ArrayTerm> termsElse = new ArrayList<ArrayTerm>(2); termsThen.add(newVar); termsThen.add(thenBranch.removeArrayITE(topLevelFormula, noDependenceVars, constraints)); termsElse.add(newVar); termsElse.add(elseBranch.removeArrayITE(topLevelFormula, noDependenceVars, constraints)); try { ArrayEq eqThen = (ArrayEq) EqualityFormula.create(termsThen, true); ArrayEq eqElse = (ArrayEq) EqualityFormula.create(termsElse, true); PropositionalIte propIte = PropositionalIte.create(condition .removeArrayITE(topLevelFormula, noDependenceVars, constraints), eqThen, eqElse); // if (Util.formulaContainsAny(propIte, noDependenceVars)) // Always make new auxiliary variables noDep to avoid combinational // loops noDependenceVars.add(newToken); constraints.add(propIte); return newVar; } catch (SuraqException exc) { throw new RuntimeException( "Unexpected exception while removing DomainITEs.", exc); } } /** * @throws IOException * @see at.iaik.suraq.smtlib.formula.Term#writeTo(java.io.Writer) */ @Override public void writeTo(Writer writer) throws IOException { writer.append('(').append(SExpressionConstants.ITE.toString()); writer.append(' '); condition.writeTo(writer); writer.append(' '); thenBranch.writeTo(writer); writer.append(' '); elseBranch.writeTo(writer); writer.append(')'); } }