test/min_cost_flow_test.cc
author Peter Kovacs <kpeter@inf.elte.hu>
Wed, 25 Mar 2009 21:37:50 +0100
changeset 606 c7d160f73d52
parent 605 5232721b3f14
child 607 9ad8d2122b50
permissions -rw-r--r--
Support multiple run() calls in NetworkSimplex (#234)
     1 /* -*- mode: C++; indent-tabs-mode: nil; -*-
     2  *
     3  * This file is a part of LEMON, a generic C++ optimization library.
     4  *
     5  * Copyright (C) 2003-2009
     6  * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
     7  * (Egervary Research Group on Combinatorial Optimization, EGRES).
     8  *
     9  * Permission to use, modify and distribute this software is granted
    10  * provided that this copyright notice appears in all copies. For
    11  * precise terms see the accompanying LICENSE file.
    12  *
    13  * This software is provided "AS IS" with no warranty of any kind,
    14  * express or implied, and with no claim as to its suitability for any
    15  * purpose.
    16  *
    17  */
    18 
    19 #include <iostream>
    20 #include <fstream>
    21 
    22 #include <lemon/list_graph.h>
    23 #include <lemon/lgf_reader.h>
    24 
    25 #include <lemon/network_simplex.h>
    26 
    27 #include <lemon/concepts/digraph.h>
    28 #include <lemon/concept_check.h>
    29 
    30 #include "test_tools.h"
    31 
    32 using namespace lemon;
    33 
    34 char test_lgf[] =
    35   "@nodes\n"
    36   "label  sup1 sup2 sup3\n"
    37   "    1    20   27    0\n"
    38   "    2    -4    0    0\n"
    39   "    3     0    0    0\n"
    40   "    4     0    0    0\n"
    41   "    5     9    0    0\n"
    42   "    6    -6    0    0\n"
    43   "    7     0    0    0\n"
    44   "    8     0    0    0\n"
    45   "    9     3    0    0\n"
    46   "   10    -2    0    0\n"
    47   "   11     0    0    0\n"
    48   "   12   -20  -27    0\n"
    49   "\n"
    50   "@arcs\n"
    51   "       cost  cap low1 low2\n"
    52   " 1  2    70   11    0    8\n"
    53   " 1  3   150    3    0    1\n"
    54   " 1  4    80   15    0    2\n"
    55   " 2  8    80   12    0    0\n"
    56   " 3  5   140    5    0    3\n"
    57   " 4  6    60   10    0    1\n"
    58   " 4  7    80    2    0    0\n"
    59   " 4  8   110    3    0    0\n"
    60   " 5  7    60   14    0    0\n"
    61   " 5 11   120   12    0    0\n"
    62   " 6  3     0    3    0    0\n"
    63   " 6  9   140    4    0    0\n"
    64   " 6 10    90    8    0    0\n"
    65   " 7  1    30    5    0    0\n"
    66   " 8 12    60   16    0    4\n"
    67   " 9 12    50    6    0    0\n"
    68   "10 12    70   13    0    5\n"
    69   "10  2   100    7    0    0\n"
    70   "10  7    60   10    0    0\n"
    71   "11 10    20   14    0    6\n"
    72   "12 11    30   10    0    0\n"
    73   "\n"
    74   "@attributes\n"
    75   "source 1\n"
    76   "target 12\n";
    77 
    78 
    79 // Check the interface of an MCF algorithm
    80 template <typename GR, typename Value>
    81 class McfClassConcept
    82 {
    83 public:
    84 
    85   template <typename MCF>
    86   struct Constraints {
    87     void constraints() {
    88       checkConcept<concepts::Digraph, GR>();
    89 
    90       MCF mcf(g);
    91 
    92       b = mcf.reset()
    93              .lowerMap(lower)
    94              .upperMap(upper)
    95              .capacityMap(upper)
    96              .boundMaps(lower, upper)
    97              .costMap(cost)
    98              .supplyMap(sup)
    99              .stSupply(n, n, k)
   100              .run();
   101 
   102       const typename MCF::FlowMap &fm = mcf.flowMap();
   103       const typename MCF::PotentialMap &pm = mcf.potentialMap();
   104 
   105       v = mcf.totalCost();
   106       double x = mcf.template totalCost<double>();
   107       v = mcf.flow(a);
   108       v = mcf.potential(n);
   109       mcf.flowMap(flow);
   110       mcf.potentialMap(pot);
   111 
   112       ignore_unused_variable_warning(fm);
   113       ignore_unused_variable_warning(pm);
   114       ignore_unused_variable_warning(x);
   115     }
   116 
   117     typedef typename GR::Node Node;
   118     typedef typename GR::Arc Arc;
   119     typedef concepts::ReadMap<Node, Value> NM;
   120     typedef concepts::ReadMap<Arc, Value> AM;
   121 
   122     const GR &g;
   123     const AM &lower;
   124     const AM &upper;
   125     const AM &cost;
   126     const NM &sup;
   127     const Node &n;
   128     const Arc &a;
   129     const Value &k;
   130     Value v;
   131     bool b;
   132 
   133     typename MCF::FlowMap &flow;
   134     typename MCF::PotentialMap &pot;
   135   };
   136 
   137 };
   138 
   139 
   140 // Check the feasibility of the given flow (primal soluiton)
   141 template < typename GR, typename LM, typename UM,
   142            typename SM, typename FM >
   143 bool checkFlow( const GR& gr, const LM& lower, const UM& upper,
   144                 const SM& supply, const FM& flow )
   145 {
   146   TEMPLATE_DIGRAPH_TYPEDEFS(GR);
   147 
   148   for (ArcIt e(gr); e != INVALID; ++e) {
   149     if (flow[e] < lower[e] || flow[e] > upper[e]) return false;
   150   }
   151 
   152   for (NodeIt n(gr); n != INVALID; ++n) {
   153     typename SM::Value sum = 0;
   154     for (OutArcIt e(gr, n); e != INVALID; ++e)
   155       sum += flow[e];
   156     for (InArcIt e(gr, n); e != INVALID; ++e)
   157       sum -= flow[e];
   158     if (sum != supply[n]) return false;
   159   }
   160 
   161   return true;
   162 }
   163 
   164 // Check the feasibility of the given potentials (dual soluiton)
   165 // using the "Complementary Slackness" optimality condition
   166 template < typename GR, typename LM, typename UM,
   167            typename CM, typename FM, typename PM >
   168 bool checkPotential( const GR& gr, const LM& lower, const UM& upper,
   169                      const CM& cost, const FM& flow, const PM& pi )
   170 {
   171   TEMPLATE_DIGRAPH_TYPEDEFS(GR);
   172 
   173   bool opt = true;
   174   for (ArcIt e(gr); opt && e != INVALID; ++e) {
   175     typename CM::Value red_cost =
   176       cost[e] + pi[gr.source(e)] - pi[gr.target(e)];
   177     opt = red_cost == 0 ||
   178           (red_cost > 0 && flow[e] == lower[e]) ||
   179           (red_cost < 0 && flow[e] == upper[e]);
   180   }
   181   return opt;
   182 }
   183 
   184 // Run a minimum cost flow algorithm and check the results
   185 template < typename MCF, typename GR,
   186            typename LM, typename UM,
   187            typename CM, typename SM >
   188 void checkMcf( const MCF& mcf, bool mcf_result,
   189                const GR& gr, const LM& lower, const UM& upper,
   190                const CM& cost, const SM& supply,
   191                bool result, typename CM::Value total,
   192                const std::string &test_id = "" )
   193 {
   194   check(mcf_result == result, "Wrong result " + test_id);
   195   if (result) {
   196     check(checkFlow(gr, lower, upper, supply, mcf.flowMap()),
   197           "The flow is not feasible " + test_id);
   198     check(mcf.totalCost() == total, "The flow is not optimal " + test_id);
   199     check(checkPotential(gr, lower, upper, cost, mcf.flowMap(),
   200                          mcf.potentialMap()),
   201           "Wrong potentials " + test_id);
   202   }
   203 }
   204 
   205 int main()
   206 {
   207   // Check the interfaces
   208   {
   209     typedef int Value;
   210     // TODO: This typedef should be enabled if the standard maps are
   211     // reference maps in the graph concepts (See #190).
   212 /**/
   213     //typedef concepts::Digraph GR;
   214     typedef ListDigraph GR;
   215 /**/
   216     checkConcept< McfClassConcept<GR, Value>,
   217                   NetworkSimplex<GR, Value> >();
   218   }
   219 
   220   // Run various MCF tests
   221   typedef ListDigraph Digraph;
   222   DIGRAPH_TYPEDEFS(ListDigraph);
   223 
   224   // Read the test digraph
   225   Digraph gr;
   226   Digraph::ArcMap<int> c(gr), l1(gr), l2(gr), u(gr);
   227   Digraph::NodeMap<int> s1(gr), s2(gr), s3(gr);
   228   ConstMap<Arc, int> cc(1), cu(std::numeric_limits<int>::max());
   229   Node v, w;
   230 
   231   std::istringstream input(test_lgf);
   232   DigraphReader<Digraph>(gr, input)
   233     .arcMap("cost", c)
   234     .arcMap("cap", u)
   235     .arcMap("low1", l1)
   236     .arcMap("low2", l2)
   237     .nodeMap("sup1", s1)
   238     .nodeMap("sup2", s2)
   239     .nodeMap("sup3", s3)
   240     .node("source", v)
   241     .node("target", w)
   242     .run();
   243 
   244   // A. Test NetworkSimplex with the default pivot rule
   245   {
   246     NetworkSimplex<Digraph> mcf(gr);
   247 
   248     mcf.upperMap(u).costMap(c);
   249     checkMcf(mcf, mcf.supplyMap(s1).run(),
   250              gr, l1, u, c, s1, true,  5240, "#A1");
   251     checkMcf(mcf, mcf.stSupply(v, w, 27).run(),
   252              gr, l1, u, c, s2, true,  7620, "#A2");
   253     mcf.lowerMap(l2);
   254     checkMcf(mcf, mcf.supplyMap(s1).run(),
   255              gr, l2, u, c, s1, true,  5970, "#A3");
   256     checkMcf(mcf, mcf.stSupply(v, w, 27).run(),
   257              gr, l2, u, c, s2, true,  8010, "#A4");
   258     mcf.reset();
   259     checkMcf(mcf, mcf.supplyMap(s1).run(),
   260              gr, l1, cu, cc, s1, true,  74, "#A5");
   261     checkMcf(mcf, mcf.lowerMap(l2).stSupply(v, w, 27).run(),
   262              gr, l2, cu, cc, s2, true,  94, "#A6");
   263     mcf.reset();
   264     checkMcf(mcf, mcf.run(),
   265              gr, l1, cu, cc, s3, true,   0, "#A7");
   266     checkMcf(mcf, mcf.boundMaps(l2, u).run(),
   267              gr, l2, u, cc, s3, false,   0, "#A8");
   268   }
   269 
   270   // B. Test NetworkSimplex with each pivot rule
   271   {
   272     NetworkSimplex<Digraph> mcf(gr);
   273     mcf.supplyMap(s1).costMap(c).capacityMap(u).lowerMap(l2);
   274 
   275     checkMcf(mcf, mcf.run(NetworkSimplex<Digraph>::FIRST_ELIGIBLE),
   276              gr, l2, u, c, s1, true,  5970, "#B1");
   277     checkMcf(mcf, mcf.run(NetworkSimplex<Digraph>::BEST_ELIGIBLE),
   278              gr, l2, u, c, s1, true,  5970, "#B2");
   279     checkMcf(mcf, mcf.run(NetworkSimplex<Digraph>::BLOCK_SEARCH),
   280              gr, l2, u, c, s1, true,  5970, "#B3");
   281     checkMcf(mcf, mcf.run(NetworkSimplex<Digraph>::CANDIDATE_LIST),
   282              gr, l2, u, c, s1, true,  5970, "#B4");
   283     checkMcf(mcf, mcf.run(NetworkSimplex<Digraph>::ALTERING_LIST),
   284              gr, l2, u, c, s1, true,  5970, "#B5");
   285   }
   286 
   287   return 0;
   288 }