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