/** * 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.math.BigInteger; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; 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.HashTagContainer; import at.iaik.suraq.util.Util; /** * A formula representing the negation of another one. * * @author Georg Hofferek <georg.hofferek@iaik.tugraz.at> * */ public class NotFormula extends BooleanCombinationFormula { /** * */ private static final long serialVersionUID = -99679765405836941L; /** * The negated internal formula. */ private final Formula formula; private final int hashCode; public static NotFormula create(Formula formula) { return FormulaCache.notFormula.put(new NotFormula(formula)); } /** * * Constructs a new <code>NotFormula</code>. * * @param formula * the negation of this formula. */ private NotFormula(Formula formula) { if (formula instanceof FormulaTerm) this.formula = ((FormulaTerm) formula).getFormula(); else this.formula = formula; hashCode = formula.hashCode(); } /** * @see at.iaik.suraq.smtlib.formula.BooleanCombinationFormula#getSubFormulas() */ @Override public Collection<Formula> getSubFormulas() { List<Formula> list = new ArrayList<Formula>(); list.add(formula); return list; } /** * Returns a copy of the negated formula. * * @return A copy of the negated formula. */ public Formula getNegatedFormula() { return formula.deepFormulaCopy(); } /** * @see at.iaik.suraq.smtlib.formula.Formula#deepFormulaCopy() */ @Override public Formula deepFormulaCopy() { return this; // experimental // return NotFormula.create(formula.deepFormulaCopy()); } /** * @see at.iaik.suraq.smtlib.formula.Formula#getArrayVariables() */ @Override public void getArrayVariables(Set<ArrayVariable> result, Set<SMTLibObject> done) { if (done.contains(this)) return; formula.getArrayVariables(result, done); done.add(this); } /** * @see at.iaik.suraq.smtlib.formula.Formula#getDomainVariables() */ @Override public void getDomainVariables(Set<DomainVariable> result, Set<SMTLibObject> done) { if (done.contains(this)) return; formula.getDomainVariables(result, done); done.add(this); } /** * @see at.iaik.suraq.smtlib.formula.Formula#getPropositionalVariables() */ @Override public void getPropositionalVariables(Set<PropositionalVariable> result, Set<SMTLibObject> done) { if (done.contains(this)) return; formula.getPropositionalVariables(result, done); done.add(this); } /** * @see at.iaik.suraq.smtlib.formula.Formula#negationNormalForm() */ @Override public Formula negationNormalForm() throws SuraqException { // And if (formula instanceof AndFormula) { List<Formula> subformulas = new ArrayList<Formula>(); for (Formula subformula : ((AndOrXorFormula) formula).formulas) subformulas.add((NotFormula.create(subformula)) .negationNormalForm()); return OrFormula.generate(subformulas); } // Or if (formula instanceof OrFormula) { List<Formula> subformulas = new ArrayList<Formula>(); for (Formula subformula : ((AndOrXorFormula) formula).formulas) subformulas.add((NotFormula.create(subformula)) .negationNormalForm()); return AndFormula.generate(subformulas); } // Xor if (formula instanceof XorFormula) { Formula converted = ((XorFormula) formula).toAndOrFormula(); return (NotFormula.create(converted)).negationNormalForm(); } // Not if (formula instanceof NotFormula) { return ((NotFormula) formula).formula.negationNormalForm(); } // Equality if (formula instanceof EqualityFormula) { EqualityFormula eqFormula = (EqualityFormula) formula; if (eqFormula.isPair()) return EqualityFormula.create(eqFormula.getTerms(), !eqFormula.isEqual()); AndFormula pairwise = eqFormula.toPairwise(); return (NotFormula.create(pairwise)).negationNormalForm(); } // ArrayProperty if (formula instanceof ArrayProperty) { throw new UnsupportedOperationException( "NNF of array properties not implemented!"); } // PropositionalConstant if (formula instanceof PropositionalConstant) return PropositionalConstant .create(!((PropositionalConstant) formula).getValue()); // PropositionalVariable if (formula instanceof PropositionalVariable) return this.deepFormulaCopy(); // Implies if (formula instanceof ImpliesFormula) { ImpliesFormula impliesFormula = (ImpliesFormula) formula; List<Formula> list = new ArrayList<Formula>(); list.add(impliesFormula.getLeftSide().negationNormalForm()); list.add((NotFormula.create(impliesFormula.getRightSide())) .negationNormalForm()); return AndFormula.generate(list); } // MacroInstance if (formula instanceof PropositionalFunctionMacroInstance) { PropositionalFunctionMacro negatedMacro = ((PropositionalFunctionMacroInstance) formula) .getMacro().negatedMacro(); Map<Token, Term> paramMap = new HashMap<Token, Term>( ((PropositionalFunctionMacroInstance) formula) .getParamMap()); return PropositionalFunctionMacroInstance.create(negatedMacro, paramMap); } // PropositionalITE if (formula instanceof PropositionalIte) { PropositionalIte iteFormula = (PropositionalIte) formula; Formula thenBranch = (NotFormula.create(iteFormula.getThenBranch())) .negationNormalForm(); Formula elseBranch = (NotFormula.create(iteFormula.getElseBranch())) .negationNormalForm(); return PropositionalIte.create(iteFormula.getCondition() .negationNormalForm(), thenBranch, elseBranch); } // something unexpected throw new SuraqException( "Unexpected formula type while trying to convert to NNF:" + formula.getClass().toString()); } /** * @see at.iaik.suraq.smtlib.formula.Formula#getUninterpretedFunctionNames() */ @Override public void getUninterpretedFunctionNames(Set<String> result, Set<SMTLibObject> done) { if (done.contains(this)) return; formula.getUninterpretedFunctionNames(result, done); done.add(this); } /** * @see at.iaik.suraq.smtlib.formula.Formula#getFunctionMacroNames() */ @Override public void getFunctionMacroNames(Set<String> result, Set<SMTLibObject> done) { if (done.contains(this)) return; formula.getFunctionMacroNames(result, done); done.add(this); } /** * @see at.iaik.suraq.smtlib.formula.Formula#getFunctionMacros() */ @Override public void getFunctionMacros(Set<FunctionMacro> result, Set<SMTLibObject> done) { if (done.contains(this)) return; formula.getFunctionMacros(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 NotFormula)) return false; if (this.hashCode() != obj.hashCode()) return false; return ((NotFormula) obj).formula.equals(formula); } /** * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return this.hashCode; } /** * @see at.iaik.suraq.smtlib.formula.Formula#getIndexSet() */ @Override public Set<DomainTerm> getIndexSet() throws SuraqException { return formula.getIndexSet(); } /** * @see at.iaik.suraq.smtlib.formula.Formula#substituteFormula(Map) */ @Override public Formula substituteFormula(Map<Token, ? extends Term> paramMap, Map<SMTLibObject, SMTLibObject> done) { if (done.containsKey(this)) { assert (done.get(this) != null); assert (done.get(this) instanceof Formula); return (Formula) done.get(this); } Formula result = NotFormula.create(formula.substituteFormula(paramMap, done)); assert (result != null); done.put(this, result); return result; } /** * @see at.iaik.suraq.smtlib.formula.Formula#removeArrayEqualitiesTerm() */ @Override public Formula removeArrayEqualities() { Formula formula = this.formula; if (formula instanceof ArrayEq) formula = ((ArrayEq) formula).toArrayProperties(); else formula = formula.removeArrayEqualities(); return NotFormula.create(formula); } /** * @see at.iaik.suraq.smtlib.formula.Formula#arrayPropertiesToFiniteConjunctions(java.util.Set) */ @Override public Formula arrayPropertiesToFiniteConjunctions(Set<DomainTerm> indexSet) { Formula formula = this.formula; if (formula instanceof ArrayProperty) formula = ((ArrayProperty) formula).toFiniteConjunction(indexSet); else formula = formula.arrayPropertiesToFiniteConjunctions(indexSet); return NotFormula.create(formula); } /** * Checks whether this <code>NotFormula</code> is a negated propositional * variable. If so, the variable is returned (without the negation). * * @return If this <code>NotFormula</code> is the negation of a * <code>PropositionalVariable</code>, the variable is returned. * Else, <code>null</code> is returned. */ public PropositionalVariable isNegatedVariable() { if (!(formula instanceof PropositionalVariable)) return null; else return (PropositionalVariable) formula; } /** * Checks whether this <code>NotFormula</code> is a negated propositional * constant. If so, the constant is returned (without the negation). * * @return If this <code>NotFormula</code> is the negation of a * <code>PropositionalConstant</code>, it is returned. Else, * <code>null</code> is returned. */ public PropositionalConstant isNegatedConstant() { if (!(formula instanceof PropositionalConstant)) return null; else return (PropositionalConstant) formula; } /** * @see at.iaik.suraq.smtlib.formula.Formula#simplify() */ @Override public Formula simplify() { Formula formula = this.formula.simplify(); if (formula instanceof PropositionalConstant) return PropositionalConstant .create(!((PropositionalConstant) formula).getValue()); if (formula instanceof NotFormula) return ((NotFormula) formula).formula; return NotFormula.create(formula); } /** * @see at.iaik.suraq.smtlib.formula.Formula#flatten() */ @Override public Formula flatten() { return NotFormula.create(formula.flatten()); } /** * @see at.iaik.suraq.smtlib.formula.Formula#toSmtlibV2() */ @Override public SExpression toSmtlibV2() { return new SExpression(SExpressionConstants.NOT, formula.toSmtlibV2()); } /** * @see at.iaik.suraq.smtlib.formula.Formula#removeArrayWrites(at.iaik.suraq.smtlib.formula.Formula) */ @Override public Formula removeArrayWrites(Formula topLevelFormula, Set<Formula> constraints, Set<Token> noDependenceVars) { return NotFormula.create(formula.removeArrayWrites(topLevelFormula, constraints, noDependenceVars)); } /** * @see at.iaik.suraq.smtlib.formula.Formula#arrayReadsToUninterpretedFunctions() */ @Override public Formula arrayReadsToUninterpretedFunctions( Set<Token> noDependenceVars) { return NotFormula.create(formula .arrayReadsToUninterpretedFunctions(noDependenceVars)); } /** * @see at.iaik.suraq.smtlib.formula.Formula#getUninterpretedFunctions() */ @Override public void getUninterpretedFunctions(Set<UninterpretedFunction> result, Set<SMTLibObject> done) { if (done.contains(this)) return; formula.getUninterpretedFunctions(result, done); done.add(this); } /** * @see at.iaik.suraq.smtlib.formula.Formula#substituteUninterpretedFunction(Token, * at.iaik.suraq.smtlib.formula.UninterpretedFunction) */ @Override public Formula substituteUninterpretedFunction( Map<Token, UninterpretedFunction> substitutions, Map<SMTLibObject, SMTLibObject> done) { if (done.get(this) != null) { assert (done.get(this) instanceof Formula); return (Formula) done.get(this); } Formula result = NotFormula.create(formula .substituteUninterpretedFunction(substitutions, done)); done.put(this, result); return result; } /** * @see at.iaik.suraq.smtlib.formula.Formula#makeArrayReadsSimple(at.iaik.suraq.smtlib.formula.Formula, * java.util.Set, java.util.Set) */ @Override public Formula makeArrayReadsSimple(Formula topLevelFormula, Set<Formula> constraints, Set<Token> noDependenceVars) { return NotFormula.create(formula.makeArrayReadsSimple(topLevelFormula, constraints, noDependenceVars)); } /** * @see at.iaik.suraq.smtlib.formula.Formula#uninterpretedPredicatesToAuxiliaryVariables(at.iaik.suraq.smtlib.formula.Formula, * java.util.Set, java.util.Set) */ /* * @Override public Formula uninterpretedPredicatesToAuxiliaryVariables( * Formula topLeveFormula, Set<Formula> constraints, Set<Token> * noDependenceVars) { return NotFormula.create( * formula.uninterpretedPredicatesToAuxiliaryVariables( topLeveFormula, * constraints, noDependenceVars)); } */ /** * Returns the elements assert-partition. * * @return assert-partition of the element. */ @Override public Set<Integer> getPartitionsFromSymbols() { return formula.getPartitionsFromSymbols(); } /** * @see at.iaik.suraq.smtlib.formula.Formula#transformToConsequentsForm() */ @Override public OrFormula transformToConsequentsForm() { return (OrFormula) transformToConsequentsForm(false, true); } /** * @see at.iaik.suraq.smtlib.formula.Formula#transformToConsequentsForm(boolean, * boolean) */ @Override public Formula transformToConsequentsForm(boolean notFlag, boolean firstLevel) { Formula notFormula; if (isValidChild(this.formula)) { notFormula = this.formula.transformToConsequentsForm(!notFlag, false); if (firstLevel == true) { if (Util.isLiteral(notFormula)) { List<Formula> literals = new ArrayList<Formula>(); literals.add(notFormula); Formula orFormula = OrFormula.generate(literals); return orFormula; } else if (notFormula instanceof OrFormula) { return notFormula; } else throw new RuntimeException( "Clausel should always be a Or Formula"); } return notFormula; } else throw new RuntimeException("Not formula has no valid child."); } /** * Checks if a given formula is a valid child for a NOT Formula. * * @param formula * formula to check * @return true, iff formula is valid */ public boolean isValidChild(Formula formula) { if (formula instanceof OrFormula) return true; if (formula instanceof AndFormula) return true; if (formula instanceof NotFormula) return true; if (formula instanceof ImpliesFormula) return true; if (Util.isLiteral(formula)) return true; return false; } /** * @see at.iaik.suraq.smtlib.formula.Formula#tseitinEncode(java.util.Map) */ @Override public PropositionalVariable tseitinEncode(List<OrFormula> clauses, Map<PropositionalVariable, Formula> encoding, Map<Formula, PropositionalVariable> done, int partition) { assert (clauses != null); assert (encoding != null); assert (done != null); if (done.get(this) != null) return done.get(this); // Set<Integer> partitions = this.getPartitionsFromSymbols(); // assert (partitions.size() == 1 || partitions.size() == 2); // if (partitions.size() == 2) // partitions.remove(-1); // assert (partitions.size() == 1); // assert (partitions.iterator().next().equals(partition) || partitions // .iterator().next().equals(-1)); PropositionalVariable tseitinVar = Util.freshTseitinVar(partition); encoding.put(tseitinVar, this); done.put(this, tseitinVar); Formula tseitinVarForSubformula = formula.tseitinEncode(clauses, encoding, done, partition); assert (Util.isLiteral(tseitinVarForSubformula)); List<Formula> disjuncts = new ArrayList<Formula>(2); disjuncts.add(tseitinVar); disjuncts.add(tseitinVarForSubformula); clauses.add(OrFormula.generate(disjuncts)); disjuncts.clear(); disjuncts.add(NotFormula.create(tseitinVar)); disjuncts.add(NotFormula.create(tseitinVarForSubformula)); clauses.add(OrFormula.generate(disjuncts)); done.put(this, tseitinVar); return tseitinVar; } /** * @see at.iaik.suraq.formula.Formula#uninterpretedPredicatesToAuxiliaryVariables(at.iaik.suraq.formula.Formula, * java.util.Map, java.util.Map) */ @Override public Formula uninterpretedPredicatesToAuxiliaryVariables( Formula topLeveFormula, Map<String, List<PropositionalVariable>> predicateInstances, Map<PropositionalVariable, List<DomainTerm>> instanceParameters, Set<Token> noDependenceVars) { Formula formula = this.formula; if (formula instanceof UninterpretedPredicateInstance) formula = ((UninterpretedPredicateInstance) formula) .applyReplaceUninterpretedPredicates(topLeveFormula, predicateInstances, instanceParameters, noDependenceVars); else formula = formula.uninterpretedPredicatesToAuxiliaryVariables( topLeveFormula, predicateInstances, instanceParameters, noDependenceVars); return NotFormula.create(formula); } /** * @see at.iaik.suraq.formula.Formula#uninterpretedFunctionsToAuxiliaryVariables(at.iaik.suraq.formula.Formula, * java.util.Map, java.util.Map) */ @Override public Formula uninterpretedFunctionsToAuxiliaryVariables( Formula topLeveFormula, Map<String, List<DomainVariable>> functionInstances, Map<DomainVariable, List<DomainTerm>> instanceParameters, Set<Token> noDependenceVars) { return NotFormula .create(formula.uninterpretedFunctionsToAuxiliaryVariables( topLeveFormula, functionInstances, instanceParameters, noDependenceVars)); } @Override public Formula replaceEquivalences(Formula topLeveFormula, Map<EqualityFormula, String> replacements, Set<Token> noDependenceVars) { return NotFormula.create(formula.replaceEquivalences(topLeveFormula, replacements, noDependenceVars)); } @Override public Formula removeDomainITE(Formula topLevelFormula, Set<Token> noDependenceVars, List<Formula> andPreList) { return NotFormula.create(formula.removeDomainITE(topLevelFormula, noDependenceVars, andPreList)); } /** * @see at.iaik.suraq.smtlib.formula.Formula#uninterpretedFunctionsBackToArrayReads(java.util.Set) */ @Override public Formula uninterpretedFunctionsBackToArrayReads( Set<ArrayVariable> arrayVars, Map<SMTLibObject, SMTLibObject> done) { if (done.get(this) != null) return (Formula) done.get(this); Formula result = NotFormula.create((Formula) formula .uninterpretedFunctionsBackToArrayReads(arrayVars, done)); done.put(this, result); return result; } /** * @see at.iaik.suraq.smtlib.formula.Formula#removeArrayITE(at.iaik.suraq.smtlib.formula.Formula, * java.util.Set, java.util.Collection) */ @Override public Formula removeArrayITE(Formula topLevelFormula, Set<Token> noDependenceVars, Collection<Formula> constraints) { return NotFormula.create(formula.removeArrayITE(topLevelFormula, noDependenceVars, constraints)); } /** * @see at.iaik.suraq.smtlib.formula.Formula#writeOut(java.io.BufferedWriter, * at.iaik.suraq.util.HashTagContainer, boolean) */ @Override public void writeOut(BufferedWriter writer, HashTagContainer tagContainer, boolean handleThisWithTagContainer) throws IOException { if (handleThisWithTagContainer) { tagContainer.handle(this, writer); } else { writer.append('(').append(SExpressionConstants.NOT.toString()); writer.append(' '); formula.writeOut(writer, tagContainer, true); writer.append(')'); } } /** * @see at.iaik.suraq.smtlib.formula.Formula#writeTo(java.io.Writer) */ @Override public void writeTo(Writer writer) throws IOException { writer.append('(').append(SExpressionConstants.NOT.toString()); writer.append(' '); formula.writeTo(writer); writer.append(')'); } /** * @see at.iaik.suraq.smtlib.formula.Formula#writeTo(java.io.Writer, * java.util.Map) */ @Override public void writeTo(Writer writer, Map<SMTLibObject, String> definitions) throws IOException { writer.append('(').append(SExpressionConstants.NOT.toString()); writer.append(' '); String id = definitions.get(formula); assert (id != null); writer.write(id); writer.append(')'); } /** * @see at.iaik.suraq.smtlib.formula.Formula#getLiterals(java.util.Set, * java.util.Set) */ @Override public void getLiterals(Set<Formula> result, Set<Formula> done) { if (done.contains(this)) return; formula.getLiterals(result, done); done.add(this); } /** * @see at.iaik.suraq.smtlib.formula.Formula#numAigNodes(java.util.Set) */ @Override public int numAigNodes(Set<Formula> done) { if (done.contains(this)) return 0; int result = formula.numAigNodes(done); done.add(this); return result; } /** * @see at.iaik.suraq.smtlib.formula.Formula#toAig(TreeMap, java.util.Map) */ @Override public int toAig(TreeMap<Integer, Integer[]> aigNodes, Map<Formula, Integer> done) { if (done.get(this) != null) return done.get(this); int result = formula.toAig(aigNodes, done); result ^= 1; done.put(this, result); return result; } /** * @see at.iaik.suraq.smtlib.formula.Formula#size(boolean, java.util.Map) */ @Override public BigInteger size(boolean expandDAG, Map<Formula, BigInteger> done) { if (done.get(this) != null) { if (expandDAG) return done.get(this); else return BigInteger.ZERO; } BigInteger result = BigInteger.ONE; result = result.add(formula.size(expandDAG, done)); done.put(this, result); return result; } /** * @see at.iaik.suraq.smtlib.formula.Formula#computeParents(java.util.Map, * java.util.Set) */ @Override public void computeParents(Map<Formula, Set<Formula>> parents, Set<Formula> done) { if (done.contains(this)) return; Set<Formula> childsParents = parents.get(formula); if (childsParents == null) { childsParents = new TreeSet<Formula>(); parents.put(formula, childsParents); } assert (childsParents != null); childsParents.add(this); formula.computeParents(parents, done); done.add(this); } /** * @see at.iaik.suraq.smtlib.formula.Formula#computeSubformulasWithOnlyLeafChildren(java.util.Set, * java.util.HashSet) */ @Override public void computeSubformulasWithOnlyLeafChildren( Set<Formula> onlyLeafChildren, Set<Formula> leaves, Set<Formula> done) { if (done.contains(this)) return; if (leaves.contains(this)) { done.add(this); return; } boolean result = true; if (!leaves.contains(formula)) result = false; formula.computeSubformulasWithOnlyLeafChildren(onlyLeafChildren, leaves, done); if (result) onlyLeafChildren.add(this); done.add(this); return; } /** * @see at.iaik.suraq.smtlib.formula.Formula#getTerms(java.util.Set, * java.util.Set) */ @Override public void getTerms(Set<Term> result, Set<Formula> done) { if (done.contains(this)) return; formula.getTerms(result, done); done.add(this); } /** * @see at.iaik.suraq.smtlib.formula.Formula#dependsOnlyOn(java.util.Set) */ @Override public boolean dependsOnlyOn(Set<Formula> formulaSet) { return formula.dependsOnlyOn(formulaSet); } }