tom

Added bellman-ford implementation.

1 +package org.onlab.graph;
2 +
3 +/**
4 + * Bellman-Ford graph search algorithm for locating shortest-paths in
5 + * directed graphs that may contain negative cycles.
6 + */
7 +public class BellmanFordGraphSearch<V extends Vertex, E extends Edge<V>>
8 + extends AbstractGraphPathSearch<V, E> {
9 +
10 + @Override
11 + public Result<V, E> search(Graph<V, E> graph, V src, V dst,
12 + EdgeWeight<V, E> weight) {
13 + checkArguments(graph, src, dst);
14 +
15 + // Prepare the graph search result.
16 + DefaultResult result = new DefaultResult(src, dst);
17 +
18 + // The source vertex has cost 0, of course.
19 + result.updateVertex(src, null, 0.0, true);
20 +
21 + int max = graph.getVertexes().size() - 1;
22 + for (int i = 0; i < max; i++) {
23 + // Relax, if possible, all egress edges of the current vertex.
24 + for (E edge : graph.getEdges()) {
25 + if (result.hasCost(edge.src())) {
26 + result.relaxEdge(edge, result.cost(edge.src()), weight);
27 + }
28 + }
29 + }
30 +
31 + // Remove any vertexes reached by traversing edges with negative weights.
32 + for (E edge : graph.getEdges()) {
33 + if (result.hasCost(edge.src())) {
34 + if (result.relaxEdge(edge, result.cost(edge.src()), weight)) {
35 + result.removeVertex(edge.dst());
36 + }
37 + }
38 + }
39 +
40 + // Finally, but the paths on the search result and return.
41 + result.buildPaths();
42 + return result;
43 + }
44 +
45 +}
...@@ -10,7 +10,8 @@ public class BreadthFirstSearch<V extends Vertex, E extends Edge<V>> ...@@ -10,7 +10,8 @@ public class BreadthFirstSearch<V extends Vertex, E extends Edge<V>>
10 extends AbstractGraphPathSearch<V, E> { 10 extends AbstractGraphPathSearch<V, E> {
11 11
12 @Override 12 @Override
13 - public Result<V, E> search(Graph<V, E> graph, V src, V dst, EdgeWeight<V, E> ew) { 13 + public Result<V, E> search(Graph<V, E> graph, V src, V dst,
14 + EdgeWeight<V, E> weight) {
14 checkArguments(graph, src, dst); 15 checkArguments(graph, src, dst);
15 16
16 // Prepare the graph result. 17 // Prepare the graph result.
...@@ -18,7 +19,7 @@ public class BreadthFirstSearch<V extends Vertex, E extends Edge<V>> ...@@ -18,7 +19,7 @@ public class BreadthFirstSearch<V extends Vertex, E extends Edge<V>>
18 19
19 // Setup the starting frontier with the source as the sole vertex. 20 // Setup the starting frontier with the source as the sole vertex.
20 Set<V> frontier = new HashSet<>(); 21 Set<V> frontier = new HashSet<>();
21 - result.costs.put(src, 0.0); 22 + result.updateVertex(src, null, 0.0, true);
22 frontier.add(src); 23 frontier.add(src);
23 24
24 boolean reachedEnd = false; 25 boolean reachedEnd = false;
...@@ -35,9 +36,8 @@ public class BreadthFirstSearch<V extends Vertex, E extends Edge<V>> ...@@ -35,9 +36,8 @@ public class BreadthFirstSearch<V extends Vertex, E extends Edge<V>>
35 V nextVertex = edge.dst(); 36 V nextVertex = edge.dst();
36 if (!result.hasCost(nextVertex)) { 37 if (!result.hasCost(nextVertex)) {
37 // If this vertex has not been visited yet, update it. 38 // If this vertex has not been visited yet, update it.
38 - result.updateVertex(nextVertex, edge, 39 + double newCost = cost + (weight == null ? 1.0 : weight.weight(edge));
39 - cost + (ew == null ? 1.0 : ew.weight(edge)), 40 + result.updateVertex(nextVertex, edge, newCost, true);
40 - true);
41 // If we have reached our intended destination, bail. 41 // If we have reached our intended destination, bail.
42 if (nextVertex.equals(dst)) { 42 if (nextVertex.equals(dst)) {
43 reachedEnd = true; 43 reachedEnd = true;
......
...@@ -12,8 +12,9 @@ public class DijkstraGraphSearch<V extends Vertex, E extends Edge<V>> ...@@ -12,8 +12,9 @@ public class DijkstraGraphSearch<V extends Vertex, E extends Edge<V>>
12 extends AbstractGraphPathSearch<V, E> { 12 extends AbstractGraphPathSearch<V, E> {
13 13
14 @Override 14 @Override
15 - public Result<V, E> search(Graph<V, E> g, V src, V dst, EdgeWeight<V, E> ew) { 15 + public Result<V, E> search(Graph<V, E> graph, V src, V dst,
16 - checkArguments(g, src, dst); 16 + EdgeWeight<V, E> weight) {
17 + checkArguments(graph, src, dst);
17 18
18 // Use the default result to remember cumulative costs and parent 19 // Use the default result to remember cumulative costs and parent
19 // edges to each each respective vertex. 20 // edges to each each respective vertex.
...@@ -25,7 +26,7 @@ public class DijkstraGraphSearch<V extends Vertex, E extends Edge<V>> ...@@ -25,7 +26,7 @@ public class DijkstraGraphSearch<V extends Vertex, E extends Edge<V>>
25 // Use the min priority queue to progressively find each nearest 26 // Use the min priority queue to progressively find each nearest
26 // vertex until we reach the desired destination, if one was given, 27 // vertex until we reach the desired destination, if one was given,
27 // or until we reach all possible destinations. 28 // or until we reach all possible destinations.
28 - Heap<V> minQueue = createMinQueue(g.getVertexes(), 29 + Heap<V> minQueue = createMinQueue(graph.getVertexes(),
29 new PathCostComparator(result)); 30 new PathCostComparator(result));
30 while (!minQueue.isEmpty()) { 31 while (!minQueue.isEmpty()) {
31 // Get the nearest vertex 32 // Get the nearest vertex
...@@ -38,8 +39,8 @@ public class DijkstraGraphSearch<V extends Vertex, E extends Edge<V>> ...@@ -38,8 +39,8 @@ public class DijkstraGraphSearch<V extends Vertex, E extends Edge<V>>
38 double cost = result.cost(nearest); 39 double cost = result.cost(nearest);
39 if (cost < Double.MAX_VALUE) { 40 if (cost < Double.MAX_VALUE) {
40 // If the vertex is reachable, relax all its egress edges. 41 // If the vertex is reachable, relax all its egress edges.
41 - for (E e : g.getEdgesFrom(nearest)) { 42 + for (E e : graph.getEdgesFrom(nearest)) {
42 - result.relaxEdge(e, cost, ew); 43 + result.relaxEdge(e, cost, weight);
43 } 44 }
44 } 45 }
45 46
......
1 +package org.onlab.graph;
2 +
3 +import org.junit.Test;
4 +
5 +import java.util.HashSet;
6 +import java.util.Set;
7 +
8 +import static org.junit.Assert.assertEquals;
9 +
10 +/**
11 + * Test of the Bellman-Ford algorithm.
12 + */
13 +public class BellmanFordGraphSearchTest extends BreadthFirstSearchTest {
14 +
15 + @Override
16 + protected AbstractGraphPathSearch<TestVertex, TestEdge> graphSearch() {
17 + return new BellmanFordGraphSearch<>();
18 + }
19 +
20 + @Test
21 + @Override
22 + public void defaultGraphTest() {
23 + executeDefaultTest(7, 5, 5.0);
24 + }
25 +
26 + @Test
27 + public void defaultHopCountWeight() {
28 + weight = null;
29 + executeDefaultTest(10, 3, 3.0);
30 + }
31 +
32 + @Test
33 + public void searchGraphWithNegativeCycles() {
34 + Set<TestVertex> vertexes = new HashSet<>(vertices());
35 + vertexes.add(Z);
36 +
37 + Set<TestEdge> edges = new HashSet<>(edges());
38 + edges.add(new TestEdge(G, Z, 1.0));
39 + edges.add(new TestEdge(Z, G, -2.0));
40 +
41 + g = new AdjacencyListsGraph<>(vertexes, edges);
42 +
43 + GraphPathSearch<TestVertex, TestEdge> search = graphSearch();
44 + Set<Path<TestVertex, TestEdge>> paths = search.search(g, A, H, weight).paths();
45 + assertEquals("incorrect paths count", 1, paths.size());
46 +
47 + Path p = paths.iterator().next();
48 + assertEquals("incorrect src", A, p.src());
49 + assertEquals("incorrect dst", H, p.dst());
50 + assertEquals("incorrect path length", 5, p.edges().size());
51 + assertEquals("incorrect path cost", 5.0, p.cost(), 0.1);
52 +
53 + paths = search.search(g, A, G, weight).paths();
54 + assertEquals("incorrect paths count", 0, paths.size());
55 +
56 + paths = search.search(g, A, null, weight).paths();
57 + printPaths(paths);
58 + assertEquals("incorrect paths count", 6, paths.size());
59 + }
60 +
61 +}
...@@ -17,6 +17,7 @@ public class GraphTest { ...@@ -17,6 +17,7 @@ public class GraphTest {
17 static final TestVertex F = new TestVertex("F"); 17 static final TestVertex F = new TestVertex("F");
18 static final TestVertex G = new TestVertex("G"); 18 static final TestVertex G = new TestVertex("G");
19 static final TestVertex H = new TestVertex("H"); 19 static final TestVertex H = new TestVertex("H");
20 + static final TestVertex Z = new TestVertex("Z");
20 21
21 protected Graph<TestVertex, TestEdge> g; 22 protected Graph<TestVertex, TestEdge> g;
22 23
......