[INFRA] Import NVIDIA/CCCL upstream as optimization reference library
CCCL (CUDA C++ Core Libraries) provides: - CUB: device/block/warp-level GPU primitives (reduce, scan, sort, topk) - Thrust: high-level parallel algorithms (transform_reduce, sort, scan) - libcudacxx: CUDA C++ standard library (atomics, barriers, memory) - cudax: experimental features (memory resources, allocators) - Tuning policies: per-SM hardware-specific algorithm parameters Competition optimization vectors mapped to CCCL: - Output TPS (83% weight): warp_reduce, block_reduce, device_topk - Input TPS (14% weight): device_scan, block_load, prefetch - Cache TPS (3% weight): prefix caching strategy patterns - Memory (0.9 util): pooled/cached/buddy allocators Source: https://github.com/NVIDIA/cccl (shallow clone, HEAD only) License: Apache-2.0
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of libcu++, the C++ Standard Library for your entire system,
|
||||
// under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef _CUDA___RANDOM_FEISTEL_BIJECTION_H
|
||||
#define _CUDA___RANDOM_FEISTEL_BIJECTION_H
|
||||
|
||||
#include <cuda/std/detail/__config>
|
||||
|
||||
#if defined(_CCCL_IMPLICIT_SYSTEM_HEADER_GCC)
|
||||
# pragma GCC system_header
|
||||
#elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_CLANG)
|
||||
# pragma clang system_header
|
||||
#elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_MSVC)
|
||||
# pragma system_header
|
||||
#endif // no system header
|
||||
|
||||
#include <cuda/__fwd/random.h>
|
||||
#include <cuda/std/__algorithm/max.h>
|
||||
#include <cuda/std/__bit/bit_cast.h>
|
||||
#include <cuda/std/__bit/integral.h>
|
||||
#include <cuda/std/__random/uniform_int_distribution.h>
|
||||
#include <cuda/std/cstdint>
|
||||
|
||||
#include <cuda/std/__cccl/prologue.h>
|
||||
|
||||
_CCCL_BEGIN_NAMESPACE_CUDA
|
||||
|
||||
//! @brief A Feistel cipher for operating on power of two sized problems
|
||||
class __feistel_bijection
|
||||
{
|
||||
private:
|
||||
static constexpr uint32_t __num_rounds = 24;
|
||||
|
||||
uint64_t __R_bits_{};
|
||||
uint64_t __L_bits_{};
|
||||
uint64_t __R_mask_{};
|
||||
uint64_t __L_mask_{};
|
||||
uint32_t __keys_[__num_rounds] = {};
|
||||
|
||||
public:
|
||||
using index_type = uint64_t;
|
||||
|
||||
_CCCL_HIDE_FROM_ABI constexpr __feistel_bijection() noexcept = default;
|
||||
|
||||
template <class _RNG>
|
||||
_CCCL_API __feistel_bijection(uint64_t __num_elements, _RNG&& __gen)
|
||||
{
|
||||
// Calculate number of bits needed to represent num_elements - 1
|
||||
// Prevent zero
|
||||
const uint64_t __max_index = ::cuda::std::max(static_cast<uint64_t>(1), __num_elements) - 1;
|
||||
const uint64_t __total_bits = static_cast<uint64_t>(::cuda::std::max(8, ::cuda::std::bit_width(__max_index)));
|
||||
|
||||
// Half bits rounded down
|
||||
__L_bits_ = __total_bits / 2;
|
||||
__L_mask_ = (1ull << __L_bits_) - 1;
|
||||
// Half the bits rounded up
|
||||
__R_bits_ = __total_bits - __L_bits_;
|
||||
__R_mask_ = (1ull << __R_bits_) - 1;
|
||||
|
||||
::cuda::std::uniform_int_distribution<uint32_t> __dist{};
|
||||
_CCCL_PRAGMA_UNROLL_FULL()
|
||||
for (auto& __key : __keys_)
|
||||
{
|
||||
__key = __dist(__gen);
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] _CCCL_API constexpr uint64_t size() const noexcept
|
||||
{
|
||||
return 1ull << (__L_bits_ + __R_bits_);
|
||||
}
|
||||
|
||||
[[nodiscard]] _CCCL_API constexpr uint64_t operator()(const uint64_t __val) const noexcept
|
||||
{
|
||||
// Mitchell, Rory, et al. "Bandwidth-optimal random shuffling for GPUs." ACM Transactions on Parallel Computing 9.1
|
||||
// (2022): 1-20.
|
||||
uint32_t __L = static_cast<uint32_t>(__val >> __R_bits_);
|
||||
uint32_t __R = static_cast<uint32_t>(__val & __R_mask_);
|
||||
for (const auto __key : __keys_)
|
||||
{
|
||||
constexpr uint64_t __m0 = 0xD2B74407B1CE6E93;
|
||||
const uint64_t __product = __m0 * __L;
|
||||
uint32_t __F_k = (__product >> 32) ^ __key;
|
||||
uint32_t __B_k = static_cast<uint32_t>(__product);
|
||||
uint32_t __L_prime = __F_k ^ __R;
|
||||
|
||||
uint32_t __R_prime = (__B_k << (__R_bits_ - __L_bits_)) | __R >> __L_bits_;
|
||||
__L = __L_prime & __L_mask_;
|
||||
__R = __R_prime & __R_mask_;
|
||||
}
|
||||
// Combine the left and right sides together to get result
|
||||
return (static_cast<uint64_t>(__L) << __R_bits_) | static_cast<uint64_t>(__R);
|
||||
}
|
||||
};
|
||||
|
||||
_CCCL_END_NAMESPACE_CUDA
|
||||
|
||||
#include <cuda/std/__cccl/epilogue.h>
|
||||
|
||||
#endif // _CUDA___RANDOM_FEISTEL_BIJECTION_H
|
||||
398
cccl_upstream/libcudacxx/include/cuda/__random/pcg_engine.h
Normal file
398
cccl_upstream/libcudacxx/include/cuda/__random/pcg_engine.h
Normal file
@@ -0,0 +1,398 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of libcu++, the C++ Standard Library for your entire system,
|
||||
// under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef _CUDA_STD___RANDOM_PCG_ENGINE_H
|
||||
#define _CUDA_STD___RANDOM_PCG_ENGINE_H
|
||||
|
||||
#include <cuda/std/detail/__config>
|
||||
|
||||
#if defined(_CCCL_IMPLICIT_SYSTEM_HEADER_GCC)
|
||||
# pragma GCC system_header
|
||||
#elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_CLANG)
|
||||
# pragma clang system_header
|
||||
#elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_MSVC)
|
||||
# pragma system_header
|
||||
#endif // no system header
|
||||
|
||||
#include <cuda/__cmath/mul_hi.h>
|
||||
#include <cuda/std/__bit/rotate.h>
|
||||
#include <cuda/std/__limits/numeric_limits.h>
|
||||
#include <cuda/std/__random/is_seed_sequence.h>
|
||||
#include <cuda/std/__type_traits/enable_if.h>
|
||||
#include <cuda/std/__type_traits/integral_constant.h>
|
||||
#include <cuda/std/__utility/pair.h>
|
||||
#include <cuda/std/array>
|
||||
#include <cuda/std/cstdint>
|
||||
|
||||
#include <cuda/std/__cccl/prologue.h>
|
||||
|
||||
_CCCL_BEGIN_NAMESPACE_CUDA
|
||||
|
||||
// Keep this here even when we have __int128 support, so that we can test it against native __int128
|
||||
class __pcg_uint128_fallback
|
||||
{
|
||||
private:
|
||||
::cuda::std::uint64_t __hi_;
|
||||
::cuda::std::uint64_t __lo_;
|
||||
|
||||
public:
|
||||
_CCCL_API constexpr __pcg_uint128_fallback() noexcept
|
||||
: __hi_{0}
|
||||
, __lo_{0}
|
||||
{}
|
||||
|
||||
_CCCL_API constexpr __pcg_uint128_fallback(::cuda::std::uint64_t __val) noexcept
|
||||
: __hi_{0}
|
||||
, __lo_{__val}
|
||||
{}
|
||||
|
||||
_CCCL_API constexpr __pcg_uint128_fallback(::cuda::std::uint64_t __hi, ::cuda::std::uint64_t __lo) noexcept
|
||||
: __hi_{__hi}
|
||||
, __lo_{__lo}
|
||||
{}
|
||||
|
||||
[[nodiscard]] _CCCL_API constexpr explicit operator ::cuda::std::uint64_t() const noexcept
|
||||
{
|
||||
return __lo_;
|
||||
}
|
||||
|
||||
[[nodiscard]] _CCCL_API constexpr explicit operator ::cuda::std::uint8_t() const noexcept
|
||||
{
|
||||
return static_cast<::cuda::std::uint8_t>(__lo_);
|
||||
}
|
||||
|
||||
[[nodiscard]] _CCCL_API constexpr __pcg_uint128_fallback operator|(::cuda::std::uint64_t __rhs) const noexcept
|
||||
{
|
||||
return __pcg_uint128_fallback(__hi_, __lo_ | __rhs);
|
||||
}
|
||||
|
||||
[[nodiscard]] _CCCL_API constexpr __pcg_uint128_fallback operator^(__pcg_uint128_fallback __rhs) const noexcept
|
||||
{
|
||||
return __pcg_uint128_fallback(__hi_ ^ __rhs.__hi_, __lo_ ^ __rhs.__lo_);
|
||||
}
|
||||
|
||||
[[nodiscard]] _CCCL_API constexpr int operator&(int __rhs) const noexcept
|
||||
{
|
||||
return __lo_ & static_cast<::cuda::std::uint64_t>(__rhs);
|
||||
}
|
||||
|
||||
[[nodiscard]] _CCCL_API constexpr __pcg_uint128_fallback operator<<(int __shift) const noexcept
|
||||
{
|
||||
_CCCL_ASSERT(__shift >= 0 && __shift < 128, "shift value out of range");
|
||||
if (__shift == 0)
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
if (__shift >= 128)
|
||||
{
|
||||
return __pcg_uint128_fallback(0, 0);
|
||||
}
|
||||
if (__shift >= 64)
|
||||
{
|
||||
return __pcg_uint128_fallback(__lo_ << (__shift - 64), 0);
|
||||
}
|
||||
return __pcg_uint128_fallback((__hi_ << __shift) | (__lo_ >> (64 - __shift)), __lo_ << __shift);
|
||||
}
|
||||
|
||||
[[nodiscard]] _CCCL_API constexpr __pcg_uint128_fallback operator>>(int __shift) const noexcept
|
||||
{
|
||||
_CCCL_ASSERT(__shift >= 0 && __shift < 128, "shift value out of range");
|
||||
if (__shift == 0)
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
if (__shift >= 128)
|
||||
{
|
||||
return __pcg_uint128_fallback(0, 0);
|
||||
}
|
||||
if (__shift >= 64)
|
||||
{
|
||||
return __pcg_uint128_fallback(0, __hi_ >> (__shift - 64));
|
||||
}
|
||||
return __pcg_uint128_fallback(__hi_ >> __shift, (__lo_ >> __shift) | (__hi_ << (64 - __shift)));
|
||||
}
|
||||
|
||||
[[nodiscard]] _CCCL_API constexpr __pcg_uint128_fallback operator+(__pcg_uint128_fallback __rhs) const noexcept
|
||||
{
|
||||
// TODO: optimize with PTX add.cc
|
||||
::cuda::std::uint64_t __new_lo = __lo_ + __rhs.__lo_;
|
||||
::cuda::std::uint64_t __carry = (__new_lo < __lo_) ? 1 : 0;
|
||||
return __pcg_uint128_fallback(__hi_ + __rhs.__hi_ + __carry, __new_lo);
|
||||
}
|
||||
|
||||
[[nodiscard]] _CCCL_API constexpr __pcg_uint128_fallback operator*(__pcg_uint128_fallback __rhs) const noexcept
|
||||
{
|
||||
__pcg_uint128_fallback __c(::cuda::mul_hi(__lo_, __rhs.__lo_), __lo_ * __rhs.__lo_);
|
||||
__c.__hi_ += __hi_ * __rhs.__lo_ + __lo_ * __rhs.__hi_;
|
||||
return __c;
|
||||
}
|
||||
|
||||
_CCCL_API constexpr __pcg_uint128_fallback& operator*=(__pcg_uint128_fallback __rhs) noexcept
|
||||
{
|
||||
return *this = *this * __rhs;
|
||||
}
|
||||
|
||||
[[nodiscard]] _CCCL_API constexpr bool operator>(int __x) const noexcept
|
||||
{
|
||||
return __hi_ != 0 || __lo_ > static_cast<::cuda::std::uint64_t>(__x);
|
||||
}
|
||||
|
||||
[[nodiscard]] _CCCL_API constexpr friend bool
|
||||
operator==(__pcg_uint128_fallback __lhs, __pcg_uint128_fallback __rhs) noexcept
|
||||
{
|
||||
return __lhs.__hi_ == __rhs.__hi_ && __lhs.__lo_ == __rhs.__lo_;
|
||||
}
|
||||
|
||||
#if _CCCL_STD_VER <= 2017
|
||||
[[nodiscard]]
|
||||
_CCCL_API constexpr friend bool operator!=(__pcg_uint128_fallback __lhs, __pcg_uint128_fallback __rhs) noexcept
|
||||
{
|
||||
return !(__lhs == __rhs);
|
||||
}
|
||||
#endif // _CCCL_STD_VER <= 2017
|
||||
};
|
||||
|
||||
//! @brief A 64-bit permuted congruential generator (PCG) random number engine.
|
||||
//!
|
||||
//! This is a high-quality, fast random number generator based on the PCG family
|
||||
//! of algorithms. It uses a 128-bit internal state and produces 64-bit output
|
||||
//! values using a permutation function applied to a linear congruential generator.
|
||||
//!
|
||||
//! Most users should use the predefined `pcg64` type alias instead of this class directly.
|
||||
//!
|
||||
//! @tparam _AHi The high 64 bits of the multiplier constant for the LCG.
|
||||
//! @tparam _ALo The low 64 bits of the multiplier constant for the LCG.
|
||||
//! @tparam _CHi The high 64 bits of the increment constant for the LCG.
|
||||
//! @tparam _CLo The low 64 bits of the increment constant for the LCG.
|
||||
//!
|
||||
//! @see https://www.pcg-random.org/ for details on the PCG family of generators.
|
||||
template <::cuda::std::uint64_t _AHi, ::cuda::std::uint64_t _ALo, ::cuda::std::uint64_t _CHi, ::cuda::std::uint64_t _CLo>
|
||||
class pcg64_engine
|
||||
{
|
||||
public:
|
||||
using result_type = ::cuda::std::uint64_t;
|
||||
|
||||
private:
|
||||
#if _CCCL_HAS_INT128()
|
||||
using __pcg64_uint128_t = __uint128_t;
|
||||
#else
|
||||
using __pcg64_uint128_t = __pcg_uint128_fallback;
|
||||
#endif
|
||||
using __bitcount_t = ::cuda::std::uint8_t;
|
||||
|
||||
static constexpr __pcg64_uint128_t __multiplier = (static_cast<__pcg64_uint128_t>(_AHi) << 64) | _ALo;
|
||||
static constexpr __pcg64_uint128_t __increment = (static_cast<__pcg64_uint128_t>(_CHi) << 64) | _CLo;
|
||||
|
||||
[[nodiscard]] _CCCL_API static constexpr result_type __output_transform(__pcg64_uint128_t __internal) noexcept
|
||||
{
|
||||
const int __rot = static_cast<__bitcount_t>(__internal >> 122);
|
||||
__internal = __internal ^ (__internal >> 64);
|
||||
return ::cuda::std::rotr(result_type(__internal), __rot);
|
||||
}
|
||||
|
||||
[[nodiscard]] _CCCL_API constexpr ::cuda::std::pair<__pcg64_uint128_t, __pcg64_uint128_t>
|
||||
__power_mod(__pcg64_uint128_t __delta) noexcept
|
||||
{
|
||||
__pcg64_uint128_t __acc_mult = 1;
|
||||
__pcg64_uint128_t __acc_plus = 0;
|
||||
__pcg64_uint128_t __cur_mult = __multiplier;
|
||||
__pcg64_uint128_t __cur_plus = __increment;
|
||||
while (__delta > 0)
|
||||
{
|
||||
if (__delta & 1)
|
||||
{
|
||||
__acc_mult *= __cur_mult;
|
||||
__acc_plus = __acc_plus * __cur_mult + __cur_plus;
|
||||
}
|
||||
__cur_plus = (__cur_mult + 1) * __cur_plus;
|
||||
__cur_mult *= __cur_mult;
|
||||
__delta = __delta >> 1;
|
||||
}
|
||||
return ::cuda::std::pair{__acc_mult, __acc_plus};
|
||||
}
|
||||
__pcg64_uint128_t __x_{};
|
||||
|
||||
public:
|
||||
static constexpr result_type default_seed = 0xcafef00dd15ea5e5ULL;
|
||||
|
||||
//! @brief Returns the smallest value the engine can produce.
|
||||
//! @return Always 0 for pcg64_engine.
|
||||
[[nodiscard]] _CCCL_API static constexpr result_type min() noexcept
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
//! @brief Returns the largest value the engine can produce.
|
||||
//! @return The maximum representable `result_type`.
|
||||
[[nodiscard]] _CCCL_API static constexpr result_type max() noexcept
|
||||
{
|
||||
return ::cuda::std::numeric_limits<result_type>::max();
|
||||
}
|
||||
|
||||
// constructors and seeding functions
|
||||
//! @brief Default-constructs the engine using `default_seed`.
|
||||
_CCCL_API constexpr pcg64_engine() noexcept
|
||||
: pcg64_engine(default_seed)
|
||||
{}
|
||||
//! @brief Constructs the engine and seeds it with `__seed`.
|
||||
//! @param __seed The seed value used to initialize the engine state.
|
||||
_CCCL_API constexpr explicit pcg64_engine(result_type __seed) noexcept
|
||||
{
|
||||
seed(__seed);
|
||||
}
|
||||
|
||||
//! @brief Constructs the engine and seeds it from a SeedSequence-like object.
|
||||
//! @tparam _Sseq A SeedSequence-like type satisfying the project's seed concept.
|
||||
//! @param __seq The seed sequence used to initialize the internal state.
|
||||
_CCCL_TEMPLATE(class _Sseq)
|
||||
_CCCL_REQUIRES(::cuda::std::__is_seed_sequence<_Sseq, pcg64_engine>)
|
||||
_CCCL_HOST_DEVICE_API constexpr explicit pcg64_engine(_Sseq& __seq)
|
||||
{
|
||||
seed(__seq);
|
||||
}
|
||||
//! @brief Seed the engine with an integer seed.
|
||||
//! @param __seed The seed value; defaults to `default_seed`.
|
||||
_CCCL_API constexpr void seed(result_type __seed = default_seed) noexcept
|
||||
{
|
||||
__x_ = (__pcg64_uint128_t(__seed) + __increment) * __multiplier + __increment;
|
||||
}
|
||||
|
||||
//! @brief Seed the engine from a SeedSequence-like object.
|
||||
//! @tparam _Sseq A SeedSequence-like type providing entropy words.
|
||||
//! @param __seq A SeedSequence-like object providing 128 bits of entropy.
|
||||
_CCCL_TEMPLATE(class _Sseq)
|
||||
_CCCL_REQUIRES(::cuda::std::__is_seed_sequence<_Sseq, pcg64_engine>)
|
||||
_CCCL_HOST_DEVICE_API constexpr void seed(_Sseq& __seq)
|
||||
{
|
||||
::cuda::std::array<::cuda::std::uint32_t, 4> data = {};
|
||||
__seq.generate(data.begin(), data.end());
|
||||
__pcg64_uint128_t seed_val = data[0];
|
||||
seed_val = (seed_val << 32) | data[1];
|
||||
seed_val = (seed_val << 32) | data[2];
|
||||
seed_val = (seed_val << 32) | data[3];
|
||||
__x_ = (seed_val + __increment) * __multiplier + __increment;
|
||||
}
|
||||
|
||||
//! @brief Generate the next pseudo-random value.
|
||||
//!
|
||||
//! Advances the internal LCG state and applies the PCG output
|
||||
//! permutation to produce a 64-bit result.
|
||||
//! @return A 64-bit pseudo-random value.
|
||||
_CCCL_API constexpr result_type operator()() noexcept
|
||||
{
|
||||
__x_ = __x_ * __multiplier + __increment;
|
||||
return __output_transform(__x_);
|
||||
}
|
||||
|
||||
//! @brief Advance the engine state by `__z` steps, discarding outputs.
|
||||
//! @param __z Number of values to discard.
|
||||
_CCCL_API constexpr void discard(unsigned long long __z) noexcept
|
||||
{
|
||||
const auto [__mult, __plus] = __power_mod(__z);
|
||||
__x_ = __x_ * __mult + __plus;
|
||||
}
|
||||
|
||||
//! @brief Equality comparison for two engines.
|
||||
//! @return True if both engines have identical internal state.
|
||||
[[nodiscard]] _CCCL_API constexpr friend bool operator==(const pcg64_engine& __x, const pcg64_engine& __y) noexcept
|
||||
{
|
||||
return __x.__x_ == __y.__x_;
|
||||
}
|
||||
|
||||
#if _CCCL_STD_VER <= 2017
|
||||
//! @brief Inequality comparison for two engines.
|
||||
[[nodiscard]] _CCCL_API constexpr friend bool operator!=(const pcg64_engine& __x, const pcg64_engine& __y) noexcept
|
||||
{
|
||||
return !(__x == __y);
|
||||
}
|
||||
#endif // _CCCL_STD_VER <= 2017
|
||||
|
||||
#if _CCCL_HOSTED()
|
||||
|
||||
template <typename _CharT, typename _Traits>
|
||||
_CCCL_API friend ::std::basic_ostream<_CharT, _Traits>&
|
||||
operator<<(::std::basic_ostream<_CharT, _Traits>& __os, const pcg64_engine& __e)
|
||||
{
|
||||
using ostream_type = ::std::basic_ostream<_CharT, _Traits>;
|
||||
using ios_base = typename ostream_type::ios_base;
|
||||
|
||||
// save old flags & fill character
|
||||
const typename ios_base::fmtflags __flags = __os.flags();
|
||||
const _CharT __fill = __os.fill();
|
||||
|
||||
__os.flags(ios_base::dec | ios_base::fixed | ios_base::left);
|
||||
__os.fill(__os.widen(' '));
|
||||
// Write 64 bits at a time
|
||||
::cuda::std::uint64_t __low = static_cast<::cuda::std::uint64_t>(__e.__x_);
|
||||
::cuda::std::uint64_t __hi = static_cast<::cuda::std::uint64_t>(__e.__x_ >> 64);
|
||||
__os << __low;
|
||||
__os << __os.widen(' ');
|
||||
__os << __hi;
|
||||
__os << __os.widen(' ');
|
||||
// restore flags & fill character
|
||||
__os.flags(__flags);
|
||||
__os.fill(__fill);
|
||||
|
||||
return __os;
|
||||
}
|
||||
|
||||
template <typename _CharT, typename _Traits>
|
||||
_CCCL_API friend ::std::basic_istream<_CharT, _Traits>&
|
||||
operator>>(::std::basic_istream<_CharT, _Traits>& __is, pcg64_engine& __e)
|
||||
{
|
||||
using istream_type = ::std::basic_istream<_CharT, _Traits>;
|
||||
using ios_base = typename istream_type::ios_base;
|
||||
|
||||
// save old flags
|
||||
const typename ios_base::fmtflags __flags = __is.flags();
|
||||
|
||||
__is.flags(ios_base::dec | ios_base::skipws);
|
||||
|
||||
::cuda::std::uint64_t __low, __hi;
|
||||
__is >> __low;
|
||||
__is >> __hi;
|
||||
// Read engine state from stream: low 64 bits then high 64 bits.
|
||||
__e.__x_ = (static_cast<__pcg64_uint128_t>(__hi) << 64) | __low;
|
||||
// restore flags
|
||||
__is.flags(__flags);
|
||||
|
||||
return __is;
|
||||
}
|
||||
#endif // _CCCL_HOSTED()
|
||||
};
|
||||
|
||||
//! @class pcg64
|
||||
//! @brief A 128-bit state PCG engine producing 64-bit output values.
|
||||
//!
|
||||
//! This class implements the PCG XSL RR 128/64 generator described in:
|
||||
//! O'neill, Melissa E. "PCG: A family of simple fast space-efficient statistically good algorithms for random number
|
||||
//! generation." ACM Transactions on Mathematical Software 204 (2014): 1-46. The engine keeps a 128-bit internal state
|
||||
//! and returns 64-bit pseudo-random values. PCG64 is a fast general purpose PRNG that passes common statistical tests,
|
||||
//! has a long period (2^128), and can discard values in O(log n) time.
|
||||
//!
|
||||
//! PCG64 produces the 10000th value 11135645891219275043 when seeded with the default seed.
|
||||
//!
|
||||
//! Usage example:
|
||||
//! @code
|
||||
//! #include <cuda/random>
|
||||
//!
|
||||
//! cuda::pcg64 eng; // default seed
|
||||
//! uint64_t v = eng(); // draw value
|
||||
//! eng.seed(42); // reseed
|
||||
//! eng.discard(10); // skip 10 outputs
|
||||
//! @endcode
|
||||
//!
|
||||
using pcg64 =
|
||||
pcg64_engine<2549297995355413924ull, 4865540595714422341ull, 6364136223846793005ull, 1442695040888963407ull>;
|
||||
|
||||
_CCCL_END_NAMESPACE_CUDA
|
||||
|
||||
#include <cuda/std/__cccl/epilogue.h>
|
||||
|
||||
#endif // _CUDA_STD___RANDOM_PCG_ENGINE_H
|
||||
@@ -0,0 +1,97 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of libcu++, the C++ Standard Library for your entire system,
|
||||
// under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef _CUDA___RANDOM_RANDOM_BIJECTION_H
|
||||
#define _CUDA___RANDOM_RANDOM_BIJECTION_H
|
||||
|
||||
#include <cuda/std/detail/__config>
|
||||
|
||||
#if defined(_CCCL_IMPLICIT_SYSTEM_HEADER_GCC)
|
||||
# pragma GCC system_header
|
||||
#elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_CLANG)
|
||||
# pragma clang system_header
|
||||
#elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_MSVC)
|
||||
# pragma system_header
|
||||
#endif // no system header
|
||||
|
||||
#include <cuda/__fwd/random.h>
|
||||
#include <cuda/__random/feistel_bijection.h>
|
||||
#include <cuda/std/__concepts/constructible.h>
|
||||
#include <cuda/std/__type_traits/is_convertible.h>
|
||||
#include <cuda/std/__type_traits/is_integral.h>
|
||||
#include <cuda/std/__type_traits/is_nothrow_default_constructible.h>
|
||||
#include <cuda/std/__utility/forward.h>
|
||||
#include <cuda/std/cstdint>
|
||||
|
||||
#include <cuda/std/__cccl/prologue.h>
|
||||
|
||||
_CCCL_BEGIN_NAMESPACE_CUDA
|
||||
|
||||
//! @brief Adaptor for a __bijection to work with any size problem. It achieves this by iterating the __bijection until
|
||||
//! the result is less than __num_elements. For a feistel bijection, the worst case number of iterations required for
|
||||
//! one call to operator() is O(__num_elements) with low probability. It has amortised O(1) complexity.
|
||||
//! @tparam _IndexType The type of the index to shuffle. Defaults to uint64_t.
|
||||
//! @tparam _Bijection The __bijection to use. A low quality random __bijection may lead to poor work balancing between
|
||||
//! calls to the operator(). Defaults to a feistel bijetion
|
||||
template <class _IndexType, class _Bijection>
|
||||
class random_bijection
|
||||
{
|
||||
private:
|
||||
static_assert(::cuda::std::is_integral_v<_IndexType>, "_IndexType must be an integral type");
|
||||
static_assert(::cuda::std::is_integral_v<typename _Bijection::index_type>,
|
||||
"_Bijection::index_type must be an integral type");
|
||||
static_assert(::cuda::std::is_convertible_v<_IndexType, typename _Bijection::index_type>,
|
||||
"_IndexType must be convertible to _Bijection::index_type");
|
||||
|
||||
_Bijection __bijection_;
|
||||
_IndexType __num_elements_;
|
||||
|
||||
public:
|
||||
using index_type = _IndexType;
|
||||
|
||||
_CCCL_EXEC_CHECK_DISABLE
|
||||
_CCCL_TEMPLATE(class _Bijection2 = _Bijection)
|
||||
_CCCL_REQUIRES(::cuda::std::default_initializable<_Bijection2>)
|
||||
_CCCL_API constexpr random_bijection() noexcept(::cuda::std::is_nothrow_default_constructible_v<_Bijection2>)
|
||||
: __bijection_()
|
||||
, __num_elements_(0)
|
||||
{}
|
||||
|
||||
template <class _RNG>
|
||||
_CCCL_API constexpr random_bijection(_IndexType __num_elements, _RNG&& __gen) noexcept
|
||||
: __bijection_(__num_elements, ::cuda::std::forward<_RNG>(__gen))
|
||||
, __num_elements_(__num_elements)
|
||||
{}
|
||||
|
||||
[[nodiscard]] _CCCL_API constexpr _IndexType operator()(_IndexType __n) const noexcept
|
||||
{
|
||||
// The initial index must be be in the range [0, __num_elemments]
|
||||
// If __n < __num_elements_ Iterating a __bijection_ like this will always terminate.
|
||||
// If __n >= __num_elements_, then this may loop forever.
|
||||
_CCCL_ASSERT(__n < __num_elements_, "random_bijection::operator(): index out of range");
|
||||
do
|
||||
{
|
||||
__n = static_cast<_IndexType>(__bijection_(__n));
|
||||
} while (__n >= __num_elements_);
|
||||
|
||||
return __n;
|
||||
}
|
||||
|
||||
[[nodiscard]] _CCCL_API constexpr _IndexType size() const noexcept
|
||||
{
|
||||
return __num_elements_;
|
||||
}
|
||||
};
|
||||
|
||||
_CCCL_END_NAMESPACE_CUDA
|
||||
|
||||
#include <cuda/std/__cccl/epilogue.h>
|
||||
|
||||
#endif // _CUDA___RANDOM_RANDOM_BIJECTION_H
|
||||
Reference in New Issue
Block a user