Ticket #234: ns-port-697d61bb33f4.patch
File ns-port-697d61bb33f4.patch, 55.0 KB (added by , 16 years ago) |
---|
-
new file lemon/network_simplex.h
# HG changeset patch # User Peter Kovacs <kpeter@inf.elte.hu> # Date 1235429870 -3600 # Node ID 697d61bb33f4091237b3c97d301921b39e8c435c # Parent 1c5d6e47921f736a22b2dc4c891111cc8235c9e0 Port NetworkSimplex from SVN -r3520 diff --git a/lemon/network_simplex.h b/lemon/network_simplex.h new file mode 100644
- + 1 /* -*- mode: C++; indent-tabs-mode: nil; -*- 2 * 3 * This file is a part of LEMON, a generic C++ optimization library. 4 * 5 * Copyright (C) 2003-2009 6 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport 7 * (Egervary Research Group on Combinatorial Optimization, EGRES). 8 * 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. 12 * 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 15 * purpose. 16 * 17 */ 18 19 #ifndef LEMON_NETWORK_SIMPLEX_H 20 #define LEMON_NETWORK_SIMPLEX_H 21 22 /// \ingroup min_cost_flow 23 /// 24 /// \file 25 /// \brief Network simplex algorithm for finding a minimum cost flow. 26 27 #include <vector> 28 #include <limits> 29 #include <algorithm> 30 31 #include <lemon/math.h> 32 33 namespace lemon { 34 35 /// \addtogroup min_cost_flow 36 /// @{ 37 38 /// \brief Implementation of the primal network simplex algorithm 39 /// for finding a \ref min_cost_flow "minimum cost flow". 40 /// 41 /// \ref NetworkSimplex implements the primal network simplex algorithm 42 /// for finding a \ref min_cost_flow "minimum cost flow". 43 /// 44 /// \tparam Digraph The digraph type the algorithm runs on. 45 /// \tparam LowerMap The type of the lower bound map. 46 /// \tparam CapacityMap The type of the capacity (upper bound) map. 47 /// \tparam CostMap The type of the cost (length) map. 48 /// \tparam SupplyMap The type of the supply map. 49 /// 50 /// \warning 51 /// - Arc capacities and costs should be \e non-negative \e integers. 52 /// - Supply values should be \e signed \e integers. 53 /// - The value types of the maps should be convertible to each other. 54 /// - \c CostMap::Value must be signed type. 55 /// 56 /// \note \ref NetworkSimplex provides five different pivot rule 57 /// implementations that significantly affect the efficiency of the 58 /// algorithm. 59 /// By default "Block Search" pivot rule is used, which proved to be 60 /// by far the most efficient according to our benchmark tests. 61 /// However another pivot rule can be selected using \ref run() 62 /// function with the proper parameter. 63 #ifdef DOXYGEN 64 template < typename Digraph, 65 typename LowerMap, 66 typename CapacityMap, 67 typename CostMap, 68 typename SupplyMap > 69 70 #else 71 template < typename Digraph, 72 typename LowerMap = typename Digraph::template ArcMap<int>, 73 typename CapacityMap = typename Digraph::template ArcMap<int>, 74 typename CostMap = typename Digraph::template ArcMap<int>, 75 typename SupplyMap = typename Digraph::template NodeMap<int> > 76 #endif 77 class NetworkSimplex 78 { 79 TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); 80 81 typedef typename CapacityMap::Value Capacity; 82 typedef typename CostMap::Value Cost; 83 typedef typename SupplyMap::Value Supply; 84 85 typedef std::vector<Arc> ArcVector; 86 typedef std::vector<Node> NodeVector; 87 typedef std::vector<int> IntVector; 88 typedef std::vector<bool> BoolVector; 89 typedef std::vector<Capacity> CapacityVector; 90 typedef std::vector<Cost> CostVector; 91 typedef std::vector<Supply> SupplyVector; 92 93 public: 94 95 /// The type of the flow map 96 typedef typename Digraph::template ArcMap<Capacity> FlowMap; 97 /// The type of the potential map 98 typedef typename Digraph::template NodeMap<Cost> PotentialMap; 99 100 public: 101 102 /// Enum type for selecting the pivot rule used by \ref run() 103 enum PivotRuleEnum { 104 FIRST_ELIGIBLE_PIVOT, 105 BEST_ELIGIBLE_PIVOT, 106 BLOCK_SEARCH_PIVOT, 107 CANDIDATE_LIST_PIVOT, 108 ALTERING_LIST_PIVOT 109 }; 110 111 private: 112 113 // State constants for arcs 114 enum ArcStateEnum { 115 STATE_UPPER = -1, 116 STATE_TREE = 0, 117 STATE_LOWER = 1 118 }; 119 120 private: 121 122 // References for the original data 123 const Digraph &_orig_graph; 124 const LowerMap *_orig_lower; 125 const CapacityMap &_orig_cap; 126 const CostMap &_orig_cost; 127 const SupplyMap *_orig_supply; 128 Node _orig_source; 129 Node _orig_target; 130 Capacity _orig_flow_value; 131 132 // Result maps 133 FlowMap *_flow_result; 134 PotentialMap *_potential_result; 135 bool _local_flow; 136 bool _local_potential; 137 138 // Data structures for storing the graph 139 ArcVector _arc; 140 NodeVector _node; 141 IntNodeMap _node_id; 142 IntVector _source; 143 IntVector _target; 144 145 // The number of nodes and arcs in the original graph 146 int _node_num; 147 int _arc_num; 148 149 // Node and arc maps 150 CapacityVector _cap; 151 CostVector _cost; 152 CostVector _supply; 153 CapacityVector _flow; 154 CostVector _pi; 155 156 // Node and arc maps for the spanning tree structure 157 IntVector _depth; 158 IntVector _parent; 159 IntVector _pred; 160 IntVector _thread; 161 BoolVector _forward; 162 IntVector _state; 163 164 // The root node 165 int _root; 166 167 // The entering arc in the current pivot iteration 168 int _in_arc; 169 170 // Temporary data used in the current pivot iteration 171 int join, u_in, v_in, u_out, v_out; 172 int right, first, second, last; 173 int stem, par_stem, new_stem; 174 Capacity delta; 175 176 private: 177 178 /// \brief Implementation of the "First Eligible" pivot rule for the 179 /// \ref NetworkSimplex "network simplex" algorithm. 180 /// 181 /// This class implements the "First Eligible" pivot rule 182 /// for the \ref NetworkSimplex "network simplex" algorithm. 183 /// 184 /// For more information see \ref NetworkSimplex::run(). 185 class FirstEligiblePivotRule 186 { 187 private: 188 189 // References to the NetworkSimplex class 190 const ArcVector &_arc; 191 const IntVector &_source; 192 const IntVector &_target; 193 const CostVector &_cost; 194 const IntVector &_state; 195 const CostVector &_pi; 196 int &_in_arc; 197 int _arc_num; 198 199 // Pivot rule data 200 int _next_arc; 201 202 public: 203 204 /// Constructor 205 FirstEligiblePivotRule(NetworkSimplex &ns) : 206 _arc(ns._arc), _source(ns._source), _target(ns._target), 207 _cost(ns._cost), _state(ns._state), _pi(ns._pi), 208 _in_arc(ns._in_arc), _arc_num(ns._arc_num), _next_arc(0) 209 {} 210 211 /// Find next entering arc 212 bool findEnteringArc() { 213 Cost c; 214 for (int e = _next_arc; e < _arc_num; ++e) { 215 c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); 216 if (c < 0) { 217 _in_arc = e; 218 _next_arc = e + 1; 219 return true; 220 } 221 } 222 for (int e = 0; e < _next_arc; ++e) { 223 c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); 224 if (c < 0) { 225 _in_arc = e; 226 _next_arc = e + 1; 227 return true; 228 } 229 } 230 return false; 231 } 232 233 }; //class FirstEligiblePivotRule 234 235 236 /// \brief Implementation of the "Best Eligible" pivot rule for the 237 /// \ref NetworkSimplex "network simplex" algorithm. 238 /// 239 /// This class implements the "Best Eligible" pivot rule 240 /// for the \ref NetworkSimplex "network simplex" algorithm. 241 /// 242 /// For more information see \ref NetworkSimplex::run(). 243 class BestEligiblePivotRule 244 { 245 private: 246 247 // References to the NetworkSimplex class 248 const ArcVector &_arc; 249 const IntVector &_source; 250 const IntVector &_target; 251 const CostVector &_cost; 252 const IntVector &_state; 253 const CostVector &_pi; 254 int &_in_arc; 255 int _arc_num; 256 257 public: 258 259 /// Constructor 260 BestEligiblePivotRule(NetworkSimplex &ns) : 261 _arc(ns._arc), _source(ns._source), _target(ns._target), 262 _cost(ns._cost), _state(ns._state), _pi(ns._pi), 263 _in_arc(ns._in_arc), _arc_num(ns._arc_num) 264 {} 265 266 /// Find next entering arc 267 bool findEnteringArc() { 268 Cost c, min = 0; 269 for (int e = 0; e < _arc_num; ++e) { 270 c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); 271 if (c < min) { 272 min = c; 273 _in_arc = e; 274 } 275 } 276 return min < 0; 277 } 278 279 }; //class BestEligiblePivotRule 280 281 282 /// \brief Implementation of the "Block Search" pivot rule for the 283 /// \ref NetworkSimplex "network simplex" algorithm. 284 /// 285 /// This class implements the "Block Search" pivot rule 286 /// for the \ref NetworkSimplex "network simplex" algorithm. 287 /// 288 /// For more information see \ref NetworkSimplex::run(). 289 class BlockSearchPivotRule 290 { 291 private: 292 293 // References to the NetworkSimplex class 294 const ArcVector &_arc; 295 const IntVector &_source; 296 const IntVector &_target; 297 const CostVector &_cost; 298 const IntVector &_state; 299 const CostVector &_pi; 300 int &_in_arc; 301 int _arc_num; 302 303 // Pivot rule data 304 int _block_size; 305 int _next_arc; 306 307 public: 308 309 /// Constructor 310 BlockSearchPivotRule(NetworkSimplex &ns) : 311 _arc(ns._arc), _source(ns._source), _target(ns._target), 312 _cost(ns._cost), _state(ns._state), _pi(ns._pi), 313 _in_arc(ns._in_arc), _arc_num(ns._arc_num), _next_arc(0) 314 { 315 // The main parameters of the pivot rule 316 const double BLOCK_SIZE_FACTOR = 2.0; 317 const int MIN_BLOCK_SIZE = 10; 318 319 _block_size = std::max( int(BLOCK_SIZE_FACTOR * sqrt(_arc_num)), 320 MIN_BLOCK_SIZE ); 321 } 322 323 /// Find next entering arc 324 bool findEnteringArc() { 325 Cost c, min = 0; 326 int cnt = _block_size; 327 int e, min_arc = _next_arc; 328 for (e = _next_arc; e < _arc_num; ++e) { 329 c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); 330 if (c < min) { 331 min = c; 332 min_arc = e; 333 } 334 if (--cnt == 0) { 335 if (min < 0) break; 336 cnt = _block_size; 337 } 338 } 339 if (min == 0 || cnt > 0) { 340 for (e = 0; e < _next_arc; ++e) { 341 c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); 342 if (c < min) { 343 min = c; 344 min_arc = e; 345 } 346 if (--cnt == 0) { 347 if (min < 0) break; 348 cnt = _block_size; 349 } 350 } 351 } 352 if (min >= 0) return false; 353 _in_arc = min_arc; 354 _next_arc = e; 355 return true; 356 } 357 358 }; //class BlockSearchPivotRule 359 360 361 /// \brief Implementation of the "Candidate List" pivot rule for the 362 /// \ref NetworkSimplex "network simplex" algorithm. 363 /// 364 /// This class implements the "Candidate List" pivot rule 365 /// for the \ref NetworkSimplex "network simplex" algorithm. 366 /// 367 /// For more information see \ref NetworkSimplex::run(). 368 class CandidateListPivotRule 369 { 370 private: 371 372 // References to the NetworkSimplex class 373 const ArcVector &_arc; 374 const IntVector &_source; 375 const IntVector &_target; 376 const CostVector &_cost; 377 const IntVector &_state; 378 const CostVector &_pi; 379 int &_in_arc; 380 int _arc_num; 381 382 // Pivot rule data 383 IntVector _candidates; 384 int _list_length, _minor_limit; 385 int _curr_length, _minor_count; 386 int _next_arc; 387 388 public: 389 390 /// Constructor 391 CandidateListPivotRule(NetworkSimplex &ns) : 392 _arc(ns._arc), _source(ns._source), _target(ns._target), 393 _cost(ns._cost), _state(ns._state), _pi(ns._pi), 394 _in_arc(ns._in_arc), _arc_num(ns._arc_num), _next_arc(0) 395 { 396 // The main parameters of the pivot rule 397 const double LIST_LENGTH_FACTOR = 1.0; 398 const int MIN_LIST_LENGTH = 10; 399 const double MINOR_LIMIT_FACTOR = 0.1; 400 const int MIN_MINOR_LIMIT = 3; 401 402 _list_length = std::max( int(LIST_LENGTH_FACTOR * sqrt(_arc_num)), 403 MIN_LIST_LENGTH ); 404 _minor_limit = std::max( int(MINOR_LIMIT_FACTOR * _list_length), 405 MIN_MINOR_LIMIT ); 406 _curr_length = _minor_count = 0; 407 _candidates.resize(_list_length); 408 } 409 410 /// Find next entering arc 411 bool findEnteringArc() { 412 Cost min, c; 413 int e, min_arc = _next_arc; 414 if (_curr_length > 0 && _minor_count < _minor_limit) { 415 // Minor iteration: select the best eligible arc from the 416 // current candidate list 417 ++_minor_count; 418 min = 0; 419 for (int i = 0; i < _curr_length; ++i) { 420 e = _candidates[i]; 421 c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); 422 if (c < min) { 423 min = c; 424 min_arc = e; 425 } 426 if (c >= 0) { 427 _candidates[i--] = _candidates[--_curr_length]; 428 } 429 } 430 if (min < 0) { 431 _in_arc = min_arc; 432 return true; 433 } 434 } 435 436 // Major iteration: build a new candidate list 437 min = 0; 438 _curr_length = 0; 439 for (e = _next_arc; e < _arc_num; ++e) { 440 c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); 441 if (c < 0) { 442 _candidates[_curr_length++] = e; 443 if (c < min) { 444 min = c; 445 min_arc = e; 446 } 447 if (_curr_length == _list_length) break; 448 } 449 } 450 if (_curr_length < _list_length) { 451 for (e = 0; e < _next_arc; ++e) { 452 c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); 453 if (c < 0) { 454 _candidates[_curr_length++] = e; 455 if (c < min) { 456 min = c; 457 min_arc = e; 458 } 459 if (_curr_length == _list_length) break; 460 } 461 } 462 } 463 if (_curr_length == 0) return false; 464 _minor_count = 1; 465 _in_arc = min_arc; 466 _next_arc = e; 467 return true; 468 } 469 470 }; //class CandidateListPivotRule 471 472 473 /// \brief Implementation of the "Altering Candidate List" pivot rule 474 /// for the \ref NetworkSimplex "network simplex" algorithm. 475 /// 476 /// This class implements the "Altering Candidate List" pivot rule 477 /// for the \ref NetworkSimplex "network simplex" algorithm. 478 /// 479 /// For more information see \ref NetworkSimplex::run(). 480 class AlteringListPivotRule 481 { 482 private: 483 484 // References to the NetworkSimplex class 485 const ArcVector &_arc; 486 const IntVector &_source; 487 const IntVector &_target; 488 const CostVector &_cost; 489 const IntVector &_state; 490 const CostVector &_pi; 491 int &_in_arc; 492 int _arc_num; 493 494 // Pivot rule data 495 int _block_size, _head_length, _curr_length; 496 int _next_arc; 497 IntVector _candidates; 498 CostVector _cand_cost; 499 500 // Functor class to compare arcs during sort of the candidate list 501 class SortFunc 502 { 503 private: 504 const CostVector &_map; 505 public: 506 SortFunc(const CostVector &map) : _map(map) {} 507 bool operator()(int left, int right) { 508 return _map[left] > _map[right]; 509 } 510 }; 511 512 SortFunc _sort_func; 513 514 public: 515 516 /// Constructor 517 AlteringListPivotRule(NetworkSimplex &ns) : 518 _arc(ns._arc), _source(ns._source), _target(ns._target), 519 _cost(ns._cost), _state(ns._state), _pi(ns._pi), 520 _in_arc(ns._in_arc), _arc_num(ns._arc_num), 521 _next_arc(0), _cand_cost(ns._arc_num), _sort_func(_cand_cost) 522 { 523 // The main parameters of the pivot rule 524 const double BLOCK_SIZE_FACTOR = 1.5; 525 const int MIN_BLOCK_SIZE = 10; 526 const double HEAD_LENGTH_FACTOR = 0.1; 527 const int MIN_HEAD_LENGTH = 3; 528 529 _block_size = std::max( int(BLOCK_SIZE_FACTOR * sqrt(_arc_num)), 530 MIN_BLOCK_SIZE ); 531 _head_length = std::max( int(HEAD_LENGTH_FACTOR * _block_size), 532 MIN_HEAD_LENGTH ); 533 _candidates.resize(_head_length + _block_size); 534 _curr_length = 0; 535 } 536 537 /// Find next entering arc 538 bool findEnteringArc() { 539 // Check the current candidate list 540 int e; 541 for (int i = 0; i < _curr_length; ++i) { 542 e = _candidates[i]; 543 _cand_cost[e] = _state[e] * 544 (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); 545 if (_cand_cost[e] >= 0) { 546 _candidates[i--] = _candidates[--_curr_length]; 547 } 548 } 549 550 // Extend the list 551 int cnt = _block_size; 552 int last_edge = 0; 553 int limit = _head_length; 554 555 for (int e = _next_arc; e < _arc_num; ++e) { 556 _cand_cost[e] = _state[e] * 557 (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); 558 if (_cand_cost[e] < 0) { 559 _candidates[_curr_length++] = e; 560 last_edge = e; 561 } 562 if (--cnt == 0) { 563 if (_curr_length > limit) break; 564 limit = 0; 565 cnt = _block_size; 566 } 567 } 568 if (_curr_length <= limit) { 569 for (int e = 0; e < _next_arc; ++e) { 570 _cand_cost[e] = _state[e] * 571 (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); 572 if (_cand_cost[e] < 0) { 573 _candidates[_curr_length++] = e; 574 last_edge = e; 575 } 576 if (--cnt == 0) { 577 if (_curr_length > limit) break; 578 limit = 0; 579 cnt = _block_size; 580 } 581 } 582 } 583 if (_curr_length == 0) return false; 584 _next_arc = last_edge + 1; 585 586 // Make heap of the candidate list (approximating a partial sort) 587 make_heap( _candidates.begin(), _candidates.begin() + _curr_length, 588 _sort_func ); 589 590 // Pop the first element of the heap 591 _in_arc = _candidates[0]; 592 pop_heap( _candidates.begin(), _candidates.begin() + _curr_length, 593 _sort_func ); 594 _curr_length = std::min(_head_length, _curr_length - 1); 595 return true; 596 } 597 598 }; //class AlteringListPivotRule 599 600 public: 601 602 /// \brief General constructor (with lower bounds). 603 /// 604 /// General constructor (with lower bounds). 605 /// 606 /// \param digraph The digraph the algorithm runs on. 607 /// \param lower The lower bounds of the arcs. 608 /// \param capacity The capacities (upper bounds) of the arcs. 609 /// \param cost The cost (length) values of the arcs. 610 /// \param supply The supply values of the nodes (signed). 611 NetworkSimplex( const Digraph &digraph, 612 const LowerMap &lower, 613 const CapacityMap &capacity, 614 const CostMap &cost, 615 const SupplyMap &supply ) : 616 _orig_graph(digraph), _orig_lower(&lower), _orig_cap(capacity), 617 _orig_cost(cost), _orig_supply(&supply), 618 _flow_result(NULL), _potential_result(NULL), 619 _local_flow(false), _local_potential(false), 620 _node_id(digraph) 621 {} 622 623 /// \brief General constructor (without lower bounds). 624 /// 625 /// General constructor (without lower bounds). 626 /// 627 /// \param digraph The digraph the algorithm runs on. 628 /// \param capacity The capacities (upper bounds) of the arcs. 629 /// \param cost The cost (length) values of the arcs. 630 /// \param supply The supply values of the nodes (signed). 631 NetworkSimplex( const Digraph &digraph, 632 const CapacityMap &capacity, 633 const CostMap &cost, 634 const SupplyMap &supply ) : 635 _orig_graph(digraph), _orig_lower(NULL), _orig_cap(capacity), 636 _orig_cost(cost), _orig_supply(&supply), 637 _flow_result(NULL), _potential_result(NULL), 638 _local_flow(false), _local_potential(false), 639 _node_id(digraph) 640 {} 641 642 /// \brief Simple constructor (with lower bounds). 643 /// 644 /// Simple constructor (with lower bounds). 645 /// 646 /// \param digraph The digraph the algorithm runs on. 647 /// \param lower The lower bounds of the arcs. 648 /// \param capacity The capacities (upper bounds) of the arcs. 649 /// \param cost The cost (length) values of the arcs. 650 /// \param s The source node. 651 /// \param t The target node. 652 /// \param flow_value The required amount of flow from node \c s 653 /// to node \c t (i.e. the supply of \c s and the demand of \c t). 654 NetworkSimplex( const Digraph &digraph, 655 const LowerMap &lower, 656 const CapacityMap &capacity, 657 const CostMap &cost, 658 Node s, Node t, 659 Capacity flow_value ) : 660 _orig_graph(digraph), _orig_lower(&lower), _orig_cap(capacity), 661 _orig_cost(cost), _orig_supply(NULL), 662 _orig_source(s), _orig_target(t), _orig_flow_value(flow_value), 663 _flow_result(NULL), _potential_result(NULL), 664 _local_flow(false), _local_potential(false), 665 _node_id(digraph) 666 {} 667 668 /// \brief Simple constructor (without lower bounds). 669 /// 670 /// Simple constructor (without lower bounds). 671 /// 672 /// \param digraph The digraph the algorithm runs on. 673 /// \param capacity The capacities (upper bounds) of the arcs. 674 /// \param cost The cost (length) values of the arcs. 675 /// \param s The source node. 676 /// \param t The target node. 677 /// \param flow_value The required amount of flow from node \c s 678 /// to node \c t (i.e. the supply of \c s and the demand of \c t). 679 NetworkSimplex( const Digraph &digraph, 680 const CapacityMap &capacity, 681 const CostMap &cost, 682 Node s, Node t, 683 Capacity flow_value ) : 684 _orig_graph(digraph), _orig_lower(NULL), _orig_cap(capacity), 685 _orig_cost(cost), _orig_supply(NULL), 686 _orig_source(s), _orig_target(t), _orig_flow_value(flow_value), 687 _flow_result(NULL), _potential_result(NULL), 688 _local_flow(false), _local_potential(false), 689 _node_id(digraph) 690 {} 691 692 /// Destructor. 693 ~NetworkSimplex() { 694 if (_local_flow) delete _flow_result; 695 if (_local_potential) delete _potential_result; 696 } 697 698 /// \brief Set the flow map. 699 /// 700 /// This function sets the flow map. 701 /// 702 /// \return <tt>(*this)</tt> 703 NetworkSimplex& flowMap(FlowMap &map) { 704 if (_local_flow) { 705 delete _flow_result; 706 _local_flow = false; 707 } 708 _flow_result = ↦ 709 return *this; 710 } 711 712 /// \brief Set the potential map. 713 /// 714 /// This function sets the potential map. 715 /// 716 /// \return <tt>(*this)</tt> 717 NetworkSimplex& potentialMap(PotentialMap &map) { 718 if (_local_potential) { 719 delete _potential_result; 720 _local_potential = false; 721 } 722 _potential_result = ↦ 723 return *this; 724 } 725 726 /// \name Execution control 727 /// The algorithm can be executed using the 728 /// \ref lemon::NetworkSimplex::run() "run()" function. 729 /// @{ 730 731 /// \brief Run the algorithm. 732 /// 733 /// This function runs the algorithm. 734 /// 735 /// \param pivot_rule The pivot rule that is used during the 736 /// algorithm. 737 /// 738 /// The available pivot rules: 739 /// 740 /// - FIRST_ELIGIBLE_PIVOT The next eligible arc is selected in 741 /// a wraparound fashion in every iteration 742 /// (\ref FirstEligiblePivotRule). 743 /// 744 /// - BEST_ELIGIBLE_PIVOT The best eligible arc is selected in 745 /// every iteration (\ref BestEligiblePivotRule). 746 /// 747 /// - BLOCK_SEARCH_PIVOT A specified number of arcs are examined in 748 /// every iteration in a wraparound fashion and the best eligible 749 /// arc is selected from this block (\ref BlockSearchPivotRule). 750 /// 751 /// - CANDIDATE_LIST_PIVOT In a major iteration a candidate list is 752 /// built from eligible arcs in a wraparound fashion and in the 753 /// following minor iterations the best eligible arc is selected 754 /// from this list (\ref CandidateListPivotRule). 755 /// 756 /// - ALTERING_LIST_PIVOT It is a modified version of the 757 /// "Candidate List" pivot rule. It keeps only the several best 758 /// eligible arcs from the former candidate list and extends this 759 /// list in every iteration (\ref AlteringListPivotRule). 760 /// 761 /// According to our comprehensive benchmark tests the "Block Search" 762 /// pivot rule proved to be the fastest and the most robust on 763 /// various test inputs. Thus it is the default option. 764 /// 765 /// \return \c true if a feasible flow can be found. 766 bool run(PivotRuleEnum pivot_rule = BLOCK_SEARCH_PIVOT) { 767 return init() && start(pivot_rule); 768 } 769 770 /// @} 771 772 /// \name Query Functions 773 /// The results of the algorithm can be obtained using these 774 /// functions.\n 775 /// \ref lemon::NetworkSimplex::run() "run()" must be called before 776 /// using them. 777 /// @{ 778 779 /// \brief Return a const reference to the flow map. 780 /// 781 /// This function returns a const reference to an arc map storing 782 /// the found flow. 783 /// 784 /// \pre \ref run() must be called before using this function. 785 const FlowMap& flowMap() const { 786 return *_flow_result; 787 } 788 789 /// \brief Return a const reference to the potential map 790 /// (the dual solution). 791 /// 792 /// This function returns a const reference to a node map storing 793 /// the found potentials (the dual solution). 794 /// 795 /// \pre \ref run() must be called before using this function. 796 const PotentialMap& potentialMap() const { 797 return *_potential_result; 798 } 799 800 /// \brief Return the flow on the given arc. 801 /// 802 /// This function returns the flow on the given arc. 803 /// 804 /// \pre \ref run() must be called before using this function. 805 Capacity flow(const Arc& arc) const { 806 return (*_flow_result)[arc]; 807 } 808 809 /// \brief Return the potential of the given node. 810 /// 811 /// This function returns the potential of the given node. 812 /// 813 /// \pre \ref run() must be called before using this function. 814 Cost potential(const Node& node) const { 815 return (*_potential_result)[node]; 816 } 817 818 /// \brief Return the total cost of the found flow. 819 /// 820 /// This function returns the total cost of the found flow. 821 /// The complexity of the function is \f$ O(e) \f$. 822 /// 823 /// \pre \ref run() must be called before using this function. 824 Cost totalCost() const { 825 Cost c = 0; 826 for (ArcIt e(_orig_graph); e != INVALID; ++e) 827 c += (*_flow_result)[e] * _orig_cost[e]; 828 return c; 829 } 830 831 /// @} 832 833 private: 834 835 // Initialize internal data structures 836 bool init() { 837 // Initialize result maps 838 if (!_flow_result) { 839 _flow_result = new FlowMap(_orig_graph); 840 _local_flow = true; 841 } 842 if (!_potential_result) { 843 _potential_result = new PotentialMap(_orig_graph); 844 _local_potential = true; 845 } 846 847 // Initialize vectors 848 _node_num = countNodes(_orig_graph); 849 _arc_num = countArcs(_orig_graph); 850 int all_node_num = _node_num + 1; 851 int all_edge_num = _arc_num + _node_num; 852 853 _arc.resize(_arc_num); 854 _node.reserve(_node_num); 855 _source.resize(all_edge_num); 856 _target.resize(all_edge_num); 857 858 _cap.resize(all_edge_num); 859 _cost.resize(all_edge_num); 860 _supply.resize(all_node_num); 861 _flow.resize(all_edge_num, 0); 862 _pi.resize(all_node_num, 0); 863 864 _depth.resize(all_node_num); 865 _parent.resize(all_node_num); 866 _pred.resize(all_node_num); 867 _thread.resize(all_node_num); 868 _forward.resize(all_node_num); 869 _state.resize(all_edge_num, STATE_LOWER); 870 871 // Initialize node related data 872 bool valid_supply = true; 873 if (_orig_supply) { 874 Supply sum = 0; 875 int i = 0; 876 for (NodeIt n(_orig_graph); n != INVALID; ++n, ++i) { 877 _node.push_back(n); 878 _node_id[n] = i; 879 _supply[i] = (*_orig_supply)[n]; 880 sum += _supply[i]; 881 } 882 valid_supply = (sum == 0); 883 } else { 884 int i = 0; 885 for (NodeIt n(_orig_graph); n != INVALID; ++n, ++i) { 886 _node.push_back(n); 887 _node_id[n] = i; 888 _supply[i] = 0; 889 } 890 _supply[_node_id[_orig_source]] = _orig_flow_value; 891 _supply[_node_id[_orig_target]] = -_orig_flow_value; 892 } 893 if (!valid_supply) return false; 894 895 // Set data for the artificial root node 896 _root = _node_num; 897 _depth[_root] = 0; 898 _parent[_root] = -1; 899 _pred[_root] = -1; 900 _thread[_root] = 0; 901 _supply[_root] = 0; 902 _pi[_root] = 0; 903 904 // Store the arcs in a mixed order 905 int k = std::max(int(sqrt(_arc_num)), 10); 906 int i = 0; 907 for (ArcIt e(_orig_graph); e != INVALID; ++e) { 908 _arc[i] = e; 909 if ((i += k) >= _arc_num) i = (i % k) + 1; 910 } 911 912 // Initialize arc maps 913 for (int i = 0; i != _arc_num; ++i) { 914 Arc e = _arc[i]; 915 _source[i] = _node_id[_orig_graph.source(e)]; 916 _target[i] = _node_id[_orig_graph.target(e)]; 917 _cost[i] = _orig_cost[e]; 918 _cap[i] = _orig_cap[e]; 919 } 920 921 // Remove non-zero lower bounds 922 if (_orig_lower) { 923 for (int i = 0; i != _arc_num; ++i) { 924 Capacity c = (*_orig_lower)[_arc[i]]; 925 if (c != 0) { 926 _cap[i] -= c; 927 _supply[_source[i]] -= c; 928 _supply[_target[i]] += c; 929 } 930 } 931 } 932 933 // Add artificial arcs and initialize the spanning tree data structure 934 Cost max_cost = std::numeric_limits<Cost>::max() / 4; 935 Capacity max_cap = std::numeric_limits<Capacity>::max(); 936 for (int u = 0, e = _arc_num; u != _node_num; ++u, ++e) { 937 _thread[u] = u + 1; 938 _depth[u] = 1; 939 _parent[u] = _root; 940 _pred[u] = e; 941 if (_supply[u] >= 0) { 942 _flow[e] = _supply[u]; 943 _forward[u] = true; 944 _pi[u] = -max_cost; 945 } else { 946 _flow[e] = -_supply[u]; 947 _forward[u] = false; 948 _pi[u] = max_cost; 949 } 950 _cost[e] = max_cost; 951 _cap[e] = max_cap; 952 _state[e] = STATE_TREE; 953 } 954 955 return true; 956 } 957 958 // Find the join node 959 void findJoinNode() { 960 int u = _source[_in_arc]; 961 int v = _target[_in_arc]; 962 while (_depth[u] > _depth[v]) u = _parent[u]; 963 while (_depth[v] > _depth[u]) v = _parent[v]; 964 while (u != v) { 965 u = _parent[u]; 966 v = _parent[v]; 967 } 968 join = u; 969 } 970 971 // Find the leaving arc of the cycle and returns true if the 972 // leaving arc is not the same as the entering arc 973 bool findLeavingArc() { 974 // Initialize first and second nodes according to the direction 975 // of the cycle 976 if (_state[_in_arc] == STATE_LOWER) { 977 first = _source[_in_arc]; 978 second = _target[_in_arc]; 979 } else { 980 first = _target[_in_arc]; 981 second = _source[_in_arc]; 982 } 983 delta = _cap[_in_arc]; 984 int result = 0; 985 Capacity d; 986 int e; 987 988 // Search the cycle along the path form the first node to the root 989 for (int u = first; u != join; u = _parent[u]) { 990 e = _pred[u]; 991 d = _forward[u] ? _flow[e] : _cap[e] - _flow[e]; 992 if (d < delta) { 993 delta = d; 994 u_out = u; 995 result = 1; 996 } 997 } 998 // Search the cycle along the path form the second node to the root 999 for (int u = second; u != join; u = _parent[u]) { 1000 e = _pred[u]; 1001 d = _forward[u] ? _cap[e] - _flow[e] : _flow[e]; 1002 if (d <= delta) { 1003 delta = d; 1004 u_out = u; 1005 result = 2; 1006 } 1007 } 1008 1009 if (result == 1) { 1010 u_in = first; 1011 v_in = second; 1012 } else { 1013 u_in = second; 1014 v_in = first; 1015 } 1016 return result != 0; 1017 } 1018 1019 // Change _flow and _state vectors 1020 void changeFlow(bool change) { 1021 // Augment along the cycle 1022 if (delta > 0) { 1023 Capacity val = _state[_in_arc] * delta; 1024 _flow[_in_arc] += val; 1025 for (int u = _source[_in_arc]; u != join; u = _parent[u]) { 1026 _flow[_pred[u]] += _forward[u] ? -val : val; 1027 } 1028 for (int u = _target[_in_arc]; u != join; u = _parent[u]) { 1029 _flow[_pred[u]] += _forward[u] ? val : -val; 1030 } 1031 } 1032 // Update the state of the entering and leaving arcs 1033 if (change) { 1034 _state[_in_arc] = STATE_TREE; 1035 _state[_pred[u_out]] = 1036 (_flow[_pred[u_out]] == 0) ? STATE_LOWER : STATE_UPPER; 1037 } else { 1038 _state[_in_arc] = -_state[_in_arc]; 1039 } 1040 } 1041 1042 // Update _thread and _parent vectors 1043 void updateThreadParent() { 1044 int u; 1045 v_out = _parent[u_out]; 1046 1047 // Handle the case when join and v_out coincide 1048 bool par_first = false; 1049 if (join == v_out) { 1050 for (u = join; u != u_in && u != v_in; u = _thread[u]) ; 1051 if (u == v_in) { 1052 par_first = true; 1053 while (_thread[u] != u_out) u = _thread[u]; 1054 first = u; 1055 } 1056 } 1057 1058 // Find the last successor of u_in (u) and the node after it (right) 1059 // according to the thread index 1060 for (u = u_in; _depth[_thread[u]] > _depth[u_in]; u = _thread[u]) ; 1061 right = _thread[u]; 1062 if (_thread[v_in] == u_out) { 1063 for (last = u; _depth[last] > _depth[u_out]; last = _thread[last]) ; 1064 if (last == u_out) last = _thread[last]; 1065 } 1066 else last = _thread[v_in]; 1067 1068 // Update stem nodes 1069 _thread[v_in] = stem = u_in; 1070 par_stem = v_in; 1071 while (stem != u_out) { 1072 _thread[u] = new_stem = _parent[stem]; 1073 1074 // Find the node just before the stem node (u) according to 1075 // the original thread index 1076 for (u = new_stem; _thread[u] != stem; u = _thread[u]) ; 1077 _thread[u] = right; 1078 1079 // Change the parent node of stem and shift stem and par_stem nodes 1080 _parent[stem] = par_stem; 1081 par_stem = stem; 1082 stem = new_stem; 1083 1084 // Find the last successor of stem (u) and the node after it (right) 1085 // according to the thread index 1086 for (u = stem; _depth[_thread[u]] > _depth[stem]; u = _thread[u]) ; 1087 right = _thread[u]; 1088 } 1089 _parent[u_out] = par_stem; 1090 _thread[u] = last; 1091 1092 if (join == v_out && par_first) { 1093 if (first != v_in) _thread[first] = right; 1094 } else { 1095 for (u = v_out; _thread[u] != u_out; u = _thread[u]) ; 1096 _thread[u] = right; 1097 } 1098 } 1099 1100 // Update _pred and _forward vectors 1101 void updatePredArc() { 1102 int u = u_out, v; 1103 while (u != u_in) { 1104 v = _parent[u]; 1105 _pred[u] = _pred[v]; 1106 _forward[u] = !_forward[v]; 1107 u = v; 1108 } 1109 _pred[u_in] = _in_arc; 1110 _forward[u_in] = (u_in == _source[_in_arc]); 1111 } 1112 1113 // Update _depth and _potential vectors 1114 void updateDepthPotential() { 1115 _depth[u_in] = _depth[v_in] + 1; 1116 Cost sigma = _forward[u_in] ? 1117 _pi[v_in] - _pi[u_in] - _cost[_pred[u_in]] : 1118 _pi[v_in] - _pi[u_in] + _cost[_pred[u_in]]; 1119 _pi[u_in] += sigma; 1120 for(int u = _thread[u_in]; _parent[u] != -1; u = _thread[u]) { 1121 _depth[u] = _depth[_parent[u]] + 1; 1122 if (_depth[u] <= _depth[u_in]) break; 1123 _pi[u] += sigma; 1124 } 1125 } 1126 1127 // Execute the algorithm 1128 bool start(PivotRuleEnum pivot_rule) { 1129 // Select the pivot rule implementation 1130 switch (pivot_rule) { 1131 case FIRST_ELIGIBLE_PIVOT: 1132 return start<FirstEligiblePivotRule>(); 1133 case BEST_ELIGIBLE_PIVOT: 1134 return start<BestEligiblePivotRule>(); 1135 case BLOCK_SEARCH_PIVOT: 1136 return start<BlockSearchPivotRule>(); 1137 case CANDIDATE_LIST_PIVOT: 1138 return start<CandidateListPivotRule>(); 1139 case ALTERING_LIST_PIVOT: 1140 return start<AlteringListPivotRule>(); 1141 } 1142 return false; 1143 } 1144 1145 template<class PivotRuleImplementation> 1146 bool start() { 1147 PivotRuleImplementation pivot(*this); 1148 1149 // Execute the network simplex algorithm 1150 while (pivot.findEnteringArc()) { 1151 findJoinNode(); 1152 bool change = findLeavingArc(); 1153 changeFlow(change); 1154 if (change) { 1155 updateThreadParent(); 1156 updatePredArc(); 1157 updateDepthPotential(); 1158 } 1159 } 1160 1161 // Check if the flow amount equals zero on all the artificial arcs 1162 for (int e = _arc_num; e != _arc_num + _node_num; ++e) { 1163 if (_flow[e] > 0) return false; 1164 } 1165 1166 // Copy flow values to _flow_result 1167 if (_orig_lower) { 1168 for (int i = 0; i != _arc_num; ++i) { 1169 Arc e = _arc[i]; 1170 (*_flow_result)[e] = (*_orig_lower)[e] + _flow[i]; 1171 } 1172 } else { 1173 for (int i = 0; i != _arc_num; ++i) { 1174 (*_flow_result)[_arc[i]] = _flow[i]; 1175 } 1176 } 1177 // Copy potential values to _potential_result 1178 for (int i = 0; i != _node_num; ++i) { 1179 (*_potential_result)[_node[i]] = _pi[i]; 1180 } 1181 1182 return true; 1183 } 1184 1185 }; //class NetworkSimplex 1186 1187 ///@} 1188 1189 } //namespace lemon 1190 1191 #endif //LEMON_NETWORK_SIMPLEX_H -
test/CMakeLists.txt
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
a b 30 30 maps_test 31 31 max_matching_test 32 32 min_cost_arborescence_test 33 min_cost_flow_test 33 34 path_test 34 35 preflow_test 35 36 radix_sort_test -
test/Makefile.am
diff --git a/test/Makefile.am b/test/Makefile.am
a b 26 26 test/maps_test \ 27 27 test/max_matching_test \ 28 28 test/min_cost_arborescence_test \ 29 test/min_cost_flow_test \ 29 30 test/path_test \ 30 31 test/preflow_test \ 31 32 test/radix_sort_test \ … … 68 69 test_mip_test_SOURCES = test/mip_test.cc 69 70 test_max_matching_test_SOURCES = test/max_matching_test.cc 70 71 test_min_cost_arborescence_test_SOURCES = test/min_cost_arborescence_test.cc 72 test_min_cost_flow_test_SOURCES = test/min_cost_flow_test.cc 71 73 test_path_test_SOURCES = test/path_test.cc 72 74 test_preflow_test_SOURCES = test/preflow_test.cc 73 75 test_radix_sort_test_SOURCES = test/radix_sort_test.cc -
new file test/min_cost_flow_test.cc
diff --git a/test/min_cost_flow_test.cc b/test/min_cost_flow_test.cc new file mode 100644
- + 1 /* -*- mode: C++; indent-tabs-mode: nil; -*- 2 * 3 * This file is a part of LEMON, a generic C++ optimization library. 4 * 5 * Copyright (C) 2003-2009 6 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport 7 * (Egervary Research Group on Combinatorial Optimization, EGRES). 8 * 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. 12 * 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 15 * purpose. 16 * 17 */ 18 19 #include <iostream> 20 #include <fstream> 21 22 #include <lemon/list_graph.h> 23 #include <lemon/smart_graph.h> 24 #include <lemon/lgf_reader.h> 25 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> 32 33 #include <lemon/concepts/digraph.h> 34 #include <lemon/concept_check.h> 35 36 #include "test_tools.h" 37 38 using namespace lemon; 39 40 char test_lgf[] = 41 "@nodes\n" 42 "label sup1 sup2 sup3\n" 43 " 1 20 27 0\n" 44 " 2 -4 0 0\n" 45 " 3 0 0 0\n" 46 " 4 0 0 0\n" 47 " 5 9 0 0\n" 48 " 6 -6 0 0\n" 49 " 7 0 0 0\n" 50 " 8 0 0 0\n" 51 " 9 3 0 0\n" 52 " 10 -2 0 0\n" 53 " 11 0 0 0\n" 54 " 12 -20 -27 0\n" 55 "\n" 56 "@arcs\n" 57 " cost cap low1 low2\n" 58 " 1 2 70 11 0 8\n" 59 " 1 3 150 3 0 1\n" 60 " 1 4 80 15 0 2\n" 61 " 2 8 80 12 0 0\n" 62 " 3 5 140 5 0 3\n" 63 " 4 6 60 10 0 1\n" 64 " 4 7 80 2 0 0\n" 65 " 4 8 110 3 0 0\n" 66 " 5 7 60 14 0 0\n" 67 " 5 11 120 12 0 0\n" 68 " 6 3 0 3 0 0\n" 69 " 6 9 140 4 0 0\n" 70 " 6 10 90 8 0 0\n" 71 " 7 1 30 5 0 0\n" 72 " 8 12 60 16 0 4\n" 73 " 9 12 50 6 0 0\n" 74 "10 12 70 13 0 5\n" 75 "10 2 100 7 0 0\n" 76 "10 7 60 10 0 0\n" 77 "11 10 20 14 0 6\n" 78 "12 11 30 10 0 0\n" 79 "\n" 80 "@attributes\n" 81 "source 1\n" 82 "target 12\n"; 83 84 85 // Check the interface of an MCF algorithm 86 template <typename GR, typename Value> 87 class McfClassConcept 88 { 89 public: 90 91 template <typename MCF> 92 struct Constraints { 93 void constraints() { 94 checkConcept<concepts::Digraph, GR>(); 95 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); 100 101 // TODO: This part should be enabled and the next part 102 // should be removed if map copying is supported 103 /* 104 flow = mcf_test1.flowMap(); 105 mcf_test1.flowMap(flow); 106 107 pot = mcf_test1.potentialMap(); 108 mcf_test1.potentialMap(pot); 109 */ 110 /**/ 111 const typename MCF::FlowMap &fm = 112 mcf_test1.flowMap(); 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); 119 /**/ 120 121 mcf_test1.run(); 122 123 v = mcf_test1.totalCost(); 124 v = mcf_test1.flow(a); 125 v = mcf_test1.potential(n); 126 } 127 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; 132 133 const GR &g; 134 const AM &lower; 135 const AM &upper; 136 const AM &cost; 137 const NM ⊃ 138 const Node &n; 139 const Arc &a; 140 const Value &k; 141 Value v; 142 143 typename MCF::FlowMap &flow; 144 typename MCF::PotentialMap &pot; 145 }; 146 147 }; 148 149 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 ) 155 { 156 TEMPLATE_DIGRAPH_TYPEDEFS(GR); 157 158 for (ArcIt e(gr); e != INVALID; ++e) { 159 if (flow[e] < lower[e] || flow[e] > upper[e]) return false; 160 } 161 162 for (NodeIt n(gr); n != INVALID; ++n) { 163 typename SM::Value sum = 0; 164 for (OutArcIt e(gr, n); e != INVALID; ++e) 165 sum += flow[e]; 166 for (InArcIt e(gr, n); e != INVALID; ++e) 167 sum -= flow[e]; 168 if (sum != supply[n]) return false; 169 } 170 171 return true; 172 } 173 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 ) 180 { 181 TEMPLATE_DIGRAPH_TYPEDEFS(GR); 182 183 bool opt = true; 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]); 190 } 191 return opt; 192 } 193 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 = "" ) 203 { 204 check(mcf_result == result, "Wrong result " + test_id); 205 if (result) { 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(), 210 mcf.potentialMap()), 211 "Wrong potentials " + test_id); 212 } 213 } 214 215 int main() 216 { 217 // Check the interfaces 218 { 219 typedef int Value; 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; 226 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> >(); 237 } 238 239 // Run various MCF tests 240 typedef ListDigraph Digraph; 241 DIGRAPH_TYPEDEFS(ListDigraph); 242 243 // Read the test digraph 244 Digraph gr; 245 Digraph::ArcMap<int> c(gr), l1(gr), l2(gr), u(gr); 246 Digraph::NodeMap<int> s1(gr), s2(gr), s3(gr); 247 Node v, w; 248 249 std::istringstream input(test_lgf); 250 DigraphReader<Digraph>(gr, input) 251 .arcMap("cost", c) 252 .arcMap("cap", u) 253 .arcMap("low1", l1) 254 .arcMap("low2", l2) 255 .nodeMap("sup1", s1) 256 .nodeMap("sup2", s2) 257 .nodeMap("sup3", s3) 258 .node("source", v) 259 .node("target", w) 260 .run(); 261 262 /* 263 // A. Test CapacityScaling with scaling 264 { 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); 271 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"); 278 } 279 280 // B. Test CapacityScaling without scaling 281 { 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); 288 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"); 295 } 296 297 // C. Test CostScaling using partial augment-relabel method 298 { 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); 305 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"); 312 } 313 314 // D. Test CostScaling using push-relabel method 315 { 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); 322 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"); 329 } 330 */ 331 332 // E. Test NetworkSimplex with FIRST_ELIGIBLE_PIVOT 333 { 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); 342 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"); 349 } 350 351 // F. Test NetworkSimplex with BEST_ELIGIBLE_PIVOT 352 { 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); 361 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"); 368 } 369 370 // G. Test NetworkSimplex with BLOCK_SEARCH_PIVOT 371 { 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); 380 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"); 387 } 388 389 // H. Test NetworkSimplex with CANDIDATE_LIST_PIVOT 390 { 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); 399 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"); 406 } 407 408 // I. Test NetworkSimplex with ALTERING_LIST_PIVOT 409 { 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); 418 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"); 425 } 426 427 /* 428 // J. Test MinCostFlow 429 { 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); 436 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"); 443 } 444 */ 445 /* 446 // K. Test MinCostMaxFlow 447 { 448 MinCostMaxFlow<Digraph> mcmf(gr, u, c, v, w); 449 mcmf.run(); 450 checkMcf(mcmf, true, gr, l1, u, c, s3, true, 7620, "#K1"); 451 } 452 */ 453 454 return 0; 455 }