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

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