/** * Author: Georg Hofferek <georg.hofferek@iaik.tugraz.at> */ package at.iaik.suraq.smtlib.formula; import java.util.ArrayList; import java.util.HashMap; 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.SExpressionConstants; import at.iaik.suraq.sexp.Token; import at.iaik.suraq.smtlib.SMTLibObject; import at.iaik.suraq.util.FormulaCache; /** * This class represents a (Boolean) function macro. It represents the * "define-fun" part of the input. Do not confuse it with * <code>PropositionalFunctionMacroInstance</code> which is an actual instance * of a macro. * * @author Georg Hofferek <georg.hofferek@iaik.tugraz.at> * */ public class PropositionalFunctionMacro extends FunctionMacro { /** * */ private static final long serialVersionUID = 1L; /** * The body of this macro. */ private final Formula body; /** * Constructs a new <code>PropositionalFunctionMacro</code> with the given * values. * * @param name * the name of this macro. * @param a * list of parameters * @param paramMap * the map from parameters to types. * @param body * the actual body. * @throws InvalidParametersException * if the size of the parameter list and the type map do not * match. */ private PropositionalFunctionMacro(Token name, List<Token> parameters, Map<Token, SExpression> paramMap, Formula body) throws InvalidParametersException { super(name, parameters, paramMap); this.body = body; } public static PropositionalFunctionMacro create(Token name, List<Token> parameters, Map<Token, SExpression> paramMap, Formula body) throws InvalidParametersException { return (PropositionalFunctionMacro) FormulaCache.functionMacro .put(new PropositionalFunctionMacro(name, parameters, paramMap, body)); } /** * Constructs a new <code>PropositionalFunctionMacro</code>, which is a deep * copy of the given one * * @param macro * the macro to (deep) copy. */ /* * public PropositionalFunctionMacro(PropositionalFunctionMacro macro) { * super(macro); this.body = macro.body.deepFormulaCopy(); } */ /** * Returns the function body of this macro. * * @return the <code>body</code> */ public Formula getBody() { return body; } /** * Creates a new macro, which is the same as this one, but in NNF. * * @return a copy of this macro in NNF. * @throws SuraqException * if conversion to NNF fails (e.g. due to invalid array * properties) */ public PropositionalFunctionMacro negationNormalForm() throws SuraqException { assert (!name.toString().endsWith("NNF")); Token nnfName = Token.generate(name.toString() + "NNF"); Map<Token, SExpression> nnfParamMap = new HashMap<Token, SExpression>( paramMap); List<Token> nnfParameters = new ArrayList<Token>(parameters); Formula nnfBody = body.negationNormalForm(); return PropositionalFunctionMacro.create(nnfName, nnfParameters, nnfParamMap, nnfBody); } /** * Creates a macro with negated body, put in NNF. * * @return a macro with a negated body, put in NNF. * @throws SuraqException */ public PropositionalFunctionMacro negatedMacro() throws SuraqException { Token negatedName = Token.generate(name.toString() + "Negated"); Map<Token, SExpression> negatedParamMap = new HashMap<Token, SExpression>( paramMap); List<Token> negatedParameters = new ArrayList<Token>(parameters); Formula negatedBody = (NotFormula.create(body)).negationNormalForm(); return PropositionalFunctionMacro.create(negatedName, negatedParameters, negatedParamMap, negatedBody); } /** * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (!(obj instanceof PropositionalFunctionMacro)) return false; if (this.hashCode() != obj.hashCode()) return false; if (this.hashCode() != obj.hashCode()) return false; PropositionalFunctionMacro other = (PropositionalFunctionMacro) obj; if (!other.name.equals(name)) return false; if (!other.parameters.equals(parameters)) return false; if (!other.paramMap.equals(paramMap)) return false; if (!other.body.equals(body)) return false; return true; } /** * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return name.hashCode() * 31 * 31 * 31 + parameters.hashCode() * 31 * 31 + paramMap.hashCode() * 31 ^ body.hashCode(); } /** * Removes array equalities from the body of the macro. */ @Override public PropositionalFunctionMacro removeArrayEqualities() { Formula body = this.body; if (body instanceof ArrayEq) body = ((ArrayEq) body).toArrayProperties(); else body = body.removeArrayEqualities(); try { return PropositionalFunctionMacro.create(name, parameters, paramMap, body); } 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 PropositionalFunctionMacro arrayPropertiesToFiniteConjunctions( Set<DomainTerm> indexSet) { Formula body = this.body; if (body instanceof ArrayProperty) body = ((ArrayProperty) body).toFiniteConjunction(indexSet); else body = body.arrayPropertiesToFiniteConjunctions(indexSet); try { return PropositionalFunctionMacro.create(name, parameters, paramMap, body); } catch (InvalidParametersException e) { e.printStackTrace(); throw new RuntimeException(e); } } /** * Simplifies the body of the macro. */ public PropositionalFunctionMacro simplify() { Formula body = this.body.simplify(); try { return PropositionalFunctionMacro.create(name, parameters, paramMap, body); } catch (InvalidParametersException e) { e.printStackTrace(); throw new RuntimeException(e); } } /** * Simplifies the body of the macro after substituting local variables * according to the given map. If the result is a constant, it is returned * as a <code>Boolean</code>. Otherwise, <code>null</code> is returned. * * @param paramMap * the map for substituting local variables. * @return <code>null</code>, if simplifcation does not yield a constant. * The constant as a <code>Boolean</code> otherwise. */ public Boolean simplify(Map<Token, Term> paramMap) { Formula bodyCopy = body.deepFormulaCopy(); bodyCopy = bodyCopy.substituteFormula(paramMap, new HashMap<SMTLibObject, SMTLibObject>()); bodyCopy = bodyCopy.simplify(); if (bodyCopy instanceof PropositionalConstant) return ((PropositionalConstant) bodyCopy).getValue(); return null; } /** * @see at.iaik.suraq.smtlib.formula.FunctionMacro#getType() */ @Override public SExpression getType() { return SExpressionConstants.BOOL_TYPE; } /** * @see at.iaik.suraq.smtlib.formula.EqualityFormula#removeArrayWrites(at.iaik.suraq.smtlib.formula.Formula, * java.util.Set, java.util.Set) */ public PropositionalFunctionMacro removeArrayWrites( Formula topLevelFormula, Set<Formula> constraints, Set<Token> noDependenceVars) { Formula body = this.body.removeArrayWrites(topLevelFormula, constraints, noDependenceVars); try { return PropositionalFunctionMacro.create(name, parameters, paramMap, body); } catch (InvalidParametersException e) { e.printStackTrace(); throw new RuntimeException(e); } } /** * Replaces array-read expression with uninterpreted function instances */ public PropositionalFunctionMacro arrayReadsToUninterpretedFunctions( Set<Token> noDependenceVars) { Formula body = this.body .arrayReadsToUninterpretedFunctions(noDependenceVars); try { return PropositionalFunctionMacro.create(name, parameters, paramMap, body); } catch (InvalidParametersException e) { e.printStackTrace(); throw new RuntimeException(e); } } /** * @see at.iaik.suraq.smtlib.formula.Formula#getUninterpretedFunctions() */ @Override public void getUninterpretedFunctions(Set<UninterpretedFunction> result, Set<SMTLibObject> done) { body.getUninterpretedFunctions(result, done); } /** * @see at.iaik.suraq.smtlib.formula.FunctionMacro#getBodyExpression() */ @Override public SExpression getBodyExpression() { return body.toSmtlibV2(); } /** * @see at.iaik.suraq.smtlib.formula.Formula#substituteUninterpretedFunction(Token, * at.iaik.suraq.smtlib.formula.UninterpretedFunction) */ @Override public PropositionalFunctionMacro substituteUninterpretedFunction( Map<Token, UninterpretedFunction> substitutions, Map<SMTLibObject, SMTLibObject> done) { if (done.get(this) != null) { assert (done.get(this) instanceof PropositionalFunctionMacro); return (PropositionalFunctionMacro) done.get(this); } Formula body = this.body.substituteUninterpretedFunction(substitutions, done); try { PropositionalFunctionMacro result = PropositionalFunctionMacro .create(name, parameters, paramMap, body); done.put(this, result); return result; } catch (InvalidParametersException e) { e.printStackTrace(); throw new RuntimeException(e); } } /** * @param topLevelFormula * @param noDependenceVars * @return */ public PropositionalFunctionMacro makeArrayReadsSimple( Formula topLevelFormula, Set<Formula> constraints, Set<Token> noDependenceVars) { Formula body = this.body.makeArrayReadsSimple(topLevelFormula, constraints, noDependenceVars); try { return PropositionalFunctionMacro.create(name, parameters, paramMap, body); } 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) */ /* * public PropositionalFunctionMacro * uninterpretedPredicatesToAuxiliaryVariables( Formula topLeveFormula, * Set<Formula> constraints, Set<Token> noDependenceVars) { * * Formula newBody = body.uninterpretedPredicatesToAuxiliaryVariables( * topLeveFormula, constraints, noDependenceVars); try { return new * PropositionalFunctionMacro(name, parameters, paramMap, newBody); } catch * (InvalidParametersException exc) { throw new RuntimeException( * "Unexpectedly unable to create PropositionalFunctionMacro.", exc); } * * } */ /** * Returns the elements assert-partition. * * @return assert-partition of the element. */ @Override public Set<Integer> getAssertPartition() { return body.getPartitionsFromSymbols(); } /** * @see at.iaik.suraq.formula.Formula#uninterpretedPredicatesToAuxiliaryVariables(at.iaik.suraq.formula.Formula, * java.util.Map, java.util.Map) */ public PropositionalFunctionMacro uninterpretedPredicatesToAuxiliaryVariables( Formula topLeveFormula, Map<String, List<PropositionalVariable>> predicateInstances, Map<PropositionalVariable, List<DomainTerm>> instanceParameters, Set<Token> noDependenceVars) { Formula body = this.body; if (body instanceof UninterpretedPredicateInstance) body = ((UninterpretedPredicateInstance) body) .applyReplaceUninterpretedPredicates(topLeveFormula, predicateInstances, instanceParameters, noDependenceVars); else body = body.uninterpretedPredicatesToAuxiliaryVariables( topLeveFormula, predicateInstances, instanceParameters, noDependenceVars); try { return PropositionalFunctionMacro.create(name, parameters, paramMap, body); } 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) */ public PropositionalFunctionMacro uninterpretedFunctionsToAuxiliaryVariables( Formula topLeveFormula, Map<String, List<DomainVariable>> functionInstances, Map<DomainVariable, List<DomainTerm>> instanceParameters, Set<Token> noDependenceVars) { Formula body = this.body.uninterpretedFunctionsToAuxiliaryVariables( topLeveFormula, functionInstances, instanceParameters, noDependenceVars); try { return PropositionalFunctionMacro.create(name, parameters, paramMap, body); } catch (InvalidParametersException e) { e.printStackTrace(); throw new RuntimeException(e); } } /** * @param arrayVars * @return */ @Override public PropositionalFunctionMacro uninterpretedFunctionsBackToArrayReads( Set<ArrayVariable> arrayVars, Map<SMTLibObject, SMTLibObject> done) { Formula newBody = (Formula) body .uninterpretedFunctionsBackToArrayReads(arrayVars, done); try { return PropositionalFunctionMacro.create(name, parameters, paramMap, newBody); } catch (InvalidParametersException exc) { throw new RuntimeException( "Unexpected InvalidParametersException while back-substituting array reads.", exc); } } /** * @see at.iaik.suraq.smtlib.SMTLibObject#getPartitionsFromSymbols() */ @Override public Set<Integer> getPartitionsFromSymbols() { throw new NotImplementedException(); } /** * @see at.iaik.suraq.smtlib.SMTLibObject#getArrayVariables(java.util.Set, * java.util.Set) */ @Override public void getArrayVariables(Set<ArrayVariable> result, Set<SMTLibObject> done) { throw new NotImplementedException(); } /** * @see at.iaik.suraq.smtlib.SMTLibObject#getDomainVariables(java.util.Set, * java.util.Set) */ @Override public void getDomainVariables(Set<DomainVariable> result, Set<SMTLibObject> done) { throw new NotImplementedException(); } /** * @see at.iaik.suraq.smtlib.SMTLibObject#getPropositionalVariables(java.util.Set, * java.util.Set) */ @Override public void getPropositionalVariables(Set<PropositionalVariable> result, Set<SMTLibObject> done) { throw new NotImplementedException(); } /** * @see at.iaik.suraq.smtlib.SMTLibObject#getUninterpretedFunctionNames(java.util.Set, * java.util.Set) */ @Override public void getUninterpretedFunctionNames(Set<String> result, Set<SMTLibObject> done) { throw new NotImplementedException(); } /** * @see at.iaik.suraq.smtlib.SMTLibObject#getFunctionMacroNames(java.util.Set, * java.util.Set) */ @Override public void getFunctionMacroNames(Set<String> result, Set<SMTLibObject> done) { result.add(this.name.toString()); } /** * @see at.iaik.suraq.smtlib.SMTLibObject#getFunctionMacros(java.util.Set, * java.util.Set) */ @Override public void getFunctionMacros(Set<FunctionMacro> result, Set<SMTLibObject> done) { result.add(this); } }