<div dir="ltr">I agree with pretty much everything you wrote Robert.  I didn't have quote the right frame but the generic class that takes a low-level core PRNG sounds like the right design, and this should make user-generated distributions easier to develop.  I was thinking along these lines inspired by the SpiPy changes that use a LowLevelCallable, e.g., <div><br></div><div><font color="#212121"><a href="https://ilovesymposia.com/2017/03/12/scipys-new-lowlevelcallable-is-a-game-changer/">https://ilovesymposia.com/2017/03/12/scipys-new-lowlevelcallable-is-a-game-changer/</a></font> <br></div><div><br></div><div>This might also allow users to extend the core PRNGs using something like Numba JIT classes as an alternative.</div><div><br></div><div>Another area that needs though is how to correctly spawn in Multiprocess application. This might be most easily addressed by providing a guide on a good way rather than the arbitrary way used now.</div><div><br></div><div>Kevin</div><div><br></div><div><br></div><div><br></div><div><br><br><div class="gmail_quote"><div dir="ltr">On Sat, Jan 27, 2018 at 5:03 PM <<a href="mailto:numpy-discussion-request@python.org">numpy-discussion-request@python.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Send NumPy-Discussion mailing list submissions to<br>
        <a href="mailto:numpy-discussion@python.org" target="_blank">numpy-discussion@python.org</a><br>
<br>
To subscribe or unsubscribe via the World Wide Web, visit<br>
        <a href="https://mail.python.org/mailman/listinfo/numpy-discussion" rel="noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/numpy-discussion</a><br>
or, via email, send a message with subject or body 'help' to<br>
        <a href="mailto:numpy-discussion-request@python.org" target="_blank">numpy-discussion-request@python.org</a><br>
<br>
You can reach the person managing the list at<br>
        <a href="mailto:numpy-discussion-owner@python.org" target="_blank">numpy-discussion-owner@python.org</a><br>
<br>
When replying, please edit your Subject line so it is more specific<br>
than "Re: Contents of NumPy-Discussion digest..."<br>
<br>
<br>
Today's Topics:<br>
<br>
   1. Re: Moving NumPy's PRNG Forward (Robert Kern)<br>
   2. Re: Using np.frombuffer and cffi.buffer on array of C structs<br>
      (problem with struct member padding) (Joe)<br>
<br>
<br>
----------------------------------------------------------------------<br>
<br>
Message: 1<br>
Date: Sat, 27 Jan 2018 09:28:54 +0900<br>
From: Robert Kern <<a href="mailto:robert.kern@gmail.com" target="_blank">robert.kern@gmail.com</a>><br>
To: Discussion of Numerical Python <<a href="mailto:numpy-discussion@python.org" target="_blank">numpy-discussion@python.org</a>><br>
Subject: Re: [Numpy-discussion] Moving NumPy's PRNG Forward<br>
Message-ID:<br>
        <CAF6FJitFLv3U7gHkYBCFW69A5BbVe=HzBAm5oxYVcXGbBdMU=<a href="mailto:w@mail.gmail.com" target="_blank">w@mail.gmail.com</a>><br>
Content-Type: text/plain; charset="utf-8"<br>
<br>
On Sat, Jan 27, 2018 at 1:14 AM, Kevin Sheppard <<a href="mailto:kevin.k.sheppard@gmail.com" target="_blank">kevin.k.sheppard@gmail.com</a>><br>
wrote:<br>
><br>
> I am a firm believer that the current situation is not sustainable.<br>
There are a lot of improvements that can practically be incorporated.<br>
While many of these are performance related, there are also improvements in<br>
accuracy over some ranges of parameters that cannot be incorporated. I also<br>
think that perfect stream reproducibility is a bit of a myth across<br>
versions since this really would require identical OS, compiler and<br>
possibly CPU for some of the generators that produce floats.<br>
><br>
> I believe there is a case for separating the random generator from core<br>
NumPy.  Some points that favor becoming a subproject:<br>
><br>
> 1. It is a pure consumer of NumPy API.  Other parts of the API do no<br>
depend on random.<br>
> 2. A stand alone package could be installed along side many different<br>
version of core NumPy which would reduce the pressure on freezing the<br>
stream.<br>
<br>
Removing numpy.random (or freezing it as deprecated legacy while all PRNG<br>
development moves elsewhere) is probably a non-starter. It's too used for<br>
us not to provide something. That said, we can (and ought to) make it much<br>
easier for external packages to provide PRNG capabilities (core PRNGs and<br>
distributions) that interoperate with the core functionality that numpy<br>
provides. I'm also happy to place a high barrier on adding more<br>
distributions to numpy.random once that is in place.<br>
<br>
Specifically, core uniform PRNGs should have a small common C API that<br>
distribution functions can use. This might just be a struct with an opaque<br>
`void*` state pointer and then 2 function pointers for drawing a uint64<br>
(whole range) and a double in [0,1) from the state. It's important to<br>
expose our core uniform PRNGs as a C API because there has been a desire to<br>
interoperate at that level, using the same PRNG state inside C or Fortran<br>
or GPU code. If that's in place, then people can write new efficient<br>
distribution functions in C that use this small C API agnostic to the core<br>
PRNG algorithm. It also makes it easy to implement new core PRNGs that the<br>
distribution functions provided by numpy.random can use.<br>
<br>
> In terms of what is needed, I think that the underlying PRNG should be<br>
swappable.  The will provide a simple mechanism to allow certain types of<br>
advancement while easily providing backward compat.  In the current design<br>
this is very hard and requires compiling many nearly identical copies of<br>
RandomState. In pseudocode something like<br>
><br>
> standard_normal(prng)<br>
><br>
> where prng is a basic class that retains the PRNG state and has a small<br>
set of core random number generators that belong to the underlying PRNG --<br>
probably something like int32, int64, double, and possibly int53. I am not<br>
advocating explicitly passing the PRNG as an argument, but having<br>
generators which can take any suitable PRNG would add a lot of flexibility<br>
in terms of taking advantage of improvements in the underlying PRNGs (see,<br>
e.g., xoroshiro128/xorshift1024).  The "small" core PRNG would have<br>
responsibility over state and streams.  The remainder of the module would<br>
transform the underlying PRNG into the required distributions.<br>
<br>
(edit: after writing the following verbiage, I realize it can be summed up<br>
with more respect to your suggestion: yes, we should do this design, but we<br>
don't need to and shouldn't give up on a class with distribution methods.)<br>
<br>
Once the core PRNG C API is in place, I don't think we necessarily need to<br>
move away from a class structure per se, though it becomes an option. We<br>
just separate the core PRNG object from the distribution-providing class.<br>
We don't need to make copies of the distribution-providing class just to<br>
use a new core PRNG. I'm coming around to Nathaniel's suggestion for the<br>
constructor API (though not the distribution-versioning, for reasons I can<br>
get into later).  We have a couple of core uniform PRNG classes like<br>
`MT19937` and `PCG128`. Those have a tiny API, and probably don't have a<br>
lot of unnecessary code clones between them. Their constructors can be<br>
different depending on the different ways they can be instantiated,<br>
depending on the PRNG's features. I'm not sure that they'll have any common<br>
methods besides `__getstate__/__setstate__` and probably a `copy()`. They<br>
will expose their C API as a Python-opaque attribute. They can have<br>
whatever algorithm-dependent methods they need (e.g. to support jumpahead).<br>
I might not even expose to Python the uint64 and U(0,1) double sampling<br>
methods, but maybe so.<br>
<br>
Then we have a single `Distributions` class that provides all of the<br>
distributions that we want to support in numpy.random (i.e. what we<br>
currently have on `RandomState` and whatever passes our higher bar in the<br>
future). It takes one of the core PRNG instances as an argument to the<br>
constructor (nominally, at least; we can design factory functions to make<br>
this more convenient).<br>
<br>
  prng = Distributions(PCG128(seed))<br>
  x = prng.normal(mean, std)<br>
<br>
If someone wants to write a WELL512 core PRNG, they can just implement that<br>
object and pass it to `Distributions()`. The `Distributions` code doesn't<br>
need to be copied, nor do we need to much around with `__new__` tricks in<br>
Cython.<br>
<br>
Why do this instead of distribution functions? Well, I have a damn lot of<br>
code that is expecting an object with at least the broad outlines of the<br>
`RandomState` interface. I'm not going to update that code to use functions<br>
instead. And if I'm not, no one is. There isn't a good transition path<br>
since the PRNG object needs to thread through all of the code, whether it's<br>
my code that I'm writing greenfield or library code that I don't control.<br>
That said, people writing new distributions outside of numpy.random would<br>
be writing functions, not trying to add to the `Distributions` class, but<br>
that's fine.<br>
<br>
It also allows the possibility for the `Distributions` class to be stateful<br>
if we want to do things like caching the next Box-Muller variate and not<br>
force that onto the core PRNG state like I currently do. Though I'd rather<br>
just drop Box-Muller, and that's not a common pattern outside of<br>
Box-Muller. But it's a possibility.<br>
<br>
--<br>
Robert Kern<br>
-------------- next part --------------<br>
An HTML attachment was scrubbed...<br>
URL: <<a href="http://mail.python.org/pipermail/numpy-discussion/attachments/20180127/c76673e3/attachment-0001.html" rel="noreferrer" target="_blank">http://mail.python.org/pipermail/numpy-discussion/attachments/20180127/c76673e3/attachment-0001.html</a>><br>
<br>
------------------------------<br>
<br>
Message: 2<br>
Date: Sat, 27 Jan 2018 10:30:47 +0100<br>
From: Joe <<a href="mailto:solarjoe@posteo.org" target="_blank">solarjoe@posteo.org</a>><br>
To: <a href="mailto:numpy-discussion@python.org" target="_blank">numpy-discussion@python.org</a><br>
Subject: Re: [Numpy-discussion] Using np.frombuffer and cffi.buffer on<br>
        array of C structs (problem with struct member padding)<br>
Message-ID: <<a href="mailto:fed22682-60fd-0a5d-aaa5-83e67d9d1069@posteo.org" target="_blank">fed22682-60fd-0a5d-aaa5-83e67d9d1069@posteo.org</a>><br>
Content-Type: text/plain; charset=utf-8; format=flowed<br>
<br>
Thanks for your help on this! This solved my issue.<br>
<br>
<br>
Am 25.01.2018 um 19:01 schrieb Allan Haldane:<br>
> There is a new section discussing alignment in the numpy 1.14 structured<br>
> array docs, which has some hints about interfacing with C structs.<br>
><br>
> These new 1.14 docs are not online yet on <a href="http://scipy.org" rel="noreferrer" target="_blank">scipy.org</a>, but in the meantime<br>
>   you can view them here:<br>
> <a href="https://ahaldane.github.io/user/basics.rec.html#automatic-byte-offsets-and-alignment" rel="noreferrer" target="_blank">https://ahaldane.github.io/user/basics.rec.html#automatic-byte-offsets-and-alignment</a><br>
><br>
> (That links specifically to the discussion of alignments and padding).<br>
><br>
> Allan<br>
><br>
> On 01/25/2018 11:33 AM, Chris Barker - NOAA Federal wrote:<br>
>><br>
>>><br>
>>> The numpy dtype constructor takes an ?align? keyword that will pad it<br>
>>> for you.<br>
>><br>
>> <a href="https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.dtype.html" rel="noreferrer" target="_blank">https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.dtype.html</a><br>
>><br>
>> -CHB<br>
>><br>
>><br>
>><br>
>> _______________________________________________<br>
>> NumPy-Discussion mailing list<br>
>> <a href="mailto:NumPy-Discussion@python.org" target="_blank">NumPy-Discussion@python.org</a><br>
>> <a href="https://mail.python.org/mailman/listinfo/numpy-discussion" rel="noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/numpy-discussion</a><br>
>><br>
><br>
> _______________________________________________<br>
> NumPy-Discussion mailing list<br>
> <a href="mailto:NumPy-Discussion@python.org" target="_blank">NumPy-Discussion@python.org</a><br>
> <a href="https://mail.python.org/mailman/listinfo/numpy-discussion" rel="noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/numpy-discussion</a><br>
><br>
<br>
<br>
------------------------------<br>
<br>
Subject: Digest Footer<br>
<br>
_______________________________________________<br>
NumPy-Discussion mailing list<br>
<a href="mailto:NumPy-Discussion@python.org" target="_blank">NumPy-Discussion@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/numpy-discussion" rel="noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/numpy-discussion</a><br>
<br>
<br>
------------------------------<br>
<br>
End of NumPy-Discussion Digest, Vol 136, Issue 37<br>
*************************************************<br>
</blockquote></div></div></div>