/** * 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.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 sun.reflect.generics.reflectiveObjects.NotImplementedException; import at.iaik.suraq.exceptions.SuraqException; import at.iaik.suraq.exceptions.WrongNumberOfParametersException; 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.HashTagContainer; import at.iaik.suraq.util.Util; /** * @author Georg Hofferek <georg.hofferek@iaik.tugraz.at> * */ public class ArrayRead extends DomainTerm { /** * */ private static final long serialVersionUID = -2549087326175334824L; /** * The array variable that is read. */ private final ArrayTerm arrayTerm; /** * The index from which is read. */ private final DomainTerm indexTerm; /** * Constructs a new <code>ArrayRead</code>. * * @param arrayTerm * the variable that is read * @param index * the index from which is read. */ private ArrayRead(ArrayTerm arrayTerm, DomainTerm index) { super(); this.arrayTerm = arrayTerm; this.indexTerm = index; } public static ArrayRead create(ArrayTerm arrayTerm, DomainTerm index) { return (ArrayRead) FormulaCache.domainTerm.put(new ArrayRead(arrayTerm, index)); } /** * @see at.iaik.suraq.smtlib.formula.DomainTerm#isEvar(java.util.Collection) */ @Override public boolean isEvar(Collection<DomainVariable> uVars) { // not applicable for ArrayRead. return false; } /** * Returns the index from which is read. * * @return the index from which is read. */ public DomainTerm getIndexTerm() { return indexTerm; } /** * Returns the array variable from which is read. * * @return the array variable from which is read. */ public ArrayTerm getArrayTerm() { return arrayTerm; } /** * @see at.iaik.suraq.smtlib.formula.Term#deepTermCopy() */ @Override public DomainTerm deepTermCopy() { return this; // experimental // return new ArrayRead((ArrayTerm) arrayTerm.deepTermCopy(), // indexTerm.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); 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); 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); 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); 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); 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); 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 ArrayRead)) return false; if (this.hashCode() != obj.hashCode()) return false; return arrayTerm.equals(((ArrayRead) obj).arrayTerm) && indexTerm.equals(((ArrayRead) obj).indexTerm); } /** * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return arrayTerm.hashCode() * 31 + indexTerm.hashCode(); } /** * @see at.iaik.suraq.smtlib.formula.Term#getIndexSet() */ @Override public Set<DomainTerm> getIndexSet() throws SuraqException { if (!(arrayTerm instanceof ArrayVariable)) throw new SuraqException( "Encountered array-read from non-variable array term while computing index set."); Set<DomainTerm> result = new HashSet<DomainTerm>(); result.add(indexTerm); 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); } Term result = ArrayRead.create( (ArrayTerm) arrayTerm.substituteTerm(paramMap, done), (DomainTerm) indexTerm.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[3]; expr[0] = SExpressionConstants.SELECT; expr[1] = arrayTerm.toSmtlibV2(); expr[2] = indexTerm.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); return ArrayRead.create(arrayTerm, indexTerm); } /** * @see at.iaik.suraq.smtlib.formula.Term#removeArrayEqualitiesTerm() */ @Override public Term removeArrayEqualitiesTerm() { ArrayTerm arrayTerm = (ArrayTerm) this.arrayTerm .removeArrayEqualitiesTerm(); DomainTerm indexTerm = (DomainTerm) this.indexTerm .removeArrayEqualitiesTerm(); return ArrayRead.create(arrayTerm, indexTerm); } /** * @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) { ArrayTerm arrayTerm = this.arrayTerm; DomainTerm indexTerm = this.indexTerm; if (arrayTerm instanceof ArrayWrite) arrayTerm = ((ArrayWrite) arrayTerm).applyWriteAxiom( topLevelFormula, constraints, noDependenceVars); else arrayTerm = (ArrayTerm) arrayTerm.removeArrayWritesTerm( topLevelFormula, constraints, noDependenceVars); indexTerm = (DomainTerm) indexTerm.removeArrayWritesTerm( topLevelFormula, constraints, noDependenceVars); return ArrayRead.create(arrayTerm, indexTerm); } /** * Returns an <code>UninterpretedFunctionInstance</code> that is * "equivalent" to this <code>ArrayRead</code>. * * @return an <code>UninterpretedFunctionInstance</code> that is * "equivalent" to this <code>ArrayRead</code>. */ public UninterpretedFunctionInstance toUninterpretedFunctionInstance( Set<Token> noDependenceVars) { try { // Complex array terms should have been removed before. assert (arrayTerm instanceof ArrayVariable); // String functionName = arrayTerm.toSmtlibV2().toString() // .replaceAll("\\W", ""); String functionName = ((ArrayVariable) arrayTerm).getVarName(); DomainTerm term = indexTerm; if (term instanceof ArrayRead) term = ((ArrayRead) term) .toUninterpretedFunctionInstance(noDependenceVars); else term = (DomainTerm) term .arrayReadsToUninterpretedFunctionsTerm(noDependenceVars); // Check if the arrayTerm contained any noDependenceVars. // This is conservative and might not be complete (i.e., may // result unnecessary unrealizability), but // in practice, array reads should only occur on primitive // array expressions, so this should not be a "real" problem. if (Util.termContainsAny(arrayTerm, noDependenceVars)) noDependenceVars.add(Token.generate(functionName)); return UninterpretedFunctionInstance.create(UninterpretedFunction .create(functionName, 1, SExpressionConstants.VALUE_TYPE), term); } catch (WrongNumberOfParametersException exc) { throw new RuntimeException( "Could not replace array-reads with uninterpreted functions", exc); } } /** * @see at.iaik.suraq.smtlib.formula.Term#arrayReadsToUninterpretedFunctions() */ @Override public Term arrayReadsToUninterpretedFunctionsTerm( Set<Token> noDependenceVars) { throw new RuntimeException( "arrayReadsToUninterpretedFunctions cannot be called on an ArrayWrite.\nUse toUninterpretedFunctionInstance instead."); } /** * @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); done.add(this); } /** * @see at.iaik.suraq.smtlib.formula.Term#substituteUninterpretedFunction(Token, * at.iaik.suraq.smtlib.formula.UninterpretedFunction) */ @Override public DomainTerm substituteUninterpretedFunction( Map<Token, UninterpretedFunction> substitutions, Map<SMTLibObject, SMTLibObject> done) { if (done.get(this) != null) { assert (done.get(this) instanceof DomainTerm); return (DomainTerm) done.get(this); } ArrayTerm arrayTerm = (ArrayTerm) this.arrayTerm .substituteUninterpretedFunction(substitutions, done); DomainTerm indexTerm = this.indexTerm.substituteUninterpretedFunction( substitutions, done); DomainTerm result = ArrayRead.create(arrayTerm, indexTerm); done.put(this, result); return result; } /** * @see at.iaik.suraq.smtlib.formula.Term#flatten() */ @Override public Term flatten() { return ArrayRead.create((ArrayTerm) arrayTerm.flatten(), (DomainTerm) indexTerm.flatten()); } /** * @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) { if (this.indexTerm instanceof DomainVariable) return this; // This read is already simple. DomainTerm oldIndexTerm = (DomainTerm) this.indexTerm .makeArrayReadsSimpleTerm(topLevelFormula, constraints, noDependenceVars); DomainVariable indexTerm = DomainVariable.create(Util .freshVarNameCached(topLevelFormula, "read")); List<DomainTerm> list = new ArrayList<DomainTerm>(2); list.add(indexTerm); list.add(oldIndexTerm); constraints.add(DomainEq.create(list, true)); noDependenceVars.add(Token.generate(indexTerm.getVarName())); return ArrayRead.create(this.arrayTerm, indexTerm); } /** * @see at.iaik.suraq.smtlib.formula.Term#uninterpretedPredicatesToAuxiliaryVariables(at.iaik.suraq.smtlib.formula.Formula, * java.util.Set, java.util.Set) */ /* * @Override public DomainTerm uninterpretedPredicatesToAuxiliaryVariables( * Formula topLeveFormula, Set<Formula> constraints, Set<Token> * noDependenceVars) { * * return new ArrayRead( * arrayTerm.uninterpretedPredicatesToAuxiliaryVariables( topLeveFormula, * constraints, noDependenceVars), * indexTerm.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()); 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 ArrayRead."); /* * arrayTerm.uninterpretedPredicatesToAuxiliaryVariables( * topLeveFormula, predicateInstances, instanceParameters, * noDependenceVars); * indexTerm.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 ArrayRead."); /* * arrayTerm.uninterpretedFunctionsToAuxiliaryVariables( topLeveFormula, * functionInstances, instanceParameters, noDependenceVars); * indexTerm.uninterpretedFunctionsToAuxiliaryVariables( topLeveFormula, * functionInstances, instanceParameters, noDependenceVars); */ } /** * @see at.iaik.suraq.smtlib.formula.DomainTerm#uninterpretedFunctionsBackToArrayReads(java.util.Set) */ @Override public DomainTerm uninterpretedFunctionsBackToArrayReads( Set<ArrayVariable> arrayVars, Map<SMTLibObject, SMTLibObject> done) { if (done.get(this) != null) return (DomainTerm) done.get(this); DomainTerm result = ArrayRead.create((ArrayTerm) arrayTerm .uninterpretedFunctionsBackToArrayReads(arrayVars, done), (DomainTerm) indexTerm.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 ArrayRead removeDomainITE(Formula topLevelFormula, Set<Token> noDependenceVars, List<Formula> andPreList) { ArrayTerm newArrayTerm = arrayTerm.removeDomainITE(topLevelFormula, noDependenceVars, andPreList); DomainTerm newIndexTerm = indexTerm.removeDomainITE(topLevelFormula, noDependenceVars, andPreList); return ArrayRead.create(newArrayTerm, newIndexTerm); } /** * @see at.iaik.suraq.smtlib.formula.DomainTerm#removeArrayITE(at.iaik.suraq.smtlib.formula.Formula, * java.util.Set, java.util.Collection) */ @Override public DomainTerm removeArrayITE(Formula topLevelFormula, Set<Token> noDependenceVars, Collection<Formula> constraints) { ArrayTerm newArrayTerm = arrayTerm.removeArrayITE(topLevelFormula, noDependenceVars, constraints); DomainTerm newIndexTerm = indexTerm.removeArrayITE(topLevelFormula, noDependenceVars, constraints); return ArrayRead.create(newArrayTerm, newIndexTerm); } /** * @see at.iaik.suraq.smtlib.formula.Term#writeOut(java.io.BufferedWriter, * at.iaik.suraq.util.HashTagContainer, boolean) */ @Override public void writeOut(BufferedWriter writer, HashTagContainer tagContainer) throws IOException { throw new NotImplementedException(); } /** * @see at.iaik.suraq.smtlib.formula.Term#writeTo(java.io.Writer) */ @Override public void writeTo(Writer writer) throws IOException { writer.write("("); writer.write(SExpressionConstants.SELECT.toString()); writer.write(" "); arrayTerm.writeTo(writer); writer.write(" "); indexTerm.writeTo(writer); writer.write(")"); } }