Skip to content

Commit 50c93b8

Browse files
authored
Merge pull request numpy#15676 from charris/backport-15511
MAINT: Large overhead in some random functions
2 parents b2ff81f + f3432e8 commit 50c93b8

File tree

3 files changed

+72
-92
lines changed

3 files changed

+72
-92
lines changed

numpy/random/_bounded_integers.pyx.in

-10
Original file line numberDiff line numberDiff line change
@@ -51,16 +51,6 @@ cdef extern from "numpy/random/distributions.h":
5151
np.npy_bool *out) nogil
5252

5353

54-
55-
_integers_types = {'bool': (0, 2),
56-
'int8': (-2**7, 2**7),
57-
'int16': (-2**15, 2**15),
58-
'int32': (-2**31, 2**31),
59-
'int64': (-2**63, 2**63),
60-
'uint8': (0, 2**8),
61-
'uint16': (0, 2**16),
62-
'uint32': (0, 2**32),
63-
'uint64': (0, 2**64)}
6454
{{
6555
py:
6656
type_info = (('uint32', 'uint32', 'uint64', 'NPY_UINT64', 0, 0, 0, '0X100000000ULL'),

numpy/random/_generator.pyx

+54-62
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ from libc.stdint cimport (uint8_t, uint16_t, uint32_t, uint64_t,
1717
from ._bounded_integers cimport (_rand_bool, _rand_int32, _rand_int64,
1818
_rand_int16, _rand_int8, _rand_uint64, _rand_uint32, _rand_uint16,
1919
_rand_uint8, _gen_mask)
20-
from ._bounded_integers import _integers_types
2120
from ._pcg64 import PCG64
2221
from numpy.random cimport bitgen_t
2322
from ._common cimport (POISSON_LAM_MAX, CONS_POSITIVE, CONS_NONE,
@@ -262,7 +261,7 @@ cdef class Generator:
262261

263262
def random(self, size=None, dtype=np.float64, out=None):
264263
"""
265-
random(size=None, dtype='d', out=None)
264+
random(size=None, dtype=np.float64, out=None)
266265
267266
Return random floats in the half-open interval [0.0, 1.0).
268267
@@ -278,10 +277,9 @@ cdef class Generator:
278277
Output shape. If the given shape is, e.g., ``(m, n, k)``, then
279278
``m * n * k`` samples are drawn. Default is None, in which case a
280279
single value is returned.
281-
dtype : {str, dtype}, optional
282-
Desired dtype of the result, either 'd' (or 'float64') or 'f'
283-
(or 'float32'). All dtypes are determined by their name. The
284-
default value is 'd'.
280+
dtype : dtype, optional
281+
Desired dtype of the result, only `float64` and `float32` are supported.
282+
Byteorder must be native. The default value is np.float64.
285283
out : ndarray, optional
286284
Alternative output array in which to place the result. If size is not None,
287285
it must have the same shape as the provided size and must match the type of
@@ -312,13 +310,13 @@ cdef class Generator:
312310
313311
"""
314312
cdef double temp
315-
key = np.dtype(dtype).name
316-
if key == 'float64':
313+
_dtype = np.dtype(dtype)
314+
if _dtype == np.float64:
317315
return double_fill(&random_standard_uniform_fill, &self._bitgen, size, self.lock, out)
318-
elif key == 'float32':
316+
elif _dtype == np.float32:
319317
return float_fill(&random_standard_uniform_fill_f, &self._bitgen, size, self.lock, out)
320318
else:
321-
raise TypeError('Unsupported dtype "%s" for random' % key)
319+
raise TypeError('Unsupported dtype %r for random' % _dtype)
322320

323321
def beta(self, a, b, size=None):
324322
"""
@@ -417,7 +415,7 @@ cdef class Generator:
417415

418416
def standard_exponential(self, size=None, dtype=np.float64, method=u'zig', out=None):
419417
"""
420-
standard_exponential(size=None, dtype='d', method='zig', out=None)
418+
standard_exponential(size=None, dtype=np.float64, method='zig', out=None)
421419
422420
Draw samples from the standard exponential distribution.
423421
@@ -431,9 +429,8 @@ cdef class Generator:
431429
``m * n * k`` samples are drawn. Default is None, in which case a
432430
single value is returned.
433431
dtype : dtype, optional
434-
Desired dtype of the result, either 'd' (or 'float64') or 'f'
435-
(or 'float32'). All dtypes are determined by their name. The
436-
default value is 'd'.
432+
Desired dtype of the result, only `float64` and `float32` are supported.
433+
Byteorder must be native. The default value is np.float64.
437434
method : str, optional
438435
Either 'inv' or 'zig'. 'inv' uses the default inverse CDF method.
439436
'zig' uses the much faster Ziggurat method of Marsaglia and Tsang.
@@ -454,24 +451,24 @@ cdef class Generator:
454451
>>> n = np.random.default_rng().standard_exponential((3, 8000))
455452
456453
"""
457-
key = np.dtype(dtype).name
458-
if key == 'float64':
454+
_dtype = np.dtype(dtype)
455+
if _dtype == np.float64:
459456
if method == u'zig':
460457
return double_fill(&random_standard_exponential_fill, &self._bitgen, size, self.lock, out)
461458
else:
462459
return double_fill(&random_standard_exponential_inv_fill, &self._bitgen, size, self.lock, out)
463-
elif key == 'float32':
460+
elif _dtype == np.float32:
464461
if method == u'zig':
465462
return float_fill(&random_standard_exponential_fill_f, &self._bitgen, size, self.lock, out)
466463
else:
467464
return float_fill(&random_standard_exponential_inv_fill_f, &self._bitgen, size, self.lock, out)
468465
else:
469-
raise TypeError('Unsupported dtype "%s" for standard_exponential'
470-
% key)
466+
raise TypeError('Unsupported dtype %r for standard_exponential'
467+
% _dtype)
471468

472469
def integers(self, low, high=None, size=None, dtype=np.int64, endpoint=False):
473470
"""
474-
integers(low, high=None, size=None, dtype='int64', endpoint=False)
471+
integers(low, high=None, size=None, dtype=np.int64, endpoint=False)
475472
476473
Return random integers from `low` (inclusive) to `high` (exclusive), or
477474
if endpoint=True, `low` (inclusive) to `high` (inclusive). Replaces
@@ -496,11 +493,9 @@ cdef class Generator:
496493
Output shape. If the given shape is, e.g., ``(m, n, k)``, then
497494
``m * n * k`` samples are drawn. Default is None, in which case a
498495
single value is returned.
499-
dtype : {str, dtype}, optional
500-
Desired dtype of the result. All dtypes are determined by their
501-
name, i.e., 'int64', 'int', etc, so byteorder is not available
502-
and a specific precision may have different C types depending
503-
on the platform. The default value is `np.int_`.
496+
dtype : dtype, optional
497+
Desired dtype of the result. Byteorder must be native.
498+
The default value is np.int64.
504499
endpoint : bool, optional
505500
If true, sample from the interval [low, high] instead of the
506501
default [low, high)
@@ -559,39 +554,39 @@ cdef class Generator:
559554
high = low
560555
low = 0
561556

562-
dt = np.dtype(dtype)
563-
key = dt.name
564-
if key not in _integers_types:
565-
raise TypeError('Unsupported dtype "%s" for integers' % key)
566-
if not dt.isnative:
567-
raise ValueError('Providing a dtype with a non-native byteorder '
568-
'is not supported. If you require '
569-
'platform-independent byteorder, call byteswap '
570-
'when required.')
557+
_dtype = np.dtype(dtype)
571558

572559
# Implementation detail: the old API used a masked method to generate
573560
# bounded uniform integers. Lemire's method is preferable since it is
574561
# faster. randomgen allows a choice, we will always use the faster one.
575562
cdef bint _masked = False
576563

577-
if key == 'int32':
564+
if _dtype == np.int32:
578565
ret = _rand_int32(low, high, size, _masked, endpoint, &self._bitgen, self.lock)
579-
elif key == 'int64':
566+
elif _dtype == np.int64:
580567
ret = _rand_int64(low, high, size, _masked, endpoint, &self._bitgen, self.lock)
581-
elif key == 'int16':
568+
elif _dtype == np.int16:
582569
ret = _rand_int16(low, high, size, _masked, endpoint, &self._bitgen, self.lock)
583-
elif key == 'int8':
570+
elif _dtype == np.int8:
584571
ret = _rand_int8(low, high, size, _masked, endpoint, &self._bitgen, self.lock)
585-
elif key == 'uint64':
572+
elif _dtype == np.uint64:
586573
ret = _rand_uint64(low, high, size, _masked, endpoint, &self._bitgen, self.lock)
587-
elif key == 'uint32':
574+
elif _dtype == np.uint32:
588575
ret = _rand_uint32(low, high, size, _masked, endpoint, &self._bitgen, self.lock)
589-
elif key == 'uint16':
576+
elif _dtype == np.uint16:
590577
ret = _rand_uint16(low, high, size, _masked, endpoint, &self._bitgen, self.lock)
591-
elif key == 'uint8':
578+
elif _dtype == np.uint8:
592579
ret = _rand_uint8(low, high, size, _masked, endpoint, &self._bitgen, self.lock)
593-
elif key == 'bool':
580+
elif _dtype == np.bool_:
594581
ret = _rand_bool(low, high, size, _masked, endpoint, &self._bitgen, self.lock)
582+
elif not _dtype.isnative:
583+
raise ValueError('Providing a dtype with a non-native byteorder '
584+
'is not supported. If you require '
585+
'platform-independent byteorder, call byteswap '
586+
'when required.')
587+
else:
588+
raise TypeError('Unsupported dtype %r for integers' % _dtype)
589+
595590

596591
if size is None and dtype in (bool, int, np.compat.long):
597592
if np.array(ret).shape == ():
@@ -977,7 +972,7 @@ cdef class Generator:
977972
# Complicated, continuous distributions:
978973
def standard_normal(self, size=None, dtype=np.float64, out=None):
979974
"""
980-
standard_normal(size=None, dtype='d', out=None)
975+
standard_normal(size=None, dtype=np.float64, out=None)
981976
982977
Draw samples from a standard Normal distribution (mean=0, stdev=1).
983978
@@ -987,10 +982,9 @@ cdef class Generator:
987982
Output shape. If the given shape is, e.g., ``(m, n, k)``, then
988983
``m * n * k`` samples are drawn. Default is None, in which case a
989984
single value is returned.
990-
dtype : {str, dtype}, optional
991-
Desired dtype of the result, either 'd' (or 'float64') or 'f'
992-
(or 'float32'). All dtypes are determined by their name. The
993-
default value is 'd'.
985+
dtype : dtype, optional
986+
Desired dtype of the result, only `float64` and `float32` are supported.
987+
Byteorder must be native. The default value is np.float64.
994988
out : ndarray, optional
995989
Alternative output array in which to place the result. If size is not None,
996990
it must have the same shape as the provided size and must match the type of
@@ -1038,14 +1032,13 @@ cdef class Generator:
10381032
[ 0.39924804, 4.68456316, 4.99394529, 4.84057254]]) # random
10391033
10401034
"""
1041-
key = np.dtype(dtype).name
1042-
if key == 'float64':
1035+
_dtype = np.dtype(dtype)
1036+
if _dtype == np.float64:
10431037
return double_fill(&random_standard_normal_fill, &self._bitgen, size, self.lock, out)
1044-
elif key == 'float32':
1038+
elif _dtype == np.float32:
10451039
return float_fill(&random_standard_normal_fill_f, &self._bitgen, size, self.lock, out)
1046-
10471040
else:
1048-
raise TypeError('Unsupported dtype "%s" for standard_normal' % key)
1041+
raise TypeError('Unsupported dtype %r for standard_normal' % _dtype)
10491042

10501043
def normal(self, loc=0.0, scale=1.0, size=None):
10511044
"""
@@ -1151,7 +1144,7 @@ cdef class Generator:
11511144

11521145
def standard_gamma(self, shape, size=None, dtype=np.float64, out=None):
11531146
"""
1154-
standard_gamma(shape, size=None, dtype='d', out=None)
1147+
standard_gamma(shape, size=None, dtype=np.float64, out=None)
11551148
11561149
Draw samples from a standard Gamma distribution.
11571150
@@ -1167,10 +1160,9 @@ cdef class Generator:
11671160
``m * n * k`` samples are drawn. If size is ``None`` (default),
11681161
a single value is returned if ``shape`` is a scalar. Otherwise,
11691162
``np.array(shape).size`` samples are drawn.
1170-
dtype : {str, dtype}, optional
1171-
Desired dtype of the result, either 'd' (or 'float64') or 'f'
1172-
(or 'float32'). All dtypes are determined by their name. The
1173-
default value is 'd'.
1163+
dtype : dtype, optional
1164+
Desired dtype of the result, only `float64` and `float32` are supported.
1165+
Byteorder must be native. The default value is np.float64.
11741166
out : ndarray, optional
11751167
Alternative output array in which to place the result. If size is
11761168
not None, it must have the same shape as the provided size and
@@ -1227,19 +1219,19 @@ cdef class Generator:
12271219
12281220
"""
12291221
cdef void *func
1230-
key = np.dtype(dtype).name
1231-
if key == 'float64':
1222+
_dtype = np.dtype(dtype)
1223+
if _dtype == np.float64:
12321224
return cont(&random_standard_gamma, &self._bitgen, size, self.lock, 1,
12331225
shape, 'shape', CONS_NON_NEGATIVE,
12341226
0.0, '', CONS_NONE,
12351227
0.0, '', CONS_NONE,
12361228
out)
1237-
if key == 'float32':
1229+
if _dtype == np.float32:
12381230
return cont_f(&random_standard_gamma_f, &self._bitgen, size, self.lock,
12391231
shape, 'shape', CONS_NON_NEGATIVE,
12401232
out)
12411233
else:
1242-
raise TypeError('Unsupported dtype "%s" for standard_gamma' % key)
1234+
raise TypeError('Unsupported dtype %r for standard_gamma' % _dtype)
12431235

12441236
def gamma(self, shape, scale=1.0, size=None):
12451237
"""

numpy/random/mtrand.pyx

+18-20
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ from libc.stdint cimport int64_t, uint64_t
1515
from ._bounded_integers cimport (_rand_bool, _rand_int32, _rand_int64,
1616
_rand_int16, _rand_int8, _rand_uint64, _rand_uint32, _rand_uint16,
1717
_rand_uint8,)
18-
from ._bounded_integers import _integers_types
1918
from ._mt19937 import MT19937 as _MT19937
2019
from numpy.random cimport bitgen_t
2120
from ._common cimport (POISSON_LAM_MAX, CONS_POSITIVE, CONS_NONE,
@@ -641,7 +640,7 @@ cdef class RandomState:
641640

642641
def randint(self, low, high=None, size=None, dtype=int):
643642
"""
644-
randint(low, high=None, size=None, dtype='l')
643+
randint(low, high=None, size=None, dtype=int)
645644
646645
Return random integers from `low` (inclusive) to `high` (exclusive).
647646
@@ -668,10 +667,8 @@ cdef class RandomState:
668667
``m * n * k`` samples are drawn. Default is None, in which case a
669668
single value is returned.
670669
dtype : dtype, optional
671-
Desired dtype of the result. All dtypes are determined by their
672-
name, i.e., 'int64', 'int', etc, so byteorder is not available
673-
and a specific precision may have different C types depending
674-
on the platform. The default value is `np.int_`.
670+
Desired dtype of the result. Byteorder must be native.
671+
The default value is int.
675672
676673
.. versionadded:: 1.11.0
677674
@@ -722,17 +719,16 @@ cdef class RandomState:
722719
high = low
723720
low = 0
724721

725-
dt = np.dtype(dtype)
726-
key = dt.name
727-
if key not in _integers_types:
728-
raise TypeError('Unsupported dtype "%s" for randint' % key)
729-
if not dt.isnative:
722+
_dtype = np.dtype(dtype)
723+
724+
if not _dtype.isnative:
730725
# numpy 1.17.0, 2019-05-28
731726
warnings.warn('Providing a dtype with a non-native byteorder is '
732727
'not supported. If you require platform-independent '
733728
'byteorder, call byteswap when required.\nIn future '
734729
'version, providing byteorder will raise a '
735730
'ValueError', DeprecationWarning)
731+
_dtype = _dtype.newbyteorder()
736732

737733
# Implementation detail: the use a masked method to generate
738734
# bounded uniform integers. Lemire's method is preferable since it is
@@ -741,24 +737,26 @@ cdef class RandomState:
741737
cdef bint _masked = True
742738
cdef bint _endpoint = False
743739

744-
if key == 'int32':
740+
if _dtype == np.int32:
745741
ret = _rand_int32(low, high, size, _masked, _endpoint, &self._bitgen, self.lock)
746-
elif key == 'int64':
742+
elif _dtype == np.int64:
747743
ret = _rand_int64(low, high, size, _masked, _endpoint, &self._bitgen, self.lock)
748-
elif key == 'int16':
744+
elif _dtype == np.int16:
749745
ret = _rand_int16(low, high, size, _masked, _endpoint, &self._bitgen, self.lock)
750-
elif key == 'int8':
746+
elif _dtype == np.int8:
751747
ret = _rand_int8(low, high, size, _masked, _endpoint, &self._bitgen, self.lock)
752-
elif key == 'uint64':
748+
elif _dtype == np.uint64:
753749
ret = _rand_uint64(low, high, size, _masked, _endpoint, &self._bitgen, self.lock)
754-
elif key == 'uint32':
750+
elif _dtype == np.uint32:
755751
ret = _rand_uint32(low, high, size, _masked, _endpoint, &self._bitgen, self.lock)
756-
elif key == 'uint16':
752+
elif _dtype == np.uint16:
757753
ret = _rand_uint16(low, high, size, _masked, _endpoint, &self._bitgen, self.lock)
758-
elif key == 'uint8':
754+
elif _dtype == np.uint8:
759755
ret = _rand_uint8(low, high, size, _masked, _endpoint, &self._bitgen, self.lock)
760-
elif key == 'bool':
756+
elif _dtype == np.bool_:
761757
ret = _rand_bool(low, high, size, _masked, _endpoint, &self._bitgen, self.lock)
758+
else:
759+
raise TypeError('Unsupported dtype %r for randint' % _dtype)
762760

763761
if size is None and dtype in (bool, int, np.compat.long):
764762
if np.array(ret).shape == ():

0 commit comments

Comments
 (0)