View Javadoc
1   /*
2    * Created on May 8, 2008
3    *
4    * Copyright (c) 2008, The JUNG Authors 
5    *
6    * All rights reserved.
7    *
8    * This software is open-source under the BSD license; see either
9    * "license.txt" or
10   * https://github.com/jrtom/jung/blob/master/LICENSE for a description.
11   */
12  package edu.uci.ics.jung.graph;
13  
14  import java.util.ArrayList;
15  import java.util.Collection;
16  import java.util.Collections;
17  import java.util.HashMap;
18  import java.util.List;
19  import java.util.Map;
20  
21  import com.google.common.base.Supplier;
22  import com.google.common.collect.ImmutableList;
23  import com.google.common.collect.ImmutableSet;
24  
25  import edu.uci.ics.jung.graph.util.EdgeType;
26  import edu.uci.ics.jung.graph.util.Pair;
27  
28  /**
29   * An implementation of <code>Tree</code> in which each vertex has
30   * &le; k children.  The value of 'k' is specified by the constructor
31   * parameter.  A specific child (edge) can be retrieved directly by specifying the
32   * index at which the child is located.  By default, new (child) vertices
33   * are added at the lowest index available, if no index is specified.
34   * 
35   */
36  @SuppressWarnings("serial")
37  public class OrderedKAryTree<V, E> extends AbstractTypedGraph<V, E> implements Tree<V, E> 
38  {
39      protected Map<E, Pair<V>> edge_vpairs;
40      protected Map<V, VertexData> vertex_data;
41      protected int height;
42      protected V root;
43      protected int order;
44      
45      /**
46       * @param <V> the vertex type for the graph Supplier
47       * @param <E> the edge type for the graph Supplier
48       * @param order the maximum number of children ("k") that any vertex can have
49       * @return a {@code Supplier} that creates an instance of this graph type.
50       */
51      public static <V,E> Supplier<DirectedGraph<V,E>> getFactory(final int order) {
52          return new Supplier<DirectedGraph<V,E>> () {
53              public DirectedGraph<V,E> get() {
54                  return new OrderedKAryTree<V,E>(order);
55              }
56          };
57      }
58      
59      /**
60       * Creates a new instance with the specified order (maximum number of children).
61       * @param order the maximum number of children ("k") that any vertex can have
62       */
63      public OrderedKAryTree(int order)
64      {
65      	super(EdgeType.DIRECTED);
66      	this.order = order;
67      	this.height = -1;
68      	this.edge_vpairs = new HashMap<E, Pair<V>>();
69      	this.vertex_data = new HashMap<V, VertexData>();
70      }
71    
72      /**
73       * @param vertex the vertex whose number of children is to be returned
74       * @return the number of children that {@code vertex} has
75       * @see edu.uci.ics.jung.graph.Tree#getChildCount(java.lang.Object)
76       */
77      public int getChildCount(V vertex) {
78          if (!containsVertex(vertex)) 
79              return 0;
80          List<E> edges = vertex_data.get(vertex).child_edges;
81          if (edges == null)
82          	return 0;
83          int count = 0;
84          for (E edge : edges)
85              count += edge == null ? 0 : 1;
86      
87          return count;
88      }
89    
90      /**
91       * @param vertex the vertex whose child edge is to be returned
92       * @param index the index of the edge to be returned
93       * @return the child edge of {@code vertex} at index {@code index}, that is, 
94       *     its <i>i</i>th child edge.
95       */
96      public E getChildEdge(V vertex, int index) 
97      {
98          if (!containsVertex(vertex)) 
99          	return null;
100         List<E> edges = vertex_data.get(vertex).child_edges;
101         if (edges == null)
102         	return null;
103         return edges.get(index);
104     }
105 
106     /**
107      * @see edu.uci.ics.jung.graph.Tree#getChildEdges(java.lang.Object)
108      */
109     public Collection<E> getChildEdges(V vertex) 
110     {
111         if (!containsVertex(vertex)) 
112         	return null;
113         List<E> edges = vertex_data.get(vertex).child_edges;
114         return edges == null ? Collections.<E>emptySet() : 
115         	new ImmutableList.Builder<E>().addAll(edges).build();
116     }
117   
118     /**
119      * Returns an ordered list of {@code vertex}'s child vertices.
120      * If there is no child in position i, then the list will contain
121      * {@code null} in position i.  If {@code vertex} has no children
122      * then the empty set will be returned.
123      * @see edu.uci.ics.jung.graph.Tree#getChildren(java.lang.Object)
124      */
125     public Collection<V> getChildren(V vertex) 
126     {
127         if (!containsVertex(vertex)) 
128             return null;
129         List<E> edges = vertex_data.get(vertex).child_edges;
130         if (edges == null)
131         	return Collections.emptySet();
132         Collection<V> children = new ArrayList<V>(order);
133         for (E edge : edges)
134             children.add(this.getOpposite(vertex, edge));
135         return new ImmutableList.Builder<V>().addAll(children).build();
136     }
137   
138     /**
139      * @see edu.uci.ics.jung.graph.Tree#getDepth(java.lang.Object)
140      * @return the depth of the vertex in this tree, or -1 if the vertex is
141      * not present in this tree
142      */
143     public int getDepth(V vertex) 
144     {
145         if (!containsVertex(vertex))
146             return -1;
147         return vertex_data.get(vertex).depth;
148     }
149   
150     /**
151      * Returns the height of the tree, or -1 if the tree is empty.
152      * @see edu.uci.ics.jung.graph.Tree#getHeight()
153      */
154     public int getHeight() 
155     {
156         return height;
157     }
158   
159     /**
160      * @see edu.uci.ics.jung.graph.Tree#getParent(java.lang.Object)
161      */
162     public V getParent(V vertex) 
163     {
164         if (!containsVertex(vertex))
165             return null;
166         else if (vertex.equals(root))
167             return null;
168         return edge_vpairs.get(vertex_data.get(vertex).parent_edge).getFirst();
169     }
170   
171     /**
172      * @see edu.uci.ics.jung.graph.Tree#getParentEdge(java.lang.Object)
173      */
174     public E getParentEdge(V vertex) 
175     {
176         if (!containsVertex(vertex))
177             return null;
178         return vertex_data.get(vertex).parent_edge;
179     }
180   
181     /**
182      * @see edu.uci.ics.jung.graph.Tree#getRoot()
183      */
184     public V getRoot() 
185     {
186         return root;
187     }
188   
189     /**
190      * @see edu.uci.ics.jung.graph.Forest#getTrees()
191      */
192     public Collection<Tree<V, E>> getTrees() 
193     {
194         Collection<Tree<V, E>> forest = new ArrayList<Tree<V, E>>(1);
195         forest.add(this);
196         return forest;
197     }
198   
199     /**
200      * Adds the specified {@code child} vertex and edge {@code e} to the graph
201      * with the specified parent vertex {@code parent}.  If {@code index} is 
202      * greater than or equal to 0, then the child is placed at position
203      * {@code index}; if it is less than 0, the child is placed at the lowest
204      * available position; if it is greater than or equal to the order of this
205      * tree, an exception is thrown.
206      * 
207      * @param e the edge to add
208      * @param parent the source of the edge to be added
209      * @param child the destination of the edge to be added
210      * @param index the position at which e is to be added as a child of {@code parent}
211      * @return {@code true} if the graph has been modified
212      * @see edu.uci.ics.jung.graph.Graph#addEdge(java.lang.Object, java.lang.Object, java.lang.Object)
213      */
214 	public boolean addEdge(E e, V parent, V child, int index) 
215     {
216         if (e == null || child == null || parent == null)
217             throw new IllegalArgumentException("Inputs may not be null");
218     	if (!containsVertex(parent))
219     		throw new IllegalArgumentException("Tree must already " +
220     				"include parent: " + parent);
221     	if (containsVertex(child))
222     		throw new IllegalArgumentException("Tree must not already " +
223     				"include child: " + child);
224 		if (parent.equals(child))
225 			throw new IllegalArgumentException("Input vertices must be distinct");
226 		if (index < 0 || index >= order)
227 		    throw new IllegalArgumentException("'index' must be in [0, [order-1]]");
228     	
229     	Pair<V> endpoints = new Pair<V>(parent, child);
230     	if (containsEdge(e))
231     		if (!endpoints.equals(edge_vpairs.get(e)))
232     			throw new IllegalArgumentException("Tree already includes edge" + 
233     					e + " with different endpoints " + edge_vpairs.get(e));
234     		else
235     			return false;
236 
237     	VertexData parent_data = vertex_data.get(parent);
238     	List<E> outedges = parent_data.child_edges;
239     	
240     	if (outedges == null)
241     	    outedges = new ArrayList<E>(this.order);
242 
243     	boolean edge_placed = false;
244     	if (index >= 0)
245     		if (outedges.get(index) != null)
246         		throw new IllegalArgumentException("Parent " + parent + 
247         				" already has a child at index " + index + " in this tree");
248     		else
249     			outedges.set(index, e);
250     	for (int i = 0; i < order; i++)
251     	{
252     		if (outedges.get(i) == null)
253     		{
254     			outedges.set(i, e);
255     			edge_placed = true;
256     			break;
257     		}
258     	}
259     	if (!edge_placed)
260     		throw new IllegalArgumentException("Parent " + parent + " already" +
261     				" has " + order + " children in this tree");
262     	
263     	// initialize VertexData for child; leave child's child_edges null for now
264     	VertexData child_data = new VertexData(e, parent_data.depth + 1);
265     	vertex_data.put(child, child_data);
266     	
267     	height = child_data.depth > height ? child_data.depth : height;
268     	edge_vpairs.put(e, endpoints);
269     	
270     	return true;
271     }
272 
273     /**
274      * @see edu.uci.ics.jung.graph.Graph#addEdge(java.lang.Object, java.lang.Object, java.lang.Object)
275      */
276 	@Override
277     public boolean addEdge(E e, V parent, V child)
278 	{
279 		return addEdge(e, parent, child, -1);
280 	}
281 
282     
283     /**
284      * @see edu.uci.ics.jung.graph.Graph#addEdge(java.lang.Object, java.lang.Object, java.lang.Object, edu.uci.ics.jung.graph.util.EdgeType)
285      */
286     @Override
287     public boolean addEdge(E e, V v1, V v2, EdgeType edge_type) 
288     {
289     	this.validateEdgeType(edge_type);
290     	return addEdge(e, v1, v2);
291     }
292   
293     /**
294      * @see edu.uci.ics.jung.graph.Graph#getDest(java.lang.Object)
295      */
296     public V getDest(E directed_edge) 
297     {
298         if (!containsEdge(directed_edge))
299             return null;
300         return edge_vpairs.get(directed_edge).getSecond();
301     }
302   
303     /**
304      * @see edu.uci.ics.jung.graph.Graph#getEndpoints(java.lang.Object)
305      */
306     public Pair<V> getEndpoints(E edge) 
307     {
308         if (!containsEdge(edge))
309             return null;
310         return edge_vpairs.get(edge);
311     }
312   
313     /**
314      * @see edu.uci.ics.jung.graph.Graph#getInEdges(java.lang.Object)
315      */
316     public Collection<E> getInEdges(V vertex) 
317     {
318         if (!containsVertex(vertex))
319             return null;
320         else if (vertex.equals(root))
321             return Collections.emptySet();
322         else
323             return Collections.singleton(getParentEdge(vertex));
324     }
325   
326     /**
327      * @see edu.uci.ics.jung.graph.Graph#getOpposite(java.lang.Object, java.lang.Object)
328      */
329     @Override
330     public V getOpposite(V vertex, E edge) 
331     {
332         if (!containsVertex(vertex) || !containsEdge(edge))
333             return null;
334         Pair<V> endpoints = edge_vpairs.get(edge);
335         V v1 = endpoints.getFirst();
336         V v2 = endpoints.getSecond();
337         return v1.equals(vertex) ? v2 : v1;
338     }
339   
340     /**
341      * @see edu.uci.ics.jung.graph.Graph#getOutEdges(java.lang.Object)
342      */
343     public Collection<E> getOutEdges(V vertex) 
344     {
345         return getChildEdges(vertex);
346     }
347   
348     /**
349      * @see edu.uci.ics.jung.graph.Graph#getPredecessorCount(java.lang.Object)
350      * @return 0 if <code>vertex</code> is the root, -1 if the vertex is 
351      * not an element of this tree, and 1 otherwise
352      */
353     @Override
354     public int getPredecessorCount(V vertex) 
355     {
356         if (!containsVertex(vertex))
357             return -1;
358         return vertex.equals(root) ? 0 : 1;
359     }
360   
361     /**
362      * @see edu.uci.ics.jung.graph.Graph#getPredecessors(java.lang.Object)
363      */
364     public Collection<V> getPredecessors(V vertex) 
365     {
366         if (!containsVertex(vertex))
367             return null;
368         if (vertex.equals(root))
369             return Collections.emptySet();
370         return Collections.singleton(getParent(vertex));
371     }
372   
373     /**
374      * @see edu.uci.ics.jung.graph.Graph#getSource(java.lang.Object)
375      */
376     public V getSource(E directed_edge) 
377     {
378         if (!containsEdge(directed_edge))
379             return null;
380         return edge_vpairs.get(directed_edge).getFirst();
381     }
382   
383     /**
384      * @see edu.uci.ics.jung.graph.Graph#getSuccessorCount(java.lang.Object)
385      */
386     @Override
387     public int getSuccessorCount(V vertex) 
388     {
389         return getChildCount(vertex);
390     }
391   
392     /**
393      * @see edu.uci.ics.jung.graph.Graph#getSuccessors(java.lang.Object)
394      */
395     public Collection<V> getSuccessors(V vertex) 
396     {
397         return getChildren(vertex);
398     }
399   
400     /**
401      * @see edu.uci.ics.jung.graph.Graph#inDegree(java.lang.Object)
402      */
403     @Override
404     public int inDegree(V vertex) 
405     {
406         if (!containsVertex(vertex))
407             return 0;
408         if (vertex.equals(root))
409             return 0;
410         return 1;
411     }
412   
413     /**
414      * @see edu.uci.ics.jung.graph.Graph#isDest(java.lang.Object, java.lang.Object)
415      */
416     public boolean isDest(V vertex, E edge) 
417     {
418         if (!containsEdge(edge) || !containsVertex(vertex))
419             return false;
420         return edge_vpairs.get(edge).getSecond().equals(vertex);
421     }
422   
423     /**
424      * Returns <code>true</code> if <code>vertex</code> is a leaf of this tree,
425      * i.e., if it has no children.
426      * @param vertex the vertex to be queried
427      * @return <code>true</code> if <code>outDegree(vertex)==0</code>
428      */
429     public boolean isLeaf(V vertex)
430     {
431         if (!containsVertex(vertex))
432             return false;
433         return outDegree(vertex) == 0;
434     }
435     
436     /**
437      * Returns true iff <code>v1</code> is the parent of <code>v2</code>.
438      * Note that if <code>v2</code> is the root and <code>v1</code> is <code>null</code>,
439      * this method returns <code>true</code>.
440      * 
441      * @see edu.uci.ics.jung.graph.Graph#isPredecessor(java.lang.Object, java.lang.Object)
442      */
443     @Override
444     public boolean isPredecessor(V v1, V v2) 
445     {
446         if (!containsVertex(v2))
447             return false;
448         return getParent(v2).equals(v1);
449     }
450   
451     /**
452      * Returns <code>true</code> if <code>vertex</code> is a leaf of this tree,
453      * i.e., if it has no children.
454      * @param vertex the vertex to be queried
455      * @return <code>true</code> if <code>outDegree(vertex)==0</code>
456      */
457     public boolean isRoot(V vertex)
458     {
459         if (root == null)
460             return false;
461         return root.equals(vertex);
462     }
463     
464     /**
465      * @see edu.uci.ics.jung.graph.Graph#isSource(java.lang.Object, java.lang.Object)
466      */
467     public boolean isSource(V vertex, E edge) 
468     {
469         if (!containsEdge(edge) || !containsVertex(vertex))
470             return false;
471         return edge_vpairs.get(edge).getFirst().equals(vertex);
472     }
473   
474     /**
475      * @see edu.uci.ics.jung.graph.Graph#isSuccessor(java.lang.Object, java.lang.Object)
476      */
477     @Override
478     public boolean isSuccessor(V v1, V v2) 
479     {
480         if (!containsVertex(v2))
481             return false;
482         if (containsVertex(v1))
483             return getParent(v1).equals(v2);
484         return isLeaf(v2) && v1 == null;
485     }
486   
487     /**
488      * @see edu.uci.ics.jung.graph.Graph#outDegree(java.lang.Object)
489      */
490     @Override
491     public int outDegree(V vertex) 
492     {
493         if (!containsVertex(vertex))
494             return 0;
495         List<E> out_edges = vertex_data.get(vertex).child_edges;
496         if (out_edges == null)
497         	return 0;
498         int degree = 0;
499         for (E e : out_edges)
500         	degree += (e == null) ? 0 : 1;
501         return degree;
502     }
503   
504     /**
505      * @see edu.uci.ics.jung.graph.Hypergraph#addEdge(java.lang.Object, java.util.Collection)
506      */
507     @Override
508     @SuppressWarnings("unchecked")
509 	public boolean addEdge(E edge, Collection<? extends V> vertices, EdgeType edge_type) 
510     {
511         if (edge == null || vertices == null)
512             throw new IllegalArgumentException("inputs may not be null");
513         if (vertices.size() != 2)
514             throw new IllegalArgumentException("'vertices' must contain " +
515             		"exactly 2 distinct vertices");
516     	this.validateEdgeType(edge_type);
517 		Pair<V> endpoints;
518 		if (vertices instanceof Pair)
519 			endpoints = (Pair<V>)vertices;
520 		else
521 			endpoints = new Pair<V>(vertices);
522 		V v1 = endpoints.getFirst();
523 		V v2 = endpoints.getSecond();
524 		if (v1.equals(v2))
525 			throw new IllegalArgumentException("Input vertices must be distinct");
526 		return addEdge(edge, v1, v2);
527     }
528   
529     /**
530      * @see edu.uci.ics.jung.graph.Hypergraph#addVertex(java.lang.Object)
531      */
532     public boolean addVertex(V vertex) 
533     {
534 		if(root == null) 
535 		{
536 			this.root = vertex;
537 			vertex_data.put(vertex, new VertexData(null, 0));
538 			this.height = 0;
539 			return true;
540 		} 
541 		else 
542 		{
543 			throw new UnsupportedOperationException("Unless you are setting " +
544 					"the root, use addEdge() or addChild()");
545 		}
546     }
547   
548     /**
549      * @see edu.uci.ics.jung.graph.Hypergraph#isIncident(java.lang.Object, java.lang.Object)
550      */
551     @Override
552     public boolean isIncident(V vertex, E edge) 
553     {
554         if (!containsVertex(vertex) || !containsEdge(edge))
555             return false;
556         return edge_vpairs.get(edge).contains(vertex);
557     }
558   
559     /**
560      * @see edu.uci.ics.jung.graph.Hypergraph#isNeighbor(java.lang.Object, java.lang.Object)
561      */
562     @Override
563     public boolean isNeighbor(V v1, V v2) 
564     {
565     	if (!containsVertex(v1) || !containsVertex(v2))
566     		return false;
567     	return getNeighbors(v1).contains(v2);
568     }
569   
570     /**
571      * @see edu.uci.ics.jung.graph.Hypergraph#containsEdge(java.lang.Object)
572      */
573     public boolean containsEdge(E edge) 
574     {
575     	return edge_vpairs.containsKey(edge);
576     }
577   
578     /**
579      * @see edu.uci.ics.jung.graph.Hypergraph#containsVertex(java.lang.Object)
580      */
581     public boolean containsVertex(V vertex) 
582     {
583     	return vertex_data.containsKey(vertex);
584     }
585   
586   
587     /**
588      * @see edu.uci.ics.jung.graph.Hypergraph#findEdge(java.lang.Object, java.lang.Object)
589      */
590     @Override
591     public E findEdge(V v1, V v2) 
592     {
593         if (!containsVertex(v1) || !containsVertex(v2))
594             return null;
595     	VertexData v1_data = vertex_data.get(v1);
596     	if (edge_vpairs.get(v1_data.parent_edge).getFirst().equals(v2))
597     		return v1_data.parent_edge;
598     	List<E> edges = v1_data.child_edges;
599     	if (edges == null)
600     		return null;
601     	for (E edge : edges)
602     		if (edge != null && edge_vpairs.get(edge).getSecond().equals(v2))
603     			return edge;
604     	return null;
605     }
606   
607     /**
608      * @see edu.uci.ics.jung.graph.Hypergraph#findEdgeSet(java.lang.Object, java.lang.Object)
609      */
610     @Override
611     public Collection<E> findEdgeSet(V v1, V v2) 
612     {
613     	E edge = findEdge(v1, v2);
614     	if (edge == null)
615     		return Collections.emptySet();
616     	else
617     		return Collections.singleton(edge);
618     }
619   
620     /**
621      * Returns the child of <code>vertex</code> at position <code>index</code> 
622      * in this tree, or <code>null</code> if it has no child at that position.
623      * @param vertex the vertex to query
624      * @param index the index of the child to return
625      * @return the child of <code>vertex</code> at position <code>index</code> 
626      * in this tree, or <code>null</code> if it has no child at that position
627      * @throws ArrayIndexOutOfBoundsException if <code>index</code> is not in 
628      * the range {@code [0, order-1]}
629      */
630     public V getChild(V vertex, int index)
631     {
632         if (index < 0 || index >= order)
633             throw new ArrayIndexOutOfBoundsException(index + " is not in [0, order-1]");
634         if (!containsVertex(vertex))
635             return null;
636         List<E> edges = vertex_data.get(vertex).child_edges;
637         if (edges == null)
638         	return null;
639         E edge = edges.get(index);
640         return edge == null ? null : edge_vpairs.get(edge).getSecond();
641     }
642     
643     /**
644      * @see edu.uci.ics.jung.graph.Hypergraph#getEdgeCount()
645      */
646     public int getEdgeCount() 
647     {
648     	return edge_vpairs.size();
649     }
650   
651     /**
652      * @see edu.uci.ics.jung.graph.Hypergraph#getEdges()
653      */
654     public Collection<E> getEdges() 
655     {
656     	return new ImmutableSet.Builder<E>().addAll(edge_vpairs.keySet()).build();
657     	//CollectionUtils.unmodifiableCollection(edge_vpairs.keySet());
658     }
659   
660     /**
661      * @see edu.uci.ics.jung.graph.Hypergraph#getIncidentCount(java.lang.Object)
662      */
663     @Override
664     public int getIncidentCount(E edge) 
665     {
666     	return 2;  // all tree edges have 2 incident vertices
667     }
668   
669     /**
670      * @see edu.uci.ics.jung.graph.Hypergraph#getIncidentEdges(java.lang.Object)
671      */
672     public Collection<E> getIncidentEdges(V vertex) 
673     {
674     	if (!containsVertex(vertex))
675     		return null;
676     	ArrayList<E> edges = new ArrayList<E>(order+1);
677     	VertexData v_data = vertex_data.get(vertex);
678     	if (v_data.parent_edge != null)
679     		edges.add(v_data.parent_edge);
680     	if (v_data.child_edges != null)
681     	{
682     		for (E edge : v_data.child_edges)
683     			if (edge != null)
684     				edges.add(edge);
685     	}
686     	if (edges.isEmpty())
687     		return Collections.emptySet();
688     	return Collections.unmodifiableCollection(edges);
689     }
690   
691     /**
692      * @see edu.uci.ics.jung.graph.Hypergraph#getIncidentVertices(java.lang.Object)
693      */
694     @Override
695     public Collection<V> getIncidentVertices(E edge) 
696     {
697     	return edge_vpairs.get(edge);
698     }
699   
700     /**
701      * @see edu.uci.ics.jung.graph.Hypergraph#getNeighborCount(java.lang.Object)
702      */
703     @Override
704     public int getNeighborCount(V vertex) 
705     {
706         if (!containsVertex(vertex))
707             return 0;
708     	return (vertex.equals(root) ? 0 : 1) + this.getChildCount(vertex);
709     }
710   
711     /**
712      * @see edu.uci.ics.jung.graph.Hypergraph#getNeighbors(java.lang.Object)
713      */
714     public Collection<V> getNeighbors(V vertex) 
715     {
716     	if (!containsVertex(vertex))
717     		return null;
718     	ArrayList<V> vertices = new ArrayList<V>(order+1);
719     	VertexData v_data = vertex_data.get(vertex);
720     	if (v_data.parent_edge != null)
721     		vertices.add(edge_vpairs.get(v_data.parent_edge).getFirst());
722     	if (v_data.child_edges != null)
723     	{
724     		for (E edge : v_data.child_edges)
725     			if (edge != null)
726     				vertices.add(edge_vpairs.get(edge).getSecond());
727     	}
728     	if (vertices.isEmpty())
729     		return Collections.emptySet();
730     	return Collections.unmodifiableCollection(vertices);
731     }
732   
733     /**
734      * @see edu.uci.ics.jung.graph.Hypergraph#getVertexCount()
735      */
736     public int getVertexCount() 
737     {
738     	return vertex_data.size();
739     }
740   
741     /**
742      * @see edu.uci.ics.jung.graph.Hypergraph#getVertices()
743      */
744     public Collection<V> getVertices() 
745     {
746       return new ImmutableSet.Builder<V>().addAll(vertex_data.keySet()).build();
747       //CollectionUtils.unmodifiableCollection(vertex_data.keySet());
748     }
749   
750     /**
751      * @see edu.uci.ics.jung.graph.Hypergraph#removeEdge(java.lang.Object)
752      */
753     public boolean removeEdge(E edge) 
754     {
755     	if (!containsEdge(edge))
756     		return false;
757     	
758     	removeVertex(edge_vpairs.get(edge).getSecond());
759     	edge_vpairs.remove(edge);
760     	
761     	return true;
762     }
763 
764     /**
765      * @see edu.uci.ics.jung.graph.Hypergraph#removeVertex(java.lang.Object)
766      */
767     public boolean removeVertex(V vertex) 
768     {
769     	if (!containsVertex(vertex))
770     		return false;
771     	
772     	// recursively remove all of vertex's children
773 		for(V v : getChildren(vertex))
774 			removeVertex(v);
775 
776 		E parent_edge = getParentEdge(vertex);
777 		edge_vpairs.remove(parent_edge);
778 		List<E> edges = vertex_data.get(vertex).child_edges;
779 		if (edges != null)
780 			for (E edge : edges)
781 				edge_vpairs.remove(edge);
782 		vertex_data.remove(vertex);
783 		
784 		return true;
785     }
786 	
787 	protected class VertexData
788 	{
789 	    List<E> child_edges;
790 		E parent_edge;
791 		int depth;
792 		
793 		protected VertexData(E parent_edge, int depth)
794 		{
795 			this.parent_edge = parent_edge;
796 			this.depth = depth;
797 		}
798 	}
799 
800 	@Override
801 	public boolean addEdge(E edge, Pair<? extends V> endpoints, EdgeType edgeType) 
802 	{
803 	    if (edge == null || endpoints == null)
804 	        throw new IllegalArgumentException("inputs must not be null");
805 		return addEdge(edge, endpoints.getFirst(), endpoints.getSecond(), edgeType);
806 	}
807 }