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.
     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_HOWARD_MMC_H
    20 #define LEMON_HOWARD_MMC_H
    21 
    22 /// \ingroup min_mean_cycle
    23 ///
    24 /// \file
    25 /// \brief Howard'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 HowardMmc class.
    37   ///
    38   /// Default traits class of HowardMmc 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 HowardMmcDefaultTraits
    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 addBack() 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 HowardMmcDefaultTraits<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 Howard's algorithm for finding a minimum
    97   /// mean cycle.
    98   ///
    99   /// This class implements Howard's policy iteration algorithm for finding
   100   /// a directed cycle of minimum mean cost in a digraph
   101   /// \ref amo93networkflows, \ref dasdan98minmeancycle.
   102   /// This class provides the most efficient algorithm for the
   103   /// minimum mean cycle problem, though the best known theoretical
   104   /// bound on its running time is exponential.
   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 HowardMmcDefaultTraits
   111   /// "HowardMmcDefaultTraits<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 = HowardMmcDefaultTraits<GR, CM> >
   120 #endif
   121   class HowardMmc
   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 HowardMmcDefaultTraits "default traits class",
   146     /// it is \ref lemon::Path "Path<Digraph>".
   147     typedef typename TR::Path Path;
   148 
   149     /// The \ref HowardMmcDefaultTraits "traits class" of the algorithm
   150     typedef TR Traits;
   151 
   152   private:
   153 
   154     TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
   155 
   156     // The digraph the algorithm runs on
   157     const Digraph &_gr;
   158     // The cost of the arcs
   159     const CostMap &_cost;
   160 
   161     // Data for the found cycles
   162     bool _curr_found, _best_found;
   163     LargeCost _curr_cost, _best_cost;
   164     int _curr_size, _best_size;
   165     Node _curr_node, _best_node;
   166 
   167     Path *_cycle_path;
   168     bool _local_path;
   169 
   170     // Internal data used by the algorithm
   171     typename Digraph::template NodeMap<Arc> _policy;
   172     typename Digraph::template NodeMap<bool> _reached;
   173     typename Digraph::template NodeMap<int> _level;
   174     typename Digraph::template NodeMap<LargeCost> _dist;
   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> > _in_arcs;
   182 
   183     // Queue used for BFS search
   184     std::vector<Node> _queue;
   185     int _qfront, _qback;
   186 
   187     Tolerance _tolerance;
   188 
   189     // Infinite constant
   190     const LargeCost INF;
   191 
   192   public:
   193 
   194     /// \name Named Template Parameters
   195     /// @{
   196 
   197     template <typename T>
   198     struct SetLargeCostTraits : public Traits {
   199       typedef T LargeCost;
   200       typedef lemon::Tolerance<T> Tolerance;
   201     };
   202 
   203     /// \brief \ref named-templ-param "Named parameter" for setting
   204     /// \c LargeCost type.
   205     ///
   206     /// \ref named-templ-param "Named parameter" for setting \c LargeCost
   207     /// type. It is used for internal computations in the algorithm.
   208     template <typename T>
   209     struct SetLargeCost
   210       : public HowardMmc<GR, CM, SetLargeCostTraits<T> > {
   211       typedef HowardMmc<GR, CM, SetLargeCostTraits<T> > Create;
   212     };
   213 
   214     template <typename T>
   215     struct SetPathTraits : public Traits {
   216       typedef T Path;
   217     };
   218 
   219     /// \brief \ref named-templ-param "Named parameter" for setting
   220     /// \c %Path type.
   221     ///
   222     /// \ref named-templ-param "Named parameter" for setting the \c %Path
   223     /// type of the found cycles.
   224     /// It must conform to the \ref lemon::concepts::Path "Path" concept
   225     /// and it must have an \c addBack() function.
   226     template <typename T>
   227     struct SetPath
   228       : public HowardMmc<GR, CM, SetPathTraits<T> > {
   229       typedef HowardMmc<GR, CM, SetPathTraits<T> > Create;
   230     };
   231 
   232     /// @}
   233 
   234   protected:
   235 
   236     HowardMmc() {}
   237 
   238   public:
   239 
   240     /// \brief Constructor.
   241     ///
   242     /// The constructor of the class.
   243     ///
   244     /// \param digraph The digraph the algorithm runs on.
   245     /// \param cost The costs of the arcs.
   246     HowardMmc( const Digraph &digraph,
   247                const CostMap &cost ) :
   248       _gr(digraph), _cost(cost), _best_found(false),
   249       _best_cost(0), _best_size(1), _cycle_path(NULL), _local_path(false),
   250       _policy(digraph), _reached(digraph), _level(digraph), _dist(digraph),
   251       _comp(digraph), _in_arcs(digraph),
   252       INF(std::numeric_limits<LargeCost>::has_infinity ?
   253           std::numeric_limits<LargeCost>::infinity() :
   254           std::numeric_limits<LargeCost>::max())
   255     {}
   256 
   257     /// Destructor.
   258     ~HowardMmc() {
   259       if (_local_path) delete _cycle_path;
   260     }
   261 
   262     /// \brief Set the path structure for storing the found cycle.
   263     ///
   264     /// This function sets an external path structure for storing the
   265     /// found cycle.
   266     ///
   267     /// If you don't call this function before calling \ref run() or
   268     /// \ref findCycleMean(), it will allocate a local \ref Path "path"
   269     /// structure. The destuctor deallocates this automatically
   270     /// allocated object, of course.
   271     ///
   272     /// \note The algorithm calls only the \ref lemon::Path::addBack()
   273     /// "addBack()" function of the given path structure.
   274     ///
   275     /// \return <tt>(*this)</tt>
   276     HowardMmc& cycle(Path &path) {
   277       if (_local_path) {
   278         delete _cycle_path;
   279         _local_path = false;
   280       }
   281       _cycle_path = &path;
   282       return *this;
   283     }
   284 
   285     /// \brief Set the tolerance used by the algorithm.
   286     ///
   287     /// This function sets the tolerance object used by the algorithm.
   288     ///
   289     /// \return <tt>(*this)</tt>
   290     HowardMmc& tolerance(const Tolerance& tolerance) {
   291       _tolerance = tolerance;
   292       return *this;
   293     }
   294 
   295     /// \brief Return a const reference to the tolerance.
   296     ///
   297     /// This function returns a const reference to the tolerance object
   298     /// used by the algorithm.
   299     const Tolerance& tolerance() const {
   300       return _tolerance;
   301     }
   302 
   303     /// \name Execution control
   304     /// The simplest way to execute the algorithm is to call the \ref run()
   305     /// function.\n
   306     /// If you only need the minimum mean cost, you may call
   307     /// \ref findCycleMean().
   308 
   309     /// @{
   310 
   311     /// \brief Run the algorithm.
   312     ///
   313     /// This function runs the algorithm.
   314     /// It can be called more than once (e.g. if the underlying digraph
   315     /// and/or the arc costs have been modified).
   316     ///
   317     /// \return \c true if a directed cycle exists in the digraph.
   318     ///
   319     /// \note <tt>mmc.run()</tt> is just a shortcut of the following code.
   320     /// \code
   321     ///   return mmc.findCycleMean() && mmc.findCycle();
   322     /// \endcode
   323     bool run() {
   324       return findCycleMean() && findCycle();
   325     }
   326 
   327     /// \brief Find the minimum cycle mean.
   328     ///
   329     /// This function finds the minimum mean cost of the directed
   330     /// cycles in the digraph.
   331     ///
   332     /// \return \c true if a directed cycle exists in the digraph.
   333     bool findCycleMean() {
   334       // Initialize and find strongly connected components
   335       init();
   336       findComponents();
   337 
   338       // Find the minimum cycle mean in the components
   339       for (int comp = 0; comp < _comp_num; ++comp) {
   340         // Find the minimum mean cycle in the current component
   341         if (!buildPolicyGraph(comp)) continue;
   342         while (true) {
   343           findPolicyCycle();
   344           if (!computeNodeDistances()) break;
   345         }
   346         // Update the best cycle (global minimum mean cycle)
   347         if ( _curr_found && (!_best_found ||
   348              _curr_cost * _best_size < _best_cost * _curr_size) ) {
   349           _best_found = true;
   350           _best_cost = _curr_cost;
   351           _best_size = _curr_size;
   352           _best_node = _curr_node;
   353         }
   354       }
   355       return _best_found;
   356     }
   357 
   358     /// \brief Find a minimum mean directed cycle.
   359     ///
   360     /// This function finds a directed cycle of minimum mean cost
   361     /// in the digraph using the data computed by findCycleMean().
   362     ///
   363     /// \return \c true if a directed cycle exists in the digraph.
   364     ///
   365     /// \pre \ref findCycleMean() must be called before using this function.
   366     bool findCycle() {
   367       if (!_best_found) return false;
   368       _cycle_path->addBack(_policy[_best_node]);
   369       for ( Node v = _best_node;
   370             (v = _gr.target(_policy[v])) != _best_node; ) {
   371         _cycle_path->addBack(_policy[v]);
   372       }
   373       return true;
   374     }
   375 
   376     /// @}
   377 
   378     /// \name Query Functions
   379     /// The results of the algorithm can be obtained using these
   380     /// functions.\n
   381     /// The algorithm should be executed before using them.
   382 
   383     /// @{
   384 
   385     /// \brief Return the total cost of the found cycle.
   386     ///
   387     /// This function returns the total cost of the found cycle.
   388     ///
   389     /// \pre \ref run() or \ref findCycleMean() must be called before
   390     /// using this function.
   391     Cost cycleCost() const {
   392       return static_cast<Cost>(_best_cost);
   393     }
   394 
   395     /// \brief Return the number of arcs on the found cycle.
   396     ///
   397     /// This function returns the number of arcs on the found cycle.
   398     ///
   399     /// \pre \ref run() or \ref findCycleMean() must be called before
   400     /// using this function.
   401     int cycleSize() const {
   402       return _best_size;
   403     }
   404 
   405     /// \brief Return the mean cost of the found cycle.
   406     ///
   407     /// This function returns the mean cost of the found cycle.
   408     ///
   409     /// \note <tt>alg.cycleMean()</tt> is just a shortcut of the
   410     /// following code.
   411     /// \code
   412     ///   return static_cast<double>(alg.cycleCost()) / alg.cycleSize();
   413     /// \endcode
   414     ///
   415     /// \pre \ref run() or \ref findCycleMean() must be called before
   416     /// using this function.
   417     double cycleMean() const {
   418       return static_cast<double>(_best_cost) / _best_size;
   419     }
   420 
   421     /// \brief Return the found cycle.
   422     ///
   423     /// This function returns a const reference to the path structure
   424     /// storing the found cycle.
   425     ///
   426     /// \pre \ref run() or \ref findCycle() must be called before using
   427     /// this function.
   428     const Path& cycle() const {
   429       return *_cycle_path;
   430     }
   431 
   432     ///@}
   433 
   434   private:
   435 
   436     // Initialize
   437     void init() {
   438       if (!_cycle_path) {
   439         _local_path = true;
   440         _cycle_path = new Path;
   441       }
   442       _queue.resize(countNodes(_gr));
   443       _best_found = false;
   444       _best_cost = 0;
   445       _best_size = 1;
   446       _cycle_path->clear();
   447     }
   448 
   449     // Find strongly connected components and initialize _comp_nodes
   450     // and _in_arcs
   451     void findComponents() {
   452       _comp_num = stronglyConnectedComponents(_gr, _comp);
   453       _comp_nodes.resize(_comp_num);
   454       if (_comp_num == 1) {
   455         _comp_nodes[0].clear();
   456         for (NodeIt n(_gr); n != INVALID; ++n) {
   457           _comp_nodes[0].push_back(n);
   458           _in_arcs[n].clear();
   459           for (InArcIt a(_gr, n); a != INVALID; ++a) {
   460             _in_arcs[n].push_back(a);
   461           }
   462         }
   463       } else {
   464         for (int i = 0; i < _comp_num; ++i)
   465           _comp_nodes[i].clear();
   466         for (NodeIt n(_gr); n != INVALID; ++n) {
   467           int k = _comp[n];
   468           _comp_nodes[k].push_back(n);
   469           _in_arcs[n].clear();
   470           for (InArcIt a(_gr, n); a != INVALID; ++a) {
   471             if (_comp[_gr.source(a)] == k) _in_arcs[n].push_back(a);
   472           }
   473         }
   474       }
   475     }
   476 
   477     // Build the policy graph in the given strongly connected component
   478     // (the out-degree of every node is 1)
   479     bool buildPolicyGraph(int comp) {
   480       _nodes = &(_comp_nodes[comp]);
   481       if (_nodes->size() < 1 ||
   482           (_nodes->size() == 1 && _in_arcs[(*_nodes)[0]].size() == 0)) {
   483         return false;
   484       }
   485       for (int i = 0; i < int(_nodes->size()); ++i) {
   486         _dist[(*_nodes)[i]] = INF;
   487       }
   488       Node u, v;
   489       Arc e;
   490       for (int i = 0; i < int(_nodes->size()); ++i) {
   491         v = (*_nodes)[i];
   492         for (int j = 0; j < int(_in_arcs[v].size()); ++j) {
   493           e = _in_arcs[v][j];
   494           u = _gr.source(e);
   495           if (_cost[e] < _dist[u]) {
   496             _dist[u] = _cost[e];
   497             _policy[u] = e;
   498           }
   499         }
   500       }
   501       return true;
   502     }
   503 
   504     // Find the minimum mean cycle in the policy graph
   505     void findPolicyCycle() {
   506       for (int i = 0; i < int(_nodes->size()); ++i) {
   507         _level[(*_nodes)[i]] = -1;
   508       }
   509       LargeCost ccost;
   510       int csize;
   511       Node u, v;
   512       _curr_found = false;
   513       for (int i = 0; i < int(_nodes->size()); ++i) {
   514         u = (*_nodes)[i];
   515         if (_level[u] >= 0) continue;
   516         for (; _level[u] < 0; u = _gr.target(_policy[u])) {
   517           _level[u] = i;
   518         }
   519         if (_level[u] == i) {
   520           // A cycle is found
   521           ccost = _cost[_policy[u]];
   522           csize = 1;
   523           for (v = u; (v = _gr.target(_policy[v])) != u; ) {
   524             ccost += _cost[_policy[v]];
   525             ++csize;
   526           }
   527           if ( !_curr_found ||
   528                (ccost * _curr_size < _curr_cost * csize) ) {
   529             _curr_found = true;
   530             _curr_cost = ccost;
   531             _curr_size = csize;
   532             _curr_node = u;
   533           }
   534         }
   535       }
   536     }
   537 
   538     // Contract the policy graph and compute node distances
   539     bool computeNodeDistances() {
   540       // Find the component of the main cycle and compute node distances
   541       // using reverse BFS
   542       for (int i = 0; i < int(_nodes->size()); ++i) {
   543         _reached[(*_nodes)[i]] = false;
   544       }
   545       _qfront = _qback = 0;
   546       _queue[0] = _curr_node;
   547       _reached[_curr_node] = true;
   548       _dist[_curr_node] = 0;
   549       Node u, v;
   550       Arc e;
   551       while (_qfront <= _qback) {
   552         v = _queue[_qfront++];
   553         for (int j = 0; j < int(_in_arcs[v].size()); ++j) {
   554           e = _in_arcs[v][j];
   555           u = _gr.source(e);
   556           if (_policy[u] == e && !_reached[u]) {
   557             _reached[u] = true;
   558             _dist[u] = _dist[v] + _cost[e] * _curr_size - _curr_cost;
   559             _queue[++_qback] = u;
   560           }
   561         }
   562       }
   563 
   564       // Connect all other nodes to this component and compute node
   565       // distances using reverse BFS
   566       _qfront = 0;
   567       while (_qback < int(_nodes->size())-1) {
   568         v = _queue[_qfront++];
   569         for (int j = 0; j < int(_in_arcs[v].size()); ++j) {
   570           e = _in_arcs[v][j];
   571           u = _gr.source(e);
   572           if (!_reached[u]) {
   573             _reached[u] = true;
   574             _policy[u] = e;
   575             _dist[u] = _dist[v] + _cost[e] * _curr_size - _curr_cost;
   576             _queue[++_qback] = u;
   577           }
   578         }
   579       }
   580 
   581       // Improve node distances
   582       bool improved = false;
   583       for (int i = 0; i < int(_nodes->size()); ++i) {
   584         v = (*_nodes)[i];
   585         for (int j = 0; j < int(_in_arcs[v].size()); ++j) {
   586           e = _in_arcs[v][j];
   587           u = _gr.source(e);
   588           LargeCost delta = _dist[v] + _cost[e] * _curr_size - _curr_cost;
   589           if (_tolerance.less(delta, _dist[u])) {
   590             _dist[u] = delta;
   591             _policy[u] = e;
   592             improved = true;
   593           }
   594         }
   595       }
   596       return improved;
   597     }
   598 
   599   }; //class HowardMmc
   600 
   601   ///@}
   602 
   603 } //namespace lemon
   604 
   605 #endif //LEMON_HOWARD_MMC_H