gravatar
kpeter (Peter Kovacs)
kpeter@inf.elte.hu
Add a detailed test file for MinMeanCycle and fix test_tools.h (#179)
0 4 1
default
5 files changed with 197 insertions and 5 deletions:
↑ Collapse diff ↑
Ignore white space 6 line context
1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
2
 *
3
 * This file is a part of LEMON, a generic C++ optimization library.
4
 *
5
 * Copyright (C) 2003-2009
6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
8
 *
9
 * Permission to use, modify and distribute this software is granted
10
 * provided that this copyright notice appears in all copies. For
11
 * precise terms see the accompanying LICENSE file.
12
 *
13
 * This software is provided "AS IS" with no warranty of any kind,
14
 * express or implied, and with no claim as to its suitability for any
15
 * purpose.
16
 *
17
 */
18

	
19
#include <iostream>
20
#include <sstream>
21

	
22
#include <lemon/smart_graph.h>
23
#include <lemon/lgf_reader.h>
24
#include <lemon/min_mean_cycle.h>
25
#include <lemon/path.h>
26
#include <lemon/concepts/digraph.h>
27
#include <lemon/concept_check.h>
28

	
29
#include "test_tools.h"
30

	
31
using namespace lemon;
32

	
33
char test_lgf[] =
34
  "@nodes\n"
35
  "label\n"
36
  "1\n"
37
  "2\n"
38
  "3\n"
39
  "4\n"
40
  "5\n"
41
  "6\n"
42
  "7\n"
43
  "@arcs\n"
44
  "    len1 len2 len3 len4  c1 c2 c3 c4\n"
45
  "1 2    1    1    1    1   0  0  0  0\n"
46
  "2 4    5    5    5    5   1  0  0  0\n"
47
  "2 3    8    8    8    8   0  0  0  0\n"
48
  "3 2   -2    0    0    0   1  0  0  0\n"
49
  "3 4    4    4    4    4   0  0  0  0\n"
50
  "3 7   -4   -4   -4   -4   0  0  0  0\n"
51
  "4 1    2    2    2    2   0  0  0  0\n"
52
  "4 3    3    3    3    3   1  0  0  0\n"
53
  "4 4    3    3    0    0   0  0  1  0\n"
54
  "5 2    4    4    4    4   0  0  0  0\n"
55
  "5 6    3    3    3    3   0  1  0  0\n"
56
  "6 5    2    2    2    2   0  1  0  0\n"
57
  "6 4   -1   -1   -1   -1   0  0  0  0\n"
58
  "6 7    1    1    1    1   0  0  0  0\n"
59
  "7 7    4    4    4   -1   0  0  0  1\n";
60

	
61
                        
62
// Check the interface of an MMC algorithm
63
template <typename GR, typename Value>
64
struct MmcClassConcept
65
{
66
  template <typename MMC>
67
  struct Constraints {
68
    void constraints() {
69
      const Constraints& me = *this;
70

	
71
      typedef typename MMC
72
        ::template SetPath<ListPath<GR> >
73
        ::template SetLargeValue<Value>
74
        ::Create MmcAlg;
75
      MmcAlg mmc(me.g, me.length);
76
      const MmcAlg& const_mmc = mmc;
77
      
78
      b = mmc.cycle(p).run();
79
      b = mmc.findMinMean();
80
      b = mmc.findCycle();
81

	
82
      v = const_mmc.cycleLength();
83
      i = const_mmc.cycleArcNum();
84
      d = const_mmc.cycleMean();
85
      p = const_mmc.cycle();
86
    }
87

	
88
    typedef concepts::ReadMap<typename GR::Arc, Value> LM;
89
  
90
    GR g;
91
    LM length;
92
    ListPath<GR> p;
93
    Value v;
94
    int i;
95
    double d;
96
    bool b;
97
  };
98
};
99

	
100
// Perform a test with the given parameters
101
template <typename MMC>
102
void checkMmcAlg(const SmartDigraph& gr,
103
                 const SmartDigraph::ArcMap<int>& lm,
104
                 const SmartDigraph::ArcMap<int>& cm,
105
                 int length, int size) {
106
  MMC alg(gr, lm);
107
  alg.findMinMean();
108
  check(alg.cycleMean() == static_cast<double>(length) / size,
109
        "Wrong cycle mean");
110
  alg.findCycle();
111
  check(alg.cycleLength() == length && alg.cycleArcNum() == size,
112
        "Wrong path");
113
  SmartDigraph::ArcMap<int> cycle(gr, 0);
114
  for (typename MMC::Path::ArcIt a(alg.cycle()); a != INVALID; ++a) {
115
    ++cycle[a];
116
  }
117
  for (SmartDigraph::ArcIt a(gr); a != INVALID; ++a) {
118
    check(cm[a] == cycle[a], "Wrong path");
119
  }
120
}
121

	
122
// Class for comparing types
123
template <typename T1, typename T2>
124
struct IsSameType {
125
  static const int result = 0;
126
};
127

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

	
133

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

	
141
  // Check the interface
142
  {
143
    typedef concepts::Digraph GR;
144
    typedef MinMeanCycle<GR, concepts::ReadMap<GR::Arc, int> > IntMmcAlg;
145
    typedef MinMeanCycle<GR, concepts::ReadMap<GR::Arc, float> > FloatMmcAlg;
146
    
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");
154
  }
155

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

	
177
    checkMmcAlg<MinMeanCycle<GR, IntArcMap> >(gr, l1, c1,  6, 3);
178
    checkMmcAlg<MinMeanCycle<GR, IntArcMap> >(gr, l2, c2,  5, 2);
179
    checkMmcAlg<MinMeanCycle<GR, IntArcMap> >(gr, l3, c3,  0, 1);
180
    checkMmcAlg<MinMeanCycle<GR, IntArcMap> >(gr, l4, c4, -1, 1);
181
  }
182

	
183
  return 0;
184
}
Ignore white space 2048 line context
1 1
/* -*- C++ -*-
2 2
 *
3 3
 * This file is a part of LEMON, a generic C++ optimization library
4 4
 *
5 5
 * Copyright (C) 2003-2008
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_MIN_MEAN_CYCLE_H
20 20
#define LEMON_MIN_MEAN_CYCLE_H
21 21

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

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

	
33 34
namespace lemon {
34 35

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

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

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

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

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

	
91 92

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

	
95 96
  /// \brief Implementation of Howard's algorithm for finding a minimum
96 97
  /// mean cycle.
97 98
  ///
98 99
  /// \ref MinMeanCycle implements Howard's algorithm for finding a
99 100
  /// directed cycle of minimum mean length (cost) in a digraph.
100 101
  ///
101 102
  /// \tparam GR The type of the digraph the algorithm runs on.
102 103
  /// \tparam LEN The type of the length map. The default
103 104
  /// map type is \ref concepts::Digraph::ArcMap "GR::ArcMap<int>".
104 105
#ifdef DOXYGEN
105 106
  template <typename GR, typename LEN, typename TR>
106 107
#else
107 108
  template < typename GR,
108 109
             typename LEN = typename GR::template ArcMap<int>,
109 110
             typename TR = MinMeanCycleDefaultTraits<GR, LEN> >
110 111
#endif
111 112
  class MinMeanCycle
112 113
  {
113 114
  public:
114 115
  
115 116
    /// The type of the digraph
116 117
    typedef typename TR::Digraph Digraph;
117 118
    /// The type of the length map
118 119
    typedef typename TR::LengthMap LengthMap;
119 120
    /// The type of the arc lengths
120 121
    typedef typename TR::Value Value;
121 122

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

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

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

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

	
143 144
  private:
144 145

	
145 146
    TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
146 147
  
147 148
    // The digraph the algorithm runs on
148 149
    const Digraph &_gr;
149 150
    // The length of the arcs
150 151
    const LengthMap &_length;
151 152

	
152 153
    // Data for the found cycles
153 154
    bool _curr_found, _best_found;
154 155
    LargeValue _curr_length, _best_length;
155 156
    int _curr_size, _best_size;
156 157
    Node _curr_node, _best_node;
157 158

	
158 159
    Path *_cycle_path;
159 160
    bool _local_path;
160 161

	
161 162
    // Internal data used by the algorithm
162 163
    typename Digraph::template NodeMap<Arc> _policy;
163 164
    typename Digraph::template NodeMap<bool> _reached;
164 165
    typename Digraph::template NodeMap<int> _level;
165 166
    typename Digraph::template NodeMap<LargeValue> _dist;
166 167

	
167 168
    // Data for storing the strongly connected components
168 169
    int _comp_num;
169 170
    typename Digraph::template NodeMap<int> _comp;
170 171
    std::vector<std::vector<Node> > _comp_nodes;
171 172
    std::vector<Node>* _nodes;
172 173
    typename Digraph::template NodeMap<std::vector<Arc> > _in_arcs;
173 174
    
174 175
    // Queue used for BFS search
175 176
    std::vector<Node> _queue;
176 177
    int _qfront, _qback;
177 178

	
178 179
    Tolerance _tolerance;
179 180
  
180 181
  public:
181 182
  
182 183
    /// \name Named Template Parameters
183 184
    /// @{
184 185

	
185 186
    template <typename T>
186 187
    struct SetLargeValueTraits : public Traits {
187 188
      typedef T LargeValue;
188 189
      typedef lemon::Tolerance<T> Tolerance;
189 190
    };
190 191

	
191 192
    /// \brief \ref named-templ-param "Named parameter" for setting
192 193
    /// \c LargeValue type.
193 194
    ///
194 195
    /// \ref named-templ-param "Named parameter" for setting \c LargeValue
195 196
    /// type. It is used for internal computations in the algorithm.
196 197
    template <typename T>
197 198
    struct SetLargeValue
198 199
      : public MinMeanCycle<GR, LEN, SetLargeValueTraits<T> > {
199 200
      typedef MinMeanCycle<GR, LEN, SetLargeValueTraits<T> > Create;
200 201
    };
201 202

	
202 203
    template <typename T>
203 204
    struct SetPathTraits : public Traits {
204 205
      typedef T Path;
205 206
    };
206 207

	
207 208
    /// \brief \ref named-templ-param "Named parameter" for setting
208 209
    /// \c %Path type.
209 210
    ///
210 211
    /// \ref named-templ-param "Named parameter" for setting the \c %Path
211 212
    /// type of the found cycles.
212 213
    /// It must conform to the \ref lemon::concepts::Path "Path" concept
213 214
    /// and it must have an \c addBack() function.
214 215
    template <typename T>
215 216
    struct SetPath
216 217
      : public MinMeanCycle<GR, LEN, SetPathTraits<T> > {
217 218
      typedef MinMeanCycle<GR, LEN, SetPathTraits<T> > Create;
218 219
    };
219 220
    
220 221
    /// @}
221 222

	
222 223
  public:
223 224

	
224 225
    /// \brief Constructor.
225 226
    ///
226 227
    /// The constructor of the class.
227 228
    ///
228 229
    /// \param digraph The digraph the algorithm runs on.
229 230
    /// \param length The lengths (costs) of the arcs.
230 231
    MinMeanCycle( const Digraph &digraph,
231 232
                  const LengthMap &length ) :
232 233
      _gr(digraph), _length(length), _cycle_path(NULL), _local_path(false),
233 234
      _policy(digraph), _reached(digraph), _level(digraph), _dist(digraph),
234 235
      _comp(digraph), _in_arcs(digraph)
235 236
    {}
236 237

	
237 238
    /// Destructor.
238 239
    ~MinMeanCycle() {
239 240
      if (_local_path) delete _cycle_path;
240 241
    }
241 242

	
242 243
    /// \brief Set the path structure for storing the found cycle.
243 244
    ///
244 245
    /// This function sets an external path structure for storing the
245 246
    /// found cycle.
246 247
    ///
247 248
    /// If you don't call this function before calling \ref run() or
248 249
    /// \ref findMinMean(), it will allocate a local \ref Path "path"
249 250
    /// structure. The destuctor deallocates this automatically
250 251
    /// allocated object, of course.
251 252
    ///
252 253
    /// \note The algorithm calls only the \ref lemon::Path::addBack()
253 254
    /// "addBack()" function of the given path structure.
254 255
    ///
255 256
    /// \return <tt>(*this)</tt>
256 257
    MinMeanCycle& cycle(Path &path) {
257 258
      if (_local_path) {
258 259
        delete _cycle_path;
259 260
        _local_path = false;
260 261
      }
261 262
      _cycle_path = &path;
262 263
      return *this;
263 264
    }
264 265

	
265 266
    /// \name Execution control
266 267
    /// The simplest way to execute the algorithm is to call the \ref run()
267 268
    /// function.\n
268 269
    /// If you only need the minimum mean length, you may call
269 270
    /// \ref findMinMean().
270 271

	
271 272
    /// @{
272 273

	
273 274
    /// \brief Run the algorithm.
274 275
    ///
275 276
    /// This function runs the algorithm.
276 277
    /// It can be called more than once (e.g. if the underlying digraph
277 278
    /// and/or the arc lengths have been modified).
278 279
    ///
279 280
    /// \return \c true if a directed cycle exists in the digraph.
280 281
    ///
281 282
    /// \note <tt>mmc.run()</tt> is just a shortcut of the following code.
282 283
    /// \code
283 284
    ///   return mmc.findMinMean() && mmc.findCycle();
284 285
    /// \endcode
285 286
    bool run() {
286 287
      return findMinMean() && findCycle();
287 288
    }
288 289

	
289 290
    /// \brief Find the minimum cycle mean.
290 291
    ///
291 292
    /// This function finds the minimum mean length of the directed
292 293
    /// cycles in the digraph.
293 294
    ///
294 295
    /// \return \c true if a directed cycle exists in the digraph.
295 296
    bool findMinMean() {
296 297
      // Initialize and find strongly connected components
297 298
      init();
298 299
      findComponents();
299 300
      
300 301
      // Find the minimum cycle mean in the components
301 302
      for (int comp = 0; comp < _comp_num; ++comp) {
302 303
        // Find the minimum mean cycle in the current component
303 304
        if (!buildPolicyGraph(comp)) continue;
304 305
        while (true) {
305 306
          findPolicyCycle();
306 307
          if (!computeNodeDistances()) break;
307 308
        }
308 309
        // Update the best cycle (global minimum mean cycle)
309 310
        if ( !_best_found || (_curr_found &&
310 311
             _curr_length * _best_size < _best_length * _curr_size) ) {
311 312
          _best_found = true;
312 313
          _best_length = _curr_length;
313 314
          _best_size = _curr_size;
314 315
          _best_node = _curr_node;
315 316
        }
316 317
      }
317 318
      return _best_found;
318 319
    }
319 320

	
320 321
    /// \brief Find a minimum mean directed cycle.
321 322
    ///
322 323
    /// This function finds a directed cycle of minimum mean length
323 324
    /// in the digraph using the data computed by findMinMean().
324 325
    ///
325 326
    /// \return \c true if a directed cycle exists in the digraph.
326 327
    ///
327 328
    /// \pre \ref findMinMean() must be called before using this function.
328 329
    bool findCycle() {
329 330
      if (!_best_found) return false;
330 331
      _cycle_path->addBack(_policy[_best_node]);
331 332
      for ( Node v = _best_node;
332 333
            (v = _gr.target(_policy[v])) != _best_node; ) {
333 334
        _cycle_path->addBack(_policy[v]);
334 335
      }
335 336
      return true;
336 337
    }
337 338

	
338 339
    /// @}
339 340

	
340 341
    /// \name Query Functions
341 342
    /// The results of the algorithm can be obtained using these
342 343
    /// functions.\n
343 344
    /// The algorithm should be executed before using them.
344 345

	
345 346
    /// @{
346 347

	
347 348
    /// \brief Return the total length of the found cycle.
348 349
    ///
349 350
    /// This function returns the total length of the found cycle.
350 351
    ///
351 352
    /// \pre \ref run() or \ref findMinMean() must be called before
352 353
    /// using this function.
353 354
    LargeValue cycleLength() const {
354 355
      return _best_length;
355 356
    }
356 357

	
357 358
    /// \brief Return the number of arcs on the found cycle.
358 359
    ///
359 360
    /// This function returns the number of arcs on the found cycle.
360 361
    ///
361 362
    /// \pre \ref run() or \ref findMinMean() must be called before
362 363
    /// using this function.
363 364
    int cycleArcNum() const {
364 365
      return _best_size;
365 366
    }
366 367

	
367 368
    /// \brief Return the mean length of the found cycle.
368 369
    ///
369 370
    /// This function returns the mean length of the found cycle.
370 371
    ///
371 372
    /// \note <tt>alg.cycleMean()</tt> is just a shortcut of the
372 373
    /// following code.
373 374
    /// \code
374 375
    ///   return static_cast<double>(alg.cycleLength()) / alg.cycleArcNum();
375 376
    /// \endcode
376 377
    ///
377 378
    /// \pre \ref run() or \ref findMinMean() must be called before
378 379
    /// using this function.
379 380
    double cycleMean() const {
380 381
      return static_cast<double>(_best_length) / _best_size;
381 382
    }
382 383

	
383 384
    /// \brief Return the found cycle.
384 385
    ///
385 386
    /// This function returns a const reference to the path structure
386 387
    /// storing the found cycle.
387 388
    ///
388 389
    /// \pre \ref run() or \ref findCycle() must be called before using
389 390
    /// this function.
390 391
    const Path& cycle() const {
391 392
      return *_cycle_path;
392 393
    }
393 394

	
394 395
    ///@}
395 396

	
396 397
  private:
397 398

	
398 399
    // Initialize
399 400
    void init() {
400 401
      if (!_cycle_path) {
401 402
        _local_path = true;
402 403
        _cycle_path = new Path;
403 404
      }
404 405
      _queue.resize(countNodes(_gr));
405 406
      _best_found = false;
406 407
      _best_length = 0;
407 408
      _best_size = 1;
408 409
      _cycle_path->clear();
409 410
    }
410 411
    
411 412
    // Find strongly connected components and initialize _comp_nodes
412 413
    // and _in_arcs
413 414
    void findComponents() {
414 415
      _comp_num = stronglyConnectedComponents(_gr, _comp);
415 416
      _comp_nodes.resize(_comp_num);
416 417
      if (_comp_num == 1) {
417 418
        _comp_nodes[0].clear();
418 419
        for (NodeIt n(_gr); n != INVALID; ++n) {
419 420
          _comp_nodes[0].push_back(n);
420 421
          _in_arcs[n].clear();
421 422
          for (InArcIt a(_gr, n); a != INVALID; ++a) {
422 423
            _in_arcs[n].push_back(a);
423 424
          }
424 425
        }
425 426
      } else {
426 427
        for (int i = 0; i < _comp_num; ++i)
427 428
          _comp_nodes[i].clear();
428 429
        for (NodeIt n(_gr); n != INVALID; ++n) {
429 430
          int k = _comp[n];
430 431
          _comp_nodes[k].push_back(n);
431 432
          _in_arcs[n].clear();
432 433
          for (InArcIt a(_gr, n); a != INVALID; ++a) {
433 434
            if (_comp[_gr.source(a)] == k) _in_arcs[n].push_back(a);
434 435
          }
435 436
        }
436 437
      }
437 438
    }
438 439

	
439 440
    // Build the policy graph in the given strongly connected component
440 441
    // (the out-degree of every node is 1)
441 442
    bool buildPolicyGraph(int comp) {
442 443
      _nodes = &(_comp_nodes[comp]);
443 444
      if (_nodes->size() < 1 ||
444 445
          (_nodes->size() == 1 && _in_arcs[(*_nodes)[0]].size() == 0)) {
445 446
        return false;
446 447
      }
447 448
      for (int i = 0; i < int(_nodes->size()); ++i) {
448 449
        _dist[(*_nodes)[i]] = std::numeric_limits<LargeValue>::max();
449 450
      }
450 451
      Node u, v;
451 452
      Arc e;
452 453
      for (int i = 0; i < int(_nodes->size()); ++i) {
453 454
        v = (*_nodes)[i];
454 455
        for (int j = 0; j < int(_in_arcs[v].size()); ++j) {
455 456
          e = _in_arcs[v][j];
456 457
          u = _gr.source(e);
457 458
          if (_length[e] < _dist[u]) {
458 459
            _dist[u] = _length[e];
459 460
            _policy[u] = e;
460 461
          }
461 462
        }
462 463
      }
463 464
      return true;
464 465
    }
465 466

	
466 467
    // Find the minimum mean cycle in the policy graph
467 468
    void findPolicyCycle() {
468 469
      for (int i = 0; i < int(_nodes->size()); ++i) {
469 470
        _level[(*_nodes)[i]] = -1;
470 471
      }
471 472
      LargeValue clength;
472 473
      int csize;
473 474
      Node u, v;
474 475
      _curr_found = false;
475 476
      for (int i = 0; i < int(_nodes->size()); ++i) {
476 477
        u = (*_nodes)[i];
477 478
        if (_level[u] >= 0) continue;
478 479
        for (; _level[u] < 0; u = _gr.target(_policy[u])) {
479 480
          _level[u] = i;
480 481
        }
481 482
        if (_level[u] == i) {
482 483
          // A cycle is found
483 484
          clength = _length[_policy[u]];
484 485
          csize = 1;
485 486
          for (v = u; (v = _gr.target(_policy[v])) != u; ) {
486 487
            clength += _length[_policy[v]];
487 488
            ++csize;
488 489
          }
489 490
          if ( !_curr_found ||
490 491
               (clength * _curr_size < _curr_length * csize) ) {
491 492
            _curr_found = true;
492 493
            _curr_length = clength;
493 494
            _curr_size = csize;
494 495
            _curr_node = u;
495 496
          }
496 497
        }
497 498
      }
498 499
    }
499 500

	
500 501
    // Contract the policy graph and compute node distances
501 502
    bool computeNodeDistances() {
502 503
      // Find the component of the main cycle and compute node distances
503 504
      // using reverse BFS
504 505
      for (int i = 0; i < int(_nodes->size()); ++i) {
505 506
        _reached[(*_nodes)[i]] = false;
506 507
      }
507 508
      _qfront = _qback = 0;
508 509
      _queue[0] = _curr_node;
509 510
      _reached[_curr_node] = true;
510 511
      _dist[_curr_node] = 0;
511 512
      Node u, v;
512 513
      Arc e;
513 514
      while (_qfront <= _qback) {
514 515
        v = _queue[_qfront++];
515 516
        for (int j = 0; j < int(_in_arcs[v].size()); ++j) {
516 517
          e = _in_arcs[v][j];
517 518
          u = _gr.source(e);
518 519
          if (_policy[u] == e && !_reached[u]) {
519 520
            _reached[u] = true;
520 521
            _dist[u] = _dist[v] + _length[e] * _curr_size - _curr_length;
521 522
            _queue[++_qback] = u;
522 523
          }
523 524
        }
524 525
      }
525 526

	
526 527
      // Connect all other nodes to this component and compute node
527 528
      // distances using reverse BFS
528 529
      _qfront = 0;
529 530
      while (_qback < int(_nodes->size())-1) {
530 531
        v = _queue[_qfront++];
531 532
        for (int j = 0; j < int(_in_arcs[v].size()); ++j) {
532 533
          e = _in_arcs[v][j];
533 534
          u = _gr.source(e);
534 535
          if (!_reached[u]) {
535 536
            _reached[u] = true;
536 537
            _policy[u] = e;
537 538
            _dist[u] = _dist[v] + _length[e] * _curr_size - _curr_length;
538 539
            _queue[++_qback] = u;
539 540
          }
540 541
        }
541 542
      }
542 543

	
543 544
      // Improve node distances
544 545
      bool improved = false;
545 546
      for (int i = 0; i < int(_nodes->size()); ++i) {
546 547
        v = (*_nodes)[i];
547 548
        for (int j = 0; j < int(_in_arcs[v].size()); ++j) {
548 549
          e = _in_arcs[v][j];
549 550
          u = _gr.source(e);
550 551
          LargeValue delta = _dist[v] + _length[e] * _curr_size - _curr_length;
551 552
          if (_tolerance.less(delta, _dist[u])) {
552 553
            _dist[u] = delta;
553 554
            _policy[u] = e;
554 555
            improved = true;
555 556
          }
556 557
        }
557 558
      }
558 559
      return improved;
559 560
    }
560 561

	
561 562
  }; //class MinMeanCycle
562 563

	
563 564
  ///@}
564 565

	
565 566
} //namespace lemon
566 567

	
567 568
#endif //LEMON_MIN_MEAN_CYCLE_H
Ignore white space 6 line context
1 1
INCLUDE_DIRECTORIES(
2 2
  ${PROJECT_SOURCE_DIR}
3 3
  ${PROJECT_BINARY_DIR}
4 4
)
5 5

	
6 6
LINK_DIRECTORIES(
7 7
  ${PROJECT_BINARY_DIR}/lemon
8 8
)
9 9

	
10 10
SET(TESTS
11 11
  adaptors_test
12 12
  bfs_test
13 13
  circulation_test
14 14
  connectivity_test
15 15
  counter_test
16 16
  dfs_test
17 17
  digraph_test
18 18
  dijkstra_test
19 19
  dim_test
20 20
  edge_set_test
21 21
  error_test
22 22
  euler_test
23 23
  gomory_hu_test
24 24
  graph_copy_test
25 25
  graph_test
26 26
  graph_utils_test
27 27
  hao_orlin_test
28 28
  heap_test
29 29
  kruskal_test
30 30
  maps_test
31 31
  matching_test
32 32
  min_cost_arborescence_test
33 33
  min_cost_flow_test
34
  min_mean_cycle_test
34 35
  path_test
35 36
  preflow_test
36 37
  radix_sort_test
37 38
  random_test
38 39
  suurballe_test
39 40
  time_measure_test
40 41
  unionfind_test
41 42
)
42 43

	
43 44
IF(LEMON_HAVE_LP)
44 45
  ADD_EXECUTABLE(lp_test lp_test.cc)
45 46
  SET(LP_TEST_LIBS lemon)
46 47

	
47 48
  IF(LEMON_HAVE_GLPK)
48 49
    SET(LP_TEST_LIBS ${LP_TEST_LIBS} ${GLPK_LIBRARIES})
49 50
  ENDIF()
50 51
  IF(LEMON_HAVE_CPLEX)
51 52
    SET(LP_TEST_LIBS ${LP_TEST_LIBS} ${CPLEX_LIBRARIES})
52 53
  ENDIF()
53 54
  IF(LEMON_HAVE_CLP)
54 55
    SET(LP_TEST_LIBS ${LP_TEST_LIBS} ${COIN_CLP_LIBRARIES})
55 56
  ENDIF()
56 57

	
57 58
  TARGET_LINK_LIBRARIES(lp_test ${LP_TEST_LIBS})
58 59
  ADD_TEST(lp_test lp_test)
59 60

	
60 61
  IF(WIN32 AND LEMON_HAVE_GLPK)
61 62
    GET_TARGET_PROPERTY(TARGET_LOC lp_test LOCATION)
62 63
    GET_FILENAME_COMPONENT(TARGET_PATH ${TARGET_LOC} PATH)
63 64
    ADD_CUSTOM_COMMAND(TARGET lp_test POST_BUILD
64 65
      COMMAND ${CMAKE_COMMAND} -E copy ${GLPK_BIN_DIR}/glpk.dll ${TARGET_PATH}
65 66
      COMMAND ${CMAKE_COMMAND} -E copy ${GLPK_BIN_DIR}/libltdl3.dll ${TARGET_PATH}
66 67
      COMMAND ${CMAKE_COMMAND} -E copy ${GLPK_BIN_DIR}/zlib1.dll ${TARGET_PATH}
67 68
    )
68 69
  ENDIF()
69 70

	
70 71
  IF(WIN32 AND LEMON_HAVE_CPLEX)
71 72
    GET_TARGET_PROPERTY(TARGET_LOC lp_test LOCATION)
72 73
    GET_FILENAME_COMPONENT(TARGET_PATH ${TARGET_LOC} PATH)
73 74
    ADD_CUSTOM_COMMAND(TARGET lp_test POST_BUILD
74 75
      COMMAND ${CMAKE_COMMAND} -E copy ${CPLEX_BIN_DIR}/cplex91.dll ${TARGET_PATH}
75 76
    )
76 77
  ENDIF()
77 78
ENDIF()
78 79

	
79 80
IF(LEMON_HAVE_MIP)
80 81
  ADD_EXECUTABLE(mip_test mip_test.cc)
81 82
  SET(MIP_TEST_LIBS lemon)
82 83

	
83 84
  IF(LEMON_HAVE_GLPK)
84 85
    SET(MIP_TEST_LIBS ${MIP_TEST_LIBS} ${GLPK_LIBRARIES})
85 86
  ENDIF()
86 87
  IF(LEMON_HAVE_CPLEX)
87 88
    SET(MIP_TEST_LIBS ${MIP_TEST_LIBS} ${CPLEX_LIBRARIES})
88 89
  ENDIF()
89 90
  IF(LEMON_HAVE_CBC)
90 91
    SET(MIP_TEST_LIBS ${MIP_TEST_LIBS} ${COIN_CBC_LIBRARIES})
91 92
  ENDIF()
92 93

	
93 94
  TARGET_LINK_LIBRARIES(mip_test ${MIP_TEST_LIBS})
94 95
  ADD_TEST(mip_test mip_test)
95 96

	
96 97
  IF(WIN32 AND LEMON_HAVE_GLPK)
97 98
    GET_TARGET_PROPERTY(TARGET_LOC mip_test LOCATION)
98 99
    GET_FILENAME_COMPONENT(TARGET_PATH ${TARGET_LOC} PATH)
99 100
    ADD_CUSTOM_COMMAND(TARGET mip_test POST_BUILD
100 101
      COMMAND ${CMAKE_COMMAND} -E copy ${GLPK_BIN_DIR}/glpk.dll ${TARGET_PATH}
101 102
      COMMAND ${CMAKE_COMMAND} -E copy ${GLPK_BIN_DIR}/libltdl3.dll ${TARGET_PATH}
102 103
      COMMAND ${CMAKE_COMMAND} -E copy ${GLPK_BIN_DIR}/zlib1.dll ${TARGET_PATH}
103 104
    )
104 105
  ENDIF()
105 106

	
106 107
  IF(WIN32 AND LEMON_HAVE_CPLEX)
107 108
    GET_TARGET_PROPERTY(TARGET_LOC mip_test LOCATION)
108 109
    GET_FILENAME_COMPONENT(TARGET_PATH ${TARGET_LOC} PATH)
109 110
    ADD_CUSTOM_COMMAND(TARGET mip_test POST_BUILD
110 111
      COMMAND ${CMAKE_COMMAND} -E copy ${CPLEX_BIN_DIR}/cplex91.dll ${TARGET_PATH}
111 112
    )
112 113
  ENDIF()
113 114
ENDIF()
114 115

	
115 116
FOREACH(TEST_NAME ${TESTS})
116 117
  ADD_EXECUTABLE(${TEST_NAME} ${TEST_NAME}.cc)
117 118
  TARGET_LINK_LIBRARIES(${TEST_NAME} lemon)
118 119
  ADD_TEST(${TEST_NAME} ${TEST_NAME})
119 120
ENDFOREACH()
Ignore white space 6 line context
1 1
EXTRA_DIST += \
2 2
	test/CMakeLists.txt
3 3

	
4 4
noinst_HEADERS += \
5 5
	test/graph_test.h \
6 6
	test/test_tools.h
7 7

	
8 8
check_PROGRAMS += \
9 9
	test/adaptors_test \
10 10
	test/bfs_test \
11 11
	test/circulation_test \
12 12
	test/connectivity_test \
13 13
	test/counter_test \
14 14
	test/dfs_test \
15 15
	test/digraph_test \
16 16
	test/dijkstra_test \
17 17
	test/dim_test \
18 18
	test/edge_set_test \
19 19
	test/error_test \
20 20
	test/euler_test \
21 21
	test/gomory_hu_test \
22 22
	test/graph_copy_test \
23 23
	test/graph_test \
24 24
	test/graph_utils_test \
25 25
	test/hao_orlin_test \
26 26
	test/heap_test \
27 27
	test/kruskal_test \
28 28
	test/maps_test \
29 29
	test/matching_test \
30 30
	test/min_cost_arborescence_test \
31 31
	test/min_cost_flow_test \
32
	test/min_mean_cycle_test \
32 33
	test/path_test \
33 34
	test/preflow_test \
34 35
	test/radix_sort_test \
35 36
	test/random_test \
36 37
	test/suurballe_test \
37 38
	test/test_tools_fail \
38 39
	test/test_tools_pass \
39 40
	test/time_measure_test \
40 41
	test/unionfind_test
41 42

	
42 43
test_test_tools_pass_DEPENDENCIES = demo
43 44

	
44 45
if HAVE_LP
45 46
check_PROGRAMS += test/lp_test
46 47
endif HAVE_LP
47 48
if HAVE_MIP
48 49
check_PROGRAMS += test/mip_test
49 50
endif HAVE_MIP
50 51

	
51 52
TESTS += $(check_PROGRAMS)
52 53
XFAIL_TESTS += test/test_tools_fail$(EXEEXT)
53 54

	
54 55
test_adaptors_test_SOURCES = test/adaptors_test.cc
55 56
test_bfs_test_SOURCES = test/bfs_test.cc
56 57
test_circulation_test_SOURCES = test/circulation_test.cc
57 58
test_counter_test_SOURCES = test/counter_test.cc
58 59
test_connectivity_test_SOURCES = test/connectivity_test.cc
59 60
test_dfs_test_SOURCES = test/dfs_test.cc
60 61
test_digraph_test_SOURCES = test/digraph_test.cc
61 62
test_dijkstra_test_SOURCES = test/dijkstra_test.cc
62 63
test_dim_test_SOURCES = test/dim_test.cc
63 64
test_edge_set_test_SOURCES = test/edge_set_test.cc
64 65
test_error_test_SOURCES = test/error_test.cc
65 66
test_euler_test_SOURCES = test/euler_test.cc
66 67
test_gomory_hu_test_SOURCES = test/gomory_hu_test.cc
67 68
test_graph_copy_test_SOURCES = test/graph_copy_test.cc
68 69
test_graph_test_SOURCES = test/graph_test.cc
69 70
test_graph_utils_test_SOURCES = test/graph_utils_test.cc
70 71
test_heap_test_SOURCES = test/heap_test.cc
71 72
test_kruskal_test_SOURCES = test/kruskal_test.cc
72 73
test_hao_orlin_test_SOURCES = test/hao_orlin_test.cc
73 74
test_lp_test_SOURCES = test/lp_test.cc
74 75
test_maps_test_SOURCES = test/maps_test.cc
75 76
test_mip_test_SOURCES = test/mip_test.cc
76 77
test_matching_test_SOURCES = test/matching_test.cc
77 78
test_min_cost_arborescence_test_SOURCES = test/min_cost_arborescence_test.cc
78 79
test_min_cost_flow_test_SOURCES = test/min_cost_flow_test.cc
80
test_min_mean_cycle_test_SOURCES = test/min_mean_cycle_test.cc
79 81
test_path_test_SOURCES = test/path_test.cc
80 82
test_preflow_test_SOURCES = test/preflow_test.cc
81 83
test_radix_sort_test_SOURCES = test/radix_sort_test.cc
82 84
test_suurballe_test_SOURCES = test/suurballe_test.cc
83 85
test_random_test_SOURCES = test/random_test.cc
84 86
test_test_tools_fail_SOURCES = test/test_tools_fail.cc
85 87
test_test_tools_pass_SOURCES = test/test_tools_pass.cc
86 88
test_time_measure_test_SOURCES = test/time_measure_test.cc
87 89
test_unionfind_test_SOURCES = test/unionfind_test.cc
Ignore white space 6 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-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
#ifndef LEMON_TEST_TEST_TOOLS_H
20 20
#define LEMON_TEST_TEST_TOOLS_H
21 21

	
22 22
///\ingroup misc
23 23
///\file
24 24
///\brief Some utilities to write test programs.
25 25

	
26 26
#include <iostream>
27 27
#include <stdlib.h>
28 28

	
29 29
///If \c rc is fail, writes an error message and exits.
30 30

	
31 31
///If \c rc is fail, writes an error message and exits.
32 32
///The error message contains the file name and the line number of the
33 33
///source code in a standard from, which makes it possible to go there
34 34
///using good source browsers like e.g. \c emacs.
35 35
///
36 36
///For example
37 37
///\code check(0==1,"This is obviously false.");\endcode will
38 38
///print something like this (and then exits).
39 39
///\verbatim file_name.cc:123: error: This is obviously false. \endverbatim
40
#define check(rc, msg) \
41
  if(!(rc)) { \
42
    std::cerr << __FILE__ ":" << __LINE__ << ": error: " << msg << std::endl; \
43
    abort(); \
44
  } else { } \
40
#define check(rc, msg)                                                  \
41
  {                                                                     \
42
    if(!(rc)) {                                                         \
43
      std::cerr << __FILE__ ":" << __LINE__ << ": error: "              \
44
                << msg << std::endl;                                    \
45
      abort();                                                          \
46
    } else { }                                                          \
47
  }                                                                     \
48
    
45 49

	
46 50
#endif
0 comments (0 inline)