gravatar
kpeter (Peter Kovacs)
kpeter@inf.elte.hu
Add HartmannOrlin algorithm class (#179) This algorithm is an improved version of Karp's original method, it applies an efficient early termination scheme. The interface is the same as Karp's and Howard's interface.
0 2 1
default
3 files changed with 632 insertions and 0 deletions:
↑ Collapse diff ↑
Show white space 6 line context
1
/* -*- C++ -*-
2
 *
3
 * This file is a part of LEMON, a generic C++ optimization library
4
 *
5
 * Copyright (C) 2003-2008
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_HARTMANN_ORLIN_H
20
#define LEMON_HARTMANN_ORLIN_H
21

	
22
/// \ingroup shortest_path
23
///
24
/// \file
25
/// \brief Hartmann-Orlin's algorithm for finding a minimum mean cycle.
26

	
27
#include <vector>
28
#include <limits>
29
#include <lemon/core.h>
30
#include <lemon/path.h>
31
#include <lemon/tolerance.h>
32
#include <lemon/connectivity.h>
33

	
34
namespace lemon {
35

	
36
  /// \brief Default traits class of HartmannOrlin algorithm.
37
  ///
38
  /// Default traits class of HartmannOrlin algorithm.
39
  /// \tparam GR The type of the digraph.
40
  /// \tparam LEN The type of the length map.
41
  /// It must conform to the \ref concepts::Rea_data "Rea_data" concept.
42
#ifdef DOXYGEN
43
  template <typename GR, typename LEN>
44
#else
45
  template <typename GR, typename LEN,
46
    bool integer = std::numeric_limits<typename LEN::Value>::is_integer>
47
#endif
48
  struct HartmannOrlinDefaultTraits
49
  {
50
    /// The type of the digraph
51
    typedef GR Digraph;
52
    /// The type of the length map
53
    typedef LEN LengthMap;
54
    /// The type of the arc lengths
55
    typedef typename LengthMap::Value Value;
56

	
57
    /// \brief The large value type used for internal computations
58
    ///
59
    /// The large value type used for internal computations.
60
    /// It is \c long \c long if the \c Value type is integer,
61
    /// otherwise it is \c double.
62
    /// \c Value must be convertible to \c LargeValue.
63
    typedef double LargeValue;
64

	
65
    /// The tolerance type used for internal computations
66
    typedef lemon::Tolerance<LargeValue> Tolerance;
67

	
68
    /// \brief The path type of the found cycles
69
    ///
70
    /// The path type of the found cycles.
71
    /// It must conform to the \ref lemon::concepts::Path "Path" concept
72
    /// and it must have an \c addBack() function.
73
    typedef lemon::Path<Digraph> Path;
74
  };
75

	
76
  // Default traits class for integer value types
77
  template <typename GR, typename LEN>
78
  struct HartmannOrlinDefaultTraits<GR, LEN, true>
79
  {
80
    typedef GR Digraph;
81
    typedef LEN LengthMap;
82
    typedef typename LengthMap::Value Value;
83
#ifdef LEMON_HAVE_LONG_LONG
84
    typedef long long LargeValue;
85
#else
86
    typedef long LargeValue;
87
#endif
88
    typedef lemon::Tolerance<LargeValue> Tolerance;
89
    typedef lemon::Path<Digraph> Path;
90
  };
91

	
92

	
93
  /// \addtogroup shortest_path
94
  /// @{
95

	
96
  /// \brief Implementation of the Hartmann-Orlin algorithm for finding
97
  /// a minimum mean cycle.
98
  ///
99
  /// This class implements the Hartmann-Orlin algorithm for finding
100
  /// a directed cycle of minimum mean length (cost) in a digraph.
101
  /// It is an improved version of \ref Karp "Karp's original algorithm",
102
  /// it applies an efficient early termination scheme.
103
  ///
104
  /// \tparam GR The type of the digraph the algorithm runs on.
105
  /// \tparam LEN The type of the length map. The default
106
  /// map type is \ref concepts::Digraph::ArcMap "GR::ArcMap<int>".
107
#ifdef DOXYGEN
108
  template <typename GR, typename LEN, typename TR>
109
#else
110
  template < typename GR,
111
             typename LEN = typename GR::template ArcMap<int>,
112
             typename TR = HartmannOrlinDefaultTraits<GR, LEN> >
113
#endif
114
  class HartmannOrlin
115
  {
116
  public:
117

	
118
    /// The type of the digraph
119
    typedef typename TR::Digraph Digraph;
120
    /// The type of the length map
121
    typedef typename TR::LengthMap LengthMap;
122
    /// The type of the arc lengths
123
    typedef typename TR::Value Value;
124

	
125
    /// \brief The large value type
126
    ///
127
    /// The large value type used for internal computations.
128
    /// Using the \ref HartmannOrlinDefaultTraits "default traits class",
129
    /// it is \c long \c long if the \c Value type is integer,
130
    /// otherwise it is \c double.
131
    typedef typename TR::LargeValue LargeValue;
132

	
133
    /// The tolerance type
134
    typedef typename TR::Tolerance Tolerance;
135

	
136
    /// \brief The path type of the found cycles
137
    ///
138
    /// The path type of the found cycles.
139
    /// Using the \ref HartmannOrlinDefaultTraits "default traits class",
140
    /// it is \ref lemon::Path "Path<Digraph>".
141
    typedef typename TR::Path Path;
142

	
143
    /// The \ref HartmannOrlinDefaultTraits "traits class" of the algorithm
144
    typedef TR Traits;
145

	
146
  private:
147

	
148
    TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
149

	
150
    // Data sturcture for path data
151
    struct PathData
152
    {
153
      bool found;
154
      LargeValue dist;
155
      Arc pred;
156
      PathData(bool f = false, LargeValue d = 0, Arc p = INVALID) :
157
        found(f), dist(d), pred(p) {}
158
    };
159

	
160
    typedef typename Digraph::template NodeMap<std::vector<PathData> >
161
      PathDataNodeMap;
162

	
163
  private:
164

	
165
    // The digraph the algorithm runs on
166
    const Digraph &_gr;
167
    // The length of the arcs
168
    const LengthMap &_length;
169

	
170
    // Data for storing the strongly connected components
171
    int _comp_num;
172
    typename Digraph::template NodeMap<int> _comp;
173
    std::vector<std::vector<Node> > _comp_nodes;
174
    std::vector<Node>* _nodes;
175
    typename Digraph::template NodeMap<std::vector<Arc> > _out_arcs;
176

	
177
    // Data for the found cycles
178
    bool _curr_found, _best_found;
179
    LargeValue _curr_length, _best_length;
180
    int _curr_size, _best_size;
181
    Node _curr_node, _best_node;
182
    int _curr_level, _best_level;
183

	
184
    Path *_cycle_path;
185
    bool _local_path;
186

	
187
    // Node map for storing path data
188
    PathDataNodeMap _data;
189
    // The processed nodes in the last round
190
    std::vector<Node> _process;
191

	
192
    Tolerance _tolerance;
193

	
194
  public:
195

	
196
    /// \name Named Template Parameters
197
    /// @{
198

	
199
    template <typename T>
200
    struct SetLargeValueTraits : public Traits {
201
      typedef T LargeValue;
202
      typedef lemon::Tolerance<T> Tolerance;
203
    };
204

	
205
    /// \brief \ref named-templ-param "Named parameter" for setting
206
    /// \c LargeValue type.
207
    ///
208
    /// \ref named-templ-param "Named parameter" for setting \c LargeValue
209
    /// type. It is used for internal computations in the algorithm.
210
    template <typename T>
211
    struct SetLargeValue
212
      : public HartmannOrlin<GR, LEN, SetLargeValueTraits<T> > {
213
      typedef HartmannOrlin<GR, LEN, SetLargeValueTraits<T> > Create;
214
    };
215

	
216
    template <typename T>
217
    struct SetPathTraits : public Traits {
218
      typedef T Path;
219
    };
220

	
221
    /// \brief \ref named-templ-param "Named parameter" for setting
222
    /// \c %Path type.
223
    ///
224
    /// \ref named-templ-param "Named parameter" for setting the \c %Path
225
    /// type of the found cycles.
226
    /// It must conform to the \ref lemon::concepts::Path "Path" concept
227
    /// and it must have an \c addFront() function.
228
    template <typename T>
229
    struct SetPath
230
      : public HartmannOrlin<GR, LEN, SetPathTraits<T> > {
231
      typedef HartmannOrlin<GR, LEN, SetPathTraits<T> > Create;
232
    };
233

	
234
    /// @}
235

	
236
  public:
237

	
238
    /// \brief Constructor.
239
    ///
240
    /// The constructor of the class.
241
    ///
242
    /// \param digraph The digraph the algorithm runs on.
243
    /// \param length The lengths (costs) of the arcs.
244
    HartmannOrlin( const Digraph &digraph,
245
                   const LengthMap &length ) :
246
      _gr(digraph), _length(length), _comp(digraph), _out_arcs(digraph),
247
      _best_found(false), _best_length(0), _best_size(1),
248
      _cycle_path(NULL), _local_path(false), _data(digraph)
249
    {}
250

	
251
    /// Destructor.
252
    ~HartmannOrlin() {
253
      if (_local_path) delete _cycle_path;
254
    }
255

	
256
    /// \brief Set the path structure for storing the found cycle.
257
    ///
258
    /// This function sets an external path structure for storing the
259
    /// found cycle.
260
    ///
261
    /// If you don't call this function before calling \ref run() or
262
    /// \ref findMinMean(), it will allocate a local \ref Path "path"
263
    /// structure. The destuctor deallocates this automatically
264
    /// allocated object, of course.
265
    ///
266
    /// \note The algorithm calls only the \ref lemon::Path::addFront()
267
    /// "addFront()" function of the given path structure.
268
    ///
269
    /// \return <tt>(*this)</tt>
270
    HartmannOrlin& cycle(Path &path) {
271
      if (_local_path) {
272
        delete _cycle_path;
273
        _local_path = false;
274
      }
275
      _cycle_path = &path;
276
      return *this;
277
    }
278

	
279
    /// \name Execution control
280
    /// The simplest way to execute the algorithm is to call the \ref run()
281
    /// function.\n
282
    /// If you only need the minimum mean length, you may call
283
    /// \ref findMinMean().
284

	
285
    /// @{
286

	
287
    /// \brief Run the algorithm.
288
    ///
289
    /// This function runs the algorithm.
290
    /// It can be called more than once (e.g. if the underlying digraph
291
    /// and/or the arc lengths have been modified).
292
    ///
293
    /// \return \c true if a directed cycle exists in the digraph.
294
    ///
295
    /// \note <tt>mmc.run()</tt> is just a shortcut of the following code.
296
    /// \code
297
    ///   return mmc.findMinMean() && mmc.findCycle();
298
    /// \endcode
299
    bool run() {
300
      return findMinMean() && findCycle();
301
    }
302

	
303
    /// \brief Find the minimum cycle mean.
304
    ///
305
    /// This function finds the minimum mean length of the directed
306
    /// cycles in the digraph.
307
    ///
308
    /// \return \c true if a directed cycle exists in the digraph.
309
    bool findMinMean() {
310
      // Initialization and find strongly connected components
311
      init();
312
      findComponents();
313
      
314
      // Find the minimum cycle mean in the components
315
      for (int comp = 0; comp < _comp_num; ++comp) {
316
        if (!initComponent(comp)) continue;
317
        processRounds();
318
        
319
        // Update the best cycle (global minimum mean cycle)
320
        if ( _curr_found && (!_best_found || 
321
             _curr_length * _best_size < _best_length * _curr_size) ) {
322
          _best_found = true;
323
          _best_length = _curr_length;
324
          _best_size = _curr_size;
325
          _best_node = _curr_node;
326
          _best_level = _curr_level;
327
        }
328
      }
329
      return _best_found;
330
    }
331

	
332
    /// \brief Find a minimum mean directed cycle.
333
    ///
334
    /// This function finds a directed cycle of minimum mean length
335
    /// in the digraph using the data computed by findMinMean().
336
    ///
337
    /// \return \c true if a directed cycle exists in the digraph.
338
    ///
339
    /// \pre \ref findMinMean() must be called before using this function.
340
    bool findCycle() {
341
      if (!_best_found) return false;
342
      IntNodeMap reached(_gr, -1);
343
      int r = _best_level + 1;
344
      Node u = _best_node;
345
      while (reached[u] < 0) {
346
        reached[u] = --r;
347
        u = _gr.source(_data[u][r].pred);
348
      }
349
      r = reached[u];
350
      Arc e = _data[u][r].pred;
351
      _cycle_path->addFront(e);
352
      _best_length = _length[e];
353
      _best_size = 1;
354
      Node v;
355
      while ((v = _gr.source(e)) != u) {
356
        e = _data[v][--r].pred;
357
        _cycle_path->addFront(e);
358
        _best_length += _length[e];
359
        ++_best_size;
360
      }
361
      return true;
362
    }
363

	
364
    /// @}
365

	
366
    /// \name Query Functions
367
    /// The results of the algorithm can be obtained using these
368
    /// functions.\n
369
    /// The algorithm should be executed before using them.
370

	
371
    /// @{
372

	
373
    /// \brief Return the total length of the found cycle.
374
    ///
375
    /// This function returns the total length of the found cycle.
376
    ///
377
    /// \pre \ref run() or \ref findMinMean() must be called before
378
    /// using this function.
379
    LargeValue cycleLength() const {
380
      return _best_length;
381
    }
382

	
383
    /// \brief Return the number of arcs on the found cycle.
384
    ///
385
    /// This function returns the number of arcs on the found cycle.
386
    ///
387
    /// \pre \ref run() or \ref findMinMean() must be called before
388
    /// using this function.
389
    int cycleArcNum() const {
390
      return _best_size;
391
    }
392

	
393
    /// \brief Return the mean length of the found cycle.
394
    ///
395
    /// This function returns the mean length of the found cycle.
396
    ///
397
    /// \note <tt>alg.cycleMean()</tt> is just a shortcut of the
398
    /// following code.
399
    /// \code
400
    ///   return static_cast<double>(alg.cycleLength()) / alg.cycleArcNum();
401
    /// \endcode
402
    ///
403
    /// \pre \ref run() or \ref findMinMean() must be called before
404
    /// using this function.
405
    double cycleMean() const {
406
      return static_cast<double>(_best_length) / _best_size;
407
    }
408

	
409
    /// \brief Return the found cycle.
410
    ///
411
    /// This function returns a const reference to the path structure
412
    /// storing the found cycle.
413
    ///
414
    /// \pre \ref run() or \ref findCycle() must be called before using
415
    /// this function.
416
    const Path& cycle() const {
417
      return *_cycle_path;
418
    }
419

	
420
    ///@}
421

	
422
  private:
423

	
424
    // Initialization
425
    void init() {
426
      if (!_cycle_path) {
427
        _local_path = true;
428
        _cycle_path = new Path;
429
      }
430
      _cycle_path->clear();
431
      _best_found = false;
432
      _best_length = 0;
433
      _best_size = 1;
434
      _cycle_path->clear();
435
      for (NodeIt u(_gr); u != INVALID; ++u)
436
        _data[u].clear();
437
    }
438

	
439
    // Find strongly connected components and initialize _comp_nodes
440
    // and _out_arcs
441
    void findComponents() {
442
      _comp_num = stronglyConnectedComponents(_gr, _comp);
443
      _comp_nodes.resize(_comp_num);
444
      if (_comp_num == 1) {
445
        _comp_nodes[0].clear();
446
        for (NodeIt n(_gr); n != INVALID; ++n) {
447
          _comp_nodes[0].push_back(n);
448
          _out_arcs[n].clear();
449
          for (OutArcIt a(_gr, n); a != INVALID; ++a) {
450
            _out_arcs[n].push_back(a);
451
          }
452
        }
453
      } else {
454
        for (int i = 0; i < _comp_num; ++i)
455
          _comp_nodes[i].clear();
456
        for (NodeIt n(_gr); n != INVALID; ++n) {
457
          int k = _comp[n];
458
          _comp_nodes[k].push_back(n);
459
          _out_arcs[n].clear();
460
          for (OutArcIt a(_gr, n); a != INVALID; ++a) {
461
            if (_comp[_gr.target(a)] == k) _out_arcs[n].push_back(a);
462
          }
463
        }
464
      }
465
    }
466

	
467
    // Initialize path data for the current component
468
    bool initComponent(int comp) {
469
      _nodes = &(_comp_nodes[comp]);
470
      int n = _nodes->size();
471
      if (n < 1 || (n == 1 && _out_arcs[(*_nodes)[0]].size() == 0)) {
472
        return false;
473
      }      
474
      for (int i = 0; i < n; ++i) {
475
        _data[(*_nodes)[i]].resize(n + 1);
476
      }
477
      return true;
478
    }
479

	
480
    // Process all rounds of computing path data for the current component.
481
    // _data[v][k] is the length of a shortest directed walk from the root
482
    // node to node v containing exactly k arcs.
483
    void processRounds() {
484
      Node start = (*_nodes)[0];
485
      _data[start][0] = PathData(true, 0);
486
      _process.clear();
487
      _process.push_back(start);
488

	
489
      int k, n = _nodes->size();
490
      int next_check = 4;
491
      bool terminate = false;
492
      for (k = 1; k <= n && int(_process.size()) < n && !terminate; ++k) {
493
        processNextBuildRound(k);
494
        if (k == next_check || k == n) {
495
          terminate = checkTermination(k);
496
          next_check = next_check * 3 / 2;
497
        }
498
      }
499
      for ( ; k <= n && !terminate; ++k) {
500
        processNextFullRound(k);
501
        if (k == next_check || k == n) {
502
          terminate = checkTermination(k);
503
          next_check = next_check * 3 / 2;
504
        }
505
      }
506
    }
507

	
508
    // Process one round and rebuild _process
509
    void processNextBuildRound(int k) {
510
      std::vector<Node> next;
511
      Node u, v;
512
      Arc e;
513
      LargeValue d;
514
      for (int i = 0; i < int(_process.size()); ++i) {
515
        u = _process[i];
516
        for (int j = 0; j < int(_out_arcs[u].size()); ++j) {
517
          e = _out_arcs[u][j];
518
          v = _gr.target(e);
519
          d = _data[u][k-1].dist + _length[e];
520
          if (!_data[v][k].found) {
521
            next.push_back(v);
522
            _data[v][k] = PathData(true, _data[u][k-1].dist + _length[e], e);
523
          }
524
          else if (_tolerance.less(d, _data[v][k].dist)) {
525
            _data[v][k] = PathData(true, d, e);
526
          }
527
        }
528
      }
529
      _process.swap(next);
530
    }
531

	
532
    // Process one round using _nodes instead of _process
533
    void processNextFullRound(int k) {
534
      Node u, v;
535
      Arc e;
536
      LargeValue d;
537
      for (int i = 0; i < int(_nodes->size()); ++i) {
538
        u = (*_nodes)[i];
539
        for (int j = 0; j < int(_out_arcs[u].size()); ++j) {
540
          e = _out_arcs[u][j];
541
          v = _gr.target(e);
542
          d = _data[u][k-1].dist + _length[e];
543
          if (!_data[v][k].found || _tolerance.less(d, _data[v][k].dist)) {
544
            _data[v][k] = PathData(true, d, e);
545
          }
546
        }
547
      }
548
    }
549
    
550
    // Check early termination
551
    bool checkTermination(int k) {
552
      typedef std::pair<int, int> Pair;
553
      typename GR::template NodeMap<Pair> level(_gr, Pair(-1, 0));
554
      typename GR::template NodeMap<LargeValue> pi(_gr);
555
      int n = _nodes->size();
556
      LargeValue length;
557
      int size;
558
      Node u;
559
      
560
      // Search for cycles that are already found
561
      _curr_found = false;
562
      for (int i = 0; i < n; ++i) {
563
        u = (*_nodes)[i];
564
        if (!_data[u][k].found) continue;
565
        for (int j = k; j >= 0; --j) {
566
          if (level[u].first == i && level[u].second > 0) {
567
            // A cycle is found
568
            length = _data[u][level[u].second].dist - _data[u][j].dist;
569
            size = level[u].second - j;
570
            if (!_curr_found || length * _curr_size < _curr_length * size) {
571
              _curr_length = length;
572
              _curr_size = size;
573
              _curr_node = u;
574
              _curr_level = level[u].second;
575
              _curr_found = true;
576
            }
577
          }
578
          level[u] = Pair(i, j);
579
          u = _gr.source(_data[u][j].pred);
580
        }
581
      }
582

	
583
      // If at least one cycle is found, check the optimality condition
584
      LargeValue d;
585
      if (_curr_found && k < n) {
586
        // Find node potentials
587
        for (int i = 0; i < n; ++i) {
588
          u = (*_nodes)[i];
589
          pi[u] = std::numeric_limits<LargeValue>::max();
590
          for (int j = 0; j <= k; ++j) {
591
            d = _data[u][j].dist * _curr_size - j * _curr_length;
592
            if (_data[u][j].found && _tolerance.less(d, pi[u])) {
593
              pi[u] = d;
594
            }
595
          }
596
        }
597

	
598
        // Check the optimality condition for all arcs
599
        bool done = true;
600
        for (ArcIt a(_gr); a != INVALID; ++a) {
601
          if (_tolerance.less(_length[a] * _curr_size - _curr_length,
602
                              pi[_gr.target(a)] - pi[_gr.source(a)]) ) {
603
            done = false;
604
            break;
605
          }
606
        }
607
        return done;
608
      }
609
      return (k == n);
610
    }
611

	
612
  }; //class HartmannOrlin
613

	
614
  ///@}
615

	
616
} //namespace lemon
617

	
618
#endif //LEMON_HARTMANN_ORLIN_H
Show white space 6 line context
... ...
@@ -83,6 +83,7 @@
83 83
	lemon/gomory_hu.h \
84 84
	lemon/graph_to_eps.h \
85 85
	lemon/grid_graph.h \
86
	lemon/hartmann_orlin.h \
86 87
	lemon/howard.h \
87 88
	lemon/hypercube_graph.h \
88 89
	lemon/karp.h \
Show white space 6 line context
... ...
@@ -26,6 +26,7 @@
26 26
#include <lemon/concept_check.h>
27 27

	
28 28
#include <lemon/karp.h>
29
#include <lemon/hartmann_orlin.h>
29 30
#include <lemon/howard.h>
30 31

	
31 32
#include "test_tools.h"
... ...
@@ -150,6 +151,12 @@
150 151
    checkConcept< MmcClassConcept<GR, float>,
151 152
                  Karp<GR, concepts::ReadMap<GR::Arc, float> > >();
152 153
    
154
    // HartmannOrlin
155
    checkConcept< MmcClassConcept<GR, int>,
156
                  HartmannOrlin<GR, concepts::ReadMap<GR::Arc, int> > >();
157
    checkConcept< MmcClassConcept<GR, float>,
158
                  HartmannOrlin<GR, concepts::ReadMap<GR::Arc, float> > >();
159
    
153 160
    // Howard
154 161
    checkConcept< MmcClassConcept<GR, int>,
155 162
                  Howard<GR, concepts::ReadMap<GR::Arc, int> > >();
... ...
@@ -189,6 +196,12 @@
189 196
    checkMmcAlg<Karp<GR, IntArcMap> >(gr, l3, c3,  0, 1);
190 197
    checkMmcAlg<Karp<GR, IntArcMap> >(gr, l4, c4, -1, 1);
191 198

	
199
    // HartmannOrlin
200
    checkMmcAlg<HartmannOrlin<GR, IntArcMap> >(gr, l1, c1,  6, 3);
201
    checkMmcAlg<HartmannOrlin<GR, IntArcMap> >(gr, l2, c2,  5, 2);
202
    checkMmcAlg<HartmannOrlin<GR, IntArcMap> >(gr, l3, c3,  0, 1);
203
    checkMmcAlg<HartmannOrlin<GR, IntArcMap> >(gr, l4, c4, -1, 1);
204

	
192 205
    // Howard
193 206
    checkMmcAlg<Howard<GR, IntArcMap> >(gr, l1, c1,  6, 3);
194 207
    checkMmcAlg<Howard<GR, IntArcMap> >(gr, l2, c2,  5, 2);
0 comments (0 inline)