Last active
December 4, 2021 19:09
-
-
Save Vindaar/1a16594fe6f2830faa17d6f6d770de4f to your computer and use it in GitHub Desktop.
Tossing with ggplotnim
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment