File 2872-Implement-seeding-with-default-algorithm.patch of Package erlang
From 9b8f09a991242b2ff737b3b7cd0e309a5cc1f2d2 Mon Sep 17 00:00:00 2001
From: Raimo Niskanen <raimo@erlang.org>
Date: Tue, 8 Dec 2020 16:44:51 +0100
Subject: [PATCH 2/6] Implement seeding with 'default' algorithm
---
lib/stdlib/doc/src/rand.xml | 34 ++++++++++++++++++++++-------
lib/stdlib/src/rand.erl | 11 ++++++++--
lib/stdlib/test/rand_SUITE.erl | 39 ++++++++++++++++++++++------------
3 files changed, 60 insertions(+), 24 deletions(-)
diff --git a/lib/stdlib/doc/src/rand.xml b/lib/stdlib/doc/src/rand.xml
index ac99736761..0eed1c2e49 100644
--- a/lib/stdlib/doc/src/rand.xml
+++ b/lib/stdlib/doc/src/rand.xml
@@ -310,6 +310,8 @@ tests. We suggest to use a sign test to extract a random Boolean value.</pre>
A list of integers sets the generator's internal state directly,
after algorithm-dependent checks of the value
and masking to the proper word size.
+ The number of integers must be equal to the
+ number of state words in the generator.
</p>
<p>
An integer is used as the initial state for a SplitMix64 generator.
@@ -432,7 +434,8 @@ tests. We suggest to use a sign test to extract a random Boolean value.</pre>
</func>
<func>
- <name name="seed" arity="1" since="OTP 18.0"/>
+ <name name="seed" arity="1" clause_i="1" since="OTP 18.0"/>
+ <name name="seed" arity="1" clause_i="2" since="OTP 24.0"/>
<fsummary>Seed random number generator.</fsummary>
<desc>
<marker id="seed-1"/>
@@ -440,6 +443,8 @@ tests. We suggest to use a sign test to extract a random Boolean value.</pre>
Seeds random number generation with the specifed algorithm and
time-dependent data if <c><anno>AlgOrStateOrExpState</anno></c>
is an algorithm.
+ <c><anno>Alg</anno> = default</c>
+ is an alias for the default algorithm.
</p>
<p>Otherwise recreates the exported seed in the process dictionary,
and returns the state. See also
@@ -448,22 +453,30 @@ tests. We suggest to use a sign test to extract a random Boolean value.</pre>
</func>
<func>
- <name name="seed" arity="2" since="OTP 18.0"/>
+ <name name="seed" arity="2" clause_i="1" since="OTP 18.0"/>
+ <name name="seed" arity="2" clause_i="2" since="OTP 24.0"/>
<fsummary>Seed the random number generation.</fsummary>
<desc>
- <p>Seeds random number generation with the specified algorithm and
- integers in the process dictionary and returns the state.</p>
+ <p>
+ Seeds random number generation with the specified algorithm and
+ integers in the process dictionary and returns the state.
+ <c><anno>Alg</anno> = default</c>
+ is an alias for the default algorithm.
+ </p>
</desc>
</func>
<func>
- <name name="seed_s" arity="1" since="OTP 18.0"/>
+ <name name="seed_s" arity="1" clause_i="1" since="OTP 18.0"/>
+ <name name="seed_s" arity="1" clause_i="2" since="OTP 24.0"/>
<fsummary>Seed random number generator.</fsummary>
<desc>
<p>
Seeds random number generation with the specifed algorithm and
time-dependent data if <c><anno>AlgOrStateOrExpState</anno></c>
is an algorithm.
+ <c><anno>Alg</anno> = default</c>
+ is an alias for the default algorithm.
</p>
<p>Otherwise recreates the exported seed and returns the state.
See also <seemfa marker="#export_seed/0">
@@ -472,11 +485,16 @@ tests. We suggest to use a sign test to extract a random Boolean value.</pre>
</func>
<func>
- <name name="seed_s" arity="2" since="OTP 18.0"/>
+ <name name="seed_s" arity="2" clause_i="1" since="OTP 18.0"/>
+ <name name="seed_s" arity="2" clause_i="2" since="OTP 24.0"/>
<fsummary>Seed the random number generation.</fsummary>
<desc>
- <p>Seeds random number generation with the specified algorithm and
- integers and returns the state.</p>
+ <p>
+ Seeds random number generation with the specified algorithm and
+ integers and returns the state.
+ <c><anno>Alg</anno> = default</c>
+ is an alias for the default algorithm.
+ </p>
</desc>
</func>
diff --git a/lib/stdlib/src/rand.erl b/lib/stdlib/src/rand.erl
index b743bd5798..1de78a23ac 100644
--- a/lib/stdlib/src/rand.erl
+++ b/lib/stdlib/src/rand.erl
@@ -248,12 +248,16 @@ export_seed_s({#{type:=Alg}, AlgState}) -> {Alg, AlgState}.
-spec seed(
AlgOrStateOrExpState :: builtin_alg() | state() | export_state()) ->
+ state();
+ (Alg :: 'default') ->
state().
seed(Alg) ->
seed_put(seed_s(Alg)).
-spec seed_s(
AlgOrStateOrExpState :: builtin_alg() | state() | export_state()) ->
+ state();
+ (Alg :: 'default') ->
state().
seed_s({AlgHandler, _AlgState} = State) when is_map(AlgHandler) ->
State;
@@ -268,11 +272,14 @@ seed_s(Alg) ->
%% seed/2: seeds RNG with the algorithm and given values
%% and returns the NEW state.
--spec seed(Alg :: builtin_alg(), Seed :: seed()) -> state().
+-spec seed(Alg :: builtin_alg(), Seed :: seed()) -> state();
+ (Alg :: 'default', Seed :: seed()) -> state().
seed(Alg, Seed) ->
seed_put(seed_s(Alg, Seed)).
--spec seed_s(Alg :: builtin_alg(), Seed :: seed()) -> state().
+-spec seed_s(Alg :: builtin_alg(), Seed :: seed()) -> state();
+ (Alg :: 'default', Seed :: seed()) -> state().
+seed_s(default, Seed) -> seed_s(?DEFAULT_ALG_HANDLER, Seed);
seed_s(Alg, Seed) ->
{AlgHandler,SeedFun} = mk_alg(Alg),
AlgState = SeedFun(Seed),
diff --git a/lib/stdlib/test/rand_SUITE.erl b/lib/stdlib/test/rand_SUITE.erl
index d368fb3fc6..230020857f 100644
--- a/lib/stdlib/test/rand_SUITE.erl
+++ b/lib/stdlib/test/rand_SUITE.erl
@@ -85,7 +85,7 @@ algs() ->
%% Test that seed and seed_s and export_seed/0 is working.
seed(Config) when is_list(Config) ->
- Algs = algs(),
+ Algs = [default|algs()],
Test = fun(Alg) ->
try seed_1(Alg)
catch _:Reason:Stacktrace ->
@@ -93,6 +93,13 @@ seed(Config) when is_list(Config) ->
end
end,
[Test(Alg) || Alg <- Algs],
+ %%
+ %% Check that export_seed/1 returns 'undefined' if there is no seed
+ erase(rand_seed),
+ undefined = rand:export_seed(),
+ %%
+ %% Other seed terms shall not work
+ {'EXIT', _} = (catch rand:seed_s(foobar, os:timestamp())),
ok.
seed_1(Alg) ->
@@ -121,22 +128,26 @@ seed_1(Alg) ->
false = (S1 =:= rand:seed_s(Alg)),
%% Negative integers works
_ = rand:seed_s(Alg, {-1,-1,-1}),
- %% Check that export_seed/1 returns 'undefined' if there is no seed
- erase(rand_seed),
- undefined = rand:export_seed(),
-
- %% Other term do not work
- {'EXIT', _} = (catch rand:seed_s(foobar, os:timestamp())),
+ %%
+ %% Other seed terms shall not work
{'EXIT', _} = (catch rand:seed_s(Alg, {asd, 1, 1})),
{'EXIT', _} = (catch rand:seed_s(Alg, {0, 234.1234, 1})),
{'EXIT', _} = (catch rand:seed_s(Alg, {0, 234, [1, 123, 123]})),
+ {'EXIT', _} = (catch rand:seed_s(Alg, asd)),
+ {'EXIT', _} = (catch rand:seed_s(Alg, make_ref())),
+ {'EXIT', _} = (catch rand:seed_s(Alg, fun () -> 0 end)),
+ {'EXIT', _} = (catch rand:seed_s(Alg, self())),
+ {'EXIT', _} = (catch rand:seed_s(Alg, {1,2})),
+ {'EXIT', _} = (catch rand:seed_s(Alg, {1,2,3,4})),
+ {'EXIT', _} = (catch rand:seed_s(Alg, #{})),
+ {'EXIT', _} = (catch rand:seed_s(Alg, [1|2])),
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Check that both APIs are consistent with each other.
api_eq(_Config) ->
- Algs = algs(),
+ Algs = [default|algs()],
Small = fun(Alg) ->
Seed = rand:seed(Alg),
io:format("Seed ~p~n",[rand:export_seed_s(Seed)]),
@@ -182,7 +193,7 @@ api_eq_1(S00) ->
%% Check that uniform/1 returns values within the proper interval.
interval_int(Config) when is_list(Config) ->
- Algs = algs(),
+ Algs = [default|algs()],
Small = fun(Alg) ->
Seed = rand:seed(Alg),
io:format("Seed ~p~n",[rand:export_seed_s(Seed)]),
@@ -216,7 +227,7 @@ interval_int_1(N, Top, Max) ->
%% Check that uniform/0 returns values within the proper interval.
interval_float(Config) when is_list(Config) ->
- Algs = algs(),
+ Algs = [default|algs()],
Test = fun(Alg) ->
_ = rand:seed(Alg),
interval_float_1(100000)
@@ -307,13 +318,13 @@ gen(_, _, _, Acc) -> lists:reverse(Acc).
basic_stats_uniform_1(Config) when is_list(Config) ->
ct:timetrap({minutes,15}), %% valgrind needs a lot of time
[basic_uniform_1(?LOOP, rand:seed_s(Alg), 0.0, array:new([{default, 0}]))
- || Alg <- algs()],
+ || Alg <- [default|algs()]],
ok.
basic_stats_uniform_2(Config) when is_list(Config) ->
ct:timetrap({minutes,15}), %% valgrind needs a lot of time
[basic_uniform_2(?LOOP, rand:seed_s(Alg), 0, array:new([{default, 0}]))
- || Alg <- algs()],
+ || Alg <- [default|algs()]],
ok.
basic_stats_standard_normal(Config) when is_list(Config) ->
@@ -323,7 +334,7 @@ basic_stats_standard_normal(Config) when is_list(Config) ->
IntendedVariance = 1,
[basic_normal_1(?LOOP, IntendedMean, IntendedVariance,
rand:seed_s(Alg), 0, 0)
- || Alg <- algs()],
+ || Alg <- [default|algs()]],
ok.
basic_stats_normal(Config) when is_list(Config) ->
@@ -342,7 +353,7 @@ basic_stats_normal(Config) when is_list(Config) ->
[float(IntendedMean), float(IntendedVariance)]),
[basic_normal_1(?LOOP, IntendedMean, IntendedVariance,
rand:seed_s(Alg), 0, 0)
- || Alg <- algs()]
+ || Alg <- [default|algs()]]
end,
IntendedMeanVariancePairs).
--
2.26.2