org.jgrapht.graph.AbstractGraph Maven / Gradle / Ivy
/*
* (C) Copyright 2003-2021, by Barak Naveh and Contributors.
*
* JGraphT : a free Java graph-theory library
*
* See the CONTRIBUTORS.md file distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the
* GNU Lesser General Public License v2.1 or later
* which is available at
* http://www.gnu.org/licenses/old-licenses/lgpl-2.1-standalone.html.
*
* SPDX-License-Identifier: EPL-2.0 OR LGPL-2.1-or-later
*/
package org.jgrapht.graph;
import org.jgrapht.*;
import org.jgrapht.util.*;
import java.util.*;
/**
* A skeletal implementation of the Graph
interface, to minimize the effort required to
* implement graph interfaces. This implementation is applicable to both: directed graphs and
* undirected graphs.
*
* @param the graph vertex type
* @param the graph edge type
*
* @author Barak Naveh
* @see Graph
*/
public abstract class AbstractGraph
implements
Graph
{
/**
* Construct a new empty graph object.
*/
protected AbstractGraph()
{
}
/**
* @see Graph#containsEdge(Object, Object)
*/
@Override
public boolean containsEdge(V sourceVertex, V targetVertex)
{
return getEdge(sourceVertex, targetVertex) != null;
}
/**
* @see Graph#removeAllEdges(Collection)
*/
@Override
public boolean removeAllEdges(Collection extends E> edges)
{
boolean modified = false;
for (E e : edges) {
modified |= removeEdge(e);
}
return modified;
}
/**
* @see Graph#removeAllEdges(Object, Object)
*/
@Override
public Set removeAllEdges(V sourceVertex, V targetVertex)
{
Set removed = getAllEdges(sourceVertex, targetVertex);
if (removed == null) {
return null;
}
removeAllEdges(removed);
return removed;
}
/**
* @see Graph#removeAllVertices(Collection)
*/
@Override
public boolean removeAllVertices(Collection extends V> vertices)
{
boolean modified = false;
for (V v : vertices) {
modified |= removeVertex(v);
}
return modified;
}
/**
* Returns a string of the parenthesized pair (V, E) representing this G=(V,E) graph. 'V' is the
* string representation of the vertex set, and 'E' is the string representation of the edge
* set.
*
* @return a string representation of this graph.
*/
@Override
public String toString()
{
return toStringFromSets(vertexSet(), edgeSet(), this.getType().isDirected());
}
/**
* Ensures that the specified vertex exists in this graph, or else throws exception.
*
* @param v vertex
*
* @return true
if this assertion holds.
*
* @throws NullPointerException if specified vertex is null
.
* @throws IllegalArgumentException if specified vertex does not exist in this graph.
*/
protected boolean assertVertexExist(V v)
{
if (containsVertex(v)) {
return true;
} else if (v == null) {
throw new NullPointerException();
} else {
throw new IllegalArgumentException("no such vertex in graph: " + v.toString());
}
}
/**
* Removes all the edges in this graph that are also contained in the specified edge array.
* After this call returns, this graph will contain no edges in common with the specified edges.
* This method will invoke the {@link Graph#removeEdge(Object)} method.
*
* @param edges edges to be removed from this graph.
*
* @return true
if this graph changed as a result of the call.
*
* @see Graph#removeEdge(Object)
* @see Graph#containsEdge(Object)
*/
protected boolean removeAllEdges(E[] edges)
{
boolean modified = false;
for (E edge : edges) {
modified |= removeEdge(edge);
}
return modified;
}
/**
* Helper for subclass implementations of toString( ).
*
* @param vertexSet the vertex set V to be printed
* @param edgeSet the edge set E to be printed
* @param directed true to use parens for each edge (representing directed); false to use curly
* braces (representing undirected)
*
* @return a string representation of (V,E)
*/
protected String toStringFromSets(
Collection extends V> vertexSet, Collection extends E> edgeSet, boolean directed)
{
List renderedEdges = new ArrayList<>();
StringBuilder sb = new StringBuilder();
for (E e : edgeSet) {
if ((e.getClass() != DefaultEdge.class)
&& (e.getClass() != DefaultWeightedEdge.class))
{
sb.append(e.toString());
sb.append("=");
}
if (directed) {
sb.append("(");
} else {
sb.append("{");
}
sb.append(getEdgeSource(e));
sb.append(",");
sb.append(getEdgeTarget(e));
if (directed) {
sb.append(")");
} else {
sb.append("}");
}
// REVIEW jvs 29-May-2006: dump weight somewhere?
renderedEdges.add(sb.toString());
sb.setLength(0);
}
return "(" + vertexSet + ", " + renderedEdges + ")";
}
/**
* Returns a hash code value for this graph. The hash code of a graph is defined to be the sum
* of the hash codes of vertices and edges in the graph. It is also based on graph topology and
* edges weights.
*
* @return the hash code value this graph
*
* @see Object#hashCode()
*/
@Override
public int hashCode()
{
int hash = vertexSet().hashCode();
final boolean isDirected = getType().isDirected();
for (E e : edgeSet()) {
int part = e.hashCode();
int source = getEdgeSource(e).hashCode();
int target = getEdgeTarget(e).hashCode();
int pairing = source + target;
if (isDirected) {
// see http://en.wikipedia.org/wiki/Pairing_function (VK);
pairing = ((pairing) * (pairing + 1) / 2) + target;
}
part = (31 * part) + pairing;
part = (31 * part) + Double.hashCode(getEdgeWeight(e));
hash += part;
}
return hash;
}
/**
* Indicates whether some other object is "equal to" this graph. Returns true
if
* the given object is also a graph, the two graphs are instances of the same graph class, have
* identical vertices and edges sets with the same weights.
*
* @param obj object to be compared for equality with this graph
*
* @return true
if the specified object is equal to this graph
*
* @see Object#equals(Object)
*/
@Override
public boolean equals(Object obj)
{
if (this == obj) {
return true;
}
if ((obj == null) || (getClass() != obj.getClass())) {
return false;
}
Graph g = TypeUtil.uncheckedCast(obj);
if (!vertexSet().equals(g.vertexSet())) {
return false;
}
if (edgeSet().size() != g.edgeSet().size()) {
return false;
}
final boolean isDirected = getType().isDirected();
for (E e : edgeSet()) {
V source = getEdgeSource(e);
V target = getEdgeTarget(e);
if (!g.containsEdge(e)) {
return false;
}
V gSource = g.getEdgeSource(e);
V gTarget = g.getEdgeTarget(e);
if (isDirected) {
if (!gSource.equals(source) || !gTarget.equals(target)) {
return false;
}
} else {
if ((!gSource.equals(source) || !gTarget.equals(target))
&& (!gSource.equals(target) || !gTarget.equals(source)))
{
return false;
}
}
if (Double.compare(getEdgeWeight(e), g.getEdgeWeight(e)) != 0) {
return false;
}
}
return true;
}
}