test/min_cost_flow_test.cc
author Peter Kovacs <kpeter@inf.elte.hu>
Fri, 03 Apr 2009 13:46:16 +0200
changeset 654 9ad8d2122b50
parent 653 c7d160f73d52
child 656 e6927fe719e6
permissions -rw-r--r--
Separate types for flow and cost values 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 Flow, typename Cost>
    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, Flow> NM;
   120     typedef concepts::ReadMap<Arc, Flow> FAM;
   121     typedef concepts::ReadMap<Arc, Cost> CAM;
   122 
   123     const GR &g;
   124     const FAM &lower;
   125     const FAM &upper;
   126     const CAM &cost;
   127     const NM &sup;
   128     const Node &n;
   129     const Arc &a;
   130     const Flow &k;
   131     Flow v;
   132     bool b;
   133 
   134     typename MCF::FlowMap &flow;
   135     typename MCF::PotentialMap &pot;
   136   };
   137 
   138 };
   139 
   140 
   141 // Check the feasibility of the given flow (primal soluiton)
   142 template < typename GR, typename LM, typename UM,
   143            typename SM, typename FM >
   144 bool checkFlow( const GR& gr, const LM& lower, const UM& upper,
   145                 const SM& supply, const FM& flow )
   146 {
   147   TEMPLATE_DIGRAPH_TYPEDEFS(GR);
   148 
   149   for (ArcIt e(gr); e != INVALID; ++e) {
   150     if (flow[e] < lower[e] || flow[e] > upper[e]) return false;
   151   }
   152 
   153   for (NodeIt n(gr); n != INVALID; ++n) {
   154     typename SM::Value sum = 0;
   155     for (OutArcIt e(gr, n); e != INVALID; ++e)
   156       sum += flow[e];
   157     for (InArcIt e(gr, n); e != INVALID; ++e)
   158       sum -= flow[e];
   159     if (sum != supply[n]) return false;
   160   }
   161 
   162   return true;
   163 }
   164 
   165 // Check the feasibility of the given potentials (dual soluiton)
   166 // using the "Complementary Slackness" optimality condition
   167 template < typename GR, typename LM, typename UM,
   168            typename CM, typename FM, typename PM >
   169 bool checkPotential( const GR& gr, const LM& lower, const UM& upper,
   170                      const CM& cost, const FM& flow, const PM& pi )
   171 {
   172   TEMPLATE_DIGRAPH_TYPEDEFS(GR);
   173 
   174   bool opt = true;
   175   for (ArcIt e(gr); opt && e != INVALID; ++e) {
   176     typename CM::Value red_cost =
   177       cost[e] + pi[gr.source(e)] - pi[gr.target(e)];
   178     opt = red_cost == 0 ||
   179           (red_cost > 0 && flow[e] == lower[e]) ||
   180           (red_cost < 0 && flow[e] == upper[e]);
   181   }
   182   return opt;
   183 }
   184 
   185 // Run a minimum cost flow algorithm and check the results
   186 template < typename MCF, typename GR,
   187            typename LM, typename UM,
   188            typename CM, typename SM >
   189 void checkMcf( const MCF& mcf, bool mcf_result,
   190                const GR& gr, const LM& lower, const UM& upper,
   191                const CM& cost, const SM& supply,
   192                bool result, typename CM::Value total,
   193                const std::string &test_id = "" )
   194 {
   195   check(mcf_result == result, "Wrong result " + test_id);
   196   if (result) {
   197     check(checkFlow(gr, lower, upper, supply, mcf.flowMap()),
   198           "The flow is not feasible " + test_id);
   199     check(mcf.totalCost() == total, "The flow is not optimal " + test_id);
   200     check(checkPotential(gr, lower, upper, cost, mcf.flowMap(),
   201                          mcf.potentialMap()),
   202           "Wrong potentials " + test_id);
   203   }
   204 }
   205 
   206 int main()
   207 {
   208   // Check the interfaces
   209   {
   210     typedef int Flow;
   211     typedef int Cost;
   212     // TODO: This typedef should be enabled if the standard maps are
   213     // reference maps in the graph concepts (See #190).
   214 /**/
   215     //typedef concepts::Digraph GR;
   216     typedef ListDigraph GR;
   217 /**/
   218     checkConcept< McfClassConcept<GR, Flow, Cost>,
   219                   NetworkSimplex<GR, Flow, Cost> >();
   220   }
   221 
   222   // Run various MCF tests
   223   typedef ListDigraph Digraph;
   224   DIGRAPH_TYPEDEFS(ListDigraph);
   225 
   226   // Read the test digraph
   227   Digraph gr;
   228   Digraph::ArcMap<int> c(gr), l1(gr), l2(gr), u(gr);
   229   Digraph::NodeMap<int> s1(gr), s2(gr), s3(gr);
   230   ConstMap<Arc, int> cc(1), cu(std::numeric_limits<int>::max());
   231   Node v, w;
   232 
   233   std::istringstream input(test_lgf);
   234   DigraphReader<Digraph>(gr, input)
   235     .arcMap("cost", c)
   236     .arcMap("cap", u)
   237     .arcMap("low1", l1)
   238     .arcMap("low2", l2)
   239     .nodeMap("sup1", s1)
   240     .nodeMap("sup2", s2)
   241     .nodeMap("sup3", s3)
   242     .node("source", v)
   243     .node("target", w)
   244     .run();
   245 
   246   // A. Test NetworkSimplex with the default pivot rule
   247   {
   248     NetworkSimplex<Digraph> mcf(gr);
   249 
   250     mcf.upperMap(u).costMap(c);
   251     checkMcf(mcf, mcf.supplyMap(s1).run(),
   252              gr, l1, u, c, s1, true,  5240, "#A1");
   253     checkMcf(mcf, mcf.stSupply(v, w, 27).run(),
   254              gr, l1, u, c, s2, true,  7620, "#A2");
   255     mcf.lowerMap(l2);
   256     checkMcf(mcf, mcf.supplyMap(s1).run(),
   257              gr, l2, u, c, s1, true,  5970, "#A3");
   258     checkMcf(mcf, mcf.stSupply(v, w, 27).run(),
   259              gr, l2, u, c, s2, true,  8010, "#A4");
   260     mcf.reset();
   261     checkMcf(mcf, mcf.supplyMap(s1).run(),
   262              gr, l1, cu, cc, s1, true,  74, "#A5");
   263     checkMcf(mcf, mcf.lowerMap(l2).stSupply(v, w, 27).run(),
   264              gr, l2, cu, cc, s2, true,  94, "#A6");
   265     mcf.reset();
   266     checkMcf(mcf, mcf.run(),
   267              gr, l1, cu, cc, s3, true,   0, "#A7");
   268     checkMcf(mcf, mcf.boundMaps(l2, u).run(),
   269              gr, l2, u, cc, s3, false,   0, "#A8");
   270   }
   271 
   272   // B. Test NetworkSimplex with each pivot rule
   273   {
   274     NetworkSimplex<Digraph> mcf(gr);
   275     mcf.supplyMap(s1).costMap(c).capacityMap(u).lowerMap(l2);
   276 
   277     checkMcf(mcf, mcf.run(NetworkSimplex<Digraph>::FIRST_ELIGIBLE),
   278              gr, l2, u, c, s1, true,  5970, "#B1");
   279     checkMcf(mcf, mcf.run(NetworkSimplex<Digraph>::BEST_ELIGIBLE),
   280              gr, l2, u, c, s1, true,  5970, "#B2");
   281     checkMcf(mcf, mcf.run(NetworkSimplex<Digraph>::BLOCK_SEARCH),
   282              gr, l2, u, c, s1, true,  5970, "#B3");
   283     checkMcf(mcf, mcf.run(NetworkSimplex<Digraph>::CANDIDATE_LIST),
   284              gr, l2, u, c, s1, true,  5970, "#B4");
   285     checkMcf(mcf, mcf.run(NetworkSimplex<Digraph>::ALTERING_LIST),
   286              gr, l2, u, c, s1, true,  5970, "#B5");
   287   }
   288 
   289   return 0;
   290 }