test/min_cost_flow_test.cc
author Peter Kovacs <kpeter@inf.elte.hu>
Thu, 12 Nov 2009 23:26:13 +0100
changeset 806 fa6f37d7a25b
parent 664 cc61d09f053b
child 818 bc75ee2ad082
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@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
 *
kpeter@601
     5
 * Copyright (C) 2003-2009
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@601
    27
kpeter@601
    28
#include <lemon/concepts/digraph.h>
kpeter@601
    29
#include <lemon/concept_check.h>
kpeter@601
    30
kpeter@601
    31
#include "test_tools.h"
kpeter@601
    32
kpeter@601
    33
using namespace lemon;
kpeter@601
    34
kpeter@601
    35
char test_lgf[] =
kpeter@601
    36
  "@nodes\n"
kpeter@640
    37
  "label  sup1 sup2 sup3 sup4 sup5 sup6\n"
kpeter@640
    38
  "    1    20   27    0   30   20   30\n"
kpeter@640
    39
  "    2    -4    0    0    0   -8   -3\n"
kpeter@640
    40
  "    3     0    0    0    0    0    0\n"
kpeter@640
    41
  "    4     0    0    0    0    0    0\n"
kpeter@640
    42
  "    5     9    0    0    0    6   11\n"
kpeter@640
    43
  "    6    -6    0    0    0   -5   -6\n"
kpeter@640
    44
  "    7     0    0    0    0    0    0\n"
kpeter@640
    45
  "    8     0    0    0    0    0    3\n"
kpeter@640
    46
  "    9     3    0    0    0    0    0\n"
kpeter@640
    47
  "   10    -2    0    0    0   -7   -2\n"
kpeter@640
    48
  "   11     0    0    0    0  -10    0\n"
kpeter@640
    49
  "   12   -20  -27    0  -30  -30  -20\n"
kpeter@640
    50
  "\n"                
kpeter@601
    51
  "@arcs\n"
kpeter@640
    52
  "       cost  cap low1 low2 low3\n"
kpeter@640
    53
  " 1  2    70   11    0    8    8\n"
kpeter@640
    54
  " 1  3   150    3    0    1    0\n"
kpeter@640
    55
  " 1  4    80   15    0    2    2\n"
kpeter@640
    56
  " 2  8    80   12    0    0    0\n"
kpeter@640
    57
  " 3  5   140    5    0    3    1\n"
kpeter@640
    58
  " 4  6    60   10    0    1    0\n"
kpeter@640
    59
  " 4  7    80    2    0    0    0\n"
kpeter@640
    60
  " 4  8   110    3    0    0    0\n"
kpeter@640
    61
  " 5  7    60   14    0    0    0\n"
kpeter@640
    62
  " 5 11   120   12    0    0    0\n"
kpeter@640
    63
  " 6  3     0    3    0    0    0\n"
kpeter@640
    64
  " 6  9   140    4    0    0    0\n"
kpeter@640
    65
  " 6 10    90    8    0    0    0\n"
kpeter@640
    66
  " 7  1    30    5    0    0   -5\n"
kpeter@640
    67
  " 8 12    60   16    0    4    3\n"
kpeter@640
    68
  " 9 12    50    6    0    0    0\n"
kpeter@640
    69
  "10 12    70   13    0    5    2\n"
kpeter@640
    70
  "10  2   100    7    0    0    0\n"
kpeter@640
    71
  "10  7    60   10    0    0   -3\n"
kpeter@640
    72
  "11 10    20   14    0    6  -20\n"
kpeter@640
    73
  "12 11    30   10    0    0  -10\n"
kpeter@601
    74
  "\n"
kpeter@601
    75
  "@attributes\n"
kpeter@601
    76
  "source 1\n"
kpeter@601
    77
  "target 12\n";
kpeter@601
    78
kpeter@601
    79
kpeter@640
    80
enum SupplyType {
kpeter@609
    81
  EQ,
kpeter@609
    82
  GEQ,
kpeter@609
    83
  LEQ
kpeter@609
    84
};
kpeter@609
    85
kpeter@601
    86
// Check the interface of an MCF algorithm
kpeter@642
    87
template <typename GR, typename Value, typename Cost>
kpeter@601
    88
class McfClassConcept
kpeter@601
    89
{
kpeter@601
    90
public:
kpeter@601
    91
kpeter@601
    92
  template <typename MCF>
kpeter@601
    93
  struct Constraints {
kpeter@601
    94
    void constraints() {
kpeter@601
    95
      checkConcept<concepts::Digraph, GR>();
kpeter@669
    96
      
kpeter@669
    97
      const Constraints& me = *this;
kpeter@601
    98
kpeter@669
    99
      MCF mcf(me.g);
kpeter@642
   100
      const MCF& const_mcf = mcf;
kpeter@601
   101
kpeter@606
   102
      b = mcf.reset()
kpeter@669
   103
             .lowerMap(me.lower)
kpeter@669
   104
             .upperMap(me.upper)
kpeter@669
   105
             .costMap(me.cost)
kpeter@669
   106
             .supplyMap(me.sup)
kpeter@669
   107
             .stSupply(me.n, me.n, me.k)
kpeter@605
   108
             .run();
kpeter@605
   109
kpeter@640
   110
      c = const_mcf.totalCost();
kpeter@642
   111
      x = const_mcf.template totalCost<double>();
kpeter@669
   112
      v = const_mcf.flow(me.a);
kpeter@669
   113
      c = const_mcf.potential(me.n);
kpeter@642
   114
      const_mcf.flowMap(fm);
kpeter@642
   115
      const_mcf.potentialMap(pm);
kpeter@601
   116
    }
kpeter@601
   117
kpeter@601
   118
    typedef typename GR::Node Node;
kpeter@601
   119
    typedef typename GR::Arc Arc;
kpeter@642
   120
    typedef concepts::ReadMap<Node, Value> NM;
kpeter@642
   121
    typedef concepts::ReadMap<Arc, Value> VAM;
kpeter@607
   122
    typedef concepts::ReadMap<Arc, Cost> CAM;
kpeter@642
   123
    typedef concepts::WriteMap<Arc, Value> FlowMap;
kpeter@642
   124
    typedef concepts::WriteMap<Node, Cost> PotMap;
kpeter@669
   125
  
kpeter@669
   126
    GR g;
kpeter@669
   127
    VAM lower;
kpeter@669
   128
    VAM upper;
kpeter@669
   129
    CAM cost;
kpeter@669
   130
    NM sup;
kpeter@669
   131
    Node n;
kpeter@669
   132
    Arc a;
kpeter@669
   133
    Value k;
kpeter@601
   134
kpeter@642
   135
    FlowMap fm;
kpeter@642
   136
    PotMap pm;
kpeter@605
   137
    bool b;
kpeter@642
   138
    double x;
kpeter@642
   139
    typename MCF::Value v;
kpeter@642
   140
    typename MCF::Cost c;
kpeter@601
   141
  };
kpeter@601
   142
kpeter@601
   143
};
kpeter@601
   144
kpeter@601
   145
kpeter@601
   146
// Check the feasibility of the given flow (primal soluiton)
kpeter@601
   147
template < typename GR, typename LM, typename UM,
kpeter@601
   148
           typename SM, typename FM >
kpeter@601
   149
bool checkFlow( const GR& gr, const LM& lower, const UM& upper,
kpeter@609
   150
                const SM& supply, const FM& flow,
kpeter@640
   151
                SupplyType type = EQ )
kpeter@601
   152
{
kpeter@601
   153
  TEMPLATE_DIGRAPH_TYPEDEFS(GR);
kpeter@601
   154
kpeter@601
   155
  for (ArcIt e(gr); e != INVALID; ++e) {
kpeter@601
   156
    if (flow[e] < lower[e] || flow[e] > upper[e]) return false;
kpeter@601
   157
  }
kpeter@601
   158
kpeter@601
   159
  for (NodeIt n(gr); n != INVALID; ++n) {
kpeter@601
   160
    typename SM::Value sum = 0;
kpeter@601
   161
    for (OutArcIt e(gr, n); e != INVALID; ++e)
kpeter@601
   162
      sum += flow[e];
kpeter@601
   163
    for (InArcIt e(gr, n); e != INVALID; ++e)
kpeter@601
   164
      sum -= flow[e];
kpeter@609
   165
    bool b = (type ==  EQ && sum == supply[n]) ||
kpeter@609
   166
             (type == GEQ && sum >= supply[n]) ||
kpeter@609
   167
             (type == LEQ && sum <= supply[n]);
kpeter@609
   168
    if (!b) return false;
kpeter@601
   169
  }
kpeter@601
   170
kpeter@601
   171
  return true;
kpeter@601
   172
}
kpeter@601
   173
kpeter@601
   174
// Check the feasibility of the given potentials (dual soluiton)
kpeter@605
   175
// using the "Complementary Slackness" optimality condition
kpeter@601
   176
template < typename GR, typename LM, typename UM,
kpeter@609
   177
           typename CM, typename SM, typename FM, typename PM >
kpeter@601
   178
bool checkPotential( const GR& gr, const LM& lower, const UM& upper,
kpeter@609
   179
                     const CM& cost, const SM& supply, const FM& flow, 
kpeter@664
   180
                     const PM& pi, SupplyType type )
kpeter@601
   181
{
kpeter@601
   182
  TEMPLATE_DIGRAPH_TYPEDEFS(GR);
kpeter@601
   183
kpeter@601
   184
  bool opt = true;
kpeter@601
   185
  for (ArcIt e(gr); opt && e != INVALID; ++e) {
kpeter@601
   186
    typename CM::Value red_cost =
kpeter@601
   187
      cost[e] + pi[gr.source(e)] - pi[gr.target(e)];
kpeter@601
   188
    opt = red_cost == 0 ||
kpeter@601
   189
          (red_cost > 0 && flow[e] == lower[e]) ||
kpeter@601
   190
          (red_cost < 0 && flow[e] == upper[e]);
kpeter@601
   191
  }
kpeter@609
   192
  
kpeter@609
   193
  for (NodeIt n(gr); opt && n != INVALID; ++n) {
kpeter@609
   194
    typename SM::Value sum = 0;
kpeter@609
   195
    for (OutArcIt e(gr, n); e != INVALID; ++e)
kpeter@609
   196
      sum += flow[e];
kpeter@609
   197
    for (InArcIt e(gr, n); e != INVALID; ++e)
kpeter@609
   198
      sum -= flow[e];
kpeter@664
   199
    if (type != LEQ) {
kpeter@664
   200
      opt = (pi[n] <= 0) && (sum == supply[n] || pi[n] == 0);
kpeter@664
   201
    } else {
kpeter@664
   202
      opt = (pi[n] >= 0) && (sum == supply[n] || pi[n] == 0);
kpeter@664
   203
    }
kpeter@609
   204
  }
kpeter@609
   205
  
kpeter@601
   206
  return opt;
kpeter@601
   207
}
kpeter@601
   208
kpeter@664
   209
// Check whether the dual cost is equal to the primal cost
kpeter@664
   210
template < typename GR, typename LM, typename UM,
kpeter@664
   211
           typename CM, typename SM, typename PM >
kpeter@664
   212
bool checkDualCost( const GR& gr, const LM& lower, const UM& upper,
kpeter@664
   213
                    const CM& cost, const SM& supply, const PM& pi,
kpeter@664
   214
                    typename CM::Value total )
kpeter@664
   215
{
kpeter@664
   216
  TEMPLATE_DIGRAPH_TYPEDEFS(GR);
kpeter@664
   217
kpeter@664
   218
  typename CM::Value dual_cost = 0;
kpeter@664
   219
  SM red_supply(gr);
kpeter@664
   220
  for (NodeIt n(gr); n != INVALID; ++n) {
kpeter@664
   221
    red_supply[n] = supply[n];
kpeter@664
   222
  }
kpeter@664
   223
  for (ArcIt a(gr); a != INVALID; ++a) {
kpeter@664
   224
    if (lower[a] != 0) {
kpeter@664
   225
      dual_cost += lower[a] * cost[a];
kpeter@664
   226
      red_supply[gr.source(a)] -= lower[a];
kpeter@664
   227
      red_supply[gr.target(a)] += lower[a];
kpeter@664
   228
    }
kpeter@664
   229
  }
kpeter@664
   230
  
kpeter@664
   231
  for (NodeIt n(gr); n != INVALID; ++n) {
kpeter@664
   232
    dual_cost -= red_supply[n] * pi[n];
kpeter@664
   233
  }
kpeter@664
   234
  for (ArcIt a(gr); a != INVALID; ++a) {
kpeter@664
   235
    typename CM::Value red_cost =
kpeter@664
   236
      cost[a] + pi[gr.source(a)] - pi[gr.target(a)];
kpeter@664
   237
    dual_cost -= (upper[a] - lower[a]) * std::max(-red_cost, 0);
kpeter@664
   238
  }
kpeter@664
   239
  
kpeter@664
   240
  return dual_cost == total;
kpeter@664
   241
}
kpeter@664
   242
kpeter@601
   243
// Run a minimum cost flow algorithm and check the results
kpeter@601
   244
template < typename MCF, typename GR,
kpeter@601
   245
           typename LM, typename UM,
kpeter@640
   246
           typename CM, typename SM,
kpeter@640
   247
           typename PT >
kpeter@640
   248
void checkMcf( const MCF& mcf, PT mcf_result,
kpeter@601
   249
               const GR& gr, const LM& lower, const UM& upper,
kpeter@601
   250
               const CM& cost, const SM& supply,
kpeter@640
   251
               PT result, bool optimal, typename CM::Value total,
kpeter@609
   252
               const std::string &test_id = "",
kpeter@640
   253
               SupplyType type = EQ )
kpeter@601
   254
{
kpeter@601
   255
  check(mcf_result == result, "Wrong result " + test_id);
kpeter@640
   256
  if (optimal) {
kpeter@642
   257
    typename GR::template ArcMap<typename SM::Value> flow(gr);
kpeter@642
   258
    typename GR::template NodeMap<typename CM::Value> pi(gr);
kpeter@642
   259
    mcf.flowMap(flow);
kpeter@642
   260
    mcf.potentialMap(pi);
kpeter@642
   261
    check(checkFlow(gr, lower, upper, supply, flow, type),
kpeter@601
   262
          "The flow is not feasible " + test_id);
kpeter@601
   263
    check(mcf.totalCost() == total, "The flow is not optimal " + test_id);
kpeter@664
   264
    check(checkPotential(gr, lower, upper, cost, supply, flow, pi, type),
kpeter@601
   265
          "Wrong potentials " + test_id);
kpeter@664
   266
    check(checkDualCost(gr, lower, upper, cost, supply, pi, total),
kpeter@664
   267
          "Wrong dual cost " + test_id);
kpeter@601
   268
  }
kpeter@601
   269
}
kpeter@601
   270
kpeter@601
   271
int main()
kpeter@601
   272
{
kpeter@601
   273
  // Check the interfaces
kpeter@601
   274
  {
kpeter@615
   275
    typedef concepts::Digraph GR;
kpeter@642
   276
    checkConcept< McfClassConcept<GR, int, int>,
kpeter@642
   277
                  NetworkSimplex<GR> >();
kpeter@642
   278
    checkConcept< McfClassConcept<GR, double, double>,
kpeter@642
   279
                  NetworkSimplex<GR, double> >();
kpeter@642
   280
    checkConcept< McfClassConcept<GR, int, double>,
kpeter@642
   281
                  NetworkSimplex<GR, int, double> >();
kpeter@601
   282
  }
kpeter@601
   283
kpeter@601
   284
  // Run various MCF tests
kpeter@601
   285
  typedef ListDigraph Digraph;
kpeter@601
   286
  DIGRAPH_TYPEDEFS(ListDigraph);
kpeter@601
   287
kpeter@601
   288
  // Read the test digraph
kpeter@601
   289
  Digraph gr;
kpeter@640
   290
  Digraph::ArcMap<int> c(gr), l1(gr), l2(gr), l3(gr), u(gr);
kpeter@640
   291
  Digraph::NodeMap<int> s1(gr), s2(gr), s3(gr), s4(gr), s5(gr), s6(gr);
kpeter@605
   292
  ConstMap<Arc, int> cc(1), cu(std::numeric_limits<int>::max());
kpeter@601
   293
  Node v, w;
kpeter@601
   294
kpeter@601
   295
  std::istringstream input(test_lgf);
kpeter@601
   296
  DigraphReader<Digraph>(gr, input)
kpeter@601
   297
    .arcMap("cost", c)
kpeter@601
   298
    .arcMap("cap", u)
kpeter@601
   299
    .arcMap("low1", l1)
kpeter@601
   300
    .arcMap("low2", l2)
kpeter@640
   301
    .arcMap("low3", l3)
kpeter@601
   302
    .nodeMap("sup1", s1)
kpeter@601
   303
    .nodeMap("sup2", s2)
kpeter@601
   304
    .nodeMap("sup3", s3)
kpeter@609
   305
    .nodeMap("sup4", s4)
kpeter@609
   306
    .nodeMap("sup5", s5)
kpeter@640
   307
    .nodeMap("sup6", s6)
kpeter@601
   308
    .node("source", v)
kpeter@601
   309
    .node("target", w)
kpeter@601
   310
    .run();
kpeter@640
   311
  
kpeter@664
   312
  // Build test digraphs with negative costs
kpeter@664
   313
  Digraph neg_gr;
kpeter@664
   314
  Node n1 = neg_gr.addNode();
kpeter@664
   315
  Node n2 = neg_gr.addNode();
kpeter@664
   316
  Node n3 = neg_gr.addNode();
kpeter@664
   317
  Node n4 = neg_gr.addNode();
kpeter@664
   318
  Node n5 = neg_gr.addNode();
kpeter@664
   319
  Node n6 = neg_gr.addNode();
kpeter@664
   320
  Node n7 = neg_gr.addNode();
kpeter@640
   321
  
kpeter@664
   322
  Arc a1 = neg_gr.addArc(n1, n2);
kpeter@664
   323
  Arc a2 = neg_gr.addArc(n1, n3);
kpeter@664
   324
  Arc a3 = neg_gr.addArc(n2, n4);
kpeter@664
   325
  Arc a4 = neg_gr.addArc(n3, n4);
kpeter@664
   326
  Arc a5 = neg_gr.addArc(n3, n2);
kpeter@664
   327
  Arc a6 = neg_gr.addArc(n5, n3);
kpeter@664
   328
  Arc a7 = neg_gr.addArc(n5, n6);
kpeter@664
   329
  Arc a8 = neg_gr.addArc(n6, n7);
kpeter@664
   330
  Arc a9 = neg_gr.addArc(n7, n5);
kpeter@640
   331
  
kpeter@664
   332
  Digraph::ArcMap<int> neg_c(neg_gr), neg_l1(neg_gr, 0), neg_l2(neg_gr, 0);
kpeter@664
   333
  ConstMap<Arc, int> neg_u1(std::numeric_limits<int>::max()), neg_u2(5000);
kpeter@664
   334
  Digraph::NodeMap<int> neg_s(neg_gr, 0);
kpeter@640
   335
  
kpeter@664
   336
  neg_l2[a7] =  1000;
kpeter@664
   337
  neg_l2[a8] = -1000;
kpeter@640
   338
  
kpeter@664
   339
  neg_s[n1] =  100;
kpeter@664
   340
  neg_s[n4] = -100;
kpeter@640
   341
  
kpeter@664
   342
  neg_c[a1] =  100;
kpeter@664
   343
  neg_c[a2] =   30;
kpeter@664
   344
  neg_c[a3] =   20;
kpeter@664
   345
  neg_c[a4] =   80;
kpeter@664
   346
  neg_c[a5] =   50;
kpeter@664
   347
  neg_c[a6] =   10;
kpeter@664
   348
  neg_c[a7] =   80;
kpeter@664
   349
  neg_c[a8] =   30;
kpeter@664
   350
  neg_c[a9] = -120;
kpeter@664
   351
kpeter@664
   352
  Digraph negs_gr;
kpeter@664
   353
  Digraph::NodeMap<int> negs_s(negs_gr);
kpeter@664
   354
  Digraph::ArcMap<int> negs_c(negs_gr);
kpeter@664
   355
  ConstMap<Arc, int> negs_l(0), negs_u(1000);
kpeter@664
   356
  n1 = negs_gr.addNode();
kpeter@664
   357
  n2 = negs_gr.addNode();
kpeter@664
   358
  negs_s[n1] = 100;
kpeter@664
   359
  negs_s[n2] = -300;
kpeter@664
   360
  negs_c[negs_gr.addArc(n1, n2)] = -1;
kpeter@664
   361
kpeter@601
   362
kpeter@605
   363
  // A. Test NetworkSimplex with the default pivot rule
kpeter@601
   364
  {
kpeter@606
   365
    NetworkSimplex<Digraph> mcf(gr);
kpeter@601
   366
kpeter@609
   367
    // Check the equality form
kpeter@606
   368
    mcf.upperMap(u).costMap(c);
kpeter@606
   369
    checkMcf(mcf, mcf.supplyMap(s1).run(),
kpeter@640
   370
             gr, l1, u, c, s1, mcf.OPTIMAL, true,   5240, "#A1");
kpeter@606
   371
    checkMcf(mcf, mcf.stSupply(v, w, 27).run(),
kpeter@640
   372
             gr, l1, u, c, s2, mcf.OPTIMAL, true,   7620, "#A2");
kpeter@606
   373
    mcf.lowerMap(l2);
kpeter@606
   374
    checkMcf(mcf, mcf.supplyMap(s1).run(),
kpeter@640
   375
             gr, l2, u, c, s1, mcf.OPTIMAL, true,   5970, "#A3");
kpeter@606
   376
    checkMcf(mcf, mcf.stSupply(v, w, 27).run(),
kpeter@640
   377
             gr, l2, u, c, s2, mcf.OPTIMAL, true,   8010, "#A4");
kpeter@606
   378
    mcf.reset();
kpeter@606
   379
    checkMcf(mcf, mcf.supplyMap(s1).run(),
kpeter@640
   380
             gr, l1, cu, cc, s1, mcf.OPTIMAL, true,   74, "#A5");
kpeter@606
   381
    checkMcf(mcf, mcf.lowerMap(l2).stSupply(v, w, 27).run(),
kpeter@640
   382
             gr, l2, cu, cc, s2, mcf.OPTIMAL, true,   94, "#A6");
kpeter@606
   383
    mcf.reset();
kpeter@606
   384
    checkMcf(mcf, mcf.run(),
kpeter@640
   385
             gr, l1, cu, cc, s3, mcf.OPTIMAL, true,    0, "#A7");
kpeter@640
   386
    checkMcf(mcf, mcf.lowerMap(l2).upperMap(u).run(),
kpeter@640
   387
             gr, l2, u, cc, s3, mcf.INFEASIBLE, false, 0, "#A8");
kpeter@640
   388
    mcf.reset().lowerMap(l3).upperMap(u).costMap(c).supplyMap(s4);
kpeter@640
   389
    checkMcf(mcf, mcf.run(),
kpeter@640
   390
             gr, l3, u, c, s4, mcf.OPTIMAL, true,   6360, "#A9");
kpeter@609
   391
kpeter@609
   392
    // Check the GEQ form
kpeter@640
   393
    mcf.reset().upperMap(u).costMap(c).supplyMap(s5);
kpeter@609
   394
    checkMcf(mcf, mcf.run(),
kpeter@640
   395
             gr, l1, u, c, s5, mcf.OPTIMAL, true,   3530, "#A10", GEQ);
kpeter@640
   396
    mcf.supplyType(mcf.GEQ);
kpeter@609
   397
    checkMcf(mcf, mcf.lowerMap(l2).run(),
kpeter@640
   398
             gr, l2, u, c, s5, mcf.OPTIMAL, true,   4540, "#A11", GEQ);
kpeter@664
   399
    mcf.supplyMap(s6);
kpeter@609
   400
    checkMcf(mcf, mcf.run(),
kpeter@640
   401
             gr, l2, u, c, s6, mcf.INFEASIBLE, false,  0, "#A12", GEQ);
kpeter@609
   402
kpeter@609
   403
    // Check the LEQ form
kpeter@640
   404
    mcf.reset().supplyType(mcf.LEQ);
kpeter@640
   405
    mcf.upperMap(u).costMap(c).supplyMap(s6);
kpeter@609
   406
    checkMcf(mcf, mcf.run(),
kpeter@640
   407
             gr, l1, u, c, s6, mcf.OPTIMAL, true,   5080, "#A13", LEQ);
kpeter@609
   408
    checkMcf(mcf, mcf.lowerMap(l2).run(),
kpeter@640
   409
             gr, l2, u, c, s6, mcf.OPTIMAL, true,   5930, "#A14", LEQ);
kpeter@664
   410
    mcf.supplyMap(s5);
kpeter@609
   411
    checkMcf(mcf, mcf.run(),
kpeter@640
   412
             gr, l2, u, c, s5, mcf.INFEASIBLE, false,  0, "#A15", LEQ);
kpeter@640
   413
kpeter@640
   414
    // Check negative costs
kpeter@664
   415
    NetworkSimplex<Digraph> neg_mcf(neg_gr);
kpeter@664
   416
    neg_mcf.lowerMap(neg_l1).costMap(neg_c).supplyMap(neg_s);
kpeter@664
   417
    checkMcf(neg_mcf, neg_mcf.run(), neg_gr, neg_l1, neg_u1,
kpeter@664
   418
      neg_c, neg_s, neg_mcf.UNBOUNDED, false,    0, "#A16");
kpeter@664
   419
    neg_mcf.upperMap(neg_u2);
kpeter@664
   420
    checkMcf(neg_mcf, neg_mcf.run(), neg_gr, neg_l1, neg_u2,
kpeter@664
   421
      neg_c, neg_s, neg_mcf.OPTIMAL, true,  -40000, "#A17");
kpeter@664
   422
    neg_mcf.reset().lowerMap(neg_l2).costMap(neg_c).supplyMap(neg_s);
kpeter@664
   423
    checkMcf(neg_mcf, neg_mcf.run(), neg_gr, neg_l2, neg_u1,
kpeter@664
   424
      neg_c, neg_s, neg_mcf.UNBOUNDED, false,    0, "#A18");
kpeter@664
   425
      
kpeter@664
   426
    NetworkSimplex<Digraph> negs_mcf(negs_gr);
kpeter@664
   427
    negs_mcf.costMap(negs_c).supplyMap(negs_s);
kpeter@664
   428
    checkMcf(negs_mcf, negs_mcf.run(), negs_gr, negs_l, negs_u,
kpeter@664
   429
      negs_c, negs_s, negs_mcf.OPTIMAL, true, -300, "#A19", GEQ);
kpeter@601
   430
  }
kpeter@601
   431
kpeter@605
   432
  // B. Test NetworkSimplex with each pivot rule
kpeter@601
   433
  {
kpeter@606
   434
    NetworkSimplex<Digraph> mcf(gr);
kpeter@640
   435
    mcf.supplyMap(s1).costMap(c).upperMap(u).lowerMap(l2);
kpeter@601
   436
kpeter@606
   437
    checkMcf(mcf, mcf.run(NetworkSimplex<Digraph>::FIRST_ELIGIBLE),
kpeter@640
   438
             gr, l2, u, c, s1, mcf.OPTIMAL, true,   5970, "#B1");
kpeter@606
   439
    checkMcf(mcf, mcf.run(NetworkSimplex<Digraph>::BEST_ELIGIBLE),
kpeter@640
   440
             gr, l2, u, c, s1, mcf.OPTIMAL, true,   5970, "#B2");
kpeter@606
   441
    checkMcf(mcf, mcf.run(NetworkSimplex<Digraph>::BLOCK_SEARCH),
kpeter@640
   442
             gr, l2, u, c, s1, mcf.OPTIMAL, true,   5970, "#B3");
kpeter@606
   443
    checkMcf(mcf, mcf.run(NetworkSimplex<Digraph>::CANDIDATE_LIST),
kpeter@640
   444
             gr, l2, u, c, s1, mcf.OPTIMAL, true,   5970, "#B4");
kpeter@606
   445
    checkMcf(mcf, mcf.run(NetworkSimplex<Digraph>::ALTERING_LIST),
kpeter@640
   446
             gr, l2, u, c, s1, mcf.OPTIMAL, true,   5970, "#B5");
kpeter@601
   447
  }
kpeter@601
   448
kpeter@601
   449
  return 0;
kpeter@601
   450
}