test/suurballe_test.cc
author Balazs Dezso <deba@inf.elte.hu>
Thu, 24 Jun 2010 09:27:53 +0200
changeset 891 bb70ad62c95f
parent 440 88ed40ad0d4f
child 854 9a7e4e606f83
child 1007 7e368d9b67f7
permissions -rw-r--r--
Fix critical bug in preflow (#372)

The wrong transition between the bound decrease and highest active
heuristics caused the bug. The last node chosen in bound decrease mode
is used in the first iteration in highest active mode.
alpar@440
     1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
alpar@345
     2
 *
alpar@440
     3
 * This file is a part of LEMON, a generic C++ optimization library.
alpar@345
     4
 *
alpar@440
     5
 * Copyright (C) 2003-2009
alpar@345
     6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
alpar@345
     7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
alpar@345
     8
 *
alpar@345
     9
 * Permission to use, modify and distribute this software is granted
alpar@345
    10
 * provided that this copyright notice appears in all copies. For
alpar@345
    11
 * precise terms see the accompanying LICENSE file.
alpar@345
    12
 *
alpar@345
    13
 * This software is provided "AS IS" with no warranty of any kind,
alpar@345
    14
 * express or implied, and with no claim as to its suitability for any
alpar@345
    15
 * purpose.
alpar@345
    16
 *
alpar@345
    17
 */
alpar@345
    18
alpar@345
    19
#include <iostream>
alpar@345
    20
alpar@345
    21
#include <lemon/list_graph.h>
alpar@345
    22
#include <lemon/lgf_reader.h>
alpar@345
    23
#include <lemon/path.h>
alpar@345
    24
#include <lemon/suurballe.h>
kpeter@623
    25
#include <lemon/concepts/digraph.h>
alpar@345
    26
alpar@345
    27
#include "test_tools.h"
alpar@345
    28
alpar@345
    29
using namespace lemon;
alpar@345
    30
alpar@423
    31
char test_lgf[] =
alpar@423
    32
  "@nodes\n"
kpeter@623
    33
  "label\n"
kpeter@623
    34
  "1\n"
kpeter@623
    35
  "2\n"
kpeter@623
    36
  "3\n"
kpeter@623
    37
  "4\n"
kpeter@623
    38
  "5\n"
kpeter@623
    39
  "6\n"
kpeter@623
    40
  "7\n"
kpeter@623
    41
  "8\n"
kpeter@623
    42
  "9\n"
kpeter@623
    43
  "10\n"
kpeter@623
    44
  "11\n"
kpeter@623
    45
  "12\n"
alpar@423
    46
  "@arcs\n"
kpeter@623
    47
  "      length\n"
kpeter@623
    48
  " 1  2  70\n"
kpeter@623
    49
  " 1  3 150\n"
kpeter@623
    50
  " 1  4  80\n"
kpeter@623
    51
  " 2  8  80\n"
kpeter@623
    52
  " 3  5 140\n"
kpeter@623
    53
  " 4  6  60\n"
kpeter@623
    54
  " 4  7  80\n"
kpeter@623
    55
  " 4  8 110\n"
kpeter@623
    56
  " 5  7  60\n"
kpeter@623
    57
  " 5 11 120\n"
kpeter@623
    58
  " 6  3   0\n"
kpeter@623
    59
  " 6  9 140\n"
kpeter@623
    60
  " 6 10  90\n"
kpeter@623
    61
  " 7  1  30\n"
kpeter@623
    62
  " 8 12  60\n"
kpeter@623
    63
  " 9 12  50\n"
kpeter@623
    64
  "10 12  70\n"
kpeter@623
    65
  "10  2 100\n"
kpeter@623
    66
  "10  7  60\n"
kpeter@623
    67
  "11 10  20\n"
kpeter@623
    68
  "12 11  30\n"
alpar@423
    69
  "@attributes\n"
alpar@423
    70
  "source  1\n"
alpar@423
    71
  "target 12\n"
alpar@423
    72
  "@end\n";
alpar@423
    73
kpeter@623
    74
// Check the interface of Suurballe
kpeter@623
    75
void checkSuurballeCompile()
kpeter@623
    76
{
kpeter@623
    77
  typedef int VType;
kpeter@623
    78
  typedef concepts::Digraph Digraph;
kpeter@623
    79
kpeter@623
    80
  typedef Digraph::Node Node;
kpeter@623
    81
  typedef Digraph::Arc Arc;
kpeter@623
    82
  typedef concepts::ReadMap<Arc, VType> LengthMap;
kpeter@623
    83
  
kpeter@623
    84
  typedef Suurballe<Digraph, LengthMap> SuurballeType;
kpeter@623
    85
kpeter@623
    86
  Digraph g;
kpeter@623
    87
  Node n;
kpeter@623
    88
  Arc e;
kpeter@623
    89
  LengthMap len;
kpeter@623
    90
  SuurballeType::FlowMap flow(g);
kpeter@623
    91
  SuurballeType::PotentialMap pi(g);
kpeter@623
    92
kpeter@623
    93
  SuurballeType suurb_test(g, len);
kpeter@623
    94
  const SuurballeType& const_suurb_test = suurb_test;
kpeter@623
    95
kpeter@623
    96
  suurb_test
kpeter@623
    97
    .flowMap(flow)
kpeter@623
    98
    .potentialMap(pi);
kpeter@623
    99
kpeter@623
   100
  int k;
kpeter@623
   101
  k = suurb_test.run(n, n);
kpeter@623
   102
  k = suurb_test.run(n, n, k);
kpeter@623
   103
  suurb_test.init(n);
kpeter@623
   104
  k = suurb_test.findFlow(n);
kpeter@623
   105
  k = suurb_test.findFlow(n, k);
kpeter@623
   106
  suurb_test.findPaths();
kpeter@623
   107
  
kpeter@623
   108
  int f;
kpeter@623
   109
  VType c;
kpeter@623
   110
  c = const_suurb_test.totalLength();
kpeter@623
   111
  f = const_suurb_test.flow(e);
kpeter@623
   112
  const SuurballeType::FlowMap& fm =
kpeter@623
   113
    const_suurb_test.flowMap();
kpeter@623
   114
  c = const_suurb_test.potential(n);
kpeter@623
   115
  const SuurballeType::PotentialMap& pm =
kpeter@623
   116
    const_suurb_test.potentialMap();
kpeter@623
   117
  k = const_suurb_test.pathNum();
kpeter@623
   118
  Path<Digraph> p = const_suurb_test.path(k);
kpeter@623
   119
  
kpeter@623
   120
  ignore_unused_variable_warning(fm);
kpeter@623
   121
  ignore_unused_variable_warning(pm);
kpeter@623
   122
}
kpeter@623
   123
kpeter@346
   124
// Check the feasibility of the flow
alpar@345
   125
template <typename Digraph, typename FlowMap>
alpar@440
   126
bool checkFlow( const Digraph& gr, const FlowMap& flow,
alpar@345
   127
                typename Digraph::Node s, typename Digraph::Node t,
alpar@345
   128
                int value )
alpar@345
   129
{
alpar@345
   130
  TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
alpar@345
   131
  for (ArcIt e(gr); e != INVALID; ++e)
alpar@345
   132
    if (!(flow[e] == 0 || flow[e] == 1)) return false;
alpar@345
   133
alpar@345
   134
  for (NodeIt n(gr); n != INVALID; ++n) {
alpar@345
   135
    int sum = 0;
alpar@345
   136
    for (OutArcIt e(gr, n); e != INVALID; ++e)
alpar@345
   137
      sum += flow[e];
alpar@345
   138
    for (InArcIt e(gr, n); e != INVALID; ++e)
alpar@345
   139
      sum -= flow[e];
alpar@345
   140
    if (n == s && sum != value) return false;
alpar@345
   141
    if (n == t && sum != -value) return false;
alpar@345
   142
    if (n != s && n != t && sum != 0) return false;
alpar@345
   143
  }
alpar@345
   144
alpar@345
   145
  return true;
alpar@345
   146
}
alpar@345
   147
kpeter@346
   148
// Check the optimalitiy of the flow
alpar@440
   149
template < typename Digraph, typename CostMap,
alpar@345
   150
           typename FlowMap, typename PotentialMap >
alpar@345
   151
bool checkOptimality( const Digraph& gr, const CostMap& cost,
alpar@345
   152
                      const FlowMap& flow, const PotentialMap& pi )
alpar@345
   153
{
kpeter@346
   154
  // Check the "Complementary Slackness" optimality condition
alpar@345
   155
  TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
alpar@345
   156
  bool opt = true;
alpar@345
   157
  for (ArcIt e(gr); e != INVALID; ++e) {
alpar@345
   158
    typename CostMap::Value red_cost =
alpar@345
   159
      cost[e] + pi[gr.source(e)] - pi[gr.target(e)];
alpar@345
   160
    opt = (flow[e] == 0 && red_cost >= 0) ||
alpar@345
   161
          (flow[e] == 1 && red_cost <= 0);
alpar@345
   162
    if (!opt) break;
alpar@345
   163
  }
alpar@345
   164
  return opt;
alpar@345
   165
}
alpar@345
   166
kpeter@346
   167
// Check a path
kpeter@346
   168
template <typename Digraph, typename Path>
alpar@345
   169
bool checkPath( const Digraph& gr, const Path& path,
alpar@345
   170
                typename Digraph::Node s, typename Digraph::Node t)
alpar@345
   171
{
alpar@345
   172
  TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
alpar@345
   173
  Node n = s;
alpar@345
   174
  for (int i = 0; i < path.length(); ++i) {
alpar@345
   175
    if (gr.source(path.nth(i)) != n) return false;
alpar@345
   176
    n = gr.target(path.nth(i));
alpar@345
   177
  }
alpar@345
   178
  return n == t;
alpar@345
   179
}
alpar@345
   180
alpar@345
   181
alpar@345
   182
int main()
alpar@345
   183
{
alpar@345
   184
  DIGRAPH_TYPEDEFS(ListDigraph);
alpar@345
   185
kpeter@346
   186
  // Read the test digraph
alpar@345
   187
  ListDigraph digraph;
alpar@345
   188
  ListDigraph::ArcMap<int> length(digraph);
kpeter@623
   189
  Node s, t;
alpar@345
   190
alpar@423
   191
  std::istringstream input(test_lgf);
alpar@345
   192
  DigraphReader<ListDigraph>(digraph, input).
kpeter@623
   193
    arcMap("length", length).
kpeter@623
   194
    node("source", s).
kpeter@623
   195
    node("target", t).
alpar@345
   196
    run();
alpar@440
   197
kpeter@346
   198
  // Find 2 paths
alpar@345
   199
  {
kpeter@623
   200
    Suurballe<ListDigraph> suurballe(digraph, length);
kpeter@623
   201
    check(suurballe.run(s, t) == 2, "Wrong number of paths");
kpeter@623
   202
    check(checkFlow(digraph, suurballe.flowMap(), s, t, 2),
alpar@345
   203
          "The flow is not feasible");
alpar@345
   204
    check(suurballe.totalLength() == 510, "The flow is not optimal");
alpar@440
   205
    check(checkOptimality(digraph, length, suurballe.flowMap(),
alpar@345
   206
                          suurballe.potentialMap()),
alpar@345
   207
          "Wrong potentials");
alpar@345
   208
    for (int i = 0; i < suurballe.pathNum(); ++i)
kpeter@623
   209
      check(checkPath(digraph, suurballe.path(i), s, t), "Wrong path");
alpar@345
   210
  }
alpar@345
   211
kpeter@346
   212
  // Find 3 paths
alpar@345
   213
  {
kpeter@623
   214
    Suurballe<ListDigraph> suurballe(digraph, length);
kpeter@623
   215
    check(suurballe.run(s, t, 3) == 3, "Wrong number of paths");
kpeter@623
   216
    check(checkFlow(digraph, suurballe.flowMap(), s, t, 3),
alpar@345
   217
          "The flow is not feasible");
alpar@345
   218
    check(suurballe.totalLength() == 1040, "The flow is not optimal");
alpar@440
   219
    check(checkOptimality(digraph, length, suurballe.flowMap(),
alpar@345
   220
                          suurballe.potentialMap()),
alpar@345
   221
          "Wrong potentials");
alpar@345
   222
    for (int i = 0; i < suurballe.pathNum(); ++i)
kpeter@623
   223
      check(checkPath(digraph, suurballe.path(i), s, t), "Wrong path");
alpar@345
   224
  }
alpar@345
   225
kpeter@346
   226
  // Find 5 paths (only 3 can be found)
alpar@345
   227
  {
kpeter@623
   228
    Suurballe<ListDigraph> suurballe(digraph, length);
kpeter@623
   229
    check(suurballe.run(s, t, 5) == 3, "Wrong number of paths");
kpeter@623
   230
    check(checkFlow(digraph, suurballe.flowMap(), s, t, 3),
alpar@345
   231
          "The flow is not feasible");
alpar@345
   232
    check(suurballe.totalLength() == 1040, "The flow is not optimal");
alpar@440
   233
    check(checkOptimality(digraph, length, suurballe.flowMap(),
alpar@345
   234
                          suurballe.potentialMap()),
alpar@345
   235
          "Wrong potentials");
alpar@345
   236
    for (int i = 0; i < suurballe.pathNum(); ++i)
kpeter@623
   237
      check(checkPath(digraph, suurballe.path(i), s, t), "Wrong path");
alpar@345
   238
  }
alpar@345
   239
alpar@345
   240
  return 0;
alpar@345
   241
}