slrand

package
v1.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 15, 2023 License: BSD-3-Clause Imports: 3 Imported by: 1

README

slrand

This package contains HLSL header files and matching Go code for various random number generation (RNG) functions, which can be copied and #included into an application's shaders directory.

We are using the Philox2x32 algorithm which is also available on CUDA on their cuRNG and in Tensorflow. It is a counter based RNG (CBRNG where the random number is a direct function of the input state, with no other internal state. For a useful discussion of other alternatives, see reddit cpp thread. The code is based on the D.E. Shaw github implementation.

The key advantage of this algorithm is its stateless nature, where the result is a deterministic but highly nonlinear function of its two inputs:

    uint2 res = Philox2x32(inout uint2 counter, uint key);

where the HLSL uint2 type is 2 uint32 32-bit unsigned integers. For GPU usage, the key is always set to the unique element being processed (e.g., the index of the data structure being updated), ensuring that different numbers are generated for each such element, and the counter should be configured as a shared global value that is incremented after every RNG call. For example, if 4 RNG calls happen within a given set of GPU code, each thread starts with the same uniform starting value that will be incremented by 4 after the GPU call, and then it locally increments its local counter after each call.

The Float and Uint32 etc wrapper functions around Philox2x32 will automatically increment the counter var passed to it, using the CounterIncr() method that manages the two 32 bit numbers as if they are a full 64 bit uint.

gosl will automatically translate the Go versions of the slrand package functions into their HLSL equivalents.

See the axon and slrand examples for how to use in combined Go / GPU code. In the axon example, the Counter is added to the Time context struct, and incremented after each cycle based on the number of random numbers generated, as determined by the parameter settings. Within each cycle, a local arg variable is incremented on each GPU processor as the computation unfolds.

Critically, these examples show that the CPU and GPU code produce identical random number sequences, which is otherwise quite difficult to achieve without this specific form of RNG.

Implementational details

Unfortunately, vulkan glslang does not support 64 bit integers, even though the shader language model has somehow been updated to support them: https://github.com/KhronosGroup/glslang/issues/2965 -- https://github.com/microsoft/DirectXShaderCompiler/issues/2067. This would also greatly speed up the impl: https://github.com/microsoft/DirectXShaderCompiler/issues/2821.

The result is that we have to use the slower version of the MulHiLo algorithm using only 32 bit uints.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func BoolP

func BoolP(counter *sltype.Uint2, key uint32, p float32) bool

BoolP returns a bool true value with probability p

func CounterAdd

func CounterAdd(counter *sltype.Uint2, inc uint32)

CounterAdd adds the given increment to the counter

func CounterIncr

func CounterIncr(counter *sltype.Uint2)

CounterIncr increments the given counter as if it was a uint64 integer.

func Float

func Float(counter *sltype.Uint2, key uint32) float32

Float returns a uniformly-distributed 32 float in range (0,1) based on given counter and key. The counter is incremented by 1 (in a 64-bit equivalent manner) as a result of this call, ensuring that the next call will produce the next random number in the sequence. The key should be the unique index of the element being updated.

func Float11

func Float11(counter *sltype.Uint2, key uint32) float32

Float11 returns a uniformly-distributed 32 float in range [-1,1] based on given counter and key. The counter is incremented by 1 (in a 64-bit equivalent manner) as a result of this call, ensuring that the next call will produce the next random number in the sequence. The key should be the unique index of the element being updated.

func Float112

func Float112(counter *sltype.Uint2, key uint32) sltype.Float2

Float112 returns two uniformly-distributed 32 floats in range [-1,1] based on given counter and key. The counter is incremented by 1 (in a 64-bit equivalent manner) as a result of this call, ensuring that the next call will produce the next random number in the sequence. The key should be the unique index of the element being updated.

func Float2

func Float2(counter *sltype.Uint2, key uint32) sltype.Float2

Float2 returns two uniformly-distributed 32 floats in range (0,1) based on given counter and key. The counter is incremented by 1 (in a 64-bit equivalent manner) as a result of this call, ensuring that the next call will produce the next random number in the sequence. The key should be the unique index of the element being updated.

func MulHiLo64

func MulHiLo64(a, b uint32) (lo, hi uint32)

MulHiLo64 is the fast, simpler version when 64 bit uints become available

func NormFloat

func NormFloat(counter *sltype.Uint2, key uint32) float32

NormFloat returns a random 32 bit floating number distributed according to the normal, Gaussian distribution with zero mean and unit variance.

func NormFloat2

func NormFloat2(counter *sltype.Uint2, key uint32) sltype.Float2

NormFloat2 returns two random 32 bit floating numbers distributed according to the normal, Gaussian distribution with zero mean and unit variance. This is done very efficiently using the Box-Muller algorithm that consumes two random 32 bit uint32 values.

func Philox2x32

func Philox2x32(counter sltype.Uint2, key uint32) sltype.Uint2

Philox2x32 implements the stateless counter-based RNG algorithm returning a random number as 2 uint3232 32 bit values, given a counter and key input that determine the result.

func Philox2x32bumpkey

func Philox2x32bumpkey(key *uint32)

Philox2x32bumpkey does one round of updating of the key

func Philox2x32round

func Philox2x32round(counter *sltype.Uint2, key uint32)

Philox2x32round does one round of updating of the counter

func SincosPi

func SincosPi(x float32) (s, c float32)

func Uint2

func Uint2(counter *sltype.Uint2, key uint32) sltype.Uint2

Uint2 returns two uniformly-distributed 32 unsigned integers, based on given counter and key. The counter is incremented by 1 (in a 64-bit equivalent manner) as a result of this call, ensuring that the next call will produce the next random numberin the sequence. The key should be the unique index of the element being updated.

func Uint2ToFloat

func Uint2ToFloat(val sltype.Uint2) sltype.Float2

Uint2ToFloat converts two uint32 32 bit integers (Uint2) into two corresponding 32 bit float values (float2) in the (0,1) interval (i.e., exclusive of 1).

func Uint2ToFloat11

func Uint2ToFloat11(val sltype.Uint2) sltype.Float2

Uint2ToFloat11 converts two uint32 32 bit integers (Uint2) into two corresponding 32 bit float values (float2) in the (0,1) interval (i.e., exclusive of 1).

func Uint32

func Uint32(counter *sltype.Uint2, key uint32) uint32

Uint32 returns a uniformly-distributed 32 unsigned integer, based on given counter and key. The counter is incremented by 1 (in a 64-bit equivalent manner) as a result of this call, ensuring that the next call will produce the next random number in the sequence. The key should be the unique index of the element being updated.

func Uint32ToFloat

func Uint32ToFloat(val uint32) float32

Uint32ToFloat converts a uint32 32 bit integer into a 32 bit float in the (0,1) interval (i.e., exclusive of 0 and 1). This differs from the Go standard by excluding 0, which is handy for passing directly to Log function, and from the reference Philox code by excluding 1 which is in the Go standard and most other standard RNGs.

func Uint32ToFloat11

func Uint32ToFloat11(val uint32) float32

Uint32ToFloat11 converts a uint32 32 bit integer into a 32 bit float in the [1,1] interval (inclusive of -1 and 1, never identically == 0)

func Uintn

func Uintn(counter *sltype.Uint2, key uint32, n uint32) uint32

Uintn returns a uint32 in the range [0,n)

Types

type Counter

type Counter struct {
	X uint32
	Y uint32
	// contains filtered or unexported fields
}

Counter is used for storing the random counter using aligned 16 byte storage

func (*Counter) Add

func (ct *Counter) Add(inc int) sltype.Uint2

Add increments the counter by given amount

func (*Counter) Reset

func (ct *Counter) Reset()

Reset resets counter to 0

func (*Counter) Set

func (ct *Counter) Set(c sltype.Uint2)

Set sets the counter from a Uint2

func (*Counter) Uint2

func (ct *Counter) Uint2() sltype.Uint2

Uint2 returns counter as a Uint2

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL