gravatar
kpeter (Peter Kovacs)
kpeter@inf.elte.hu
Improve the tree update process and a pivot rule (#391) and make some parts of the code clearer using better names
0 1 0
default
1 file changed with 111 insertions and 96 deletions:
↑ Collapse diff ↑
Show white space 384 line context
1 1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
2 2
 *
3 3
 * This file is a part of LEMON, a generic C++ optimization library.
4 4
 *
5 5
 * Copyright (C) 2003-2010
6 6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7 7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
8 8
 *
9 9
 * Permission to use, modify and distribute this software is granted
10 10
 * provided that this copyright notice appears in all copies. For
11 11
 * precise terms see the accompanying LICENSE file.
12 12
 *
13 13
 * This software is provided "AS IS" with no warranty of any kind,
14 14
 * express or implied, and with no claim as to its suitability for any
15 15
 * purpose.
16 16
 *
17 17
 */
18 18

	
19 19
#ifndef LEMON_NETWORK_SIMPLEX_H
20 20
#define LEMON_NETWORK_SIMPLEX_H
21 21

	
22 22
/// \ingroup min_cost_flow_algs
23 23
///
24 24
/// \file
25 25
/// \brief Network Simplex algorithm for finding a minimum cost flow.
26 26

	
27 27
#include <vector>
28 28
#include <limits>
29 29
#include <algorithm>
30 30

	
31 31
#include <lemon/core.h>
32 32
#include <lemon/math.h>
33 33

	
34 34
namespace lemon {
35 35

	
36 36
  /// \addtogroup min_cost_flow_algs
37 37
  /// @{
38 38

	
39 39
  /// \brief Implementation of the primal Network Simplex algorithm
40 40
  /// for finding a \ref min_cost_flow "minimum cost flow".
41 41
  ///
42 42
  /// \ref NetworkSimplex implements the primal Network Simplex algorithm
43 43
  /// for finding a \ref min_cost_flow "minimum cost flow"
44 44
  /// \ref amo93networkflows, \ref dantzig63linearprog,
45 45
  /// \ref kellyoneill91netsimplex.
46 46
  /// This algorithm is a highly efficient specialized version of the
47 47
  /// linear programming simplex method directly for the minimum cost
48 48
  /// flow problem.
49 49
  ///
50 50
  /// In general, %NetworkSimplex is the fastest implementation available
51 51
  /// in LEMON for this problem.
52 52
  /// Moreover, it supports both directions of the supply/demand inequality
53 53
  /// constraints. For more information, see \ref SupplyType.
54 54
  ///
55 55
  /// Most of the parameters of the problem (except for the digraph)
56 56
  /// can be given using separate functions, and the algorithm can be
57 57
  /// executed using the \ref run() function. If some parameters are not
58 58
  /// specified, then default values will be used.
59 59
  ///
60 60
  /// \tparam GR The digraph type the algorithm runs on.
61 61
  /// \tparam V The number type used for flow amounts, capacity bounds
62 62
  /// and supply values in the algorithm. By default, it is \c int.
63 63
  /// \tparam C The number type used for costs and potentials in the
64 64
  /// algorithm. By default, it is the same as \c V.
65 65
  ///
66 66
  /// \warning Both number types must be signed and all input data must
67 67
  /// be integer.
68 68
  ///
69 69
  /// \note %NetworkSimplex provides five different pivot rule
70 70
  /// implementations, from which the most efficient one is used
71 71
  /// by default. For more information, see \ref PivotRule.
72 72
  template <typename GR, typename V = int, typename C = V>
73 73
  class NetworkSimplex
74 74
  {
75 75
  public:
76 76

	
77 77
    /// The type of the flow amounts, capacity bounds and supply values
78 78
    typedef V Value;
79 79
    /// The type of the arc costs
80 80
    typedef C Cost;
81 81

	
82 82
  public:
83 83

	
84 84
    /// \brief Problem type constants for the \c run() function.
85 85
    ///
86 86
    /// Enum type containing the problem type constants that can be
87 87
    /// returned by the \ref run() function of the algorithm.
88 88
    enum ProblemType {
89 89
      /// The problem has no feasible solution (flow).
90 90
      INFEASIBLE,
91 91
      /// The problem has optimal solution (i.e. it is feasible and
92 92
      /// bounded), and the algorithm has found optimal flow and node
93 93
      /// potentials (primal and dual solutions).
94 94
      OPTIMAL,
95 95
      /// The objective function of the problem is unbounded, i.e.
96 96
      /// there is a directed cycle having negative total cost and
97 97
      /// infinite upper bound.
98 98
      UNBOUNDED
99 99
    };
100 100

	
101 101
    /// \brief Constants for selecting the type of the supply constraints.
102 102
    ///
103 103
    /// Enum type containing constants for selecting the supply type,
104 104
    /// i.e. the direction of the inequalities in the supply/demand
105 105
    /// constraints of the \ref min_cost_flow "minimum cost flow problem".
106 106
    ///
107 107
    /// The default supply type is \c GEQ, the \c LEQ type can be
108 108
    /// selected using \ref supplyType().
109 109
    /// The equality form is a special case of both supply types.
110 110
    enum SupplyType {
111 111
      /// This option means that there are <em>"greater or equal"</em>
112 112
      /// supply/demand constraints in the definition of the problem.
113 113
      GEQ,
114 114
      /// This option means that there are <em>"less or equal"</em>
115 115
      /// supply/demand constraints in the definition of the problem.
116 116
      LEQ
117 117
    };
118 118

	
119 119
    /// \brief Constants for selecting the pivot rule.
120 120
    ///
121 121
    /// Enum type containing constants for selecting the pivot rule for
122 122
    /// the \ref run() function.
123 123
    ///
124 124
    /// \ref NetworkSimplex provides five different pivot rule
125 125
    /// implementations that significantly affect the running time
126 126
    /// of the algorithm.
127 127
    /// By default, \ref BLOCK_SEARCH "Block Search" is used, which
128 128
    /// proved to be the most efficient and the most robust on various
129 129
    /// test inputs.
130 130
    /// However, another pivot rule can be selected using the \ref run()
131 131
    /// function with the proper parameter.
132 132
    enum PivotRule {
133 133

	
134 134
      /// The \e First \e Eligible pivot rule.
135 135
      /// The next eligible arc is selected in a wraparound fashion
136 136
      /// in every iteration.
137 137
      FIRST_ELIGIBLE,
138 138

	
139 139
      /// The \e Best \e Eligible pivot rule.
140 140
      /// The best eligible arc is selected in every iteration.
141 141
      BEST_ELIGIBLE,
142 142

	
143 143
      /// The \e Block \e Search pivot rule.
144 144
      /// A specified number of arcs are examined in every iteration
145 145
      /// in a wraparound fashion and the best eligible arc is selected
146 146
      /// from this block.
147 147
      BLOCK_SEARCH,
148 148

	
149 149
      /// The \e Candidate \e List pivot rule.
150 150
      /// In a major iteration a candidate list is built from eligible arcs
151 151
      /// in a wraparound fashion and in the following minor iterations
152 152
      /// the best eligible arc is selected from this list.
153 153
      CANDIDATE_LIST,
154 154

	
155 155
      /// The \e Altering \e Candidate \e List pivot rule.
156 156
      /// It is a modified version of the Candidate List method.
157 157
      /// It keeps only the several best eligible arcs from the former
158 158
      /// candidate list and extends this list in every iteration.
159 159
      ALTERING_LIST
160 160
    };
161 161

	
162 162
  private:
163 163

	
164 164
    TEMPLATE_DIGRAPH_TYPEDEFS(GR);
165 165

	
166 166
    typedef std::vector<int> IntVector;
167 167
    typedef std::vector<Value> ValueVector;
168 168
    typedef std::vector<Cost> CostVector;
169
    typedef std::vector<char> BoolVector;
170
    // Note: vector<char> is used instead of vector<bool> for efficiency reasons
169
    typedef std::vector<signed char> CharVector;
170
    // Note: vector<signed char> is used instead of vector<ArcState> and 
171
    // vector<ArcDirection> for efficiency reasons
171 172

	
172 173
    // State constants for arcs
173 174
    enum ArcState {
174 175
      STATE_UPPER = -1,
175 176
      STATE_TREE  =  0,
176 177
      STATE_LOWER =  1
177 178
    };
178 179

	
179
    typedef std::vector<signed char> StateVector;
180
    // Note: vector<signed char> is used instead of vector<ArcState> for
181
    // efficiency reasons
180
    // Direction constants for tree arcs
181
    enum ArcDirection {
182
      DIR_DOWN = -1,
183
      DIR_UP   =  1
184
    };
182 185

	
183 186
  private:
184 187

	
185 188
    // Data related to the underlying digraph
186 189
    const GR &_graph;
187 190
    int _node_num;
188 191
    int _arc_num;
189 192
    int _all_arc_num;
190 193
    int _search_arc_num;
191 194

	
192 195
    // Parameters of the problem
193 196
    bool _have_lower;
194 197
    SupplyType _stype;
195 198
    Value _sum_supply;
196 199

	
197 200
    // Data structures for storing the digraph
198 201
    IntNodeMap _node_id;
199 202
    IntArcMap _arc_id;
200 203
    IntVector _source;
201 204
    IntVector _target;
202 205
    bool _arc_mixing;
203 206

	
204 207
    // Node and arc data
205 208
    ValueVector _lower;
206 209
    ValueVector _upper;
207 210
    ValueVector _cap;
208 211
    CostVector _cost;
209 212
    ValueVector _supply;
210 213
    ValueVector _flow;
211 214
    CostVector _pi;
212 215

	
213 216
    // Data for storing the spanning tree structure
214 217
    IntVector _parent;
215 218
    IntVector _pred;
216 219
    IntVector _thread;
217 220
    IntVector _rev_thread;
218 221
    IntVector _succ_num;
219 222
    IntVector _last_succ;
223
    CharVector _pred_dir;
224
    CharVector _state;
220 225
    IntVector _dirty_revs;
221
    BoolVector _forward;
222
    StateVector _state;
223 226
    int _root;
224 227

	
225 228
    // Temporary data used in the current pivot iteration
226 229
    int in_arc, join, u_in, v_in, u_out, v_out;
227
    int first, second, right, last;
228
    int stem, par_stem, new_stem;
229 230
    Value delta;
230 231

	
231 232
    const Value MAX;
232 233

	
233 234
  public:
234 235

	
235 236
    /// \brief Constant for infinite upper bounds (capacities).
236 237
    ///
237 238
    /// Constant for infinite upper bounds (capacities).
238 239
    /// It is \c std::numeric_limits<Value>::infinity() if available,
239 240
    /// \c std::numeric_limits<Value>::max() otherwise.
240 241
    const Value INF;
241 242

	
242 243
  private:
243 244

	
244 245
    // Implementation of the First Eligible pivot rule
245 246
    class FirstEligiblePivotRule
246 247
    {
247 248
    private:
248 249

	
249 250
      // References to the NetworkSimplex class
250 251
      const IntVector  &_source;
251 252
      const IntVector  &_target;
252 253
      const CostVector &_cost;
253
      const StateVector &_state;
254
      const CharVector &_state;
254 255
      const CostVector &_pi;
255 256
      int &_in_arc;
256 257
      int _search_arc_num;
257 258

	
258 259
      // Pivot rule data
259 260
      int _next_arc;
260 261

	
261 262
    public:
262 263

	
263 264
      // Constructor
264 265
      FirstEligiblePivotRule(NetworkSimplex &ns) :
265 266
        _source(ns._source), _target(ns._target),
266 267
        _cost(ns._cost), _state(ns._state), _pi(ns._pi),
267 268
        _in_arc(ns.in_arc), _search_arc_num(ns._search_arc_num),
268 269
        _next_arc(0)
269 270
      {}
270 271

	
271 272
      // Find next entering arc
272 273
      bool findEnteringArc() {
273 274
        Cost c;
274 275
        for (int e = _next_arc; e != _search_arc_num; ++e) {
275 276
          c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]);
276 277
          if (c < 0) {
277 278
            _in_arc = e;
278 279
            _next_arc = e + 1;
279 280
            return true;
280 281
          }
281 282
        }
282 283
        for (int e = 0; e != _next_arc; ++e) {
283 284
          c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]);
284 285
          if (c < 0) {
285 286
            _in_arc = e;
286 287
            _next_arc = e + 1;
287 288
            return true;
288 289
          }
289 290
        }
290 291
        return false;
291 292
      }
292 293

	
293 294
    }; //class FirstEligiblePivotRule
294 295

	
295 296

	
296 297
    // Implementation of the Best Eligible pivot rule
297 298
    class BestEligiblePivotRule
298 299
    {
299 300
    private:
300 301

	
301 302
      // References to the NetworkSimplex class
302 303
      const IntVector  &_source;
303 304
      const IntVector  &_target;
304 305
      const CostVector &_cost;
305
      const StateVector &_state;
306
      const CharVector &_state;
306 307
      const CostVector &_pi;
307 308
      int &_in_arc;
308 309
      int _search_arc_num;
309 310

	
310 311
    public:
311 312

	
312 313
      // Constructor
313 314
      BestEligiblePivotRule(NetworkSimplex &ns) :
314 315
        _source(ns._source), _target(ns._target),
315 316
        _cost(ns._cost), _state(ns._state), _pi(ns._pi),
316 317
        _in_arc(ns.in_arc), _search_arc_num(ns._search_arc_num)
317 318
      {}
318 319

	
319 320
      // Find next entering arc
320 321
      bool findEnteringArc() {
321 322
        Cost c, min = 0;
322 323
        for (int e = 0; e != _search_arc_num; ++e) {
323 324
          c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]);
324 325
          if (c < min) {
325 326
            min = c;
326 327
            _in_arc = e;
327 328
          }
328 329
        }
329 330
        return min < 0;
330 331
      }
331 332

	
332 333
    }; //class BestEligiblePivotRule
333 334

	
334 335

	
335 336
    // Implementation of the Block Search pivot rule
336 337
    class BlockSearchPivotRule
337 338
    {
338 339
    private:
339 340

	
340 341
      // References to the NetworkSimplex class
341 342
      const IntVector  &_source;
342 343
      const IntVector  &_target;
343 344
      const CostVector &_cost;
344
      const StateVector &_state;
345
      const CharVector &_state;
345 346
      const CostVector &_pi;
346 347
      int &_in_arc;
347 348
      int _search_arc_num;
348 349

	
349 350
      // Pivot rule data
350 351
      int _block_size;
351 352
      int _next_arc;
352 353

	
353 354
    public:
354 355

	
355 356
      // Constructor
356 357
      BlockSearchPivotRule(NetworkSimplex &ns) :
357 358
        _source(ns._source), _target(ns._target),
358 359
        _cost(ns._cost), _state(ns._state), _pi(ns._pi),
359 360
        _in_arc(ns.in_arc), _search_arc_num(ns._search_arc_num),
360 361
        _next_arc(0)
361 362
      {
362 363
        // The main parameters of the pivot rule
363 364
        const double BLOCK_SIZE_FACTOR = 1.0;
364 365
        const int MIN_BLOCK_SIZE = 10;
365 366

	
366 367
        _block_size = std::max( int(BLOCK_SIZE_FACTOR *
367 368
                                    std::sqrt(double(_search_arc_num))),
368 369
                                MIN_BLOCK_SIZE );
369 370
      }
370 371

	
371 372
      // Find next entering arc
372 373
      bool findEnteringArc() {
373 374
        Cost c, min = 0;
374 375
        int cnt = _block_size;
375 376
        int e;
376 377
        for (e = _next_arc; e != _search_arc_num; ++e) {
377 378
          c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]);
378 379
          if (c < min) {
379 380
            min = c;
380 381
            _in_arc = e;
381 382
          }
382 383
          if (--cnt == 0) {
383 384
            if (min < 0) goto search_end;
384 385
            cnt = _block_size;
385 386
          }
386 387
        }
387 388
        for (e = 0; e != _next_arc; ++e) {
388 389
          c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]);
389 390
          if (c < min) {
390 391
            min = c;
391 392
            _in_arc = e;
392 393
          }
393 394
          if (--cnt == 0) {
394 395
            if (min < 0) goto search_end;
395 396
            cnt = _block_size;
396 397
          }
397 398
        }
398 399
        if (min >= 0) return false;
399 400

	
400 401
      search_end:
401 402
        _next_arc = e;
402 403
        return true;
403 404
      }
404 405

	
405 406
    }; //class BlockSearchPivotRule
406 407

	
407 408

	
408 409
    // Implementation of the Candidate List pivot rule
409 410
    class CandidateListPivotRule
410 411
    {
411 412
    private:
412 413

	
413 414
      // References to the NetworkSimplex class
414 415
      const IntVector  &_source;
415 416
      const IntVector  &_target;
416 417
      const CostVector &_cost;
417
      const StateVector &_state;
418
      const CharVector &_state;
418 419
      const CostVector &_pi;
419 420
      int &_in_arc;
420 421
      int _search_arc_num;
421 422

	
422 423
      // Pivot rule data
423 424
      IntVector _candidates;
424 425
      int _list_length, _minor_limit;
425 426
      int _curr_length, _minor_count;
426 427
      int _next_arc;
427 428

	
428 429
    public:
429 430

	
430 431
      /// Constructor
431 432
      CandidateListPivotRule(NetworkSimplex &ns) :
432 433
        _source(ns._source), _target(ns._target),
433 434
        _cost(ns._cost), _state(ns._state), _pi(ns._pi),
434 435
        _in_arc(ns.in_arc), _search_arc_num(ns._search_arc_num),
435 436
        _next_arc(0)
436 437
      {
437 438
        // The main parameters of the pivot rule
438 439
        const double LIST_LENGTH_FACTOR = 0.25;
439 440
        const int MIN_LIST_LENGTH = 10;
440 441
        const double MINOR_LIMIT_FACTOR = 0.1;
441 442
        const int MIN_MINOR_LIMIT = 3;
442 443

	
443 444
        _list_length = std::max( int(LIST_LENGTH_FACTOR *
444 445
                                     std::sqrt(double(_search_arc_num))),
445 446
                                 MIN_LIST_LENGTH );
446 447
        _minor_limit = std::max( int(MINOR_LIMIT_FACTOR * _list_length),
447 448
                                 MIN_MINOR_LIMIT );
448 449
        _curr_length = _minor_count = 0;
449 450
        _candidates.resize(_list_length);
450 451
      }
451 452

	
452 453
      /// Find next entering arc
453 454
      bool findEnteringArc() {
454 455
        Cost min, c;
455 456
        int e;
456 457
        if (_curr_length > 0 && _minor_count < _minor_limit) {
457 458
          // Minor iteration: select the best eligible arc from the
458 459
          // current candidate list
459 460
          ++_minor_count;
460 461
          min = 0;
461 462
          for (int i = 0; i < _curr_length; ++i) {
462 463
            e = _candidates[i];
463 464
            c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]);
464 465
            if (c < min) {
465 466
              min = c;
466 467
              _in_arc = e;
467 468
            }
468 469
            else if (c >= 0) {
469 470
              _candidates[i--] = _candidates[--_curr_length];
470 471
            }
471 472
          }
472 473
          if (min < 0) return true;
473 474
        }
474 475

	
475 476
        // Major iteration: build a new candidate list
476 477
        min = 0;
477 478
        _curr_length = 0;
478 479
        for (e = _next_arc; e != _search_arc_num; ++e) {
479 480
          c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]);
480 481
          if (c < 0) {
481 482
            _candidates[_curr_length++] = e;
482 483
            if (c < min) {
483 484
              min = c;
484 485
              _in_arc = e;
485 486
            }
486 487
            if (_curr_length == _list_length) goto search_end;
487 488
          }
488 489
        }
489 490
        for (e = 0; e != _next_arc; ++e) {
490 491
          c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]);
491 492
          if (c < 0) {
492 493
            _candidates[_curr_length++] = e;
493 494
            if (c < min) {
494 495
              min = c;
495 496
              _in_arc = e;
496 497
            }
497 498
            if (_curr_length == _list_length) goto search_end;
498 499
          }
499 500
        }
500 501
        if (_curr_length == 0) return false;
501 502

	
502 503
      search_end:
503 504
        _minor_count = 1;
504 505
        _next_arc = e;
505 506
        return true;
506 507
      }
507 508

	
508 509
    }; //class CandidateListPivotRule
509 510

	
510 511

	
511 512
    // Implementation of the Altering Candidate List pivot rule
512 513
    class AlteringListPivotRule
513 514
    {
514 515
    private:
515 516

	
516 517
      // References to the NetworkSimplex class
517 518
      const IntVector  &_source;
518 519
      const IntVector  &_target;
519 520
      const CostVector &_cost;
520
      const StateVector &_state;
521
      const CharVector &_state;
521 522
      const CostVector &_pi;
522 523
      int &_in_arc;
523 524
      int _search_arc_num;
524 525

	
525 526
      // Pivot rule data
526 527
      int _block_size, _head_length, _curr_length;
527 528
      int _next_arc;
528 529
      IntVector _candidates;
529 530
      CostVector _cand_cost;
530 531

	
531 532
      // Functor class to compare arcs during sort of the candidate list
532 533
      class SortFunc
533 534
      {
534 535
      private:
535 536
        const CostVector &_map;
536 537
      public:
537 538
        SortFunc(const CostVector &map) : _map(map) {}
538 539
        bool operator()(int left, int right) {
539 540
          return _map[left] > _map[right];
540 541
        }
541 542
      };
542 543

	
543 544
      SortFunc _sort_func;
544 545

	
545 546
    public:
546 547

	
547 548
      // Constructor
548 549
      AlteringListPivotRule(NetworkSimplex &ns) :
549 550
        _source(ns._source), _target(ns._target),
550 551
        _cost(ns._cost), _state(ns._state), _pi(ns._pi),
551 552
        _in_arc(ns.in_arc), _search_arc_num(ns._search_arc_num),
552 553
        _next_arc(0), _cand_cost(ns._search_arc_num), _sort_func(_cand_cost)
553 554
      {
554 555
        // The main parameters of the pivot rule
555 556
        const double BLOCK_SIZE_FACTOR = 1.0;
556 557
        const int MIN_BLOCK_SIZE = 10;
557 558
        const double HEAD_LENGTH_FACTOR = 0.1;
558 559
        const int MIN_HEAD_LENGTH = 3;
559 560

	
560 561
        _block_size = std::max( int(BLOCK_SIZE_FACTOR *
561 562
                                    std::sqrt(double(_search_arc_num))),
562 563
                                MIN_BLOCK_SIZE );
563 564
        _head_length = std::max( int(HEAD_LENGTH_FACTOR * _block_size),
564 565
                                 MIN_HEAD_LENGTH );
565 566
        _candidates.resize(_head_length + _block_size);
566 567
        _curr_length = 0;
567 568
      }
568 569

	
569 570
      // Find next entering arc
570 571
      bool findEnteringArc() {
571 572
        // Check the current candidate list
572 573
        int e;
574
        Cost c;
573 575
        for (int i = 0; i != _curr_length; ++i) {
574 576
          e = _candidates[i];
575
          _cand_cost[e] = _state[e] *
576
            (_cost[e] + _pi[_source[e]] - _pi[_target[e]]);
577
          if (_cand_cost[e] >= 0) {
577
          c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]);
578
          if (c < 0) {
579
            _cand_cost[e] = c;
580
          } else {
578 581
            _candidates[i--] = _candidates[--_curr_length];
579 582
          }
580 583
        }
581 584

	
582 585
        // Extend the list
583 586
        int cnt = _block_size;
584 587
        int limit = _head_length;
585 588

	
586 589
        for (e = _next_arc; e != _search_arc_num; ++e) {
587
          _cand_cost[e] = _state[e] *
588
            (_cost[e] + _pi[_source[e]] - _pi[_target[e]]);
589
          if (_cand_cost[e] < 0) {
590
          c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]);
591
          if (c < 0) {
592
            _cand_cost[e] = c;
590 593
            _candidates[_curr_length++] = e;
591 594
          }
592 595
          if (--cnt == 0) {
593 596
            if (_curr_length > limit) goto search_end;
594 597
            limit = 0;
595 598
            cnt = _block_size;
596 599
          }
597 600
        }
598 601
        for (e = 0; e != _next_arc; ++e) {
599 602
          _cand_cost[e] = _state[e] *
600 603
            (_cost[e] + _pi[_source[e]] - _pi[_target[e]]);
601 604
          if (_cand_cost[e] < 0) {
602 605
            _candidates[_curr_length++] = e;
603 606
          }
604 607
          if (--cnt == 0) {
605 608
            if (_curr_length > limit) goto search_end;
606 609
            limit = 0;
607 610
            cnt = _block_size;
608 611
          }
609 612
        }
610 613
        if (_curr_length == 0) return false;
611 614

	
612 615
      search_end:
613 616

	
614 617
        // Make heap of the candidate list (approximating a partial sort)
615 618
        make_heap( _candidates.begin(), _candidates.begin() + _curr_length,
616 619
                   _sort_func );
617 620

	
618 621
        // Pop the first element of the heap
619 622
        _in_arc = _candidates[0];
620 623
        _next_arc = e;
621 624
        pop_heap( _candidates.begin(), _candidates.begin() + _curr_length,
622 625
                  _sort_func );
623 626
        _curr_length = std::min(_head_length, _curr_length - 1);
624 627
        return true;
625 628
      }
626 629

	
627 630
    }; //class AlteringListPivotRule
628 631

	
629 632
  public:
630 633

	
631 634
    /// \brief Constructor.
632 635
    ///
633 636
    /// The constructor of the class.
634 637
    ///
635 638
    /// \param graph The digraph the algorithm runs on.
636 639
    /// \param arc_mixing Indicate if the arcs have to be stored in a
637 640
    /// mixed order in the internal data structure.
638 641
    /// In special cases, it could lead to better overall performance,
639 642
    /// but it is usually slower. Therefore it is disabled by default.
640 643
    NetworkSimplex(const GR& graph, bool arc_mixing = false) :
641 644
      _graph(graph), _node_id(graph), _arc_id(graph),
642 645
      _arc_mixing(arc_mixing),
643 646
      MAX(std::numeric_limits<Value>::max()),
644 647
      INF(std::numeric_limits<Value>::has_infinity ?
645 648
          std::numeric_limits<Value>::infinity() : MAX)
646 649
    {
647 650
      // Check the number types
648 651
      LEMON_ASSERT(std::numeric_limits<Value>::is_signed,
649 652
        "The flow type of NetworkSimplex must be signed");
650 653
      LEMON_ASSERT(std::numeric_limits<Cost>::is_signed,
651 654
        "The cost type of NetworkSimplex must be signed");
652 655

	
653 656
      // Reset data structures
654 657
      reset();
655 658
    }
656 659

	
657 660
    /// \name Parameters
658 661
    /// The parameters of the algorithm can be specified using these
659 662
    /// functions.
660 663

	
661 664
    /// @{
662 665

	
663 666
    /// \brief Set the lower bounds on the arcs.
664 667
    ///
665 668
    /// This function sets the lower bounds on the arcs.
666 669
    /// If it is not used before calling \ref run(), the lower bounds
667 670
    /// will be set to zero on all arcs.
668 671
    ///
669 672
    /// \param map An arc map storing the lower bounds.
670 673
    /// Its \c Value type must be convertible to the \c Value type
671 674
    /// of the algorithm.
672 675
    ///
673 676
    /// \return <tt>(*this)</tt>
674 677
    template <typename LowerMap>
675 678
    NetworkSimplex& lowerMap(const LowerMap& map) {
676 679
      _have_lower = true;
677 680
      for (ArcIt a(_graph); a != INVALID; ++a) {
678 681
        _lower[_arc_id[a]] = map[a];
679 682
      }
680 683
      return *this;
681 684
    }
682 685

	
683 686
    /// \brief Set the upper bounds (capacities) on the arcs.
684 687
    ///
685 688
    /// This function sets the upper bounds (capacities) on the arcs.
686 689
    /// If it is not used before calling \ref run(), the upper bounds
687 690
    /// will be set to \ref INF on all arcs (i.e. the flow value will be
688 691
    /// unbounded from above).
689 692
    ///
690 693
    /// \param map An arc map storing the upper bounds.
691 694
    /// Its \c Value type must be convertible to the \c Value type
692 695
    /// of the algorithm.
693 696
    ///
694 697
    /// \return <tt>(*this)</tt>
695 698
    template<typename UpperMap>
696 699
    NetworkSimplex& upperMap(const UpperMap& map) {
697 700
      for (ArcIt a(_graph); a != INVALID; ++a) {
698 701
        _upper[_arc_id[a]] = map[a];
699 702
      }
700 703
      return *this;
701 704
    }
702 705

	
703 706
    /// \brief Set the costs of the arcs.
704 707
    ///
705 708
    /// This function sets the costs of the arcs.
706 709
    /// If it is not used before calling \ref run(), the costs
707 710
    /// will be set to \c 1 on all arcs.
708 711
    ///
709 712
    /// \param map An arc map storing the costs.
710 713
    /// Its \c Value type must be convertible to the \c Cost type
711 714
    /// of the algorithm.
712 715
    ///
713 716
    /// \return <tt>(*this)</tt>
714 717
    template<typename CostMap>
715 718
    NetworkSimplex& costMap(const CostMap& map) {
716 719
      for (ArcIt a(_graph); a != INVALID; ++a) {
717 720
        _cost[_arc_id[a]] = map[a];
718 721
      }
719 722
      return *this;
720 723
    }
721 724

	
722 725
    /// \brief Set the supply values of the nodes.
723 726
    ///
724 727
    /// This function sets the supply values of the nodes.
725 728
    /// If neither this function nor \ref stSupply() is used before
726 729
    /// calling \ref run(), the supply of each node will be set to zero.
727 730
    ///
728 731
    /// \param map A node map storing the supply values.
729 732
    /// Its \c Value type must be convertible to the \c Value type
730 733
    /// of the algorithm.
731 734
    ///
732 735
    /// \return <tt>(*this)</tt>
733 736
    template<typename SupplyMap>
734 737
    NetworkSimplex& supplyMap(const SupplyMap& map) {
735 738
      for (NodeIt n(_graph); n != INVALID; ++n) {
736 739
        _supply[_node_id[n]] = map[n];
737 740
      }
738 741
      return *this;
739 742
    }
740 743

	
741 744
    /// \brief Set single source and target nodes and a supply value.
742 745
    ///
743 746
    /// This function sets a single source node and a single target node
744 747
    /// and the required flow value.
745 748
    /// If neither this function nor \ref supplyMap() is used before
746 749
    /// calling \ref run(), the supply of each node will be set to zero.
747 750
    ///
748 751
    /// Using this function has the same effect as using \ref supplyMap()
749 752
    /// with such a map in which \c k is assigned to \c s, \c -k is
750 753
    /// assigned to \c t and all other nodes have zero supply value.
751 754
    ///
752 755
    /// \param s The source node.
753 756
    /// \param t The target node.
754 757
    /// \param k The required amount of flow from node \c s to node \c t
755 758
    /// (i.e. the supply of \c s and the demand of \c t).
756 759
    ///
757 760
    /// \return <tt>(*this)</tt>
758 761
    NetworkSimplex& stSupply(const Node& s, const Node& t, Value k) {
759 762
      for (int i = 0; i != _node_num; ++i) {
760 763
        _supply[i] = 0;
761 764
      }
762 765
      _supply[_node_id[s]] =  k;
763 766
      _supply[_node_id[t]] = -k;
764 767
      return *this;
765 768
    }
766 769

	
767 770
    /// \brief Set the type of the supply constraints.
768 771
    ///
769 772
    /// This function sets the type of the supply/demand constraints.
770 773
    /// If it is not used before calling \ref run(), the \ref GEQ supply
771 774
    /// type will be used.
772 775
    ///
773 776
    /// For more information, see \ref SupplyType.
774 777
    ///
775 778
    /// \return <tt>(*this)</tt>
776 779
    NetworkSimplex& supplyType(SupplyType supply_type) {
777 780
      _stype = supply_type;
778 781
      return *this;
779 782
    }
780 783

	
781 784
    /// @}
782 785

	
783 786
    /// \name Execution Control
784 787
    /// The algorithm can be executed using \ref run().
785 788

	
786 789
    /// @{
787 790

	
788 791
    /// \brief Run the algorithm.
789 792
    ///
790 793
    /// This function runs the algorithm.
791 794
    /// The paramters can be specified using functions \ref lowerMap(),
792 795
    /// \ref upperMap(), \ref costMap(), \ref supplyMap(), \ref stSupply(),
793 796
    /// \ref supplyType().
794 797
    /// For example,
795 798
    /// \code
796 799
    ///   NetworkSimplex<ListDigraph> ns(graph);
797 800
    ///   ns.lowerMap(lower).upperMap(upper).costMap(cost)
798 801
    ///     .supplyMap(sup).run();
799 802
    /// \endcode
800 803
    ///
801 804
    /// This function can be called more than once. All the given parameters
802 805
    /// are kept for the next call, unless \ref resetParams() or \ref reset()
803 806
    /// is used, thus only the modified parameters have to be set again.
804 807
    /// If the underlying digraph was also modified after the construction
805 808
    /// of the class (or the last \ref reset() call), then the \ref reset()
806 809
    /// function must be called.
807 810
    ///
808 811
    /// \param pivot_rule The pivot rule that will be used during the
809 812
    /// algorithm. For more information, see \ref PivotRule.
810 813
    ///
811 814
    /// \return \c INFEASIBLE if no feasible flow exists,
812 815
    /// \n \c OPTIMAL if the problem has optimal solution
813 816
    /// (i.e. it is feasible and bounded), and the algorithm has found
814 817
    /// optimal flow and node potentials (primal and dual solutions),
815 818
    /// \n \c UNBOUNDED if the objective function of the problem is
816 819
    /// unbounded, i.e. there is a directed cycle having negative total
817 820
    /// cost and infinite upper bound.
818 821
    ///
819 822
    /// \see ProblemType, PivotRule
820 823
    /// \see resetParams(), reset()
821 824
    ProblemType run(PivotRule pivot_rule = BLOCK_SEARCH) {
822 825
      if (!init()) return INFEASIBLE;
823 826
      return start(pivot_rule);
824 827
    }
825 828

	
826 829
    /// \brief Reset all the parameters that have been given before.
827 830
    ///
828 831
    /// This function resets all the paramaters that have been given
829 832
    /// before using functions \ref lowerMap(), \ref upperMap(),
830 833
    /// \ref costMap(), \ref supplyMap(), \ref stSupply(), \ref supplyType().
831 834
    ///
832 835
    /// It is useful for multiple \ref run() calls. Basically, all the given
833 836
    /// parameters are kept for the next \ref run() call, unless
834 837
    /// \ref resetParams() or \ref reset() is used.
835 838
    /// If the underlying digraph was also modified after the construction
836 839
    /// of the class or the last \ref reset() call, then the \ref reset()
837 840
    /// function must be used, otherwise \ref resetParams() is sufficient.
838 841
    ///
839 842
    /// For example,
840 843
    /// \code
841 844
    ///   NetworkSimplex<ListDigraph> ns(graph);
842 845
    ///
843 846
    ///   // First run
844 847
    ///   ns.lowerMap(lower).upperMap(upper).costMap(cost)
845 848
    ///     .supplyMap(sup).run();
846 849
    ///
847 850
    ///   // Run again with modified cost map (resetParams() is not called,
848 851
    ///   // so only the cost map have to be set again)
849 852
    ///   cost[e] += 100;
850 853
    ///   ns.costMap(cost).run();
851 854
    ///
852 855
    ///   // Run again from scratch using resetParams()
853 856
    ///   // (the lower bounds will be set to zero on all arcs)
854 857
    ///   ns.resetParams();
855 858
    ///   ns.upperMap(capacity).costMap(cost)
856 859
    ///     .supplyMap(sup).run();
857 860
    /// \endcode
858 861
    ///
859 862
    /// \return <tt>(*this)</tt>
860 863
    ///
861 864
    /// \see reset(), run()
862 865
    NetworkSimplex& resetParams() {
863 866
      for (int i = 0; i != _node_num; ++i) {
864 867
        _supply[i] = 0;
865 868
      }
866 869
      for (int i = 0; i != _arc_num; ++i) {
867 870
        _lower[i] = 0;
868 871
        _upper[i] = INF;
869 872
        _cost[i] = 1;
870 873
      }
871 874
      _have_lower = false;
872 875
      _stype = GEQ;
873 876
      return *this;
874 877
    }
875 878

	
876 879
    /// \brief Reset the internal data structures and all the parameters
877 880
    /// that have been given before.
878 881
    ///
879 882
    /// This function resets the internal data structures and all the
880 883
    /// paramaters that have been given before using functions \ref lowerMap(),
881 884
    /// \ref upperMap(), \ref costMap(), \ref supplyMap(), \ref stSupply(),
882 885
    /// \ref supplyType().
883 886
    ///
884 887
    /// It is useful for multiple \ref run() calls. Basically, all the given
885 888
    /// parameters are kept for the next \ref run() call, unless
886 889
    /// \ref resetParams() or \ref reset() is used.
887 890
    /// If the underlying digraph was also modified after the construction
888 891
    /// of the class or the last \ref reset() call, then the \ref reset()
889 892
    /// function must be used, otherwise \ref resetParams() is sufficient.
890 893
    ///
891 894
    /// See \ref resetParams() for examples.
892 895
    ///
893 896
    /// \return <tt>(*this)</tt>
894 897
    ///
895 898
    /// \see resetParams(), run()
896 899
    NetworkSimplex& reset() {
897 900
      // Resize vectors
898 901
      _node_num = countNodes(_graph);
899 902
      _arc_num = countArcs(_graph);
900 903
      int all_node_num = _node_num + 1;
901 904
      int max_arc_num = _arc_num + 2 * _node_num;
902 905

	
903 906
      _source.resize(max_arc_num);
904 907
      _target.resize(max_arc_num);
905 908

	
906 909
      _lower.resize(_arc_num);
907 910
      _upper.resize(_arc_num);
908 911
      _cap.resize(max_arc_num);
909 912
      _cost.resize(max_arc_num);
910 913
      _supply.resize(all_node_num);
911 914
      _flow.resize(max_arc_num);
912 915
      _pi.resize(all_node_num);
913 916

	
914 917
      _parent.resize(all_node_num);
915 918
      _pred.resize(all_node_num);
916
      _forward.resize(all_node_num);
919
      _pred_dir.resize(all_node_num);
917 920
      _thread.resize(all_node_num);
918 921
      _rev_thread.resize(all_node_num);
919 922
      _succ_num.resize(all_node_num);
920 923
      _last_succ.resize(all_node_num);
921 924
      _state.resize(max_arc_num);
922 925

	
923 926
      // Copy the graph
924 927
      int i = 0;
925 928
      for (NodeIt n(_graph); n != INVALID; ++n, ++i) {
926 929
        _node_id[n] = i;
927 930
      }
928 931
      if (_arc_mixing) {
929 932
        // Store the arcs in a mixed order
930 933
        int k = std::max(int(std::sqrt(double(_arc_num))), 10);
931 934
        int i = 0, j = 0;
932 935
        for (ArcIt a(_graph); a != INVALID; ++a) {
933 936
          _arc_id[a] = i;
934 937
          _source[i] = _node_id[_graph.source(a)];
935 938
          _target[i] = _node_id[_graph.target(a)];
936 939
          if ((i += k) >= _arc_num) i = ++j;
937 940
        }
938 941
      } else {
939 942
        // Store the arcs in the original order
940 943
        int i = 0;
941 944
        for (ArcIt a(_graph); a != INVALID; ++a, ++i) {
942 945
          _arc_id[a] = i;
943 946
          _source[i] = _node_id[_graph.source(a)];
944 947
          _target[i] = _node_id[_graph.target(a)];
945 948
        }
946 949
      }
947 950

	
948 951
      // Reset parameters
949 952
      resetParams();
950 953
      return *this;
951 954
    }
952 955

	
953 956
    /// @}
954 957

	
955 958
    /// \name Query Functions
956 959
    /// The results of the algorithm can be obtained using these
957 960
    /// functions.\n
958 961
    /// The \ref run() function must be called before using them.
959 962

	
960 963
    /// @{
961 964

	
962 965
    /// \brief Return the total cost of the found flow.
963 966
    ///
964 967
    /// This function returns the total cost of the found flow.
965 968
    /// Its complexity is O(e).
966 969
    ///
967 970
    /// \note The return type of the function can be specified as a
968 971
    /// template parameter. For example,
969 972
    /// \code
970 973
    ///   ns.totalCost<double>();
971 974
    /// \endcode
972 975
    /// It is useful if the total cost cannot be stored in the \c Cost
973 976
    /// type of the algorithm, which is the default return type of the
974 977
    /// function.
975 978
    ///
976 979
    /// \pre \ref run() must be called before using this function.
977 980
    template <typename Number>
978 981
    Number totalCost() const {
979 982
      Number c = 0;
980 983
      for (ArcIt a(_graph); a != INVALID; ++a) {
981 984
        int i = _arc_id[a];
982 985
        c += Number(_flow[i]) * Number(_cost[i]);
983 986
      }
984 987
      return c;
985 988
    }
986 989

	
987 990
#ifndef DOXYGEN
988 991
    Cost totalCost() const {
989 992
      return totalCost<Cost>();
990 993
    }
991 994
#endif
992 995

	
993 996
    /// \brief Return the flow on the given arc.
994 997
    ///
995 998
    /// This function returns the flow on the given arc.
996 999
    ///
997 1000
    /// \pre \ref run() must be called before using this function.
998 1001
    Value flow(const Arc& a) const {
999 1002
      return _flow[_arc_id[a]];
1000 1003
    }
1001 1004

	
1002 1005
    /// \brief Return the flow map (the primal solution).
1003 1006
    ///
1004 1007
    /// This function copies the flow value on each arc into the given
1005 1008
    /// map. The \c Value type of the algorithm must be convertible to
1006 1009
    /// the \c Value type of the map.
1007 1010
    ///
1008 1011
    /// \pre \ref run() must be called before using this function.
1009 1012
    template <typename FlowMap>
1010 1013
    void flowMap(FlowMap &map) const {
1011 1014
      for (ArcIt a(_graph); a != INVALID; ++a) {
1012 1015
        map.set(a, _flow[_arc_id[a]]);
1013 1016
      }
1014 1017
    }
1015 1018

	
1016 1019
    /// \brief Return the potential (dual value) of the given node.
1017 1020
    ///
1018 1021
    /// This function returns the potential (dual value) of the
1019 1022
    /// given node.
1020 1023
    ///
1021 1024
    /// \pre \ref run() must be called before using this function.
1022 1025
    Cost potential(const Node& n) const {
1023 1026
      return _pi[_node_id[n]];
1024 1027
    }
1025 1028

	
1026 1029
    /// \brief Return the potential map (the dual solution).
1027 1030
    ///
1028 1031
    /// This function copies the potential (dual value) of each node
1029 1032
    /// into the given map.
1030 1033
    /// The \c Cost type of the algorithm must be convertible to the
1031 1034
    /// \c Value type of the map.
1032 1035
    ///
1033 1036
    /// \pre \ref run() must be called before using this function.
1034 1037
    template <typename PotentialMap>
1035 1038
    void potentialMap(PotentialMap &map) const {
1036 1039
      for (NodeIt n(_graph); n != INVALID; ++n) {
1037 1040
        map.set(n, _pi[_node_id[n]]);
1038 1041
      }
1039 1042
    }
1040 1043

	
1041 1044
    /// @}
1042 1045

	
1043 1046
  private:
1044 1047

	
1045 1048
    // Initialize internal data structures
1046 1049
    bool init() {
1047 1050
      if (_node_num == 0) return false;
1048 1051

	
1049 1052
      // Check the sum of supply values
1050 1053
      _sum_supply = 0;
1051 1054
      for (int i = 0; i != _node_num; ++i) {
1052 1055
        _sum_supply += _supply[i];
1053 1056
      }
1054 1057
      if ( !((_stype == GEQ && _sum_supply <= 0) ||
1055 1058
             (_stype == LEQ && _sum_supply >= 0)) ) return false;
1056 1059

	
1057 1060
      // Remove non-zero lower bounds
1058 1061
      if (_have_lower) {
1059 1062
        for (int i = 0; i != _arc_num; ++i) {
1060 1063
          Value c = _lower[i];
1061 1064
          if (c >= 0) {
1062 1065
            _cap[i] = _upper[i] < MAX ? _upper[i] - c : INF;
1063 1066
          } else {
1064 1067
            _cap[i] = _upper[i] < MAX + c ? _upper[i] - c : INF;
1065 1068
          }
1066 1069
          _supply[_source[i]] -= c;
1067 1070
          _supply[_target[i]] += c;
1068 1071
        }
1069 1072
      } else {
1070 1073
        for (int i = 0; i != _arc_num; ++i) {
1071 1074
          _cap[i] = _upper[i];
1072 1075
        }
1073 1076
      }
1074 1077

	
1075 1078
      // Initialize artifical cost
1076 1079
      Cost ART_COST;
1077 1080
      if (std::numeric_limits<Cost>::is_exact) {
1078 1081
        ART_COST = std::numeric_limits<Cost>::max() / 2 + 1;
1079 1082
      } else {
1080 1083
        ART_COST = 0;
1081 1084
        for (int i = 0; i != _arc_num; ++i) {
1082 1085
          if (_cost[i] > ART_COST) ART_COST = _cost[i];
1083 1086
        }
1084 1087
        ART_COST = (ART_COST + 1) * _node_num;
1085 1088
      }
1086 1089

	
1087 1090
      // Initialize arc maps
1088 1091
      for (int i = 0; i != _arc_num; ++i) {
1089 1092
        _flow[i] = 0;
1090 1093
        _state[i] = STATE_LOWER;
1091 1094
      }
1092 1095

	
1093 1096
      // Set data for the artificial root node
1094 1097
      _root = _node_num;
1095 1098
      _parent[_root] = -1;
1096 1099
      _pred[_root] = -1;
1097 1100
      _thread[_root] = 0;
1098 1101
      _rev_thread[0] = _root;
1099 1102
      _succ_num[_root] = _node_num + 1;
1100 1103
      _last_succ[_root] = _root - 1;
1101 1104
      _supply[_root] = -_sum_supply;
1102 1105
      _pi[_root] = 0;
1103 1106

	
1104 1107
      // Add artificial arcs and initialize the spanning tree data structure
1105 1108
      if (_sum_supply == 0) {
1106 1109
        // EQ supply constraints
1107 1110
        _search_arc_num = _arc_num;
1108 1111
        _all_arc_num = _arc_num + _node_num;
1109 1112
        for (int u = 0, e = _arc_num; u != _node_num; ++u, ++e) {
1110 1113
          _parent[u] = _root;
1111 1114
          _pred[u] = e;
1112 1115
          _thread[u] = u + 1;
1113 1116
          _rev_thread[u + 1] = u;
1114 1117
          _succ_num[u] = 1;
1115 1118
          _last_succ[u] = u;
1116 1119
          _cap[e] = INF;
1117 1120
          _state[e] = STATE_TREE;
1118 1121
          if (_supply[u] >= 0) {
1119
            _forward[u] = true;
1122
            _pred_dir[u] = DIR_UP;
1120 1123
            _pi[u] = 0;
1121 1124
            _source[e] = u;
1122 1125
            _target[e] = _root;
1123 1126
            _flow[e] = _supply[u];
1124 1127
            _cost[e] = 0;
1125 1128
          } else {
1126
            _forward[u] = false;
1129
            _pred_dir[u] = DIR_DOWN;
1127 1130
            _pi[u] = ART_COST;
1128 1131
            _source[e] = _root;
1129 1132
            _target[e] = u;
1130 1133
            _flow[e] = -_supply[u];
1131 1134
            _cost[e] = ART_COST;
1132 1135
          }
1133 1136
        }
1134 1137
      }
1135 1138
      else if (_sum_supply > 0) {
1136 1139
        // LEQ supply constraints
1137 1140
        _search_arc_num = _arc_num + _node_num;
1138 1141
        int f = _arc_num + _node_num;
1139 1142
        for (int u = 0, e = _arc_num; u != _node_num; ++u, ++e) {
1140 1143
          _parent[u] = _root;
1141 1144
          _thread[u] = u + 1;
1142 1145
          _rev_thread[u + 1] = u;
1143 1146
          _succ_num[u] = 1;
1144 1147
          _last_succ[u] = u;
1145 1148
          if (_supply[u] >= 0) {
1146
            _forward[u] = true;
1149
            _pred_dir[u] = DIR_UP;
1147 1150
            _pi[u] = 0;
1148 1151
            _pred[u] = e;
1149 1152
            _source[e] = u;
1150 1153
            _target[e] = _root;
1151 1154
            _cap[e] = INF;
1152 1155
            _flow[e] = _supply[u];
1153 1156
            _cost[e] = 0;
1154 1157
            _state[e] = STATE_TREE;
1155 1158
          } else {
1156
            _forward[u] = false;
1159
            _pred_dir[u] = DIR_DOWN;
1157 1160
            _pi[u] = ART_COST;
1158 1161
            _pred[u] = f;
1159 1162
            _source[f] = _root;
1160 1163
            _target[f] = u;
1161 1164
            _cap[f] = INF;
1162 1165
            _flow[f] = -_supply[u];
1163 1166
            _cost[f] = ART_COST;
1164 1167
            _state[f] = STATE_TREE;
1165 1168
            _source[e] = u;
1166 1169
            _target[e] = _root;
1167 1170
            _cap[e] = INF;
1168 1171
            _flow[e] = 0;
1169 1172
            _cost[e] = 0;
1170 1173
            _state[e] = STATE_LOWER;
1171 1174
            ++f;
1172 1175
          }
1173 1176
        }
1174 1177
        _all_arc_num = f;
1175 1178
      }
1176 1179
      else {
1177 1180
        // GEQ supply constraints
1178 1181
        _search_arc_num = _arc_num + _node_num;
1179 1182
        int f = _arc_num + _node_num;
1180 1183
        for (int u = 0, e = _arc_num; u != _node_num; ++u, ++e) {
1181 1184
          _parent[u] = _root;
1182 1185
          _thread[u] = u + 1;
1183 1186
          _rev_thread[u + 1] = u;
1184 1187
          _succ_num[u] = 1;
1185 1188
          _last_succ[u] = u;
1186 1189
          if (_supply[u] <= 0) {
1187
            _forward[u] = false;
1190
            _pred_dir[u] = DIR_DOWN;
1188 1191
            _pi[u] = 0;
1189 1192
            _pred[u] = e;
1190 1193
            _source[e] = _root;
1191 1194
            _target[e] = u;
1192 1195
            _cap[e] = INF;
1193 1196
            _flow[e] = -_supply[u];
1194 1197
            _cost[e] = 0;
1195 1198
            _state[e] = STATE_TREE;
1196 1199
          } else {
1197
            _forward[u] = true;
1200
            _pred_dir[u] = DIR_UP;
1198 1201
            _pi[u] = -ART_COST;
1199 1202
            _pred[u] = f;
1200 1203
            _source[f] = u;
1201 1204
            _target[f] = _root;
1202 1205
            _cap[f] = INF;
1203 1206
            _flow[f] = _supply[u];
1204 1207
            _state[f] = STATE_TREE;
1205 1208
            _cost[f] = ART_COST;
1206 1209
            _source[e] = _root;
1207 1210
            _target[e] = u;
1208 1211
            _cap[e] = INF;
1209 1212
            _flow[e] = 0;
1210 1213
            _cost[e] = 0;
1211 1214
            _state[e] = STATE_LOWER;
1212 1215
            ++f;
1213 1216
          }
1214 1217
        }
1215 1218
        _all_arc_num = f;
1216 1219
      }
1217 1220

	
1218 1221
      return true;
1219 1222
    }
1220 1223

	
1221 1224
    // Find the join node
1222 1225
    void findJoinNode() {
1223 1226
      int u = _source[in_arc];
1224 1227
      int v = _target[in_arc];
1225 1228
      while (u != v) {
1226 1229
        if (_succ_num[u] < _succ_num[v]) {
1227 1230
          u = _parent[u];
1228 1231
        } else {
1229 1232
          v = _parent[v];
1230 1233
        }
1231 1234
      }
1232 1235
      join = u;
1233 1236
    }
1234 1237

	
1235 1238
    // Find the leaving arc of the cycle and returns true if the
1236 1239
    // leaving arc is not the same as the entering arc
1237 1240
    bool findLeavingArc() {
1238 1241
      // Initialize first and second nodes according to the direction
1239 1242
      // of the cycle
1243
      int first, second;
1240 1244
      if (_state[in_arc] == STATE_LOWER) {
1241 1245
        first  = _source[in_arc];
1242 1246
        second = _target[in_arc];
1243 1247
      } else {
1244 1248
        first  = _target[in_arc];
1245 1249
        second = _source[in_arc];
1246 1250
      }
1247 1251
      delta = _cap[in_arc];
1248 1252
      int result = 0;
1249
      Value d;
1253
      Value c, d;
1250 1254
      int e;
1251 1255

	
1252
      // Search the cycle along the path form the first node to the root
1256
      // Search the cycle form the first node to the join node
1253 1257
      for (int u = first; u != join; u = _parent[u]) {
1254 1258
        e = _pred[u];
1255
        d = _forward[u] ?
1256
          _flow[e] : (_cap[e] >= MAX ? INF : _cap[e] - _flow[e]);
1259
        d = _flow[e];
1260
        if (_pred_dir[u] == DIR_DOWN) {
1261
          c = _cap[e];
1262
          d = c >= MAX ? INF : c - d;
1263
        }
1257 1264
        if (d < delta) {
1258 1265
          delta = d;
1259 1266
          u_out = u;
1260 1267
          result = 1;
1261 1268
        }
1262 1269
      }
1263
      // Search the cycle along the path form the second node to the root
1270

	
1271
      // Search the cycle form the second node to the join node
1264 1272
      for (int u = second; u != join; u = _parent[u]) {
1265 1273
        e = _pred[u];
1266
        d = _forward[u] ?
1267
          (_cap[e] >= MAX ? INF : _cap[e] - _flow[e]) : _flow[e];
1274
        d = _flow[e];
1275
        if (_pred_dir[u] == DIR_UP) {
1276
          c = _cap[e];
1277
          d = c >= MAX ? INF : c - d;
1278
        }
1268 1279
        if (d <= delta) {
1269 1280
          delta = d;
1270 1281
          u_out = u;
1271 1282
          result = 2;
1272 1283
        }
1273 1284
      }
1274 1285

	
1275 1286
      if (result == 1) {
1276 1287
        u_in = first;
1277 1288
        v_in = second;
1278 1289
      } else {
1279 1290
        u_in = second;
1280 1291
        v_in = first;
1281 1292
      }
1282 1293
      return result != 0;
1283 1294
    }
1284 1295

	
1285 1296
    // Change _flow and _state vectors
1286 1297
    void changeFlow(bool change) {
1287 1298
      // Augment along the cycle
1288 1299
      if (delta > 0) {
1289 1300
        Value val = _state[in_arc] * delta;
1290 1301
        _flow[in_arc] += val;
1291 1302
        for (int u = _source[in_arc]; u != join; u = _parent[u]) {
1292
          _flow[_pred[u]] += _forward[u] ? -val : val;
1303
          _flow[_pred[u]] -= _pred_dir[u] * val;
1293 1304
        }
1294 1305
        for (int u = _target[in_arc]; u != join; u = _parent[u]) {
1295
          _flow[_pred[u]] += _forward[u] ? val : -val;
1306
          _flow[_pred[u]] += _pred_dir[u] * val;
1296 1307
        }
1297 1308
      }
1298 1309
      // Update the state of the entering and leaving arcs
1299 1310
      if (change) {
1300 1311
        _state[in_arc] = STATE_TREE;
1301 1312
        _state[_pred[u_out]] =
1302 1313
          (_flow[_pred[u_out]] == 0) ? STATE_LOWER : STATE_UPPER;
1303 1314
      } else {
1304 1315
        _state[in_arc] = -_state[in_arc];
1305 1316
      }
1306 1317
    }
1307 1318

	
1308 1319
    // Update the tree structure
1309 1320
    void updateTreeStructure() {
1310
      int u, w;
1311 1321
      int old_rev_thread = _rev_thread[u_out];
1312 1322
      int old_succ_num = _succ_num[u_out];
1313 1323
      int old_last_succ = _last_succ[u_out];
1314 1324
      v_out = _parent[u_out];
1315 1325

	
1316
      u = _last_succ[u_in];  // the last successor of u_in
1317
      right = _thread[u];    // the node after it
1326
      // Check if u_in and u_out coincide
1327
      if (u_in == u_out) {
1328
        // Update _parent, _pred, _pred_dir
1329
        _parent[u_in] = v_in;
1330
        _pred[u_in] = in_arc;
1331
        _pred_dir[u_in] = u_in == _source[in_arc] ? DIR_UP : DIR_DOWN;
1318 1332

	
1333
        // Update _thread and _rev_thread
1334
        if (_thread[v_in] != u_out) {
1335
          int after = _thread[old_last_succ];
1336
          _thread[old_rev_thread] = after;
1337
          _rev_thread[after] = old_rev_thread;
1338
          after = _thread[v_in];
1339
          _thread[v_in] = u_out;
1340
          _rev_thread[u_out] = v_in;
1341
          _thread[old_last_succ] = after;
1342
          _rev_thread[after] = old_last_succ;
1343
        }
1344
      } else {
1319 1345
      // Handle the case when old_rev_thread equals to v_in
1320 1346
      // (it also means that join and v_out coincide)
1321
      if (old_rev_thread == v_in) {
1322
        last = _thread[_last_succ[u_out]];
1323
      } else {
1324
        last = _thread[v_in];
1325
      }
1347
        int thread_continue = old_rev_thread == v_in ?
1348
          _thread[old_last_succ] : _thread[v_in];
1326 1349

	
1327 1350
      // Update _thread and _parent along the stem nodes (i.e. the nodes
1328 1351
      // between u_in and u_out, whose parent have to be changed)
1329
      _thread[v_in] = stem = u_in;
1352
        int stem = u_in;              // the current stem node
1353
        int par_stem = v_in;          // the new parent of stem
1354
        int next_stem;                // the next stem node
1355
        int last = _last_succ[u_in];  // the last successor of stem
1356
        int before, after = _thread[last];
1357
        _thread[v_in] = u_in;
1330 1358
      _dirty_revs.clear();
1331 1359
      _dirty_revs.push_back(v_in);
1332
      par_stem = v_in;
1333 1360
      while (stem != u_out) {
1334 1361
        // Insert the next stem node into the thread list
1335
        new_stem = _parent[stem];
1336
        _thread[u] = new_stem;
1337
        _dirty_revs.push_back(u);
1362
          next_stem = _parent[stem];
1363
          _thread[last] = next_stem;
1364
          _dirty_revs.push_back(last);
1338 1365

	
1339 1366
        // Remove the subtree of stem from the thread list
1340
        w = _rev_thread[stem];
1341
        _thread[w] = right;
1342
        _rev_thread[right] = w;
1367
          before = _rev_thread[stem];
1368
          _thread[before] = after;
1369
          _rev_thread[after] = before;
1343 1370

	
1344 1371
        // Change the parent node and shift stem nodes
1345 1372
        _parent[stem] = par_stem;
1346 1373
        par_stem = stem;
1347
        stem = new_stem;
1374
          stem = next_stem;
1348 1375

	
1349
        // Update u and right
1350
        u = _last_succ[stem] == _last_succ[par_stem] ?
1376
          // Update last and after
1377
          last = _last_succ[stem] == _last_succ[par_stem] ?
1351 1378
          _rev_thread[par_stem] : _last_succ[stem];
1352
        right = _thread[u];
1379
          after = _thread[last];
1353 1380
      }
1354 1381
      _parent[u_out] = par_stem;
1355
      _thread[u] = last;
1356
      _rev_thread[last] = u;
1357
      _last_succ[u_out] = u;
1382
        _thread[last] = thread_continue;
1383
        _rev_thread[thread_continue] = last;
1384
        _last_succ[u_out] = last;
1358 1385

	
1359 1386
      // Remove the subtree of u_out from the thread list except for
1360 1387
      // the case when old_rev_thread equals to v_in
1361
      // (it also means that join and v_out coincide)
1362 1388
      if (old_rev_thread != v_in) {
1363
        _thread[old_rev_thread] = right;
1364
        _rev_thread[right] = old_rev_thread;
1389
          _thread[old_rev_thread] = after;
1390
          _rev_thread[after] = old_rev_thread;
1365 1391
      }
1366 1392

	
1367 1393
      // Update _rev_thread using the new _thread values
1368 1394
      for (int i = 0; i != int(_dirty_revs.size()); ++i) {
1369
        u = _dirty_revs[i];
1395
          int u = _dirty_revs[i];
1370 1396
        _rev_thread[_thread[u]] = u;
1371 1397
      }
1372 1398

	
1373
      // Update _pred, _forward, _last_succ and _succ_num for the
1399
        // Update _pred, _pred_dir, _last_succ and _succ_num for the
1374 1400
      // stem nodes from u_out to u_in
1375 1401
      int tmp_sc = 0, tmp_ls = _last_succ[u_out];
1376
      u = u_out;
1377
      while (u != u_in) {
1378
        w = _parent[u];
1379
        _pred[u] = _pred[w];
1380
        _forward[u] = !_forward[w];
1381
        tmp_sc += _succ_num[u] - _succ_num[w];
1402
        for (int u = u_out, p = _parent[u]; u != u_in; u = p, p = _parent[u]) {
1403
          _pred[u] = _pred[p];
1404
          _pred_dir[u] = -_pred_dir[p];
1405
          tmp_sc += _succ_num[u] - _succ_num[p];
1382 1406
        _succ_num[u] = tmp_sc;
1383
        _last_succ[w] = tmp_ls;
1384
        u = w;
1407
          _last_succ[p] = tmp_ls;
1385 1408
      }
1386 1409
      _pred[u_in] = in_arc;
1387
      _forward[u_in] = (u_in == _source[in_arc]);
1410
        _pred_dir[u_in] = u_in == _source[in_arc] ? DIR_UP : DIR_DOWN;
1388 1411
      _succ_num[u_in] = old_succ_num;
1389

	
1390
      // Set limits for updating _last_succ form v_in and v_out
1391
      // towards the root
1392
      int up_limit_in = -1;
1393
      int up_limit_out = -1;
1394
      if (_last_succ[join] == v_in) {
1395
        up_limit_out = join;
1396
      } else {
1397
        up_limit_in = join;
1398 1412
      }
1399 1413

	
1400 1414
      // Update _last_succ from v_in towards the root
1401
      for (u = v_in; u != up_limit_in && _last_succ[u] == v_in;
1402
           u = _parent[u]) {
1403
        _last_succ[u] = _last_succ[u_out];
1415
      int up_limit_out = _last_succ[join] == v_in ? join : -1;
1416
      int last_succ_out = _last_succ[u_out];
1417
      for (int u = v_in; u != -1 && _last_succ[u] == v_in; u = _parent[u]) {
1418
        _last_succ[u] = last_succ_out;
1404 1419
      }
1420

	
1405 1421
      // Update _last_succ from v_out towards the root
1406 1422
      if (join != old_rev_thread && v_in != old_rev_thread) {
1407
        for (u = v_out; u != up_limit_out && _last_succ[u] == old_last_succ;
1423
        for (int u = v_out; u != up_limit_out && _last_succ[u] == old_last_succ;
1408 1424
             u = _parent[u]) {
1409 1425
          _last_succ[u] = old_rev_thread;
1410 1426
        }
1411
      } else {
1412
        for (u = v_out; u != up_limit_out && _last_succ[u] == old_last_succ;
1427
      }
1428
      else if (last_succ_out != old_last_succ) {
1429
        for (int u = v_out; u != up_limit_out && _last_succ[u] == old_last_succ;
1413 1430
             u = _parent[u]) {
1414
          _last_succ[u] = _last_succ[u_out];
1431
          _last_succ[u] = last_succ_out;
1415 1432
        }
1416 1433
      }
1417 1434

	
1418 1435
      // Update _succ_num from v_in to join
1419
      for (u = v_in; u != join; u = _parent[u]) {
1436
      for (int u = v_in; u != join; u = _parent[u]) {
1420 1437
        _succ_num[u] += old_succ_num;
1421 1438
      }
1422 1439
      // Update _succ_num from v_out to join
1423
      for (u = v_out; u != join; u = _parent[u]) {
1440
      for (int u = v_out; u != join; u = _parent[u]) {
1424 1441
        _succ_num[u] -= old_succ_num;
1425 1442
      }
1426 1443
    }
1427 1444

	
1428
    // Update potentials
1445
    // Update potentials in the subtree that has been moved
1429 1446
    void updatePotential() {
1430
      Cost sigma = _forward[u_in] ?
1431
        _pi[v_in] - _pi[u_in] - _cost[_pred[u_in]] :
1432
        _pi[v_in] - _pi[u_in] + _cost[_pred[u_in]];
1433
      // Update potentials in the subtree, which has been moved
1447
      Cost sigma = _pi[v_in] - _pi[u_in] -
1448
                   _pred_dir[u_in] * _cost[in_arc];
1434 1449
      int end = _thread[_last_succ[u_in]];
1435 1450
      for (int u = u_in; u != end; u = _thread[u]) {
1436 1451
        _pi[u] += sigma;
1437 1452
      }
1438 1453
    }
1439 1454

	
1440 1455
    // Heuristic initial pivots
1441 1456
    bool initialPivots() {
1442 1457
      Value curr, total = 0;
1443 1458
      std::vector<Node> supply_nodes, demand_nodes;
1444 1459
      for (NodeIt u(_graph); u != INVALID; ++u) {
1445 1460
        curr = _supply[_node_id[u]];
1446 1461
        if (curr > 0) {
1447 1462
          total += curr;
1448 1463
          supply_nodes.push_back(u);
1449 1464
        }
1450 1465
        else if (curr < 0) {
1451 1466
          demand_nodes.push_back(u);
1452 1467
        }
1453 1468
      }
1454 1469
      if (_sum_supply > 0) total -= _sum_supply;
1455 1470
      if (total <= 0) return true;
1456 1471

	
1457 1472
      IntVector arc_vector;
1458 1473
      if (_sum_supply >= 0) {
1459 1474
        if (supply_nodes.size() == 1 && demand_nodes.size() == 1) {
1460 1475
          // Perform a reverse graph search from the sink to the source
1461 1476
          typename GR::template NodeMap<bool> reached(_graph, false);
1462 1477
          Node s = supply_nodes[0], t = demand_nodes[0];
1463 1478
          std::vector<Node> stack;
1464 1479
          reached[t] = true;
1465 1480
          stack.push_back(t);
1466 1481
          while (!stack.empty()) {
1467 1482
            Node u, v = stack.back();
1468 1483
            stack.pop_back();
1469 1484
            if (v == s) break;
1470 1485
            for (InArcIt a(_graph, v); a != INVALID; ++a) {
1471 1486
              if (reached[u = _graph.source(a)]) continue;
1472 1487
              int j = _arc_id[a];
1473 1488
              if (_cap[j] >= total) {
1474 1489
                arc_vector.push_back(j);
1475 1490
                reached[u] = true;
1476 1491
                stack.push_back(u);
1477 1492
              }
1478 1493
            }
1479 1494
          }
1480 1495
        } else {
1481 1496
          // Find the min. cost incomming arc for each demand node
1482 1497
          for (int i = 0; i != int(demand_nodes.size()); ++i) {
1483 1498
            Node v = demand_nodes[i];
1484 1499
            Cost c, min_cost = std::numeric_limits<Cost>::max();
1485 1500
            Arc min_arc = INVALID;
1486 1501
            for (InArcIt a(_graph, v); a != INVALID; ++a) {
1487 1502
              c = _cost[_arc_id[a]];
1488 1503
              if (c < min_cost) {
1489 1504
                min_cost = c;
1490 1505
                min_arc = a;
1491 1506
              }
1492 1507
            }
1493 1508
            if (min_arc != INVALID) {
1494 1509
              arc_vector.push_back(_arc_id[min_arc]);
1495 1510
            }
1496 1511
          }
1497 1512
        }
1498 1513
      } else {
1499 1514
        // Find the min. cost outgoing arc for each supply node
1500 1515
        for (int i = 0; i != int(supply_nodes.size()); ++i) {
1501 1516
          Node u = supply_nodes[i];
1502 1517
          Cost c, min_cost = std::numeric_limits<Cost>::max();
1503 1518
          Arc min_arc = INVALID;
1504 1519
          for (OutArcIt a(_graph, u); a != INVALID; ++a) {
1505 1520
            c = _cost[_arc_id[a]];
1506 1521
            if (c < min_cost) {
1507 1522
              min_cost = c;
1508 1523
              min_arc = a;
1509 1524
            }
1510 1525
          }
1511 1526
          if (min_arc != INVALID) {
1512 1527
            arc_vector.push_back(_arc_id[min_arc]);
1513 1528
          }
1514 1529
        }
1515 1530
      }
1516 1531

	
1517 1532
      // Perform heuristic initial pivots
1518 1533
      for (int i = 0; i != int(arc_vector.size()); ++i) {
1519 1534
        in_arc = arc_vector[i];
1520 1535
        if (_state[in_arc] * (_cost[in_arc] + _pi[_source[in_arc]] -
1521 1536
            _pi[_target[in_arc]]) >= 0) continue;
1522 1537
        findJoinNode();
1523 1538
        bool change = findLeavingArc();
1524 1539
        if (delta >= MAX) return false;
1525 1540
        changeFlow(change);
1526 1541
        if (change) {
1527 1542
          updateTreeStructure();
1528 1543
          updatePotential();
1529 1544
        }
1530 1545
      }
1531 1546
      return true;
1532 1547
    }
1533 1548

	
1534 1549
    // Execute the algorithm
1535 1550
    ProblemType start(PivotRule pivot_rule) {
1536 1551
      // Select the pivot rule implementation
1537 1552
      switch (pivot_rule) {
1538 1553
        case FIRST_ELIGIBLE:
1539 1554
          return start<FirstEligiblePivotRule>();
1540 1555
        case BEST_ELIGIBLE:
1541 1556
          return start<BestEligiblePivotRule>();
1542 1557
        case BLOCK_SEARCH:
1543 1558
          return start<BlockSearchPivotRule>();
1544 1559
        case CANDIDATE_LIST:
1545 1560
          return start<CandidateListPivotRule>();
1546 1561
        case ALTERING_LIST:
1547 1562
          return start<AlteringListPivotRule>();
1548 1563
      }
1549 1564
      return INFEASIBLE; // avoid warning
1550 1565
    }
1551 1566

	
1552 1567
    template <typename PivotRuleImpl>
1553 1568
    ProblemType start() {
1554 1569
      PivotRuleImpl pivot(*this);
1555 1570

	
1556 1571
      // Perform heuristic initial pivots
1557 1572
      if (!initialPivots()) return UNBOUNDED;
1558 1573

	
1559 1574
      // Execute the Network Simplex algorithm
1560 1575
      while (pivot.findEnteringArc()) {
1561 1576
        findJoinNode();
1562 1577
        bool change = findLeavingArc();
1563 1578
        if (delta >= MAX) return UNBOUNDED;
1564 1579
        changeFlow(change);
1565 1580
        if (change) {
1566 1581
          updateTreeStructure();
1567 1582
          updatePotential();
1568 1583
        }
1569 1584
      }
1570 1585

	
1571 1586
      // Check feasibility
1572 1587
      for (int e = _search_arc_num; e != _all_arc_num; ++e) {
1573 1588
        if (_flow[e] != 0) return INFEASIBLE;
1574 1589
      }
1575 1590

	
1576 1591
      // Transform the solution and the supply map to the original form
1577 1592
      if (_have_lower) {
1578 1593
        for (int i = 0; i != _arc_num; ++i) {
1579 1594
          Value c = _lower[i];
1580 1595
          if (c != 0) {
1581 1596
            _flow[i] += c;
1582 1597
            _supply[_source[i]] += c;
1583 1598
            _supply[_target[i]] -= c;
1584 1599
          }
1585 1600
        }
1586 1601
      }
1587 1602

	
1588 1603
      // Shift potentials to meet the requirements of the GEQ/LEQ type
1589 1604
      // optimality conditions
1590 1605
      if (_sum_supply == 0) {
1591 1606
        if (_stype == GEQ) {
1592 1607
          Cost max_pot = -std::numeric_limits<Cost>::max();
1593 1608
          for (int i = 0; i != _node_num; ++i) {
1594 1609
            if (_pi[i] > max_pot) max_pot = _pi[i];
1595 1610
          }
1596 1611
          if (max_pot > 0) {
1597 1612
            for (int i = 0; i != _node_num; ++i)
1598 1613
              _pi[i] -= max_pot;
1599 1614
          }
1600 1615
        } else {
1601 1616
          Cost min_pot = std::numeric_limits<Cost>::max();
1602 1617
          for (int i = 0; i != _node_num; ++i) {
1603 1618
            if (_pi[i] < min_pot) min_pot = _pi[i];
1604 1619
          }
1605 1620
          if (min_pot < 0) {
1606 1621
            for (int i = 0; i != _node_num; ++i)
1607 1622
              _pi[i] -= min_pot;
1608 1623
          }
1609 1624
        }
1610 1625
      }
1611 1626

	
1612 1627
      return OPTIMAL;
1613 1628
    }
1614 1629

	
1615 1630
  }; //class NetworkSimplex
1616 1631

	
1617 1632
  ///@}
1618 1633

	
1619 1634
} //namespace lemon
1620 1635

	
1621 1636
#endif //LEMON_NETWORK_SIMPLEX_H
0 comments (0 inline)