lemon/howard_mmc.h
author Peter Kovacs <kpeter@inf.elte.hu>
Tue, 15 Mar 2011 19:32:21 +0100
changeset 936 ddd3c0d3d9bf
parent 864 d3ea191c3412
child 1002 f63ba40a60f4
permissions -rw-r--r--
Implement the scaling Price Refinement heuristic in CostScaling (#417)
instead of Early Termination.

These two heuristics are similar, but the newer one is faster
and not only makes it possible to skip some epsilon phases, but
it can improve the performance of the other phases, as well.
alpar@877
     1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
kpeter@758
     2
 *
alpar@877
     3
 * This file is a part of LEMON, a generic C++ optimization library.
kpeter@758
     4
 *
alpar@877
     5
 * Copyright (C) 2003-2010
kpeter@758
     6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
kpeter@758
     7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
kpeter@758
     8
 *
kpeter@758
     9
 * Permission to use, modify and distribute this software is granted
kpeter@758
    10
 * provided that this copyright notice appears in all copies. For
kpeter@758
    11
 * precise terms see the accompanying LICENSE file.
kpeter@758
    12
 *
kpeter@758
    13
 * This software is provided "AS IS" with no warranty of any kind,
kpeter@758
    14
 * express or implied, and with no claim as to its suitability for any
kpeter@758
    15
 * purpose.
kpeter@758
    16
 *
kpeter@758
    17
 */
kpeter@758
    18
kpeter@864
    19
#ifndef LEMON_HOWARD_MMC_H
kpeter@864
    20
#define LEMON_HOWARD_MMC_H
kpeter@758
    21
kpeter@768
    22
/// \ingroup min_mean_cycle
kpeter@758
    23
///
kpeter@758
    24
/// \file
kpeter@758
    25
/// \brief Howard's algorithm for finding a minimum mean cycle.
kpeter@758
    26
kpeter@758
    27
#include <vector>
kpeter@763
    28
#include <limits>
kpeter@758
    29
#include <lemon/core.h>
kpeter@758
    30
#include <lemon/path.h>
kpeter@758
    31
#include <lemon/tolerance.h>
kpeter@758
    32
#include <lemon/connectivity.h>
kpeter@758
    33
kpeter@758
    34
namespace lemon {
kpeter@758
    35
kpeter@864
    36
  /// \brief Default traits class of HowardMmc class.
kpeter@761
    37
  ///
kpeter@864
    38
  /// Default traits class of HowardMmc class.
kpeter@761
    39
  /// \tparam GR The type of the digraph.
kpeter@864
    40
  /// \tparam CM The type of the cost map.
kpeter@761
    41
  /// It must conform to the \ref concepts::ReadMap "ReadMap" concept.
kpeter@761
    42
#ifdef DOXYGEN
kpeter@864
    43
  template <typename GR, typename CM>
kpeter@761
    44
#else
kpeter@864
    45
  template <typename GR, typename CM,
kpeter@864
    46
    bool integer = std::numeric_limits<typename CM::Value>::is_integer>
kpeter@761
    47
#endif
kpeter@864
    48
  struct HowardMmcDefaultTraits
kpeter@761
    49
  {
kpeter@761
    50
    /// The type of the digraph
kpeter@761
    51
    typedef GR Digraph;
kpeter@864
    52
    /// The type of the cost map
kpeter@864
    53
    typedef CM CostMap;
kpeter@864
    54
    /// The type of the arc costs
kpeter@864
    55
    typedef typename CostMap::Value Cost;
kpeter@761
    56
kpeter@864
    57
    /// \brief The large cost type used for internal computations
kpeter@761
    58
    ///
kpeter@864
    59
    /// The large cost type used for internal computations.
kpeter@864
    60
    /// It is \c long \c long if the \c Cost type is integer,
kpeter@761
    61
    /// otherwise it is \c double.
kpeter@864
    62
    /// \c Cost must be convertible to \c LargeCost.
kpeter@864
    63
    typedef double LargeCost;
kpeter@761
    64
kpeter@761
    65
    /// The tolerance type used for internal computations
kpeter@864
    66
    typedef lemon::Tolerance<LargeCost> Tolerance;
kpeter@761
    67
kpeter@761
    68
    /// \brief The path type of the found cycles
kpeter@761
    69
    ///
kpeter@761
    70
    /// The path type of the found cycles.
kpeter@761
    71
    /// It must conform to the \ref lemon::concepts::Path "Path" concept
kpeter@761
    72
    /// and it must have an \c addBack() function.
kpeter@761
    73
    typedef lemon::Path<Digraph> Path;
kpeter@761
    74
  };
kpeter@761
    75
kpeter@864
    76
  // Default traits class for integer cost types
kpeter@864
    77
  template <typename GR, typename CM>
kpeter@864
    78
  struct HowardMmcDefaultTraits<GR, CM, true>
kpeter@761
    79
  {
kpeter@761
    80
    typedef GR Digraph;
kpeter@864
    81
    typedef CM CostMap;
kpeter@864
    82
    typedef typename CostMap::Value Cost;
kpeter@761
    83
#ifdef LEMON_HAVE_LONG_LONG
kpeter@864
    84
    typedef long long LargeCost;
kpeter@761
    85
#else
kpeter@864
    86
    typedef long LargeCost;
kpeter@761
    87
#endif
kpeter@864
    88
    typedef lemon::Tolerance<LargeCost> Tolerance;
kpeter@761
    89
    typedef lemon::Path<Digraph> Path;
kpeter@761
    90
  };
kpeter@761
    91
kpeter@761
    92
kpeter@768
    93
  /// \addtogroup min_mean_cycle
kpeter@758
    94
  /// @{
kpeter@758
    95
kpeter@758
    96
  /// \brief Implementation of Howard's algorithm for finding a minimum
kpeter@758
    97
  /// mean cycle.
kpeter@758
    98
  ///
kpeter@764
    99
  /// This class implements Howard's policy iteration algorithm for finding
kpeter@864
   100
  /// a directed cycle of minimum mean cost in a digraph
kpeter@771
   101
  /// \ref amo93networkflows, \ref dasdan98minmeancycle.
kpeter@768
   102
  /// This class provides the most efficient algorithm for the
kpeter@768
   103
  /// minimum mean cycle problem, though the best known theoretical
kpeter@768
   104
  /// bound on its running time is exponential.
kpeter@758
   105
  ///
kpeter@758
   106
  /// \tparam GR The type of the digraph the algorithm runs on.
kpeter@864
   107
  /// \tparam CM The type of the cost map. The default
kpeter@758
   108
  /// map type is \ref concepts::Digraph::ArcMap "GR::ArcMap<int>".
kpeter@825
   109
  /// \tparam TR The traits class that defines various types used by the
kpeter@864
   110
  /// algorithm. By default, it is \ref HowardMmcDefaultTraits
kpeter@864
   111
  /// "HowardMmcDefaultTraits<GR, CM>".
kpeter@825
   112
  /// In most cases, this parameter should not be set directly,
kpeter@825
   113
  /// consider to use the named template parameters instead.
kpeter@758
   114
#ifdef DOXYGEN
kpeter@864
   115
  template <typename GR, typename CM, typename TR>
kpeter@758
   116
#else
kpeter@758
   117
  template < typename GR,
kpeter@864
   118
             typename CM = typename GR::template ArcMap<int>,
kpeter@864
   119
             typename TR = HowardMmcDefaultTraits<GR, CM> >
kpeter@758
   120
#endif
kpeter@864
   121
  class HowardMmc
kpeter@758
   122
  {
kpeter@758
   123
  public:
alpar@877
   124
kpeter@761
   125
    /// The type of the digraph
kpeter@761
   126
    typedef typename TR::Digraph Digraph;
kpeter@864
   127
    /// The type of the cost map
kpeter@864
   128
    typedef typename TR::CostMap CostMap;
kpeter@864
   129
    /// The type of the arc costs
kpeter@864
   130
    typedef typename TR::Cost Cost;
kpeter@761
   131
kpeter@864
   132
    /// \brief The large cost type
kpeter@761
   133
    ///
kpeter@864
   134
    /// The large cost type used for internal computations.
kpeter@864
   135
    /// By default, it is \c long \c long if the \c Cost type is integer,
kpeter@761
   136
    /// otherwise it is \c double.
kpeter@864
   137
    typedef typename TR::LargeCost LargeCost;
kpeter@761
   138
kpeter@761
   139
    /// The tolerance type
kpeter@761
   140
    typedef typename TR::Tolerance Tolerance;
kpeter@761
   141
kpeter@761
   142
    /// \brief The path type of the found cycles
kpeter@761
   143
    ///
kpeter@761
   144
    /// The path type of the found cycles.
kpeter@864
   145
    /// Using the \ref HowardMmcDefaultTraits "default traits class",
kpeter@761
   146
    /// it is \ref lemon::Path "Path<Digraph>".
kpeter@761
   147
    typedef typename TR::Path Path;
kpeter@761
   148
kpeter@864
   149
    /// The \ref HowardMmcDefaultTraits "traits class" of the algorithm
kpeter@761
   150
    typedef TR Traits;
kpeter@758
   151
kpeter@758
   152
  private:
kpeter@758
   153
kpeter@758
   154
    TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
alpar@877
   155
kpeter@758
   156
    // The digraph the algorithm runs on
kpeter@758
   157
    const Digraph &_gr;
kpeter@864
   158
    // The cost of the arcs
kpeter@864
   159
    const CostMap &_cost;
kpeter@758
   160
kpeter@760
   161
    // Data for the found cycles
kpeter@760
   162
    bool _curr_found, _best_found;
kpeter@864
   163
    LargeCost _curr_cost, _best_cost;
kpeter@760
   164
    int _curr_size, _best_size;
kpeter@760
   165
    Node _curr_node, _best_node;
kpeter@760
   166
kpeter@758
   167
    Path *_cycle_path;
kpeter@760
   168
    bool _local_path;
kpeter@758
   169
kpeter@760
   170
    // Internal data used by the algorithm
kpeter@760
   171
    typename Digraph::template NodeMap<Arc> _policy;
kpeter@760
   172
    typename Digraph::template NodeMap<bool> _reached;
kpeter@760
   173
    typename Digraph::template NodeMap<int> _level;
kpeter@864
   174
    typename Digraph::template NodeMap<LargeCost> _dist;
kpeter@758
   175
kpeter@760
   176
    // Data for storing the strongly connected components
kpeter@760
   177
    int _comp_num;
kpeter@758
   178
    typename Digraph::template NodeMap<int> _comp;
kpeter@760
   179
    std::vector<std::vector<Node> > _comp_nodes;
kpeter@760
   180
    std::vector<Node>* _nodes;
kpeter@760
   181
    typename Digraph::template NodeMap<std::vector<Arc> > _in_arcs;
alpar@877
   182
kpeter@760
   183
    // Queue used for BFS search
kpeter@760
   184
    std::vector<Node> _queue;
kpeter@760
   185
    int _qfront, _qback;
kpeter@761
   186
kpeter@761
   187
    Tolerance _tolerance;
alpar@877
   188
kpeter@767
   189
    // Infinite constant
kpeter@864
   190
    const LargeCost INF;
kpeter@767
   191
kpeter@761
   192
  public:
alpar@877
   193
kpeter@761
   194
    /// \name Named Template Parameters
kpeter@761
   195
    /// @{
kpeter@761
   196
kpeter@761
   197
    template <typename T>
kpeter@864
   198
    struct SetLargeCostTraits : public Traits {
kpeter@864
   199
      typedef T LargeCost;
kpeter@761
   200
      typedef lemon::Tolerance<T> Tolerance;
kpeter@761
   201
    };
kpeter@761
   202
kpeter@761
   203
    /// \brief \ref named-templ-param "Named parameter" for setting
kpeter@864
   204
    /// \c LargeCost type.
kpeter@761
   205
    ///
kpeter@864
   206
    /// \ref named-templ-param "Named parameter" for setting \c LargeCost
kpeter@761
   207
    /// type. It is used for internal computations in the algorithm.
kpeter@761
   208
    template <typename T>
kpeter@864
   209
    struct SetLargeCost
kpeter@864
   210
      : public HowardMmc<GR, CM, SetLargeCostTraits<T> > {
kpeter@864
   211
      typedef HowardMmc<GR, CM, SetLargeCostTraits<T> > Create;
kpeter@761
   212
    };
kpeter@761
   213
kpeter@761
   214
    template <typename T>
kpeter@761
   215
    struct SetPathTraits : public Traits {
kpeter@761
   216
      typedef T Path;
kpeter@761
   217
    };
kpeter@761
   218
kpeter@761
   219
    /// \brief \ref named-templ-param "Named parameter" for setting
kpeter@761
   220
    /// \c %Path type.
kpeter@761
   221
    ///
kpeter@761
   222
    /// \ref named-templ-param "Named parameter" for setting the \c %Path
kpeter@761
   223
    /// type of the found cycles.
kpeter@761
   224
    /// It must conform to the \ref lemon::concepts::Path "Path" concept
kpeter@761
   225
    /// and it must have an \c addBack() function.
kpeter@761
   226
    template <typename T>
kpeter@761
   227
    struct SetPath
kpeter@864
   228
      : public HowardMmc<GR, CM, SetPathTraits<T> > {
kpeter@864
   229
      typedef HowardMmc<GR, CM, SetPathTraits<T> > Create;
kpeter@761
   230
    };
alpar@877
   231
kpeter@761
   232
    /// @}
kpeter@758
   233
kpeter@863
   234
  protected:
kpeter@863
   235
kpeter@864
   236
    HowardMmc() {}
kpeter@863
   237
kpeter@758
   238
  public:
kpeter@758
   239
kpeter@758
   240
    /// \brief Constructor.
kpeter@758
   241
    ///
kpeter@758
   242
    /// The constructor of the class.
kpeter@758
   243
    ///
kpeter@758
   244
    /// \param digraph The digraph the algorithm runs on.
kpeter@864
   245
    /// \param cost The costs of the arcs.
kpeter@864
   246
    HowardMmc( const Digraph &digraph,
kpeter@864
   247
               const CostMap &cost ) :
kpeter@864
   248
      _gr(digraph), _cost(cost), _best_found(false),
kpeter@864
   249
      _best_cost(0), _best_size(1), _cycle_path(NULL), _local_path(false),
kpeter@760
   250
      _policy(digraph), _reached(digraph), _level(digraph), _dist(digraph),
kpeter@767
   251
      _comp(digraph), _in_arcs(digraph),
kpeter@864
   252
      INF(std::numeric_limits<LargeCost>::has_infinity ?
kpeter@864
   253
          std::numeric_limits<LargeCost>::infinity() :
kpeter@864
   254
          std::numeric_limits<LargeCost>::max())
kpeter@758
   255
    {}
kpeter@758
   256
kpeter@758
   257
    /// Destructor.
kpeter@864
   258
    ~HowardMmc() {
kpeter@758
   259
      if (_local_path) delete _cycle_path;
kpeter@758
   260
    }
kpeter@758
   261
kpeter@758
   262
    /// \brief Set the path structure for storing the found cycle.
kpeter@758
   263
    ///
kpeter@758
   264
    /// This function sets an external path structure for storing the
kpeter@758
   265
    /// found cycle.
kpeter@758
   266
    ///
kpeter@758
   267
    /// If you don't call this function before calling \ref run() or
kpeter@864
   268
    /// \ref findCycleMean(), it will allocate a local \ref Path "path"
kpeter@758
   269
    /// structure. The destuctor deallocates this automatically
kpeter@758
   270
    /// allocated object, of course.
kpeter@758
   271
    ///
kpeter@758
   272
    /// \note The algorithm calls only the \ref lemon::Path::addBack()
kpeter@758
   273
    /// "addBack()" function of the given path structure.
kpeter@758
   274
    ///
kpeter@758
   275
    /// \return <tt>(*this)</tt>
kpeter@864
   276
    HowardMmc& cycle(Path &path) {
kpeter@758
   277
      if (_local_path) {
kpeter@758
   278
        delete _cycle_path;
kpeter@758
   279
        _local_path = false;
kpeter@758
   280
      }
kpeter@758
   281
      _cycle_path = &path;
kpeter@758
   282
      return *this;
kpeter@758
   283
    }
kpeter@758
   284
kpeter@769
   285
    /// \brief Set the tolerance used by the algorithm.
kpeter@769
   286
    ///
kpeter@769
   287
    /// This function sets the tolerance object used by the algorithm.
kpeter@769
   288
    ///
kpeter@769
   289
    /// \return <tt>(*this)</tt>
kpeter@864
   290
    HowardMmc& tolerance(const Tolerance& tolerance) {
kpeter@769
   291
      _tolerance = tolerance;
kpeter@769
   292
      return *this;
kpeter@769
   293
    }
kpeter@769
   294
kpeter@769
   295
    /// \brief Return a const reference to the tolerance.
kpeter@769
   296
    ///
kpeter@769
   297
    /// This function returns a const reference to the tolerance object
kpeter@769
   298
    /// used by the algorithm.
kpeter@769
   299
    const Tolerance& tolerance() const {
kpeter@769
   300
      return _tolerance;
kpeter@769
   301
    }
kpeter@769
   302
kpeter@758
   303
    /// \name Execution control
kpeter@758
   304
    /// The simplest way to execute the algorithm is to call the \ref run()
kpeter@758
   305
    /// function.\n
kpeter@864
   306
    /// If you only need the minimum mean cost, you may call
kpeter@864
   307
    /// \ref findCycleMean().
kpeter@758
   308
kpeter@758
   309
    /// @{
kpeter@758
   310
kpeter@758
   311
    /// \brief Run the algorithm.
kpeter@758
   312
    ///
kpeter@758
   313
    /// This function runs the algorithm.
kpeter@759
   314
    /// It can be called more than once (e.g. if the underlying digraph
kpeter@864
   315
    /// and/or the arc costs have been modified).
kpeter@758
   316
    ///
kpeter@758
   317
    /// \return \c true if a directed cycle exists in the digraph.
kpeter@758
   318
    ///
kpeter@759
   319
    /// \note <tt>mmc.run()</tt> is just a shortcut of the following code.
kpeter@758
   320
    /// \code
kpeter@864
   321
    ///   return mmc.findCycleMean() && mmc.findCycle();
kpeter@758
   322
    /// \endcode
kpeter@758
   323
    bool run() {
kpeter@864
   324
      return findCycleMean() && findCycle();
kpeter@758
   325
    }
kpeter@758
   326
kpeter@759
   327
    /// \brief Find the minimum cycle mean.
kpeter@758
   328
    ///
kpeter@864
   329
    /// This function finds the minimum mean cost of the directed
kpeter@759
   330
    /// cycles in the digraph.
kpeter@758
   331
    ///
kpeter@759
   332
    /// \return \c true if a directed cycle exists in the digraph.
kpeter@864
   333
    bool findCycleMean() {
kpeter@760
   334
      // Initialize and find strongly connected components
kpeter@760
   335
      init();
kpeter@760
   336
      findComponents();
alpar@877
   337
kpeter@759
   338
      // Find the minimum cycle mean in the components
kpeter@758
   339
      for (int comp = 0; comp < _comp_num; ++comp) {
kpeter@760
   340
        // Find the minimum mean cycle in the current component
kpeter@760
   341
        if (!buildPolicyGraph(comp)) continue;
kpeter@758
   342
        while (true) {
kpeter@760
   343
          findPolicyCycle();
kpeter@758
   344
          if (!computeNodeDistances()) break;
kpeter@758
   345
        }
kpeter@760
   346
        // Update the best cycle (global minimum mean cycle)
kpeter@767
   347
        if ( _curr_found && (!_best_found ||
kpeter@864
   348
             _curr_cost * _best_size < _best_cost * _curr_size) ) {
kpeter@760
   349
          _best_found = true;
kpeter@864
   350
          _best_cost = _curr_cost;
kpeter@760
   351
          _best_size = _curr_size;
kpeter@760
   352
          _best_node = _curr_node;
kpeter@760
   353
        }
kpeter@758
   354
      }
kpeter@760
   355
      return _best_found;
kpeter@758
   356
    }
kpeter@758
   357
kpeter@758
   358
    /// \brief Find a minimum mean directed cycle.
kpeter@758
   359
    ///
kpeter@864
   360
    /// This function finds a directed cycle of minimum mean cost
kpeter@864
   361
    /// in the digraph using the data computed by findCycleMean().
kpeter@758
   362
    ///
kpeter@758
   363
    /// \return \c true if a directed cycle exists in the digraph.
kpeter@758
   364
    ///
kpeter@864
   365
    /// \pre \ref findCycleMean() must be called before using this function.
kpeter@758
   366
    bool findCycle() {
kpeter@760
   367
      if (!_best_found) return false;
kpeter@760
   368
      _cycle_path->addBack(_policy[_best_node]);
kpeter@760
   369
      for ( Node v = _best_node;
kpeter@760
   370
            (v = _gr.target(_policy[v])) != _best_node; ) {
kpeter@758
   371
        _cycle_path->addBack(_policy[v]);
kpeter@758
   372
      }
kpeter@758
   373
      return true;
kpeter@758
   374
    }
kpeter@758
   375
kpeter@758
   376
    /// @}
kpeter@758
   377
kpeter@758
   378
    /// \name Query Functions
kpeter@759
   379
    /// The results of the algorithm can be obtained using these
kpeter@758
   380
    /// functions.\n
kpeter@758
   381
    /// The algorithm should be executed before using them.
kpeter@758
   382
kpeter@758
   383
    /// @{
kpeter@758
   384
kpeter@864
   385
    /// \brief Return the total cost of the found cycle.
kpeter@758
   386
    ///
kpeter@864
   387
    /// This function returns the total cost of the found cycle.
kpeter@758
   388
    ///
kpeter@864
   389
    /// \pre \ref run() or \ref findCycleMean() must be called before
kpeter@758
   390
    /// using this function.
kpeter@864
   391
    Cost cycleCost() const {
kpeter@864
   392
      return static_cast<Cost>(_best_cost);
kpeter@758
   393
    }
kpeter@758
   394
kpeter@758
   395
    /// \brief Return the number of arcs on the found cycle.
kpeter@758
   396
    ///
kpeter@758
   397
    /// This function returns the number of arcs on the found cycle.
kpeter@758
   398
    ///
kpeter@864
   399
    /// \pre \ref run() or \ref findCycleMean() must be called before
kpeter@758
   400
    /// using this function.
kpeter@864
   401
    int cycleSize() const {
kpeter@760
   402
      return _best_size;
kpeter@758
   403
    }
kpeter@758
   404
kpeter@864
   405
    /// \brief Return the mean cost of the found cycle.
kpeter@758
   406
    ///
kpeter@864
   407
    /// This function returns the mean cost of the found cycle.
kpeter@758
   408
    ///
kpeter@760
   409
    /// \note <tt>alg.cycleMean()</tt> is just a shortcut of the
kpeter@758
   410
    /// following code.
kpeter@758
   411
    /// \code
kpeter@864
   412
    ///   return static_cast<double>(alg.cycleCost()) / alg.cycleSize();
kpeter@758
   413
    /// \endcode
kpeter@758
   414
    ///
kpeter@864
   415
    /// \pre \ref run() or \ref findCycleMean() must be called before
kpeter@758
   416
    /// using this function.
kpeter@758
   417
    double cycleMean() const {
kpeter@864
   418
      return static_cast<double>(_best_cost) / _best_size;
kpeter@758
   419
    }
kpeter@758
   420
kpeter@758
   421
    /// \brief Return the found cycle.
kpeter@758
   422
    ///
kpeter@758
   423
    /// This function returns a const reference to the path structure
kpeter@758
   424
    /// storing the found cycle.
kpeter@758
   425
    ///
kpeter@758
   426
    /// \pre \ref run() or \ref findCycle() must be called before using
kpeter@758
   427
    /// this function.
kpeter@758
   428
    const Path& cycle() const {
kpeter@758
   429
      return *_cycle_path;
kpeter@758
   430
    }
kpeter@758
   431
kpeter@758
   432
    ///@}
kpeter@758
   433
kpeter@758
   434
  private:
kpeter@758
   435
kpeter@760
   436
    // Initialize
kpeter@760
   437
    void init() {
kpeter@760
   438
      if (!_cycle_path) {
kpeter@760
   439
        _local_path = true;
kpeter@760
   440
        _cycle_path = new Path;
kpeter@758
   441
      }
kpeter@760
   442
      _queue.resize(countNodes(_gr));
kpeter@760
   443
      _best_found = false;
kpeter@864
   444
      _best_cost = 0;
kpeter@760
   445
      _best_size = 1;
kpeter@760
   446
      _cycle_path->clear();
kpeter@760
   447
    }
alpar@877
   448
kpeter@760
   449
    // Find strongly connected components and initialize _comp_nodes
kpeter@760
   450
    // and _in_arcs
kpeter@760
   451
    void findComponents() {
kpeter@760
   452
      _comp_num = stronglyConnectedComponents(_gr, _comp);
kpeter@760
   453
      _comp_nodes.resize(_comp_num);
kpeter@760
   454
      if (_comp_num == 1) {
kpeter@760
   455
        _comp_nodes[0].clear();
kpeter@760
   456
        for (NodeIt n(_gr); n != INVALID; ++n) {
kpeter@760
   457
          _comp_nodes[0].push_back(n);
kpeter@760
   458
          _in_arcs[n].clear();
kpeter@760
   459
          for (InArcIt a(_gr, n); a != INVALID; ++a) {
kpeter@760
   460
            _in_arcs[n].push_back(a);
kpeter@760
   461
          }
kpeter@760
   462
        }
kpeter@760
   463
      } else {
kpeter@760
   464
        for (int i = 0; i < _comp_num; ++i)
kpeter@760
   465
          _comp_nodes[i].clear();
kpeter@760
   466
        for (NodeIt n(_gr); n != INVALID; ++n) {
kpeter@760
   467
          int k = _comp[n];
kpeter@760
   468
          _comp_nodes[k].push_back(n);
kpeter@760
   469
          _in_arcs[n].clear();
kpeter@760
   470
          for (InArcIt a(_gr, n); a != INVALID; ++a) {
kpeter@760
   471
            if (_comp[_gr.source(a)] == k) _in_arcs[n].push_back(a);
kpeter@760
   472
          }
kpeter@760
   473
        }
kpeter@758
   474
      }
kpeter@760
   475
    }
kpeter@760
   476
kpeter@760
   477
    // Build the policy graph in the given strongly connected component
kpeter@760
   478
    // (the out-degree of every node is 1)
kpeter@760
   479
    bool buildPolicyGraph(int comp) {
kpeter@760
   480
      _nodes = &(_comp_nodes[comp]);
kpeter@760
   481
      if (_nodes->size() < 1 ||
kpeter@760
   482
          (_nodes->size() == 1 && _in_arcs[(*_nodes)[0]].size() == 0)) {
kpeter@760
   483
        return false;
kpeter@758
   484
      }
kpeter@760
   485
      for (int i = 0; i < int(_nodes->size()); ++i) {
kpeter@767
   486
        _dist[(*_nodes)[i]] = INF;
kpeter@760
   487
      }
kpeter@760
   488
      Node u, v;
kpeter@760
   489
      Arc e;
kpeter@760
   490
      for (int i = 0; i < int(_nodes->size()); ++i) {
kpeter@760
   491
        v = (*_nodes)[i];
kpeter@760
   492
        for (int j = 0; j < int(_in_arcs[v].size()); ++j) {
kpeter@760
   493
          e = _in_arcs[v][j];
kpeter@760
   494
          u = _gr.source(e);
kpeter@864
   495
          if (_cost[e] < _dist[u]) {
kpeter@864
   496
            _dist[u] = _cost[e];
kpeter@760
   497
            _policy[u] = e;
kpeter@760
   498
          }
kpeter@758
   499
        }
kpeter@758
   500
      }
kpeter@758
   501
      return true;
kpeter@758
   502
    }
kpeter@758
   503
kpeter@760
   504
    // Find the minimum mean cycle in the policy graph
kpeter@760
   505
    void findPolicyCycle() {
kpeter@760
   506
      for (int i = 0; i < int(_nodes->size()); ++i) {
kpeter@760
   507
        _level[(*_nodes)[i]] = -1;
kpeter@760
   508
      }
kpeter@864
   509
      LargeCost ccost;
kpeter@758
   510
      int csize;
kpeter@758
   511
      Node u, v;
kpeter@760
   512
      _curr_found = false;
kpeter@760
   513
      for (int i = 0; i < int(_nodes->size()); ++i) {
kpeter@760
   514
        u = (*_nodes)[i];
kpeter@760
   515
        if (_level[u] >= 0) continue;
kpeter@760
   516
        for (; _level[u] < 0; u = _gr.target(_policy[u])) {
kpeter@760
   517
          _level[u] = i;
kpeter@760
   518
        }
kpeter@760
   519
        if (_level[u] == i) {
kpeter@760
   520
          // A cycle is found
kpeter@864
   521
          ccost = _cost[_policy[u]];
kpeter@760
   522
          csize = 1;
kpeter@760
   523
          for (v = u; (v = _gr.target(_policy[v])) != u; ) {
kpeter@864
   524
            ccost += _cost[_policy[v]];
kpeter@760
   525
            ++csize;
kpeter@758
   526
          }
kpeter@760
   527
          if ( !_curr_found ||
kpeter@864
   528
               (ccost * _curr_size < _curr_cost * csize) ) {
kpeter@760
   529
            _curr_found = true;
kpeter@864
   530
            _curr_cost = ccost;
kpeter@760
   531
            _curr_size = csize;
kpeter@760
   532
            _curr_node = u;
kpeter@758
   533
          }
kpeter@758
   534
        }
kpeter@758
   535
      }
kpeter@758
   536
    }
kpeter@758
   537
kpeter@760
   538
    // Contract the policy graph and compute node distances
kpeter@758
   539
    bool computeNodeDistances() {
kpeter@760
   540
      // Find the component of the main cycle and compute node distances
kpeter@760
   541
      // using reverse BFS
kpeter@760
   542
      for (int i = 0; i < int(_nodes->size()); ++i) {
kpeter@760
   543
        _reached[(*_nodes)[i]] = false;
kpeter@760
   544
      }
kpeter@760
   545
      _qfront = _qback = 0;
kpeter@760
   546
      _queue[0] = _curr_node;
kpeter@760
   547
      _reached[_curr_node] = true;
kpeter@760
   548
      _dist[_curr_node] = 0;
kpeter@758
   549
      Node u, v;
kpeter@760
   550
      Arc e;
kpeter@760
   551
      while (_qfront <= _qback) {
kpeter@760
   552
        v = _queue[_qfront++];
kpeter@760
   553
        for (int j = 0; j < int(_in_arcs[v].size()); ++j) {
kpeter@760
   554
          e = _in_arcs[v][j];
kpeter@758
   555
          u = _gr.source(e);
kpeter@760
   556
          if (_policy[u] == e && !_reached[u]) {
kpeter@760
   557
            _reached[u] = true;
kpeter@864
   558
            _dist[u] = _dist[v] + _cost[e] * _curr_size - _curr_cost;
kpeter@760
   559
            _queue[++_qback] = u;
kpeter@758
   560
          }
kpeter@758
   561
        }
kpeter@758
   562
      }
kpeter@760
   563
kpeter@760
   564
      // Connect all other nodes to this component and compute node
kpeter@760
   565
      // distances using reverse BFS
kpeter@760
   566
      _qfront = 0;
kpeter@760
   567
      while (_qback < int(_nodes->size())-1) {
kpeter@760
   568
        v = _queue[_qfront++];
kpeter@760
   569
        for (int j = 0; j < int(_in_arcs[v].size()); ++j) {
kpeter@760
   570
          e = _in_arcs[v][j];
kpeter@760
   571
          u = _gr.source(e);
kpeter@760
   572
          if (!_reached[u]) {
kpeter@760
   573
            _reached[u] = true;
kpeter@760
   574
            _policy[u] = e;
kpeter@864
   575
            _dist[u] = _dist[v] + _cost[e] * _curr_size - _curr_cost;
kpeter@760
   576
            _queue[++_qback] = u;
kpeter@760
   577
          }
kpeter@760
   578
        }
kpeter@760
   579
      }
kpeter@760
   580
kpeter@760
   581
      // Improve node distances
kpeter@758
   582
      bool improved = false;
kpeter@760
   583
      for (int i = 0; i < int(_nodes->size()); ++i) {
kpeter@760
   584
        v = (*_nodes)[i];
kpeter@760
   585
        for (int j = 0; j < int(_in_arcs[v].size()); ++j) {
kpeter@760
   586
          e = _in_arcs[v][j];
kpeter@760
   587
          u = _gr.source(e);
kpeter@864
   588
          LargeCost delta = _dist[v] + _cost[e] * _curr_size - _curr_cost;
kpeter@761
   589
          if (_tolerance.less(delta, _dist[u])) {
kpeter@760
   590
            _dist[u] = delta;
kpeter@760
   591
            _policy[u] = e;
kpeter@760
   592
            improved = true;
kpeter@760
   593
          }
kpeter@758
   594
        }
kpeter@758
   595
      }
kpeter@758
   596
      return improved;
kpeter@758
   597
    }
kpeter@758
   598
kpeter@864
   599
  }; //class HowardMmc
kpeter@758
   600
kpeter@758
   601
  ///@}
kpeter@758
   602
kpeter@758
   603
} //namespace lemon
kpeter@758
   604
kpeter@864
   605
#endif //LEMON_HOWARD_MMC_H