Skip to content

Conversation

@oleksandr-pavlyk
Copy link
Contributor

  1. Introduces support for non-deterministic hardware instruction RDRAND-based basic random number generator on relevant architectures.
In [1]: import mkl_random, numpy as np

In [2]: rs = mkl_random.RandomState(brng='NON_DETERMINISTIC')

In [3]: rs.randn(10)
Out[3]: 
array([ 1.69156146,  0.56649183,  0.26323201,  0.46801072, -0.97351586,
       -1.43365592, -0.73531088, -0.90349218,  0.23288929, -0.24443191])

Because it is hardware-based TRNG, reading pickled state does not produce the same randomness:

In [10]: import pickle

In [11]: rs = mkl_random.RandomState(brng='non_deterministic')

In [12]: rs2 = pickle.loads(pickle.dumps(rs))

In [13]: rs.randint(0, 2**32, size=5)
Out[13]: array([ 649482295, 3967010060, 2807993698, 1176520041, 2802939972])

In [14]: rs2.randint(0, 2**32, size=5)
Out[14]: array([  58520572, 2008182244, 2128388840, 2600218768, 2531220520])

compare to doing the same with pseudo-randomness generator:

In [15]: rs = mkl_random.RandomState(brng='SFMT19937')

In [16]: rs2 = pickle.loads(pickle.dumps(rs))

In [17]: rs.randint(0, 2**32, size=5)
Out[17]: array([3569610330,  417479194,  261680738, 3266235240, 3210854201])

In [18]: rs2.randint(0, 2**32, size=5)
Out[18]: array([3569610330,  417479194,  261680738, 3266235240, 3210854201])
  1. Use Intel(R) Math Kernel Library viRngMultinomial directly to draw samples from multinomial distribution
In [19]: pvec = mkl_random.rand(100)

In [20]: pvec /= pvec.sum()

In [21]: pvec.sum()
Out[21]: 1.0

In [22]: %timeit mkl_random.multinomial(1000, pvec, size=10**5)
642 ms ± 1.02 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [23]: s = mkl_random.multinomial(1000, pvec, size=10**5)

In [24]: s[:, 0].mean()
Out[24]: 8.29136

In [25]: pvec[0] * 1000
Out[25]: 8.28811517092862

```
rs = mkl_random.RandomState(brng='NON_DETERMINSTIC')
rs.randn(10)
```

The non-deterministic generator is True RNG, based on processor
instruction RDRAND, see

https://software.intel.com/en-us/mkl-developer-reference-c-basic-generators

Also reorgnalized setup to use mkl_random/_version.py, and bumped
the version to 1.1.0
```
In [1]: import mkl_random, numpy as np

In [2]: %time mkl_random.multinomial(527, np.array([1/16, 3/16, 5/16, 7/16], 'd'), size=10**6)
CPU times: user 820 ms, sys: 0 ns, total: 820 ms
Wall time: 819 ms
Out[2]:
array([[ 29,  90, 176, 232],
       [ 32,  91, 185, 219],
       [ 35,  90, 169, 233],
       ...,
       [ 42,  93, 157, 235],
       [ 28, 105, 152, 242],
       [ 32,  79, 179, 237]], dtype=int32)

In [3]: %timeit mkl_random.multinomial(527, np.array([1/16, 3/16, 5/16, 7/16], 'd'), size=10**6)
803 ms ± 9.77 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [4]: %timeit mkl_random.multinomial(527, np.array([1/16, 3/16, 5/16, 7/16], 'd'), size=10**5)
80.5 ms ± 874 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
```

Previously,

```
In [1]: import mkl_random, numpy as np

In [2]: %timeit mkl_random.multinomial(527, np.array([1/16, 3/16, 5/16, 7/16], 'd'), size=10**6)
1.35 s ± 2.35 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [3]: %timeit mkl_random.multinomial(527, np.array([1/16, 3/16, 5/16, 7/16], 'd'), size=10**5)
135 ms ± 613 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
```
@oleksandr-pavlyk oleksandr-pavlyk merged commit 5b2ee1a into master Sep 5, 2019
@oleksandr-pavlyk oleksandr-pavlyk deleted the support-non-deterministic-generator branch September 5, 2019 21:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant