Generators and lower-level interfaces

Generator choice

Philox4x32 R10 is the default CPU generator and one of the two qualified CUDA generators. Threefry2x32 is JAX compatible and provides the other qualified CUDA path. Philox4x32R7 trades a smaller safety margin for speed.

Squares64 remains experimental. Its conditioned seed-to-key map is non-injective and non-surjective, and it lacks external validation. ARS5 requires AES support. Every host that constructs or restores ARS5 must provide that support.

Use labeled raw-key constructors in durable code. Philox and Threefry use native (key_hi, key_lo) order. ARS5 uses Random123 word order. Squares uses one raw key word.

Philox4x32(; key_hi=0x2a, key_lo=0x2b)
Threefry2x32(; key_hi=0x2a, key_lo=0x2b)
ARS5(; key_word0=0x0, key_word1=0x1, key_word2=0x2, key_word3=0x3)
Squares64(; key=0x2a)

Integer constructors and supported seed! methods reduce seeds modulo 2^64. This rule includes negative and arbitrary-precision integers. Raw Squares restoration skips seed conditioning and checks the raw-key invariant again.

Raw blocks and cursor capabilities

bits(key, counter::UInt64) returns a generator-specific raw block. cursor_block(key, family, block) is the public, unexported extension protocol for cursor families. Do not extend private _block methods.

A third-party cursor generator must be isbits. It must provide constant blockwords, cursor_max_block, cursor_families, and cursor_block results, with 1 <= blockwords(R) <= 255. Integer reseeding, durable codecs, device profiles, and AD inactivity are optional and independent.

Third-party family IDs use the literal 0x80:0xbf band. Packages register an owner UUID, name, and ID during __init__. The registry detects collisions but does not assign IDs or enter the draw path.

Checkpoint codecs use stable token types. A package registers its generator and codec from __init__. Trait methods remain the authority for type-to-ID mappings. Device profiles are registered data rather than extension methods. Claim support only for a tested generator, backend, operation, and element type.

Host cursor arithmetic uses checked UInt128. Device code uses explicit UInt64 block-and-lane carry. A device profile must not introduce a 128-bit integer requirement.

Collections, ranges, and packed bits

Collection sampling uses ordinal positions and preserves valid axes. Shuffle, permutation, and cycle use their own tagged families and the fixed-work range law. Owned spans above 2^32 use two 64-bit slots and the portable 128-bit reduction described in the draw guide.

Logical BitArray methods consume one cursor word per bit and match scalar Bool calls. packed_bitrand and packed_bitrand! consume one aligned 64-bit slot per storage chunk. They write Julia's native least-significant-bit chunk order. Use the packed path for throughput.

The measured logical path was about 65 times slower than packed generation on one host. Treat that as machine-specific evidence, not a portable ratio.

Accelerator support

KernelAbstractions defines the package's kernel interface. Version 0.1.0 qualifies Philox4x32 and Threefry2x32 on CUDA for host-controlled mutable rand!, randn!, and randexp! with Float32 and Float64.

The wrapper stays on the host. The kernel receives an immutable start address and fixed draw metadata. Device code can use pure addressed keys or local cursors. The qualification covers no other generator, backend, range fill, or Reactant pair.

GPUArrays' rand_native! and randn_native! use backend-native RNG streams. They do not preserve the portable package stream.

Differentiation

The EnzymeCore extension marks bundled keys and cursors inactive because they contain no differentiable data. A third-party cursor may use the same treatment only when its key has no floating fields.

Host Enzyme rules cover rand!, randn!, and randexp!. Each rule runs the primal fill once, advances the cursor as a direct fill would, and zeroes all single or batched destination shadows. Random state is non-differentiable, but caller-owned floating-point arguments retain gradients.

Owned Enzyme fills passed functional CuArray CUDA acceptance on an A100. The result verifies accelerator execution and cursor state, but not performance.

Reactant threads explicit cursor state through a compiled graph and writes the next cursor to the caller's wrapper. A CPU trace does not prove accelerator execution. Reactant support in 0.1.0 is an experimental functional preview without a performance guarantee. In one Reactant 0.2.279 A100 run, the full lifecycle cost 5.05 to 8.43 times the immutable graph across twelve length-2^20 rows. A separate minimal device-resident Philox rand(Float32) shape without transfers cost 1.1964 times as much. Use the qualified KernelAbstractions CUDA path for supported host-dispatched GPU fills.

Performance

The wrapper has one private block-cache entry. Cache shape is neither checkpoint state nor public API. Any new cache policy must preserve values and cursors, avoid homogeneous regression, and show a measured gain for mixed work.

Binding CPU evidence covers a homogeneous scalar chain, a 2^20 fill, and one packed-bit row. CUDA evidence compares mutable and immutable addressed fills in one process. Every reported ratio applies only to its workload and host.