[m-users.] Announcement: mercury-mt Mercury only Mersenne Twister random numbers

Mark Brown mark at mercurylang.org
Tue Feb 21 00:32:08 AEDT 2023


Hi Mark,

As Volker said, thanks for sharing your work.  In regards to your question,

> Question for Mercury users: is it better to do this as a ground generator or as a unique generator?

Short answer: it's generally best for a library to supply as many
instances as it can correctly implement.  For this application it
would be better to implement it as a unique generator, and use
adapters to make other instances as needed.

Long answer: the choice for the user is similar to the choice of
whether or not to use destructive update in other circumstances.  If
there is a significant amount of state that is frequently updated,
then destructive update is probably worthwhile even though the user
will need to manage uniqueness as a result.  Since MT requires about
2.5k of state and is likely to be used when lots of calls are made,
the unique generator will be the one that most users would want.

If a shared generator is required by the user and they don't mind
copying the state for every number generated, this can be done with
one of the adapters down near the bottom of the random.m interface
rather than re-implementing the algorithm. For example, you can import
mt_unique and define a type:

    :- type random == shared_random(params, ustate).

Then create a generator as follows:

    seed(12345u32, P, R),
    S0 = make_shared_random(P, R)

See the attached file test_mt_1.m.

It's also possible to attach a generator to the I/O state using
make_io_urandom, so that the generator can be used more conveniently
without copying, and without the generator itself needing to be
unique.

The "ugly truth" answer: the shared implementation you've given still
uses arrays underneath, and these are destructively updated and aren't
supposed to be shared.  As a consequence this typeclass instance
doesn't behave correctly if the generator is not actually used in a
unique way.  For example, if the runif test was called twice in
sequence, passing the final state from the first call as the initial
state of the second, we'd expect to observe different numbers.  If it
was run a third time, using the *first* state, it should reproduce the
first numbers again, but the attached file test_mt_2.m shows that it
doesn't.

The underlying problem is that if arrays are put in data structures,
and you refer to an array that has been elsewhere updated, you can get
the new value when logically it should return the old value.  The
correct way to handle this, aside from not referring to old arrays in
the first place, is to copy arrays when required.  That's what the
shared adapter does via urandom_dup   Ideally, the compiler would
check that this is done correctly, but unfortunately the current
implementation doesn't always do that - see the caveat at the start of
array.m.

I've included in the above test some code to demonstrate the problem
just with arrays on their own.

Shortest answer: I'll add some docs to the random.m module to clarify
for instance implementors.  :-)

Hope this helps!

Mark

On Sun, Feb 12, 2023 at 12:38 AM Mark Clements <mark.clements at ki.se> wrote:
>
> I have written a Mercury-only implementation of the Mersenne Twister random number generator. This is a very common and reasonably good pseudo random number generator. For details:
>
> https://github.com/mclements/mercury-mt
>
> Sincerely, Mark.
>
>
> När du skickar e-post till Karolinska Institutet (KI) innebär detta att KI kommer att behandla dina personuppgifter. Här finns information om hur KI behandlar personuppgifter<https://ki.se/medarbetare/integritetsskyddspolicy>.
>
>
> Sending email to Karolinska Institutet (KI) will result in KI processing your personal data. You can read more about KI’s processing of personal data here<https://ki.se/en/staff/data-protection-policy>.
> _______________________________________________
> users mailing list
> users at lists.mercurylang.org
> https://lists.mercurylang.org/listinfo/users
-------------- next part --------------
A non-text attachment was scrubbed...
Name: test_mt_2.m
Type: text/x-objcsrc
Size: 1686 bytes
Desc: not available
URL: <http://lists.mercurylang.org/archives/users/attachments/20230221/c1b39a4a/attachment.bin>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: test_mt_1.m
Type: text/x-objcsrc
Size: 1465 bytes
Desc: not available
URL: <http://lists.mercurylang.org/archives/users/attachments/20230221/c1b39a4a/attachment-0001.bin>


More information about the users mailing list