All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jgrapht.graph.Subgraph Maven / Gradle / Ivy

/* ==========================================
 * JGraphT : a free Java graph-theory library
 * ==========================================
 *
 * Project Info:  http://jgrapht.sourceforge.net/
 * Project Creator:  Barak Naveh (http://sourceforge.net/users/barak_naveh)
 *
 * (C) Copyright 2003-2008, by Barak Naveh and Contributors.
 *
 * This program and the accompanying materials are dual-licensed under
 * either
 *
 * (a) the terms of the GNU Lesser General Public License version 2.1
 * as published by the Free Software Foundation, or (at your option) any
 * later version.
 *
 * or (per the licensee's choosing)
 *
 * (b) the terms of the Eclipse Public License v1.0 as published by
 * the Eclipse Foundation.
 */
/* -------------
 * Subgraph.java
 * -------------
 * (C) Copyright 2003-2008, by Barak Naveh and Contributors.
 *
 * Original Author:  Barak Naveh
 * Contributor(s):   Christian Hammer
 *
 * $Id$
 *
 * Changes
 * -------
 * 24-Jul-2003 : Initial revision (BN);
 * 26-Jul-2003 : Accurate constructors to avoid casting problems (BN);
 * 10-Aug-2003 : Adaptation to new event model (BN);
 * 23-Oct-2003 : Allowed non-listenable graph as base (BN);
 * 07-Feb-2004 : Enabled serialization (BN);
 * 11-Mar-2004 : Made generic (CH);
 * 15-Mar-2004 : Integrity is now checked using Maps (CH);
 * 20-Mar-2004 : Cancelled verification of element identity to base graph (BN);
 * 21-Sep-2004 : Added induced subgraph (who?)
 * 07-May-2006 : Changed from List to Set (JVS);
 * 28-May-2006 : Moved connectivity info from edge to graph (JVS);
 *
 */
package org.jgrapht.graph;

import java.io.*;

import java.util.*;

import org.jgrapht.*;
import org.jgrapht.event.*;
import org.jgrapht.util.*;


/**
 * A subgraph is a graph that has a subset of vertices and a subset of edges
 * with respect to some base graph. More formally, a subgraph G(V,E) that is
 * based on a base graph Gb(Vb,Eb) satisfies the following subgraph
 * property: V is a subset of Vb and E is a subset of Eb. Other than
 * this property, a subgraph is a graph with any respect and fully complies with
 * the Graph interface.
 *
 * 

If the base graph is a {@link org.jgrapht.ListenableGraph}, the subgraph * listens on the base graph and guarantees the subgraph property. If an edge or * a vertex is removed from the base graph, it is automatically removed from the * subgraph. Subgraph listeners are informed on such removal only if it results * in a cascaded removal from the subgraph. If the subgraph has been created as * an induced subgraph it also keeps track of edges being added to its vertices. * If vertices are added to the base graph, the subgraph remains unaffected.

* *

If the base graph is not a ListenableGraph, then the subgraph * property cannot be guaranteed. If edges or vertices are removed from the base * graph, they are not removed from the subgraph.

* *

Modifications to Subgraph are allowed as long as the subgraph property is * maintained. Addition of vertices or edges are allowed as long as they also * exist in the base graph. Removal of vertices or edges is always allowed. The * base graph is never affected by any modification made to the * subgraph.

* *

A subgraph may provide a "live-window" on a base graph, so that changes * made to its vertices or edges are immediately reflected in the base graph, * and vice versa. For that to happen, vertices and edges added to the subgraph * must be identical (that is, reference-equal and not only value-equal) * to their respective ones in the base graph. Previous versions of this class * enforced such identity, at a severe performance cost. Currently it is no * longer enforced. If you want to achieve a "live-window"functionality, your * safest tactics would be to NOT override the equals() methods of * your vertices and edges. If you use a class that has already overridden the * equals() method, such as String, than you can use a * wrapper around it, or else use it directly but exercise a great care to avoid * having different-but-equal instances in the subgraph and the base graph.

* *

This graph implementation guarantees deterministic vertex and edge set * ordering (via {@link LinkedHashSet}).

* * @author Barak Naveh * @see Graph * @see Set * @since Jul 18, 2003 */ public class Subgraph> extends AbstractGraph implements Serializable { private static final long serialVersionUID = 3208313055169665387L; private static final String NO_SUCH_EDGE_IN_BASE = "no such edge in base graph"; private static final String NO_SUCH_VERTEX_IN_BASE = "no such vertex in base graph"; // Set edgeSet = new LinkedHashSet(); // friendly to improve performance Set vertexSet = new LinkedHashSet(); // friendly to improve // performance // private transient Set unmodifiableEdgeSet = null; private transient Set unmodifiableVertexSet = null; private G base; private boolean isInduced = false; /** * Creates a new Subgraph. * * @param base the base (backing) graph on which the subgraph will be based. * @param vertexSubset vertices to include in the subgraph. If * null then all vertices are included. * @param edgeSubset edges to in include in the subgraph. If * null then all the edges whose vertices found in the graph are * included. */ public Subgraph(G base, Set vertexSubset, Set edgeSubset) { super(); this.base = base; if (edgeSubset == null) { isInduced = true; } if (base instanceof ListenableGraph) { ((ListenableGraph) base).addGraphListener( new BaseGraphListener()); } addVerticesUsingFilter(base.vertexSet(), vertexSubset); addEdgesUsingFilter(base.edgeSet(), edgeSubset); } /** * Creates a new induced Subgraph. The subgraph will keep track of edges * being added to its vertex subset as well as deletion of edges and * vertices. If base it not listenable, this is identical to the call * Subgraph(base, vertexSubset, null) . * * @param base the base (backing) graph on which the subgraph will be based. * @param vertexSubset vertices to include in the subgraph. If * null then all vertices are included. */ public Subgraph(G base, Set vertexSubset) { this(base, vertexSubset, null); } /** * @see Graph#getAllEdges(Object, Object) */ @Override public Set getAllEdges(V sourceVertex, V targetVertex) { Set edges = null; if (containsVertex(sourceVertex) && containsVertex(targetVertex)) { edges = new ArrayUnenforcedSet(); Set baseEdges = base.getAllEdges(sourceVertex, targetVertex); for (Iterator iter = baseEdges.iterator(); iter.hasNext();) { E e = iter.next(); if (edgeSet.contains(e)) { // add if subgraph also contains // it edges.add(e); } } } return edges; } /** * @see Graph#getEdge(Object, Object) */ @Override public E getEdge(V sourceVertex, V targetVertex) { Set edges = getAllEdges(sourceVertex, targetVertex); if ((edges == null) || edges.isEmpty()) { return null; } else { return edges.iterator().next(); } } /** * @see Graph#getEdgeFactory() */ @Override public EdgeFactory getEdgeFactory() { return base.getEdgeFactory(); } /** * @see Graph#addEdge(Object, Object) */ @Override public E addEdge(V sourceVertex, V targetVertex) { assertVertexExist(sourceVertex); assertVertexExist(targetVertex); if (!base.containsEdge(sourceVertex, targetVertex)) { throw new IllegalArgumentException(NO_SUCH_EDGE_IN_BASE); } Set edges = base.getAllEdges(sourceVertex, targetVertex); for (Iterator iter = edges.iterator(); iter.hasNext();) { E e = iter.next(); if (!containsEdge(e)) { edgeSet.add(e); return e; } } return null; } /** * @see Graph#addEdge(Object, Object, Object) */ @Override public boolean addEdge(V sourceVertex, V targetVertex, E e) { if (e == null) { throw new NullPointerException(); } if (!base.containsEdge(e)) { throw new IllegalArgumentException(NO_SUCH_EDGE_IN_BASE); } assertVertexExist(sourceVertex); assertVertexExist(targetVertex); assert (base.getEdgeSource(e) == sourceVertex); assert (base.getEdgeTarget(e) == targetVertex); if (containsEdge(e)) { return false; } else { edgeSet.add(e); return true; } } /** * Adds the specified vertex to this subgraph. * * @param v the vertex to be added. * * @return true if the vertex was added, otherwise * false. * * @throws NullPointerException * @throws IllegalArgumentException * * @see Subgraph * @see Graph#addVertex(Object) */ @Override public boolean addVertex(V v) { if (v == null) { throw new NullPointerException(); } if (!base.containsVertex(v)) { throw new IllegalArgumentException(NO_SUCH_VERTEX_IN_BASE); } if (containsVertex(v)) { return false; } else { vertexSet.add(v); return true; } } /** * @see Graph#containsEdge(Object) */ @Override public boolean containsEdge(E e) { return edgeSet.contains(e); } /** * @see Graph#containsVertex(Object) */ @Override public boolean containsVertex(V v) { return vertexSet.contains(v); } /** * @see Graph#edgeSet() */ @Override public Set edgeSet() { if (unmodifiableEdgeSet == null) { unmodifiableEdgeSet = Collections.unmodifiableSet(edgeSet); } return unmodifiableEdgeSet; } /** * @see Graph#edgesOf(Object) */ @Override public Set edgesOf(V vertex) { assertVertexExist(vertex); Set edges = new ArrayUnenforcedSet(); Set baseEdges = base.edgesOf(vertex); for (E e : baseEdges) { if (containsEdge(e)) { edges.add(e); } } return edges; } /** * @see Graph#removeEdge(Object) */ @Override public boolean removeEdge(E e) { return edgeSet.remove(e); } /** * @see Graph#removeEdge(Object, Object) */ @Override public E removeEdge(V sourceVertex, V targetVertex) { E e = getEdge(sourceVertex, targetVertex); return edgeSet.remove(e) ? e : null; } /** * @see Graph#removeVertex(Object) */ @Override public boolean removeVertex(V v) { // If the base graph does NOT contain v it means we are here in // response to removal of v from the base. In such case we don't need // to remove all the edges of v as they were already removed. if (containsVertex(v) && base.containsVertex(v)) { removeAllEdges(edgesOf(v)); } return vertexSet.remove(v); } /** * @see Graph#vertexSet() */ @Override public Set vertexSet() { if (unmodifiableVertexSet == null) { unmodifiableVertexSet = Collections.unmodifiableSet(vertexSet); } return unmodifiableVertexSet; } /** * @see Graph#getEdgeSource(Object) */ @Override public V getEdgeSource(E e) { return base.getEdgeSource(e); } /** * @see Graph#getEdgeTarget(Object) */ @Override public V getEdgeTarget(E e) { return base.getEdgeTarget(e); } private void addEdgesUsingFilter(Set edgeSet, Set filter) { E e; boolean containsVertices; boolean edgeIncluded; for (Iterator iter = edgeSet.iterator(); iter.hasNext();) { e = iter.next(); V sourceVertex = base.getEdgeSource(e); V targetVertex = base.getEdgeTarget(e); containsVertices = containsVertex(sourceVertex) && containsVertex(targetVertex); // note the use of short circuit evaluation edgeIncluded = (filter == null) || filter.contains(e); if (containsVertices && edgeIncluded) { addEdge(sourceVertex, targetVertex, e); } } } private void addVerticesUsingFilter(Set vertexSet, Set filter) { V v; for (Iterator iter = vertexSet.iterator(); iter.hasNext();) { v = iter.next(); // note the use of short circuit evaluation if ((filter == null) || filter.contains(v)) { addVertex(v); } } } public G getBase() { return base; } /** * @see Graph#getEdgeWeight(Object) */ @Override public double getEdgeWeight(E e) { return base.getEdgeWeight(e); } /** * @see WeightedGraph#setEdgeWeight(Object, double) */ public void setEdgeWeight(E e, double weight) { ((WeightedGraph) base).setEdgeWeight(e, weight); } /** * An internal listener on the base graph. * * @author Barak Naveh * @since Jul 20, 2003 */ private class BaseGraphListener implements GraphListener, Serializable { private static final long serialVersionUID = 4343535244243546391L; /** * @see GraphListener#edgeAdded(GraphEdgeChangeEvent) */ @Override public void edgeAdded(GraphEdgeChangeEvent e) { if (isInduced) { E edge = e.getEdge(); V source = e.getEdgeSource(); V target = e.getEdgeTarget(); if (containsVertex(source) && containsVertex(target)) { addEdge( source, target, edge); } } } /** * @see GraphListener#edgeRemoved(GraphEdgeChangeEvent) */ @Override public void edgeRemoved(GraphEdgeChangeEvent e) { E edge = e.getEdge(); removeEdge(edge); } /** * @see VertexSetListener#vertexAdded(GraphVertexChangeEvent) */ @Override public void vertexAdded(GraphVertexChangeEvent e) { // we don't care } /** * @see VertexSetListener#vertexRemoved(GraphVertexChangeEvent) */ @Override public void vertexRemoved(GraphVertexChangeEvent e) { V vertex = e.getVertex(); removeVertex(vertex); } } } // End Subgraph.java




© 2015 - 2024 Weber Informatics LLC | Privacy Policy