gravatar
kpeter (Peter Kovacs)
kpeter@inf.elte.hu
Add Karp algorithm class (#179) based on the MinMeanCycle implementation in SVN -r3436. The interface is reworked to be the same as Howard's interface.
0 2 1
default
3 files changed with 587 insertions and 10 deletions:
↑ Collapse diff ↑
Ignore white space 24 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_KARP_H
20
#define LEMON_KARP_H
21

	
22
/// \ingroup shortest_path
23
///
24
/// \file
25
/// \brief Karp'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 Karp algorithm.
37
  ///
38
  /// Default traits class of Karp 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::ReadMap "ReadMap" 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 KarpDefaultTraits
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 KarpDefaultTraits<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 Karp's algorithm for finding a minimum
97
  /// mean cycle.
98
  ///
99
  /// This class implements Karp's algorithm for finding a directed
100
  /// cycle of minimum mean length (cost) in a digraph.
101
  ///
102
  /// \tparam GR The type of the digraph the algorithm runs on.
103
  /// \tparam LEN The type of the length map. The default
104
  /// map type is \ref concepts::Digraph::ArcMap "GR::ArcMap<int>".
105
#ifdef DOXYGEN
106
  template <typename GR, typename LEN, typename TR>
107
#else
108
  template < typename GR,
109
             typename LEN = typename GR::template ArcMap<int>,
110
             typename TR = KarpDefaultTraits<GR, LEN> >
111
#endif
112
  class Karp
113
  {
114
  public:
115

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

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

	
131
    /// The tolerance type
132
    typedef typename TR::Tolerance Tolerance;
133

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

	
141
    /// The \ref KarpDefaultTraits "traits class" of the algorithm
142
    typedef TR Traits;
143

	
144
  private:
145

	
146
    TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
147

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

	
158
    typedef typename Digraph::template NodeMap<std::vector<PathData> >
159
      PathDataNodeMap;
160

	
161
  private:
162

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

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

	
175
    // Data for the found cycle
176
    LargeValue _cycle_length;
177
    int _cycle_size;
178
    Node _cycle_node;
179

	
180
    Path *_cycle_path;
181
    bool _local_path;
182

	
183
    // Node map for storing path data
184
    PathDataNodeMap _data;
185
    // The processed nodes in the last round
186
    std::vector<Node> _process;
187

	
188
    Tolerance _tolerance;
189

	
190
  public:
191

	
192
    /// \name Named Template Parameters
193
    /// @{
194

	
195
    template <typename T>
196
    struct SetLargeValueTraits : public Traits {
197
      typedef T LargeValue;
198
      typedef lemon::Tolerance<T> Tolerance;
199
    };
200

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

	
212
    template <typename T>
213
    struct SetPathTraits : public Traits {
214
      typedef T Path;
215
    };
216

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

	
230
    /// @}
231

	
232
  public:
233

	
234
    /// \brief Constructor.
235
    ///
236
    /// The constructor of the class.
237
    ///
238
    /// \param digraph The digraph the algorithm runs on.
239
    /// \param length The lengths (costs) of the arcs.
240
    Karp( const Digraph &digraph,
241
          const LengthMap &length ) :
242
      _gr(digraph), _length(length), _comp(digraph), _out_arcs(digraph),
243
      _cycle_length(0), _cycle_size(1), _cycle_node(INVALID),
244
      _cycle_path(NULL), _local_path(false), _data(digraph)
245
    {}
246

	
247
    /// Destructor.
248
    ~Karp() {
249
      if (_local_path) delete _cycle_path;
250
    }
251

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

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

	
281
    /// @{
282

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

	
299
    /// \brief Find the minimum cycle mean.
300
    ///
301
    /// This function finds the minimum mean length of the directed
302
    /// cycles in the digraph.
303
    ///
304
    /// \return \c true if a directed cycle exists in the digraph.
305
    bool findMinMean() {
306
      // Initialization and find strongly connected components
307
      init();
308
      findComponents();
309
      
310
      // Find the minimum cycle mean in the components
311
      for (int comp = 0; comp < _comp_num; ++comp) {
312
        if (!initComponent(comp)) continue;
313
        processRounds();
314
        updateMinMean();
315
      }
316
      return (_cycle_node != INVALID);
317
    }
318

	
319
    /// \brief Find a minimum mean directed cycle.
320
    ///
321
    /// This function finds a directed cycle of minimum mean length
322
    /// in the digraph using the data computed by findMinMean().
323
    ///
324
    /// \return \c true if a directed cycle exists in the digraph.
325
    ///
326
    /// \pre \ref findMinMean() must be called before using this function.
327
    bool findCycle() {
328
      if (_cycle_node == INVALID) return false;
329
      IntNodeMap reached(_gr, -1);
330
      int r = _data[_cycle_node].size();
331
      Node u = _cycle_node;
332
      while (reached[u] < 0) {
333
        reached[u] = --r;
334
        u = _gr.source(_data[u][r].pred);
335
      }
336
      r = reached[u];
337
      Arc e = _data[u][r].pred;
338
      _cycle_path->addFront(e);
339
      _cycle_length = _length[e];
340
      _cycle_size = 1;
341
      Node v;
342
      while ((v = _gr.source(e)) != u) {
343
        e = _data[v][--r].pred;
344
        _cycle_path->addFront(e);
345
        _cycle_length += _length[e];
346
        ++_cycle_size;
347
      }
348
      return true;
349
    }
350

	
351
    /// @}
352

	
353
    /// \name Query Functions
354
    /// The results of the algorithm can be obtained using these
355
    /// functions.\n
356
    /// The algorithm should be executed before using them.
357

	
358
    /// @{
359

	
360
    /// \brief Return the total length of the found cycle.
361
    ///
362
    /// This function returns the total length of the found cycle.
363
    ///
364
    /// \pre \ref run() or \ref findMinMean() must be called before
365
    /// using this function.
366
    LargeValue cycleLength() const {
367
      return _cycle_length;
368
    }
369

	
370
    /// \brief Return the number of arcs on the found cycle.
371
    ///
372
    /// This function returns the number of arcs on the found cycle.
373
    ///
374
    /// \pre \ref run() or \ref findMinMean() must be called before
375
    /// using this function.
376
    int cycleArcNum() const {
377
      return _cycle_size;
378
    }
379

	
380
    /// \brief Return the mean length of the found cycle.
381
    ///
382
    /// This function returns the mean length of the found cycle.
383
    ///
384
    /// \note <tt>alg.cycleMean()</tt> is just a shortcut of the
385
    /// following code.
386
    /// \code
387
    ///   return static_cast<double>(alg.cycleLength()) / alg.cycleArcNum();
388
    /// \endcode
389
    ///
390
    /// \pre \ref run() or \ref findMinMean() must be called before
391
    /// using this function.
392
    double cycleMean() const {
393
      return static_cast<double>(_cycle_length) / _cycle_size;
394
    }
395

	
396
    /// \brief Return the found cycle.
397
    ///
398
    /// This function returns a const reference to the path structure
399
    /// storing the found cycle.
400
    ///
401
    /// \pre \ref run() or \ref findCycle() must be called before using
402
    /// this function.
403
    const Path& cycle() const {
404
      return *_cycle_path;
405
    }
406

	
407
    ///@}
408

	
409
  private:
410

	
411
    // Initialization
412
    void init() {
413
      if (!_cycle_path) {
414
        _local_path = true;
415
        _cycle_path = new Path;
416
      }
417
      _cycle_path->clear();
418
      _cycle_length = 0;
419
      _cycle_size = 1;
420
      _cycle_node = INVALID;
421
      for (NodeIt u(_gr); u != INVALID; ++u)
422
        _data[u].clear();
423
    }
424

	
425
    // Find strongly connected components and initialize _comp_nodes
426
    // and _out_arcs
427
    void findComponents() {
428
      _comp_num = stronglyConnectedComponents(_gr, _comp);
429
      _comp_nodes.resize(_comp_num);
430
      if (_comp_num == 1) {
431
        _comp_nodes[0].clear();
432
        for (NodeIt n(_gr); n != INVALID; ++n) {
433
          _comp_nodes[0].push_back(n);
434
          _out_arcs[n].clear();
435
          for (OutArcIt a(_gr, n); a != INVALID; ++a) {
436
            _out_arcs[n].push_back(a);
437
          }
438
        }
439
      } else {
440
        for (int i = 0; i < _comp_num; ++i)
441
          _comp_nodes[i].clear();
442
        for (NodeIt n(_gr); n != INVALID; ++n) {
443
          int k = _comp[n];
444
          _comp_nodes[k].push_back(n);
445
          _out_arcs[n].clear();
446
          for (OutArcIt a(_gr, n); a != INVALID; ++a) {
447
            if (_comp[_gr.target(a)] == k) _out_arcs[n].push_back(a);
448
          }
449
        }
450
      }
451
    }
452

	
453
    // Initialize path data for the current component
454
    bool initComponent(int comp) {
455
      _nodes = &(_comp_nodes[comp]);
456
      int n = _nodes->size();
457
      if (n < 1 || (n == 1 && _out_arcs[(*_nodes)[0]].size() == 0)) {
458
        return false;
459
      }      
460
      for (int i = 0; i < n; ++i) {
461
        _data[(*_nodes)[i]].resize(n + 1);
462
      }
463
      return true;
464
    }
465

	
466
    // Process all rounds of computing path data for the current component.
467
    // _data[v][k] is the length of a shortest directed walk from the root
468
    // node to node v containing exactly k arcs.
469
    void processRounds() {
470
      Node start = (*_nodes)[0];
471
      _data[start][0] = PathData(true, 0);
472
      _process.clear();
473
      _process.push_back(start);
474

	
475
      int k, n = _nodes->size();
476
      for (k = 1; k <= n && int(_process.size()) < n; ++k) {
477
        processNextBuildRound(k);
478
      }
479
      for ( ; k <= n; ++k) {
480
        processNextFullRound(k);
481
      }
482
    }
483

	
484
    // Process one round and rebuild _process
485
    void processNextBuildRound(int k) {
486
      std::vector<Node> next;
487
      Node u, v;
488
      Arc e;
489
      LargeValue d;
490
      for (int i = 0; i < int(_process.size()); ++i) {
491
        u = _process[i];
492
        for (int j = 0; j < int(_out_arcs[u].size()); ++j) {
493
          e = _out_arcs[u][j];
494
          v = _gr.target(e);
495
          d = _data[u][k-1].dist + _length[e];
496
          if (!_data[v][k].found) {
497
            next.push_back(v);
498
            _data[v][k] = PathData(true, _data[u][k-1].dist + _length[e], e);
499
          }
500
          else if (_tolerance.less(d, _data[v][k].dist)) {
501
            _data[v][k] = PathData(true, d, e);
502
          }
503
        }
504
      }
505
      _process.swap(next);
506
    }
507

	
508
    // Process one round using _nodes instead of _process
509
    void processNextFullRound(int k) {
510
      Node u, v;
511
      Arc e;
512
      LargeValue d;
513
      for (int i = 0; i < int(_nodes->size()); ++i) {
514
        u = (*_nodes)[i];
515
        for (int j = 0; j < int(_out_arcs[u].size()); ++j) {
516
          e = _out_arcs[u][j];
517
          v = _gr.target(e);
518
          d = _data[u][k-1].dist + _length[e];
519
          if (!_data[v][k].found || _tolerance.less(d, _data[v][k].dist)) {
520
            _data[v][k] = PathData(true, d, e);
521
          }
522
        }
523
      }
524
    }
525

	
526
    // Update the minimum cycle mean
527
    void updateMinMean() {
528
      int n = _nodes->size();
529
      for (int i = 0; i < n; ++i) {
530
        Node u = (*_nodes)[i];
531
        if (!_data[u][n].found) continue;
532
        LargeValue length, max_length = 0;
533
        int size, max_size = 1;
534
        bool found_curr = false;
535
        for (int k = 0; k < n; ++k) {
536
          if (!_data[u][k].found) continue;
537
          length = _data[u][n].dist - _data[u][k].dist;
538
          size = n - k;
539
          if (!found_curr || length * max_size > max_length * size) {
540
            found_curr = true;
541
            max_length = length;
542
            max_size = size;
543
          }
544
        }
545
        if ( found_curr && (_cycle_node == INVALID ||
546
             max_length * _cycle_size < _cycle_length * max_size) ) {
547
          _cycle_length = max_length;
548
          _cycle_size = max_size;
549
          _cycle_node = u;
550
        }
551
      }
552
    }
553

	
554
  }; //class Karp
555

	
556
  ///@}
557

	
558
} //namespace lemon
559

	
560
#endif //LEMON_KARP_H
Ignore white space 6 line context
... ...
@@ -76,24 +76,25 @@
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 86
	lemon/howard.h \
87 87
	lemon/hypercube_graph.h \
88
	lemon/karp.h \
88 89
	lemon/kruskal.h \
89 90
	lemon/hao_orlin.h \
90 91
	lemon/lgf_reader.h \
91 92
	lemon/lgf_writer.h \
92 93
	lemon/list_graph.h \
93 94
	lemon/lp.h \
94 95
	lemon/lp_base.h \
95 96
	lemon/lp_skeleton.h \
96 97
	lemon/list_graph.h \
97 98
	lemon/maps.h \
98 99
	lemon/matching.h \
99 100
	lemon/math.h \
Ignore white space 6 line context
... ...
@@ -12,29 +12,31 @@
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
#include <lemon/howard.h>
25 24
#include <lemon/path.h>
26 25
#include <lemon/concepts/digraph.h>
27 26
#include <lemon/concept_check.h>
28 27

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

	
29 31
#include "test_tools.h"
30 32

	
31 33
using namespace lemon;
32 34

	
33 35
char test_lgf[] =
34 36
  "@nodes\n"
35 37
  "label\n"
36 38
  "1\n"
37 39
  "2\n"
38 40
  "3\n"
39 41
  "4\n"
40 42
  "5\n"
... ...
@@ -132,53 +134,67 @@
132 134

	
133 135

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

	
141 143
  // Check the interface
142 144
  {
143 145
    typedef concepts::Digraph GR;
144
    typedef Howard<GR, concepts::ReadMap<GR::Arc, int> > IntMmcAlg;
145
    typedef Howard<GR, concepts::ReadMap<GR::Arc, float> > FloatMmcAlg;
146

	
147
    // Karp
148
    checkConcept< MmcClassConcept<GR, int>,
149
                  Karp<GR, concepts::ReadMap<GR::Arc, int> > >();
150
    checkConcept< MmcClassConcept<GR, float>,
151
                  Karp<GR, concepts::ReadMap<GR::Arc, float> > >();
146 152
    
147
    checkConcept<MmcClassConcept<GR, int>, IntMmcAlg>();
148
    checkConcept<MmcClassConcept<GR, float>, FloatMmcAlg>();
149
  
150
    if (IsSameType<IntMmcAlg::LargeValue, long_int>::result == 0)
151
      check(false, "Wrong LargeValue type");
152
    if (IsSameType<FloatMmcAlg::LargeValue, double>::result == 0)
153
      check(false, "Wrong LargeValue type");
153
    // Howard
154
    checkConcept< MmcClassConcept<GR, int>,
155
                  Howard<GR, concepts::ReadMap<GR::Arc, int> > >();
156
    checkConcept< MmcClassConcept<GR, float>,
157
                  Howard<GR, concepts::ReadMap<GR::Arc, float> > >();
158

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

	
156 165
  // Run various tests
157 166
  {
158 167
    typedef SmartDigraph GR;
159 168
    DIGRAPH_TYPEDEFS(GR);
160 169
    
161 170
    GR gr;
162 171
    IntArcMap l1(gr), l2(gr), l3(gr), l4(gr);
163 172
    IntArcMap c1(gr), c2(gr), c3(gr), c4(gr);
164 173
    
165 174
    std::istringstream input(test_lgf);
166 175
    digraphReader(gr, input).
167 176
      arcMap("len1", l1).
168 177
      arcMap("len2", l2).
169 178
      arcMap("len3", l3).
170 179
      arcMap("len4", l4).
171 180
      arcMap("c1", c1).
172 181
      arcMap("c2", c2).
173 182
      arcMap("c3", c3).
174 183
      arcMap("c4", c4).
175 184
      run();
176 185

	
186
    // Karp
187
    checkMmcAlg<Karp<GR, IntArcMap> >(gr, l1, c1,  6, 3);
188
    checkMmcAlg<Karp<GR, IntArcMap> >(gr, l2, c2,  5, 2);
189
    checkMmcAlg<Karp<GR, IntArcMap> >(gr, l3, c3,  0, 1);
190
    checkMmcAlg<Karp<GR, IntArcMap> >(gr, l4, c4, -1, 1);
191

	
192
    // Howard
177 193
    checkMmcAlg<Howard<GR, IntArcMap> >(gr, l1, c1,  6, 3);
178 194
    checkMmcAlg<Howard<GR, IntArcMap> >(gr, l2, c2,  5, 2);
179 195
    checkMmcAlg<Howard<GR, IntArcMap> >(gr, l3, c3,  0, 1);
180 196
    checkMmcAlg<Howard<GR, IntArcMap> >(gr, l4, c4, -1, 1);
181 197
  }
182 198

	
183 199
  return 0;
184 200
}
0 comments (0 inline)