PageRenderTime 40ms CodeModel.GetById 9ms RepoModel.GetById 0ms app.codeStats 1ms

/java/src/com/mxgraph/analysis/mxGraphAnalysis.java

https://bitbucket.org/lgleim/mxgraph2
Java | 463 lines | 213 code | 54 blank | 196 comment | 50 complexity | 272a5f0f989a678255b154de336cf0ef MD5 | raw file
  1. /*
  2. * Copyright (c) 2001-2005, Gaudenz Alder
  3. *
  4. * All rights reserved.
  5. *
  6. * This file is licensed under the JGraph software license, a copy of which
  7. * will have been provided to you in the file LICENSE at the root of your
  8. * installation directory. If you are unable to locate this file please
  9. * contact JGraph sales for another copy.
  10. */
  11. package com.mxgraph.analysis;
  12. import java.util.ArrayList;
  13. import java.util.Arrays;
  14. import java.util.Collections;
  15. import java.util.Comparator;
  16. import java.util.Hashtable;
  17. import java.util.List;
  18. import com.mxgraph.view.mxCellState;
  19. import com.mxgraph.view.mxGraph;
  20. import com.mxgraph.view.mxGraphView;
  21. /**
  22. * A singleton class that provides algorithms for graphs. Assume these
  23. * variables for the following examples:<br>
  24. * <code>
  25. * mxICostFunction cf = mxDistanceCostFunction();
  26. * Object[] v = graph.getChildVertices(graph.getDefaultParent());
  27. * Object[] e = graph.getChildEdges(graph.getDefaultParent());
  28. * mxGraphAnalysis mga = mxGraphAnalysis.getInstance();
  29. * </code>
  30. *
  31. * <h3>Shortest Path (Dijkstra)</h3>
  32. *
  33. * For example, to find the shortest path between the first and the second
  34. * selected cell in a graph use the following code: <br>
  35. * <br>
  36. * <code>Object[] path = mga.getShortestPath(graph, from, to, cf, v.length, true);</code>
  37. *
  38. * <h3>Minimum Spanning Tree</h3>
  39. *
  40. * This algorithm finds the set of edges with the minimal length that connect
  41. * all vertices. This algorithm can be used as follows:
  42. * <h5>Prim</h5>
  43. * <code>mga.getMinimumSpanningTree(graph, v, cf, true))</code>
  44. * <h5>Kruskal</h5>
  45. * <code>mga.getMinimumSpanningTree(graph, v, e, cf))</code>
  46. *
  47. * <h3>Connection Components</h3>
  48. *
  49. * The union find may be used as follows to determine whether two cells are
  50. * connected: <code>boolean connected = uf.differ(vertex1, vertex2)</code>.
  51. *
  52. * @see mxICostFunction
  53. */
  54. public class mxGraphAnalysis
  55. {
  56. /**
  57. * Holds the shared instance of this class.
  58. */
  59. protected static mxGraphAnalysis instance = new mxGraphAnalysis();
  60. /**
  61. *
  62. */
  63. protected mxGraphAnalysis()
  64. {
  65. // empty
  66. }
  67. /**
  68. * @return Returns the sharedInstance.
  69. */
  70. public static mxGraphAnalysis getInstance()
  71. {
  72. return instance;
  73. }
  74. /**
  75. * Sets the shared instance of this class.
  76. *
  77. * @param instance The instance to set.
  78. */
  79. public static void setInstance(mxGraphAnalysis instance)
  80. {
  81. mxGraphAnalysis.instance = instance;
  82. }
  83. /**
  84. * Returns the shortest path between two cells or their descendants
  85. * represented as an array of edges in order of traversal. <br>
  86. * This implementation is based on the Dijkstra algorithm.
  87. *
  88. * @param graph The object that defines the graph structure
  89. * @param from The source cell.
  90. * @param to The target cell (aka sink).
  91. * @param cf The cost function that defines the edge length.
  92. * @param steps The maximum number of edges to traverse.
  93. * @param directed If edge directions should be taken into account.
  94. * @return Returns the shortest path as an alternating array of vertices
  95. * and edges, starting with <code>from</code> and ending with
  96. * <code>to</code>.
  97. *
  98. * @see #createPriorityQueue()
  99. */
  100. public Object[] getShortestPath(mxGraph graph, Object from, Object to,
  101. mxICostFunction cf, int steps, boolean directed)
  102. {
  103. // Sets up a pqueue and a hashtable to store the predecessor for each
  104. // cell in tha graph traversal. The pqueue is initialized
  105. // with the from element at prio 0.
  106. mxGraphView view = graph.getView();
  107. mxFibonacciHeap q = createPriorityQueue();
  108. Hashtable<Object, Object> pred = new Hashtable<Object, Object>();
  109. q.decreaseKey(q.getNode(from, true), 0); // Inserts automatically
  110. // The main loop of the dijkstra algorithm is based on the pqueue being
  111. // updated with the actual shortest distance to the source vertex.
  112. for (int j = 0; j < steps; j++)
  113. {
  114. mxFibonacciHeap.Node node = q.removeMin();
  115. double prio = node.getKey();
  116. Object obj = node.getUserObject();
  117. // Exits the loop if the target node or vertex has been reached
  118. if (obj == to)
  119. {
  120. break;
  121. }
  122. // Gets all outgoing edges of the closest cell to the source
  123. Object[] e = (directed) ? graph.getOutgoingEdges(obj) : graph
  124. .getConnections(obj);
  125. if (e != null)
  126. {
  127. for (int i = 0; i < e.length; i++)
  128. {
  129. Object[] opp = graph.getOpposites(new Object[] { e[i] },
  130. obj);
  131. if (opp != null && opp.length > 0)
  132. {
  133. Object neighbour = opp[0];
  134. // Updates the priority in the pqueue for the opposite node
  135. // to be the distance of this step plus the cost to
  136. // traverese the edge to the neighbour. Note that the
  137. // priority queue will make sure that in the next step the
  138. // node with the smallest prio will be traversed.
  139. if (neighbour != null && neighbour != obj
  140. && neighbour != from)
  141. {
  142. double newPrio = prio
  143. + ((cf != null) ? cf.getCost(view
  144. .getState(e[i])) : 1);
  145. node = q.getNode(neighbour, true);
  146. double oldPrio = node.getKey();
  147. if (newPrio < oldPrio)
  148. {
  149. pred.put(neighbour, e[i]);
  150. q.decreaseKey(node, newPrio);
  151. }
  152. }
  153. }
  154. }
  155. }
  156. if (q.isEmpty())
  157. {
  158. break;
  159. }
  160. }
  161. // Constructs a path array by walking backwards through the predessecor
  162. // map and filling up a list of edges, which is subsequently returned.
  163. ArrayList<Object> list = new ArrayList<Object>(2 * steps);
  164. Object obj = to;
  165. Object edge = pred.get(obj);
  166. if (edge != null)
  167. {
  168. list.add(obj);
  169. while (edge != null)
  170. {
  171. list.add(0, edge);
  172. mxCellState state = view.getState(edge);
  173. Object source = (state != null) ? state
  174. .getVisibleTerminal(true) : view.getVisibleTerminal(
  175. edge, true);
  176. boolean isSource = source == obj;
  177. obj = (state != null) ? state.getVisibleTerminal(!isSource)
  178. : view.getVisibleTerminal(edge, !isSource);
  179. list.add(0, obj);
  180. edge = pred.get(obj);
  181. }
  182. }
  183. return list.toArray();
  184. }
  185. /**
  186. * Returns the minimum spanning tree (MST) for the graph defined by G=(E,V).
  187. * The MST is defined as the set of all vertices with minimal lengths that
  188. * forms no cycles in G.<br>
  189. * This implementation is based on the algorihm by Prim-Jarnik. It uses
  190. * O(|E|+|V|log|V|) time when used with a Fibonacci heap and a graph whith a
  191. * double linked-list datastructure, as is the case with the default
  192. * implementation.
  193. *
  194. * @param graph
  195. * the object that describes the graph
  196. * @param v
  197. * the vertices of the graph
  198. * @param cf
  199. * the cost function that defines the edge length
  200. *
  201. * @return Returns the MST as an array of edges
  202. *
  203. * @see #createPriorityQueue()
  204. */
  205. public Object[] getMinimumSpanningTree(mxGraph graph, Object[] v,
  206. mxICostFunction cf, boolean directed)
  207. {
  208. ArrayList<Object> mst = new ArrayList<Object>(v.length);
  209. // Sets up a pqueue and a hashtable to store the predecessor for each
  210. // cell in tha graph traversal. The pqueue is initialized
  211. // with the from element at prio 0.
  212. mxFibonacciHeap q = createPriorityQueue();
  213. Hashtable<Object, Object> pred = new Hashtable<Object, Object>();
  214. Object u = v[0];
  215. q.decreaseKey(q.getNode(u, true), 0);
  216. for (int i = 1; i < v.length; i++)
  217. {
  218. q.getNode(v[i], true);
  219. }
  220. // The main loop of the dijkstra algorithm is based on the pqueue being
  221. // updated with the actual shortest distance to the source vertex.
  222. while (!q.isEmpty())
  223. {
  224. mxFibonacciHeap.Node node = q.removeMin();
  225. u = node.getUserObject();
  226. Object edge = pred.get(u);
  227. if (edge != null)
  228. {
  229. mst.add(edge);
  230. }
  231. // Gets all outgoing edges of the closest cell to the source
  232. Object[] e = (directed) ? graph.getOutgoingEdges(u) : graph
  233. .getConnections(u);
  234. Object[] opp = graph.getOpposites(e, u);
  235. if (e != null)
  236. {
  237. for (int i = 0; i < e.length; i++)
  238. {
  239. Object neighbour = opp[i];
  240. // Updates the priority in the pqueue for the opposite node
  241. // to be the distance of this step plus the cost to
  242. // traverese the edge to the neighbour. Note that the
  243. // priority queue will make sure that in the next step the
  244. // node with the smallest prio will be traversed.
  245. if (neighbour != null && neighbour != u)
  246. {
  247. node = q.getNode(neighbour, false);
  248. if (node != null)
  249. {
  250. double newPrio = cf.getCost(graph.getView()
  251. .getState(e[i]));
  252. double oldPrio = node.getKey();
  253. if (newPrio < oldPrio)
  254. {
  255. pred.put(neighbour, e[i]);
  256. q.decreaseKey(node, newPrio);
  257. }
  258. }
  259. }
  260. }
  261. }
  262. }
  263. return mst.toArray();
  264. }
  265. /**
  266. * Returns the minimum spanning tree (MST) for the graph defined by G=(E,V).
  267. * The MST is defined as the set of all vertices with minimal lenths that
  268. * forms no cycles in G.<br>
  269. * This implementation is based on the algorihm by Kruskal. It uses
  270. * O(|E|log|E|)=O(|E|log|V|) time for sorting the edges, O(|V|) create sets,
  271. * O(|E|) find and O(|V|) union calls on the union find structure, thus
  272. * yielding no more than O(|E|log|V|) steps. For a faster implementatin
  273. *
  274. * @see #getMinimumSpanningTree(mxGraph, Object[], mxICostFunction,
  275. * boolean)
  276. *
  277. * @param graph The object that contains the graph.
  278. * @param v The vertices of the graph.
  279. * @param e The edges of the graph.
  280. * @param cf The cost function that defines the edge length.
  281. *
  282. * @return Returns the MST as an array of edges.
  283. *
  284. * @see #createUnionFind(Object[])
  285. */
  286. public Object[] getMinimumSpanningTree(mxGraph graph, Object[] v,
  287. Object[] e, mxICostFunction cf)
  288. {
  289. // Sorts all edges according to their lengths, then creates a union
  290. // find structure for all vertices. Then walks through all edges by
  291. // increasing length and tries adding to the MST. Only edges are added
  292. // that do not form cycles in the graph, that is, where the source
  293. // and target are in different sets in the union find structure.
  294. // Whenever an edge is added to the MST, the two different sets are
  295. // unified.
  296. mxGraphView view = graph.getView();
  297. mxUnionFind uf = createUnionFind(v);
  298. ArrayList<Object> result = new ArrayList<Object>(e.length);
  299. mxCellState[] edgeStates = sort(view.getCellStates(e), cf);
  300. for (int i = 0; i < edgeStates.length; i++)
  301. {
  302. Object source = edgeStates[i].getVisibleTerminal(true);
  303. Object target = edgeStates[i].getVisibleTerminal(false);
  304. mxUnionFind.Node setA = uf.find(uf.getNode(source));
  305. mxUnionFind.Node setB = uf.find(uf.getNode(target));
  306. if (setA == null || setB == null || setA != setB)
  307. {
  308. uf.union(setA, setB);
  309. result.add(edgeStates[i].getCell());
  310. }
  311. }
  312. return result.toArray();
  313. }
  314. /**
  315. * Returns a union find structure representing the connection components of
  316. * G=(E,V).
  317. *
  318. * @param graph The object that contains the graph.
  319. * @param v The vertices of the graph.
  320. * @param e The edges of the graph.
  321. * @return Returns the connection components in G=(E,V)
  322. *
  323. * @see #createUnionFind(Object[])
  324. */
  325. public mxUnionFind getConnectionComponents(mxGraph graph, Object[] v,
  326. Object[] e)
  327. {
  328. mxGraphView view = graph.getView();
  329. mxUnionFind uf = createUnionFind(v);
  330. for (int i = 0; i < e.length; i++)
  331. {
  332. mxCellState state = view.getState(e[i]);
  333. Object source = (state != null) ? state.getVisibleTerminal(true)
  334. : view.getVisibleTerminal(e[i], true);
  335. Object target = (state != null) ? state.getVisibleTerminal(false)
  336. : view.getVisibleTerminal(e[i], false);
  337. uf.union(uf.find(uf.getNode(source)), uf.find(uf.getNode(target)));
  338. }
  339. return uf;
  340. }
  341. /**
  342. * Returns a sorted set for <code>cells</code> with respect to
  343. * <code>cf</code>.
  344. *
  345. * @param states
  346. * the cell states to sort
  347. * @param cf
  348. * the cost function that defines the order
  349. *
  350. * @return Returns an ordered set of <code>cells</code> wrt.
  351. * <code>cf</code>
  352. */
  353. public mxCellState[] sort(mxCellState[] states, final mxICostFunction cf)
  354. {
  355. List<mxCellState> result = Arrays.asList(states);
  356. Collections.sort(result, new Comparator<mxCellState>()
  357. {
  358. /**
  359. *
  360. */
  361. public int compare(mxCellState o1, mxCellState o2)
  362. {
  363. Double d1 = new Double(cf.getCost(o1));
  364. Double d2 = new Double(cf.getCost(o2));
  365. return d1.compareTo(d2);
  366. }
  367. });
  368. return (mxCellState[]) result.toArray();
  369. }
  370. /**
  371. * Returns the sum of all cost for <code>cells</code> with respect to
  372. * <code>cf</code>.
  373. *
  374. * @param states
  375. * the cell states to use for the sum
  376. * @param cf
  377. * the cost function that defines the costs
  378. *
  379. * @return Returns the sum of all cell cost
  380. */
  381. public double sum(mxCellState[] states, mxICostFunction cf)
  382. {
  383. double sum = 0;
  384. for (int i = 0; i < states.length; i++)
  385. {
  386. sum += cf.getCost(states[i]);
  387. }
  388. return sum;
  389. }
  390. /**
  391. * Hook for subclassers to provide a custom union find structure.
  392. *
  393. * @param v
  394. * the array of all elements
  395. *
  396. * @return Returns a union find structure for <code>v</code>
  397. */
  398. protected mxUnionFind createUnionFind(Object[] v)
  399. {
  400. return new mxUnionFind(v);
  401. }
  402. /**
  403. * Hook for subclassers to provide a custom fibonacci heap.
  404. */
  405. protected mxFibonacciHeap createPriorityQueue()
  406. {
  407. return new mxFibonacciHeap();
  408. }
  409. }