001/* Computation of the all pair shortest path of a DirectedGraph using the 002 Floyd-Warshall algorithm. 003 004 Copyright (c) 2003-2014 The University of Maryland. All rights reserved. 005 Permission is hereby granted, without written agreement and without 006 license or royalty fees, to use, copy, modify, and distribute this 007 software and its documentation for any purpose, provided that the above 008 copyright notice and the following two paragraphs appear in all copies 009 of this software. 010 011 IN NO EVENT SHALL THE UNIVERSITY OF MARYLAND BE LIABLE TO ANY PARTY 012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 014 THE UNIVERSITY OF MARYLAND HAS BEEN ADVISED OF THE POSSIBILITY OF 015 SUCH DAMAGE. 016 017 THE UNIVERSITY OF MARYLAND SPECIFICALLY DISCLAIMS ANY WARRANTIES, 018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 021 MARYLAND HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 022 ENHANCEMENTS, OR MODIFICATIONS. 023 024 025 */ 026package ptolemy.graph.analysis.strategy; 027 028import java.util.ArrayList; 029import java.util.Iterator; 030import java.util.List; 031 032import ptolemy.graph.DirectedGraph; 033import ptolemy.graph.Edge; 034import ptolemy.graph.Graph; 035import ptolemy.graph.Node; 036import ptolemy.graph.analysis.analyzer.AllPairShortestPathAnalyzer; 037import ptolemy.graph.mapping.ToDoubleMapping; 038 039/////////////////////////////////////////////////////////////////// 040//// FloydWarshallAllPairShortestPathStrategy 041 042/** 043 Computation of the all pair shortest path of a directed graph using the 044 Floyd-Warshall algorithm. The result is in the form of two dimensional array 045 (matrix). 046 The first dimension is indexed by the source node label while the second one is 047 indexed by the sink node label. In graphs that have multiple edges between two 048 nodes obviously the edge with the minimum weight is being considered for 049 the shortest path. 050 The distance between a node and itself is being considered Double.MAX_VALUE, 051 unless otherwise specified by a self edge for a cyclic graph. 052 ((double[][])result())[i][i] would be the length of the shortest cycle that 053 includes the node with label "i". 054 <p> 055 @see ptolemy.graph.analysis.AllPairShortestPathAnalysis 056 @since Ptolemy II 4.0 057 @Pt.ProposedRating Red (shahrooz) 058 @Pt.AcceptedRating Red (ssb) 059 @author Shahrooz Shahparnia 060 @version $Id$ 061 */ 062public class FloydWarshallAllPairShortestPathStrategy 063 extends FloydWarshallStrategy implements AllPairShortestPathAnalyzer { 064 /** Construct an AllPairShortestPathAnalyzer which works using the 065 * Floyd-Warshall strategy. 066 * 067 * @param graph The given graph. 068 * @param edgeLengths The edge lengths. 069 */ 070 public FloydWarshallAllPairShortestPathStrategy(Graph graph, 071 ToDoubleMapping edgeLengths) { 072 super(graph); 073 _edgeLengths = edgeLengths; 074 } 075 076 /////////////////////////////////////////////////////////////////// 077 //// public methods //// 078 079 /** Return the nodes on the shortest path from the node 080 * startNode to the node endNode in the form of an ordered list. 081 * 082 * @param startNode The starting node of the path. 083 * @param endNode The ending node of the path. 084 * @return Return the nodes on the shortest path from the 085 * node startNode to the node endNode in the form of an ordered list. 086 */ 087 @Override 088 public List shortestPath(Node startNode, Node endNode) { 089 ArrayList shortestPath = null; 090 int startNodeLabel = graph().nodeLabel(startNode); 091 int endNodeLabel = graph().nodeLabel(endNode); 092 //int n = graph().nodeCount(); 093 int[][] nodeLabels = predecessors(); 094 095 if (nodeLabels[startNodeLabel][endNodeLabel] != -1) { 096 shortestPath = new ArrayList(); 097 shortestPath.add(endNode); 098 099 Node nodeOnPath = endNode; 100 101 while (nodeOnPath != startNode) { 102 int nodeOnPathLabel = graph().nodeLabel(nodeOnPath); 103 nodeOnPath = graph() 104 .node(nodeLabels[startNodeLabel][nodeOnPathLabel]); 105 shortestPath.add(nodeOnPath); 106 } 107 } 108 109 return shortestPath; 110 } 111 112 /** Return the length of the shortest path from the node 113 * startNode to the node endNode. 114 * 115 * @param startNode The starting node of the path. 116 * @param endNode The end node of the path. 117 * @return Return the length of the shortest path from the node 118 * startNode to the node endNode. 119 */ 120 @Override 121 public double shortestPathLength(Node startNode, Node endNode) { 122 double result = 0.0; 123 //int n = graph().nodeCount(); 124 double[][] shortestPathResults = (double[][]) _result(); 125 result = shortestPathResults[graph().nodeLabel(startNode)][graph() 126 .nodeLabel(endNode)]; 127 return result; 128 } 129 130 /** Return the all pair shortest path of the graph in the form of 131 * two dimensional array (matrix). The first dimension is indexed by the 132 * source node label while the second one is indexed by the 133 * sink node label. In graphs that have multiple edges between two nodes 134 * obviously the edge with the minimum weight is being considered for 135 * the shortest path. 136 * The distance between a node and itself is being considered 137 * Double.MAX_VALUE unless otherwise specified by a self edge. 138 * for a cyclic graph ((double[][])result())[i][i] would be the length 139 * of the shortest cycle that includes the node with label "i". 140 * 141 * @see ptolemy.graph.Graph#nodeLabel 142 * @return The all pair shortest path matrix as a double[][]. 143 */ 144 @Override 145 public double[][] shortestPathMatrix() { 146 return (double[][]) _result(); 147 } 148 149 /** Return a description of the analyzer. 150 * 151 * @return Return a description of the analyzer.. 152 */ 153 @Override 154 public String toString() { 155 return "All pair shortest path analyzer" 156 + " based on the Floyd-Warshall algorithm."; 157 } 158 159 /** Check for compatibility between the analysis and the given 160 * graph. A graph needs to be an instance of a DirectedGraph in order 161 * to use this algorithm. In addition the given object should be the same 162 * graph associated with this analyzer. 163 * 164 * @return True if the graph is a directed graph. 165 */ 166 @Override 167 public boolean valid() { 168 return graph() instanceof DirectedGraph; 169 } 170 171 /////////////////////////////////////////////////////////////////// 172 //// protected methods //// 173 174 /** Compute the all pair shortest path of the graph in the form of 175 * two dimensional array (matrix). 176 * 177 * @return The all pair shortest path matrix as a double[][] Object. 178 */ 179 @Override 180 protected Object _compute() { 181 int n = graph().nodeCount(); 182 183 // Initialize shortest path matrix 184 _allPairShortestPath = new double[n + 1][n][n]; 185 _predecessors = new int[n + 1][n][n]; 186 187 for (int i = 0; i < n; i++) { 188 for (int j = 0; j < n; j++) { 189 _predecessors[0][i][j] = -1; 190 191 _allPairShortestPath[0][i][j] = Double.MAX_VALUE; 192 } 193 194 Node node = graph().node(i); 195 Iterator outputEdges = ((DirectedGraph) graph()).outputEdges(node) 196 .iterator(); 197 198 while (outputEdges.hasNext()) { 199 Edge edge = (Edge) outputEdges.next(); 200 int sinkLabel = ((DirectedGraph) graph()) 201 .nodeLabel(edge.sink()); 202 203 if (_allPairShortestPath[0][i][sinkLabel] > _edgeLengths 204 .toDouble(edge)) { 205 _allPairShortestPath[0][i][sinkLabel] = _edgeLengths 206 .toDouble(edge); 207 } 208 209 _predecessors[0][i][sinkLabel] = i; 210 } 211 } 212 213 super._compute(); 214 _predecessorResult = _predecessors[n]; 215 return _allPairShortestPath[n]; 216 } 217 218 /** The FloydWarshall computation associated with this, 219 * analysis. 220 * 221 * @param k The counting parameter of the first loop of the Floyd-Warshall 222 * computation. 223 * @param i The counting parameter of the second loop of the Floyd-Warshall 224 * computation. 225 * @param j The counting parameter of the third and last loop of the 226 * Floyd-Warshall computation. 227 */ 228 @Override 229 protected final void _floydWarshallComputation(int k, int i, int j) { 230 double b = Double.MAX_VALUE; 231 double a = _allPairShortestPath[k][i][j]; 232 233 if (i != k && k != j) { 234 b = _allPairShortestPath[k][i][k] + _allPairShortestPath[k][k][j]; 235 } else if (i == k && k != j) { 236 b = _allPairShortestPath[k][k][j]; 237 } else if (i != k && k == j) { 238 b = _allPairShortestPath[k][i][k]; 239 } 240 241 if (b >= a) { 242 _allPairShortestPath[k + 1][i][j] = a; 243 _predecessors[k + 1][i][j] = _predecessors[k][i][j]; 244 } else { 245 _allPairShortestPath[k + 1][i][j] = b; 246 _predecessors[k + 1][i][j] = _predecessors[k][k][j]; 247 } 248 } 249 250 /////////////////////////////////////////////////////////////////// 251 //// private methods //// 252 253 /** Return the node before the end node on the shortest path from a starting 254 * node to an ending node. The first dimension is indexed by the 255 * start node label while the second one is indexed by the 256 * end node label. The {@link #shortestPathMatrix} method should be called 257 * before this method in order to make the result consistent with the 258 * current state (graph, edge values, ...). 259 * 260 * @return Return the node before the end node on the shortest path from a 261 * starting node to an ending node. 262 */ 263 private int[][] predecessors() { 264 return _predecessorResult; 265 } 266 267 /////////////////////////////////////////////////////////////////// 268 //// private variables //// 269 private ToDoubleMapping _edgeLengths; 270 271 private int[][][] _predecessors; 272 273 private int[][] _predecessorResult; 274 275 private double[][][] _allPairShortestPath; 276}