/**
* 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.lang.reflect.Constructor;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
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.ImmutableArrayList;
/**
* A common superclass for And- Or- and Xor-formulas to avoid code redundancy.
*
* @author Georg Hofferek <georg.hofferek@iaik.tugraz.at>
*
*/
public abstract class AndOrXorFormula extends BooleanCombinationFormula {
/**
*
*/
private static final long serialVersionUID = 3515032983832421411L;
/**
* The list of sub-formulas.
*/
protected final ImmutableArrayList<Formula> formulas;
private final int hashCode;
/**
*
* Constructs a new <code>AndOrXorFormula</code>. Initializes the list of
* subformulas.
*
* @param formulas
* the list of subformulas.
*/
protected AndOrXorFormula(List<? extends Formula> formulas) {
ArrayList<Formula> tmp = new ArrayList<Formula>();
for (Formula formula : formulas) {
if (formula instanceof FormulaTerm)
tmp.add(((FormulaTerm) formula).getFormula());
else
tmp.add(formula);
}
if (formulas.size() < 1)
tmp.add(PropositionalConstant.create(true));
this.formulas = new ImmutableArrayList<Formula>(tmp);
this.hashCode = formulas.hashCode();
}
/**
* Creates a new <code>AndOrXorFormula</code> which is of the same type as
* <code>this</code> object and has the given subformulas.
*
* @param formulas
* the subformulas
* @return a new <code>AndOrXorFormula</code> with the same type as
* <code>this</code>.
*/
protected AndOrXorFormula create(List<? extends Formula> formulas) {
Class<? extends AndOrXorFormula> myClass = this.getClass();
// Class<?> listClass = formulas.getClass();
AndOrXorFormula instance = null;
try {
Constructor<?>[] constructors = myClass.getDeclaredConstructors();
if (constructors.length == 0)
throw new RuntimeException("No constructors found.");
for (Constructor<?> constructor : constructors) {
Class<?>[] parameters = constructor.getParameterTypes();
if (parameters.length != 1)
continue;
if (!(parameters[0].isInstance(formulas)))
continue;
instance = (AndOrXorFormula) constructor.newInstance(formulas);
}
if (instance == null)
throw new RuntimeException();
return FormulaCache.andOrXorFormula.put(instance);
// return instance;
} catch (Throwable exc) {
exc.printStackTrace();
throw new RuntimeException("Unable to create AndOrXorFormula", exc);
}
// TODO: cache!!!
}
/**
* @see at.iaik.suraq.smtlib.formula.Formula#getArrayVariables()
*/
@Override
public void getArrayVariables(Set<ArrayVariable> result,
Set<SMTLibObject> done) {
if (done.contains(this))
return;
for (Formula formula : formulas)
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;
for (Formula formula : formulas)
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;
for (Formula formula : formulas)
formula.getPropositionalVariables(result, done);
done.add(this);
}
/**
* @see at.iaik.suraq.smtlib.formula.BooleanCombinationFormula#getSubFormulas()
*/
@Override
public Collection<Formula> getSubFormulas() {
return new ArrayList<Formula>(formulas);
}
/**
* @see at.iaik.suraq.smtlib.formula.Formula#deepFormulaCopy()
*/
@Override
public Formula deepFormulaCopy() {
return this; // experimental
/*
* List<Formula> subformulas = new ArrayList<Formula>(); for (Formula
* formula : formulas) { if (formula == null)
* System.out.println(formula);
*
* subformulas.add(formula.deepFormulaCopy()); } return
* create(subformulas);
*/
}
/**
* @see at.iaik.suraq.smtlib.formula.Formula#negationNormalForm()
*/
@Override
public Formula negationNormalForm() throws SuraqException {
List<Formula> nnfFormulas = new ArrayList<Formula>();
for (Formula formula : formulas)
nnfFormulas.add(formula.negationNormalForm());
return create(nnfFormulas);
}
/**
* @see at.iaik.suraq.smtlib.formula.Formula#getUninterpretedFunctionNames()
*/
@Override
public void getUninterpretedFunctionNames(Set<String> result,
Set<SMTLibObject> done) {
if (done.contains(this))
return;
for (Formula formula : formulas)
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;
for (Formula formula : formulas)
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;
for (Formula formula : formulas)
formula.getFunctionMacros(result, done);
done.add(this);
}
/**
* @see at.iaik.suraq.smtlib.formula.Formula#getIndexSet()
*/
@Override
public Set<DomainTerm> getIndexSet() throws SuraqException {
Set<DomainTerm> indexSet = new HashSet<DomainTerm>();
for (Formula formula : formulas)
indexSet.addAll(formula.getIndexSet());
return indexSet;
}
/**
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (this.hashCode() != obj.hashCode())
return false;
if (!(this.getClass().isInstance(obj)))
return false;
return this.formulas.equals(((AndOrXorFormula) obj).formulas);
}
/**
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
/*
* int hashCode = 0; for (Formula formula : formulas) hashCode ^=
* formula.hashCode();
*/
return this.hashCode;
// NOTE, that the hashcode will be the same for an AND and an OR-Class
// with the same attributes
}
/**
* @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);
}
List<Formula> convertedFormulas = new ArrayList<Formula>();
for (Formula formula : formulas)
convertedFormulas.add(formula.substituteFormula(paramMap, done));
Formula result = create(convertedFormulas);
assert (result != null);
done.put(this, result);
return result;
}
/**
* @see at.iaik.suraq.smtlib.formula.Formula#removeArrayEqualitiesTerm()
*/
@Override
public Formula removeArrayEqualities() {
List<Formula> children = new ArrayList<Formula>();
for (int count = 0; count < formulas.size(); count++) {
if (formulas.get(count) instanceof ArrayEq)
children.add(((ArrayEq) formulas.get(count))
.toArrayProperties());
else
children.add(formulas.get(count).removeArrayEqualities());
}
return create(children);
}
/**
* @see at.iaik.suraq.smtlib.formula.Formula#arrayPropertiesToFiniteConjunctions(java.util.Set)
*/
@Override
public Formula arrayPropertiesToFiniteConjunctions(Set<DomainTerm> indexSet) {
List<Formula> children = new ArrayList<Formula>();
for (int count = 0; count < formulas.size(); count++) {
if (formulas.get(count) instanceof ArrayProperty)
children.add(((ArrayProperty) formulas.get(count))
.toFiniteConjunction(indexSet));
else
children.add(formulas.get(count)
.arrayPropertiesToFiniteConjunctions(indexSet));
}
return create(children);
}
/**
* @see at.iaik.suraq.smtlib.formula.Formula#simplify()
*/
@Override
public Formula simplify() {
List<Formula> children = new ArrayList<Formula>();
// Default, unless a subclass has more clever method
for (int count = 0; count < formulas.size(); count++)
children.add(formulas.get(count).simplify());
return create(children);
}
/**
* @see at.iaik.suraq.smtlib.formula.Formula#flatten()
*/
@Override
public Formula flatten() {
List<Formula> flattenedFormulas = new ArrayList<Formula>();
for (Formula formula : formulas)
flattenedFormulas.add(formula.flatten());
return create(flattenedFormulas);
}
/**
* @see at.iaik.suraq.smtlib.formula.Formula#toSmtlibV2()
*/
@Override
public SExpression toSmtlibV2() {
List<SExpression> children = new ArrayList<SExpression>();
children.add(this.getOperator());
for (Formula formula : formulas)
children.add(formula.toSmtlibV2());
return new SExpression(children);
}
/**
* Returns the token representing the operator (and/or/xor) of this formula.
*
* @return The operator token.
*/
protected abstract Token getOperator();
/**
* @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) {
List<Formula> children = new ArrayList<Formula>();
for (Formula formula : this.getSubFormulas())
children.add(formula.removeArrayWrites(topLevelFormula,
constraints, noDependenceVars));
return create(children);
}
/**
* @see at.iaik.suraq.smtlib.formula.Formula#arrayReadsToUninterpretedFunctions()
*/
@Override
public Formula arrayReadsToUninterpretedFunctions(
Set<Token> noDependenceVars) {
List<Formula> children = new ArrayList<Formula>();
for (Formula formula : formulas)
children.add(formula
.arrayReadsToUninterpretedFunctions(noDependenceVars));
return create(children);
}
/**
* @see at.iaik.suraq.smtlib.formula.Formula#getUninterpretedFunctions()
*/
@Override
public void getUninterpretedFunctions(Set<UninterpretedFunction> result,
Set<SMTLibObject> done) {
if (done.contains(this))
return;
for (Formula formula : formulas)
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);
}
List<Formula> children = new ArrayList<Formula>();
for (Formula formula : formulas)
children.add(formula.substituteUninterpretedFunction(substitutions,
done));
Formula result = create(children);
done.put(this, result);
return result;
}
/**
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return this.toSmtlibV2().toString();
}
/**
* @see at.iaik.suraq.smtlib.formula.Formula#makeArrayReadsSimple(Formula,
* java.util.Set, Set)
*/
@Override
public Formula makeArrayReadsSimple(Formula topLevelFormula,
Set<Formula> constraints, Set<Token> noDependenceVars) {
List<Formula> children = new ArrayList<Formula>();
for (Formula formula : formulas)
children.add(formula.makeArrayReadsSimple(topLevelFormula,
constraints, noDependenceVars));
return create(children);
}
/**
* @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) { List<Formula> newFormulas = new ArrayList<Formula>();
* for (Formula formula : formulas) newFormulas.add(formula
* .uninterpretedPredicatesToAuxiliaryVariables( topLeveFormula,
* constraints, noDependenceVars));
*
* return this.create(newFormulas); }
*/
/**
* Returns the elements assert-partition.
*
* @return assert-partition of the element.
*/
@Override
public Set<Integer> getPartitionsFromSymbols() {
Set<Integer> partitions = new TreeSet<Integer>();
for (Formula formula : formulas)
partitions.addAll(formula.getPartitionsFromSymbols());
return partitions;
}
/**
* @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) {
List<Formula> children = new ArrayList<Formula>();
Collection<Formula> subformulas = this.getSubFormulas();
for (Formula formula : subformulas)
if (formula instanceof UninterpretedPredicateInstance) {
Formula auxVar = ((UninterpretedPredicateInstance) formula)
.applyReplaceUninterpretedPredicates(topLeveFormula,
predicateInstances, instanceParameters,
noDependenceVars);
// added by chille: 03.07.2012
children.add(auxVar);
// removed by chille:
// formulas.remove(formula);
// formulas.add(auxVar);
} else
children.add(formula
.uninterpretedPredicatesToAuxiliaryVariables(
topLeveFormula, predicateInstances,
instanceParameters, noDependenceVars));
return create(children);
}
/**
* @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) {
List<Formula> children = new ArrayList<Formula>();
for (Formula formula : this.getSubFormulas())
children.add(formula.uninterpretedFunctionsToAuxiliaryVariables(
topLeveFormula, functionInstances, instanceParameters,
noDependenceVars));
return create(children);
}
@Override
public Formula replaceEquivalences(Formula topLevelFormula,
Map<EqualityFormula, String> replacements,
Set<Token> noDependenceVars) {
List<Formula> children = new ArrayList<Formula>();
for (int i = 0; i < formulas.size(); i++)
children.add(formulas.get(i).replaceEquivalences(topLevelFormula,
replacements, noDependenceVars));
return create(children);
}
@Override
public Formula removeDomainITE(Formula topLevelFormula,
Set<Token> noDependenceVars, List<Formula> andPreList) {
List<Formula> children = new ArrayList<Formula>();
for (int i = 0; i < formulas.size(); i++)
children.add(formulas.get(i).removeDomainITE(topLevelFormula,
noDependenceVars, andPreList));
return create(children);
}
/**
* @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);
List<Formula> newFormulas = new ArrayList<Formula>(formulas.size());
for (Formula formula : formulas) {
Formula newFormula = (Formula) formula
.uninterpretedFunctionsBackToArrayReads(arrayVars, done);
newFormulas.add(newFormula);
}
Formula result = this.create(newFormulas);
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 AndOrXorFormula removeArrayITE(Formula topLevelFormula,
Set<Token> noDependenceVars, Collection<Formula> constraints) {
List<Formula> newSubformulas = new ArrayList<Formula>(formulas.size());
for (Formula subformula : formulas) {
newSubformulas.add(subformula.removeArrayITE(topLevelFormula,
noDependenceVars, constraints));
}
return this.create(newSubformulas);
}
/**
* @throws IOException
* @see at.iaik.suraq.smtlib.formula.Formula#writeOut(java.io.BufferedWriter,
* java.util.Map, java.util.Map)
*/
@Override
public void writeOut(BufferedWriter writer, HashTagContainer tagContainer,
boolean handleThisWithTagContainer) throws IOException {
if (handleThisWithTagContainer)
tagContainer.handle(this, writer);
else {
writer.append('(');
if (this instanceof AndFormula)
writer.append(SExpressionConstants.AND.toString());
else {
if (this instanceof OrFormula)
writer.append(SExpressionConstants.OR.toString());
else {
if (this instanceof XorFormula)
writer.append(SExpressionConstants.XOR.toString());
else {
throw new RuntimeException("Unexpected formula type.");
}
}
}
writer.append(' ');
for (Formula subformula : formulas) {
subformula.writeOut(writer, tagContainer, true);
}
writer.append(") ");
}
}
/**
* @throws IOException
* @see at.iaik.suraq.smtlib.formula.Formula#writeTo(java.io.Writer)
*/
@Override
public void writeTo(Writer writer) throws IOException {
writer.append('(');
if (this instanceof AndFormula)
writer.append(SExpressionConstants.AND.toString());
else {
if (this instanceof OrFormula)
writer.append(SExpressionConstants.OR.toString());
else {
if (this instanceof XorFormula)
writer.append(SExpressionConstants.XOR.toString());
else {
throw new RuntimeException("Unexpected formula type.");
}
}
}
for (Formula subformula : formulas) {
writer.append(' ');
subformula.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('(');
if (this instanceof AndFormula)
writer.append(SExpressionConstants.AND.toString());
else {
if (this instanceof OrFormula)
writer.append(SExpressionConstants.OR.toString());
else {
if (this instanceof XorFormula)
writer.append(SExpressionConstants.XOR.toString());
else {
throw new RuntimeException("Unexpected formula type.");
}
}
}
for (Formula subformula : formulas) {
writer.append(' ');
String id = definitions.get(subformula);
assert (id != null);
writer.append(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;
for (Formula subformula : formulas)
subformula.getLiterals(result, done);
done.add(this);
}
/**
* @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;
for (Formula formula : formulas)
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;
for (Formula child : formulas) {
Set<Formula> childsParents = parents.get(child);
if (childsParents == null) {
childsParents = new TreeSet<Formula>();
parents.put(child, childsParents);
}
assert (childsParents != null);
childsParents.add(this);
child.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;
for (Formula formula : formulas) {
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;
for (Formula formula : formulas)
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) {
if (formulaSet.containsAll(formulas))
return true;
return false;
}
}