diff --git a/dpnp/random/dpnp_iface_random.py b/dpnp/random/dpnp_iface_random.py index 677f2a7e94bc..ade85bb2fe18 100644 --- a/dpnp/random/dpnp_iface_random.py +++ b/dpnp/random/dpnp_iface_random.py @@ -1,7 +1,7 @@ # cython: language_level=3 # -*- coding: utf-8 -*- # ***************************************************************************** -# Copyright (c) 2016-2022, Intel Corporation +# Copyright (c) 2016-2023, Intel Corporation # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -98,11 +98,20 @@ ] -def _get_random_state(): - global _dpnp_random_state - if _dpnp_random_state is None: - _dpnp_random_state = RandomState() - return _dpnp_random_state +def _get_random_state(device=None, sycl_queue=None): + global _dpnp_random_states + + if not isinstance(_dpnp_random_states, dict): + _dpnp_random_states = dict() + sycl_queue = dpnp.get_normalized_queue_device(device=device, sycl_queue=sycl_queue) + if sycl_queue not in _dpnp_random_states: + rs = RandomState(device=device, sycl_queue=sycl_queue) + if sycl_queue == rs.get_sycl_queue(): + _dpnp_random_states[sycl_queue] = rs + else: + raise RuntimeError("Normalized SYCL queue {} mismatched with one returned by RandmoState {}" + .format(sycl_queue, rs.get_sycl_queue())) + return _dpnp_random_states[sycl_queue] def beta(a, b, size=None): @@ -774,20 +783,42 @@ def negative_binomial(n, p, size=None): return call_origin(numpy.random.negative_binomial, n, p, size) -def normal(loc=0.0, scale=1.0, size=None, usm_type='device'): +def normal(loc=0.0, + scale=1.0, + size=None, + device=None, + usm_type="device", + sycl_queue=None): """ - Normal distribution. - Draw random samples from a normal (Gaussian) distribution. For full documentation refer to :obj:`numpy.random.normal`. + Parameters + ---------- + device : {None, string, SyclDevice, SyclQueue}, optional + An array API concept of device where the output array is created. + The `device` can be ``None`` (the default), an OneAPI filter selector string, + an instance of :class:`dpctl.SyclDevice` corresponding to a non-partitioned SYCL device, + an instance of :class:`dpctl.SyclQueue`, or a `Device` object returned by + :obj:`dpnp.dpnp_array.dpnp_array.device` property. + usm_type : {"device", "shared", "host"}, optional + The type of SYCL USM allocation for the output array. + sycl_queue : {None, SyclQueue}, optional + A SYCL queue to use for output array allocation and copying. + + Returns + ------- + out : dpnp.ndarray + Drawn samples from the parameterized normal distribution. + Output array data type is the same as input `dtype`. If `dtype` is ``None`` (the default), + :obj:`dpnp.float64` type will be used if device supports it, or :obj:`dpnp.float32` otherwise. + Limitations ----------- - Parameters ``loc`` and ``scale`` are supported as scalar. + Parameters `loc` and `scale` are supported as scalar. Otherwise, :obj:`numpy.random.normal(loc, scale, size)` samples are drawn. - Output array data type is :obj:`dpnp.float64` if device supports it - or :obj:`dpnp.float32` otherwise. + Parameter `dtype` is supported only as :obj:`dpnp.float32`, :obj:`dpnp.float64` or ``None``. Examples -------- @@ -796,11 +827,9 @@ def normal(loc=0.0, scale=1.0, size=None, usm_type='device'): >>> s = dpnp.random.normal(mu, sigma, 1000) """ - return _get_random_state().normal(loc=loc, - scale=scale, - size=size, - dtype=None, - usm_type=usm_type) + + rs = _get_random_state(device=device, sycl_queue=sycl_queue) + return rs.normal(loc=loc, scale=scale, size=size, dtype=None, usm_type=usm_type) def noncentral_chisquare(df, nonc, size=None): @@ -986,7 +1015,11 @@ def power(a, size=None): return call_origin(numpy.random.power, a, size) -def rand(d0, *dn, usm_type="device"): +def rand(d0, + *dn, + device=None, + usm_type="device", + sycl_queue=None): """ Random values in a given shape. @@ -995,10 +1028,24 @@ def rand(d0, *dn, usm_type="device"): For full documentation refer to :obj:`numpy.random.rand`. - Limitations - ----------- - Output array data type is :obj:`dpnp.float64` if device supports it - or :obj:`dpnp.float32` otherwise. + Parameters + ---------- + device : {None, string, SyclDevice, SyclQueue}, optional + An array API concept of device where the output array is created. + The `device` can be ``None`` (the default), an OneAPI filter selector string, + an instance of :class:`dpctl.SyclDevice` corresponding to a non-partitioned SYCL device, + an instance of :class:`dpctl.SyclQueue`, or a `Device` object returned by + :obj:`dpnp.dpnp_array.dpnp_array.device` property. + usm_type : {"device", "shared", "host"}, optional + The type of SYCL USM allocation for the output array. + sycl_queue : {None, SyclQueue}, optional + A SYCL queue to use for output array allocation and copying. + + Returns + ------- + out : dpnp.ndarray + Random values in a given shape. + Output array data type is :obj:`dpnp.float64` if device supports it, or :obj:`dpnp.float32` otherwise. Examples -------- @@ -1012,20 +1059,48 @@ def rand(d0, *dn, usm_type="device"): """ - return _get_random_state().rand(d0, *dn, usm_type=usm_type) + rs = _get_random_state(device=device, sycl_queue=sycl_queue) + return rs.rand(d0, *dn, usm_type=usm_type) -def randint(low, high=None, size=None, dtype=int, usm_type="device"): +def randint(low, + high=None, + size=None, + dtype=int, + device=None, + usm_type="device", + sycl_queue=None): """ Return random integers from `low` (inclusive) to `high` (exclusive). For full documentation refer to :obj:`numpy.random.randint`. + Parameters + ---------- + device : {None, string, SyclDevice, SyclQueue}, optional + An array API concept of device where the output array is created. + The `device` can be ``None`` (the default), an OneAPI filter selector string, + an instance of :class:`dpctl.SyclDevice` corresponding to a non-partitioned SYCL device, + an instance of :class:`dpctl.SyclQueue`, or a `Device` object returned by + :obj:`dpnp.dpnp_array.dpnp_array.device` property. + usm_type : {"device", "shared", "host"}, optional + The type of SYCL USM allocation for the output array. + sycl_queue : {None, SyclQueue}, optional + A SYCL queue to use for output array allocation and copying. + + Returns + ------- + out : dpnp.ndarray + `size`-shaped array of random integers from the appropriate distribution, + or a single such random int if `size` is not provided. + Output array data type is the same as input `dtype`. + Limitations ----------- - Parameters ``low`` and ``high`` are supported only as scalar. - Parameter ``dtype`` is supported only as `int`. - Otherwise, :obj:`numpy.random.randint(low, high, size, dtype)` samples are drawn. + Parameters `low` and `high` are supported only as a scalar. + Parameter `dtype` is supported only as :obj:`dpnp.int32` or ``int``, + but ``int`` value is considered to be exactly equivalent to :obj:`dpnp.int32`. + Otherwise, :obj:`numpy.random.RandomState.randint(low, high, size, dtype)` samples are drawn. Examples -------- @@ -1041,23 +1116,39 @@ def randint(low, high=None, size=None, dtype=int, usm_type="device"): """ - return _get_random_state().randint(low=low, - high=high, - size=size, - dtype=dtype, - usm_type=usm_type) + rs = _get_random_state(device=device, sycl_queue=sycl_queue) + return rs.randint(low=low, high=high, size=size, dtype=dtype, usm_type=usm_type) -def randn(d0, *dn, usm_type="device"): +def randn(d0, + *dn, + device=None, + usm_type="device", + sycl_queue=None): """ Return a sample (or samples) from the "standard normal" distribution. For full documentation refer to :obj:`numpy.random.randn`. - Limitations - ----------- - Output array data type is :obj:`dpnp.float64` if device supports it - or :obj:`dpnp.float32` otherwise. + Parameters + ---------- + device : {None, string, SyclDevice, SyclQueue}, optional + An array API concept of device where the output array is created. + The `device` can be ``None`` (the default), an OneAPI filter selector string, + an instance of :class:`dpctl.SyclDevice` corresponding to a non-partitioned SYCL device, + an instance of :class:`dpctl.SyclQueue`, or a `Device` object returned by + :obj:`dpnp.dpnp_array.dpnp_array.device` property. + usm_type : {"device", "shared", "host"}, optional + The type of SYCL USM allocation for the output array. + sycl_queue : {None, SyclQueue}, optional + A SYCL queue to use for output array allocation and copying. + + Returns + ------- + out : dpnp.ndarray + A ``(d0, d1, ..., dn)``-shaped array of floating-point samples from + the standard normal distribution, or a single such float if no parameters were supplied. + Output array data type is :obj:`dpnp.float64` if device supports it, or :obj:`dpnp.float32` otherwise. Examples -------- @@ -1075,20 +1166,38 @@ def randn(d0, *dn, usm_type="device"): """ - return _get_random_state().randn(d0, *dn, usm_type=usm_type) + rs = _get_random_state(device=device, sycl_queue=sycl_queue) + return rs.randn(d0, *dn, usm_type=usm_type) -def random(size=None, usm_type="device"): +def random(size=None, + device=None, + usm_type="device", + sycl_queue=None): """ Return random floats in the half-open interval [0.0, 1.0). Alias for random_sample. For full documentation refer to :obj:`numpy.random.random`. - Limitations - ----------- - Output array data type is :obj:`dpnp.float64` if device supports it - or :obj:`dpnp.float32` otherwise. + Parameters + ---------- + device : {None, string, SyclDevice, SyclQueue}, optional + An array API concept of device where the output array is created. + The `device` can be ``None`` (the default), an OneAPI filter selector string, + an instance of :class:`dpctl.SyclDevice` corresponding to a non-partitioned SYCL device, + an instance of :class:`dpctl.SyclQueue`, or a `Device` object returned by + :obj:`dpnp.dpnp_array.dpnp_array.device` property. + usm_type : {"device", "shared", "host"}, optional + The type of SYCL USM allocation for the output array. + sycl_queue : {None, SyclQueue}, optional + A SYCL queue to use for output array allocation and copying. + + Returns + ------- + out : dpnp.ndarray + Array of random floats of shape `size` (if ``size=None``, zero dimension array with a single float is returned). + Output array data type is :obj:`dpnp.float64` if device supports it, or :obj:`dpnp.float32` otherwise. Examples -------- @@ -1102,20 +1211,43 @@ def random(size=None, usm_type="device"): """ - return random_sample(size=size, usm_type=usm_type) + return random_sample(size=size, device=device, usm_type=usm_type, sycl_queue=sycl_queue) -def random_integers(low, high=None, size=None, usm_type="device"): +def random_integers(low, + high=None, + size=None, + device=None, + usm_type="device", + sycl_queue=None): """ Random integers between `low` and `high`, inclusive. For full documentation refer to :obj:`numpy.random.random_integers`. + Parameters + ---------- + device : {None, string, SyclDevice, SyclQueue}, optional + An array API concept of device where the output array is created. + The `device` can be ``None`` (the default), an OneAPI filter selector string, + an instance of :class:`dpctl.SyclDevice` corresponding to a non-partitioned SYCL device, + an instance of :class:`dpctl.SyclQueue`, or a `Device` object returned by + :obj:`dpnp.dpnp_array.dpnp_array.device` property. + usm_type : {"device", "shared", "host"}, optional + The type of SYCL USM allocation for the output array. + sycl_queue : {None, SyclQueue}, optional + A SYCL queue to use for output array allocation and copying. + + Returns + ------- + out : dpnp.ndarray + `size`-shaped array of random integers from the appropriate distribution, + or a single such random int if `size` is not provided. + Limitations ----------- - Parameters ``low`` and ``high`` are supported as scalar. - Otherwise, :obj:`numpy.random.random_integers(low, high, size)` samples - are drawn. + Parameters `low` and `high` are supported as scalar. + Otherwise, :obj:`numpy.random.random_integers(low, high, size)` samples are drawn. See Also -------- @@ -1134,12 +1266,15 @@ def random_integers(low, high=None, size=None, usm_type="device"): elif not dpnp.isscalar(high): pass else: - return randint(low, int(high) + 1, size=size, usm_type=usm_type) + return randint(low, int(high) + 1, size=size, device=device, usm_type=usm_type, sycl_queue=sycl_queue) return call_origin(numpy.random.random_integers, low, high, size) -def random_sample(size=None, usm_type="device"): +def random_sample(size=None, + device=None, + usm_type="device", + sycl_queue=None): """ Return random floats in the half-open interval [0.0, 1.0). @@ -1147,10 +1282,24 @@ def random_sample(size=None, usm_type="device"): For full documentation refer to :obj:`numpy.random.random_sample`. - Limitations - ----------- - Output array data type is :obj:`dpnp.float64` if device supports it - or :obj:`dpnp.float32` otherwise. + Parameters + ---------- + device : {None, string, SyclDevice, SyclQueue}, optional + An array API concept of device where the output array is created. + The `device` can be ``None`` (the default), an OneAPI filter selector string, + an instance of :class:`dpctl.SyclDevice` corresponding to a non-partitioned SYCL device, + an instance of :class:`dpctl.SyclQueue`, or a `Device` object returned by + :obj:`dpnp.dpnp_array.dpnp_array.device` property. + usm_type : {"device", "shared", "host"}, optional + The type of SYCL USM allocation for the output array. + sycl_queue : {None, SyclQueue}, optional + A SYCL queue to use for output array allocation and copying. + + Returns + ------- + out : dpnp.ndarray + Array of random floats of shape `size` (if ``size=None``, zero dimension array with a single float is returned). + Output array data type is :obj:`dpnp.float64` if device supports it, or :obj:`dpnp.float32` otherwise. Examples -------- @@ -1164,21 +1313,38 @@ def random_sample(size=None, usm_type="device"): """ - return _get_random_state().random_sample(size=size, - usm_type=usm_type) + rs = _get_random_state(device=device, sycl_queue=sycl_queue) + return rs.random_sample(size=size, usm_type=usm_type) -def ranf(size=None, usm_type="device"): +def ranf(size=None, + device=None, + usm_type="device", + sycl_queue=None): """ Return random floats in the half-open interval [0.0, 1.0). This is an alias of random_sample. For full documentation refer to :obj:`numpy.random.ranf`. - Limitations - ----------- - Output array data type is :obj:`dpnp.float64` if device supports it - or :obj:`dpnp.float32` otherwise. + Parameters + ---------- + device : {None, string, SyclDevice, SyclQueue}, optional + An array API concept of device where the output array is created. + The `device` can be ``None`` (the default), an OneAPI filter selector string, + an instance of :class:`dpctl.SyclDevice` corresponding to a non-partitioned SYCL device, + an instance of :class:`dpctl.SyclQueue`, or a `Device` object returned by + :obj:`dpnp.dpnp_array.dpnp_array.device` property. + usm_type : {"device", "shared", "host"}, optional + The type of SYCL USM allocation for the output array. + sycl_queue : {None, SyclQueue}, optional + A SYCL queue to use for output array allocation and copying. + + Returns + ------- + out : dpnp.ndarray + Array of random floats of shape `size` (if ``size=None``, zero dimension array with a single float is returned). + Output array data type is :obj:`dpnp.float64` if device supports it, or :obj:`dpnp.float32` otherwise. Examples -------- @@ -1193,7 +1359,7 @@ def ranf(size=None, usm_type="device"): """ - return random_sample(size=size, usm_type=usm_type) + return random_sample(size=size, device=device, usm_type=usm_type, sycl_queue=sycl_queue) def rayleigh(scale=1.0, size=None): @@ -1230,17 +1396,34 @@ def rayleigh(scale=1.0, size=None): return call_origin(numpy.random.rayleigh, scale, size) -def sample(size=None, usm_type="device"): +def sample(size=None, + device=None, + usm_type="device", + sycl_queue=None): """ Return random floats in the half-open interval [0.0, 1.0). This is an alias of random_sample. For full documentation refer to :obj:`numpy.random.sample`. - Limitations - ----------- - Output array data type is :obj:`dpnp.float64` if device supports it - or :obj:`dpnp.float32` otherwise. + Parameters + ---------- + device : {None, string, SyclDevice, SyclQueue}, optional + An array API concept of device where the output array is created. + The `device` can be ``None`` (the default), an OneAPI filter selector string, + an instance of :class:`dpctl.SyclDevice` corresponding to a non-partitioned SYCL device, + an instance of :class:`dpctl.SyclQueue`, or a `Device` object returned by + :obj:`dpnp.dpnp_array.dpnp_array.device` property. + usm_type : {"device", "shared", "host"}, optional + The type of SYCL USM allocation for the output array. + sycl_queue : {None, SyclQueue}, optional + A SYCL queue to use for output array allocation and copying. + + Returns + ------- + out : dpnp.ndarray + Array of random floats of shape `size` (if ``size=None``, zero dimension array with a single float is returned). + Output array data type is :obj:`dpnp.float64` if device supports it, or :obj:`dpnp.float32` otherwise. Examples -------- @@ -1255,7 +1438,7 @@ def sample(size=None, usm_type="device"): """ - return random_sample(size=size, usm_type=usm_type) + return random_sample(size=size, device=device, usm_type=usm_type, sycl_queue=sycl_queue) def shuffle(x1): @@ -1283,18 +1466,35 @@ def shuffle(x1): return -def seed(seed=None): +def seed(seed=None, + device=None, + sycl_queue=None): """ - Reseed a legacy mt19937 random number generator engine. + Reseed a legacy MT19937 random number generator engine. + + Parameters + ---------- + device : {None, string, SyclDevice, SyclQueue}, optional + An array API concept of device where an array with generated numbers will be created. + The `device` can be ``None`` (the default), an OneAPI filter selector string, + an instance of :class:`dpctl.SyclDevice` corresponding to a non-partitioned SYCL device, + an instance of :class:`dpctl.SyclQueue`, or a `Device` object returned by + :obj:`dpnp.dpnp_array.dpnp_array.device` property. + sycl_queue : {None, SyclQueue}, optional + A SYCL queue to use for an array with generated numbers. Limitations ----------- - Parameter ``seed`` is supported as a scalar. - Otherwise, the function will use :obj:`numpy.random.seed` on the backend - and will be executed on fallback backend. + Parameter `seed` is supported as either a scalar or an array of maximumum three integer scalars. """ + # update a mt19937 random number for both RandomState and legacy functionality + global _dpnp_random_states + + sycl_queue = dpnp.get_normalized_queue_device(device=device, sycl_queue=sycl_queue) + _dpnp_random_states[sycl_queue] = RandomState(seed=seed, sycl_queue=sycl_queue) + if not use_origin_backend(seed): # TODO: # array_like of ints for `seed` @@ -1307,10 +1507,6 @@ def seed(seed=None): else: # TODO: # migrate to a single approach with RandomState class - - # update a mt19937 random number for both RandomState and legacy functionality - global _dpnp_random_state - _dpnp_random_state = RandomState(seed) dpnp_rng_srand(seed) # always reseed numpy engine also @@ -1405,17 +1601,34 @@ def standard_gamma(shape, size=None): return call_origin(numpy.random.standard_gamma, shape, size) -def standard_normal(size=None, usm_type="device"): - """Standard normal distribution. - +def standard_normal(size=None, + device=None, + usm_type="device", + sycl_queue=None): + """ Draw samples from a standard Normal distribution (mean=0, stdev=1). For full documentation refer to :obj:`numpy.random.standard_normal`. - Limitations - ----------- - Output array data type is :obj:`dpnp.float64` if device supports it - or :obj:`dpnp.float32` otherwise. + Parameters + ---------- + device : {None, string, SyclDevice, SyclQueue}, optional + An array API concept of device where the output array is created. + The `device` can be ``None`` (the default), an OneAPI filter selector string, + an instance of :class:`dpctl.SyclDevice` corresponding to a non-partitioned SYCL device, + an instance of :class:`dpctl.SyclQueue`, or a `Device` object returned by + :obj:`dpnp.dpnp_array.dpnp_array.device` property. + usm_type : {"device", "shared", "host"}, optional + The type of SYCL USM allocation for the output array. + sycl_queue : {None, SyclQueue}, optional + A SYCL queue to use for output array allocation and copying. + + Returns + ------- + out : dpnp.ndarray + A floating-point array of shape `size` of drawn samples, or a + single sample if `size` was not specified. + Output array data type is :obj:`dpnp.float64` if device supports it, or :obj:`dpnp.float32` otherwise. Examples -------- @@ -1423,7 +1636,9 @@ def standard_normal(size=None, usm_type="device"): >>> s = dpnp.random.standard_normal(1000) """ - return _get_random_state().standard_normal(size=size, usm_type=usm_type) + + rs = _get_random_state(device=device, sycl_queue=sycl_queue) + return rs.standard_normal(size=size, usm_type=usm_type) def standard_t(df, size=None): @@ -1506,18 +1721,45 @@ def triangular(left, mode, right, size=None): return call_origin(numpy.random.triangular, left, mode, right, size) -def uniform(low=0.0, high=1.0, size=None, usm_type='device'): +def uniform(low=0.0, + high=1.0, + size=None, + device=None, + usm_type="device", + sycl_queue=None): """ Draw samples from a uniform distribution. + Samples are uniformly distributed over the half-open interval [low, high) (includes low, but excludes high). + In other words, any value within the given interval is equally likely to be drawn by uniform. + For full documentation refer to :obj:`numpy.random.uniform`. + Parameters + ---------- + device : {None, string, SyclDevice, SyclQueue}, optional + An array API concept of device where the output array is created. + The `device` can be ``None`` (the default), an OneAPI filter selector string, + an instance of :class:`dpctl.SyclDevice` corresponding to a non-partitioned SYCL device, + an instance of :class:`dpctl.SyclQueue`, or a `Device` object returned by + :obj:`dpnp.dpnp_array.dpnp_array.device` property. + usm_type : {"device", "shared", "host"}, optional + The type of SYCL USM allocation for the output array. + sycl_queue : {None, SyclQueue}, optional + A SYCL queue to use for output array allocation and copying. + + Returns + ------- + out : dpnp.ndarray + Drawn samples from the parameterized uniform distribution. + Output array data type is the same as input `dtype`. If `dtype` is ``None`` (the default), + :obj:`dpnp.float64` type will be used if device supports it, or :obj:`dpnp.float32` otherwise. + Limitations ----------- - Parameters ``low`` and ``high`` are supported as scalar. - Otherwise, :obj:`numpy.random.uniform(low, high, size)` samples are drawn. - Output array data type is :obj:`dpnp.float64` if device supports it - or :obj:`dpnp.float32` otherwise. + Parameters `low` and `high` are supported as a scalar. Otherwise, + :obj:`numpy.random.uniform(low, high, size)` samples are drawn. + Parameter `dtype` is supported only as :obj:`dpnp.int32`, :obj:`dpnp.float32`, :obj:`dpnp.float64` or ``None``. Examples -------- @@ -1530,11 +1772,9 @@ def uniform(low=0.0, high=1.0, size=None, usm_type='device'): :obj:`dpnp.random.random` : Floats uniformly distributed over ``[0, 1)``. """ - return _get_random_state().uniform(low=low, - high=high, - size=size, - dtype=None, - usm_type=usm_type) + + rs = _get_random_state(device=device, sycl_queue=sycl_queue) + return rs.uniform(low=low, high=high, size=size, dtype=None, usm_type=usm_type) def vonmises(mu, kappa, size=None): @@ -1679,4 +1919,4 @@ def zipf(a, size=None): return call_origin(numpy.random.zipf, a, size) -_dpnp_random_state = None +_dpnp_random_states = {} diff --git a/dpnp/random/dpnp_random_state.py b/dpnp/random/dpnp_random_state.py index 1d4648c31c47..412d9dec0f81 100644 --- a/dpnp/random/dpnp_random_state.py +++ b/dpnp/random/dpnp_random_state.py @@ -1,7 +1,7 @@ # cython: language_level=3 # -*- coding: utf-8 -*- # ***************************************************************************** -# Copyright (c) 2016-2022, Intel Corporation +# Copyright (c) 2016-2023, Intel Corporation # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -76,7 +76,12 @@ class RandomState: """ def __init__(self, seed=None, device=None, sycl_queue=None): - self._seed = 1 if seed is None else seed + if seed is None: + # ask NumPy to generate an array of three random integers as default seed value + self._seed = numpy.random.randint(low=0, high=numpy.iinfo(numpy.int32).max + 1, size=3) + else: + self._seed = seed + self._sycl_queue = dpnp.get_normalized_queue_device(device=device, sycl_queue=sycl_queue) self._sycl_device = self._sycl_queue.sycl_device @@ -290,7 +295,7 @@ def rand(self, *args, usm_type="device"): def randint(self, low, high=None, size=None, dtype=int, usm_type="device"): """ - Draw random integers from low (inclusive) to high (exclusive). + Draw random integers from `low` (inclusive) to `high` (exclusive). Return random integers from the “discrete uniform” distribution of the specified type in the “half-open” interval [low, high). diff --git a/tests/test_sycl_queue.py b/tests/test_sycl_queue.py index 1eae3df9393f..413596e2cc76 100644 --- a/tests/test_sycl_queue.py +++ b/tests/test_sycl_queue.py @@ -338,36 +338,101 @@ def test_broadcasting(func, data1, data2, device): assert_sycl_queue_equal(result_queue, expected_queue) +@pytest.mark.parametrize( + "func, kwargs", + [ + pytest.param("normal", + {'loc': 1.0, 'scale': 3.4, 'size': (5, 12)}), + pytest.param("rand", + {'d0': 20}), + pytest.param("randint", + {'low': 2, 'high': 15, 'size': (4, 8, 16), 'dtype': dpnp.int32}), + pytest.param("randn", + {'d0': 20}), + pytest.param("random", + {'size': (35, 45)}), + pytest.param("random_integers", + {'low': -17, 'high': 3, 'size': (12, 16)}), + pytest.param("random_sample", + {'size': (7, 7)}), + pytest.param("ranf", + {'size': (10, 7, 12)}), + pytest.param("sample", + {'size': (7, 9)}), + pytest.param("standard_normal", + {'size': (4, 4, 8)}), + pytest.param("uniform", + {'low': 1.0, 'high': 2.0, 'size': (4, 2, 5)}) + ]) +@pytest.mark.parametrize("device", + valid_devices, + ids=[device.filter_string for device in valid_devices]) @pytest.mark.parametrize("usm_type", ["host", "device", "shared"]) -@pytest.mark.parametrize("size", - [None, (), 3, (2, 1), (4, 2, 5)], - ids=['None', '()', '3', '(2,1)', '(4,2,5)']) -def test_uniform(usm_type, size): - low = 1.0 - high = 2.0 - res = dpnp.random.uniform(low, high, size=size, usm_type=usm_type) +def test_random(func, kwargs, device, usm_type): + kwargs = {**kwargs, 'device': device, 'usm_type': usm_type} + + # test with default SYCL queue per a device + res_array = getattr(dpnp.random, func)(**kwargs) + assert device == res_array.sycl_device + assert usm_type == res_array.usm_type + + sycl_queue = dpctl.SyclQueue(device, property="in_order") + kwargs['device'] = None + kwargs['sycl_queue'] = sycl_queue - assert usm_type == res.usm_type + # test with in-order SYCL queue per a device and passed as argument + res_array = getattr(dpnp.random, func)(**kwargs) + assert usm_type == res_array.usm_type + assert_sycl_queue_equal(res_array.sycl_queue, sycl_queue) +@pytest.mark.parametrize( + "func, args, kwargs", + [ + pytest.param("normal", + [], + {'loc': 1.0, 'scale': 3.4, 'size': (5, 12)}), + pytest.param("rand", + [15, 30, 5], + {}), + pytest.param("randint", + [], + {'low': 2, 'high': 15, 'size': (4, 8, 16), 'dtype': dpnp.int32}), + pytest.param("randn", + [20, 5, 40], + {}), + pytest.param("random_sample", + [], + {'size': (7, 7)}), + pytest.param("standard_normal", + [], + {'size': (4, 4, 8)}), + pytest.param("uniform", + [], + {'low': 1.0, 'high': 2.0, 'size': (4, 2, 5)}) + ]) +@pytest.mark.parametrize("device", + valid_devices, + ids=[device.filter_string for device in valid_devices]) @pytest.mark.parametrize("usm_type", ["host", "device", "shared"]) -@pytest.mark.parametrize("seed", - [None, (), 123, (12, 58), (147, 56, 896), [1, 654, 78]], - ids=['None', '()', '123', '(12,58)', '(147,56,896)', '[1,654,78]']) -def test_rs_uniform(usm_type, seed): - seed = 123 - sycl_queue = dpctl.SyclQueue() - low = 1.0 - high = 2.0 - rs = dpnp.random.RandomState(seed, sycl_queue=sycl_queue) - res = rs.uniform(low, high, usm_type=usm_type) - - assert usm_type == res.usm_type - - res_sycl_queue = res.get_array().sycl_queue - assert_sycl_queue_equal(res_sycl_queue, sycl_queue) +def test_random_state(func, args, kwargs, device, usm_type): + kwargs = {**kwargs, 'usm_type': usm_type} + + # test with default SYCL queue per a device + rs = dpnp.random.RandomState(seed=1234567, device=device) + res_array = getattr(rs, func)(*args, **kwargs) + assert device == res_array.sycl_device + assert usm_type == res_array.usm_type + + sycl_queue = dpctl.SyclQueue(device=device, property="in_order") + + # test with in-order SYCL queue per a device and passed as argument + rs = dpnp.random.RandomState((147, 56, 896), sycl_queue=sycl_queue) + res_array = getattr(rs, func)(*args, **kwargs) + assert usm_type == res_array.usm_type + assert_sycl_queue_equal(res_array.sycl_queue, sycl_queue) @pytest.mark.usefixtures("allow_fall_back_on_numpy")