View Javadoc

1   /*
2    * Created on Oct 18, 2005
3    *
4    * Copyright (c) 2005, the JUNG Project and the Regents of the University 
5    * of California
6    * All rights reserved.
7    *
8    * This software is open-source under the BSD license; see either
9    * "license.txt" or
10   * http://jung.sourceforge.net/license.txt for a description.
11   */
12  package edu.uci.ics.jung.graph;
13  
14  import java.util.Collection;
15  import java.util.Collections;
16  import java.util.HashMap;
17  import java.util.HashSet;
18  import java.util.Map;
19  import java.util.Set;
20  
21  import org.apache.commons.collections15.Factory;
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
28   * and permits directed, undirected, and parallel edges.
29   */
30  @SuppressWarnings("serial")
31  public class SparseMultigraph<V,E> 
32      extends AbstractGraph<V,E>
33      implements MultiGraph<V,E> {
34  	
35      /**
36       * Returns a {@code Factory} that creates an instance of this graph type.
37       * @param <V> the vertex type for the graph factory
38       * @param <E> the edge type for the graph factory
39       */
40  	public static <V,E> Factory<Graph<V,E>> getFactory() { 
41  		return new Factory<Graph<V,E>> () {
42  			public Graph<V,E> create() {
43  				return new SparseMultigraph<V,E>();
44  			}
45  		};
46  	}
47      
48      // TODO: refactor internal representation: right now directed edges each have two references (in vertices and directedEdges)
49      // and undirected also have two (incoming and outgoing).  
50      protected Map<V, Pair<Set<E>>> vertices; // Map of vertices to Pair of adjacency sets {incoming, outgoing}
51      protected Map<E, Pair<V>> edges;            // Map of edges to incident vertex pairs
52      protected Set<E> directedEdges;
53  
54      /**
55       * Creates a new instance.
56       */
57      public SparseMultigraph()
58      {
59          vertices = new HashMap<V, Pair<Set<E>>>();
60          edges = new HashMap<E, Pair<V>>();
61          directedEdges = new HashSet<E>();
62      }
63  
64      public Collection<E> getEdges()
65      {
66          return Collections.unmodifiableCollection(edges.keySet());
67      }
68  
69      public Collection<V> getVertices()
70      {
71          return Collections.unmodifiableCollection(vertices.keySet());
72      }
73      
74      public boolean containsVertex(V vertex) {
75      	return vertices.keySet().contains(vertex);
76      }
77      
78      public boolean containsEdge(E edge) {
79      	return edges.keySet().contains(edge);
80      }
81  
82      protected Collection<E> getIncoming_internal(V vertex)
83      {
84          return vertices.get(vertex).getFirst();
85      }
86      
87      protected Collection<E> getOutgoing_internal(V vertex)
88      {
89          return vertices.get(vertex).getSecond();
90      }
91      
92      public boolean addVertex(V vertex) {
93          if(vertex == null) {
94              throw new IllegalArgumentException("vertex may not be null");
95          }
96          if (!vertices.containsKey(vertex)) {
97              vertices.put(vertex, new Pair<Set<E>>(new HashSet<E>(), new HashSet<E>()));
98              return true;
99          } else {
100         	return false;
101         }
102     }
103 
104     public boolean removeVertex(V vertex) {
105         if (!containsVertex(vertex))
106             return false;
107         
108         // copy to avoid concurrent modification in removeEdge
109         Set<E> incident = new HashSet<E>(getIncoming_internal(vertex));
110         incident.addAll(getOutgoing_internal(vertex));
111         
112         for (E edge : incident)
113             removeEdge(edge);
114         
115         vertices.remove(vertex);
116         
117         return true;
118     }
119     
120     @Override
121     public boolean addEdge(E edge, Pair<? extends V> endpoints, EdgeType edgeType) {
122 
123         Pair<V> new_endpoints = getValidatedEndpoints(edge, endpoints);
124         if (new_endpoints == null)
125             return false;
126         
127         V v1 = new_endpoints.getFirst();
128         V v2 = new_endpoints.getSecond();
129         
130         if (!vertices.containsKey(v1))
131             this.addVertex(v1);
132         
133         if (!vertices.containsKey(v2))
134             this.addVertex(v2);
135         
136 
137         vertices.get(v1).getSecond().add(edge);        
138         vertices.get(v2).getFirst().add(edge);        
139         edges.put(edge, new_endpoints);
140         if(edgeType == EdgeType.DIRECTED) {
141         	directedEdges.add(edge);
142         } else {
143           vertices.get(v1).getFirst().add(edge);        
144           vertices.get(v2).getSecond().add(edge);        
145         }
146         return true;
147     }
148     
149     public boolean removeEdge(E edge)
150     {
151         if (!containsEdge(edge)) {
152             return false;
153         }
154         
155         Pair<V> endpoints = getEndpoints(edge);
156         V v1 = endpoints.getFirst();
157         V v2 = endpoints.getSecond();
158         
159         // remove edge from incident vertices' adjacency sets
160         vertices.get(v1).getSecond().remove(edge);
161         vertices.get(v2).getFirst().remove(edge);
162 
163         if(directedEdges.remove(edge) == false) {
164         	
165         	// its an undirected edge, remove the other ends
166             vertices.get(v2).getSecond().remove(edge);
167             vertices.get(v1).getFirst().remove(edge);
168         }
169         edges.remove(edge);
170         return true;
171     }
172     
173     public Collection<E> getInEdges(V vertex)
174     {
175     	if (!containsVertex(vertex))
176     		return null;
177         return Collections.unmodifiableCollection(vertices.get(vertex).getFirst());
178     }
179 
180     public Collection<E> getOutEdges(V vertex)
181     {
182     	if (!containsVertex(vertex))
183     		return null;
184         return Collections.unmodifiableCollection(vertices.get(vertex).getSecond());
185     }
186 
187     // TODO: this will need to get changed if we modify the internal representation
188     public Collection<V> getPredecessors(V vertex)
189     {
190     	if (!containsVertex(vertex))
191     		return null;
192 
193         Set<V> preds = new HashSet<V>();
194         for (E edge : getIncoming_internal(vertex)) {
195         	if(getEdgeType(edge) == EdgeType.DIRECTED) {
196         		preds.add(this.getSource(edge));
197         	} else {
198         		preds.add(getOpposite(vertex, edge));
199         	}
200         }
201         return Collections.unmodifiableCollection(preds);
202     }
203 
204     // TODO: this will need to get changed if we modify the internal representation
205     public Collection<V> getSuccessors(V vertex)
206     {
207     	if (!containsVertex(vertex))
208     		return null;
209         Set<V> succs = new HashSet<V>();
210         for (E edge : getOutgoing_internal(vertex)) {
211         	if(getEdgeType(edge) == EdgeType.DIRECTED) {
212         		succs.add(this.getDest(edge));
213         	} else {
214         		succs.add(getOpposite(vertex, edge));
215         	}
216         }
217         return Collections.unmodifiableCollection(succs);
218     }
219 
220     public Collection<V> getNeighbors(V vertex)
221     {
222     	if (!containsVertex(vertex))
223     		return null;
224         Collection<V> out = new HashSet<V>();
225         out.addAll(this.getPredecessors(vertex));
226         out.addAll(this.getSuccessors(vertex));
227         return out;
228     }
229 
230     public Collection<E> getIncidentEdges(V vertex)
231     {
232     	if (!containsVertex(vertex))
233     		return null;
234         Collection<E> out = new HashSet<E>();
235         out.addAll(this.getInEdges(vertex));
236         out.addAll(this.getOutEdges(vertex));
237         return out;
238     }
239 
240     @Override
241     public E findEdge(V v1, V v2)
242     {
243     	if (!containsVertex(v1) || !containsVertex(v2))
244     		return null;
245         for (E edge : getOutgoing_internal(v1))
246             if (this.getOpposite(v1, edge).equals(v2))
247                 return edge;
248         
249         return null;
250     }
251 
252     public Pair<V> getEndpoints(E edge)
253     {
254         return edges.get(edge);
255     }
256 
257     public V getSource(E edge) {
258     	if(directedEdges.contains(edge)) {
259     		return this.getEndpoints(edge).getFirst();
260     	}
261     	return null;
262     }
263 
264     public V getDest(E edge) {
265     	if(directedEdges.contains(edge)) {
266     		return this.getEndpoints(edge).getSecond();
267     	}
268     	return null;
269     }
270 
271     public boolean isSource(V vertex, E edge) {
272     	if (!containsEdge(edge) || !containsVertex(vertex))
273     		return false;
274         return getSource(edge).equals(vertex);
275     }
276 
277     public boolean isDest(V vertex, E edge) {
278     	if (!containsEdge(edge) || !containsVertex(vertex))
279     		return false;
280         return getDest(edge).equals(vertex);
281     }
282 
283     public EdgeType getEdgeType(E edge) {
284     	return directedEdges.contains(edge) ?
285     		EdgeType.DIRECTED :
286     			EdgeType.UNDIRECTED;
287     }
288 
289 	@SuppressWarnings("unchecked")
290 	public Collection<E> getEdges(EdgeType edgeType) {
291 		if(edgeType == EdgeType.DIRECTED) {
292 			return Collections.unmodifiableSet(this.directedEdges);
293 		} else if(edgeType == EdgeType.UNDIRECTED) {
294 			Collection<E> edges = new HashSet<E>(getEdges());
295 			edges.removeAll(directedEdges);
296 			return edges;
297 		} else {
298 			return Collections.EMPTY_SET;
299 		}
300 		
301 	}
302 
303 	public int getEdgeCount() {
304 		return edges.keySet().size();
305 	}
306 
307 	public int getVertexCount() {
308 		return vertices.keySet().size();
309 	}
310 
311     public int getEdgeCount(EdgeType edge_type)
312     {
313         return getEdges(edge_type).size();
314     }
315 
316 	public EdgeType getDefaultEdgeType() 
317 	{
318 		return EdgeType.UNDIRECTED;
319 	}
320 }