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