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