def interval(self, mx, size): """Generate multiple integers independently sampled uniformly from ``[0, mx]``. Args: mx (int): Upper bound of the interval size (None or int or tuple): Shape of the array or the scalar returned. Returns: int or cupy.ndarray: If ``None``, an :class:`cupy.ndarray` with shape ``()`` is returned. If ``int``, 1-D array of length size is returned. If ``tuple``, multi-dimensional array with shape ``size`` is returned. Currently, each element of the array is ``numpy.int32``. """ dtype = numpy.int32 if size is None: return self.interval(mx, 1).reshape(()) elif isinstance(size, int): size = (size, ) if mx == 0: return cupy.zeros(size, dtype=dtype) mask = (1 << mx.bit_length()) - 1 mask = cupy.array(mask, dtype=dtype) ret = cupy.zeros(size, dtype=dtype) sample = cupy.zeros(size, dtype=dtype) done = cupy.zeros(size, dtype=numpy.bool_) while True: curand.generate( self._generator, sample.data.ptr, sample.size) sample &= mask success = sample <= mx ret = cupy.where(success, sample, ret) done |= success if done.all(): return ret
def tomaxint(self, size=None): """Draws integers between 0 and max integer inclusive. Args: size (int or tuple of ints): Output shape. Returns: cupy.ndarray: Drawn samples. .. seealso:: :meth:`numpy.random.RandomState.tomaxint` """ if size is None: size = () sample = cupy.empty(size, dtype=cupy.int_) # cupy.random only uses int32 random generator size_in_int = sample.dtype.itemsize // 4 curand.generate(self._generator, sample.data.ptr, sample.size * size_in_int) # Disable sign bit sample &= cupy.iinfo(cupy.int_).max return sample
def interval(self, mx, size): """Generate multiple integers independently sampled uniformly from ``[0, mx]``. Args: mx (int): Upper bound of the interval size (None or int or tuple): Shape of the array or the scalar returned. Returns: int or cupy.ndarray: If ``None``, an :class:`cupy.ndarray` with shape ``()`` is returned. If ``int``, 1-D array of length size is returned. If ``tuple``, multi-dimensional array with shape ``size`` is returned. Currently, only 32 bit integers can be sampled. If 0 :math:`\\leq` ``mx`` :math:`\\leq` 0x7fffffff, a ``numpy.int32`` array is returned. If 0x80000000 :math:`\\leq` ``mx`` :math:`\\leq` 0xffffffff, a ``numpy.uint32`` array is returned. """ if size is None: return self.interval(mx, 1).reshape(()) elif isinstance(size, int): size = (size, ) if mx == 0: return cupy.zeros(size, dtype=numpy.int32) if mx < 0: raise ValueError('mx must be non-negative (actual: {})'.format(mx)) elif mx <= 0x7fffffff: dtype = numpy.int32 elif mx <= 0xffffffff: dtype = numpy.uint32 else: raise ValueError( 'mx must be within uint32 range (actual: {})'.format(mx)) mask = (1 << mx.bit_length()) - 1 mask = cupy.array(mask, dtype=dtype) n = functools.reduce(operator.mul, size, 1) sample = cupy.empty((n, ), dtype=dtype) n_rem = n # The number of remaining elements to sample ret = None while n_rem > 0: curand.generate(self._generator, sample.data.ptr, sample.size) # Drop the samples that exceed the upper limit sample &= mask success = sample <= mx if ret is None: # If the sampling has finished in the first iteration, # just return the sample. if success.all(): n_rem = 0 ret = sample break # Allocate the return array. ret = cupy.empty((n, ), dtype=dtype) n_succ = min(n_rem, int(success.sum())) ret[n - n_rem:n - n_rem + n_succ] = sample[success][:n_succ] n_rem -= n_succ assert n_rem == 0 return ret.reshape(size)
def _curand_generate(self, num, dtype): sample = cupy.empty((num, ), dtype=dtype) # Call 32-bit RNG to fill 32-bit or 64-bit `sample` size32 = sample.view(dtype=numpy.uint32).size curand.generate(self._generator, sample.data.ptr, size32) return sample
def _permutation(self, num): """Returns a permuted range.""" sample = cupy.empty((num, ), dtype=numpy.int32) curand.generate(self._generator, sample.data.ptr, num) array = cupy.argsort(sample) return array