#pragma once #include #include #include "functions.h" #include #include #include #include #include #include #include #include #include //#include namespace cgv { namespace math { /** * High quality random number generator, * which is a little bit slower than typical random number generators * but with a period about 3.138 x 10^57. */ struct random { private: unsigned long long u,v,w; double storedval; public: /// set a new seed void set_seed(unsigned long long seed) { w = 1; v = 4101842887655102017LL; u = seed^v; unsigned long long ull; uniform(ull); v = u; uniform(ull); w = v; uniform(ull); } ///standard constructor uses system time as random seed random() : storedval(0.0) { unsigned long long seed = clock(); set_seed(seed); } ///constructor initializes random generator with given seed random(unsigned long long seed) : storedval(0.0) { set_seed(seed); } ///generates 64bit pseudo random integer void uniform(unsigned long long& rv) { u = u*2862933555777941757LL + 7046029254386353087LL; v ^= v >> 17; v ^= v <<31; v ^= v >> 8; w = 4294957665U*(w & 0xffffffff) + (w >> 32); unsigned long long x = u ^(u << 21); x ^= x >>35; x^=x << 4; rv= (x+v)^w; } ///generates a 32bit pseudo random unsigned integer void uniform(unsigned int& rv) { unsigned long long v; uniform(v); rv= (unsigned int) v; } ///generates a 32bit pseudo random signed integer void uniform(int& rv) { unsigned long long v; uniform(v); rv = (int) v; } ///generates a 32bit pseudo random signed integer void uniform(long& rv) { unsigned long long v; uniform(v); rv = (long) v; } ///generates a 64bit pseudo random signed integer void uniform(long long& rv) { unsigned long long v; uniform(v); rv = (long long) v; } ///generates a pseudo random boolean void uniform(bool& rv) { unsigned long long v; uniform(v); rv= v%2 == 0; } ///generates a pseudo random integer between min and max void uniform(const unsigned min,const unsigned max, unsigned& rv) { uniform(rv); rv =rv%(max-min+1)+min; } ///generates a pseudo random integer between min and max void uniform(const int min,const int max, int& rv) { uniform(rv); rv =(int)(rv%(unsigned)(max-min+1))+min; } ///generates a pseudo random double-precision floating point number uniformly distributed between 0 and 1 void uniform(double& rv) { unsigned long long v; uniform(v); rv= 5.42101086242752217E-20 * v; } ///generates a pseudo random double-precision floating point number uniformly distributed between min and max void uniform(const double min,const double max, double &rv) { double v; uniform(v); rv= (max-min)*v + min; } ///generates a pseudo random single-precision floating point number uniformly distributed between 0 and 1 void uniform(float & rv) { double v; uniform(v); rv =(float) v; } ///generates a pseudo random single-precision floating point number uniformly distributed between 0 and 1 void uniform(const float min,const float max, float& rv) { float f; uniform(f); rv= (max-min)*f + min; } ///generates a pseudo random single precision vector with uniformly distribute components between 0 and 1 void uniform( vec& rv) { for(unsigned i = 0; i < rv.size();i++) uniform(rv(i)); } ///generates a pseudo random single precision vector with uniformly distribute components between min and max void uniform(const float min,const float max, vec& rv) { for(unsigned i = 0; i < rv.size();i++) uniform(min,max,rv(i)); } ///generates a pseudo random double precision vector with uniformly distribute components between 0 and 1 void uniform(vec& rv) { for(unsigned i = 0; i < rv.size();i++) uniform(rv(i)); } ///generates a pseudo random double precision vector with uniformly distribute components between min and max void uniform(const double min,const double max, vec& rv) { for(unsigned i = 0; i < rv.size();i++) uniform(min,max,rv(i)); } ///generates a pseudo random single precision full matrix with uniformly distribute components between 0 and 1 void uniform(mat& rv) { for(unsigned i = 0; i < rv.nrows(); i++) for(unsigned j = 0; j < rv.ncols(); j++) uniform(rv(i,j)); } ///generates a pseudo random single precision full matrix with uniformly distribute components between min and max void uniform(const float min,const float max, mat& rv) { for(unsigned i = 0; i < rv.nrows(); i++) for(unsigned j = 0; j < rv.ncols(); j++) uniform(min,max,rv(i,j)); } ///generates a pseudo random permutation matrix void uniform(perm_mat& rv) { unsigned j; for(unsigned i = 0; i < rv.size();i++) { uniform(j); j=(i+j)%rv.size(); rv.swap(i,j); } std::random_shuffle(&(rv(0)),&(rv(rv.nrows()))); } ///generates a pseudo random single precision upper triangular matrix with uniformly distribute components between 0 and 1 void uniform(up_tri_mat& rv) { for(unsigned i = 0; i < rv.nrows(); i++) for(unsigned j = i; j < rv.ncols(); j++) uniform(rv(i,j)); } ///generates a pseudo random single precision upper triangular matrix with uniformly distribute components between min and max void uniform(const float min, const float max,up_tri_mat& rv) { for(unsigned i = 0; i < rv.nrows(); i++) for(unsigned j = i; j < rv.ncols(); j++) uniform(min,max,rv(i,j)); } ///generates a pseudo random double precision upper triangular matrix with uniformly distribute components between 0 and 1 void uniform(up_tri_mat& rv) { for(unsigned i = 0; i < rv.nrows(); i++) for(unsigned j = i; j < rv.ncols(); j++) uniform(rv(i,j)); } ///generates a pseudo random double precision upper triangular matrix with uniformly distribute components between min and max void uniform(const double min, const double max,up_tri_mat& rv) { for(unsigned i = 0; i < rv.nrows(); i++) for(unsigned j = i; j < rv.ncols(); j++) uniform(min,max,rv(i,j)); } ///generates a pseudo random single precision lower triangular matrix with uniformly distribute components between 0 and 1 void uniform( low_tri_mat& rv) { for(unsigned i = 0; i < rv.nrows(); i++) for(unsigned j = 0; j <= i; j++) uniform(rv(i,j)); } ///generates a pseudo random single precision lower triangular matrix with uniformly distribute components between min and max void uniform(const float min,const float max, low_tri_mat& rv) { for(unsigned i = 0; i < rv.nrows(); i++) for(unsigned j = 0; j <= i; j++) uniform(min,max,rv(i,j)); } ///generates a pseudo random double precision lower triangular matrix with uniformly distribute components between 0 and 1 void uniform( low_tri_mat& rv) { for(unsigned j = 0; j < rv.ncols(); j++) for(unsigned i = 0; i < j; i++) uniform(rv(i,j)); } ///generates a pseudo random double precision lower triangular matrix with uniformly distribute components between min and max void uniform(const double min,const double max, low_tri_mat& rv) { for(unsigned j = 0; j < rv.ncols(); j++) for(unsigned i = 0; i < j; i++) uniform(min,max,rv(i,j)); } ///generates a pseudo random single precision diagonal matrix with uniformly distribute components between 0 and 1 void uniform(diag_mat& rv) { for(unsigned i = 0; i < rv.nrows(); i++) uniform(rv(i)); } ///generates a pseudo random single precision diagonal matrix with uniformly distribute components between min and max void uniform(const float min,const float max, diag_mat& rv) { for(unsigned i = 0; i < rv.nrows(); i++) uniform(min,max,rv(i)); } ///generates a pseudo random double precision diagonal matrix with uniformly distribute components between 0 and 1 void uniform(diag_mat& rv) { for(unsigned i = 0; i < rv.nrows(); i++) uniform(rv(i)); } ///generates a pseudo random double precision diagonal matrix with uniformly distribute components between min and max void uniform(const double min,const double max, diag_mat& rv) { for(unsigned i = 0; i < rv.nrows(); i++) uniform(min,max,rv(i)); } ///generates a pseudo random double full matrix with uniformly distribute components between 0 and 1 void uniform(mat& rv) { for(unsigned i = 0; i < rv.nrows(); i++) for(unsigned j = 0; j < rv.ncols(); j++) uniform(rv(i,j)); } ///generates a pseudo random double full matrix with uniformly distribute components between min and max void uniform(const double min,const double max, mat& rv) { for(unsigned i = 0; i < rv.nrows(); i++) for(unsigned j = 0; j < rv.ncols(); j++) uniform(min,max,rv(i,j)); } ///generates a normal deviate double-precision floating point value with mu = 0 and sigma = 1 void normal(double& rv) { double v1,v2,rsq,fac; if(storedval == 0.) { do{ uniform(v1); uniform(v2); v1 = 2.0 * v1-1.0; v2 = 2.0 * v2-1.0; rsq = v1*v1+v2*v2; }while(rsq >= 1.0 || rsq == 0.0); fac = sqrt(-2.0*std::log(rsq)/rsq); storedval = v1*fac; rv= v2*fac; }else { fac = storedval; storedval = 0.; rv= fac; } } ///generates a normal deviate single-precision floating point value with mu = 0 and sigma = 1 void normal(float& rv) { double d; normal(d); rv = (float)d; } ///generates a normal deviate double-precision floating point value with mu and sigma void normal(const double mu, const double sigma, double &rv) { double d; normal(d); rv =mu + sigma * d; } ///generates a normal deviate single-precision floating point value with mu and sigma void normal(const float mu, const float sigma, float& rv) { float f; normal(f); rv= mu + sigma * f; } ///generates a single precision random direction (uniformly distributed position on the unit sphere) void uniform_direction(vec& v) { for(unsigned i = 0;i < v.size(); i++) normal(v(i)); v.normalize(); } ///generates a double precision random direction (uniformly distributed position on the unit sphere) void uniform_direction(vec& v) { for(unsigned i = 0;i < v.size();i++) normal(v(i)); v.normalize(); } ///generates a single precision random orientation represented as a unit quaternion void uniform_quat_orientation(vec& q) { float x[3]; uniform(x[0]); uniform(x[1]); uniform(x[2]); float a, b, c, d, s; float z, r, theta, omega; z = x[0]; r = sqrt( 1 - z * z ); theta = 2.0f * 3.14159f * x[1]; omega = 3.14159f * x[2]; s = sin( omega ); a = cos( omega ); b = s * cos( theta ) * r; c = s * sin( theta ) * r; d = s * z; q.set(b,c,d,a); } ///generates a double precision random orientation ///represented as a unit quaternion void uniform_quat_orientation(vec& q) { q.resize(4); double x[3]; uniform(x[0]); uniform(x[1]); uniform(x[2]); double a, b, c, d, s; double z, r, theta, omega; z = x[0]; r = sqrt( 1 - z * z ); theta = 2.0 * 3.14159 * x[1]; omega = 3.14159 * x[2]; s = sin( omega ); a = cos( omega ); b = s * cos( theta ) * r; c = s * sin( theta ) * r; d = s * z; q.set(b,c,d,a); } ///generates a single precision random orientation represented as a rotation matrix void uniform_orientation(mat& m) { if(m.nrows() == 3 && m.ncols() == 3) { vec q(4); uniform_quat_orientation(q); m = quat_2_mat_33(q); return; } if(m.nrows() == 4 && m.ncols() == 4) { vec q(4); uniform_quat_orientation(q); m = quat_2_mat_44(q); return; } assert(false); } ///generates a double precision random orientation represented as a rotation matrix void uniform_orientation( mat& m) { if(m.nrows() == 3 && m.ncols() == 3) { vec q(4); uniform_quat_orientation(q); m = quat_2_mat_33(q); return; } if(m.nrows() == 4 && m.ncols() == 4) { vec q(4); uniform_quat_orientation(q); m = quat_2_mat_44(q); return; } assert(false); } ///creates an uniform distributed random point in unit box (0,0,...,0)..(1,1,...,1); if dim(p)=0, it is set to 3 void uniform_point_in_unit_box(vec& p) { if (p.size() == 0) p.resize(3); for (unsigned i=0; i& minp,const vec& maxp, vec& p) { assert(minp.size() == maxp.size()); if (p.size() != minp.size()) p.resize(minp.size()); for (unsigned i=0; i& p) { uniform_direction(p); double r; uniform(r); r = pow(r, 1.0/p.size()); p *= r; } ///creates an uniform distributed random point in triangle p1,p2,p3 void uniform_point_in_triangle(const vec& p1, const vec& p2, const vec& p3,vec p) { double u,v; uniform(u); uniform(v); if(u+v > 1.0) { u=1.0-u; v=1.0-v; } p= u*p1 + v*p2 +(1.0-u-v)*p3; } ///creates an uniform distributed random point on the surface of a sphere with given center and radius void uniform_point_on_sphere(const vec& center,const double& radius, vec& p) { for(unsigned i = 0;i < p.size();i++) normal(p(i)); p.normalize(); p=center+radius*p; } ///creates a vector of k unique indices drawn from 0 to n-1 void uniform_nchoosek(unsigned n, unsigned k, vec& indices) { std::set s; unsigned v; while(s.size() < k) { uniform(0,n-1,v); s.insert(v); } indices.resize(k); unsigned i=0; for(std::set::iterator it =s.begin(); it != s.end();it++,i++) indices(i)=*it; } }; } }