COIN-OR::LEMON - Graph Library

Ticket #72: 4f7224faf3bd.patch

File 4f7224faf3bd.patch, 20.3 KB (added by Balazs Dezso, 16 years ago)
  • lemon/Makefile.am

    # HG changeset patch
    # User Balazs Dezso <deba@inf.elte.hu>
    # Date 1224280518 -7200
    # Node ID 4f7224faf3bd0bf460965b685cd503a838251df9
    # Parent  6dbd5184c6a99e936a7de899e64c114e30c0f94f
    Porting radix sorts from SVN #3509
    
    diff -r 6dbd5184c6a9 -r 4f7224faf3bd lemon/Makefile.am
    a b  
    3636        lemon/maps.h \
    3737        lemon/math.h \
    3838        lemon/path.h \
     39        lemon/radix_sort.h \
    3940        lemon/random.h \
    4041        lemon/smart_graph.h \
    4142        lemon/time_measure.h \
  • new file lemon/radix_sort.h

    diff -r 6dbd5184c6a9 -r 4f7224faf3bd lemon/radix_sort.h
    - +  
     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 RADIX_SORT_H
     20#define RADIX_SORT_H
     21
     22/// \ingroup auxalg
     23/// \file
     24/// \brief Radix sort
     25///
     26/// Linear time sorting algorithms
     27
     28#include <vector>
     29#include <limits>
     30#include <iterator>
     31#include <algorithm>
     32
     33namespace lemon {
     34
     35  namespace _radix_sort_bits {
     36
     37    template <typename Value>
     38    struct Identity {
     39      const Value& operator()(const Value& val) {
     40        return val;
     41      }
     42    };
     43
     44
     45    template <typename Value, typename Iterator, typename Functor>
     46    Iterator radixSortPartition(Iterator first, Iterator last,
     47                                Functor functor, Value mask) {
     48      while (first != last && !(functor(*first) & mask)) {
     49        ++first;
     50      }
     51      if (first == last) {
     52        return first;
     53      }
     54      --last;
     55      while (first != last && (functor(*last) & mask)) {
     56        --last;
     57      }
     58      if (first == last) {
     59        return first;
     60      }
     61      std::iter_swap(first, last);
     62      ++first;
     63      if (!(first < last)) {
     64        return first;
     65      }
     66      while (true) {
     67        while (!(functor(*first) & mask)) {
     68          ++first;
     69        }
     70        --last;
     71        while (functor(*last) & mask) {
     72          --last;
     73        }
     74        if (!(first < last)) {
     75          return first;
     76        }
     77        std::iter_swap(first, last);
     78        ++first;
     79      }
     80    }
     81
     82    template <typename Iterator, typename Functor>
     83    Iterator radixSortSignPartition(Iterator first, Iterator last,
     84                                    Functor functor) {
     85      while (first != last && functor(*first) < 0) {
     86        ++first;
     87      }
     88      if (first == last) {
     89        return first;
     90      }
     91      --last;
     92      while (first != last && functor(*last) >= 0) {
     93        --last;
     94      }
     95      if (first == last) {
     96        return first;
     97      }
     98      std::iter_swap(first, last);
     99      ++first;
     100      if (!(first < last)) {
     101        return first;
     102      }
     103      while (true) {
     104        while (functor(*first) < 0) {
     105          ++first;
     106        }
     107        --last;
     108        while (functor(*last) >= 0) {
     109          --last;
     110        }
     111        if (!(first < last)) {
     112          return first;
     113        }
     114        std::iter_swap(first, last);
     115        ++first;
     116      }
     117    }
     118
     119    template <typename Value, typename Iterator, typename Functor>
     120    void radixIntroSort(Iterator first, Iterator last,
     121                        Functor functor, Value mask) {
     122      while (mask != 0 && last - first > 1) {
     123        Iterator cut = radixSortPartition(first, last, functor, mask);
     124        mask >>= 1;
     125        radixIntroSort(first, cut, functor, mask);
     126        first = cut;
     127      }
     128    }
     129
     130    template <typename Value, typename Iterator, typename Functor>
     131    void radixSignedSort(Iterator first, Iterator last, Functor functor) {
     132
     133      Iterator cut = radixSortSignPartition(first, last, functor);
     134
     135      Value mask;
     136      int max_digit;
     137      Iterator it;
     138
     139      mask = ~0; max_digit = 0;
     140      for (it = first; it != cut; ++it) {
     141        while ((mask & functor(*it)) != mask) {
     142          ++max_digit;
     143          mask <<= 1;
     144        }
     145      }
     146      radixIntroSort(first, cut, functor, 1 << max_digit);
     147
     148      mask = 0; max_digit = 0;
     149      for (it = cut; it != last; ++it) {
     150        while ((mask | functor(*it)) != mask) {
     151          ++max_digit;
     152          mask <<= 1; mask |= 1;
     153        }
     154      }
     155      radixIntroSort(cut, last, functor, 1 << max_digit);
     156    }
     157
     158    template <typename Value, typename Iterator, typename Functor>
     159    void radixUnsignedSort(Iterator first, Iterator last, Functor functor) {
     160
     161      Value mask = 0;
     162      int max_digit = 0;
     163
     164      Iterator it;
     165      for (it = first; it != last; ++it) {
     166        while ((mask | functor(*it)) != mask) {
     167          ++max_digit;
     168          mask <<= 1; mask |= 1;
     169        }
     170      }
     171      radixIntroSort(first, last, functor, 1 << max_digit);
     172    }
     173
     174
     175    template <typename Value,
     176              bool sign = std::numeric_limits<Value>::is_signed >
     177    struct RadixSortSelector {
     178      template <typename Iterator, typename Functor>
     179      static void sort(Iterator first, Iterator last, Functor functor) {
     180        radixSignedSort<Value>(first, last, functor);
     181      }
     182    };
     183
     184    template <typename Value>
     185    struct RadixSortSelector<Value, false> {
     186      template <typename Iterator, typename Functor>
     187      static void sort(Iterator first, Iterator last, Functor functor) {
     188        radixUnsignedSort<Value>(first, last, functor);
     189      }
     190    };
     191
     192  }
     193
     194  /// \ingroup auxalg
     195  ///
     196  /// \brief Sorts the STL compatible range into ascending order.
     197  ///
     198  /// The \c radixSort sorts the STL compatible range into ascending
     199  /// order.  The radix sort algorithm can sort the items which mapped
     200  /// to an integer with an adaptable unary function \c functor and the
     201  /// order will be ascending by these mapped values. As function
     202  /// specialization it is possible to use a normal function instead
     203  /// of the functor object or if the functor is not given it will use
     204  /// an identity function instead.
     205  ///
     206  /// This implemented radix sort is a special quick sort which pivot
     207  /// value is choosen to partite the items on the next
     208  /// bit. Therefore, let be \c c the maximal capacity and \c n the
     209  /// number of the items in the container, the time complexity of the
     210  /// algorithm is \f$ O(\log(c)n) \f$ and the additional space
     211  /// complexity is \f$ O(\log(c)) \f$.
     212  ///
     213  /// \param first The begin of the given range.
     214  /// \param last The end of the given range.
     215  /// \param functor An adaptible unary function or a normal function
     216  /// which maps the items to any integer type which can be either
     217  /// signed or unsigned.
     218  template <typename Iterator, typename Functor>
     219  void radixSort(Iterator first, Iterator last, Functor functor) {
     220    using namespace _radix_sort_bits;
     221    typedef typename Functor::result_type Value;
     222    RadixSortSelector<Value>::sort(first, last, functor);
     223  }
     224
     225  template <typename Iterator, typename Value, typename Key>
     226  void radixSort(Iterator first, Iterator last, Value (*functor)(Key)) {
     227    using namespace _radix_sort_bits;
     228    RadixSortSelector<Value>::sort(first, last, functor);
     229  }
     230
     231  template <typename Iterator, typename Value, typename Key>
     232  void radixSort(Iterator first, Iterator last, Value& (*functor)(Key)) {
     233    using namespace _radix_sort_bits;
     234    RadixSortSelector<Value>::sort(first, last, functor);
     235  }
     236
     237  template <typename Iterator, typename Value, typename Key>
     238  void radixSort(Iterator first, Iterator last, Value (*functor)(Key&)) {
     239    using namespace _radix_sort_bits;
     240    RadixSortSelector<Value>::sort(first, last, functor);
     241  }
     242
     243  template <typename Iterator, typename Value, typename Key>
     244  void radixSort(Iterator first, Iterator last, Value& (*functor)(Key&)) {
     245    using namespace _radix_sort_bits;
     246    RadixSortSelector<Value>::sort(first, last, functor);
     247  }
     248
     249  template <typename Iterator>
     250  void radixSort(Iterator first, Iterator last) {
     251    using namespace _radix_sort_bits;
     252    typedef typename std::iterator_traits<Iterator>::value_type Value;
     253    RadixSortSelector<Value>::sort(first, last, Identity<Value>());
     254  }
     255
     256  namespace _radix_sort_bits {
     257
     258    template <typename Value>
     259    unsigned char valueByte(Value value, int byte) {
     260      return value >> (std::numeric_limits<unsigned char>::digits * byte);
     261    }
     262
     263    template <typename Functor, typename Key>
     264    void counterIntroSort(Key *first, Key *last, Key *target,
     265                          int byte, Functor functor) {
     266      const int size =
     267        unsigned(std::numeric_limits<unsigned char>::max()) + 1;
     268      std::vector<int> counter(size);
     269      for (int i = 0; i < size; ++i) {
     270        counter[i] = 0;
     271      }
     272      Key *it = first;
     273      while (first != last) {
     274        ++counter[valueByte(functor(*first), byte)];
     275        ++first;
     276      }
     277      int prev, num = 0;
     278      for (int i = 0; i < size; ++i) {
     279        prev = num;
     280        num += counter[i];
     281        counter[i] = prev;
     282      }
     283      while (it != last) {
     284        target[counter[valueByte(functor(*it), byte)]++] = *it;
     285        ++it;
     286      }
     287    }
     288
     289    template <typename Functor, typename Key>
     290    void signedCounterIntroSort(Key *first, Key *last, Key *target,
     291                                int byte, Functor functor) {
     292      const int size =
     293        unsigned(std::numeric_limits<unsigned char>::max()) + 1;
     294      std::vector<int> counter(size);
     295      for (int i = 0; i < size; ++i) {
     296        counter[i] = 0;
     297      }
     298      Key *it = first;
     299      while (first != last) {
     300        counter[valueByte(functor(*first), byte)]++;
     301        ++first;
     302      }
     303      int prev, num = 0;
     304      for (int i = size / 2; i < size; ++i) {
     305        prev = num;
     306        num += counter[i];
     307        counter[i] = prev;
     308      }
     309      for (int i = 0; i < size / 2; ++i) {
     310        prev = num;
     311        num += counter[i];
     312        counter[i] = prev;
     313      }
     314      while (it != last) {
     315        target[counter[valueByte(functor(*it), byte)]++] = *it;
     316        ++it;
     317      }
     318    }
     319
     320 
     321    template <typename Value, typename Iterator, typename Functor>
     322    void counterSignedSort(Iterator first, Iterator last, Functor functor) {
     323      if (first == last) return;
     324      typedef typename std::iterator_traits<Iterator>::value_type Key;
     325      typedef std::allocator<Key> Allocator;
     326      Allocator allocator;
     327
     328      int length = std::distance(first, last);
     329      Key* buffer = allocator.allocate(2 * length);
     330      try {
     331        bool dir = true;
     332        std::copy(first, last, buffer);
     333        for (int i = 0; i < int(sizeof(Value)) - 1; ++i) {
     334          if (dir) {
     335            counterIntroSort(buffer, buffer + length, buffer + length,
     336                             i, functor);
     337          } else {
     338            counterIntroSort(buffer + length, buffer + 2 * length, buffer,
     339                             i, functor);
     340          }
     341          dir = !dir;
     342        }
     343        if (dir) {
     344          signedCounterIntroSort(buffer, buffer + length, buffer + length,
     345                                 sizeof(Value) - 1, functor);
     346          std::copy(buffer + length, buffer + 2 * length, first);
     347        }       else {
     348          signedCounterIntroSort(buffer + length, buffer + 2 * length, buffer,
     349                                 sizeof(Value) - 1, functor);
     350          std::copy(buffer, buffer + length, first);
     351        }
     352      } catch (...) {
     353        allocator.deallocate(buffer, 2 * length);
     354        throw;
     355      }
     356      allocator.deallocate(buffer, 2 * length);
     357    }
     358
     359    template <typename Value, typename Iterator, typename Functor>
     360    void counterUnsignedSort(Iterator first, Iterator last, Functor functor) {
     361      if (first == last) return;
     362      typedef typename std::iterator_traits<Iterator>::value_type Key;
     363      typedef std::allocator<Key> Allocator;
     364      Allocator allocator;
     365
     366      int length = std::distance(first, last);
     367      Key *buffer = allocator.allocate(2 * length);
     368      try {
     369        bool dir = true;
     370        std::copy(first, last, buffer);
     371        for (int i = 0; i < int(sizeof(Value)); ++i) {
     372          if (dir) {
     373            counterIntroSort(buffer, buffer + length,
     374                             buffer + length, i, functor);
     375          } else {
     376            counterIntroSort(buffer + length, buffer + 2 * length,
     377                             buffer, i, functor);
     378          }
     379          dir = !dir;
     380        }
     381        if (dir) {
     382          std::copy(buffer, buffer + length, first);
     383        }       else {
     384          std::copy(buffer + length, buffer + 2 * length, first);
     385        }
     386      } catch (...) {
     387        allocator.deallocate(buffer, 2 * length);
     388        throw;
     389      }
     390      allocator.deallocate(buffer, 2 * length);
     391    }
     392
     393
     394
     395    template <typename Value,
     396              bool sign = std::numeric_limits<Value>::is_signed >
     397    struct CounterSortSelector {
     398      template <typename Iterator, typename Functor>
     399      static void sort(Iterator first, Iterator last, Functor functor) {
     400        counterSignedSort<Value>(first, last, functor);
     401      }
     402    };
     403
     404    template <typename Value>
     405    struct CounterSortSelector<Value, false> {
     406      template <typename Iterator, typename Functor>
     407      static void sort(Iterator first, Iterator last, Functor functor) {
     408        counterUnsignedSort<Value>(first, last, functor);
     409      }
     410    };
     411
     412  }
     413
     414  /// \ingroup auxalg
     415  ///
     416  /// \brief Sorts stable the STL compatible range into ascending order.
     417  ///
     418  /// The \c counterSort sorts the STL compatible range into ascending
     419  /// order.  The counter sort algorithm can sort the items which
     420  /// mapped to an integer with an adaptable unary function \c functor
     421  /// and the order will be ascending by these mapped values. As
     422  /// function specialization it is possible to use a normal function
     423  /// instead of the functor object or if the functor is not given it
     424  /// will use an identity function instead.
     425  ///
     426  /// The implemented counter sort use a radix forward sort on the
     427  /// bytes of the integer number. The algorithm sorts the items
     428  /// byte-by-byte, first it counts how many times occurs a byte value
     429  /// in the containerm, and with the occurence number the container
     430  /// can be copied to an other in asceding order in \c O(n) time.
     431  /// Let be \c c the maximal capacity of the integer type and \c n
     432  /// the number of the items in the container, the time complexity of
     433  /// the algorithm is \f$ O(\log(c)n) \f$ and the additional space
     434  /// complexity is \f$ O(n) \f$.
     435  ///
     436  /// The sorting algorithm is stable, i.e. the order of two equal
     437  /// element remains the same.
     438  ///
     439  /// \param first The begin of the given range.
     440  /// \param last The end of the given range.
     441  /// \param functor An adaptible unary function or a normal function
     442  /// which maps the items to any integer type which can be either
     443  /// signed or unsigned.
     444  template <typename Iterator, typename Functor>
     445  void counterSort(Iterator first, Iterator last, Functor functor) {
     446    using namespace _radix_sort_bits;
     447    typedef typename Functor::result_type Value;
     448    CounterSortSelector<Value>::sort(first, last, functor);
     449  }
     450
     451  template <typename Iterator, typename Value, typename Key>
     452  void counterSort(Iterator first, Iterator last, Value (*functor)(Key)) {
     453    using namespace _radix_sort_bits;
     454    CounterSortSelector<Value>::sort(first, last, functor);
     455  }
     456
     457  template <typename Iterator, typename Value, typename Key>
     458  void counterSort(Iterator first, Iterator last, Value& (*functor)(Key)) {
     459    using namespace _radix_sort_bits;
     460    CounterSortSelector<Value>::sort(first, last, functor);
     461  }
     462
     463  template <typename Iterator, typename Value, typename Key>
     464  void counterSort(Iterator first, Iterator last, Value (*functor)(Key&)) {
     465    using namespace _radix_sort_bits;
     466    CounterSortSelector<Value>::sort(first, last, functor);
     467  }
     468
     469  template <typename Iterator, typename Value, typename Key>
     470  void counterSort(Iterator first, Iterator last, Value& (*functor)(Key&)) {
     471    using namespace _radix_sort_bits;
     472    CounterSortSelector<Value>::sort(first, last, functor);
     473  }
     474
     475  template <typename Iterator>
     476  void counterSort(Iterator first, Iterator last) {
     477    using namespace _radix_sort_bits;
     478    typedef typename std::iterator_traits<Iterator>::value_type Value;
     479    CounterSortSelector<Value>::sort(first, last, Identity<Value>());
     480  }
     481
     482}
     483
     484#endif
  • test/CMakeLists.txt

    diff -r 6dbd5184c6a9 -r 4f7224faf3bd test/CMakeLists.txt
    a b  
    1616  heap_test
    1717  kruskal_test
    1818  maps_test
     19  radix_sort_test
    1920  random_test
    2021  path_test
    2122  time_measure_test
  • test/Makefile.am

    diff -r 6dbd5184c6a9 -r 4f7224faf3bd test/Makefile.am
    a b  
    1919        test/heap_test \
    2020        test/kruskal_test \
    2121        test/maps_test \
     22        test/radix_sort_test \
    2223        test/random_test \
    2324        test/path_test \
    2425        test/test_tools_fail \
     
    4344test_kruskal_test_SOURCES = test/kruskal_test.cc
    4445test_maps_test_SOURCES = test/maps_test.cc
    4546test_path_test_SOURCES = test/path_test.cc
     47test_radix_sort_test_SOURCES = test/radix_sort_test.cc
    4648test_random_test_SOURCES = test/random_test.cc
    4749test_test_tools_fail_SOURCES = test/test_tools_fail.cc
    4850test_test_tools_pass_SOURCES = test/test_tools_pass.cc
  • new file test/radix_sort_test.cc

    diff -r 6dbd5184c6a9 -r 4f7224faf3bd test/radix_sort_test.cc
    - +  
     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 <lemon/time_measure.h>
     20#include <lemon/smart_graph.h>
     21#include <lemon/maps.h>
     22#include <lemon/radix_sort.h>
     23#include <lemon/math.h>
     24
     25#include "test_tools.h"
     26
     27#include <vector>
     28#include <algorithm>
     29
     30using namespace lemon;
     31
     32static const int n = 10000;
     33
     34struct Negate {
     35  typedef int argument_type;
     36  typedef int result_type;
     37  int operator()(int a) { return - a; }
     38};
     39
     40int negate(int a) { return - a; }
     41
     42
     43void generateIntSequence(int n, std::vector<int>& data) {
     44  int prime = 9973;
     45  int root = 136, value = 1;
     46  for (int i = 0; i < n; ++i) {
     47    data.push_back(value - prime / 2);
     48    value = (value * root) % prime;
     49  }
     50}
     51
     52void generateCharSequence(int n, std::vector<unsigned char>& data) {
     53  int prime = 251;
     54  int root = 3, value = root;
     55  for (int i = 0; i < n; ++i) {
     56    data.push_back(static_cast<unsigned char>(value));
     57    value = (value * root) % prime;
     58  }
     59}
     60
     61void checkRadixSort() {
     62  {
     63    std::vector<int> data1;
     64    generateIntSequence(n, data1);
     65
     66    std::vector<int> data2(data1);
     67    std::sort(data1.begin(), data1.end());
     68
     69    radixSort(data2.begin(), data2.end());
     70    for (int i = 0; i < n; ++i) {
     71      check(data1[i] == data2[i], "Test failed");
     72    }
     73
     74    radixSort(data2.begin(), data2.end(), Negate());
     75    for (int i = 0; i < n; ++i) {
     76      check(data1[i] == data2[n - 1 - i], "Test failed");
     77    }
     78
     79    radixSort(data2.begin(), data2.end(), negate);
     80    for (int i = 0; i < n; ++i) {
     81      check(data1[i] == data2[n - 1 - i], "Test failed");
     82    }
     83
     84  }
     85 
     86  {
     87    std::vector<unsigned char> data1(n);
     88    generateCharSequence(n, data1);
     89
     90    std::vector<unsigned char> data2(data1);
     91    std::sort(data1.begin(), data1.end());
     92
     93    radixSort(data2.begin(), data2.end());
     94    for (int i = 0; i < n; ++i) {
     95      check(data1[i] == data2[i], "Test failed");
     96    }
     97
     98  }
     99}
     100
     101
     102void checkCounterSort() {
     103  {
     104    std::vector<int> data1;
     105    generateIntSequence(n, data1);
     106
     107    std::vector<int> data2(data1);
     108    std::sort(data1.begin(), data1.end());
     109
     110    counterSort(data2.begin(), data2.end());
     111    for (int i = 0; i < n; ++i) {
     112      check(data1[i] == data2[i], "Test failed");
     113    }
     114
     115    counterSort(data2.begin(), data2.end(), Negate());
     116    for (int i = 0; i < n; ++i) {
     117      check(data1[i] == data2[n - 1 - i], "Test failed");
     118    }
     119
     120    counterSort(data2.begin(), data2.end(), negate);
     121    for (int i = 0; i < n; ++i) {
     122      check(data1[i] == data2[n - 1 - i], "Test failed");
     123    }
     124  }
     125
     126  {
     127    std::vector<unsigned char> data1(n);
     128    generateCharSequence(n, data1);
     129
     130    std::vector<unsigned char> data2(data1);
     131    std::sort(data1.begin(), data1.end());
     132
     133    radixSort(data2.begin(), data2.end());
     134    for (int i = 0; i < n; ++i) {
     135      check(data1[i] == data2[i], "Test failed");
     136    }
     137
     138  }
     139}
     140
     141int main() {
     142
     143  checkRadixSort(); 
     144  checkCounterSort();
     145
     146  return 0;
     147}