12#ifndef EIGEN_TENSOR_TENSOR_RANDOM_H
13#define EIGEN_TENSOR_TENSOR_RANDOM_H
16#include "./InternalHeaderCheck.h"
21EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE uint64_t get_random_seed() {
22#if defined(EIGEN_GPU_COMPILE_PHASE)
25 eigen_assert(threadIdx.z == 0);
26 return blockIdx.x * blockDim.x + threadIdx.x + gridDim.x * blockDim.x * (blockIdx.y * blockDim.y + threadIdx.y);
29 return random<uint64_t>();
33EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
unsigned PCG_XSH_RS_generator(uint64_t* state, uint64_t stream) {
35 uint64_t current = *state;
37 *state = current * 6364136223846793005ULL + (stream << 1 | 1);
39 return static_cast<unsigned>((current ^ (current >> 22)) >> (22 + (current >> 61)));
42EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE uint64_t PCG_XSH_RS_state(uint64_t seed) {
43 seed = seed ? seed : get_random_seed();
44 return seed * 6364136223846793005ULL + 0xda3e39cb94b95bdbULL;
51EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE uint64_t PCG_XSH_RS_state_for_index(uint64_t base_state, uint64_t index) {
52 return splitmix64_mix(base_state + index * 0x9e3779b97f4a7c15ULL);
56EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T RandomToTypeUniform(uint64_t* state, uint64_t stream) {
57 unsigned rnd = PCG_XSH_RS_generator(state, stream);
58 return static_cast<T
>(rnd);
62EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
bool RandomToTypeUniform<bool>(uint64_t* state, uint64_t stream) {
63 unsigned rnd = PCG_XSH_RS_generator(state, stream);
64 return (rnd & 0x1) != 0;
68EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Eigen::half RandomToTypeUniform<Eigen::half>(uint64_t* state, uint64_t stream) {
70 unsigned rnd = PCG_XSH_RS_generator(state, stream);
71 const uint16_t half_bits =
static_cast<uint16_t
>(rnd & 0x3ffu) | (
static_cast<uint16_t
>(15) << 10);
72 Eigen::half result = Eigen::numext::bit_cast<Eigen::half>(half_bits);
73 return result - Eigen::half(1.0f);
77EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Eigen::bfloat16 RandomToTypeUniform<Eigen::bfloat16>(uint64_t* state,
80 unsigned rnd = PCG_XSH_RS_generator(state, stream);
81 const uint16_t half_bits =
static_cast<uint16_t
>(rnd & 0x7fu) | (
static_cast<uint16_t
>(127) << 7);
82 Eigen::bfloat16 result = Eigen::numext::bit_cast<Eigen::bfloat16>(half_bits);
83 return result - Eigen::bfloat16(1.0f);
87EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
float RandomToTypeUniform<float>(uint64_t* state, uint64_t stream) {
94 const unsigned rnd = PCG_XSH_RS_generator(state, stream);
95 result.raw = rnd & 0x7fffffu;
97 result.raw |= (
static_cast<uint32_t
>(127) << 23);
98 return result.fp - 1.0f;
102EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
double RandomToTypeUniform<double>(uint64_t* state, uint64_t stream) {
111 unsigned rnd1 = PCG_XSH_RS_generator(state, stream) & 0xfffffu;
113 unsigned rnd2 = PCG_XSH_RS_generator(state, stream);
114 result.raw = (
static_cast<uint64_t
>(rnd1) << 32) | rnd2;
116 result.raw |= (
static_cast<uint64_t
>(1023) << 52);
118 return result.dp - 1.0;
122EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::complex<float> RandomToTypeUniform<std::complex<float> >(uint64_t* state,
124 const float real = RandomToTypeUniform<float>(state, stream);
125 const float imag = RandomToTypeUniform<float>(state, stream);
126 return std::complex<float>(real, imag);
129EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::complex<double> RandomToTypeUniform<std::complex<double> >(uint64_t* state,
131 const double real = RandomToTypeUniform<double>(state, stream);
132 const double imag = RandomToTypeUniform<double>(state, stream);
133 return std::complex<double>(real, imag);
140class UniformRandomGenerator {
142 static constexpr bool PacketAccess =
true;
145 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE UniformRandomGenerator(uint64_t seed = 0) : m_state(PCG_XSH_RS_state(seed)) {}
147 template <
typename Index>
148 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T operator()(Index i)
const {
149 const uint64_t index =
static_cast<uint64_t
>(i);
150 uint64_t state = PCG_XSH_RS_state_for_index(m_state, index);
151 return RandomToTypeUniform<T>(&state, index);
154 template <
typename Packet,
typename Index>
155 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(Index i)
const {
156 const int packetSize = internal::unpacket_traits<Packet>::size;
157 EIGEN_ALIGN_TO_BOUNDARY(unpacket_traits<Packet>::alignment) T values[packetSize];
159 for (
int j = 0; j < packetSize; ++j) {
160 values[j] = (*this)(i + j);
162 return internal::pload<Packet>(values);
169template <
typename Scalar>
170struct functor_traits<UniformRandomGenerator<Scalar> > {
173 Cost = 12 * NumTraits<Scalar>::AddCost * ((
sizeof(Scalar) +
sizeof(float) - 1) /
sizeof(float)),
174 PacketAccess = UniformRandomGenerator<Scalar>::PacketAccess,
182EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T RandomToTypeNormal(uint64_t* state, uint64_t stream) {
188 u = RandomToTypeUniform<T>(state, stream);
189 v = T(1.7156) * (RandomToTypeUniform<T>(state, stream) - T(0.5));
190 const T x = u - T(0.449871);
191 const T y = numext::abs(v) + T(0.386595);
192 q = x * x + y * (T(0.196) * y - T(0.25472) * x);
195 }
while (u == T(0) || (q > T(0.27597) && (q > T(0.27846) || v * v > T(-4) * numext::log(u) * u * u)));
206EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Eigen::half RandomToTypeNormal<Eigen::half>(uint64_t* state, uint64_t stream) {
207 return Eigen::half(RandomToTypeNormal<float>(state, stream));
210EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Eigen::bfloat16 RandomToTypeNormal<Eigen::bfloat16>(uint64_t* state,
212 return Eigen::bfloat16(RandomToTypeNormal<float>(state, stream));
216EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::complex<float> RandomToTypeNormal<std::complex<float> >(uint64_t* state,
218 const float real = RandomToTypeNormal<float>(state, stream);
219 const float imag = RandomToTypeNormal<float>(state, stream);
220 return std::complex<float>(real, imag);
223EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::complex<double> RandomToTypeNormal<std::complex<double> >(uint64_t* state,
225 const double real = RandomToTypeNormal<double>(state, stream);
226 const double imag = RandomToTypeNormal<double>(state, stream);
227 return std::complex<double>(real, imag);
233class NormalRandomGenerator {
235 static constexpr bool PacketAccess =
true;
238 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE NormalRandomGenerator(uint64_t seed = 0) : m_state(PCG_XSH_RS_state(seed)) {}
240 template <
typename Index>
241 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T operator()(Index i)
const {
242 const uint64_t index =
static_cast<uint64_t
>(i);
243 uint64_t state = PCG_XSH_RS_state_for_index(m_state, index);
244 return RandomToTypeNormal<T>(&state, index);
247 template <
typename Packet,
typename Index>
248 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(Index i)
const {
249 const int packetSize = internal::unpacket_traits<Packet>::size;
250 EIGEN_ALIGN_TO_BOUNDARY(unpacket_traits<Packet>::alignment) T values[packetSize];
252 for (
int j = 0; j < packetSize; ++j) {
253 values[j] = (*this)(i + j);
255 return internal::pload<Packet>(values);
262template <
typename Scalar>
263struct functor_traits<NormalRandomGenerator<Scalar> > {
267 Cost = 3 * functor_traits<UniformRandomGenerator<Scalar> >::Cost + 15 * NumTraits<Scalar>::AddCost +
268 8 * NumTraits<Scalar>::AddCost + 3 * functor_traits<scalar_log_op<Scalar> >::Cost / 2,
269 PacketAccess = NormalRandomGenerator<Scalar>::PacketAccess,
Namespace containing all symbols from the Eigen library.