COIN-OR::LEMON - Graph Library

Ticket #56: 5087694945e4.patch

File 5087694945e4.patch, 27.8 KB (added by Balazs Dezso, 13 years ago)

Port of Nagamochi-Ibaraki

  • lemon/Makefile.am

    # HG changeset patch
    # User Balazs Dezso <deba@inf.elte.hu>
    # Date 1289723103 -3600
    # Node ID 5087694945e47bb61f90b69b93bd85a17fdeecff
    # Parent  1937b6455b7d0cff4f1e21bdd7c5a66b4c1af1cf
    New implementation for Nagamochi-Ibaraki algorithm
    
    diff -r 1937b6455b7d -r 5087694945e4 lemon/Makefile.am
    a b  
    107107        lemon/matching.h \
    108108        lemon/math.h \
    109109        lemon/min_cost_arborescence.h \
     110        lemon/nagamochi_ibaraki.h \
    110111        lemon/nauty_reader.h \
    111112        lemon/network_simplex.h \
    112113        lemon/pairing_heap.h \
  • new file lemon/nagamochi_ibaraki.h

    diff -r 1937b6455b7d -r 5087694945e4 lemon/nagamochi_ibaraki.h
    - +  
     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-2010
     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_NAGAMOCHI_IBARAKI_H
     20#define LEMON_NAGAMOCHI_IBARAKI_H
     21
     22
     23/// \ingroup min_cut
     24/// \file
     25/// \brief Implementation of the Nagamochi-Ibaraki algorithm.
     26
     27#include <lemon/core.h>
     28#include <lemon/bin_heap.h>
     29#include <lemon/bucket_heap.h>
     30#include <lemon/maps.h>
     31#include <lemon/radix_sort.h>
     32#include <lemon/unionfind.h>
     33
     34#include <cassert>
     35
     36namespace lemon {
     37
     38  /// \brief Default traits class for NagamochiIbaraki class.
     39  ///
     40  /// Default traits class for NagamochiIbaraki class.
     41  /// \param GR The undirected graph type.
     42  /// \param CM Type of capacity map.
     43  template <typename GR, typename CM>
     44  struct NagamochiIbarakiDefaultTraits {
     45    /// The type of the capacity map.
     46    typedef typename CM::Value Value;
     47
     48    /// The undirected graph type the algorithm runs on.
     49    typedef GR Graph;
     50
     51    /// \brief The type of the map that stores the edge capacities.
     52    ///
     53    /// The type of the map that stores the edge capacities.
     54    /// It must meet the \ref concepts::ReadMap "ReadMap" concept.
     55    typedef CM CapacityMap;
     56
     57    /// \brief Instantiates a CapacityMap.
     58    ///
     59    /// This function instantiates a \ref CapacityMap.
     60#ifdef DOXYGEN
     61    static CapacityMap *createCapacityMap(const Graph& graph)
     62#else
     63    static CapacityMap *createCapacityMap(const Graph&)
     64#endif
     65    {
     66        LEMON_ASSERT(false, "CapacityMap is not initialized");
     67        return 0; // ignore warnings
     68    }
     69
     70    /// \brief The cross reference type used by heap.
     71    ///
     72    /// The cross reference type used by heap.
     73    /// Usually \c Graph::NodeMap<int>.
     74    typedef typename Graph::template NodeMap<int> HeapCrossRef;
     75
     76    /// \brief Instantiates a HeapCrossRef.
     77    ///
     78    /// This function instantiates a \ref HeapCrossRef.
     79    /// \param g is the graph, to which we would like to define the
     80    /// \ref HeapCrossRef.
     81    static HeapCrossRef *createHeapCrossRef(const Graph& g) {
     82      return new HeapCrossRef(g);
     83    }
     84
     85    /// \brief The heap type used by NagamochiIbaraki algorithm.
     86    ///
     87    /// The heap type used by NagamochiIbaraki algorithm. It has to
     88    /// maximize the priorities.
     89    ///
     90    /// \sa BinHeap
     91    /// \sa NagamochiIbaraki
     92    typedef BinHeap<Value, HeapCrossRef, std::greater<Value> > Heap;
     93
     94    /// \brief Instantiates a Heap.
     95    ///
     96    /// This function instantiates a \ref Heap.
     97    /// \param r is the cross reference of the heap.
     98    static Heap *createHeap(HeapCrossRef& r) {
     99      return new Heap(r);
     100    }
     101  };
     102
     103  /// \ingroup min_cut
     104  ///
     105  /// \brief Calculates the minimum cut in an undirected graph.
     106  ///
     107  /// Calculates the minimum cut in an undirected graph with the
     108  /// Nagamochi-Ibaraki algorithm. The algorithm separates the graph's
     109  /// nodes into two partitions with the minimum sum of edge capacities
     110  /// between the two partitions. The algorithm can be used to test
     111  /// the network reliability, especially to test how many links have
     112  /// to be destroyed in the network to split it to at least two
     113  /// distinict subnetworks.
     114  ///
     115  /// The complexity of the algorithm is \f$ O(nm\log(n)) \f$ but with
     116  /// \ref FibHeap "Fibonacci heap" it can be decreased to
     117  /// \f$ O(nm+n^2\log(n)) \f$.  When the edges have unit capacities,
     118  /// \c BucketHeap can be used which yields \f$ O(nm) \f$ time
     119  /// complexity.
     120  ///
     121  /// \warning The value type of the capacity map should be able to
     122  /// hold any cut value of the graph, otherwise the result can
     123  /// overflow.
     124  /// \note This capacity is supposed to be integer type.
     125#ifdef DOXYGEN
     126  template <typename GR, typename CM, typename TR>
     127#else
     128  template <typename GR,
     129            typename CM = typename GR::template EdgeMap<int>,
     130            typename TR = NagamochiIbarakiDefaultTraits<GR, CM> >
     131#endif
     132  class NagamochiIbaraki {
     133  public:
     134
     135    typedef TR Traits;
     136    /// The type of the underlying graph.
     137    typedef typename Traits::Graph Graph;
     138
     139    /// The type of the capacity map.
     140    typedef typename Traits::CapacityMap CapacityMap;
     141    /// The value type of the capacity map.
     142    typedef typename Traits::CapacityMap::Value Value;
     143
     144    /// The heap type used by the algorithm.
     145    typedef typename Traits::Heap Heap;
     146    /// The cross reference type used for the heap.
     147    typedef typename Traits::HeapCrossRef HeapCrossRef;
     148
     149    ///\name Named template parameters
     150
     151    ///@{
     152
     153    struct SetUnitCapacityTraits : public Traits {
     154      typedef ConstMap<typename Graph::Edge, Const<int, 1> > CapacityMap;
     155      static CapacityMap *createCapacityMap(const Graph&) {
     156        return new CapacityMap();
     157      }
     158    };
     159
     160    /// \brief \ref named-templ-param "Named parameter" for setting
     161    /// the capacity map to a constMap<Edge, int, 1>() instance
     162    ///
     163    /// \ref named-templ-param "Named parameter" for setting
     164    /// the capacity map to a constMap<Edge, int, 1>() instance
     165    struct SetUnitCapacity
     166      : public NagamochiIbaraki<Graph, CapacityMap,
     167                                SetUnitCapacityTraits> {
     168      typedef NagamochiIbaraki<Graph, CapacityMap,
     169                               SetUnitCapacityTraits> Create;
     170    };
     171
     172
     173    template <class H, class CR>
     174    struct SetHeapTraits : public Traits {
     175      typedef CR HeapCrossRef;
     176      typedef H Heap;
     177      static HeapCrossRef *createHeapCrossRef(int num) {
     178        LEMON_ASSERT(false, "HeapCrossRef is not initialized");
     179        return 0; // ignore warnings
     180      }
     181      static Heap *createHeap(HeapCrossRef &) {
     182        LEMON_ASSERT(false, "Heap is not initialized");
     183        return 0; // ignore warnings
     184      }
     185    };
     186
     187    /// \brief \ref named-templ-param "Named parameter" for setting
     188    /// heap and cross reference type
     189    ///
     190    /// \ref named-templ-param "Named parameter" for setting heap and
     191    /// cross reference type. The heap has to maximize the priorities.
     192    template <class H, class CR = RangeMap<int> >
     193    struct SetHeap
     194      : public NagamochiIbaraki<Graph, CapacityMap, SetHeapTraits<H, CR> > {
     195      typedef NagamochiIbaraki< Graph, CapacityMap, SetHeapTraits<H, CR> >
     196      Create;
     197    };
     198
     199    template <class H, class CR>
     200    struct SetStandardHeapTraits : public Traits {
     201      typedef CR HeapCrossRef;
     202      typedef H Heap;
     203      static HeapCrossRef *createHeapCrossRef(int size) {
     204        return new HeapCrossRef(size);
     205      }
     206      static Heap *createHeap(HeapCrossRef &crossref) {
     207        return new Heap(crossref);
     208      }
     209    };
     210
     211    /// \brief \ref named-templ-param "Named parameter" for setting
     212    /// heap and cross reference type with automatic allocation
     213    ///
     214    /// \ref named-templ-param "Named parameter" for setting heap and
     215    /// cross reference type with automatic allocation. They should
     216    /// have standard constructor interfaces to be able to
     217    /// automatically created by the algorithm (i.e. the graph should
     218    /// be passed to the constructor of the cross reference and the
     219    /// cross reference should be passed to the constructor of the
     220    /// heap). However, external heap and cross reference objects
     221    /// could also be passed to the algorithm using the \ref heap()
     222    /// function before calling \ref run() or \ref init(). The heap
     223    /// has to maximize the priorities.
     224    /// \sa SetHeap
     225    template <class H, class CR = RangeMap<int> >
     226    struct SetStandardHeap
     227      : public NagamochiIbaraki<Graph, CapacityMap,
     228                                SetStandardHeapTraits<H, CR> > {
     229      typedef NagamochiIbaraki<Graph, CapacityMap,
     230                               SetStandardHeapTraits<H, CR> > Create;
     231    };
     232
     233    ///@}
     234
     235
     236  private:
     237
     238    const Graph &_graph;
     239    const CapacityMap *_capacity;
     240    bool _local_capacity; // unit capacity
     241
     242    struct ArcData {
     243      typename Graph::Node target;
     244      int prev, next;
     245    };
     246    struct EdgeData {
     247      Value capacity;
     248      Value cut;
     249    };
     250
     251    struct NodeData {
     252      int first_arc;
     253      typename Graph::Node prev, next;
     254      int curr_arc;
     255      typename Graph::Node last_rep;
     256      Value sum;
     257    };
     258
     259    typename Graph::template NodeMap<NodeData> *_nodes;
     260    std::vector<ArcData> _arcs;
     261    std::vector<EdgeData> _edges;
     262
     263    typename Graph::Node _first_node;
     264    int _node_num;
     265
     266    Value _min_cut;
     267
     268    HeapCrossRef *_heap_cross_ref;
     269    bool _local_heap_cross_ref;
     270    Heap *_heap;
     271    bool _local_heap;
     272
     273    typedef typename Graph::template NodeMap<typename Graph::Node> NodeList;
     274    NodeList *_next_rep;
     275
     276    typedef typename Graph::template NodeMap<bool> MinCutMap;
     277    MinCutMap *_cut_map;
     278
     279    void createStructures() {
     280      if (!_nodes) {
     281        _nodes = new (typename Graph::template NodeMap<NodeData>)(_graph);
     282      }
     283      if (!_capacity) {
     284        _local_capacity = true;
     285        _capacity = Traits::createCapacityMap(_graph);
     286      }
     287      if (!_heap_cross_ref) {
     288        _local_heap_cross_ref = true;
     289        _heap_cross_ref = Traits::createHeapCrossRef(_graph);
     290      }
     291      if (!_heap) {
     292        _local_heap = true;
     293        _heap = Traits::createHeap(*_heap_cross_ref);
     294      }
     295      if (!_next_rep) {
     296        _next_rep = new NodeList(_graph);
     297      }
     298      if (!_cut_map) {
     299        _cut_map = new MinCutMap(_graph);
     300      }
     301    }
     302
     303  public :
     304
     305    typedef NagamochiIbaraki Create;
     306
     307
     308    /// \brief Constructor.
     309    ///
     310    /// \param graph The graph the algorithm runs on.
     311    /// \param capacity The capacity map used by the algorithm.
     312    NagamochiIbaraki(const Graph& graph, const CapacityMap& capacity)
     313      : _graph(graph), _capacity(&capacity), _local_capacity(false),
     314        _nodes(0), _arcs(), _edges(), _min_cut(),
     315        _heap_cross_ref(0), _local_heap_cross_ref(false),
     316        _heap(0), _local_heap(false),
     317        _next_rep(0), _cut_map(0) {}
     318
     319    /// \brief Constructor.
     320    ///
     321    /// This constructor can be used only when the Traits class
     322    /// defines how can the local capacity map be instantiated.
     323    /// If the SetUnitCapacity used the algorithm automatically
     324    /// constructs the capacity map.
     325    ///
     326    ///\param graph The graph the algorithm runs on.
     327    NagamochiIbaraki(const Graph& graph)
     328      : _graph(graph), _capacity(0), _local_capacity(false),
     329        _nodes(0), _arcs(), _edges(), _min_cut(),
     330        _heap_cross_ref(0), _local_heap_cross_ref(false),
     331        _heap(0), _local_heap(false),
     332        _next_rep(0), _cut_map(0) {}
     333
     334    /// \brief Destructor.
     335    ///
     336    /// Destructor.
     337    ~NagamochiIbaraki() {
     338      if (_local_capacity) delete _capacity;
     339      if (_nodes) delete _nodes;
     340      if (_local_heap) delete _heap;
     341      if (_local_heap_cross_ref) delete _heap_cross_ref;
     342      if (_next_rep) delete _next_rep;
     343      if (_cut_map) delete _cut_map;
     344    }
     345
     346    /// \brief Sets the heap and the cross reference used by algorithm.
     347    ///
     348    /// Sets the heap and the cross reference used by algorithm.
     349    /// If you don't use this function before calling \ref run(),
     350    /// it will allocate one. The destuctor deallocates this
     351    /// automatically allocated heap and cross reference, of course.
     352    /// \return <tt> (*this) </tt>
     353    NagamochiIbaraki &heap(Heap& hp, HeapCrossRef &cr)
     354    {
     355      if (_local_heap_cross_ref) {
     356        delete _heap_cross_ref;
     357        _local_heap_cross_ref = false;
     358      }
     359      _heap_cross_ref = &cr;
     360      if (_local_heap) {
     361        delete _heap;
     362        _local_heap = false;
     363      }
     364      _heap = &hp;
     365      return *this;
     366    }
     367
     368    /// \name Execution control
     369    /// The simplest way to execute the algorithm is to use
     370    /// one of the member functions called \c run().
     371    /// \n
     372    /// If you need more control on the execution,
     373    /// first you must call \ref init() and then call the start()
     374    /// or proper times the processNextPhase() member functions.
     375
     376    ///@{
     377
     378    /// \brief Initializes the internal data structures.
     379    ///
     380    /// Initializes the internal data structures.
     381    void init() {
     382      createStructures();
     383
     384      int edge_num = countEdges(_graph);
     385      _edges.resize(edge_num);
     386      _arcs.resize(2 * edge_num);
     387
     388      typename Graph::Node prev = INVALID;
     389      _node_num = 0;
     390      for (typename Graph::NodeIt n(_graph); n != INVALID; ++n) {
     391        (*_cut_map)[n] = false;
     392        (*_next_rep)[n] = INVALID;
     393        (*_nodes)[n].last_rep = n;
     394        (*_nodes)[n].first_arc = -1;
     395        (*_nodes)[n].curr_arc = -1;
     396        (*_nodes)[n].prev = prev;
     397        if (prev != INVALID) {
     398          (*_nodes)[prev].next = n;
     399        }
     400        (*_nodes)[n].next = INVALID;
     401        (*_nodes)[n].sum = 0;
     402        prev = n;
     403        ++_node_num;
     404      }
     405
     406      _first_node = typename Graph::NodeIt(_graph);
     407
     408      int index = 0;
     409      for (typename Graph::NodeIt n(_graph); n != INVALID; ++n) {
     410        for (typename Graph::OutArcIt a(_graph, n); a != INVALID; ++a) {
     411          typename Graph::Node m = _graph.target(a);
     412         
     413          if (!(n < m)) continue;
     414
     415          (*_nodes)[n].sum += (*_capacity)[a];
     416          (*_nodes)[m].sum += (*_capacity)[a];
     417         
     418          int c = (*_nodes)[m].curr_arc;
     419          if (c != -1 && _arcs[c ^ 1].target == n) {
     420            _edges[c >> 1].capacity += (*_capacity)[a];
     421          } else {
     422            _edges[index].capacity = (*_capacity)[a];
     423           
     424            _arcs[index << 1].prev = -1;
     425            if ((*_nodes)[n].first_arc != -1) {
     426              _arcs[(*_nodes)[n].first_arc].prev = (index << 1);
     427            }
     428            _arcs[index << 1].next = (*_nodes)[n].first_arc;
     429            (*_nodes)[n].first_arc = (index << 1);
     430            _arcs[index << 1].target = m;
     431
     432            (*_nodes)[m].curr_arc = (index << 1);
     433           
     434            _arcs[(index << 1) | 1].prev = -1;
     435            if ((*_nodes)[m].first_arc != -1) {
     436              _arcs[(*_nodes)[m].first_arc].prev = ((index << 1) | 1);
     437            }
     438            _arcs[(index << 1) | 1].next = (*_nodes)[m].first_arc;
     439            (*_nodes)[m].first_arc = ((index << 1) | 1);
     440            _arcs[(index << 1) | 1].target = n;
     441           
     442            ++index;
     443          }
     444        }
     445      }
     446
     447      typename Graph::Node cut_node = INVALID;
     448      _min_cut = std::numeric_limits<Value>::max();
     449
     450      for (typename Graph::Node n = _first_node;
     451           n != INVALID; n = (*_nodes)[n].next) {
     452        if ((*_nodes)[n].sum < _min_cut) {
     453          cut_node = n;
     454          _min_cut = (*_nodes)[n].sum;
     455        }
     456      }
     457      (*_cut_map)[cut_node] = true;
     458      if (_min_cut == 0) {
     459        _first_node = INVALID;
     460      }
     461    }
     462
     463  public:
     464
     465    /// \brief Processes the next phase
     466    ///
     467    /// Processes the next phase in the algorithm. It must be called
     468    /// at most one less the number of the nodes in the graph.
     469    ///
     470    ///\return %True when the algorithm finished.
     471    bool processNextPhase() {
     472      if (_first_node == INVALID) return true;
     473
     474      _heap->clear();
     475      for (typename Graph::Node n = _first_node;
     476           n != INVALID; n = (*_nodes)[n].next) {
     477        (*_heap_cross_ref)[n] = Heap::PRE_HEAP;
     478      }
     479
     480      std::vector<typename Graph::Node> order;
     481      order.reserve(_node_num);
     482      int sep = 0;
     483
     484      Value alpha = 0;
     485      Value pmc = std::numeric_limits<Value>::max();
     486
     487      _heap->push(_first_node, static_cast<Value>(0));
     488      while (!_heap->empty()) {
     489        typename Graph::Node n = _heap->top();
     490        Value v = _heap->prio();
     491
     492        _heap->pop();
     493        for (int a = (*_nodes)[n].first_arc; a != -1; a = _arcs[a].next) {
     494          switch (_heap->state(_arcs[a].target)) {
     495          case Heap::PRE_HEAP:
     496            {
     497              Value nv = _edges[a >> 1].capacity;
     498              _heap->push(_arcs[a].target, nv);
     499              _edges[a >> 1].cut = nv;
     500            } break;
     501          case Heap::IN_HEAP:
     502            {
     503              Value nv = _edges[a >> 1].capacity + (*_heap)[_arcs[a].target];
     504              _heap->decrease(_arcs[a].target, nv);
     505              _edges[a >> 1].cut = nv;
     506            } break;
     507          case Heap::POST_HEAP:
     508            break;
     509          }
     510        }
     511
     512        alpha += (*_nodes)[n].sum;
     513        alpha -= 2 * v;
     514
     515        order.push_back(n);
     516        if (!_heap->empty()) {
     517          if (alpha < pmc) {
     518            pmc = alpha;
     519            sep = order.size();
     520          }
     521        }
     522      }
     523
     524      if (static_cast<int>(order.size()) < _node_num) {
     525        _first_node = INVALID;
     526        for (typename Graph::NodeIt n(_graph); n != INVALID; ++n) {
     527          (*_cut_map)[n] = false;
     528        }
     529        for (int i = 0; i < static_cast<int>(order.size()); ++i) {
     530          typename Graph::Node n = order[i];
     531          while (n != INVALID) {
     532            (*_cut_map)[n] = true;
     533            n = (*_next_rep)[n];
     534          }
     535        }
     536        _min_cut = 0;
     537        return true;
     538      }
     539
     540      if (pmc < _min_cut) {
     541        for (typename Graph::NodeIt n(_graph); n != INVALID; ++n) {
     542          (*_cut_map)[n] = false;
     543        }
     544        for (int i = 0; i < sep; ++i) {
     545          typename Graph::Node n = order[i];
     546          while (n != INVALID) {
     547            (*_cut_map)[n] = true;
     548            n = (*_next_rep)[n];
     549          }
     550        }
     551        _min_cut = pmc;
     552      }
     553
     554      for (typename Graph::Node n = _first_node;
     555           n != INVALID; n = (*_nodes)[n].next) {
     556        bool merged = false;
     557        for (int a = (*_nodes)[n].first_arc; a != -1; a = _arcs[a].next) {
     558          if (!(_edges[a >> 1].cut < pmc)) {
     559            if (!merged) {
     560              for (int b = (*_nodes)[n].first_arc; b != -1; b = _arcs[b].next) {
     561                (*_nodes)[_arcs[b].target].curr_arc = b;         
     562              }
     563              merged = true;
     564            }
     565            typename Graph::Node m = _arcs[a].target;
     566            int nb = 0;
     567            for (int b = (*_nodes)[m].first_arc; b != -1; b = nb) {
     568              nb = _arcs[b].next;
     569              if ((b ^ a) == 1) continue;
     570              typename Graph::Node o = _arcs[b].target;
     571              int c = (*_nodes)[o].curr_arc;
     572              if (c != -1 && _arcs[c ^ 1].target == n) {
     573                _edges[c >> 1].capacity += _edges[b >> 1].capacity;
     574                (*_nodes)[n].sum += _edges[b >> 1].capacity;
     575                if (_edges[b >> 1].cut < _edges[c >> 1].cut) {
     576                  _edges[b >> 1].cut = _edges[c >> 1].cut;
     577                }
     578                if (_arcs[b ^ 1].prev != -1) {
     579                  _arcs[_arcs[b ^ 1].prev].next = _arcs[b ^ 1].next;
     580                } else {
     581                  (*_nodes)[o].first_arc = _arcs[b ^ 1].next;
     582                }
     583                if (_arcs[b ^ 1].next != -1) {
     584                  _arcs[_arcs[b ^ 1].next].prev = _arcs[b ^ 1].prev;
     585                }
     586              } else {
     587                if (_arcs[a].next != -1) {
     588                  _arcs[_arcs[a].next].prev = b;
     589                }
     590                _arcs[b].next = _arcs[a].next;
     591                _arcs[b].prev = a;
     592                _arcs[a].next = b;
     593                _arcs[b ^ 1].target = n;
     594
     595                (*_nodes)[n].sum += _edges[b >> 1].capacity;
     596                (*_nodes)[o].curr_arc = b;
     597              }
     598            }
     599
     600            if (_arcs[a].prev != -1) {
     601              _arcs[_arcs[a].prev].next = _arcs[a].next;
     602            } else {
     603              (*_nodes)[n].first_arc = _arcs[a].next;
     604            }           
     605            if (_arcs[a].next != -1) {
     606              _arcs[_arcs[a].next].prev = _arcs[a].prev;
     607            }
     608
     609            (*_nodes)[n].sum -= _edges[a >> 1].capacity;
     610            (*_next_rep)[(*_nodes)[n].last_rep] = m;
     611            (*_nodes)[n].last_rep = (*_nodes)[m].last_rep;
     612           
     613            if ((*_nodes)[m].prev != INVALID) {
     614              (*_nodes)[(*_nodes)[m].prev].next = (*_nodes)[m].next;
     615            } else{
     616              _first_node = (*_nodes)[m].next;
     617            }
     618            if ((*_nodes)[m].next != INVALID) {
     619              (*_nodes)[(*_nodes)[m].next].prev = (*_nodes)[m].prev;
     620            }
     621            --_node_num;
     622          }
     623        }
     624      }
     625
     626      if (_node_num == 1) {
     627        _first_node = INVALID;
     628        return true;
     629      }
     630
     631      return false;
     632    }
     633
     634    /// \brief Executes the algorithm.
     635    ///
     636    /// Executes the algorithm.
     637    ///
     638    /// \pre init() must be called
     639    void start() {
     640      while (!processNextPhase()) {}
     641    }
     642
     643
     644    /// \brief Runs %NagamochiIbaraki algorithm.
     645    ///
     646    /// This method runs the %Min cut algorithm
     647    ///
     648    /// \note mc.run(s) is just a shortcut of the following code.
     649    ///\code
     650    ///  mc.init();
     651    ///  mc.start();
     652    ///\endcode
     653    void run() {
     654      init();
     655      start();
     656    }
     657
     658    ///@}
     659
     660    /// \name Query Functions
     661    ///
     662    /// The result of the %NagamochiIbaraki
     663    /// algorithm can be obtained using these functions.\n
     664    /// Before the use of these functions, either run() or start()
     665    /// must be called.
     666
     667    ///@{
     668
     669    /// \brief Returns the min cut value.
     670    ///
     671    /// Returns the min cut value if the algorithm finished.
     672    /// After the first processNextPhase() it is a value of a
     673    /// valid cut in the graph.
     674    Value minCutValue() const {
     675      return _min_cut;
     676    }
     677
     678    /// \brief Returns a min cut in a NodeMap.
     679    ///
     680    /// It sets the nodes of one of the two partitions to true and
     681    /// the other partition to false.
     682    /// \param cutMap A \ref concepts::WriteMap "writable" node map with
     683    /// \c bool (or convertible) value type.
     684    template <typename CutMap>
     685    Value minCutMap(CutMap& cutMap) const {
     686      for (typename Graph::NodeIt n(_graph); n != INVALID; ++n) {
     687        cutMap.set(n, (*_cut_map)[n]);
     688      }
     689      return minCutValue();
     690    }
     691
     692    ///@}
     693
     694  };
     695}
     696
     697#endif
  • test/CMakeLists.txt

    diff -r 1937b6455b7d -r 5087694945e4 test/CMakeLists.txt
    a b  
    3535  min_cost_arborescence_test
    3636  min_cost_flow_test
    3737  min_mean_cycle_test
     38  nagamochi_ibaraki_test
    3839  path_test
    3940  planarity_test
    4041  preflow_test
  • test/Makefile.am

    diff -r 1937b6455b7d -r 5087694945e4 test/Makefile.am
    a b  
    3737        test/min_cost_arborescence_test \
    3838        test/min_cost_flow_test \
    3939        test/min_mean_cycle_test \
     40        test/nagamochi_ibaraki_test \
    4041        test/path_test \
    4142        test/planarity_test \
    4243        test/preflow_test \
     
    8990test_min_cost_arborescence_test_SOURCES = test/min_cost_arborescence_test.cc
    9091test_min_cost_flow_test_SOURCES = test/min_cost_flow_test.cc
    9192test_min_mean_cycle_test_SOURCES = test/min_mean_cycle_test.cc
     93test_nagamochi_ibaraki_test_SOURCES = test/nagamochi_ibaraki_test.cc
    9294test_path_test_SOURCES = test/path_test.cc
    9395test_planarity_test_SOURCES = test/planarity_test.cc
    9496test_preflow_test_SOURCES = test/preflow_test.cc
  • new file test/nagamochi_ibaraki_test.cc

    diff -r 1937b6455b7d -r 5087694945e4 test/nagamochi_ibaraki_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-2010
     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 <sstream>
     20
     21#include <lemon/smart_graph.h>
     22#include <lemon/adaptors.h>
     23#include <lemon/concepts/graph.h>
     24#include <lemon/concepts/maps.h>
     25#include <lemon/lgf_reader.h>
     26#include <lemon/nagamochi_ibaraki.h>
     27
     28#include "test_tools.h"
     29
     30using namespace lemon;
     31using namespace std;
     32
     33const std::string lgf =
     34  "@nodes\n"
     35  "label\n"
     36  "0\n"
     37  "1\n"
     38  "2\n"
     39  "3\n"
     40  "4\n"
     41  "5\n"
     42  "@edges\n"
     43  "     cap1 cap2 cap3\n"
     44  "0 1  1    1    1   \n"
     45  "0 2  2    2    4   \n"
     46  "1 2  4    4    4   \n"
     47  "3 4  1    1    1   \n"
     48  "3 5  2    2    4   \n"
     49  "4 5  4    4    4   \n"
     50  "2 3  1    6    6   \n";
     51
     52void checkNagamochiIbarakiCompile()
     53{
     54  typedef int Value;
     55  typedef concepts::Graph Graph;
     56
     57  typedef Graph::Node Node;
     58  typedef Graph::Edge Edge;
     59  typedef concepts::ReadMap<Edge, Value> CapMap;
     60  typedef concepts::WriteMap<Node, bool> CutMap;
     61
     62  Graph g;
     63  Node n;
     64  CapMap cap;
     65  CutMap cut;
     66  Value v;
     67  bool b;
     68
     69  NagamochiIbaraki<Graph, CapMap> ni_test(g, cap);
     70  const NagamochiIbaraki<Graph, CapMap>& const_ni_test = ni_test;
     71
     72  ni_test.init();
     73  ni_test.start();
     74  b = ni_test.processNextPhase();
     75  ni_test.run();
     76
     77  v = const_ni_test.minCutValue();
     78  v = const_ni_test.minCutMap(cut);
     79}
     80
     81template <typename Graph, typename CapMap, typename CutMap>
     82typename CapMap::Value
     83  cutValue(const Graph& graph, const CapMap& cap, const CutMap& cut)
     84{
     85  typename CapMap::Value sum = 0;
     86  for (typename Graph::EdgeIt e(graph); e != INVALID; ++e) {
     87    if (cut[graph.u(e)] != cut[graph.v(e)]) {
     88      sum += cap[e];
     89    }
     90  }
     91  return sum;
     92}
     93
     94int main() {
     95  SmartGraph graph;
     96  SmartGraph::EdgeMap<int> cap1(graph), cap2(graph), cap3(graph);
     97  SmartGraph::NodeMap<bool> cut(graph);
     98
     99  istringstream input(lgf);
     100  graphReader(graph, input)
     101    .edgeMap("cap1", cap1)
     102    .edgeMap("cap2", cap2)
     103    .edgeMap("cap3", cap3)
     104    .run();
     105
     106  {
     107    NagamochiIbaraki<SmartGraph> ni(graph, cap1);
     108    ni.run();
     109    ni.minCutMap(cut);
     110
     111    check(ni.minCutValue() == 1, "Wrong cut value");
     112    check(ni.minCutValue() == cutValue(graph, cap1, cut), "Wrong cut value");
     113  }
     114  {
     115    NagamochiIbaraki<SmartGraph> ni(graph, cap2);
     116    ni.run();
     117    ni.minCutMap(cut);
     118
     119    check(ni.minCutValue() == 3, "Wrong cut value");
     120    check(ni.minCutValue() == cutValue(graph, cap2, cut), "Wrong cut value");
     121  }
     122  {
     123    NagamochiIbaraki<SmartGraph> ni(graph, cap3);
     124    ni.run();
     125    ni.minCutMap(cut);
     126
     127    check(ni.minCutValue() == 5, "Wrong cut value");
     128    check(ni.minCutValue() == cutValue(graph, cap3, cut), "Wrong cut value");
     129  }
     130  {
     131    NagamochiIbaraki<SmartGraph>::SetUnitCapacity::Create ni(graph);
     132    ni.run();
     133    ni.minCutMap(cut);
     134
     135    ConstMap<SmartGraph::Edge, int> cap4(1);
     136    check(ni.minCutValue() == 1, "Wrong cut value");
     137    check(ni.minCutValue() == cutValue(graph, cap4, cut), "Wrong cut value");
     138  }
     139
     140  return 0;
     141}