{"id":15286816,"url":"https://github.com/juliarandom/randomextensions.jl","last_synced_at":"2025-07-21T12:35:20.125Z","repository":{"id":61799316,"uuid":"118408644","full_name":"JuliaRandom/RandomExtensions.jl","owner":"JuliaRandom","description":"Extensions to Julia's stdlib Random module","archived":false,"fork":false,"pushed_at":"2024-04-08T04:34:26.000Z","size":344,"stargazers_count":18,"open_issues_count":7,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-06-26T01:49:16.439Z","etag":null,"topics":["julia","julialang","rng"],"latest_commit_sha":null,"homepage":"","language":"Julia","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/JuliaRandom.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2018-01-22T05:01:40.000Z","updated_at":"2025-05-22T11:30:57.000Z","dependencies_parsed_at":"2025-04-13T03:57:20.356Z","dependency_job_id":"800496e2-24ef-405d-8774-f88fd1c7def2","html_url":"https://github.com/JuliaRandom/RandomExtensions.jl","commit_stats":{"total_commits":141,"total_committers":2,"mean_commits":70.5,"dds":0.007092198581560294,"last_synced_commit":"f5d9723da41cb85f8c8be6ae21cb220ea3101ccc"},"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/JuliaRandom/RandomExtensions.jl","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JuliaRandom%2FRandomExtensions.jl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JuliaRandom%2FRandomExtensions.jl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JuliaRandom%2FRandomExtensions.jl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JuliaRandom%2FRandomExtensions.jl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/JuliaRandom","download_url":"https://codeload.github.com/JuliaRandom/RandomExtensions.jl/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JuliaRandom%2FRandomExtensions.jl/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266303400,"owners_count":23908367,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-21T11:47:31.412Z","response_time":64,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["julia","julialang","rng"],"created_at":"2024-09-30T15:18:37.468Z","updated_at":"2025-07-21T12:35:20.104Z","avatar_url":"https://github.com/JuliaRandom.png","language":"Julia","funding_links":[],"categories":[],"sub_categories":[],"readme":"# RandomExtensions\n\n[![Tests Status](https://github.com/JuliaRandom/RandomExtensions.jl/workflows/CI/badge.svg)](https://github.com/JuliaRandom/RandomExtensions.jl/actions?query=workflow%3ACI)\n[![codecov](https://codecov.io/gh/JuliaRandom/RandomExtensions.jl/graph/badge.svg?token=3crLCcitZR)](https://codecov.io/gh/JuliaRandom/RandomExtensions.jl)\n[![](https://img.shields.io/badge/docs-stable-blue.svg)](https://JuliaRandom.github.io/RandomExtensions.jl/stable)\n[![](https://img.shields.io/badge/docs-dev-blue.svg)](https://JuliaRandom.github.io/RandomExtensions.jl/dev)\n\nThis package explores a possible extension of `rand`-related\nfunctionalities (from the `Random` module); the code is initially\ntaken from \u003chttps://github.com/JuliaLang/julia/pull/24912\u003e.\nNote that type piracy is committed!\nWhile hopefully useful, this package is still experimental, and\nhence unstable. User feedback, and design or implementation contributions are welcome.\n\nThis does essentially four things:\n\n1) define distribution objects, to give first-class status to features\n   provided by `Random`; for example `rand(Normal(), 3)` is equivalent\n   to `randn(3)`; other available distributions: `Exponential`,\n   `CloseOpen` (for generation of floats in a close-open range) and friends,\n   `Uniform` (which can wrap an implicit uniform distribution);\n\n2) define `make` methods, which can combine distributions for objects made of multiple scalars, like\n   `Pair`, `Tuple`, or `Complex`, or describe how to generate more complex objects, like containers;\n\n3) extend the `rand([rng], [S], dims)` API to allow the generation of other containers than arrays\n   (like `Set`, `Dict`, `SparseArray`, `String`, `BitArray`);\n\n4) define a `Rand` iterator, which produces lazily random values.\n\n\nPoint 1) defines a `Distribution` type which is incompatible with the\n\"Distributions.jl\" package. Input on how to unify the two approaches is\nwelcome.\n\nPoint 2) is really the core of this package. `make` provides a vocabulary to define the generation\nof \"scalars\" which require more than one argument to be described, e.g. pairs from `1:3` to `Int`\n(`rand(make(Pair, 1:3, Int))`) or regular containers (e.g. `make(Array, 2, 3)`). The point of\ncalling `make` rather than putting all the arguments in `rand` directly is simplicity and\ncomposability: the `make` call always occurs as the second argument to `rand` (or first if the RNG\nis omitted). For example, `rand(make(Array, 2, 3), 3)` creates an array of matrices.\nOf course, `make` is not necessary, in that the same can be achieved with an ad hoc `struct`,\nwhich in some cases is clearer (e.g. `Normal(m, s)` rather than something like `make(Float64, Val(:Normal), m, s)`).\n\nAs an experimental feature, the following alternative API is available:\n- `rand(T =\u003e x)` is equivalent to `rand(make(T, x))`\n- `rand(T =\u003e (x, y, ...))` is equivalent to `rand(make(T, x, y, ...))`\n\nThis is for convenience only (it may be more readable), but may be less efficient due to the\nfact that the type of a pair containing a type doesn't know this exact type (e.g. `Pair =\u003e Int`\nhas type `Pair{UnionAll,DataType}`), so `rand` can't infer the type of the generated value.\nThanks to inlining, the inferred types can however be sufficiently tight in some cases\n(e.g. `rand(Complex =\u003e Int, 3)` is of type `Vector{Complex{Int64}}` instead of `Vector{Any}`).\n\nPoint 3) allows something like `rand(1:30, Set, 10)` to produce a `Set` of length `10` with values\nfrom `1:30`. The idea is that `rand([rng], [S], Cont, etc...)` should always be equivalent to\n`rand([rng], make(Cont, [S], etc...))`. This design goes somewhat against the trend in `Base` to create\ncontainers using their constructors -- which by the way may be achieved via the `Rand` iterator from\npoint 4). Still, I like the terse approach here, as it simply generalizes to other containers the\n_current_ `rand` API creating arrays. See the issue linked above for a discussion on these topics.\n\nFor convenience, the following names from `Random` are re-exported\nin this package: `rand!`, `AbstractRNG`, `MersenneTwister`,\n`RandomDevice` (`rand` is in `Base`). Functions like `randn!` or\n`randstring` are considered to be obsoleted by this package so are not\nre-exported. It is still necessary to import `Random` separately in order\nto use functions which don't extend the `rand` API, namely\n`randsubseq`, `shuffle`, `randperm`, `randcycle`, and their mutating\nvariants.\n\n\nThere is not much documentation for now: `rand`'s docstring is updated,\nand here are some examples:\n\n```julia\njulia\u003e rand(CloseOpen(Float64)) # equivalent to rand(Float64)\n0.7678877639669386\n\njulia\u003e rand(CloseClose(1.0f0, 10)) # generation in [1.0f0, 10.0f0]\n6.62467f0\n\njulia\u003e rand(OpenOpen(2.0^52, 2.0^52+1)) == 2.0^52 # exactness not guaranteed for \"unreasonable\" values!\ntrue\n\njulia\u003e rand(Normal(0.0, 10.0)) # explicit μ and σ parameters\n-8.473790458128912\n\njulia\u003e rand(Uniform(1:3)) # equivalent to rand(1:3)\n2\n\njulia\u003e rand(make(Pair, 1:10, Normal())) # random Pair, where both members have distinct distributions\n5 =\u003e 0.674375\n\njulia\u003e rand(make(Pair{Number,Any}, 1:10, Normal())) # specify the Pair type\nPair{Number, Any}(1, -0.131617)\n\njulia\u003e rand(Pair{Float64,Int}) # equivalent to rand(make(Pair, Float64, Int))\n0.321676 =\u003e -4583276276690463733\n\njulia\u003e rand(make(Tuple, 1:10, UInt8, OpenClose()))\n(9, 0x6b, 0.34900083923775505)\n\njulia\u003e rand(Tuple{Float64,Int}) # equivalent to rand(make(Tuple, Float64, Int))\n(0.9830769470405203, -6048436354564488035)\n\njulia\u003e rand(make(NTuple{3}, 1:10)) # produces a 3-tuple with values from 1:10\n(5, 9, 6)\n\njulia\u003e rand(make(NTuple{N,UInt8} where N, 1:3, 5))\n(0x02, 0x03, 0x02, 0x03, 0x02)\n\njulia\u003e rand(make(NTuple{3}, make(Pair, 1:9, Bool))) # make calls can be nested\n(2 =\u003e false, 8 =\u003e true, 7 =\u003e false)\n\njulia\u003e rand(make(Complex, Normal())) # each coordinate is drawn from the normal distribution\n1.5112317924121632 + 0.723463453534426im\n\njulia\u003e rand(make(Complex, Normal(), 1:10)) # distinct distributions\n1.096731587266045 + 8.0im\n\njulia\u003e rand(Normal(ComplexF64)) # equivalent to randn(ComplexF64)\n0.9322376894079347 + 0.2812214248483498im\n\njulia\u003e rand(Set, 3)\nSet{Float64} with 3 elements:\n  0.0675168818514279\n  0.31058418699493895\n  0.15029104540378424\n\njulia\u003e rand!(ans, Exponential())\nSet{Float64} with 3 elements:\n  1.082312697650858\n  1.2984094155972015\n  0.016146678329819485\n\njulia\u003e rand(1:9, Set, 3) # if you try `rand(1:3, Set, 9)`, it will take a while ;-)\nSet{Int64} with 3 elements:\n  4\n  7\n  1\n\njulia\u003e rand(Dict{String,Int8}, 2)\nDict{String, Int8} with 2 entries:\n  \"vxybIbae\" =\u003e 42\n  \"bO2fTwuq\" =\u003e -13\n\njulia\u003e rand(make(Pair, 1:9, Normal()), Dict, 3)\nDict{Int64, Float64} with 3 entries:\n  9 =\u003e 0.916406\n  3 =\u003e -2.44958\n  8 =\u003e -0.703348\n\njulia\u003e using SparseArrays\n\njulia\u003e rand(SparseVector, 0.3, 9) # equivalent to sprand(9, 0.3)\n9-element SparseVector{Float64, Int64} with 3 stored entries:\n  [1]  =  0.173858\n  [6]  =  0.568631\n  [8]  =  0.297207\n\njulia\u003e rand(Normal(), SparseMatrixCSC, 0.3, 2, 3) # equivalent to sprandn(2, 3, 0.3)\n2×3 SparseMatrixCSC{Float64, Int64} with 2 stored entries:\n  ⋅        -1.5617   ⋅\n 0.572305    ⋅       ⋅\n\n# like for Array, sparse arrays enjoy to be special cased: `SparseVector` or `SparseMatrixCSC`\n# can be omitted in the `rand` call (not in the `make` call):\n\njulia\u003e rand(make(SparseVector, 1:9, 0.3, 2), 0.1, 4, 3) # possible, bug ugly output when non-empty :-/\n4×3 SparseMatrixCSC{SparseVector{Int64,Int64},Int64} with 0 stored entries\n\njulia\u003e rand(String, 4) # equivalent to randstring(4)\n\"5o75\"\n\njulia\u003e rand(\"123\", String, 4) # like above, String creation with the \"container\" syntax ...\n\"2131\"\n\njulia\u003e rand(make(String, 3, \"123\")) # ... which is as always equivalent to a call to make\n\"211\"\n\njulia\u003e rand(String, Set, 3) # String considered as a scalar\nSet{String} with 3 elements:\n  \"jDbjXu9b\"\n  \"0Lo75VKo\"\n  \"webpNhfY\"\n\njulia\u003e rand(BitArray, 3) # equivalent to, but unfortunately more verbose than, bitrand(3)\n3-element BitVector:\n 1\n 1\n 0\n\njulia\u003e rand(Bernoulli(0.2), BitVector, 10) # using the Bernoulli distribution\n10-element BitVector:\n 0\n 1\n 0\n 1\n 0\n 0\n 0\n 0\n 0\n 1\n\njulia\u003e rand(1:3, NTuple{3}) # NTuple{3} considered as a container, equivalent to rand(make(NTuple{3}, 1:3))\n(3, 3, 1)\n\njulia\u003e rand(1:3, Tuple{Int,UInt8, BigFloat}) # works also with more general tuple types ...\n(3, 0x02, 2.0)\n\njulia\u003e rand(1:3, NamedTuple{(:a, :b)}) # ... and with named tuples\n(a = 3, b = 2)\n\njulia\u003e RandomExtensions.random_staticarrays() # poor man's conditional modules!\n# ugly warning\n\njulia\u003e rand(make(MVector{2,AbstractString}, String), SMatrix{3, 2})\n3×2 SArray{Tuple{3,2},MArray{Tuple{2},AbstractString,1,2},2,6} with indices SOneTo(3)×SOneTo(2):\n [\"SzPKXHFk\", \"1eFXaUiM\"]  [\"RJnHwhb7\", \"jqfLcY8a\"]\n [\"FMTKcBY8\", \"eoYtNntD\"]  [\"FzdD530L\", \"ux6sWGMU\"]\n [\"fFJuUtJQ\", \"H2mAQrIV\"]  [\"pt0OYFJw\", \"O0fCfjjR\"]\n\njulia\u003e Set(Iterators.take(Rand(RandomDevice(), 1:10), 3)) # RNG defaults to Random.default_rng()\nSet{Int64} with 2 elements: # note that the set can end up with less than 3 elements if `Rand` generates duplicates\n  5\n  9\n\njulia\u003e collect(Iterators.take(Uniform(1:10), 3)) # distributions can be iterated over, using Random.default_rng() implicitly\n3-element Vector{Int64}:\n 9\n 6\n 8\n\njulia\u003e rand(Complex =\u003e Int) # equivalent to rand(make(Complex, Int)) (experimental)\n4610038282330316390 + 4899086469899572461im\n\njulia\u003e rand(Pair =\u003e (String, Int8)) # equivalent to rand(make(Pair, String, Int8)) (experimental)\n\"ODNXIePK\" =\u003e 4\n```\n\nIn some cases, the `Rand` iterator can provide efficiency gains compared to\nrepeated calls to `rand`, as it uses the same mechanism as array generation.\nFor example, given `a = zeros(1000)` and `s = BitSet(1:1000)`,\n`a .+ Rand(s).()` is three times faster than `a .+ rand.(Ref(s))`.\n\nNote: as seen in the examples above, `String` can be considered as a scalar or as a container (in the `rand` API).\nIn a call like `rand(String)`, both APIs coincide, but in `rand(String, 3)`, should we construct a `String` of\nlength `3` (container API), or an array of strings of default length `8` ? Currently, the package chooses\nthe first interpretation, partly because it was the first implemented, and also because it may actually be the one\nmost useful (and offers the tersest API to compete with `randstring`).\nBut as this package is still unstable, this choice may be revisited in the future.\nNote that it's easy to get the result of the second interpretation via either `rand(make(String), 3)`,\n`rand(String, (3,))` or `rand(String, Vector, 3)`.\n\nHow to extend: the `make` function is meant to be extensible, and there are some helper functions\nwhich make it easy, but this is still experimental. By default, `make(T, args...)` will\ncreate a `Make{maketype(T, args...)}` object, say `m`, which contain `args...` as fields. For type\nstable code, the `rand` machinery likes to know the exact type of the object which will be generated by\n`rand(m)`, and `maketype(T, args...)` is supposed to return that type. For example,\n`maketype(Pair, 1:3, UInt) == Pair{Int,UInt}`.\nThen just define `rand` for `m` like documented in the `Random` module, e.g.\n`rand(rng::AbstractRNG, sp::SamplerTrivial{\u003c:Make{P}}) where {P\u003c:Pair} = P(rand(sp[][1]), rand(sp[][2]))`.\nFor convenience, `maketype(T, ...)` defaults to `T`, which means that for simple cases, only the\n`rand` function has to be defined. But in cases like for `Pair` above, if `maketype` is not\ndefined, the generated type will be assumed to be `Pair`, which is not a concrete type\n(and hence suboptimal).\n\nThis package started out of frustration with the limitations of the `Random` module. Besides\ngenerating simple scalars and arrays, very little is supported out of the box. For example,\ngenerating a random `Dict` is too complex. Moreover, there are too many functions for my taste:\n`rand`, `randn`, `randexp`, `sprand` (with its exotic `rfn` parameter), `sprandn`, ~~`sprandexp`~~,\n`randstring`, `bitrand`, and mutating counterparts (but I believe `randn` will never go away, as\nit's so terse). I hope that this package can serve as a starting point towards improving `Random`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjuliarandom%2Frandomextensions.jl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjuliarandom%2Frandomextensions.jl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjuliarandom%2Frandomextensions.jl/lists"}