Fermat
distributions.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2010-2019, NVIDIA Corporation
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of NVIDIA Corporation nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
32 #ifndef __CUGAR_DISTRIBUTIONS_H
33 #define __CUGAR_DISTRIBUTIONS_H
34 
35 #include <cugar/sampling/random.h>
36 #include <cugar/linalg/vector.h>
37 #include <cugar/linalg/matrix.h>
38 
39 namespace cugar {
40 
79 template <typename Derived_type>
84 {
88  template <typename Generator>
89  inline float next(Generator& gen) const
90  {
91  return static_cast<const Derived_type*>(this)->map( gen.next() );
92  }
93 };
94 
98 struct Uniform_distribution : Base_distribution<Uniform_distribution>
99 {
103  CUGAR_HOST_DEVICE Uniform_distribution(const float b) : m_b( b ) {}
104 
108  inline CUGAR_HOST_DEVICE float map(const float U) const { return m_b * (U*2.0f - 1.0f); }
109 
113  inline CUGAR_HOST_DEVICE float density(const float x) const
114  {
115  return (x >= -m_b && x <= m_b) ? m_b * 2.0f : 0.0f;
116  }
117 
118 private:
119  float m_b;
120 };
124 struct Cosine_distribution : Base_distribution<Cosine_distribution>
125 {
129  inline CUGAR_HOST_DEVICE float map(const float U) const
130  {
131  return asin( 0.5f * U ) * 2.0f / M_PIf;
132  }
136  inline CUGAR_HOST_DEVICE float density(const float x) const
137  {
138  if (x >= -1.0f && x <= 1.0f)
139  return M_PIf*0.25f * cosf( x * M_PIf*0.5f );
140  return 0.0f;
141  }
142 };
146 struct Pareto_distribution : Base_distribution<Pareto_distribution>
147 {
152  CUGAR_HOST_DEVICE Pareto_distribution(const float a, const float min) : m_a( a ), m_inv_a( 1.0f / a ), m_min( min ) {}
153 
157  inline CUGAR_HOST_DEVICE float map(const float U) const
158  {
159  return U < 0.5f ?
160  m_min / powf( (0.5f - U)*2.0f, m_inv_a ) :
161  -m_min / powf( (U - 0.5f)*2.0f, m_inv_a );
162  }
166  inline CUGAR_HOST_DEVICE float density(const float x) const
167  {
168  if (x >= -m_min && x <= m_min)
169  return 0.0f;
170 
171  return 0.5f * m_a * powf( m_min, m_a ) / powf( fabsf(x), m_a + 1.0f );
172  }
173 
174 private:
175  float m_a;
176  float m_inv_a;
177  float m_min;
178 };
182 struct Bounded_pareto_distribution : Base_distribution<Bounded_pareto_distribution>
183 {
189  CUGAR_HOST_DEVICE Bounded_pareto_distribution(const float a, const float min, const float max) :
190  m_a( a ), m_inv_a( 1.0f / a ), m_min( min ), m_max( max ),
191  m_min_a( powf( m_min, m_a ) ),
192  m_max_a( powf( m_max, m_a ) ) {}
193 
197  inline CUGAR_HOST_DEVICE float map(const float U) const
198  {
199  if (U < 0.5f)
200  {
201  const float u = (0.5f - U)*2.0f;
202  return powf( -(u * m_max_a - u * m_min_a - m_max_a) / (m_max_a*m_min_a), -m_inv_a);
203  }
204  else
205  {
206  const float u = (U - 0.5f)*2.0f;
207  return -powf( -(u * m_max_a - u * m_min_a - m_max_a) / (m_max_a*m_min_a), -m_inv_a);
208  }
209  }
213  inline CUGAR_HOST_DEVICE float density(const float x) const
214  {
215  if (x >= -m_min && x <= m_min)
216  return 0.0f;
217  if (x <= -m_max || x >= m_max)
218  return 0.0f;
219 
220  return 0.5f * m_a * m_min_a * powf( fabsf(x), -m_a - 1.0f ) / (1.0f - m_min_a / m_max_a);
221  }
222 
223 private:
224  float m_a;
225  float m_inv_a;
226  float m_min;
227  float m_max;
228  float m_min_a;
229  float m_max_a;
230 };
234 struct Bounded_exponential : Base_distribution<Bounded_exponential>
235 {
239  CUGAR_HOST_DEVICE Bounded_exponential(const float b) :
240  m_s1( b / 16.0f ),
241  m_s2( b ),
242  m_ln( -logf(m_s2/m_s1) ) {}
243 
247  CUGAR_HOST_DEVICE Bounded_exponential(const float b1, const float b2) :
248  m_s1(b1),
249  m_s2(b2),
250  m_ln(-logf(m_s2 / m_s1)) {}
251 
255  inline CUGAR_HOST_DEVICE float map(const float U) const
256  {
257  return U < 0.5f ?
258  +m_s2 * expf( m_ln*(0.5f - U)*2.0f ) :
259  -m_s2 * expf( m_ln*(U - 0.5f)*2.0f );
260  }
264  inline CUGAR_HOST_DEVICE float density(const float x) const
265  {
266  // positive x:
267  // => x / s2 = exp( ln * (0.5 - U) * 2
268  // => log( x / s2 ) = ln * (0.5 - U) * 2
269  // => log( x / s2 ) / (2 * ln) = (0.5 - U)
270  // => U = 0.5 - log( x / s2 ) / (2 * ln)
271  // => CDF(x) = 1 - (0.5 - log( x / s2 ) / (2 * ln))
272  // => PDF(x) = 1 / (x * 2 * ln)
273 
274  // negative x:
275  // => -x / s2 = exp( ln * (U - 0.5) * 2
276  // => log( -x / s2 ) = ln * (U - 0.5) * 2
277  // => log( -x / s2 ) / (2 * ln) = (U - 0.5)
278  // => U = log( -x / s2 ) / (2 * ln) + 0.5
279  // => CDF(x) = 1 - (log( -x / s2 ) / (2 * ln) + 0.5)
280  // => PDF(x) = -1 / (x * 2 * ln)
281  return
282  x > +m_s2 ? 0.5f / (x * 2 * m_ln) :
283  x < -m_s2 ? -0.5f / (x * 2 * m_ln) :
284  0.0f;
285  }
286 
287 private:
288  float m_s1;
289  float m_s2;
290  float m_ln;
291 };
295 struct Cauchy_distribution : Base_distribution<Cauchy_distribution>
296 {
300  CUGAR_HOST_DEVICE Cauchy_distribution(const float gamma) :
301  m_gamma( gamma ) {}
302 
306  inline CUGAR_HOST_DEVICE float map(const float U) const
307  {
308  return m_gamma * tanf( float(M_PI) * (U - 0.5f) );
309  }
313  inline CUGAR_HOST_DEVICE float density(const float x) const
314  {
315  return (m_gamma / (x*x + m_gamma*m_gamma)) / float(M_PI);
316  }
317 
318 private:
319  float m_gamma;
320 };
324 struct Exponential_distribution : Base_distribution<Exponential_distribution>
325 {
329  CUGAR_HOST_DEVICE Exponential_distribution(const float lambda) :
330  m_lambda( lambda ) {}
331 
335  inline CUGAR_HOST_DEVICE float map(const float U) const
336  {
337  const float eps = 1.0e-5f;
338  return U < 0.5f ?
339  -logf( cugar::max( (0.5f - U)*2.0f, eps ) ) / m_lambda :
340  logf( cugar::max( (U - 0.5f)*2.0f, eps ) ) / m_lambda;
341  }
345  inline CUGAR_HOST_DEVICE float density(const float x) const
346  {
347  return 0.5f * m_lambda * expf( -m_lambda * fabsf(x) );
348  }
349 
350 private:
351  float m_lambda;
352 };
357 {
361  CUGAR_HOST_DEVICE Gaussian_distribution_symm_2d(const float sigma) :
362  m_sigma( sigma ) {}
363 
367  inline CUGAR_HOST_DEVICE Vector2f map(const Vector2f uv) const
368  {
369  const float eps = 1.0e-5f;
370  const float r = m_sigma * sqrtf( - 2.0f * logf(cugar::max( uv[0], eps ) ) );
371  return Vector2f(
372  r * cosf( 2.0f * float(M_PI) * uv[1] ),
373  r * sinf( 2.0f * float(M_PI) * uv[1] ) );
374  }
378  inline CUGAR_HOST_DEVICE float density(const Vector2f x) const
379  {
380  return expf( -square_length(x) / (2.0f * m_sigma*m_sigma) ) / (2.0f * float(M_PI) * m_sigma*m_sigma);
381  }
382 
383 private:
384  float m_sigma;
385 };
390 {
391  enum MatrixType { COVARIANCE_MATRIX, PRECISION_MATRIX };
392 
398  CUGAR_HOST_DEVICE Gaussian_distribution_2d()
399  {
400  m_mu = cugar::Vector2f(0.0f, 0.0f);
401 
402  m_prec[0] = cugar::Vector2f(1.0f, 0.0f);
403  m_prec[1] = cugar::Vector2f(0.0f, 1.0f);
404  m_chol[0] = cugar::Vector2f(1.0f, 0.0f);
405  m_chol[1] = cugar::Vector2f(0.0f, 1.0f);
406 
407  m_norm = 1.0f;
408  }
409 
415  CUGAR_HOST_DEVICE Gaussian_distribution_2d(const Vector2f mu, const Matrix2x2f matrix, const MatrixType matrix_type = COVARIANCE_MATRIX) :
416  m_mu( mu )
417  {
418  if (matrix_type == COVARIANCE_MATRIX)
419  {
420  // compute the precision matrix
421  const Matrix2x2f& sigma = matrix;
422  invert( sigma, m_prec );
423 
424  // compute the cholesky factorization of sigma
425  cholesky( sigma, m_chol );
426 
427  // compute the normalization constant
428  m_norm = 1.0f / sqrtf( 2.0f * float(M_PI) * det(sigma) );
429  }
430  else
431  {
432  m_prec = matrix;
433 
434  // compute the covariance matrix
435  Matrix2x2f sigma;
436  invert( m_prec, sigma );
437 
438  // compute the cholesky factorization of sigma
439  cholesky( sigma, m_chol );
440 
441  // compute the normalization constant
442  m_norm = 1.0f / sqrtf( 2.0f * float(M_PI) * det(sigma) );
443  }
444  }
445 
450  CUGAR_HOST_DEVICE Gaussian_distribution_2d(const Vector2f mu, const Matrix2x2f sigma, const Matrix2x2f prec) :
451  m_mu( mu ), m_prec( prec )
452  {
453  cholesky( sigma, m_chol );
454 
455  // compute the normalization constant
456  m_norm = 1.0f / sqrtf( 2.0f * float(M_PI) * det(sigma) );
457  }
458 
462  inline CUGAR_HOST_DEVICE Vector2f map(const Vector2f uv) const
463  {
464  const float eps = 1.0e-5f;
465  const float r = sqrtf( - 2.0f * logf(cugar::max( uv[0], eps ) ) );
466  const Vector2f normal = Vector2f(
467  r * cosf( 2.0f * float(M_PI) * uv[1] ),
468  r * sinf( 2.0f * float(M_PI) * uv[1] ) );
469 
470  return m_mu + m_chol * normal;
471  }
475  inline CUGAR_HOST_DEVICE float density(const Vector2f x) const
476  {
477  const float x2 = dot( x - m_mu, m_prec * (x - m_mu) );
478  return m_norm * expf( -0.5f * x2 );
479  }
480 
483  CUGAR_HOST_DEVICE Vector2f mean() const
484  {
485  return m_mu;
486  }
487 
490  CUGAR_HOST_DEVICE const Matrix2x2f& precision() const
491  {
492  return m_prec;
493  }
494 
497  CUGAR_HOST_DEVICE const Matrix2x2f covariance() const
498  {
499  Matrix2x2f sigma;
500  invert( m_prec, sigma );
501  return sigma;
502  }
503 
504 private:
505  Vector2f m_mu;
506  Matrix2x2f m_prec;
507  Matrix2x2f m_chol;
508  float m_norm;
509 };
510 
514 template <typename Generator, typename Distribution>
516 {
521  CUGAR_HOST_DEVICE Transform_generator(Generator& gen, const Distribution& dist) : m_gen( gen ), m_dist( dist ) {}
522 
525  inline CUGAR_HOST_DEVICE float next() const
526  {
527  return m_dist.map( m_gen.next() );
528  }
532  inline CUGAR_HOST_DEVICE float density(const float x) const
533  {
534  return m_dist.density( x );
535  }
536 
537  Generator& m_gen;
538  Distribution m_dist;
539 };
540 
546 {
550  CUGAR_HOST_DEVICE Gaussian_generator(const float sigma) :
551  m_sigma( sigma ),
552  m_cached( false ) {}
553 
557  template <typename Generator>
558  inline CUGAR_HOST_DEVICE float next(Generator& random)
559  {
560  if (m_cached)
561  {
562  m_cached = false;
563  return m_cache;
564  }
565 
566  const Vector2f uv( random.next(), random.next() );
567  const float eps = 1.0e-5f;
568  const float r = m_sigma * sqrtf( - 2.0f * logf(cugar::max( uv[0], eps ) ) );
569  const float y0 = r * cosf( 2.0f * float(M_PI) * uv[1] );
570  const float y1 = r * sinf( 2.0f * float(M_PI) * uv[1] );
571 
572  m_cache = y1;
573  m_cached = true;
574  return y0;
575  }
579  inline CUGAR_HOST_DEVICE float density(const float x) const
580  {
581  const float SQRT_TWO_PI = sqrtf(2.0f * M_PIf);
582  return expf( -x*x/(2.0f*m_sigma*m_sigma) ) / (SQRT_TWO_PI*m_sigma);
583  }
584 
585 private:
586  float m_sigma;
587  float m_cache;
588  bool m_cached;
589 };
590 
594 } // namespace cugar
595 
596 #endif
CUGAR_HOST_DEVICE const Matrix2x2f & precision() const
Definition: distributions.h:490
CUGAR_HOST_DEVICE float map(const float U) const
Definition: distributions.h:255
CUGAR_HOST_DEVICE Vector2f map(const Vector2f uv) const
Definition: distributions.h:462
CUGAR_HOST_DEVICE float next(Generator &random)
Definition: distributions.h:558
Definition: distributions.h:515
Definition: distributions.h:146
CUGAR_HOST_DEVICE float map(const float U) const
Definition: distributions.h:157
Definition: distributions.h:83
CUGAR_HOST_DEVICE float density(const float x) const
Definition: distributions.h:136
CUGAR_HOST_DEVICE float density(const float x) const
Definition: distributions.h:579
CUGAR_HOST_DEVICE Transform_generator(Generator &gen, const Distribution &dist)
Definition: distributions.h:521
Definition: distributions.h:234
CUGAR_HOST_DEVICE float density(const float x) const
Definition: distributions.h:313
Definition: distributions.h:98
CUGAR_HOST_DEVICE float density(const Vector2f x) const
Definition: distributions.h:378
Definition: distributions.h:389
CUGAR_HOST_DEVICE Vector2f map(const Vector2f uv) const
Definition: distributions.h:367
CUGAR_HOST_DEVICE float density(const float x) const
Definition: distributions.h:113
CUGAR_HOST_DEVICE Uniform_distribution(const float b)
Definition: distributions.h:103
Definition: distributions.h:324
CUGAR_HOST_DEVICE float map(const float U) const
Definition: distributions.h:108
CUGAR_HOST_DEVICE Bounded_exponential(const float b)
Definition: distributions.h:239
CUGAR_HOST_DEVICE float density(const float x) const
Definition: distributions.h:213
float next(Generator &gen) const
Definition: distributions.h:89
CUGAR_HOST_DEVICE Vector2f mean() const
Definition: distributions.h:483
CUGAR_HOST_DEVICE Gaussian_distribution_2d()
Definition: distributions.h:398
CUGAR_HOST_DEVICE float density(const float x) const
Definition: distributions.h:166
CUGAR_HOST_DEVICE float map(const float U) const
Definition: distributions.h:335
CUGAR_HOST_DEVICE float map(const float U) const
Definition: distributions.h:197
CUGAR_HOST_DEVICE float density(const float x) const
Definition: distributions.h:264
CUGAR_HOST_DEVICE Gaussian_generator(const float sigma)
Definition: distributions.h:550
CUGAR_HOST_DEVICE Gaussian_distribution_symm_2d(const float sigma)
Definition: distributions.h:361
CUGAR_HOST_DEVICE Pareto_distribution(const float a, const float min)
Definition: distributions.h:152
CUGAR_HOST_DEVICE Bounded_exponential(const float b1, const float b2)
Definition: distributions.h:247
Definition: distributions.h:356
CUGAR_HOST_DEVICE Cauchy_distribution(const float gamma)
Definition: distributions.h:300
float random()
Definition: tiled_sampling.h:44
CUGAR_HOST_DEVICE Gaussian_distribution_2d(const Vector2f mu, const Matrix2x2f matrix, const MatrixType matrix_type=COVARIANCE_MATRIX)
Definition: distributions.h:415
CUGAR_HOST_DEVICE Exponential_distribution(const float lambda)
Definition: distributions.h:329
CUGAR_HOST_DEVICE const Matrix2x2f covariance() const
Definition: distributions.h:497
CUGAR_HOST_DEVICE Bounded_pareto_distribution(const float a, const float min, const float max)
Definition: distributions.h:189
Define a vector_view POD type and plain_view() for std::vector.
Definition: diff.h:38
CUGAR_HOST_DEVICE float density(const Vector2f x) const
Definition: distributions.h:475
Definition: distributions.h:182
CUGAR_HOST_DEVICE Gaussian_distribution_2d(const Vector2f mu, const Matrix2x2f sigma, const Matrix2x2f prec)
Definition: distributions.h:450
Definition: distributions.h:295
Definition: distributions.h:545
CUGAR_HOST_DEVICE float map(const float U) const
Definition: distributions.h:306
CUGAR_HOST_DEVICE float density(const float x) const
Definition: distributions.h:345
Defines several random samplers.
CUGAR_HOST_DEVICE float density(const float x) const
Definition: distributions.h:532
CUGAR_HOST_DEVICE float next() const
Definition: distributions.h:525
CUGAR_HOST_DEVICE float map(const float U) const
Definition: distributions.h:129
Definition: distributions.h:124