Re: [m-users.] Random Number Generator

Volker Wysk <[email protected]>
Newsgroups gmane.comp.lang.mercury.general
Message-ID <[email protected]>
Am Montag, dem 31.07.2023 um 22:33 +1000 schrieb Julien Fischer:
> On Mon, 31 Jul 2023, Volker Wysk wrote:
> 
> > Am Montag, dem 31.07.2023 um 09:46 +1000 schrieb Mark Brown:
> 
> > > In C terms, this is akin to having access to a global resource (e,g,,
> > > /dev/urandom), but having your code pass around the file handle with
> > > which the process accesses it. You could avoid passing around the
> > > handle by using a global static variable if you wanted.
> > > 
> > > Similarly, in Mercury you could use a module-local mutable variable to
> > > store the system_rng handle, once initialized.
> > 
> > I'm using system_rng for creating a random seed only. It's the "M" variable
> > of type io_urandom(P, S), the result of make_io_urandom, which I don't want
> > to carry around.
> > 
> > I've looked for info on mutable variables and found the modules thread.mvar,
> > store and mutvar (which is undocumented). It's confusing. It uses impurity
> > and I can't see how to make and initialize a handle to a mutable variable
> > local to a module, such that nothing needs to be carried around. It looks to
> > me like some use of promise_pure is needed - but would that be safe?
> 
> Mark is referring to module-local mutable variables as described in
> section 10.6 of the reference manual. Have a look at what the
> attach_to_io_state attribute does.

I've got it working, using a mutable variable. Now there's no more dummy
variable that needs to be carried around. Thanks!

I've attached it, for people who like to learn by example (hint! ;-) ).

> 
> > > > Actually, that M argument is of type params and this is a dummy type (from
> > > > the source code of random.sfc64):
> > > > 
> > > > :- type params
> > > >     --->    params.
> > > > 
> > > > It's the same for random.sfc32, but not for random.sfc16. And the module
> > > > random.sfc64 defines this:
> > > > 
> > > > :- pred generate_uint64(uint64::out, ustate::di, ustate::uo) is det.
> > > > 
> > > > That's looks like what I need, but there isn't such a member of the urandom
> > > > type class, which I need to use when I want it to be attached to the IO
> > > > state.
> > > 
> > > Since you're digging into the implementation, you could look at the
> > > source code of make_io_urandom to see what's going on. It wraps the
> > > ustate, which is destructively updatable because it is unique (it's an
> > > array), in a mutvar, which is destructively updatable because it is
> > > attached to the I/O state.
> > > 
> > > By "destructively updatable" I mean that there is some way for the
> > > compiler to verify that such an update is safe. The two interfaces
> > > provide two such options, though the actual update that is happening
> > > is the same either way.
> > 
> > Sorry, but this makes me even more confused. I think, I'll bite the bullet
> > and pass around that dummy variable.
> 
> The dummy variable is necessary because otherwise you couldn't create
> instances of the urandom type class.  Also, for some random number
> generators, it is not a dummy variable (e.g. on some systems the
> system_rng handle contains the file descriptor used to open /dev/urandom
> etc.)

I was wondering why the dummy (or non-dummy) value isn't included in the
random state. Zoltan's answer makes that clear.

Cheers,
Volker

_______________________________________________
users mailing list
[email protected]
https://lists.mercurylang.org/listinfo/users
random128.m (text/x-matlab, 2.7 KB)
%====================================================================================================
% The 128 bit random number generator for directory identities
%====================================================================================================
:- module random128.
:- interface.
:- import_module io.


% Make a 128 bit random number and return it as a hexadecimal string of length 32. On the first call, this will
% initialize the used random number generator with a seed received from the system random number generator (for
% Linux, this reads from /dev/urandom).

:- pred random128(string::out, io::di, io::uo) is det.


% :- pred main(io::di, io::uo) is det.

:- implementation.
:- import_module random, random.sfc64, random.system_rng, string, list, maybe, int, int64, require.


random128(Random, !IO) :-
    get_maybedummy(MaybeDummy, !IO),
    (
        % Already seeded the random generator
        MaybeDummy = yes(Dummy)
    ;
        % Seed the random generator
        MaybeDummy = no,
        open_system_rng(MaybeHandle, !IO),
        (
            MaybeHandle = maybe.ok(Handle),

            random.system_rng.generate_uint64(Handle, Seed1, !IO),
            random.system_rng.generate_uint64(Handle, Seed2, !IO),
            random.system_rng.generate_uint64(Handle, Seed3, !IO),

            random.sfc64.seed(Seed1, Seed2, Seed3, P, RandState),
            make_io_urandom(P, RandState, Dummy, !IO),

            set_maybedummy(yes(Dummy), !IO)
        ;
            MaybeHandle = maybe.error(Msg),
            unexpected($pred, "Error opening system random number generator:\n" ++ Msg)
        )
    ),

    random.generate_uint64(Dummy, Rand1, !IO),
    random.generate_uint64(Dummy, Rand2, !IO),
    Random = fill_hex_16(string.uint64_to_hex_string(Rand1)) ++
             fill_hex_16(string.uint64_to_hex_string(Rand2)).



% Mutable variable for storing the dummy value which is needed for the random.generate_uint64 predicate. So we
% don't need to carry this value around. See section "10.6 Module-local mutable variables" in the Language
% Reference Manual.

:- mutable(
    maybedummy,
    maybe(random.io_urandom(random.sfc64.params, random.sfc64.ustate)),
    no,
    ground,
    [attach_to_io_state, untrailed]
).



% Fill the string with leading zeros, such that it has 16 digits.

:- func fill_hex_16(string) = string.

fill_hex_16(HexStr) =
    string.join_list(
        "",
        map((func(_) = "0"), 1 .. (16-length(HexStr)))
        ++ [HexStr]).


% main(!IO) :-
%     foldl(
%         (pred(_::in, !.IO1::di, !:IO1::uo) is det :- 
%             random128(Rand, !IO1),
%             io.format("Rand = %s\n", [s(Rand)], !IO1)
%         ),
%         1 .. 10,
%         !IO).
signature.asc (application/pgp-signature, 833 B)
-----BEGIN PGP SIGNATURE-----

iQIzBAABCgAdFiEE6QXGh82Ov3+2nrxp+K4ydFOsHoUFAmTIu0sACgkQ+K4ydFOs
HoVcnQ/+O53Lxv+/9hrrOb0/5bAsnAXj+8XioaFLJdpLKYPGoKGnL7ZuybOJjuzS
OgNvJRm1sN7/x4c0BfozNmDjstjNj6iUx+qQoAr/SDHyWbQeo+Gp+6nMHOp6YH7D
5owxJRw/wcda2Nt9G7VfbBz5m4M32MGXVx9Xao0JlBMTL+DeMoxgQhempu3cYWO0
kigf+sWUOQFwc5nKxKRO6mQB2sE0WfsSO72od/txB4Bg6c8gjt3Gu+zUo7SAWL0v
CdLAZD8scDvNZsQe3S+A0WM8U/JhR2bliTKO7VgppV36bkN51ehNh+0694baEKSG
fW10iBfjbUsHidrP4mW1MpLl/YRmWu/LXVt5csrdWLtXJ09gD2K0lk5O+gbYxiM6
4NhrhU1VXaEdCeE+Sk+M22v0XkvNrAsgNatVl6/cGUpMG4AenCVDb64c2QrtDlQL
x+3NBJ+Z7vNt7oz4cXYZ2ex2hTjEwJVjmMXJmePwu3nWSGcQHBzEqorpjJTwax3S
MHm0LypZr4mq/aQ8xYgyLCqQmG/wErIHPXEETa2viexP+M/NwhBXI1ORjutQwC1c
BB7jWKxHfYw6ToIKB2SEvvnEOHkS8GcTIslJ7cj5qooH3J80OuOwTYu8xAipMdtb
bvxLhmfGVcxkAv92dX6CSvtbmGn0fC0EZ8RNrsc+8gKD8JDRYWE=
=+bLI
-----END PGP SIGNATURE-----
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.