Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[unimportant] Using sample with RGB #434

Closed
anandijain opened this issue Aug 2, 2020 · 5 comments
Closed

[unimportant] Using sample with RGB #434

anandijain opened this issue Aug 2, 2020 · 5 comments

Comments

@anandijain
Copy link

I am interested in sampling random colors without replacement.

Currently using 24bit RGB, and I'm doing this horrible triple loop to generate all colors and then using StatsBase.sample(;replace=false).

Does anyone have a solution to this?

I'd like to not use rand because even though its unlikely that two colors are the same, I don't want to risk it.

@kimikage
Copy link
Collaborator

kimikage commented Aug 3, 2020

What property do you want for pseudo-random numbers (colors)? For example, does the property include cryptographic security?

Shuffling is essentially a bijective map. If you have less requirements, you can easily create such bijective maps with bitwise-shuffling or xor. (cf. LFSR)

UInt32 numbers (in [0, 2^24-1]) can be reinterpreted to RGB24.

Edit:
You can also use LCGs with the period of 2^24, e.g.

f(x) = (UInt32(9012345) * x + UInt32(1234567)) & 0xFFFFFF # The coefficients are just an example. DO NOT use them.

Of course, the LCGs have disadvantages.

In any case, since UInt32 and RGB24/ARGB32 can be reinterpreted with each other, I would like to add the specific examples to the documentation rather than add new APIs in Colors.jl. BTW, I'm not satisfied with the current rand implementation in ColorTypes.jl, but I don't have enough motivation to make a breaking change (cf. JuliaGraphics/ColorTypes.jl#150).

@kimikage
Copy link
Collaborator

kimikage commented Aug 3, 2020

An example with Xorshift.

using Random

mutable struct Xorshift24 <: AbstractRNG
    prev::UInt32
    Xorshift24(seed::Integer) = new(seed % 0xFFFFFF + 1) 
end

function Random.rand(rng::Xorshift24, ::Random.SamplerType{UInt32}) # The parameters are just an example.  I don't know the randomness.
    x = rng.prev
    x ⊻= x >> 13
    x ⊻= (x << 19) >> 8
    x ⊻= x >> 2
    rng.prev = x
end
julia> r = rand(Xorshift24(0), UInt32, 2^24 - 1);

julia> length(unique(r))
16777215

julia> reinterpret(RGB24, rand(Xorshift24(1234), UInt32, 2, 2))
2×2 reinterpret(RGB24, ::Array{UInt32,2}):
 RGB24(0.184,0.231,0.906)  RGB24(0.22,0.82,0.58)
 RGB24(0.773,0.22,0.224)   RGB24(0.58,0.816,0.275)

Of course, (if there is no risk of the type piracy,) you can overload the rand for RGB24

function Random.rand(rng::Xorshift24, ::Random.SamplerType{RGB24})
    reinterpret(RGB24, rand(rng, UInt32))
end

@anandijain
Copy link
Author

anandijain commented Aug 3, 2020

Thank you for the great answer!!

I would be using sample just to make videos/art, not anything critical, so cryptographic security is overkill (although would be pretty cool).

I don't have a ton of experience with random number generators, but it looks like your example shows no collisions when I try it, which is the main property I was looking for, and it is much, much faster.

Edit
Should I close issue?

@kimikage
Copy link
Collaborator

kimikage commented Aug 4, 2020

I'm glad I could help you.

When you use the periodic random number sequences for video/art, please note that you may easily consume all 2^24 colors. The seed allows you to change the starting point, but essentially it repeats the same pattern.

Also note that the black (0, 0, 0) does not appear in the sequences with period of 2^N-1, like the Xorshift shown above. This can be resolved by replacing the "absentee" with another color using xor, or by inserting a black in the sequence using if-else:

x = rng.prev === 0xC0FFEE ? 0x000000 : rng.prev === 0x000000 ? 0xC0FFEE : rng.prev

Should I close issue?

I've added this "documentation" issue to the ToDo list in #398, so you can close this issue. You can also continue this discussion, because not adding new APIs is a matter of my personal preference. 😄

@kimikage
Copy link
Collaborator

We will probably change the implementation of rand in ColorTypes.jl in the near future. I'll try to update the documentation based on that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants