/** * Author: Georg Hofferek <georg.hofferek@iaik.tugraz.at> */ package at.iaik.suraq.smtlib.formula; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import at.iaik.suraq.sexp.SExpressionConstants; import at.iaik.suraq.sexp.Token; import at.iaik.suraq.util.FormulaCache; import at.iaik.suraq.util.Util; /** * * A formula that is a conjunction of other formulas. * * @author Georg Hofferek <georg.hofferek@iaik.tugraz.at> * */ public class AndFormula extends AndOrXorFormula { /** * */ private static final long serialVersionUID = 870670778366136999L; /** * * Constructs a new <code>AndFormula</code>, consisting of the conjunction * of the given formulas. * * @param formulas * the formulas to conjunct. */ public AndFormula(List<? extends Formula> formulas) { super(formulas); } public static AndFormula generate(List<? extends Formula> formulas) { // return FormulaCache.andFormula.put(new AndFormula(formulas)); return (AndFormula) FormulaCache.andOrXorFormula.put(new AndFormula( formulas)); } /** * Returns a collection of the conjuncted formulas. * * @return a collection of the conjuncted formulas. (Copy) */ public List<Formula> getConjuncts() { return new ArrayList<Formula>(formulas); } /** * @see at.iaik.suraq.smtlib.formula.Formula#simplify() */ @Override public Formula simplify() { Set<PropositionalVariable> negativeVars = new HashSet<PropositionalVariable>(); Set<PropositionalVariable> positiveVars = new HashSet<PropositionalVariable>(); ArrayList<Formula> formulas = new ArrayList<Formula>(this.formulas); for (int count = 0; count < formulas.size(); count++) { Formula formula = formulas.get(count).simplify(); formulas.set(count, formula); if (formula instanceof PropositionalConstant) { if (!((PropositionalConstant) formula).getValue()) { return PropositionalConstant.create(false); } else formulas.remove(formula); } if (formula instanceof NotFormula) { if (((NotFormula) formula).isNegatedConstant() != null) { if (((NotFormula) formula).isNegatedConstant().getValue()) return PropositionalConstant.create(false); } PropositionalVariable var = ((NotFormula) formula) .isNegatedVariable(); if (var != null) { if (positiveVars.contains(var)) return PropositionalConstant.create(false); negativeVars.add(var); } if (formulas.contains(((NotFormula) formula) .getNegatedFormula())) return PropositionalConstant.create(false); } if (formula instanceof PropositionalVariable) { if (negativeVars.contains(formula)) return PropositionalConstant.create(false); positiveVars.add((PropositionalVariable) formula); } } // No simplifications found return create(formulas); } /** * @see at.iaik.suraq.smtlib.formula.AndOrXorFormula#getOperator() */ @Override protected Token getOperator() { return SExpressionConstants.AND; } /** * @see at.iaik.suraq.smtlib.formula.Formula#transformToConsequentsForm() */ @Override public OrFormula transformToConsequentsForm() { return (OrFormula) transformToConsequentsForm(false, true); } /** * @see at.iaik.suraq.smtlib.formula.Formula#transformFormulaToConsequentsFormula(at.iaik.suraq.smtlib.formula.Formula, * boolean, boolean) */ @Override public Formula transformToConsequentsForm(boolean notFlag, boolean firstLevel) { if (notFlag == false) throw new RuntimeException( "an AND Formula is only allowed to occur inside an NOT formula.\n So notFlag has to be true"); // apply deMorgan rule: NOT (a AND b) <=> NOT a OR NOT b List<Formula> subFormulas = new ArrayList<Formula>(); for (Formula subFormula : this.formulas) { if (isValidChild(subFormula)) { if (subFormula instanceof AndFormula) { // remove nested AND Formula ArrayList<Formula> conjuncts = (ArrayList<Formula>) ((AndFormula) subFormula) .getConjuncts(); for (Formula conjunct : conjuncts) { Formula transformedSubFormula = conjunct .transformToConsequentsForm(notFlag, false); subFormulas.add(transformedSubFormula); } } else { Formula transformedSubFormula = subFormula .transformToConsequentsForm(notFlag, false); subFormulas.add(transformedSubFormula); } } else throw new RuntimeException( "Unexpected Chid: Child of an AND Formula can either be an AND Formula, NOT Formula or a Literal"); } return OrFormula.generate(subFormulas); } /** * Checks if a given Formula is a literal, or an AND Formula or a NOT * formula. * * @param formula * formula to check * @return true, iff formula is valid */ public boolean isValidChild(Formula formula) { if (formula instanceof AndFormula) return true; if (formula instanceof NotFormula) 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); List<Formula> disjuncts = new ArrayList<Formula>(formulas.size() + 1); for (Formula formula : formulas) { Formula currentTseitinVar = formula.tseitinEncode(clauses, encoding, done, partition); assert (Util.isLiteral(currentTseitinVar)); disjuncts.add(NotFormula.create(currentTseitinVar)); List<Formula> tmp = new ArrayList<Formula>(2); tmp.add(NotFormula.create(tseitinVar)); tmp.add(currentTseitinVar); clauses.add(OrFormula.generate(tmp)); } disjuncts.add(tseitinVar); clauses.add(OrFormula.generate(disjuncts)); done.put(this, tseitinVar); return tseitinVar; } /** * @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 = 0; for (Formula formula : formulas) result += formula.numAigNodes(done); result += formulas.size() - 1; done.add(this); return result; } /** * @see at.iaik.suraq.smtlib.formula.Formula#toAig(java.util.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); assert (formulas.size() > 0); if (formulas.size() == 1) return formulas.get(0).toAig(aigNodes, done); Integer[] intermediateNode = { formulas.get(0).toAig(aigNodes, done), formulas.get(1).toAig(aigNodes, done) }; int intermediate = Util.nextFreePositiveAigLiteral(aigNodes, done); aigNodes.put(intermediate, intermediateNode); for (int count = 2; count < formulas.size(); count++) { Integer[] currentNode = { intermediate, formulas.get(count).toAig(aigNodes, done) }; int current = Util.nextFreePositiveAigLiteral(aigNodes, done); aigNodes.put(current, currentNode); intermediate = current; } done.put(this, intermediate); return intermediate; } }