View Javadoc
1   /*
2    * Created on Feb 4, 2007
3    *
4    * Copyright (c) 2007, 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.io.Serializable;
15  import java.util.ArrayList;
16  import java.util.Collection;
17  import java.util.Collections;
18  import java.util.HashMap;
19  import java.util.HashSet;
20  import java.util.Map;
21  import java.util.Set;
22  
23  import com.google.common.base.Supplier;
24  
25  import edu.uci.ics.jung.graph.util.EdgeType;
26  
27  /**
28   * An implementation of <code>Hypergraph</code> that is suitable for sparse graphs and 
29   * permits parallel edges.
30   */
31  @SuppressWarnings("serial")
32  public class SetHypergraph<V,H> 
33  	implements Hypergraph<V,H>, MultiGraph<V,H>, Serializable
34  {
35      protected Map<V, Set<H>> vertices; // Map of vertices to incident hyperedge sets
36      protected Map<H, Set<V>> edges;    // Map of hyperedges to incident vertex sets
37   
38      /**
39       * Returns a <code>Factory</code> which creates instances of this class.
40       * @param <V> vertex type of the hypergraph to be created
41       * @param <H> edge type of the hypergraph to be created
42       * @return a <code>Factory</code> which creates instances of this class
43       */
44      public static <V,H> Supplier<Hypergraph<V,H>> getFactory() {
45          return new Supplier<Hypergraph<V,H>> () {
46              public Hypergraph<V,H> get() {
47                  return new SetHypergraph<V,H>();
48              }
49          };
50      }
51  
52      /**
53       * Creates a <code>SetHypergraph</code> and initializes the internal data structures.
54       */
55      public SetHypergraph()
56      {
57          vertices = new HashMap<V, Set<H>>();
58          edges = new HashMap<H, Set<V>>();
59      }
60      
61      /**
62       * Adds <code>hyperedge</code> to this graph and connects them to the vertex collection <code>to_attach</code>.
63       * Any vertices in <code>to_attach</code> that appear more than once will only appear once in the
64       * incident vertex collection for <code>hyperedge</code>, that is, duplicates will be ignored.
65       * 
66       * @see Hypergraph#addEdge(Object, Collection)
67       */
68      public boolean addEdge(H hyperedge, Collection<? extends V> to_attach)
69      {
70          if (hyperedge == null)
71              throw new IllegalArgumentException("input hyperedge may not be null");
72          
73          if (to_attach == null)
74              throw new IllegalArgumentException("endpoints may not be null");
75  
76          if(to_attach.contains(null)) 
77              throw new IllegalArgumentException("cannot add an edge with a null endpoint");
78          
79          Set<V> new_endpoints = new HashSet<V>(to_attach);
80          if (edges.containsKey(hyperedge))
81          {
82              Collection<V> attached = edges.get(hyperedge);
83              if (!attached.equals(new_endpoints))
84              {
85                  throw new IllegalArgumentException("Edge " + hyperedge + 
86                          " exists in this graph with endpoints " + attached);
87              }
88              else
89                  return false;
90          }
91          edges.put(hyperedge, new_endpoints);
92          for (V v : to_attach)
93          {
94              // add v if it's not already in the graph
95              addVertex(v);
96              
97              // associate v with hyperedge
98              vertices.get(v).add(hyperedge);
99          }
100         return true;
101     }
102     
103     /**
104      * @see Hypergraph#addEdge(Object, Collection, EdgeType)
105      */
106     public boolean addEdge(H hyperedge, Collection<? extends V> to_attach, 
107     	EdgeType edge_type)
108     {
109     	if (edge_type != EdgeType.UNDIRECTED)
110     		throw new IllegalArgumentException("Edge type for this " +
111     				"implementation must be EdgeType.HYPER, not " + 
112     				edge_type);
113     	return addEdge(hyperedge, to_attach);
114     }
115     
116     /**
117      * @see Hypergraph#getEdgeType(Object)
118      */
119     public EdgeType getEdgeType(H edge)
120     {
121         if (containsEdge(edge))
122             return EdgeType.UNDIRECTED;
123         else
124             return null;
125     }
126     
127     public boolean containsVertex(V vertex) {
128     	return vertices.keySet().contains(vertex);
129     }
130     
131     public boolean containsEdge(H edge) {
132     	return edges.keySet().contains(edge);
133     }
134 
135     public Collection<H> getEdges()
136     {
137         return edges.keySet();
138     }
139     
140     public Collection<V> getVertices()
141     {
142         return vertices.keySet();
143     }
144 
145     public int getEdgeCount()
146     {
147         return edges.size();
148     }
149     
150     public int getVertexCount()
151     {
152         return vertices.size();
153     }
154     
155     public Collection<V> getNeighbors(V vertex)
156     {
157         if (!containsVertex(vertex))
158             return null;
159         
160         Set<V> neighbors = new HashSet<V>();
161         for (H hyperedge : vertices.get(vertex))
162         {
163             neighbors.addAll(edges.get(hyperedge));
164         }
165         return neighbors;
166     }
167     
168     public Collection<H> getIncidentEdges(V vertex)
169     {
170         return vertices.get(vertex);
171     }
172     
173     public Collection<V> getIncidentVertices(H edge)
174     {
175         return edges.get(edge);
176     }
177     
178     public H findEdge(V v1, V v2)
179     {
180         if (!containsVertex(v1) || !containsVertex(v2))
181             return null;
182         
183         for (H h : getIncidentEdges(v1))
184         {
185             if (isIncident(v2, h))
186                 return h;
187         }
188         return null;
189     }
190 
191     public Collection<H> findEdgeSet(V v1, V v2)
192     {
193         if (!containsVertex(v1) || !containsVertex(v2))
194             return null;
195         
196         Collection<H> edges = new ArrayList<H>();
197         for (H h : getIncidentEdges(v1))
198         {
199             if (isIncident(v2, h))
200                 edges.add(h);
201         }
202         return Collections.unmodifiableCollection(edges);
203     }
204     
205     public boolean addVertex(V vertex)
206     {
207     	if(vertex == null) 
208     	    throw new IllegalArgumentException("cannot add a null vertex");
209         if (containsVertex(vertex))
210             return false;
211         vertices.put(vertex, new HashSet<H>());
212         return true;
213     }
214     
215     public boolean removeVertex(V vertex)
216     {
217         if (!containsVertex(vertex))
218             return false;
219         for (H hyperedge : vertices.get(vertex))
220         {
221             edges.get(hyperedge).remove(vertex);
222         }
223         vertices.remove(vertex);
224         return true;
225     }
226     
227     public boolean removeEdge(H hyperedge)
228     {
229         if (!containsEdge(hyperedge))
230             return false;
231         for (V vertex : edges.get(hyperedge))
232         {
233             vertices.get(vertex).remove(hyperedge);
234         }
235         edges.remove(hyperedge);
236         return true;
237     }
238     
239     public boolean isNeighbor(V v1, V v2)
240     {
241         if (!containsVertex(v1) || !containsVertex(v2))
242             return false;
243         
244         if (vertices.get(v2).isEmpty())
245             return false;
246         for (H hyperedge : vertices.get(v1))
247         {
248             if (edges.get(hyperedge).contains(v2))
249                 return true;
250         }
251         return false;
252     }
253     
254     public boolean isIncident(V vertex, H edge)
255     {
256         if (!containsVertex(vertex) || !containsEdge(edge))
257             return false;
258         
259         return vertices.get(vertex).contains(edge);
260     }
261     
262     public int degree(V vertex)
263     {
264         if (!containsVertex(vertex))
265             return 0;
266         
267         return vertices.get(vertex).size();
268     }
269     
270     public int getNeighborCount(V vertex)
271     {
272         if (!containsVertex(vertex))
273             return 0;
274         
275         return getNeighbors(vertex).size();
276     }
277     
278     public int getIncidentCount(H edge)
279     {
280         if (!containsEdge(edge))
281             return 0;
282         
283         return edges.get(edge).size();
284     }
285 
286     public int getEdgeCount(EdgeType edge_type)
287     {
288         if (edge_type == EdgeType.UNDIRECTED)
289             return edges.size();
290         return 0;
291     }
292 
293     public Collection<H> getEdges(EdgeType edge_type)
294     {
295         if (edge_type == EdgeType.UNDIRECTED)
296             return edges.keySet();
297         return null;
298     }
299 
300 	public EdgeType getDefaultEdgeType() 
301 	{
302 		return EdgeType.UNDIRECTED;
303 	}
304 
305 	public Collection<H> getInEdges(V vertex) 
306 	{
307 		return getIncidentEdges(vertex);
308 	}
309 
310 	public Collection<H> getOutEdges(V vertex) 
311 	{
312 		return getIncidentEdges(vertex);
313 	}
314 
315 	public int inDegree(V vertex) 
316 	{
317 		return degree(vertex);
318 	}
319 
320 	public int outDegree(V vertex) 
321 	{
322 		return degree(vertex);
323 	}
324 
325 	public V getDest(H directed_edge) 
326 	{
327 		return null;
328 	}
329 
330 	public V getSource(H directed_edge) 
331 	{
332 		return null;
333 	}
334 
335 	public Collection<V> getPredecessors(V vertex) 
336 	{
337 		return getNeighbors(vertex);
338 	}
339 
340 	public Collection<V> getSuccessors(V vertex) 
341 	{
342 		return getNeighbors(vertex);
343 	}
344 }