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-2010 |
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 |
178 typedef concepts::ReadMap<Node, Value> NM; |
178 typedef concepts::ReadMap<Node, Value> NM; |
179 typedef concepts::ReadMap<Arc, Value> VAM; |
179 typedef concepts::ReadMap<Arc, Value> VAM; |
180 typedef concepts::ReadMap<Arc, Cost> CAM; |
180 typedef concepts::ReadMap<Arc, Cost> CAM; |
181 typedef concepts::WriteMap<Arc, Value> FlowMap; |
181 typedef concepts::WriteMap<Arc, Value> FlowMap; |
182 typedef concepts::WriteMap<Node, Cost> PotMap; |
182 typedef concepts::WriteMap<Node, Cost> PotMap; |
183 |
183 |
184 GR g; |
184 GR g; |
185 VAM lower; |
185 VAM lower; |
186 VAM upper; |
186 VAM upper; |
187 CAM cost; |
187 CAM cost; |
188 NM sup; |
188 NM sup; |
232 // Check the feasibility of the given potentials (dual soluiton) |
232 // Check the feasibility of the given potentials (dual soluiton) |
233 // using the "Complementary Slackness" optimality condition |
233 // using the "Complementary Slackness" optimality condition |
234 template < typename GR, typename LM, typename UM, |
234 template < typename GR, typename LM, typename UM, |
235 typename CM, typename SM, typename FM, typename PM > |
235 typename CM, typename SM, typename FM, typename PM > |
236 bool checkPotential( const GR& gr, const LM& lower, const UM& upper, |
236 bool checkPotential( const GR& gr, const LM& lower, const UM& upper, |
237 const CM& cost, const SM& supply, const FM& flow, |
237 const CM& cost, const SM& supply, const FM& flow, |
238 const PM& pi, SupplyType type ) |
238 const PM& pi, SupplyType type ) |
239 { |
239 { |
240 TEMPLATE_DIGRAPH_TYPEDEFS(GR); |
240 TEMPLATE_DIGRAPH_TYPEDEFS(GR); |
241 |
241 |
242 bool opt = true; |
242 bool opt = true; |
245 cost[e] + pi[gr.source(e)] - pi[gr.target(e)]; |
245 cost[e] + pi[gr.source(e)] - pi[gr.target(e)]; |
246 opt = red_cost == 0 || |
246 opt = red_cost == 0 || |
247 (red_cost > 0 && flow[e] == lower[e]) || |
247 (red_cost > 0 && flow[e] == lower[e]) || |
248 (red_cost < 0 && flow[e] == upper[e]); |
248 (red_cost < 0 && flow[e] == upper[e]); |
249 } |
249 } |
250 |
250 |
251 for (NodeIt n(gr); opt && n != INVALID; ++n) { |
251 for (NodeIt n(gr); opt && n != INVALID; ++n) { |
252 typename SM::Value sum = 0; |
252 typename SM::Value sum = 0; |
253 for (OutArcIt e(gr, n); e != INVALID; ++e) |
253 for (OutArcIt e(gr, n); e != INVALID; ++e) |
254 sum += flow[e]; |
254 sum += flow[e]; |
255 for (InArcIt e(gr, n); e != INVALID; ++e) |
255 for (InArcIt e(gr, n); e != INVALID; ++e) |
258 opt = (pi[n] <= 0) && (sum == supply[n] || pi[n] == 0); |
258 opt = (pi[n] <= 0) && (sum == supply[n] || pi[n] == 0); |
259 } else { |
259 } else { |
260 opt = (pi[n] >= 0) && (sum == supply[n] || pi[n] == 0); |
260 opt = (pi[n] >= 0) && (sum == supply[n] || pi[n] == 0); |
261 } |
261 } |
262 } |
262 } |
263 |
263 |
264 return opt; |
264 return opt; |
265 } |
265 } |
266 |
266 |
267 // Check whether the dual cost is equal to the primal cost |
267 // Check whether the dual cost is equal to the primal cost |
268 template < typename GR, typename LM, typename UM, |
268 template < typename GR, typename LM, typename UM, |
283 dual_cost += lower[a] * cost[a]; |
283 dual_cost += lower[a] * cost[a]; |
284 red_supply[gr.source(a)] -= lower[a]; |
284 red_supply[gr.source(a)] -= lower[a]; |
285 red_supply[gr.target(a)] += lower[a]; |
285 red_supply[gr.target(a)] += lower[a]; |
286 } |
286 } |
287 } |
287 } |
288 |
288 |
289 for (NodeIt n(gr); n != INVALID; ++n) { |
289 for (NodeIt n(gr); n != INVALID; ++n) { |
290 dual_cost -= red_supply[n] * pi[n]; |
290 dual_cost -= red_supply[n] * pi[n]; |
291 } |
291 } |
292 for (ArcIt a(gr); a != INVALID; ++a) { |
292 for (ArcIt a(gr); a != INVALID; ++a) { |
293 typename CM::Value red_cost = |
293 typename CM::Value red_cost = |
294 cost[a] + pi[gr.source(a)] - pi[gr.target(a)]; |
294 cost[a] + pi[gr.source(a)] - pi[gr.target(a)]; |
295 dual_cost -= (upper[a] - lower[a]) * std::max(-red_cost, 0); |
295 dual_cost -= (upper[a] - lower[a]) * std::max(-red_cost, 0); |
296 } |
296 } |
297 |
297 |
298 return dual_cost == total; |
298 return dual_cost == total; |
299 } |
299 } |
300 |
300 |
301 // Run a minimum cost flow algorithm and check the results |
301 // Run a minimum cost flow algorithm and check the results |
302 template < typename MCF, typename GR, |
302 template < typename MCF, typename GR, |
330 void runMcfGeqTests( Param param, |
330 void runMcfGeqTests( Param param, |
331 const std::string &test_str = "", |
331 const std::string &test_str = "", |
332 bool full_neg_cost_support = false ) |
332 bool full_neg_cost_support = false ) |
333 { |
333 { |
334 MCF mcf1(gr), mcf2(neg1_gr), mcf3(neg2_gr); |
334 MCF mcf1(gr), mcf2(neg1_gr), mcf3(neg2_gr); |
335 |
335 |
336 // Basic tests |
336 // Basic tests |
337 mcf1.upperMap(u).costMap(c).supplyMap(s1); |
337 mcf1.upperMap(u).costMap(c).supplyMap(s1); |
338 checkMcf(mcf1, mcf1.run(param), gr, l1, u, c, s1, |
338 checkMcf(mcf1, mcf1.run(param), gr, l1, u, c, s1, |
339 mcf1.OPTIMAL, true, 5240, test_str + "-1"); |
339 mcf1.OPTIMAL, true, 5240, test_str + "-1"); |
340 mcf1.stSupply(v, w, 27); |
340 mcf1.stSupply(v, w, 27); |
433 .nodeMap("sup5", s5) |
433 .nodeMap("sup5", s5) |
434 .nodeMap("sup6", s6) |
434 .nodeMap("sup6", s6) |
435 .node("source", v) |
435 .node("source", v) |
436 .node("target", w) |
436 .node("target", w) |
437 .run(); |
437 .run(); |
438 |
438 |
439 std::istringstream neg_inp1(test_neg1_lgf); |
439 std::istringstream neg_inp1(test_neg1_lgf); |
440 DigraphReader<Digraph>(neg1_gr, neg_inp1) |
440 DigraphReader<Digraph>(neg1_gr, neg_inp1) |
441 .arcMap("cost", neg1_c) |
441 .arcMap("cost", neg1_c) |
442 .arcMap("low1", neg1_l1) |
442 .arcMap("low1", neg1_l1) |
443 .arcMap("low2", neg1_l2) |
443 .arcMap("low2", neg1_l2) |
444 .nodeMap("sup", neg1_s) |
444 .nodeMap("sup", neg1_s) |
445 .run(); |
445 .run(); |
446 |
446 |
447 std::istringstream neg_inp2(test_neg2_lgf); |
447 std::istringstream neg_inp2(test_neg2_lgf); |
448 DigraphReader<Digraph>(neg2_gr, neg_inp2) |
448 DigraphReader<Digraph>(neg2_gr, neg_inp2) |
449 .arcMap("cost", neg2_c) |
449 .arcMap("cost", neg2_c) |
450 .nodeMap("sup", neg2_s) |
450 .nodeMap("sup", neg2_s) |
451 .run(); |
451 .run(); |
452 |
452 |
453 // Check the interface of NetworkSimplex |
453 // Check the interface of NetworkSimplex |
454 { |
454 { |
455 typedef concepts::Digraph GR; |
455 typedef concepts::Digraph GR; |
456 checkConcept< McfClassConcept<GR, int, int>, |
456 checkConcept< McfClassConcept<GR, int, int>, |
457 NetworkSimplex<GR> >(); |
457 NetworkSimplex<GR> >(); |
499 checkConcept< McfClassConcept<GR, int, double>, |
499 checkConcept< McfClassConcept<GR, int, double>, |
500 CycleCanceling<GR, int, double> >(); |
500 CycleCanceling<GR, int, double> >(); |
501 } |
501 } |
502 |
502 |
503 // Test NetworkSimplex |
503 // Test NetworkSimplex |
504 { |
504 { |
505 typedef NetworkSimplex<Digraph> MCF; |
505 typedef NetworkSimplex<Digraph> MCF; |
506 runMcfGeqTests<MCF>(MCF::FIRST_ELIGIBLE, "NS-FE", true); |
506 runMcfGeqTests<MCF>(MCF::FIRST_ELIGIBLE, "NS-FE", true); |
507 runMcfLeqTests<MCF>(MCF::FIRST_ELIGIBLE, "NS-FE"); |
507 runMcfLeqTests<MCF>(MCF::FIRST_ELIGIBLE, "NS-FE"); |
508 runMcfGeqTests<MCF>(MCF::BEST_ELIGIBLE, "NS-BE", true); |
508 runMcfGeqTests<MCF>(MCF::BEST_ELIGIBLE, "NS-BE", true); |
509 runMcfLeqTests<MCF>(MCF::BEST_ELIGIBLE, "NS-BE"); |
509 runMcfLeqTests<MCF>(MCF::BEST_ELIGIBLE, "NS-BE"); |
512 runMcfGeqTests<MCF>(MCF::CANDIDATE_LIST, "NS-CL", true); |
512 runMcfGeqTests<MCF>(MCF::CANDIDATE_LIST, "NS-CL", true); |
513 runMcfLeqTests<MCF>(MCF::CANDIDATE_LIST, "NS-CL"); |
513 runMcfLeqTests<MCF>(MCF::CANDIDATE_LIST, "NS-CL"); |
514 runMcfGeqTests<MCF>(MCF::ALTERING_LIST, "NS-AL", true); |
514 runMcfGeqTests<MCF>(MCF::ALTERING_LIST, "NS-AL", true); |
515 runMcfLeqTests<MCF>(MCF::ALTERING_LIST, "NS-AL"); |
515 runMcfLeqTests<MCF>(MCF::ALTERING_LIST, "NS-AL"); |
516 } |
516 } |
517 |
517 |
518 // Test CapacityScaling |
518 // Test CapacityScaling |
519 { |
519 { |
520 typedef CapacityScaling<Digraph> MCF; |
520 typedef CapacityScaling<Digraph> MCF; |
521 runMcfGeqTests<MCF>(0, "SSP"); |
521 runMcfGeqTests<MCF>(0, "SSP"); |
522 runMcfGeqTests<MCF>(2, "CAS"); |
522 runMcfGeqTests<MCF>(2, "CAS"); |