net.automatalib.algorithms.graph.sssp.DijkstraSSSP Maven / Gradle / Ivy
/* Copyright (C) 2013 TU Dortmund
* This file is part of AutomataLib, http://www.automatalib.net/.
*
* AutomataLib is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 3.0 as published by the Free Software Foundation.
*
* AutomataLib is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with AutomataLib; if not, see
* http://www.gnu.de/documents/lgpl.en.html.
*/
package net.automatalib.algorithms.graph.sssp;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import net.automatalib.algorithms.graph.GraphAlgorithms;
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;
/**
* Implementation of Dijkstras algorithm for the single-source shortest path
* problem.
*
* @author Malte Isberner
*
* @param node class
* @param edge class
*/
public class DijkstraSSSP implements SSSPResult {
/*
* Internal data record
*/
private static final class Record implements Comparable> {
public final N node;
public float dist;
public ElementReference ref;
public E reach;
public Record parent;
int depth;
public Record(N node, float dist) {
this(node, dist, null, null);
}
public Record(N node, float dist, E reach, 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) {
if(dist < o.dist)
return -1;
return (dist == o.dist) ? 0 : 1;
}
}
/**
* 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
*/
public static SSSPResult findSSSP(Graph graph, N init, EdgeWeights edgeWeights) {
DijkstraSSSP dijkstra = new DijkstraSSSP(graph, init, edgeWeights);
dijkstra.findSSSP();
return dijkstra;
}
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();
}
/**
* 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);
}
}
}
}
/*
* (non-Javadoc)
* @see net.automatalib.algorithms.graph.sssp.SSSPResult#getShortestPathDistance(java.lang.Object)
*/
@Override
public float getShortestPathDistance(N target) {
Record rec = records.get(target);
if(rec == null)
return GraphAlgorithms.INVALID_DISTANCE;
return rec.dist;
}
/*
* (non-Javadoc)
* @see net.automatalib.algorithms.graph.sssp.SSSPResult#getShortestPath(java.lang.Object)
*/
@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;
}
/*
* (non-Javadoc)
* @see net.automatalib.algorithms.graph.sssp.SSSPResult#getInitialNode()
*/
@Override
public N getInitialNode() {
return init;
}
/*
* (non-Javadoc)
* @see net.automatalib.algorithms.graph.sssp.SSSPResult#getShortestPathEdge(java.lang.Object)
*/
@Override
public E getShortestPathEdge(N target) {
Record rec = records.get(target);
if(rec == null)
return null;
return rec.reach;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy