package jadex.tools.comanalyzer.graph; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.commons.collections15.Factory; import edu.uci.ics.jung.graph.Graph; import edu.uci.ics.jung.graph.SparseGraph; import edu.uci.ics.jung.graph.util.EdgeType; import edu.uci.ics.jung.graph.util.Pair; /** * Implementation of an Graph that can be used as a simple or a multi graph with * directed and undirected edges. */ public class MultidirectedMultiGraph extends SparseGraph implements Graph, Serializable { //-------- static part -------- /** * Returns the factory for the graph. * * @param <V> The vertex type. * @param <E> The edge type. * @return The Factory for the graph.. */ public static Factory getFactory() { return new Factory() { public Object create() { return new MultidirectedMultiGraph(); } }; } /** * Returns a new MultidirectedMultiGraph. * @param <V> The vertex type. * @param <E> The edge type. * @return The MultidirectedMultiGraph. */ public static Graph create() { return new MultidirectedMultiGraph(); }; // -------- constants -------- /** Indicates incoming edges in the map */ protected static final int INCOMING = 0; /** Indicates outgoing edges in the map */ protected static final int OUTGOING = 1; /** Indicates incident (undirected) edges in the map */ protected static final int INCIDENT = 2; /** * Map of vertices to adjacency maps of vertices to {incoming, outgoing, * incident} edges */ protected Map vertex_maps; /** Map of directed edges to incident vertex sets */ protected Map directed_edges; // /** Map of undirected edges to incident vertex sets */ protected Map undirected_edges; //-------- constructor -------- /** * Creates a new graph. */ public MultidirectedMultiGraph() { vertex_maps = new HashMap(); directed_edges = new HashMap(); undirected_edges = new HashMap(); } //-------- Graph interface -------- /** * Adds a directed edge to the graph. * * @param edge The edge. * @param endpoints The endpoints. * @return <code>true</code> if success. */ public boolean addEdge(Object edge, Pair endpoints) { return addEdge(edge, endpoints, EdgeType.DIRECTED); } /** * Adds a edge to the graph with a specific edge type. * * @param edge The edge. * @param endpoints The endpoints. * @param edgeType The edge type. * @return <code>true</code> if success. */ public boolean addEdge(Object edge, Pair endpoints, EdgeType edgeType) { Pair new_endpoints = getValidatedEndpoints(edge, endpoints); if(new_endpoints == null) { return false; } Object v1 = new_endpoints.getFirst(); Object v2 = new_endpoints.getSecond(); if(!containsVertex(v1)) this.addVertex(v1); if(!containsVertex(v2)) this.addVertex(v2); // if(edgeType == EdgeType.DIRECTED) { getOutgoing_internal(v1).add(edge); getIncoming_internal(v2).add(edge); directed_edges.put(edge, new_endpoints); } else { getIncident_internal(v1).add(edge); getIncident_internal(v2).add(edge); undirected_edges.put(edge, new_endpoints); } return true; } /** * Adds a directed edge to the graph. * * @param edge The edge. * @param v1 The first vertex. * @param v2 The second vertex. * @return <code>true</code> if success. */ public boolean addEdge(Object e, Object v1, Object v2) { return addEdge(e, new Pair(v1, v2)); } /** * Adds a edge to the graph with a specific edge type. * * @param edge The edge. * @param v1 The first vertex. * @param v2 The second vertex.. * @param edgeType The edge type. * @return <code>true</code> if success. */ public boolean addEdge(Object e, Object v1, Object v2, EdgeType edgeType) { return addEdge(e, new Pair(v1, v2), edgeType); } /** * Returns the first edge between the two vertices. * * @param v1 The first vertex. * @param v2 The second vertex. * @return The edge or <code>null</code> if there is no incident edge * between the vertices. */ public Object findEdge(Object v1, Object v2) { if(!containsVertex(v1) || !containsVertex(v2)) return null; for(Iterator it = getOutEdges(v1).iterator(); it.hasNext();) { Object e = it.next(); if(getOpposite(v1, e).equals(v2)) return e; } return null; } /** * Returns a collection of edges between the two vertices. * * @param v1 The first vertex. * @param v2 The second vertex. * @return The collection of edges or <code>null</code> if there is no * incident edge between the vertices. */ public Collection findEdgeSet(Object v1, Object v2) { if(!containsVertex(v1) || !containsVertex(v2)) return null; Collection edges = new ArrayList(); for(Iterator it = getOutEdges(v1).iterator(); it.hasNext();) { Object e = it.next(); if(getOpposite(v1, e).equals(v2)) edges.add(e); } return Collections.unmodifiableCollection(edges); } /** * Returns the incoming edges of the vertex. * @param vertex The vertx * @return The collection of edges. */ public Collection getInEdges(Object vertex) { if(!containsVertex(vertex)) return null; // combine directed inedges and undirected Collection in = new HashSet(); in.addAll(getIncoming_internal(vertex)); in.addAll(getIncident_internal(vertex)); // remove null key if present // in.remove(null); return Collections.unmodifiableCollection(in); } /** * Returns the outgoing edges of the vertex. * @param vertex The vertx * @return The collection of edges. */ public Collection getOutEdges(Object vertex) { if(!containsVertex(vertex)) return null; // combine directed outedges and undirected Collection out = new HashSet(); out.addAll(getIncident_internal(vertex)); out.addAll(getOutgoing_internal(vertex)); // remove null key if present // out.remove(null); return Collections.unmodifiableCollection(out); } /** * Returns the vertices that have an outgoing edge to the given vertex. * @param vertex The vertex. * @return The collection of vertices. */ public Collection getPredecessors(Object vertex) { if(!containsVertex(vertex)) return null; // consider only directed inedges Collection preds = new HashSet(); for(Iterator it = getIncoming_internal(vertex).iterator(); it.hasNext();) { preds.add(getSource(it.next())); } return Collections.unmodifiableCollection(preds); } /** * Returns the vertices that have an incoming edge from the given vertex. * @param vertex The vertex. * @return The collection of vertices. */ public Collection getSuccessors(Object vertex) { if(!containsVertex(vertex)) return null; Collection succs = new HashSet(); for(Iterator it = getOutgoing_internal(vertex).iterator(); it.hasNext();) succs.add(getDest(it.next())); return Collections.unmodifiableCollection(succs); } /** * Returns the edges for a given edge type. * @param edgeType The edge tzpe. * @return The collection of edges. */ public Collection getEdges(EdgeType edgeType) { if(edgeType == EdgeType.DIRECTED) return Collections.unmodifiableCollection(directed_edges.keySet()); else if(edgeType == EdgeType.UNDIRECTED) return Collections.unmodifiableCollection(undirected_edges.keySet()); else return null; // return Collections.unmodifiableCollection(new ArrayList<E>(0)); } /** * Returns the endpoints of the edge. * @param edge The edge. * @return The endpoints. */ public Pair getEndpoints(Object edge) { Pair endpoints; endpoints = (Pair)directed_edges.get(edge); if(endpoints == null) return (Pair)undirected_edges.get(edge); else return endpoints; } /** * Returns the edge type of en edge. * @param edge The edge. * @return The edge type. */ public EdgeType getEdgeType(Object edge) { if(directed_edges.containsKey(edge)) return EdgeType.DIRECTED; else if(undirected_edges.containsKey(edge)) return EdgeType.UNDIRECTED; else return null; } /** * Returns the source of a directed edge. * @param directed_edge The edge. * @return The vertex. */ public Object getSource(Object directed_edge) { if(getEdgeType(directed_edge) == EdgeType.DIRECTED) return ((Pair)directed_edges.get(directed_edge)).getFirst(); else return null; } /** * Returns the destination of a directed edge. * @param directed_edge The edge. * @return The vertex. */ public Object getDest(Object directed_edge) { if(getEdgeType(directed_edge) == EdgeType.DIRECTED) return ((Pair)directed_edges.get(directed_edge)).getSecond(); else return null; } /** * Returns <code>true</code> if the vertex is the source of the edge. * @param vertex The vertex. * @param edge The edge. * @return <code>true</code> if the vertex is the source. */ public boolean isSource(Object vertex, Object edge) { if(!containsVertex(vertex) || !containsEdge(edge)) return false; Object source = getSource(edge); if(source != null) return source.equals(vertex); else return false; } /** * Returns <code>true</code> if the vertex is the destination of the edge. * @param vertex The vertex. * @param edge The edge. * @return <code>true</code> if the vertex is the destination. */ public boolean isDest(Object vertex, Object edge) { if(!containsVertex(vertex) || !containsEdge(edge)) return false; Object dest = getDest(edge); if(dest != null) return dest.equals(vertex); else return false; } /** * Returns all edges of the graph. * @return The collection of edges. */ public Collection getEdges() { Collection edges = new ArrayList(); edges.addAll(directed_edges.keySet()); edges.addAll(undirected_edges.keySet()); return Collections.unmodifiableCollection(edges); } /** * Returns all vertices of the graph. * @return The collection of vertices. */ public Collection getVertices() { return Collections.unmodifiableCollection(vertex_maps.keySet()); } /** * Returns <code>true</code> if the graph contains the vertex. * @param vertex The vertex. * @return <code>true</code> if the vertex is in the graph. */ public boolean containsVertex(Object vertex) { return vertex_maps.containsKey(vertex); } /** * Returns <code>true</code> if the graph contains the edge. * @param edge The edge. * @return <code>true</code> if the edge is in the graph. */ public boolean containsEdge(Object edge) { return directed_edges.containsKey(edge) || undirected_edges.containsKey(edge); } /** * @return The edge count. */ public int getEdgeCount() { return directed_edges.size() + undirected_edges.size(); } /** * @return The vertex count. */ public int getVertexCount() { return vertex_maps.size(); } /** * Returns the neighbor vertices of a given vertex. * @param vertex The vertex. * @return The collection of neighbors. */ public Collection getNeighbors(Object vertex) { // consider directed edges and undirected edges Collection neighbors = new HashSet(); for(Iterator it = getIncoming_internal(vertex).iterator(); it.hasNext();) { neighbors.add(getSource(it.next())); } for(Iterator it = getOutgoing_internal(vertex).iterator(); it.hasNext();) { neighbors.add(getDest(it.next())); } // A vertex isnt neighbor to itself for(Iterator it = getIncident_internal(vertex).iterator(); it.hasNext();) { Pair endpoints = getEndpoints(it.next()); Object e_a = endpoints.getFirst(); Object e_b = endpoints.getSecond(); if(vertex.equals(e_a)) { neighbors.add(e_b); } else { neighbors.add(e_a); } } return Collections.unmodifiableCollection(neighbors); } /** * Returns the degree (number of incident edges) of a vertex. * @param vertex The vertex. * @return The degree. */ public int degree(Object vertex) { // if (!containsVertex(vertex)) // return 0; return getIncidentEdges(vertex).size(); } /** * Returns the incident edges of the vertex. * @param vertex The vertex. * @return The collection of edges. */ public Collection getIncidentEdges(Object vertex) { if(!containsVertex(vertex)) return null; // combine directed outedges and undirected Collection incident = new HashSet(); incident.addAll(getIncident_internal(vertex)); incident.addAll(getIncoming_internal(vertex)); incident.addAll(getOutgoing_internal(vertex)); return Collections.unmodifiableCollection(incident); } /** * Adds a vertex to the graph. * @param vertex The vertex. * @return <code>true</code> if success. */ public boolean addVertex(Object vertex) { if(vertex == null) { throw new IllegalArgumentException("vertex may not be null"); } if(!containsVertex(vertex)) { vertex_maps.put(vertex, new HashSet[]{new HashSet(), new HashSet(), new HashSet()}); return true; } else { return false; } } /** * Removes a vertex from the graph. * @param vertex The vertex. * @return <code>true</code> if success */ public boolean removeVertex(Object vertex) { if(!containsVertex(vertex)) return false; if(getIncidentEdges(vertex) == null) { System.err.println("no edge in main"); } // copy to avoid concurrent modification in removeEdge List incident = new ArrayList(getIncidentEdges(vertex)); for(int i = 0; i < incident.size(); i++) removeEdge(incident.get(i)); vertex_maps.remove(vertex); return true; } /** * Removes a edge from the graph. * @param edge The edge. * @return <code>true</code> if success */ public boolean removeEdge(Object edge) { if(!containsEdge(edge)) return false; Pair endpoints = getEndpoints(edge); Object v1 = endpoints.getFirst(); Object v2 = endpoints.getSecond(); // remove edge from incident vertices' adjacency maps if(getEdgeType(edge) == EdgeType.DIRECTED) { getOutgoing_internal(v1).remove(edge); getIncoming_internal(v2).remove(edge); directed_edges.remove(edge); } else { getIncident_internal(v1).remove(edge); getIncident_internal(v2).remove(edge); undirected_edges.remove(edge); } return true; } // -------- helper methods -------- /** * Returns the incoming edges of the vertex * @param vertex The vertex. * @return The collection of edges. */ protected Collection getIncoming_internal(Object vertex) { return (Collection)((Object[])vertex_maps.get(vertex))[INCOMING]; } /** * Returns the incident edges of the vertex * @param vertex The vertex. * @return The collection of edges. */ protected Collection getIncident_internal(Object vertex) { return (Collection)((Object[])vertex_maps.get(vertex))[INCIDENT]; } /** * Returns the outgoing edges of the vertex * @param vertex The vertex. * @return The collection of edges. */ protected Collection getOutgoing_internal(Object vertex) { return (Collection)((Object[])vertex_maps.get(vertex))[OUTGOING]; } }