/**
* Author: Georg Hofferek <georg.hofferek@iaik.tugraz.at>
*/
package at.iaik.suraq.proof;
import java.util.HashSet;
import java.util.Set;
import at.iaik.suraq.smtlib.TransformedZ3Proof;
import at.iaik.suraq.smtlib.Z3Proof;
import at.iaik.suraq.smtlib.formula.EqualityFormula;
import at.iaik.suraq.smtlib.formula.Formula;
import at.iaik.suraq.util.ImmutableSet;
import at.iaik.suraq.util.Util;
/**
*
*
* @author Georg Hofferek <georg.hofferek@iaik.tugraz.at>
*
*/
public final class AnnotatedProofNode {
private final int leftPartition;
private final int rightPartition;
private final TransformedZ3Proof consequent;
private final TransformedZ3Proof premise1;
private final TransformedZ3Proof premise2;
private final TransformedZ3Proof premise3;
private final AnnotatedProofNode annotatedPremise1;
private final AnnotatedProofNode annotatedPremise2;
private final AnnotatedProofNode annotatedPremise3;
private final int hash;
private final ImmutableSet<Formula> hypotheses;
/**
* Constructs a new <code>AnnotatedProofNode</code>. If one premise is
* <code>null</code>, all subsequent premises must be <code>null</code> too.
*
* @param leftPartition
* @param rightPartition
* @param consequent
* @param premise1
* @param premise2
* @param premise3
*/
public AnnotatedProofNode(int leftPartition, int rightPartition,
TransformedZ3Proof consequent, AnnotatedProofNode premise1,
AnnotatedProofNode premise2, AnnotatedProofNode premise3) {
super();
assert (leftPartition > 0);
assert (rightPartition > 0);
assert (consequent != null);
this.leftPartition = leftPartition;
this.rightPartition = rightPartition;
this.consequent = consequent;
assert ((premise1 == null && premise2 == null && premise3 == null) || (premise1 != null
&& premise2 != null && premise3 != null));
this.annotatedPremise1 = premise1;
this.annotatedPremise2 = premise2;
this.annotatedPremise3 = premise3;
this.premise1 = premise1 == null ? null : premise1.consequent;
this.premise2 = premise2 == null ? null : premise2.consequent;
this.premise3 = premise3 == null ? null : premise3.consequent;
if (numPremises() > 0) {
assert (this.premise1 != null);
assert (this.premise2 != null);
assert (this.premise3 != null);
Set<Formula> tmp = new HashSet<Formula>();
tmp.addAll(premise1.hypotheses);
tmp.addAll(premise2.hypotheses);
tmp.addAll(premise3.hypotheses);
hypotheses = ImmutableSet.create(tmp);
assert (Util.isLiteral(Util.getSingleLiteral(this.premise1
.getConsequent())));
assert (Util.isLiteral(Util.getSingleLiteral(this.premise2
.getConsequent())));
assert (Util.isLiteral(Util.getSingleLiteral(this.premise3
.getConsequent())));
Formula[] premises = {
Util.getSingleLiteral(this.premise1.getConsequent()),
Util.getSingleLiteral(this.premise2.getConsequent()),
Util.getSingleLiteral(this.premise3.getConsequent()) };
int numDisequalities = 0;
for (Formula premise : premises) {
if (Util.isNegativeLiteral(premise))
numDisequalities++;
}
assert (numDisequalities <= 1);
Object[] part1 = ((EqualityFormula) Util.makeLiteralPositive(Util
.getSingleLiteral((this.premise1.getConsequent()))))
.getTerms().toArray();
Object[] part2 = ((EqualityFormula) Util.makeLiteralPositive(Util
.getSingleLiteral((this.premise2.getConsequent()))))
.getTerms().toArray();
Object[] part3 = ((EqualityFormula) Util.makeLiteralPositive(Util
.getSingleLiteral((this.premise3.getConsequent()))))
.getTerms().toArray();
Object[] consequentTerms = ((EqualityFormula) Util
.makeLiteralPositive(Util.getSingleLiteral((this.consequent
.getConsequent())))).getTerms().toArray();
if (!consequentTerms[0].equals(part1[0]))
assert (false);
assert (consequentTerms[1].equals(part3[1]));
assert (part1[1].equals(part2[0]));
assert (part2[1].equals(part3[0]));
Set<Integer> premise1Partitions = this.premise1.getConsequent()
.getPartitionsFromSymbols();
Set<Integer> premise2Partitions = this.premise2.getConsequent()
.getPartitionsFromSymbols();
Set<Integer> premise3Partitions = this.premise3.getConsequent()
.getPartitionsFromSymbols();
Set<Integer> consequentPartitions = this.consequent.getConsequent()
.getPartitionsFromSymbols();
assert (premise1Partitions.size() == 1 || (premise1Partitions
.size() == 2 && premise1Partitions.contains(-1)));
assert (premise1Partitions.contains(this.leftPartition) || (premise1Partitions
.size() == 1 && premise1Partitions.contains(-1)));
assert (premise2Partitions.size() == 1 && premise2Partitions
.contains(-1));
assert (premise3Partitions.size() == 1 || (premise3Partitions
.size() == 2 && premise3Partitions.contains(-1)));
assert (premise3Partitions.contains(this.rightPartition) || (premise3Partitions
.size() == 1 && premise3Partitions.contains(-1)));
assert (consequentPartitions.size() <= 3);
assert (consequentPartitions.contains(leftPartition) || consequentPartitions
.contains(-1));
assert (consequentPartitions.contains(rightPartition) || consequentPartitions
.contains(-1));
} else { // numPremises() == 0
assert (numPremises() == 0);
assert (this.leftPartition == this.rightPartition);
hypotheses = consequent.getHypothesisFormulas();
consequent.setHasBeenMadeLocal();
}
this.hash = (premise1 == null ? 0 : premise1.hashCode())
^ (premise2 == null ? 0 : premise2.hashCode())
^ (premise3 == null ? 0 : premise3.hashCode())
^ consequent.hashCode()
^ (new Integer(leftPartition)).toString().hashCode()
^ (new Integer(rightPartition)).toString().hashCode()
^ hypotheses.hashCode();
}
/**
* Constructs a new <code>AnnotatedProofNode</code>.
*
* @param transformedZ3Proof
*/
public AnnotatedProofNode(TransformedZ3Proof transformedZ3Proof) {
this(Util.getSinglePartitionOfProof(transformedZ3Proof), Util
.getSinglePartitionOfProof(transformedZ3Proof),
transformedZ3Proof, null, null, null);
}
/**
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
return this.hash;
}
/**
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!(obj instanceof AnnotatedProofNode))
return false;
AnnotatedProofNode other = (AnnotatedProofNode) obj;
if (this.leftPartition != other.leftPartition)
return false;
if (this.rightPartition != other.rightPartition)
return false;
if (this.consequent != other.consequent)
return false;
if (this.premise1 != other.premise1)
return false;
if (this.premise2 != other.premise2)
return false;
if (this.premise3 != other.premise3)
return false;
return true;
}
/**
* @param consequent
* the consequent to compare
* @return <code>true</code> if the given consequent equals the one of this
* node
*/
public boolean hasConsequent(Formula consequent) {
return this.consequent.getConsequent().transformToConsequentsForm()
.equals(consequent.transformToConsequentsForm());
}
/**
* @param consequent
* the consequent to compare
* @return <code>true</code> if the given consequent equals the one of this
* node
*/
public boolean hasConsequent(Z3Proof consequent) {
return this.consequent.equals(consequent);
}
/**
* Returns the partition, if the left and the right partition are equal.
* Throws a <code>RuntimeException</code> if they are different.
*
* @return the partition of this node (left==right)
*/
public int getPartition() {
if (leftPartition != rightPartition)
throw new RuntimeException(
"Left and right partitions are not equal!");
return leftPartition;
}
/**
* @return the <code>leftPartition</code>
*/
public int getLeftPartition() {
return leftPartition;
}
/**
* @return the <code>rightPartition</code>
*/
public int getRightPartition() {
return rightPartition;
}
/**
* @return the <code>consequent</code>
*/
public TransformedZ3Proof getConsequent() {
return consequent;
}
/**
* @return the <code>premise1</code>
*/
public TransformedZ3Proof getPremise1() {
return premise1;
}
/**
* @return the <code>premise2</code>
*/
public TransformedZ3Proof getPremise2() {
return premise2;
}
/**
* @return the <code>premise3</code>
*/
public TransformedZ3Proof getPremise3() {
return premise3;
}
/**
* Returns the number of (non-<code>null</code>) premises. Relies on the
* fact that if one premise is <code>null</code>, all subsequent premises
* must be <code>null</code> too.
*
* @return the number of non-<code>null</code> premises.
*/
public int numPremises() {
if (premise1 == null)
return 0;
else if (premise2 == null)
return 1;
else if (premise3 == null)
return 2;
else
return 3;
}
/**
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append("Partitions: ");
buffer.append(leftPartition);
buffer.append(", ");
buffer.append(rightPartition);
buffer.append("\n");
buffer.append("Premise 1: ");
buffer.append(premise1 == null ? "null" : premise1.getConsequent()
.toString().replaceAll("\\s{2,}", " ").replace("\n", ""));
buffer.append("\n");
buffer.append("Premise 2: ");
buffer.append(premise2 == null ? "null" : premise2.getConsequent()
.toString().replaceAll("\\s{2,}", " ").replace("\n", ""));
buffer.append("\n");
buffer.append("Premise 3: ");
buffer.append(premise3 == null ? "null" : premise3.getConsequent()
.toString().replaceAll("\\s{2,}", " ").replace("\n", ""));
buffer.append("\n");
buffer.append("Consequent: ");
buffer.append(consequent == null ? "null" : consequent.getConsequent()
.toString().replaceAll("\\s{2,}", " ").replace("\n", ""));
buffer.append("\n");
return buffer.toString();
}
/**
* @return the <code>hypotheses</code> (copy)
*/
public ImmutableSet<Formula> getHypotheses() {
return hypotheses;
}
/**
* @return the <code>annotatedPremise1</code>
*/
public AnnotatedProofNode getAnnotatedPremise1() {
return annotatedPremise1;
}
/**
* @return the <code>annotatedPremise2</code>
*/
public AnnotatedProofNode getAnnotatedPremise2() {
return annotatedPremise2;
}
/**
* @return the <code>annotatedPremise3</code>
*/
public AnnotatedProofNode getAnnotatedPremise3() {
return annotatedPremise3;
}
}