Extend min cost flow test file + check dual costs (#291)
authorPeter Kovacs <kpeter@inf.elte.hu>
Tue, 12 May 2009 12:08:06 +0200
changeset 662cc61d09f053b
parent 661 8b0df68370a4
child 663 e652b6f9a29f
Extend min cost flow test file + check dual costs (#291)
test/min_cost_flow_test.cc
     1.1 --- a/test/min_cost_flow_test.cc	Tue May 12 12:06:40 2009 +0200
     1.2 +++ b/test/min_cost_flow_test.cc	Tue May 12 12:08:06 2009 +0200
     1.3 @@ -174,7 +174,7 @@
     1.4             typename CM, typename SM, typename FM, typename PM >
     1.5  bool checkPotential( const GR& gr, const LM& lower, const UM& upper,
     1.6                       const CM& cost, const SM& supply, const FM& flow, 
     1.7 -                     const PM& pi )
     1.8 +                     const PM& pi, SupplyType type )
     1.9  {
    1.10    TEMPLATE_DIGRAPH_TYPEDEFS(GR);
    1.11  
    1.12 @@ -193,12 +193,50 @@
    1.13        sum += flow[e];
    1.14      for (InArcIt e(gr, n); e != INVALID; ++e)
    1.15        sum -= flow[e];
    1.16 -    opt = (sum == supply[n]) || (pi[n] == 0);
    1.17 +    if (type != LEQ) {
    1.18 +      opt = (pi[n] <= 0) && (sum == supply[n] || pi[n] == 0);
    1.19 +    } else {
    1.20 +      opt = (pi[n] >= 0) && (sum == supply[n] || pi[n] == 0);
    1.21 +    }
    1.22    }
    1.23    
    1.24    return opt;
    1.25  }
    1.26  
    1.27 +// Check whether the dual cost is equal to the primal cost
    1.28 +template < typename GR, typename LM, typename UM,
    1.29 +           typename CM, typename SM, typename PM >
    1.30 +bool checkDualCost( const GR& gr, const LM& lower, const UM& upper,
    1.31 +                    const CM& cost, const SM& supply, const PM& pi,
    1.32 +                    typename CM::Value total )
    1.33 +{
    1.34 +  TEMPLATE_DIGRAPH_TYPEDEFS(GR);
    1.35 +
    1.36 +  typename CM::Value dual_cost = 0;
    1.37 +  SM red_supply(gr);
    1.38 +  for (NodeIt n(gr); n != INVALID; ++n) {
    1.39 +    red_supply[n] = supply[n];
    1.40 +  }
    1.41 +  for (ArcIt a(gr); a != INVALID; ++a) {
    1.42 +    if (lower[a] != 0) {
    1.43 +      dual_cost += lower[a] * cost[a];
    1.44 +      red_supply[gr.source(a)] -= lower[a];
    1.45 +      red_supply[gr.target(a)] += lower[a];
    1.46 +    }
    1.47 +  }
    1.48 +  
    1.49 +  for (NodeIt n(gr); n != INVALID; ++n) {
    1.50 +    dual_cost -= red_supply[n] * pi[n];
    1.51 +  }
    1.52 +  for (ArcIt a(gr); a != INVALID; ++a) {
    1.53 +    typename CM::Value red_cost =
    1.54 +      cost[a] + pi[gr.source(a)] - pi[gr.target(a)];
    1.55 +    dual_cost -= (upper[a] - lower[a]) * std::max(-red_cost, 0);
    1.56 +  }
    1.57 +  
    1.58 +  return dual_cost == total;
    1.59 +}
    1.60 +
    1.61  // Run a minimum cost flow algorithm and check the results
    1.62  template < typename MCF, typename GR,
    1.63             typename LM, typename UM,
    1.64 @@ -220,8 +258,10 @@
    1.65      check(checkFlow(gr, lower, upper, supply, flow, type),
    1.66            "The flow is not feasible " + test_id);
    1.67      check(mcf.totalCost() == total, "The flow is not optimal " + test_id);
    1.68 -    check(checkPotential(gr, lower, upper, cost, supply, flow, pi),
    1.69 +    check(checkPotential(gr, lower, upper, cost, supply, flow, pi, type),
    1.70            "Wrong potentials " + test_id);
    1.71 +    check(checkDualCost(gr, lower, upper, cost, supply, pi, total),
    1.72 +          "Wrong dual cost " + test_id);
    1.73    }
    1.74  }
    1.75  
    1.76 @@ -266,45 +306,56 @@
    1.77      .node("target", w)
    1.78      .run();
    1.79    
    1.80 -  // Build a test digraph for testing negative costs
    1.81 -  Digraph ngr;
    1.82 -  Node n1 = ngr.addNode();
    1.83 -  Node n2 = ngr.addNode();
    1.84 -  Node n3 = ngr.addNode();
    1.85 -  Node n4 = ngr.addNode();
    1.86 -  Node n5 = ngr.addNode();
    1.87 -  Node n6 = ngr.addNode();
    1.88 -  Node n7 = ngr.addNode();
    1.89 +  // Build test digraphs with negative costs
    1.90 +  Digraph neg_gr;
    1.91 +  Node n1 = neg_gr.addNode();
    1.92 +  Node n2 = neg_gr.addNode();
    1.93 +  Node n3 = neg_gr.addNode();
    1.94 +  Node n4 = neg_gr.addNode();
    1.95 +  Node n5 = neg_gr.addNode();
    1.96 +  Node n6 = neg_gr.addNode();
    1.97 +  Node n7 = neg_gr.addNode();
    1.98    
    1.99 -  Arc a1 = ngr.addArc(n1, n2);
   1.100 -  Arc a2 = ngr.addArc(n1, n3);
   1.101 -  Arc a3 = ngr.addArc(n2, n4);
   1.102 -  Arc a4 = ngr.addArc(n3, n4);
   1.103 -  Arc a5 = ngr.addArc(n3, n2);
   1.104 -  Arc a6 = ngr.addArc(n5, n3);
   1.105 -  Arc a7 = ngr.addArc(n5, n6);
   1.106 -  Arc a8 = ngr.addArc(n6, n7);
   1.107 -  Arc a9 = ngr.addArc(n7, n5);
   1.108 +  Arc a1 = neg_gr.addArc(n1, n2);
   1.109 +  Arc a2 = neg_gr.addArc(n1, n3);
   1.110 +  Arc a3 = neg_gr.addArc(n2, n4);
   1.111 +  Arc a4 = neg_gr.addArc(n3, n4);
   1.112 +  Arc a5 = neg_gr.addArc(n3, n2);
   1.113 +  Arc a6 = neg_gr.addArc(n5, n3);
   1.114 +  Arc a7 = neg_gr.addArc(n5, n6);
   1.115 +  Arc a8 = neg_gr.addArc(n6, n7);
   1.116 +  Arc a9 = neg_gr.addArc(n7, n5);
   1.117    
   1.118 -  Digraph::ArcMap<int> nc(ngr), nl1(ngr, 0), nl2(ngr, 0);
   1.119 -  ConstMap<Arc, int> nu1(std::numeric_limits<int>::max()), nu2(5000);
   1.120 -  Digraph::NodeMap<int> ns(ngr, 0);
   1.121 +  Digraph::ArcMap<int> neg_c(neg_gr), neg_l1(neg_gr, 0), neg_l2(neg_gr, 0);
   1.122 +  ConstMap<Arc, int> neg_u1(std::numeric_limits<int>::max()), neg_u2(5000);
   1.123 +  Digraph::NodeMap<int> neg_s(neg_gr, 0);
   1.124    
   1.125 -  nl2[a7] =  1000;
   1.126 -  nl2[a8] = -1000;
   1.127 +  neg_l2[a7] =  1000;
   1.128 +  neg_l2[a8] = -1000;
   1.129    
   1.130 -  ns[n1] =  100;
   1.131 -  ns[n4] = -100;
   1.132 +  neg_s[n1] =  100;
   1.133 +  neg_s[n4] = -100;
   1.134    
   1.135 -  nc[a1] =  100;
   1.136 -  nc[a2] =   30;
   1.137 -  nc[a3] =   20;
   1.138 -  nc[a4] =   80;
   1.139 -  nc[a5] =   50;
   1.140 -  nc[a6] =   10;
   1.141 -  nc[a7] =   80;
   1.142 -  nc[a8] =   30;
   1.143 -  nc[a9] = -120;
   1.144 +  neg_c[a1] =  100;
   1.145 +  neg_c[a2] =   30;
   1.146 +  neg_c[a3] =   20;
   1.147 +  neg_c[a4] =   80;
   1.148 +  neg_c[a5] =   50;
   1.149 +  neg_c[a6] =   10;
   1.150 +  neg_c[a7] =   80;
   1.151 +  neg_c[a8] =   30;
   1.152 +  neg_c[a9] = -120;
   1.153 +
   1.154 +  Digraph negs_gr;
   1.155 +  Digraph::NodeMap<int> negs_s(negs_gr);
   1.156 +  Digraph::ArcMap<int> negs_c(negs_gr);
   1.157 +  ConstMap<Arc, int> negs_l(0), negs_u(1000);
   1.158 +  n1 = negs_gr.addNode();
   1.159 +  n2 = negs_gr.addNode();
   1.160 +  negs_s[n1] = 100;
   1.161 +  negs_s[n2] = -300;
   1.162 +  negs_c[negs_gr.addArc(n1, n2)] = -1;
   1.163 +
   1.164  
   1.165    // A. Test NetworkSimplex with the default pivot rule
   1.166    {
   1.167 @@ -342,7 +393,7 @@
   1.168      mcf.supplyType(mcf.GEQ);
   1.169      checkMcf(mcf, mcf.lowerMap(l2).run(),
   1.170               gr, l2, u, c, s5, mcf.OPTIMAL, true,   4540, "#A11", GEQ);
   1.171 -    mcf.supplyType(mcf.CARRY_SUPPLIES).supplyMap(s6);
   1.172 +    mcf.supplyMap(s6);
   1.173      checkMcf(mcf, mcf.run(),
   1.174               gr, l2, u, c, s6, mcf.INFEASIBLE, false,  0, "#A12", GEQ);
   1.175  
   1.176 @@ -353,20 +404,26 @@
   1.177               gr, l1, u, c, s6, mcf.OPTIMAL, true,   5080, "#A13", LEQ);
   1.178      checkMcf(mcf, mcf.lowerMap(l2).run(),
   1.179               gr, l2, u, c, s6, mcf.OPTIMAL, true,   5930, "#A14", LEQ);
   1.180 -    mcf.supplyType(mcf.SATISFY_DEMANDS).supplyMap(s5);
   1.181 +    mcf.supplyMap(s5);
   1.182      checkMcf(mcf, mcf.run(),
   1.183               gr, l2, u, c, s5, mcf.INFEASIBLE, false,  0, "#A15", LEQ);
   1.184  
   1.185      // Check negative costs
   1.186 -    NetworkSimplex<Digraph> nmcf(ngr);
   1.187 -    nmcf.lowerMap(nl1).costMap(nc).supplyMap(ns);
   1.188 -    checkMcf(nmcf, nmcf.run(),
   1.189 -      ngr, nl1, nu1, nc, ns, nmcf.UNBOUNDED, false,    0, "#A16");
   1.190 -    checkMcf(nmcf, nmcf.upperMap(nu2).run(),
   1.191 -      ngr, nl1, nu2, nc, ns, nmcf.OPTIMAL, true,  -40000, "#A17");
   1.192 -    nmcf.reset().lowerMap(nl2).costMap(nc).supplyMap(ns);
   1.193 -    checkMcf(nmcf, nmcf.run(),
   1.194 -      ngr, nl2, nu1, nc, ns, nmcf.UNBOUNDED, false,    0, "#A18");
   1.195 +    NetworkSimplex<Digraph> neg_mcf(neg_gr);
   1.196 +    neg_mcf.lowerMap(neg_l1).costMap(neg_c).supplyMap(neg_s);
   1.197 +    checkMcf(neg_mcf, neg_mcf.run(), neg_gr, neg_l1, neg_u1,
   1.198 +      neg_c, neg_s, neg_mcf.UNBOUNDED, false,    0, "#A16");
   1.199 +    neg_mcf.upperMap(neg_u2);
   1.200 +    checkMcf(neg_mcf, neg_mcf.run(), neg_gr, neg_l1, neg_u2,
   1.201 +      neg_c, neg_s, neg_mcf.OPTIMAL, true,  -40000, "#A17");
   1.202 +    neg_mcf.reset().lowerMap(neg_l2).costMap(neg_c).supplyMap(neg_s);
   1.203 +    checkMcf(neg_mcf, neg_mcf.run(), neg_gr, neg_l2, neg_u1,
   1.204 +      neg_c, neg_s, neg_mcf.UNBOUNDED, false,    0, "#A18");
   1.205 +      
   1.206 +    NetworkSimplex<Digraph> negs_mcf(negs_gr);
   1.207 +    negs_mcf.costMap(negs_c).supplyMap(negs_s);
   1.208 +    checkMcf(negs_mcf, negs_mcf.run(), negs_gr, negs_l, negs_u,
   1.209 +      negs_c, negs_s, negs_mcf.OPTIMAL, true, -300, "#A19", GEQ);
   1.210    }
   1.211  
   1.212    // B. Test NetworkSimplex with each pivot rule