[Lemon-commits] alpar: r3241 - lemon/trunk/lemon

Lemon SVN svn at lemon.cs.elte.hu
Tue Mar 13 17:32:36 CET 2007


Author: alpar
Date: Tue Mar 13 17:32:35 2007
New Revision: 3241

Added:
   lemon/trunk/lemon/min_mean_cycle.h
Modified:
   lemon/trunk/lemon/Makefile.am

Log:
Minimum mean cycle algorithm contributed by Peter Kovacs.


Modified: lemon/trunk/lemon/Makefile.am
==============================================================================
--- lemon/trunk/lemon/Makefile.am	(original)
+++ lemon/trunk/lemon/Makefile.am	Tue Mar 13 17:32:35 2007
@@ -89,6 +89,7 @@
 	lemon/matrix_maps.h \
 	lemon/max_matching.h \
 	lemon/min_cost_arborescence.h \
+	lemon/min_mean_cycle.h \
 	lemon/mip_glpk.h \
 	lemon/mip_cplex.h \
 	lemon/nagamochi_ibaraki.h \

Added: lemon/trunk/lemon/min_mean_cycle.h
==============================================================================
--- (empty file)
+++ lemon/trunk/lemon/min_mean_cycle.h	Tue Mar 13 17:32:35 2007
@@ -0,0 +1,380 @@
+/* -*- C++ -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library
+ *
+ * Copyright (C) 2003-2007
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_MIN_MEAN_CYCLE_H
+#define LEMON_MIN_MEAN_CYCLE_H
+
+/// \ingroup min_cost_flow
+///
+/// \file 
+/// \brief Karp algorithm for finding a minimum mean cycle.
+
+#include <lemon/graph_utils.h>
+#include <lemon/topology.h>
+#include <lemon/path.h>
+
+namespace lemon {
+
+  /// \addtogroup min_cost_flow
+  /// @{
+
+  /// \brief Implementation of Karp's algorithm for finding a 
+  /// minimum mean cycle.
+  ///
+  /// The \ref lemon::MinMeanCycle "MinMeanCycle" implements Karp's 
+  /// algorithm for finding a minimum mean cycle.
+  ///
+  /// \param Graph The directed graph type the algorithm runs on.
+  /// \param LengthMap The type of the length (cost) map.
+  ///
+  /// \author Peter Kovacs
+
+#ifdef DOXYGEN
+  template <typename Graph, typename LengthMap>
+#else
+  template <typename Graph,
+    typename LengthMap = typename Graph::template EdgeMap<int> >
+#endif
+
+  class MinMeanCycle
+  {
+    typedef typename Graph::Node Node;
+    typedef typename Graph::NodeIt NodeIt;
+    typedef typename Graph::Edge Edge;
+    typedef typename Graph::EdgeIt EdgeIt;
+    typedef typename Graph::InEdgeIt InEdgeIt;
+    typedef typename Graph::OutEdgeIt OutEdgeIt;
+
+    typedef typename LengthMap::Value Length;
+    
+    typedef typename Graph::template NodeMap<int> IntNodeMap;
+    typedef typename Graph::template NodeMap<Edge> PredNodeMap;
+    typedef Path<Graph> Path;
+    typedef std::vector<Node> NodeVector;
+    typedef typename NodeVector::iterator NodeVectorIt;
+
+  protected:
+  
+    /// \brief Data sturcture for path data.
+    struct PathData {
+      bool found;
+      Length dist;
+      Edge pred;
+      PathData(bool _found = false, Length _dist = 0) : 
+	found(_found), dist(_dist), pred(INVALID) {}
+      PathData(bool _found, Length _dist, Edge _pred) : 
+	found(_found), dist(_dist), pred(_pred) {}
+    };
+    
+  private:
+  
+    typedef typename Graph::template NodeMap<std::vector<PathData> > PathVectorNodeMap;
+  
+  protected:
+
+    /// \brief Node map for storing path data.
+    /// 
+    /// Node map for storing path data of all nodes in the current
+    /// component. dmap[v][k] is the length of a shortest directed walk 
+    /// to node v from the starting node containing exactly k edges.
+    PathVectorNodeMap dmap;
+    
+    /// \brief The directed graph the algorithm runs on.
+    const Graph& graph;
+    /// \brief The length of the edges.
+    const LengthMap& length;
+    
+    /// \brief The total length of the found cycle.
+    Length cycle_length;
+    /// \brief The number of edges in the found cycle.
+    int cycle_size;
+    /// \brief The found cycle.
+    Path *cycle_path;
+    /// \brief The found cycle.
+    bool local_path;
+    
+    /// \brief Node map for identifying strongly connected components.
+    IntNodeMap comp;
+    /// \brief The number of strongly connected components.
+    int comp_num;
+    /// \brief %Counter for identifying the current component.
+    int comp_cnt;
+    /// \brief Nodes of the current component.
+    NodeVector nodes;
+    /// \brief The processed nodes in the last round.
+    NodeVector process;
+    
+  public :
+
+    /// \brief The constructor of the class.
+    ///
+    /// The constructor of the class.
+    ///
+    /// \param _graph The directed graph the algorithm runs on.
+    /// \param _length The length (cost) of the edges.
+    MinMeanCycle( const Graph& _graph,
+		  const LengthMap& _length ) :
+      graph(_graph), length(_length), dmap(_graph), 
+      cycle_length(0), cycle_size(-1), comp(_graph),
+      cycle_path(NULL), local_path(false)
+    { }
+
+    /// \brief The destructor of the class.
+    ~MinMeanCycle() { 
+      if (local_path) delete cycle_path;
+    }
+
+  protected:
+    
+    /// \brief Initializes the internal data structures.
+    void init() {
+      comp_num = stronglyConnectedComponents(graph, comp);
+      if (!cycle_path) {
+	local_path = true;
+	cycle_path = new Path;
+      }
+    }
+
+    /// \brief Initializes the internal data structures for the current
+    /// component.
+    void initCurrent() {
+      nodes.clear();
+      // Finding the nodes of the current component
+      for (NodeIt v(graph); v != INVALID; ++v) {
+	if (comp[v] == comp_cnt) nodes.push_back(v);
+      }
+
+      // Creating vectors for all nodes
+      int n = nodes.size();
+      for (NodeVectorIt vi = nodes.begin(); vi != nodes.end(); ++vi) {
+	dmap[*vi].resize(n + 1);
+      }
+    }
+    
+    /// \brief Processes all rounds of computing required path data.
+    void processRounds() {
+      dmap[nodes[0]][0] = PathData(true, 0);
+      process.clear();
+      for (OutEdgeIt oe(graph, nodes[0]); oe != INVALID; ++oe) {
+	Node v = graph.target(oe);
+	if (comp[v] != comp_cnt || v == nodes[0]) continue;
+	dmap[v][1] = PathData(true, length[oe], oe);
+	process.push_back(v);
+      }
+      int n = nodes.size(), k;
+      for (k = 2; k <= n && process.size() < n; ++k) {
+	processNextBuildRound(k);
+      }
+      for ( ; k <= n; ++k) {
+	processNextFullRound(k);
+      }
+    }
+    
+    /// \brief Processes one round of computing required path data and
+    /// rebuilds \ref process vector.
+    void processNextBuildRound(int k) {
+      NodeVector next;
+      for (NodeVectorIt ui = process.begin(); ui != process.end(); ++ui) {
+	for (OutEdgeIt oe(graph, *ui); oe != INVALID; ++oe) {
+	  Node v = graph.target(oe);
+	  if (comp[v] != comp_cnt) continue;
+	  if ( !dmap[v][k].found || (dmap[v][k].dist > dmap[*ui][k-1].dist + length[oe]) ) {
+	    if (!dmap[v][k].found) next.push_back(v); 
+	    dmap[v][k] = PathData(true, dmap[*ui][k-1].dist + length[oe], oe);
+	  }
+	}
+      }
+      process.swap(next);
+    }
+
+    /// \brief Processes one round of computing required path data
+    /// using \ref nodes vector instead of \ref process vector.
+    void processNextFullRound(int k) {
+      for (NodeVectorIt ui = nodes.begin(); ui != nodes.end(); ++ui) {
+	for (OutEdgeIt oe(graph, *ui); oe != INVALID; ++oe) {
+	  Node v = graph.target(oe);
+	  if (comp[v] != comp_cnt) continue;
+	  if ( !dmap[v][k].found || (dmap[v][k].dist > dmap[*ui][k-1].dist + length[oe]) ) {
+	    dmap[v][k] = PathData(true, dmap[*ui][k-1].dist + length[oe], oe);
+	  }
+	}
+      }
+    }
+    
+    /// \brief Finds the minimum cycle mean value according to the path
+    /// data stored in \ref dmap.
+    ///
+    /// Finds the minimum cycle mean value according to the path data
+    /// stored in \ref dmap.
+    ///
+    /// \retval min_length The total length of the found cycle.
+    /// \retval min_size The number of edges in the found cycle.
+    /// \retval min_node A node for obtaining a critical cycle.
+    ///
+    /// \return \c true if a cycle exists in the graph.
+    bool findMinCycleMean(Length &min_length, int &min_size, Node &min_node) {
+      bool found_min = false;
+      for (NodeVectorIt vi = nodes.begin(); vi != nodes.end(); ++vi) {
+	Length len;
+	int size;
+	bool found_one = false;
+	int n = nodes.size();
+	for (int k = 0; k < n; ++k) {
+	  Length _len = dmap[*vi][n].dist - dmap[*vi][k].dist;
+	  int _size = n - k; 
+	  if ( dmap[*vi][n].found && dmap[*vi][k].found && (!found_one || len * _size < _len * size) ) {
+	    found_one = true;
+	    len = _len;
+	    size = _size;
+	  }
+	}
+	if (found_one && (!found_min || len * min_size < min_length * size)) {
+	  found_min = true;
+	  min_length = len;
+	  min_size = size;
+	  min_node = *vi;
+	}
+      }
+      return found_min;
+    }
+    
+    /// \brief Finds a critical (minimum mean) cycle according to the
+    /// path data stored in \ref dmap.
+    void findCycle(const Node &min_n) {
+      IntNodeMap reached(graph, -1);
+      int r = reached[min_n] = dmap[min_n].size() - 1;
+      Node u = graph.source(dmap[min_n][r].pred);
+      while (reached[u] < 0) {
+	reached[u] = --r;
+	u = graph.source(dmap[u][r].pred);
+      }
+      r = reached[u];
+      Edge ce = dmap[u][r].pred;
+      cycle_path->addFront(ce);
+      Node v;
+      while ((v = graph.source(ce)) != u) {
+	ce = dmap[v][--r].pred;
+	cycle_path->addFront(ce);
+      }
+    }
+    
+  public:
+
+    /// \brief Runs the algorithm.
+    ///
+    /// Runs the algorithm.
+    ///
+    /// \return \c true if a cycle exists in the graph.
+    bool run() {
+      init();
+      // Searching for the minimum mean cycle in all components
+      bool found_cycle = false;
+      Node cycle_node;
+      for (comp_cnt = 0; comp_cnt < comp_num; ++comp_cnt) {
+      
+	initCurrent();
+	processRounds();
+	
+	Length min_length;
+	int min_size;
+	Node min_node;
+	bool found_min = findMinCycleMean(min_length, min_size, min_node);
+	
+	if ( found_min && (!found_cycle || min_length * cycle_size  < cycle_length * min_size) ) {
+	  found_cycle = true;
+	  cycle_length = min_length;
+	  cycle_size = min_size;
+	  cycle_node = min_node;
+	}
+      }
+      if (found_cycle) findCycle(cycle_node);
+      return found_cycle;
+    }
+    
+    /// \brief Returns the total length of the found critical cycle.
+    ///
+    /// Returns the total length of the found critical cycle.
+    ///
+    /// \pre \ref run() must be called before using this function.
+    Length cycleLength() const { 
+      return cycle_length;
+    }
+    
+    /// \brief Returns the number of edges in the found critical 
+    /// cycle.
+    ///
+    /// Returns the number of edges in the found critical cycle.
+    ///
+    /// \pre \ref run() must be called before using this function.
+    int cycleEdgeNum() const { 
+      return cycle_size;
+    }
+    
+    /// \brief Returns the mean length of the found critical cycle.
+    ///
+    /// Returns the mean length of the found critical cycle.
+    ///
+    /// \pre \ref run() must be called before using this function.
+    ///
+    /// \warning LengthMap::Value must be convertible to double.
+    double minMean() const { 
+      return (double)cycle_length / (double)cycle_size;
+    }
+
+    /// \brief Returns a const reference to the \ref lemon::Path "Path"
+    /// structure of the found flow.
+    ///
+    /// Returns a const reference to the \ref lemon::Path "Path"
+    /// structure of the found flow.
+    ///
+    /// \pre \ref run() must be called before using this function.
+    ///
+    /// \sa \ref cyclePath()
+    const Path &cycle() const {
+      return *cycle_path;
+    }
+    
+    /// \brief Sets the \ref lemon::Path "Path" structure storing the 
+    /// found cycle.
+    /// 
+    /// Sets the \ref lemon::Path "Path" structure storing the found 
+    /// cycle. If you don't use this function before calling 
+    /// \ref run(), it will allocate one. The destuctor deallocates 
+    /// this automatically allocated map, of course.
+    ///
+    /// \note The algorithm calls only the \ref lemon::Path::addFront()
+    /// "addFront()" method of the given \ref lemon::Path "Path" 
+    /// structure.
+    /// 
+    /// \return \c (*this)
+    MinMeanCycle &cyclePath(Path& path) {
+      if (local_path) {
+	delete cycle_path;
+	local_path = false;
+      }
+      cycle_path = &path;
+      return *this;
+    }
+
+  }; //class MinMeanCycle
+
+  ///@}
+
+} //namespace lemon
+
+#endif //LEMON_MIN_MEAN_CYCLE_H



More information about the Lemon-commits mailing list