# HG changeset patch
# User Peter Kovacs <kpeter@inf.elte.hu>
# Date 1249253644 -7200
# Node ID 75325dfccf3898d9df23913cc64979e069a85502
# Parent  f9746e45246ee740d32043c486868935988f9b55
Add negativeCycle() function to BellmanFord (#51)

diff -r f9746e45246e -r 75325dfccf38 lemon/bellman_ford.h
--- a/lemon/bellman_ford.h	Mon Aug 03 00:52:45 2009 +0200
+++ b/lemon/bellman_ford.h	Mon Aug 03 00:54:04 2009 +0200
@@ -770,44 +770,34 @@
       return (*_dist)[v] != OperationTraits::infinity();
     }
 
-    // TODO: implement negative cycle
-//    /// \brief Gives back a negative cycle.
-//    ///    
-//    /// This function gives back a negative cycle.
-//    /// If the algorithm have not found yet negative cycle it will give back
-//    /// an empty path.
-//    Path negativeCycle() {
-//      typename Digraph::template NodeMap<int> state(*digraph, 0);
-//      for (ActiveIt it(*this); it != INVALID; ++it) {
-//        if (state[it] == 0) {
-//          for (Node t = it; predArc(t) != INVALID; t = predNode(t)) {
-//            if (state[t] == 0) {
-//              state[t] = 1;
-//            } else if (state[t] == 2) {
-//              break;
-//            } else {
-//              p.clear();
-//              typename Path::Builder b(p);
-//              b.setStartNode(t);
-//              b.pushFront(predArc(t));
-//              for(Node s = predNode(t); s != t; s = predNode(s)) {
-//                b.pushFront(predArc(s));
-//              }
-//              b.commit();
-//              return true;
-//            }
-//          }
-//          for (Node t = it; predArc(t) != INVALID; t = predNode(t)) {
-//            if (state[t] == 1) {
-//              state[t] = 2;
-//            } else {
-//              break;
-//            }
-//          }
-//        }
-//      }
-//      return false;
-//    }
+    /// \brief Gives back a negative cycle.
+    ///    
+    /// This function gives back a directed cycle with negative total
+    /// length if the algorithm has already found one.
+    /// Otherwise it gives back an empty path.
+    lemon::Path<Digraph> negativeCycle() {
+      typename Digraph::template NodeMap<int> state(*_gr, -1);
+      lemon::Path<Digraph> cycle;
+      for (int i = 0; i < int(_process.size()); ++i) {
+        if (state[_process[i]] != -1) continue;
+        for (Node v = _process[i]; (*_pred)[v] != INVALID;
+             v = _gr->source((*_pred)[v])) {
+          if (state[v] == i) {
+            cycle.addFront((*_pred)[v]);
+            for (Node u = _gr->source((*_pred)[v]); u != v;
+                 u = _gr->source((*_pred)[u])) {
+              cycle.addFront((*_pred)[u]);
+            }
+            return cycle;
+          }
+          else if (state[v] >= 0) {
+            break;
+          }
+          state[v] = i;
+        }
+      }
+      return cycle;
+    }
     
     ///@}
   };
diff -r f9746e45246e -r 75325dfccf38 test/bellman_ford_test.cc
--- a/test/bellman_ford_test.cc	Mon Aug 03 00:52:45 2009 +0200
+++ b/test/bellman_ford_test.cc	Mon Aug 03 00:54:04 2009 +0200
@@ -220,8 +220,64 @@
   }
 }
 
+void checkBellmanFordNegativeCycle() {
+  DIGRAPH_TYPEDEFS(SmartDigraph);
+
+  SmartDigraph gr;
+  IntArcMap length(gr);
+  
+  Node n1 = gr.addNode();
+  Node n2 = gr.addNode();
+  Node n3 = gr.addNode();
+  Node n4 = gr.addNode();
+  
+  Arc a1 = gr.addArc(n1, n2);
+  Arc a2 = gr.addArc(n2, n2);
+  
+  length[a1] = 2;
+  length[a2] = -1;
+  
+  {
+    BellmanFord<SmartDigraph, IntArcMap> bf(gr, length);
+    bf.run(n1);
+    StaticPath<SmartDigraph> p = bf.negativeCycle();
+    check(p.length() == 1 && p.front() == p.back() && p.front() == a2,
+          "Wrong negative cycle.");
+  }
+ 
+  length[a2] = 0;
+  
+  {
+    BellmanFord<SmartDigraph, IntArcMap> bf(gr, length);
+    bf.run(n1);
+    check(bf.negativeCycle().empty(),
+          "Negative cycle should not be found.");
+  }
+  
+  length[gr.addArc(n1, n3)] = 5;
+  length[gr.addArc(n4, n3)] = 1;
+  length[gr.addArc(n2, n4)] = 2;
+  length[gr.addArc(n3, n2)] = -4;
+  
+  {
+    BellmanFord<SmartDigraph, IntArcMap> bf(gr, length);
+    bf.init();
+    bf.addSource(n1);
+    for (int i = 0; i < 4; ++i) {
+      check(bf.negativeCycle().empty(),
+            "Negative cycle should not be found.");
+      bf.processNextRound();
+    }
+    StaticPath<SmartDigraph> p = bf.negativeCycle();
+    check(p.length() == 3, "Wrong negative cycle.");
+    check(length[p.nth(0)] + length[p.nth(1)] + length[p.nth(2)] == -1,
+          "Wrong negative cycle.");
+  }
+}
+
 int main() {
   checkBellmanFord<ListDigraph, int>();
   checkBellmanFord<SmartDigraph, double>();
+  checkBellmanFordNegativeCycle();
   return 0;
 }