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 ↑
Ignore 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
Ignore white space 6 line context
... ...
@@ -62,48 +62,49 @@
62 62
	lemon/bucket_heap.h \
63 63
	lemon/cbc.h \
64 64
	lemon/circulation.h \
65 65
	lemon/clp.h \
66 66
	lemon/color.h \
67 67
	lemon/concept_check.h \
68 68
	lemon/connectivity.h \
69 69
	lemon/counter.h \
70 70
	lemon/core.h \
71 71
	lemon/cplex.h \
72 72
	lemon/dfs.h \
73 73
	lemon/dijkstra.h \
74 74
	lemon/dim2.h \
75 75
	lemon/dimacs.h \
76 76
	lemon/edge_set.h \
77 77
	lemon/elevator.h \
78 78
	lemon/error.h \
79 79
	lemon/euler.h \
80 80
	lemon/fib_heap.h \
81 81
	lemon/full_graph.h \
82 82
	lemon/glpk.h \
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 \
89 90
	lemon/kruskal.h \
90 91
	lemon/hao_orlin.h \
91 92
	lemon/lgf_reader.h \
92 93
	lemon/lgf_writer.h \
93 94
	lemon/list_graph.h \
94 95
	lemon/lp.h \
95 96
	lemon/lp_base.h \
96 97
	lemon/lp_skeleton.h \
97 98
	lemon/list_graph.h \
98 99
	lemon/maps.h \
99 100
	lemon/matching.h \
100 101
	lemon/math.h \
101 102
	lemon/min_cost_arborescence.h \
102 103
	lemon/nauty_reader.h \
103 104
	lemon/network_simplex.h \
104 105
	lemon/path.h \
105 106
	lemon/preflow.h \
106 107
	lemon/radix_heap.h \
107 108
	lemon/radix_sort.h \
108 109
	lemon/random.h \
109 110
	lemon/smart_graph.h \
Ignore white space 48 line context
... ...
@@ -5,48 +5,49 @@
5 5
 * Copyright (C) 2003-2009
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
#include <iostream>
20 20
#include <sstream>
21 21

	
22 22
#include <lemon/smart_graph.h>
23 23
#include <lemon/lgf_reader.h>
24 24
#include <lemon/path.h>
25 25
#include <lemon/concepts/digraph.h>
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"
32 33

	
33 34
using namespace lemon;
34 35

	
35 36
char test_lgf[] =
36 37
  "@nodes\n"
37 38
  "label\n"
38 39
  "1\n"
39 40
  "2\n"
40 41
  "3\n"
41 42
  "4\n"
42 43
  "5\n"
43 44
  "6\n"
44 45
  "7\n"
45 46
  "@arcs\n"
46 47
  "    len1 len2 len3 len4  c1 c2 c3 c4\n"
47 48
  "1 2    1    1    1    1   0  0  0  0\n"
48 49
  "2 4    5    5    5    5   1  0  0  0\n"
49 50
  "2 3    8    8    8    8   0  0  0  0\n"
50 51
  "3 2   -2    0    0    0   1  0  0  0\n"
51 52
  "3 4    4    4    4    4   0  0  0  0\n"
52 53
  "3 7   -4   -4   -4   -4   0  0  0  0\n"
... ...
@@ -129,72 +130,84 @@
129 130

	
130 131
template <typename T>
131 132
struct IsSameType<T,T> {
132 133
  static const int result = 1;
133 134
};
134 135

	
135 136

	
136 137
int main() {
137 138
  #ifdef LEMON_HAVE_LONG_LONG
138 139
    typedef long long long_int;
139 140
  #else
140 141
    typedef long long_int;
141 142
  #endif
142 143

	
143 144
  // Check the interface
144 145
  {
145 146
    typedef concepts::Digraph GR;
146 147

	
147 148
    // Karp
148 149
    checkConcept< MmcClassConcept<GR, int>,
149 150
                  Karp<GR, concepts::ReadMap<GR::Arc, int> > >();
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> > >();
156 163
    checkConcept< MmcClassConcept<GR, float>,
157 164
                  Howard<GR, concepts::ReadMap<GR::Arc, float> > >();
158 165

	
159 166
    if (IsSameType<Howard<GR, concepts::ReadMap<GR::Arc, int> >::LargeValue,
160 167
          long_int>::result == 0) check(false, "Wrong LargeValue type");
161 168
    if (IsSameType<Howard<GR, concepts::ReadMap<GR::Arc, float> >::LargeValue,
162 169
          double>::result == 0) check(false, "Wrong LargeValue type");
163 170
  }
164 171

	
165 172
  // Run various tests
166 173
  {
167 174
    typedef SmartDigraph GR;
168 175
    DIGRAPH_TYPEDEFS(GR);
169 176
    
170 177
    GR gr;
171 178
    IntArcMap l1(gr), l2(gr), l3(gr), l4(gr);
172 179
    IntArcMap c1(gr), c2(gr), c3(gr), c4(gr);
173 180
    
174 181
    std::istringstream input(test_lgf);
175 182
    digraphReader(gr, input).
176 183
      arcMap("len1", l1).
177 184
      arcMap("len2", l2).
178 185
      arcMap("len3", l3).
179 186
      arcMap("len4", l4).
180 187
      arcMap("c1", c1).
181 188
      arcMap("c2", c2).
182 189
      arcMap("c3", c3).
183 190
      arcMap("c4", c4).
184 191
      run();
185 192

	
186 193
    // Karp
187 194
    checkMmcAlg<Karp<GR, IntArcMap> >(gr, l1, c1,  6, 3);
188 195
    checkMmcAlg<Karp<GR, IntArcMap> >(gr, l2, c2,  5, 2);
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);
195 208
    checkMmcAlg<Howard<GR, IntArcMap> >(gr, l3, c3,  0, 1);
196 209
    checkMmcAlg<Howard<GR, IntArcMap> >(gr, l4, c4, -1, 1);
197 210
  }
198 211

	
199 212
  return 0;
200 213
}
0 comments (0 inline)