1
2
3
4
5 package edu.uci.ics.jung.algorithms.shortestpath;
6
7 import java.util.HashMap;
8 import java.util.HashSet;
9 import java.util.Iterator;
10 import java.util.List;
11 import java.util.ListIterator;
12 import java.util.Map;
13 import java.util.Set;
14
15 import junit.framework.TestCase;
16
17 import com.google.common.base.Function;
18 import com.google.common.base.Functions;
19 import com.google.common.base.Supplier;
20 import com.google.common.collect.BiMap;
21
22 import edu.uci.ics.jung.algorithms.util.Indexer;
23 import edu.uci.ics.jung.graph.DirectedGraph;
24 import edu.uci.ics.jung.graph.DirectedSparseMultigraph;
25 import edu.uci.ics.jung.graph.Graph;
26 import edu.uci.ics.jung.graph.UndirectedGraph;
27 import edu.uci.ics.jung.graph.UndirectedSparseMultigraph;
28
29
30
31
32
33 public class TestShortestPath extends TestCase
34 {
35 private DirectedGraph<String,Integer> dg;
36 private UndirectedGraph<String,Integer> ug;
37
38
39 private static int[][] edges =
40 {{1,2,2}, {1,4,1},
41 {2,4,3}, {2,5,10},
42 {3,1,4}, {3,6,5},
43 {4,3,2}, {4,5,2}, {4,6,8}, {4,7,4},
44 {5,7,6},
45 {7,6,1},
46 {8,9,4},
47 {9,10,1},
48 {10,8,2}};
49
50 private static Integer[][] ug_incomingEdges =
51 {
52 {null, new Integer(0), new Integer(6), new Integer(1), new Integer(7), new Integer(11), new Integer(9), null, null, null},
53 {new Integer(0), null, new Integer(6), new Integer(2), new Integer(7), new Integer(11), new Integer(9), null, null, null},
54 {new Integer(1), new Integer(2), null, new Integer(6), new Integer(7), new Integer(5), new Integer(9), null, null, null},
55 {new Integer(1), new Integer(2), new Integer(6), null, new Integer(7), new Integer(11), new Integer(9), null, null, null},
56 {new Integer(1), new Integer(2), new Integer(6), new Integer(7), null, new Integer(11), new Integer(10), null, null, null},
57 {new Integer(1), new Integer(2), new Integer(5), new Integer(9), new Integer(10), null, new Integer(11), null, null, null},
58 {new Integer(1), new Integer(2), new Integer(5), new Integer(9), new Integer(10), new Integer(11), null, null, null, null},
59 {null, null, null, null, null, null, null, null, new Integer(13), new Integer(14)},
60 {null, null, null, null, null, null, null, new Integer(14), null, new Integer(13)},
61 {null, null, null, null, null, null, null, new Integer(14), new Integer(13), null},
62 };
63
64 private static Integer[][] dg_incomingEdges =
65 {
66 {null, new Integer(0), new Integer(6), new Integer(1), new Integer(7), new Integer(11), new Integer(9), null, null, null},
67 {new Integer(4), null, new Integer(6), new Integer(2), new Integer(7), new Integer(11), new Integer(9), null, null, null},
68 {new Integer(4), new Integer(0), null, new Integer(1), new Integer(7), new Integer(5), new Integer(9), null, null, null},
69 {new Integer(4), new Integer(0), new Integer(6), null, new Integer(7), new Integer(11), new Integer(9), null, null, null},
70 {null, null, null, null, null, new Integer(11), new Integer(10), null, null, null},
71 {null, null, null, null, null, null, null, null, null, null},
72 {null, null, null, null, null, new Integer(11), null, null, null, null},
73 {null, null, null, null, null, null, null, null, new Integer(12), new Integer(13)},
74 {null, null, null, null, null, null, null, new Integer(14), null, new Integer(13)},
75 {null, null, null, null, null, null, null, new Integer(14), new Integer(12), null}
76 };
77
78 private static double[][] dg_distances =
79 {
80 {0, 2, 3, 1, 3, 6, 5, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY},
81 {9, 0, 5, 3, 5, 8, 7, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY},
82 {4, 6, 0, 5, 7, 5, 9, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY},
83 {6, 8, 2, 0, 2, 5, 4, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY},
84 {Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, 0, 7, 6, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY},
85 {Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, 0, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY},
86 {Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, 1, 0, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY},
87 {Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, 0, 4, 5},
88 {Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, 3, 0, 1},
89 {Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, 2, 6, 0}
90 };
91
92 private static double[][] ug_distances =
93 {
94 {0, 2, 3, 1, 3, 6, 5, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY},
95 {2, 0, 5, 3, 5, 8, 7, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY},
96 {3, 5, 0, 2, 4, 5, 6, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY},
97 {1, 3, 2, 0, 2, 5, 4, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY},
98 {3, 5, 4, 2, 0, 7, 6, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY},
99 {6, 8, 5, 5, 7, 0, 1, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY},
100 {5, 7, 6, 4, 6, 1, 0, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY},
101 {Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, 0, 3, 2},
102 {Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, 3, 0, 1},
103 {Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, 2, 1, 0}
104 };
105
106
107 private static Integer[][] shortestPaths1 =
108 {
109 null,
110 {new Integer(0)},
111 {new Integer(1), new Integer(6)},
112 {new Integer(1)},
113 {new Integer(1), new Integer(7)},
114 {new Integer(1), new Integer(9), new Integer(11)},
115 {new Integer(1), new Integer(9)},
116 null,
117 null,
118 null
119 };
120
121 private Map<Graph<String,Integer>,Integer[]> edgeArrays;
122
123 private Map<Integer,Number> edgeWeights;
124
125 private Function<Integer,Number> nev;
126
127 private Supplier<String> vertexFactoryDG =
128 new Supplier<String>() {
129 int count = 0;
130 public String get() {
131 return "V"+count++;
132 }};
133 private Supplier<String> vertexFactoryUG =
134 new Supplier<String>() {
135 int count = 0;
136 public String get() {
137 return "U"+count++;
138 }};
139
140 BiMap<String,Integer> did;
141 BiMap<String,Integer> uid;
142
143 @Override
144 protected void setUp() {
145 edgeWeights = new HashMap<Integer,Number>();
146 nev = Functions.<Integer,Number>forMap(edgeWeights);
147 dg = new DirectedSparseMultigraph<String,Integer>();
148 for(int i=0; i<dg_distances.length; i++) {
149 dg.addVertex(vertexFactoryDG.get());
150 }
151 did = Indexer.<String>create(dg.getVertices(), 1);
152 Integer[] dg_array = new Integer[edges.length];
153 addEdges(dg, did, dg_array);
154
155 ug = new UndirectedSparseMultigraph<String,Integer>();
156 for(int i=0; i<ug_distances.length; i++) {
157 ug.addVertex(vertexFactoryUG.get());
158 }
159 uid = Indexer.<String>create(ug.getVertices(),1);
160
161
162 Integer[] ug_array = new Integer[edges.length];
163 addEdges(ug, uid, ug_array);
164
165 edgeArrays = new HashMap<Graph<String,Integer>,Integer[]>();
166 edgeArrays.put(dg, dg_array);
167 edgeArrays.put(ug, ug_array);
168 }
169
170 @Override
171 protected void tearDown() throws Exception {
172 }
173
174 public void exceptionTest(Graph<String,Integer> g, BiMap<String,Integer> indexer, int index)
175 {
176 DijkstraShortestPath<String,Integer> dsp =
177 new DijkstraShortestPath<String,Integer>(g, nev);
178
179 String start = indexer.inverse().get(index);
180 Integer e = null;
181
182 String v = "NOT IN GRAPH";
183
184 try
185 {
186 dsp.getDistance(start, v);
187 fail("getDistance(): illegal destination vertex");
188 }
189 catch (IllegalArgumentException iae) {}
190 try
191 {
192 dsp.getDistance(v, start);
193 fail("getDistance(): illegal source vertex");
194 }
195 catch (IllegalArgumentException iae) {}
196 try
197 {
198 dsp.getDistanceMap(v, 1);
199 fail("getDistanceMap(): illegal source vertex");
200 }
201 catch (IllegalArgumentException iae) {}
202 try
203 {
204 dsp.getDistanceMap(start, 0);
205 fail("getDistanceMap(): too few vertices requested");
206 }
207 catch (IllegalArgumentException iae) {}
208 try
209 {
210 dsp.getDistanceMap(start, g.getVertexCount()+1);
211 fail("getDistanceMap(): too many vertices requested");
212 }
213 catch (IllegalArgumentException iae) {}
214
215 try
216 {
217 dsp.getIncomingEdge(start, v);
218 fail("getIncomingEdge(): illegal destination vertex");
219 }
220 catch (IllegalArgumentException iae) {}
221 try
222 {
223 dsp.getIncomingEdge(v, start);
224 fail("getIncomingEdge(): illegal source vertex");
225 }
226 catch (IllegalArgumentException iae) {}
227 try
228 {
229 dsp.getIncomingEdgeMap(v, 1);
230 fail("getIncomingEdgeMap(): illegal source vertex");
231 }
232 catch (IllegalArgumentException iae) {}
233 try
234 {
235 dsp.getIncomingEdgeMap(start, 0);
236 fail("getIncomingEdgeMap(): too few vertices requested");
237 }
238 catch (IllegalArgumentException iae) {}
239 try
240 {
241 dsp.getDistanceMap(start, g.getVertexCount()+1);
242 fail("getIncomingEdgeMap(): too many vertices requested");
243 }
244 catch (IllegalArgumentException iae) {}
245
246 try
247 {
248
249 String v1 = indexer.inverse().get(1);
250 String v2 = indexer.inverse().get(7);
251 e = g.getEdgeCount()+1;
252 g.addEdge(e, v1, v2);
253 edgeWeights.put(e, -2);
254
255 dsp.reset();
256 dsp.getDistanceMap(start);
257
258
259
260
261
262
263
264
265
266
267
268
269 fail("DijkstraShortestPath should not accept negative edge weights");
270 }
271 catch (IllegalArgumentException iae)
272 {
273 g.removeEdge(e);
274 }
275 }
276
277 public void testDijkstra()
278 {
279 setUp();
280 exceptionTest(dg, did, 1);
281
282 setUp();
283 exceptionTest(ug, uid, 1);
284
285 setUp();
286 getPathTest(dg, did, 1);
287
288 setUp();
289 getPathTest(ug, uid, 1);
290
291 for (int i = 1; i <= dg_distances.length; i++)
292 {
293 setUp();
294 weightedTest(dg, did, i, true);
295
296 setUp();
297 weightedTest(dg, did, i, false);
298 }
299
300 for (int i = 1; i <= ug_distances.length; i++)
301 {
302 setUp();
303 weightedTest(ug, uid, i, true);
304
305 setUp();
306 weightedTest(ug, uid, i, false);
307 }
308
309 }
310
311 private void getPathTest(Graph<String,Integer> g, BiMap<String,Integer> indexer, int index)
312 {
313 DijkstraShortestPath<String,Integer> dsp =
314 new DijkstraShortestPath<String,Integer>(g, nev);
315
316 String start = indexer.inverse().get(index);
317 Integer[] edge_array = edgeArrays.get(g);
318 Integer[] incomingEdges1 = null;
319 if (g instanceof DirectedGraph)
320 incomingEdges1 = dg_incomingEdges[index-1];
321 if (g instanceof UndirectedGraph)
322 incomingEdges1 = ug_incomingEdges[index-1];
323 assertEquals(incomingEdges1.length, g.getVertexCount());
324
325
326 dsp.reset();
327 for (int i = 1; i <= incomingEdges1.length; i++)
328 {
329 List<Integer> shortestPath = dsp.getPath(start, indexer.inverse().get(i));
330 Integer[] indices = shortestPaths1[i-1];
331 for (ListIterator<Integer> iter = shortestPath.listIterator(); iter.hasNext(); )
332 {
333 int j = iter.nextIndex();
334 Integer e = iter.next();
335 if (e != null)
336 assertEquals(edge_array[indices[j].intValue()], e);
337 else
338 assertNull(indices[j]);
339 }
340 }
341 }
342
343 private void weightedTest(Graph<String,Integer> g, BiMap<String,Integer> indexer, int index, boolean cached) {
344
345 String start = indexer.inverse().get(index);
346 double[] distances1 = null;
347 Integer[] incomingEdges1 = null;
348 if (g instanceof DirectedGraph)
349 {
350 distances1 = dg_distances[index-1];
351 incomingEdges1 = dg_incomingEdges[index-1];
352 }
353 if (g instanceof UndirectedGraph)
354 {
355 distances1 = ug_distances[index-1];
356 incomingEdges1 = ug_incomingEdges[index-1];
357 }
358 assertEquals(distances1.length, g.getVertexCount());
359 assertEquals(incomingEdges1.length, g.getVertexCount());
360 DijkstraShortestPath<String,Integer> dsp =
361 new DijkstraShortestPath<String,Integer>(g, nev, cached);
362 Integer[] edge_array = edgeArrays.get(g);
363
364
365 for (int i = 1; i <= distances1.length; i++) {
366 String v = indexer.inverse().get(i);
367 Number n = dsp.getDistance(start, v);
368 double d = distances1[i-1];
369 double dist;
370 if (n == null)
371 dist = Double.POSITIVE_INFINITY;
372 else
373 dist = n.doubleValue();
374
375 assertEquals(d, dist, .001);
376 }
377
378
379 dsp.reset();
380 for (int i = 1; i <= incomingEdges1.length; i++)
381 {
382 String v = indexer.inverse().get(i);
383 Integer e = dsp.getIncomingEdge(start, v);
384 if (e != null)
385 assertEquals(edge_array[incomingEdges1[i-1].intValue()], e);
386 else
387 assertNull(incomingEdges1[i-1]);
388 }
389
390
391 dsp.reset();
392 Map<String,Number> distances = dsp.getDistanceMap(start);
393 assertTrue(distances.size() <= g.getVertexCount());
394 double d_prev = 0;
395 Set<String> reachable = new HashSet<String>();
396 for (Iterator<String> d_iter = distances.keySet().iterator(); d_iter.hasNext(); )
397 {
398 String cur = d_iter.next();
399 double d_cur = ((Double)distances.get(cur)).doubleValue();
400 assertTrue(d_cur >= d_prev);
401
402 d_prev = d_cur;
403 int i = indexer.get(cur);
404 assertEquals(distances1[i-1], d_cur, .001);
405 reachable.add(cur);
406 }
407
408 for (Iterator<String> v_iter = g.getVertices().iterator(); v_iter.hasNext(); )
409 {
410 String v = v_iter.next();
411 assertEquals(reachable.contains(v), distances.keySet().contains(v));
412 }
413
414
415 dsp.reset();
416 Map<String,Integer> incomingEdgeMap = dsp.getIncomingEdgeMap(start);
417 assertTrue(incomingEdgeMap.size() <= g.getVertexCount());
418 for (Iterator<String> e_iter = incomingEdgeMap.keySet().iterator(); e_iter.hasNext(); )
419 {
420 String v = e_iter.next();
421 Integer e = incomingEdgeMap.get(v);
422 int i = indexer.get(v);
423
424
425
426
427
428
429
430
431
432 if (e != null)
433 assertEquals(edge_array[incomingEdges1[i-1].intValue()], e);
434 else
435 assertNull(incomingEdges1[i-1]);
436 }
437
438
439 dsp.reset();
440 for (int i = 1; i <= distances1.length; i++)
441 {
442 distances = dsp.getDistanceMap(start, i);
443 assertTrue(distances.size() <= i);
444 d_prev = 0;
445
446 reachable.clear();
447 for (Iterator<String> d_iter = distances.keySet().iterator(); d_iter.hasNext(); )
448 {
449 String cur = d_iter.next();
450 double d_cur = ((Double)distances.get(cur)).doubleValue();
451 assertTrue(d_cur >= d_prev);
452
453 d_prev = d_cur;
454 int j = indexer.get(cur);
455
456 assertEquals(distances1[j-1], d_cur, .001);
457 reachable.add(cur);
458 }
459 for (Iterator<String> v_iter = g.getVertices().iterator(); v_iter.hasNext(); )
460 {
461 String v = v_iter.next();
462 assertEquals(reachable.contains(v), distances.keySet().contains(v));
463 }
464 }
465
466
467 dsp.reset();
468 for (int i = 1; i <= incomingEdges1.length; i++)
469 {
470 incomingEdgeMap = dsp.getIncomingEdgeMap(start, i);
471 assertTrue(incomingEdgeMap.size() <= i);
472 for (Iterator<String> e_iter = incomingEdgeMap.keySet().iterator(); e_iter.hasNext(); )
473 {
474 String v = e_iter.next();
475 Integer e = incomingEdgeMap.get(v);
476 int j = indexer.get(v);
477 if (e != null)
478 assertEquals(edge_array[incomingEdges1[j-1].intValue()], e);
479 else
480 assertNull(incomingEdges1[j-1]);
481 }
482 }
483 }
484
485 public void addEdges(Graph<String,Integer> g, BiMap<String,Integer> indexer, Integer[] edge_array)
486 {
487
488
489 for (int i = 0; i < edges.length; i++)
490 {
491 int[] edge = edges[i];
492 Integer e = i;
493 g.addEdge(i, indexer.inverse().get(edge[0]), indexer.inverse().get(edge[1]));
494 edge_array[i] = e;
495 if (edge.length > 2) {
496 edgeWeights.put(e, edge[2]);
497
498 }
499 }
500 }
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528 }