COIN-OR::LEMON - Graph Library

Ticket #47: 2f64c4a692a8.patch

File 2f64c4a692a8.patch, 22.5 KB (added by Alpar Juttner, 16 years ago)
  • lemon/Makefile.am

    # HG changeset patch
    # User Alpar Juttner <alpar@cs.elte.hu>
    # Date 1225219193 0
    # Node ID 2f64c4a692a87056623c6fffafd76432806ee593
    # Parent  956a29f3088780b83149718f6ae7756cb187d5fe
    Port Suurballe algorithm from svn -r3512
    
    diff --git a/lemon/Makefile.am b/lemon/Makefile.am
    a b  
    4040        lemon/path.h \
    4141        lemon/random.h \
    4242        lemon/smart_graph.h \
     43        lemon/suurballe.h \
    4344        lemon/time_measure.h \
    4445        lemon/tolerance.h \
    4546        lemon/unionfind.h
  • new file lemon/suurballe.h

    diff --git a/lemon/suurballe.h b/lemon/suurballe.h
    new file mode 100644
    - +  
     1/* -*- C++ -*-
     2 *
     3 * This file is a part of LEMON, a generic C++ optimization library
     4 *
     5 * Copyright (C) 2003-2008
     6 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
     7 * (Egervary Research Group on Combinatorial Optimization, EGRES).
     8 *
     9 * Permission to use, modify and distribute this software is granted
     10 * provided that this copyright notice appears in all copies. For
     11 * precise terms see the accompanying LICENSE file.
     12 *
     13 * This software is provided "AS IS" with no warranty of any kind,
     14 * express or implied, and with no claim as to its suitability for any
     15 * purpose.
     16 *
     17 */
     18
     19#ifndef LEMON_SUURBALLE_H
     20#define LEMON_SUURBALLE_H
     21
     22///\ingroup shortest_path
     23///\file
     24///\brief An algorithm for finding arc-disjoint paths between two
     25/// nodes having minimum total length.
     26
     27#include <vector>
     28#include <lemon/bin_heap.h>
     29#include <lemon/path.h>
     30
     31namespace lemon {
     32
     33  /// \addtogroup shortest_path
     34  /// @{
     35
     36  /// \brief Implementation of an algorithm for finding arc-disjoint
     37  /// paths between two nodes having minimum total length.
     38  ///
     39  /// \ref lemon::Suurballe "Suurballe" implements an algorithm for
     40  /// finding arc-disjoint paths having minimum total length (cost)
     41  /// from a given source node to a given target node in a directed
     42  /// digraph.
     43  ///
     44  /// In fact, this implementation is the specialization of the
     45  /// \ref CapacityScaling "successive shortest path" algorithm.
     46  ///
     47  /// \tparam Digraph The directed digraph type the algorithm runs on.
     48  /// \tparam LengthMap The type of the length (cost) map.
     49  ///
     50  /// \warning Length values should be \e non-negative \e integers.
     51  ///
     52  /// \note For finding node-disjoint paths this algorithm can be used
     53  /// with \ref SplitDigraphAdaptor.
     54  ///
     55  /// \author Attila Bernath and Peter Kovacs
     56 
     57  template < typename Digraph,
     58             typename LengthMap = typename Digraph::template ArcMap<int> >
     59  class Suurballe
     60  {
     61    TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
     62
     63    typedef typename LengthMap::Value Length;
     64    typedef ConstMap<Arc, int> ConstArcMap;
     65    typedef typename Digraph::template NodeMap<Arc> PredMap;
     66
     67  public:
     68
     69    /// The type of the flow map.
     70    typedef typename Digraph::template ArcMap<int> FlowMap;
     71    /// The type of the potential map.
     72    typedef typename Digraph::template NodeMap<Length> PotentialMap;
     73    /// The type of the path structures.
     74    typedef SimplePath<Digraph> Path;
     75
     76  private:
     77 
     78    /// \brief Special implementation of the \ref Dijkstra algorithm
     79    /// for finding shortest paths in the residual network.
     80    ///
     81    /// \ref ResidualDijkstra is a special implementation of the
     82    /// \ref Dijkstra algorithm for finding shortest paths in the
     83    /// residual network of the digraph with respect to the reduced arc
     84    /// lengths and modifying the node potentials according to the
     85    /// distance of the nodes.
     86    class ResidualDijkstra
     87    {
     88      typedef typename Digraph::template NodeMap<int> HeapCrossRef;
     89      typedef BinHeap<Length, HeapCrossRef> Heap;
     90
     91    private:
     92
     93      // The directed digraph the algorithm runs on
     94      const Digraph &_graph;
     95
     96      // The main maps
     97      const FlowMap &_flow;
     98      const LengthMap &_length;
     99      PotentialMap &_potential;
     100
     101      // The distance map
     102      PotentialMap _dist;
     103      // The pred arc map
     104      PredMap &_pred;
     105      // The processed (i.e. permanently labeled) nodes
     106      std::vector<Node> _proc_nodes;
     107     
     108      Node _s;
     109      Node _t;
     110
     111    public:
     112
     113      /// Constructor.
     114      ResidualDijkstra( const Digraph &digraph,
     115                        const FlowMap &flow,
     116                        const LengthMap &length,
     117                        PotentialMap &potential,
     118                        PredMap &pred,
     119                        Node s, Node t ) :
     120        _graph(digraph), _flow(flow), _length(length), _potential(potential),
     121        _dist(digraph), _pred(pred), _s(s), _t(t) {}
     122
     123      /// \brief Runs the algorithm. Returns \c true if a path is found
     124      /// from the source node to the target node.
     125      bool run() {
     126        HeapCrossRef heap_cross_ref(_graph, Heap::PRE_HEAP);
     127        Heap heap(heap_cross_ref);
     128        heap.push(_s, 0);
     129        _pred[_s] = INVALID;
     130        _proc_nodes.clear();
     131
     132        // Processing nodes
     133        while (!heap.empty() && heap.top() != _t) {
     134          Node u = heap.top(), v;
     135          Length d = heap.prio() + _potential[u], nd;
     136          _dist[u] = heap.prio();
     137          heap.pop();
     138          _proc_nodes.push_back(u);
     139
     140          // Traversing outgoing arcs
     141          for (OutArcIt e(_graph, u); e != INVALID; ++e) {
     142            if (_flow[e] == 0) {
     143              v = _graph.target(e);
     144              switch(heap.state(v)) {
     145              case Heap::PRE_HEAP:
     146                heap.push(v, d + _length[e] - _potential[v]);
     147                _pred[v] = e;
     148                break;
     149              case Heap::IN_HEAP:
     150                nd = d + _length[e] - _potential[v];
     151                if (nd < heap[v]) {
     152                  heap.decrease(v, nd);
     153                  _pred[v] = e;
     154                }
     155                break;
     156              case Heap::POST_HEAP:
     157                break;
     158              }
     159            }
     160          }
     161
     162          // Traversing incoming arcs
     163          for (InArcIt e(_graph, u); e != INVALID; ++e) {
     164            if (_flow[e] == 1) {
     165              v = _graph.source(e);
     166              switch(heap.state(v)) {
     167              case Heap::PRE_HEAP:
     168                heap.push(v, d - _length[e] - _potential[v]);
     169                _pred[v] = e;
     170                break;
     171              case Heap::IN_HEAP:
     172                nd = d - _length[e] - _potential[v];
     173                if (nd < heap[v]) {
     174                  heap.decrease(v, nd);
     175                  _pred[v] = e;
     176                }
     177                break;
     178              case Heap::POST_HEAP:
     179                break;
     180              }
     181            }
     182          }
     183        }
     184        if (heap.empty()) return false;
     185
     186        // Updating potentials of processed nodes
     187        Length t_dist = heap.prio();
     188        for (int i = 0; i < int(_proc_nodes.size()); ++i)
     189          _potential[_proc_nodes[i]] += _dist[_proc_nodes[i]] - t_dist;
     190        return true;
     191      }
     192
     193    }; //class ResidualDijkstra
     194
     195  private:
     196
     197    // The directed digraph the algorithm runs on
     198    const Digraph &_graph;
     199    // The length map
     200    const LengthMap &_length;
     201   
     202    // Arc map of the current flow
     203    FlowMap *_flow;
     204    bool _local_flow;
     205    // Node map of the current potentials
     206    PotentialMap *_potential;
     207    bool _local_potential;
     208
     209    // The source node
     210    Node _source;
     211    // The target node
     212    Node _target;
     213
     214    // Container to store the found paths
     215    std::vector< SimplePath<Digraph> > paths;
     216    int _path_num;
     217
     218    // The pred arc map
     219    PredMap _pred;
     220    // Implementation of the Dijkstra algorithm for finding augmenting
     221    // shortest paths in the residual network
     222    ResidualDijkstra *_dijkstra;
     223
     224  public:
     225
     226    /// \brief Constructor.
     227    ///
     228    /// Constructor.
     229    ///
     230    /// \param digraph The directed digraph the algorithm runs on.
     231    /// \param length The length (cost) values of the arcs.
     232    /// \param s The source node.
     233    /// \param t The target node.
     234    Suurballe( const Digraph &digraph,
     235               const LengthMap &length,
     236               Node s, Node t ) :
     237      _graph(digraph), _length(length), _flow(0), _local_flow(false),
     238      _potential(0), _local_potential(false), _source(s), _target(t),
     239      _pred(digraph) {}
     240
     241    /// Destructor.
     242    ~Suurballe() {
     243      if (_local_flow) delete _flow;
     244      if (_local_potential) delete _potential;
     245      delete _dijkstra;
     246    }
     247
     248    /// \brief Sets the flow map.
     249    ///
     250    /// Sets the flow map.
     251    ///
     252    /// The found flow contains only 0 and 1 values. It is the union of
     253    /// the found arc-disjoint paths.
     254    ///
     255    /// \return \c (*this)
     256    Suurballe& flowMap(FlowMap &map) {
     257      if (_local_flow) {
     258        delete _flow;
     259        _local_flow = false;
     260      }
     261      _flow = &map;
     262      return *this;
     263    }
     264
     265    /// \brief Sets the potential map.
     266    ///
     267    /// Sets the potential map.
     268    ///
     269    /// The potentials provide the dual solution of the underlying
     270    /// minimum cost flow problem.
     271    ///
     272    /// \return \c (*this)
     273    Suurballe& potentialMap(PotentialMap &map) {
     274      if (_local_potential) {
     275        delete _potential;
     276        _local_potential = false;
     277      }
     278      _potential = &map;
     279      return *this;
     280    }
     281
     282    /// \name Execution control
     283    /// The simplest way to execute the algorithm is to call the run()
     284    /// function.
     285    /// \n
     286    /// If you only need the flow that is the union of the found
     287    /// arc-disjoint paths, you may call init() and findFlow().
     288
     289    /// @{
     290
     291    /// \brief Runs the algorithm.
     292    ///
     293    /// Runs the algorithm.
     294    ///
     295    /// \param k The number of paths to be found.
     296    ///
     297    /// \return \c k if there are at least \c k arc-disjoint paths
     298    /// from \c s to \c t. Otherwise it returns the number of
     299    /// arc-disjoint paths found.
     300    ///
     301    /// \note Apart from the return value, <tt>s.run(k)</tt> is just a
     302    /// shortcut of the following code.
     303    /// \code
     304    ///   s.init();
     305    ///   s.findFlow(k);
     306    ///   s.findPaths();
     307    /// \endcode
     308    int run(int k = 2) {
     309      init();
     310      findFlow(k);
     311      findPaths();
     312      return _path_num;
     313    }
     314
     315    /// \brief Initializes the algorithm.
     316    ///
     317    /// Initializes the algorithm.
     318    void init() {
     319      // Initializing maps
     320      if (!_flow) {
     321        _flow = new FlowMap(_graph);
     322        _local_flow = true;
     323      }
     324      if (!_potential) {
     325        _potential = new PotentialMap(_graph);
     326        _local_potential = true;
     327      }
     328      for (ArcIt e(_graph); e != INVALID; ++e) (*_flow)[e] = 0;
     329      for (NodeIt n(_graph); n != INVALID; ++n) (*_potential)[n] = 0;
     330
     331      _dijkstra = new ResidualDijkstra( _graph, *_flow, _length,
     332                                        *_potential, _pred,
     333                                        _source, _target );
     334    }
     335
     336    /// \brief Executes the successive shortest path algorithm to find
     337    /// an optimal flow.
     338    ///
     339    /// Executes the successive shortest path algorithm to find a
     340    /// minimum cost flow, which is the union of \c k or less
     341    /// arc-disjoint paths.
     342    ///
     343    /// \return \c k if there are at least \c k arc-disjoint paths
     344    /// from \c s to \c t. Otherwise it returns the number of
     345    /// arc-disjoint paths found.
     346    ///
     347    /// \pre \ref init() must be called before using this function.
     348    int findFlow(int k = 2) {
     349      // Finding shortest paths
     350      _path_num = 0;
     351      while (_path_num < k) {
     352        // Running Dijkstra
     353        if (!_dijkstra->run()) break;
     354        ++_path_num;
     355
     356        // Setting the flow along the found shortest path
     357        Node u = _target;
     358        Arc e;
     359        while ((e = _pred[u]) != INVALID) {
     360          if (u == _graph.target(e)) {
     361            (*_flow)[e] = 1;
     362            u = _graph.source(e);
     363          } else {
     364            (*_flow)[e] = 0;
     365            u = _graph.target(e);
     366          }
     367        }
     368      }
     369      return _path_num;
     370    }
     371   
     372    /// \brief Computes the paths from the flow.
     373    ///
     374    /// Computes the paths from the flow.
     375    ///
     376    /// \pre \ref init() and \ref findFlow() must be called before using
     377    /// this function.
     378    void findPaths() {
     379      // Creating the residual flow map (the union of the paths not
     380      // found so far)
     381      FlowMap res_flow(_graph);
     382      for(ArcIt a(_graph);a!=INVALID;++a) res_flow[a]=(*_flow)[a];
     383
     384      paths.clear();
     385      paths.resize(_path_num);
     386      for (int i = 0; i < _path_num; ++i) {
     387        Node n = _source;
     388        while (n != _target) {
     389          OutArcIt e(_graph, n);
     390          for ( ; res_flow[e] == 0; ++e) ;
     391          n = _graph.target(e);
     392          paths[i].addBack(e);
     393          res_flow[e] = 0;
     394        }
     395      }
     396    }
     397
     398    /// @}
     399
     400    /// \name Query Functions
     401    /// The result of the algorithm can be obtained using these
     402    /// functions.
     403    /// \n The algorithm should be executed before using them.
     404
     405    /// @{
     406
     407    /// \brief Returns a const reference to the arc map storing the
     408    /// found flow.
     409    ///
     410    /// Returns a const reference to the arc map storing the flow that
     411    /// is the union of the found arc-disjoint paths.
     412    ///
     413    /// \pre \ref run() or findFlow() must be called before using this
     414    /// function.
     415    const FlowMap& flowMap() const {
     416      return *_flow;
     417    }
     418
     419    /// \brief Returns a const reference to the node map storing the
     420    /// found potentials (the dual solution).
     421    ///
     422    /// Returns a const reference to the node map storing the found
     423    /// potentials that provide the dual solution of the underlying
     424    /// minimum cost flow problem.
     425    ///
     426    /// \pre \ref run() or findFlow() must be called before using this
     427    /// function.
     428    const PotentialMap& potentialMap() const {
     429      return *_potential;
     430    }
     431
     432    /// \brief Returns the flow on the given arc.
     433    ///
     434    /// Returns the flow on the given arc.
     435    /// It is \c 1 if the arc is involved in one of the found paths,
     436    /// otherwise it is \c 0.
     437    ///
     438    /// \pre \ref run() or findFlow() must be called before using this
     439    /// function.
     440    int flow(const Arc& arc) const {
     441      return (*_flow)[arc];
     442    }
     443
     444    /// \brief Returns the potential of the given node.
     445    ///
     446    /// Returns the potential of the given node.
     447    ///
     448    /// \pre \ref run() or findFlow() must be called before using this
     449    /// function.
     450    Length potential(const Node& node) const {
     451      return (*_potential)[node];
     452    }
     453
     454    /// \brief Returns the total length (cost) of the found paths (flow).
     455    ///
     456    /// Returns the total length (cost) of the found paths (flow).
     457    /// The complexity of the function is \f$ O(e) \f$.
     458    ///
     459    /// \pre \ref run() or findFlow() must be called before using this
     460    /// function.
     461    Length totalLength() const {
     462      Length c = 0;
     463      for (ArcIt e(_graph); e != INVALID; ++e)
     464        c += (*_flow)[e] * _length[e];
     465      return c;
     466    }
     467
     468    /// \brief Returns the number of the found paths.
     469    ///
     470    /// Returns the number of the found paths.
     471    ///
     472    /// \pre \ref run() or findFlow() must be called before using this
     473    /// function.
     474    int pathNum() const {
     475      return _path_num;
     476    }
     477
     478    /// \brief Returns a const reference to the specified path.
     479    ///
     480    /// Returns a const reference to the specified path.
     481    ///
     482    /// \param i The function returns the \c i-th path.
     483    /// \c i must be between \c 0 and <tt>%pathNum()-1</tt>.
     484    ///
     485    /// \pre \ref run() or findPaths() must be called before using this
     486    /// function.
     487    Path path(int i) const {
     488      return paths[i];
     489    }
     490
     491    /// @}
     492
     493  }; //class Suurballe
     494
     495  ///@}
     496
     497} //namespace lemon
     498
     499#endif //LEMON_SUURBALLE_H
  • test/Makefile.am

    diff --git a/test/Makefile.am b/test/Makefile.am
    a b  
    11EXTRA_DIST += \
    2         test/CMakeLists.txt
     2        test/CMakeLists.txt \
     3        test/min_cost_flow_test.lgf
    34
    45noinst_HEADERS += \
    56        test/graph_test.h \
     
    2223        test/max_matching_test \
    2324        test/random_test \
    2425        test/path_test \
     26        test/suurballe_test \
    2527        test/test_tools_fail \
    2628        test/test_tools_pass \
    2729        test/time_measure_test \
     
    4547test_maps_test_SOURCES = test/maps_test.cc
    4648test_max_matching_test_SOURCES = test/max_matching_test.cc
    4749test_path_test_SOURCES = test/path_test.cc
     50test_suurballe_test_SOURCES = test/suurballe_test.cc
    4851test_random_test_SOURCES = test/random_test.cc
    4952test_test_tools_fail_SOURCES = test/test_tools_fail.cc
    5053test_test_tools_pass_SOURCES = test/test_tools_pass.cc
  • new file test/min_cost_flow_test.lgf

    diff --git a/test/min_cost_flow_test.lgf b/test/min_cost_flow_test.lgf
    new file mode 100644
    - +  
     1@nodes
     2label   supply1 supply2 supply3
     31       0       20      27     
     42       0       -4      0               
     53       0       0       0       
     64       0       0       0       
     75       0       9       0       
     86       0       -6      0       
     97       0       0       0       
     108       0       0       0       
     119       0       3       0       
     1210      0       -2      0       
     1311      0       0       0               
     1412      0       -20     -27     
     15               
     16@arcs
     17                cost    capacity        lower1  lower2
     181       2       70      11              0       8
     191       3       150     3               0       1
     201       4       80      15              0       2
     212       8       80      12              0       0
     223       5       140     5               0       3
     234       6       60      10              0       1
     244       7       80      2               0       0
     254       8       110     3               0       0
     265       7       60      14              0       0
     275       11      120     12              0       0
     286       3       0       3               0       0
     296       9       140     4               0       0
     306       10      90      8               0       0
     317       1       30      5               0       0
     328       12      60      16              0       4
     339       12      50      6               0       0
     3410      12      70      13              0       5
     3510      2       100     7               0       0
     3610      7       60      10              0       0
     3711      10      20      14              0       6
     3812      11      30      10              0       0
     39
     40@attributes
     41source  1
     42target  12
     43
     44@end
  • new file test/suurballe_test.cc

    diff --git a/test/suurballe_test.cc b/test/suurballe_test.cc
    new file mode 100644
    - +  
     1/* -*- C++ -*-
     2 *
     3 * This file is a part of LEMON, a generic C++ optimization library
     4 *
     5 * Copyright (C) 2003-2008
     6 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
     7 * (Egervary Research Group on Combinatorial Optimization, EGRES).
     8 *
     9 * Permission to use, modify and distribute this software is granted
     10 * provided that this copyright notice appears in all copies. For
     11 * precise terms see the accompanying LICENSE file.
     12 *
     13 * This software is provided "AS IS" with no warranty of any kind,
     14 * express or implied, and with no claim as to its suitability for any
     15 * purpose.
     16 *
     17 */
     18
     19#include <iostream>
     20#include <fstream>
     21
     22#include <lemon/list_graph.h>
     23#include <lemon/lgf_reader.h>
     24#include <lemon/path.h>
     25#include <lemon/suurballe.h>
     26
     27#include "test_tools.h"
     28
     29using namespace lemon;
     30
     31// Checks the feasibility of the flow
     32template <typename Digraph, typename FlowMap>
     33bool checkFlow( const Digraph& gr, const FlowMap& flow,
     34                typename Digraph::Node s, typename Digraph::Node t,
     35                int value )
     36{
     37  TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
     38  for (ArcIt e(gr); e != INVALID; ++e)
     39    if (!(flow[e] == 0 || flow[e] == 1)) return false;
     40
     41  for (NodeIt n(gr); n != INVALID; ++n) {
     42    int sum = 0;
     43    for (OutArcIt e(gr, n); e != INVALID; ++e)
     44      sum += flow[e];
     45    for (InArcIt e(gr, n); e != INVALID; ++e)
     46      sum -= flow[e];
     47    if (n == s && sum != value) return false;
     48    if (n == t && sum != -value) return false;
     49    if (n != s && n != t && sum != 0) return false;
     50  }
     51
     52  return true;
     53}
     54
     55// Checks the optimalitiy of the flow
     56template < typename Digraph, typename CostMap,
     57           typename FlowMap, typename PotentialMap >
     58bool checkOptimality( const Digraph& gr, const CostMap& cost,
     59                      const FlowMap& flow, const PotentialMap& pi )
     60{
     61  // Checking the Complementary Slackness optimality condition
     62  TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
     63  bool opt = true;
     64  for (ArcIt e(gr); e != INVALID; ++e) {
     65    typename CostMap::Value red_cost =
     66      cost[e] + pi[gr.source(e)] - pi[gr.target(e)];
     67    opt = (flow[e] == 0 && red_cost >= 0) ||
     68          (flow[e] == 1 && red_cost <= 0);
     69    if (!opt) break;
     70  }
     71  return opt;
     72}
     73
     74// Checks a path
     75template < typename Digraph, typename Path >
     76bool checkPath( const Digraph& gr, const Path& path,
     77                typename Digraph::Node s, typename Digraph::Node t)
     78{
     79  // Checking the Complementary Slackness optimality condition
     80  TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
     81  Node n = s;
     82  for (int i = 0; i < path.length(); ++i) {
     83    if (gr.source(path.nth(i)) != n) return false;
     84    n = gr.target(path.nth(i));
     85  }
     86  return n == t;
     87}
     88
     89
     90int main()
     91{
     92  DIGRAPH_TYPEDEFS(ListDigraph);
     93
     94  // Reading the test digraph
     95  ListDigraph digraph;
     96  ListDigraph::ArcMap<int> length(digraph);
     97  Node source, target;
     98
     99  std::string fname;
     100  if(getenv("srcdir"))
     101    fname = std::string(getenv("srcdir"));
     102  else fname = ".";
     103  fname += "/test/min_cost_flow_test.lgf";
     104
     105  std::ifstream input(fname.c_str());
     106  check(input, "Input file '" << fname << "' not found");
     107  DigraphReader<ListDigraph>(digraph, input).
     108    arcMap("cost", length).
     109    node("source", source).
     110    node("target", target).
     111    run();
     112  input.close();
     113 
     114  // Finding 2 paths
     115  {
     116    Suurballe<ListDigraph> suurballe(digraph, length, source, target);
     117    check(suurballe.run(2) == 2, "Wrong number of paths");
     118    check(checkFlow(digraph, suurballe.flowMap(), source, target, 2),
     119          "The flow is not feasible");
     120    check(suurballe.totalLength() == 510, "The flow is not optimal");
     121    check(checkOptimality(digraph, length, suurballe.flowMap(),
     122                          suurballe.potentialMap()),
     123          "Wrong potentials");
     124    for (int i = 0; i < suurballe.pathNum(); ++i)
     125      check(checkPath(digraph, suurballe.path(i), source, target),
     126            "Wrong path");
     127  }
     128
     129  // Finding 3 paths
     130  {
     131    Suurballe<ListDigraph> suurballe(digraph, length, source, target);
     132    check(suurballe.run(3) == 3, "Wrong number of paths");
     133    check(checkFlow(digraph, suurballe.flowMap(), source, target, 3),
     134          "The flow is not feasible");
     135    check(suurballe.totalLength() == 1040, "The flow is not optimal");
     136    check(checkOptimality(digraph, length, suurballe.flowMap(),
     137                          suurballe.potentialMap()),
     138          "Wrong potentials");
     139    for (int i = 0; i < suurballe.pathNum(); ++i)
     140      check(checkPath(digraph, suurballe.path(i), source, target),
     141            "Wrong path");
     142  }
     143
     144  // Finding 5 paths (only 3 can be found)
     145  {
     146    Suurballe<ListDigraph> suurballe(digraph, length, source, target);
     147    check(suurballe.run(5) == 3, "Wrong number of paths");
     148    check(checkFlow(digraph, suurballe.flowMap(), source, target, 3),
     149          "The flow is not feasible");
     150    check(suurballe.totalLength() == 1040, "The flow is not optimal");
     151    check(checkOptimality(digraph, length, suurballe.flowMap(),
     152                          suurballe.potentialMap()),
     153          "Wrong potentials");
     154    for (int i = 0; i < suurballe.pathNum(); ++i)
     155      check(checkPath(digraph, suurballe.path(i), source, target),
     156            "Wrong path");
     157  }
     158
     159  return 0;
     160}