lemon/min_mean_cycle.h
author alpar
Mon, 21 Jan 2008 15:35:55 +0000
changeset 2557 673cb4d1060b
parent 2553 bfced05fa852
child 2583 7216b6a52ab9
permissions -rw-r--r--
Reveal an existing functionality in the documentation
     1 /* -*- C++ -*-
     2  *
     3  * This file is a part of LEMON, a generic C++ optimization library
     4  *
     5  * Copyright (C) 2003-2008
     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_MIN_MEAN_CYCLE_H
    20 #define LEMON_MIN_MEAN_CYCLE_H
    21 
    22 /// \ingroup shortest_path
    23 ///
    24 /// \file
    25 /// \brief Howard's algorithm for finding a minimum mean directed cycle.
    26 
    27 #include <vector>
    28 #include <lemon/graph_utils.h>
    29 #include <lemon/topology.h>
    30 #include <lemon/path.h>
    31 #include <lemon/tolerance.h>
    32 
    33 namespace lemon {
    34 
    35   /// \addtogroup shortest_path
    36   /// @{
    37 
    38   /// \brief Implementation of Howard's algorithm for finding a minimum
    39   /// mean directed cycle.
    40   ///
    41   /// \ref MinMeanCycle implements Howard's algorithm for finding a
    42   /// minimum mean directed cycle.
    43   ///
    44   /// \param Graph The directed graph type the algorithm runs on.
    45   /// \param LengthMap The type of the length (cost) map.
    46   ///
    47   /// \warning \c LengthMap::Value must be convertible to \c double.
    48   ///
    49   /// \author Peter Kovacs
    50 
    51   template < typename Graph,
    52              typename LengthMap = typename Graph::template EdgeMap<int> >
    53   class MinMeanCycle
    54   {
    55     GRAPH_TYPEDEFS(typename Graph);
    56 
    57     typedef typename LengthMap::Value Length;
    58     typedef Path<Graph> Path;
    59 
    60   protected:
    61 
    62     typename Graph::template NodeMap<bool> _reached;
    63     typename Graph::template NodeMap<double> _dist;
    64     typename Graph::template NodeMap<Edge> _policy;
    65 
    66     /// The directed graph the algorithm runs on.
    67     const Graph &_graph;
    68     /// The length of the edges.
    69     const LengthMap &_length;
    70 
    71     /// The total length of the found cycle.
    72     Length _cycle_length;
    73     /// The number of edges on the found cycle.
    74     int _cycle_size;
    75     /// The found cycle.
    76     Path *_cycle_path;
    77 
    78     bool _local_path;
    79     bool _cycle_found;
    80     Node _cycle_node;
    81 
    82     typename Graph::template NodeMap<int> _component;
    83     int _component_num;
    84 
    85     std::vector<Node> _nodes;
    86     std::vector<Edge> _edges;
    87     Tolerance<double> _tolerance;
    88 
    89   public:
    90 
    91     /// \brief The constructor of the class.
    92     ///
    93     /// The constructor of the class.
    94     ///
    95     /// \param graph The directed graph the algorithm runs on.
    96     /// \param length The length (cost) of the edges.
    97     MinMeanCycle( const Graph &graph,
    98                   const LengthMap &length ) :
    99       _graph(graph), _length(length), _dist(graph), _reached(graph),
   100       _policy(graph), _component(graph), _cycle_length(0),
   101       _cycle_size(-1), _cycle_path(NULL), _local_path(false)
   102     { }
   103 
   104     /// The destructor of the class.
   105     ~MinMeanCycle() {
   106       if (_local_path) delete _cycle_path;
   107     }
   108 
   109   protected:
   110 
   111     // Initializes the internal data structures for the current strongly
   112     // connected component and creating the policy graph.
   113     // The policy graph can be represented by the _policy map because
   114     // the out degree of every node is 1.
   115     bool initCurrentComponent(int comp) {
   116       // Finding the nodes of the current component
   117       _nodes.clear();
   118       for (NodeIt n(_graph); n != INVALID; ++n) {
   119         if (_component[n] == comp) _nodes.push_back(n);
   120       }
   121       if (_nodes.size() <= 1) return false;
   122       // Finding the edges of the current component
   123       _edges.clear();
   124       for (EdgeIt e(_graph); e != INVALID; ++e) {
   125         if ( _component[_graph.source(e)] == comp &&
   126              _component[_graph.target(e)] == comp )
   127           _edges.push_back(e);
   128       }
   129       // Initializing _reached, _dist, _policy maps
   130       for (int i = 0; i < _nodes.size(); ++i) {
   131         _reached[_nodes[i]] = false;
   132         _policy[_nodes[i]] = INVALID;
   133       }
   134       Node u; Edge e;
   135       for (int j = 0; j < _edges.size(); ++j) {
   136         e = _edges[j];
   137         u = _graph.source(e);
   138         if (!_reached[u] || _length[e] < _dist[u]) {
   139           _dist[u] = _length[e];
   140           _policy[u] = e;
   141           _reached[u] = true;
   142         }
   143       }
   144       return true;
   145     }
   146 
   147     // Finds all cycles in the policy graph.
   148     // Sets _cycle_found to true if a cycle is found and sets
   149     // _cycle_length, _cycle_size, _cycle_node to represent the minimum
   150     // mean cycle in the policy graph.
   151     bool findPolicyCycles(int comp) {
   152       typename Graph::template NodeMap<int> level(_graph, -1);
   153       _cycle_found = false;
   154       Length clength;
   155       int csize;
   156       int path_cnt = 0;
   157       Node u, v;
   158       // Searching for cycles
   159       for (int i = 0; i < _nodes.size(); ++i) {
   160         if (level[_nodes[i]] < 0) {
   161           u = _nodes[i];
   162           level[u] = path_cnt;
   163           while (level[u = _graph.target(_policy[u])] < 0)
   164             level[u] = path_cnt;
   165           if (level[u] == path_cnt) {
   166             // A cycle is found
   167             clength = _length[_policy[u]];
   168             csize = 1;
   169             for (v = u; (v = _graph.target(_policy[v])) != u; ) {
   170               clength += _length[_policy[v]];
   171               ++csize;
   172             }
   173             if ( !_cycle_found ||
   174                  clength * _cycle_size < _cycle_length * csize ) {
   175               _cycle_found = true;
   176               _cycle_length = clength;
   177               _cycle_size = csize;
   178               _cycle_node = u;
   179             }
   180           }
   181           ++path_cnt;
   182         }
   183       }
   184       return _cycle_found;
   185     }
   186 
   187     // Contracts the policy graph to be connected by cutting all cycles
   188     // except for the main cycle (i.e. the minimum mean cycle).
   189     void contractPolicyGraph(int comp) {
   190       // Finding the component of the main cycle using
   191       // reverse BFS search
   192       typename Graph::template NodeMap<int> found(_graph, false);
   193       std::deque<Node> queue;
   194       queue.push_back(_cycle_node);
   195       found[_cycle_node] = true;
   196       Node u, v;
   197       while (!queue.empty()) {
   198         v = queue.front(); queue.pop_front();
   199         for (InEdgeIt e(_graph, v); e != INVALID; ++e) {
   200           u = _graph.source(e);
   201           if (_component[u] == comp && !found[u] && _policy[u] == e) {
   202             found[u] = true;
   203             queue.push_back(u);
   204           }
   205         }
   206       }
   207       // Connecting all other nodes to this component using
   208       // reverse BFS search
   209       queue.clear();
   210       for (int i = 0; i < _nodes.size(); ++i)
   211         if (found[_nodes[i]]) queue.push_back(_nodes[i]);
   212       int found_cnt = queue.size();
   213       while (found_cnt < _nodes.size() && !queue.empty()) {
   214         v = queue.front(); queue.pop_front();
   215         for (InEdgeIt e(_graph, v); e != INVALID; ++e) {
   216           u = _graph.source(e);
   217           if (_component[u] == comp && !found[u]) {
   218             found[u] = true;
   219             ++found_cnt;
   220             _policy[u] = e;
   221             queue.push_back(u);
   222           }
   223         }
   224       }
   225     }
   226 
   227     // Computes node distances in the policy graph and updates the
   228     // policy graph if the node distances can be improved.
   229     bool computeNodeDistances(int comp) {
   230       // Computing node distances using reverse BFS search
   231       double cycle_mean = (double)_cycle_length / _cycle_size;
   232       typename Graph::template NodeMap<int> found(_graph, false);
   233       std::deque<Node> queue;
   234       queue.push_back(_cycle_node);
   235       found[_cycle_node] = true;
   236       Node u, v;
   237       while (!queue.empty()) {
   238         v = queue.front(); queue.pop_front();
   239         for (InEdgeIt e(_graph, v); e != INVALID; ++e) {
   240           u = _graph.source(e);
   241           if (_component[u] == comp && !found[u] && _policy[u] == e) {
   242             found[u] = true;
   243             _dist[u] = _dist[v] + _length[e] - cycle_mean;
   244             queue.push_back(u);
   245           }
   246         }
   247       }
   248       // Improving node distances
   249       bool improved = false;
   250       for (int j = 0; j < _edges.size(); ++j) {
   251         Edge e = _edges[j];
   252         u = _graph.source(e); v = _graph.target(e);
   253         double delta = _dist[v] + _length[e] - cycle_mean;
   254         if (_tolerance.less(delta, _dist[u])) {
   255           improved = true;
   256           _dist[u] = delta;
   257           _policy[u] = e;
   258         }
   259       }
   260       return improved;
   261     }
   262 
   263   public:
   264 
   265     /// \brief Runs the algorithm.
   266     ///
   267     /// Runs the algorithm.
   268     ///
   269     /// \return Returns \c true if a directed cycle exists in the graph.
   270     ///
   271     /// \note Apart from the return value, <tt>mmc.run()</tt> is just a
   272     /// shortcut of the following code.
   273     /// \code
   274     ///   mmc.init();
   275     ///   mmc.findMinMean();
   276     ///   mmc.findCycle();
   277     /// \endcode
   278     bool run() {
   279       init();
   280       return findMinMean() && findCycle();
   281     }
   282 
   283     /// \brief Initializes the internal data structures.
   284     ///
   285     /// Initializes the internal data structures.
   286     ///
   287     /// \sa reset()
   288     void init() {
   289       _tolerance.epsilon(1e-8);
   290       if (!_cycle_path) {
   291         _local_path = true;
   292         _cycle_path = new Path;
   293       }
   294       _cycle_found = false;
   295       _component_num = stronglyConnectedComponents(_graph, _component);
   296     }
   297 
   298     /// \brief Resets the internal data structures.
   299     ///
   300     /// Resets the internal data structures so that \ref findMinMean()
   301     /// and \ref findCycle() can be called again (e.g. when the
   302     /// underlaying graph has been modified).
   303     ///
   304     /// \sa init()
   305     void reset() {
   306       if (_cycle_path) _cycle_path->clear();
   307       _cycle_found = false;
   308       _component_num = stronglyConnectedComponents(_graph, _component);
   309     }
   310 
   311     /// \brief Finds the minimum cycle mean length in the graph.
   312     ///
   313     /// Computes all the required data and finds the minimum cycle mean
   314     /// length in the graph.
   315     ///
   316     /// \return Returns \c true if a directed cycle exists in the graph.
   317     ///
   318     /// \pre \ref init() must be called before using this function.
   319     bool findMinMean() {
   320       // Finding the minimum mean cycle in the components
   321       for (int comp = 0; comp < _component_num; ++comp) {
   322         if (!initCurrentComponent(comp)) continue;
   323         while (true) {
   324           if (!findPolicyCycles(comp)) return false;
   325           contractPolicyGraph(comp);
   326           if (!computeNodeDistances(comp)) return true;
   327         }
   328       }
   329     }
   330 
   331     /// \brief Finds a critical (minimum mean) directed cycle.
   332     ///
   333     /// Finds a critical (minimum mean) directed cycle using the data
   334     /// computed in the \ref findMinMean() function.
   335     ///
   336     /// \return Returns \c true if a directed cycle exists in the graph.
   337     ///
   338     /// \pre \ref init() and \ref findMinMean() must be called before
   339     /// using this function.
   340     bool findCycle() {
   341       if (!_cycle_found) return false;
   342       _cycle_path->addBack(_policy[_cycle_node]);
   343       for ( Node v = _cycle_node;
   344             (v = _graph.target(_policy[v])) != _cycle_node; ) {
   345         _cycle_path->addBack(_policy[v]);
   346       }
   347       return true;
   348     }
   349 
   350     /// \brief Returns the total length of the found cycle.
   351     ///
   352     /// Returns the total length of the found cycle.
   353     ///
   354     /// \pre \ref run() or \ref findMinMean() must be called before
   355     /// using this function.
   356     Length cycleLength() const {
   357       return _cycle_length;
   358     }
   359 
   360     /// \brief Returns the number of edges on the found cycle.
   361     ///
   362     /// Returns the number of edges on the found cycle.
   363     ///
   364     /// \pre \ref run() or \ref findMinMean() must be called before
   365     /// using this function.
   366     int cycleEdgeNum() const {
   367       return _cycle_size;
   368     }
   369 
   370     /// \brief Returns the mean length of the found cycle.
   371     ///
   372     /// Returns the mean length of the found cycle.
   373     ///
   374     /// \pre \ref run() or \ref findMinMean() must be called before
   375     /// using this function.
   376     ///
   377     /// \note <tt>mmc.cycleMean()</tt> is just a shortcut of the
   378     /// following code.
   379     /// \code
   380     ///   return double(mmc.cycleLength()) / mmc.cycleEdgeNum();
   381     /// \endcode
   382     double cycleMean() const {
   383       return (double)_cycle_length / _cycle_size;
   384     }
   385 
   386     /// \brief Returns a const reference to the \ref Path "path"
   387     /// structure storing the found cycle.
   388     ///
   389     /// Returns a const reference to the \ref Path "path"
   390     /// structure storing the found cycle.
   391     ///
   392     /// \pre \ref run() or \ref findCycle() must be called before using
   393     /// this function.
   394     ///
   395     /// \sa cyclePath()
   396     const Path& cycle() const {
   397       return *_cycle_path;
   398     }
   399 
   400     /// \brief Sets the \ref Path "path" structure for storing the found
   401     /// cycle.
   402     ///
   403     /// Sets an external \ref Path "path" structure for storing the
   404     /// found cycle.
   405     ///
   406     /// If you don't call this function before calling \ref run() or
   407     /// \ref init(), it will allocate a local \ref Path "path"
   408     /// structure.
   409     /// The destuctor deallocates this automatically allocated map,
   410     /// of course.
   411     ///
   412     /// \note The algorithm calls only the \ref lemon::Path::addBack()
   413     /// "addBack()" function of the given \ref Path "path" structure.
   414     ///
   415     /// \return <tt>(*this)</tt>
   416     ///
   417     /// \sa cycle()
   418     MinMeanCycle& cyclePath(Path &path) {
   419       if (_local_path) {
   420         delete _cycle_path;
   421         _local_path = false;
   422       }
   423       _cycle_path = &path;
   424       return *this;
   425     }
   426 
   427   }; //class MinMeanCycle
   428 
   429   ///@}
   430 
   431 } //namespace lemon
   432 
   433 #endif //LEMON_MIN_MEAN_CYCLE_H