
jcommon.graph.DirectedAcyclicGraph Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of graph Show documentation
Show all versions of graph Show documentation
Java library for simple in-memory graph operations such as iterative and concurrent topological sorts.
The newest version!
/*
Copyright (C) 2012-2013 the original author or authors.
See the LICENSE.txt file distributed with this work for additional
information regarding copyright ownership.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package jcommon.graph;
import jcommon.graph.impl.AdjacencyList;
import jcommon.graph.impl.Edge;
import jcommon.graph.impl.SimpleTopologicalSort;
import java.lang.reflect.Constructor;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Factory and implementation of a dependency graph that can topologically sort its vertices.
*
* @param Type of {@link IVertex} vertices that this graph contains.
*
* @see IGraph
*/
public class DirectedAcyclicGraph, TValue extends Object, TProcessedValue extends Object> implements Cloneable, IGraph {
private Set vertices = new LinkedHashSet(5, 0.8f);
private Set> edges = new LinkedHashSet>(8, 0.8f);
/**
* Protected constructor to prevent public instantiation.
*/
protected DirectedAcyclicGraph() {
}
/**
* @see IGraph#getVertices()
*/
@Override
public Set getVertices() {
return Collections.unmodifiableSet(vertices);
}
/**
* @see IGraph#getEdges()
*/
@Override
public Set> getEdges() {
return Collections.unmodifiableSet(edges);
}
/**
* @see IGraph#clone()
*/
@Override
protected Object clone() throws CloneNotSupportedException {
return copyGraph(this);
}
/**
* Copies the {@link DirectedAcyclicGraph} portion of a class that extends {@link DirectedAcyclicGraph}. Anything else that
* is specific to a superclass should be added to the returned instance.
*
* @param graph An instance of {@link DirectedAcyclicGraph} that needs copying.
* @param Type of {@link IVertex} of the graph vertices.
* @param Type of {@link DirectedAcyclicGraph} of the graph being copied.
* @return A new instance of type {@link TGraph} with {@link DirectedAcyclicGraph} specific fields already filled in.
*/
@SuppressWarnings("unchecked")
protected static , TVertex extends IVertex, TValue extends Object, TProcessedValue extends Object> TGraph copyGraph(final TGraph graph) {
try {
final Class g_class = graph.getClass();
final Constructor extends DirectedAcyclicGraph> construct = g_class.getDeclaredConstructor();
construct.setAccessible(true);
final TGraph g = (TGraph)construct.newInstance();
g.vertices = new LinkedHashSet(graph.vertices);
g.edges = new LinkedHashSet>(graph.edges);
return g;
} catch(Throwable t) {
return null;
}
}
/**
* @see IGraph#copy()
*/
public IGraph copy() {
return copyGraph(this);
}
/**
* Convenience method for easily constructing an instance of {@link IGraph} with the provided vertices.
*
* @param vertices A list of {@link IVertex} vertices to be added to a new {@link IGraph}.
* @param Type of {@link IVertex} of the vertices in the new {@link IGraph}.
* @return A new instance of {@link IGraph} with the provided vertices already added.
*/
public static , TValue extends Object, TProcessedValue extends Object> IGraph build(final TVertex...vertices) {
final DirectedAcyclicGraph g = new DirectedAcyclicGraph();
if (vertices != null) {
for(TVertex d : vertices) {
g.addVertex(d);
}
}
return g;
}
/**
* Convenience method for easily constructing an instance of {@link IGraph} with an empty set of vertices.
*
* @param Type of {@link IVertex} of the vertices in the new {@link IGraph}.
* @return A new instance of {@link IGraph} with an empty set of vertices.
*/
public static , TValue extends Object, TProcessedValue extends Object> IGraph create() {
return build((TVertex[])null);
}
/**
* @see IGraph#addVertex(IVertex)
*/
@Override
public IGraph addVertex(final TVertex vertex) {
if (vertex == null)
throw new IllegalArgumentException("vertex must not be null");
vertices.add(vertex);
return this;
}
/**
* @see IGraph#removeVertex(IVertex)
*/
@Override
public IGraph removeVertex(final TVertex vertex) {
if (vertex == null)
throw new IllegalArgumentException("vertex must not be null");
vertices.remove(vertex);
return this;
}
/**
* @see IGraph#addEdge(IVertex, IVertex)
*/
@Override
public IGraph addEdge(final TVertex from, final TVertex to) {
edges.add(new Edge(from, to));
return this;
}
/**
* @see IGraph#removeEdge(IVertex, IVertex)
*/
@Override
public IGraph removeEdge(final TVertex from, final TVertex to) {
edges.remove(new Edge(from, to));
return this;
}
/**
* @see IGraph#validate()
*/
@Override
public boolean validate() {
//Ensure that every from/to in an edge is present in our set of vertices.
//If we refer to one that isn't in there, then we've got a problem.
for(IEdge r : edges) {
if (!vertices.contains(r.getFrom()) || !vertices.contains(r.getTo()))
return false;
}
return true;
}
/**
* @see IGraph#sort()
*/
@Override
public List sort() throws CyclicGraphException {
return sort(new SimpleTopologicalSort());
}
/**
* @see IGraph#sort(ITopologicalSortStrategy)
*/
@Override
public List sort(final ITopologicalSortStrategy strategy) throws CyclicGraphException {
if (strategy == null)
throw new IllegalArgumentException("strategy cannot be null");
if (!validate())
throw new IllegalStateException("The graph is invalid. Please confirm that all vertices are present for every relationship.");
return strategy.sort(new AdjacencyList(vertices, edges));
}
/**
* @see IGraph#sortAsync(ITopologicalSortCallback)
*/
@Override
public ITopologicalSortAsyncResult sortAsync(final ITopologicalSortCallback callback) {
return sortAsync(new SimpleTopologicalSort(), callback, null);
}
/**
* @see IGraph#sortAsync(ITopologicalSortCallback, ITopologicalSortErrorCallback)
*/
@Override
public ITopologicalSortAsyncResult sortAsync(final ITopologicalSortCallback callback, final ITopologicalSortErrorCallback errorCallback) {
return sortAsync(new SimpleTopologicalSort(), callback, errorCallback);
}
/**
* @see IGraph#sortAsync(ITopologicalSortStrategy, ITopologicalSortCallback)
*/
@Override
public ITopologicalSortAsyncResult sortAsync(final ITopologicalSortStrategy strategy, final ITopologicalSortCallback callback) {
return sortAsync(strategy, callback, null);
}
/**
* @see IGraph#sortAsync(ITopologicalSortStrategy, ITopologicalSortCallback, ITopologicalSortErrorCallback)
*/
@Override
public ITopologicalSortAsyncResult sortAsync(final ITopologicalSortStrategy strategy, final ITopologicalSortCallback callback, final ITopologicalSortErrorCallback errorCallback) {
final ExecutorService executor = Executors.newFixedThreadPool(Math.max(2, Runtime.getRuntime().availableProcessors() + 1));
final ITopologicalSortAsyncResult result = sortAsync(executor, strategy, callback, errorCallback);
//We don't explicity shutdown b/c we may not be done processing
//at this point. If need to abort prematurely, the caller can
//access the executor service from the .getExecutorService()
//method.
return result;
}
/**
* @see IGraph#sortAsync(java.util.concurrent.ExecutorService, ITopologicalSortCallback)
*/
@Override
public ITopologicalSortAsyncResult sortAsync(final ExecutorService executor, final ITopologicalSortCallback callback) {
return sortAsync(executor, new SimpleTopologicalSort(), callback, null);
}
/**
* @see IGraph#sortAsync(java.util.concurrent.ExecutorService, ITopologicalSortCallback, ITopologicalSortErrorCallback)
*/
@Override
public ITopologicalSortAsyncResult sortAsync(final ExecutorService executor, final ITopologicalSortCallback callback, final ITopologicalSortErrorCallback errorCallback) {
return sortAsync(executor, new SimpleTopologicalSort(), callback, errorCallback);
}
/**
* @see IGraph#sortAsync(java.util.concurrent.ExecutorService, ITopologicalSortStrategy, ITopologicalSortCallback)
*/
@Override
public ITopologicalSortAsyncResult sortAsync(final ExecutorService executor, final ITopologicalSortStrategy strategy, final ITopologicalSortCallback callback) {
return sortAsync(executor, strategy, callback, null);
}
/**
* @see IGraph#sortAsync(java.util.concurrent.ExecutorService, ITopologicalSortStrategy, ITopologicalSortCallback, ITopologicalSortErrorCallback)
*/
@Override
public ITopologicalSortAsyncResult sortAsync(final ExecutorService executor, final ITopologicalSortStrategy strategy, final ITopologicalSortCallback callback, final ITopologicalSortErrorCallback errorCallback) {
if (strategy == null)
throw new IllegalArgumentException("strategy cannot be null");
if (callback == null)
throw new IllegalArgumentException("callback cannot be null");
if (!validate())
throw new IllegalStateException("The graph is invalid. Please confirm that all vertices are present for every relationship.");
return strategy.sortAsync(executor, new AdjacencyList(vertices, edges), callback, errorCallback);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy