API reference

The manual explains workflows and backend limits. These docstrings describe exported entry points.

Destination slots

A sampling specification sits in the slot its upstream package uses, and the destination takes the remaining slot.

FillSignatureFollows
Primitive and rangerand_next!(rng, dest[, range])Random.rand!
Fixed distributionrand_next!(rng, d, dest)Distributions.rand!
Populationrandsample!(rng, pop[, weights], dest)StatsBase.sample!

Continuation fills return (dest, next_rng). Standard Random draws and fills require a mutable generator, such as StatefulRNG.

Generators

PureRNGs.AbstractPureRNG — Type
AbstractPureRNG

The abstract supertype of PureRNGs' generators. It exists for dispatch and inspection. Subtyping it outside the package is unsupported: the package's methods assume the key, position, and device layout of its own generators.

PureRNGs.Philox2x32 — Type
Philox2x32(seed)
Philox2x32(key::NTuple{1,UInt32})
Philox2x32(seed, position)
Philox2x32(key, position)

Construct a Philox generator with a 32-bit key and two 32-bit output words per counter block. The generator starts at the beginning of its stream on the CPU.

The integer seed must be non-negative and fit in 32 bits. The tuple form sets the key exactly. The two-argument forms start at position consumed bits, as returned by rngposition. Its 32-bit key makes derived-key collisions common: about 1% likely after 9,300 program-wide derivations and 50% after 77,000.

PureRNGs.Philox4x32 — Type
Philox4x32(seed)
Philox4x32(key::NTuple{2,UInt32})
Philox4x32(seed, position)
Philox4x32(key, position)

Construct a Philox generator with a 64-bit key and four 32-bit output words per counter block. The generator starts at the beginning of its stream on the CPU.

The integer seed must be non-negative and fit in 64 bits. The tuple form sets the key words exactly, from least to most significant. The two-argument forms start at position consumed bits, as returned by rngposition.

PureRNGs.Philox2x64 — Type
Philox2x64(seed)
Philox2x64(key::NTuple{1,UInt64})
Philox2x64(seed, position)
Philox2x64(key, position)

Construct a Philox generator with a 64-bit key and two 64-bit output words per counter block. The generator starts at the beginning of its stream on the CPU.

The integer seed must be non-negative and fit in 64 bits. The tuple form sets the key exactly. The two-argument forms start at position consumed bits, as returned by rngposition.

PureRNGs.Philox4x64 — Type
Philox4x64(seed)
Philox4x64(key::NTuple{2,UInt64})
Philox4x64(seed, position)
Philox4x64(key, position)

Construct a Philox generator with a 128-bit key and four 64-bit output words per counter block. The generator starts at the beginning of its stream on the CPU.

The integer seed must be non-negative and fit in 128 bits. The tuple form sets the key words exactly, from least to most significant. The two-argument forms start at position consumed bits, as returned by rngposition.

PureRNGs.Threefry2x32 — Type
Threefry2x32(seed)
Threefry2x32(key::NTuple{2,UInt32})
Threefry2x32(seed, position)
Threefry2x32(key, position)

Construct a Threefry generator with a 64-bit key and two 32-bit output words per counter block. The generator starts at the beginning of its stream on the CPU.

The integer seed must be non-negative and fit in 64 bits. The tuple form sets the key words exactly, from least to most significant. The two-argument forms start at position consumed bits, as returned by rngposition.

PureRNGs.Threefry4x32 — Type
Threefry4x32(seed)
Threefry4x32(key::NTuple{4,UInt32})
Threefry4x32(seed, position)
Threefry4x32(key, position)

Construct a Threefry generator with a 128-bit key and four 32-bit output words per counter block. The generator starts at the beginning of its stream on the CPU.

The integer seed must be non-negative and fit in 128 bits. The tuple form sets the key words exactly, from least to most significant. The two-argument forms start at position consumed bits, as returned by rngposition.

PureRNGs.Threefry2x64 — Type
Threefry2x64(seed)
Threefry2x64(key::NTuple{2,UInt64})
Threefry2x64(seed, position)
Threefry2x64(key, position)

Construct a Threefry generator with a 128-bit key and two 64-bit output words per counter block. The generator starts at the beginning of its stream on the CPU.

The integer seed must be non-negative and fit in 128 bits. The tuple form sets the key words exactly, from least to most significant. The two-argument forms start at position consumed bits, as returned by rngposition.

PureRNGs.Threefry4x64 — Type
Threefry4x64(seed)
Threefry4x64(key::NTuple{4,UInt64})
Threefry4x64(seed, position)
Threefry4x64(key, position)

Construct a Threefry generator with a 256-bit key and four 64-bit output words per counter block. The generator starts at the beginning of its stream on the CPU.

The integer seed must be non-negative and fit in 256 bits. The tuple form sets the key words exactly, from least to most significant. The two-argument forms start at position consumed bits, as returned by rngposition.

PureRNGs.Philox4x32R7 — Type
Philox4x32R7(seed)
Philox4x32R7(key::NTuple{2,UInt32})

Philox4x32 with seven rounds, the smallest round count that Salmon, Moraes, Dror, and Shaw (2011, Table 2) report as passing BigCrush for this shape. It shares every method with Philox4x32 and produces a different stream.

PureRNGs.Philox2x64R6 — Type
Philox2x64R6(seed)
Philox2x64R6(key::NTuple{1,UInt64})

Philox2x64 with six rounds, the smallest round count that Salmon, Moraes, Dror, and Shaw (2011, Table 2) report as passing BigCrush for this shape. It shares every method with Philox2x64 and produces a different stream.

PureRNGs.Philox4x64R7 — Type
Philox4x64R7(seed)
Philox4x64R7(key::NTuple{2,UInt64})

Philox4x64 with seven rounds, the smallest round count that Salmon, Moraes, Dror, and Shaw (2011, Table 2) report as passing BigCrush for this shape. It shares every method with Philox4x64 and produces a different stream.

PureRNGs.Threefry2x64R13 — Type
Threefry2x64R13(seed)
Threefry2x64R13(key::NTuple{2,UInt64})

Threefry2x64 with thirteen rounds, the smallest round count that Salmon, Moraes, Dror, and Shaw (2011, Table 2) report as passing BigCrush for this shape. It shares every method with Threefry2x64 and produces a different stream.

PureRNGs.Threefry4x32R12 — Type
Threefry4x32R12(seed)
Threefry4x32R12(key::NTuple{4,UInt32})

Threefry4x32 with twelve rounds, the smallest round count that Salmon, Moraes, Dror, and Shaw (2011, Table 2) report as passing BigCrush for this shape. It shares every method with Threefry4x32 and produces a different stream.

PureRNGs.Threefry4x64R13 — Type
Threefry4x64R13(seed)
Threefry4x64R13(key::NTuple{4,UInt64})

Threefry4x64 with thirteen rounds: one more than the twelve that Salmon, Moraes, Dror, and Shaw (2011, Table 2) report as the minimum passing BigCrush for this shape, and the reduced round count in Random123's known-answer tests. It shares every method with Threefry4x64 and produces a different stream.

PureRNGs.ChaCha — Type
ChaCha(seed)
ChaCha(key::NTuple{8,UInt32})
ChaCha(seed, position)
ChaCha(key, position)

Construct a ChaCha generator with a 256-bit key, twelve rounds, and sixteen 32-bit output words per counter block. The generator starts at the beginning of its stream on the CPU. ChaCha8 and ChaCha20 select the other common round counts.

The integer seed must be non-negative and fit in 256 bits. The tuple form sets the key words exactly, from least to most significant. The two-argument forms start at position consumed bits, as returned by rngposition.

PureRNGs.ChaCha8 — Type
ChaCha8(seed)
ChaCha8(key::NTuple{8,UInt32})

ChaCha with eight rounds, the fastest common choice for random number generation. It shares every method with ChaCha and produces a different stream.

PureRNGs.ChaCha12 — Type
ChaCha12(seed)
ChaCha12(key::NTuple{8,UInt32})

ChaCha with its default twelve rounds, the round count with a comfortable margin over the best known attacks. ChaCha12(seed) and ChaCha(seed) are the same generator.

PureRNGs.ChaCha20 — Type
ChaCha20(seed)
ChaCha20(key::NTuple{8,UInt32})

ChaCha with twenty rounds, the cipher's round count. It shares every method with ChaCha and produces a different stream.

Continuation draws

PureRNGs.rand_next — Function
rand_next(rng[, T]) -> (value, next_rng)
rand_next(rng, collection) -> (value, next_rng)
rand_next(rng[, T], dims...) -> (values, next_rng)
rand_next(rng, collection, dims...) -> (values, next_rng)

Draw from rng and return the advanced immutable generator with the result. Omitting T selects Float64. Supported scalar types are Bool, the 8- to 128-bit signed and unsigned integers, Float16, Float32, Float64, Complex values of those three, and Char, which is uniform over the Unicode scalar values as in Random. Integer ranges support signed and unsigned integer element types through 128 bits. Dimensions may also be one tuple, as in Random. The 128-bit types run on the CPU only.

A collection is an integer range, any other array or range, a tuple, a string, a dict, or a set. A pick from it consumes and returns what one randsample_next draw does. A lone tuple is a collection, including a tuple of integers. Use rand_next(rng, Float64, (m, n)) for tuple dimensions. Strings, dicts, and sets reach the drawn position by iteration.

The allocating forms create an array on the generator's device. The input generator never changes.

Examples

julia> rng = Philox4x32(20250918);

julia> value, next_rng = rand_next(rng, UInt32);

julia> value
0x23b42aea

julia> first(rand_next(next_rng, UInt32))
0x467098dd

julia> first(rand_next(rng, UInt32, 3))
3-element Vector{UInt32}:
 0x23b42aea
 0x467098dd
 0xc25ecc0b
PureRNGs.rand_next! — Function
rand_next!(rng, destination; threaded=false) -> (destination, next_rng)
rand_next!(rng, destination, range; threaded=false) -> (destination, next_rng)

Fill destination from rng and return the advanced immutable generator with the same destination. The destination element type must be a result type rand_next supports, or with range the integer element type of that range, and its device must match the generator.

Fills run serially by default. Set threaded=true to split a CPU fill across threads; the keyword never changes the generated stream. The input generator never changes.

PureRNGs.randn_next — Function
randn_next(rng[, T]) -> (value, next_rng)
randn_next(rng[, T], dims...) -> (values, next_rng)

Draw standard normal values from rng and return the advanced immutable generator with the result. Omitting T selects Float64; T may be Float16, Float32, Float64, or a Complex of one of them. A Float16 normal is the Float32 normal on the same bits, rounded once.

The allocating form creates an array on the generator's device. The input generator never changes.

PureRNGs.randn_next! — Function
randn_next!(rng, destination; threaded=false) -> (destination, next_rng)

Fill a floating-point or complex destination with standard normal values and return the advanced immutable generator with the same destination. The destination's device must match the generator.

Fills run serially by default. Set threaded=true to split a CPU fill across threads; the keyword never changes the generated stream. The input generator never changes.

PureRNGs.randexp_next — Function
randexp_next(rng[, T]) -> (value, next_rng)
randexp_next(rng[, T], dims...) -> (values, next_rng)

Draw standard exponential values from rng and return the advanced immutable generator with the result. Omitting T selects Float64; T may be Float16, Float32, or Float64.

The allocating form creates an array on the generator's device. The input generator never changes.

PureRNGs.randexp_next! — Function
randexp_next!(rng, destination; threaded=false) -> (destination, next_rng)

Fill a Float16, Float32, or Float64 destination with standard exponential values and return the advanced immutable generator with the same destination. The destination's device must match the generator.

Fills run serially by default. Set threaded=true to split a CPU fill across threads; the keyword never changes the generated stream. The input generator never changes.

Unified pure and mutable calls

These adapters return (value, next_rng) for either kind of generator. Source arguments precede destinations in randset!!, including for distributions.

PureRNGs.randgen!! — Function
randgen!!(rng, from_what, dims...) -> (value, next_rng)
randgen!!(rng, from_what, dims::Dims) -> (values, next_rng)

Draw from a type, population, or supported distribution with either a pure or mutable RNG. Arguments, keywords, sample shapes, and values follow the native rand_next or Random.rand method. Nonempty tuple dimensions are splatted, so (n,) and n select the same sample layout. The source is not modified. Population elements may be borrowed, not copied.

Always use both returned values. A mutable RNG advances in place; a pure RNG returns its continuation without changing the input. The !! contract permits mutation but does not invalidate immutable snapshots. It does not add fixed-work, device, or failure-atomicity guarantees to the native method.

PureRNGs.randset!! — Function
randset!!(rng, from_what, old_value) -> (value, next_rng)

Replace a scalar with one draw, or reuse a writable array with a native bulk fill. The source precedes the destination, including for distributions. A scalar type source selects the result element type; a different destination element type causes replacement. Array shapes otherwise follow the native fill, including a vector for one multivariate draw or a matrix with one draw per column.

Ranges and immutable StaticArrays are replaced. Arrays of immutable samples use their native fill methods. A static array type with a static template denotes one whole sample. Arbitrary tuples and structs are single values, not recursively filled containers. Extensions may define further replacement rules.

The source is not modified. A destination that aliases a supported source is replaced before sampling. Custom source methods must preserve the same contract. Population elements can still be borrowed. Use both returned values and do not reuse the old RNG or destination in generic code. A failure can leave a mutable RNG advanced or a destination partly written, as with the native fill. No failed draw is retried. See randgen!!.

PureRNGs.randugen!! — Function
randugen!!(rng[, T], dims...) -> (value, next_rng)
randugen!!(rng[, T], dims::Dims) -> (values, next_rng)

Draw uniform values, with Float64 as the default result type. A tuple here is always a shape. Use randgen!! to sample a population or distribution.

PureRNGs.randuset!! — Function
randuset!!(rng, old_value) -> (value, next_rng)

Replace a scalar or fill an array with uniform values of its existing element type. See randset!! for replacement, ownership, and failure rules.

PureRNGs.randngen!! — Function
randngen!!(rng[, T], dims...) -> (value, next_rng)
randngen!!(rng[, T], dims::Dims) -> (values, next_rng)

Draw standard normal values through randn_next or Random.randn. The result type defaults to Float64. See randgen!! for ownership.

PureRNGs.randnset!! — Function
randnset!!(rng, old_value) -> (value, next_rng)

Replace a scalar or fill an array with standard normal values of its existing element type. See randset!! for replacement, ownership, and failure rules.

PureRNGs.randexpgen!! — Function
randexpgen!!(rng[, T], dims...) -> (value, next_rng)
randexpgen!!(rng[, T], dims::Dims) -> (values, next_rng)

Draw standard exponential values through randexp_next or Random.randexp. The result type defaults to Float64. See randgen!! for ownership.

PureRNGs.randexpset!! — Function
randexpset!!(rng, old_value) -> (value, next_rng)

Replace a scalar or fill an array with standard exponential values of its existing element type. See randset!! for replacement, ownership, and failure rules.

Addressed draws

PureRNGs.rand_at — Function
rand_at(rng, T, i)
rand_at(rng, T, i:j)
rand_at(rng, collection, i)

Return the ith uniform draw at or after the current position of rng, where i is one-based, or the vector of draws i through j. Supported result types are those of rand_next. Passing a collection in place of T returns the ith pick from that collection.

Addressed draws do not advance or change rng. They throw when i is not positive or the addressed draw exceeds the generator's counter capacity.

The collection and distribution forms of rand_at take a single index.

Examples

julia> rng = Philox4x32(20250918);

julia> rand_at(rng, UInt32, 3)
0xc25ecc0b

julia> rand_at(rng, UInt32, 1:3)
3-element Vector{UInt32}:
 0x23b42aea
 0x467098dd
 0xc25ecc0b
PureRNGs.randn_at — Function
randn_at(rng, T, i)
randn_at(rng, T, i:j)

Return the ith standard normal draw at or after the current position of rng, where i is one-based, or the vector of draws i through j. T is any type randn_next accepts.

Addressed draws do not advance or change rng. They throw when i is not positive or the addressed draw exceeds the generator's counter capacity.

PureRNGs.randexp_at — Function
randexp_at(rng, T, i)
randexp_at(rng, T, i:j)

Return the ith standard exponential draw at or after the current position of rng, where i is one-based, or the vector of draws i through j. T is Float16, Float32, or Float64.

Addressed draws do not advance or change rng. They throw when i is not positive or the addressed draw exceeds the generator's counter capacity.

Key derivation

PureRNGs.splitrng — Function
splitrng(rng)
splitrng(rng, n; threaded=false)
splitrng(rng, Val(N))

Derive child keys from distinct counter addresses. The ordinary n form returns a vector. The Val form returns an allocation-free tuple for static or GPU code. The default derives two children.

The n form takes threaded, which selects a parallel derivation on the CPU and defaults to false. The children are identical for either value.

Derivation reads only the parent key. It ignores the parent position, preserves the device, and starts each child at position zero. It never changes the parent. Calling splitrng again on an advanced parent therefore returns the same children, so derive from stable identifiers rather than from a stream position.

Child keys are core output and can collide. Across n program-wide derivations with k key bits, the collision probability is about n^2 / 2^(k+1). A collision makes both child subtrees identical. Use a generator with at least 128 key bits for per-particle or per-proposal derivation at scale.

Examples

julia> rng = Philox4x32(20250918);

julia> left, right = splitrng(rng);

julia> first(rand_next(left, UInt32)), first(rand_next(right, UInt32))
(0xea1624f3, 0x34564a30)

julia> advanced = last(rand_next(rng, UInt32));

julia> first(rand_next(first(splitrng(advanced)), UInt32))
0xea1624f3
PureRNGs.subrng — Function
subrng(rng, purpose)

Derive one child key for the stable integer purpose. Use fixed purpose ids for independent roles, such as subrng(root, 1) for proposals and subrng(root, 2) for resampling. Use subrng(root, chunk_id) to assign explicit large-job chunks.

purpose is reduced modulo 2^64, so a negative value or a value at or above 2^64 aliases the child of an existing purpose id. Purpose ids are a separate namespace from stream positions, which rngposition returns as a UInt128, or a BigInt for Philox4x64 and Threefry4x64.

Derivation reads only the parent key. It ignores the parent position, preserves the device, and starts the child at position zero. It never changes the parent. The same key and purpose always produce the same child. Calling subrng again on an advanced parent therefore returns the same child, so derive from stable identifiers rather than from a stream position.

Child keys are core output and can collide. Across n program-wide derivations with k key bits, the collision probability is about n^2 / 2^(k+1). A collision makes both child subtrees identical. Use a generator with at least 128 key bits for per-particle or per-proposal derivation at scale.

Examples

julia> rng = Philox4x32(20250918);

julia> first(rand_next(subrng(rng, 1), UInt32))
0x04970499

julia> first(rand_next(subrng(rng, 2), UInt32))
0x65feaf98

julia> rand_next(subrng(rng, -1), UInt32) == rand_next(subrng(rng, big(2)^64 - 1), UInt32)
true

State access

PureRNGs.rngkey — Function
rngkey(rng) -> NTuple

Return the key words of rng, from least to most significant. The tuple has the type accepted by the generator's key constructor.

PureRNGs.rngposition — Function
rngposition(rng) -> Integer

Return the number of stream bits rng has consumed. The result is a UInt128 for generators with a 64-bit block counter and a BigInt for Philox4x64 and Threefry4x64. An exhausted generator reports the generator's full stream capacity.

Pass the result to the generator's constructor together with rngkey to rebuild the generator at the same position.

Population sampling

PureRNGs.randsample — Function
randsample(rng, population[, count]; replace=true, threaded=false)
randsample(rng, population, weights[, count]; replace=true, threaded=false)

Sample from population. Without count, return as many draws as the population has elements. With weights, use non-negative finite weights proportional to the desired probabilities.

Sampling is with replacement by default. With replace=false, the sample is the first count elements of shuffle_next(rng, collect(population)): it consumes 64 bits per population element for every count, and count may not exceed the population.

Weighted sampling with replace=false draws E = randexp_next(rng, Float64, n) and returns the population in increasing order of E[i] / weights[i], ties by index, truncated to count. This is successive sampling proportional to the remaining weights (Efraimidis and Spirakis 2006). It consumes 52 bits per population element for every count, and count may not exceed the number of positive weights. It does not accept a WeightTable. Device exponentials can differ from CPU exponentials in the last ulp, so a device sample can differ from the CPU sample when two ratios are that close.

The no-count form returns length(pop) samples, unlike StatsBase.sample(rng, a), which returns one element. randsample(rng, pop, 1) returns a one-element vector.

The result is a vector on the generator's device. This convenience form does not return the advanced generator; use randsample_next when subsequent draws must continue after the sample.

Examples

julia> rng = Philox4x32(20250918);

julia> pop = [10, 20, 30, 40];

julia> randsample(rng, pop)
4-element Vector{Int64}:
 10
 40
 30
 10

julia> randsample(rng, pop, 1)
1-element Vector{Int64}:
 10
PureRNGs.randsample_next — Function
randsample_next(rng, population[, count]; replace=true, threaded=false) -> (values, next_rng)
randsample_next(rng, population, weights[, count]; replace=true, threaded=false) -> (values, next_rng)

Sample from population and return the advanced immutable generator with the result. Without count, return as many draws as the population has elements. With weights, use non-negative finite weights proportional to the desired probabilities. replace is as for randsample.

The result is a vector on the generator's device. The input generator never changes.

PureRNGs.randsample! — Function
randsample!(rng, population[, weights], destination; replace=true, threaded=false) -> destination

Sample into destination, with replacement unless replace=false (see randsample). Its length determines the number of draws, and it must have exactly the prepared population element type. Return the identical destination. Fills run on the calling task by default; threaded=true splits a CPU fill across threads without changing the values.

Inputs and the complete random span are validated before writing. A destination that might alias population is rejected; it may alias weights after the weights have been privately prepared. Empty destinations still validate inputs. They consume no bits with replacement; without replacement, consumption still depends on the population size. Weighted fills may allocate preparation scratch space.

Examples

julia> rng = Philox4x32(20250918);

julia> destination = zeros(Int, 5);

julia> randsample!(rng, [10, 20, 30, 40], destination)
5-element Vector{Int64}:
 10
 40
 30
 10
 10
PureRNGs.randsample_next! — Function
randsample_next!(rng, population[, weights], destination; replace=true, threaded=false) -> (destination, next_rng)

Sample into destination and return the advanced immutable generator. The fill and validation rules are the same as for randsample!. The input generator is not changed.

PureRNGs.WeightTable — Type
WeightTable(weights)

Prepared weights for repeated weighted sampling. Holds the cumulative table the weighted forms build on every call, so a caller with fixed weights pays that cost once. Accepted wherever a weight vector is. Draws with a table equal draws with the weights it was built from. A table lives on the device of its weights and serves generators on that device. Treat the prepared storage as read-only: a sampling destination must not share its memory.

Rebuild the table when its source weights change. CUDA uses parallel accumulation for large tables, so selected elements need not match CPU accumulation.

Examples

julia> rng = Philox4x32(20250918);

julia> pop = [10, 20, 30, 40];

julia> weights = [1.0, 1.0, 1.0, 7.0];

julia> table = WeightTable(weights);

julia> randsample(rng, pop, table, 6)
6-element Vector{Int64}:
 20
 20
 40
 40
 40
 10

julia> randsample(rng, pop, table, 6) == randsample(rng, pop, weights, 6)
true

Permutations

PureRNGs.randperm_next — Function
randperm_next(rng, n; threaded=false) -> (permutation, next_rng)

Return a random permutation of 1:n and the advanced immutable generator. The permutation orders n uniform UInt64 draws at the held position, so it consumes 64n bits, and it is the same on the CPU and on a GPU. Draws that tie are shuffled within their run with draws from subrng(rng, key) without changing parent consumption. The fixed-width range mapping used for ties has finite-grid bias, so permutations are not exactly uniform.

The result has the element type of n and lives on the generator's device. threaded=true splits the CPU key draw across threads without changing values. The input generator never changes.

Examples

julia> rng = Philox4x32(20250918);

julia> permutation, next_rng = randperm_next(rng, 5);

julia> sort(permutation) == 1:5
true
PureRNGs.randperm_next! — Function
randperm_next!(rng, destination; threaded=false) -> (destination, next_rng)

Fill destination with the permutation of 1:length(destination) that randperm_next returns, in linear order, and return the advanced immutable generator.

PureRNGs.randcycle_next — Function
randcycle_next(rng, n; threaded=false) -> (cycle, next_rng)

Return a random cyclic permutation of 1:n and the advanced immutable generator. With p = first(randperm_next(rng, n)), the cycle sends p[i] to p[i + 1] and p[n] to p[1], so it consumes what randperm_next does, with the same finite-grid limitation.

PureRNGs.randcycle_next! — Function
randcycle_next!(rng, destination; threaded=false) -> (destination, next_rng)

Fill destination with the cyclic permutation that randcycle_next returns for length(destination), in linear order, and return the advanced immutable generator.

PureRNGs.shuffle_next — Function
shuffle_next(rng, values; threaded=false) -> (shuffled, next_rng)

Return a shuffled copy of values and the advanced immutable generator. Element i of the copy, in linear order, is element p[i] of values, where p = first(randperm_next(rng, length(values))).

PureRNGs.shuffle_next! — Function
shuffle_next!(rng, values; threaded=false) -> (values, next_rng)

Shuffle values in place as shuffle_next does and return the advanced immutable generator.

Mutable interoperability

PureRNGs.StatefulRNG — Type
StatefulRNG(rng)

Wrap an immutable generator for host-only consumers of Random.AbstractRNG. Construction preserves the key and position and rebinds the generator to the CPU. parent(bridge) returns the exact immutable generator currently held by the bridge without allocating, mutating, or advancing it.

Package-owned one-argument Array and BitArray fills preflight their full counter span. The integer-range Array fill preserves Julia's scalar bridge behavior: counter exhaustion may leave its maximal valid prefix written, with the held generator after that prefix. A foreign Random fill has no chained-scalar consumption-order guarantee and may also leave its destination partially written. The held generator remains valid at the position after the last successful draw.

Examples

julia> using Random

julia> bridge = StatefulRNG(Philox4x32(20250918));

julia> rand(bridge, UInt32)
0x23b42aea

julia> rand(bridge, UInt32)
0x467098dd

julia> first(rand_next(parent(bridge), UInt32))
0xc25ecc0b

Errors

PureRNGs.StreamExhausted — Type
StreamExhausted{R}(bits)

Thrown when a draw needs more logical bits than the generator has left in its stream. The type parameter R is the concrete type of that generator, and the single field bits::UInt128 is the span the draw required. The exception holds no generator value: keeping one alive across the capacity check costs every draw. The caller still holds the generator it passed in. Construction with an out-of-range position and argument validation keep throwing ArgumentError.

An addressed draw on Philox4x64 or Threefry4x64 can name a span wider than typemax(UInt128). The field then holds typemax(UInt128).