package shef.instantiator.andortree; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import cs227b.teamIago.resolver.Expression; import cs227b.teamIago.resolver.Implication; import cs227b.teamIago.resolver.Predicate; import cs227b.teamIago.resolver.Substitution; /** * A node in an AND OR tree * * @author jonathan * */ public class Node { /** * Prune a node remove all the non-completed children * * XXX this should be rendered obsolete by the introduction of actual ground * instantiation * * @param node * @return true if the node is or contains */ public static boolean prune(Node node) { if(node.nodetype == NodeType.DISTINCT){ // System.out.println(node); throw new RuntimeException("not sure how to prune a DISTINCT node"); } // this is a truth node can wipe its children if(node.nodetype == NodeType.TRUTH){ node.children = new ArrayList<Node>(); return true; } boolean hasTruthInChildren = false; Iterator<Node> it = node.children.iterator(); while(it.hasNext()){ Node n = it.next(); if(!prune(n)){ it.remove(); } else { hasTruthInChildren = true; } } return hasTruthInChildren; } /** The implication this node represents */ private Implication implication; /** Is this node negated in the AND/OR tree? */ public boolean negated = false; /** The parent of this node */ private Node parent; /** The depth of this node */ private int depth; /** Children of the node */ private List<Node> children = new ArrayList<Node>(); /** The type of node */ public NodeType nodetype; /** The expression which this node really fulfills */ private Expression head; /** * Create a new Node * * @param imp * the implication to represent * @param nodeType * the node type */ public Node(Implication imp, NodeType nodeType) { this.setImplication(imp); this.nodetype = nodeType; } /** * Add a node to this node's children list update the child's parent and * depth */ public void addChild(Node child) { child.parent = this; child.depth = this.depth + 1; children.add(child); } public Node clone() { Node n = new Node(this.getImplication(), this.getNodeType()); List<Node> cs = n.getChildren(); for (Node child : this.getChildren()) { cs.add(child.clone()); } return n; } /** * Creates a clone of the node, not including children which fail to map to * the substitution * * @param s * @return the node with sub applied */ public Node clone(Substitution s) { // first apply the substitution Implication newImp = (Implication) this.getImplication().apply(s); // create the new node which is going to be the container Node n = new Node(newImp, this.getNodeType()); n.children = this.children; // // manual copy - removed for being SLOW // Expression newConseq = newImp.getConsequence(); // List<Node> cs = n.getChildren(); // for (Node child : this.getChildren()) { // // fill the node - but don't include the clauses which wouldn't map // Expression childConseq = child.getImplication().getConsequence(); // if ((newConseq.mapTo(s, childConseq) != null)) // cs.add(child.clone()); // } return n; } /** * Return the list of children * * @return */ public List<Node> getChildren() { return children; } /** * Return how deep in the tree is this XXX this may return the wrong value * don't rely on this * * @return */ public int getDepth() { return depth; } /** * Return the consequent of the implication * * @return */ public Expression getHead() { return head; } /** * Return the implication this node represents * * @return */ public Implication getImplication() { return implication; } /** * Return the number of children this node has * * @return */ public int getChildCount() { return children.size(); } /** * Return the number of negative children this node has * * @return */ public int getNegChildCount() { return getChildCount() - getPosChildCount(); } /** * Return the node type * * @return */ public NodeType getNodeType() { return nodetype; } /** * Returns the number of positive children this node has * * @return */ public int getPosChildCount() { int p = 0; for (Node n : children) { if (!n.negated) { p++; } } return p; } /** * Returns the parent node * * @return */ public Node getParent() { return parent; } /** * Returns true if the head of every child has no variables * * @return */ public boolean isCompleted() { // should only really be called on TRUE and AND nodes for (Node child : getChildren()) { // the node has some variables in it if (child.getHead().getVars().size() > 0) { return false; } } return true; } /** * Output util - prints a node and calls chidren to be printed * * @param lvl * @return */ private String printNode(int lvl) { StringBuffer s = new StringBuffer(); s.append(printSpacer(lvl) + " " + toString() + "\n"); Iterator<Node> it = children.iterator(); while (it.hasNext()) { Node node = (Node) it.next(); s.append(node.printNode(lvl + 1)); } return s.toString(); } /** * Output util - spaces printing * * @param lvl * @return */ private String printSpacer(int lvl) { StringBuffer sb = new StringBuffer(lvl); for (int j = 0; j < lvl; j++) { sb.append(" "); } return sb.toString(); } /** * Print the node as the root of a tree */ public String printTree() { return printNode(0); } /** * Removes the supplied node from the list of children * * @param toRemove * @return true if list DID contain the node */ public boolean removeChild(Node toRemove) { return children.remove(toRemove); } /** * Assigns the children of this node to a new ArrayList Note: the old list * is left */ public void resetChildren() { children = new ArrayList<Node>(); } /** * Set a new implication for this node to represent * * @param implication */ public void setImplication(Implication implication) { // XXX should this even be allowed?! this.implication = implication; this.head = implication.getConsequence(); } public String toString() { return this.nodetype + (negated ? " not" : "") + " " + getHead(); } public void becomeTruth() { // could be an atomic OR a predicate truth Expression truth = ((Predicate) this.getHead()).getOperands().get(0); this.setImplication(new Implication(truth, this.getImplication().getPremises())); this.nodetype = NodeType.TRUTH; } public void addAll(Collection<Node> ns) { for (Node n : ns) { this.addChild(n); } } }