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