org.jgrapht.graph.AbstractBaseGraph Maven / Gradle / Ivy
/*
* (C) Copyright 2003-2017, by Barak Naveh and Contributors.
*
* JGraphT : a free Java graph-theory library
*
* 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.
*/
package org.jgrapht.graph;
import java.io.*;
import java.util.*;
import org.jgrapht.*;
import org.jgrapht.graph.specifics.*;
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}).
*
*
* @param the graph vertex type
* @param the graph edge type
*
* @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";
private static final String GRAPH_SPECIFICS_MUST_NOT_BE_NULL =
"Graph specifics must not be null";
private boolean allowingLoops;
private EdgeFactory edgeFactory;
private Map edgeMap;
private transient Set unmodifiableEdgeSet = null;
private transient Set unmodifiableVertexSet = null;
private Specifics specifics;
private boolean allowingMultipleEdges;
/**
* 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)
{
Objects.requireNonNull(ef);
edgeMap = new LinkedHashMap<>();
edgeFactory = ef;
allowingLoops = allowLoops;
allowingMultipleEdges = allowMultipleEdges;
specifics = Objects.requireNonNull(createSpecifics(), GRAPH_SPECIFICS_MUST_NOT_BE_NULL);
}
/**
* {@inheritDoc}
*/
@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;
}
/**
* {@inheritDoc}
*/
@Override
public E getEdge(V sourceVertex, V targetVertex)
{
return specifics.getEdge(sourceVertex, targetVertex);
}
/**
* {@inheritDoc}
*/
@Override
public EdgeFactory getEdgeFactory()
{
return edgeFactory;
}
/**
* {@inheritDoc}
*/
@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;
}
}
/**
* {@inheritDoc}
*/
@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;
}
/**
* {@inheritDoc}
*/
@Override
public boolean addVertex(V v)
{
if (v == null) {
throw new NullPointerException();
} else if (containsVertex(v)) {
return false;
} else {
specifics.addVertex(v);
return true;
}
}
/**
* {@inheritDoc}
*/
@Override
public V getEdgeSource(E e)
{
return TypeUtil.uncheckedCast(getIntrusiveEdge(e).source, null);
}
/**
* {@inheritDoc}
*/
@Override
public V getEdgeTarget(E e)
{
return TypeUtil.uncheckedCast(getIntrusiveEdge(e).target, null);
}
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 in case the clone is not supported
*
* @see java.lang.Object#clone()
*/
@Override
public Object clone()
{
try {
AbstractBaseGraph newGraph = TypeUtil.uncheckedCast(super.clone(), null);
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();
}
}
/**
* {@inheritDoc}
*/
@Override
public boolean containsEdge(E e)
{
return edgeMap.containsKey(e);
}
/**
* {@inheritDoc}
*/
@Override
public boolean containsVertex(V v)
{
return specifics.getVertexSet().contains(v);
}
/**
* Returns the degree of the specified vertex.
*
* @param vertex vertex whose degree is to be calculated.
* @return the degree of the specified vertex.
* @see UndirectedGraph#degreeOf(Object)
*/
public int degreeOf(V vertex)
{
return specifics.degreeOf(vertex);
}
/**
* {@inheritDoc}
*/
@Override
public Set edgeSet()
{
if (unmodifiableEdgeSet == null) {
unmodifiableEdgeSet = Collections.unmodifiableSet(edgeMap.keySet());
}
return unmodifiableEdgeSet;
}
/**
* {@inheritDoc}
*/
@Override
public Set edgesOf(V vertex)
{
assertVertexExist(vertex);
return specifics.edgesOf(vertex);
}
/**
* Returns the "in degree" of the specified vertex.
*
* @param vertex vertex whose in degree is to be calculated.
* @return the in degree of the specified vertex.
*
* @see DirectedGraph#inDegreeOf(Object)
*/
public int inDegreeOf(V vertex)
{
assertVertexExist(vertex);
return specifics.inDegreeOf(vertex);
}
/**
* Returns a set of all edges incoming into the specified vertex.
*
* @param vertex the vertex for which the list of incoming edges to be returned
* @return a set of all edges incoming into the specified vertex
* @see DirectedGraph#incomingEdgesOf(Object)
*/
public Set incomingEdgesOf(V vertex)
{
assertVertexExist(vertex);
return specifics.incomingEdgesOf(vertex);
}
/**
* Returns the "out degree" of the specified vertex.
*
* @param vertex vertex whose out degree is to be calculated
* @return the out degree of the specified vertex
* @see DirectedGraph#outDegreeOf(Object)
*/
public int outDegreeOf(V vertex)
{
assertVertexExist(vertex);
return specifics.outDegreeOf(vertex);
}
/**
* Returns a set of all edges outgoing from the specified vertex.
*
* @param vertex the vertex for which the list of outgoing edges to be returned
* @return a set of all edges outgoing from the specified vertex
* @see DirectedGraph#outgoingEdgesOf(Object)
*/
public Set outgoingEdgesOf(V vertex)
{
assertVertexExist(vertex);
return specifics.outgoingEdgesOf(vertex);
}
/**
* {@inheritDoc}
*/
@Override
public E removeEdge(V sourceVertex, V targetVertex)
{
E e = getEdge(sourceVertex, targetVertex);
if (e != null) {
specifics.removeEdgeFromTouchingVertices(e);
edgeMap.remove(e);
}
return e;
}
/**
* {@inheritDoc}
*/
@Override
public boolean removeEdge(E e)
{
if (containsEdge(e)) {
specifics.removeEdgeFromTouchingVertices(e);
edgeMap.remove(e);
return true;
} else {
return false;
}
}
/**
* {@inheritDoc}
*/
@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;
}
}
/**
* {@inheritDoc}
*/
@Override
public Set vertexSet()
{
if (unmodifiableVertexSet == null) {
unmodifiableVertexSet = Collections.unmodifiableSet(specifics.getVertexSet());
}
return unmodifiableVertexSet;
}
/**
* {@inheritDoc}
*/
@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;
}
}
/**
* Assigns a weight to an edge.
*
* @param e edge on which to set weight
* @param weight new weight for edge
* @see WeightedGraph#setEdgeWeight(Object, double)
*/
public void setEdgeWeight(E e, double weight)
{
assert (e instanceof DefaultWeightedEdge) : e.getClass();
((DefaultWeightedEdge) e).weight = weight;
}
/**
* Create the specifics for this graph. Subclasses can override this method in order to adjust
* the specifics and thus the space-time tradeoffs of the graph implementation.
*
* @return the specifics used by this graph
*/
protected 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");
}
}
/**
* Create undirected specifics for the graph
*
* @return undirected specifics for the graph
* @deprecated specifics can be changed by overriding directly {@link #createSpecifics()}.
*/
@Deprecated
protected Specifics createUndirectedSpecifics()
{
return new FastLookupUndirectedSpecifics<>(this);
}
/**
* Create directed specifics for the graph
*
* @return directed specifics for the graph
* @deprecated specifics can be changed by overriding directly {@link #createSpecifics()}.
*/
@Deprecated
protected Specifics createDirectedSpecifics()
{
return new FastLookupDirectedSpecifics<>(this);
}
}
// End AbstractBaseGraph.java