@@ -11,79 +11,6 @@ _randint_type = {'bool': (0, 2),
1111
1212ctypedef np.npy_bool bool_t
1313
14- {{
15- py:
16- ctypes = (('int64', 'uint64'),
17- ('int32', 'uint32'),
18- ('int16', 'uint16'),
19- ('int8', 'uint8'),
20- ('uint64', 'uint64'),
21- ('uint32', 'uint32'),
22- ('uint16', 'uint16'),
23- ('uint8', 'uint8'),
24- ('bool','bool'),
25- )}}
26-
27- {{for nptype, utype in ctypes}}
28-
29- {{ py: otype = nptype + '_' if nptype == 'bool' else nptype }}
30-
31- cdef object _rand_{{nptype}}(low, high, size, aug_state *state, lock):
32- """
33- _rand_{{nptype}}(self, low, high, size, rngstate)
34-
35- Return random np.{{nptype}} integers between `low` and `high`, inclusive.
36-
37- Return random integers from the "discrete uniform" distribution in the
38- closed interval [`low`, `high`). If `high` is None (the default),
39- then results are from [0, `low`). On entry the arguments are presumed
40- to have been validated for size and order for the np.{{nptype}} type.
41-
42- Parameters
43- ----------
44- low : int
45- Lowest (signed) integer to be drawn from the distribution (unless
46- ``high=None``, in which case this parameter is the *highest* such
47- integer).
48- high : int
49- If provided, the largest (signed) integer to be drawn from the
50- distribution (see above for behavior if ``high=None``).
51- size : int or tuple of ints
52- Output shape. If the given shape is, e.g., ``(m, n, k)``, then
53- ``m * n * k`` samples are drawn. Default is None, in which case a
54- single value is returned.
55- rngstate : encapsulated pointer to rk_state
56- The specific type depends on the python version. In Python 2 it is
57- a PyCObject, in Python 3 a PyCapsule object.
58-
59- Returns
60- -------
61- out : python scalar or ndarray of np.{{nptype}}
62- `size`-shaped array of random integers from the appropriate
63- distribution, or a single such random int if `size` not provided.
64-
65- """
66- cdef {{utype}}_t off, rng, buf
67- cdef {{utype}}_t *out
68- cdef np.ndarray array
69- cdef np.npy_intp cnt
70-
71- rng = <{{utype}}_t>(high - low)
72- off = <{{utype}}_t>(<{{nptype}}_t>low)
73- if size is None:
74- with lock:
75- random_bounded_{{utype}}_fill(state, off, rng, 1, &buf)
76- return np.{{otype}}(<{{nptype}}_t>buf)
77- else:
78- array = <np.ndarray>np.empty(size, np.{{nptype}})
79- cnt = np.PyArray_SIZE(array)
80- out = <{{utype}}_t *>np.PyArray_DATA(array)
81- with lock, nogil:
82- random_bounded_{{utype}}_fill(state, off, rng, cnt, out)
83- return array
84-
85- {{endfor}}
86-
8714cdef inline uint64_t _gen_mask(uint64_t max_val) nogil:
8815 # Smallest bit mask >= max
8916 cdef uint64_t mask = max_val
@@ -110,9 +37,9 @@ bc_ctypes = (('uint32', 'uint32', 'uint64', 'NPY_UINT64', 0, 0, 0, '0X100000000U
11037
11138{{ py: otype = nptype + '_' if nptype == 'bool' else nptype }}
11239
113- cdef object _rand_{{nptype}}_combined (object low, object high, object size, aug_state *state, object lock):
40+ cdef object _rand_{{nptype}}(object low, object high, object size, aug_state *state, object lock):
11441 """
115- _rand_{{nptype}}_combined (low, high, size, *state, lock)
42+ _rand_{{nptype}}(low, high, size, *state, lock)
11643
11744 Return random np.{{nptype}} integers between `low` and `high`, inclusive.
11845
@@ -225,223 +152,6 @@ cdef object _rand_{{nptype}}_combined(object low, object high, object size, aug_
225152{{endfor}}
226153
227154
228- {{
229- py:
230- bc_ctypes = (('uint32', 'uint32', 'uint64', 'NPY_UINT64', 0, 0, 0, '0X100000000ULL'),
231- ('uint16', 'uint16', 'uint32', 'NPY_UINT32', 1, 16, 0, '0X10000UL'),
232- ('uint8', 'uint8', 'uint16', 'NPY_UINT16', 3, 8, 0, '0X100UL'),
233- ('bool','uint8', 'uint8', 'NPY_UINT8', 31, 1, 0, '0x2UL'),
234- ('int32', 'uint32', 'uint64', 'NPY_INT64', 0, 0, '-0x80000000LL', '0x80000000LL'),
235- ('int16', 'uint16', 'uint32', 'NPY_INT32', 1, 16, '-0x8000LL', '0x8000LL' ),
236- ('int8', 'uint8', 'uint16', 'NPY_INT16', 3, 8, '-0x80LL', '0x80LL' ),
237- )}}
238-
239- {{for nptype, utype, nptype_up, npctype, remaining, bitshift, lb, ub in bc_ctypes}}
240-
241- {{ py: otype = nptype + '_' if nptype == 'bool' else nptype }}
242-
243- cdef object _rand_{{nptype}}_broadcast(object low, object high, object size, aug_state *state, object lock):
244- """
245- Generate bounded random {{nptype}} values using broadcasting
246-
247- Parameters
248- ----------
249- low : int or array-like
250- Array containing the lowest (signed) integers to be drawn from the
251- distribution.
252- high : int or array-like
253- Array containing the the open interval bound for the distribution.
254- size : int or tuple of ints
255- Output shape. If the given shape is, e.g., ``(m, n, k)``, then
256- ``m * n * k`` samples are drawn. Default is None, in which case
257- the output shape is determined by the broadcast shapes of low and
258- high
259- state : augmented random state
260- State to use in the core random number generators
261- lock : threading.Lock
262- Lock to prevent multiple using a single RandomState simultaneously
263-
264- Returns
265- -------
266- out : ndarray of np.{{nptype}}
267- array of random integers from the appropriate distribution where the
268- size is determined by size if provided or the broadcast shape of low
269- and high
270- """
271- cdef np.ndarray low_arr, high_arr, out_arr
272- cdef np.npy_intp i
273- cdef np.broadcast it
274- cdef int buf_rem = 0
275-
276- cdef {{utype}}_t *out_data
277- cdef {{utype}}_t val, mask, off
278- cdef {{nptype_up}}_t rng, last_rng, low_v, high_v
279- cdef uint32_t buf
280-
281- # TODO: Direct error check? Probably not
282- # TODO: Make constant?
283- low_arr = <np.ndarray>low
284- high_arr = <np.ndarray>high
285- if np.any(np.less(low_arr, {{lb}})):
286- raise ValueError('low is out of bounds for {{nptype}}')
287- if np.any(np.greater(high_arr, {{ub}})):
288- raise ValueError('high is out of bounds for {{nptype}}')
289- if np.any(np.greater_equal(low_arr, high_arr)):
290- raise ValueError('low >= high')
291-
292- low_arr = <np.ndarray>np.PyArray_FROM_OTF(low, np.{{npctype}}, np.NPY_ALIGNED | np.NPY_FORCECAST)
293- high_arr = <np.ndarray>np.PyArray_FROM_OTF(high, np.{{npctype}}, np.NPY_ALIGNED | np.NPY_FORCECAST)
294-
295- if size is not None:
296- out_arr = <np.ndarray>np.empty(size, np.{{otype}})
297- else:
298- it = np.PyArray_MultiIterNew2(low_arr, high_arr)
299- out_arr = <np.ndarray>np.empty(it.shape, np.{{otype}})
300-
301- it = np.PyArray_MultiIterNew3(low_arr, high_arr, out_arr)
302- out_data = <{{utype}}_t *>np.PyArray_DATA(out_arr)
303- n = np.PyArray_SIZE(out_arr)
304- mask = last_rng = 0
305- with lock, nogil:
306- for i in range(n):
307- low_v = (<{{nptype_up}}_t*>np.PyArray_MultiIter_DATA(it, 0))[0]
308- high_v = (<{{nptype_up}}_t*>np.PyArray_MultiIter_DATA(it, 1))[0]
309- rng = (high_v - 1) - low_v
310- off = <{{utype}}_t>(<{{nptype_up}}_t>low_v)
311- if rng == 0:
312- out_data[i] = 0
313- continue
314-
315- if rng != last_rng:
316- # TODO: Is this too much of an optimization? is it worth it?
317- # Smallest bit mask >= max
318- mask = <{{utype}}_t>_gen_mask(rng)
319-
320- while True:
321- if not buf_rem:
322- buf = random_uint32(state)
323- buf_rem = {{remaining}}
324- else:
325- buf >>= {{bitshift}}
326- buf_rem -= 1
327- val = <{{utype}}_t>buf & mask
328- if val <= rng:
329- break
330- out_data[i] = off + val
331-
332- np.PyArray_MultiIter_NEXT(it)
333-
334- return out_arr
335-
336- {{endfor}}
337-
338-
339- {{
340- py:
341- big_bc_ctypes = (('uint64', 'uint64', 'NPY_UINT64', '0x0ULL', '0xFFFFFFFFFFFFFFFFULL'),
342- ('int64', 'uint64', 'NPY_INT64', '-0x8000000000000000LL', '0x7FFFFFFFFFFFFFFFLL' )
343- )}}
344-
345- {{for nptype, utype, npctype, lb, ub in big_bc_ctypes}}
346-
347- {{ py: otype = nptype}}
348-
349- cdef object _rand_{{nptype}}_broadcast(object low, object high, object size, aug_state *state, object lock):
350- """
351- Generate bounded random {{nptype}} values using broadcasting
352-
353- Parameters
354- ----------
355- low : int or array-like
356- Array containing the lowest (signed) integers to be drawn from the
357- distribution.
358- high : int or array-like
359- Array containing the the open interval bound for the distribution.
360- size : int or tuple of ints
361- Output shape. If the given shape is, e.g., ``(m, n, k)``, then
362- ``m * n * k`` samples are drawn. Default is None, in which case
363- the output shape is determined by the broadcast shapes of low and
364- high
365- state : augmented random state
366- State to use in the core random number generators
367- lock : threading.Lock
368- Lock to prevent multiple using a single RandomState simultaneously
369-
370- Returns
371- -------
372- out : ndarray of np.{{nptype}}
373- array of random integers from the appropriate distribution where the
374- size is determined by size if provided or the broadcast shape of low
375- and high
376- """
377- cdef np.ndarray low_arr, high_arr, out_arr, highm1_arr
378- cdef np.npy_intp i
379- cdef np.broadcast it
380- cdef int buf_rem = 0
381- cdef object closed_upper
382-
383- cdef uint64_t *out_data
384- cdef {{nptype}}_t *highm1_data
385- cdef {{nptype}}_t low_v, high_v
386- cdef uint64_t rng, last_rng, val, mask, off
387-
388- low_arr = <np.ndarray>low
389- high_arr = <np.ndarray>high
390-
391- if np.any(np.less(low_arr, {{lb}})):
392- raise ValueError('low is out of bounds for {{nptype}}')
393-
394- highm1_arr = <np.ndarray>np.empty_like(high_arr, dtype=np.{{nptype}})
395- highm1_data = <{{nptype}}_t *>np.PyArray_DATA(highm1_arr)
396- n = np.PyArray_SIZE(high_arr)
397- flat = high_arr.flat
398- for i in range(n):
399- closed_upper = int(flat[i]) - 1
400- if closed_upper > {{ub}}:
401- raise ValueError('high is out of bounds for {{nptype}}')
402- if closed_upper < {{lb}}:
403- raise ValueError('low >= high')
404-
405- highm1_data[i] = <{{nptype}}_t>closed_upper
406-
407- if np.any(np.greater(low_arr, highm1_arr)):
408- raise ValueError('low >= high')
409-
410- high_arr = highm1_arr
411- low_arr = <np.ndarray>np.PyArray_FROM_OTF(low, np.{{npctype}}, np.NPY_ALIGNED | np.NPY_FORCECAST)
412-
413- if size is not None:
414- out_arr = <np.ndarray>np.empty(size, np.{{nptype}})
415- else:
416- it = np.PyArray_MultiIterNew2(low_arr, high_arr)
417- out_arr = <np.ndarray>np.empty(it.shape, np.{{nptype}})
418-
419- it = np.PyArray_MultiIterNew3(low_arr, high_arr, out_arr)
420- out_data = <uint64_t *>np.PyArray_DATA(out_arr)
421- n = np.PyArray_SIZE(out_arr)
422- mask = last_rng = 0
423- with lock, nogil:
424- for i in range(n):
425- low_v = (<{{nptype}}_t*>np.PyArray_MultiIter_DATA(it, 0))[0]
426- high_v = (<{{nptype}}_t*>np.PyArray_MultiIter_DATA(it, 1))[0]
427- rng = <{{nptype}}_t>(high_v - low_v) # No -1 here since implemented above
428- off = low_v
429- if rng == 0:
430- out_data[i] = 0
431- continue
432-
433- if rng != last_rng:
434- mask = _gen_mask(rng)
435- out_data[i] = random_bounded_uint64(state, off, rng, mask)
436-
437- np.PyArray_MultiIter_NEXT(it)
438-
439- return out_arr
440-
441- {{endfor}}
442-
443-
444-
445155{{
446156py:
447157big_bc_ctypes = (('uint64', 'uint64', 'NPY_UINT64', '0x0ULL', '0xFFFFFFFFFFFFFFFFULL'),
@@ -452,9 +162,9 @@ big_bc_ctypes = (('uint64', 'uint64', 'NPY_UINT64', '0x0ULL', '0xFFFFFFFFFFFFFFF
452162
453163{{ py: otype = nptype}}
454164
455- cdef object _rand_{{nptype}}_combined (object low, object high, object size, aug_state *state, object lock):
165+ cdef object _rand_{{nptype}}(object low, object high, object size, aug_state *state, object lock):
456166 """
457- Generate bounded random {{nptype}} values using broadcasting
167+ Generate bounded random {{nptype}} values
458168
459169 Parameters
460170 ----------
0 commit comments