Added bellman-ford implementation.
diff --git a/utils/misc/src/main/java/org/onlab/graph/BellmanFordGraphSearch.java b/utils/misc/src/main/java/org/onlab/graph/BellmanFordGraphSearch.java
new file mode 100644
index 0000000..513c686
--- /dev/null
+++ b/utils/misc/src/main/java/org/onlab/graph/BellmanFordGraphSearch.java
@@ -0,0 +1,45 @@
+package org.onlab.graph;
+
+/**
+ * Bellman-Ford graph search algorithm for locating shortest-paths in
+ * directed graphs that may contain negative cycles.
+ */
+public class BellmanFordGraphSearch<V extends Vertex, E extends Edge<V>>
+ extends AbstractGraphPathSearch<V, E> {
+
+ @Override
+ public Result<V, E> search(Graph<V, E> graph, V src, V dst,
+ EdgeWeight<V, E> weight) {
+ checkArguments(graph, src, dst);
+
+ // Prepare the graph search result.
+ DefaultResult result = new DefaultResult(src, dst);
+
+ // The source vertex has cost 0, of course.
+ result.updateVertex(src, null, 0.0, true);
+
+ int max = graph.getVertexes().size() - 1;
+ for (int i = 0; i < max; i++) {
+ // Relax, if possible, all egress edges of the current vertex.
+ for (E edge : graph.getEdges()) {
+ if (result.hasCost(edge.src())) {
+ result.relaxEdge(edge, result.cost(edge.src()), weight);
+ }
+ }
+ }
+
+ // Remove any vertexes reached by traversing edges with negative weights.
+ for (E edge : graph.getEdges()) {
+ if (result.hasCost(edge.src())) {
+ if (result.relaxEdge(edge, result.cost(edge.src()), weight)) {
+ result.removeVertex(edge.dst());
+ }
+ }
+ }
+
+ // Finally, but the paths on the search result and return.
+ result.buildPaths();
+ return result;
+ }
+
+}
diff --git a/utils/misc/src/main/java/org/onlab/graph/BreadthFirstSearch.java b/utils/misc/src/main/java/org/onlab/graph/BreadthFirstSearch.java
index c02afea..daf8ca2 100644
--- a/utils/misc/src/main/java/org/onlab/graph/BreadthFirstSearch.java
+++ b/utils/misc/src/main/java/org/onlab/graph/BreadthFirstSearch.java
@@ -10,7 +10,8 @@
extends AbstractGraphPathSearch<V, E> {
@Override
- public Result<V, E> search(Graph<V, E> graph, V src, V dst, EdgeWeight<V, E> ew) {
+ public Result<V, E> search(Graph<V, E> graph, V src, V dst,
+ EdgeWeight<V, E> weight) {
checkArguments(graph, src, dst);
// Prepare the graph result.
@@ -18,7 +19,7 @@
// Setup the starting frontier with the source as the sole vertex.
Set<V> frontier = new HashSet<>();
- result.costs.put(src, 0.0);
+ result.updateVertex(src, null, 0.0, true);
frontier.add(src);
boolean reachedEnd = false;
@@ -35,9 +36,8 @@
V nextVertex = edge.dst();
if (!result.hasCost(nextVertex)) {
// If this vertex has not been visited yet, update it.
- result.updateVertex(nextVertex, edge,
- cost + (ew == null ? 1.0 : ew.weight(edge)),
- true);
+ double newCost = cost + (weight == null ? 1.0 : weight.weight(edge));
+ result.updateVertex(nextVertex, edge, newCost, true);
// If we have reached our intended destination, bail.
if (nextVertex.equals(dst)) {
reachedEnd = true;
diff --git a/utils/misc/src/main/java/org/onlab/graph/DijkstraGraphSearch.java b/utils/misc/src/main/java/org/onlab/graph/DijkstraGraphSearch.java
index dc71859..535da09 100644
--- a/utils/misc/src/main/java/org/onlab/graph/DijkstraGraphSearch.java
+++ b/utils/misc/src/main/java/org/onlab/graph/DijkstraGraphSearch.java
@@ -12,8 +12,9 @@
extends AbstractGraphPathSearch<V, E> {
@Override
- public Result<V, E> search(Graph<V, E> g, V src, V dst, EdgeWeight<V, E> ew) {
- checkArguments(g, src, dst);
+ public Result<V, E> search(Graph<V, E> graph, V src, V dst,
+ EdgeWeight<V, E> weight) {
+ checkArguments(graph, src, dst);
// Use the default result to remember cumulative costs and parent
// edges to each each respective vertex.
@@ -25,7 +26,7 @@
// Use the min priority queue to progressively find each nearest
// vertex until we reach the desired destination, if one was given,
// or until we reach all possible destinations.
- Heap<V> minQueue = createMinQueue(g.getVertexes(),
+ Heap<V> minQueue = createMinQueue(graph.getVertexes(),
new PathCostComparator(result));
while (!minQueue.isEmpty()) {
// Get the nearest vertex
@@ -38,8 +39,8 @@
double cost = result.cost(nearest);
if (cost < Double.MAX_VALUE) {
// If the vertex is reachable, relax all its egress edges.
- for (E e : g.getEdgesFrom(nearest)) {
- result.relaxEdge(e, cost, ew);
+ for (E e : graph.getEdgesFrom(nearest)) {
+ result.relaxEdge(e, cost, weight);
}
}
diff --git a/utils/misc/src/test/java/org/onlab/graph/BellmanFordGraphSearchTest.java b/utils/misc/src/test/java/org/onlab/graph/BellmanFordGraphSearchTest.java
new file mode 100644
index 0000000..4ee9006
--- /dev/null
+++ b/utils/misc/src/test/java/org/onlab/graph/BellmanFordGraphSearchTest.java
@@ -0,0 +1,61 @@
+package org.onlab.graph;
+
+import org.junit.Test;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Test of the Bellman-Ford algorithm.
+ */
+public class BellmanFordGraphSearchTest extends BreadthFirstSearchTest {
+
+ @Override
+ protected AbstractGraphPathSearch<TestVertex, TestEdge> graphSearch() {
+ return new BellmanFordGraphSearch<>();
+ }
+
+ @Test
+ @Override
+ public void defaultGraphTest() {
+ executeDefaultTest(7, 5, 5.0);
+ }
+
+ @Test
+ public void defaultHopCountWeight() {
+ weight = null;
+ executeDefaultTest(10, 3, 3.0);
+ }
+
+ @Test
+ public void searchGraphWithNegativeCycles() {
+ Set<TestVertex> vertexes = new HashSet<>(vertices());
+ vertexes.add(Z);
+
+ Set<TestEdge> edges = new HashSet<>(edges());
+ edges.add(new TestEdge(G, Z, 1.0));
+ edges.add(new TestEdge(Z, G, -2.0));
+
+ g = new AdjacencyListsGraph<>(vertexes, edges);
+
+ GraphPathSearch<TestVertex, TestEdge> search = graphSearch();
+ Set<Path<TestVertex, TestEdge>> paths = search.search(g, A, H, weight).paths();
+ assertEquals("incorrect paths count", 1, paths.size());
+
+ Path p = paths.iterator().next();
+ assertEquals("incorrect src", A, p.src());
+ assertEquals("incorrect dst", H, p.dst());
+ assertEquals("incorrect path length", 5, p.edges().size());
+ assertEquals("incorrect path cost", 5.0, p.cost(), 0.1);
+
+ paths = search.search(g, A, G, weight).paths();
+ assertEquals("incorrect paths count", 0, paths.size());
+
+ paths = search.search(g, A, null, weight).paths();
+ printPaths(paths);
+ assertEquals("incorrect paths count", 6, paths.size());
+ }
+
+}
diff --git a/utils/misc/src/test/java/org/onlab/graph/GraphTest.java b/utils/misc/src/test/java/org/onlab/graph/GraphTest.java
index a95af93..44b1137 100644
--- a/utils/misc/src/test/java/org/onlab/graph/GraphTest.java
+++ b/utils/misc/src/test/java/org/onlab/graph/GraphTest.java
@@ -17,6 +17,7 @@
static final TestVertex F = new TestVertex("F");
static final TestVertex G = new TestVertex("G");
static final TestVertex H = new TestVertex("H");
+ static final TestVertex Z = new TestVertex("Z");
protected Graph<TestVertex, TestEdge> g;