test/bellman_ford_test.cc
author Peter Kovacs <kpeter@inf.elte.hu>
Thu, 12 Nov 2009 23:26:13 +0100
changeset 806 fa6f37d7a25b
parent 781 6f10c6ec5a21
parent 790 1870cfd14fb6
child 844 a6eb9698c321
permissions -rw-r--r--
Entirely rework CapacityScaling (#180)

- Use the new interface similarly to NetworkSimplex.
- Rework the implementation using an efficient internal structure
for handling the residual network. This improvement made the
code much faster (up to 2-5 times faster on large graphs).
- Handle GEQ supply type (LEQ is not supported).
- Handle negative costs for arcs of finite capacity.
(Note that this algorithm cannot handle arcs of negative cost
and infinite upper bound, thus it returns UNBOUNDED if such
an arc exists.)
- Extend the documentation.
     1 /* -*- mode: C++; indent-tabs-mode: nil; -*-
     2  *
     3  * This file is a part of LEMON, a generic C++ optimization library.
     4  *
     5  * Copyright (C) 2003-2009
     6  * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
     7  * (Egervary Research Group on Combinatorial Optimization, EGRES).
     8  *
     9  * Permission to use, modify and distribute this software is granted
    10  * provided that this copyright notice appears in all copies. For
    11  * precise terms see the accompanying LICENSE file.
    12  *
    13  * This software is provided "AS IS" with no warranty of any kind,
    14  * express or implied, and with no claim as to its suitability for any
    15  * purpose.
    16  *
    17  */
    18 
    19 #include <lemon/concepts/digraph.h>
    20 #include <lemon/smart_graph.h>
    21 #include <lemon/list_graph.h>
    22 #include <lemon/lgf_reader.h>
    23 #include <lemon/bellman_ford.h>
    24 #include <lemon/path.h>
    25 
    26 #include "graph_test.h"
    27 #include "test_tools.h"
    28 
    29 using namespace lemon;
    30 
    31 char test_lgf[] =
    32   "@nodes\n"
    33   "label\n"
    34   "0\n"
    35   "1\n"
    36   "2\n"
    37   "3\n"
    38   "4\n"
    39   "@arcs\n"
    40   "    length\n"
    41   "0 1 3\n"
    42   "1 2 -3\n"
    43   "1 2 -5\n"
    44   "1 3 -2\n"
    45   "0 2 -1\n"
    46   "1 2 -4\n"
    47   "0 3 2\n"
    48   "4 2 -5\n"
    49   "2 3 1\n"
    50   "@attributes\n"
    51   "source 0\n"
    52   "target 3\n";
    53 
    54 
    55 void checkBellmanFordCompile()
    56 {
    57   typedef int Value;
    58   typedef concepts::Digraph Digraph;
    59   typedef concepts::ReadMap<Digraph::Arc,Value> LengthMap;
    60   typedef BellmanFord<Digraph, LengthMap> BF;
    61   typedef Digraph::Node Node;
    62   typedef Digraph::Arc Arc;
    63 
    64   Digraph gr;
    65   Node s, t, n;
    66   Arc e;
    67   Value l;
    68   int k=3;
    69   bool b;
    70   BF::DistMap d(gr);
    71   BF::PredMap p(gr);
    72   LengthMap length;
    73   concepts::Path<Digraph> pp;
    74 
    75   {
    76     BF bf_test(gr,length);
    77     const BF& const_bf_test = bf_test;
    78 
    79     bf_test.run(s);
    80     bf_test.run(s,k);
    81 
    82     bf_test.init();
    83     bf_test.addSource(s);
    84     bf_test.addSource(s, 1);
    85     b = bf_test.processNextRound();
    86     b = bf_test.processNextWeakRound();
    87 
    88     bf_test.start();
    89     bf_test.checkedStart();
    90     bf_test.limitedStart(k);
    91 
    92     l  = const_bf_test.dist(t);
    93     e  = const_bf_test.predArc(t);
    94     s  = const_bf_test.predNode(t);
    95     b  = const_bf_test.reached(t);
    96     d  = const_bf_test.distMap();
    97     p  = const_bf_test.predMap();
    98     pp = const_bf_test.path(t);
    99     pp = const_bf_test.negativeCycle();
   100     
   101     for (BF::ActiveIt it(const_bf_test); it != INVALID; ++it) {}
   102   }
   103   {
   104     BF::SetPredMap<concepts::ReadWriteMap<Node,Arc> >
   105       ::SetDistMap<concepts::ReadWriteMap<Node,Value> >
   106       ::SetOperationTraits<BellmanFordDefaultOperationTraits<Value> >
   107       ::Create bf_test(gr,length);
   108 
   109     LengthMap length_map;
   110     concepts::ReadWriteMap<Node,Arc> pred_map;
   111     concepts::ReadWriteMap<Node,Value> dist_map;
   112     
   113     bf_test
   114       .lengthMap(length_map)
   115       .predMap(pred_map)
   116       .distMap(dist_map);
   117 
   118     bf_test.run(s);
   119     bf_test.run(s,k);
   120 
   121     bf_test.init();
   122     bf_test.addSource(s);
   123     bf_test.addSource(s, 1);
   124     b = bf_test.processNextRound();
   125     b = bf_test.processNextWeakRound();
   126 
   127     bf_test.start();
   128     bf_test.checkedStart();
   129     bf_test.limitedStart(k);
   130 
   131     l  = bf_test.dist(t);
   132     e  = bf_test.predArc(t);
   133     s  = bf_test.predNode(t);
   134     b  = bf_test.reached(t);
   135     pp = bf_test.path(t);
   136     pp = bf_test.negativeCycle();
   137   }
   138 }
   139 
   140 void checkBellmanFordFunctionCompile()
   141 {
   142   typedef int Value;
   143   typedef concepts::Digraph Digraph;
   144   typedef Digraph::Arc Arc;
   145   typedef Digraph::Node Node;
   146   typedef concepts::ReadMap<Digraph::Arc,Value> LengthMap;
   147 
   148   Digraph g;
   149   bool b;
   150   bellmanFord(g,LengthMap()).run(Node());
   151   b = bellmanFord(g,LengthMap()).run(Node(),Node());
   152   bellmanFord(g,LengthMap())
   153     .predMap(concepts::ReadWriteMap<Node,Arc>())
   154     .distMap(concepts::ReadWriteMap<Node,Value>())
   155     .run(Node());
   156   b=bellmanFord(g,LengthMap())
   157     .predMap(concepts::ReadWriteMap<Node,Arc>())
   158     .distMap(concepts::ReadWriteMap<Node,Value>())
   159     .path(concepts::Path<Digraph>())
   160     .dist(Value())
   161     .run(Node(),Node());
   162 }
   163 
   164 
   165 template <typename Digraph, typename Value>
   166 void checkBellmanFord() {
   167   TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
   168   typedef typename Digraph::template ArcMap<Value> LengthMap;
   169 
   170   Digraph gr;
   171   Node s, t;
   172   LengthMap length(gr);
   173 
   174   std::istringstream input(test_lgf);
   175   digraphReader(gr, input).
   176     arcMap("length", length).
   177     node("source", s).
   178     node("target", t).
   179     run();
   180 
   181   BellmanFord<Digraph, LengthMap>
   182     bf(gr, length);
   183   bf.run(s);
   184   Path<Digraph> p = bf.path(t);
   185 
   186   check(bf.reached(t) && bf.dist(t) == -1, "Bellman-Ford found a wrong path.");
   187   check(p.length() == 3, "path() found a wrong path.");
   188   check(checkPath(gr, p), "path() found a wrong path.");
   189   check(pathSource(gr, p) == s, "path() found a wrong path.");
   190   check(pathTarget(gr, p) == t, "path() found a wrong path.");
   191   
   192   ListPath<Digraph> path;
   193   Value dist;
   194   bool reached = bellmanFord(gr,length).path(path).dist(dist).run(s,t);
   195 
   196   check(reached && dist == -1, "Bellman-Ford found a wrong path.");
   197   check(path.length() == 3, "path() found a wrong path.");
   198   check(checkPath(gr, path), "path() found a wrong path.");
   199   check(pathSource(gr, path) == s, "path() found a wrong path.");
   200   check(pathTarget(gr, path) == t, "path() found a wrong path.");
   201 
   202   for(ArcIt e(gr); e!=INVALID; ++e) {
   203     Node u=gr.source(e);
   204     Node v=gr.target(e);
   205     check(!bf.reached(u) || (bf.dist(v) - bf.dist(u) <= length[e]),
   206           "Wrong output. dist(target)-dist(source)-arc_length=" <<
   207           bf.dist(v) - bf.dist(u) - length[e]);
   208   }
   209 
   210   for(NodeIt v(gr); v!=INVALID; ++v) {
   211     if (bf.reached(v)) {
   212       check(v==s || bf.predArc(v)!=INVALID, "Wrong tree.");
   213       if (bf.predArc(v)!=INVALID ) {
   214         Arc e=bf.predArc(v);
   215         Node u=gr.source(e);
   216         check(u==bf.predNode(v),"Wrong tree.");
   217         check(bf.dist(v) - bf.dist(u) == length[e],
   218               "Wrong distance! Difference: " <<
   219               bf.dist(v) - bf.dist(u) - length[e]);
   220       }
   221     }
   222   }
   223 }
   224 
   225 void checkBellmanFordNegativeCycle() {
   226   DIGRAPH_TYPEDEFS(SmartDigraph);
   227 
   228   SmartDigraph gr;
   229   IntArcMap length(gr);
   230   
   231   Node n1 = gr.addNode();
   232   Node n2 = gr.addNode();
   233   Node n3 = gr.addNode();
   234   Node n4 = gr.addNode();
   235   
   236   Arc a1 = gr.addArc(n1, n2);
   237   Arc a2 = gr.addArc(n2, n2);
   238   
   239   length[a1] = 2;
   240   length[a2] = -1;
   241   
   242   {
   243     BellmanFord<SmartDigraph, IntArcMap> bf(gr, length);
   244     bf.run(n1);
   245     StaticPath<SmartDigraph> p = bf.negativeCycle();
   246     check(p.length() == 1 && p.front() == p.back() && p.front() == a2,
   247           "Wrong negative cycle.");
   248   }
   249  
   250   length[a2] = 0;
   251   
   252   {
   253     BellmanFord<SmartDigraph, IntArcMap> bf(gr, length);
   254     bf.run(n1);
   255     check(bf.negativeCycle().empty(),
   256           "Negative cycle should not be found.");
   257   }
   258   
   259   length[gr.addArc(n1, n3)] = 5;
   260   length[gr.addArc(n4, n3)] = 1;
   261   length[gr.addArc(n2, n4)] = 2;
   262   length[gr.addArc(n3, n2)] = -4;
   263   
   264   {
   265     BellmanFord<SmartDigraph, IntArcMap> bf(gr, length);
   266     bf.init();
   267     bf.addSource(n1);
   268     for (int i = 0; i < 4; ++i) {
   269       check(bf.negativeCycle().empty(),
   270             "Negative cycle should not be found.");
   271       bf.processNextRound();
   272     }
   273     StaticPath<SmartDigraph> p = bf.negativeCycle();
   274     check(p.length() == 3, "Wrong negative cycle.");
   275     check(length[p.nth(0)] + length[p.nth(1)] + length[p.nth(2)] == -1,
   276           "Wrong negative cycle.");
   277   }
   278 }
   279 
   280 int main() {
   281   checkBellmanFord<ListDigraph, int>();
   282   checkBellmanFord<SmartDigraph, double>();
   283   checkBellmanFordNegativeCycle();
   284   return 0;
   285 }