org.jgrapht.graph.guava.BaseValueGraphAdapter Maven / Gradle / Ivy
/*
* (C) Copyright 2018-2018, by Dimitrios Michail 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.guava;
import com.google.common.graph.*;
import org.jgrapht.*;
import org.jgrapht.Graph;
import org.jgrapht.graph.AbstractGraph;
import org.jgrapht.graph.*;
import java.io.*;
import java.util.*;
import java.util.function.*;
import static java.util.stream.Collectors.*;
/**
* A base abstract implementation for the graph adapter class using Guava's {@link ValueGraph}. This
* is a helper class in order to support both mutable and immutable value graphs.
*
* @author Dimitrios Michail
*
* @param the graph vertex type
* @param the value type
* @param type of the underlying Guava's value graph
*/
public abstract class BaseValueGraphAdapter>
extends
AbstractGraph>
implements
Graph>,
Cloneable,
Serializable
{
private static final long serialVersionUID = 3833510139696864917L;
protected static final String LOOPS_NOT_ALLOWED = "loops not allowed";
protected transient Set unmodifiableVertexSet = null;
protected transient Set> unmodifiableEdgeSet = null;
protected Supplier vertexSupplier;
protected Supplier> edgeSupplier;
protected ToDoubleFunction valueConverter;
protected transient VG valueGraph;
/**
* Create a new adapter.
*
* @param valueGraph the mutable value graph
* @param valueConverter a function that converts a value to a double
*/
public BaseValueGraphAdapter(VG valueGraph, ToDoubleFunction valueConverter)
{
this(valueGraph, valueConverter, null, null);
}
/**
* Create a new adapter.
*
* @param valueGraph the mutable value graph
* @param valueConverter a function that converts a value to a double
* @param vertexSupplier the vertex supplier
* @param edgeSupplier the edge supplier
*/
public BaseValueGraphAdapter(
VG valueGraph, ToDoubleFunction valueConverter, Supplier vertexSupplier,
Supplier> edgeSupplier)
{
this.vertexSupplier = vertexSupplier;
this.edgeSupplier = edgeSupplier;
this.valueGraph = Objects.requireNonNull(valueGraph);
this.valueConverter = Objects.requireNonNull(valueConverter);
}
@Override
public Supplier getVertexSupplier()
{
return vertexSupplier;
}
/**
* Set the vertex supplier that the graph uses whenever it needs to create new vertices.
*
*
* A graph uses the vertex supplier to create new vertex objects whenever a user calls method
* {@link Graph#addVertex()}. Users can also create the vertex in user code and then use method
* {@link Graph#addVertex(Object)} to add the vertex.
*
*
* In contrast with the {@link Supplier} interface, the vertex supplier has the additional
* requirement that a new and distinct result is returned every time it is invoked. More
* specifically for a new vertex to be added in a graph v
must not be equal
* to any other vertex in the graph. More formally, the graph must not contain any vertex
* v2
such that v2.equals(v)
.
*
* @param vertexSupplier the vertex supplier
*/
public void setVertexSupplier(Supplier vertexSupplier)
{
this.vertexSupplier = vertexSupplier;
}
@Override
public Supplier> getEdgeSupplier()
{
return edgeSupplier;
}
/**
* Set the edge supplier that the graph uses whenever it needs to create new edges.
*
*
* A graph uses the edge supplier to create new edge objects whenever a user calls method
* {@link Graph#addEdge(Object, Object)}. Users can also create the edge in user code and then
* use method {@link Graph#addEdge(Object, Object, Object)} to add the edge.
*
*
* In contrast with the {@link Supplier} interface, the edge supplier has the additional
* requirement that a new and distinct result is returned every time it is invoked. More
* specifically for a new edge to be added in a graph e
must not be equal to
* any other edge in the graph (even if the graph allows edge-multiplicity). More formally, the
* graph must not contain any edge e2
such that e2.equals(e)
.
*
* @param edgeSupplier the edge supplier
*/
public void setEdgeSupplier(Supplier> edgeSupplier)
{
this.edgeSupplier = edgeSupplier;
}
@Override
public EndpointPair getEdge(V sourceVertex, V targetVertex)
{
if (sourceVertex == null || targetVertex == null) {
return null;
} else if (!valueGraph.hasEdgeConnecting(sourceVertex, targetVertex)) {
return null;
} else {
return createEdge(sourceVertex, targetVertex);
}
}
@Override
@Deprecated
public EdgeFactory> getEdgeFactory()
{
return null;
}
@Override
public Set vertexSet()
{
if (unmodifiableVertexSet == null) {
unmodifiableVertexSet = Collections.unmodifiableSet(valueGraph.nodes());
}
return unmodifiableVertexSet;
}
@Override
public V getEdgeSource(EndpointPair e)
{
return e.nodeU();
}
@Override
public V getEdgeTarget(EndpointPair e)
{
return e.nodeV();
}
@Override
public GraphType getType()
{
return (valueGraph.isDirected() ? new DefaultGraphType.Builder().directed()
: new DefaultGraphType.Builder().undirected())
.weighted(true).allowMultipleEdges(false)
.allowSelfLoops(valueGraph.allowsSelfLoops()).build();
}
@Override
public boolean containsEdge(EndpointPair e)
{
return valueGraph.edges().contains(e);
}
@Override
public boolean containsVertex(V v)
{
return valueGraph.nodes().contains(v);
}
@Override
public Set> edgeSet()
{
if (unmodifiableEdgeSet == null) {
unmodifiableEdgeSet = Collections.unmodifiableSet(valueGraph.edges());
}
return unmodifiableEdgeSet;
}
@Override
public int degreeOf(V vertex)
{
return valueGraph.degree(vertex);
}
@Override
public Set> edgesOf(V vertex)
{
return valueGraph.incidentEdges(vertex);
}
@Override
public int inDegreeOf(V vertex)
{
return valueGraph.inDegree(vertex);
}
@Override
public Set> incomingEdgesOf(V vertex)
{
return valueGraph
.predecessors(vertex).stream().map(other -> createEdge(other, vertex))
.collect(collectingAndThen(toSet(), Collections::unmodifiableSet));
}
@Override
public int outDegreeOf(V vertex)
{
return valueGraph.outDegree(vertex);
}
@Override
public Set> outgoingEdgesOf(V vertex)
{
return valueGraph
.successors(vertex).stream().map(other -> createEdge(vertex, other))
.collect(collectingAndThen(toSet(), Collections::unmodifiableSet));
}
@Override
public double getEdgeWeight(EndpointPair e)
{
if (e == null) {
throw new NullPointerException();
} else if (!valueGraph.hasEdgeConnecting(e.nodeU(), e.nodeV())) {
throw new IllegalArgumentException("no such edge in graph: " + e.toString());
} else {
return valueGraph
.edgeValue(e.nodeU(), e.nodeV()).map(valueConverter::applyAsDouble)
.orElse(Graph.DEFAULT_EDGE_WEIGHT);
}
}
@Override
public Set> getAllEdges(V sourceVertex, V targetVertex)
{
if (sourceVertex == null || targetVertex == null
|| !valueGraph.nodes().contains(sourceVertex)
|| !valueGraph.nodes().contains(targetVertex))
{
return null;
} else if (!valueGraph.hasEdgeConnecting(sourceVertex, targetVertex)) {
return Collections.emptySet();
} else {
return Collections.singleton(createEdge(sourceVertex, targetVertex));
}
}
/**
* Create an edge
*
* @param s the source vertex
* @param t the target vertex
* @return the edge
*/
final EndpointPair createEdge(V s, V t)
{
return valueGraph.isDirected() ? EndpointPair.ordered(s, t) : EndpointPair.unordered(s, t);
}
}