# HG changeset patch
# User Peter Kovacs <kpeter@inf.elte.hu>
# Date 1352959529 -3600
# Node ID 21a9f829ab68555675534cb075253929315be385
# Parent 764826c6e2b451f09cfa6e588a3de005bc308154
Optional iteration limit in HowardMmc (#438)
diff --git a/lemon/howard_mmc.h b/lemon/howard_mmc.h
a
|
b
|
|
149 | 149 | /// The \ref HowardMmcDefaultTraits "traits class" of the algorithm |
150 | 150 | typedef TR Traits; |
151 | 151 | |
| 152 | /// \brief Constants for the causes of search termination. |
| 153 | /// |
| 154 | /// Enum type containing constants for the different causes of search |
| 155 | /// termination. The \ref findCycleMean() function returns one of |
| 156 | /// these values. |
| 157 | enum TerminationCause { |
| 158 | |
| 159 | /// No directed cycle can be found in the digraph. |
| 160 | NO_CYCLE = 0, |
| 161 | |
| 162 | /// Optimal solution (minimum cycle mean) is found. |
| 163 | OPTIMAL = 1, |
| 164 | |
| 165 | /// The iteration count limit is reached. |
| 166 | ITERATION_LIMIT |
| 167 | }; |
| 168 | |
152 | 169 | private: |
153 | 170 | |
154 | 171 | TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); |
… |
… |
|
324 | 341 | return findCycleMean() && findCycle(); |
325 | 342 | } |
326 | 343 | |
327 | | /// \brief Find the minimum cycle mean. |
| 344 | /// \brief Find the minimum cycle mean (or an upper bound). |
328 | 345 | /// |
329 | 346 | /// This function finds the minimum mean cost of the directed |
330 | | /// cycles in the digraph. |
| 347 | /// cycles in the digraph (or an upper bound for it). |
331 | 348 | /// |
332 | | /// \return \c true if a directed cycle exists in the digraph. |
333 | | bool findCycleMean() { |
| 349 | /// By default, the function finds the exact minimum cycle mean, |
| 350 | /// but an optional limit can also be specified for the number of |
| 351 | /// iterations performed during the search process. |
| 352 | /// The return value indicates if the optimal solution is found |
| 353 | /// or the iteration limit is reached. In the latter case, an |
| 354 | /// approximate solution is provided, which corresponds to a directed |
| 355 | /// cycle whose mean cost is relatively small, but not necessarily |
| 356 | /// minimal. |
| 357 | /// |
| 358 | /// \param limit The maximum allowed number of iterations during |
| 359 | /// the search process. Its default value implies that the algorithm |
| 360 | /// runs until it finds the exact optimal solution. |
| 361 | /// |
| 362 | /// \return The termination cause of the search process. |
| 363 | /// For more information, see \ref TerminationCause. |
| 364 | TerminationCause findCycleMean(int limit = std::numeric_limits<int>::max()) { |
334 | 365 | // Initialize and find strongly connected components |
335 | 366 | init(); |
336 | 367 | findComponents(); |
337 | 368 | |
338 | 369 | // Find the minimum cycle mean in the components |
| 370 | int iter_count = 0; |
| 371 | bool iter_limit_reached = false; |
339 | 372 | for (int comp = 0; comp < _comp_num; ++comp) { |
340 | 373 | // Find the minimum mean cycle in the current component |
341 | 374 | if (!buildPolicyGraph(comp)) continue; |
342 | 375 | while (true) { |
| 376 | if (++iter_count > limit) { |
| 377 | iter_limit_reached = true; |
| 378 | break; |
| 379 | } |
343 | 380 | findPolicyCycle(); |
344 | 381 | if (!computeNodeDistances()) break; |
345 | 382 | } |
| 383 | |
346 | 384 | // Update the best cycle (global minimum mean cycle) |
347 | 385 | if ( _curr_found && (!_best_found || |
348 | 386 | _curr_cost * _best_size < _best_cost * _curr_size) ) { |
… |
… |
|
351 | 389 | _best_size = _curr_size; |
352 | 390 | _best_node = _curr_node; |
353 | 391 | } |
| 392 | |
| 393 | if (iter_limit_reached) break; |
354 | 394 | } |
355 | | return _best_found; |
| 395 | |
| 396 | if (iter_limit_reached) { |
| 397 | return ITERATION_LIMIT; |
| 398 | } else { |
| 399 | return _best_found ? OPTIMAL : NO_CYCLE; |
| 400 | } |
356 | 401 | } |
357 | 402 | |
358 | 403 | /// \brief Find a minimum mean directed cycle. |
diff --git a/test/min_mean_cycle_test.cc b/test/min_mean_cycle_test.cc
a
|
b
|
|
110 | 110 | const SmartDigraph::ArcMap<int>& cm, |
111 | 111 | int cost, int size) { |
112 | 112 | MMC alg(gr, lm); |
113 | | alg.findCycleMean(); |
| 113 | check(alg.findCycleMean(), "Wrong result"); |
114 | 114 | check(alg.cycleMean() == static_cast<double>(cost) / size, |
115 | 115 | "Wrong cycle mean"); |
116 | 116 | alg.findCycle(); |
… |
… |
|
210 | 210 | checkMmcAlg<HowardMmc<GR, IntArcMap> >(gr, l2, c2, 5, 2); |
211 | 211 | checkMmcAlg<HowardMmc<GR, IntArcMap> >(gr, l3, c3, 0, 1); |
212 | 212 | checkMmcAlg<HowardMmc<GR, IntArcMap> >(gr, l4, c4, -1, 1); |
| 213 | |
| 214 | // Howard with iteration limit |
| 215 | HowardMmc<GR, IntArcMap> mmc(gr, l1); |
| 216 | check((mmc.findCycleMean(2) == HowardMmc<GR, IntArcMap>::ITERATION_LIMIT), |
| 217 | "Wrong termination cause"); |
| 218 | check((mmc.findCycleMean(4) == HowardMmc<GR, IntArcMap>::OPTIMAL), |
| 219 | "Wrong termination cause"); |
213 | 220 | } |
214 | 221 | |
215 | 222 | return 0; |