/// <summary> /// Get scramble constants that can be used for quasirandom number generation. /// <para/> /// The array contains constants for many dimensions. Each dimension /// has a single ulong constant. /// </summary> /// <returns></returns> public static ulong[] GetScrambleConstants64() { IntPtr ptr; CurandStatus status = CudaRandNativeMethods.curandGetScrambleConstants64(out ptr); Debug.WriteLine(String.Format("{0:G}, {1}: {2}", DateTime.Now, "curandGetScrambleConstants64", status)); if (status != CurandStatus.Success) { throw new CudaRandException(status); } //Marshall.Copy cannot directly copy to an ulong[] array. //So first copy to long[] and then to ulong[]... long[] consts_long = new long[MaxDimensions]; ulong[] consts_ulong = new ulong[MaxDimensions]; //Copy unmanaged array (ptr) to managed array of long[]: Marshal.Copy(ptr, consts_long, 0, MaxDimensions); //Pin ulong[] array to get IntPtr and copy data again. GCHandle handle = GCHandle.Alloc(consts_ulong, GCHandleType.Pinned); Marshal.Copy(consts_long, 0, handle.AddrOfPinnedObject(), MaxDimensions); handle.Free(); return(consts_ulong); }
/// <summary> /// Use generator to generate num double results into the device memory at /// outputPtr. The device memory must have been previously allocated and be /// large enough to hold all the results. Launches are done with the stream /// set using curandSetStream(), or the null stream if no stream has been set. /// <para/> /// Results are 64-bit floating point values with log-normal distribution based on /// an associated normal distribution with mean mean and standard deviation stddev. /// <para/> /// Normally distributed results are generated from pseudorandom generators /// with a Box-Muller transform, and so require num to be even. /// Quasirandom generators use an inverse cumulative distribution /// function to preserve dimensionality. /// The normally distributed results are transformed into log-normal distribution. /// <para/> /// There may be slight numerical differences between results generated /// on the GPU with generators created with ::curandCreateGenerator() /// and results calculated on the CPU with generators created with /// ::curandCreateGeneratorHost(). These differences arise because of /// differences in results for transcendental functions. In addition, /// future versions of CURAND may use newer versions of the CUDA math /// library, so different versions of CURAND may give slightly different /// numerical values. /// </summary> /// <param name="output">CudaDeviceVariable</param> /// <param name="mean"></param> /// <param name="stddev"></param> public void GenerateLogNormal(CudaDeviceVariable <double> output, double mean, double stddev) { _status = CudaRandNativeMethods.curandGenerateLogNormalDouble(_generator, output.DevicePointer, output.Size, mean, stddev); Debug.WriteLine(String.Format("{0:G}, {1}: {2}", DateTime.Now, "curandGenerateLogNormalDouble", _status)); if (_status != CurandStatus.Success) { throw new CudaRandException(_status); } }
/// <summary> /// Use generator to generate num double results into the device memory at /// outputPtr. The device memory must have been previously allocated and be /// large enough to hold all the results. Launches are done with the stream /// set using curandSetStream(), or the null stream if no stream has been set. /// <para/> /// Results are 64-bit floating point values with log-normal distribution based on /// an associated normal distribution with mean mean and standard deviation stddev. /// <para/> /// Normally distributed results are generated from pseudorandom generators /// with a Box-Muller transform, and so require num to be even. /// Quasirandom generators use an inverse cumulative distribution /// function to preserve dimensionality. /// The normally distributed results are transformed into log-normal distribution. /// <para/> /// There may be slight numerical differences between results generated /// on the GPU with generators created with ::curandCreateGenerator() /// and results calculated on the CPU with generators created with /// ::curandCreateGeneratorHost(). These differences arise because of /// differences in results for transcendental functions. In addition, /// future versions of CURAND may use newer versions of the CUDA math /// library, so different versions of CURAND may give slightly different /// numerical values. /// </summary> /// <param name="output">CudaDeviceVariable</param> /// <param name="mean"></param> /// <param name="stddev"></param> public void GenerateLogNormal(double[] output, double mean, double stddev) { _status = CudaRandNativeMethods.curandGenerateLogNormalDouble(_generator, output, output.LongLength, mean, stddev); Debug.WriteLine(String.Format("{0:G}, {1}: {2}", DateTime.Now, "curandGenerateLogNormalDouble", _status)); if (_status != CurandStatus.Success) { throw new CudaRandException(_status); } }
/// <summary> /// Use generator to generate num float results into the device memory at /// outputPtr. The device memory must have been previously allocated and be /// large enough to hold all the results. Launches are done with the stream /// set using SetStream(), or the null stream if no stream has been set. /// <para/> /// Results are 32-bit floating point values between 0.0f and 1.0f, /// excluding 0.0f and including 1.0f. /// </summary> /// <param name="output">CudaDeviceVariable</param> public void GenerateUniform(CudaDeviceVariable <float> output) { _status = CudaRandNativeMethods.curandGenerateUniform(_generator, output.DevicePointer, output.Size); Debug.WriteLine(String.Format("{0:G}, {1}: {2}", DateTime.Now, "curandGenerateUniform", _status)); if (_status != CurandStatus.Success) { throw new CudaRandException(_status); } }
/// <summary> /// Set the number of dimensions to be generated by the quasirandom number generator. /// <para/> /// Legal values for dimensions are 1 to 20000. /// </summary> /// <param name="dimensions">Legal values for dimensions are 1 to 20000.</param> public void SetQuasiRandomGeneratorDimensions(uint dimensions) { _status = CudaRandNativeMethods.curandSetQuasiRandomGeneratorDimensions(_generator, dimensions); Debug.WriteLine(String.Format("{0:G}, {1}: {2}", DateTime.Now, "curandSetQuasiRandomGeneratorDimensions", _status)); if (_status != CurandStatus.Success) { throw new CudaRandException(_status); } }
/// <summary> /// Use generator to generate num float results into the device memory at /// outputPtr. The device memory must have been previously allocated and be /// large enough to hold all the results. Launches are done with the stream /// set using SetStream(), or the null stream if no stream has been set. /// <para/> /// Results are 32-bit floating point values between 0.0f and 1.0f, /// excluding 0.0f and including 1.0f. /// </summary> /// <param name="output">DevicePtr of type float*</param> /// <param name="size">Number of random elements to create</param> public void GenerateUniform32(CUdeviceptr output, SizeT size) { _status = CudaRandNativeMethods.curandGenerateUniform(_generator, output, size); Debug.WriteLine(String.Format("{0:G}, {1}: {2}", DateTime.Now, "curandGenerateUniform", _status)); if (_status != CurandStatus.Success) { throw new CudaRandException(_status); } }
/// <summary> /// Set the absolute offset of the pseudo or quasirandom number generator. /// <para/> /// All values of offset are valid. The offset position is absolute, not /// relative to the current position in the sequence. /// </summary> /// <param name="offset">All values of offset are valid.</param> public void SetOffset(ulong offset) { _status = CudaRandNativeMethods.curandSetGeneratorOffset(_generator, offset); Debug.WriteLine(String.Format("{0:G}, {1}: {2}", DateTime.Now, "curandSetGeneratorOffset", _status)); if (_status != CurandStatus.Success) { throw new CudaRandException(_status); } }
/// <summary> /// Set the seed value of the pseudorandom number generator.<para/> /// All values of seed are valid. Different seeds will produce different sequences. /// Different seeds will often not be statistically correlated with each other, /// but some pairs of seed values may generate sequences which are statistically correlated. /// </summary> /// <param name="seed">All values of seed are valid.</param> public void SetPseudoRandomGeneratorSeed(ulong seed) { _status = CudaRandNativeMethods.curandSetPseudoRandomGeneratorSeed(_generator, seed); Debug.WriteLine(String.Format("{0:G}, {1}: {2}", DateTime.Now, "curandSetPseudoRandomGeneratorSeed", _status)); if (_status != CurandStatus.Success) { throw new CudaRandException(_status); } }
/// <summary> /// Set the current stream for CURAND kernel launches. All library functions /// will use this stream until set again. /// </summary> /// <param name="stream"></param> public void SetStream(CUstream stream) { _status = CudaRandNativeMethods.curandSetStream(_generator, stream); Debug.WriteLine(String.Format("{0:G}, {1}: {2}", DateTime.Now, "curandSetStream", _status)); if (_status != CurandStatus.Success) { throw new CudaRandException(_status); } }
/// <summary> /// Generate the starting state of the generator. This function is /// automatically called by generation functions such as /// Generate(CudaDeviceVariable) and GenerateUniform(CudaDeviceVariable). /// It can be called manually for performance testing reasons to separate /// timings for starting state generation and random number generation. /// </summary> public void GenerateSeeds() { _status = CudaRandNativeMethods.curandGenerateSeeds(_generator); Debug.WriteLine(String.Format("{0:G}, {1}: {2}", DateTime.Now, "curandGenerateSeeds", _status)); if (_status != CurandStatus.Success) { throw new CudaRandException(_status); } }
/// <summary> /// Use generator to generate num double results into the device memory at /// outputPtr. The device memory must have been previously allocated and be /// large enough to hold all the results. Launches are done with the stream /// set using curandSetStream(), or the null stream if no stream has been set. /// <para/> /// Results are 64-bit floating point values with log-normal distribution based on /// an associated normal distribution with mean mean and standard deviation stddev. /// <para/> /// Normally distributed results are generated from pseudorandom generators /// with a Box-Muller transform, and so require num to be even. /// Quasirandom generators use an inverse cumulative distribution /// function to preserve dimensionality. /// The normally distributed results are transformed into log-normal distribution. /// <para/> /// There may be slight numerical differences between results generated /// on the GPU with generators created with ::curandCreateGenerator() /// and results calculated on the CPU with generators created with /// ::curandCreateGeneratorHost(). These differences arise because of /// differences in results for transcendental functions. In addition, /// future versions of CURAND may use newer versions of the CUDA math /// library, so different versions of CURAND may give slightly different /// numerical values. /// </summary> /// <param name="output">DevicePtr of type double*</param> /// <param name="size">Number of random elements to create</param> /// <param name="mean"></param> /// <param name="stddev"></param> public void GenerateLogNormal64(CUdeviceptr output, SizeT size, float mean, float stddev) { _status = CudaRandNativeMethods.curandGenerateLogNormalDouble(_generator, output, size, mean, stddev); Debug.WriteLine(String.Format("{0:G}, {1}: {2}", DateTime.Now, "curandGenerateLogNormalDouble", _status)); if (_status != CurandStatus.Success) { throw new CudaRandException(_status); } }
/// <summary> /// Use generator to generate num float results into the device memory at /// outputPtr. The device memory must have been previously allocated and be /// large enough to hold all the results. Launches are done with the stream /// set using SetStream(), or the null stream if no stream has been set. /// <para/> /// Results are 32-bit floating point values between 0.0f and 1.0f, /// excluding 0.0f and including 1.0f. /// </summary> /// <param name="output">CudaDeviceVariable</param> public void GenerateUniform(float[] output) { _status = CudaRandNativeMethods.curandGenerateUniform(_generator, output, output.LongLength); Debug.WriteLine(String.Format("{0:G}, {1}: {2}", DateTime.Now, "curandGenerateUniform", _status)); if (_status != CurandStatus.Success) { throw new CudaRandException(_status); } }
/// <summary> /// Generate Poisson-distributed unsigned ints.<para/> /// Use <c>generator</c> to generate <c>num</c> unsigned int results into the device memory at /// <c>outputPtr</c>. The device memory must have been previously allocated and be /// large enough to hold all the results. Launches are done with the stream /// set using <c>curandSetStream()</c>, or the null stream if no stream has been set. /// Results are 32-bit unsigned int point values with poisson distribution based on /// an associated poisson distribution with lambda <c>lambda</c>. /// </summary> /// <param name="generator">Generator to use</param> /// <param name="output">Pointer to host memory to store CPU-generated results</param> public void Generate(CudaRandHost generator, uint[] output) { _status = CudaRandNativeMethods.curandGeneratePoisson(generator.Generator, output, output.Length, _lambda); Debug.WriteLine(String.Format("{0:G}, {1}: {2}", DateTime.Now, "curandGeneratePoisson", _status)); if (_status != CurandStatus.Success) { throw new CudaRandException(_status); } }
/// <summary> /// Generate Poisson-distributed unsigned ints.<para/> /// Use <c>generator</c> to generate <c>num</c> unsigned int results into the device memory at /// <c>outputPtr</c>. The device memory must have been previously allocated and be /// large enough to hold all the results. Launches are done with the stream /// set using <c>curandSetStream()</c>, or the null stream if no stream has been set. /// Results are 32-bit unsigned int point values with poisson distribution based on /// an associated poisson distribution with lambda <c>lambda</c>. /// </summary> /// <param name="generator">Generator to use</param> /// <param name="output">Pointer to device memory to store CUDA-generated results</param> public void Generate(CudaRandDevice generator, CudaDeviceVariable <uint> output) { _status = CudaRandNativeMethods.curandGeneratePoisson(generator.Generator, output.DevicePointer, output.Size, _lambda); Debug.WriteLine(String.Format("{0:G}, {1}: {2}", DateTime.Now, "curandGeneratePoisson", _status)); if (_status != CurandStatus.Success) { throw new CudaRandException(_status); } }
/// <summary> /// Creates a new random number generator of type Type /// </summary> /// <param name="Type">Generator type</param> public CudaRandDevice(GeneratorType Type) { _generator = new CurandGenerator(); _status = CudaRandNativeMethods.curandCreateGenerator(ref _generator, Type); Debug.WriteLine(String.Format("{0:G}, {1}: {2}", DateTime.Now, "curandCreateGenerator", _status)); if (_status != CurandStatus.Success) { throw new CudaRandException(_status); } }
/// <summary> /// Creates a new poisson distribution.<para/> /// Construct histogram array for poisson distribution.<para/> /// Construct histogram array for poisson distribution with lambda <c>lambda</c>. /// For lambda greater than 2000 optimization with normal distribution is used. /// </summary> /// <param name="lambda">lambda for poisson distribution</param> public PoissonDistribution(double lambda) { _distributions = new DiscreteDistribution(); _lambda = lambda; _status = CudaRandNativeMethods.curandCreatePoissonDistribution(lambda, ref _distributions); Debug.WriteLine(String.Format("{0:G}, {1}: {2}", DateTime.Now, "curandCreatePoissonDistribution", _status)); if (_status != CurandStatus.Success) { throw new CudaRandException(_status); } }
/// <summary> /// For IDisposable /// </summary> /// <param name="fDisposing"></param> protected virtual void Dispose(bool fDisposing) { if (fDisposing && !disposed) { _status = CudaRandNativeMethods.curandDestroyDistribution(_distributions); Debug.WriteLine(String.Format("{0:G}, {1}: {2}", DateTime.Now, "curandDestroyDistribution", _status)); disposed = true; } if (!fDisposing && !disposed) { Debug.WriteLine(String.Format("CudaRand not-disposed warning: {0}", this.GetType())); } }
/// <summary> /// Returns the version number of the dynamically linked CURAND library. /// </summary> public static Version GetVersion() { int version = 0; CurandStatus _status = CudaRandNativeMethods.curandGetVersion(ref version); Debug.WriteLine(String.Format("{0:G}, {1}: {2}", DateTime.Now, "curandGetVersion", _status)); if (_status != CurandStatus.Success) { throw new CudaRandException(_status); } return(new Version((int)version / 1000, (int)version % 100)); }
/// <summary> /// Get an array of direction vectors that can be used for quasirandom number generation. /// <para/> /// The array contains vectors for many dimensions. Each dimension /// has 64 vectors. Each individual vector is an unsigned long long. /// <para/> /// Legal values for set are: /// - <see cref="DirectionVectorSet.JoeKuo6_64"/> (20,000 dimensions) /// - <see cref="DirectionVectorSet.ScrambledJoeKuo6_64"/> (20,000 dimensions) /// </summary> /// <param name="set"></param> /// <returns></returns> public static DirectionVectors64[] GetDirectionVectors64(DirectionVectorSet set) { IntPtr ptr; CurandStatus status = CudaRandNativeMethods.curandGetDirectionVectors64(out ptr, set); Debug.WriteLine(String.Format("{0:G}, {1}: {2}", DateTime.Now, "curandGetDirectionVectors64", status)); if (status != CurandStatus.Success) { throw new CudaRandException(status); } DirectionVectors64[] vec = new DirectionVectors64[MaxDimensions]; for (int i = 0; i < MaxDimensions; i++) { vec[i] = (DirectionVectors64)Marshal.PtrToStructure(new IntPtr(ptr.ToInt64() + i * 64 * Marshal.SizeOf(typeof(ulong))), typeof(DirectionVectors64)); } return(vec); }