View Javadoc
1   /*
2    * Created on Apr 15, 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.util.ArrayList;
15  import java.util.Collection;
16  import java.util.Collections;
17  import java.util.HashMap;
18  import java.util.HashSet;
19  import java.util.Map;
20  
21  import com.google.common.base.Supplier;
22  
23  import edu.uci.ics.jung.graph.util.EdgeType;
24  import edu.uci.ics.jung.graph.util.Pair;
25  
26  /**
27   * An implementation of <code>Graph</code> that is suitable for sparse graphs and
28   * permits both directed and undirected edges.
29   */
30  @SuppressWarnings("serial")
31  public class SparseGraph<V,E> 
32      extends AbstractGraph<V,E> 
33      implements Graph<V,E>
34  {
35      /**
36       * @param <V> the vertex type for the graph Supplier
37       * @param <E> the edge type for the graph Supplier
38       * @return a {@code Supplier} that creates an instance of this graph type.
39       */
40      public static <V,E> Supplier<Graph<V,E>> getFactory() 
41      { 
42          return new Supplier<Graph<V,E>> () 
43          {
44              public Graph<V,E> get() 
45              {
46                  return new SparseGraph<V,E>();
47              }
48          };
49      }
50  
51      protected static final int INCOMING = 0;
52      protected static final int OUTGOING = 1;
53      protected static final int INCIDENT = 2;
54      
55      protected Map<V, Map<V,E>[]> vertex_maps; // Map of vertices to adjacency maps of vertices to {incoming, outgoing, incident} edges
56      protected Map<E, Pair<V>> directed_edges;    // Map of directed edges to incident vertex sets
57      protected Map<E, Pair<V>> undirected_edges;    // Map of undirected edges to incident vertex sets
58      
59      /**
60       * Creates an instance.
61       */
62      public SparseGraph()
63      {
64          vertex_maps = new HashMap<V, Map<V,E>[]>();
65          directed_edges = new HashMap<E, Pair<V>>();
66          undirected_edges = new HashMap<E, Pair<V>>();
67      }
68      
69      @Override
70      public E findEdge(V v1, V v2)
71      {
72          if (!containsVertex(v1) || !containsVertex(v2))
73              return null;
74          E edge = vertex_maps.get(v1)[OUTGOING].get(v2);
75          if (edge == null)
76              edge = vertex_maps.get(v1)[INCIDENT].get(v2);
77          return edge;
78      }
79  
80      @Override
81      public Collection<E> findEdgeSet(V v1, V v2)
82      {
83          if (!containsVertex(v1) || !containsVertex(v2))
84              return null;
85          Collection<E> edges = new ArrayList<E>(2);
86          E e1 = vertex_maps.get(v1)[OUTGOING].get(v2);
87          if (e1 != null)
88              edges.add(e1);
89          E e2 = vertex_maps.get(v1)[INCIDENT].get(v2);
90          if (e1 != null)
91              edges.add(e2);
92          return edges;
93      }
94      
95      @Override
96      public boolean addEdge(E edge, Pair<? extends V> endpoints, EdgeType edgeType)
97      {
98          Pair<V> new_endpoints = getValidatedEndpoints(edge, endpoints);
99          if (new_endpoints == null)
100             return false;
101         
102         V v1 = new_endpoints.getFirst();
103         V v2 = new_endpoints.getSecond();
104         
105         // undirected edges and directed edges are not considered to be parallel to each other,
106         // so as long as anything that's returned by findEdge is not of the same type as
107         // edge, we're fine
108         E connection = findEdge(v1, v2);
109         if (connection != null && getEdgeType(connection) == edgeType)
110             return false;
111 
112         if (!containsVertex(v1))
113             this.addVertex(v1);
114         
115         if (!containsVertex(v2))
116             this.addVertex(v2);
117         
118         // map v1 to <v2, edge> and vice versa
119         if (edgeType == EdgeType.DIRECTED)
120         {
121             vertex_maps.get(v1)[OUTGOING].put(v2, edge);
122             vertex_maps.get(v2)[INCOMING].put(v1, edge);
123             directed_edges.put(edge, new_endpoints);
124         }
125         else
126         {
127             vertex_maps.get(v1)[INCIDENT].put(v2, edge);
128             vertex_maps.get(v2)[INCIDENT].put(v1, edge);
129             undirected_edges.put(edge, new_endpoints);
130         }
131         
132         return true;
133     }
134 
135     
136     
137     public Collection<E> getInEdges(V vertex)
138     {
139         if (!containsVertex(vertex))
140             return null;
141         
142         // combine directed inedges and undirected
143         Collection<E> in = new HashSet<E>(vertex_maps.get(vertex)[INCOMING].values());
144         in.addAll(vertex_maps.get(vertex)[INCIDENT].values());
145         return Collections.unmodifiableCollection(in);
146     }
147 
148     public Collection<E> getOutEdges(V vertex)
149     {
150         if (!containsVertex(vertex))
151             return null;
152         
153         // combine directed outedges and undirected
154         Collection<E> out = new HashSet<E>(vertex_maps.get(vertex)[OUTGOING].values());
155         out.addAll(vertex_maps.get(vertex)[INCIDENT].values());
156         return Collections.unmodifiableCollection(out);
157     }
158 
159     public Collection<V> getPredecessors(V vertex)
160     {
161         if (!containsVertex(vertex))
162             return null;
163         
164         // consider directed inedges and undirected
165         Collection<V> preds = new HashSet<V>(vertex_maps.get(vertex)[INCOMING].keySet());
166         preds.addAll(vertex_maps.get(vertex)[INCIDENT].keySet());
167         return Collections.unmodifiableCollection(preds);
168     }
169 
170     public Collection<V> getSuccessors(V vertex)
171     {
172         if (!containsVertex(vertex))
173             return null;
174         
175         // consider directed outedges and undirected
176         Collection<V> succs = new HashSet<V>(vertex_maps.get(vertex)[OUTGOING].keySet());
177         succs.addAll(vertex_maps.get(vertex)[INCIDENT].keySet());
178         return Collections.unmodifiableCollection(succs);
179     }
180 
181     public Collection<E> getEdges(EdgeType edgeType)
182     {
183         if (edgeType == EdgeType.DIRECTED)
184             return Collections.unmodifiableCollection(directed_edges.keySet());
185         else if (edgeType == EdgeType.UNDIRECTED)
186             return Collections.unmodifiableCollection(undirected_edges.keySet());
187         else
188             return null;
189     }
190 
191     public Pair<V> getEndpoints(E edge)
192     {
193         Pair<V> endpoints;
194         endpoints = directed_edges.get(edge);
195         if (endpoints == null)
196             return undirected_edges.get(edge);
197         else
198             return endpoints;
199     }
200 
201     public EdgeType getEdgeType(E edge)
202     {
203         if (directed_edges.containsKey(edge))
204             return EdgeType.DIRECTED;
205         else if (undirected_edges.containsKey(edge))
206             return EdgeType.UNDIRECTED;
207         else
208             return null;
209     }
210 
211     public V getSource(E directed_edge)
212     {
213         if (getEdgeType(directed_edge) == EdgeType.DIRECTED)
214             return directed_edges.get(directed_edge).getFirst();
215         else
216             return null;
217     }
218 
219     public V getDest(E directed_edge)
220     {
221         if (getEdgeType(directed_edge) == EdgeType.DIRECTED)
222             return directed_edges.get(directed_edge).getSecond();
223         else
224             return null;
225     }
226 
227     public boolean isSource(V vertex, E edge)
228     {
229         if (!containsVertex(vertex) || !containsEdge(edge))
230             return false;
231         
232         V source = getSource(edge);
233         if (source != null)
234             return source.equals(vertex);
235         else
236             return false;
237     }
238 
239     public boolean isDest(V vertex, E edge)
240     {
241         if (!containsVertex(vertex) || !containsEdge(edge))
242             return false;
243         
244         V dest = getDest(edge);
245         if (dest != null)
246             return dest.equals(vertex);
247         else
248             return false;
249     }
250 
251     public Collection<E> getEdges()
252     {
253         Collection<E> edges = new ArrayList<E>(directed_edges.keySet());
254         edges.addAll(undirected_edges.keySet());
255         return Collections.unmodifiableCollection(edges);
256     }
257 
258     public Collection<V> getVertices()
259     {
260         return Collections.unmodifiableCollection(vertex_maps.keySet());
261     }
262 
263     public boolean containsVertex(V vertex)
264     {
265         return vertex_maps.containsKey(vertex);
266     }
267 
268     public boolean containsEdge(E edge)
269     {
270         return directed_edges.containsKey(edge) || undirected_edges.containsKey(edge);
271     }
272 
273     public int getEdgeCount()
274     {
275         return directed_edges.size() + undirected_edges.size();
276     }
277 
278     public int getVertexCount()
279     {
280         return vertex_maps.size();
281     }
282 
283     public Collection<V> getNeighbors(V vertex)
284     {
285         if (!containsVertex(vertex))
286             return null;
287         // consider directed edges and undirected edges
288         Collection<V> neighbors = new HashSet<V>(vertex_maps.get(vertex)[INCOMING].keySet());
289         neighbors.addAll(vertex_maps.get(vertex)[OUTGOING].keySet());
290         neighbors.addAll(vertex_maps.get(vertex)[INCIDENT].keySet());
291         return Collections.unmodifiableCollection(neighbors);
292     }
293 
294     public Collection<E> getIncidentEdges(V vertex)
295     {
296         if (!containsVertex(vertex))
297             return null;
298         Collection<E> incident = new HashSet<E>(vertex_maps.get(vertex)[INCOMING].values());
299         incident.addAll(vertex_maps.get(vertex)[OUTGOING].values());
300         incident.addAll(vertex_maps.get(vertex)[INCIDENT].values());
301         return Collections.unmodifiableCollection(incident);
302     }
303 
304     @SuppressWarnings("unchecked")
305     public boolean addVertex(V vertex)
306     {
307         if(vertex == null) {
308             throw new IllegalArgumentException("vertex may not be null");
309         }
310         if (!containsVertex(vertex)) {
311             vertex_maps.put(vertex, new HashMap[]{new HashMap<V,E>(), new HashMap<V,E>(), new HashMap<V,E>()});
312             return true;
313         } else {
314             return false;
315         }
316     }
317 
318     public boolean removeVertex(V vertex)
319     {
320         if (!containsVertex(vertex))
321             return false;
322         
323         // copy to avoid concurrent modification in removeEdge
324         Collection<E> incident = new ArrayList<E>(getIncidentEdges(vertex));
325         
326         for (E edge : incident)
327             removeEdge(edge);
328         
329         vertex_maps.remove(vertex);
330         
331         return true;
332     }
333 
334     public boolean removeEdge(E edge)
335     {
336         if (!containsEdge(edge)) 
337             return false;
338         
339         Pair<V> endpoints = getEndpoints(edge);
340         V v1 = endpoints.getFirst();
341         V v2 = endpoints.getSecond();
342         
343         // remove edge from incident vertices' adjacency maps
344         if (getEdgeType(edge) == EdgeType.DIRECTED)
345         {
346             vertex_maps.get(v1)[OUTGOING].remove(v2);
347             vertex_maps.get(v2)[INCOMING].remove(v1);
348             directed_edges.remove(edge);
349         }
350         else
351         {
352             vertex_maps.get(v1)[INCIDENT].remove(v2);
353             vertex_maps.get(v2)[INCIDENT].remove(v1);
354             undirected_edges.remove(edge);
355         }
356 
357         return true;
358     }
359     
360     public int getEdgeCount(EdgeType edge_type)
361     {
362         if (edge_type == EdgeType.DIRECTED)
363             return directed_edges.size();
364         if (edge_type == EdgeType.UNDIRECTED)
365             return undirected_edges.size();
366         return 0;
367     }
368 
369 	public EdgeType getDefaultEdgeType() 
370 	{
371 		return EdgeType.UNDIRECTED;
372 	}
373 }