diff options
| author | YurenHao0426 <blackhao0426@gmail.com> | 2026-06-13 12:35:36 -0500 |
|---|---|---|
| committer | YurenHao0426 <blackhao0426@gmail.com> | 2026-06-13 12:35:36 -0500 |
| commit | 66e0d8b9fd4d0f7a2231d689c055e26fdf1cf04a (patch) | |
| tree | c29cba61124018755a19b02c9d33e3ad5f2e05cc /research/flossing/external/julia-1.6.7/share/julia/stdlib/v1.6/Random/docs | |
Curated export for clone-and-run Maze training (2x A6000) + diagnostics.
trm/hrm pretrain.py carry trajectory-augmentation code (backward-compatible).
Heavy artifacts (checkpoints/wandb/npz) gitignored; see PROVENANCE.md.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Diffstat (limited to 'research/flossing/external/julia-1.6.7/share/julia/stdlib/v1.6/Random/docs')
| -rw-r--r-- | research/flossing/external/julia-1.6.7/share/julia/stdlib/v1.6/Random/docs/src/index.md | 358 |
1 files changed, 358 insertions, 0 deletions
diff --git a/research/flossing/external/julia-1.6.7/share/julia/stdlib/v1.6/Random/docs/src/index.md b/research/flossing/external/julia-1.6.7/share/julia/stdlib/v1.6/Random/docs/src/index.md new file mode 100644 index 0000000..ca86de4 --- /dev/null +++ b/research/flossing/external/julia-1.6.7/share/julia/stdlib/v1.6/Random/docs/src/index.md @@ -0,0 +1,358 @@ +# Random Numbers + +```@meta +DocTestSetup = :(using Random) +``` + +Random number generation in Julia uses the [Mersenne Twister library](http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/#dSFMT) +via `MersenneTwister` objects. Julia has a global RNG, which is used by default. Other RNG types +can be plugged in by inheriting the `AbstractRNG` type; they can then be used to have multiple +streams of random numbers. Besides `MersenneTwister`, Julia also provides the `RandomDevice` RNG +type, which is a wrapper over the OS provided entropy. + +Most functions related to random generation accept an optional `AbstractRNG` object as first argument, +which defaults to the global one if not provided. Moreover, some of them accept optionally +dimension specifications `dims...` (which can be given as a tuple) to generate arrays of random +values. In a multi-threaded program, you should generally use different RNG objects from different threads +in order to be thread-safe. However, the default global RNG is thread-safe as of Julia 1.3 (because +it internally corresponds to a per-thread RNG). + +A `MersenneTwister` or `RandomDevice` RNG can generate uniformly random numbers of the following types: +[`Float16`](@ref), [`Float32`](@ref), [`Float64`](@ref), [`BigFloat`](@ref), [`Bool`](@ref), +[`Int8`](@ref), [`UInt8`](@ref), [`Int16`](@ref), [`UInt16`](@ref), [`Int32`](@ref), +[`UInt32`](@ref), [`Int64`](@ref), [`UInt64`](@ref), [`Int128`](@ref), [`UInt128`](@ref), +[`BigInt`](@ref) (or complex numbers of those types). +Random floating point numbers are generated uniformly in ``[0, 1)``. As `BigInt` represents +unbounded integers, the interval must be specified (e.g. `rand(big.(1:6))`). + +Additionally, normal and exponential distributions are implemented for some `AbstractFloat` and +`Complex` types, see [`randn`](@ref) and [`randexp`](@ref) for details. + +!!! warning + Because the precise way in which random numbers are generated is considered an implementation detail, bug fixes and speed improvements may change the stream of numbers that are generated after a version change. Relying on a specific seed or generated stream of numbers during unit testing is thus discouraged - consider testing properties of the methods in question instead. + +## Random numbers module +```@docs +Random.Random +``` + +## Random generation functions + +```@docs +Random.rand +Random.rand! +Random.bitrand +Random.randn +Random.randn! +Random.randexp +Random.randexp! +Random.randstring +``` + +## Subsequences, permutations and shuffling + +```@docs +Random.randsubseq +Random.randsubseq! +Random.randperm +Random.randperm! +Random.randcycle +Random.randcycle! +Random.shuffle +Random.shuffle! +``` + +## Generators (creation and seeding) + +```@docs +Random.seed! +Random.AbstractRNG +Random.MersenneTwister +Random.RandomDevice +``` + +## Hooking into the `Random` API + +There are two mostly orthogonal ways to extend `Random` functionalities: +1) generating random values of custom types +2) creating new generators + +The API for 1) is quite functional, but is relatively recent so it may still have to evolve in subsequent releases of the `Random` module. +For example, it's typically sufficient to implement one `rand` method in order to have all other usual methods work automatically. + +The API for 2) is still rudimentary, and may require more work than strictly necessary from the implementor, +in order to support usual types of generated values. + +### Generating random values of custom types + +Generating random values for some distributions may involve various trade-offs. *Pre-computed* values, such as an [alias table](https://en.wikipedia.org/wiki/Alias_method) for discrete distributions, or [“squeezing” functions](https://en.wikipedia.org/wiki/Rejection_sampling) for univariate distributions, can speed up sampling considerably. How much information should be pre-computed can depend on the number of values we plan to draw from a distribution. Also, some random number generators can have certain properties that various algorithms may want to exploit. + +The `Random` module defines a customizable framework for obtaining random values that can address these issues. Each invocation of `rand` generates a *sampler* which can be customized with the above trade-offs in mind, by adding methods to `Sampler`, which in turn can dispatch on the random number generator, the object that characterizes the distribution, and a suggestion for the number of repetitions. Currently, for the latter, `Val{1}` (for a single sample) and `Val{Inf}` (for an arbitrary number) are used, with `Random.Repetition` an alias for both. + +The object returned by `Sampler` is then used to generate the random values. When implementing the random generation interface for a value `X` that can be sampled from, the implementor should define the method + +```julia +rand(rng, sampler) +``` +for the particular `sampler` returned by `Sampler(rng, X, repetition)`. + +Samplers can be arbitrary values that implement `rand(rng, sampler)`, but for most applications the following predefined samplers may be sufficient: + +1. `SamplerType{T}()` can be used for implementing samplers that draw from type `T` (e.g. `rand(Int)`). This is the default returned by `Sampler` for *types*. + +2. `SamplerTrivial(self)` is a simple wrapper for `self`, which can be accessed with `[]`. This is the recommended sampler when no pre-computed information is needed (e.g. `rand(1:3)`), and is the default returned by `Sampler` for *values*. + +3. `SamplerSimple(self, data)` also contains the additional `data` field, which can be used to store arbitrary pre-computed values, which should be computed in a *custom method* of `Sampler`. + +We provide examples for each of these. We assume here that the choice of algorithm is independent of the RNG, so we use `AbstractRNG` in our signatures. + +```@docs +Random.Sampler +Random.SamplerType +Random.SamplerTrivial +Random.SamplerSimple +``` + +Decoupling pre-computation from actually generating the values is part of the API, and is also available to the user. As an example, assume that `rand(rng, 1:20)` has to be called repeatedly in a loop: the way to take advantage of this decoupling is as follows: + +```julia +rng = MersenneTwister() +sp = Random.Sampler(rng, 1:20) # or Random.Sampler(MersenneTwister, 1:20) +for x in X + n = rand(rng, sp) # similar to n = rand(rng, 1:20) + # use n +end +``` + +This is the mechanism that is also used in the standard library, e.g. by the default implementation of random array generation (like in `rand(1:20, 10)`). + +#### Generating values from a type + +Given a type `T`, it's currently assumed that if `rand(T)` is defined, an object of type `T` will be produced. `SamplerType` is the *default sampler for types*. In order to define random generation of values of type `T`, the `rand(rng::AbstractRNG, ::Random.SamplerType{T})` method should be defined, and should return values what `rand(rng, T)` is expected to return. + +Let's take the following example: we implement a `Die` type, with a variable number `n` of sides, numbered from `1` to `n`. We want `rand(Die)` to produce a `Die` with a random number of up to 20 sides (and at least 4): + +```jldoctest Die +struct Die + nsides::Int # number of sides +end + +Random.rand(rng::AbstractRNG, ::Random.SamplerType{Die}) = Die(rand(rng, 4:20)) + +# output + +``` + +Scalar and array methods for `Die` now work as expected: + +```jldoctest Die; setup = :(Random.seed!(1)) +julia> rand(Die) +Die(15) + +julia> rand(MersenneTwister(0), Die) +Die(11) + +julia> rand(Die, 3) +3-element Vector{Die}: + Die(18) + Die(5) + Die(4) + +julia> a = Vector{Die}(undef, 3); rand!(a) +3-element Vector{Die}: + Die(5) + Die(20) + Die(15) +``` + +#### A simple sampler without pre-computed data + +Here we define a sampler for a collection. If no pre-computed data is required, it can be implemented with a `SamplerTrivial` sampler, which is in fact the *default fallback for values*. + +In order to define random generation out of objects of type `S`, the following method should be defined: `rand(rng::AbstractRNG, sp::Random.SamplerTrivial{S})`. Here, `sp` simply wraps an object of type `S`, which can be accessed via `sp[]`. Continuing the `Die` example, we want now to define `rand(d::Die)` to produce an `Int` corresponding to one of `d`'s sides: + +```jldoctest Die; setup = :(Random.seed!(1)) +julia> Random.rand(rng::AbstractRNG, d::Random.SamplerTrivial{Die}) = rand(rng, 1:d[].nsides); + +julia> rand(Die(4)) +3 + +julia> rand(Die(4), 3) +3-element Vector{Any}: + 4 + 1 + 1 +``` + +Given a collection type `S`, it's currently assumed that if `rand(::S)` is defined, an object of type `eltype(S)` will be produced. In the last example, a `Vector{Any}` is produced; the reason is that `eltype(Die) == Any`. The remedy is to define `Base.eltype(::Type{Die}) = Int`. + +#### Generating values for an `AbstractFloat` type + +`AbstractFloat` types are special-cased, because by default random values are not produced in the whole type domain, but rather in `[0,1)`. The following method should be implemented for `T <: AbstractFloat`: `Random.rand(::AbstractRNG, ::Random.SamplerTrivial{Random.CloseOpen01{T}})` + +#### An optimized sampler with pre-computed data + +Consider a discrete distribution, where numbers `1:n` are drawn with given probabilities that sum to one. When many values are needed from this distribution, the fastest method is using an [alias table](https://en.wikipedia.org/wiki/Alias_method). We don't provide the algorithm for building such a table here, but suppose it is available in `make_alias_table(probabilities)` instead, and `draw_number(rng, alias_table)` can be used to draw a random number from it. + +Suppose that the distribution is described by +```julia +struct DiscreteDistribution{V <: AbstractVector} + probabilities::V +end +``` +and that we *always* want to build an alias table, regardless of the number of values needed (we learn how to customize this below). The methods +```julia +Random.eltype(::Type{<:DiscreteDistribution}) = Int + +function Random.Sampler(::Type{<:AbstractRNG}, distribution::DiscreteDistribution, ::Repetition) + SamplerSimple(disribution, make_alias_table(distribution.probabilities)) +end +``` +should be defined to return a sampler with pre-computed data, then +```julia +function rand(rng::AbstractRNG, sp::SamplerSimple{<:DiscreteDistribution}) + draw_number(rng, sp.data) +end +``` +will be used to draw the values. + +#### Custom sampler types + +The `SamplerSimple` type is sufficient for most use cases with precomputed data. However, in order to demonstrate how to use custom sampler types, here we implement something similar to `SamplerSimple`. + +Going back to our `Die` example: `rand(::Die)` uses random generation from a range, so there is an opportunity for this optimization. We call our custom sampler `SamplerDie`. + +```julia +import Random: Sampler, rand + +struct SamplerDie <: Sampler{Int} # generates values of type Int + die::Die + sp::Sampler{Int} # this is an abstract type, so this could be improved +end + +Sampler(RNG::Type{<:AbstractRNG}, die::Die, r::Random.Repetition) = + SamplerDie(die, Sampler(RNG, 1:die.nsides, r)) +# the `r` parameter will be explained later on + +rand(rng::AbstractRNG, sp::SamplerDie) = rand(rng, sp.sp) +``` + +It's now possible to get a sampler with `sp = Sampler(rng, die)`, and use `sp` instead of `die` in any `rand` call involving `rng`. In the simplistic example above, `die` doesn't need to be stored in `SamplerDie` but this is often the case in practice. + +Of course, this pattern is so frequent that the helper type used above, namely `Random.SamplerSimple`, is available, +saving us the definition of `SamplerDie`: we could have implemented our decoupling with: + +```julia +Sampler(RNG::Type{<:AbstractRNG}, die::Die, r::Random.Repetition) = + SamplerSimple(die, Sampler(RNG, 1:die.nsides, r)) + +rand(rng::AbstractRNG, sp::SamplerSimple{Die}) = rand(rng, sp.data) +``` + +Here, `sp.data` refers to the second parameter in the call to the `SamplerSimple` constructor +(in this case equal to `Sampler(rng, 1:die.nsides, r)`), while the `Die` object can be accessed +via `sp[]`. + +Like `SamplerDie`, any custom sampler must be a subtype of `Sampler{T}` where `T` is the type +of the generated values. Note that `SamplerSimple(x, data) isa Sampler{eltype(x)}`, +so this constrains what the first argument to `SamplerSimple` can be +(it's recommended to use `SamplerSimple` like in the `Die` example, where +`x` is simply forwarded while defining a `Sampler` method). +Similarly, `SamplerTrivial(x) isa Sampler{eltype(x)}`. + +Another helper type is currently available for other cases, `Random.SamplerTag`, but is +considered as internal API, and can break at any time without proper deprecations. + + +#### Using distinct algorithms for scalar or array generation + +In some cases, whether one wants to generate only a handful of values or a large number of values +will have an impact on the choice of algorithm. This is handled with the third parameter of the +`Sampler` constructor. Let's assume we defined two helper types for `Die`, say `SamplerDie1` +which should be used to generate only few random values, and `SamplerDieMany` for many values. +We can use those types as follows: + +```julia +Sampler(RNG::Type{<:AbstractRNG}, die::Die, ::Val{1}) = SamplerDie1(...) +Sampler(RNG::Type{<:AbstractRNG}, die::Die, ::Val{Inf}) = SamplerDieMany(...) +``` + +Of course, `rand` must also be defined on those types (i.e. `rand(::AbstractRNG, ::SamplerDie1)` and `rand(::AbstractRNG, ::SamplerDieMany)`). Note that, as usual, `SamplerTrivial` and `SamplerSimple` can be used if custom types are not necessary. + +Note: `Sampler(rng, x)` is simply a shorthand for `Sampler(rng, x, Val(Inf))`, and +`Random.Repetition` is an alias for `Union{Val{1}, Val{Inf}}`. + + +### Creating new generators + +The API is not clearly defined yet, but as a rule of thumb: +1) any `rand` method producing "basic" types (`isbitstype` integer and floating types in `Base`) + should be defined for this specific RNG, if they are needed; +2) other documented `rand` methods accepting an `AbstractRNG` should work out of the box, + (provided the methods from 1) what are relied on are implemented), + but can of course be specialized for this RNG if there is room for optimization; +3) `copy` for pseudo-RNGs should return an independent copy that generates the exact same random sequence as the + original from that point when called in the same way. When this is not feasible (e.g. hardware-based RNGs), + `copy` must not be implemented. + +Concerning 1), a `rand` method may happen to work automatically, but it's not officially +supported and may break without warnings in a subsequent release. + +To define a new `rand` method for an hypothetical `MyRNG` generator, and a value specification `s` +(e.g. `s == Int`, or `s == 1:10`) of type `S==typeof(s)` or `S==Type{s}` if `s` is a type, +the same two methods as we saw before must be defined: + +1) `Sampler(::Type{MyRNG}, ::S, ::Repetition)`, which returns an object of type say `SamplerS` +2) `rand(rng::MyRNG, sp::SamplerS)` + +It can happen that `Sampler(rng::AbstractRNG, ::S, ::Repetition)` is +already defined in the `Random` module. It would then be possible to +skip step 1) in practice (if one wants to specialize generation for +this particular RNG type), but the corresponding `SamplerS` type is +considered as internal detail, and may be changed without warning. + + +#### Specializing array generation + +In some cases, for a given RNG type, generating an array of random +values can be more efficient with a specialized method than by merely +using the decoupling technique explained before. This is for example +the case for `MersenneTwister`, which natively writes random values in +an array. + +To implement this specialization for `MyRNG` +and for a specification `s`, producing elements of type `S`, +the following method can be defined: +`rand!(rng::MyRNG, a::AbstractArray{S}, ::SamplerS)`, +where `SamplerS` is the type of the sampler returned by `Sampler(MyRNG, s, Val(Inf))`. +Instead of `AbstractArray`, it's possible to implement the functionality only for a subtype, e.g. `Array{S}`. +The non-mutating array method of `rand` will automatically call this specialization internally. + +```@meta +DocTestSetup = nothing +``` + +# Reproducibility + +By using an RNG parameter initialized with a given seed, you can reproduce the same pseudorandom +number sequence when running your program multiple times. However, a minor release of Julia (e.g. +1.3 to 1.4) *may change* the sequence of pseudorandom numbers generated from a specific seed, in +particular if `MersenneTwister` is used. (Even if the sequence produced by a low-level function like +[`rand`](@ref) does not change, the output of higher-level functions like [`randsubseq`](@ref) may +change due to algorithm updates.) Rationale: guaranteeing that pseudorandom streams never change +prohibits many algorithmic improvements. + +If you need to guarantee exact reproducibility of random data, it is advisable to simply *save the +data* (e.g. as a supplementary attachment in a scientific publication). (You can also, of course, +specify a particular Julia version and package manifest, especially if you require bit +reproducibility.) + +Software tests that rely on *specific* "random" data should also generally either save the data, +embed it into the test code, or use third-party packages like +[StableRNGs.jl](https://github.com/JuliaRandom/StableRNGs.jl). On the other hand, tests that should +pass for *most* random data (e.g. testing `A \ (A*x) ≈ x` for a random matrix `A = randn(n,n)`) can +use an RNG with a fixed seed to ensure that simply running the test many times does not encounter a +failure due to very improbable data (e.g. an extremely ill-conditioned matrix). + +The statistical *distribution* from which random samples are drawn *is* guaranteed to be the same +across any minor Julia releases. |
