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