# HG changeset patch # User alpar # Date 1173803555 0 # Node ID fe0a8fe162714d78f1e819d63d9c1beaf94fca23 # Parent 467ca6d165566ba060e69d153d2d075a66122c88 Minimum mean cycle algorithm contributed by Peter Kovacs. diff -r 467ca6d16556 -r fe0a8fe16271 lemon/Makefile.am --- a/lemon/Makefile.am Tue Mar 13 15:42:06 2007 +0000 +++ b/lemon/Makefile.am Tue Mar 13 16:32:35 2007 +0000 @@ -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 \ diff -r 467ca6d16556 -r fe0a8fe16271 lemon/min_mean_cycle.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lemon/min_mean_cycle.h Tue Mar 13 16:32:35 2007 +0000 @@ -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 +#include +#include + +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 +#else + template > +#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 IntNodeMap; + typedef typename Graph::template NodeMap PredNodeMap; + typedef Path Path; + typedef std::vector 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 > 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