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

net.automatalib.util.graphs.sssp.DijkstraSSSP Maven / Gradle / Ivy

Go to download

This artifact provides various common utility operations for analyzing and manipulating automata and graphs, such as traversal, minimization and copying.

There is a newer version: 0.11.0
Show newest version
/* Copyright (C) 2013-2019 TU Dortmund
 * This file is part of AutomataLib, http://www.automatalib.net/.
 *
 * 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 net.automatalib.util.graphs.sssp;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;

import net.automatalib.commons.smartcollections.BinaryHeap;
import net.automatalib.commons.smartcollections.ElementReference;
import net.automatalib.commons.smartcollections.SmartDynamicPriorityQueue;
import net.automatalib.commons.util.mappings.MutableMapping;
import net.automatalib.graphs.Graph;
import net.automatalib.graphs.concepts.EdgeWeights;
import net.automatalib.util.graphs.Graphs;

/**
 * Implementation of Dijkstras algorithm for the single-source shortest path problem.
 *
 * @param 
 *         node class
 * @param 
 *         edge class
 *
 * @author Malte Isberner
 */
@ParametersAreNonnullByDefault
public class DijkstraSSSP implements SSSPResult {

    private final Graph graph;
    private final N init;
    private final EdgeWeights edgeWeights;
    private final MutableMapping> records;

    /**
     * Constructor.
     *
     * @param graph
     *         the graph in which to search for shortest paths
     * @param init
     *         the initial node
     * @param edgeWeights
     *         the edge weights
     */
    public DijkstraSSSP(Graph graph, N init, EdgeWeights edgeWeights) {
        this.graph = graph;
        this.init = init;
        this.edgeWeights = edgeWeights;
        this.records = graph.createStaticNodeMapping();
    }

    /**
     * Search for the shortest paths from a single source node in a graph.
     *
     * @param graph
     *         the graph in which to perform the search
     * @param init
     *         the initial (source) node
     * @param edgeWeights
     *         the edge weights
     *
     * @return the single-source shortest path results
     */
    @Nonnull
    public static  SSSPResult findSSSP(Graph graph, N init, EdgeWeights edgeWeights) {
        DijkstraSSSP dijkstra = new DijkstraSSSP<>(graph, init, edgeWeights);
        dijkstra.findSSSP();
        return dijkstra;
    }

    /**
     * Start the search. This method may only be invoked once.
     */
    public void findSSSP() {
        Record initRec = new Record<>(init, 0.0f);
        if (records.put(init, initRec) != null) {
            throw new IllegalStateException("Search has already been performed!");
        }

        SmartDynamicPriorityQueue> pq = BinaryHeap.create(graph.size());
        initRec.ref = pq.referencedAdd(initRec);

        while (!pq.isEmpty()) {
            // Remove node with minimum distance
            Record rec = pq.extractMin();
            float dist = rec.dist;

            N node = rec.node;

            // edge scanning
            for (E edge : graph.getOutgoingEdges(node)) {
                float w = edgeWeights.getEdgeWeight(edge);
                float newDist = dist + w;

                N tgt = graph.getTarget(edge);
                Record tgtRec = records.get(tgt);
                if (tgtRec == null) {
                    // node has not been visited before, add a record
                    // and add it to the queue
                    tgtRec = new Record<>(tgt, newDist, edge, rec);
                    tgtRec.ref = pq.referencedAdd(tgtRec);
                    records.put(tgt, tgtRec);
                } else if (newDist < tgtRec.dist) {
                    // using currently considered edge decreases current distance
                    tgtRec.dist = newDist;
                    tgtRec.reach = edge;
                    tgtRec.depth = rec.depth + 1;
                    tgtRec.parent = rec;
                    // update it's position in the queue
                    pq.keyChanged(tgtRec.ref);
                }
            }
        }
    }

    @Override
    public N getInitialNode() {
        return init;
    }

    @Override
    public float getShortestPathDistance(N target) {
        Record rec = records.get(target);
        if (rec == null) {
            return Graphs.INVALID_DISTANCE;
        }
        return rec.dist;
    }

    @Override
    public List getShortestPath(N target) {
        Record rec = records.get(target);
        if (rec == null) {
            return null;
        }

        if (rec.depth == 0) {
            return Collections.emptyList();
        }

        List result = new ArrayList<>(rec.depth);

        E edge;
        while ((edge = rec.reach) != null) {
            result.add(edge);
            rec = rec.parent;
        }

        Collections.reverse(result);
        return result;
    }

    @Override
    public E getShortestPathEdge(N target) {
        Record rec = records.get(target);
        if (rec == null) {
            return null;
        }
        return rec.reach;
    }

    /**
     * Internal data record.
     * Note: this class has a natural ordering that is inconsistent with equals.
     */
    @ParametersAreNonnullByDefault
    private static final class Record implements Comparable> {

        @Nonnull
        public final N node;
        public float dist;
        @Nullable
        public ElementReference ref;
        @Nullable
        public E reach;
        @Nullable
        public Record parent;
        int depth;

        Record(N node, float dist) {
            this(node, dist, null, null);
        }

        Record(N node, float dist, @Nullable E reach, @Nullable Record parent) {
            this.node = node;
            this.dist = dist;
            this.reach = reach;
            this.parent = parent;
            this.depth = (parent != null) ? parent.depth + 1 : 0;
        }

        @Override
        public int compareTo(Record o) {
            return Float.compare(dist, o.dist);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy