Coverage Report - edu.uci.ics.jung.graph.DelegateTree
 
Classes in this File Line Coverage Branch Coverage Complexity
DelegateTree
38%
35/91
22%
11/48
2.276
DelegateTree$1
0%
0/2
N/A
2.276
 
 1  
 package edu.uci.ics.jung.graph;
 2  
 
 3  
 import java.util.ArrayList;
 4  
 import java.util.Collection;
 5  
 import java.util.Collections;
 6  
 import java.util.HashMap;
 7  
 import java.util.List;
 8  
 import java.util.Map;
 9  
 
 10  
 import org.apache.commons.collections15.Factory;
 11  
 
 12  
 import edu.uci.ics.jung.graph.util.EdgeType;
 13  
 import edu.uci.ics.jung.graph.util.Pair;
 14  
 
 15  
 /**
 16  
  * An implementation of <code>Tree<V,E></code> that delegates to
 17  
  * a specified instance of <code>DirectedGraph<V,E></code>.
 18  
  * @author Tom Nelson
 19  
  *
 20  
  * @param <V> the vertex type
 21  
  * @param <E> the edge type
 22  
  */
 23  
 @SuppressWarnings("serial")
 24  
 public class DelegateTree<V,E> extends GraphDecorator<V,E> implements Tree<V,E>
 25  
 {
 26  
     /**
 27  
      * Returns a {@code Factory} that creates an instance of this graph type.
 28  
      * @param <V> the vertex type for the graph factory
 29  
      * @param <E> the edge type for the graph factory
 30  
      */
 31  
     public static final <V,E> Factory<Tree<V,E>> getFactory() {
 32  0
                 return new Factory<Tree<V,E>> () {
 33  0
                         public Tree<V,E> create() {
 34  0
                                 return new DelegateTree<V,E>(new DirectedSparseMultigraph<V,E>());
 35  
                         }
 36  
                 };
 37  
         }
 38  
 
 39  
         protected V root;
 40  
     protected Map<V, Integer> vertex_depths;
 41  
     
 42  
     /**
 43  
      * Creates an instance.
 44  
      */
 45  
     public DelegateTree() {
 46  8
             this(DirectedSparseMultigraph.<V,E>getFactory());
 47  8
     }
 48  
 
 49  
         /**
 50  
          * create an instance with passed values.
 51  
          * @param graphFactory must create a DirectedGraph to use as a delegate
 52  
          */
 53  
         public DelegateTree(Factory<DirectedGraph<V,E>> graphFactory) {
 54  16
                 super(graphFactory.create());
 55  16
         this.vertex_depths = new HashMap<V, Integer>();
 56  16
         }
 57  
         
 58  
         /**
 59  
          * Creates a new <code>DelegateTree</code> which delegates to <code>graph</code>.
 60  
          * Assumes that <code>graph</code> is already a tree; if it's not, future behavior
 61  
          * of this instance is undefined.
 62  
          */
 63  
         public DelegateTree(DirectedGraph<V,E> graph) {
 64  0
                 super(graph);
 65  
 //                if(graph.getVertexCount() != 0) throw new IllegalArgumentException(
 66  
 //                        "Passed DirectedGraph must be empty");
 67  0
         this.vertex_depths = new HashMap<V, Integer>();
 68  0
         }
 69  
         
 70  
         /**
 71  
          * Add an edge to the tree, connecting v1, the parent and v2, the child.
 72  
          * v1 must already exist in the tree, and v2 must not already exist
 73  
          * the passed edge must be unique in the tree. Passing an edgeType
 74  
          * other than EdgeType.DIRECTED may cause an illegal argument exception 
 75  
          * in the delegate graph.
 76  
          * 
 77  
          * @param e a unique edge to add
 78  
          * @param v1 the parent node
 79  
          * @param v2 the child node
 80  
          * @param edgeType should be EdgeType.DIRECTED
 81  
          * @return true if this call mutates the underlying graph
 82  
          * @see edu.uci.ics.jung.graph.Graph#addEdge(java.lang.Object, java.lang.Object, java.lang.Object, edu.uci.ics.jung.graph.util.EdgeType)
 83  
          */
 84  
         @Override
 85  
         public boolean addEdge(E e, V v1, V v2, EdgeType edgeType) {
 86  0
                 return addChild(e, v1, v2, edgeType);
 87  
         }
 88  
 
 89  
         /**
 90  
          * Add an edge to the tree, connecting v1, the parent and v2, the child.
 91  
          * v1 must already exist in the tree, and v2 must not already exist
 92  
          * the passed edge must be unique in the tree. 
 93  
          * 
 94  
          * @param e a unique edge to add
 95  
          * @param v1 the parent node
 96  
          * @param v2 the child node
 97  
          * @return true if this call mutates the underlying graph
 98  
          * @see edu.uci.ics.jung.graph.Graph#addEdge(java.lang.Object, java.lang.Object, java.lang.Object)
 99  
          */
 100  
         @Override
 101  
         public boolean addEdge(E e, V v1, V v2) {
 102  84
                 return addChild(e, v1, v2);
 103  
         }
 104  
 
 105  
         /**
 106  
          * Will set the root of the Tree, only if the Tree is empty and the
 107  
          * root is currently unset.
 108  
          * 
 109  
          * @param vertex the tree root to set
 110  
          * @return true if this call mutates the underlying graph
 111  
          * @see edu.uci.ics.jung.graph.Graph#addVertex(java.lang.Object)
 112  
          * @throws UnsupportedOperationException if the root was previously set
 113  
          */
 114  
         @Override
 115  
         public boolean addVertex(V vertex) {
 116  16
                 if(root == null) {
 117  16
                         this.root = vertex;
 118  16
             vertex_depths.put(vertex, 0);
 119  16
                         return delegate.addVertex(vertex);
 120  
                 } else {
 121  0
                         throw new UnsupportedOperationException("Unless you are setting the root, use addChild()");
 122  
                 }
 123  
         }
 124  
 
 125  
         /**
 126  
          * remove the passed node, and all nodes that are descendants of the
 127  
          * passed node.
 128  
          * @param vertex
 129  
          * @return <code>true</code> iff the tree was modified 
 130  
          * @see edu.uci.ics.jung.graph.Graph#removeVertex(java.lang.Object)
 131  
          */
 132  
         @Override
 133  
         public boolean removeVertex(V vertex) {
 134  18
             if (!delegate.containsVertex(vertex))
 135  0
                 return false;
 136  18
                 for(V v : getChildren(vertex)) {
 137  12
                         removeVertex(v);
 138  12
             vertex_depths.remove(v);
 139  
                 }
 140  
         
 141  
         // recalculate height
 142  18
                 vertex_depths.remove(vertex);
 143  18
                 return delegate.removeVertex(vertex);
 144  
         }
 145  
         
 146  
         /**
 147  
          * add the passed child node as a child of parent.
 148  
          * parent must exist in the tree, and child must not already exist.
 149  
          * 
 150  
          * @param edge the unique edge to connect the parent and child nodes
 151  
          * @param parent the existing parent to attach the child to
 152  
          * @param child the new child to add to the tree as a child of parent
 153  
          * @param edgeType must be EdgeType.DIRECTED or the underlying graph may throw an exception
 154  
          * @return whether this call mutates the underlying graph
 155  
          */
 156  
         public boolean addChild(E edge, V parent, V child, EdgeType edgeType) {
 157  0
                 Collection<V> vertices = delegate.getVertices();
 158  0
                 if(vertices.contains(parent) == false) {
 159  0
                         throw new IllegalArgumentException("Tree must already contain parent "+parent);
 160  
                 }
 161  0
                 if(vertices.contains(child)) {
 162  0
                         throw new IllegalArgumentException("Tree must not already contain child "+child);
 163  
                 }
 164  0
         vertex_depths.put(child, vertex_depths.get(parent) + 1);
 165  0
                 return delegate.addEdge(edge, parent, child, edgeType);
 166  
         }
 167  
 
 168  
         /**
 169  
          * add the passed child node as a child of parent.
 170  
          * parent must exist in the tree, and child must not already exist
 171  
          * @param edge the unique edge to connect the parent and child nodes
 172  
          * @param parent the existing parent to attach the child to
 173  
          * @param child the new child to add to the tree as a child of parent
 174  
          * @return whether this call mutates the underlying graph
 175  
          */
 176  
         public boolean addChild(E edge, V parent, V child) {
 177  84
                 Collection<V> vertices = delegate.getVertices();
 178  84
                 if(vertices.contains(parent) == false) {
 179  0
                         throw new IllegalArgumentException("Tree must already contain parent "+parent);
 180  
                 }
 181  84
                 if(vertices.contains(child)) {
 182  4
                         throw new IllegalArgumentException("Tree must not already contain child "+child);
 183  
                 }
 184  80
         vertex_depths.put(child, vertex_depths.get(parent) + 1);
 185  80
                 return delegate.addEdge(edge, parent, child);
 186  
         }
 187  
         
 188  
         /**
 189  
          * get the number of children of the passed parent node
 190  
          */
 191  
         public int getChildCount(V parent) {
 192  0
             if (!delegate.containsVertex(parent))
 193  0
                 return 0;
 194  0
                 return getChildren(parent).size();
 195  
         }
 196  
 
 197  
         /**
 198  
          * get the immediate children nodes of the passed parent
 199  
          */
 200  
         public Collection<V> getChildren(V parent) {
 201  18
         if (!delegate.containsVertex(parent))
 202  0
             return null;
 203  18
                 return delegate.getSuccessors(parent);
 204  
         }
 205  
 
 206  
         /**
 207  
          * get the single parent node of the passed child
 208  
          */
 209  
         public V getParent(V child) {
 210  0
         if (!delegate.containsVertex(child))
 211  0
             return null;
 212  0
                 Collection<V> predecessors = delegate.getPredecessors(child);
 213  0
                 if(predecessors.size() == 0) {
 214  0
                         return null;
 215  
                 }
 216  0
                 return predecessors.iterator().next();
 217  
         }
 218  
 
 219  
         /**
 220  
          * Returns an ordered list of the nodes beginning at the root
 221  
          * and ending at {@code vertex}, including all intermediate
 222  
          * nodes.
 223  
          * @param vertex the last node in the path from the root
 224  
          * @return an ordered list of the nodes from root to child
 225  
          */
 226  
         public List<V> getPath(V vertex) {
 227  0
         if (!delegate.containsVertex(vertex))
 228  0
             return null;
 229  0
                 List<V> vertex_to_root = new ArrayList<V>();
 230  0
                 vertex_to_root.add(vertex);
 231  0
                 V parent = getParent(vertex);
 232  0
                 while(parent != null) {
 233  0
                         vertex_to_root.add(parent);
 234  0
                         parent = getParent(parent);
 235  
                 }
 236  
                 // reverse list so that it goes from root to child
 237  0
                 List<V> root_to_vertex = new ArrayList<V>(vertex_to_root.size());
 238  0
                 for (int i = vertex_to_root.size() - 1; i >= 0; i--)
 239  0
                         root_to_vertex.add(vertex_to_root.get(i));
 240  0
                 return root_to_vertex;
 241  
         }
 242  
 
 243  
         /**
 244  
          * getter for the root of the tree
 245  
          * @return the root
 246  
          */
 247  
         public V getRoot() {
 248  2
                 return root;
 249  
         }
 250  
         
 251  
         /**
 252  
          * sets the root to the passed value, only if the root is
 253  
          * previously unset
 254  
          * @param root the initial tree root
 255  
          */
 256  
         public void setRoot(V root) {
 257  0
                 addVertex(root);
 258  0
         }
 259  
 
 260  
         /**
 261  
          * removes a node from the tree, causing all descendants of
 262  
          * the removed node also to be removed
 263  
          * @param orphan the node to remove
 264  
          * @return whether this call mutates the underlying graph
 265  
          */
 266  
         public boolean removeChild(V orphan) {
 267  0
                 return removeVertex(orphan);
 268  
         }
 269  
 
 270  
         /**
 271  
          * computes and returns the depth of the tree from the
 272  
          * root to the passed vertex
 273  
          * 
 274  
          * @param v the node who's depth is computed
 275  
          * @return the depth to the passed node.
 276  
          */
 277  
         public int getDepth(V v) {
 278  340
         return this.vertex_depths.get(v);
 279  
         }
 280  
 
 281  
         /**
 282  
          * Computes and returns the height of the tree.
 283  
          * 
 284  
          * @return the height
 285  
          */
 286  
         public int getHeight() {
 287  34
                 int height = 0;
 288  34
                 for(V v : getVertices()) {
 289  306
                         height = Math.max(height, getDepth(v));
 290  
                 }
 291  34
                 return height;
 292  
         }
 293  
 
 294  
         /**
 295  
          * Returns <code>true</code> if <code>v</code> is neither 
 296  
          * a leaf nor the root of this tree.
 297  
          * @return <code>true</code> if <code>v</code> is neither 
 298  
      * a leaf nor the root of this tree
 299  
          */
 300  
         public boolean isInternal(V v) {
 301  0
             if (!delegate.containsVertex(v))
 302  0
                 return false;
 303  0
                 return isLeaf(v) == false && isRoot(v) == false;
 304  
         }
 305  
 
 306  
         /**
 307  
          * Returns <code>true</code> if the passed node has no
 308  
          * children.
 309  
          * @return <code>true</code> if the passed node has no
 310  
      * children
 311  
          */
 312  
         public boolean isLeaf(V v) {
 313  0
         if (!delegate.containsVertex(v))
 314  0
             return false;
 315  0
                 return getChildren(v).size() == 0;
 316  
         }
 317  
 
 318  
         /**
 319  
          * computes whether the passed node is a root node
 320  
          * (has no children)
 321  
          */
 322  
         public boolean isRoot(V v) {
 323  0
         if (!delegate.containsVertex(v))
 324  0
             return false;
 325  0
                 return getParent(v) == null;
 326  
         }
 327  
 
 328  
         @Override
 329  
     public int getIncidentCount(E edge)
 330  
     {
 331  0
         if (!delegate.containsEdge(edge))
 332  0
             return 0;
 333  
         // all edges in a tree connect exactly 2 vertices
 334  0
         return 2;
 335  
     }
 336  
     
 337  
         @SuppressWarnings("unchecked")
 338  
   @Override
 339  
         public boolean addEdge(E edge, Collection<? extends V> vertices) {
 340  8
                 Pair<V> pair = null;
 341  8
                 if(vertices instanceof Pair) {
 342  8
                         pair = (Pair<V>)vertices;
 343  
                 } else {
 344  0
                         pair = new Pair<V>(vertices);
 345  
                 }
 346  8
                 return addEdge(edge, pair.getFirst(), pair.getSecond());
 347  
         }
 348  
         
 349  
         @Override
 350  
         public String toString() {
 351  0
                 return "Tree of "+delegate.toString();
 352  
         }
 353  
 
 354  
         public Collection<Tree<V, E>> getTrees() {
 355  6
                 return Collections.<Tree<V,E>>singleton(this);
 356  
         }
 357  
 
 358  
   public Collection<E> getChildEdges(V vertex) {
 359  0
       return getOutEdges(vertex);
 360  
   }
 361  
 
 362  
   public E getParentEdge(V vertex) {
 363  0
       return getInEdges(vertex).iterator().next();
 364  
   }
 365  
 }