/** * 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 array write expression. * * @author Georg Hofferek <georg.hofferek@iaik.tugraz.at> * */ public class ArrayWrite extends ArrayTerm { /** * */ private static final long serialVersionUID = -2087596963751666011L; /** * The array to which this expression writes. */ private final ArrayTerm arrayTerm; /** * The index to which this expression writes. */ private final DomainTerm indexTerm; /** * The value that is written. */ private final DomainTerm valueTerm; /** * Constructs a new <code>ArrayWrite</code>. * * @param arrayTerm * the array to which is written. * @param indexTerm * the index to which is written. * @param valueTerm * the value being written. */ private ArrayWrite(ArrayTerm arrayTerm, DomainTerm indexTerm, DomainTerm valueTerm) { this.arrayTerm = arrayTerm; this.indexTerm = indexTerm; this.valueTerm = valueTerm; } public static ArrayWrite create(ArrayTerm arrayTerm, DomainTerm indexTerm, DomainTerm valueTerm) { return (ArrayWrite) FormulaCache.term.put(new ArrayWrite(arrayTerm, indexTerm, valueTerm)); } /** * Returns the array to which is written. * * @return the <code>arrayTerm</code> */ public ArrayTerm getArrayTerm() { return arrayTerm; } /** * Returns the index to which is written. * * @return the <code>indexTerm</code> */ public DomainTerm getIndexTerm() { return indexTerm; } /** * Returns the value being written. * * @return the <code>valueTerm</code> */ public DomainTerm getValueTerm() { return valueTerm; } /** * @see at.iaik.suraq.smtlib.formula.Term#deepTermCopy() */ @Override public Term deepTermCopy() { return this; // return new ArrayWrite((ArrayTerm) arrayTerm.deepTermCopy(), // indexTerm.deepTermCopy(), valueTerm.deepTermCopy()); } /** * @see at.iaik.suraq.smtlib.formula.Term#getArrayVariables() */ @Override public void getArrayVariables(Set<ArrayVariable> result, Set<SMTLibObject> done) { if (done.contains(this)) return; arrayTerm.getArrayVariables(result, done); indexTerm.getArrayVariables(result, done); valueTerm.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; arrayTerm.getDomainVariables(result, done); indexTerm.getDomainVariables(result, done); valueTerm.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; arrayTerm.getPropositionalVariables(result, done); indexTerm.getPropositionalVariables(result, done); valueTerm.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; arrayTerm.getFunctionMacroNames(result, done); indexTerm.getFunctionMacroNames(result, done); valueTerm.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; arrayTerm.getFunctionMacros(result, done); indexTerm.getFunctionMacros(result, done); valueTerm.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; arrayTerm.getUninterpretedFunctionNames(result, done); indexTerm.getUninterpretedFunctionNames(result, done); valueTerm.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 ArrayWrite)) return false; if (this.hashCode() != obj.hashCode()) return false; return ((ArrayWrite) obj).arrayTerm.equals(arrayTerm) && ((ArrayWrite) obj).indexTerm.equals(indexTerm) && ((ArrayWrite) obj).valueTerm.equals(valueTerm); } /** * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return arrayTerm.hashCode() * 31 * 31 + indexTerm.hashCode() * 31 + valueTerm.hashCode(); } /** * @see at.iaik.suraq.smtlib.formula.Term#getIndexSet() */ @Override public Set<DomainTerm> getIndexSet() throws SuraqException { throw new SuraqException( "Encountered array write while computing index set."); } /** * @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); } Term result = ArrayWrite.create( (ArrayTerm) arrayTerm.substituteTerm(paramMap, done), (DomainTerm) indexTerm.substituteTerm(paramMap, done), (DomainTerm) valueTerm.substituteTerm(paramMap, done)); assert (result != null); done.put(this, result); return result; } /** * @see at.iaik.suraq.smtlib.formula.Term#toSmtlibV2() */ @Override public SExpression toSmtlibV2() { SExpression[] expr = new SExpression[4]; expr[0] = SExpressionConstants.STORE; expr[1] = arrayTerm.toSmtlibV2(); expr[2] = indexTerm.toSmtlibV2(); expr[3] = valueTerm.toSmtlibV2(); return new SExpression(expr); } /** * @see at.iaik.suraq.smtlib.formula.Term#arrayPropertiesToFiniteConjunctions(java.util.Set) */ @Override public Term arrayPropertiesToFiniteConjunctionsTerm(Set<DomainTerm> indexSet) { ArrayTerm arrayTerm = (ArrayTerm) this.arrayTerm .arrayPropertiesToFiniteConjunctionsTerm(indexSet); DomainTerm indexTerm = (DomainTerm) this.indexTerm .arrayPropertiesToFiniteConjunctionsTerm(indexSet); DomainTerm valueTerm = (DomainTerm) this.valueTerm .arrayPropertiesToFiniteConjunctionsTerm(indexSet); return ArrayWrite.create(arrayTerm, indexTerm, valueTerm); } /** * @see at.iaik.suraq.smtlib.formula.Term#removeArrayEqualitiesTerm() */ @Override public Term removeArrayEqualitiesTerm() { ArrayTerm arrayTerm = (ArrayTerm) this.arrayTerm .removeArrayEqualitiesTerm(); DomainTerm indexTerm = (DomainTerm) this.indexTerm .removeArrayEqualitiesTerm(); DomainTerm valueTerm = (DomainTerm) this.valueTerm .removeArrayEqualitiesTerm(); return ArrayWrite.create(arrayTerm, indexTerm, valueTerm); } /** * @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) { throw new RuntimeException( "removeArrayWrites cannot be called on an ArrayWrite.\nUse applyWriteAxiom instead."); } /** * Applies the write axiom to this <code>ArrayWrite</code> term. I.e., * returns a (fresh) <code>ArrayVariable</code> to be used instead of this * term. * * @param topLevelFormula * the top-level formula (w.r.t. which fresh names are selected) * @param constraints * A set of formulas to which the constraints of the write * axiom's application will be added. * @return an <code>ArrayVariable</code> with a fresh name. */ public ArrayVariable applyWriteAxiom(Formula topLevelFormula, Set<Formula> constraints, Set<Token> noDependenceVars) { ArrayVariable result; DomainTerm index; DomainTerm value; // First, recursively remove writes from sub-parts if (arrayTerm instanceof ArrayWrite) result = ((ArrayWrite) arrayTerm).applyWriteAxiom(topLevelFormula, constraints, noDependenceVars); else { assert (arrayTerm instanceof ArrayVariable); result = (ArrayVariable) arrayTerm; } index = indexTerm; index = (DomainTerm) index.removeArrayWritesTerm(topLevelFormula, constraints, noDependenceVars); if (!(index instanceof DomainVariable)) { DomainVariable simpleIndex = DomainVariable.create(Util .freshVarNameCached(topLevelFormula, "read")); List<DomainTerm> terms = new ArrayList<DomainTerm>(); terms.add(simpleIndex); terms.add(index); constraints.add(DomainEq.create(terms, true)); noDependenceVars.add(Token.generate(simpleIndex.getVarName())); index = simpleIndex; } value = valueTerm; value = (DomainTerm) value.removeArrayWritesTerm(topLevelFormula, constraints, noDependenceVars); // now apply axiom String oldVar = result.getVarName(); ArrayVariable newVar = ArrayVariable.create(Util.freshVarNameCached( topLevelFormula, oldVar + "_store")); ArrayRead newRead = ArrayRead.create(newVar, index); newRead = (ArrayRead) newRead.makeArrayReadsSimpleTerm(topLevelFormula, constraints, noDependenceVars); value = (DomainTerm) value.makeArrayReadsSimpleTerm(topLevelFormula, constraints, noDependenceVars); Set<DomainTerm> domainTerms = new HashSet<DomainTerm>(); domainTerms.add(newRead); domainTerms.add(value); constraints.add(DomainEq.create(domainTerms, true)); DomainVariable newUVar = DomainVariable.create(Util.freshVarNameCached( topLevelFormula, "uVar")); domainTerms.clear(); domainTerms.add(index); domainTerms.add(newUVar); Formula indexGuard = DomainEq.create(domainTerms, false); domainTerms.clear(); domainTerms.add(ArrayRead.create(newVar, newUVar)); domainTerms.add(ArrayRead.create(result, newUVar)); Formula valueConstraint = DomainEq.create(domainTerms, true); Set<DomainVariable> uVars = new HashSet<DomainVariable>(); uVars.add(newUVar); try { constraints.add(ArrayProperty.create(uVars, indexGuard, valueConstraint)); } catch (SuraqException exc) { exc.printStackTrace(); throw new RuntimeException("Could not apply write axiom.", exc); } // Make the new array a noDependenceVar // (store-results are "future" values, on which we should not depend.) noDependenceVars.add(Token.generate(newVar.getVarName())); return newVar; } /** * @see at.iaik.suraq.smtlib.formula.Term#arrayReadsToUninterpretedFunctions() */ @Override public Term arrayReadsToUninterpretedFunctionsTerm( Set<Token> noDependenceVars) { ArrayTerm arrayTerm = this.arrayTerm; DomainTerm indexTerm = this.indexTerm; DomainTerm valueTerm = this.valueTerm; arrayTerm = (ArrayTerm) arrayTerm .arrayReadsToUninterpretedFunctionsTerm(noDependenceVars); if (indexTerm instanceof ArrayRead) indexTerm = ((ArrayRead) indexTerm) .toUninterpretedFunctionInstance(noDependenceVars); else indexTerm = (DomainTerm) indexTerm .arrayReadsToUninterpretedFunctionsTerm(noDependenceVars); if (valueTerm instanceof ArrayRead) valueTerm = ((ArrayRead) valueTerm) .toUninterpretedFunctionInstance(noDependenceVars); else valueTerm = (DomainTerm) valueTerm .arrayReadsToUninterpretedFunctionsTerm(noDependenceVars); return ArrayWrite.create(arrayTerm, indexTerm, valueTerm); } /** * @see at.iaik.suraq.smtlib.formula.Term#getUninterpretedFunctions() */ @Override public void getUninterpretedFunctions(Set<UninterpretedFunction> result, Set<SMTLibObject> done) { if (done.contains(this)) return; arrayTerm.getUninterpretedFunctions(result, done); indexTerm.getUninterpretedFunctions(result, done); valueTerm.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); } ArrayTerm arrayTerm = (ArrayTerm) this.arrayTerm .substituteUninterpretedFunction(substitutions, done); DomainTerm indexTerm = this.indexTerm.substituteUninterpretedFunction( substitutions, done); Term result = ArrayWrite.create(arrayTerm, indexTerm, valueTerm); done.put(this, result); return result; } /** * @see at.iaik.suraq.smtlib.formula.Term#flatten() */ @Override public Term flatten() { return ArrayWrite.create((ArrayTerm) arrayTerm.flatten(), (DomainTerm) indexTerm.flatten(), (DomainTerm) valueTerm.flatten()); } /** * @see at.iaik.suraq.smtlib.formula.Term#makeArrayReadsSimple(at.iaik.suraq.smtlib.formula.Formula, * java.util.Set, Set) */ @Override public Term makeArrayReadsSimpleTerm(Formula topLevelFormula, Set<Formula> constraints, Set<Token> noDependenceVars) { ArrayTerm arrayTerm = (ArrayTerm) this.arrayTerm .makeArrayReadsSimpleTerm(topLevelFormula, constraints, noDependenceVars); DomainTerm indexTerm = (DomainTerm) this.indexTerm .makeArrayReadsSimpleTerm(topLevelFormula, constraints, noDependenceVars); DomainTerm valueTerm = (DomainTerm) this.valueTerm .makeArrayReadsSimpleTerm(topLevelFormula, constraints, noDependenceVars); return ArrayWrite.create(arrayTerm, indexTerm, valueTerm); } /** * @see at.iaik.suraq.smtlib.formula.ArrayTerm#uninterpretedPredicatesToAuxiliaryVariables(at.iaik.suraq.smtlib.formula.Formula, * java.util.Set, java.util.Set) */ /* * @Override public ArrayTerm uninterpretedPredicatesToAuxiliaryVariables( * Formula topLeveFormula, Set<Formula> constraints, Set<Token> * noDependenceVars) { return new ArrayWrite( * arrayTerm.uninterpretedPredicatesToAuxiliaryVariables( topLeveFormula, * constraints, noDependenceVars), * indexTerm.uninterpretedPredicatesToAuxiliaryVariables( topLeveFormula, * constraints, noDependenceVars), * valueTerm.uninterpretedPredicatesToAuxiliaryVariables( topLeveFormula, * constraints, noDependenceVars)); } */ /** * Returns the elements assert-partition. * * @return assert-partition of the element. */ @Override public Set<Integer> getPartitionsFromSymbols() { Set<Integer> partitions = arrayTerm.getPartitionsFromSymbols(); partitions.addAll(indexTerm.getPartitionsFromSymbols()); partitions.addAll(valueTerm.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 ArrayWrite."); /* * arrayTerm.uninterpretedPredicatesToAuxiliaryVariables( * topLeveFormula, predicateInstances, instanceParameters, * noDependenceVars); * indexTerm.uninterpretedPredicatesToAuxiliaryVariables( * topLeveFormula, predicateInstances, instanceParameters, * noDependenceVars); * valueTerm.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 ArrayWrite."); /* * arrayTerm.uninterpretedFunctionsToAuxiliaryVariables( topLeveFormula, * functionInstances, instanceParameters, noDependenceVars); * indexTerm.uninterpretedFunctionsToAuxiliaryVariables( topLeveFormula, * functionInstances, instanceParameters,noDependenceVars); * valueTerm.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 = ArrayWrite.create((ArrayTerm) arrayTerm .uninterpretedFunctionsBackToArrayReads(arrayVars, done), (DomainTerm) indexTerm.uninterpretedFunctionsBackToArrayReads( arrayVars, done), (DomainTerm) valueTerm.uninterpretedFunctionsBackToArrayReads( arrayVars, done)); done.put(this, result); return result; } /** * @see at.iaik.suraq.smtlib.formula.ArrayTerm#removeDomainITE(at.iaik.suraq.smtlib.formula.Formula, * java.util.Set, java.util.List) */ @Override public ArrayWrite removeDomainITE(Formula topLevelFormula, Set<Token> noDependenceVars, List<Formula> andPreList) { ArrayTerm newArrayTerm = arrayTerm.removeDomainITE(topLevelFormula, noDependenceVars, andPreList); DomainTerm newIndexTerm = indexTerm.removeDomainITE(topLevelFormula, noDependenceVars, andPreList); DomainTerm newValueTerm = valueTerm.removeDomainITE(topLevelFormula, noDependenceVars, andPreList); return ArrayWrite.create(newArrayTerm, newIndexTerm, newValueTerm); } /** * @see at.iaik.suraq.smtlib.formula.ArrayTerm#removeArrayITE(at.iaik.suraq.smtlib.formula.Formula, * java.util.Set, java.util.Collection) */ @Override public ArrayTerm removeArrayITE(Formula topLevelFormula, Set<Token> noDependenceVars, Collection<Formula> constraints) { ArrayTerm newArrayTerm = arrayTerm.removeArrayITE(topLevelFormula, noDependenceVars, constraints); DomainTerm newIndexTerm = indexTerm.removeArrayITE(topLevelFormula, noDependenceVars, constraints); DomainTerm newValueTerm = valueTerm.removeArrayITE(topLevelFormula, noDependenceVars, constraints); return ArrayWrite.create(newArrayTerm, newIndexTerm, newValueTerm); } /** * @see at.iaik.suraq.smtlib.formula.Term#writeTo(java.io.Writer) */ @Override public void writeTo(Writer writer) throws IOException { writer.write("("); writer.write(SExpressionConstants.STORE.toString()); writer.write(" "); arrayTerm.writeTo(writer); writer.write(" "); indexTerm.writeTo(writer); writer.write(" "); valueTerm.writeTo(writer); writer.write(")"); } }