All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jgrapht.alg.AllDirectedPaths Maven / Gradle / Ivy

There is a newer version: 1.5.2
Show newest version
/*
 * (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 org.jgrapht.alg;

import java.util.*;

import org.jgrapht.*;
import org.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 org.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 - 2024 Weber Informatics LLC | Privacy Policy