/**
* Author: Ashutosh Gupta <agupta@ist.ac.at>
*/
package at.iaik.suraq.resProof;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
public class ResNode implements Comparable<ResNode> {
/**
* The id of this node.
*/
public final int id;
/**
* The clause of this node
*/
private Clause clause;
/**
* The pivot of this resolution step, or 0 if this is a leaf.
*/
private int pivot = 0;
/**
* The partition of this node.
*/
private int part = 0;
/**
* The left child. Contains the pivot in positive polarity.
*/
private ResNode left = null;
/**
* The right child. Contains the pivot in negative polarity.
*/
private ResNode right = null;
/**
* This used to be called "children". Working hypothesis is that it actually
* means parents.
*/
public final Set<ResNode> parents = new TreeSet<ResNode>();
/**
*
* Constructs a new <code>ResNode</code>.
*
* @param id
*/
public ResNode(int id) {
// if (id == 1991555)
// assert (id == 1991555);
this.id = id;
this.clause = new Clause();
}
/**
*
* Constructs a new <code>ResNode</code>.
*
* @param id
* @param clause
* @param left
* @param right
* @param pivot
* @param part
*/
public ResNode(int id, Clause clause, ResNode left, ResNode right,
int pivot, int part) {
// if (id == 1991555)
// assert (id == 1991555);
this.id = id;
this.part = part;
if (left == null && right == null) {
assert (clause != null);
this.clause = new Clause(clause);
return;
}
assert (left != null && right != null); // "At least a parent is missing!",
boolean isLeftPos = true;
if (pivot == 0) {
Iterator<Literal> itr = left.clause.iterator();
while (itr.hasNext()) {
Literal lit = itr.next();
if (right.clause.contains(lit.negate())) {
pivot = lit.id();
isLeftPos = lit.isPos();
break;
}
}
assert (pivot != 0); // "pivot not found!",
} else {
if (left.clause.contains(pivot, true)
&& right.clause.contains(pivot, false)) {
isLeftPos = true;
} else if (right.clause.contains(pivot, true)
&& left.clause.contains(pivot, false)) {
isLeftPos = false;
} else {
assert (false);// "Parents do not contain literals of pivot!",
}
}
this.pivot = pivot;
if (isLeftPos) {
this.left = left;
this.right = right;
} else {
this.left = right;
this.right = left;
}
if (clause == null) {
this.clause = new Clause(this.left.clause, this.right.clause,
this.pivot);
} else {
// check if clause is result of the resolution!
assert (!clause.contains(pivot, true));
assert (!clause.contains(pivot, false));
for (Literal lit : this.left.clause) {
if (lit.id() != pivot)
assert (clause.contains(lit));
}
for (Literal lit : this.right.clause) {
if (lit.id() != pivot)
assert (clause.contains(lit));
}
for (Literal lit : clause) {
assert (this.left.clause.contains(lit) || this.right.clause
.contains(lit));
}
this.clause = new Clause(clause);
}
this.left.addParent(this);
this.right.addParent(this);
}
/**
* Not sure what this does exactly. Seems to remove unreachable nodes.
*/
public void cleanUp() {
if (!isLeaf() && parents.isEmpty()) {
ResNode oldLeft = this.left;
this.left = null;
ResNode oldRight = this.right;
this.right = null;
oldLeft.removeParent(this);
oldLeft.cleanUp();
if (oldLeft != oldRight) {
oldRight.removeParent(this);
oldRight.cleanUp();
}
// clause.clear();
// this is ready for garbage collection.
}
}
/**
* Removes the given node from the set of parents.
*
* @param node
*/
public void removeParent(ResNode node) {
assert (node.left != this && node.right != this);
assert (parents.contains(node));// "Removing non-existent child",
parents.remove(node);
}
/**
* Removes the given node from the set of parents and performs clean up.
*
* @param n
*/
public void rmParentWithCleanUp(ResNode n) {
removeParent(n);
cleanUp();
}
/**
* Adds the given node to the set of parents.
*
* @param n
*/
public void addParent(ResNode n) {
parents.add(n);
}
/**
* Converts this node into a leaf of the given partition.
*
* @param part
*/
public void convertToLeaf(int part) {
this.part = part;
ResNode oldLeft = this.left;
ResNode oldRight = this.right;
this.left = null;
this.right = null;
oldLeft.rmParentWithCleanUp(this);
oldRight.rmParentWithCleanUp(this);
this.pivot = 0;
}
/**
* Fails if this is not a leaf and none of the children has lit.
*
* @param lit
* @return -1 if move is disallowed, 1 if both children have lit, 2 if left
* child has lit, 3 if right child has lit.
*/
public int checkMovable(Literal lit) {
if (isLeaf() || part != -1)
return -1; // move disallowed
boolean ll = left.clause.contains(lit);
boolean lr = right.clause.contains(lit);
if (ll && lr)
return 1; // both children have lit
if (ll)
return 2; // left child has lit
if (lr)
return 3; // right children has lit
assert (false);// "lit is not in any child",
return 0;
}
/**
* Moves a grandchild to a child position.
*
* @param leftChild
* if <code>true</code> take left child
* @param leftGrandChild
* if <code>take</code> left child of child specified by
* <code>leftChild</code>
*/
public void moveChild(boolean leftChild, boolean leftGrandChild) {
ResNode looser = null;
ResNode gainer = null;
if (leftChild)
looser = left;
else
looser = right;
assert (looser != null);
if (leftGrandChild)
gainer = looser.left;
else
gainer = looser.right;
assert (gainer != null);
if (leftChild)
left = gainer;
else
right = gainer;
gainer.addParent(this);
looser.rmParentWithCleanUp(this);
}
/**
* Moves the parents of this node to one of its children.
*
* @param toLeftChild
* if <code>true</code> move parents to left child.
*/
public void moveParents(boolean toLeftChild) {
ResNode gainer = null;
if (toLeftChild)
gainer = left;
else
gainer = right;
assert (gainer != null);
Iterator<ResNode> itr = parents.iterator();
while (itr.hasNext()) {
ResNode parent = itr.next();
assert (parent.left == this || parent.right == this);
if (parent.left == this)
parent.left = gainer;
else
parent.right = gainer;
gainer.addParent(parent);
}
parents.clear();
cleanUp();
}
/**
* Checks whether this node has become obsolete, and if not recomputes its
* clause.
*
* @return <code>true</code> iff this node is still alive.
*/
public boolean refresh() {
if (!left.clause.contains(pivot, true)) {
moveParents(true);
return false; // Node is dead
}
if (!right.clause.contains(pivot, false)) {
moveParents(false);
return false; // Node is dead
}
clause = new Clause(left.clause, right.clause, pivot);
return true; // Node is still valid
}
/**
*
* @return the clause of this node
*/
public Clause getClause() {
return clause;
}
/**
* @return the <code>pivot</code>
*/
public int getPivot() {
return pivot;
}
/**
* @param <code>pivot</code> the new value for <code>pivot</code>
*/
public void setPivot(int pivot) {
this.pivot = pivot;
}
/**
* @return the <code>part</code>
*/
public int getPart() {
return part;
}
/**
* @param <code>part</code> the new value for <code>part</code>
*/
public void setPart(int part) {
this.part = part;
}
/**
* @return the <code>left</code> child. Contains the pivot in positive
* polarity.
*/
public ResNode getLeft() {
return left;
}
/**
* @param <code>left</code> the new value for <code>left</code>
*/
public void setLeft(ResNode left) {
assert (left != null);
this.left = left;
}
/**
* @return the <code>right</code> child. Contains the pivot in negative
* polarity.
*/
public ResNode getRight() {
return right;
}
/**
* @param <code>right</code> the new value for <code>right</code>
*/
public void setRight(ResNode right) {
assert (right != null);
this.right = right;
}
/**
*
* @return <code>true</code> iff this is a leaf.
*/
public boolean isLeaf() {
assert (!(left == null ^ right == null));
return left == null && right == null;
}
public void print() {
System.out.println("------------------------------------");
if (isLeaf())
System.out.println(id + "> (leaf) part:" + part);
else
System.out.println(id + "> left:" + left.id + " right:" + right.id
+ " pivot:" + pivot);
System.out.println("Clause: " + clause);
Iterator<ResNode> itr = parents.iterator();
System.out.print("Chidren: [");
while (itr.hasNext()) {
ResNode n = itr.next();
System.out.print(n.id + ",");
}
System.out.println("]");
}
@Override
public String toString() {
if (left == null && right == null)
return id + ":" + clause + " (p" + part + ")";
else if (part != -1)
return id + ":" + clause + " left:"
+ (left == null ? "null" : left.id) + " right:"
+ (right == null ? "null" : right.id) + " piv:" + pivot
+ " (p" + part + ")";
else
return id + ":" + clause + " left:"
+ (left == null ? "null" : left.id) + " right:"
+ (right == null ? "null" : right.id) + " piv:" + pivot;
}
/**
* @see java.lang.Comparable#compareTo(java.lang.Object)
*/
@Override
public int compareTo(ResNode other) {
return this.id - other.id;
}
/**
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
return this.id;
}
/**
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!(obj instanceof ResNode))
return false;
if (this.hashCode() != obj.hashCode())
return false;
ResNode other = (ResNode) obj;
if (this.id != other.id)
return false;
if (this.part != other.part)
return false;
if (this.pivot != other.pivot)
return false;
if (!this.left.equals(other.left))
return false;
if (!this.right.equals(other.right))
return false;
if (!this.parents.equals(other.parents))
return false;
return true;
}
/**
* @return the number of nodes in the subproof starting at this node,
* unwinding the DAG to a tree.
*/
public int treeSize() {
if (this.isLeaf())
return 1;
return this.left.treeSize() + this.right.treeSize() + 1;
}
/**
*
* @param nodeSizes
* @return DAG-aware computation of the tree size
*/
public long treeSize(Map<ResNode, Long> nodeSizes) {
if (nodeSizes.keySet().contains(this))
return nodeSizes.get(this);
if (this.isLeaf()) {
nodeSizes.put(this, 1l);
return 1;
}
long leftSize = this.left.treeSize(nodeSizes);
long rightSize = this.right.treeSize(nodeSizes);
long result = leftSize + rightSize + 1;
nodeSizes.put(this, result);
return result;
}
/**
*
* @return a set of all descendants of this node.
*/
public Set<ResNode> getDescendants() {
Set<ResNode> result = new HashSet<ResNode>();
this.getDescendantsRecursion(result);
return result;
}
/**
* Recursion for computing descendants
*
* @param result
* descendants will be added to this set.
*/
private void getDescendantsRecursion(Set<ResNode> result) {
if (result.contains(this))
return;
result.add(this);
if (!this.isLeaf()) {
this.left.getDescendantsRecursion(result);
this.right.getDescendantsRecursion(result);
}
}
}