COIN-OR::LEMON - Graph Library

Ticket #296: ticket296.patch

File ticket296.patch, 52.6 KB (added by David Torres Sanchez, 4 years ago)
  • lemon/multicommodity_flow.h

    diff -r 86d9dd6da44d lemon/multicommodity_flow.h
    a b  
    22 *
    33 * This file is a part of LEMON, a generic C++ optimization library.
    44 *
    5  * Copyright (C) 2003-2009
     5 * Copyright (C) 2003-2021
    66 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
    77 * (Egervary Research Group on Combinatorial Optimization, EGRES).
    88 *
     
    1414 * express or implied, and with no claim as to its suitability for any
    1515 * purpose.
    1616 *
     17 * Additional Copyright file multicommodity_flow.h: Lancaster University (2021)
    1718 */
    1819
    19 #ifndef LEMON_MULTICOMMODITY_FLOW_H
    20 #define LEMON_MULTICOMMODITY_FLOW_H
     20#ifndef LEMON_MULTICOMMODITY_FLOW_H_
     21#define LEMON_MULTICOMMODITY_FLOW_H_
    2122
    2223/// \ingroup approx
    2324///
    2425/// \file
    25 /// \brief Approximation algorithms for solving multicommodity flow problems.
     26/// \brief Fleischer's algorithms for finding approximate multicommodity flows.
    2627
     28#include <algorithm>  // min
     29#include <limits>     // numeric_limits
     30#include <random>     // random_device, mt19937
     31#include <set>
    2732#include <vector>
    28 #include <lemon/bfs.h>
    29 #include <lemon/dijkstra.h>
    30 #include <lemon/preflow.h>
    31 #include <lemon/adaptors.h>
    32 #include <lemon/tolerance.h>
    33 #include <lemon/path.h>
    34 #include <lemon/math.h>
    3533
    36 //
    37 // TODO:
    38 //
    39 //   - The algorithms should provide primal and dual solution as well:
    40 //       primal objective value, primal solution (flow), primal solution (flow) for each commodity
    41 //       dual objective value, dual solution
    42 //     Note that these algorithms are approximation methods, so the found primal and dual obj. values
    43 //     are not necessarily optimal, ie. the found primal obj. value could be smaller than the found
    44 //     dual objective value and their ratio provides a proof for the approximation factor of both
    45 //     the primal and the dual solution.
    46 //   
    47 //   - compute an upper bound for the optimal primal obj. value, e.g. using
    48 //       x_i = min ( out_cap(s_i), in_cap(t_i) )  for each commodity i
    49 //     the sum of x_i or the minimum of x_i/d_i ratios can be utilized.
    50 //     
    51 //   - give back as good approximation guarantee r as possible for which:
    52 //     dual = r*primal
    53 //
    54 //   - revise the implementations and their API
    55 //
     34#include "lemon/adaptors.h"
     35#include "lemon/bfs.h"
     36#include "lemon/concepts/maps.h"
     37#include "lemon/dijkstra.h"
     38#include "lemon/maps.h"
     39#include "lemon/math.h"
     40#include "lemon/path.h"
     41#include "lemon/preflow.h"
     42#include "lemon/static_graph.h"
     43#include "lemon/tolerance.h"
    5644
    5745namespace lemon {
    5846
    59   /// \addtogroup approx
     47/// \brief Default traits class of \ref ApproxMCF class.
     48///
     49/// Default traits class of \ref ApproxMCF class.
     50/// \tparam GR The type of the digraph.
     51/// \tparam CAPType The type of the capacity values.
     52/// \tparam CAPMap The type of the capacity map.
     53/// \tparam V The type for the flows and costs.
     54/// It must conform to the \ref concepts::ReadMap "ReadMap" concept.
     55#ifdef DOXYGEN
     56template<typename GR, typename CAPType, typename CAPMap, typename V>
     57#else
     58template<
     59    typename GR,
     60    typename CAPMap = typename GR::template ArcMap<double>,
     61    typename V      = double>
     62#endif
     63struct ApproxMCNFDefaultTraits {
     64  /// The type of the digraph
     65  typedef GR Digraph;
     66  /// The type of the capacity map
     67  typedef CAPMap CapacityMap;
     68  /// The type of the capacity map values. By default is double.
     69  typedef typename CapacityMap::Value CapacityValue;
     70
     71  /// \brief The type used for flow values and costs.
     72  ///
     73  /// \c CapacityValue must be convertible to \c Value.
     74  /// By default is \c double.
     75  typedef V                                        Value;
     76  typedef typename Digraph::template ArcMap<Value> ValueMap;
     77
     78  /// The tolerance type used for internal computations
     79  typedef lemon::Tolerance<Value> Tolerance;
     80
     81  /// \brief The path type of the decomposed flows
     82  ///
     83  /// It must conform to the \ref lemon::concepts::Path "Path" concept
     84  typedef lemon::Path<Digraph>                 Path;
     85  typedef typename lemon::Path<Digraph>::ArcIt PathArcIt;
     86
     87  /// \brief Instantiates a ValueMap.
     88  ///
     89  /// This function instantiates a \ref ValueMap.
     90  /// \param digraph The digraph for which we would like to define
     91  /// the large cost map. This can be used for flows or otherwise.
     92  static ValueMap* createValueMapPtr(
     93      const Digraph& digraph,
     94      const Value&   value = 0) {
     95    return new ValueMap(digraph, value);
     96  }
     97  // Same as above just const
     98  static const ValueMap* createValueMapConstPtr(
     99      const Digraph& digraph,
     100      const Value&   value = 0) {
     101    return new ValueMap(digraph, value);
     102  }
     103};
     104
     105/// \addtogroup approx
     106/// @{
     107/// \brief Fleischer's algorithms for the multicommodity flow problem.
     108///
     109/// Default traits class of \ref ApproxMCF class.
     110/// \tparam GR The type of the digraph.
     111/// \tparam TR The type of the traits class.
     112#ifdef DOXYGEN
     113template<typename GR, typename TR>
     114#else
     115template<
     116    typename GR,
     117    typename CM = typename GR::template ArcMap<double>,
     118    typename TR = ApproxMCNFDefaultTraits<GR, CM>>
     119#endif
     120class ApproxMCF {
     121 public:
     122  /// The type of the digraph
     123  typedef typename TR::Digraph Digraph;
     124  /// The type of the capacity map
     125  typedef typename TR::CapacityMap CapacityMap;
     126  /// The type of the capacity values
     127  typedef typename TR::CapacityValue CapacityValue;
     128
     129  /// \brief The large cost type
     130  ///
     131  /// The large cost type used for internal computations.
     132  /// By default is \c double.
     133  typedef typename TR::Value Value;
     134  /// Arc Map with values of type \ref Value
     135  typedef typename TR::ValueMap ValueMap;
     136
     137  /// The tolerance type
     138  typedef typename TR::Tolerance Tolerance;
     139
     140  /// \brief The path type of the found cycles
     141  ///
     142  /// The path type of the found cycles.
     143  /// Using the \ref lemon::ApproxMCNFDefaultTraits "default traits class",
     144  /// it is \ref lemon::Path "Path<Digraph>".
     145  typedef typename TR::Path Path;
     146  /// The arc iterator for paths.
     147  typedef typename TR::PathArcIt PathArcIt;
     148
     149  /// The \ref lemon::ApproxMCNFDefaultTraits "traits class" of the
     150  /// algorithm
     151  typedef TR Traits;
     152
     153  /// Types of approximation type.
     154  enum ApproxType {
     155    /// Maximum flow using Fleischer's algorithm.
     156    FLEISCHER_MAX,
     157    /// Maximum concurrent flow using Fleischer's algorithm.
     158    FLEISCHER_MAX_CONCURRENT,
     159    /// Minimum cost concurrent flow using binary search with cost-bounded
     160    /// \ref FLEISCHER_MAX_CONCURRENT
     161    BINARY_SEARCH_MIN_COST
     162  };
     163
     164 private:
     165  struct PathData {
     166    Path path;
     167    // The amount of flow through the path
     168    Value value;
     169    // The minimum capacity along all edges in the path
     170    CapacityValue min_cap;
     171    // The actual cost of the path
     172    Value cost;
     173    int   hash;
     174
     175    PathData() {}
     176    PathData(const Path& p, Value v, CapacityValue m, Value c, int h = 0)
     177        : path(p), value(v), min_cap(m), cost(c), hash(h) {}
     178  };
     179
     180  int hash(const Path& path) const {
     181    int h = path.length();
     182    for (PathArcIt a(path); a != INVALID; ++a)
     183      h = (h << 4) ^ (h >> 28) ^ _graph.id(a);
     184    return h;
     185  }
     186
     187  // Matrix indexed by commodity with all the paths found. i.e. [i][p] where i
     188  // is the commodity index and p is the path index.
     189  typedef std::vector<std::vector<PathData>> PathMatrix;
     190  // Vector indexed by commodity with \ref ValueMap pointers.
     191  typedef std::vector<ValueMap*>       ValueMapVector;
     192  typedef std::vector<const ValueMap*> ConstValueMapVector;
     193
     194  TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
     195
     196  const Digraph& _graph;
     197  const int      _num_nodes;
     198  const int      _num_arcs;
     199  // Input capacity map
     200  const CapacityMap& _cap;
     201
     202  // The number of commodities
     203  int _num_commodities;
     204  // The source nodes for each commodity
     205  std::vector<Node> _source;
     206  // The target nodes for each commodity
     207  std::vector<Node> _target;
     208  // The demands for each commodity (may be 0, or undefined).
     209  std::vector<CapacityValue> _demand;
     210  // The cost for each commodity (may be 0, or undefined)
     211  // See \ref ValueMapVector.
     212  ConstValueMapVector _cost;
     213
     214  /**
     215   * Algorithm parameters
     216   */
     217  // type of approximation algorithm. See \ref ApproxType.
     218  ApproxType _approx_type;
     219  // Stopping criterion
     220  Value _epsilon;
     221  // Whether the internal heuristics will be applied at the end of the
     222  // algorithms
     223  bool _heuristic;
     224  // Whether there is feasible unsplitable flow
     225  bool _feasible_unsplit;
     226  // Objective function of the primal problem
     227  Value _obj;
     228  // Objective function of the dual problem
     229  Value _dual_obj;
     230  bool  _local_cost;
     231  //
     232  Value _delta;
     233  // Expected maximum number of iterations
     234  Value _max_iter;
     235  //
     236  Value _limit;
     237  // Number of iterations
     238  int _iter;
     239  // Tolerance function. See \ref lemon::Tolerance.
     240  Tolerance _tol;
     241
     242  // For the BINARY_SEARCH_MIN_COST case
     243  // Cost of the final solution.
     244  Value _total_cost;
     245  // Cost bounding factor.
     246  Value _phi;
     247  // Cost bound.
     248  Value _cost_bound;
     249
     250  // The aggregated flow per arc over all commodities
     251  ValueMap _total_flow;
     252  // The value of the length per arc (the dual solution).
     253  ValueMap _len;
     254  // The flow for each commodity. See \ref ValueMapVector.
     255  ValueMapVector _flow;
     256  // The paths found for different commodities. See \ref PathMatrix.
     257  PathMatrix _paths;
     258
     259  // Solution Attributes
     260  std::vector<Path>  _final_paths;
     261  std::vector<Value> _final_flows;
     262  std::vector<Value> _final_costs;
     263
     264 public:
     265  /// \brief Default constructor
     266  ApproxMCF(const Digraph& gr, const CapacityMap& cp)
     267      : _graph(gr),
     268        _num_nodes(countNodes(_graph)),
     269        _num_arcs(countArcs(_graph)),
     270        _cap(cp),
     271        _num_commodities(0),
     272        _feasible_unsplit(true),
     273        _obj(0),
     274        _dual_obj(0),
     275        _local_cost(true),
     276        _iter(0),
     277        _cost_bound(0),
     278        _total_flow(_graph),
     279        _len(_graph) {}
     280
     281  ~ApproxMCF() {
     282    for (int i = 0; i < _num_commodities; ++i) {
     283      delete _flow[i];
     284      _flow[i] = nullptr;
     285      if (_local_cost) {
     286        delete _cost[i];
     287        _cost[i] = nullptr;
     288      }
     289    }
     290    _flow.clear();
     291    _cost.clear();
     292  }
     293
     294  /// \name Parameters
     295  /// The parameters of the algorithm can be specified using these
     296  /// functions.
     297
    60298  /// @{
    61299
    62   /// \brief Implementation of an approximation algorithm for finding
    63   /// a maximum multicommodity flow.
     300  /// \brief Set single commodity parameters.
    64301  ///
    65   /// \ref MaxMulticommodityFlow implements Lisa Fleischer's algorithm
    66   /// for finding a maximum multicommodity flow.
     302  /// \param s The source node.
     303  /// \param t The target node.
     304  /// \param d The required amount of flow from node \c s to node \c t
     305  /// (i.e. the supply of \c s and the demand of \c t).
     306  /// \param cost_map The cost arc map.
    67307  ///
    68   /// \tparam Digraph The type of the digraph the algorithm runs on.
    69   /// \tparam CAP The type of the capacity map.
    70   /// The default map type is \ref concepts::Digraph::ArcMap
    71   /// "GR::ArcMap<double>".
    72   /// \tparam V The value type used in the algorithm.
    73   /// The default value type is \c CAP::Value.
    74 #ifdef DOXYGEN
    75   template < typename GR,
    76              typename CAP,
    77              typename V >
    78 #else
    79   template < typename GR,
    80              typename CAP = typename GR::template ArcMap<double>,
    81              typename V = typename CAP::Value >
    82 #endif
    83   class MaxMulticommodityFlow
    84   {
    85     TEMPLATE_DIGRAPH_TYPEDEFS(GR);
    86 
    87     typedef SimplePath<GR> SPath;
    88     typedef typename SPath::ArcIt PathArcIt;
    89 
    90   public:
    91 
    92     ///  The type of the digraph the algorithm runs on.
    93     typedef GR Digraph;
    94     /// The type of the capacity map.
    95     typedef CAP CapacityMap;
    96     /// The value type of the algorithm.
    97     typedef V Value;
    98 
    99 #ifdef DOXYGEN
    100     /// The type of the flow map (primal solution).
    101     typedef Digraph::ArcMap<Value> FlowMap;
    102     /// The type of the length map (dual soluiton).
    103     typedef Digraph::ArcMap<Value> LengthMap;
    104 #else
    105     /// The type of the flow map (primal solution).
    106     typedef typename Digraph::template ArcMap<Value> FlowMap;
    107     /// The type of the length map (dual soluiton).
    108     typedef typename Digraph::template ArcMap<Value> LengthMap;
    109 #endif
    110 
    111   private:
    112 
    113     // The digraph the algorithm runs on
    114     const Digraph &_g;
    115     // The capacity map
    116     const CapacityMap &_cap;
    117 
    118     // The number of commdities
    119     int _k;
    120     // The source nodes for each commodity
    121     std::vector<Node> _s;
    122     // The sink nodes for each commodity
    123     std::vector<Node> _t;
    124     // The weight of each commodity
    125     // std::vector<Weight> _w;
     308  /// \return <tt>(*this)</tt>
     309  ApproxMCF& addCommodity(
     310      const Node&          s,
     311      const Node&          t,
     312      const CapacityValue& d,
     313      const ValueMap&      cost_map) {
     314    _source.push_back(s);
     315    _target.push_back(t);
     316    if (d > 0)
     317      _demand.push_back(d);
     318    _local_cost = false;
     319    _cost.push_back(&cost_map);
     320    ++_num_commodities;
     321    return *this;
     322  }
    126323
    127     // The flow map (the primal solution).
    128     FlowMap _flow;
    129     // The length map (the dual solution).
    130     LengthMap _len;
    131 
    132     struct PathData {
    133       SPath path;
    134       Value value;
    135       Value min_cap;
    136       int hash;
    137 
    138       PathData() {}
    139       PathData(const SPath& p, Value v, Value mc, int h = 0) :
    140         path(p), value(v), min_cap(mc), hash(h) {}
    141     };
    142 
    143   public:
    144 
    145     /// \brief Constructor.
    146     ///
    147     /// Constructor.
    148     ///
    149     /// \param digraph The digraph the algorithm runs on.
    150     /// \param capacity The capacities of the edges.
    151     MaxMulticommodityFlow( const Digraph &digraph,
    152                            const CapacityMap &capacity ) :
    153       _g(digraph), _cap(capacity), _k(0),
    154       _flow(_g), _len(_g)
    155     {}
     324  /// @overload no cost map, optional demand
     325  ApproxMCF&
     326  addCommodity(const Node& s, const Node& t, const CapacityValue& d = 0) {
     327    const ValueMap* cost_map_ptr = Traits::createValueMapConstPtr(_graph);
     328    addCommodity(s, t, d, *cost_map_ptr);
     329    _local_cost = true;
     330    return *this;
     331  }
    156332
    157     /// \brief Constructor.
    158     ///
    159     /// Constructor.
    160     ///
    161     /// \param gr The digraph the algorithm runs on.
    162     /// \param capacity The capacities of the edges.
    163     /// \param k The number of commodities.
    164     /// \param sources A vector containing the source nodes
    165     /// (its size must be at least \c k).
    166     /// \param sinks A vector containing the sink nodes
    167     /// (its size must be at least \c k).
    168     MaxMulticommodityFlow( const Digraph &gr,
    169                            const CapacityMap &capacity,
    170                            int k,
    171                            const std::vector<Node>& sources,
    172                            const std::vector<Node>& sinks ) :
    173       _g(gr), _cap(capacity),
    174       _k(k), _s(sources), _t(sinks),
    175       _flow(_g), _len(_g)
    176     {
    177       _s.resize(k);
    178       _t.resize(k);
    179     }
     333  /// @}
    180334
    181     /// Destructor.
    182     ~MaxMulticommodityFlow() {}
     335  /// \name Execution control
    183336
    184     /// \brief Add a new commodity.
    185     ///
    186     /// This function adds a new commodity with the given source and
    187     /// sink nodes.
    188     void addCommodity(const Node& s, const Node& t) {
    189       ++_k;
    190       _s.push_back(s);
    191       _t.push_back(t);
    192     }
    193 
    194     /// \name Execution control
    195 
    196     /// @{
     337  /// @{
    197338
    198     /// \brief Run the algorithm for finding a maximum multicommodity flow.
    199     ///
    200     /// This function runs the algorithm for finding a maximum multicommodity
    201     /// flow.
    202     /// \param r The approximation factor. It must be greater than 1.
    203     /// \return The effective approximation factor (at least 1), i.e. the
    204     /// ratio of the values of the found dual and primal solutions.
    205     /// Therefore both the primal and dual solutions are r-approximate.
    206     ///
    207     /// \note The smaller parameter \c r is, the slower the algorithm runs,
    208     /// but it might find better solution. According to our tests, using
    209     /// the default value the algorithm performs well and it usually manage
    210     /// to find the exact optimum due to heuristic improvements.
    211     Value run(Value r = 2.0, Value opt = 0) {
    212 
    213     #define MMF_FLEISCHER_IMPR
    214     #define MMF_HEURISTIC_IMPR
    215     //#define MMF_EXP_UPDATE
    216     //#define MMF_DEBUG_OUTPUT
    217 
    218       // Initialize epsilon and delta parameters
    219       Tolerance<Value> ftol, ctol;
    220       if (!ftol.less(1.0, r)) return 0;
    221 #ifdef MMF_FLEISCHER_IMPR
    222   #ifdef MMF_EXP_UPDATE
    223       Value epsilon = (r + 1 - 2 * pow(r, 0.5)) / (r - 1);
    224   #else
    225       Value epsilon = (2 * r + 1 - pow(8 * r + 1, 0.5)) / (2 * r);
    226   #endif
    227 #else
    228   #ifdef MMF_EXP_UPDATE
    229       Value epsilon = (2 * r + 1 - pow(8 * r + 1, 0.5)) / (2 * r);
    230   #else
    231       Value epsilon = 1 - pow(r, -0.5);
    232   #endif
    233 #endif
    234      
    235 #ifdef MMF_DEBUG_OUTPUT     
    236       std::cout << "r = " << r << "; epsilon = " << epsilon << "\n";
    237 #endif
    238      
    239       int node_num = countNodes(_g);
    240       Value delta = pow(1 + epsilon, 1 - 1/epsilon) /
    241                     pow(node_num, 1/epsilon);
    242       ctol.epsilon(delta * 0.0001);
    243 
    244       // Initialize flow values and lengths
    245       for (ArcIt a(_g); a != INVALID; ++a) {
    246         _flow[a] = 0;
    247         _len[a] = delta;
    248       }
    249 
    250       // Check commodities
    251       for (int i = 0; i < _k; ++i) {
    252         if (_s[i] == _t[i] || !bfs(_g).run(_s[i], _t[i])) {
    253           _s[i] = _s[_k - 1];
    254           _t[i] = _t[_k - 1];
    255           --_k;
    256         }
    257       }
    258       if (_k <= 0) return 0;
    259 
     339  /// \brief Run the algorithm for finding a multicommodity flow.
     340  ///
     341  /// This function runs the algorithm for finding a maximum/minimum cost
     342  /// multicommodity flow.
     343  ///
     344  /// \param at  The type of approximation algorithm to use. @see \ref
     345  /// ApproxMCF::ApproxType.
     346  /// \param heuristic Whether the internal heuristics will be applied at the
     347  // end of Fleischer's algorithm.
     348  /// \param epsilon The stopping criterion. Must be positive and larger than
     349  /// 0. The smaller the value, the more accurate the result, but the longer the
     350  /// execution time. By default is 0.1.
     351  void run(
     352      const ApproxType& at        = FLEISCHER_MAX,
     353      const bool&       heuristic = true,
     354      const Value&      epsilon   = 0.1) {
     355    _approx_type = at;
     356    _epsilon     = epsilon;
     357    _heuristic   = heuristic;
     358    check();
     359    switch (_approx_type) {
     360      case FLEISCHER_MAX:
     361        runFleischerMax();
     362        break;
     363      case BINARY_SEARCH_MIN_COST:
     364        runBinarySearchMinCost();
     365        break;
     366      case FLEISCHER_MAX_CONCURRENT:
     367        runFleischerMaxConcurrent();
     368        break;
     369    }
     370  }
    260371
    261       // Successive improvement along shortest paths
    262       std::vector<std::vector<PathData> > paths(_k);
    263 #ifdef MMF_FLEISCHER_IMPR
    264       Value limit = delta * (1 + epsilon);
    265       int i = 0;
    266 #else
    267       std::vector<SPath> curr_paths(_k);
    268 #endif
    269       SPath curr_path;
    270       Value curr_dist;
    271       int iter = 0;
    272       while (true) {
    273 #ifdef MMF_FLEISCHER_IMPR
    274         // Find the shortest path for the i-th commodity
    275         // (w.r.t the current length function)
    276         dijkstra(_g, _len).path(curr_path).dist(curr_dist)
    277           .run(_s[i], _t[i]);
    278        
    279         // Check if the path can be used and increase i or the
    280         // length limit if necessary
    281         if (!ctol.less(curr_dist, limit)) {
    282           if (++i == _k) {
    283             if (!ctol.less(limit, 1.0)) break;
    284             i = 0;
    285             limit *= (1 + epsilon);
    286             if (ctol.less(1.0, limit)) limit = 1.0;
    287           }
    288           continue;
    289         }
    290 #else
    291         // Find the shortest path
    292         Value min_dist = 1.0;
    293         int i = -1;
    294         for (int j = 0; j < _k; ++j) {
    295           if ( !dijkstra(_g, _len).path(curr_paths[j]).dist(curr_dist).
    296                 run(_s[j], _t[j]) ) {
    297             std::cerr << "\n\nERROR!!! "<<j<<":"<<_k<<"\n\n";
    298           }
    299           if (curr_dist < min_dist) {
    300             min_dist = curr_dist;
    301             i = j;
    302           }
    303         }
    304         if (i < 0) break;
    305         curr_path = curr_paths[i];
    306 #endif
     372  /// @}
     373
     374 private:
     375  // Initialize flow values and lengths
     376  void init() {
     377    _iter     = 0;
     378    _obj      = 0;
     379    _dual_obj = 0;
     380    // Allocate paths
     381    _paths.resize(_num_commodities);
     382    // Solution paths
     383    _final_paths.resize(_num_commodities);
     384    _final_flows.resize(_num_commodities);
     385    _final_costs.resize(_num_commodities);
    307386
    308         ++iter;
    309 
    310         // Check if the path is used before
    311         int h = hash(curr_path);
    312         int j;
    313         for (j = 0; j < int(paths[i].size()); ++j) {
    314           bool b = (paths[i][j].hash == h) &&
    315                    (paths[i][j].path.length() == curr_path.length());
    316           if (b) {
    317             for (PathArcIt a1(paths[i][j].path), a2(curr_path);
    318                  b && a1 != INVALID && a2 != INVALID; ++a1, ++a2)
    319               b = _g.id(a1) == _g.id(a2);
    320             if (b) break;
    321           }
    322         }
     387    for (int i = 0; i < _num_commodities; ++i)
     388      _paths[i].clear();
     389    _delta =
     390        pow(1 + _epsilon, 1 - 1 / _epsilon) / pow(_num_nodes, 1 / _epsilon);
     391    _tol.epsilon(_delta * 1e-5);
     392    _limit = _delta * (1 + _epsilon);
    323393
    324         // Set/modify the flow value for the found path
    325         Value gamma;
    326         if (j == int(paths[i].size())) {
    327           gamma = std::numeric_limits<Value>::infinity();
    328           for (PathArcIt a(curr_path); a != INVALID; ++a) {
    329             if (_cap[a] < gamma) gamma = _cap[a];
    330           }
    331           paths[i].push_back(PathData(curr_path, gamma, gamma, h));
    332         } else {
    333           gamma = paths[i][j].min_cap;
    334           paths[i][j].value += gamma;
    335         }
    336 
    337         // Modify the arc lengths along the current path
    338 #ifdef MMF_EXP_UPDATE
    339         for (PathArcIt a(curr_path); a != INVALID; ++a)
    340           _len[a] *= exp(epsilon * gamma / _cap[a]);
    341 #else
    342         for (PathArcIt a(curr_path); a != INVALID; ++a)
    343           _len[a] *= 1 + epsilon * gamma / _cap[a];
    344 #endif
    345       }
    346 
    347       // Setting flow values
    348       for (int i = 0; i < _k; ++i) {
    349         for (int j = 0; j < int(paths[i].size()); ++j) {
    350           Value val = paths[i][j].value;
    351           for (PathArcIt a(paths[i][j].path); a != INVALID; ++a)
    352             _flow[a] += val;
     394    // Allocate/reset flow per commodity and arc
     395    _flow.resize(_num_commodities);
     396    for (int i = 0; i < _num_commodities; ++i)
     397      if (!_flow[i]) {
     398        _flow[i] = Traits::createValueMapPtr(_graph);
     399      } else {
     400        for (ArcIt a(_graph); a != INVALID; ++a) {
     401          (*_flow[i])[a] = 0;
    353402        }
    354403      }
    355404
    356       // Scaling the solution
    357       Value lambda = 0;
    358       for (ArcIt a(_g); a != INVALID; ++a) {
    359         if (_flow[a] / _cap[a] > lambda) lambda = _flow[a] / _cap[a];
     405    // Initialise length and flow map
     406    for (ArcIt a(_graph); a != INVALID; ++a) {
     407      _len[a]        = _delta;
     408      _total_flow[a] = 0;
     409    }
     410
     411    // Initialise phi for cost bounding
     412    if (_approx_type == BINARY_SEARCH_MIN_COST && _cost_bound > 0)
     413      _phi = _delta / _cost_bound;
     414    else
     415      _phi = 0;
     416  }
     417
     418  // Preprocessing checks to ensure that:
     419  //
     420  // 1. Commodities are well-defined
     421  // 2. Input sizes are consistent
     422  // 3. Concurrent case: Feasible split flow exists for each commodity that
     423  // satisfies demand. In the case this doesn't pass, will throw an exception.
     424  //
     425  // TODO(): Group commodities by source, so we only have to solve the shortest
     426  // path once for each group (and length values).
     427  void check() {
     428    LEMON_ASSERT(_tol.positive(_epsilon), "Epsilon must be greater than 0");
     429
     430    // Remove commodities with source = sink or unreachable
     431    for (int i = 0; i < _num_commodities; ++i) {
     432      if (_source[i] == _target[i] ||
     433          !bfs(_graph).run(_source[i], _target[i])) {
     434        _source[i] = _source[_num_commodities - 1];
     435        _target[i] = _target[_num_commodities - 1];
     436        --_num_commodities;
     437      }
     438    }
     439
     440    const int& s_size = _source.size();
     441    const int& t_size = _target.size();
     442    const int& d_size = _demand.size();
     443
     444    switch (_approx_type) {
     445      case FLEISCHER_MAX: {
     446        LEMON_ASSERT(_tol.positive(_num_commodities), "No commodities");
     447        // Check consistency of vector sizes
     448        LEMON_ASSERT(
     449            (_num_commodities == s_size && s_size == t_size &&
     450             !_tol.positive(d_size)),
     451            "All vectors should be of size equal to the number of commodities, "
     452            "and have no demand.");
     453        break;
    360454      }
    361       if (ftol.positive(lambda)) {
    362         lambda = 1 / lambda;
    363         for (ArcIt a(_g); a != INVALID; ++a) _flow[a] *= lambda;
    364         for (int i = 0; i < _k; ++i) {
    365           for (int j = 0; j < int(paths[i].size()); ++j)
    366             paths[i][j].value *= lambda;
     455      case FLEISCHER_MAX_CONCURRENT:
     456      case BINARY_SEARCH_MIN_COST: {
     457        // Check consistency of vector sizes
     458        LEMON_ASSERT(
     459            (_num_commodities == s_size && s_size == t_size &&
     460             s_size == d_size),
     461            "All vectors should be of size equal to the number of commodities");
     462        // Remove commodities with 0 demand.
     463        for (int i = 0; i < _num_commodities; ++i) {
     464          if (!_tol.positive(_demand[i])) {
     465            _source[i] = _source[_num_commodities - 1];
     466            _target[i] = _target[_num_commodities - 1];
     467            --_num_commodities;
     468          }
     469        }
     470        LEMON_ASSERT(_tol.positive(_num_commodities), "No commodities");
     471
     472        // Check if feasible routing of demand exists for each commodity
     473        for (int i = 0; i < _num_commodities; ++i) {
     474          // Only check commodity if the demand in non-zero
     475          // Check if feasible split flow exists
     476          // Total capacity outgoing at the source
     477          CapacityValue total_cap_source = 0;
     478          CapacityValue max_cap_source   = 0;
     479          for (OutArcIt a(_graph, _source[i]); a != INVALID; ++a) {
     480            total_cap_source += _cap[a];
     481            if (max_cap_source < _cap[a])
     482              max_cap_source = _cap[a];
     483          }
     484
     485          // Total capacity incoming at the target
     486          CapacityValue total_cap_target = 0;
     487          CapacityValue max_cap_target   = 0;
     488          for (InArcIt a(_graph, _target[i]); a != INVALID; ++a) {
     489            total_cap_target += _cap[a];
     490            if (max_cap_target < _cap[a])
     491              max_cap_target = _cap[a];
     492          }
     493
     494          // Check if enough capacity to satisfy the demand
     495          LEMON_ASSERT(
     496              (total_cap_source >= _demand[i] &&
     497               total_cap_target >= _demand[i]),
     498              "No feasible (split) flow to satisfy demand for commodity" +
     499                  std::to_string(i));
     500
     501          // Check if feasible unsplittable flow exists that satisfies demand
     502          if (max_cap_source < _demand[i] || max_cap_target < _demand[i])
     503            _feasible_unsplit = false;
    367504        }
    368505      }
     506    }
     507  }
    369508
    370 #ifdef MMF_DEBUG_OUTPUT
    371       Value value1 = 0;
    372       for (int i = 0; i < _k; ++i) {
    373         for (InArcIt a(_g, _t[i]); a != INVALID; ++a) value1 += _flow[a];
    374         for (OutArcIt a(_g, _t[i]); a != INVALID; ++a) value1 -= _flow[a];
     509  // Run standard max concurrent algorithm iteratively updating the budget, or
     510  // cost bound, a la binary search to obtain an approximation to the
     511  // multicommodity flow minimum cost
     512  void runBinarySearchMinCost() {
     513    // Run standard max concurrent
     514    runFleischerMaxConcurrent();
     515
     516    Value lower_bound = 0, upper_bound = getTotalCost();
     517
     518    // Best solution attributes
     519    Value          curr_best_cost = std::numeric_limits<Value>::infinity();
     520    ValueMapVector curr_best_flow;
     521
     522    while ((upper_bound - lower_bound) / upper_bound > _epsilon &&
     523           upper_bound >= lower_bound) {
     524      // Run Max Concurrent algorithm with cost bound
     525      _cost_bound = (upper_bound + lower_bound) / 2;
     526      runFleischerMaxConcurrent();
     527      // Update upper/lower bounds
     528      if (_total_cost < _cost_bound)
     529        upper_bound = _cost_bound;
     530      else
     531        lower_bound = _cost_bound;
     532      // Save current solution if appropriate
     533      if (_total_cost < curr_best_cost) {
     534        curr_best_cost = _total_cost;
     535        curr_best_flow = _flow;
    375536      }
    376       Value max_opt = value1 / (1 - epsilon);
     537    }
     538    // Update flow
     539    _total_cost = curr_best_cost;
     540    _flow       = curr_best_flow;
     541  }
    377542
    378       std::cout << "\n";
    379       std::cout << "Computation finished. Iterations: " << iter << "\n";
    380       std::cout << "Solution value:   " << value1;
    381       if (opt > 0) std::cout << "  \t" << value1 / opt * 100 << "%";
    382       std::cout << std::endl;
    383 #else
    384       opt = opt; // avoid warning
    385 #endif
     543  void runFleischerMaxConcurrent() {
     544    // Successive improvement along shortest paths
     545    init();
     546    Path  curr_path;
     547    Value curr_dist;
     548    while (true) {
     549      // Find the shortest path for the i-th commodity
     550      // (w.r.t the current length function)
     551      for (int i = 0; i < _num_commodities; ++i) {
     552        // Route demand
     553        CapacityValue d_i = _demand[i];
     554        while (true) {  // while (phase)
     555          dijkstra(_graph, _len)
     556              .path(curr_path)
     557              .dist(curr_dist)
     558              .run(_source[i], _target[i]);
     559          // Get
     560          const CapacityValue& routed_flow = updatePaths(curr_path, i, d_i);
     561          // Update demand
     562          d_i -= routed_flow;
     563          updateLen(curr_path, routed_flow, i);
     564          updateDualObjective();
     565          if (d_i <= 0 || !_tol.less(_dual_obj, 1))
     566            break;
     567        }  // end while (phase)
     568      }
     569      ++_iter;
     570      updateDualObjective();
     571      if (!_tol.less(_dual_obj, 1))
     572        break;
     573    }  // end while (main)
     574
     575    // Clean up
     576    scaleFinalFlowsMaxConcurrent();
     577
     578    if (_heuristic)
     579      randomisedRounding();
     580
     581    setFlowPerCommodity();
     582    setFinalCost();
     583    saveFinalPaths();
     584  }
     585
     586  void runFleischerMax() {
     587    // Successive improvement along shortest paths
     588    int   i = 0;
     589    Path  curr_path;
     590    Value curr_dist;
     591    init();
     592    while (true) {  // start while
     593      dijkstra(_graph, _len)
     594          .path(curr_path)
     595          .dist(curr_dist)
     596          .run(_source[i], _target[i]);
    386597
    387 #ifdef MMF_DEBUG_OUTPUT
    388       Value tmp = 0;
    389       for (ArcIt a(_g); a != INVALID; ++a)
    390         tmp += _cap[a] * _len[a];
    391       std::cout << "Final dual: " << tmp << "\n";
    392 #endif
     598      // Check if the path can be used and increase i or the length limit if
     599      // necessary
     600      if (!_tol.less(curr_dist, _limit)) {
     601        if (++i == _num_commodities) {
     602          if (!_tol.less(_limit, 1.0))
     603            break;
     604          i = 0;
     605          _limit *= (1 + _epsilon);
     606          if (_tol.less(1.0, _limit))
     607            _limit = 1.0;
     608        }
     609        continue;
     610      }
     611      const CapacityValue& routed_flow = updatePaths(curr_path, i);
     612      // Update dual values
     613      updateLen(curr_path, routed_flow, i);
     614      ++_iter;
     615    }  // end while
     616
     617    scaleFinalFlowsMaxFlow();
     618
     619    if (_heuristic) {
     620      runHeurMax1();
     621      runHeurMax2();
     622    }
     623
     624    setFlowPerCommodity();
     625
     626    // Get dual objective
     627    _dual_obj = getDualObjective();
     628    // Get objective value
     629    _obj = 0;
     630    for (int i = 0; i < _num_commodities; ++i) {
     631      for (InArcIt a(_graph, _target[i]); a != INVALID; ++a)
     632        _obj += (*_flow[i])[a];
     633      for (OutArcIt a(_graph, _target[i]); a != INVALID; ++a)
     634        _obj -= (*_flow[i])[a];
     635    }
     636  }
    393637
    394 #ifdef MMF_HEURISTIC_IMPR
    395       // Heuristic improvement 1: improve the solution along one of the
    396       // found paths if it is possible
    397       int opi = 0;
    398       for (int i = 0; i < _k; ++i) {
    399         for (int j = 0; j < int(paths[i].size()); ++j) {
    400           Value d = std::numeric_limits<Value>::infinity();
    401           for (PathArcIt a(paths[i][j].path); a != INVALID; ++a)
    402             if (_cap[a] - _flow[a] < d) d = _cap[a] - _flow[a];
    403           if (ftol.positive(d)) {
    404             paths[i][j].value += d;
    405             for (PathArcIt a(paths[i][j].path); a != INVALID; ++a)
    406               _flow[a] += d;
    407             ++opi;
     638  // Randomised rounding - if flow is split over multiple paths, randomised
     639  // rounding randomly rounds up the largest proportion of flow/cost.
     640  //
     641  // Only runs if flow can be routed without splitting.
     642  // If costs are given, to make expensive paths less likely to occur, we use,
     643  // for each path j a value[j] = flow / cost for the discrete distribution.
     644  // This distribution samples path j with a probability value[j] / sum values
     645  void randomisedRounding() {
     646    // Only works if flow can be routed without splitting.
     647    if (!_feasible_unsplit)
     648      return;
     649    for (int i = 0; i < _num_commodities; ++i) {
     650      const int&         p_size       = static_cast<int>(_paths[i].size());
     651      Value              total_flow_i = 0;
     652      std::vector<Value> values(p_size, 0);
     653
     654      for (int j = 0; j < p_size; ++j) {
     655        const Value& val  = _paths[i][j].value;
     656        const Value& cost = _paths[i][j].cost;
     657        total_flow_i += val;
     658        values[j] = val;
     659        if (_tol.positive(cost))
     660          values[j] /= cost;
     661      }
     662      // Get random index wrt values[j] / sum of values
     663      int                          chosen_p_idx;
     664      std::random_device           rd;
     665      std::mt19937                 gen(rd());
     666      std::discrete_distribution<> d(values.begin(), values.end());
     667      chosen_p_idx = d(gen);
     668      // Check routing all demand through chosen_p_idx remains capacity feasible
     669      bool capacity_feasible = true;
     670      // cost is all demand routed through here
     671      for (PathArcIt a(_paths[i][chosen_p_idx].path); a != INVALID; ++a) {
     672        if (_total_flow[a] - _paths[i][chosen_p_idx].value + _demand[i] >
     673            _cap[a]) {
     674          capacity_feasible = false;
     675          break;
     676        }
     677      }
     678      if (capacity_feasible) {
     679        for (int j = 0; j < p_size; ++j) {
     680          // Update total flows and path flow
     681          if (j == chosen_p_idx) {  // path j routes demand
     682            for (PathArcIt a(_paths[i][j].path); a != INVALID; ++a) {
     683              _total_flow[a] = _total_flow[a] - _paths[i][j].value + _demand[i];
     684            }
     685            _paths[i][j].value = _demand[i];
     686          } else {  // path j flow is 0
     687            for (PathArcIt a(_paths[i][j].path); a != INVALID; ++a) {
     688              _total_flow[a] = _total_flow[a] - _paths[i][j].value;
     689            }
     690            _paths[i][j].value = 0;
    408691          }
    409692        }
    410693      }
     694    }
     695  }
    411696
    412       // Heuristic improvement 2: improve the solution along new paths
    413       // if it is possible
    414       int npi = 0;
    415       BoolArcMap filter(_g);
    416       for (ArcIt a(_g); a != INVALID; ++a)
    417         filter[a] = ftol.positive(_cap[a] - _flow[a]);
    418       FilterArcs<const Digraph, BoolArcMap> sub_graph(_g, filter);
    419       SPath p;
    420       for (int i = 0; i < _k; ++i) {
    421         while (bfs(sub_graph).path(p).run(_s[i], _t[i])) {
    422           Value d = std::numeric_limits<Value>::infinity();
    423           for (PathArcIt a(p); a != INVALID; ++a)
    424             if (_cap[a] - _flow[a] < d) d = _cap[a] - _flow[a];
    425           paths[i].push_back(PathData(p, d, d));
    426           for (PathArcIt a(p); a != INVALID; ++a) {
    427             _flow[a] += d;
    428             filter[a] = ftol.positive(_cap[a] - _flow[a]);
    429           }
    430           ++npi;
     697  // Heuristic improvement 1 (for FLEISCHER_MAX only).
     698  //
     699  // Attempts to improve the solution along one of the found paths if it is
     700  // possible
     701  void runHeurMax1() {
     702    for (int i = 0; i < _num_commodities; ++i) {
     703      for (int j = 0; j < static_cast<int>(_paths[i].size()); ++j) {
     704        CapacityValue d = std::numeric_limits<CapacityValue>::infinity();
     705        for (PathArcIt a(_paths[i][j].path); a != INVALID; ++a)
     706          if (_cap[a] - _total_flow[a] < d)
     707            d = _cap[a] - _total_flow[a];
     708        if (_tol.positive(d)) {
     709          _paths[i][j].value += d;
     710          for (PathArcIt a(_paths[i][j].path); a != INVALID; ++a)
     711            _total_flow[a] += d;
     712        }
     713      }
     714    }
     715  }
     716
     717  // Heuristic improvement 2 (for FLEISCHER_MAX only).
     718  //
     719  // Attempts to improve the solution along new paths
     720  void runHeurMax2() {
     721    BoolArcMap filter(_graph);
     722    for (ArcIt a(_graph); a != INVALID; ++a)
     723      filter[a] = _tol.positive(_cap[a] - _total_flow[a]);
     724    FilterArcs<const Digraph, BoolArcMap> sub_graph(_graph, filter);
     725    Path                                  p;
     726    for (int i = 0; i < _num_commodities; ++i) {
     727      while (bfs(sub_graph).path(p).run(_source[i], _target[i])) {
     728        CapacityValue d = std::numeric_limits<CapacityValue>::infinity();
     729        for (PathArcIt a(p); a != INVALID; ++a)
     730          if (_cap[a] - _total_flow[a] < d)
     731            d = _cap[a] - _total_flow[a];
     732        _paths[i].push_back(PathData(p, d, d, 0, 0));
     733        for (PathArcIt a(p); a != INVALID; ++a) {
     734          _total_flow[a] += d;
     735          filter[a] = _tol.positive(_cap[a] - _total_flow[a]);
    431736        }
    432737      }
    433 #endif
    434 
    435 #ifdef MMF_DEBUG_OUTPUT
    436       Value value2 = 0;
    437       for (int i = 0; i < _k; ++i) {
    438         for (InArcIt a(_g, _t[i]); a != INVALID; ++a) value2 += _flow[a];
    439         for (OutArcIt a(_g, _t[i]); a != INVALID; ++a) value2 -= _flow[a];
    440       }
    441       epsilon = 1 - value2 / max_opt;
     738    }
     739  }
    442740
    443   #ifdef MMF_HEURISTIC_IMPR
    444       std::cout << "\nHeuristics applied. Old impr: " << opi << "  new impr: " << npi << "\n";
    445   #endif
    446       std::cout << "Solution value:   " << value2;
    447       if (opt > 0) std::cout << "  \t" << value2 / opt * 100 << "%";
    448       std::cout << std::endl << std::endl;
    449 #endif
     741  // Update paths for current commodity and return flow routed
     742  Value updatePaths(
     743      const Path&          curr_path,
     744      const int&           i,
     745      const CapacityValue& d_i =
     746          std::numeric_limits<CapacityValue>::infinity()) {
     747    int h = hash(curr_path);
     748    int j;  // path index
     749    for (j = 0; j < static_cast<int>(_paths[i].size()); ++j) {
     750      bool b = (_paths[i][j].hash == h) &&
     751               (_paths[i][j].path.length() == curr_path.length());
     752      if (b) {
     753        for (PathArcIt a1(_paths[i][j].path), a2(curr_path);
     754             b && a1 != INVALID && a2 != INVALID;
     755             ++a1, ++a2)
     756          b = _graph.id(a1) == _graph.id(a2);
     757        if (b)
     758          break;
     759      }
     760    }
     761    const bool path_seen = !(j == static_cast<int>(_paths[i].size()));
    450762
    451       // TODO: better return value
    452       return r;
     763    // Set/modify the flow value for the found path
     764    Value         routed_flow = 0;
     765    CapacityValue min_cap;
     766    if (!path_seen) {
     767      // Add new path
     768      Value path_cost = 0;
     769      min_cap         = std::numeric_limits<CapacityValue>::infinity();
     770      for (PathArcIt a(curr_path); a != INVALID; ++a) {
     771        path_cost += (*_cost[i])[a];
     772        if (_cap[a] < min_cap)
     773          min_cap = _cap[a];
     774      }
     775      routed_flow = std::min(min_cap, d_i);
     776      // Save path
     777      _paths[i].push_back(
     778          PathData(curr_path, routed_flow, min_cap, path_cost, h));
     779    } else {
     780      // Update path flow
     781      min_cap     = _paths[i][j].min_cap;
     782      routed_flow = std::min(min_cap, d_i);
     783      _paths[i][j].value += routed_flow;
    453784    }
     785    return routed_flow;
     786  }
    454787
    455     /// @}
     788  // Modify the arc lengths along the current path
     789  void updateLen(const Path& p, const Value& f, const int& i) {
     790    Value path_cost = 0;
     791    for (PathArcIt a(p); a != INVALID; ++a) {
     792      const Value& c_a = (*_cost[i])[a];
     793      _len[a] *= 1 + _epsilon * f / _cap[a] + c_a * _phi;
     794      path_cost += c_a;
     795    }
     796    // Update phi if needed
     797    if (_tol.positive(_phi))
     798      _phi *= (1 + (_epsilon * path_cost * f) / _cost_bound);
     799  }
    456800
    457   private:
     801  void updateDualObjective() {
     802    _dual_obj = 0;
     803    for (ArcIt a(_graph); a != INVALID; ++a)
     804      _dual_obj += _cap[a] * _len[a];
     805  }
    458806
    459     int hash(const SPath& path) {
    460       int h = path.length();
    461       for (PathArcIt a(path); a != INVALID; ++a)
    462         h = (h<<4) ^ (h>>28) ^ _g.id(a);
    463       return h;
     807  void setFinalCost() {
     808    _total_cost = 0;
     809    for (int i = 0; i < _num_commodities; ++i) {
     810      for (int j = 0; j < static_cast<int>((_paths[i].size())); ++j) {
     811        for (PathArcIt a(_paths[i][j].path); a != INVALID; ++a)
     812          _total_cost += (*_cost[i])[a] * (*_flow[i])[a];
     813      }
    464814    }
     815  }
    465816
    466   public:
    467 
    468     /// \name Query Functions
    469     /// The result of the algorithm can be obtained using these
    470     /// functions.\n
    471     /// \ref run() must be called before using them.
    472 
    473     /// @{
     817  // Scale flows in the \ref FLEISCHER_MAX_CONCURRENT.
     818  // Flows are scaled by the number of iterations.
     819  void scaleFinalFlowsMaxConcurrent() {
     820    int scaler = _iter;
     821    for (int i = 0; i < _num_commodities; ++i) {
     822      for (int j = 0; j < static_cast<int>(_paths[i].size()); ++j) {
     823        _paths[i][j].value /= scaler;
     824        for (PathArcIt a(_paths[i][j].path); a != INVALID; ++a) {
     825          _total_flow[a] += _paths[i][j].value;
     826        }
     827      }
     828    }
     829    _obj = (_iter) / scaler;
     830  }
    474831
    475     /// \brief Return the flow value on the given arc.
    476     ///
    477     /// This function returns the flow value on the given arc.
    478     ///
    479     /// \pre \ref run() must be called before using this function.
    480     Value flow(const Arc& arc) const {
    481       return _flow[arc];
     832  // Update total flow map
     833  void updateTotalFlow() {
     834    for (int i = 0; i < _num_commodities; ++i) {
     835      for (int j = 0; j < static_cast<int>(_paths[i].size()); ++j) {
     836        CapacityValue val = _paths[i][j].value;
     837        for (PathArcIt a(_paths[i][j].path); a != INVALID; ++a)
     838          _total_flow[a] += val;
     839      }
    482840    }
     841  }
    483842
    484     /// \brief Return a const reference to an arc map storing the
    485     /// found flow.
    486     ///
    487     /// This function returns a const reference to an arc map storing
    488     /// the found flow.
    489     ///
    490     /// \pre \ref run() must be called before using this function.
    491     const FlowMap& flowMap() const {
    492       return _flow;
     843  // Scale flows per commodity for the FLEISCHER_MAX case.
     844  // scaler = max {total_flow_a / cap_a} such that all flows are capacity
     845  // feasible
     846  void scaleFinalFlowsMaxFlow() {
     847    updateTotalFlow();
     848    Value scaler = 0;
     849    for (ArcIt a(_graph); a != INVALID; ++a) {
     850      if (_total_flow[a] / _cap[a] > scaler)
     851        scaler = _total_flow[a] / _cap[a];
     852    }
     853    if (_tol.positive(scaler)) {
     854      for (ArcIt a(_graph); a != INVALID; ++a) {
     855        _total_flow[a] /= scaler;
     856      }
     857      for (int i = 0; i < _num_commodities; ++i) {
     858        for (int j = 0; j < static_cast<int>(_paths[i].size()); ++j)
     859          _paths[i][j].value /= scaler;
     860      }
    493861    }
     862  }
     863
     864  // Set flow decomposed solution for exposure
     865  void setFlowPerCommodity() {
     866    // Setting flow values using saved paths
     867    for (int i = 0; i < _num_commodities; ++i) {
     868      for (int j = 0; j < static_cast<int>(_paths[i].size()); ++j) {
     869        Value val = _paths[i][j].value;
     870        for (PathArcIt a(_paths[i][j].path); a != INVALID; ++a)
     871          (*_flow[i])[a] += val;
     872      }
     873    }
     874  }
     875
     876  void saveFinalPaths() {
     877    for (int i = 0; i < _num_commodities; ++i) {
     878      const int& p_size     = static_cast<int>(_paths[i].size());
     879      bool       saved_path = false;
     880      Value      path_flow  = 0;
     881      Value      path_cost  = std::numeric_limits<Value>::infinity();
     882      Path       path;
    494883
    495     /// \brief Return the length of the given arc (the dual value).
    496     ///
    497     /// This function returns the length of the given arc (the dual value).
    498     ///
    499     /// \pre \ref run() must be called before using this function.
    500     Value length(const Arc& arc) const {
    501       return _len[arc];
     884      for (int j = 0; j < p_size; ++j) {
     885        const Value& v = _paths[i][j].value;
     886        const Value& c = _paths[i][j].cost;
     887        if (_tol.positive(v)) {
     888          if (saved_path)
     889            std::cout << "[WARNING] multiple paths with positive flow"
     890                      << std::endl;
     891          // Keep path with largest flow
     892          if (path_flow < v && c < path_cost) {
     893            path       = _paths[i][j].path;
     894            path_flow  = v;
     895            path_cost  = c;
     896            saved_path = true;
     897          }
     898        }
     899      }
     900      _final_paths[i] = path;
     901      _final_flows[i] = path_flow;
     902      _final_costs[i] = path_cost;
    502903    }
     904  }
     905
     906 public:
     907  const Value& flow(const int& k, const Arc& arc) const {
     908    return (*_flow[k])[arc];
     909  }
    503910
    504     /// \brief Return a const reference to an arc map storing the
    505     /// found lengths (the dual solution).
    506     ///
    507     /// This function returns a const reference to an arc map storing
    508     /// the found lengths (the dual solution).
    509     ///
    510     /// \pre \ref run() must be called before using this function.
    511     const LengthMap& lengthMap() const {
    512       return _len;
    513     }
     911  const Value& flow(const int& k, const int& arc_id) const {
     912    return (*_flow[k])[_graph.arcFromId(arc_id)];
     913  }
     914
     915  const Value& length(const Arc& arc) const { return _len[arc]; }
     916
     917  const ValueMap& lengthMap() const { return _len; }
     918
     919  const Value& getObjective() const { return _obj; }
     920
     921  const Value& getDualObjective() const { return _dual_obj; }
     922
     923  const Value& getTotalCost() const { return _total_cost; }
    514924
    515     /// @}
     925  const ValueMap& getFlowMap(const int& k) const { return *_flow[k]; }
    516926
    517   }; //class MaxMulticommodityFlow
     927  const Path& getPath(const int& k) const { return _final_paths[k]; }
     928
     929  const Value& getPathCost(const int& k) const { return _final_costs[k]; }
    518930
    519   ///@}
     931  const Value& getPathFlow(const int& k) const { return _final_flows[k]; }
     932};  // namespace lemon
     933/// @}
    520934
    521 } //namespace lemon
     935}  // namespace lemon
    522936
    523 #endif //LEMON_MULTICOMMODITY_FLOW_H
     937#endif  // LEMON_MULTICOMMODITY_FLOW_H_
  • new file test/multicommodity_flow_test.cc

    diff -r 86d9dd6da44d test/multicommodity_flow_test.cc
    - +  
     1/* -*- mode: C++; indent-tabs-mode: nil; -*-
     2 *
     3 * This file is a part of LEMON, a generic C++ optimization library.
     4 *
     5 * Copyright (C) 2003-2021
     6 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
     7 * (Egervary Research Group on Combinatorial Optimization, EGRES).
     8 *
     9 * Permission to use, modify and distribute this software is granted
     10 * provided that this copyright notice appears in all copies. For
     11 * precise terms see the accompanying LICENSE file.
     12 *
     13 * This software is provided "AS IS" with no warranty of any kind,
     14 * express or implied, and with no claim as to its suitability for any
     15 * purpose.
     16 *
     17 */
     18
     19#include <lemon/concepts/digraph.h>
     20#include <lemon/concepts/maps.h>
     21#include <lemon/lgf_reader.h>
     22#include <lemon/multicommodity_flow.h>
     23#include <lemon/smart_graph.h>
     24
     25#include <iostream>
     26#include <sstream>
     27
     28#include "test/test_tools.h"
     29
     30char test_lgf[] =
     31    "@nodes\n"
     32    "label\n"
     33    "0\n"
     34    "1\n"
     35    "2\n"
     36    "3\n"
     37    "@arcs\n"
     38    "    label  cap   cost  solution_1  solution_2 solution_1_max  "
     39    "solution_2_max\n"
     40    "0 1   0    10.0  1.0      10.0        0.0         10.0    0.0\n"
     41    "0 2   1    10.0  1.0       0.0        10.0        8.3     1.7\n"
     42    "1 3   2    10.0  1.0      10.0        0.0         10.0    0.0\n"
     43    "2 3   3    10.0  1000.0   0.0         0.0         8.3     0.0\n"
     44    "@attributes\n"
     45    "source_1 0\n"
     46    "target_1 3\n"
     47    "source_2 0\n"
     48    "target_2 2\n";
     49
     50using namespace lemon;
     51
     52// Returns string for test-naming
     53template<typename GR, typename A = typename GR::Arc>
     54std::string getEdgeName(const GR& graph, const A& edge) {
     55  return std::to_string(graph.id(graph.source(edge))) + "->" +
     56         std::to_string(graph.id(graph.target(edge)));
     57}
     58
     59template<class Digraph>
     60void checkApproxMCF() {
     61  TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
     62
     63  Digraph                                           graph;
     64  Node                                              s1, t1, s2, t2;
     65  typedef typename Digraph::template ArcMap<double> DoubleMap;
     66  DoubleMap cap(graph), cost(graph), sol1(graph), sol2(graph), sol1_max(graph),
     67      sol2_max(graph);
     68  Tolerance<double> tol;
     69  tol.epsilon(1e-1);  // 1 decimal place
     70
     71  std::istringstream input(test_lgf);
     72  DigraphReader<Digraph>(graph, input)
     73      .arcMap("cap", cap)
     74      .arcMap("cost", cost)
     75      .arcMap("solution_1", sol1)  // flow in the solution for commodity 1
     76      .arcMap("solution_2", sol2)  // flow in the solution for commodity 1
     77      .arcMap(
     78          "solution_1_max",
     79          sol1_max)  // flow in the solution for commodity (max-flow) 1
     80      .arcMap(
     81          "solution_2_max",
     82          sol2_max)          // flow in the solution for commodity (max-flow) 1
     83      .node("source_1", s1)  // source node commodity 1
     84      .node("target_1", t1)  // target node commodity 1
     85      .node("source_2", s2)  // source node commodity 2
     86      .node("target_2", t2)  // target node commodity 2
     87      .run();
     88
     89  // Max
     90  {
     91    ApproxMCF<Digraph> max(graph, cap);
     92    max.addCommodity(s1, t1).addCommodity(s2, t2).run();
     93    for (ArcIt e(graph); e != INVALID; ++e) {
     94      const std::string test_name =
     95          "[FLEISCHER_MAX] flow on " + getEdgeName<Digraph>(graph, e);
     96      // Check flow for commodity 1 (index 0) to 1 decimal place
     97      check(
     98          !tol.different(max.flow(0, e), sol1_max[e]),
     99          test_name + " commodity 1");
     100      // Check flow for commodity 2 (index 1) to 1 decimal place
     101      check(
     102          !tol.different(max.flow(1, e), sol2_max[e]),
     103          test_name + " commodity 2");
     104    }
     105  }
     106
     107  // Max Concurrent
     108  {
     109    ApproxMCF<Digraph> max(graph, cap);
     110    max.addCommodity(s1, t1, 10.0)
     111        .addCommodity(s2, t2, 10.0)
     112        .run(ApproxMCF<Digraph>::FLEISCHER_MAX_CONCURRENT);
     113    for (ArcIt e(graph); e != INVALID; ++e) {
     114      const std::string test_name = "[FLEISCHER_MAX_CONCURRENT] flow on " +
     115                                    getEdgeName<Digraph>(graph, e);
     116      // Check commodity 1 (index 0)
     117      check(max.flow(0, e) == sol1[e], test_name + " commodity 1");
     118      // Check commodity 2 (index 1)
     119      check(max.flow(1, e) == sol2[e], test_name + " commodity 2");
     120    }
     121  }
     122
     123  // Min cost
     124  {
     125    ApproxMCF<Digraph> max(graph, cap);
     126    max.addCommodity(s1, t1, 10.0, cost)
     127        .addCommodity(s2, t2, 10.0, cost)
     128        .run(ApproxMCF<Digraph>::BINARY_SEARCH_MIN_COST);
     129    for (ArcIt e(graph); e != INVALID; ++e) {
     130      const std::string test_name =
     131          "[BINARY_SEARCH_MIN_COST] flow on " + getEdgeName<Digraph>(graph, e);
     132      // Check commodity 1 (index 0)
     133      check(max.flow(0, e) == sol1[e], test_name + " commodity 1");
     134      // Check commodity 2 (index 1)
     135      check(max.flow(1, e) == sol2[e], test_name + " commodity 2");
     136    }
     137    // Check total cost
     138    check(max.getTotalCost() == 30.0, "min-cost failed");
     139  }
     140
     141  // Max Concurrent - 3 commodities
     142  {
     143    ApproxMCF<Digraph> max(graph, cap);
     144    max.addCommodity(s1, t1, 5.0, cost)
     145        .addCommodity(s1, t2, 10.0, cost)
     146        .addCommodity(s1, t1, 5.0, cost)
     147        .run(ApproxMCF<Digraph>::FLEISCHER_MAX_CONCURRENT);
     148
     149    const DoubleMap& flow = max.getFlowMap(0);
     150    check(
     151        max.getTotalCost() == 30.0,
     152        "3 commodities FLEISCHER_MAX_CONCURRENT failed");
     153  }
     154}
     155
     156template<class Digraph>
     157void checkApproxMCFDisconnected() {
     158  TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
     159
     160  Digraph                                           graph;
     161  typedef typename Digraph::template ArcMap<double> DoubleMap;
     162  DoubleMap cap(graph), cost(graph), sol1(graph), sol2(graph);
     163
     164  Node n0 = graph.addNode();
     165  Node n1 = graph.addNode();
     166  Node n2 = graph.addNode();
     167  Node n3 = graph.addNode();
     168
     169  Arc a;
     170  a       = graph.addArc(n0, n1);
     171  cap[a]  = 10.0;
     172  cost[a] = 1.0;
     173  sol1[a] = 10.0;
     174  sol2[a] = 0.0;
     175
     176  a       = graph.addArc(n2, n3);
     177  cap[a]  = 10.0;
     178  cost[a] = 1.0;
     179  sol1[a] = 0.0;
     180  sol2[a] = 10.0;
     181
     182  // Max
     183  {
     184    ApproxMCF<Digraph> max(graph, cap);
     185    max.addCommodity(n0, n1).addCommodity(n2, n3).run();
     186    for (ArcIt e(graph); e != INVALID; ++e) {
     187      const std::string test_name =
     188          "[FLEISCHER_MAX] flow on " + getEdgeName<Digraph>(graph, e);
     189      // Check commodity 1
     190      check(max.flow(0, e) == sol1[e], test_name + " commodity 1");
     191      // Check commodity 2
     192      check(max.flow(1, e) == sol2[e], test_name + " commodity 2");
     193    }
     194  }
     195  // Max Concurrent
     196  {
     197    ApproxMCF<Digraph> max(graph, cap);
     198    max.addCommodity(n0, n1, 10.0, cost)
     199        .addCommodity(n2, n3, 10.0, cost)
     200        .run(ApproxMCF<Digraph>::FLEISCHER_MAX_CONCURRENT);
     201    for (ArcIt e(graph); e != INVALID; ++e) {
     202      const std::string test_name = "[FLEISCHER_MAX_CONCURRENT] flow on " +
     203                                    getEdgeName<Digraph>(graph, e);
     204      // Check commodity 1
     205      check(max.flow(0, e) == sol1[e], test_name + " commodity 1");
     206      // Check commodity 2
     207      check(max.flow(1, e) == sol2[e], test_name + " commodity 2");
     208    }
     209  }
     210}
     211
     212int main() {
     213  checkApproxMCF<SmartDigraph>();
     214  checkApproxMCF<ListDigraph>();
     215  checkApproxMCFDisconnected<SmartDigraph>();
     216  checkApproxMCFDisconnected<ListDigraph>();
     217}