# HG changeset patch # User Peter Kovacs # Date 1268514098 -3600 # Node ID d3ea191c341258fddc1366953daefc8b1903073c # Parent a93f1a27d83125233114f2052c1e523c5e2f26e1 Rename min mean cycle classes and their members (#179) with respect to the possible introduction of min ratio cycle algorithms in the future. The renamed classes: - Karp --> KarpMmc - HartmannOrlin --> HartmannOrlinMmc - Howard --> HowardMmc The renamed members: - cycleLength() --> cycleCost() - cycleArcNum() --> cycleSize() - findMinMean() --> findCycleMean() - Value --> Cost - LargeValue --> LargeCost - SetLargeValue --> SetLargeCost diff -r a93f1a27d831 -r d3ea191c3412 lemon/Makefile.am --- a/lemon/Makefile.am Mon Mar 08 08:33:41 2010 +0100 +++ b/lemon/Makefile.am Sat Mar 13 22:01:38 2010 +0100 @@ -89,10 +89,10 @@ lemon/gomory_hu.h \ lemon/graph_to_eps.h \ lemon/grid_graph.h \ - lemon/hartmann_orlin.h \ - lemon/howard.h \ + lemon/hartmann_orlin_mmc.h \ + lemon/howard_mmc.h \ lemon/hypercube_graph.h \ - lemon/karp.h \ + lemon/karp_mmc.h \ lemon/kruskal.h \ lemon/hao_orlin.h \ lemon/lgf_reader.h \ diff -r a93f1a27d831 -r d3ea191c3412 lemon/cycle_canceling.h --- a/lemon/cycle_canceling.h Mon Mar 08 08:33:41 2010 +0100 +++ b/lemon/cycle_canceling.h Sat Mar 13 22:01:38 2010 +0100 @@ -34,7 +34,7 @@ #include #include #include -#include +#include namespace lemon { @@ -924,14 +924,14 @@ void startMinMeanCycleCanceling() { typedef SimplePath SPath; typedef typename SPath::ArcIt SPathArcIt; - typedef typename Howard + typedef typename HowardMmc ::template SetPath::Create MMC; SPath cycle; MMC mmc(_sgr, _cost_map); mmc.cycle(cycle); buildResidualNetwork(); - while (mmc.findMinMean() && mmc.cycleLength() < 0) { + while (mmc.findCycleMean() && mmc.cycleCost() < 0) { // Find the cycle mmc.findCycle(); @@ -1132,17 +1132,17 @@ } } } else { - typedef Howard MMC; + typedef HowardMmc MMC; typedef typename BellmanFord ::template SetDistMap::Create BF; // Set epsilon to the minimum cycle mean buildResidualNetwork(); MMC mmc(_sgr, _cost_map); - mmc.findMinMean(); + mmc.findCycleMean(); epsilon = -mmc.cycleMean(); - Cost cycle_cost = mmc.cycleLength(); - int cycle_size = mmc.cycleArcNum(); + Cost cycle_cost = mmc.cycleCost(); + int cycle_size = mmc.cycleSize(); // Compute feasible potentials for the current epsilon for (int i = 0; i != int(_cost_vec.size()); ++i) { diff -r a93f1a27d831 -r d3ea191c3412 lemon/hartmann_orlin.h --- a/lemon/hartmann_orlin.h Mon Mar 08 08:33:41 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,650 +0,0 @@ -/* -*- C++ -*- - * - * This file is a part of LEMON, a generic C++ optimization library - * - * Copyright (C) 2003-2008 - * 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_HARTMANN_ORLIN_H -#define LEMON_HARTMANN_ORLIN_H - -/// \ingroup min_mean_cycle -/// -/// \file -/// \brief Hartmann-Orlin's algorithm for finding a minimum mean cycle. - -#include -#include -#include -#include -#include -#include - -namespace lemon { - - /// \brief Default traits class of HartmannOrlin algorithm. - /// - /// Default traits class of HartmannOrlin algorithm. - /// \tparam GR The type of the digraph. - /// \tparam LEN The type of the length map. - /// It must conform to the \ref concepts::Rea_data "Rea_data" concept. -#ifdef DOXYGEN - template -#else - template ::is_integer> -#endif - struct HartmannOrlinDefaultTraits - { - /// The type of the digraph - typedef GR Digraph; - /// The type of the length map - typedef LEN LengthMap; - /// The type of the arc lengths - typedef typename LengthMap::Value Value; - - /// \brief The large value type used for internal computations - /// - /// The large value type used for internal computations. - /// It is \c long \c long if the \c Value type is integer, - /// otherwise it is \c double. - /// \c Value must be convertible to \c LargeValue. - typedef double LargeValue; - - /// The tolerance type used for internal computations - typedef lemon::Tolerance Tolerance; - - /// \brief The path type of the found cycles - /// - /// The path type of the found cycles. - /// It must conform to the \ref lemon::concepts::Path "Path" concept - /// and it must have an \c addFront() function. - typedef lemon::Path Path; - }; - - // Default traits class for integer value types - template - struct HartmannOrlinDefaultTraits - { - typedef GR Digraph; - typedef LEN LengthMap; - typedef typename LengthMap::Value Value; -#ifdef LEMON_HAVE_LONG_LONG - typedef long long LargeValue; -#else - typedef long LargeValue; -#endif - typedef lemon::Tolerance Tolerance; - typedef lemon::Path Path; - }; - - - /// \addtogroup min_mean_cycle - /// @{ - - /// \brief Implementation of the Hartmann-Orlin algorithm for finding - /// a minimum mean cycle. - /// - /// This class implements the Hartmann-Orlin algorithm for finding - /// a directed cycle of minimum mean length (cost) in a digraph - /// \ref amo93networkflows, \ref dasdan98minmeancycle. - /// It is an improved version of \ref Karp "Karp"'s original algorithm, - /// it applies an efficient early termination scheme. - /// It runs in time O(ne) and uses space O(n2+e). - /// - /// \tparam GR The type of the digraph the algorithm runs on. - /// \tparam LEN The type of the length map. The default - /// map type is \ref concepts::Digraph::ArcMap "GR::ArcMap". - /// \tparam TR The traits class that defines various types used by the - /// algorithm. By default, it is \ref HartmannOrlinDefaultTraits - /// "HartmannOrlinDefaultTraits". - /// In most cases, this parameter should not be set directly, - /// consider to use the named template parameters instead. -#ifdef DOXYGEN - template -#else - template < typename GR, - typename LEN = typename GR::template ArcMap, - typename TR = HartmannOrlinDefaultTraits > -#endif - class HartmannOrlin - { - public: - - /// The type of the digraph - typedef typename TR::Digraph Digraph; - /// The type of the length map - typedef typename TR::LengthMap LengthMap; - /// The type of the arc lengths - typedef typename TR::Value Value; - - /// \brief The large value type - /// - /// The large value type used for internal computations. - /// By default, it is \c long \c long if the \c Value type is integer, - /// otherwise it is \c double. - typedef typename TR::LargeValue LargeValue; - - /// The tolerance type - typedef typename TR::Tolerance Tolerance; - - /// \brief The path type of the found cycles - /// - /// The path type of the found cycles. - /// Using the \ref HartmannOrlinDefaultTraits "default traits class", - /// it is \ref lemon::Path "Path". - typedef typename TR::Path Path; - - /// The \ref HartmannOrlinDefaultTraits "traits class" of the algorithm - typedef TR Traits; - - private: - - TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); - - // Data sturcture for path data - struct PathData - { - LargeValue dist; - Arc pred; - PathData(LargeValue d, Arc p = INVALID) : - dist(d), pred(p) {} - }; - - typedef typename Digraph::template NodeMap > - PathDataNodeMap; - - private: - - // The digraph the algorithm runs on - const Digraph &_gr; - // The length of the arcs - const LengthMap &_length; - - // Data for storing the strongly connected components - int _comp_num; - typename Digraph::template NodeMap _comp; - std::vector > _comp_nodes; - std::vector* _nodes; - typename Digraph::template NodeMap > _out_arcs; - - // Data for the found cycles - bool _curr_found, _best_found; - LargeValue _curr_length, _best_length; - int _curr_size, _best_size; - Node _curr_node, _best_node; - int _curr_level, _best_level; - - Path *_cycle_path; - bool _local_path; - - // Node map for storing path data - PathDataNodeMap _data; - // The processed nodes in the last round - std::vector _process; - - Tolerance _tolerance; - - // Infinite constant - const LargeValue INF; - - public: - - /// \name Named Template Parameters - /// @{ - - template - struct SetLargeValueTraits : public Traits { - typedef T LargeValue; - typedef lemon::Tolerance Tolerance; - }; - - /// \brief \ref named-templ-param "Named parameter" for setting - /// \c LargeValue type. - /// - /// \ref named-templ-param "Named parameter" for setting \c LargeValue - /// type. It is used for internal computations in the algorithm. - template - struct SetLargeValue - : public HartmannOrlin > { - typedef HartmannOrlin > Create; - }; - - template - struct SetPathTraits : public Traits { - typedef T Path; - }; - - /// \brief \ref named-templ-param "Named parameter" for setting - /// \c %Path type. - /// - /// \ref named-templ-param "Named parameter" for setting the \c %Path - /// type of the found cycles. - /// It must conform to the \ref lemon::concepts::Path "Path" concept - /// and it must have an \c addFront() function. - template - struct SetPath - : public HartmannOrlin > { - typedef HartmannOrlin > Create; - }; - - /// @} - - protected: - - HartmannOrlin() {} - - public: - - /// \brief Constructor. - /// - /// The constructor of the class. - /// - /// \param digraph The digraph the algorithm runs on. - /// \param length The lengths (costs) of the arcs. - HartmannOrlin( const Digraph &digraph, - const LengthMap &length ) : - _gr(digraph), _length(length), _comp(digraph), _out_arcs(digraph), - _best_found(false), _best_length(0), _best_size(1), - _cycle_path(NULL), _local_path(false), _data(digraph), - INF(std::numeric_limits::has_infinity ? - std::numeric_limits::infinity() : - std::numeric_limits::max()) - {} - - /// Destructor. - ~HartmannOrlin() { - if (_local_path) delete _cycle_path; - } - - /// \brief Set the path structure for storing the found cycle. - /// - /// This function sets an external path structure for storing the - /// found cycle. - /// - /// If you don't call this function before calling \ref run() or - /// \ref findMinMean(), it will allocate a local \ref Path "path" - /// structure. The destuctor deallocates this automatically - /// allocated object, of course. - /// - /// \note The algorithm calls only the \ref lemon::Path::addFront() - /// "addFront()" function of the given path structure. - /// - /// \return (*this) - HartmannOrlin& cycle(Path &path) { - if (_local_path) { - delete _cycle_path; - _local_path = false; - } - _cycle_path = &path; - return *this; - } - - /// \brief Set the tolerance used by the algorithm. - /// - /// This function sets the tolerance object used by the algorithm. - /// - /// \return (*this) - HartmannOrlin& tolerance(const Tolerance& tolerance) { - _tolerance = tolerance; - return *this; - } - - /// \brief Return a const reference to the tolerance. - /// - /// This function returns a const reference to the tolerance object - /// used by the algorithm. - const Tolerance& tolerance() const { - return _tolerance; - } - - /// \name Execution control - /// The simplest way to execute the algorithm is to call the \ref run() - /// function.\n - /// If you only need the minimum mean length, you may call - /// \ref findMinMean(). - - /// @{ - - /// \brief Run the algorithm. - /// - /// This function runs the algorithm. - /// It can be called more than once (e.g. if the underlying digraph - /// and/or the arc lengths have been modified). - /// - /// \return \c true if a directed cycle exists in the digraph. - /// - /// \note mmc.run() is just a shortcut of the following code. - /// \code - /// return mmc.findMinMean() && mmc.findCycle(); - /// \endcode - bool run() { - return findMinMean() && findCycle(); - } - - /// \brief Find the minimum cycle mean. - /// - /// This function finds the minimum mean length of the directed - /// cycles in the digraph. - /// - /// \return \c true if a directed cycle exists in the digraph. - bool findMinMean() { - // Initialization and find strongly connected components - init(); - findComponents(); - - // Find the minimum cycle mean in the components - for (int comp = 0; comp < _comp_num; ++comp) { - if (!initComponent(comp)) continue; - processRounds(); - - // Update the best cycle (global minimum mean cycle) - if ( _curr_found && (!_best_found || - _curr_length * _best_size < _best_length * _curr_size) ) { - _best_found = true; - _best_length = _curr_length; - _best_size = _curr_size; - _best_node = _curr_node; - _best_level = _curr_level; - } - } - return _best_found; - } - - /// \brief Find a minimum mean directed cycle. - /// - /// This function finds a directed cycle of minimum mean length - /// in the digraph using the data computed by findMinMean(). - /// - /// \return \c true if a directed cycle exists in the digraph. - /// - /// \pre \ref findMinMean() must be called before using this function. - bool findCycle() { - if (!_best_found) return false; - IntNodeMap reached(_gr, -1); - int r = _best_level + 1; - Node u = _best_node; - while (reached[u] < 0) { - reached[u] = --r; - u = _gr.source(_data[u][r].pred); - } - r = reached[u]; - Arc e = _data[u][r].pred; - _cycle_path->addFront(e); - _best_length = _length[e]; - _best_size = 1; - Node v; - while ((v = _gr.source(e)) != u) { - e = _data[v][--r].pred; - _cycle_path->addFront(e); - _best_length += _length[e]; - ++_best_size; - } - return true; - } - - /// @} - - /// \name Query Functions - /// The results of the algorithm can be obtained using these - /// functions.\n - /// The algorithm should be executed before using them. - - /// @{ - - /// \brief Return the total length of the found cycle. - /// - /// This function returns the total length of the found cycle. - /// - /// \pre \ref run() or \ref findMinMean() must be called before - /// using this function. - Value cycleLength() const { - return static_cast(_best_length); - } - - /// \brief Return the number of arcs on the found cycle. - /// - /// This function returns the number of arcs on the found cycle. - /// - /// \pre \ref run() or \ref findMinMean() must be called before - /// using this function. - int cycleArcNum() const { - return _best_size; - } - - /// \brief Return the mean length of the found cycle. - /// - /// This function returns the mean length of the found cycle. - /// - /// \note alg.cycleMean() is just a shortcut of the - /// following code. - /// \code - /// return static_cast(alg.cycleLength()) / alg.cycleArcNum(); - /// \endcode - /// - /// \pre \ref run() or \ref findMinMean() must be called before - /// using this function. - double cycleMean() const { - return static_cast(_best_length) / _best_size; - } - - /// \brief Return the found cycle. - /// - /// This function returns a const reference to the path structure - /// storing the found cycle. - /// - /// \pre \ref run() or \ref findCycle() must be called before using - /// this function. - const Path& cycle() const { - return *_cycle_path; - } - - ///@} - - private: - - // Initialization - void init() { - if (!_cycle_path) { - _local_path = true; - _cycle_path = new Path; - } - _cycle_path->clear(); - _best_found = false; - _best_length = 0; - _best_size = 1; - _cycle_path->clear(); - for (NodeIt u(_gr); u != INVALID; ++u) - _data[u].clear(); - } - - // Find strongly connected components and initialize _comp_nodes - // and _out_arcs - void findComponents() { - _comp_num = stronglyConnectedComponents(_gr, _comp); - _comp_nodes.resize(_comp_num); - if (_comp_num == 1) { - _comp_nodes[0].clear(); - for (NodeIt n(_gr); n != INVALID; ++n) { - _comp_nodes[0].push_back(n); - _out_arcs[n].clear(); - for (OutArcIt a(_gr, n); a != INVALID; ++a) { - _out_arcs[n].push_back(a); - } - } - } else { - for (int i = 0; i < _comp_num; ++i) - _comp_nodes[i].clear(); - for (NodeIt n(_gr); n != INVALID; ++n) { - int k = _comp[n]; - _comp_nodes[k].push_back(n); - _out_arcs[n].clear(); - for (OutArcIt a(_gr, n); a != INVALID; ++a) { - if (_comp[_gr.target(a)] == k) _out_arcs[n].push_back(a); - } - } - } - } - - // Initialize path data for the current component - bool initComponent(int comp) { - _nodes = &(_comp_nodes[comp]); - int n = _nodes->size(); - if (n < 1 || (n == 1 && _out_arcs[(*_nodes)[0]].size() == 0)) { - return false; - } - for (int i = 0; i < n; ++i) { - _data[(*_nodes)[i]].resize(n + 1, PathData(INF)); - } - return true; - } - - // Process all rounds of computing path data for the current component. - // _data[v][k] is the length of a shortest directed walk from the root - // node to node v containing exactly k arcs. - void processRounds() { - Node start = (*_nodes)[0]; - _data[start][0] = PathData(0); - _process.clear(); - _process.push_back(start); - - int k, n = _nodes->size(); - int next_check = 4; - bool terminate = false; - for (k = 1; k <= n && int(_process.size()) < n && !terminate; ++k) { - processNextBuildRound(k); - if (k == next_check || k == n) { - terminate = checkTermination(k); - next_check = next_check * 3 / 2; - } - } - for ( ; k <= n && !terminate; ++k) { - processNextFullRound(k); - if (k == next_check || k == n) { - terminate = checkTermination(k); - next_check = next_check * 3 / 2; - } - } - } - - // Process one round and rebuild _process - void processNextBuildRound(int k) { - std::vector next; - Node u, v; - Arc e; - LargeValue d; - for (int i = 0; i < int(_process.size()); ++i) { - u = _process[i]; - for (int j = 0; j < int(_out_arcs[u].size()); ++j) { - e = _out_arcs[u][j]; - v = _gr.target(e); - d = _data[u][k-1].dist + _length[e]; - if (_tolerance.less(d, _data[v][k].dist)) { - if (_data[v][k].dist == INF) next.push_back(v); - _data[v][k] = PathData(d, e); - } - } - } - _process.swap(next); - } - - // Process one round using _nodes instead of _process - void processNextFullRound(int k) { - Node u, v; - Arc e; - LargeValue d; - for (int i = 0; i < int(_nodes->size()); ++i) { - u = (*_nodes)[i]; - for (int j = 0; j < int(_out_arcs[u].size()); ++j) { - e = _out_arcs[u][j]; - v = _gr.target(e); - d = _data[u][k-1].dist + _length[e]; - if (_tolerance.less(d, _data[v][k].dist)) { - _data[v][k] = PathData(d, e); - } - } - } - } - - // Check early termination - bool checkTermination(int k) { - typedef std::pair Pair; - typename GR::template NodeMap level(_gr, Pair(-1, 0)); - typename GR::template NodeMap pi(_gr); - int n = _nodes->size(); - LargeValue length; - int size; - Node u; - - // Search for cycles that are already found - _curr_found = false; - for (int i = 0; i < n; ++i) { - u = (*_nodes)[i]; - if (_data[u][k].dist == INF) continue; - for (int j = k; j >= 0; --j) { - if (level[u].first == i && level[u].second > 0) { - // A cycle is found - length = _data[u][level[u].second].dist - _data[u][j].dist; - size = level[u].second - j; - if (!_curr_found || length * _curr_size < _curr_length * size) { - _curr_length = length; - _curr_size = size; - _curr_node = u; - _curr_level = level[u].second; - _curr_found = true; - } - } - level[u] = Pair(i, j); - if (j != 0) { - u = _gr.source(_data[u][j].pred); - } - } - } - - // If at least one cycle is found, check the optimality condition - LargeValue d; - if (_curr_found && k < n) { - // Find node potentials - for (int i = 0; i < n; ++i) { - u = (*_nodes)[i]; - pi[u] = INF; - for (int j = 0; j <= k; ++j) { - if (_data[u][j].dist < INF) { - d = _data[u][j].dist * _curr_size - j * _curr_length; - if (_tolerance.less(d, pi[u])) pi[u] = d; - } - } - } - - // Check the optimality condition for all arcs - bool done = true; - for (ArcIt a(_gr); a != INVALID; ++a) { - if (_tolerance.less(_length[a] * _curr_size - _curr_length, - pi[_gr.target(a)] - pi[_gr.source(a)]) ) { - done = false; - break; - } - } - return done; - } - return (k == n); - } - - }; //class HartmannOrlin - - ///@} - -} //namespace lemon - -#endif //LEMON_HARTMANN_ORLIN_H diff -r a93f1a27d831 -r d3ea191c3412 lemon/hartmann_orlin_mmc.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lemon/hartmann_orlin_mmc.h Sat Mar 13 22:01:38 2010 +0100 @@ -0,0 +1,650 @@ +/* -*- C++ -*- + * + * This file is a part of LEMON, a generic C++ optimization library + * + * Copyright (C) 2003-2008 + * 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_HARTMANN_ORLIN_MMC_H +#define LEMON_HARTMANN_ORLIN_MMC_H + +/// \ingroup min_mean_cycle +/// +/// \file +/// \brief Hartmann-Orlin's algorithm for finding a minimum mean cycle. + +#include +#include +#include +#include +#include +#include + +namespace lemon { + + /// \brief Default traits class of HartmannOrlinMmc class. + /// + /// Default traits class of HartmannOrlinMmc class. + /// \tparam GR The type of the digraph. + /// \tparam CM The type of the cost map. + /// It must conform to the \ref concepts::Rea_data "Rea_data" concept. +#ifdef DOXYGEN + template +#else + template ::is_integer> +#endif + struct HartmannOrlinMmcDefaultTraits + { + /// The type of the digraph + typedef GR Digraph; + /// The type of the cost map + typedef CM CostMap; + /// The type of the arc costs + typedef typename CostMap::Value Cost; + + /// \brief The large cost type used for internal computations + /// + /// The large cost type used for internal computations. + /// It is \c long \c long if the \c Cost type is integer, + /// otherwise it is \c double. + /// \c Cost must be convertible to \c LargeCost. + typedef double LargeCost; + + /// The tolerance type used for internal computations + typedef lemon::Tolerance Tolerance; + + /// \brief The path type of the found cycles + /// + /// The path type of the found cycles. + /// It must conform to the \ref lemon::concepts::Path "Path" concept + /// and it must have an \c addFront() function. + typedef lemon::Path Path; + }; + + // Default traits class for integer cost types + template + struct HartmannOrlinMmcDefaultTraits + { + typedef GR Digraph; + typedef CM CostMap; + typedef typename CostMap::Value Cost; +#ifdef LEMON_HAVE_LONG_LONG + typedef long long LargeCost; +#else + typedef long LargeCost; +#endif + typedef lemon::Tolerance Tolerance; + typedef lemon::Path Path; + }; + + + /// \addtogroup min_mean_cycle + /// @{ + + /// \brief Implementation of the Hartmann-Orlin algorithm for finding + /// a minimum mean cycle. + /// + /// This class implements the Hartmann-Orlin algorithm for finding + /// a directed cycle of minimum mean cost in a digraph + /// \ref amo93networkflows, \ref dasdan98minmeancycle. + /// It is an improved version of \ref Karp "Karp"'s original algorithm, + /// it applies an efficient early termination scheme. + /// It runs in time O(ne) and uses space O(n2+e). + /// + /// \tparam GR The type of the digraph the algorithm runs on. + /// \tparam CM The type of the cost map. The default + /// map type is \ref concepts::Digraph::ArcMap "GR::ArcMap". + /// \tparam TR The traits class that defines various types used by the + /// algorithm. By default, it is \ref HartmannOrlinMmcDefaultTraits + /// "HartmannOrlinMmcDefaultTraits". + /// In most cases, this parameter should not be set directly, + /// consider to use the named template parameters instead. +#ifdef DOXYGEN + template +#else + template < typename GR, + typename CM = typename GR::template ArcMap, + typename TR = HartmannOrlinMmcDefaultTraits > +#endif + class HartmannOrlinMmc + { + public: + + /// The type of the digraph + typedef typename TR::Digraph Digraph; + /// The type of the cost map + typedef typename TR::CostMap CostMap; + /// The type of the arc costs + typedef typename TR::Cost Cost; + + /// \brief The large cost type + /// + /// The large cost type used for internal computations. + /// By default, it is \c long \c long if the \c Cost type is integer, + /// otherwise it is \c double. + typedef typename TR::LargeCost LargeCost; + + /// The tolerance type + typedef typename TR::Tolerance Tolerance; + + /// \brief The path type of the found cycles + /// + /// The path type of the found cycles. + /// Using the \ref HartmannOrlinMmcDefaultTraits "default traits class", + /// it is \ref lemon::Path "Path". + typedef typename TR::Path Path; + + /// The \ref HartmannOrlinMmcDefaultTraits "traits class" of the algorithm + typedef TR Traits; + + private: + + TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); + + // Data sturcture for path data + struct PathData + { + LargeCost dist; + Arc pred; + PathData(LargeCost d, Arc p = INVALID) : + dist(d), pred(p) {} + }; + + typedef typename Digraph::template NodeMap > + PathDataNodeMap; + + private: + + // The digraph the algorithm runs on + const Digraph &_gr; + // The cost of the arcs + const CostMap &_cost; + + // Data for storing the strongly connected components + int _comp_num; + typename Digraph::template NodeMap _comp; + std::vector > _comp_nodes; + std::vector* _nodes; + typename Digraph::template NodeMap > _out_arcs; + + // Data for the found cycles + bool _curr_found, _best_found; + LargeCost _curr_cost, _best_cost; + int _curr_size, _best_size; + Node _curr_node, _best_node; + int _curr_level, _best_level; + + Path *_cycle_path; + bool _local_path; + + // Node map for storing path data + PathDataNodeMap _data; + // The processed nodes in the last round + std::vector _process; + + Tolerance _tolerance; + + // Infinite constant + const LargeCost INF; + + public: + + /// \name Named Template Parameters + /// @{ + + template + struct SetLargeCostTraits : public Traits { + typedef T LargeCost; + typedef lemon::Tolerance Tolerance; + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// \c LargeCost type. + /// + /// \ref named-templ-param "Named parameter" for setting \c LargeCost + /// type. It is used for internal computations in the algorithm. + template + struct SetLargeCost + : public HartmannOrlinMmc > { + typedef HartmannOrlinMmc > Create; + }; + + template + struct SetPathTraits : public Traits { + typedef T Path; + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// \c %Path type. + /// + /// \ref named-templ-param "Named parameter" for setting the \c %Path + /// type of the found cycles. + /// It must conform to the \ref lemon::concepts::Path "Path" concept + /// and it must have an \c addFront() function. + template + struct SetPath + : public HartmannOrlinMmc > { + typedef HartmannOrlinMmc > Create; + }; + + /// @} + + protected: + + HartmannOrlinMmc() {} + + public: + + /// \brief Constructor. + /// + /// The constructor of the class. + /// + /// \param digraph The digraph the algorithm runs on. + /// \param cost The costs of the arcs. + HartmannOrlinMmc( const Digraph &digraph, + const CostMap &cost ) : + _gr(digraph), _cost(cost), _comp(digraph), _out_arcs(digraph), + _best_found(false), _best_cost(0), _best_size(1), + _cycle_path(NULL), _local_path(false), _data(digraph), + INF(std::numeric_limits::has_infinity ? + std::numeric_limits::infinity() : + std::numeric_limits::max()) + {} + + /// Destructor. + ~HartmannOrlinMmc() { + if (_local_path) delete _cycle_path; + } + + /// \brief Set the path structure for storing the found cycle. + /// + /// This function sets an external path structure for storing the + /// found cycle. + /// + /// If you don't call this function before calling \ref run() or + /// \ref findCycleMean(), it will allocate a local \ref Path "path" + /// structure. The destuctor deallocates this automatically + /// allocated object, of course. + /// + /// \note The algorithm calls only the \ref lemon::Path::addFront() + /// "addFront()" function of the given path structure. + /// + /// \return (*this) + HartmannOrlinMmc& cycle(Path &path) { + if (_local_path) { + delete _cycle_path; + _local_path = false; + } + _cycle_path = &path; + return *this; + } + + /// \brief Set the tolerance used by the algorithm. + /// + /// This function sets the tolerance object used by the algorithm. + /// + /// \return (*this) + HartmannOrlinMmc& tolerance(const Tolerance& tolerance) { + _tolerance = tolerance; + return *this; + } + + /// \brief Return a const reference to the tolerance. + /// + /// This function returns a const reference to the tolerance object + /// used by the algorithm. + const Tolerance& tolerance() const { + return _tolerance; + } + + /// \name Execution control + /// The simplest way to execute the algorithm is to call the \ref run() + /// function.\n + /// If you only need the minimum mean cost, you may call + /// \ref findCycleMean(). + + /// @{ + + /// \brief Run the algorithm. + /// + /// This function runs the algorithm. + /// It can be called more than once (e.g. if the underlying digraph + /// and/or the arc costs have been modified). + /// + /// \return \c true if a directed cycle exists in the digraph. + /// + /// \note mmc.run() is just a shortcut of the following code. + /// \code + /// return mmc.findCycleMean() && mmc.findCycle(); + /// \endcode + bool run() { + return findCycleMean() && findCycle(); + } + + /// \brief Find the minimum cycle mean. + /// + /// This function finds the minimum mean cost of the directed + /// cycles in the digraph. + /// + /// \return \c true if a directed cycle exists in the digraph. + bool findCycleMean() { + // Initialization and find strongly connected components + init(); + findComponents(); + + // Find the minimum cycle mean in the components + for (int comp = 0; comp < _comp_num; ++comp) { + if (!initComponent(comp)) continue; + processRounds(); + + // Update the best cycle (global minimum mean cycle) + if ( _curr_found && (!_best_found || + _curr_cost * _best_size < _best_cost * _curr_size) ) { + _best_found = true; + _best_cost = _curr_cost; + _best_size = _curr_size; + _best_node = _curr_node; + _best_level = _curr_level; + } + } + return _best_found; + } + + /// \brief Find a minimum mean directed cycle. + /// + /// This function finds a directed cycle of minimum mean cost + /// in the digraph using the data computed by findCycleMean(). + /// + /// \return \c true if a directed cycle exists in the digraph. + /// + /// \pre \ref findCycleMean() must be called before using this function. + bool findCycle() { + if (!_best_found) return false; + IntNodeMap reached(_gr, -1); + int r = _best_level + 1; + Node u = _best_node; + while (reached[u] < 0) { + reached[u] = --r; + u = _gr.source(_data[u][r].pred); + } + r = reached[u]; + Arc e = _data[u][r].pred; + _cycle_path->addFront(e); + _best_cost = _cost[e]; + _best_size = 1; + Node v; + while ((v = _gr.source(e)) != u) { + e = _data[v][--r].pred; + _cycle_path->addFront(e); + _best_cost += _cost[e]; + ++_best_size; + } + return true; + } + + /// @} + + /// \name Query Functions + /// The results of the algorithm can be obtained using these + /// functions.\n + /// The algorithm should be executed before using them. + + /// @{ + + /// \brief Return the total cost of the found cycle. + /// + /// This function returns the total cost of the found cycle. + /// + /// \pre \ref run() or \ref findCycleMean() must be called before + /// using this function. + Cost cycleCost() const { + return static_cast(_best_cost); + } + + /// \brief Return the number of arcs on the found cycle. + /// + /// This function returns the number of arcs on the found cycle. + /// + /// \pre \ref run() or \ref findCycleMean() must be called before + /// using this function. + int cycleSize() const { + return _best_size; + } + + /// \brief Return the mean cost of the found cycle. + /// + /// This function returns the mean cost of the found cycle. + /// + /// \note alg.cycleMean() is just a shortcut of the + /// following code. + /// \code + /// return static_cast(alg.cycleCost()) / alg.cycleSize(); + /// \endcode + /// + /// \pre \ref run() or \ref findCycleMean() must be called before + /// using this function. + double cycleMean() const { + return static_cast(_best_cost) / _best_size; + } + + /// \brief Return the found cycle. + /// + /// This function returns a const reference to the path structure + /// storing the found cycle. + /// + /// \pre \ref run() or \ref findCycle() must be called before using + /// this function. + const Path& cycle() const { + return *_cycle_path; + } + + ///@} + + private: + + // Initialization + void init() { + if (!_cycle_path) { + _local_path = true; + _cycle_path = new Path; + } + _cycle_path->clear(); + _best_found = false; + _best_cost = 0; + _best_size = 1; + _cycle_path->clear(); + for (NodeIt u(_gr); u != INVALID; ++u) + _data[u].clear(); + } + + // Find strongly connected components and initialize _comp_nodes + // and _out_arcs + void findComponents() { + _comp_num = stronglyConnectedComponents(_gr, _comp); + _comp_nodes.resize(_comp_num); + if (_comp_num == 1) { + _comp_nodes[0].clear(); + for (NodeIt n(_gr); n != INVALID; ++n) { + _comp_nodes[0].push_back(n); + _out_arcs[n].clear(); + for (OutArcIt a(_gr, n); a != INVALID; ++a) { + _out_arcs[n].push_back(a); + } + } + } else { + for (int i = 0; i < _comp_num; ++i) + _comp_nodes[i].clear(); + for (NodeIt n(_gr); n != INVALID; ++n) { + int k = _comp[n]; + _comp_nodes[k].push_back(n); + _out_arcs[n].clear(); + for (OutArcIt a(_gr, n); a != INVALID; ++a) { + if (_comp[_gr.target(a)] == k) _out_arcs[n].push_back(a); + } + } + } + } + + // Initialize path data for the current component + bool initComponent(int comp) { + _nodes = &(_comp_nodes[comp]); + int n = _nodes->size(); + if (n < 1 || (n == 1 && _out_arcs[(*_nodes)[0]].size() == 0)) { + return false; + } + for (int i = 0; i < n; ++i) { + _data[(*_nodes)[i]].resize(n + 1, PathData(INF)); + } + return true; + } + + // Process all rounds of computing path data for the current component. + // _data[v][k] is the cost of a shortest directed walk from the root + // node to node v containing exactly k arcs. + void processRounds() { + Node start = (*_nodes)[0]; + _data[start][0] = PathData(0); + _process.clear(); + _process.push_back(start); + + int k, n = _nodes->size(); + int next_check = 4; + bool terminate = false; + for (k = 1; k <= n && int(_process.size()) < n && !terminate; ++k) { + processNextBuildRound(k); + if (k == next_check || k == n) { + terminate = checkTermination(k); + next_check = next_check * 3 / 2; + } + } + for ( ; k <= n && !terminate; ++k) { + processNextFullRound(k); + if (k == next_check || k == n) { + terminate = checkTermination(k); + next_check = next_check * 3 / 2; + } + } + } + + // Process one round and rebuild _process + void processNextBuildRound(int k) { + std::vector next; + Node u, v; + Arc e; + LargeCost d; + for (int i = 0; i < int(_process.size()); ++i) { + u = _process[i]; + for (int j = 0; j < int(_out_arcs[u].size()); ++j) { + e = _out_arcs[u][j]; + v = _gr.target(e); + d = _data[u][k-1].dist + _cost[e]; + if (_tolerance.less(d, _data[v][k].dist)) { + if (_data[v][k].dist == INF) next.push_back(v); + _data[v][k] = PathData(d, e); + } + } + } + _process.swap(next); + } + + // Process one round using _nodes instead of _process + void processNextFullRound(int k) { + Node u, v; + Arc e; + LargeCost d; + for (int i = 0; i < int(_nodes->size()); ++i) { + u = (*_nodes)[i]; + for (int j = 0; j < int(_out_arcs[u].size()); ++j) { + e = _out_arcs[u][j]; + v = _gr.target(e); + d = _data[u][k-1].dist + _cost[e]; + if (_tolerance.less(d, _data[v][k].dist)) { + _data[v][k] = PathData(d, e); + } + } + } + } + + // Check early termination + bool checkTermination(int k) { + typedef std::pair Pair; + typename GR::template NodeMap level(_gr, Pair(-1, 0)); + typename GR::template NodeMap pi(_gr); + int n = _nodes->size(); + LargeCost cost; + int size; + Node u; + + // Search for cycles that are already found + _curr_found = false; + for (int i = 0; i < n; ++i) { + u = (*_nodes)[i]; + if (_data[u][k].dist == INF) continue; + for (int j = k; j >= 0; --j) { + if (level[u].first == i && level[u].second > 0) { + // A cycle is found + cost = _data[u][level[u].second].dist - _data[u][j].dist; + size = level[u].second - j; + if (!_curr_found || cost * _curr_size < _curr_cost * size) { + _curr_cost = cost; + _curr_size = size; + _curr_node = u; + _curr_level = level[u].second; + _curr_found = true; + } + } + level[u] = Pair(i, j); + if (j != 0) { + u = _gr.source(_data[u][j].pred); + } + } + } + + // If at least one cycle is found, check the optimality condition + LargeCost d; + if (_curr_found && k < n) { + // Find node potentials + for (int i = 0; i < n; ++i) { + u = (*_nodes)[i]; + pi[u] = INF; + for (int j = 0; j <= k; ++j) { + if (_data[u][j].dist < INF) { + d = _data[u][j].dist * _curr_size - j * _curr_cost; + if (_tolerance.less(d, pi[u])) pi[u] = d; + } + } + } + + // Check the optimality condition for all arcs + bool done = true; + for (ArcIt a(_gr); a != INVALID; ++a) { + if (_tolerance.less(_cost[a] * _curr_size - _curr_cost, + pi[_gr.target(a)] - pi[_gr.source(a)]) ) { + done = false; + break; + } + } + return done; + } + return (k == n); + } + + }; //class HartmannOrlinMmc + + ///@} + +} //namespace lemon + +#endif //LEMON_HARTMANN_ORLIN_MMC_H diff -r a93f1a27d831 -r d3ea191c3412 lemon/howard.h --- a/lemon/howard.h Mon Mar 08 08:33:41 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,605 +0,0 @@ -/* -*- C++ -*- - * - * This file is a part of LEMON, a generic C++ optimization library - * - * Copyright (C) 2003-2008 - * 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_HOWARD_H -#define LEMON_HOWARD_H - -/// \ingroup min_mean_cycle -/// -/// \file -/// \brief Howard's algorithm for finding a minimum mean cycle. - -#include -#include -#include -#include -#include -#include - -namespace lemon { - - /// \brief Default traits class of Howard class. - /// - /// Default traits class of Howard class. - /// \tparam GR The type of the digraph. - /// \tparam LEN The type of the length map. - /// It must conform to the \ref concepts::ReadMap "ReadMap" concept. -#ifdef DOXYGEN - template -#else - template ::is_integer> -#endif - struct HowardDefaultTraits - { - /// The type of the digraph - typedef GR Digraph; - /// The type of the length map - typedef LEN LengthMap; - /// The type of the arc lengths - typedef typename LengthMap::Value Value; - - /// \brief The large value type used for internal computations - /// - /// The large value type used for internal computations. - /// It is \c long \c long if the \c Value type is integer, - /// otherwise it is \c double. - /// \c Value must be convertible to \c LargeValue. - typedef double LargeValue; - - /// The tolerance type used for internal computations - typedef lemon::Tolerance Tolerance; - - /// \brief The path type of the found cycles - /// - /// The path type of the found cycles. - /// It must conform to the \ref lemon::concepts::Path "Path" concept - /// and it must have an \c addBack() function. - typedef lemon::Path Path; - }; - - // Default traits class for integer value types - template - struct HowardDefaultTraits - { - typedef GR Digraph; - typedef LEN LengthMap; - typedef typename LengthMap::Value Value; -#ifdef LEMON_HAVE_LONG_LONG - typedef long long LargeValue; -#else - typedef long LargeValue; -#endif - typedef lemon::Tolerance Tolerance; - typedef lemon::Path Path; - }; - - - /// \addtogroup min_mean_cycle - /// @{ - - /// \brief Implementation of Howard's algorithm for finding a minimum - /// mean cycle. - /// - /// This class implements Howard's policy iteration algorithm for finding - /// a directed cycle of minimum mean length (cost) in a digraph - /// \ref amo93networkflows, \ref dasdan98minmeancycle. - /// This class provides the most efficient algorithm for the - /// minimum mean cycle problem, though the best known theoretical - /// bound on its running time is exponential. - /// - /// \tparam GR The type of the digraph the algorithm runs on. - /// \tparam LEN The type of the length map. The default - /// map type is \ref concepts::Digraph::ArcMap "GR::ArcMap". - /// \tparam TR The traits class that defines various types used by the - /// algorithm. By default, it is \ref HowardDefaultTraits - /// "HowardDefaultTraits". - /// In most cases, this parameter should not be set directly, - /// consider to use the named template parameters instead. -#ifdef DOXYGEN - template -#else - template < typename GR, - typename LEN = typename GR::template ArcMap, - typename TR = HowardDefaultTraits > -#endif - class Howard - { - public: - - /// The type of the digraph - typedef typename TR::Digraph Digraph; - /// The type of the length map - typedef typename TR::LengthMap LengthMap; - /// The type of the arc lengths - typedef typename TR::Value Value; - - /// \brief The large value type - /// - /// The large value type used for internal computations. - /// By default, it is \c long \c long if the \c Value type is integer, - /// otherwise it is \c double. - typedef typename TR::LargeValue LargeValue; - - /// The tolerance type - typedef typename TR::Tolerance Tolerance; - - /// \brief The path type of the found cycles - /// - /// The path type of the found cycles. - /// Using the \ref HowardDefaultTraits "default traits class", - /// it is \ref lemon::Path "Path". - typedef typename TR::Path Path; - - /// The \ref HowardDefaultTraits "traits class" of the algorithm - typedef TR Traits; - - private: - - TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); - - // The digraph the algorithm runs on - const Digraph &_gr; - // The length of the arcs - const LengthMap &_length; - - // Data for the found cycles - bool _curr_found, _best_found; - LargeValue _curr_length, _best_length; - int _curr_size, _best_size; - Node _curr_node, _best_node; - - Path *_cycle_path; - bool _local_path; - - // Internal data used by the algorithm - typename Digraph::template NodeMap _policy; - typename Digraph::template NodeMap _reached; - typename Digraph::template NodeMap _level; - typename Digraph::template NodeMap _dist; - - // Data for storing the strongly connected components - int _comp_num; - typename Digraph::template NodeMap _comp; - std::vector > _comp_nodes; - std::vector* _nodes; - typename Digraph::template NodeMap > _in_arcs; - - // Queue used for BFS search - std::vector _queue; - int _qfront, _qback; - - Tolerance _tolerance; - - // Infinite constant - const LargeValue INF; - - public: - - /// \name Named Template Parameters - /// @{ - - template - struct SetLargeValueTraits : public Traits { - typedef T LargeValue; - typedef lemon::Tolerance Tolerance; - }; - - /// \brief \ref named-templ-param "Named parameter" for setting - /// \c LargeValue type. - /// - /// \ref named-templ-param "Named parameter" for setting \c LargeValue - /// type. It is used for internal computations in the algorithm. - template - struct SetLargeValue - : public Howard > { - typedef Howard > Create; - }; - - template - struct SetPathTraits : public Traits { - typedef T Path; - }; - - /// \brief \ref named-templ-param "Named parameter" for setting - /// \c %Path type. - /// - /// \ref named-templ-param "Named parameter" for setting the \c %Path - /// type of the found cycles. - /// It must conform to the \ref lemon::concepts::Path "Path" concept - /// and it must have an \c addBack() function. - template - struct SetPath - : public Howard > { - typedef Howard > Create; - }; - - /// @} - - protected: - - Howard() {} - - public: - - /// \brief Constructor. - /// - /// The constructor of the class. - /// - /// \param digraph The digraph the algorithm runs on. - /// \param length The lengths (costs) of the arcs. - Howard( const Digraph &digraph, - const LengthMap &length ) : - _gr(digraph), _length(length), _best_found(false), - _best_length(0), _best_size(1), _cycle_path(NULL), _local_path(false), - _policy(digraph), _reached(digraph), _level(digraph), _dist(digraph), - _comp(digraph), _in_arcs(digraph), - INF(std::numeric_limits::has_infinity ? - std::numeric_limits::infinity() : - std::numeric_limits::max()) - {} - - /// Destructor. - ~Howard() { - if (_local_path) delete _cycle_path; - } - - /// \brief Set the path structure for storing the found cycle. - /// - /// This function sets an external path structure for storing the - /// found cycle. - /// - /// If you don't call this function before calling \ref run() or - /// \ref findMinMean(), it will allocate a local \ref Path "path" - /// structure. The destuctor deallocates this automatically - /// allocated object, of course. - /// - /// \note The algorithm calls only the \ref lemon::Path::addBack() - /// "addBack()" function of the given path structure. - /// - /// \return (*this) - Howard& cycle(Path &path) { - if (_local_path) { - delete _cycle_path; - _local_path = false; - } - _cycle_path = &path; - return *this; - } - - /// \brief Set the tolerance used by the algorithm. - /// - /// This function sets the tolerance object used by the algorithm. - /// - /// \return (*this) - Howard& tolerance(const Tolerance& tolerance) { - _tolerance = tolerance; - return *this; - } - - /// \brief Return a const reference to the tolerance. - /// - /// This function returns a const reference to the tolerance object - /// used by the algorithm. - const Tolerance& tolerance() const { - return _tolerance; - } - - /// \name Execution control - /// The simplest way to execute the algorithm is to call the \ref run() - /// function.\n - /// If you only need the minimum mean length, you may call - /// \ref findMinMean(). - - /// @{ - - /// \brief Run the algorithm. - /// - /// This function runs the algorithm. - /// It can be called more than once (e.g. if the underlying digraph - /// and/or the arc lengths have been modified). - /// - /// \return \c true if a directed cycle exists in the digraph. - /// - /// \note mmc.run() is just a shortcut of the following code. - /// \code - /// return mmc.findMinMean() && mmc.findCycle(); - /// \endcode - bool run() { - return findMinMean() && findCycle(); - } - - /// \brief Find the minimum cycle mean. - /// - /// This function finds the minimum mean length of the directed - /// cycles in the digraph. - /// - /// \return \c true if a directed cycle exists in the digraph. - bool findMinMean() { - // Initialize and find strongly connected components - init(); - findComponents(); - - // Find the minimum cycle mean in the components - for (int comp = 0; comp < _comp_num; ++comp) { - // Find the minimum mean cycle in the current component - if (!buildPolicyGraph(comp)) continue; - while (true) { - findPolicyCycle(); - if (!computeNodeDistances()) break; - } - // Update the best cycle (global minimum mean cycle) - if ( _curr_found && (!_best_found || - _curr_length * _best_size < _best_length * _curr_size) ) { - _best_found = true; - _best_length = _curr_length; - _best_size = _curr_size; - _best_node = _curr_node; - } - } - return _best_found; - } - - /// \brief Find a minimum mean directed cycle. - /// - /// This function finds a directed cycle of minimum mean length - /// in the digraph using the data computed by findMinMean(). - /// - /// \return \c true if a directed cycle exists in the digraph. - /// - /// \pre \ref findMinMean() must be called before using this function. - bool findCycle() { - if (!_best_found) return false; - _cycle_path->addBack(_policy[_best_node]); - for ( Node v = _best_node; - (v = _gr.target(_policy[v])) != _best_node; ) { - _cycle_path->addBack(_policy[v]); - } - return true; - } - - /// @} - - /// \name Query Functions - /// The results of the algorithm can be obtained using these - /// functions.\n - /// The algorithm should be executed before using them. - - /// @{ - - /// \brief Return the total length of the found cycle. - /// - /// This function returns the total length of the found cycle. - /// - /// \pre \ref run() or \ref findMinMean() must be called before - /// using this function. - Value cycleLength() const { - return static_cast(_best_length); - } - - /// \brief Return the number of arcs on the found cycle. - /// - /// This function returns the number of arcs on the found cycle. - /// - /// \pre \ref run() or \ref findMinMean() must be called before - /// using this function. - int cycleArcNum() const { - return _best_size; - } - - /// \brief Return the mean length of the found cycle. - /// - /// This function returns the mean length of the found cycle. - /// - /// \note alg.cycleMean() is just a shortcut of the - /// following code. - /// \code - /// return static_cast(alg.cycleLength()) / alg.cycleArcNum(); - /// \endcode - /// - /// \pre \ref run() or \ref findMinMean() must be called before - /// using this function. - double cycleMean() const { - return static_cast(_best_length) / _best_size; - } - - /// \brief Return the found cycle. - /// - /// This function returns a const reference to the path structure - /// storing the found cycle. - /// - /// \pre \ref run() or \ref findCycle() must be called before using - /// this function. - const Path& cycle() const { - return *_cycle_path; - } - - ///@} - - private: - - // Initialize - void init() { - if (!_cycle_path) { - _local_path = true; - _cycle_path = new Path; - } - _queue.resize(countNodes(_gr)); - _best_found = false; - _best_length = 0; - _best_size = 1; - _cycle_path->clear(); - } - - // Find strongly connected components and initialize _comp_nodes - // and _in_arcs - void findComponents() { - _comp_num = stronglyConnectedComponents(_gr, _comp); - _comp_nodes.resize(_comp_num); - if (_comp_num == 1) { - _comp_nodes[0].clear(); - for (NodeIt n(_gr); n != INVALID; ++n) { - _comp_nodes[0].push_back(n); - _in_arcs[n].clear(); - for (InArcIt a(_gr, n); a != INVALID; ++a) { - _in_arcs[n].push_back(a); - } - } - } else { - for (int i = 0; i < _comp_num; ++i) - _comp_nodes[i].clear(); - for (NodeIt n(_gr); n != INVALID; ++n) { - int k = _comp[n]; - _comp_nodes[k].push_back(n); - _in_arcs[n].clear(); - for (InArcIt a(_gr, n); a != INVALID; ++a) { - if (_comp[_gr.source(a)] == k) _in_arcs[n].push_back(a); - } - } - } - } - - // Build the policy graph in the given strongly connected component - // (the out-degree of every node is 1) - bool buildPolicyGraph(int comp) { - _nodes = &(_comp_nodes[comp]); - if (_nodes->size() < 1 || - (_nodes->size() == 1 && _in_arcs[(*_nodes)[0]].size() == 0)) { - return false; - } - for (int i = 0; i < int(_nodes->size()); ++i) { - _dist[(*_nodes)[i]] = INF; - } - Node u, v; - Arc e; - for (int i = 0; i < int(_nodes->size()); ++i) { - v = (*_nodes)[i]; - for (int j = 0; j < int(_in_arcs[v].size()); ++j) { - e = _in_arcs[v][j]; - u = _gr.source(e); - if (_length[e] < _dist[u]) { - _dist[u] = _length[e]; - _policy[u] = e; - } - } - } - return true; - } - - // Find the minimum mean cycle in the policy graph - void findPolicyCycle() { - for (int i = 0; i < int(_nodes->size()); ++i) { - _level[(*_nodes)[i]] = -1; - } - LargeValue clength; - int csize; - Node u, v; - _curr_found = false; - for (int i = 0; i < int(_nodes->size()); ++i) { - u = (*_nodes)[i]; - if (_level[u] >= 0) continue; - for (; _level[u] < 0; u = _gr.target(_policy[u])) { - _level[u] = i; - } - if (_level[u] == i) { - // A cycle is found - clength = _length[_policy[u]]; - csize = 1; - for (v = u; (v = _gr.target(_policy[v])) != u; ) { - clength += _length[_policy[v]]; - ++csize; - } - if ( !_curr_found || - (clength * _curr_size < _curr_length * csize) ) { - _curr_found = true; - _curr_length = clength; - _curr_size = csize; - _curr_node = u; - } - } - } - } - - // Contract the policy graph and compute node distances - bool computeNodeDistances() { - // Find the component of the main cycle and compute node distances - // using reverse BFS - for (int i = 0; i < int(_nodes->size()); ++i) { - _reached[(*_nodes)[i]] = false; - } - _qfront = _qback = 0; - _queue[0] = _curr_node; - _reached[_curr_node] = true; - _dist[_curr_node] = 0; - Node u, v; - Arc e; - while (_qfront <= _qback) { - v = _queue[_qfront++]; - for (int j = 0; j < int(_in_arcs[v].size()); ++j) { - e = _in_arcs[v][j]; - u = _gr.source(e); - if (_policy[u] == e && !_reached[u]) { - _reached[u] = true; - _dist[u] = _dist[v] + _length[e] * _curr_size - _curr_length; - _queue[++_qback] = u; - } - } - } - - // Connect all other nodes to this component and compute node - // distances using reverse BFS - _qfront = 0; - while (_qback < int(_nodes->size())-1) { - v = _queue[_qfront++]; - for (int j = 0; j < int(_in_arcs[v].size()); ++j) { - e = _in_arcs[v][j]; - u = _gr.source(e); - if (!_reached[u]) { - _reached[u] = true; - _policy[u] = e; - _dist[u] = _dist[v] + _length[e] * _curr_size - _curr_length; - _queue[++_qback] = u; - } - } - } - - // Improve node distances - bool improved = false; - for (int i = 0; i < int(_nodes->size()); ++i) { - v = (*_nodes)[i]; - for (int j = 0; j < int(_in_arcs[v].size()); ++j) { - e = _in_arcs[v][j]; - u = _gr.source(e); - LargeValue delta = _dist[v] + _length[e] * _curr_size - _curr_length; - if (_tolerance.less(delta, _dist[u])) { - _dist[u] = delta; - _policy[u] = e; - improved = true; - } - } - } - return improved; - } - - }; //class Howard - - ///@} - -} //namespace lemon - -#endif //LEMON_HOWARD_H diff -r a93f1a27d831 -r d3ea191c3412 lemon/howard_mmc.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lemon/howard_mmc.h Sat Mar 13 22:01:38 2010 +0100 @@ -0,0 +1,605 @@ +/* -*- C++ -*- + * + * This file is a part of LEMON, a generic C++ optimization library + * + * Copyright (C) 2003-2008 + * 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_HOWARD_MMC_H +#define LEMON_HOWARD_MMC_H + +/// \ingroup min_mean_cycle +/// +/// \file +/// \brief Howard's algorithm for finding a minimum mean cycle. + +#include +#include +#include +#include +#include +#include + +namespace lemon { + + /// \brief Default traits class of HowardMmc class. + /// + /// Default traits class of HowardMmc class. + /// \tparam GR The type of the digraph. + /// \tparam CM The type of the cost map. + /// It must conform to the \ref concepts::ReadMap "ReadMap" concept. +#ifdef DOXYGEN + template +#else + template ::is_integer> +#endif + struct HowardMmcDefaultTraits + { + /// The type of the digraph + typedef GR Digraph; + /// The type of the cost map + typedef CM CostMap; + /// The type of the arc costs + typedef typename CostMap::Value Cost; + + /// \brief The large cost type used for internal computations + /// + /// The large cost type used for internal computations. + /// It is \c long \c long if the \c Cost type is integer, + /// otherwise it is \c double. + /// \c Cost must be convertible to \c LargeCost. + typedef double LargeCost; + + /// The tolerance type used for internal computations + typedef lemon::Tolerance Tolerance; + + /// \brief The path type of the found cycles + /// + /// The path type of the found cycles. + /// It must conform to the \ref lemon::concepts::Path "Path" concept + /// and it must have an \c addBack() function. + typedef lemon::Path Path; + }; + + // Default traits class for integer cost types + template + struct HowardMmcDefaultTraits + { + typedef GR Digraph; + typedef CM CostMap; + typedef typename CostMap::Value Cost; +#ifdef LEMON_HAVE_LONG_LONG + typedef long long LargeCost; +#else + typedef long LargeCost; +#endif + typedef lemon::Tolerance Tolerance; + typedef lemon::Path Path; + }; + + + /// \addtogroup min_mean_cycle + /// @{ + + /// \brief Implementation of Howard's algorithm for finding a minimum + /// mean cycle. + /// + /// This class implements Howard's policy iteration algorithm for finding + /// a directed cycle of minimum mean cost in a digraph + /// \ref amo93networkflows, \ref dasdan98minmeancycle. + /// This class provides the most efficient algorithm for the + /// minimum mean cycle problem, though the best known theoretical + /// bound on its running time is exponential. + /// + /// \tparam GR The type of the digraph the algorithm runs on. + /// \tparam CM The type of the cost map. The default + /// map type is \ref concepts::Digraph::ArcMap "GR::ArcMap". + /// \tparam TR The traits class that defines various types used by the + /// algorithm. By default, it is \ref HowardMmcDefaultTraits + /// "HowardMmcDefaultTraits". + /// In most cases, this parameter should not be set directly, + /// consider to use the named template parameters instead. +#ifdef DOXYGEN + template +#else + template < typename GR, + typename CM = typename GR::template ArcMap, + typename TR = HowardMmcDefaultTraits > +#endif + class HowardMmc + { + public: + + /// The type of the digraph + typedef typename TR::Digraph Digraph; + /// The type of the cost map + typedef typename TR::CostMap CostMap; + /// The type of the arc costs + typedef typename TR::Cost Cost; + + /// \brief The large cost type + /// + /// The large cost type used for internal computations. + /// By default, it is \c long \c long if the \c Cost type is integer, + /// otherwise it is \c double. + typedef typename TR::LargeCost LargeCost; + + /// The tolerance type + typedef typename TR::Tolerance Tolerance; + + /// \brief The path type of the found cycles + /// + /// The path type of the found cycles. + /// Using the \ref HowardMmcDefaultTraits "default traits class", + /// it is \ref lemon::Path "Path". + typedef typename TR::Path Path; + + /// The \ref HowardMmcDefaultTraits "traits class" of the algorithm + typedef TR Traits; + + private: + + TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); + + // The digraph the algorithm runs on + const Digraph &_gr; + // The cost of the arcs + const CostMap &_cost; + + // Data for the found cycles + bool _curr_found, _best_found; + LargeCost _curr_cost, _best_cost; + int _curr_size, _best_size; + Node _curr_node, _best_node; + + Path *_cycle_path; + bool _local_path; + + // Internal data used by the algorithm + typename Digraph::template NodeMap _policy; + typename Digraph::template NodeMap _reached; + typename Digraph::template NodeMap _level; + typename Digraph::template NodeMap _dist; + + // Data for storing the strongly connected components + int _comp_num; + typename Digraph::template NodeMap _comp; + std::vector > _comp_nodes; + std::vector* _nodes; + typename Digraph::template NodeMap > _in_arcs; + + // Queue used for BFS search + std::vector _queue; + int _qfront, _qback; + + Tolerance _tolerance; + + // Infinite constant + const LargeCost INF; + + public: + + /// \name Named Template Parameters + /// @{ + + template + struct SetLargeCostTraits : public Traits { + typedef T LargeCost; + typedef lemon::Tolerance Tolerance; + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// \c LargeCost type. + /// + /// \ref named-templ-param "Named parameter" for setting \c LargeCost + /// type. It is used for internal computations in the algorithm. + template + struct SetLargeCost + : public HowardMmc > { + typedef HowardMmc > Create; + }; + + template + struct SetPathTraits : public Traits { + typedef T Path; + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// \c %Path type. + /// + /// \ref named-templ-param "Named parameter" for setting the \c %Path + /// type of the found cycles. + /// It must conform to the \ref lemon::concepts::Path "Path" concept + /// and it must have an \c addBack() function. + template + struct SetPath + : public HowardMmc > { + typedef HowardMmc > Create; + }; + + /// @} + + protected: + + HowardMmc() {} + + public: + + /// \brief Constructor. + /// + /// The constructor of the class. + /// + /// \param digraph The digraph the algorithm runs on. + /// \param cost The costs of the arcs. + HowardMmc( const Digraph &digraph, + const CostMap &cost ) : + _gr(digraph), _cost(cost), _best_found(false), + _best_cost(0), _best_size(1), _cycle_path(NULL), _local_path(false), + _policy(digraph), _reached(digraph), _level(digraph), _dist(digraph), + _comp(digraph), _in_arcs(digraph), + INF(std::numeric_limits::has_infinity ? + std::numeric_limits::infinity() : + std::numeric_limits::max()) + {} + + /// Destructor. + ~HowardMmc() { + if (_local_path) delete _cycle_path; + } + + /// \brief Set the path structure for storing the found cycle. + /// + /// This function sets an external path structure for storing the + /// found cycle. + /// + /// If you don't call this function before calling \ref run() or + /// \ref findCycleMean(), it will allocate a local \ref Path "path" + /// structure. The destuctor deallocates this automatically + /// allocated object, of course. + /// + /// \note The algorithm calls only the \ref lemon::Path::addBack() + /// "addBack()" function of the given path structure. + /// + /// \return (*this) + HowardMmc& cycle(Path &path) { + if (_local_path) { + delete _cycle_path; + _local_path = false; + } + _cycle_path = &path; + return *this; + } + + /// \brief Set the tolerance used by the algorithm. + /// + /// This function sets the tolerance object used by the algorithm. + /// + /// \return (*this) + HowardMmc& tolerance(const Tolerance& tolerance) { + _tolerance = tolerance; + return *this; + } + + /// \brief Return a const reference to the tolerance. + /// + /// This function returns a const reference to the tolerance object + /// used by the algorithm. + const Tolerance& tolerance() const { + return _tolerance; + } + + /// \name Execution control + /// The simplest way to execute the algorithm is to call the \ref run() + /// function.\n + /// If you only need the minimum mean cost, you may call + /// \ref findCycleMean(). + + /// @{ + + /// \brief Run the algorithm. + /// + /// This function runs the algorithm. + /// It can be called more than once (e.g. if the underlying digraph + /// and/or the arc costs have been modified). + /// + /// \return \c true if a directed cycle exists in the digraph. + /// + /// \note mmc.run() is just a shortcut of the following code. + /// \code + /// return mmc.findCycleMean() && mmc.findCycle(); + /// \endcode + bool run() { + return findCycleMean() && findCycle(); + } + + /// \brief Find the minimum cycle mean. + /// + /// This function finds the minimum mean cost of the directed + /// cycles in the digraph. + /// + /// \return \c true if a directed cycle exists in the digraph. + bool findCycleMean() { + // Initialize and find strongly connected components + init(); + findComponents(); + + // Find the minimum cycle mean in the components + for (int comp = 0; comp < _comp_num; ++comp) { + // Find the minimum mean cycle in the current component + if (!buildPolicyGraph(comp)) continue; + while (true) { + findPolicyCycle(); + if (!computeNodeDistances()) break; + } + // Update the best cycle (global minimum mean cycle) + if ( _curr_found && (!_best_found || + _curr_cost * _best_size < _best_cost * _curr_size) ) { + _best_found = true; + _best_cost = _curr_cost; + _best_size = _curr_size; + _best_node = _curr_node; + } + } + return _best_found; + } + + /// \brief Find a minimum mean directed cycle. + /// + /// This function finds a directed cycle of minimum mean cost + /// in the digraph using the data computed by findCycleMean(). + /// + /// \return \c true if a directed cycle exists in the digraph. + /// + /// \pre \ref findCycleMean() must be called before using this function. + bool findCycle() { + if (!_best_found) return false; + _cycle_path->addBack(_policy[_best_node]); + for ( Node v = _best_node; + (v = _gr.target(_policy[v])) != _best_node; ) { + _cycle_path->addBack(_policy[v]); + } + return true; + } + + /// @} + + /// \name Query Functions + /// The results of the algorithm can be obtained using these + /// functions.\n + /// The algorithm should be executed before using them. + + /// @{ + + /// \brief Return the total cost of the found cycle. + /// + /// This function returns the total cost of the found cycle. + /// + /// \pre \ref run() or \ref findCycleMean() must be called before + /// using this function. + Cost cycleCost() const { + return static_cast(_best_cost); + } + + /// \brief Return the number of arcs on the found cycle. + /// + /// This function returns the number of arcs on the found cycle. + /// + /// \pre \ref run() or \ref findCycleMean() must be called before + /// using this function. + int cycleSize() const { + return _best_size; + } + + /// \brief Return the mean cost of the found cycle. + /// + /// This function returns the mean cost of the found cycle. + /// + /// \note alg.cycleMean() is just a shortcut of the + /// following code. + /// \code + /// return static_cast(alg.cycleCost()) / alg.cycleSize(); + /// \endcode + /// + /// \pre \ref run() or \ref findCycleMean() must be called before + /// using this function. + double cycleMean() const { + return static_cast(_best_cost) / _best_size; + } + + /// \brief Return the found cycle. + /// + /// This function returns a const reference to the path structure + /// storing the found cycle. + /// + /// \pre \ref run() or \ref findCycle() must be called before using + /// this function. + const Path& cycle() const { + return *_cycle_path; + } + + ///@} + + private: + + // Initialize + void init() { + if (!_cycle_path) { + _local_path = true; + _cycle_path = new Path; + } + _queue.resize(countNodes(_gr)); + _best_found = false; + _best_cost = 0; + _best_size = 1; + _cycle_path->clear(); + } + + // Find strongly connected components and initialize _comp_nodes + // and _in_arcs + void findComponents() { + _comp_num = stronglyConnectedComponents(_gr, _comp); + _comp_nodes.resize(_comp_num); + if (_comp_num == 1) { + _comp_nodes[0].clear(); + for (NodeIt n(_gr); n != INVALID; ++n) { + _comp_nodes[0].push_back(n); + _in_arcs[n].clear(); + for (InArcIt a(_gr, n); a != INVALID; ++a) { + _in_arcs[n].push_back(a); + } + } + } else { + for (int i = 0; i < _comp_num; ++i) + _comp_nodes[i].clear(); + for (NodeIt n(_gr); n != INVALID; ++n) { + int k = _comp[n]; + _comp_nodes[k].push_back(n); + _in_arcs[n].clear(); + for (InArcIt a(_gr, n); a != INVALID; ++a) { + if (_comp[_gr.source(a)] == k) _in_arcs[n].push_back(a); + } + } + } + } + + // Build the policy graph in the given strongly connected component + // (the out-degree of every node is 1) + bool buildPolicyGraph(int comp) { + _nodes = &(_comp_nodes[comp]); + if (_nodes->size() < 1 || + (_nodes->size() == 1 && _in_arcs[(*_nodes)[0]].size() == 0)) { + return false; + } + for (int i = 0; i < int(_nodes->size()); ++i) { + _dist[(*_nodes)[i]] = INF; + } + Node u, v; + Arc e; + for (int i = 0; i < int(_nodes->size()); ++i) { + v = (*_nodes)[i]; + for (int j = 0; j < int(_in_arcs[v].size()); ++j) { + e = _in_arcs[v][j]; + u = _gr.source(e); + if (_cost[e] < _dist[u]) { + _dist[u] = _cost[e]; + _policy[u] = e; + } + } + } + return true; + } + + // Find the minimum mean cycle in the policy graph + void findPolicyCycle() { + for (int i = 0; i < int(_nodes->size()); ++i) { + _level[(*_nodes)[i]] = -1; + } + LargeCost ccost; + int csize; + Node u, v; + _curr_found = false; + for (int i = 0; i < int(_nodes->size()); ++i) { + u = (*_nodes)[i]; + if (_level[u] >= 0) continue; + for (; _level[u] < 0; u = _gr.target(_policy[u])) { + _level[u] = i; + } + if (_level[u] == i) { + // A cycle is found + ccost = _cost[_policy[u]]; + csize = 1; + for (v = u; (v = _gr.target(_policy[v])) != u; ) { + ccost += _cost[_policy[v]]; + ++csize; + } + if ( !_curr_found || + (ccost * _curr_size < _curr_cost * csize) ) { + _curr_found = true; + _curr_cost = ccost; + _curr_size = csize; + _curr_node = u; + } + } + } + } + + // Contract the policy graph and compute node distances + bool computeNodeDistances() { + // Find the component of the main cycle and compute node distances + // using reverse BFS + for (int i = 0; i < int(_nodes->size()); ++i) { + _reached[(*_nodes)[i]] = false; + } + _qfront = _qback = 0; + _queue[0] = _curr_node; + _reached[_curr_node] = true; + _dist[_curr_node] = 0; + Node u, v; + Arc e; + while (_qfront <= _qback) { + v = _queue[_qfront++]; + for (int j = 0; j < int(_in_arcs[v].size()); ++j) { + e = _in_arcs[v][j]; + u = _gr.source(e); + if (_policy[u] == e && !_reached[u]) { + _reached[u] = true; + _dist[u] = _dist[v] + _cost[e] * _curr_size - _curr_cost; + _queue[++_qback] = u; + } + } + } + + // Connect all other nodes to this component and compute node + // distances using reverse BFS + _qfront = 0; + while (_qback < int(_nodes->size())-1) { + v = _queue[_qfront++]; + for (int j = 0; j < int(_in_arcs[v].size()); ++j) { + e = _in_arcs[v][j]; + u = _gr.source(e); + if (!_reached[u]) { + _reached[u] = true; + _policy[u] = e; + _dist[u] = _dist[v] + _cost[e] * _curr_size - _curr_cost; + _queue[++_qback] = u; + } + } + } + + // Improve node distances + bool improved = false; + for (int i = 0; i < int(_nodes->size()); ++i) { + v = (*_nodes)[i]; + for (int j = 0; j < int(_in_arcs[v].size()); ++j) { + e = _in_arcs[v][j]; + u = _gr.source(e); + LargeCost delta = _dist[v] + _cost[e] * _curr_size - _curr_cost; + if (_tolerance.less(delta, _dist[u])) { + _dist[u] = delta; + _policy[u] = e; + improved = true; + } + } + } + return improved; + } + + }; //class HowardMmc + + ///@} + +} //namespace lemon + +#endif //LEMON_HOWARD_MMC_H diff -r a93f1a27d831 -r d3ea191c3412 lemon/karp.h --- a/lemon/karp.h Mon Mar 08 08:33:41 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,590 +0,0 @@ -/* -*- C++ -*- - * - * This file is a part of LEMON, a generic C++ optimization library - * - * Copyright (C) 2003-2008 - * 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_KARP_H -#define LEMON_KARP_H - -/// \ingroup min_mean_cycle -/// -/// \file -/// \brief Karp's algorithm for finding a minimum mean cycle. - -#include -#include -#include -#include -#include -#include - -namespace lemon { - - /// \brief Default traits class of Karp algorithm. - /// - /// Default traits class of Karp algorithm. - /// \tparam GR The type of the digraph. - /// \tparam LEN The type of the length map. - /// It must conform to the \ref concepts::ReadMap "ReadMap" concept. -#ifdef DOXYGEN - template -#else - template ::is_integer> -#endif - struct KarpDefaultTraits - { - /// The type of the digraph - typedef GR Digraph; - /// The type of the length map - typedef LEN LengthMap; - /// The type of the arc lengths - typedef typename LengthMap::Value Value; - - /// \brief The large value type used for internal computations - /// - /// The large value type used for internal computations. - /// It is \c long \c long if the \c Value type is integer, - /// otherwise it is \c double. - /// \c Value must be convertible to \c LargeValue. - typedef double LargeValue; - - /// The tolerance type used for internal computations - typedef lemon::Tolerance Tolerance; - - /// \brief The path type of the found cycles - /// - /// The path type of the found cycles. - /// It must conform to the \ref lemon::concepts::Path "Path" concept - /// and it must have an \c addFront() function. - typedef lemon::Path Path; - }; - - // Default traits class for integer value types - template - struct KarpDefaultTraits - { - typedef GR Digraph; - typedef LEN LengthMap; - typedef typename LengthMap::Value Value; -#ifdef LEMON_HAVE_LONG_LONG - typedef long long LargeValue; -#else - typedef long LargeValue; -#endif - typedef lemon::Tolerance Tolerance; - typedef lemon::Path Path; - }; - - - /// \addtogroup min_mean_cycle - /// @{ - - /// \brief Implementation of Karp's algorithm for finding a minimum - /// mean cycle. - /// - /// This class implements Karp's algorithm for finding a directed - /// cycle of minimum mean length (cost) in a digraph - /// \ref amo93networkflows, \ref dasdan98minmeancycle. - /// It runs in time O(ne) and uses space O(n2+e). - /// - /// \tparam GR The type of the digraph the algorithm runs on. - /// \tparam LEN The type of the length map. The default - /// map type is \ref concepts::Digraph::ArcMap "GR::ArcMap". - /// \tparam TR The traits class that defines various types used by the - /// algorithm. By default, it is \ref KarpDefaultTraits - /// "KarpDefaultTraits". - /// In most cases, this parameter should not be set directly, - /// consider to use the named template parameters instead. -#ifdef DOXYGEN - template -#else - template < typename GR, - typename LEN = typename GR::template ArcMap, - typename TR = KarpDefaultTraits > -#endif - class Karp - { - public: - - /// The type of the digraph - typedef typename TR::Digraph Digraph; - /// The type of the length map - typedef typename TR::LengthMap LengthMap; - /// The type of the arc lengths - typedef typename TR::Value Value; - - /// \brief The large value type - /// - /// The large value type used for internal computations. - /// By default, it is \c long \c long if the \c Value type is integer, - /// otherwise it is \c double. - typedef typename TR::LargeValue LargeValue; - - /// The tolerance type - typedef typename TR::Tolerance Tolerance; - - /// \brief The path type of the found cycles - /// - /// The path type of the found cycles. - /// Using the \ref KarpDefaultTraits "default traits class", - /// it is \ref lemon::Path "Path". - typedef typename TR::Path Path; - - /// The \ref KarpDefaultTraits "traits class" of the algorithm - typedef TR Traits; - - private: - - TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); - - // Data sturcture for path data - struct PathData - { - LargeValue dist; - Arc pred; - PathData(LargeValue d, Arc p = INVALID) : - dist(d), pred(p) {} - }; - - typedef typename Digraph::template NodeMap > - PathDataNodeMap; - - private: - - // The digraph the algorithm runs on - const Digraph &_gr; - // The length of the arcs - const LengthMap &_length; - - // Data for storing the strongly connected components - int _comp_num; - typename Digraph::template NodeMap _comp; - std::vector > _comp_nodes; - std::vector* _nodes; - typename Digraph::template NodeMap > _out_arcs; - - // Data for the found cycle - LargeValue _cycle_length; - int _cycle_size; - Node _cycle_node; - - Path *_cycle_path; - bool _local_path; - - // Node map for storing path data - PathDataNodeMap _data; - // The processed nodes in the last round - std::vector _process; - - Tolerance _tolerance; - - // Infinite constant - const LargeValue INF; - - public: - - /// \name Named Template Parameters - /// @{ - - template - struct SetLargeValueTraits : public Traits { - typedef T LargeValue; - typedef lemon::Tolerance Tolerance; - }; - - /// \brief \ref named-templ-param "Named parameter" for setting - /// \c LargeValue type. - /// - /// \ref named-templ-param "Named parameter" for setting \c LargeValue - /// type. It is used for internal computations in the algorithm. - template - struct SetLargeValue - : public Karp > { - typedef Karp > Create; - }; - - template - struct SetPathTraits : public Traits { - typedef T Path; - }; - - /// \brief \ref named-templ-param "Named parameter" for setting - /// \c %Path type. - /// - /// \ref named-templ-param "Named parameter" for setting the \c %Path - /// type of the found cycles. - /// It must conform to the \ref lemon::concepts::Path "Path" concept - /// and it must have an \c addFront() function. - template - struct SetPath - : public Karp > { - typedef Karp > Create; - }; - - /// @} - - protected: - - Karp() {} - - public: - - /// \brief Constructor. - /// - /// The constructor of the class. - /// - /// \param digraph The digraph the algorithm runs on. - /// \param length The lengths (costs) of the arcs. - Karp( const Digraph &digraph, - const LengthMap &length ) : - _gr(digraph), _length(length), _comp(digraph), _out_arcs(digraph), - _cycle_length(0), _cycle_size(1), _cycle_node(INVALID), - _cycle_path(NULL), _local_path(false), _data(digraph), - INF(std::numeric_limits::has_infinity ? - std::numeric_limits::infinity() : - std::numeric_limits::max()) - {} - - /// Destructor. - ~Karp() { - if (_local_path) delete _cycle_path; - } - - /// \brief Set the path structure for storing the found cycle. - /// - /// This function sets an external path structure for storing the - /// found cycle. - /// - /// If you don't call this function before calling \ref run() or - /// \ref findMinMean(), it will allocate a local \ref Path "path" - /// structure. The destuctor deallocates this automatically - /// allocated object, of course. - /// - /// \note The algorithm calls only the \ref lemon::Path::addFront() - /// "addFront()" function of the given path structure. - /// - /// \return (*this) - Karp& cycle(Path &path) { - if (_local_path) { - delete _cycle_path; - _local_path = false; - } - _cycle_path = &path; - return *this; - } - - /// \brief Set the tolerance used by the algorithm. - /// - /// This function sets the tolerance object used by the algorithm. - /// - /// \return (*this) - Karp& tolerance(const Tolerance& tolerance) { - _tolerance = tolerance; - return *this; - } - - /// \brief Return a const reference to the tolerance. - /// - /// This function returns a const reference to the tolerance object - /// used by the algorithm. - const Tolerance& tolerance() const { - return _tolerance; - } - - /// \name Execution control - /// The simplest way to execute the algorithm is to call the \ref run() - /// function.\n - /// If you only need the minimum mean length, you may call - /// \ref findMinMean(). - - /// @{ - - /// \brief Run the algorithm. - /// - /// This function runs the algorithm. - /// It can be called more than once (e.g. if the underlying digraph - /// and/or the arc lengths have been modified). - /// - /// \return \c true if a directed cycle exists in the digraph. - /// - /// \note mmc.run() is just a shortcut of the following code. - /// \code - /// return mmc.findMinMean() && mmc.findCycle(); - /// \endcode - bool run() { - return findMinMean() && findCycle(); - } - - /// \brief Find the minimum cycle mean. - /// - /// This function finds the minimum mean length of the directed - /// cycles in the digraph. - /// - /// \return \c true if a directed cycle exists in the digraph. - bool findMinMean() { - // Initialization and find strongly connected components - init(); - findComponents(); - - // Find the minimum cycle mean in the components - for (int comp = 0; comp < _comp_num; ++comp) { - if (!initComponent(comp)) continue; - processRounds(); - updateMinMean(); - } - return (_cycle_node != INVALID); - } - - /// \brief Find a minimum mean directed cycle. - /// - /// This function finds a directed cycle of minimum mean length - /// in the digraph using the data computed by findMinMean(). - /// - /// \return \c true if a directed cycle exists in the digraph. - /// - /// \pre \ref findMinMean() must be called before using this function. - bool findCycle() { - if (_cycle_node == INVALID) return false; - IntNodeMap reached(_gr, -1); - int r = _data[_cycle_node].size(); - Node u = _cycle_node; - while (reached[u] < 0) { - reached[u] = --r; - u = _gr.source(_data[u][r].pred); - } - r = reached[u]; - Arc e = _data[u][r].pred; - _cycle_path->addFront(e); - _cycle_length = _length[e]; - _cycle_size = 1; - Node v; - while ((v = _gr.source(e)) != u) { - e = _data[v][--r].pred; - _cycle_path->addFront(e); - _cycle_length += _length[e]; - ++_cycle_size; - } - return true; - } - - /// @} - - /// \name Query Functions - /// The results of the algorithm can be obtained using these - /// functions.\n - /// The algorithm should be executed before using them. - - /// @{ - - /// \brief Return the total length of the found cycle. - /// - /// This function returns the total length of the found cycle. - /// - /// \pre \ref run() or \ref findMinMean() must be called before - /// using this function. - Value cycleLength() const { - return static_cast(_cycle_length); - } - - /// \brief Return the number of arcs on the found cycle. - /// - /// This function returns the number of arcs on the found cycle. - /// - /// \pre \ref run() or \ref findMinMean() must be called before - /// using this function. - int cycleArcNum() const { - return _cycle_size; - } - - /// \brief Return the mean length of the found cycle. - /// - /// This function returns the mean length of the found cycle. - /// - /// \note alg.cycleMean() is just a shortcut of the - /// following code. - /// \code - /// return static_cast(alg.cycleLength()) / alg.cycleArcNum(); - /// \endcode - /// - /// \pre \ref run() or \ref findMinMean() must be called before - /// using this function. - double cycleMean() const { - return static_cast(_cycle_length) / _cycle_size; - } - - /// \brief Return the found cycle. - /// - /// This function returns a const reference to the path structure - /// storing the found cycle. - /// - /// \pre \ref run() or \ref findCycle() must be called before using - /// this function. - const Path& cycle() const { - return *_cycle_path; - } - - ///@} - - private: - - // Initialization - void init() { - if (!_cycle_path) { - _local_path = true; - _cycle_path = new Path; - } - _cycle_path->clear(); - _cycle_length = 0; - _cycle_size = 1; - _cycle_node = INVALID; - for (NodeIt u(_gr); u != INVALID; ++u) - _data[u].clear(); - } - - // Find strongly connected components and initialize _comp_nodes - // and _out_arcs - void findComponents() { - _comp_num = stronglyConnectedComponents(_gr, _comp); - _comp_nodes.resize(_comp_num); - if (_comp_num == 1) { - _comp_nodes[0].clear(); - for (NodeIt n(_gr); n != INVALID; ++n) { - _comp_nodes[0].push_back(n); - _out_arcs[n].clear(); - for (OutArcIt a(_gr, n); a != INVALID; ++a) { - _out_arcs[n].push_back(a); - } - } - } else { - for (int i = 0; i < _comp_num; ++i) - _comp_nodes[i].clear(); - for (NodeIt n(_gr); n != INVALID; ++n) { - int k = _comp[n]; - _comp_nodes[k].push_back(n); - _out_arcs[n].clear(); - for (OutArcIt a(_gr, n); a != INVALID; ++a) { - if (_comp[_gr.target(a)] == k) _out_arcs[n].push_back(a); - } - } - } - } - - // Initialize path data for the current component - bool initComponent(int comp) { - _nodes = &(_comp_nodes[comp]); - int n = _nodes->size(); - if (n < 1 || (n == 1 && _out_arcs[(*_nodes)[0]].size() == 0)) { - return false; - } - for (int i = 0; i < n; ++i) { - _data[(*_nodes)[i]].resize(n + 1, PathData(INF)); - } - return true; - } - - // Process all rounds of computing path data for the current component. - // _data[v][k] is the length of a shortest directed walk from the root - // node to node v containing exactly k arcs. - void processRounds() { - Node start = (*_nodes)[0]; - _data[start][0] = PathData(0); - _process.clear(); - _process.push_back(start); - - int k, n = _nodes->size(); - for (k = 1; k <= n && int(_process.size()) < n; ++k) { - processNextBuildRound(k); - } - for ( ; k <= n; ++k) { - processNextFullRound(k); - } - } - - // Process one round and rebuild _process - void processNextBuildRound(int k) { - std::vector next; - Node u, v; - Arc e; - LargeValue d; - for (int i = 0; i < int(_process.size()); ++i) { - u = _process[i]; - for (int j = 0; j < int(_out_arcs[u].size()); ++j) { - e = _out_arcs[u][j]; - v = _gr.target(e); - d = _data[u][k-1].dist + _length[e]; - if (_tolerance.less(d, _data[v][k].dist)) { - if (_data[v][k].dist == INF) next.push_back(v); - _data[v][k] = PathData(d, e); - } - } - } - _process.swap(next); - } - - // Process one round using _nodes instead of _process - void processNextFullRound(int k) { - Node u, v; - Arc e; - LargeValue d; - for (int i = 0; i < int(_nodes->size()); ++i) { - u = (*_nodes)[i]; - for (int j = 0; j < int(_out_arcs[u].size()); ++j) { - e = _out_arcs[u][j]; - v = _gr.target(e); - d = _data[u][k-1].dist + _length[e]; - if (_tolerance.less(d, _data[v][k].dist)) { - _data[v][k] = PathData(d, e); - } - } - } - } - - // Update the minimum cycle mean - void updateMinMean() { - int n = _nodes->size(); - for (int i = 0; i < n; ++i) { - Node u = (*_nodes)[i]; - if (_data[u][n].dist == INF) continue; - LargeValue length, max_length = 0; - int size, max_size = 1; - bool found_curr = false; - for (int k = 0; k < n; ++k) { - if (_data[u][k].dist == INF) continue; - length = _data[u][n].dist - _data[u][k].dist; - size = n - k; - if (!found_curr || length * max_size > max_length * size) { - found_curr = true; - max_length = length; - max_size = size; - } - } - if ( found_curr && (_cycle_node == INVALID || - max_length * _cycle_size < _cycle_length * max_size) ) { - _cycle_length = max_length; - _cycle_size = max_size; - _cycle_node = u; - } - } - } - - }; //class Karp - - ///@} - -} //namespace lemon - -#endif //LEMON_KARP_H diff -r a93f1a27d831 -r d3ea191c3412 lemon/karp_mmc.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lemon/karp_mmc.h Sat Mar 13 22:01:38 2010 +0100 @@ -0,0 +1,590 @@ +/* -*- C++ -*- + * + * This file is a part of LEMON, a generic C++ optimization library + * + * Copyright (C) 2003-2008 + * 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_KARP_MMC_H +#define LEMON_KARP_MMC_H + +/// \ingroup min_mean_cycle +/// +/// \file +/// \brief Karp's algorithm for finding a minimum mean cycle. + +#include +#include +#include +#include +#include +#include + +namespace lemon { + + /// \brief Default traits class of KarpMmc class. + /// + /// Default traits class of KarpMmc class. + /// \tparam GR The type of the digraph. + /// \tparam CM The type of the cost map. + /// It must conform to the \ref concepts::ReadMap "ReadMap" concept. +#ifdef DOXYGEN + template +#else + template ::is_integer> +#endif + struct KarpMmcDefaultTraits + { + /// The type of the digraph + typedef GR Digraph; + /// The type of the cost map + typedef CM CostMap; + /// The type of the arc costs + typedef typename CostMap::Value Cost; + + /// \brief The large cost type used for internal computations + /// + /// The large cost type used for internal computations. + /// It is \c long \c long if the \c Cost type is integer, + /// otherwise it is \c double. + /// \c Cost must be convertible to \c LargeCost. + typedef double LargeCost; + + /// The tolerance type used for internal computations + typedef lemon::Tolerance Tolerance; + + /// \brief The path type of the found cycles + /// + /// The path type of the found cycles. + /// It must conform to the \ref lemon::concepts::Path "Path" concept + /// and it must have an \c addFront() function. + typedef lemon::Path Path; + }; + + // Default traits class for integer cost types + template + struct KarpMmcDefaultTraits + { + typedef GR Digraph; + typedef CM CostMap; + typedef typename CostMap::Value Cost; +#ifdef LEMON_HAVE_LONG_LONG + typedef long long LargeCost; +#else + typedef long LargeCost; +#endif + typedef lemon::Tolerance Tolerance; + typedef lemon::Path Path; + }; + + + /// \addtogroup min_mean_cycle + /// @{ + + /// \brief Implementation of Karp's algorithm for finding a minimum + /// mean cycle. + /// + /// This class implements Karp's algorithm for finding a directed + /// cycle of minimum mean cost in a digraph + /// \ref amo93networkflows, \ref dasdan98minmeancycle. + /// It runs in time O(ne) and uses space O(n2+e). + /// + /// \tparam GR The type of the digraph the algorithm runs on. + /// \tparam CM The type of the cost map. The default + /// map type is \ref concepts::Digraph::ArcMap "GR::ArcMap". + /// \tparam TR The traits class that defines various types used by the + /// algorithm. By default, it is \ref KarpMmcDefaultTraits + /// "KarpMmcDefaultTraits". + /// In most cases, this parameter should not be set directly, + /// consider to use the named template parameters instead. +#ifdef DOXYGEN + template +#else + template < typename GR, + typename CM = typename GR::template ArcMap, + typename TR = KarpMmcDefaultTraits > +#endif + class KarpMmc + { + public: + + /// The type of the digraph + typedef typename TR::Digraph Digraph; + /// The type of the cost map + typedef typename TR::CostMap CostMap; + /// The type of the arc costs + typedef typename TR::Cost Cost; + + /// \brief The large cost type + /// + /// The large cost type used for internal computations. + /// By default, it is \c long \c long if the \c Cost type is integer, + /// otherwise it is \c double. + typedef typename TR::LargeCost LargeCost; + + /// The tolerance type + typedef typename TR::Tolerance Tolerance; + + /// \brief The path type of the found cycles + /// + /// The path type of the found cycles. + /// Using the \ref KarpMmcDefaultTraits "default traits class", + /// it is \ref lemon::Path "Path". + typedef typename TR::Path Path; + + /// The \ref KarpMmcDefaultTraits "traits class" of the algorithm + typedef TR Traits; + + private: + + TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); + + // Data sturcture for path data + struct PathData + { + LargeCost dist; + Arc pred; + PathData(LargeCost d, Arc p = INVALID) : + dist(d), pred(p) {} + }; + + typedef typename Digraph::template NodeMap > + PathDataNodeMap; + + private: + + // The digraph the algorithm runs on + const Digraph &_gr; + // The cost of the arcs + const CostMap &_cost; + + // Data for storing the strongly connected components + int _comp_num; + typename Digraph::template NodeMap _comp; + std::vector > _comp_nodes; + std::vector* _nodes; + typename Digraph::template NodeMap > _out_arcs; + + // Data for the found cycle + LargeCost _cycle_cost; + int _cycle_size; + Node _cycle_node; + + Path *_cycle_path; + bool _local_path; + + // Node map for storing path data + PathDataNodeMap _data; + // The processed nodes in the last round + std::vector _process; + + Tolerance _tolerance; + + // Infinite constant + const LargeCost INF; + + public: + + /// \name Named Template Parameters + /// @{ + + template + struct SetLargeCostTraits : public Traits { + typedef T LargeCost; + typedef lemon::Tolerance Tolerance; + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// \c LargeCost type. + /// + /// \ref named-templ-param "Named parameter" for setting \c LargeCost + /// type. It is used for internal computations in the algorithm. + template + struct SetLargeCost + : public KarpMmc > { + typedef KarpMmc > Create; + }; + + template + struct SetPathTraits : public Traits { + typedef T Path; + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// \c %Path type. + /// + /// \ref named-templ-param "Named parameter" for setting the \c %Path + /// type of the found cycles. + /// It must conform to the \ref lemon::concepts::Path "Path" concept + /// and it must have an \c addFront() function. + template + struct SetPath + : public KarpMmc > { + typedef KarpMmc > Create; + }; + + /// @} + + protected: + + KarpMmc() {} + + public: + + /// \brief Constructor. + /// + /// The constructor of the class. + /// + /// \param digraph The digraph the algorithm runs on. + /// \param cost The costs of the arcs. + KarpMmc( const Digraph &digraph, + const CostMap &cost ) : + _gr(digraph), _cost(cost), _comp(digraph), _out_arcs(digraph), + _cycle_cost(0), _cycle_size(1), _cycle_node(INVALID), + _cycle_path(NULL), _local_path(false), _data(digraph), + INF(std::numeric_limits::has_infinity ? + std::numeric_limits::infinity() : + std::numeric_limits::max()) + {} + + /// Destructor. + ~KarpMmc() { + if (_local_path) delete _cycle_path; + } + + /// \brief Set the path structure for storing the found cycle. + /// + /// This function sets an external path structure for storing the + /// found cycle. + /// + /// If you don't call this function before calling \ref run() or + /// \ref findCycleMean(), it will allocate a local \ref Path "path" + /// structure. The destuctor deallocates this automatically + /// allocated object, of course. + /// + /// \note The algorithm calls only the \ref lemon::Path::addFront() + /// "addFront()" function of the given path structure. + /// + /// \return (*this) + KarpMmc& cycle(Path &path) { + if (_local_path) { + delete _cycle_path; + _local_path = false; + } + _cycle_path = &path; + return *this; + } + + /// \brief Set the tolerance used by the algorithm. + /// + /// This function sets the tolerance object used by the algorithm. + /// + /// \return (*this) + KarpMmc& tolerance(const Tolerance& tolerance) { + _tolerance = tolerance; + return *this; + } + + /// \brief Return a const reference to the tolerance. + /// + /// This function returns a const reference to the tolerance object + /// used by the algorithm. + const Tolerance& tolerance() const { + return _tolerance; + } + + /// \name Execution control + /// The simplest way to execute the algorithm is to call the \ref run() + /// function.\n + /// If you only need the minimum mean cost, you may call + /// \ref findCycleMean(). + + /// @{ + + /// \brief Run the algorithm. + /// + /// This function runs the algorithm. + /// It can be called more than once (e.g. if the underlying digraph + /// and/or the arc costs have been modified). + /// + /// \return \c true if a directed cycle exists in the digraph. + /// + /// \note mmc.run() is just a shortcut of the following code. + /// \code + /// return mmc.findCycleMean() && mmc.findCycle(); + /// \endcode + bool run() { + return findCycleMean() && findCycle(); + } + + /// \brief Find the minimum cycle mean. + /// + /// This function finds the minimum mean cost of the directed + /// cycles in the digraph. + /// + /// \return \c true if a directed cycle exists in the digraph. + bool findCycleMean() { + // Initialization and find strongly connected components + init(); + findComponents(); + + // Find the minimum cycle mean in the components + for (int comp = 0; comp < _comp_num; ++comp) { + if (!initComponent(comp)) continue; + processRounds(); + updateMinMean(); + } + return (_cycle_node != INVALID); + } + + /// \brief Find a minimum mean directed cycle. + /// + /// This function finds a directed cycle of minimum mean cost + /// in the digraph using the data computed by findCycleMean(). + /// + /// \return \c true if a directed cycle exists in the digraph. + /// + /// \pre \ref findCycleMean() must be called before using this function. + bool findCycle() { + if (_cycle_node == INVALID) return false; + IntNodeMap reached(_gr, -1); + int r = _data[_cycle_node].size(); + Node u = _cycle_node; + while (reached[u] < 0) { + reached[u] = --r; + u = _gr.source(_data[u][r].pred); + } + r = reached[u]; + Arc e = _data[u][r].pred; + _cycle_path->addFront(e); + _cycle_cost = _cost[e]; + _cycle_size = 1; + Node v; + while ((v = _gr.source(e)) != u) { + e = _data[v][--r].pred; + _cycle_path->addFront(e); + _cycle_cost += _cost[e]; + ++_cycle_size; + } + return true; + } + + /// @} + + /// \name Query Functions + /// The results of the algorithm can be obtained using these + /// functions.\n + /// The algorithm should be executed before using them. + + /// @{ + + /// \brief Return the total cost of the found cycle. + /// + /// This function returns the total cost of the found cycle. + /// + /// \pre \ref run() or \ref findCycleMean() must be called before + /// using this function. + Cost cycleCost() const { + return static_cast(_cycle_cost); + } + + /// \brief Return the number of arcs on the found cycle. + /// + /// This function returns the number of arcs on the found cycle. + /// + /// \pre \ref run() or \ref findCycleMean() must be called before + /// using this function. + int cycleSize() const { + return _cycle_size; + } + + /// \brief Return the mean cost of the found cycle. + /// + /// This function returns the mean cost of the found cycle. + /// + /// \note alg.cycleMean() is just a shortcut of the + /// following code. + /// \code + /// return static_cast(alg.cycleCost()) / alg.cycleSize(); + /// \endcode + /// + /// \pre \ref run() or \ref findCycleMean() must be called before + /// using this function. + double cycleMean() const { + return static_cast(_cycle_cost) / _cycle_size; + } + + /// \brief Return the found cycle. + /// + /// This function returns a const reference to the path structure + /// storing the found cycle. + /// + /// \pre \ref run() or \ref findCycle() must be called before using + /// this function. + const Path& cycle() const { + return *_cycle_path; + } + + ///@} + + private: + + // Initialization + void init() { + if (!_cycle_path) { + _local_path = true; + _cycle_path = new Path; + } + _cycle_path->clear(); + _cycle_cost = 0; + _cycle_size = 1; + _cycle_node = INVALID; + for (NodeIt u(_gr); u != INVALID; ++u) + _data[u].clear(); + } + + // Find strongly connected components and initialize _comp_nodes + // and _out_arcs + void findComponents() { + _comp_num = stronglyConnectedComponents(_gr, _comp); + _comp_nodes.resize(_comp_num); + if (_comp_num == 1) { + _comp_nodes[0].clear(); + for (NodeIt n(_gr); n != INVALID; ++n) { + _comp_nodes[0].push_back(n); + _out_arcs[n].clear(); + for (OutArcIt a(_gr, n); a != INVALID; ++a) { + _out_arcs[n].push_back(a); + } + } + } else { + for (int i = 0; i < _comp_num; ++i) + _comp_nodes[i].clear(); + for (NodeIt n(_gr); n != INVALID; ++n) { + int k = _comp[n]; + _comp_nodes[k].push_back(n); + _out_arcs[n].clear(); + for (OutArcIt a(_gr, n); a != INVALID; ++a) { + if (_comp[_gr.target(a)] == k) _out_arcs[n].push_back(a); + } + } + } + } + + // Initialize path data for the current component + bool initComponent(int comp) { + _nodes = &(_comp_nodes[comp]); + int n = _nodes->size(); + if (n < 1 || (n == 1 && _out_arcs[(*_nodes)[0]].size() == 0)) { + return false; + } + for (int i = 0; i < n; ++i) { + _data[(*_nodes)[i]].resize(n + 1, PathData(INF)); + } + return true; + } + + // Process all rounds of computing path data for the current component. + // _data[v][k] is the cost of a shortest directed walk from the root + // node to node v containing exactly k arcs. + void processRounds() { + Node start = (*_nodes)[0]; + _data[start][0] = PathData(0); + _process.clear(); + _process.push_back(start); + + int k, n = _nodes->size(); + for (k = 1; k <= n && int(_process.size()) < n; ++k) { + processNextBuildRound(k); + } + for ( ; k <= n; ++k) { + processNextFullRound(k); + } + } + + // Process one round and rebuild _process + void processNextBuildRound(int k) { + std::vector next; + Node u, v; + Arc e; + LargeCost d; + for (int i = 0; i < int(_process.size()); ++i) { + u = _process[i]; + for (int j = 0; j < int(_out_arcs[u].size()); ++j) { + e = _out_arcs[u][j]; + v = _gr.target(e); + d = _data[u][k-1].dist + _cost[e]; + if (_tolerance.less(d, _data[v][k].dist)) { + if (_data[v][k].dist == INF) next.push_back(v); + _data[v][k] = PathData(d, e); + } + } + } + _process.swap(next); + } + + // Process one round using _nodes instead of _process + void processNextFullRound(int k) { + Node u, v; + Arc e; + LargeCost d; + for (int i = 0; i < int(_nodes->size()); ++i) { + u = (*_nodes)[i]; + for (int j = 0; j < int(_out_arcs[u].size()); ++j) { + e = _out_arcs[u][j]; + v = _gr.target(e); + d = _data[u][k-1].dist + _cost[e]; + if (_tolerance.less(d, _data[v][k].dist)) { + _data[v][k] = PathData(d, e); + } + } + } + } + + // Update the minimum cycle mean + void updateMinMean() { + int n = _nodes->size(); + for (int i = 0; i < n; ++i) { + Node u = (*_nodes)[i]; + if (_data[u][n].dist == INF) continue; + LargeCost cost, max_cost = 0; + int size, max_size = 1; + bool found_curr = false; + for (int k = 0; k < n; ++k) { + if (_data[u][k].dist == INF) continue; + cost = _data[u][n].dist - _data[u][k].dist; + size = n - k; + if (!found_curr || cost * max_size > max_cost * size) { + found_curr = true; + max_cost = cost; + max_size = size; + } + } + if ( found_curr && (_cycle_node == INVALID || + max_cost * _cycle_size < _cycle_cost * max_size) ) { + _cycle_cost = max_cost; + _cycle_size = max_size; + _cycle_node = u; + } + } + } + + }; //class KarpMmc + + ///@} + +} //namespace lemon + +#endif //LEMON_KARP_MMC_H diff -r a93f1a27d831 -r d3ea191c3412 test/min_mean_cycle_test.cc --- a/test/min_mean_cycle_test.cc Mon Mar 08 08:33:41 2010 +0100 +++ b/test/min_mean_cycle_test.cc Sat Mar 13 22:01:38 2010 +0100 @@ -25,9 +25,9 @@ #include #include -#include -#include -#include +#include +#include +#include #include "test_tools.h" @@ -63,7 +63,7 @@ // Check the interface of an MMC algorithm -template +template struct MmcClassConcept { template @@ -73,30 +73,30 @@ typedef typename MMC ::template SetPath > - ::template SetLargeValue + ::template SetLargeCost ::Create MmcAlg; - MmcAlg mmc(me.g, me.length); + MmcAlg mmc(me.g, me.cost); const MmcAlg& const_mmc = mmc; typename MmcAlg::Tolerance tol = const_mmc.tolerance(); mmc.tolerance(tol); b = mmc.cycle(p).run(); - b = mmc.findMinMean(); + b = mmc.findCycleMean(); b = mmc.findCycle(); - v = const_mmc.cycleLength(); - i = const_mmc.cycleArcNum(); + v = const_mmc.cycleCost(); + i = const_mmc.cycleSize(); d = const_mmc.cycleMean(); p = const_mmc.cycle(); } - typedef concepts::ReadMap LM; + typedef concepts::ReadMap CM; GR g; - LM length; + CM cost; ListPath p; - Value v; + Cost v; int i; double d; bool b; @@ -108,13 +108,13 @@ void checkMmcAlg(const SmartDigraph& gr, const SmartDigraph::ArcMap& lm, const SmartDigraph::ArcMap& cm, - int length, int size) { + int cost, int size) { MMC alg(gr, lm); - alg.findMinMean(); - check(alg.cycleMean() == static_cast(length) / size, + alg.findCycleMean(); + check(alg.cycleMean() == static_cast(cost) / size, "Wrong cycle mean"); alg.findCycle(); - check(alg.cycleLength() == length && alg.cycleArcNum() == size, + check(alg.cycleCost() == cost && alg.cycleSize() == size, "Wrong path"); SmartDigraph::ArcMap cycle(gr, 0); for (typename MMC::Path::ArcIt a(alg.cycle()); a != INVALID; ++a) { @@ -148,28 +148,28 @@ { typedef concepts::Digraph GR; - // Karp + // KarpMmc checkConcept< MmcClassConcept, - Karp > >(); + KarpMmc > >(); checkConcept< MmcClassConcept, - Karp > >(); + KarpMmc > >(); - // HartmannOrlin + // HartmannOrlinMmc checkConcept< MmcClassConcept, - HartmannOrlin > >(); + HartmannOrlinMmc > >(); checkConcept< MmcClassConcept, - HartmannOrlin > >(); + HartmannOrlinMmc > >(); - // Howard + // HowardMmc checkConcept< MmcClassConcept, - Howard > >(); + HowardMmc > >(); checkConcept< MmcClassConcept, - Howard > >(); + HowardMmc > >(); - if (IsSameType >::LargeValue, - long_int>::result == 0) check(false, "Wrong LargeValue type"); - if (IsSameType >::LargeValue, - double>::result == 0) check(false, "Wrong LargeValue type"); + check((IsSameType > + ::LargeCost, long_int>::result == 1), "Wrong LargeCost type"); + check((IsSameType > + ::LargeCost, double>::result == 1), "Wrong LargeCost type"); } // Run various tests @@ -194,22 +194,22 @@ run(); // Karp - checkMmcAlg >(gr, l1, c1, 6, 3); - checkMmcAlg >(gr, l2, c2, 5, 2); - checkMmcAlg >(gr, l3, c3, 0, 1); - checkMmcAlg >(gr, l4, c4, -1, 1); + checkMmcAlg >(gr, l1, c1, 6, 3); + checkMmcAlg >(gr, l2, c2, 5, 2); + checkMmcAlg >(gr, l3, c3, 0, 1); + checkMmcAlg >(gr, l4, c4, -1, 1); // HartmannOrlin - checkMmcAlg >(gr, l1, c1, 6, 3); - checkMmcAlg >(gr, l2, c2, 5, 2); - checkMmcAlg >(gr, l3, c3, 0, 1); - checkMmcAlg >(gr, l4, c4, -1, 1); + checkMmcAlg >(gr, l1, c1, 6, 3); + checkMmcAlg >(gr, l2, c2, 5, 2); + checkMmcAlg >(gr, l3, c3, 0, 1); + checkMmcAlg >(gr, l4, c4, -1, 1); // Howard - checkMmcAlg >(gr, l1, c1, 6, 3); - checkMmcAlg >(gr, l2, c2, 5, 2); - checkMmcAlg >(gr, l3, c3, 0, 1); - checkMmcAlg >(gr, l4, c4, -1, 1); + checkMmcAlg >(gr, l1, c1, 6, 3); + checkMmcAlg >(gr, l2, c2, 5, 2); + checkMmcAlg >(gr, l3, c3, 0, 1); + checkMmcAlg >(gr, l4, c4, -1, 1); } return 0;