Current section

Files

Jump to
gleam_stats src gleam_stats@generators.erl
Raw

src/gleam_stats@generators.erl

-module(gleam_stats@generators).
-compile(no_auto_import).
-export([seed_mt19937/1, seed_pcg32/2, seed_lcg32/1]).
-export_type([mersenne_twister/0, permuted_congruential_generator/0, linear_congruential_generator/0]).
-type mersenne_twister() :: {mersenne_twister,
integer(),
integer(),
integer(),
integer(),
integer(),
integer(),
integer(),
integer(),
integer(),
integer(),
integer(),
integer(),
integer()}.
-type permuted_congruential_generator() :: {permuted_congruential_generator,
integer(),
integer(),
integer(),
integer(),
integer(),
integer()}.
-type linear_congruential_generator() :: {linear_congruential_generator,
integer(),
integer()}.
-spec lowest_bits(integer(), mersenne_twister()) -> integer().
lowest_bits(X, Mt) ->
gleam@bitwise:'and'(
X,
gleam@bitwise:shift_left(1, erlang:element(2, Mt))
- 1
).
-spec lower_bitmask(mersenne_twister()) -> integer().
lower_bitmask(Mt) ->
gleam@bitwise:shift_left(1, erlang:element(5, Mt)) - 1.
-spec upper_bitmask(mersenne_twister()) -> integer().
upper_bitmask(Mt) ->
lowest_bits(gleam@bitwise:'not'(lower_bitmask(Mt)), Mt).
-spec seed_mt19937(integer()) -> gleam@iterator:iterator(integer()).
seed_mt19937(Seed) ->
Mt = {mersenne_twister,
32,
624,
397,
31,
16#9908B0DF,
11,
16#FFFFFFFF,
18,
16#9D2C5680,
16#EFC60000,
7,
15,
1812433253},
_pipe = gleam@list:range(1, erlang:element(3, Mt)),
_pipe@1 = gleam@iterator:from_list(_pipe),
_pipe@2 = gleam@iterator:scan(
_pipe@1,
Seed,
fun(Acc, X) ->
lowest_bits(
(erlang:element(14, Mt)
* gleam@bitwise:exclusive_or(
Acc,
gleam@bitwise:shift_right(Acc, erlang:element(2, Mt) - 2)
))
+ X,
Mt
)
end
),
_pipe@3 = gleam@iterator:to_list(_pipe@2),
_pipe@4 = (fun(Arr) -> [Seed | Arr] end)(_pipe@3),
mt19937_rng(_pipe@4, Mt).
-spec mt19937_replace_rn(integer(), list(integer()), integer()) -> list(integer()).
mt19937_replace_rn(Rn, Arr, Index) ->
_pipe = Arr,
gleam@list:index_map(_pipe, fun(I, X) -> case I =:= Index of
true ->
Rn;
false ->
X
end end).
-spec mt19937_next_rn(list(integer()), integer(), mersenne_twister()) -> integer().
mt19937_next_rn(Arr, Index, Mt) ->
V0 = gleam@list:at(Arr, Index),
V1 = gleam@list:at(Arr, case erlang:element(3, Mt) of
0 -> 0;
Gleam@denominator -> (Index + 1) rem Gleam@denominator
end),
V2 = gleam@list:at(Arr, case erlang:element(3, Mt) of
0 -> 0;
Gleam@denominator@1 -> (Index + erlang:element(4, Mt)) rem Gleam@denominator@1
end),
case {V0, V1, V2} of
{{ok, V0@1}, {ok, V1@1}, {ok, V2@1}} ->
V3 = gleam@bitwise:'and'(V0@1, upper_bitmask(Mt)) + gleam@bitwise:'and'(
V1@1,
lower_bitmask(Mt)
),
V4 = gleam@bitwise:shift_right(V3, 1),
case (V3 rem 2) =:= 0 of
true ->
gleam@bitwise:exclusive_or(V2@1, V4);
false ->
gleam@bitwise:exclusive_or(
V2@1,
gleam@bitwise:exclusive_or(V4, erlang:element(6, Mt))
)
end
end.
-spec do_twist(list(integer()), integer(), mersenne_twister()) -> list(integer()).
do_twist(Arr, Index, Mt) ->
case Index >= erlang:element(3, Mt) of
true ->
Arr;
false ->
_pipe = mt19937_next_rn(Arr, Index, Mt),
_pipe@1 = mt19937_replace_rn(_pipe, Arr, Index),
do_twist(_pipe@1, Index + 1, Mt)
end.
-spec twist(list(integer()), mersenne_twister()) -> list(integer()).
twist(Arr, Mt) ->
do_twist(Arr, 0, Mt).
-spec shout(integer(), mersenne_twister()) -> integer().
shout(X, Mt) ->
_pipe = X,
_pipe@1 = (fun(Y) ->
gleam@bitwise:exclusive_or(
Y,
gleam@bitwise:'and'(
gleam@bitwise:shift_right(Y, erlang:element(7, Mt)),
erlang:element(8, Mt)
)
)
end)(_pipe),
_pipe@2 = (fun(Y@1) ->
gleam@bitwise:exclusive_or(
Y@1,
gleam@bitwise:'and'(
gleam@bitwise:shift_left(Y@1, erlang:element(12, Mt)),
erlang:element(10, Mt)
)
)
end)(_pipe@1),
_pipe@3 = (fun(Y@2) ->
gleam@bitwise:exclusive_or(
Y@2,
gleam@bitwise:'and'(
gleam@bitwise:shift_left(Y@2, erlang:element(13, Mt)),
erlang:element(11, Mt)
)
)
end)(_pipe@2),
_pipe@4 = (fun(Y@3) ->
gleam@bitwise:exclusive_or(
Y@3,
gleam@bitwise:shift_right(Y@3, erlang:element(9, Mt))
)
end)(_pipe@3),
(fun(Y@4) -> lowest_bits(Y@4, Mt) end)(_pipe@4).
-spec mt19937_next_state({integer(), list(integer())}, mersenne_twister()) -> gleam@iterator:step(integer(), {integer(),
list(integer())}).
mt19937_next_state(State, Mt) ->
Index = gleam@pair:first(State),
Arr = gleam@pair:second(State),
{ok, X@1} = case gleam@list:at(Arr, Index) of
{ok, X} -> {ok, X};
_try ->
erlang:error(#{gleam_error => assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _try,
module => <<"gleam_stats/generators"/utf8>>,
function => <<"mt19937_next_state"/utf8>>,
line => 259})
end,
{next, shout(X@1, Mt), {Index + 1, Arr}}.
-spec mt19937_rng(list(integer()), mersenne_twister()) -> gleam@iterator:iterator(integer()).
mt19937_rng(Arr, Mt) ->
gleam@iterator:unfold(
{erlang:element(3, Mt), Arr},
fun(State) -> case gleam@pair:first(State) =:= erlang:element(3, Mt) of
true ->
_pipe@1 = {0,
begin
_pipe = gleam@pair:second(State),
twist(_pipe, Mt)
end},
mt19937_next_state(_pipe@1, Mt);
false ->
_pipe@2 = State,
mt19937_next_state(_pipe@2, Mt)
end end
).
-spec pcg32_next_rn({integer(), integer()}, permuted_congruential_generator()) -> integer().
pcg32_next_rn(State, Pcg) ->
Old_state = gleam@pair:first(State),
Xorshifted = gleam@bitwise:'and'(
gleam@bitwise:shift_right(
gleam@bitwise:exclusive_or(
gleam@bitwise:shift_right(Old_state, erlang:element(3, Pcg)),
Old_state
),
erlang:element(4, Pcg)
),
4294967295
),
Rotation = gleam@bitwise:'and'(
gleam@bitwise:shift_right(Old_state, erlang:element(5, Pcg)),
4294967295
),
gleam@bitwise:'and'(
gleam@bitwise:'or'(
gleam@bitwise:shift_right(Xorshifted, Rotation),
gleam@bitwise:shift_left(
Xorshifted,
gleam@bitwise:'and'(-1 * Rotation, erlang:element(6, Pcg))
)
),
4294967295
).
-spec pcg32_init(integer(), integer(), permuted_congruential_generator()) -> {integer(),
integer()}.
pcg32_init(Seed, Seq, Pcg) ->
_pipe = {0,
gleam@bitwise:'or'(
gleam@bitwise:shift_left(
gleam@bitwise:'and'(Seq, 18446744073709551615),
erlang:element(
2,
{permuted_congruential_generator,
1,
18,
27,
59,
31,
6364136223846793005}
)
),
erlang:element(2, Pcg)
)},
_pipe@1 = pcg32_next_state(_pipe, Pcg),
_pipe@2 = (fun(State) ->
{S, I} = State,
{gleam@bitwise:'and'(
S
+ gleam@bitwise:'and'(Seed, 18446744073709551615),
18446744073709551615
),
I}
end)(_pipe@1),
pcg32_next_state(_pipe@2, Pcg).
-spec pcg32_next_state(
{integer(), integer()},
permuted_congruential_generator()
) -> {integer(), integer()}.
pcg32_next_state(State, Pcg) ->
{S, I} = State,
{gleam@bitwise:'and'((S * erlang:element(7, Pcg)) + I, 18446744073709551615),
I}.
-spec seed_pcg32(integer(), integer()) -> gleam@iterator:iterator(integer()).
seed_pcg32(Seed, Seq) ->
Pcg = {permuted_congruential_generator,
1,
18,
27,
59,
31,
6364136223846793005},
_pipe = pcg32_init(Seed, Seq, Pcg),
gleam@iterator:unfold(
_pipe,
fun(State) ->
Next_rn = pcg32_next_rn(State, Pcg),
Next_state = pcg32_next_state(State, Pcg),
{next, Next_rn, Next_state}
end
).
-spec lcg32_init(integer(), linear_congruential_generator()) -> integer().
lcg32_init(Seed, Lcg) ->
gleam@bitwise:'and'(
(erlang:element(2, Lcg)
* Seed)
+ erlang:element(3, Lcg),
4294967295
).
-spec lcg32_next_state(integer(), linear_congruential_generator()) -> integer().
lcg32_next_state(State, Lcg) ->
gleam@bitwise:'and'(
(erlang:element(2, Lcg)
* State)
+ erlang:element(3, Lcg),
4294967295
).
-spec seed_lcg32(integer()) -> gleam@iterator:iterator(integer()).
seed_lcg32(Seed) ->
Lcg = {linear_congruential_generator, 1664525, 1013904223},
_pipe = lcg32_init(Seed, Lcg),
gleam@iterator:unfold(
_pipe,
fun(State) ->
Next_state = lcg32_next_state(State, Lcg),
{next, Next_state, Next_state}
end
).