test/min_cost_flow_test.cc
author Peter Kovacs <kpeter@inf.elte.hu>
Tue, 15 Mar 2011 19:32:21 +0100
changeset 936 ddd3c0d3d9bf
parent 830 75c97c3786d6
child 1092 dceba191c00d
child 1129 b40c2bbb8da5
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.
kpeter@601
     1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
kpeter@601
     2
 *
kpeter@601
     3
 * This file is a part of LEMON, a generic C++ optimization library.
kpeter@601
     4
 *
alpar@877
     5
 * Copyright (C) 2003-2010
kpeter@601
     6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
kpeter@601
     7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
kpeter@601
     8
 *
kpeter@601
     9
 * Permission to use, modify and distribute this software is granted
kpeter@601
    10
 * provided that this copyright notice appears in all copies. For
kpeter@601
    11
 * precise terms see the accompanying LICENSE file.
kpeter@601
    12
 *
kpeter@601
    13
 * This software is provided "AS IS" with no warranty of any kind,
kpeter@601
    14
 * express or implied, and with no claim as to its suitability for any
kpeter@601
    15
 * purpose.
kpeter@601
    16
 *
kpeter@601
    17
 */
kpeter@601
    18
kpeter@601
    19
#include <iostream>
kpeter@601
    20
#include <fstream>
kpeter@640
    21
#include <limits>
kpeter@601
    22
kpeter@601
    23
#include <lemon/list_graph.h>
kpeter@601
    24
#include <lemon/lgf_reader.h>
kpeter@601
    25
kpeter@601
    26
#include <lemon/network_simplex.h>
kpeter@819
    27
#include <lemon/capacity_scaling.h>
kpeter@819
    28
#include <lemon/cost_scaling.h>
kpeter@819
    29
#include <lemon/cycle_canceling.h>
kpeter@601
    30
kpeter@601
    31
#include <lemon/concepts/digraph.h>
kpeter@819
    32
#include <lemon/concepts/heap.h>
kpeter@601
    33
#include <lemon/concept_check.h>
kpeter@601
    34
kpeter@601
    35
#include "test_tools.h"
kpeter@601
    36
kpeter@601
    37
using namespace lemon;
kpeter@601
    38
kpeter@818
    39
// Test networks
kpeter@601
    40
char test_lgf[] =
kpeter@601
    41
  "@nodes\n"
kpeter@640
    42
  "label  sup1 sup2 sup3 sup4 sup5 sup6\n"
kpeter@640
    43
  "    1    20   27    0   30   20   30\n"
kpeter@640
    44
  "    2    -4    0    0    0   -8   -3\n"
kpeter@640
    45
  "    3     0    0    0    0    0    0\n"
kpeter@640
    46
  "    4     0    0    0    0    0    0\n"
kpeter@640
    47
  "    5     9    0    0    0    6   11\n"
kpeter@640
    48
  "    6    -6    0    0    0   -5   -6\n"
kpeter@640
    49
  "    7     0    0    0    0    0    0\n"
kpeter@640
    50
  "    8     0    0    0    0    0    3\n"
kpeter@640
    51
  "    9     3    0    0    0    0    0\n"
kpeter@640
    52
  "   10    -2    0    0    0   -7   -2\n"
kpeter@640
    53
  "   11     0    0    0    0  -10    0\n"
kpeter@640
    54
  "   12   -20  -27    0  -30  -30  -20\n"
alpar@877
    55
  "\n"
kpeter@601
    56
  "@arcs\n"
kpeter@640
    57
  "       cost  cap low1 low2 low3\n"
kpeter@640
    58
  " 1  2    70   11    0    8    8\n"
kpeter@640
    59
  " 1  3   150    3    0    1    0\n"
kpeter@640
    60
  " 1  4    80   15    0    2    2\n"
kpeter@640
    61
  " 2  8    80   12    0    0    0\n"
kpeter@640
    62
  " 3  5   140    5    0    3    1\n"
kpeter@640
    63
  " 4  6    60   10    0    1    0\n"
kpeter@640
    64
  " 4  7    80    2    0    0    0\n"
kpeter@640
    65
  " 4  8   110    3    0    0    0\n"
kpeter@640
    66
  " 5  7    60   14    0    0    0\n"
kpeter@640
    67
  " 5 11   120   12    0    0    0\n"
kpeter@640
    68
  " 6  3     0    3    0    0    0\n"
kpeter@640
    69
  " 6  9   140    4    0    0    0\n"
kpeter@640
    70
  " 6 10    90    8    0    0    0\n"
kpeter@640
    71
  " 7  1    30    5    0    0   -5\n"
kpeter@640
    72
  " 8 12    60   16    0    4    3\n"
kpeter@640
    73
  " 9 12    50    6    0    0    0\n"
kpeter@640
    74
  "10 12    70   13    0    5    2\n"
kpeter@640
    75
  "10  2   100    7    0    0    0\n"
kpeter@640
    76
  "10  7    60   10    0    0   -3\n"
kpeter@640
    77
  "11 10    20   14    0    6  -20\n"
kpeter@640
    78
  "12 11    30   10    0    0  -10\n"
kpeter@601
    79
  "\n"
kpeter@601
    80
  "@attributes\n"
kpeter@601
    81
  "source 1\n"
kpeter@601
    82
  "target 12\n";
kpeter@601
    83
kpeter@818
    84
char test_neg1_lgf[] =
kpeter@818
    85
  "@nodes\n"
kpeter@818
    86
  "label   sup\n"
kpeter@818
    87
  "    1   100\n"
kpeter@818
    88
  "    2     0\n"
kpeter@818
    89
  "    3     0\n"
kpeter@818
    90
  "    4  -100\n"
kpeter@818
    91
  "    5     0\n"
kpeter@818
    92
  "    6     0\n"
kpeter@818
    93
  "    7     0\n"
kpeter@818
    94
  "@arcs\n"
kpeter@818
    95
  "      cost   low1   low2\n"
kpeter@818
    96
  "1 2    100      0      0\n"
kpeter@818
    97
  "1 3     30      0      0\n"
kpeter@818
    98
  "2 4     20      0      0\n"
kpeter@818
    99
  "3 4     80      0      0\n"
kpeter@818
   100
  "3 2     50      0      0\n"
kpeter@818
   101
  "5 3     10      0      0\n"
kpeter@818
   102
  "5 6     80      0   1000\n"
kpeter@818
   103
  "6 7     30      0  -1000\n"
kpeter@818
   104
  "7 5   -120      0      0\n";
alpar@877
   105
kpeter@818
   106
char test_neg2_lgf[] =
kpeter@818
   107
  "@nodes\n"
kpeter@818
   108
  "label   sup\n"
kpeter@818
   109
  "    1   100\n"
kpeter@818
   110
  "    2  -300\n"
kpeter@818
   111
  "@arcs\n"
kpeter@818
   112
  "      cost\n"
kpeter@818
   113
  "1 2     -1\n";
kpeter@818
   114
kpeter@818
   115
kpeter@818
   116
// Test data
kpeter@818
   117
typedef ListDigraph Digraph;
kpeter@818
   118
DIGRAPH_TYPEDEFS(ListDigraph);
kpeter@818
   119
kpeter@818
   120
Digraph gr;
kpeter@818
   121
Digraph::ArcMap<int> c(gr), l1(gr), l2(gr), l3(gr), u(gr);
kpeter@818
   122
Digraph::NodeMap<int> s1(gr), s2(gr), s3(gr), s4(gr), s5(gr), s6(gr);
kpeter@818
   123
ConstMap<Arc, int> cc(1), cu(std::numeric_limits<int>::max());
kpeter@818
   124
Node v, w;
kpeter@818
   125
kpeter@818
   126
Digraph neg1_gr;
kpeter@818
   127
Digraph::ArcMap<int> neg1_c(neg1_gr), neg1_l1(neg1_gr), neg1_l2(neg1_gr);
kpeter@818
   128
ConstMap<Arc, int> neg1_u1(std::numeric_limits<int>::max()), neg1_u2(5000);
kpeter@818
   129
Digraph::NodeMap<int> neg1_s(neg1_gr);
kpeter@818
   130
kpeter@818
   131
Digraph neg2_gr;
kpeter@818
   132
Digraph::ArcMap<int> neg2_c(neg2_gr);
kpeter@818
   133
ConstMap<Arc, int> neg2_l(0), neg2_u(1000);
kpeter@818
   134
Digraph::NodeMap<int> neg2_s(neg2_gr);
kpeter@818
   135
kpeter@601
   136
kpeter@640
   137
enum SupplyType {
kpeter@609
   138
  EQ,
kpeter@609
   139
  GEQ,
kpeter@609
   140
  LEQ
kpeter@609
   141
};
kpeter@609
   142
kpeter@818
   143
kpeter@601
   144
// Check the interface of an MCF algorithm
kpeter@642
   145
template <typename GR, typename Value, typename Cost>
kpeter@601
   146
class McfClassConcept
kpeter@601
   147
{
kpeter@601
   148
public:
kpeter@601
   149
kpeter@601
   150
  template <typename MCF>
kpeter@601
   151
  struct Constraints {
kpeter@601
   152
    void constraints() {
kpeter@601
   153
      checkConcept<concepts::Digraph, GR>();
alpar@877
   154
kpeter@669
   155
      const Constraints& me = *this;
kpeter@601
   156
kpeter@669
   157
      MCF mcf(me.g);
kpeter@642
   158
      const MCF& const_mcf = mcf;
kpeter@601
   159
kpeter@830
   160
      b = mcf.reset().resetParams()
kpeter@669
   161
             .lowerMap(me.lower)
kpeter@669
   162
             .upperMap(me.upper)
kpeter@669
   163
             .costMap(me.cost)
kpeter@669
   164
             .supplyMap(me.sup)
kpeter@669
   165
             .stSupply(me.n, me.n, me.k)
kpeter@605
   166
             .run();
kpeter@605
   167
kpeter@640
   168
      c = const_mcf.totalCost();
kpeter@642
   169
      x = const_mcf.template totalCost<double>();
kpeter@669
   170
      v = const_mcf.flow(me.a);
kpeter@669
   171
      c = const_mcf.potential(me.n);
kpeter@642
   172
      const_mcf.flowMap(fm);
kpeter@642
   173
      const_mcf.potentialMap(pm);
kpeter@601
   174
    }
kpeter@601
   175
kpeter@601
   176
    typedef typename GR::Node Node;
kpeter@601
   177
    typedef typename GR::Arc Arc;
kpeter@642
   178
    typedef concepts::ReadMap<Node, Value> NM;
kpeter@642
   179
    typedef concepts::ReadMap<Arc, Value> VAM;
kpeter@607
   180
    typedef concepts::ReadMap<Arc, Cost> CAM;
kpeter@642
   181
    typedef concepts::WriteMap<Arc, Value> FlowMap;
kpeter@642
   182
    typedef concepts::WriteMap<Node, Cost> PotMap;
alpar@877
   183
kpeter@669
   184
    GR g;
kpeter@669
   185
    VAM lower;
kpeter@669
   186
    VAM upper;
kpeter@669
   187
    CAM cost;
kpeter@669
   188
    NM sup;
kpeter@669
   189
    Node n;
kpeter@669
   190
    Arc a;
kpeter@669
   191
    Value k;
kpeter@601
   192
kpeter@642
   193
    FlowMap fm;
kpeter@642
   194
    PotMap pm;
kpeter@605
   195
    bool b;
kpeter@642
   196
    double x;
kpeter@642
   197
    typename MCF::Value v;
kpeter@642
   198
    typename MCF::Cost c;
kpeter@601
   199
  };
kpeter@601
   200
kpeter@601
   201
};
kpeter@601
   202
kpeter@601
   203
kpeter@601
   204
// Check the feasibility of the given flow (primal soluiton)
kpeter@601
   205
template < typename GR, typename LM, typename UM,
kpeter@601
   206
           typename SM, typename FM >
kpeter@601
   207
bool checkFlow( const GR& gr, const LM& lower, const UM& upper,
kpeter@609
   208
                const SM& supply, const FM& flow,
kpeter@640
   209
                SupplyType type = EQ )
kpeter@601
   210
{
kpeter@601
   211
  TEMPLATE_DIGRAPH_TYPEDEFS(GR);
kpeter@601
   212
kpeter@601
   213
  for (ArcIt e(gr); e != INVALID; ++e) {
kpeter@601
   214
    if (flow[e] < lower[e] || flow[e] > upper[e]) return false;
kpeter@601
   215
  }
kpeter@601
   216
kpeter@601
   217
  for (NodeIt n(gr); n != INVALID; ++n) {
kpeter@601
   218
    typename SM::Value sum = 0;
kpeter@601
   219
    for (OutArcIt e(gr, n); e != INVALID; ++e)
kpeter@601
   220
      sum += flow[e];
kpeter@601
   221
    for (InArcIt e(gr, n); e != INVALID; ++e)
kpeter@601
   222
      sum -= flow[e];
kpeter@609
   223
    bool b = (type ==  EQ && sum == supply[n]) ||
kpeter@609
   224
             (type == GEQ && sum >= supply[n]) ||
kpeter@609
   225
             (type == LEQ && sum <= supply[n]);
kpeter@609
   226
    if (!b) return false;
kpeter@601
   227
  }
kpeter@601
   228
kpeter@601
   229
  return true;
kpeter@601
   230
}
kpeter@601
   231
kpeter@601
   232
// Check the feasibility of the given potentials (dual soluiton)
kpeter@605
   233
// using the "Complementary Slackness" optimality condition
kpeter@601
   234
template < typename GR, typename LM, typename UM,
kpeter@609
   235
           typename CM, typename SM, typename FM, typename PM >
kpeter@601
   236
bool checkPotential( const GR& gr, const LM& lower, const UM& upper,
alpar@877
   237
                     const CM& cost, const SM& supply, const FM& flow,
kpeter@664
   238
                     const PM& pi, SupplyType type )
kpeter@601
   239
{
kpeter@601
   240
  TEMPLATE_DIGRAPH_TYPEDEFS(GR);
kpeter@601
   241
kpeter@601
   242
  bool opt = true;
kpeter@601
   243
  for (ArcIt e(gr); opt && e != INVALID; ++e) {
kpeter@601
   244
    typename CM::Value red_cost =
kpeter@601
   245
      cost[e] + pi[gr.source(e)] - pi[gr.target(e)];
kpeter@601
   246
    opt = red_cost == 0 ||
kpeter@601
   247
          (red_cost > 0 && flow[e] == lower[e]) ||
kpeter@601
   248
          (red_cost < 0 && flow[e] == upper[e]);
kpeter@601
   249
  }
alpar@877
   250
kpeter@609
   251
  for (NodeIt n(gr); opt && n != INVALID; ++n) {
kpeter@609
   252
    typename SM::Value sum = 0;
kpeter@609
   253
    for (OutArcIt e(gr, n); e != INVALID; ++e)
kpeter@609
   254
      sum += flow[e];
kpeter@609
   255
    for (InArcIt e(gr, n); e != INVALID; ++e)
kpeter@609
   256
      sum -= flow[e];
kpeter@664
   257
    if (type != LEQ) {
kpeter@664
   258
      opt = (pi[n] <= 0) && (sum == supply[n] || pi[n] == 0);
kpeter@664
   259
    } else {
kpeter@664
   260
      opt = (pi[n] >= 0) && (sum == supply[n] || pi[n] == 0);
kpeter@664
   261
    }
kpeter@609
   262
  }
alpar@877
   263
kpeter@601
   264
  return opt;
kpeter@601
   265
}
kpeter@601
   266
kpeter@664
   267
// Check whether the dual cost is equal to the primal cost
kpeter@664
   268
template < typename GR, typename LM, typename UM,
kpeter@664
   269
           typename CM, typename SM, typename PM >
kpeter@664
   270
bool checkDualCost( const GR& gr, const LM& lower, const UM& upper,
kpeter@664
   271
                    const CM& cost, const SM& supply, const PM& pi,
kpeter@664
   272
                    typename CM::Value total )
kpeter@664
   273
{
kpeter@664
   274
  TEMPLATE_DIGRAPH_TYPEDEFS(GR);
kpeter@664
   275
kpeter@664
   276
  typename CM::Value dual_cost = 0;
kpeter@664
   277
  SM red_supply(gr);
kpeter@664
   278
  for (NodeIt n(gr); n != INVALID; ++n) {
kpeter@664
   279
    red_supply[n] = supply[n];
kpeter@664
   280
  }
kpeter@664
   281
  for (ArcIt a(gr); a != INVALID; ++a) {
kpeter@664
   282
    if (lower[a] != 0) {
kpeter@664
   283
      dual_cost += lower[a] * cost[a];
kpeter@664
   284
      red_supply[gr.source(a)] -= lower[a];
kpeter@664
   285
      red_supply[gr.target(a)] += lower[a];
kpeter@664
   286
    }
kpeter@664
   287
  }
alpar@877
   288
kpeter@664
   289
  for (NodeIt n(gr); n != INVALID; ++n) {
kpeter@664
   290
    dual_cost -= red_supply[n] * pi[n];
kpeter@664
   291
  }
kpeter@664
   292
  for (ArcIt a(gr); a != INVALID; ++a) {
kpeter@664
   293
    typename CM::Value red_cost =
kpeter@664
   294
      cost[a] + pi[gr.source(a)] - pi[gr.target(a)];
kpeter@664
   295
    dual_cost -= (upper[a] - lower[a]) * std::max(-red_cost, 0);
kpeter@664
   296
  }
alpar@877
   297
kpeter@664
   298
  return dual_cost == total;
kpeter@664
   299
}
kpeter@664
   300
kpeter@601
   301
// Run a minimum cost flow algorithm and check the results
kpeter@601
   302
template < typename MCF, typename GR,
kpeter@601
   303
           typename LM, typename UM,
kpeter@640
   304
           typename CM, typename SM,
kpeter@640
   305
           typename PT >
kpeter@640
   306
void checkMcf( const MCF& mcf, PT mcf_result,
kpeter@601
   307
               const GR& gr, const LM& lower, const UM& upper,
kpeter@601
   308
               const CM& cost, const SM& supply,
kpeter@640
   309
               PT result, bool optimal, typename CM::Value total,
kpeter@609
   310
               const std::string &test_id = "",
kpeter@640
   311
               SupplyType type = EQ )
kpeter@601
   312
{
kpeter@601
   313
  check(mcf_result == result, "Wrong result " + test_id);
kpeter@640
   314
  if (optimal) {
kpeter@642
   315
    typename GR::template ArcMap<typename SM::Value> flow(gr);
kpeter@642
   316
    typename GR::template NodeMap<typename CM::Value> pi(gr);
kpeter@642
   317
    mcf.flowMap(flow);
kpeter@642
   318
    mcf.potentialMap(pi);
kpeter@642
   319
    check(checkFlow(gr, lower, upper, supply, flow, type),
kpeter@601
   320
          "The flow is not feasible " + test_id);
kpeter@601
   321
    check(mcf.totalCost() == total, "The flow is not optimal " + test_id);
kpeter@664
   322
    check(checkPotential(gr, lower, upper, cost, supply, flow, pi, type),
kpeter@601
   323
          "Wrong potentials " + test_id);
kpeter@664
   324
    check(checkDualCost(gr, lower, upper, cost, supply, pi, total),
kpeter@664
   325
          "Wrong dual cost " + test_id);
kpeter@601
   326
  }
kpeter@601
   327
}
kpeter@601
   328
kpeter@818
   329
template < typename MCF, typename Param >
kpeter@818
   330
void runMcfGeqTests( Param param,
kpeter@818
   331
                     const std::string &test_str = "",
kpeter@818
   332
                     bool full_neg_cost_support = false )
kpeter@818
   333
{
kpeter@818
   334
  MCF mcf1(gr), mcf2(neg1_gr), mcf3(neg2_gr);
alpar@877
   335
kpeter@818
   336
  // Basic tests
kpeter@818
   337
  mcf1.upperMap(u).costMap(c).supplyMap(s1);
kpeter@818
   338
  checkMcf(mcf1, mcf1.run(param), gr, l1, u, c, s1,
kpeter@818
   339
           mcf1.OPTIMAL, true,     5240, test_str + "-1");
kpeter@818
   340
  mcf1.stSupply(v, w, 27);
kpeter@818
   341
  checkMcf(mcf1, mcf1.run(param), gr, l1, u, c, s2,
kpeter@818
   342
           mcf1.OPTIMAL, true,     7620, test_str + "-2");
kpeter@818
   343
  mcf1.lowerMap(l2).supplyMap(s1);
kpeter@818
   344
  checkMcf(mcf1, mcf1.run(param), gr, l2, u, c, s1,
kpeter@818
   345
           mcf1.OPTIMAL, true,     5970, test_str + "-3");
kpeter@818
   346
  mcf1.stSupply(v, w, 27);
kpeter@818
   347
  checkMcf(mcf1, mcf1.run(param), gr, l2, u, c, s2,
kpeter@818
   348
           mcf1.OPTIMAL, true,     8010, test_str + "-4");
kpeter@830
   349
  mcf1.resetParams().supplyMap(s1);
kpeter@818
   350
  checkMcf(mcf1, mcf1.run(param), gr, l1, cu, cc, s1,
kpeter@818
   351
           mcf1.OPTIMAL, true,       74, test_str + "-5");
kpeter@818
   352
  mcf1.lowerMap(l2).stSupply(v, w, 27);
kpeter@818
   353
  checkMcf(mcf1, mcf1.run(param), gr, l2, cu, cc, s2,
kpeter@818
   354
           mcf1.OPTIMAL, true,       94, test_str + "-6");
kpeter@818
   355
  mcf1.reset();
kpeter@818
   356
  checkMcf(mcf1, mcf1.run(param), gr, l1, cu, cc, s3,
kpeter@818
   357
           mcf1.OPTIMAL, true,        0, test_str + "-7");
kpeter@818
   358
  mcf1.lowerMap(l2).upperMap(u);
kpeter@818
   359
  checkMcf(mcf1, mcf1.run(param), gr, l2, u, cc, s3,
kpeter@818
   360
           mcf1.INFEASIBLE, false,    0, test_str + "-8");
kpeter@818
   361
  mcf1.lowerMap(l3).upperMap(u).costMap(c).supplyMap(s4);
kpeter@818
   362
  checkMcf(mcf1, mcf1.run(param), gr, l3, u, c, s4,
kpeter@818
   363
           mcf1.OPTIMAL, true,     6360, test_str + "-9");
kpeter@818
   364
kpeter@818
   365
  // Tests for the GEQ form
kpeter@830
   366
  mcf1.resetParams().upperMap(u).costMap(c).supplyMap(s5);
kpeter@818
   367
  checkMcf(mcf1, mcf1.run(param), gr, l1, u, c, s5,
kpeter@818
   368
           mcf1.OPTIMAL, true,     3530, test_str + "-10", GEQ);
kpeter@818
   369
  mcf1.lowerMap(l2);
kpeter@818
   370
  checkMcf(mcf1, mcf1.run(param), gr, l2, u, c, s5,
kpeter@818
   371
           mcf1.OPTIMAL, true,     4540, test_str + "-11", GEQ);
kpeter@818
   372
  mcf1.supplyMap(s6);
kpeter@818
   373
  checkMcf(mcf1, mcf1.run(param), gr, l2, u, c, s6,
kpeter@818
   374
           mcf1.INFEASIBLE, false,    0, test_str + "-12", GEQ);
kpeter@818
   375
kpeter@818
   376
  // Tests with negative costs
kpeter@818
   377
  mcf2.lowerMap(neg1_l1).costMap(neg1_c).supplyMap(neg1_s);
kpeter@818
   378
  checkMcf(mcf2, mcf2.run(param), neg1_gr, neg1_l1, neg1_u1, neg1_c, neg1_s,
kpeter@818
   379
           mcf2.UNBOUNDED, false,     0, test_str + "-13");
kpeter@818
   380
  mcf2.upperMap(neg1_u2);
kpeter@818
   381
  checkMcf(mcf2, mcf2.run(param), neg1_gr, neg1_l1, neg1_u2, neg1_c, neg1_s,
kpeter@818
   382
           mcf2.OPTIMAL, true,   -40000, test_str + "-14");
kpeter@830
   383
  mcf2.resetParams().lowerMap(neg1_l2).costMap(neg1_c).supplyMap(neg1_s);
kpeter@818
   384
  checkMcf(mcf2, mcf2.run(param), neg1_gr, neg1_l2, neg1_u1, neg1_c, neg1_s,
kpeter@818
   385
           mcf2.UNBOUNDED, false,     0, test_str + "-15");
kpeter@818
   386
kpeter@818
   387
  mcf3.costMap(neg2_c).supplyMap(neg2_s);
kpeter@818
   388
  if (full_neg_cost_support) {
kpeter@818
   389
    checkMcf(mcf3, mcf3.run(param), neg2_gr, neg2_l, neg2_u, neg2_c, neg2_s,
kpeter@818
   390
             mcf3.OPTIMAL, true,   -300, test_str + "-16", GEQ);
kpeter@818
   391
  } else {
kpeter@818
   392
    checkMcf(mcf3, mcf3.run(param), neg2_gr, neg2_l, neg2_u, neg2_c, neg2_s,
kpeter@818
   393
             mcf3.UNBOUNDED, false,   0, test_str + "-17", GEQ);
kpeter@818
   394
  }
kpeter@818
   395
  mcf3.upperMap(neg2_u);
kpeter@818
   396
  checkMcf(mcf3, mcf3.run(param), neg2_gr, neg2_l, neg2_u, neg2_c, neg2_s,
kpeter@818
   397
           mcf3.OPTIMAL, true,     -300, test_str + "-18", GEQ);
kpeter@818
   398
}
kpeter@818
   399
kpeter@818
   400
template < typename MCF, typename Param >
kpeter@818
   401
void runMcfLeqTests( Param param,
kpeter@818
   402
                     const std::string &test_str = "" )
kpeter@818
   403
{
kpeter@818
   404
  // Tests for the LEQ form
kpeter@818
   405
  MCF mcf1(gr);
kpeter@818
   406
  mcf1.supplyType(mcf1.LEQ);
kpeter@818
   407
  mcf1.upperMap(u).costMap(c).supplyMap(s6);
kpeter@818
   408
  checkMcf(mcf1, mcf1.run(param), gr, l1, u, c, s6,
kpeter@818
   409
           mcf1.OPTIMAL, true,   5080, test_str + "-19", LEQ);
kpeter@818
   410
  mcf1.lowerMap(l2);
kpeter@818
   411
  checkMcf(mcf1, mcf1.run(param), gr, l2, u, c, s6,
kpeter@818
   412
           mcf1.OPTIMAL, true,   5930, test_str + "-20", LEQ);
kpeter@818
   413
  mcf1.supplyMap(s5);
kpeter@818
   414
  checkMcf(mcf1, mcf1.run(param), gr, l2, u, c, s5,
kpeter@818
   415
           mcf1.INFEASIBLE, false,  0, test_str + "-21", LEQ);
kpeter@818
   416
}
kpeter@818
   417
kpeter@818
   418
kpeter@601
   419
int main()
kpeter@601
   420
{
kpeter@818
   421
  // Read the test networks
kpeter@601
   422
  std::istringstream input(test_lgf);
kpeter@601
   423
  DigraphReader<Digraph>(gr, input)
kpeter@601
   424
    .arcMap("cost", c)
kpeter@601
   425
    .arcMap("cap", u)
kpeter@601
   426
    .arcMap("low1", l1)
kpeter@601
   427
    .arcMap("low2", l2)
kpeter@640
   428
    .arcMap("low3", l3)
kpeter@601
   429
    .nodeMap("sup1", s1)
kpeter@601
   430
    .nodeMap("sup2", s2)
kpeter@601
   431
    .nodeMap("sup3", s3)
kpeter@609
   432
    .nodeMap("sup4", s4)
kpeter@609
   433
    .nodeMap("sup5", s5)
kpeter@640
   434
    .nodeMap("sup6", s6)
kpeter@601
   435
    .node("source", v)
kpeter@601
   436
    .node("target", w)
kpeter@601
   437
    .run();
alpar@877
   438
kpeter@818
   439
  std::istringstream neg_inp1(test_neg1_lgf);
kpeter@818
   440
  DigraphReader<Digraph>(neg1_gr, neg_inp1)
kpeter@818
   441
    .arcMap("cost", neg1_c)
kpeter@818
   442
    .arcMap("low1", neg1_l1)
kpeter@818
   443
    .arcMap("low2", neg1_l2)
kpeter@818
   444
    .nodeMap("sup", neg1_s)
kpeter@818
   445
    .run();
alpar@877
   446
kpeter@818
   447
  std::istringstream neg_inp2(test_neg2_lgf);
kpeter@818
   448
  DigraphReader<Digraph>(neg2_gr, neg_inp2)
kpeter@818
   449
    .arcMap("cost", neg2_c)
kpeter@818
   450
    .nodeMap("sup", neg2_s)
kpeter@818
   451
    .run();
alpar@877
   452
kpeter@818
   453
  // Check the interface of NetworkSimplex
kpeter@601
   454
  {
kpeter@818
   455
    typedef concepts::Digraph GR;
kpeter@818
   456
    checkConcept< McfClassConcept<GR, int, int>,
kpeter@818
   457
                  NetworkSimplex<GR> >();
kpeter@818
   458
    checkConcept< McfClassConcept<GR, double, double>,
kpeter@818
   459
                  NetworkSimplex<GR, double> >();
kpeter@818
   460
    checkConcept< McfClassConcept<GR, int, double>,
kpeter@818
   461
                  NetworkSimplex<GR, int, double> >();
kpeter@601
   462
  }
kpeter@601
   463
kpeter@819
   464
  // Check the interface of CapacityScaling
kpeter@819
   465
  {
kpeter@819
   466
    typedef concepts::Digraph GR;
kpeter@819
   467
    checkConcept< McfClassConcept<GR, int, int>,
kpeter@819
   468
                  CapacityScaling<GR> >();
kpeter@819
   469
    checkConcept< McfClassConcept<GR, double, double>,
kpeter@819
   470
                  CapacityScaling<GR, double> >();
kpeter@819
   471
    checkConcept< McfClassConcept<GR, int, double>,
kpeter@819
   472
                  CapacityScaling<GR, int, double> >();
kpeter@819
   473
    typedef CapacityScaling<GR>::
kpeter@819
   474
      SetHeap<concepts::Heap<int, RangeMap<int> > >::Create CAS;
kpeter@819
   475
    checkConcept< McfClassConcept<GR, int, int>, CAS >();
kpeter@819
   476
  }
kpeter@819
   477
kpeter@819
   478
  // Check the interface of CostScaling
kpeter@819
   479
  {
kpeter@819
   480
    typedef concepts::Digraph GR;
kpeter@819
   481
    checkConcept< McfClassConcept<GR, int, int>,
kpeter@819
   482
                  CostScaling<GR> >();
kpeter@819
   483
    checkConcept< McfClassConcept<GR, double, double>,
kpeter@819
   484
                  CostScaling<GR, double> >();
kpeter@819
   485
    checkConcept< McfClassConcept<GR, int, double>,
kpeter@819
   486
                  CostScaling<GR, int, double> >();
kpeter@819
   487
    typedef CostScaling<GR>::
kpeter@819
   488
      SetLargeCost<double>::Create COS;
kpeter@819
   489
    checkConcept< McfClassConcept<GR, int, int>, COS >();
kpeter@819
   490
  }
kpeter@819
   491
kpeter@819
   492
  // Check the interface of CycleCanceling
kpeter@819
   493
  {
kpeter@819
   494
    typedef concepts::Digraph GR;
kpeter@819
   495
    checkConcept< McfClassConcept<GR, int, int>,
kpeter@819
   496
                  CycleCanceling<GR> >();
kpeter@819
   497
    checkConcept< McfClassConcept<GR, double, double>,
kpeter@819
   498
                  CycleCanceling<GR, double> >();
kpeter@819
   499
    checkConcept< McfClassConcept<GR, int, double>,
kpeter@819
   500
                  CycleCanceling<GR, int, double> >();
kpeter@819
   501
  }
kpeter@819
   502
kpeter@818
   503
  // Test NetworkSimplex
alpar@877
   504
  {
kpeter@818
   505
    typedef NetworkSimplex<Digraph> MCF;
kpeter@818
   506
    runMcfGeqTests<MCF>(MCF::FIRST_ELIGIBLE, "NS-FE", true);
kpeter@818
   507
    runMcfLeqTests<MCF>(MCF::FIRST_ELIGIBLE, "NS-FE");
kpeter@818
   508
    runMcfGeqTests<MCF>(MCF::BEST_ELIGIBLE,  "NS-BE", true);
kpeter@818
   509
    runMcfLeqTests<MCF>(MCF::BEST_ELIGIBLE,  "NS-BE");
kpeter@818
   510
    runMcfGeqTests<MCF>(MCF::BLOCK_SEARCH,   "NS-BS", true);
kpeter@818
   511
    runMcfLeqTests<MCF>(MCF::BLOCK_SEARCH,   "NS-BS");
kpeter@818
   512
    runMcfGeqTests<MCF>(MCF::CANDIDATE_LIST, "NS-CL", true);
kpeter@818
   513
    runMcfLeqTests<MCF>(MCF::CANDIDATE_LIST, "NS-CL");
kpeter@818
   514
    runMcfGeqTests<MCF>(MCF::ALTERING_LIST,  "NS-AL", true);
kpeter@818
   515
    runMcfLeqTests<MCF>(MCF::ALTERING_LIST,  "NS-AL");
kpeter@601
   516
  }
alpar@877
   517
kpeter@819
   518
  // Test CapacityScaling
kpeter@819
   519
  {
kpeter@819
   520
    typedef CapacityScaling<Digraph> MCF;
kpeter@819
   521
    runMcfGeqTests<MCF>(0, "SSP");
kpeter@819
   522
    runMcfGeqTests<MCF>(2, "CAS");
kpeter@819
   523
  }
kpeter@819
   524
kpeter@819
   525
  // Test CostScaling
kpeter@819
   526
  {
kpeter@819
   527
    typedef CostScaling<Digraph> MCF;
kpeter@819
   528
    runMcfGeqTests<MCF>(MCF::PUSH, "COS-PR");
kpeter@819
   529
    runMcfGeqTests<MCF>(MCF::AUGMENT, "COS-AR");
kpeter@819
   530
    runMcfGeqTests<MCF>(MCF::PARTIAL_AUGMENT, "COS-PAR");
kpeter@819
   531
  }
kpeter@819
   532
kpeter@819
   533
  // Test CycleCanceling
kpeter@819
   534
  {
kpeter@819
   535
    typedef CycleCanceling<Digraph> MCF;
kpeter@819
   536
    runMcfGeqTests<MCF>(MCF::SIMPLE_CYCLE_CANCELING, "SCC");
kpeter@819
   537
    runMcfGeqTests<MCF>(MCF::MINIMUM_MEAN_CYCLE_CANCELING, "MMCC");
kpeter@819
   538
    runMcfGeqTests<MCF>(MCF::CANCEL_AND_TIGHTEN, "CAT");
kpeter@819
   539
  }
kpeter@601
   540
kpeter@601
   541
  return 0;
kpeter@601
   542
}