1 /* -*- mode: C++; indent-tabs-mode: nil; -*-
3 * This file is a part of LEMON, a generic C++ optimization library.
5 * Copyright (C) 2003-2009
6 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7 * (Egervary Research Group on Combinatorial Optimization, EGRES).
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.
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
22 #include <lemon/list_graph.h>
23 #include <lemon/smart_graph.h>
24 #include <lemon/lgf_reader.h>
26 //#include <lemon/cycle_canceling.h>
27 //#include <lemon/capacity_scaling.h>
28 //#include <lemon/cost_scaling.h>
29 #include <lemon/network_simplex.h>
30 //#include <lemon/min_cost_flow.h>
31 //#include <lemon/min_cost_max_flow.h>
33 #include <lemon/concepts/digraph.h>
34 #include <lemon/concept_check.h>
36 #include "test_tools.h"
38 using namespace lemon;
42 "label sup1 sup2 sup3\n"
57 " cost cap low1 low2\n"
85 // Check the interface of an MCF algorithm
86 template <typename GR, typename Value>
91 template <typename MCF>
94 checkConcept<concepts::Digraph, GR>();
96 MCF mcf_test1(g, lower, upper, cost, sup);
97 MCF mcf_test2(g, upper, cost, sup);
98 MCF mcf_test3(g, lower, upper, cost, n, n, k);
99 MCF mcf_test4(g, upper, cost, n, n, k);
101 // TODO: This part should be enabled and the next part
102 // should be removed if map copying is supported
104 flow = mcf_test1.flowMap();
105 mcf_test1.flowMap(flow);
107 pot = mcf_test1.potentialMap();
108 mcf_test1.potentialMap(pot);
111 const typename MCF::FlowMap &fm =
113 mcf_test1.flowMap(flow);
114 const typename MCF::PotentialMap &pm =
115 mcf_test1.potentialMap();
116 mcf_test1.potentialMap(pot);
117 ignore_unused_variable_warning(fm);
118 ignore_unused_variable_warning(pm);
123 v = mcf_test1.totalCost();
124 v = mcf_test1.flow(a);
125 v = mcf_test1.potential(n);
128 typedef typename GR::Node Node;
129 typedef typename GR::Arc Arc;
130 typedef concepts::ReadMap<Node, Value> NM;
131 typedef concepts::ReadMap<Arc, Value> AM;
143 typename MCF::FlowMap &flow;
144 typename MCF::PotentialMap &pot;
150 // Check the feasibility of the given flow (primal soluiton)
151 template < typename GR, typename LM, typename UM,
152 typename SM, typename FM >
153 bool checkFlow( const GR& gr, const LM& lower, const UM& upper,
154 const SM& supply, const FM& flow )
156 TEMPLATE_DIGRAPH_TYPEDEFS(GR);
158 for (ArcIt e(gr); e != INVALID; ++e) {
159 if (flow[e] < lower[e] || flow[e] > upper[e]) return false;
162 for (NodeIt n(gr); n != INVALID; ++n) {
163 typename SM::Value sum = 0;
164 for (OutArcIt e(gr, n); e != INVALID; ++e)
166 for (InArcIt e(gr, n); e != INVALID; ++e)
168 if (sum != supply[n]) return false;
174 // Check the feasibility of the given potentials (dual soluiton)
175 // using the Complementary Slackness optimality condition
176 template < typename GR, typename LM, typename UM,
177 typename CM, typename FM, typename PM >
178 bool checkPotential( const GR& gr, const LM& lower, const UM& upper,
179 const CM& cost, const FM& flow, const PM& pi )
181 TEMPLATE_DIGRAPH_TYPEDEFS(GR);
184 for (ArcIt e(gr); opt && e != INVALID; ++e) {
185 typename CM::Value red_cost =
186 cost[e] + pi[gr.source(e)] - pi[gr.target(e)];
187 opt = red_cost == 0 ||
188 (red_cost > 0 && flow[e] == lower[e]) ||
189 (red_cost < 0 && flow[e] == upper[e]);
194 // Run a minimum cost flow algorithm and check the results
195 template < typename MCF, typename GR,
196 typename LM, typename UM,
197 typename CM, typename SM >
198 void checkMcf( const MCF& mcf, bool mcf_result,
199 const GR& gr, const LM& lower, const UM& upper,
200 const CM& cost, const SM& supply,
201 bool result, typename CM::Value total,
202 const std::string &test_id = "" )
204 check(mcf_result == result, "Wrong result " + test_id);
206 check(checkFlow(gr, lower, upper, supply, mcf.flowMap()),
207 "The flow is not feasible " + test_id);
208 check(mcf.totalCost() == total, "The flow is not optimal " + test_id);
209 check(checkPotential(gr, lower, upper, cost, mcf.flowMap(),
211 "Wrong potentials " + test_id);
217 // Check the interfaces
220 // This typedef should be enabled if the standard maps are
221 // reference maps in the graph concepts
222 //typedef concepts::Digraph GR;
223 typedef ListDigraph GR;
224 typedef concepts::ReadMap<GR::Node, Value> NM;
225 typedef concepts::ReadMap<GR::Arc, Value> AM;
227 //checkConcept< McfClassConcept<GR, Value>,
228 // CycleCanceling<GR, AM, AM, AM, NM> >();
229 //checkConcept< McfClassConcept<GR, Value>,
230 // CapacityScaling<GR, AM, AM, AM, NM> >();
231 //checkConcept< McfClassConcept<GR, Value>,
232 // CostScaling<GR, AM, AM, AM, NM> >();
233 checkConcept< McfClassConcept<GR, Value>,
234 NetworkSimplex<GR, AM, AM, AM, NM> >();
235 //checkConcept< MinCostFlow<GR, Value>,
236 // NetworkSimplex<GR, AM, AM, AM, NM> >();
239 // Run various MCF tests
240 typedef ListDigraph Digraph;
241 DIGRAPH_TYPEDEFS(ListDigraph);
243 // Read the test digraph
245 Digraph::ArcMap<int> c(gr), l1(gr), l2(gr), u(gr);
246 Digraph::NodeMap<int> s1(gr), s2(gr), s3(gr);
249 std::istringstream input(test_lgf);
250 DigraphReader<Digraph>(gr, input)
263 // A. Test CapacityScaling with scaling
265 CapacityScaling<Digraph> mcf1(gr, u, c, s1);
266 CapacityScaling<Digraph> mcf2(gr, u, c, v, w, 27);
267 CapacityScaling<Digraph> mcf3(gr, u, c, s3);
268 CapacityScaling<Digraph> mcf4(gr, l2, u, c, s1);
269 CapacityScaling<Digraph> mcf5(gr, l2, u, c, v, w, 27);
270 CapacityScaling<Digraph> mcf6(gr, l2, u, c, s3);
272 checkMcf(mcf1, mcf1.run(), gr, l1, u, c, s1, true, 5240, "#A1");
273 checkMcf(mcf2, mcf2.run(), gr, l1, u, c, s2, true, 7620, "#A2");
274 checkMcf(mcf3, mcf3.run(), gr, l1, u, c, s3, true, 0, "#A3");
275 checkMcf(mcf4, mcf4.run(), gr, l2, u, c, s1, true, 5970, "#A4");
276 checkMcf(mcf5, mcf5.run(), gr, l2, u, c, s2, true, 8010, "#A5");
277 checkMcf(mcf6, mcf6.run(), gr, l2, u, c, s3, false, 0, "#A6");
280 // B. Test CapacityScaling without scaling
282 CapacityScaling<Digraph> mcf1(gr, u, c, s1);
283 CapacityScaling<Digraph> mcf2(gr, u, c, v, w, 27);
284 CapacityScaling<Digraph> mcf3(gr, u, c, s3);
285 CapacityScaling<Digraph> mcf4(gr, l2, u, c, s1);
286 CapacityScaling<Digraph> mcf5(gr, l2, u, c, v, w, 27);
287 CapacityScaling<Digraph> mcf6(gr, l2, u, c, s3);
289 checkMcf(mcf1, mcf1.run(false), gr, l1, u, c, s1, true, 5240, "#B1");
290 checkMcf(mcf2, mcf2.run(false), gr, l1, u, c, s2, true, 7620, "#B2");
291 checkMcf(mcf3, mcf3.run(false), gr, l1, u, c, s3, true, 0, "#B3");
292 checkMcf(mcf4, mcf4.run(false), gr, l2, u, c, s1, true, 5970, "#B4");
293 checkMcf(mcf5, mcf5.run(false), gr, l2, u, c, s2, true, 8010, "#B5");
294 checkMcf(mcf6, mcf6.run(false), gr, l2, u, c, s3, false, 0, "#B6");
297 // C. Test CostScaling using partial augment-relabel method
299 CostScaling<Digraph> mcf1(gr, u, c, s1);
300 CostScaling<Digraph> mcf2(gr, u, c, v, w, 27);
301 CostScaling<Digraph> mcf3(gr, u, c, s3);
302 CostScaling<Digraph> mcf4(gr, l2, u, c, s1);
303 CostScaling<Digraph> mcf5(gr, l2, u, c, v, w, 27);
304 CostScaling<Digraph> mcf6(gr, l2, u, c, s3);
306 checkMcf(mcf1, mcf1.run(), gr, l1, u, c, s1, true, 5240, "#C1");
307 checkMcf(mcf2, mcf2.run(), gr, l1, u, c, s2, true, 7620, "#C2");
308 checkMcf(mcf3, mcf3.run(), gr, l1, u, c, s3, true, 0, "#C3");
309 checkMcf(mcf4, mcf4.run(), gr, l2, u, c, s1, true, 5970, "#C4");
310 checkMcf(mcf5, mcf5.run(), gr, l2, u, c, s2, true, 8010, "#C5");
311 checkMcf(mcf6, mcf6.run(), gr, l2, u, c, s3, false, 0, "#C6");
314 // D. Test CostScaling using push-relabel method
316 CostScaling<Digraph> mcf1(gr, u, c, s1);
317 CostScaling<Digraph> mcf2(gr, u, c, v, w, 27);
318 CostScaling<Digraph> mcf3(gr, u, c, s3);
319 CostScaling<Digraph> mcf4(gr, l2, u, c, s1);
320 CostScaling<Digraph> mcf5(gr, l2, u, c, v, w, 27);
321 CostScaling<Digraph> mcf6(gr, l2, u, c, s3);
323 checkMcf(mcf1, mcf1.run(false), gr, l1, u, c, s1, true, 5240, "#D1");
324 checkMcf(mcf2, mcf2.run(false), gr, l1, u, c, s2, true, 7620, "#D2");
325 checkMcf(mcf3, mcf3.run(false), gr, l1, u, c, s3, true, 0, "#D3");
326 checkMcf(mcf4, mcf4.run(false), gr, l2, u, c, s1, true, 5970, "#D4");
327 checkMcf(mcf5, mcf5.run(false), gr, l2, u, c, s2, true, 8010, "#D5");
328 checkMcf(mcf6, mcf6.run(false), gr, l2, u, c, s3, false, 0, "#D6");
332 // E. Test NetworkSimplex with FIRST_ELIGIBLE_PIVOT
334 NetworkSimplex<Digraph>::PivotRuleEnum pr =
335 NetworkSimplex<Digraph>::FIRST_ELIGIBLE_PIVOT;
336 NetworkSimplex<Digraph> mcf1(gr, u, c, s1);
337 NetworkSimplex<Digraph> mcf2(gr, u, c, v, w, 27);
338 NetworkSimplex<Digraph> mcf3(gr, u, c, s3);
339 NetworkSimplex<Digraph> mcf4(gr, l2, u, c, s1);
340 NetworkSimplex<Digraph> mcf5(gr, l2, u, c, v, w, 27);
341 NetworkSimplex<Digraph> mcf6(gr, l2, u, c, s3);
343 checkMcf(mcf1, mcf1.run(pr), gr, l1, u, c, s1, true, 5240, "#E1");
344 checkMcf(mcf2, mcf2.run(pr), gr, l1, u, c, s2, true, 7620, "#E2");
345 checkMcf(mcf3, mcf3.run(pr), gr, l1, u, c, s3, true, 0, "#E3");
346 checkMcf(mcf4, mcf4.run(pr), gr, l2, u, c, s1, true, 5970, "#E4");
347 checkMcf(mcf5, mcf5.run(pr), gr, l2, u, c, s2, true, 8010, "#E5");
348 checkMcf(mcf6, mcf6.run(pr), gr, l2, u, c, s3, false, 0, "#E6");
351 // F. Test NetworkSimplex with BEST_ELIGIBLE_PIVOT
353 NetworkSimplex<Digraph>::PivotRuleEnum pr =
354 NetworkSimplex<Digraph>::BEST_ELIGIBLE_PIVOT;
355 NetworkSimplex<Digraph> mcf1(gr, u, c, s1);
356 NetworkSimplex<Digraph> mcf2(gr, u, c, v, w, 27);
357 NetworkSimplex<Digraph> mcf3(gr, u, c, s3);
358 NetworkSimplex<Digraph> mcf4(gr, l2, u, c, s1);
359 NetworkSimplex<Digraph> mcf5(gr, l2, u, c, v, w, 27);
360 NetworkSimplex<Digraph> mcf6(gr, l2, u, c, s3);
362 checkMcf(mcf1, mcf1.run(pr), gr, l1, u, c, s1, true, 5240, "#F1");
363 checkMcf(mcf2, mcf2.run(pr), gr, l1, u, c, s2, true, 7620, "#F2");
364 checkMcf(mcf3, mcf3.run(pr), gr, l1, u, c, s3, true, 0, "#F3");
365 checkMcf(mcf4, mcf4.run(pr), gr, l2, u, c, s1, true, 5970, "#F4");
366 checkMcf(mcf5, mcf5.run(pr), gr, l2, u, c, s2, true, 8010, "#F5");
367 checkMcf(mcf6, mcf6.run(pr), gr, l2, u, c, s3, false, 0, "#F6");
370 // G. Test NetworkSimplex with BLOCK_SEARCH_PIVOT
372 NetworkSimplex<Digraph>::PivotRuleEnum pr =
373 NetworkSimplex<Digraph>::BLOCK_SEARCH_PIVOT;
374 NetworkSimplex<Digraph> mcf1(gr, u, c, s1);
375 NetworkSimplex<Digraph> mcf2(gr, u, c, v, w, 27);
376 NetworkSimplex<Digraph> mcf3(gr, u, c, s3);
377 NetworkSimplex<Digraph> mcf4(gr, l2, u, c, s1);
378 NetworkSimplex<Digraph> mcf5(gr, l2, u, c, v, w, 27);
379 NetworkSimplex<Digraph> mcf6(gr, l2, u, c, s3);
381 checkMcf(mcf1, mcf1.run(pr), gr, l1, u, c, s1, true, 5240, "#G1");
382 checkMcf(mcf2, mcf2.run(pr), gr, l1, u, c, s2, true, 7620, "#G2");
383 checkMcf(mcf3, mcf3.run(pr), gr, l1, u, c, s3, true, 0, "#G3");
384 checkMcf(mcf4, mcf4.run(pr), gr, l2, u, c, s1, true, 5970, "#G4");
385 checkMcf(mcf5, mcf5.run(pr), gr, l2, u, c, s2, true, 8010, "#G5");
386 checkMcf(mcf6, mcf6.run(pr), gr, l2, u, c, s3, false, 0, "#G6");
389 // H. Test NetworkSimplex with CANDIDATE_LIST_PIVOT
391 NetworkSimplex<Digraph>::PivotRuleEnum pr =
392 NetworkSimplex<Digraph>::CANDIDATE_LIST_PIVOT;
393 NetworkSimplex<Digraph> mcf1(gr, u, c, s1);
394 NetworkSimplex<Digraph> mcf2(gr, u, c, v, w, 27);
395 NetworkSimplex<Digraph> mcf3(gr, u, c, s3);
396 NetworkSimplex<Digraph> mcf4(gr, l2, u, c, s1);
397 NetworkSimplex<Digraph> mcf5(gr, l2, u, c, v, w, 27);
398 NetworkSimplex<Digraph> mcf6(gr, l2, u, c, s3);
400 checkMcf(mcf1, mcf1.run(pr), gr, l1, u, c, s1, true, 5240, "#H1");
401 checkMcf(mcf2, mcf2.run(pr), gr, l1, u, c, s2, true, 7620, "#H2");
402 checkMcf(mcf3, mcf3.run(pr), gr, l1, u, c, s3, true, 0, "#H3");
403 checkMcf(mcf4, mcf4.run(pr), gr, l2, u, c, s1, true, 5970, "#H4");
404 checkMcf(mcf5, mcf5.run(pr), gr, l2, u, c, s2, true, 8010, "#H5");
405 checkMcf(mcf6, mcf6.run(pr), gr, l2, u, c, s3, false, 0, "#H6");
408 // I. Test NetworkSimplex with ALTERING_LIST_PIVOT
410 NetworkSimplex<Digraph>::PivotRuleEnum pr =
411 NetworkSimplex<Digraph>::ALTERING_LIST_PIVOT;
412 NetworkSimplex<Digraph> mcf1(gr, u, c, s1);
413 NetworkSimplex<Digraph> mcf2(gr, u, c, v, w, 27);
414 NetworkSimplex<Digraph> mcf3(gr, u, c, s3);
415 NetworkSimplex<Digraph> mcf4(gr, l2, u, c, s1);
416 NetworkSimplex<Digraph> mcf5(gr, l2, u, c, v, w, 27);
417 NetworkSimplex<Digraph> mcf6(gr, l2, u, c, s3);
419 checkMcf(mcf1, mcf1.run(pr), gr, l1, u, c, s1, true, 5240, "#I1");
420 checkMcf(mcf2, mcf2.run(pr), gr, l1, u, c, s2, true, 7620, "#I2");
421 checkMcf(mcf3, mcf3.run(pr), gr, l1, u, c, s3, true, 0, "#I3");
422 checkMcf(mcf4, mcf4.run(pr), gr, l2, u, c, s1, true, 5970, "#I4");
423 checkMcf(mcf5, mcf5.run(pr), gr, l2, u, c, s2, true, 8010, "#I5");
424 checkMcf(mcf6, mcf6.run(pr), gr, l2, u, c, s3, false, 0, "#I6");
428 // J. Test MinCostFlow
430 MinCostFlow<Digraph> mcf1(gr, u, c, s1);
431 MinCostFlow<Digraph> mcf2(gr, u, c, v, w, 27);
432 MinCostFlow<Digraph> mcf3(gr, u, c, s3);
433 MinCostFlow<Digraph> mcf4(gr, l2, u, c, s1);
434 MinCostFlow<Digraph> mcf5(gr, l2, u, c, v, w, 27);
435 MinCostFlow<Digraph> mcf6(gr, l2, u, c, s3);
437 checkMcf(mcf1, mcf1.run(), gr, l1, u, c, s1, true, 5240, "#J1");
438 checkMcf(mcf2, mcf2.run(), gr, l1, u, c, s2, true, 7620, "#J2");
439 checkMcf(mcf3, mcf3.run(), gr, l1, u, c, s3, true, 0, "#J3");
440 checkMcf(mcf4, mcf4.run(), gr, l2, u, c, s1, true, 5970, "#J4");
441 checkMcf(mcf5, mcf5.run(), gr, l2, u, c, s2, true, 8010, "#J5");
442 checkMcf(mcf6, mcf6.run(), gr, l2, u, c, s3, false, 0, "#J6");
446 // K. Test MinCostMaxFlow
448 MinCostMaxFlow<Digraph> mcmf(gr, u, c, v, w);
450 checkMcf(mcmf, true, gr, l1, u, c, s3, true, 7620, "#K1");