@@ -11,79 +11,6 @@ _randint_type = {'bool': (0, 2),
11
11
12
12
ctypedef np.npy_bool bool_t
13
13
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
-
87
14
cdef inline uint64_t _gen_mask(uint64_t max_val) nogil:
88
15
# Smallest bit mask >= max
89
16
cdef uint64_t mask = max_val
@@ -110,9 +37,9 @@ bc_ctypes = (('uint32', 'uint32', 'uint64', 'NPY_UINT64', 0, 0, 0, '0X100000000U
110
37
111
38
{{ py: otype = nptype + '_' if nptype == 'bool' else nptype }}
112
39
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):
114
41
"""
115
- _rand_{{nptype}}_combined (low, high, size, *state, lock)
42
+ _rand_{{nptype}}(low, high, size, *state, lock)
116
43
117
44
Return random np.{{nptype}} integers between `low` and `high`, inclusive.
118
45
@@ -225,223 +152,6 @@ cdef object _rand_{{nptype}}_combined(object low, object high, object size, aug_
225
152
{{endfor}}
226
153
227
154
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
-
445
155
{{
446
156
py:
447
157
big_bc_ctypes = (('uint64', 'uint64', 'NPY_UINT64', '0x0ULL', '0xFFFFFFFFFFFFFFFFULL'),
@@ -452,9 +162,9 @@ big_bc_ctypes = (('uint64', 'uint64', 'NPY_UINT64', '0x0ULL', '0xFFFFFFFFFFFFFFF
452
162
453
163
{{ py: otype = nptype}}
454
164
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):
456
166
"""
457
- Generate bounded random {{nptype}} values using broadcasting
167
+ Generate bounded random {{nptype}} values
458
168
459
169
Parameters
460
170
----------
0 commit comments