Skip to content
Snippets Groups Projects
  • Martyn Gigg's avatar
    b573d4dd
    Replace boost::random with std::random · b573d4dd
    Martyn Gigg authored
    This includes dragging the libcxx implementation of normal_distribution
    and uniform_int_distribution into our source. MSVC, clang and gcc don't
    agree on how this should be implemented leading to problems with
    comparing test results across platforms. Using a single implementation
    gives the same results on each platform.
    b573d4dd
    History
    Replace boost::random with std::random
    Martyn Gigg authored
    This includes dragging the libcxx implementation of normal_distribution
    and uniform_int_distribution into our source. MSVC, clang and gcc don't
    agree on how this should be implemented leading to problems with
    comparing test results across platforms. Using a single implementation
    gives the same results on each platform.
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
uniform_int_distribution.h 10.06 KiB
#ifndef MANTID_KERNEL_UNIFORM_INT_DISRIBUTION_H_
#define MANTID_KERNEL_UNIFORM_INT_DISRIBUTION_H_
/**
  Copyright © 2018 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge
  National Laboratory & European Spallation Source

  This file is part of Mantid.

  Mantid is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 3 of the License, or
  (at your option) any later version.

  Mantid is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.

  File change history is stored at: <https://github.com/mantidproject/mantid>
  Code Documentation is available at: <http://doxygen.mantidproject.org>
 */
#include <limits>
#include <random>
#include <type_traits>

// Implementation of uniform_int_distribution taken from llvm/libcxx at
// https://github.com/llvm-mirror/libcxx/blob/master/include/algorithm#L2965
//
// Each of our supported platforms has the header but minor differences in the
// results yield problems consistency of our tests across platorms.
//
// Modifications to enable compilation:
//  * define required macros just for this header
//  * prefix some structures with std:: now they are not in std:: namespace
//  * applied clang format

#ifdef _MSC_VER
#define __CHAR_BIT__ CHAR_BIT
#define INLINE_VISIBILITY __forceinline
#else
#define INLINE_VISIBILITY __attribute__((__always_inline__))
#endif

namespace Mantid {
namespace Kernel {

//@cond

// Precondition:  __x != 0
inline INLINE_VISIBILITY unsigned __clz(unsigned __x) {
#ifndef _MSC_VER
  return static_cast<unsigned>(__builtin_clz(__x));
#else
  static_assert(sizeof(unsigned) == sizeof(unsigned long), "");
  static_assert(sizeof(unsigned long) == 4, "");
  unsigned long where;
  // Search from LSB to MSB for first set bit.
  // Returns zero if no set bit is found.
  if (_BitScanReverse(&where, __x))
    return 31 - where;
  return 32; // Undefined Behavior.
#endif
}

inline INLINE_VISIBILITY unsigned long __clz(unsigned long __x) {
#ifndef _MSC_VER
  return static_cast<unsigned long>(__builtin_clzl(__x));
#else
  static_assert(sizeof(unsigned) == sizeof(unsigned long), "");
  return __clz(static_cast<unsigned>(__x));
#endif
}

inline INLINE_VISIBILITY unsigned long long __clz(unsigned long long __x) {
#ifndef _MSC_VER
  return static_cast<unsigned long long>(__builtin_clzll(__x));
#else
  unsigned long where;
// BitScanReverse scans from MSB to LSB for first set bit.
// Returns 0 if no set bit is found.
#if defined(_LIBCPP_HAS_BITSCAN64)
  if (_BitScanReverse64(&where, __x))
    return static_cast<int>(63 - where);
#else
  // Scan the high 32 bits.
  if (_BitScanReverse(&where, static_cast<unsigned long>(__x >> 32)))
    return 63 - (where + 32); // Create a bit offset from the MSB.
  // Scan the low 32 bits.
  if (_BitScanReverse(&where, static_cast<unsigned long>(__x)))
    return 63 - where;
#endif
  return 64; // Undefined Behavior.
#endif // _MSC_VER
}

// __independent_bits_engine

template <unsigned long long _Xp, size_t _Rp> struct __log2_imp {
  static const size_t value = _Xp & ((unsigned long long)(1) << _Rp)
                                  ? _Rp
                                  : __log2_imp<_Xp, _Rp - 1>::value;
};

template <unsigned long long _Xp> struct __log2_imp<_Xp, 0> {
  static const size_t value = 0;
};

template <size_t _Rp> struct __log2_imp<0, _Rp> {
  static const size_t value = _Rp + 1;
};

template <class _UIntType, _UIntType _Xp> struct __log2 {
  static const size_t value =
      __log2_imp<_Xp, sizeof(_UIntType) * __CHAR_BIT__ - 1>::value;
};

template <class _Engine, class _UIntType> class __independent_bits_engine {
public:
  // types
  typedef _UIntType result_type;

private:
  typedef typename _Engine::result_type _Engine_result_type;
  typedef typename std::conditional<
      sizeof(_Engine_result_type) <= sizeof(result_type), result_type,
      _Engine_result_type>::type _Working_result_type;

  _Engine &__e_;
  size_t __w_;
  size_t __w0_;
  size_t __n_;
  size_t __n0_;
  _Working_result_type __y0_;
  _Working_result_type __y1_;
  _Engine_result_type __mask0_;
  _Engine_result_type __mask1_;
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4307)
#endif
  static constexpr const _Working_result_type _Rp =
      _Engine::max() - _Engine::min() + _Working_result_type(1);
#ifdef _MSC_VER
#pragma warning(pop)
#endif
  static constexpr const size_t __m = __log2<_Working_result_type, _Rp>::value;
  static constexpr const size_t _WDt =
      std::numeric_limits<_Working_result_type>::digits;
  static constexpr const size_t _EDt =
      std::numeric_limits<_Engine_result_type>::digits;

public:
  // constructors and seeding functions
  __independent_bits_engine(_Engine &__e, size_t __w);

  // generating functions
  result_type operator()() {
    return __eval(std::integral_constant<bool, _Rp != 0>());
  }

private:
  result_type __eval(std::false_type);
  result_type __eval(std::true_type);
};

template <class _Engine, class _UIntType>
__independent_bits_engine<_Engine, _UIntType>::__independent_bits_engine(
    _Engine &__e, size_t __w)
    : __e_(__e), __w_(__w) {
  __n_ = __w_ / __m + (__w_ % __m != 0);
  __w0_ = __w_ / __n_;
  if (_Rp == 0)
    __y0_ = _Rp;
  else if (__w0_ < _WDt)
    __y0_ = (_Rp >> __w0_) << __w0_;
  else
    __y0_ = 0;
  if (_Rp - __y0_ > __y0_ / __n_) {
    ++__n_;
    __w0_ = __w_ / __n_;
    if (__w0_ < _WDt)
      __y0_ = (_Rp >> __w0_) << __w0_;
    else
      __y0_ = 0;
  }
  __n0_ = __n_ - __w_ % __n_;
  if (__w0_ < _WDt - 1)
    __y1_ = (_Rp >> (__w0_ + 1)) << (__w0_ + 1);
  else
    __y1_ = 0;
  __mask0_ = __w0_ > 0 ? _Engine_result_type(~0) >> (_EDt - __w0_)
                       : _Engine_result_type(0);
  __mask1_ = __w0_ < _EDt - 1 ? _Engine_result_type(~0) >> (_EDt - (__w0_ + 1))
                              : _Engine_result_type(~0);
}

template <class _Engine, class _UIntType>
inline _UIntType
    __independent_bits_engine<_Engine, _UIntType>::__eval(std::false_type) {
  return static_cast<result_type>(__e_() & __mask0_);
}

template <class _Engine, class _UIntType>
_UIntType
    __independent_bits_engine<_Engine, _UIntType>::__eval(std::true_type) {
  const size_t _WRt = std::numeric_limits<result_type>::digits;
  result_type _Sp = 0;
  for (size_t __k = 0; __k < __n0_; ++__k) {
    _Engine_result_type __u;
    do {
      __u = __e_() - _Engine::min();
    } while (__u >= __y0_);
    if (__w0_ < _WRt)
      _Sp <<= __w0_;
    else
      _Sp = 0;
    _Sp += static_cast<result_type>(__u & __mask0_);
  }
  for (size_t __k = __n0_; __k < __n_; ++__k) {
    _Engine_result_type __u;
    do {
      __u = __e_() - _Engine::min();
    } while (__u >= __y1_);
    if (__w0_ < _WRt - 1)
      _Sp <<= __w0_ + 1;
    else
      _Sp = 0;
    _Sp += static_cast<result_type>(__u & __mask1_);
  }
  return _Sp;
}

//@endcond

// uniform_int_distribution

template <class _IntType = int> class uniform_int_distribution {
public:
  // types
  typedef _IntType result_type;

  class param_type {
    result_type __a_;
    result_type __b_;

  public:
    typedef uniform_int_distribution distribution_type;

    explicit param_type(
        result_type __a = 0,
        result_type __b = std::numeric_limits<result_type>::max())
        : __a_(__a), __b_(__b) {}

    result_type a() const { return __a_; }
    result_type b() const { return __b_; }

    friend bool operator==(const param_type &__x, const param_type &__y) {
      return __x.__a_ == __y.__a_ && __x.__b_ == __y.__b_;
    }
    friend bool operator!=(const param_type &__x, const param_type &__y) {
      return !(__x == __y);
    }
  };

private:
  param_type __p_;

public:
  // constructors and reset functions
  explicit uniform_int_distribution(
      result_type __a = 0,
      result_type __b = std::numeric_limits<result_type>::max())
      : __p_(param_type(__a, __b)) {}
  explicit uniform_int_distribution(const param_type &__p) : __p_(__p) {}
  void reset() {}
  // generating functions
  template <class _URNG> result_type operator()(_URNG &__g) {
    return (*this)(__g, __p_);
  }
  template <class _URNG>
  result_type operator()(_URNG &__g, const param_type &__p);

  // property functions
  result_type a() const { return __p_.a(); }
  result_type b() const { return __p_.b(); }

  param_type param() const { return __p_; }
  void param(const param_type &__p) { __p_ = __p; }

  result_type min() const { return a(); }
  result_type max() const { return b(); }

  friend bool operator==(const uniform_int_distribution &__x,
                         const uniform_int_distribution &__y) {
    return __x.__p_ == __y.__p_;
  }
  friend bool operator!=(const uniform_int_distribution &__x,
                         const uniform_int_distribution &__y) {
    return !(__x == __y);
  }
};

template <class _IntType>
template <class _URNG>
typename uniform_int_distribution<_IntType>::result_type
    uniform_int_distribution<_IntType>::
    operator()(_URNG &__g, const param_type &__p) {
  typedef typename std::conditional<sizeof(result_type) <= sizeof(uint32_t),
                                    uint32_t, uint64_t>::type _UIntType;
  const _UIntType _Rp = __p.b() - __p.a() + _UIntType(1);
  if (_Rp == 1)
    return __p.a();
  const size_t _Dt = std::numeric_limits<_UIntType>::digits;
  typedef __independent_bits_engine<_URNG, _UIntType> _Eng;
  if (_Rp == 0)
    return static_cast<result_type>(_Eng(__g, _Dt)());
  size_t __w = _Dt - __clz(_Rp) - 1;
  if ((_Rp & (std::numeric_limits<_UIntType>::max() >> (_Dt - __w))) != 0)
    ++__w;
  _Eng __e(__g, __w);
  _UIntType __u;
  do {
    __u = __e();
  } while (__u >= _Rp);
  return static_cast<result_type>(__u + __p.a());
}

} // namespace Kernel
} // namespace Mantid

// Clean up macros
#undef INLINE_VISIBILITY
#ifdef _MANTID_CHAR_BIT_DEFINED_HERE
#undef __CHAR_BIT__
#undef _MANTID_CHAR_BIT_DEFINED_HERE
#endif

#endif // MANTID_KERNEL_UNIFORM_INT_DISRIBUTION_H_