test/min_cost_flow_test.cc
changeset 884 bc75ee2ad082
parent 716 4faca85d40e6
child 885 d93490b861e9
equal deleted inserted replaced
9:01fff1bd3558 10:3c01b296faed
    30 
    30 
    31 #include "test_tools.h"
    31 #include "test_tools.h"
    32 
    32 
    33 using namespace lemon;
    33 using namespace lemon;
    34 
    34 
       
    35 // Test networks
    35 char test_lgf[] =
    36 char test_lgf[] =
    36   "@nodes\n"
    37   "@nodes\n"
    37   "label  sup1 sup2 sup3 sup4 sup5 sup6\n"
    38   "label  sup1 sup2 sup3 sup4 sup5 sup6\n"
    38   "    1    20   27    0   30   20   30\n"
    39   "    1    20   27    0   30   20   30\n"
    39   "    2    -4    0    0    0   -8   -3\n"
    40   "    2    -4    0    0    0   -8   -3\n"
    74   "\n"
    75   "\n"
    75   "@attributes\n"
    76   "@attributes\n"
    76   "source 1\n"
    77   "source 1\n"
    77   "target 12\n";
    78   "target 12\n";
    78 
    79 
       
    80 char test_neg1_lgf[] =
       
    81   "@nodes\n"
       
    82   "label   sup\n"
       
    83   "    1   100\n"
       
    84   "    2     0\n"
       
    85   "    3     0\n"
       
    86   "    4  -100\n"
       
    87   "    5     0\n"
       
    88   "    6     0\n"
       
    89   "    7     0\n"
       
    90   "@arcs\n"
       
    91   "      cost   low1   low2\n"
       
    92   "1 2    100      0      0\n"
       
    93   "1 3     30      0      0\n"
       
    94   "2 4     20      0      0\n"
       
    95   "3 4     80      0      0\n"
       
    96   "3 2     50      0      0\n"
       
    97   "5 3     10      0      0\n"
       
    98   "5 6     80      0   1000\n"
       
    99   "6 7     30      0  -1000\n"
       
   100   "7 5   -120      0      0\n";
       
   101   
       
   102 char test_neg2_lgf[] =
       
   103   "@nodes\n"
       
   104   "label   sup\n"
       
   105   "    1   100\n"
       
   106   "    2  -300\n"
       
   107   "@arcs\n"
       
   108   "      cost\n"
       
   109   "1 2     -1\n";
       
   110 
       
   111 
       
   112 // Test data
       
   113 typedef ListDigraph Digraph;
       
   114 DIGRAPH_TYPEDEFS(ListDigraph);
       
   115 
       
   116 Digraph gr;
       
   117 Digraph::ArcMap<int> c(gr), l1(gr), l2(gr), l3(gr), u(gr);
       
   118 Digraph::NodeMap<int> s1(gr), s2(gr), s3(gr), s4(gr), s5(gr), s6(gr);
       
   119 ConstMap<Arc, int> cc(1), cu(std::numeric_limits<int>::max());
       
   120 Node v, w;
       
   121 
       
   122 Digraph neg1_gr;
       
   123 Digraph::ArcMap<int> neg1_c(neg1_gr), neg1_l1(neg1_gr), neg1_l2(neg1_gr);
       
   124 ConstMap<Arc, int> neg1_u1(std::numeric_limits<int>::max()), neg1_u2(5000);
       
   125 Digraph::NodeMap<int> neg1_s(neg1_gr);
       
   126 
       
   127 Digraph neg2_gr;
       
   128 Digraph::ArcMap<int> neg2_c(neg2_gr);
       
   129 ConstMap<Arc, int> neg2_l(0), neg2_u(1000);
       
   130 Digraph::NodeMap<int> neg2_s(neg2_gr);
       
   131 
    79 
   132 
    80 enum SupplyType {
   133 enum SupplyType {
    81   EQ,
   134   EQ,
    82   GEQ,
   135   GEQ,
    83   LEQ
   136   LEQ
    84 };
   137 };
       
   138 
    85 
   139 
    86 // Check the interface of an MCF algorithm
   140 // Check the interface of an MCF algorithm
    87 template <typename GR, typename Value, typename Cost>
   141 template <typename GR, typename Value, typename Cost>
    88 class McfClassConcept
   142 class McfClassConcept
    89 {
   143 {
   266     check(checkDualCost(gr, lower, upper, cost, supply, pi, total),
   320     check(checkDualCost(gr, lower, upper, cost, supply, pi, total),
   267           "Wrong dual cost " + test_id);
   321           "Wrong dual cost " + test_id);
   268   }
   322   }
   269 }
   323 }
   270 
   324 
       
   325 template < typename MCF, typename Param >
       
   326 void runMcfGeqTests( Param param,
       
   327                      const std::string &test_str = "",
       
   328                      bool full_neg_cost_support = false )
       
   329 {
       
   330   MCF mcf1(gr), mcf2(neg1_gr), mcf3(neg2_gr);
       
   331   
       
   332   // Basic tests
       
   333   mcf1.upperMap(u).costMap(c).supplyMap(s1);
       
   334   checkMcf(mcf1, mcf1.run(param), gr, l1, u, c, s1,
       
   335            mcf1.OPTIMAL, true,     5240, test_str + "-1");
       
   336   mcf1.stSupply(v, w, 27);
       
   337   checkMcf(mcf1, mcf1.run(param), gr, l1, u, c, s2,
       
   338            mcf1.OPTIMAL, true,     7620, test_str + "-2");
       
   339   mcf1.lowerMap(l2).supplyMap(s1);
       
   340   checkMcf(mcf1, mcf1.run(param), gr, l2, u, c, s1,
       
   341            mcf1.OPTIMAL, true,     5970, test_str + "-3");
       
   342   mcf1.stSupply(v, w, 27);
       
   343   checkMcf(mcf1, mcf1.run(param), gr, l2, u, c, s2,
       
   344            mcf1.OPTIMAL, true,     8010, test_str + "-4");
       
   345   mcf1.reset().supplyMap(s1);
       
   346   checkMcf(mcf1, mcf1.run(param), gr, l1, cu, cc, s1,
       
   347            mcf1.OPTIMAL, true,       74, test_str + "-5");
       
   348   mcf1.lowerMap(l2).stSupply(v, w, 27);
       
   349   checkMcf(mcf1, mcf1.run(param), gr, l2, cu, cc, s2,
       
   350            mcf1.OPTIMAL, true,       94, test_str + "-6");
       
   351   mcf1.reset();
       
   352   checkMcf(mcf1, mcf1.run(param), gr, l1, cu, cc, s3,
       
   353            mcf1.OPTIMAL, true,        0, test_str + "-7");
       
   354   mcf1.lowerMap(l2).upperMap(u);
       
   355   checkMcf(mcf1, mcf1.run(param), gr, l2, u, cc, s3,
       
   356            mcf1.INFEASIBLE, false,    0, test_str + "-8");
       
   357   mcf1.lowerMap(l3).upperMap(u).costMap(c).supplyMap(s4);
       
   358   checkMcf(mcf1, mcf1.run(param), gr, l3, u, c, s4,
       
   359            mcf1.OPTIMAL, true,     6360, test_str + "-9");
       
   360 
       
   361   // Tests for the GEQ form
       
   362   mcf1.reset().upperMap(u).costMap(c).supplyMap(s5);
       
   363   checkMcf(mcf1, mcf1.run(param), gr, l1, u, c, s5,
       
   364            mcf1.OPTIMAL, true,     3530, test_str + "-10", GEQ);
       
   365   mcf1.lowerMap(l2);
       
   366   checkMcf(mcf1, mcf1.run(param), gr, l2, u, c, s5,
       
   367            mcf1.OPTIMAL, true,     4540, test_str + "-11", GEQ);
       
   368   mcf1.supplyMap(s6);
       
   369   checkMcf(mcf1, mcf1.run(param), gr, l2, u, c, s6,
       
   370            mcf1.INFEASIBLE, false,    0, test_str + "-12", GEQ);
       
   371 
       
   372   // Tests with negative costs
       
   373   mcf2.lowerMap(neg1_l1).costMap(neg1_c).supplyMap(neg1_s);
       
   374   checkMcf(mcf2, mcf2.run(param), neg1_gr, neg1_l1, neg1_u1, neg1_c, neg1_s,
       
   375            mcf2.UNBOUNDED, false,     0, test_str + "-13");
       
   376   mcf2.upperMap(neg1_u2);
       
   377   checkMcf(mcf2, mcf2.run(param), neg1_gr, neg1_l1, neg1_u2, neg1_c, neg1_s,
       
   378            mcf2.OPTIMAL, true,   -40000, test_str + "-14");
       
   379   mcf2.reset().lowerMap(neg1_l2).costMap(neg1_c).supplyMap(neg1_s);
       
   380   checkMcf(mcf2, mcf2.run(param), neg1_gr, neg1_l2, neg1_u1, neg1_c, neg1_s,
       
   381            mcf2.UNBOUNDED, false,     0, test_str + "-15");
       
   382 
       
   383   mcf3.costMap(neg2_c).supplyMap(neg2_s);
       
   384   if (full_neg_cost_support) {
       
   385     checkMcf(mcf3, mcf3.run(param), neg2_gr, neg2_l, neg2_u, neg2_c, neg2_s,
       
   386              mcf3.OPTIMAL, true,   -300, test_str + "-16", GEQ);
       
   387   } else {
       
   388     checkMcf(mcf3, mcf3.run(param), neg2_gr, neg2_l, neg2_u, neg2_c, neg2_s,
       
   389              mcf3.UNBOUNDED, false,   0, test_str + "-17", GEQ);
       
   390   }
       
   391   mcf3.upperMap(neg2_u);
       
   392   checkMcf(mcf3, mcf3.run(param), neg2_gr, neg2_l, neg2_u, neg2_c, neg2_s,
       
   393            mcf3.OPTIMAL, true,     -300, test_str + "-18", GEQ);
       
   394 }
       
   395 
       
   396 template < typename MCF, typename Param >
       
   397 void runMcfLeqTests( Param param,
       
   398                      const std::string &test_str = "" )
       
   399 {
       
   400   // Tests for the LEQ form
       
   401   MCF mcf1(gr);
       
   402   mcf1.supplyType(mcf1.LEQ);
       
   403   mcf1.upperMap(u).costMap(c).supplyMap(s6);
       
   404   checkMcf(mcf1, mcf1.run(param), gr, l1, u, c, s6,
       
   405            mcf1.OPTIMAL, true,   5080, test_str + "-19", LEQ);
       
   406   mcf1.lowerMap(l2);
       
   407   checkMcf(mcf1, mcf1.run(param), gr, l2, u, c, s6,
       
   408            mcf1.OPTIMAL, true,   5930, test_str + "-20", LEQ);
       
   409   mcf1.supplyMap(s5);
       
   410   checkMcf(mcf1, mcf1.run(param), gr, l2, u, c, s5,
       
   411            mcf1.INFEASIBLE, false,  0, test_str + "-21", LEQ);
       
   412 }
       
   413 
       
   414 
   271 int main()
   415 int main()
   272 {
   416 {
   273   // Check the interfaces
   417   // Read the test networks
   274   {
       
   275     typedef concepts::Digraph GR;
       
   276     checkConcept< McfClassConcept<GR, int, int>,
       
   277                   NetworkSimplex<GR> >();
       
   278     checkConcept< McfClassConcept<GR, double, double>,
       
   279                   NetworkSimplex<GR, double> >();
       
   280     checkConcept< McfClassConcept<GR, int, double>,
       
   281                   NetworkSimplex<GR, int, double> >();
       
   282   }
       
   283 
       
   284   // Run various MCF tests
       
   285   typedef ListDigraph Digraph;
       
   286   DIGRAPH_TYPEDEFS(ListDigraph);
       
   287 
       
   288   // Read the test digraph
       
   289   Digraph gr;
       
   290   Digraph::ArcMap<int> c(gr), l1(gr), l2(gr), l3(gr), u(gr);
       
   291   Digraph::NodeMap<int> s1(gr), s2(gr), s3(gr), s4(gr), s5(gr), s6(gr);
       
   292   ConstMap<Arc, int> cc(1), cu(std::numeric_limits<int>::max());
       
   293   Node v, w;
       
   294 
       
   295   std::istringstream input(test_lgf);
   418   std::istringstream input(test_lgf);
   296   DigraphReader<Digraph>(gr, input)
   419   DigraphReader<Digraph>(gr, input)
   297     .arcMap("cost", c)
   420     .arcMap("cost", c)
   298     .arcMap("cap", u)
   421     .arcMap("cap", u)
   299     .arcMap("low1", l1)
   422     .arcMap("low1", l1)
   307     .nodeMap("sup6", s6)
   430     .nodeMap("sup6", s6)
   308     .node("source", v)
   431     .node("source", v)
   309     .node("target", w)
   432     .node("target", w)
   310     .run();
   433     .run();
   311   
   434   
   312   // Build test digraphs with negative costs
   435   std::istringstream neg_inp1(test_neg1_lgf);
   313   Digraph neg_gr;
   436   DigraphReader<Digraph>(neg1_gr, neg_inp1)
   314   Node n1 = neg_gr.addNode();
   437     .arcMap("cost", neg1_c)
   315   Node n2 = neg_gr.addNode();
   438     .arcMap("low1", neg1_l1)
   316   Node n3 = neg_gr.addNode();
   439     .arcMap("low2", neg1_l2)
   317   Node n4 = neg_gr.addNode();
   440     .nodeMap("sup", neg1_s)
   318   Node n5 = neg_gr.addNode();
   441     .run();
   319   Node n6 = neg_gr.addNode();
   442   
   320   Node n7 = neg_gr.addNode();
   443   std::istringstream neg_inp2(test_neg2_lgf);
   321   
   444   DigraphReader<Digraph>(neg2_gr, neg_inp2)
   322   Arc a1 = neg_gr.addArc(n1, n2);
   445     .arcMap("cost", neg2_c)
   323   Arc a2 = neg_gr.addArc(n1, n3);
   446     .nodeMap("sup", neg2_s)
   324   Arc a3 = neg_gr.addArc(n2, n4);
   447     .run();
   325   Arc a4 = neg_gr.addArc(n3, n4);
   448   
   326   Arc a5 = neg_gr.addArc(n3, n2);
   449   // Check the interface of NetworkSimplex
   327   Arc a6 = neg_gr.addArc(n5, n3);
       
   328   Arc a7 = neg_gr.addArc(n5, n6);
       
   329   Arc a8 = neg_gr.addArc(n6, n7);
       
   330   Arc a9 = neg_gr.addArc(n7, n5);
       
   331   
       
   332   Digraph::ArcMap<int> neg_c(neg_gr), neg_l1(neg_gr, 0), neg_l2(neg_gr, 0);
       
   333   ConstMap<Arc, int> neg_u1(std::numeric_limits<int>::max()), neg_u2(5000);
       
   334   Digraph::NodeMap<int> neg_s(neg_gr, 0);
       
   335   
       
   336   neg_l2[a7] =  1000;
       
   337   neg_l2[a8] = -1000;
       
   338   
       
   339   neg_s[n1] =  100;
       
   340   neg_s[n4] = -100;
       
   341   
       
   342   neg_c[a1] =  100;
       
   343   neg_c[a2] =   30;
       
   344   neg_c[a3] =   20;
       
   345   neg_c[a4] =   80;
       
   346   neg_c[a5] =   50;
       
   347   neg_c[a6] =   10;
       
   348   neg_c[a7] =   80;
       
   349   neg_c[a8] =   30;
       
   350   neg_c[a9] = -120;
       
   351 
       
   352   Digraph negs_gr;
       
   353   Digraph::NodeMap<int> negs_s(negs_gr);
       
   354   Digraph::ArcMap<int> negs_c(negs_gr);
       
   355   ConstMap<Arc, int> negs_l(0), negs_u(1000);
       
   356   n1 = negs_gr.addNode();
       
   357   n2 = negs_gr.addNode();
       
   358   negs_s[n1] = 100;
       
   359   negs_s[n2] = -300;
       
   360   negs_c[negs_gr.addArc(n1, n2)] = -1;
       
   361 
       
   362 
       
   363   // A. Test NetworkSimplex with the default pivot rule
       
   364   {
   450   {
   365     NetworkSimplex<Digraph> mcf(gr);
   451     typedef concepts::Digraph GR;
   366 
   452     checkConcept< McfClassConcept<GR, int, int>,
   367     // Check the equality form
   453                   NetworkSimplex<GR> >();
   368     mcf.upperMap(u).costMap(c);
   454     checkConcept< McfClassConcept<GR, double, double>,
   369     checkMcf(mcf, mcf.supplyMap(s1).run(),
   455                   NetworkSimplex<GR, double> >();
   370              gr, l1, u, c, s1, mcf.OPTIMAL, true,   5240, "#A1");
   456     checkConcept< McfClassConcept<GR, int, double>,
   371     checkMcf(mcf, mcf.stSupply(v, w, 27).run(),
   457                   NetworkSimplex<GR, int, double> >();
   372              gr, l1, u, c, s2, mcf.OPTIMAL, true,   7620, "#A2");
   458   }
   373     mcf.lowerMap(l2);
   459 
   374     checkMcf(mcf, mcf.supplyMap(s1).run(),
   460   // Test NetworkSimplex
   375              gr, l2, u, c, s1, mcf.OPTIMAL, true,   5970, "#A3");
   461   { 
   376     checkMcf(mcf, mcf.stSupply(v, w, 27).run(),
   462     typedef NetworkSimplex<Digraph> MCF;
   377              gr, l2, u, c, s2, mcf.OPTIMAL, true,   8010, "#A4");
   463     runMcfGeqTests<MCF>(MCF::FIRST_ELIGIBLE, "NS-FE", true);
   378     mcf.reset();
   464     runMcfLeqTests<MCF>(MCF::FIRST_ELIGIBLE, "NS-FE");
   379     checkMcf(mcf, mcf.supplyMap(s1).run(),
   465     runMcfGeqTests<MCF>(MCF::BEST_ELIGIBLE,  "NS-BE", true);
   380              gr, l1, cu, cc, s1, mcf.OPTIMAL, true,   74, "#A5");
   466     runMcfLeqTests<MCF>(MCF::BEST_ELIGIBLE,  "NS-BE");
   381     checkMcf(mcf, mcf.lowerMap(l2).stSupply(v, w, 27).run(),
   467     runMcfGeqTests<MCF>(MCF::BLOCK_SEARCH,   "NS-BS", true);
   382              gr, l2, cu, cc, s2, mcf.OPTIMAL, true,   94, "#A6");
   468     runMcfLeqTests<MCF>(MCF::BLOCK_SEARCH,   "NS-BS");
   383     mcf.reset();
   469     runMcfGeqTests<MCF>(MCF::CANDIDATE_LIST, "NS-CL", true);
   384     checkMcf(mcf, mcf.run(),
   470     runMcfLeqTests<MCF>(MCF::CANDIDATE_LIST, "NS-CL");
   385              gr, l1, cu, cc, s3, mcf.OPTIMAL, true,    0, "#A7");
   471     runMcfGeqTests<MCF>(MCF::ALTERING_LIST,  "NS-AL", true);
   386     checkMcf(mcf, mcf.lowerMap(l2).upperMap(u).run(),
   472     runMcfLeqTests<MCF>(MCF::ALTERING_LIST,  "NS-AL");
   387              gr, l2, u, cc, s3, mcf.INFEASIBLE, false, 0, "#A8");
       
   388     mcf.reset().lowerMap(l3).upperMap(u).costMap(c).supplyMap(s4);
       
   389     checkMcf(mcf, mcf.run(),
       
   390              gr, l3, u, c, s4, mcf.OPTIMAL, true,   6360, "#A9");
       
   391 
       
   392     // Check the GEQ form
       
   393     mcf.reset().upperMap(u).costMap(c).supplyMap(s5);
       
   394     checkMcf(mcf, mcf.run(),
       
   395              gr, l1, u, c, s5, mcf.OPTIMAL, true,   3530, "#A10", GEQ);
       
   396     mcf.supplyType(mcf.GEQ);
       
   397     checkMcf(mcf, mcf.lowerMap(l2).run(),
       
   398              gr, l2, u, c, s5, mcf.OPTIMAL, true,   4540, "#A11", GEQ);
       
   399     mcf.supplyMap(s6);
       
   400     checkMcf(mcf, mcf.run(),
       
   401              gr, l2, u, c, s6, mcf.INFEASIBLE, false,  0, "#A12", GEQ);
       
   402 
       
   403     // Check the LEQ form
       
   404     mcf.reset().supplyType(mcf.LEQ);
       
   405     mcf.upperMap(u).costMap(c).supplyMap(s6);
       
   406     checkMcf(mcf, mcf.run(),
       
   407              gr, l1, u, c, s6, mcf.OPTIMAL, true,   5080, "#A13", LEQ);
       
   408     checkMcf(mcf, mcf.lowerMap(l2).run(),
       
   409              gr, l2, u, c, s6, mcf.OPTIMAL, true,   5930, "#A14", LEQ);
       
   410     mcf.supplyMap(s5);
       
   411     checkMcf(mcf, mcf.run(),
       
   412              gr, l2, u, c, s5, mcf.INFEASIBLE, false,  0, "#A15", LEQ);
       
   413 
       
   414     // Check negative costs
       
   415     NetworkSimplex<Digraph> neg_mcf(neg_gr);
       
   416     neg_mcf.lowerMap(neg_l1).costMap(neg_c).supplyMap(neg_s);
       
   417     checkMcf(neg_mcf, neg_mcf.run(), neg_gr, neg_l1, neg_u1,
       
   418       neg_c, neg_s, neg_mcf.UNBOUNDED, false,    0, "#A16");
       
   419     neg_mcf.upperMap(neg_u2);
       
   420     checkMcf(neg_mcf, neg_mcf.run(), neg_gr, neg_l1, neg_u2,
       
   421       neg_c, neg_s, neg_mcf.OPTIMAL, true,  -40000, "#A17");
       
   422     neg_mcf.reset().lowerMap(neg_l2).costMap(neg_c).supplyMap(neg_s);
       
   423     checkMcf(neg_mcf, neg_mcf.run(), neg_gr, neg_l2, neg_u1,
       
   424       neg_c, neg_s, neg_mcf.UNBOUNDED, false,    0, "#A18");
       
   425       
       
   426     NetworkSimplex<Digraph> negs_mcf(negs_gr);
       
   427     negs_mcf.costMap(negs_c).supplyMap(negs_s);
       
   428     checkMcf(negs_mcf, negs_mcf.run(), negs_gr, negs_l, negs_u,
       
   429       negs_c, negs_s, negs_mcf.OPTIMAL, true, -300, "#A19", GEQ);
       
   430   }
       
   431 
       
   432   // B. Test NetworkSimplex with each pivot rule
       
   433   {
       
   434     NetworkSimplex<Digraph> mcf(gr);
       
   435     mcf.supplyMap(s1).costMap(c).upperMap(u).lowerMap(l2);
       
   436 
       
   437     checkMcf(mcf, mcf.run(NetworkSimplex<Digraph>::FIRST_ELIGIBLE),
       
   438              gr, l2, u, c, s1, mcf.OPTIMAL, true,   5970, "#B1");
       
   439     checkMcf(mcf, mcf.run(NetworkSimplex<Digraph>::BEST_ELIGIBLE),
       
   440              gr, l2, u, c, s1, mcf.OPTIMAL, true,   5970, "#B2");
       
   441     checkMcf(mcf, mcf.run(NetworkSimplex<Digraph>::BLOCK_SEARCH),
       
   442              gr, l2, u, c, s1, mcf.OPTIMAL, true,   5970, "#B3");
       
   443     checkMcf(mcf, mcf.run(NetworkSimplex<Digraph>::CANDIDATE_LIST),
       
   444              gr, l2, u, c, s1, mcf.OPTIMAL, true,   5970, "#B4");
       
   445     checkMcf(mcf, mcf.run(NetworkSimplex<Digraph>::ALTERING_LIST),
       
   446              gr, l2, u, c, s1, mcf.OPTIMAL, true,   5970, "#B5");
       
   447   }
   473   }
   448 
   474 
   449   return 0;
   475   return 0;
   450 }
   476 }