001/* Maximum profit to cost ratio analyzer which uses Parhi's algorithm for 002 iteration bound. 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.HashMap; 030import java.util.Iterator; 031import java.util.List; 032 033import ptolemy.graph.DirectedGraph; 034import ptolemy.graph.Edge; 035import ptolemy.graph.Graph; 036import ptolemy.graph.Node; 037import ptolemy.graph.analysis.SingleSourceLongestPathAnalysis; 038import ptolemy.graph.analysis.analyzer.CycleExistenceAnalyzer; 039import ptolemy.graph.analysis.analyzer.CycleMeanAnalyzer; 040import ptolemy.graph.analysis.analyzer.MaximumProfitToCostRatioAnalyzer; 041import ptolemy.graph.mapping.ToDoubleMapMapping; 042import ptolemy.graph.mapping.ToDoubleMapping; 043import ptolemy.graph.mapping.ToIntMapping; 044 045/////////////////////////////////////////////////////////////////// 046//// ParhiMaximumProfitToCostRatioStrategy 047 048/** 049 Maximum profit to cost ratio analyzer which uses Parhi's algorithm for 050 iteration bound. 051 <p> 052 For details about the algorithm, please refer to: 053 <p> 054 K. Ito and K. K. Parhi. Determining the minimum iteration period of an 055 algorithm. Journal of VLSI Signal Processing, 11(3):229-244, December 1995 056 <p> 057 @see ptolemy.graph.analysis.MaximumProfitToCostRatioAnalysis 058 @since Ptolemy II 4.0 059 @Pt.ProposedRating Red (shahrooz) 060 @Pt.AcceptedRating Red (ssb) 061 @author Shahrooz Shahparnia 062 @version $Id$ 063 */ 064public class ParhiMaximumProfitToCostRatioStrategy extends CachedStrategy 065 implements MaximumProfitToCostRatioAnalyzer { 066 /** Construct an instance of this class. 067 * 068 * @param graph The given graph. 069 * @param edgeProfits The profits associated with the edges of the graph. 070 * @param edgeCosts The costs associated with the edges of the graph. 071 */ 072 public ParhiMaximumProfitToCostRatioStrategy(Graph graph, 073 ToDoubleMapping edgeProfits, ToIntMapping edgeCosts) { 074 super(graph); 075 _edgeProfits = edgeProfits; 076 _edgeCosts = edgeCosts; 077 } 078 079 /////////////////////////////////////////////////////////////////// 080 //// public methods //// 081 082 /** Return the nodes on the cycle that corresponds to the maximum profit to 083 * cost ratio. 084 * 085 * @return The nodes on the cycle as an ordered list. 086 */ 087 @Override 088 public List cycle() { 089 _result(); 090 return _maximumProfitToCostRatioCycle; 091 } 092 093 /** Return the maximum profit to cost ratio of the given graph. 094 * 095 * @return Return the maximum profit to cost ratio of the given graph. 096 */ 097 @Override 098 public double maximumRatio() { 099 return ((Double) _result()).doubleValue(); 100 } 101 102 /** Return a description of the analyzer. 103 * 104 * @return Return a description of the analyzer.. 105 */ 106 @Override 107 public String toString() { 108 return "All pair shortest path analyzer" 109 + " based on Parhi's algorithm."; 110 } 111 112 /** Check for compatibility between the analysis and the given 113 * graph. A graph needs to be an instance of a DirectedGraph and cyclic 114 * in order to have a maximum profit to cost ratio. In addition the given 115 * object should be the same graph associated with this analyzer. 116 * 117 * @return True if the graph is a directed and cyclic graph. 118 */ 119 @Override 120 public boolean valid() { 121 boolean result = false; 122 123 if (graph() instanceof DirectedGraph) { 124 CycleExistenceAnalyzer analyzer = new FloydWarshallCycleExistenceStrategy( 125 graph()); 126 result = analyzer.hasCycle(); 127 } 128 129 return result; 130 } 131 132 /////////////////////////////////////////////////////////////////// 133 //// protected methods //// 134 // build a delay graph an use it as the application graph. 135 // what result() returns is the iteration bound, and what cycle 136 // returns is a cycle of delays. 137 // This cycle of delays is converted to a cycle in the original graph 138 // through the _maximumProfitToCostCycle method, which return that 139 // cycle. 140 141 /* Return the maximum profit to cost ratio of the given graph. 142 * 143 * @return Return the maximum profit to cost ratio of the given graph. 144 */ 145 @Override 146 protected Object _compute() { 147 _delayNodeList = new ArrayList(); 148 _maximumProfitToCostRatioCycle = new ArrayList(); 149 150 DirectedGraph originalGraph = (DirectedGraph) graph(); 151 152 // Build a new graph with the delays as nodes added to the previous 153 // graph. 154 DirectedGraph graphPlusDelaysAsNodes = (DirectedGraph) originalGraph 155 .cloneAs(new DirectedGraph()); 156 Object[] edges = graphPlusDelaysAsNodes.edges().toArray(); 157 HashMap edgeProfitsMap = new HashMap(); 158 159 for (int j = 0; j < edges.length; j++) { 160 Edge edge = (Edge) edges[j]; 161 Node source = edge.source(); 162 Node sink = edge.sink(); 163 164 //_edgeCostsMap.put(edge, _edgeCosts.toInt()); 165 // For all the edges that have at least one delay 166 if (_edgeCosts.toInt(edge) != 0) { 167 graphPlusDelaysAsNodes.removeEdge(edge); 168 169 int delays = _edgeCosts.toInt(edge); 170 171 for (int i = 0; i < delays; i++) { 172 Node addedNode = graphPlusDelaysAsNodes 173 .addNodeWeight("D" + j + i); 174 _delayNodeList.add(addedNode); 175 176 Edge addedEdge = graphPlusDelaysAsNodes.addEdge(source, 177 addedNode); 178 edgeProfitsMap.put(addedEdge, Double.valueOf(0.0)); 179 source = addedNode; 180 } 181 182 Edge lastAddedEdge = graphPlusDelaysAsNodes.addEdge(source, 183 sink); 184 edgeProfitsMap.put(lastAddedEdge, 185 Double.valueOf(_edgeProfits.toDouble(edge))); 186 } else { 187 edgeProfitsMap.put(edge, 188 Double.valueOf(_edgeProfits.toDouble(edge))); 189 } 190 } 191 192 HashMap D = new HashMap(_delayNodeList.size()); 193 edges = graphPlusDelaysAsNodes.edges().toArray(); 194 195 // compute the first order longest path matrix 196 HashMap predecessorMap = new HashMap(); 197 198 for (Iterator delayNodes = _delayNodeList.iterator(); delayNodes 199 .hasNext();) { 200 Node delayNode = (Node) delayNodes.next(); 201 DirectedGraph thisRoundGraph = (DirectedGraph) graphPlusDelaysAsNodes 202 .clone(); 203 HashMap delayGraphProfitMap = new HashMap(); 204 205 for (Object edge2 : edges) { 206 Edge edge = (Edge) edge2; 207 Node source = edge.source(); 208 Node sink = edge.sink(); 209 210 if (sink == delayNode) { 211 predecessorMap.put(delayNode, source); 212 } 213 214 if (_delayNodeList.contains(source) 215 || _delayNodeList.contains(sink)) { 216 if (source == delayNode) { 217 delayGraphProfitMap.put(edge, edgeProfitsMap.get(edge)); 218 } 219 220 if (sink == delayNode) { 221 thisRoundGraph.removeEdge(edge); 222 } 223 224 if (source != delayNode && sink != delayNode) { 225 if (_delayNodeList.contains(source)) { 226 thisRoundGraph.removeEdge(edge); 227 } else { 228 delayGraphProfitMap.put(edge, 229 edgeProfitsMap.get(edge)); 230 } 231 } 232 } else { 233 delayGraphProfitMap.put(edge, edgeProfitsMap.get(edge)); 234 } 235 } 236 237 SingleSourceLongestPathAnalysis longestPath = null; 238 longestPath = new SingleSourceLongestPathAnalysis(thisRoundGraph, 239 delayNode, new ToDoubleMapMapping(delayGraphProfitMap)); 240 D.put(delayNode, longestPath); 241 } 242 243 _makeFirstOrderLongestPathMatrix(D, graphPlusDelaysAsNodes, 244 predecessorMap); 245 246 // create the delay graph on which the maximum cycle mean is going to 247 // be executed. 248 DirectedGraph delayGraph = new DirectedGraph(); 249 HashMap delayGraphEdgeProfits = new HashMap(); 250 251 for (int i = 0; i < _delayNodeList.size(); i++) { 252 delayGraph.addNode((Node) _delayNodeList.get(i)); 253 } 254 255 for (int i = 0; i < _delayNodeList.size(); i++) { 256 for (int j = 0; j < _delayNodeList.size(); j++) { 257 Node source = (Node) _delayNodeList.get(i); 258 Node sink = (Node) _delayNodeList.get(j); 259 260 if (_firstOrderLongestPathMatrix[i][j] >= 0) { 261 if (!(source == sink 262 && _firstOrderLongestPathMatrix[i][j] == 0)) { 263 Edge addedEdge = delayGraph.addEdge(source, sink); 264 delayGraphEdgeProfits.put(addedEdge, Double 265 .valueOf(_firstOrderLongestPathMatrix[i][j])); 266 } 267 } 268 } 269 } 270 271 double result = _computeMCM(delayGraph, 272 new ToDoubleMapMapping(delayGraphEdgeProfits)); 273 274 // creating the cycle that leads to the result 275 //edges = graphPlusDelaysAsNodes.edges().toArray(); 276 277 Object[] delayNodes = _delayCycle.toArray(); 278 279 for (int i = 0; i < delayNodes.length; i++) { 280 Node delayNode = (Node) delayNodes[i]; 281 282 for (int j = 0; j < delayNodes.length; j++) { 283 if (i != j || delayNodes.length != 1) { 284 Node endDelayNode = (Node) delayNodes[j]; 285 List path = ((SingleSourceLongestPathAnalysis) D 286 .get(delayNode)).path(endDelayNode); 287 288 for (int k = 0; k < path.size(); k++) { 289 if (!_delayNodeList.contains(path.get(k))) { 290 _maximumProfitToCostRatioCycle.add(path.get(k)); 291 } 292 } 293 } else if (delayNodes.length == 1) { 294 Node predecessor = (Node) predecessorMap.get(delayNode); 295 296 if (!_delayNodeList.contains(predecessor)) { 297 List path = ((SingleSourceLongestPathAnalysis) D 298 .get(delayNode)).path(predecessor); 299 300 for (int k = 0; k < path.size(); k++) { 301 if (!_delayNodeList.contains(path.get(k))) { 302 _maximumProfitToCostRatioCycle.add(path.get(k)); 303 } 304 } 305 } 306 } 307 } 308 } 309 310 return Double.valueOf(result); 311 } 312 313 /////////////////////////////////////////////////////////////////// 314 //// private methods //// 315 316 /* To compute the maximum cycle mean of the delay graph. 317 * Derived class may override this method in case that they need to do 318 * further transformation on the delay graph or the edgeLength, such as 319 * making the edge costs negative in order to compute the minimum cycle 320 * mean. 321 */ 322 private double _computeMCM(DirectedGraph graph, 323 ToDoubleMapping edgeLength) { 324 CycleMeanAnalyzer cycleMean = new KarpCycleMeanStrategy(graph, 325 edgeLength); 326 double result = cycleMean.maximumCycleMean(); 327 _delayCycle = cycleMean.cycle(); 328 return result; 329 } 330 331 // computes the First Order Longest Path Matrix which is a matrix 332 // of longest distances from every node to every other node indexed 333 // by the node label. 334 private double[][] _makeFirstOrderLongestPathMatrix(HashMap D, 335 DirectedGraph graph, HashMap predecessorMap) { 336 _firstOrderLongestPathMatrix = new double[_delayNodeList 337 .size()][_delayNodeList.size()]; 338 339 for (int i = 0; i < _delayNodeList.size(); i++) { 340 for (int j = 0; j < _delayNodeList.size(); j++) { 341 Node column = (Node) _delayNodeList.get(i); 342 Node row = (Node) _delayNodeList.get(j); 343 double value = 0; 344 double[] distances = ((SingleSourceLongestPathAnalysis) D 345 .get(column)).distance(); 346 Node predecessor = (Node) predecessorMap.get(row); 347 348 if (i != j || _delayNodeList.contains(predecessor)) { 349 value = distances[graph.nodeLabel(row)]; 350 } else { 351 value = distances[graph.nodeLabel(predecessor)]; 352 } 353 354 _firstOrderLongestPathMatrix[i][j] = value; 355 } 356 } 357 358 return _firstOrderLongestPathMatrix; 359 } 360 361 /////////////////////////////////////////////////////////////////// 362 //// private variables //// 363 private double[][] _firstOrderLongestPathMatrix; 364 365 private List _delayCycle; 366 367 private ArrayList _delayNodeList; 368 369 private ArrayList _maximumProfitToCostRatioCycle; 370 371 private ToDoubleMapping _edgeProfits; 372 373 private ToIntMapping _edgeCosts; 374}