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

org.jgrapht.graph.AbstractBaseGraph 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.
 */
/* ----------------------
 * AbstractBaseGraph.java
 * ----------------------
 * (C) Copyright 2003-2008, by Barak Naveh and Contributors.
 *
 * Original Author:  Barak Naveh
 * Contributor(s):   John V. Sichi
 *                   Christian Hammer
 *
 * $Id$
 *
 * Changes
 * -------
 * 24-Jul-2003 : Initial revision (BN);
 * 10-Aug-2003 : General edge refactoring (BN);
 * 06-Nov-2003 : Change edge sharing semantics (JVS);
 * 07-Feb-2004 : Enabled serialization (BN);
 * 11-Mar-2004 : Made generic (CH);
 * 01-Jun-2005 : Added EdgeListFactory (JVS);
 * 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.util.*;


/**
 * The most general implementation of the {@link org.jgrapht.Graph} interface.
 * Its subclasses add various restrictions to get more specific graphs. The
 * decision whether it is directed or undirected is decided at construction time
 * and cannot be later modified (see constructor for details).
 *
 * 

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

* * @author Barak Naveh * @since Jul 24, 2003 */ public abstract class AbstractBaseGraph extends AbstractGraph implements Graph, Cloneable, Serializable { private static final long serialVersionUID = -1263088497616142427L; private static final String LOOPS_NOT_ALLOWED = "loops not allowed"; boolean allowingLoops; private EdgeFactory edgeFactory; private EdgeSetFactory edgeSetFactory; private Map edgeMap; private transient Set unmodifiableEdgeSet = null; private transient Set unmodifiableVertexSet = null; private Specifics specifics; private boolean allowingMultipleEdges; private transient TypeUtil vertexTypeDecl = null; /** * Construct a new graph. The graph can either be directed or undirected, * depending on the specified edge factory. * * @param ef the edge factory of the new graph. * @param allowMultipleEdges whether to allow multiple edges or not. * @param allowLoops whether to allow edges that are self-loops or not. * * @throws NullPointerException if the specified edge factory is * null. */ protected AbstractBaseGraph( EdgeFactory ef, boolean allowMultipleEdges, boolean allowLoops) { if (ef == null) { throw new NullPointerException(); } edgeMap = new LinkedHashMap(); edgeFactory = ef; allowingLoops = allowLoops; allowingMultipleEdges = allowMultipleEdges; specifics = createSpecifics(); this.edgeSetFactory = new ArrayListFactory(); } /** * @see Graph#getAllEdges(Object, Object) */ @Override public Set getAllEdges(V sourceVertex, V targetVertex) { return specifics.getAllEdges(sourceVertex, targetVertex); } /** * Returns true if and only if self-loops are allowed in this * graph. A self loop is an edge that its source and target vertices are the * same. * * @return true if and only if graph loops are allowed. */ public boolean isAllowingLoops() { return allowingLoops; } /** * Returns true if and only if multiple edges are allowed in * this graph. The meaning of multiple edges is that there can be many edges * going from vertex v1 to vertex v2. * * @return true if and only if multiple edges are allowed. */ public boolean isAllowingMultipleEdges() { return allowingMultipleEdges; } /** * @see Graph#getEdge(Object, Object) */ @Override public E getEdge(V sourceVertex, V targetVertex) { return specifics.getEdge(sourceVertex, targetVertex); } /** * @see Graph#getEdgeFactory() */ @Override public EdgeFactory getEdgeFactory() { return edgeFactory; } /** * Set the {@link EdgeSetFactory} to use for this graph. Initially, a graph * is created with a default implementation which always supplies an {@link * java.util.ArrayList} with capacity 1. * * @param edgeSetFactory factory to use for subsequently created edge sets * (this call has no effect on existing edge sets) */ public void setEdgeSetFactory(EdgeSetFactory edgeSetFactory) { this.edgeSetFactory = edgeSetFactory; } /** * @see Graph#addEdge(Object, Object) */ @Override public E addEdge(V sourceVertex, V targetVertex) { assertVertexExist(sourceVertex); assertVertexExist(targetVertex); if (!allowingMultipleEdges && containsEdge(sourceVertex, targetVertex)) { return null; } if (!allowingLoops && sourceVertex.equals(targetVertex)) { throw new IllegalArgumentException(LOOPS_NOT_ALLOWED); } E e = edgeFactory.createEdge(sourceVertex, targetVertex); if (containsEdge(e)) { // this restriction should stay! return null; } else { IntrusiveEdge intrusiveEdge = createIntrusiveEdge(e, sourceVertex, targetVertex); edgeMap.put(e, intrusiveEdge); specifics.addEdgeToTouchingVertices(e); return e; } } /** * @see Graph#addEdge(Object, Object, Object) */ @Override public boolean addEdge(V sourceVertex, V targetVertex, E e) { if (e == null) { throw new NullPointerException(); } else if (containsEdge(e)) { return false; } assertVertexExist(sourceVertex); assertVertexExist(targetVertex); if (!allowingMultipleEdges && containsEdge(sourceVertex, targetVertex)) { return false; } if (!allowingLoops && sourceVertex.equals(targetVertex)) { throw new IllegalArgumentException(LOOPS_NOT_ALLOWED); } IntrusiveEdge intrusiveEdge = createIntrusiveEdge(e, sourceVertex, targetVertex); edgeMap.put(e, intrusiveEdge); specifics.addEdgeToTouchingVertices(e); return true; } private IntrusiveEdge createIntrusiveEdge( E e, V sourceVertex, V targetVertex) { IntrusiveEdge intrusiveEdge; if (e instanceof IntrusiveEdge) { intrusiveEdge = (IntrusiveEdge) e; } else { intrusiveEdge = new IntrusiveEdge(); } intrusiveEdge.source = sourceVertex; intrusiveEdge.target = targetVertex; return intrusiveEdge; } /** * @see Graph#addVertex(Object) */ @Override public boolean addVertex(V v) { if (v == null) { throw new NullPointerException(); } else if (containsVertex(v)) { return false; } else { specifics.addVertex(v); return true; } } /** * @see Graph#getEdgeSource(Object) */ @Override public V getEdgeSource(E e) { return TypeUtil.uncheckedCast( getIntrusiveEdge(e).source, vertexTypeDecl); } /** * @see Graph#getEdgeTarget(Object) */ @Override public V getEdgeTarget(E e) { return TypeUtil.uncheckedCast( getIntrusiveEdge(e).target, vertexTypeDecl); } private IntrusiveEdge getIntrusiveEdge(E e) { if (e instanceof IntrusiveEdge) { return (IntrusiveEdge) e; } return edgeMap.get(e); } /** * Returns a shallow copy of this graph instance. Neither edges nor vertices * are cloned. * * @return a shallow copy of this set. * * @throws RuntimeException * * @see java.lang.Object#clone() */ @Override public Object clone() { try { TypeUtil> typeDecl = null; AbstractBaseGraph newGraph = TypeUtil.uncheckedCast(super.clone(), typeDecl); newGraph.edgeMap = new LinkedHashMap(); newGraph.edgeFactory = this.edgeFactory; newGraph.unmodifiableEdgeSet = null; newGraph.unmodifiableVertexSet = null; // NOTE: it's important for this to happen in an object // method so that the new inner class instance gets associated with // the right outer class instance newGraph.specifics = newGraph.createSpecifics(); Graphs.addGraph(newGraph, this); return newGraph; } catch (CloneNotSupportedException e) { e.printStackTrace(); throw new RuntimeException(); } } /** * @see Graph#containsEdge(Object) */ @Override public boolean containsEdge(E e) { return edgeMap.containsKey(e); } /** * @see Graph#containsVertex(Object) */ @Override public boolean containsVertex(V v) { return specifics.getVertexSet().contains(v); } /** * @see UndirectedGraph#degreeOf(Object) */ public int degreeOf(V vertex) { return specifics.degreeOf(vertex); } /** * @see Graph#edgeSet() */ @Override public Set edgeSet() { if (unmodifiableEdgeSet == null) { unmodifiableEdgeSet = Collections.unmodifiableSet(edgeMap.keySet()); } return unmodifiableEdgeSet; } /** * @see Graph#edgesOf(Object) */ @Override public Set edgesOf(V vertex) { return specifics.edgesOf(vertex); } /** * @see DirectedGraph#inDegreeOf(Object) */ public int inDegreeOf(V vertex) { return specifics.inDegreeOf(vertex); } /** * @see DirectedGraph#incomingEdgesOf(Object) */ public Set incomingEdgesOf(V vertex) { return specifics.incomingEdgesOf(vertex); } /** * @see DirectedGraph#outDegreeOf(Object) */ public int outDegreeOf(V vertex) { return specifics.outDegreeOf(vertex); } /** * @see DirectedGraph#outgoingEdgesOf(Object) */ public Set outgoingEdgesOf(V vertex) { return specifics.outgoingEdgesOf(vertex); } /** * @see Graph#removeEdge(Object, Object) */ @Override public E removeEdge(V sourceVertex, V targetVertex) { E e = getEdge(sourceVertex, targetVertex); if (e != null) { specifics.removeEdgeFromTouchingVertices(e); edgeMap.remove(e); } return e; } /** * @see Graph#removeEdge(Object) */ @Override public boolean removeEdge(E e) { if (containsEdge(e)) { specifics.removeEdgeFromTouchingVertices(e); edgeMap.remove(e); return true; } else { return false; } } /** * @see Graph#removeVertex(Object) */ @Override public boolean removeVertex(V v) { if (containsVertex(v)) { Set touchingEdgesList = edgesOf(v); // cannot iterate over list - will cause // ConcurrentModificationException removeAllEdges(new ArrayList(touchingEdgesList)); specifics.getVertexSet().remove(v); // remove the vertex itself return true; } else { return false; } } /** * @see Graph#vertexSet() */ @Override public Set vertexSet() { if (unmodifiableVertexSet == null) { unmodifiableVertexSet = Collections.unmodifiableSet(specifics.getVertexSet()); } return unmodifiableVertexSet; } /** * @see Graph#getEdgeWeight(Object) */ @Override public double getEdgeWeight(E e) { if (e instanceof DefaultWeightedEdge) { return ((DefaultWeightedEdge) e).getWeight(); } else if (e == null) { throw new NullPointerException(); } else { return WeightedGraph.DEFAULT_EDGE_WEIGHT; } } /** * @see WeightedGraph#setEdgeWeight(Object, double) */ public void setEdgeWeight(E e, double weight) { assert (e instanceof DefaultWeightedEdge) : e.getClass(); ((DefaultWeightedEdge) e).weight = weight; } private Specifics createSpecifics() { if (this instanceof DirectedGraph) { return createDirectedSpecifics(); } else if (this instanceof UndirectedGraph) { return createUndirectedSpecifics(); } else { throw new IllegalArgumentException( "must be instance of either DirectedGraph or UndirectedGraph"); } } protected UndirectedSpecifics createUndirectedSpecifics() { return new UndirectedSpecifics(); } protected DirectedSpecifics createDirectedSpecifics() { return new DirectedSpecifics(); } /** * . * * @author Barak Naveh */ private abstract class Specifics implements Serializable { private static final long serialVersionUID = 785196247314761183L; public abstract void addVertex(V vertex); public abstract Set getVertexSet(); /** * . * * @param sourceVertex * @param targetVertex * * @return */ public abstract Set getAllEdges(V sourceVertex, V targetVertex); /** * . * * @param sourceVertex * @param targetVertex * * @return */ public abstract E getEdge(V sourceVertex, V targetVertex); /** * Adds the specified edge to the edge containers of its source and * target vertices. * * @param e */ public abstract void addEdgeToTouchingVertices(E e); /** * . * * @param vertex * * @return */ public abstract int degreeOf(V vertex); /** * . * * @param vertex * * @return */ public abstract Set edgesOf(V vertex); /** * . * * @param vertex * * @return */ public abstract int inDegreeOf(V vertex); /** * . * * @param vertex * * @return */ public abstract Set incomingEdgesOf(V vertex); /** * . * * @param vertex * * @return */ public abstract int outDegreeOf(V vertex); /** * . * * @param vertex * * @return */ public abstract Set outgoingEdgesOf(V vertex); /** * Removes the specified edge from the edge containers of its source and * target vertices. * * @param e */ public abstract void removeEdgeFromTouchingVertices(E e); } private static class ArrayListFactory implements EdgeSetFactory, Serializable { private static final long serialVersionUID = 5936902837403445985L; /** * @see EdgeSetFactory.createEdgeSet */ @Override public Set createEdgeSet(VV vertex) { // NOTE: use size 1 to keep memory usage under control // for the common case of vertices with low degree return new ArrayUnenforcedSet(1); } } /** * A container for vertex edges. * *

In this edge container we use array lists to minimize memory toll. * However, for high-degree vertices we replace the entire edge container * with a direct access subclass (to be implemented).

* * @author Barak Naveh */ protected static class DirectedEdgeContainer implements Serializable { private static final long serialVersionUID = 7494242245729767106L; Set incoming; Set outgoing; private transient Set unmodifiableIncoming = null; private transient Set unmodifiableOutgoing = null; DirectedEdgeContainer(EdgeSetFactory edgeSetFactory, VV vertex) { incoming = edgeSetFactory.createEdgeSet(vertex); outgoing = edgeSetFactory.createEdgeSet(vertex); } /** * A lazy build of unmodifiable incoming edge set. * * @return */ public Set getUnmodifiableIncomingEdges() { if (unmodifiableIncoming == null) { unmodifiableIncoming = Collections.unmodifiableSet(incoming); } return unmodifiableIncoming; } /** * A lazy build of unmodifiable outgoing edge set. * * @return */ public Set getUnmodifiableOutgoingEdges() { if (unmodifiableOutgoing == null) { unmodifiableOutgoing = Collections.unmodifiableSet(outgoing); } return unmodifiableOutgoing; } /** * . * * @param e */ public void addIncomingEdge(EE e) { incoming.add(e); } /** * . * * @param e */ public void addOutgoingEdge(EE e) { outgoing.add(e); } /** * . * * @param e */ public void removeIncomingEdge(EE e) { incoming.remove(e); } /** * . * * @param e */ public void removeOutgoingEdge(EE e) { outgoing.remove(e); } } /** * . * * @author Barak Naveh */ protected class DirectedSpecifics extends Specifics implements Serializable { private static final long serialVersionUID = 8971725103718958232L; private static final String NOT_IN_DIRECTED_GRAPH = "no such operation in a directed graph"; protected Map> vertexMapDirected; public DirectedSpecifics() { this(new LinkedHashMap>()); } public DirectedSpecifics(Map> vertexMap) { this.vertexMapDirected = vertexMap; } @Override public void addVertex(V v) { // add with a lazy edge container entry vertexMapDirected.put(v, null); } @Override public Set getVertexSet() { return vertexMapDirected.keySet(); } /** * @see Graph#getAllEdges(Object, Object) */ @Override public Set getAllEdges(V sourceVertex, V targetVertex) { Set edges = null; if (containsVertex(sourceVertex) && containsVertex(targetVertex)) { edges = new ArrayUnenforcedSet(); DirectedEdgeContainer ec = getEdgeContainer(sourceVertex); Iterator iter = ec.outgoing.iterator(); while (iter.hasNext()) { E e = iter.next(); if (getEdgeTarget(e).equals(targetVertex)) { edges.add(e); } } } return edges; } /** * @see Graph#getEdge(Object, Object) */ @Override public E getEdge(V sourceVertex, V targetVertex) { if (containsVertex(sourceVertex) && containsVertex(targetVertex)) { DirectedEdgeContainer ec = getEdgeContainer(sourceVertex); Iterator iter = ec.outgoing.iterator(); while (iter.hasNext()) { E e = iter.next(); if (getEdgeTarget(e).equals(targetVertex)) { return e; } } } return null; } @Override public void addEdgeToTouchingVertices(E e) { V source = getEdgeSource(e); V target = getEdgeTarget(e); getEdgeContainer(source).addOutgoingEdge(e); getEdgeContainer(target).addIncomingEdge(e); } /** * @see UndirectedGraph#degreeOf(Object) */ @Override public int degreeOf(V vertex) { throw new UnsupportedOperationException(NOT_IN_DIRECTED_GRAPH); } /** * @see Graph#edgesOf(Object) */ @Override public Set edgesOf(V vertex) { ArrayUnenforcedSet inAndOut = new ArrayUnenforcedSet(getEdgeContainer(vertex).incoming); inAndOut.addAll(getEdgeContainer(vertex).outgoing); // we have two copies for each self-loop - remove one of them. if (allowingLoops) { Set loops = getAllEdges(vertex, vertex); for (int i = 0; i < inAndOut.size();) { Object e = inAndOut.get(i); if (loops.contains(e)) { inAndOut.remove(i); loops.remove(e); // so we remove it only once } else { i++; } } } return Collections.unmodifiableSet(inAndOut); } /** * @see DirectedGraph#inDegreeOf(Object) */ @Override public int inDegreeOf(V vertex) { return getEdgeContainer(vertex).incoming.size(); } /** * @see DirectedGraph#incomingEdgesOf(Object) */ @Override public Set incomingEdgesOf(V vertex) { return getEdgeContainer(vertex).getUnmodifiableIncomingEdges(); } /** * @see DirectedGraph#outDegreeOf(Object) */ @Override public int outDegreeOf(V vertex) { return getEdgeContainer(vertex).outgoing.size(); } /** * @see DirectedGraph#outgoingEdgesOf(Object) */ @Override public Set outgoingEdgesOf(V vertex) { return getEdgeContainer(vertex).getUnmodifiableOutgoingEdges(); } @Override public void removeEdgeFromTouchingVertices(E e) { V source = getEdgeSource(e); V target = getEdgeTarget(e); getEdgeContainer(source).removeOutgoingEdge(e); getEdgeContainer(target).removeIncomingEdge(e); } /** * A lazy build of edge container for specified vertex. * * @param vertex a vertex in this graph. * * @return EdgeContainer */ private DirectedEdgeContainer getEdgeContainer(V vertex) { assertVertexExist(vertex); DirectedEdgeContainer ec = vertexMapDirected.get(vertex); if (ec == null) { ec = new DirectedEdgeContainer(edgeSetFactory, vertex); vertexMapDirected.put(vertex, ec); } return ec; } } /** * A container of for vertex edges. * *

In this edge container we use array lists to minimize memory toll. * However, for high-degree vertices we replace the entire edge container * with a direct access subclass (to be implemented).

* * @author Barak Naveh */ private static class UndirectedEdgeContainer implements Serializable { private static final long serialVersionUID = -6623207588411170010L; Set vertexEdges; private transient Set unmodifiableVertexEdges = null; UndirectedEdgeContainer( EdgeSetFactory edgeSetFactory, VV vertex) { vertexEdges = edgeSetFactory.createEdgeSet(vertex); } /** * A lazy build of unmodifiable list of vertex edges * * @return */ public Set getUnmodifiableVertexEdges() { if (unmodifiableVertexEdges == null) { unmodifiableVertexEdges = Collections.unmodifiableSet(vertexEdges); } return unmodifiableVertexEdges; } /** * . * * @param e */ public void addEdge(EE e) { vertexEdges.add(e); } /** * . * * @return */ public int edgeCount() { return vertexEdges.size(); } /** * . * * @param e */ public void removeEdge(EE e) { vertexEdges.remove(e); } } /** * . * * @author Barak Naveh */ protected class UndirectedSpecifics extends Specifics implements Serializable { private static final long serialVersionUID = 6494588405178655873L; private static final String NOT_IN_UNDIRECTED_GRAPH = "no such operation in an undirected graph"; private Map> vertexMapUndirected; public UndirectedSpecifics() { this(new LinkedHashMap>()); } public UndirectedSpecifics( Map> vertexMap) { this.vertexMapUndirected = vertexMap; } @Override public void addVertex(V v) { // add with a lazy edge container entry vertexMapUndirected.put(v, null); } @Override public Set getVertexSet() { return vertexMapUndirected.keySet(); } /** * @see Graph#getAllEdges(Object, Object) */ @Override public Set getAllEdges(V sourceVertex, V targetVertex) { Set edges = null; if (containsVertex(sourceVertex) && containsVertex(targetVertex)) { edges = new ArrayUnenforcedSet(); Iterator iter = getEdgeContainer(sourceVertex).vertexEdges.iterator(); while (iter.hasNext()) { E e = iter.next(); boolean equal = isEqualsStraightOrInverted( sourceVertex, targetVertex, e); if (equal) { edges.add(e); } } } return edges; } /** * @see Graph#getEdge(Object, Object) */ @Override public E getEdge(V sourceVertex, V targetVertex) { if (containsVertex(sourceVertex) && containsVertex(targetVertex)) { Iterator iter = getEdgeContainer(sourceVertex).vertexEdges.iterator(); while (iter.hasNext()) { E e = iter.next(); boolean equal = isEqualsStraightOrInverted( sourceVertex, targetVertex, e); if (equal) { return e; } } } return null; } private boolean isEqualsStraightOrInverted( Object sourceVertex, Object targetVertex, E e) { boolean equalStraight = sourceVertex.equals(getEdgeSource(e)) && targetVertex.equals(getEdgeTarget(e)); boolean equalInverted = sourceVertex.equals(getEdgeTarget(e)) && targetVertex.equals(getEdgeSource(e)); return equalStraight || equalInverted; } @Override public void addEdgeToTouchingVertices(E e) { V source = getEdgeSource(e); V target = getEdgeTarget(e); getEdgeContainer(source).addEdge(e); if (!source.equals(target)) { getEdgeContainer(target).addEdge(e); } } @Override public int degreeOf(V vertex) { if (allowingLoops) { // then we must count, and add loops twice int degree = 0; Set edges = getEdgeContainer(vertex).vertexEdges; for (E e : edges) { if (getEdgeSource(e).equals(getEdgeTarget(e))) { degree += 2; } else { degree += 1; } } return degree; } else { return getEdgeContainer(vertex).edgeCount(); } } /** * @see Graph#edgesOf(Object) */ @Override public Set edgesOf(V vertex) { return getEdgeContainer(vertex).getUnmodifiableVertexEdges(); } /** * @see DirectedGraph#inDegreeOf(Object) */ @Override public int inDegreeOf(V vertex) { throw new UnsupportedOperationException(NOT_IN_UNDIRECTED_GRAPH); } /** * @see DirectedGraph#incomingEdgesOf(Object) */ @Override public Set incomingEdgesOf(V vertex) { throw new UnsupportedOperationException(NOT_IN_UNDIRECTED_GRAPH); } /** * @see DirectedGraph#outDegreeOf(Object) */ @Override public int outDegreeOf(V vertex) { throw new UnsupportedOperationException(NOT_IN_UNDIRECTED_GRAPH); } /** * @see DirectedGraph#outgoingEdgesOf(Object) */ @Override public Set outgoingEdgesOf(V vertex) { throw new UnsupportedOperationException(NOT_IN_UNDIRECTED_GRAPH); } @Override public void removeEdgeFromTouchingVertices(E e) { V source = getEdgeSource(e); V target = getEdgeTarget(e); getEdgeContainer(source).removeEdge(e); if (!source.equals(target)) { getEdgeContainer(target).removeEdge(e); } } /** * A lazy build of edge container for specified vertex. * * @param vertex a vertex in this graph. * * @return EdgeContainer */ private UndirectedEdgeContainer getEdgeContainer(V vertex) { assertVertexExist(vertex); UndirectedEdgeContainer ec = vertexMapUndirected.get(vertex); if (ec == null) { ec = new UndirectedEdgeContainer( edgeSetFactory, vertex); vertexMapUndirected.put(vertex, ec); } return ec; } } } // End AbstractBaseGraph.java




© 2015 - 2024 Weber Informatics LLC | Privacy Policy