random.bend
bend-kit-random@0.1.0.1 · 168 lines · 26 definitions
1
2import Base
3
4
5
6
7
8
9type Rng is Data:
10 Rng{a: U32, b: U32, c: U32, d: U32}
11
12def rotl(+x: U32, l: Nat, r: Nat) -> U32:
13 ((x << l) .|. (x >> r) : U32)
14
15
16def mix(+z: U32) -> U32:
17 +y = ((z .^. (z >> 16n)) * 569420461 : U32)
18 +w = ((y .^. (y >> 15n)) * 1935289751 : U32)
19 (w .^. (w >> 15n) : U32)
20
21
22def seed(+s: U32) -> Rng:
23 Rng{mix((s + 2654435769 : U32)), mix((s + 1013904242 : U32)),
24 mix((s + 3668340011 : U32)), mix((s + 2027808484 : U32))}
25
26def from_state.if(zero: Bool, a: U32, b: U32, c: U32, d: U32) -> Rng:
27 match zero:
28 case True{}:
29 seed(0)
30 case False{}:
31 Rng{a, b, c, d}
32
33
34def from_state(+a: U32, +b: U32, +c: U32, +d: U32) -> Rng:
35 from_state.if(U32.is_zero((a .|. b .|. c .|. d : U32)), a, b, c, d)
36
37
38def next(r: Rng) -> U32 & Rng:
39 match r:
40 case Rng{+a, +b, +c, +d}:
41 +c1 = (c .^. a : U32)
42 +d1 = (d .^. b : U32)
43 ((rotl((b * 5 : U32), 7n, 25n) * 9 : U32),
44 Rng{(a .^. d1 : U32), (b .^. c1 : U32), (c1 .^. (b << 9n) : U32),
45 rotl(d1, 11n, 21n)})
46
47def Bool.case(-A: Type, b: Bool, t: Unit -> A, f: Unit -> A) -> A:
48 match b:
49 case True{}:
50 t(Unit{})
51 case False{}:
52 f(Unit{})
53
54
55def below.go(fuel: Nat, +n: U32, +t: U32, xr: U32 & Rng) -> U32 & Rng:
56 match fuel:
57 case 0n:
58 (x, r) = xr
59 ((x % n : U32), r)
60 case 1n+p:
61 (+x, +r) = xr
62 Bool.case(U32 & Rng, U32.is_ge(x, t),
63 u => ((x % n : U32), r),
64 u => below.go(p, n, t, next(r)))
65
66def below.if(small: Bool, +n: U32, r: Rng) -> U32 & Rng:
67 match small:
68 case True{}:
69 (0, r)
70 case False{}:
71 below.go(64n, n, ((0 - n : U32) % n : U32), next(r))
72
73
74
75def below(+n: U32, r: Rng) -> U32 & Rng:
76 below.if(U32.is_lt(n, 2), n, r)
77
78def range.fin(lo: U32, xr: U32 & Rng) -> U32 & Rng:
79 (x, r) = xr
80 ((lo + x : U32), r)
81
82
83def range(+lo: U32, hi: U32, r: Rng) -> U32 & Rng:
84 range.fin(lo, below((hi - lo : U32), r))
85
86def unit.fin(xr: U32 & Rng) -> F32 & Rng:
87 (x, r) = xr
88 (F32.div(U32.to_f32((x >> 8n : U32)), 16777216.0), r)
89
90
91def unit(r: Rng) -> F32 & Rng:
92 unit.fin(next(r))
93
94def shuffle.fill(~T: Data, xs: List<&2, T>, +i: U32, a: Array<T>) -> Array<T>:
95 match xs:
96 case Nil{}:
97 a
98 case Con{h, t}:
99 shuffle.fill(~T, t, (i + 1 : U32), Array.set(T, a, i, h))
100
101def shuffle.swap.set(~T: Data, +i: U32, +j: U32, xi: T, ax: Array<T> & T) -> Array<T>:
102 (a, xj) = ax
103 Array.set(T, Array.set(T, a, i, xj), j, xi)
104
105def shuffle.swap(~T: Data, +i: U32, +j: U32, ax: Array<T> & T) -> Array<T>:
106 (a, xi) = ax
107 shuffle.swap.set(~T, i, j, xi, Array.get(T, a, j))
108
109
110
111def shuffle.go(~T: Data, k: Nat, +i: U32, a: Array<T>, jr: U32 & Rng) -> Array<T> & Rng:
112 match k:
113 case 0n:
114 (j, r) = jr
115 (a, r)
116 case 1n+p:
117 (+j, r) = jr
118 shuffle.go(~T, p, (i - 1 : U32), shuffle.swap(~T, i, j, Array.get(T, a, i)),
119 below(i, r))
120
121
122def shuffle.read(~T: Data, k: Nat, ax: Array<T> & T, acc: List<&2, T>) -> List<&2, T>:
123 match k:
124 case 0n:
125 (a, x) = ax
126 x <> acc
127 case 1n+(+p):
128 (a, x) = ax
129 shuffle.read(~T, p, Array.get(T, a, U32.from_nat(p)), x <> acc)
130
131def shuffle.fin(~T: Data, +m: U32, ar: Array<T> & Rng) -> List<&2, T> & Rng:
132 (a, r) = ar
133 (shuffle.read(~T, U32.to_nat(m), Array.get(T, a, m), Nil{}), r)
134
135def shuffle.run(~T: Data, +h: T, +xs: List<&2, T>, r: Rng) -> List<&2, T> & Rng:
136 +m = (U32.from_nat(List.length(&2, T, xs)) - 1 : U32)
137 shuffle.fin(~T, m,
138 shuffle.go(~T, U32.to_nat(m), m,
139 shuffle.fill(~T, xs, 0, Array.new(T, Nat.add(1n, U32.log2(m)), h)),
140 below((m + 1 : U32), r)))
141
142
143
144def shuffle(~T: Data, xs: List<&2, T>, r: Rng) -> List<&2, T> & Rng:
145 match xs:
146 case Nil{}:
147 (Nil{}, r)
148 case Con{+h, t}:
149 shuffle.run(~T, h, h <> t, r)
150
151
152def entropy() -> IO(Result<&1, &1, U32 & String, U32 & U32 & U32 & U32>):
153 import "./effs/random.c"
154 import "./effs/random.js"
155
156def from_os.fin(e: Result<&1, &1, U32 & String, U32 & U32 & U32 & U32>) ->
157 Result<&1, &1, U32 & String, Rng>:
158 match e:
159 case Fail{err}:
160 Fail{err}
161 case Done{(a, b, c, d)}:
162 Done{from_state(a, b, c, d)}
163
164
165def from_os() -> IO(Result<&1, &1, U32 & String, Rng>):
166 do IO<Result<&1, &1, U32 & String, Rng>>:
167 e : Result<&1, &1, U32 & String, U32 & U32 & U32 & U32> <- entropy()
168 return from_os.fin(e)