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