/**
* 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 disjunction of other formulas.
*
* @author Georg Hofferek <georg.hofferek@iaik.tugraz.at>
*
*/
public class OrFormula extends AndOrXorFormula {
/**
*
*/
private static final long serialVersionUID = -1803216846463035758L;
/**
*
* Constructs a new <code>OrFormula</code>, consisting of the disjunction of
* the given formulas.
*
* @param formulas
* the formulas to disjunct.
*/
public OrFormula(List<Formula> formulas) {
super(formulas);
}
public static OrFormula generate(List<Formula> formulas) {
// return FormulaCache.orFormula.put(new OrFormula(formulas));
return (OrFormula) FormulaCache.andOrXorFormula.put(new OrFormula(
formulas));
}
/**
* Returns a collection of the disjuncted formulas.
*
* @return a collection of the disjuncted formulas. (Copy)
*/
public List<Formula> getDisjuncts() {
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(true);
} else
formulas.remove(formula);
}
if (formula instanceof NotFormula) {
if (((NotFormula) formula).isNegatedConstant() != null) {
if (!((NotFormula) formula).isNegatedConstant().getValue())
return PropositionalConstant.create(true);
}
PropositionalVariable var = ((NotFormula) formula)
.isNegatedVariable();
if (var != null) {
if (positiveVars.contains(var))
return PropositionalConstant.create(true);
negativeVars.add(var);
}
if (formulas.contains(((NotFormula) formula)
.getNegatedFormula()))
return PropositionalConstant.create(true);
}
if (formula instanceof PropositionalVariable) {
if (negativeVars.contains(formula))
return PropositionalConstant.create(true);
positiveVars.add((PropositionalVariable) formula);
}
}
// No simplifications found
return create(formulas);
}
/**
* @see at.iaik.suraq.smtlib.formula.AndOrXorFormula#getOperator()
*/
@Override
protected Token getOperator() {
return SExpressionConstants.OR;
}
/**
* @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) {
// Special case: not(or(Literal)) --> or(not(literal)
if ((notFlag == true) && (this.formulas.size() != 1))
throw new RuntimeException(
"an Or Formula is not allowed to occur inside an NOT formula.\n So notFlag has to be false");
List<Formula> subFormulas = new ArrayList<Formula>();
for (Formula subFormula : this.formulas) {
if (isValidChild(subFormula)) {
if (subFormula instanceof OrFormula) {
// remove nested OR Formula
ArrayList<Formula> disjuncts = (ArrayList<Formula>) ((OrFormula) subFormula)
.getDisjuncts();
for (Formula disjunct : disjuncts) {
Formula transformedSubFormula = disjunct
.transformToConsequentsForm(notFlag, false);
if (!subFormulas.contains(transformedSubFormula))
subFormulas.add(transformedSubFormula);
}
} else {
Formula transformedSubFormula = subFormula
.transformToConsequentsForm(notFlag, false);
if (!subFormulas.contains(transformedSubFormula))
subFormulas.add(transformedSubFormula);
}
} else
throw new RuntimeException(
"Unexpected Chid: Child of an OR Formula is not valid");
}
Formula orFormula = OrFormula.generate(subFormulas);
return orFormula;
}
/**
* Checks if a given formula is a valid child of a OR 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 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.List,
* 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);
List<Formula> disjuncts = new ArrayList<Formula>(formulas.size() + 1);
encoding.put(tseitinVar, this.deepFormulaCopy());
done.put(this, tseitinVar);
for (Formula formula : formulas) {
Formula currentTseitinVar = formula.tseitinEncode(clauses,
encoding, done, partition);
assert (Util.isLiteral(currentTseitinVar));
disjuncts.add(currentTseitinVar);
List<Formula> tmp = new ArrayList<Formula>(2);
tmp.add(NotFormula.create(currentTseitinVar));
tmp.add(tseitinVar);
clauses.add(OrFormula.generate(tmp));
}
disjuncts.add(NotFormula.create(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) ^ 1,
formulas.get(1).toAig(aigNodes, done) ^ 1 };
int intermediate = Util.nextFreePositiveAigLiteral(aigNodes, done);
aigNodes.put(intermediate, intermediateNode);
for (int count = 2; count < formulas.size(); count++) {
Integer[] currentNode = { intermediate ^ 1,
formulas.get(count).toAig(aigNodes, done) ^ 1 };
int current = Util.nextFreePositiveAigLiteral(aigNodes, done);
aigNodes.put(current, currentNode);
intermediate = current;
}
intermediate ^= 1;
done.put(this, intermediate);
return intermediate;
}
}