[m-rev.] for review: delete the old random number generator

Julien Fischer jfischer at opturion.com
Mon Mar 14 17:26:08 AEDT 2022


For review by anyone.

The main thing requiring review here is the NEWS file.
(I am aware that there are further bits of the extras that need
updating, I will do that separately.)

-------------------------------------------

Delete the old random number generator.

It has been deprecated since Mercury 20.01.

library/random.m:
     Delete the old generator.

library/array.m:
     Delete the predicate random_permutation/4.

NEWS:
     Announce the above.

tests/hard_coded/string_hash.m:
     Update this test to use the new RNG framework.

tests/hard_coded/Mmakefile:
tests/hard_coded/random_permutation.{m,exp}:
tests/hard_coded/random_simple.{m,exp}:
     Delete these tests, they were specific to the old RNG.

extras/curs/samples/nibbles.m:
extras/solver_types/library/any_array.m:
     Replace use of the old RNG.

Julien.

diff --git a/NEWS b/NEWS
index d93a15c..f394df9 100644
--- a/NEWS
+++ b/NEWS
@@ -12,9 +12,18 @@ Changes that may break compatibility
    as obsolete, while other predicates that had been marked as obsolete
    before the release of Mercury 22.01 have been removed.

+* The old random number generator in the `random` module has been removed.
+
  Changes to the Mercury standard library
  ---------------------------------------

+### Changes to the `array` module
+
+* The following predicate has been removed:
+
+    - pred `random_permutation/4`
+      (replacement: `random.suffle_array/4` or `random.shuffle_array/5`)
+
  ### Changes to the `benchmarking` module

  * The following predicates have been added:
@@ -176,6 +185,20 @@ This new module has these predicates:
      - pred `have_make_temp_directory/0`
      - pred `get_temp_directory/3`

+### Changes to the `random` module
+
+The old random number generator has been removed. It has been replaced by the
+new type class random number generation framework defined in this module.
+As a result, the following predicates have been removed:
+
+   - pred `init/2`
+   - pred `random/3`
+   - pred `random/5`
+   - pred `randmax/3`
+   - pred `randcount/3`
+   - pred `permutation/4`
+            (replacement: `random.shuffle_list/4` or `random.shuffle_list/5`)
+
  ### Changes to the `term_io` module

  * The following predicates have been removed:
diff --git a/extras/curs/samples/nibbles.m b/extras/curs/samples/nibbles.m
index 5d7fc98..21a0bbc 100644
--- a/extras/curs/samples/nibbles.m
+++ b/extras/curs/samples/nibbles.m
@@ -27,16 +27,16 @@
  :- import_module char.
  :- import_module int.
  :- import_module list.
+:- import_module maybe.
  :- import_module random.
+:- import_module random.sfc32.
+:- import_module random.system_rng.
  :- import_module require.
  :- import_module std_util.
  :- import_module string.
-:- import_module time.

  %-----------------------------------------------------------------------------%

-:- type rs == random.supply.
-
  :- type world
      --->    world(
              cols        :: int,
@@ -66,34 +66,50 @@
  :- type apple
      --->    no_apple
      ;       apple(
-                x   :: int,
-                y   :: int,
-                repr    :: int
+                x    :: int,
+                y    :: int,
+                repr :: int
              ).

  %-----------------------------------------------------------------------------%

  main(!IO) :-
-    time.time(Now, !IO),
-    time.localtime(Now, LocalNow, !IO),
-    random.init(LocalNow ^ tm_min * 60 + LocalNow ^ tm_sec, RS),
-    curs.start(!IO),
-    curs.nodelay(yes, !IO),
-    curs.rows_cols(Rows, Cols, !IO),
-    curs.flushinp(!IO),
-    play_game(Cols, Rows, !IO, RS, _RS1),
-    curs.stop(!IO).
+    open_system_rng(MaybeSystemRNG, !IO),
+    (
+        MaybeSystemRNG = ok(SystemRNG),
+        system_rng.generate_uint32(SystemRNG, SeedA, !IO),
+        system_rng.generate_uint32(SystemRNG, SeedB, !IO),
+        system_rng.generate_uint32(SystemRNG, SeedC, !IO),
+        close_system_rng(SystemRNG, !IO),
+
+        sfc32.seed(SeedA, SeedB, SeedC, RNG0, RS),
+        make_io_urandom(RNG0, RS, RNG, !IO),
+
+        curs.start(!IO),
+        curs.nodelay(yes, !IO),
+        curs.rows_cols(Rows, Cols, !IO),
+        curs.flushinp(!IO),
+        play_game(RNG, Cols, Rows, !IO),
+        curs.stop(!IO)
+    ;
+        MaybeSystemRNG = error(ErrMsg),
+        io.stderr_stream(Stderr, !IO),
+        io.format(Stderr, "Error %s.\n", [s(ErrMsg)], !IO),
+        io.set_exit_status(1, !IO)
+    ).

-:- pred play_game(int::in, int::in, io::di, io::uo, rs::mdi, rs::muo) is det.
+:- pred play_game(io_urandom(P, S)::in, int::in, int::in, io::di, io::uo) is det
+    <= urandom(P, S).

-play_game(Cols, Rows, !IO, !RS) :-
+play_game(RNG, Cols, Rows, !IO) :-
      Snake = snake(right, {Cols / 2, Rows / 2}, [], 10),
      World = world(Cols, Rows, Snake, 1, no_apple, 0),
-    game_loop(World, !IO, !RS).
+    game_loop(RNG, World, !IO).

-:- pred game_loop(world::in, io::di, io::uo, rs::mdi, rs::muo) is det.
+:- pred game_loop(io_urandom(P, S)::in, world::in, io::di, io::uo) is det
+    <= urandom(P, S).

-game_loop(!.World, !IO, !RS) :-
+game_loop(RNG, !.World, !IO) :-
      handle_input(!World, !IO, Quit),
      (
          Quit = no,
@@ -104,8 +120,8 @@ game_loop(!.World, !IO, !RS) :-
              show_game_over(!IO)
          else
              sleep.usleep(50000, !IO),
-            maybe_replenish_apple(!World, !RS),
-            game_loop(!.World, !IO, !RS)
+            maybe_replenish_apple(RNG, !World, !IO),
+            game_loop(RNG, !.World, !IO)
          )
      ;
          Quit = yes
@@ -237,11 +253,12 @@ snake_is_dead(World) :-

  %-----------------------------------------------------------------------------%

-:- pred maybe_replenish_apple(world::in, world::out, rs::mdi, rs::muo) is det.
+:- pred maybe_replenish_apple(io_urandom(P, S)::in, world::in, world::out,
+    io::di, io::uo) is det <= urandom(P, S).

-maybe_replenish_apple(World0, World, !RS) :-
+maybe_replenish_apple(RNG, World0, World, !IO) :-
      ( if World0 ^ apple = no_apple then
-        new_apple(World0, !RS, NewApple),
+        new_apple(RNG, World0, NewApple, !IO),
          NextAppleNum = inc_apple_num(World0 ^ next_apple_num),
          World = ((World0
              ^ apple := NewApple)
@@ -250,13 +267,14 @@ maybe_replenish_apple(World0, World, !RS) :-
          World = World0
      ).

-:- pred new_apple(world::in, rs::mdi, rs::muo, apple::out) is det.
+:- pred new_apple(io_urandom(P, S)::in, world::in, apple::out, io::di, io::uo)
+    is det <= urandom(P, S).

-new_apple(World, !RS, Apple) :-
-    random.random(1, World ^ cols-2, X, !RS),
-    random.random(1, World ^ rows-2, Y, !RS),
+new_apple(RNG, World, Apple, !IO) :-
+    uniform_int_in_range(RNG, 1, World ^ cols - 2, X, !IO),
+    uniform_int_in_range(RNG, 1, World ^ rows - 2, Y, !IO),
      ( if touches_snake(X, Y, World) then
-        new_apple(World, !RS, Apple)
+        new_apple(RNG, World, Apple, !IO)
      else
          Apple = apple(X, Y, apple_char(World ^ next_apple_num))
      ).
diff --git a/extras/solver_types/library/any_array.m b/extras/solver_types/library/any_array.m
index ba0c11e..211bc56 100644
--- a/extras/solver_types/library/any_array.m
+++ b/extras/solver_types/library/any_array.m
@@ -283,14 +283,24 @@
  :- mode any_array.foldr(func(ia, ia) = oa is det, any_array_ui, ia) = oa
          is det.

-    % any_array.random_permutation(A0, A, RS0, RS) permutes the elements in
-    % A0 given random seed RS0 and returns the permuted any_array in A
-    % and the next random seed in RS.
+    % any_array.random_permutation(A0, A, R0, R) permutes the elements in A0
+    % given random number generator R0 and returns the permuted any_array in A
+    % and the next random generator in R.
      %
  :- pred any_array.random_permutation(any_array(T), any_array(T),
-        random.supply, random.supply).
+    R, R) <= random(R).
  :- mode any_array.random_permutation(any_array_di, any_array_uo,
-        mdi, muo) is det.
+    in, out) is det.
+
+    % any_array.random_permutation(RNG, A0, A, RS0, RS) permutes the elements
+    % in A0 given unique random number generator RNG and initial random state
+    % RS0. It returns the permuted any_array in A and the updated random
+    % number generator state in RS.
+    %
+:- pred any_array.random_permutation(P, any_array(T), any_array(T),
+    S, S) <= urandom(P, S).
+:- mode any_array.random_permutation(in, any_array_di, any_array_uo,
+    di, uo) is det.

  %-----------------------------------------------------------------------------%
  %-----------------------------------------------------------------------------%
@@ -797,25 +807,44 @@ Array ^ elem(Index) =

  %------------------------------------------------------------------------------%

-any_array.random_permutation(A0, A, RS0, RS) :-
+random_permutation(A0, A, !R) :-
      Lo = any_array.min(A0),
      Hi = any_array.max(A0),
      Sz = any_array.size(A0),
-    permutation_2(Lo, Lo, Hi, Sz, A0, A, RS0, RS).
+    permutation_2(Lo, Lo, Hi, Sz, A0, A, !R).
+
+:- pred permutation_2(int::in, int::in, int::in, int::in,
+    any_array(T)::any_array_di, any_array(T)::any_array_uo, R::in, R::out) is det
+    <= random(R).
+
+permutation_2(I, Lo, Hi, Sz, !A, !R) :-
+    ( if I > Hi then
+        true
+    else
+        uniform_int_in_range(Lo, Sz, J, !R),
+        !:A = swap_elems(!.A, I, J),
+        permutation_2(I + 1, Lo, Hi, Sz, !A, !R)
+    ).

-:- pred permutation_2(int, int, int, int, any_array(T), any_array(T),
-        random.supply, random.supply).
-:- mode permutation_2(in, in, in, in, any_array_di, any_array_uo, mdi, muo) is det.
+%------------------------------------------------------------------------------%

-permutation_2(I, Lo, Hi, Sz, A0, A, RS0, RS) :-
-    ( I > Hi ->
-        A  = A0,
-        RS = RS0
-    ;
-        random.random(R, RS0, RS1),
-        J  = Lo + (R `rem` Sz),
-        A1 = swap_elems(A0, I, J),
-        permutation_2(I + 1, Lo, Hi, Sz, A1, A, RS1, RS)
+any_array.random_permutation(P, A0, A, !S) :-
+    Lo = any_array.min(A0),
+    Hi = any_array.max(A0),
+    Sz = any_array.size(A0),
+    permutation_2(P, Lo, Lo, Hi, Sz, A0, A, !S).
+
+:- pred permutation_2(P::in, int::in, int::in, int::in, int::in,
+    any_array(T)::any_array_di, any_array(T)::any_array_uo, S::di, S::uo)
+    is det <= urandom(P, S).
+
+permutation_2(P, I, Lo, Hi, Sz, !A, !S) :-
+    ( if I > Hi then
+        true
+    else
+        uniform_int_in_range(P, Lo, Sz, J, !S),
+        !:A = swap_elems(!.A, I, J),
+        permutation_2(P, I + 1, Lo, Hi, Sz, !A, !S)
      ).

  %------------------------------------------------------------------------------%
diff --git a/library/array.m b/library/array.m
index 8a200c0..6df93c0 100644
--- a/library/array.m
+++ b/library/array.m
@@ -45,7 +45,6 @@

  :- import_module list.
  :- import_module pretty_printer.
-:- import_module random.

  :- type array(T).

@@ -826,13 +825,6 @@
      %
  :- func append(array(T)::in, array(T)::in) = (array(T)::array_uo) is det.

-    % random_permutation(A0, A, RS0, RS) permutes the elements in
-    % A0 given random seed RS0 and returns the permuted array in A
-    % and the next random seed in RS.
-    %
-:- pred random_permutation(array(T)::array_di, array(T)::array_uo,
-    random.supply::mdi, random.supply::muo) is det.
-
      % Convert an array to a pretty_printer.doc for formatting.
      %
  :- func array_to_doc(array(T)) = pretty_printer.doc.
@@ -2581,37 +2573,6 @@ append(A, B) = C :-

  %---------------------------------------------------------------------------%

-random_permutation(A0, A, RS0, RS) :-
-    Lo = array.min(A0),
-    Hi = array.max(A0),
-    Sz = array.size(A0),
-    permutation_2(Lo, Lo, Hi, Sz, A0, A, RS0, RS).
-
-:- pred permutation_2(int::in, int::in, int::in, int::in,
-    array(T)::array_di, array(T)::array_uo,
-    random.supply::mdi, random.supply::muo) is det.
-
-permutation_2(I, Lo, Hi, Sz, !A, !RS) :-
-    ( if I > Hi then
-        true
-    else
-        random.random(R, !RS),
-        J  = Lo + (R `rem` Sz),
-        swap_elems(I, J, !A),
-        permutation_2(I + 1, Lo, Hi, Sz, !A, !RS)
-    ).
-
-:- pred swap_elems(int::in, int::in, array(T)::array_di, array(T)::array_uo)
-    is det.
-
-swap_elems(I, J, !A) :-
-    array.lookup(!.A, I, XI),
-    array.lookup(!.A, J, XJ),
-    array.unsafe_set(I, XJ, !A),
-    array.unsafe_set(J, XI, !A).
-
-%---------------------------------------------------------------------------%
-
  foldl(Fn, A, X) =
      do_foldl_func(Fn, A, X, array.min(A), array.max(A)).

diff --git a/library/random.m b/library/random.m
index a0bad45..59ae035 100644
--- a/library/random.m
+++ b/library/random.m
@@ -355,116 +355,6 @@

  %---------------------------------------------------------------------------%
  %---------------------------------------------------------------------------%
-%
-% Interface to the older random number generator. This is now deprecated.
-%
-% Define a set of random number generator predicates. This implementation
-% uses a threaded random-number supply.  The supply can be used in a
-% non-unique way, which means that each thread returns the same list of
-% random numbers.  However, this may not be desired so in the interests
-% of safety it is also declared with (backtrackable) unique modes.
-%
-% The coefficients used in the implementation were taken from Numerical
-% Recipes in C (Press et al), and are originally due to Knuth.  These
-% coefficients are described as producing a "Quick and Dirty" random number
-% generator, which generates the numbers very quickly but not necessarily
-% with a high degree of quality.  As with all random number generators,
-% the user is advised to consider carefully whether this generator meets
-% their requirements in terms of "randomness".  For applications which have
-% special needs (e.g. cryptographic key generation), a generator such as
-% this is unlikely to be suitable.
-%
-% Note that random number generators of this type have several known
-% pitfalls which the user may need to avoid:
-%
-%   1) The high bits tend to be more random than the low bits.  If
-%   you wish to generate a random integer within a given range, you
-%   should something like 'div' to reduce the random numbers to the
-%   required range rather than something like 'mod' (or just use
-%   random.random/5).
-%
-%   2) Similarly, you should not try to break a random number up into
-%   components.  Instead, you should generate each number with a
-%   separate call to this module.
-%
-%   3) There can be sequential correlation between successive calls,
-%   so you shouldn't try to generate tuples of random numbers, for
-%   example, by generating each component of the tuple in sequential
-%   order.  If you do, it is likely that the resulting sequence will
-%   not cover the full range of possible tuples.
-%
-%---------------------------------------------------------------------------%
-
-    % The type `supply' represents a supply of random numbers.
-    %
-:- type supply.
-
-    % init(Seed, RS).
-    %
-    % Creates a supply of random numbers RS using the specified Seed.
-    %
-    % This predicate has been declared obsolete because all of the
-    % interface from here on is deprecated. All code using this part
-    % of the interface will need to be updated.
-    %
-:- pragma obsolete(pred(init/2)).
-:- pred init(int::in, supply::uo) is det.
-
-    % random(Num, !RS).
-    %
-    % Extracts a number Num in the range 0 .. RandMax from the random number
-    % supply !RS.
-    %
-:- pred random(int, supply, supply).
-:- mode random(out, in, out) is det.
-:- mode random(out, mdi, muo) is det.
-
-    % random(Low, Range, Num, !RS).
-    %
-    % Extracts a number Num in the range Low .. (Low + Range - 1) from the
-    % random number supply !RS.  For best results, the value of Range should be
-    % no greater than about 100.
-    %
-:- pred random(int, int, int, supply, supply).
-:- mode random(in, in, out, in, out) is det.
-:- mode random(in, in, out, mdi, muo) is det.
-
-    % randmax(RandMax, !RS).
-    %
-    % Binds RandMax to the maximum random number that can be returned from the
-    % random number supply !RS, the state of the supply is unchanged.
-    %
-:- pred randmax(int, supply, supply).
-:- mode randmax(out, in, out) is det.
-:- mode randmax(out, mdi, muo) is det.
-
-    % randcount(RandCount, !RS).
-    %
-    % Binds RandCount to the number of distinct random numbers that can be
-    % returned from the random number supply !RS.  The state of the supply is
-    % unchanged.  This will be one more than the number returned by randmax/3.
-    %
-:- pred randcount(int, supply, supply).
-:- mode randcount(out, in, out) is det.
-:- mode randcount(out, mdi, muo) is det.
-
-    % permutation(List0, List, !RS).
-    %
-    % Binds List to a random permutation of List0.
-    %
-:- pred permutation(list(T), list(T), supply, supply).
-:- mode permutation(in, out, in, out) is det.
-:- mode permutation(in, out, mdi, muo) is det.
-
-%---------------------------------------------------------------------------%
-%---------------------------------------------------------------------------%
-
-:- implementation.
-    % Everything after the first `:- implementation' does not appear
-    % in the Mercury Library Reference Manual.
-:- interface.
-
-%---------------------------------------------------------------------------%

  :- implementation.

@@ -854,108 +744,5 @@ make_io_urandom(P, S, Pio, !IO) :-
      ).

  %---------------------------------------------------------------------------%
-%---------------------------------------------------------------------------%
-
-:- type supply
-    --->    rs(int). % I(j)
-
-:- pred params(int::out, int::out, int::out) is det. % a, c, m
-
-params(9301, 49297, 233280).
-
-init(I0, rs(RS)) :-
-    copy(I0, RS).
-
-random(I, rs(RS0), rs(RS)) :-
-    RS0 = I0,
-    random.params(A, C, M),
-    I = ((I0 * A) + C) mod M,
-    copy(I, RS).
-
-    % We could make this more robust by checking whether the range is
-    % less than a certain threshold, and using a more sophisticated
-    % algorithm if the threshold is exceeded.  But that would defeat
-    % the purpose of having a "quick and dirty" random number generator,
-    % so we don't do that.
-random(Low, Range, Num, !RandomSupply) :-
-    random(R, !RandomSupply),
-    randcount(M, !RandomSupply),
-    % With our current set of parameters and a reasonable choice of Range,
-    % the following should never overflow.
-    Num = Low + (Range * R) // M.
-
-randmax(M1, RS, RS) :-
-    params(_A, _C, M),
-    M1 = M - 1.
-
-randcount(M, RS, RS) :-
-    params(_A, _C, M).
-
-%---------------------------------------------------------------------------%
-
-    % The random permutation is implemented via a "sampling without
-    % replacement" method. In init_record, we build up an array in which
-    % every integer in the range 0 .. Length - 1 is mapped to the
-    % corresponding element in the list.  The sampling stage
-    % iterates from Length - 1 down to 0. The invariant being
-    % maintained is that at iteration I, the elements in the image of
-    % the part of the map indexed by 0 .. I-1 are the elements that have
-    % not been selected yet. At each iteration, perform_sampling generates
-    % a random number Index in the range 0 .. I-1, adds the element that
-    % Index is mapped to, Next, to the permutation, and then ensures that
-    % Next is not generated again by swapping it with the image of I-1.
-
-permutation(List0, List, !RS) :-
-    Samples = array(List0),
-    Len = array.size(Samples),
-    perform_sampling(Len, Samples, [], List, !RS).
-
-:- pred perform_sampling(int, array(T), list(T), list(T),
-    random.supply, random.supply).
-:- mode perform_sampling(in, array_di, in, out, in, out) is det.
-:- mode perform_sampling(in, array_di, in, out, mdi, muo) is det.
-
-perform_sampling(I, !.Record, !Order, !RS) :-
-    ( if I =< 0 then
-        true
-    else
-        I1 = I - 1,
-        random.random(0, I, Index, !RS),
-        array.lookup(!.Record, Index, Next),
-        array.lookup(!.Record, I1, MaxImage),
-        !:Order = [Next | !.Order],
-        array.set(Index, MaxImage, !Record),
-        array.set(I1, Next, !Record),
-        perform_sampling(I1, !.Record, !Order, !RS)
-    ).
-
-%---------------------------------------------------------------------------%
-
-    % The following predicate was just for test purposes.
-    % It should not be used by user programs.
-    %
-:- pred test(int::in, int::in, list(int)::out, int::out) is det.
-:- pragma consider_used(pred(test/4)).
-:- pragma obsolete(pred(test/4)).
-
-test(Seed, N, Nums, Max) :-
-    init(Seed, RS),
-    randmax(Max, RS, RS1),
-    test_2(N, Nums, RS1, _RS2).
-
-:- pred test_2(int, list(int), supply, supply).
-:- mode test_2(in, out, in, out) is det.
-
-test_2(N, Is, !RS) :-
-    ( if N > 0 then
-        N1 = N - 1,
-        random(I, !RS),
-        test_2(N1, Is0, !RS),
-        Is = [I | Is0]
-    else
-        Is = []
-    ).
-
-%---------------------------------------------------------------------------%
  :- end_module random.
  %---------------------------------------------------------------------------%
diff --git a/tests/hard_coded/Mmakefile b/tests/hard_coded/Mmakefile
index d197ec0..e2dfe6e 100644
--- a/tests/hard_coded/Mmakefile
+++ b/tests/hard_coded/Mmakefile
@@ -326,8 +326,6 @@ ORDINARY_PROGS = \
  	quantifier \
  	quantifier2 \
  	quoting_bug_test \
-	random_permutation \
-	random_simple \
  	rational_test \
  	read_binary_int16 \
  	read_binary_int32 \
diff --git a/tests/hard_coded/random_permutation.exp b/tests/hard_coded/random_permutation.exp
deleted file mode 100644
index f09768a..0000000
--- a/tests/hard_coded/random_permutation.exp
+++ /dev/null
@@ -1,9 +0,0 @@
-Test passed.
-Test passed.
-Test passed.
-Test passed.
-Test passed.
-Test passed.
-Test passed.
-Test passed.
-Test passed.
diff --git a/tests/hard_coded/random_permutation.m b/tests/hard_coded/random_permutation.m
deleted file mode 100644
index 804530e..0000000
--- a/tests/hard_coded/random_permutation.m
+++ /dev/null
@@ -1,47 +0,0 @@
-%---------------------------------------------------------------------------%
-% vim: ts=4 sw=4 et ft=mercury
-%---------------------------------------------------------------------------%
-
-:- module random_permutation.
-:- interface.
-:- import_module io.
-
-:- pred main(io::di, io::uo) is det.
-
-:- implementation.
-
-:- import_module int.
-:- import_module list.
-:- import_module random.
-
-main(!IO) :-
-    List = gen_sorted_list(1, 100),
-    random.init(1, RS),
-    do_tests(List, 10, RS, !IO).
-
-:- pred do_tests(list(int)::in, int::in, random.supply::mdi,
-    io::di, io::uo) is det.
-
-do_tests(List, Count, RS0, !IO) :-
-    ( if Count > 1 then
-        random.permutation(List, Perm, RS0, RS1),
-        list.sort_and_remove_dups(Perm, SortedList),
-        ( if SortedList = List then
-            io.write_string("Test passed.\n", !IO)
-        else
-            io.write_string("Test failed!\n", !IO)
-        ),
-        do_tests(List, Count - 1, RS1, !IO)
-    else
-        true
-    ).
-
-:- func gen_sorted_list(int, int) = list(int).
-
-gen_sorted_list(M, N) =
-    ( if M > N then
-        []
-    else
-        [M | gen_sorted_list(M + 1, N)]
-    ).
-
diff --git a/tests/hard_coded/random_simple.exp b/tests/hard_coded/random_simple.exp
deleted file mode 100644
index 669a531..0000000
--- a/tests/hard_coded/random_simple.exp
+++ /dev/null
@@ -1,2 +0,0 @@
-Test passed.
-Test passed.
diff --git a/tests/hard_coded/random_simple.m b/tests/hard_coded/random_simple.m
deleted file mode 100644
index 04d5f8a..0000000
--- a/tests/hard_coded/random_simple.m
+++ /dev/null
@@ -1,36 +0,0 @@
-%---------------------------------------------------------------------------%
-% vim: ts=4 sw=4 et ft=mercury
-%---------------------------------------------------------------------------%
-
-:- module random_simple.
-:- interface.
-:- import_module io.
-
-:- pred main(io::di, io::uo) is det.
-
-:- implementation.
-:- import_module int.
-:- import_module random.
-
-main(!IO) :-
-    Seed = 3,
-    random.init(Seed, RS0),
-    test(1, 20, RS0, RS1, !IO),
-    test(-1, 20, RS1, _, !IO).
-
-:- pred test(int::in, int::in, random.supply::mdi, random.supply::muo,
-    io::di, io::uo) is det.
-
-test(Range, Count, RS0, RS, !IO) :-
-    ( if Count > 0 then
-        random.random(0, Range, N, RS0, RS1),
-        ( if N = 0 then
-            test(Range, Count - 1, RS1, RS, !IO)
-        else
-            io.write_string("Test failed.\n", !IO),
-            RS = RS1
-        )
-    else
-        io.write_string("Test passed.\n", !IO),
-        RS = RS0
-    ).
diff --git a/tests/hard_coded/string_hash.m b/tests/hard_coded/string_hash.m
index 30200b9..82b628b 100644
--- a/tests/hard_coded/string_hash.m
+++ b/tests/hard_coded/string_hash.m
@@ -26,13 +26,14 @@
  :- import_module int.
  :- import_module list.
  :- import_module random.
+:- import_module random.sfc32.
  :- import_module require.
  :- import_module string.

  main(!IO) :-
      MaxLength = 1024,
-    random.init(1, RS0),
-    test(MaxLength, yes, Succeeded, RS0, _, !IO),
+    sfc32.init(RNG, RS0),
+    test(RNG, MaxLength, yes, Succeeded, RS0, _, !IO),
      (
          Succeeded = yes,
          io.write_string("all tests succeeded\n", !IO)
@@ -41,14 +42,14 @@ main(!IO) :-
          io.write_string("some tests failed\n", !IO)
      ).

-:- pred test(int::in, bool::in, bool::out,
-    random.supply::mdi, random.supply::muo, io::di, io::uo) is det.
+:- pred test(RNG::in, int::in, bool::in, bool::out,
+    State::di, State::uo, io::di, io::uo) is det <= urandom(RNG, State).

-test(Length, !Succeeded, !RS, !IO) :-
+test(RNG, Length, !Succeeded, !RS, !IO) :-
      ( if Length < 0 then
          true
      else
-        make_char_list(Length, [], List, !RS),
+        make_char_list(RNG, Length, [], List, !RS),
          string.from_char_list(List, String),

          LibHash1 = string.hash(String),
@@ -75,30 +76,30 @@ test(Length, !Succeeded, !RS, !IO) :-
          RuntimeHash6 = runtime_string_hash6(String),
          test_hash("hash6", LibHash6, RuntimeHash6, String, !Succeeded, !IO),

-        test(Length - 1, !Succeeded, !RS, !IO)
+        test(RNG, Length - 1, !Succeeded, !RS, !IO)
      ).

-:- pred make_char_list(int::in, list(char)::in, list(char)::out,
-    random.supply::mdi, random.supply::muo) is det.
+:- pred make_char_list(RNG::in, int::in, list(char)::in, list(char)::out,
+    State::di, State::uo) is det <= urandom(RNG, State).

-make_char_list(Length, !List, !RS) :-
+make_char_list(RNG, Length, !List, !RS) :-
      ( if Length = 0 then
          true
      else
-        rand_char(Char, !RS),
+        rand_char(RNG, Char, !RS),
          !:List = [Char | !.List],
-        make_char_list(Length - 1, !List, !RS)
+        make_char_list(RNG, Length - 1, !List, !RS)
      ).

-:- pred rand_char(char::out, random.supply::mdi, random.supply::muo) is det.
+:- pred rand_char(RNG::in, char::out, State::di, State::uo) is det
+    <= urandom(RNG, State).

-rand_char(Char, !RS) :-
-    random.random(Rand, !RS),
+rand_char(RNG, Char, !RS) :-
      % U+0001..U+10ffff (avoid null character).
-    Int = 1 + (Rand `mod` char.max_char_value),
+    uniform_int_in_range(RNG, 1, char.max_char_value, Int, !RS),
      char.det_from_int(Int, Char0),
      ( if is_surrogate(Char0) then
-        rand_char(Char, !RS)
+        rand_char(RNG, Char, !RS)
      else
          Char = Char0
      ).



More information about the reviews mailing list