/**
* 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.HashMap;
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.InvalidParametersException;
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.FormulaCache;
import at.iaik.suraq.util.HashTagContainer;
import at.iaik.suraq.util.ImmutableHashMap;
/**
* @author Georg Hofferek <georg.hofferek@iaik.tugraz.at>
*
*/
public class TermFunctionMacroInstance extends DomainTerm {
/**
*
*/
private static final long serialVersionUID = -2357506879919697251L;
/**
* The macro of which this is an instance.
*/
private final TermFunctionMacro macro;
/**
* A map from parameter names to the terms.
*/
private final ImmutableHashMap<Token, Term> paramMap;
/**
* Constructs a new <code>TermFunctionMacroInstance</code>.
*
* @param macro
* the function macro of which this will be an instance.
* @param paramMap
* the map from parameter names to their terms
* @throws InvalidParametersException
* if the given map either misses a parameter or the type of the
* term in the map disagrees with the macro.
*/
private TermFunctionMacroInstance(TermFunctionMacro macro,
Map<Token, Term> paramMap) throws InvalidParametersException {
for (Token parameter : macro.getParameters()) {
if (!paramMap.containsKey(parameter))
throw new InvalidParametersException(
"Given map misses parameter " + parameter.toString());
if (!paramMap.get(parameter).getType()
.equals(macro.getParamType(parameter)))
throw new InvalidParametersException(
"Type mismatch for parameter " + parameter.toString());
}
this.macro = macro;
this.paramMap = new ImmutableHashMap<Token, Term>(paramMap);
}
public static TermFunctionMacroInstance create(TermFunctionMacro macro,
Map<Token, Term> paramMap) throws InvalidParametersException {
return (TermFunctionMacroInstance) FormulaCache.domainTerm
.put(new TermFunctionMacroInstance(macro, paramMap));
}
/**
* Returns the macro of which this is an instance.
*
* @return the <code>macro</code>
*/
public TermFunctionMacro getMacro() {
return macro;
}
/**
* Returns the term corresponding to the parameter <code>token</code>.
*
* @param token
* the token identifying the parameter of which the term should
* be returned.
* @return the term mapped to by the given token.
*/
public Term getTerm(Token token) {
return paramMap.get(token);
}
/**
* Returns a copy of the parameter map.
*
* @return the <code>paramMap</code>
*/
public Map<Token, Term> getParamMap() {
return new HashMap<Token, Term>(paramMap);
}
/**
* @see at.iaik.suraq.smtlib.formula.Term#getType()
*/
@Override
public SExpression getType() {
return macro.getType();
}
/**
* @see at.iaik.suraq.smtlib.formula.Term#deepTermCopy()
*/
@Override
public DomainTerm deepTermCopy() {
return this; // experimental
/*
* TermFunctionMacro macro = new TermFunctionMacro(this.macro);
* Map<Token, Term> paramMap = new HashMap<Token, Term>(); for (Token
* token : this.paramMap.keySet()) paramMap.put((Token)
* token.deepCopy(), this.paramMap.get(token) .deepTermCopy());
*
* try { return new TermFunctionMacroInstance(macro, paramMap); } catch
* (InvalidParametersException exc) { // This should never happen!
* assert (false); throw new RuntimeException(
* "Unexpected situation while copying function macro instance.", exc);
* }
*/
}
/**
* @see at.iaik.suraq.smtlib.formula.Term#getArrayVariables()
*/
@Override
public void getArrayVariables(Set<ArrayVariable> result,
Set<SMTLibObject> done) {
if (done.contains(this))
return;
for (Term term : paramMap.values())
term.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;
for (Term term : paramMap.values())
term.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;
for (Term term : paramMap.values())
term.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;
for (Term term : paramMap.values())
term.getFunctionMacroNames(result, done);
done.add(this);
}
/**
* @see at.iaik.suraq.smtlib.formula.Term#getFunctionMacros()
*/
@Override
public void getFunctionMacros(Set<FunctionMacro> result,
Set<SMTLibObject> done) {
result.add(macro);
}
/**
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!(obj instanceof PropositionalFunctionMacroInstance))
return false;
if (this.hashCode() != obj.hashCode())
return false;
if (!((TermFunctionMacroInstance) obj).macro.equals(macro))
return false;
if (!((TermFunctionMacroInstance) obj).paramMap.equals(paramMap))
return false;
return true;
}
/**
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
return macro.hashCode() * 31 + paramMap.hashCode();
}
/**
* @see at.iaik.suraq.smtlib.formula.Term#getUninterpretedFunctionNames()
*/
@Override
public void getUninterpretedFunctionNames(Set<String> result,
Set<SMTLibObject> done) {
if (done.contains(this))
return;
for (Term term : paramMap.values())
term.getUninterpretedFunctionNames(result, done);
done.add(this);
}
/**
* @see at.iaik.suraq.smtlib.SMTLibObject#getUninterpretedFunctions(java.util.Set,
* java.util.Set)
*/
@Override
public void getUninterpretedFunctions(Set<UninterpretedFunction> result,
Set<SMTLibObject> done) {
if (done.contains(this))
return;
for (Term term : paramMap.values())
term.getUninterpretedFunctions(result, done);
done.add(this);
}
/**
* @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);
}
Map<Token, Term> convertedMap = new HashMap<Token, Term>();
for (Token token : this.paramMap.keySet())
convertedMap.put(
token,
this.paramMap.get(token).substituteTerm(paramMap,
new HashMap<SMTLibObject, SMTLibObject>()));
try {
Term result = new TermFunctionMacroInstance(macro, convertedMap);
assert (result != null);
done.put(this, result);
return result;
} catch (InvalidParametersException exc) {
throw new RuntimeException(
"Unexpected exception while converting TermFunctionMacroInstance to caller scope.",
exc);
}
}
/**
* @see at.iaik.suraq.smtlib.formula.Term#getIndexSet()
*/
@Override
public Set<DomainTerm> getIndexSet() throws SuraqException {
Set<DomainTerm> localIndexSet = macro.getBody().getIndexSet();
Set<DomainTerm> result = new HashSet<DomainTerm>();
for (DomainTerm term : localIndexSet) {
result.add((DomainTerm) term.substituteTerm(paramMap,
new HashMap<SMTLibObject, SMTLibObject>()));
}
return result;
}
/**
* @see at.iaik.suraq.smtlib.formula.Term#toSmtlibV2()
*/
@Override
public SExpression toSmtlibV2() {
List<SExpression> expr = new ArrayList<SExpression>();
expr.add(macro.getName());
for (Token param : macro.getParameters())
expr.add(paramMap.get(param).toSmtlibV2());
return new SExpression(expr);
}
/**
* Removes array equalities from the body of the macro.
*/
@Override
public Term removeArrayEqualitiesTerm() {
TermFunctionMacro macro = (TermFunctionMacro) this.macro
.removeArrayEqualities();
Map<Token, Term> paramMap = new HashMap<Token, Term>();
for (Token token : paramMap.keySet())
paramMap.put(token, this.paramMap.get(token)
.removeArrayEqualitiesTerm());
try {
return TermFunctionMacroInstance.create(macro, paramMap);
} catch (InvalidParametersException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
/**
* Converts array properties in the body of the macro to finite conjunctions
*
* @param indexSet
* the index set.
*/
@Override
public Term arrayPropertiesToFiniteConjunctionsTerm(Set<DomainTerm> indexSet) {
TermFunctionMacro macro = (TermFunctionMacro) this.macro
.arrayPropertiesToFiniteConjunctions(indexSet);
Map<Token, Term> paramMap = new HashMap<Token, Term>();
for (Token token : paramMap.keySet())
paramMap.put(token, this.paramMap.get(token)
.arrayPropertiesToFiniteConjunctionsTerm(indexSet));
try {
return TermFunctionMacroInstance.create(macro, paramMap);
} catch (InvalidParametersException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
/**
* @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) {
// FIXME: this cannot work:
throw new RuntimeException("Cannot work");
// Set<Formula> localConstraints = macro.removeArrayWrites(
// topLevelFormula, noDependenceVars);
// for (Formula localConstraint : localConstraints)
// constraints.add(localConstraint.substituteFormula(paramMap));
//
// Map<Token, Term> paramMap2 = new HashMap<Token, Term>();
// for (Token key : paramMap.keySet()) {
// // for (Term term : paramMap.values())
// paramMap2.put(
// key,
// paramMap.get(key).removeArrayWritesTerm(topLevelFormula,
// constraints, noDependenceVars));
// }
// try {
// return new TermFunctionMacroInstance(macro, paramMap2);
// } catch (InvalidParametersException e) {
// e.printStackTrace();
// throw new RuntimeException(e);
// }
}
/**
* @see at.iaik.suraq.smtlib.formula.Term#arrayReadsToUninterpretedFunctions()
*/
@Override
public Term arrayReadsToUninterpretedFunctionsTerm(
Set<Token> noDependenceVars) {
TermFunctionMacro macro = (TermFunctionMacro) this.macro
.arrayReadsToUninterpretedFunctions(noDependenceVars);
Map<Token, Term> paramMap2 = new HashMap<Token, Term>();
for (Token key : paramMap.keySet()) {
Term term = paramMap.get(key);
if (term instanceof ArrayRead)
paramMap2.put(key, ((ArrayRead) term)
.toUninterpretedFunctionInstance(noDependenceVars));
else
paramMap2
.put(key,
term.arrayReadsToUninterpretedFunctionsTerm(noDependenceVars));
}
try {
return TermFunctionMacroInstance.create(macro, paramMap2);
} catch (InvalidParametersException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
/**
* @see at.iaik.suraq.smtlib.formula.Term#substituteUninterpretedFunction(Token,
* at.iaik.suraq.smtlib.formula.UninterpretedFunction)
*/
@Override
public TermFunctionMacroInstance substituteUninterpretedFunction(
Map<Token, UninterpretedFunction> substitutions,
Map<SMTLibObject, SMTLibObject> done) {
if (done.get(this) != null) {
assert (done.get(this) instanceof TermFunctionMacroInstance);
return (TermFunctionMacroInstance) done.get(this);
}
TermFunctionMacro macro = (TermFunctionMacro) this.macro
.substituteUninterpretedFunction(substitutions, done);
Map<Token, Term> paramMap2 = new HashMap<Token, Term>();
for (Token token : paramMap.keySet())
paramMap2.put(token, this.paramMap.get(token)
.substituteUninterpretedFunction(substitutions, done));
try {
TermFunctionMacroInstance result = TermFunctionMacroInstance
.create(macro, paramMap2);
done.put(this, result);
return result;
} catch (InvalidParametersException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
/**
* @see at.iaik.suraq.smtlib.formula.Formula#flatten()
*/
@Override
public Term flatten() {
return macro
.getBody()
.substituteTerm(paramMap,
new HashMap<SMTLibObject, SMTLibObject>()).flatten();
}
/**
* @see at.iaik.suraq.smtlib.formula.DomainTerm#isEvar(java.util.Collection)
*/
@Override
public boolean isEvar(Collection<DomainVariable> uVars) {
return ((DomainTerm) this.flatten()).isEvar(uVars);
}
/**
* @see at.iaik.suraq.smtlib.formula.Formula#makeArrayReadsSimple(at.iaik.suraq.smtlib.formula.Formula,
* java.util.Set, java.util.Set)
*/
@Override
public Term makeArrayReadsSimpleTerm(Formula topLevelFormula,
Set<Formula> constraints, Set<Token> noDependenceVars) {
Set<Formula> localConstraints = macro.makeArrayReadsSimple(
topLevelFormula, noDependenceVars);
for (Formula localConstraint : localConstraints) {
Map<SMTLibObject, SMTLibObject> done = new HashMap<SMTLibObject, SMTLibObject>();
constraints.add(localConstraint.substituteFormula(paramMap, done));
}
Map<Token, Term> paramMap2 = new HashMap<Token, Term>();
for (Token token : paramMap.keySet())
paramMap2.put(
token,
paramMap.get(token).makeArrayReadsSimpleTerm(
topLevelFormula, constraints, noDependenceVars));
try {
return TermFunctionMacroInstance.create(macro, paramMap2);
} catch (InvalidParametersException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
/**
* @see at.iaik.suraq.smtlib.formula.Formula#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) { Set<Formula> localConstraints = new
* HashSet<Formula>(); TermFunctionMacro newMacro = macro
* .uninterpretedPredicatesToAuxiliaryVariables(topLeveFormula,
* localConstraints, noDependenceVars); for (Formula localConstraint :
* localConstraints)
* constraints.add(localConstraint.substituteFormula(paramMap));
*
* Map<Token, Term> newParamMap = new HashMap<Token, Term>(); for (Token
* token : paramMap.keySet()) newParamMap.put( token, paramMap.get(token)
* .uninterpretedPredicatesToAuxiliaryVariables( topLeveFormula,
* constraints, noDependenceVars)); try { return new
* TermFunctionMacroInstance(newMacro, newParamMap); } catch
* (InvalidParametersException exc) { throw new RuntimeException(
* "Unexpectedly unable to create TermFunctionMacroInstance.", exc); } }
*/
/**
* Returns the elements assert-partition.
*
* @return assert-partition of the element.
*/
@Override
public Set<Integer> getPartitionsFromSymbols() {
Set<Integer> partitions = macro.getAssertPartition();
for (Term term : paramMap.values())
partitions.addAll(term.getPartitionsFromSymbols());
return partitions;
}
/**
* @see at.iaik.suraq.formula.Formula#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) {
TermFunctionMacro macro = (TermFunctionMacro) this.macro
.uninterpretedPredicatesToAuxiliaryVariables(topLeveFormula,
predicateInstances, instanceParameters,
noDependenceVars);
Map<Token, Term> paramMap2 = new HashMap<Token, Term>();
for (Token token : paramMap.keySet())
paramMap2.put(
token,
paramMap.get(token)
.uninterpretedPredicatesToAuxiliaryVariablesTerm(
topLeveFormula, predicateInstances,
instanceParameters, noDependenceVars));
try {
return TermFunctionMacroInstance.create(macro, paramMap2);
} catch (InvalidParametersException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
/**
* @see at.iaik.suraq.formula.Formula#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) {
TermFunctionMacro macro = (TermFunctionMacro) this.macro
.uninterpretedFunctionsToAuxiliaryVariables(topLeveFormula,
functionInstances, instanceParameters, noDependenceVars);
Map<Token, Term> paramMap2 = new HashMap<Token, Term>();
for (Token token : paramMap.keySet())
paramMap2.put(
token,
paramMap.get(token)
.uninterpretedFunctionsToAuxiliaryVariablesTerm(
topLeveFormula, functionInstances,
instanceParameters, noDependenceVars));
try {
return TermFunctionMacroInstance.create(macro, paramMap2);
} catch (InvalidParametersException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
/**
* @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);
Map<Token, Term> newParamMap = new HashMap<Token, Term>();
for (Token key : paramMap.keySet()) {
newParamMap.put(key, (Term) paramMap.get(key)
.uninterpretedFunctionsBackToArrayReads(arrayVars, done));
}
TermFunctionMacro newMacro = macro
.uninterpretedFunctionsBackToArrayReads(arrayVars, done);
try {
DomainTerm result = TermFunctionMacroInstance.create(newMacro,
newParamMap);
done.put(this, result);
return result;
} catch (InvalidParametersException exc) {
throw new RuntimeException(
"Unexpected InvalidParametersException while back-substituting array reads.",
exc);
}
}
/**
* @see at.iaik.suraq.smtlib.formula.DomainTerm#removeDomainITE(at.iaik.suraq.smtlib.formula.Formula,
* java.util.Set, java.util.List)
*/
@Override
public DomainTerm removeDomainITE(Formula topLevelFormula,
Set<Token> noDependenceVars, List<Formula> andPreList) {
throw new RuntimeException(
"Macros should be flattened before removing DomainITEs.");
}
/**
* @see at.iaik.suraq.smtlib.formula.Term#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) {
throw new RuntimeException(
"Macros should be flattened before removing ArrayITEs.");
}
/**
* @see at.iaik.suraq.smtlib.formula.Term#writeOut(java.io.BufferedWriter,
* at.iaik.suraq.util.HashTagContainer, boolean)
*/
@Override
public void writeOut(BufferedWriter writer, HashTagContainer tagContaine)
throws IOException {
throw new NotImplementedException();
}
/**
* @see at.iaik.suraq.smtlib.formula.Formula#writeTo(java.io.Writer)
*/
@Override
public void writeTo(Writer writer) throws IOException {
throw new NotImplementedException();
}
}