PCL
Random.h
Go to the documentation of this file.
1 // ____ ______ __
2 // / __ \ / ____// /
3 // / /_/ // / / /
4 // / ____// /___ / /___ PixInsight Class Library
5 // /_/ \____//_____/ PCL 2.7.0
6 // ----------------------------------------------------------------------------
7 // pcl/Random.h - Released 2024-06-18T15:48:54Z
8 // ----------------------------------------------------------------------------
9 // This file is part of the PixInsight Class Library (PCL).
10 // PCL is a multiplatform C++ framework for development of PixInsight modules.
11 //
12 // Copyright (c) 2003-2024 Pleiades Astrophoto S.L. All Rights Reserved.
13 //
14 // Redistribution and use in both source and binary forms, with or without
15 // modification, is permitted provided that the following conditions are met:
16 //
17 // 1. All redistributions of source code must retain the above copyright
18 // notice, this list of conditions and the following disclaimer.
19 //
20 // 2. All redistributions in binary form must reproduce the above copyright
21 // notice, this list of conditions and the following disclaimer in the
22 // documentation and/or other materials provided with the distribution.
23 //
24 // 3. Neither the names "PixInsight" and "Pleiades Astrophoto", nor the names
25 // of their contributors, may be used to endorse or promote products derived
26 // from this software without specific prior written permission. For written
27 // permission, please contact info@pixinsight.com.
28 //
29 // 4. All products derived from this software, in any form whatsoever, must
30 // reproduce the following acknowledgment in the end-user documentation
31 // and/or other materials provided with the product:
32 //
33 // "This product is based on software from the PixInsight project, developed
34 // by Pleiades Astrophoto and its contributors (https://pixinsight.com/)."
35 //
36 // Alternatively, if that is where third-party acknowledgments normally
37 // appear, this acknowledgment must be reproduced in the product itself.
38 //
39 // THIS SOFTWARE IS PROVIDED BY PLEIADES ASTROPHOTO AND ITS CONTRIBUTORS
40 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
41 // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PLEIADES ASTROPHOTO OR ITS
43 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
44 // EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, BUSINESS
45 // INTERRUPTION; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; AND LOSS OF USE,
46 // DATA OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
47 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
48 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
49 // POSSIBILITY OF SUCH DAMAGE.
50 // ----------------------------------------------------------------------------
51 
52 #ifndef __PCL_Random_h
53 #define __PCL_Random_h
54 
56 
57 #include <pcl/Defs.h>
58 #include <pcl/Diagnostics.h>
59 
60 #include <pcl/AutoPointer.h>
61 #include <pcl/Vector.h>
62 
63 namespace pcl
64 {
65 
66 // ----------------------------------------------------------------------------
67 
90 
103 {
104  union { uint64 u64; uint32 u32[ 2 ]; } seed;
105  seed.u64 = RandomSeed64();
106  return seed.u32[0] ^ seed.u32[1];
107 }
108 
109 // ----------------------------------------------------------------------------
110 
111 class FastMersenneTwister;
112 
113 // ----------------------------------------------------------------------------
114 
154 class PCL_CLASS RandomNumberGenerator
155 {
156 public:
157 
171  RandomNumberGenerator( double ymax = 1.0, uint32 seed = 0 );
172 
177 
181  double operator ()()
182  {
183  return m_rmax*Rand32();
184  }
185 
190 
195  double Rand1()
196  {
197  return double( Rand32() )/uint32_max;
198  }
199 
205  double Uniform()
206  {
207  return operator()();
208  }
209 
214  double Normal( double mean = 0, double sigma = 1 );
215 
222  double Gaussian( double mean = 0, double sigma = 1 )
223  {
224  return Normal( mean, sigma );
225  }
226 
231  int Poisson( double lambda );
232 
236  double UpperBound() const
237  {
238  return m_ymax;
239  }
240 
244  void SetUpperBound( double ymax )
245  {
246  PCL_PRECONDITION( ymax > 0 )
247  PCL_PRECONDITION( 1 + ymax != 1 )
248  m_rmax = (m_ymax = ymax)/double( uint32_max );
249  m_normal = false;
250  }
251 
252 private:
253 
255  double m_ymax;
256  double m_rmax;
257  bool m_normal;
258  double m_vs; // second result from Box–Muller transform
259  DVector m_lambda; // precalculated for current Poisson lambda
260 };
261 
262 // ----------------------------------------------------------------------------
263 
298 class PCL_CLASS XorShift1024
299 {
300 public:
301 
309  XorShift1024( uint64 seed = 0 ) noexcept( false )
310  {
311  Initialize( seed );
312  }
313 
317  double operator ()() noexcept
318  {
319  return 5.4210108624275221703311e-20 * UI64(); // 1.0/(2^64 -1)
320  }
321 
325  uint64 UI64() noexcept
326  {
327  uint64 s0 = m_s[m_p];
328  uint64 s1 = m_s[m_p = (m_p + 1) & 15];
329  s1 ^= s1 << 31; // a
330  s1 ^= s1 >> 11; // b
331  s0 ^= s0 >> 30; // c
332  return (m_s[m_p] = s0 ^ s1) * 1181783497276652981ull;
333  }
334 
338  uint32 UI32() noexcept
339  {
340  return uint32( UI64() );
341  }
342 
347  uint64 UI64N( uint64 n ) noexcept
348  {
349  return UI64() % n;
350  }
351 
355  uint32 UIN( uint32 n ) noexcept
356  {
357  return UI64() % n;
358  }
359 
363  uint32 UI32N( uint32 n ) noexcept
364  {
365  return UIN( n );
366  }
367 
374  void Initialize( uint64 x )
375  {
376  if ( x == 0 )
377  x = RandomSeed64();
378  // Use a xorshift64* generator to initialize the state space.
379  for ( int i = 0; i < 16; ++i )
380  {
381  x ^= x >> 12; // a
382  x ^= x << 25; // b
383  x ^= x >> 27; // c
384  m_s[i] = x * 2685821657736338717ull;
385  }
386  m_p = 0;
387  }
388 
389 private:
390 
391  uint64 m_s[ 16 ]; // state space
392  int m_p; // current index
393 };
394 
395 // ----------------------------------------------------------------------------
396 
401 class PCL_CLASS XoShiRoBase
402 {
403 public:
404 
408  XoShiRoBase() = default;
409 
410 protected:
411 
416  static uint64 RotL( const uint64 x, int k ) noexcept
417  {
418  return (x << k) | (x >> (64 - k));
419  }
420 
426  static uint64 SplitMix64( uint64& x ) noexcept
427  {
428  uint64 z = (x += 0x9e3779b97f4a7c15);
429  z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
430  z = (z ^ (z >> 27)) * 0x94d049bb133111eb;
431  return z ^ (z >> 31);
432  }
433 
440  static double UI64ToDouble( uint64 x ) noexcept
441  {
442  return (x >> 11) * 0x1.0p-53;
443  }
444 };
445 
446 // ----------------------------------------------------------------------------
447 
477 class PCL_CLASS XoShiRo256ss : public XoShiRoBase
478 {
479 public:
480 
488  XoShiRo256ss( uint64 seed = 0 ) noexcept( false )
489  {
490  Initialize( seed );
491  }
492 
496  double operator ()() noexcept
497  {
498  return UI64ToDouble( UI64() );
499  }
500 
504  uint64 UI64() noexcept
505  {
506  const uint64 result = RotL( m_s[1]*5, 7 ) * 9;
507  const uint64 t = m_s[1] << 17;
508  m_s[2] ^= m_s[0];
509  m_s[3] ^= m_s[1];
510  m_s[1] ^= m_s[2];
511  m_s[0] ^= m_s[3];
512  m_s[2] ^= t;
513  m_s[3] = RotL( m_s[3], 45 );
514  return result;
515  }
516 
520  uint32 UI32() noexcept
521  {
522  return uint32( UI64() );
523  }
524 
529  uint64 UI64N( uint64 n ) noexcept
530  {
531  return UI64() % n;
532  }
533 
537  uint32 UIN( uint32 n ) noexcept
538  {
539  return UI64() % n;
540  }
541 
545  uint32 UI32N( uint32 n ) noexcept
546  {
547  return UIN( n );
548  }
549 
556  void Initialize( uint64 x )
557  {
558  if ( x == 0 )
559  x = RandomSeed64();
560  // Use a SplitMix64 generator to initialize the state space.
561  for ( int i = 0; i < 4; ++i )
562  m_s[i] = SplitMix64( x );
563  }
564 
565 private:
566 
567  uint64 m_s[ 4 ];
568 };
569 
570 // ----------------------------------------------------------------------------
571 
601 class PCL_CLASS XoRoShiRo1024ss : public XoShiRoBase
602 {
603 public:
604 
612  XoRoShiRo1024ss( uint64 seed = 0 ) noexcept( false )
613  {
614  Initialize( seed );
615  }
616 
620  double operator ()() noexcept
621  {
622  return UI64ToDouble( UI64() );
623  }
624 
628  uint64 UI64() noexcept
629  {
630  const int q = m_p;
631  const uint64 s0 = m_s[m_p = (m_p + 1) & 15];
632  uint64 s15 = m_s[q];
633  const uint64 result = RotL( s0*5, 7 ) * 9;
634  s15 ^= s0;
635  m_s[q] = RotL( s0, 25 ) ^ s15 ^ (s15 << 27);
636  m_s[m_p] = RotL( s15, 36 );
637  return result;
638  }
639 
643  uint32 UI32() noexcept
644  {
645  return uint32( UI64() );
646  }
647 
652  uint64 UI64N( uint64 n ) noexcept
653  {
654  return UI64() % n;
655  }
656 
660  uint32 UIN( uint32 n ) noexcept
661  {
662  return UI64() % n;
663  }
664 
668  uint32 UI32N( uint32 n ) noexcept
669  {
670  return UIN( n );
671  }
672 
679  void Initialize( uint64 x )
680  {
681  if ( x == 0 )
682  x = RandomSeed64();
683  // Use a SplitMix64 generator to initialize the state space.
684  for ( int i = 0; i < 16; ++i )
685  m_s[i] = SplitMix64( x );
686  m_p = 0;
687  }
688 
689 private:
690 
691  uint64 m_s[ 16 ];
692  int m_p;
693 };
694 
695 // ----------------------------------------------------------------------------
696 
702 template <class RNG>
703 class PCL_CLASS NormalRandomDeviates
704 {
705 public:
706 
711  NormalRandomDeviates( RNG& R ) noexcept( false )
712  : m_R( R )
713  {
714  }
715 
720  double operator ()() noexcept
721  {
722  /*
723  * Marsaglia polar method.
724  */
725  double x;
726  if ( m_first )
727  {
728  do
729  {
730  double u1 = m_R();
731  double u2 = m_R();
732  m_v1 = 2*u1 - 1;
733  m_v2 = 2*u2 - 1;
734  m_s = m_v1*m_v1 + m_v2*m_v2;
735  }
736  while ( m_s >= 1 || m_s <= std::numeric_limits<double>::epsilon() );
737 
738  x = m_v1 * Sqrt( -2*Ln( m_s )/m_s );
739  }
740  else
741  x = m_v2 * Sqrt( -2*Ln( m_s )/m_s );
742 
743  m_first = !m_first;
744  return x;
745  }
746 
747 private:
748 
749  RNG& m_R;
750  double m_v1 = 0;
751  double m_v2 = 0;
752  double m_s = 0;
753  bool m_first = true;
754 };
755 
756 // ----------------------------------------------------------------------------
757 
763 template <class RNG>
764 class PCL_CLASS PoissonRandomDeviates
765 {
766 public:
767 
772  PoissonRandomDeviates( RNG& R ) noexcept( false )
773  : m_R( R )
774  {
775  }
776 
780  int operator ()( double value ) noexcept
781  {
782  if ( value < 30 )
783  {
784  /*
785  * Implementation of the algorithm by Donald E. Knuth, 1969.
786  *
787  * This algorithm is slow (unusable) for large values.
788  */
789  double p = 1, L = Exp( -value );
790  int k = 0;
791  do
792  {
793  ++k;
794  p *= m_R();
795  }
796  while ( p > L );
797  return k-1;
798  }
799 
800  /*
801  * Code adapted from 'Random number generation in C++', by John D. Cook:
802  *
803  * https://www.johndcook.com/blog/cpp_random_number_generation/
804  *
805  * The algorithm is from "The Computer Generation of Poisson Random
806  * Variables" by A. C. Atkinson, Journal of the Royal Statistical
807  * Society Series C (Applied Statistics) Vol. 28, No. 1. (1979)
808  *
809  * This algorithm is slow (unusable) for small values.
810  */
811  double c = 0.767 - 3.36/value;
812  double beta = Const<double>::pi()/Sqrt( 3*value );
813  double alpha = beta*value;
814  double k = Ln( c ) - value - Ln( beta );
815  for ( ;; )
816  {
817  double u = m_R();
818  double x = (alpha - Ln( (1 - u)/u ))/beta;
819  int n = int( Floor( x + 0.5 ) );
820  if ( n < 0 )
821  continue;
822  double v = m_R();
823  double y = alpha - beta*x;
824  double temp = 1 + Exp( y );
825  double lhs = y + Ln( v/temp/temp );
826  double rhs = k + n*Ln( value ) - LnFactorial( n );
827  if ( lhs <= rhs )
828  return n;
829  }
830  }
831 
832 private:
833 
834  RNG& m_R;
835 };
836 
837 // ----------------------------------------------------------------------------
838 
844 template <class RNG>
845 class PCL_CLASS GammaRandomDeviates
846 {
847 public:
848 
853  GammaRandomDeviates( RNG& R, double shape = 1, double scale = 1 ) noexcept( false )
854  : m_R( R )
855  , m_shape( shape )
856  , m_scale( scale )
857  , m_normal( R )
858  {
859  if ( m_shape <= 0 )
860  throw Error( "GammaRandomDeviates(): The function shape parameter must be > 0." );
861  if ( m_scale <= 0 )
862  throw Error( "GammaRandomDeviates(): The scale parameter must be > 0." );
863 
864  m_d = ((m_shape >= 1) ? m_shape : m_shape + 1) - 1.0/3.0;
865  m_c = 1/Sqrt( 9*m_d );
866  }
867 
872  double operator ()() noexcept
873  {
874  /*
875  * Code adapted from 'Random number generation in C++', by John D. Cook:
876  * https://www.johndcook.com/blog/cpp_random_number_generation/
877  *
878  * Implementation based on "A Simple Method for Generating Gamma
879  * Variables" by George Marsaglia and Wai Wan Tsang. ACM Transactions on
880  * Mathematical Software Vol 26, No 3, September 2000, pages 363-372.
881  */
882  for ( ;; )
883  {
884  double x, v;
885  do
886  {
887  x = m_normal();
888  v = 1 + m_c*x;
889  }
890  while ( v <= 0 );
891  v = v*v*v;
892  double u = m_R();
893  double xsquared = x*x;
894  if ( u < 1 - 0.0331*xsquared*xsquared || Ln( u ) < 0.5*xsquared + m_d*(1 - v + Ln( v )) )
895  {
896  double g = m_scale*m_d*v;
897  if ( m_shape < 1 )
898  g *= Pow( m_R(), 1/m_shape );
899  return g;
900  }
901  }
902  }
903 
904 private:
905 
906  RNG& m_R;
907  double m_shape;
908  double m_scale;
909  double m_d;
910  double m_c;
911  NormalRandomDeviates<RNG> m_normal;
912 };
913 
914 // ----------------------------------------------------------------------------
915 
916 } // pcl
917 
918 #endif // __PCL_Random_h
919 
920 // ----------------------------------------------------------------------------
921 // EOF pcl/Random.h - Released 2024-06-18T15:48:54Z
static constexpr T pi()
Definition: Constants.h:94
A simple exception with an associated error message.
Definition: Exception.h:239
Generation of random gamma deviates.
Definition: Random.h:846
GammaRandomDeviates(RNG &R, double shape=1, double scale=1) noexcept(false)
Definition: Random.h:853
Generic vector of arbitrary length.
Definition: Vector.h:107
Generation of random normal (Gaussian) deviates.
Definition: Random.h:704
NormalRandomDeviates(RNG &R) noexcept(false)
Definition: Random.h:711
Generation of random Poisson deviates.
Definition: Random.h:765
PoissonRandomDeviates(RNG &R) noexcept(false)
Definition: Random.h:772
Mersenne Twister (MT19937) pseudo-random number generator.
Definition: Random.h:155
double UpperBound() const
Definition: Random.h:236
int Poisson(double lambda)
double Normal(double mean=0, double sigma=1)
double Gaussian(double mean=0, double sigma=1)
Definition: Random.h:222
RandomNumberGenerator(double ymax=1.0, uint32 seed=0)
void SetUpperBound(double ymax)
Definition: Random.h:244
Implementation of the xoroshiro1024** pseudo-random number generator.
Definition: Random.h:602
void Initialize(uint64 x)
Definition: Random.h:679
uint32 UI32N(uint32 n) noexcept
Definition: Random.h:668
uint32 UI32() noexcept
Definition: Random.h:643
uint64 UI64N(uint64 n) noexcept
Definition: Random.h:652
uint32 UIN(uint32 n) noexcept
Definition: Random.h:660
uint64 UI64() noexcept
Definition: Random.h:628
XoRoShiRo1024ss(uint64 seed=0) noexcept(false)
Definition: Random.h:612
Implementation of the xoshiro256** pseudo-random number generator.
Definition: Random.h:478
uint64 UI64() noexcept
Definition: Random.h:504
XoShiRo256ss(uint64 seed=0) noexcept(false)
Definition: Random.h:488
uint32 UI32N(uint32 n) noexcept
Definition: Random.h:545
uint64 UI64N(uint64 n) noexcept
Definition: Random.h:529
uint32 UI32() noexcept
Definition: Random.h:520
uint32 UIN(uint32 n) noexcept
Definition: Random.h:537
void Initialize(uint64 x)
Definition: Random.h:556
Base class of xoshiro and xoroshiro pseudo-random number generators.
Definition: Random.h:402
XoShiRoBase()=default
Implementation of the XorShift1024* pseudo-random number generator.
Definition: Random.h:299
uint32 UIN(uint32 n) noexcept
Definition: Random.h:355
void Initialize(uint64 x)
Definition: Random.h:374
uint64 UI64N(uint64 n) noexcept
Definition: Random.h:347
XorShift1024(uint64 seed=0) noexcept(false)
Definition: Random.h:309
uint32 UI32() noexcept
Definition: Random.h:338
uint64 UI64() noexcept
Definition: Random.h:325
uint32 UI32N(uint32 n) noexcept
Definition: Random.h:363
Complex< T1 > Pow(const Complex< T1 > &c, T2 x) noexcept
Definition: Complex.h:747
Complex< T > Sqrt(const Complex< T > &c) noexcept
Definition: Complex.h:674
Complex< T > Exp(const Complex< T > &c) noexcept
Definition: Complex.h:714
Complex< T > Ln(const Complex< T > &c) noexcept
Definition: Complex.h:725
#define uint32_max
Definition: Defs.h:875
T RotL(T x, uint32 n) noexcept
Definition: Math.h:1330
double LnFactorial(int n) noexcept
Definition: Math.h:732
constexpr T Floor(T x) noexcept
Definition: Math.h:628
unsigned long long uint64
Definition: Defs.h:682
unsigned int uint32
Definition: Defs.h:666
uint64 RandomSeed64()
uint32 RandomSeed32()
Definition: Random.h:102
PCL root namespace.
Definition: AbstractImage.h:77