Skip to content

Instantly share code, notes, and snippets.

@Vindaar
Last active December 4, 2021 19:09
Show Gist options
  • Save Vindaar/1a16594fe6f2830faa17d6f6d770de4f to your computer and use it in GitHub Desktop.
Save Vindaar/1a16594fe6f2830faa17d6f6d770de4f to your computer and use it in GitHub Desktop.
Tossing with ggplotnim
# Note by @Vindaar: this is just a modified version from here:
# https://forum.nim-lang.org/t/7102
# that uses ggplotnim
# Generate random pairs of non-equal numbers and test the routine's distribution
# License: MIT
# Usage:
# ./randpairs [1-6;c]
import os, random, hashes, tables, strutils, stats, ggplotnim
const MAX = 10
const RUNS = 100000
func hash(a: (int,int)): Hash =
result = a[0]*MAX + a[1]
#ElegantBeef's coin toss
proc rand_pair_a(max: int): (int, int) =
let n = rand(max)
result = if rand(1).bool and max != n or n == 0:
(n, rand((n + 1)..max))
else:
(n, rand(0..<n))
#nikki's max substitution
proc rand_pair_b(max: int): (int, int) =
result[0] = rand(max)
result[1] = rand(max-1)
if result[1] == result[0]:
result[1] = max
# dumb looping
proc rand_pair_c(max: int): (int, int) =
var a,b: int
while a == b:
a = rand(max)
b = rand(max)
result = (a,b)
# less dumb looping
proc rand_pair_d(max: int): (int, int) =
let a = rand(max)
var b = rand(max)
while a == b:
b = rand(max)
result = (a,b)
# control
proc rand_pair_control(max: int): (int, int) =
result = (rand(max),rand(max))
#disruptek
proc rand_pair_e(max: int): (int, int) =
let
a = rand(max)
b = ((a + rand(max-1)) mod max)
result = (a, b)
#nikki's II:
proc rand_pair_f(max: int): (int, int) =
# | 1: (0, 2) | 3: (1, 2) | |
# | 0: (0, 1) | | 5: (2, 1) |
# | | 2: (1, 0) | 4: (2, 0) |
# above is an example for n = 3 i.e., 0..<3
# in the above the format is i: (x, y)
# i is from 0..<6 (where 6 = 3 * (3 - 1))
#
# we generate i randomly in that range, then map
# to the corresponding (x, y)
let n = max+1 #converted to inclusive range
let i = rand(0..<(n * (n - 1)))
let x = i div (n - 1)
var y = i mod (n - 1)
if y >= x:
y += 1
result = (x, y)
proc genDf(fn: proc(max: int): (int, int),
fnName: string): DataFrame =
randomize()
var count = initCountTable[(int, int)](RUNS)
for i in 0..<MAX: # we need zeroes in the output for GnuPlot
for j in 0..<MAX:
count[(i,j)] = 1
for i in 0..<RUNS:
let pair = fn(MAX-1)
count.inc(pair)
var stat: RunningStat
func fToStr(f:float):string =
formatFloat(f,ffDecimal,1)
var
x: seq[int]
y: seq[int]
z: seq[int]
for p in count.pairs:
let c = p[1]-1
if c > 0:
stat.push(c)
x.add p[0][0]
y.add p[0][1]
z.add c
result = seqsToDf(x, y, z)
let cas = fnName & " min=" & fToStr(stat.min) & " max=" & fToStr(stat.max) &
" st.deviation=" & fToStr(stat.standardDeviation())
result["Case"] = constantColumn(cas, result.len)
when isMainModule:
let fns = [(rand_pair_a, "a) ElegantBeef's coin toss"),
(rand_pair_b, "b) nikki's max substitution"),
(rand_pair_c, "c) dump looping"),
(rand_pair_d, "d) less dumb looping"),
(rand_pair_e, "e) disruptek"),
(rand_pair_f, "f) nikki's II"),
(rand_pair_control, "g) control")]
var df: DataFrame
for fn in fns:
df.add genDf(fn[0], fn[1])
ggplot(df, aes("x", "y", fill = "z")) +
facet_wrap("Case") +
geom_tile() +
geom_text(aes(text = "z")) +
scale_fill_continuous(scale = (low: 900.0, high: 1100.0)) +
# reverse to get 0 at bottom for y scale + is a discrete scale
scale_y_reverse(dcKind = dcDiscrete) +
theme_opaque() +
ggsave("/tmp/heatmap.png", width = 1600, height = 1200)
@Vindaar
Copy link
Author

Vindaar commented Nov 16, 2020

heatmap

@Vindaar
Copy link
Author

Vindaar commented Nov 17, 2020

And in small to embed

heatmap_small

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