Skip to content

Instantly share code, notes, and snippets.

@demotomohiro
Created August 30, 2021 09:25
Show Gist options
  • Save demotomohiro/9516fe686da376bbce8a4470e52752ab to your computer and use it in GitHub Desktop.
Save demotomohiro/9516fe686da376bbce8a4470e52752ab to your computer and use it in GitHub Desktop.
## Visualize how Pseudo-random number generators created with jump function and with random seed use PRNG state space.
## Visualize how Pseudo-random number generators created
## with jump function and with random seed use PRNG state space.
## Install pixie with `nimble install pixie`
import std/[strformat, random]
import pixie
const
numRows = 32
numColumns = 64
numStates = numRows * numColumns
numRandGen = 4
numRand = numStates div numRandGen
stateWh = vec2(8, 8)
stateMargin = vec2(4, 4)
vertMargin = (stateWh.y + stateMargin.y) * (numRows + 2)
initPos = stateWh
let image = newImage(initPos.x.int + (stateWh.x + stateMargin.x).int * numColumns, vertMargin.int * 2)
image.fill(rgba(255, 255, 255, 255))
let ctx = newContext(image)
ctx.fillStyle = rgba(64, 64, 255, 255)
ctx.strokeStyle.color = rgba(128, 0, 0, 255)
var pos = initPos
for i in 0 ..< numRows:
for j in 0 ..< numColumns:
ctx.fillRect(rect(pos, stateWh))
ctx.fillRect(rect(pos + vec2(0, vertMargin), stateWh))
pos.x += stateWh.x + stateMargin.x
pos.x = initPos.x
pos.y += (stateWh.y + stateMargin.y)
proc drawPRNG(stateId: int; isBottom = false) =
proc drawPRNGImpl(ip: IVec2; isBottom: bool) {.inline.} =
let
fp = vec2(ip)
p = fp * (stateWh + stateMargin) + vec2(0, if isBottom: vertMargin else: 0)
rct = rect(initPos + p - (stateMargin * 0.5), (stateWh + stateMargin) * vec2(numRandGen, 1))
ctx.fillRoundedRect(rct, stateMargin.x)
ctx.strokeRoundedRect(rct, stateMargin.x)
let ip = ivec2(int32(stateId mod numColumns), int32(stateId div numColumns))
drawPRNGImpl(ip, isBottom)
if ip.x + numRandGen > numColumns:
drawPRNGImpl(ivec2(((ip.x + numRandGen) mod numColumns) - numRandGen, ((ip.y + 1) mod numRows)), isBottom)
ctx.fillStyle = rgba(255, 0, 0, 64)
pos = initPos
randomize()
for i in 0 ..< (numRand div 4):
drawPRNG(i * numRandGen)
let r = rand(numStates - 1)
drawPRNG(r.int, true)
image.writeFile(&"prng{i:03}.png")
@demotomohiro
Copy link
Author

prng

Each blue box represents a pseudo random number generater(PRNG) state.
Red rounded box represents PRNG that generates 4 random numbers by updating state 4 times.
Upper block represents how PRNGs created with jump function uses PRNG states.
Lower block represents how PRNGs created with random seed uses PRNG states.
In lower block, several PRNGs uses same states.
That means a part of random number output sequence from one PRNG matchs a part of random number output sequence from other PRNG.

This animation gif was created from output png files with following command:

ffmpeg -f image2 -framerate 2 -i prng%03d.png prng.gif

It seems uploading mp4 or mov files to gist comment doesn't work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment