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}