:py:mod:`kwarray.fast_rand` =========================== .. py:module:: kwarray.fast_rand .. autoapi-nested-parse:: Fast 32-bit random functions for numpy as of 2018. (More recent versions of numpy may have these natively supported). Module Contents --------------- Functions ~~~~~~~~~ .. autoapisummary:: kwarray.fast_rand.uniform kwarray.fast_rand.standard_normal kwarray.fast_rand.standard_normal32 kwarray.fast_rand.standard_normal64 kwarray.fast_rand.uniform32 .. py:function:: uniform(low=0.0, high=1.0, size=None, dtype=np.float32, rng=np.random) Draws float32 samples from a uniform distribution. Samples are uniformly distributed over the half-open interval ``[low, high)`` (includes low, but excludes high). :Parameters: * **low** (*float, default=0.0*) -- Lower boundary of the output interval. All values generated will be greater than or equal to low. * **high** (*float, default=1.0*) -- Upper boundary of the output interval. All values generated will be less than high. * **size** (*int | Tuple[int], default=None*) -- Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), a single value is returned if ``low`` and ``high`` are both scalars. Otherwise, ``np.broadcast(low, high).size`` samples are drawn. * **dtype** (*type*) -- either np.float32 or np.float64 * **rng** (*numpy.random.RandomState*) -- underlying random state :returns: normally distributed random numbers with chosen dtype :rtype: ndarray[dtype] Benchmark: >>> from timerit import Timerit >>> import kwarray >>> size = (300, 300, 3) >>> for timer in Timerit(100, bestof=10, label='dtype=np.float32'): >>> rng = kwarray.ensure_rng(0) >>> with timer: >>> ours = standard_normal(size, rng=rng, dtype=np.float32) >>> # Timed best=4.705 ms, mean=4.75 ± 0.085 ms for dtype=np.float32 >>> for timer in Timerit(100, bestof=10, label='dtype=np.float64'): >>> rng = kwarray.ensure_rng(0) >>> with timer: >>> theirs = standard_normal(size, rng=rng, dtype=np.float64) >>> # Timed best=9.327 ms, mean=9.794 ± 0.4 ms for rng.np.float64 .. py:function:: standard_normal(size, mean=0, std=1, dtype=float, rng=np.random) Draw samples from a standard Normal distribution with a specified mean and standard deviation. :Parameters: * **size** (*int | Tuple[int, *int]*) -- shape of the returned ndarray * **mean** (*float, default=0*) -- mean of the normal distribution * **std** (*float, default=1*) -- standard deviation of the normal distribution * **dtype** (*type*) -- either np.float32 or np.float64 * **rng** (*numpy.random.RandomState*) -- underlying random state :returns: normally distributed random numbers with chosen dtype :rtype: ndarray[dtype] Benchmark: >>> from timerit import Timerit >>> import kwarray >>> size = (300, 300, 3) >>> for timer in Timerit(100, bestof=10, label='dtype=np.float32'): >>> rng = kwarray.ensure_rng(0) >>> with timer: >>> ours = standard_normal(size, rng=rng, dtype=np.float32) >>> # Timed best=4.705 ms, mean=4.75 ± 0.085 ms for dtype=np.float32 >>> for timer in Timerit(100, bestof=10, label='dtype=np.float64'): >>> rng = kwarray.ensure_rng(0) >>> with timer: >>> theirs = standard_normal(size, rng=rng, dtype=np.float64) >>> # Timed best=9.327 ms, mean=9.794 ± 0.4 ms for rng.np.float64 .. py:function:: standard_normal32(size, mean=0, std=1, rng=np.random) Fast normally distributed random variables using the Box–Muller transform The difference between this function and :func:`numpy.random.standard_normal` is that we use float32 arrays in the backend instead of float64. Halving the amount of bits that need to be manipulated can significantly reduce the execution time, and 32-bit precision is often good enough. :Parameters: * **size** (*int | Tuple[int, *int]*) -- shape of the returned ndarray * **mean** (*float, default=0*) -- mean of the normal distribution * **std** (*float, default=1*) -- standard deviation of the normal distribution * **rng** (*numpy.random.RandomState*) -- underlying random state :returns: normally distributed random numbers :rtype: ndarray[float32] .. rubric:: References https://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform SeeAlso: * standard_normal * standard_normal64 .. rubric:: Example >>> import scipy >>> import scipy.stats >>> pts = 1000 >>> # Our numbers are normally distributed with high probability >>> rng = np.random.RandomState(28041990) >>> ours_a = standard_normal32(pts, rng=rng) >>> ours_b = standard_normal32(pts, rng=rng) + 2 >>> ours = np.concatenate((ours_a, ours_b)) # numerical stability? >>> p = scipy.stats.normaltest(ours)[1] >>> print('Probability our data is non-normal is: {:.4g}'.format(p)) Probability our data is non-normal is: 1.573e-14 >>> rng = np.random.RandomState(28041990) >>> theirs_a = rng.standard_normal(pts) >>> theirs_b = rng.standard_normal(pts) + 2 >>> theirs = np.concatenate((theirs_a, theirs_b)) >>> p = scipy.stats.normaltest(theirs)[1] >>> print('Probability their data is non-normal is: {:.4g}'.format(p)) Probability their data is non-normal is: 3.272e-11 .. rubric:: Example >>> pts = 1000 >>> rng = np.random.RandomState(28041990) >>> ours = standard_normal32(pts, mean=10, std=3, rng=rng) >>> assert np.abs(ours.std() - 3.0) < 0.1 >>> assert np.abs(ours.mean() - 10.0) < 0.1 .. rubric:: Example >>> # Test an even and odd numbers of points >>> assert standard_normal32(3).shape == (3,) >>> assert standard_normal32(2).shape == (2,) >>> assert standard_normal32(1).shape == (1,) >>> assert standard_normal32(0).shape == (0,) >>> assert standard_normal32((3, 1)).shape == (3, 1) >>> assert standard_normal32((3, 0)).shape == (3, 0) .. py:function:: standard_normal64(size, mean=0, std=1, rng=np.random) Simple wrapper around rng.standard_normal to make an API compatible with :func:`standard_normal32`. :Parameters: * **size** (*int | Tuple[int, *int]*) -- shape of the returned ndarray * **mean** (*float, default=0*) -- mean of the normal distribution * **std** (*float, default=1*) -- standard deviation of the normal distribution * **rng** (*numpy.random.RandomState*) -- underlying random state :returns: normally distributed random numbers :rtype: ndarray[float64] SeeAlso: * standard_normal * standard_normal32 .. rubric:: Example >>> pts = 1000 >>> rng = np.random.RandomState(28041994) >>> out = standard_normal64(pts, mean=10, std=3, rng=rng) >>> assert np.abs(out.std() - 3.0) < 0.1 >>> assert np.abs(out.mean() - 10.0) < 0.1 .. py:function:: uniform32(low=0.0, high=1.0, size=None, rng=np.random) Draws float32 samples from a uniform distribution. Samples are uniformly distributed over the half-open interval ``[low, high)`` (includes low, but excludes high). :Parameters: * **low** (*float, default=0.0*) -- Lower boundary of the output interval. All values generated will be greater than or equal to low. * **high** (*float, default=1.0*) -- Upper boundary of the output interval. All values generated will be less than high. * **size** (*int | Tuple[int], default=None*) -- Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. If size is ``None`` (default), a single value is returned if ``low`` and ``high`` are both scalars. Otherwise, ``np.broadcast(low, high).size`` samples are drawn. .. rubric:: Example >>> rng = np.random.RandomState(0) >>> uniform32(low=0.0, high=1.0, size=None, rng=rng) 0.5488... >>> uniform32(low=0.0, high=1.0, size=2000, rng=rng).sum() 1004.94... >>> uniform32(low=-10, high=10.0, size=2000, rng=rng).sum() 202.44... Benchmark: >>> from timerit import Timerit >>> import kwarray >>> size = 512 * 512 >>> for timer in Timerit(100, bestof=10, label='theirs: dtype=np.float64'): >>> rng = kwarray.ensure_rng(0) >>> with timer: >>> theirs = rng.uniform(size=size) >>> for timer in Timerit(100, bestof=10, label='theirs: dtype=np.float32'): >>> rng = kwarray.ensure_rng(0) >>> with timer: >>> theirs = rng.rand(size).astype(np.float32) >>> for timer in Timerit(100, bestof=10, label='ours: dtype=np.float32'): >>> rng = kwarray.ensure_rng(0) >>> with timer: >>> ours = uniform32(size=size)