Java tutorial
/* ***** BEGIN LICENSE BLOCK ***** * Copyright (C) 2008-2011, The 100GET-E3-R3G Project Team. * * This work has been funded by the Federal Ministry of Education * and Research of the Federal Republic of Germany * (BMBF Frderkennzeichen 01BP0775). It is part of the EUREKA project * "100 Gbit/s Carrier-Grade Ethernet Transport Technologies * (CELTIC CP4-001)". The authors alone are responsible for this work. * * See the file AUTHORS for details and contact information. * * This file is part of MuLaViTo (Multi-Layer Visualization Tool). * * MuLaViTo is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License Version 3 or later * (the "GPL"), or the GNU Lesser General Public License Version 3 or later * (the "LGPL") as published by the Free Software Foundation. * * MuLaViTo 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 General Public License * or the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License and * GNU Lesser General Public License along with MuLaViTo; see the file * COPYING. If not, see <http://www.gnu.org/licenses/>. * * ***** END LICENSE BLOCK ***** */ package mulavito.algorithms.shortestpath.ksp; import java.util.ArrayList; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.PriorityQueue; import java.util.Set; import org.apache.commons.collections15.ListUtils; import org.apache.commons.collections15.Predicate; import org.apache.commons.collections15.Transformer; import edu.uci.ics.jung.algorithms.filters.EdgePredicateFilter; import edu.uci.ics.jung.algorithms.shortestpath.DijkstraShortestPath; import edu.uci.ics.jung.graph.Graph; /** * <p> * Calculate the first <i>k</i>-shortest paths between source node and target * node using <i>Yen</i>'s algorithm. * </p> * * <p> * Method {@link #getkShortestPath} returns the first k shortest paths (KSP) for * a given <code>source</code> and <code>target</code>. * </p> * * <p> *"This paper presents an algorithm for finding the K loop-less paths that have * the shortest lengths from one node to another node in a network. The * significance of the new algorithm is that its computational upper bound * increases only linearly with the value of K. Consequently, in general, the * new algorithm is extremely efficient as com- pared with the algorithms * proposed by Bock, Kantner, and Haynes [2],Pollack [7], [81, Clarke, * Krikorian, and Rausan [3],Sakarovitch [9]and others. This paper first reviews * the algorithms presently available for finding the K shortest loop-less paths * in terms of the computational effort and memory addresses they require. This * is followed by the presentation of the new algorithm and its justification. * Finally, the efficiency of the new algorithm is examined and compared with * that of other algorithms." * * <pre> * @Article{ Yen71, * author = {Yen, Jin Y.}, * title = {{Another algorithm for finding the K shortest loop-less network paths}}, * journal = {Management Science} * volume = {17}, * number = {11}, * month = jul, * year = {1971}, * pages = {712--716}, * publisher = {JSTOR} * } * </pre> * * </p> * * @author Michael Duelli * @author Thilo Mller * @author Xiaohua Qin (original implementation) * * @param <V> * The parameter for vertices * @param <E> * The parameter for edges */ public class Yen<V, E> extends KShortestPathAlgorithm<V, E> { public Yen(Graph<V, E> graph, Transformer<E, Number> nev) { super(graph, nev); } private final class WeightedPath implements Comparable<WeightedPath> { private final List<E> path; private final double weight; public WeightedPath(List<E> path) { this.path = path; double tmp = 0.0; for (E e : path) tmp += nev.transform(e).doubleValue(); this.weight = tmp; } public List<E> getPath() { return path; } @Override public int compareTo(WeightedPath o) { if (weight < o.weight) return -1; else if (weight > o.weight) return 1; // from here on equal weight int sizeDiff = path.size() - o.path.size(); if (sizeDiff < 0) return -1; else if (sizeDiff > 0) return 1; return 0; } @Override public String toString() { return path + ";" + weight; } } @Override protected List<List<E>> getShortestPathsIntern(final V source, final V target, int k) { LinkedList<List<E>> found_paths = new LinkedList<List<E>>(); PriorityQueue<WeightedPath> prioQ = new PriorityQueue<WeightedPath>(); DijkstraShortestPath<V, E> blockedDijkstra; // Check if target is reachable from source. if (dijkstra.getDistance(source, target) == null) return found_paths; // Add Dijkstra solution, the first shortest path. found_paths.add(dijkstra.getPath(source, target)); while (found_paths.size() < k) { List<E> curShortestPath = found_paths.getLast(); int maxIndex = curShortestPath.size(); List<V> curShortestPathNodes = new LinkedList<V>(); curShortestPathNodes.add(source); for (E e : found_paths.getLast()) { V v = graph.getEndpoints(e).getFirst(); if (!curShortestPathNodes.contains(v)) curShortestPathNodes.add(v); v = graph.getEndpoints(e).getSecond(); if (!curShortestPathNodes.contains(v)) curShortestPathNodes.add(v); } curShortestPathNodes.remove(target); // Split path into Head and NextEdge for (int i = 0; i < maxIndex; i++) { List<E> head = curShortestPath.subList(0, i); // V deviation = head.isEmpty() ? source : graph.getEndpoints(head.get(i - 1)).getSecond(); V deviation = curShortestPathNodes.get(i); // 1. Block edges. Graph<V, E> blocked = blockFilter(head, deviation, curShortestPathNodes, found_paths); // 2. Get shortest path in graph with blocked edges. blockedDijkstra = new DijkstraShortestPath<V, E>(blocked, nev); Number dist = blockedDijkstra.getDistance(deviation, target); if (dist == null) continue; List<E> tail = blockedDijkstra.getPath(deviation, target); // 3. Combine head and tail into new path. List<E> candidate = new ArrayList<E>(); candidate.addAll(head); candidate.addAll(tail); // Check if we already found this solution boolean duplicate = false; for (WeightedPath path : prioQ) if (ListUtils.isEqualList(path.getPath(), candidate)) { duplicate = true; break; } if (!duplicate) prioQ.add(new WeightedPath(candidate)); } if (prioQ.isEmpty()) break; // We have not found any new candidate! else found_paths.add(prioQ.poll().getPath()); } return found_paths; } /** * Blocks all incident edges of the vertices in head as well as the edge * connecting head to the next node by creating a new filtered graph. * * @param head * The current head, from source to deviation node * @param deviation * The edge to the next node * @param foundPaths * The solutions already found and to check against * @return The filtered graph without the blocked edges. */ private Graph<V, E> blockFilter(List<E> head, V deviation, List<V> curShortestPathNodes, List<List<E>> foundPaths) { final Set<E> blocked = new HashSet<E>(); // Block incident edges to make all vertices in head unreachable. for (V v : curShortestPathNodes) { if (v.equals(deviation)) break; for (E e2 : graph.getIncidentEdges(v)) blocked.add(e2); } /*for (E e : head) for (E e2 : graph.getIncidentEdges(graph.getEndpoints(e).getFirst())) blocked.add(e2);*/ // Block all outgoing edges that have been used at deviation vertex for (List<E> path : foundPaths) if (path.size() > head.size() && ListUtils.isEqualList(path.subList(0, head.size()), head)) for (E e : path) if (graph.getEndpoints(e).contains(deviation)) { blocked.add(e); //break; // Continue with next path. } EdgePredicateFilter<V, E> filter = new EdgePredicateFilter<V, E>(new Predicate<E>() { @Override public boolean evaluate(E e) { return !blocked.contains(e); } }); return filter.transform(graph); } }