test/bellman_ford_test.cc
author Peter Kovacs <kpeter@inf.elte.hu>
Tue, 15 Mar 2011 19:32:21 +0100
changeset 1047 ddd3c0d3d9bf
parent 956 141f9c0db4a3
parent 958 d6052a9c4e8d
child 1160 00f8d9f9920d
permissions -rw-r--r--
Implement the scaling Price Refinement heuristic in CostScaling (#417)
instead of Early Termination.

These two heuristics are similar, but the newer one is faster
and not only makes it possible to skip some epsilon phases, but
it can improve the performance of the other phases, as well.
     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-2010
     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 }