1 /* -*- mode: C++; indent-tabs-mode: nil; -*- |
1 /* -*- mode: C++; indent-tabs-mode: nil; -*- |
2 * |
2 * |
3 * This file is a part of LEMON, a generic C++ optimization library. |
3 * This file is a part of LEMON, a generic C++ optimization library. |
4 * |
4 * |
5 * Copyright (C) 2003-2009 |
5 * Copyright (C) 2003-2011 |
6 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport |
6 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport |
7 * (Egervary Research Group on Combinatorial Optimization, EGRES). |
7 * (Egervary Research Group on Combinatorial Optimization, EGRES). |
8 * |
8 * |
9 * Permission to use, modify and distribute this software is granted |
9 * Permission to use, modify and distribute this software is granted |
10 * provided that this copyright notice appears in all copies. For |
10 * provided that this copyright notice appears in all copies. For |
120 typedef concepts::ReadMap<Node, Value> NM; |
120 typedef concepts::ReadMap<Node, Value> NM; |
121 typedef concepts::ReadMap<Arc, Value> VAM; |
121 typedef concepts::ReadMap<Arc, Value> VAM; |
122 typedef concepts::ReadMap<Arc, Cost> CAM; |
122 typedef concepts::ReadMap<Arc, Cost> CAM; |
123 typedef concepts::WriteMap<Arc, Value> FlowMap; |
123 typedef concepts::WriteMap<Arc, Value> FlowMap; |
124 typedef concepts::WriteMap<Node, Cost> PotMap; |
124 typedef concepts::WriteMap<Node, Cost> PotMap; |
125 |
125 |
126 GR g; |
126 GR g; |
127 VAM lower; |
127 VAM lower; |
128 VAM upper; |
128 VAM upper; |
129 CAM cost; |
129 CAM cost; |
130 NM sup; |
130 NM sup; |
174 // Check the feasibility of the given potentials (dual soluiton) |
174 // Check the feasibility of the given potentials (dual soluiton) |
175 // using the "Complementary Slackness" optimality condition |
175 // using the "Complementary Slackness" optimality condition |
176 template < typename GR, typename LM, typename UM, |
176 template < typename GR, typename LM, typename UM, |
177 typename CM, typename SM, typename FM, typename PM > |
177 typename CM, typename SM, typename FM, typename PM > |
178 bool checkPotential( const GR& gr, const LM& lower, const UM& upper, |
178 bool checkPotential( const GR& gr, const LM& lower, const UM& upper, |
179 const CM& cost, const SM& supply, const FM& flow, |
179 const CM& cost, const SM& supply, const FM& flow, |
180 const PM& pi, SupplyType type ) |
180 const PM& pi, SupplyType type ) |
181 { |
181 { |
182 TEMPLATE_DIGRAPH_TYPEDEFS(GR); |
182 TEMPLATE_DIGRAPH_TYPEDEFS(GR); |
183 |
183 |
184 bool opt = true; |
184 bool opt = true; |
187 cost[e] + pi[gr.source(e)] - pi[gr.target(e)]; |
187 cost[e] + pi[gr.source(e)] - pi[gr.target(e)]; |
188 opt = red_cost == 0 || |
188 opt = red_cost == 0 || |
189 (red_cost > 0 && flow[e] == lower[e]) || |
189 (red_cost > 0 && flow[e] == lower[e]) || |
190 (red_cost < 0 && flow[e] == upper[e]); |
190 (red_cost < 0 && flow[e] == upper[e]); |
191 } |
191 } |
192 |
192 |
193 for (NodeIt n(gr); opt && n != INVALID; ++n) { |
193 for (NodeIt n(gr); opt && n != INVALID; ++n) { |
194 typename SM::Value sum = 0; |
194 typename SM::Value sum = 0; |
195 for (OutArcIt e(gr, n); e != INVALID; ++e) |
195 for (OutArcIt e(gr, n); e != INVALID; ++e) |
196 sum += flow[e]; |
196 sum += flow[e]; |
197 for (InArcIt e(gr, n); e != INVALID; ++e) |
197 for (InArcIt e(gr, n); e != INVALID; ++e) |
200 opt = (pi[n] <= 0) && (sum == supply[n] || pi[n] == 0); |
200 opt = (pi[n] <= 0) && (sum == supply[n] || pi[n] == 0); |
201 } else { |
201 } else { |
202 opt = (pi[n] >= 0) && (sum == supply[n] || pi[n] == 0); |
202 opt = (pi[n] >= 0) && (sum == supply[n] || pi[n] == 0); |
203 } |
203 } |
204 } |
204 } |
205 |
205 |
206 return opt; |
206 return opt; |
207 } |
207 } |
208 |
208 |
209 // Check whether the dual cost is equal to the primal cost |
209 // Check whether the dual cost is equal to the primal cost |
210 template < typename GR, typename LM, typename UM, |
210 template < typename GR, typename LM, typename UM, |
225 dual_cost += lower[a] * cost[a]; |
225 dual_cost += lower[a] * cost[a]; |
226 red_supply[gr.source(a)] -= lower[a]; |
226 red_supply[gr.source(a)] -= lower[a]; |
227 red_supply[gr.target(a)] += lower[a]; |
227 red_supply[gr.target(a)] += lower[a]; |
228 } |
228 } |
229 } |
229 } |
230 |
230 |
231 for (NodeIt n(gr); n != INVALID; ++n) { |
231 for (NodeIt n(gr); n != INVALID; ++n) { |
232 dual_cost -= red_supply[n] * pi[n]; |
232 dual_cost -= red_supply[n] * pi[n]; |
233 } |
233 } |
234 for (ArcIt a(gr); a != INVALID; ++a) { |
234 for (ArcIt a(gr); a != INVALID; ++a) { |
235 typename CM::Value red_cost = |
235 typename CM::Value red_cost = |
236 cost[a] + pi[gr.source(a)] - pi[gr.target(a)]; |
236 cost[a] + pi[gr.source(a)] - pi[gr.target(a)]; |
237 dual_cost -= (upper[a] - lower[a]) * std::max(-red_cost, 0); |
237 dual_cost -= (upper[a] - lower[a]) * std::max(-red_cost, 0); |
238 } |
238 } |
239 |
239 |
240 return dual_cost == total; |
240 return dual_cost == total; |
241 } |
241 } |
242 |
242 |
243 // Run a minimum cost flow algorithm and check the results |
243 // Run a minimum cost flow algorithm and check the results |
244 template < typename MCF, typename GR, |
244 template < typename MCF, typename GR, |
306 .nodeMap("sup5", s5) |
306 .nodeMap("sup5", s5) |
307 .nodeMap("sup6", s6) |
307 .nodeMap("sup6", s6) |
308 .node("source", v) |
308 .node("source", v) |
309 .node("target", w) |
309 .node("target", w) |
310 .run(); |
310 .run(); |
311 |
311 |
312 // Build test digraphs with negative costs |
312 // Build test digraphs with negative costs |
313 Digraph neg_gr; |
313 Digraph neg_gr; |
314 Node n1 = neg_gr.addNode(); |
314 Node n1 = neg_gr.addNode(); |
315 Node n2 = neg_gr.addNode(); |
315 Node n2 = neg_gr.addNode(); |
316 Node n3 = neg_gr.addNode(); |
316 Node n3 = neg_gr.addNode(); |
317 Node n4 = neg_gr.addNode(); |
317 Node n4 = neg_gr.addNode(); |
318 Node n5 = neg_gr.addNode(); |
318 Node n5 = neg_gr.addNode(); |
319 Node n6 = neg_gr.addNode(); |
319 Node n6 = neg_gr.addNode(); |
320 Node n7 = neg_gr.addNode(); |
320 Node n7 = neg_gr.addNode(); |
321 |
321 |
322 Arc a1 = neg_gr.addArc(n1, n2); |
322 Arc a1 = neg_gr.addArc(n1, n2); |
323 Arc a2 = neg_gr.addArc(n1, n3); |
323 Arc a2 = neg_gr.addArc(n1, n3); |
324 Arc a3 = neg_gr.addArc(n2, n4); |
324 Arc a3 = neg_gr.addArc(n2, n4); |
325 Arc a4 = neg_gr.addArc(n3, n4); |
325 Arc a4 = neg_gr.addArc(n3, n4); |
326 Arc a5 = neg_gr.addArc(n3, n2); |
326 Arc a5 = neg_gr.addArc(n3, n2); |
327 Arc a6 = neg_gr.addArc(n5, n3); |
327 Arc a6 = neg_gr.addArc(n5, n3); |
328 Arc a7 = neg_gr.addArc(n5, n6); |
328 Arc a7 = neg_gr.addArc(n5, n6); |
329 Arc a8 = neg_gr.addArc(n6, n7); |
329 Arc a8 = neg_gr.addArc(n6, n7); |
330 Arc a9 = neg_gr.addArc(n7, n5); |
330 Arc a9 = neg_gr.addArc(n7, n5); |
331 |
331 |
332 Digraph::ArcMap<int> neg_c(neg_gr), neg_l1(neg_gr, 0), neg_l2(neg_gr, 0); |
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); |
333 ConstMap<Arc, int> neg_u1(std::numeric_limits<int>::max()), neg_u2(5000); |
334 Digraph::NodeMap<int> neg_s(neg_gr, 0); |
334 Digraph::NodeMap<int> neg_s(neg_gr, 0); |
335 |
335 |
336 neg_l2[a7] = 1000; |
336 neg_l2[a7] = 1000; |
337 neg_l2[a8] = -1000; |
337 neg_l2[a8] = -1000; |
338 |
338 |
339 neg_s[n1] = 100; |
339 neg_s[n1] = 100; |
340 neg_s[n4] = -100; |
340 neg_s[n4] = -100; |
341 |
341 |
342 neg_c[a1] = 100; |
342 neg_c[a1] = 100; |
343 neg_c[a2] = 30; |
343 neg_c[a2] = 30; |
344 neg_c[a3] = 20; |
344 neg_c[a3] = 20; |
345 neg_c[a4] = 80; |
345 neg_c[a4] = 80; |
346 neg_c[a5] = 50; |
346 neg_c[a5] = 50; |
420 checkMcf(neg_mcf, neg_mcf.run(), neg_gr, neg_l1, 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"); |
421 neg_c, neg_s, neg_mcf.OPTIMAL, true, -40000, "#A17"); |
422 neg_mcf.reset().lowerMap(neg_l2).costMap(neg_c).supplyMap(neg_s); |
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, |
423 checkMcf(neg_mcf, neg_mcf.run(), neg_gr, neg_l2, neg_u1, |
424 neg_c, neg_s, neg_mcf.UNBOUNDED, false, 0, "#A18"); |
424 neg_c, neg_s, neg_mcf.UNBOUNDED, false, 0, "#A18"); |
425 |
425 |
426 NetworkSimplex<Digraph> negs_mcf(negs_gr); |
426 NetworkSimplex<Digraph> negs_mcf(negs_gr); |
427 negs_mcf.costMap(negs_c).supplyMap(negs_s); |
427 negs_mcf.costMap(negs_c).supplyMap(negs_s); |
428 checkMcf(negs_mcf, negs_mcf.run(), negs_gr, negs_l, negs_u, |
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); |
429 negs_c, negs_s, negs_mcf.OPTIMAL, true, -300, "#A19", GEQ); |
430 } |
430 } |