com.salesforce.jgrapht.alg.AllDirectedPaths Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of AptSpringProcessor Show documentation
Show all versions of AptSpringProcessor Show documentation
This project contains the apt processor that implements all the checks enumerated in @Verify. It is a self contained, and
shaded jar.
/*
* (C) Copyright 2015-2017, by Vera-Licona Research Group 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 com.salesforce.jgrapht.alg;
import java.util.*;
import com.salesforce.jgrapht.*;
import com.salesforce.jgrapht.graph.*;
/**
* A Dijkstra-like algorithm to find all paths between two sets of nodes in a directed graph, with
* options to search only simple paths and to limit the path length.
*
* @param the graph vertex type
* @param the graph edge type
*
* @author Andrew Gainer-Dewar
* @since Feb, 2016
*
* @deprecated In favor of {@link com.salesforce.jgrapht.alg.shortestpath.AllDirectedPaths}.
*/
@Deprecated
public class AllDirectedPaths
{
private final DirectedGraph graph;
/**
* Create a new instance
*
* @param graph the input graph
*/
public AllDirectedPaths(DirectedGraph graph)
{
if (graph == null) {
throw new IllegalArgumentException("Graph cannot be null!");
}
this.graph = graph;
}
/**
* Calculate (and return) all paths from the source vertex to the target vertex.
*
* @param sourceVertex the source vertex
* @param targetVertex the target vertex
* @param simplePathsOnly if true, only search simple (non-self-intersecting) paths
* @param maxPathLength maximum number of edges to allow in a path (if null, all paths are
* considered, which may be very slow due to potentially huge output)
* @return all paths from the source vertex to the target vertex
*/
public List> getAllPaths(
V sourceVertex, V targetVertex, boolean simplePathsOnly, Integer maxPathLength)
{
return getAllPaths(
Collections.singleton(sourceVertex), Collections.singleton(targetVertex),
simplePathsOnly, maxPathLength);
}
/**
* Calculate (and return) all paths from the source vertices to the target vertices.
*
* @param sourceVertices the source vertices
* @param targetVertices the target vertices
* @param simplePathsOnly if true, only search simple (non-self-intersecting) paths
* @param maxPathLength maximum number of edges to allow in a path (if null, all paths are
* considered, which may be very slow due to potentially huge output)
*
* @return list of all paths from the sources to the targets containing no more than
* maxPathLength edges
*/
public List> getAllPaths(
Set sourceVertices, Set targetVertices, boolean simplePathsOnly,
Integer maxPathLength)
{
if ((maxPathLength != null) && (maxPathLength < 0)) {
throw new IllegalArgumentException("maxPathLength must be non-negative if defined");
}
if (!simplePathsOnly && (maxPathLength == null)) {
throw new IllegalArgumentException(
"If search is not restricted to simple paths, a maximum path length must be set to avoid infinite cycles");
}
if ((sourceVertices.isEmpty()) || (targetVertices.isEmpty())) {
return Collections.emptyList();
}
// Decorate the edges with the minimum path lengths through them
Map edgeMinDistancesFromTargets =
edgeMinDistancesBackwards(targetVertices, maxPathLength);
// Generate all the paths
return generatePaths(
sourceVertices, targetVertices, simplePathsOnly, maxPathLength,
edgeMinDistancesFromTargets);
}
/**
* Compute the minimum number of edges in a path to the targets through each edge, so long as it
* is not greater than a bound.
*
* @param targetVertices the target vertices
* @param maxPathLength maximum number of edges to allow in a path (if null, all edges will be
* considered, which may be expensive)
*
* @return the minimum number of edges in a path from each edge to the targets, encoded in a Map
*/
private Map edgeMinDistancesBackwards(Set targetVertices, Integer maxPathLength)
{
/*
* We walk backwards through the network from the target vertices, marking edges and
* vertices with their minimum distances as we go.
*/
Map edgeMinDistances = new HashMap<>();
Map vertexMinDistances = new HashMap<>();
Queue verticesToProcess = new LinkedList<>();
// Input sanity checking
if (maxPathLength != null) {
if (maxPathLength < 0) {
throw new IllegalArgumentException("maxPathLength must be non-negative if defined");
}
if (maxPathLength == 0) {
return edgeMinDistances;
}
}
// Bootstrap the process with the target vertices
for (V target : targetVertices) {
vertexMinDistances.put(target, 0);
verticesToProcess.add(target);
}
// Work through the node queue. When it's empty, we're done!
for (V vertex; (vertex = verticesToProcess.poll()) != null;) {
assert vertexMinDistances.containsKey(vertex);
Integer childDistance = vertexMinDistances.get(vertex) + 1;
// Check whether the incoming edges of this node are correctly
// decorated
for (E edge : graph.incomingEdgesOf(vertex)) {
// Mark the edge if needed
if (!edgeMinDistances.containsKey(edge)
|| (edgeMinDistances.get(edge) > childDistance))
{
edgeMinDistances.put(edge, childDistance);
}
// Mark the edge's source vertex if needed
V edgeSource = graph.getEdgeSource(edge);
if (!vertexMinDistances.containsKey(edgeSource)
|| (vertexMinDistances.get(edgeSource) > childDistance))
{
vertexMinDistances.put(edgeSource, childDistance);
if ((maxPathLength == null) || (childDistance < maxPathLength)) {
verticesToProcess.add(edgeSource);
}
}
}
}
assert verticesToProcess.isEmpty();
return edgeMinDistances;
}
/**
* Generate all paths from the sources to the targets, using pre-computed minimum distances.
*
* @param sourceVertices the source vertices
* @param targetVertices the target vertices
* @param maxPathLength maximum number of edges to allow in a path
* @param simplePathsOnly if true, only search simple (non-self-intersecting) paths (if null,
* all edges will be considered, which may be expensive)
* @param edgeMinDistancesFromTargets the minimum number of edges in a path to a target through
* each edge, as computed by {@code
* edgeMinDistancesBackwards}.
*
* @return a List of all GraphPaths from the sources to the targets satisfying the given
* constraints
*/
private List> generatePaths(
Set sourceVertices, Set targetVertices, boolean simplePathsOnly,
Integer maxPathLength, Map edgeMinDistancesFromTargets)
{
/*
* We walk forwards through the network from the source vertices, exploring all outgoing
* edges whose minimum distances is small enough.
*/
List> completePaths = new ArrayList<>();
Deque> incompletePaths = new LinkedList<>();
// Input sanity checking
if (maxPathLength != null) {
if (maxPathLength < 0) {
throw new IllegalArgumentException("maxPathLength must be non-negative if defined");
}
if (maxPathLength == 0) {
return completePaths;
}
}
// Bootstrap the search with the source vertices
for (V source : sourceVertices) {
if (targetVertices.contains(source)) {
completePaths.add(new GraphWalk<>(graph, source, source, new ArrayList<>(), 0));
}
for (E edge : graph.outgoingEdgesOf(source)) {
assert graph.getEdgeSource(edge).equals(source);
if (targetVertices.contains(graph.getEdgeTarget(edge))) {
completePaths.add(makePath(Collections.singletonList(edge)));
}
if (edgeMinDistancesFromTargets.containsKey(edge)) {
List path = Collections.singletonList(edge);
incompletePaths.add(path);
}
}
}
// Walk through the queue of incomplete paths
for (List incompletePath; (incompletePath = incompletePaths.poll()) != null;) {
Integer lengthSoFar = incompletePath.size();
assert (maxPathLength == null) || (lengthSoFar < maxPathLength);
E leafEdge = incompletePath.get(lengthSoFar - 1);
V leafNode = graph.getEdgeTarget(leafEdge);
Set pathVertices = new HashSet<>();
for (E pathEdge : incompletePath) {
pathVertices.add(graph.getEdgeSource(pathEdge));
pathVertices.add(graph.getEdgeTarget(pathEdge));
}
for (E outEdge : graph.outgoingEdgesOf(leafNode)) {
// Proceed if the outgoing edge is marked and the mark
// is sufficiently small
if (edgeMinDistancesFromTargets.containsKey(outEdge)
&& ((maxPathLength == null) || ((edgeMinDistancesFromTargets.get(outEdge)
+ lengthSoFar) <= maxPathLength)))
{
List newPath = new ArrayList<>(incompletePath);
newPath.add(outEdge);
// If requested, make sure this path isn't self-intersecting
if (simplePathsOnly && pathVertices.contains(graph.getEdgeTarget(outEdge))) {
continue;
}
// If this path reaches a target, add it to completePaths
if (targetVertices.contains(graph.getEdgeTarget(outEdge))) {
GraphPath completePath = makePath(newPath);
assert sourceVertices.contains(completePath.getStartVertex());
assert targetVertices.contains(completePath.getEndVertex());
assert (maxPathLength == null)
|| (completePath.getWeight() <= maxPathLength);
completePaths.add(completePath);
}
// If this path is short enough, consider further
// extensions of it
if ((maxPathLength == null) || (newPath.size() < maxPathLength)) {
incompletePaths.addFirst(newPath); // We use
// incompletePaths in
// FIFO mode to avoid
// memory blowup
}
}
}
}
assert incompletePaths.isEmpty();
return completePaths;
}
/**
* Transform an ordered list of edges into a GraphPath
*
* @param edges the edges
*
* @return the corresponding GraphPath
*/
private GraphPath makePath(List edges)
{
V source = graph.getEdgeSource(edges.get(0));
V target = graph.getEdgeTarget(edges.get(edges.size() - 1));
double weight = edges.size();
return new GraphWalk<>(graph, source, target, edges, weight);
}
}
// End AllDirectedPaths.java
© 2015 - 2025 Weber Informatics LLC | Privacy Policy