/************************************************************************* Random number generator: normal numbers This function generates one random number from normal distribution. Its performance is equal to that of HQRNDNormal2() State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ double hqrndnormal(hqrndstate& state) { double result; double v1; double v2; hqrndnormal2(state, v1, v2); result = v1; return result; }
/************************************************************************* Random number generator: random X and Y such that X^2+Y^2=1 State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ void hqrndunit2(hqrndstate& state, double& x, double& y) { double v; double mx; double mn; do { hqrndnormal2(state, x, y); } while(!(ap::fp_neq(x,0)||ap::fp_neq(y,0))); mx = ap::maxreal(fabs(x), fabs(y)); mn = ap::minreal(fabs(x), fabs(y)); v = mx*sqrt(1+ap::sqr(mn/mx)); x = x/v; y = y/v; }
/************************************************************************* Hermitian multiplication of NxN matrix by random Haar distributed complex orthogonal matrix INPUT PARAMETERS: A - matrix, array[0..N-1, 0..N-1] N - matrix size OUTPUT PARAMETERS: A - Q^H*A*Q, where Q is random NxN orthogonal matrix -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void hmatrixrndmultiply(ap::complex_2d_array& a, int n) { ap::complex tau; ap::complex lambda; int s; int i; int j; double u1; double u2; ap::complex_1d_array w; ap::complex_1d_array v; double sm; hqrndstate state; int i_; // // General case. // w.setbounds(0, n-1); v.setbounds(1, n); hqrndrandomize(state); for(s = 2; s <= n; s++) { // // Prepare random normal v // do { for(i = 1; i <= s; i++) { hqrndnormal2(state, tau.x, tau.y); v(i) = tau; } lambda = 0.0; for(i_=1; i_<=s;i_++) { lambda += v(i_)*ap::conj(v(i_)); } } while(lambda==0); // // Prepare and apply reflection // complexgeneratereflection(v, s, tau); v(1) = 1; complexapplyreflectionfromtheright(a, tau, v, 0, n-1, n-s, n-1, w); complexapplyreflectionfromtheleft(a, ap::conj(tau), v, n-s, n-1, 0, n-1, w); } // // Second pass. // for(i = 0; i <= n-1; i++) { hqrndunit2(state, tau.x, tau.y); for(i_=0; i_<=n-1;i_++) { a(i_,i) = tau*a(i_,i); } tau = ap::conj(tau); for(i_=0; i_<=n-1;i_++) { a(i,i_) = tau*a(i,i_); } } }
/************************************************************************* Symmetric multiplication of NxN matrix by random Haar distributed orthogonal matrix INPUT PARAMETERS: A - matrix, array[0..N-1, 0..N-1] N - matrix size OUTPUT PARAMETERS: A - Q'*A*Q, where Q is random NxN orthogonal matrix -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void smatrixrndmultiply(ap::real_2d_array& a, int n) { double tau; double lambda; int s; int i; int j; double u1; double u2; ap::real_1d_array w; ap::real_1d_array v; double sm; hqrndstate state; // // General case. // w.setbounds(0, n-1); v.setbounds(1, n); hqrndrandomize(state); for(s = 2; s <= n; s++) { // // Prepare random normal v // do { i = 1; while(i<=s) { hqrndnormal2(state, u1, u2); v(i) = u1; if( i+1<=s ) { v(i+1) = u2; } i = i+2; } lambda = ap::vdotproduct(&v(1), &v(1), ap::vlen(1,s)); } while(ap::fp_eq(lambda,0)); // // Prepare and apply reflection // generatereflection(v, s, tau); v(1) = 1; applyreflectionfromtheright(a, tau, v, 0, n-1, n-s, n-1, w); applyreflectionfromtheleft(a, tau, v, n-s, n-1, 0, n-1, w); } // // Second pass. // for(i = 0; i <= n-1; i++) { tau = 2*ap::randominteger(2)-1; ap::vmul(a.getcolumn(i, 0, n-1), tau); ap::vmul(&a(i, 0), ap::vlen(0,n-1), tau); } }
/************************************************************************* Multiplication of MxN complex matrix by MxM random Haar distributed complex orthogonal matrix INPUT PARAMETERS: A - matrix, array[0..M-1, 0..N-1] M, N- matrix size OUTPUT PARAMETERS: A - Q*A, where Q is random MxM orthogonal matrix -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void cmatrixrndorthogonalfromtheleft(ap::complex_2d_array& a, int m, int n) { ap::complex tau; ap::complex lambda; int s; int i; int j; double u1; double u2; ap::complex_1d_array w; ap::complex_1d_array v; double sm; hqrndstate state; int i_; ap::ap_error::make_assertion(n>=1&&m>=1, "CMatrixRndOrthogonalFromTheRight: N<1 or M<1!"); if( m==1 ) { // // special case // hqrndrandomize(state); hqrndunit2(state, tau.x, tau.y); for(j = 0; j <= n-1; j++) { a(0,j) = a(0,j)*tau; } return; } // // General case. // First pass. // w.setbounds(0, n-1); v.setbounds(1, m); hqrndrandomize(state); for(s = 2; s <= m; s++) { // // Prepare random normal v // do { for(i = 1; i <= s; i++) { hqrndnormal2(state, tau.x, tau.y); v(i) = tau; } lambda = 0.0; for(i_=1; i_<=s;i_++) { lambda += v(i_)*ap::conj(v(i_)); } } while(lambda==0); // // Prepare and apply reflection // complexgeneratereflection(v, s, tau); v(1) = 1; complexapplyreflectionfromtheleft(a, tau, v, m-s, m-1, 0, n-1, w); } // // Second pass. // for(i = 0; i <= m-1; i++) { hqrndunit2(state, tau.x, tau.y); for(i_=0; i_<=n-1;i_++) { a(i,i_) = tau*a(i,i_); } } }
/************************************************************************* Multiplication of MxN matrix by MxM random Haar distributed orthogonal matrix INPUT PARAMETERS: A - matrix, array[0..M-1, 0..N-1] M, N- matrix size OUTPUT PARAMETERS: A - Q*A, where Q is random MxM orthogonal matrix -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void rmatrixrndorthogonalfromtheleft(ap::real_2d_array& a, int m, int n) { double tau; double lambda; int s; int i; int j; double u1; double u2; ap::real_1d_array w; ap::real_1d_array v; double sm; hqrndstate state; ap::ap_error::make_assertion(n>=1&&m>=1, "RMatrixRndOrthogonalFromTheRight: N<1 or M<1!"); if( m==1 ) { // // special case // tau = 2*ap::randominteger(2)-1; for(j = 0; j <= n-1; j++) { a(0,j) = a(0,j)*tau; } return; } // // General case. // First pass. // w.setbounds(0, n-1); v.setbounds(1, m); hqrndrandomize(state); for(s = 2; s <= m; s++) { // // Prepare random normal v // do { i = 1; while(i<=s) { hqrndnormal2(state, u1, u2); v(i) = u1; if( i+1<=s ) { v(i+1) = u2; } i = i+2; } lambda = ap::vdotproduct(&v(1), &v(1), ap::vlen(1,s)); } while(ap::fp_eq(lambda,0)); // // Prepare and apply reflection // generatereflection(v, s, tau); v(1) = 1; applyreflectionfromtheleft(a, tau, v, m-s, m-1, 0, n-1, w); } // // Second pass. // for(i = 0; i <= m-1; i++) { tau = 2*ap::randominteger(2)-1; ap::vmul(&a(i, 0), ap::vlen(0,n-1), tau); } }
bool testhqrnd(bool silent) { bool result; bool waserrors; int samplesize; double sigmathreshold; int passcount; int n; int i; int pass; int s1; int s2; int i1; int i2; double r1; double r2; ap::real_1d_array x; double mean; double means; double stddev; double stddevs; double lambda; bool seederrors; bool urerrors; double ursigmaerr; bool uierrors; double uisigmaerr; bool normerrors; double normsigmaerr; bool experrors; double expsigmaerr; hqrndstate state; waserrors = false; sigmathreshold = 7; samplesize = 100000; passcount = 50; x.setbounds(0, samplesize-1); // // Test seed errors // seederrors = false; for(pass = 1; pass <= passcount; pass++) { s1 = 1+ap::randominteger(32000); s2 = 1+ap::randominteger(32000); unsetstate(state); hqrndseed(s1, s2, state); i1 = hqrnduniformi(100, state); unsetstate(state); hqrndseed(s1, s2, state); i2 = hqrnduniformi(100, state); seederrors = seederrors||i1!=i2; unsetstate(state); hqrndseed(s1, s2, state); r1 = hqrnduniformr(state); unsetstate(state); hqrndseed(s1, s2, state); r2 = hqrnduniformr(state); seederrors = seederrors||ap::fp_neq(r1,r2); } // // Test HQRNDRandomize() and real uniform generator // unsetstate(state); hqrndrandomize(state); urerrors = false; ursigmaerr = 0; for(i = 0; i <= samplesize-1; i++) { x(i) = hqrnduniformr(state); } for(i = 0; i <= samplesize-1; i++) { urerrors = urerrors||ap::fp_less_eq(x(i),0)||ap::fp_greater_eq(x(i),1); } calculatemv(x, samplesize, mean, means, stddev, stddevs); if( ap::fp_neq(means,0) ) { ursigmaerr = ap::maxreal(ursigmaerr, fabs((mean-0.5)/means)); } else { urerrors = true; } if( ap::fp_neq(stddevs,0) ) { ursigmaerr = ap::maxreal(ursigmaerr, fabs((stddev-sqrt(double(1)/double(12)))/stddevs)); } else { urerrors = true; } urerrors = urerrors||ap::fp_greater(ursigmaerr,sigmathreshold); // // Test HQRNDRandomize() and integer uniform // unsetstate(state); hqrndrandomize(state); uierrors = false; uisigmaerr = 0; for(n = 2; n <= 10; n++) { for(i = 0; i <= samplesize-1; i++) { x(i) = hqrnduniformi(n, state); } for(i = 0; i <= samplesize-1; i++) { uierrors = uierrors||ap::fp_less(x(i),0)||ap::fp_greater_eq(x(i),n); } calculatemv(x, samplesize, mean, means, stddev, stddevs); if( ap::fp_neq(means,0) ) { uisigmaerr = ap::maxreal(uisigmaerr, fabs((mean-0.5*(n-1))/means)); } else { uierrors = true; } if( ap::fp_neq(stddevs,0) ) { uisigmaerr = ap::maxreal(uisigmaerr, fabs((stddev-sqrt((ap::sqr(double(n))-1)/12))/stddevs)); } else { uierrors = true; } } uierrors = uierrors||ap::fp_greater(uisigmaerr,sigmathreshold); // // Special 'close-to-limit' test on uniformity of integers // (straightforward implementation like 'RND mod N' will return // non-uniform numbers for N=2/3*LIMIT) // unsetstate(state); hqrndrandomize(state); uierrors = false; uisigmaerr = 0; n = ap::round(2.0/3.0*2147483563.0); for(i = 0; i <= samplesize-1; i++) { x(i) = hqrnduniformi(n, state); } for(i = 0; i <= samplesize-1; i++) { uierrors = uierrors||ap::fp_less(x(i),0)||ap::fp_greater_eq(x(i),n); } calculatemv(x, samplesize, mean, means, stddev, stddevs); if( ap::fp_neq(means,0) ) { uisigmaerr = ap::maxreal(uisigmaerr, fabs((mean-0.5*(n-1))/means)); } else { uierrors = true; } if( ap::fp_neq(stddevs,0) ) { uisigmaerr = ap::maxreal(uisigmaerr, fabs((stddev-sqrt((ap::sqr(double(n))-1)/12))/stddevs)); } else { uierrors = true; } uierrors = uierrors||ap::fp_greater(uisigmaerr,sigmathreshold); // // Test normal // unsetstate(state); hqrndrandomize(state); normerrors = false; normsigmaerr = 0; i = 0; while(i<samplesize) { hqrndnormal2(state, r1, r2); x(i) = r1; if( i+1<samplesize ) { x(i+1) = r2; } i = i+2; } calculatemv(x, samplesize, mean, means, stddev, stddevs); if( ap::fp_neq(means,0) ) { normsigmaerr = ap::maxreal(normsigmaerr, fabs((mean-0)/means)); } else { normerrors = true; } if( ap::fp_neq(stddevs,0) ) { normsigmaerr = ap::maxreal(normsigmaerr, fabs((stddev-1)/stddevs)); } else { normerrors = true; } normerrors = normerrors||ap::fp_greater(normsigmaerr,sigmathreshold); // // Test exponential // unsetstate(state); hqrndrandomize(state); experrors = false; expsigmaerr = 0; lambda = 2+5*ap::randomreal(); for(i = 0; i <= samplesize-1; i++) { x(i) = hqrndexponential(lambda, state); } for(i = 0; i <= samplesize-1; i++) { uierrors = uierrors||ap::fp_less(x(i),0); } calculatemv(x, samplesize, mean, means, stddev, stddevs); if( ap::fp_neq(means,0) ) { expsigmaerr = ap::maxreal(expsigmaerr, fabs((mean-1.0/lambda)/means)); } else { experrors = true; } if( ap::fp_neq(stddevs,0) ) { expsigmaerr = ap::maxreal(expsigmaerr, fabs((stddev-1.0/lambda)/stddevs)); } else { experrors = true; } experrors = experrors||ap::fp_greater(expsigmaerr,sigmathreshold); // // Final report // waserrors = seederrors||urerrors||uierrors||normerrors||experrors; if( !silent ) { printf("RNG TEST\n"); printf("SEED TEST: "); if( !seederrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("UNIFORM CONTINUOUS: "); if( !urerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("UNIFORM INTEGER: "); if( !uierrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("NORMAL: "); if( !normerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("EXPONENTIAL: "); if( !experrors ) { printf("OK\n"); } else { printf("FAILED\n"); } if( waserrors ) { printf("TEST SUMMARY: FAILED\n"); } else { printf("TEST SUMMARY: PASSED\n"); } printf("\n\n"); } result = !waserrors; return result; }