Expression Templates Library (ETL)
uniform.hpp
Go to the documentation of this file.
1 //=======================================================================
2 // Copyright (c) 2014-2023 Baptiste Wicht
3 // Distributed under the terms of the MIT License.
4 // (See accompanying file LICENSE or copy at
5 // http://opensource.org/licenses/MIT)
6 //=======================================================================
7 
13 #pragma once
14 
15 #ifdef ETL_CURAND_MODE
17 #endif
18 
21 
22 #include <chrono> //for std::time
23 
24 namespace etl {
25 
30 template <typename T>
31 using uniform_distribution = std::conditional_t<std::is_floating_point_v<T>, std::uniform_real_distribution<T>, std::uniform_int_distribution<T>>;
32 
36 template <typename T = double>
38  using value_type = T;
39 
40  const T start;
41  const T end;
44 
48  static constexpr bool gpu_computable = curand_enabled
49  && ((is_single_precision_t<T> && impl::egblas::has_scalar_sadd && impl::egblas::has_scalar_smul)
50  || (is_double_precision_t<T> && impl::egblas::has_scalar_dadd && impl::egblas::has_scalar_dmul));
51 
57  uniform_generator_op(T start, T end) : start(start), end(end), rand_engine(std::time(nullptr)), distribution(start, end) {}
58 
64  return distribution(rand_engine);
65  }
66 
67 #ifdef ETL_CURAND_MODE
68 
75  template <typename Y>
76  auto gpu_compute_hint(Y& y) noexcept {
77  auto t1 = etl::force_temporary_gpu_dim_only_t<T>(y);
78 
79  curandGenerator_t gen;
80 
81  // Create the generator
82  curand_call(curandCreateGenerator(&gen, CURAND_RNG_PSEUDO_DEFAULT));
83 
84  // Seed it with the internal random engine
85  std::uniform_int_distribution<long> seed_dist;
86  curand_call(curandSetPseudoRandomGeneratorSeed(gen, seed_dist(rand_engine)));
87 
88  // Generate the random numbers in [0,1]
89  impl::curand::generate_uniform(gen, t1.gpu_memory(), etl::size(y));
90 
91  // mul by b-a => [0,b-a]
92  auto s1 = T(end) - T(start);
93  impl::egblas::scalar_mul(t1.gpu_memory(), etl::size(y), 1, s1);
94 
95  // Add a => [a,b]
96  auto s2 = T(start);
97  impl::egblas::scalar_add(t1.gpu_memory(), etl::size(y), 1, s2);
98 
99  return t1;
100  }
101 
108  template <typename Y>
109  Y& gpu_compute(Y& y) noexcept {
110  y.ensure_gpu_allocated();
111 
112  curandGenerator_t gen;
113 
114  // Create the generator
115  curand_call(curandCreateGenerator(&gen, CURAND_RNG_PSEUDO_DEFAULT));
116 
117  // Seed it with the internal random engine
118  std::uniform_int_distribution<long> seed_dist;
119  curand_call(curandSetPseudoRandomGeneratorSeed(gen, seed_dist(rand_engine)));
120 
121  // Generate the random numbers in [0,1]
122  impl::curand::generate_uniform(gen, y.gpu_memory(), etl::size(y));
123 
124  // mul by b-a => [0,b-a]
125  auto s1 = T(end) - T(start);
126  impl::egblas::scalar_mul(y.gpu_memory(), etl::size(y), 1, s1);
127 
128  // Add a => [a,b]
129  auto s2 = T(start);
130  impl::egblas::scalar_add(y.gpu_memory(), etl::size(y), 1, s2);
131 
132  y.validate_gpu();
133  y.invalidate_cpu();
134 
135  return y;
136  }
137 
138 #endif
139 
146  friend std::ostream& operator<<(std::ostream& os, [[maybe_unused]] const uniform_generator_op& s) {
147  return os << "U(0,1)";
148  }
149 };
150 
154 template <typename G, typename T = double>
156  using value_type = T;
157 
158  const T start;
159  const T end;
162 
166  static constexpr bool gpu_computable = curand_enabled
167  && ((is_single_precision_t<T> && impl::egblas::has_scalar_sadd && impl::egblas::has_scalar_smul)
168  || (is_double_precision_t<T> && impl::egblas::has_scalar_dadd && impl::egblas::has_scalar_dmul));
169 
175  uniform_generator_g_op(G& g, T start, T end) : start(start), end(end), rand_engine(g), distribution(start, end) {}
176 
182  return distribution(rand_engine);
183  }
184 
185 #ifdef ETL_CURAND_MODE
186 
193  template <typename Y>
194  auto gpu_compute_hint(Y& y) noexcept {
195  auto t1 = etl::force_temporary_gpu_dim_only_t<T>(y);
196 
197  curandGenerator_t gen;
198 
199  // Create the generator
200  curand_call(curandCreateGenerator(&gen, CURAND_RNG_PSEUDO_DEFAULT));
201 
202  // Seed it with the internal random engine
203  std::uniform_int_distribution<long> seed_dist;
204  curand_call(curandSetPseudoRandomGeneratorSeed(gen, seed_dist(rand_engine)));
205 
206  // Generate the random numbers in [0,1]
207  impl::curand::generate_uniform(gen, t1.gpu_memory(), etl::size(y));
208 
209  // mul by b-a => [0,b-a]
210  auto s1 = T(end) - T(start);
211  impl::egblas::scalar_mul(t1.gpu_memory(), etl::size(y), 1, s1);
212 
213  // Add a => [a,b]
214  auto s2 = T(start);
215  impl::egblas::scalar_add(t1.gpu_memory(), etl::size(y), 1, s2);
216 
217  return t1;
218  }
219 
226  template <typename Y>
227  Y& gpu_compute(Y& y) noexcept {
228  y.ensure_gpu_allocated();
229 
230  curandGenerator_t gen;
231 
232  // Create the generator
233  curand_call(curandCreateGenerator(&gen, CURAND_RNG_PSEUDO_DEFAULT));
234 
235  // Seed it with the internal random engine
236  std::uniform_int_distribution<long> seed_dist;
237  curand_call(curandSetPseudoRandomGeneratorSeed(gen, seed_dist(rand_engine)));
238 
239  // Generate the random numbers in [0,1]
240  impl::curand::generate_uniform(gen, y.gpu_memory(), etl::size(y));
241 
242  // mul by b-a => [0,b-a]
243  auto s1 = T(end) - T(start);
244  impl::egblas::scalar_mul(y.gpu_memory(), etl::size(y), 1, s1);
245 
246  // Add a => [a,b]
247  auto s2 = T(start);
248  impl::egblas::scalar_add(y.gpu_memory(), etl::size(y), 1, s2);
249 
250  y.validate_gpu();
251  y.invalidate_cpu();
252 
253  return y;
254  }
255 
256 #endif
257 
264  friend std::ostream& operator<<(std::ostream& os, [[maybe_unused]] const uniform_generator_g_op& s) {
265  return os << "U(0,1)";
266  }
267 };
268 
269 } //end of namespace etl
EGBLAS wrappers for the scalar_mul operation.
auto s(T &&value)
Force the evaluation of the given expression.
Definition: stop.hpp:18
T value_type
The value type.
Definition: uniform.hpp:156
uniform_distribution< value_type > distribution
The used distribution.
Definition: uniform.hpp:43
uniform_generator_op(T start, T end)
Construct a new generator with the given start and end of the range.
Definition: uniform.hpp:57
Generator from an uniform distribution using a custom random engine.
Definition: uniform.hpp:155
std::conditional_t< std::is_floating_point_v< T >, std::uniform_real_distribution< T >, std::uniform_int_distribution< T > > uniform_distribution
Selector helper to get an uniform_distribution based on the type (real or int)
Definition: uniform.hpp:31
value_type operator()()
Generate a new value.
Definition: uniform.hpp:63
EGBLAS wrappers for the scalar_add operation.
constexpr bool curand_enabled
Indicates if the NVIDIA CURAND library is available for ETL.
Definition: config.hpp:109
static constexpr bool gpu_computable
Indicates if the operator can be computed on GPU.
Definition: uniform.hpp:48
uniform_generator_g_op(G &g, T start, T end)
Construct a new generator with the given start and end of the range.
Definition: uniform.hpp:175
const T start
The start of the distribution.
Definition: uniform.hpp:158
Root namespace for the ETL library.
Definition: adapter.hpp:15
friend std::ostream & operator<<(std::ostream &os, [[maybe_unused]] const uniform_generator_g_op &s)
Outputs the given generator to the given stream.
Definition: uniform.hpp:264
G & rand_engine
The random engine.
Definition: uniform.hpp:160
const T end
The end of the distribution.
Definition: uniform.hpp:41
Generator from an uniform distribution.
Definition: uniform.hpp:37
const T end
The end of the distribution.
Definition: uniform.hpp:159
constexpr size_t size(const E &expr) noexcept
Returns the size of the given ETL expression.
Definition: helpers.hpp:108
uniform_distribution< value_type > distribution
The used distribution.
Definition: uniform.hpp:161
value_type operator()()
Generate a new value.
Definition: uniform.hpp:181
const T start
The start of the distribution.
Definition: uniform.hpp:40
std::mt19937_64 random_engine
The random engine used by the library.
Definition: random.hpp:22
Utility functions for curand.
T value_type
The value type.
Definition: uniform.hpp:38
const auto & gpu_compute_hint([[maybe_unused]] Y &y) const
Return a GPU computed version of this expression.
Definition: sub_view.hpp:653
random_engine rand_engine
The random engine.
Definition: uniform.hpp:42
friend std::ostream & operator<<(std::ostream &os, [[maybe_unused]] const uniform_generator_op &s)
Outputs the given generator to the given stream.
Definition: uniform.hpp:146