{"id":16499263,"url":"https://github.com/mschauer/goldensequences.jl","last_synced_at":"2025-10-18T04:52:22.710Z","repository":{"id":38196346,"uuid":"213610763","full_name":"mschauer/GoldenSequences.jl","owner":"mschauer","description":"Generalized golden sequences, a form of low discrepancy sequence or quasi random numbers","archived":false,"fork":false,"pushed_at":"2022-06-14T08:55:03.000Z","size":1197,"stargazers_count":18,"open_issues_count":3,"forks_count":3,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-10-19T17:47:52.287Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Julia","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mschauer.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-10-08T10:13:55.000Z","updated_at":"2024-05-26T13:36:59.000Z","dependencies_parsed_at":"2022-08-19T10:00:27.173Z","dependency_job_id":null,"html_url":"https://github.com/mschauer/GoldenSequences.jl","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mschauer%2FGoldenSequences.jl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mschauer%2FGoldenSequences.jl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mschauer%2FGoldenSequences.jl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mschauer%2FGoldenSequences.jl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mschauer","download_url":"https://codeload.github.com/mschauer/GoldenSequences.jl/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241404416,"owners_count":19957655,"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","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":[],"created_at":"2024-10-11T14:51:45.497Z","updated_at":"2025-10-18T04:52:17.675Z","avatar_url":"https://github.com/mschauer.png","language":"Julia","funding_links":[],"categories":[],"sub_categories":[],"readme":"# GoldenSequences.jl\nGeneralized golden sequences, a form of low discrepancy sequence or quasi random numbers\nSee [Martin Roberts: The Unreasonable Effectiveness\nof Quasirandom Sequences](http://extremelearning.com.au/unreasonable-effectiveness-of-quasirandom-sequences/) for background.\n\nThe `d`-dimensional sequence follows\n```\nx[i] = (x[i-1] .+ z) .% true, x[0] = x0\n```\nwhere\n```\nz = [ϕ[k]^(-i) for i in 1:d]\n```\nand `ϕ[k]` solves `ϕ[k]^(d+1) = ϕ[k] + 1` (with `ϕ[1]` the golden mean.)\n\nGolden sequence\n===============\n```\njulia\u003e GoldenSequence(0.0)[1]\n0.6180339887498949\n```\n\nShifted golden sequence starting in 0.5\n```\njulia\u003e  GoldenSequence(0.5)[0]\n0.5\n\njulia\u003e  GoldenSequence(0.5)[1]\n0.1180339887498949\n```\n\n`GoldenSequence` returns an infinite iterator:\n```\njulia\u003e collect(take(GoldenSequence(0.0), 10))\n10-element Array{Float64,1}:\n 0.0                \n 0.6180339887498949\n 0.2360679774997898\n 0.8541019662496847\n 0.4721359549995796\n 0.09016994374947451\n 0.7082039324993694\n 0.3262379212492643\n 0.9442719099991592\n 0.5623058987490541\n```\n\nRandom colors: Low discrepancy series are good choice for (quasi-) random colors\n```\nusing Colors\nn = 20\nc = map(x-\u003eRGB(x...), (take(GoldenSequence(3), n))) # perfect for random colors\n```\n![Colors](https://raw.githubusercontent.com/mschauer/GoldenSequences.jl/master/randomcolors.png)\n\n2D golden sequence\n==================\n\n```\njulia\u003e  GoldenSequence(2)[1]\n(0.7548776662466927, 0.5698402909980532)\n```\n\nAs low discrepancy series these number are well distributed (left), better than random numbers (right):\n\n```julia\nusing Makie\nn = 155\nx = collect(Iterators.take(GoldenSequence(2), n))\np1 = scatter(x, markersize=0.02)\ny = [(rand(),rand()) for i in 1:n]\np2 = scatter(y, markersize=0.02, color=:red)\nvbox(p1, p2)\n```\n\n![Quasi-random vs. random](https://raw.githubusercontent.com/mschauer/GoldenSequences.jl/master/quasivsrandom.png)\n\nCartesian Golden Sequence\n=========================\n\nWith a bit of effort, one can use Golden Sequences to generate spacefilling quasirandom sequences of cartesian indices.\nFor example `GoldenCartesianSequence((m[1], m[2]))` will create a 2D Cartesian sequence corresponding to (approximate) samples of the Golden sequence in `1:m[1]` x `1:m[2]`. \n\nFor that, `GoldenCartesianSequence((m[1], ..., m[d]))` will create full period linear congruential generators (LCG) `x[i+1] = (x[i] + c[k]) % m[k]` approximating `phi[d]^[-k]` by `c[k]/m[k]` such that `c[k]` and `m[k]` are coprime.\n\nIf `m[1], ..., m[d]` are coprime themselves, these `LCG` will have together period `prod(m)` and the sequence will be space filling, that is `sort(collect(take(GoldenCartesianSequence(m), prod(m)))) == CartesianIndices(m)[:]`.\n\nThis means that if `m[k]` is the denominator of a good rational approximation `c[k]//m[k] ≈ ϕ[d]^(-k)`, then the indices will be well distributed even for large `i`. \n\nFor example if `m = (2819, 3508)`:\n\n![Quasi-random cartesian indices](https://raw.githubusercontent.com/mschauer/GoldenSequences.jl/master/cartesian2.png)\n\nThe image shows the fraction of the first 0.00005 (red) and the first 0.002 indices (black) in the `GoldenCartesianSequence((2819, 3508))`.\n\nIn short, good `m` are coprime denominators of fractions given by the function `rationalize`\n\n```julia\nd = 2\nm = @. denominator(rationalize(GoldenSequences.phis[d]^(-(1:d)), tol=0.0000001))\n```\n\n```\njulia\u003e m\n2-element Array{Int64,1}:\n 2819\n 3508\n\njulia\u003e gcd(m[1], m[2])\n1\n```\n\nThere are some connections here to Knuth's multiplicative hashing method\n```julia\nhash(i) = mod(i*2654435769, 2^32)\n```\nwhere `2654435769` is approximately `2^32*ϕ`.\n\nInterface\n=========\n\n```\nGoldenSequence(n::Int) # Float64 n-dimensional golden sequence\nGoldenSequence(x0::Number) # 1-d golden sequence shifted by `x0`\nGoldenSequence(x0) # length(x)-d golden sequence shifted/starting in 'x0'\n```\n\n\nA flower\n========\nFlower petals grow in spots not covering older petals, the new spot is at an angle given by the golden sequence.\n\n```\nusing Colors\nusing Makie\nn = 20\nc = map(x-\u003eRGB(x...), (take(GoldenSequence(3), n))) # perfect for random colors\nx = collect(take(GoldenSequence(0.0), n))\npetals = [(i*cos(2pi*x), i*sin(2pi*x)) for (i,x) in  enumerate(x)]\nscatter(reverse(petals), color=c, markersize=10*(n:-1:1))\n```\n\n![Flower petals](https://raw.githubusercontent.com/mschauer/GoldenSequences.jl/master/flower.png)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmschauer%2Fgoldensequences.jl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmschauer%2Fgoldensequences.jl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmschauer%2Fgoldensequences.jl/lists"}