From 160719aeb242e6d69bba717315ea5ffd91281bc1 Mon Sep 17 00:00:00 2001 From: Nikita Grigorian Date: Wed, 4 Nov 2026 11:46:56 -0800 Subject: [PATCH] Rebuild RandomState and dpnp.random functions on the device RNG RandomState and the module functions now delegate to the Generator samplers, keeping NumPy's legacy checks and messages, also for parameters on the device. The module keeps one RandomState per queue, and adds get_state, set_state, get_bit_generator and set_bit_generator. Enable the CuPy random tests the device RNG supports. --- CHANGELOG.md | 2 + doc/reference/random.rst | 53 +- dpnp/AGENTS.md | 4 +- dpnp/random/__init__.py | 8 + dpnp/random/_generator.py | 179 +- dpnp/random/dpnp_iface_random.py | 2609 ++++++----------- dpnp/random/dpnp_random_state.py | 1248 +++++--- dpnp/tests/skipped_tests.tbl | 10 - dpnp/tests/skipped_tests_cuda.tbl | 662 ----- dpnp/tests/skipped_tests_gpu.tbl | 18 - dpnp/tests/test_random.py | 87 +- dpnp/tests/test_random_state.py | 1782 +++++------ dpnp/tests/test_sycl_queue.py | 71 +- dpnp/tests/test_usm_type.py | 3 +- .../cupy/random_tests/common_distributions.py | 13 + .../cupy/random_tests/test_bit_generator.py | 3 +- .../cupy/random_tests/test_distributions.py | 8 +- .../cupy/random_tests/test_generator.py | 5 +- .../cupy/random_tests/test_generator_api.py | 28 +- .../cupy/random_tests/test_permutations.py | 36 +- .../cupy/random_tests/test_random.py | 2 +- .../cupy/random_tests/test_sample.py | 20 +- 22 files changed, 2811 insertions(+), 4040 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d7df4c2ab55f..911f08be5165 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Added the multivariate distributions, `permutation`, `shuffle`, `permuted`, `choice` and `bytes` to `dpnp.random.Generator` [#3160](https://github.com/IntelPython/dpnp/pull/3160) * Added the `dpnp.random.PCG64DXSM` bit generator, which matches `numpy.random.PCG64DXSM` for raw values, `random`, `uniform` and `bytes` [#3161](https://github.com/IntelPython/dpnp/pull/3161) * Added the `dpnp.random.MRG32k3a` bit generator [#3161](https://github.com/IntelPython/dpnp/pull/3161) +* Added `dpnp.random.get_state`, `dpnp.random.set_state`, `dpnp.random.get_bit_generator` and `dpnp.random.set_bit_generator`, and support for a bit generator as the seed of `dpnp.random.RandomState` [#3162](https://github.com/IntelPython/dpnp/pull/3162) ### Changed @@ -24,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Merged the `ufunc` and `indexing` extensions into `dpnp.libtensor._tensor_elementwise_impl` and `dpnp.libtensor._tensor_impl`, while `statistics` and `window` extensions became part of libtensor [#3131](https://github.com/IntelPython/dpnp/pull/3131) * Moved `blas`, `fft`, `lapack`, `sparse` and `vm` extensions into `dpnp/libtensor/extensions` [#3131](https://github.com/IntelPython/dpnp/pull/3131) * Moved the libtensor headers shipped with dpnp from `dpnp/tensor/libtensor/include` to `dpnp/libtensor/include`, and changed `dpnp.get_include` to return that directory [#3131](https://github.com/IntelPython/dpnp/pull/3131) +* Reimplemented `dpnp.random.RandomState` and the `dpnp.random` functions on device kernels, giving the same values on every device. `device`, `usm_type` and `sycl_queue` are now keyword-only, `randint(dtype=int)` returns `int64` and `shuffle` requires a `dpnp.ndarray` [#3162](https://github.com/IntelPython/dpnp/pull/3162) ### Deprecated diff --git a/doc/reference/random.rst b/doc/reference/random.rst index 810a5ff7f5bd..d528920f5267 100644 --- a/doc/reference/random.rst +++ b/doc/reference/random.rst @@ -8,10 +8,9 @@ Random sampling (:mod:`dpnp.random`) DPNP draws random numbers on the SYCL device, by default with the counter-based Philox4x32x10 generator of the oneMKL device RNG API, or with NumPy's PCG64DXSM generator or the MRG32k3a generator of the oneMKL device -RNG API. It provides the -:class:`Generator` API of NumPy, recommended for new code. The legacy -:class:`RandomState` API and the module-level functions still use the -host-side oneMKL RNG. +RNG API. It provides both NumPy random APIs: the :class:`Generator` API recommended for new code, +and the legacy :class:`RandomState` API with the module-level functions +built on it. .. code-block:: python @@ -41,8 +40,8 @@ Differences from NumPy which defaults to the default floating-point type of the device. All methods take a ``usm_type`` keyword. * Parameters on the host (Python scalars, lists and NumPy arrays) are - checked as in NumPy. Parameters in :class:`dpnp.ndarray` are - not, since that would wait for the device. + checked as in NumPy. In :class:`Generator`, parameters in + :class:`dpnp.ndarray` are not, since that would wait for the device. Invalid ones give undefined values, such as NaN or the smallest ``int64``, but the kernels handle them safely: they never loop without end or access memory out of bounds. Floating-point arrays given for integer parameters @@ -58,9 +57,15 @@ Differences from NumPy * ``zipf`` follows the Zipf distribution truncated to the largest ``int64``. NumPy's rejection test rounds to accepting every sample above ``2**53``, which makes its tail too heavy for ``a`` close to 1. -* ``hypergeometric`` requires ``ngood`` and ``nbad`` below ``10**9``. -* :meth:`Generator.shuffle` only accepts a :class:`dpnp.ndarray`, as in - CuPy. +* :meth:`RandomState.randint` and :func:`randint` return ``int64`` values by + default, as do :meth:`RandomState.random_integers`, + :func:`random_integers` and :meth:`RandomState.tomaxint`, whose values + reach the largest ``int64``. NumPy returns a C ``long`` instead, which is + ``int32`` on Windows. +* ``hypergeometric`` requires ``ngood`` and ``nbad`` below ``10**9``, also in + :class:`RandomState`. +* :meth:`Generator.shuffle` and :func:`shuffle` only accept a + :class:`dpnp.ndarray`, as in CuPy. Random Generator ---------------- @@ -157,6 +162,24 @@ Legacy random generation .. hint:: `NumPy API Reference: Legacy random generation `_ +:class:`RandomState` keeps the parameter checks of NumPy's legacy one, also +for parameters in :class:`dpnp.ndarray`, as CuPy's does, so that a call with +such parameters waits for the device to check them. The module-level +functions use one :class:`RandomState` per SYCL queue: the +queue given by the ``device`` or ``sycl_queue`` keyword, or else the queue of +a :class:`dpnp.ndarray` parameter, or else the default queue. + +.. autosummary:: + :toctree: generated/ + :nosignatures: + + RandomState + seed + get_state + set_state + get_bit_generator + set_bit_generator + Simple random data ^^^^^^^^^^^^^^^^^^ @@ -227,15 +250,3 @@ Distributions wald weibull zipf - -Random generator -^^^^^^^^^^^^^^^^ - -.. autosummary:: - :toctree: generated/ - :nosignatures: - - RandomState - seed - get_random_state - set_random_state diff --git a/dpnp/AGENTS.md b/dpnp/AGENTS.md index 8d2a8d977af2..0aedf8e654ac 100644 --- a/dpnp/AGENTS.md +++ b/dpnp/AGENTS.md @@ -6,7 +6,7 @@ - `dpnp_algo/dpnp_elementwise_common.py`: ufunc wrapper classes (`DPNPUnaryFunc`, `DPNPBinaryFunc`, two-output and specialised variants) - `dpnp_utils/`: shared helpers (`get_usm_allocations`, `map_dtype_to_device`, reduction wrappers) - `linalg/`, `fft/`, `random/`, `scipy/`, `lib/`: subpackages, each exporting through its own `__init__.py` -- `random/`: `_bit_generator.py` (`BitGenerator`, `Philox4x3210`, `PCG64DXSM`, `MRG32k3a`; `SeedSequence` is NumPy's) and `_generator.py` (`Generator`, which implements every distribution). The kernels are in `dpnp.libtensor._rng_impl`. +- `random/`: `_bit_generator.py` (`BitGenerator`, `Philox4x3210`, `PCG64DXSM`, `MRG32k3a`; `SeedSequence` is NumPy's), `_generator.py` (`Generator`, which implements every distribution), `dpnp_random_state.py` (`RandomState`, the same samplers with NumPy's legacy checks) and `dpnp_iface_random.py` (module functions, one `RandomState` per queue). The kernels are in `dpnp.libtensor._rng_impl`. - Legacy, don't extend: the Cython `dpnp_algo` path and `dpnp_backend_c` (still used by `dpnp.partition` and `dpnp.random`), and the NumPy fallback `call_origin`. New kernels go into `dpnp/libtensor` (see `dpnp/libtensor/AGENTS.md`). ## Adding a Public Function @@ -21,7 +21,7 @@ - Extension calls are ordered with `_manager = dpctl.utils.SequentialOrderManager[exec_q]`: pass `depends=_manager.submitted_events`, then `_manager.add_event_pair(ht_ev, ev)`. Don't add blocking waits. - Use `dpnp.default_float_type(...)` or `map_dtype_to_device(...)` for the default float type. - Deprecated ufuncs use `DPNPDeprecatedUnaryFunc(..., deprecated_msg=...)`. -- A `dpnp.random` distribution is a `Generator` method: it calls `self._check_queues(...)` on its array parameters (raises `ExecutionPlacementError`), checks host parameters as NumPy does, and draws through `_cont`, `_float_sample` or `_discrete_sample` into `BitGenerator._fill`. Parameters on the device are not checked, as the check waits for the device. Temporaries take the output's `usm_type`. +- A `dpnp.random` distribution is a `Generator` method: it calls `self._check_queues(...)` on its array parameters (raises `ExecutionPlacementError`), checks host parameters as NumPy does, and draws through `_cont`, `_float_sample` or `_discrete_sample` into `BitGenerator._fill`. `RandomState` and the module function delegate to it. Parameters on the device are checked only by `RandomState` (`_check_device`), as the check waits for the device. Temporaries take the output's `usm_type`. - Unsupported NumPy keywords raise `NotImplementedError` (`dpnp.check_limitations`) and are listed under `Limitations` in the docstring. - The Array API spec version is set in three places that change together: `__array_api_version__` in `dpnp/tensor/_array_api.py`, `ARRAY_API_TESTS_VERSION` in `.github/workflows/conda-package.yml` and `doc/reference/array_api.rst` (plus the version test in `dpnp/tests/test_ndarray.py`). Inspection utilities come from `__array_namespace_info__` in `dpnp_array_api_info.py`. - `dpnp.tensor` replaces `dpctl.tensor`, which no longer exists here; `SyclQueue`, `SyclDevice`, `dpctl.memory` and `SequentialOrderManager` still come from `dpctl`. diff --git a/dpnp/random/__init__.py b/dpnp/random/__init__.py index dbf860948850..90170ba616aa 100644 --- a/dpnp/random/__init__.py +++ b/dpnp/random/__init__.py @@ -45,6 +45,8 @@ f, gamma, geometric, + get_bit_generator, + get_state, gumbel, hypergeometric, laplace, @@ -71,6 +73,8 @@ rayleigh, sample, seed, + set_bit_generator, + set_state, shuffle, standard_cauchy, standard_exponential, @@ -104,6 +108,8 @@ "f", "gamma", "geometric", + "get_bit_generator", + "get_state", "gumbel", "hypergeometric", "laplace", @@ -131,6 +137,8 @@ "sample", "shuffle", "seed", + "set_bit_generator", + "set_state", "standard_cauchy", "standard_exponential", "standard_gamma", diff --git a/dpnp/random/_generator.py b/dpnp/random/_generator.py index 4978d5ad53a9..d96ddfd74e16 100644 --- a/dpnp/random/_generator.py +++ b/dpnp/random/_generator.py @@ -84,6 +84,7 @@ _CONS_BOUNDED_LT_0_1 = 6 _CONS_GT_1 = 7 _CONS_POISSON = 8 +_CONS_GTE_1 = 9 _POISSON_LAM_MAX = _INT64_MAX - numpy.sqrt(_INT64_MAX) * 10 _HYPERGEOM_MAX = 10**9 @@ -175,79 +176,125 @@ def _check_real(value): raise TypeError(f"must be real number, not {t.__name__}") -def _uniform_range(low, high, overflow_msg): +def _uniform_range(low, high, overflow_msg, device=False): """ ``high - low``, raising OverflowError with `overflow_msg` unless it is - finite, or ``None`` when either param is on the device. + finite, or ``None`` when either param is on the device, unless `device` + is true. """ - xp, (flow, fhigh) = _check_arrays((low, high), numpy.float64) + xp, (flow, fhigh) = _check_arrays((low, high), device, numpy.float64) if xp is None: return None - with numpy.errstate(over="ignore", invalid="ignore"): - rng = numpy.subtract(fhigh, flow) - if _is_scalar_path(low, high): - _check_real(low) - _check_real(high) - if not numpy.all(numpy.isfinite(rng)): + if xp is dpnp: + rng = dpnp.subtract(fhigh, flow) + else: + with numpy.errstate(over="ignore", invalid="ignore"): + rng = numpy.subtract(fhigh, flow) + if _is_scalar_path(low, high): + _check_real(low) + _check_real(high) + if not xp.all(xp.isfinite(rng)): raise OverflowError(overflow_msg) return rng -def _check_arrays(params, dtype=None): +def _on_device(value): + """ + `value` for a check on the device, as a floating-point array unless it + already is one. + + """ + + value = dpnp.asarray(value) + if dpnp.issubdtype(value.dtype, dpnp.inexact): + return value + return value.astype(dpnp.default_float_type(sycl_queue=value.sycl_queue)) + + +def _check_arrays(params, device, dtype=None): """ - `params` as arrays of `dtype` to check, with the module to check them - by, which is ``None`` when some are on the device, as the check would - wait for the device. + `params` as arrays to check, with the module to check them by, which is + ``None`` when some are on the device and `device` is false. + + Host parameters are converted to `dtype`, and moved to the device when + others are on the device. """ - if any(dpnp.is_supported_array_type(p) for p in params): + queues = [p.sycl_queue for p in params if dpnp.is_supported_array_type(p)] + host = [ + None if dpnp.is_supported_array_type(p) else numpy.asarray(p, dtype) + for p in params + ] + if not queues: + return numpy, host + if not device: return None, [None] * len(params) - return numpy, [numpy.asarray(p, dtype) for p in params] + + def _to_device(p, h): + if h is None: + return dpnp.asarray(p) + if ( + h.dtype == numpy.float64 + and not queues[0].sycl_device.has_aspect_fp64 + ): + h = h.astype(numpy.float32) + return dpnp.asarray(h, sycl_queue=queues[0]) + + return dpnp, [_to_device(p, h) for p, h in zip(params, host)] # pylint: disable=too-many-branches -def _check_constraint(value, name, cons, scalar): +def _check_constraint(value, name, cons, scalar, device=False): """ Raise ValueError, as NumPy does, when the parameter `value` violates the constraint `cons`. - Parameters on the device are not checked, as the check waits for the - device. `scalar` selects the messages of NumPy's scalar path. + Parameters on the device are checked only with `device`, as the check + waits for the device. `scalar` selects the messages of NumPy's scalar + path. """ if dpnp.is_supported_array_type(value): - return - val = numpy.asarray(value, dtype=numpy.float64) - if scalar: - _check_real(value) + if not device: + return + xp = dpnp + val = _on_device(value) + else: + xp = numpy + val = numpy.asarray(value, dtype=numpy.float64) + if scalar: + _check_real(value) if cons == _CONS_NONE: return nan_msg = "is NaN" if scalar else "contains NaNs" if cons == _CONS_NON_NEGATIVE: - if numpy.any(~numpy.isnan(val) & numpy.signbit(val)): + if xp.any(~xp.isnan(val) & xp.signbit(val)): raise ValueError(f"{name} < 0") elif cons in (_CONS_POSITIVE, _CONS_POSITIVE_NOT_NAN): - if cons == _CONS_POSITIVE_NOT_NAN and numpy.any(numpy.isnan(val)): + if cons == _CONS_POSITIVE_NOT_NAN and xp.any(xp.isnan(val)): raise ValueError(f"{name} must not be NaN") - if numpy.any(val <= 0): + if xp.any(val <= 0): raise ValueError(f"{name} <= 0") elif cons == _CONS_BOUNDED_0_1: - if not numpy.all((val >= 0) & (val <= 1)): + if not xp.all((val >= 0) & (val <= 1)): raise ValueError(f"{name} < 0, {name} > 1 or {name} {nan_msg}") elif cons == _CONS_BOUNDED_GT_0_1: - if not numpy.all((val > 0) & (val <= 1)): + if not xp.all((val > 0) & (val <= 1)): raise ValueError(f"{name} <= 0, {name} > 1 or {name} contains NaNs") elif cons == _CONS_BOUNDED_LT_0_1: - if not numpy.all((val >= 0) & (val < 1)): + if not xp.all((val >= 0) & (val < 1)): raise ValueError(f"{name} < 0, {name} >= 1 or {name} {nan_msg}") elif cons == _CONS_GT_1: - if not numpy.all(val > 1): + if not xp.all(val > 1): raise ValueError(f"{name} <= 1 or {name} {nan_msg}") + elif cons == _CONS_GTE_1: + if not xp.all(val >= 1): + raise ValueError(f"{name} < 1 or {name} {nan_msg}") elif cons == _CONS_POISSON: # the array path checks the upper bound first, so NaN fails it if scalar: @@ -256,9 +303,9 @@ def _check_constraint(value, name, cons, scalar): if val > _POISSON_LAM_MAX: raise ValueError(f"{name} value too large") else: - if not numpy.all(val <= _POISSON_LAM_MAX): + if not xp.all(val <= _POISSON_LAM_MAX): raise ValueError(f"{name} value too large") - if not numpy.all(val >= 0): + if not xp.all(val >= 0): raise ValueError(f"{name} < 0 or {name} contains NaNs") @@ -325,6 +372,9 @@ class Generator: """ + # Whether parameters on the device are checked, waiting for the device + _check_device = False + def __init__(self, bit_generator): if not isinstance(bit_generator, BitGenerator): raise TypeError( @@ -546,7 +596,9 @@ def _cont(self, kernel, name, size, dtype, usm_type, *params, out=None): self._check_queues(*values, out) scalar = _is_scalar_path(*values) for value, pname, cons in params: - _check_constraint(value, pname, cons, scalar) + _check_constraint( + value, pname, cons, scalar, device=self._check_device + ) return self._float_sample( kernel, values, size, dtype, usm_type, name, out=out ) @@ -652,6 +704,7 @@ def uniform( if scalar else "Range exceeds valid bounds" ), + self._check_device, ) if rng is not None: _check_constraint( @@ -659,6 +712,7 @@ def uniform( "high - low", _CONS_NON_NEGATIVE, scalar, + device=self._check_device, ) return self._float_sample( ri._uniform, (low, high), size, dtype, usm_type, "uniform" @@ -997,7 +1051,9 @@ def triangular( params = (left, mode, right) self._check_queues(*params) - xp, (fleft, fmode, fright) = _check_arrays(params, numpy.float64) + xp, (fleft, fmode, fright) = _check_arrays( + params, self._check_device, numpy.float64 + ) if xp is not None: if xp is numpy and _is_scalar_path(*params): for p in params: @@ -1055,6 +1111,7 @@ def standard_gamma( "shape", _CONS_NON_NEGATIVE, _is_scalar_path(shape), + device=self._check_device, ) return self._float_sample( ri._gamma, @@ -1242,6 +1299,7 @@ def poisson(self, lam=1.0, size=None, *, usm_type="device"): "lam", _CONS_POISSON, _is_scalar_path(lam), + device=self._check_device, ) return self._discrete_sample( ri._poisson, (lam,), size, usm_type, f32_bounds=(_F32_LT_2_63,) @@ -1264,8 +1322,12 @@ def binomial(self, n, p, size=None, *, usm_type="device"): scalar = _is_scalar_path(n, p) # NumPy converts both parameters before checking either n = _as_int64(n) - _check_constraint(p, "p", _CONS_BOUNDED_0_1, scalar) - _check_constraint(n, "n", _CONS_NON_NEGATIVE, scalar) + _check_constraint( + p, "p", _CONS_BOUNDED_0_1, scalar, device=self._check_device + ) + _check_constraint( + n, "n", _CONS_NON_NEGATIVE, scalar, device=self._check_device + ) return self._discrete_sample( ri._binomial, (n, p), size, usm_type, param_types=(_int64, None) ) @@ -1285,8 +1347,12 @@ def negative_binomial(self, n, p, size=None, *, usm_type="device"): self._check_queues(n, p) # NumPy takes scalar parameters as arrays here, so None gives NaN - _check_constraint(n, "n", _CONS_POSITIVE_NOT_NAN, False) - _check_constraint(p, "p", _CONS_BOUNDED_GT_0_1, False) + _check_constraint( + n, "n", _CONS_POSITIVE_NOT_NAN, False, device=self._check_device + ) + _check_constraint( + p, "p", _CONS_BOUNDED_GT_0_1, False, device=self._check_device + ) if not ( dpnp.is_supported_array_type(n) or dpnp.is_supported_array_type(p) ): @@ -1322,6 +1388,7 @@ def geometric(self, p, size=None, *, usm_type="device"): "p", _CONS_BOUNDED_GT_0_1, _is_scalar_path(p), + device=self._check_device, ) return self._discrete_sample( ri._geometric, (p,), size, usm_type, f32_bounds=(_F32_GT_0,) @@ -1346,6 +1413,7 @@ def logseries(self, p, size=None, *, usm_type="device"): "p", _CONS_BOUNDED_LT_0_1, _is_scalar_path(p), + device=self._check_device, ) return self._discrete_sample( ri._logseries, (p,), size, usm_type, f32_bounds=(_F32_LT_1,) @@ -1367,7 +1435,9 @@ def zipf(self, a, size=None, *, usm_type="device"): """ self._check_queues(a) - _check_constraint(a, "a", _CONS_GT_1, _is_scalar_path(a)) + _check_constraint( + a, "a", _CONS_GT_1, _is_scalar_path(a), device=self._check_device + ) return self._discrete_sample( ri._zipf, (a,), size, usm_type, f32_bounds=(_F32_GT_1,) ) @@ -1393,16 +1463,18 @@ def hypergeometric( scalar = _is_scalar_path(*params) for x in params[:2]: - xp, (xa,) = _check_arrays((x,)) + xp, (xa,) = _check_arrays((x,), self._check_device) if xp is not None and xp.any(xa >= _HYPERGEOM_MAX): raise ValueError( "both ngood and nbad must be less than " f"{_HYPERGEOM_MAX}" ) - xp, (good, bad, sample) = _check_arrays(params) + xp, (good, bad, sample) = _check_arrays(params, self._check_device) if xp is not None and xp.any(good + bad < sample): raise ValueError("ngood + nbad < nsample") for x, name in zip(params, names): - _check_constraint(x, name, _CONS_NON_NEGATIVE, scalar) + _check_constraint( + x, name, _CONS_NON_NEGATIVE, scalar, device=self._check_device + ) return self._discrete_sample( ri._hypergeometric, @@ -1521,9 +1593,12 @@ def multinomial(self, n, pvals, size=None, *, usm_type="device"): "pvals must have at least 1 dimension and the last dimension " "of pvals must be greater than 0." ) - if on_host: - _check_constraint(pvals, "pvals", _CONS_BOUNDED_0_1, False) - if numpy.any(pvals[..., :-1].sum(axis=-1) > 1.0 + 1e-12): + if on_host or self._check_device: + xp = numpy if on_host else dpnp + _check_constraint( + pvals, "pvals", _CONS_BOUNDED_0_1, False, device=True + ) + if xp.any(pvals[..., :-1].sum(axis=-1) > 1.0 + 1e-12): raise ValueError( "sum(pvals[:-1]) > 1.0" if pvals.ndim == 1 @@ -1536,6 +1611,7 @@ def multinomial(self, n, pvals, size=None, *, usm_type="device"): "n", _CONS_NON_NEGATIVE, numpy.ndim(n) == 0, + device=self._check_device, ) d = pvals.shape[-1] @@ -1994,7 +2070,13 @@ def _choice(self, a, size, replace, p, axis, usm_type, msgs): raise ValueError(msgs["p_1d"]) if p_dev.size != pop_size: raise ValueError(msgs["p_size"]) - p_check = p_host + if p_host is None and self._check_device: + p_check = p_dev + atol = numpy.sqrt(numpy.finfo(numpy.float64).eps) + if dpnp.issubdtype(p_dev.dtype, dpnp.floating): + atol = max(atol, numpy.sqrt(numpy.finfo(p_dev.dtype).eps)) + else: + p_check = p_host if p_check is not None: p_sum = float(p_check.sum()) if numpy.isnan(p_sum): @@ -2127,8 +2209,11 @@ def _check_bounds(low, high): params = (low, high) def _on_host(x): - # bounds on the device are not checked - return None if dpnp.is_supported_array_type(x) else x + if not dpnp.is_supported_array_type(x): + return x + # NumPy's checks of mixed integer types and Python integers + # are exact, so bounds on the device are checked on the host + return dpnp.asnumpy(x) if self._check_device else None _check_bounds( *( diff --git a/dpnp/random/dpnp_iface_random.py b/dpnp/random/dpnp_iface_random.py index ca1e3d1a463a..0ec4ff1c7bcd 100644 --- a/dpnp/random/dpnp_iface_random.py +++ b/dpnp/random/dpnp_iface_random.py @@ -1,4 +1,3 @@ -# cython: language_level=3 # ***************************************************************************** # Copyright (c) 2016, Intel Corporation # All rights reserved. @@ -28,1156 +27,985 @@ # ***************************************************************************** """ -Module Intel NumPy Random +The functions of :mod:`dpnp.random` of NumPy's legacy API. -Set of functions to implement NumPy random module API +Every function draws from a :class:`dpnp.random.RandomState` of the SYCL +queue given by `device` or `sycl_queue`. Without either, the common queue of +the parameters that are :class:`dpnp.ndarray` is used, or else the default +queue, and parameters on incompatible queues raise +:class:`dpnp.exceptions.ExecutionPlacementError`. There is one state per +queue, which :func:`seed` reseeds. .. seealso:: :obj:`numpy.random` """ -import operator -import threading +# pylint: disable=redefined-builtin +# pylint: disable=too-many-arguments -import numpy +import threading import dpnp -from dpnp.dpnp_algo import * -from dpnp.dpnp_utils import * +import dpnp.tensor as dpt +from dpnp.exceptions import ExecutionPlacementError + +from ._bit_generator import BitGenerator, Philox4x3210 +from .dpnp_random_state import RandomState, _reseed_in_place + +# The states of the queues. The lock guarantees that concurrent callers +# asking for the state of the same queue get the same instance back rather +# than each building one of their own. +_dpnp_random_states = {} +_random_states_lock = threading.Lock() + +_QUEUE_PARAMS = """\ + device : {None, string, SyclDevice, SyclQueue, Device}, optional + An array API concept of device where the output array is created. + `device` can be ``None``, a 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 :class:`dpnp.tensor.Device` object returned by + :attr:`dpnp.ndarray.device`. + + Default: ``None``. + sycl_queue : {None, SyclQueue}, optional + A SYCL queue to use for output array allocation and copying. + + Default: ``None``.""" + +_USM_PARAM = """\ + usm_type : {"device", "shared", "host"}, optional + The type of SYCL USM allocation for the output array. -from .dpnp_algo_random import * -from .dpnp_random_state import RandomState + Default: ``"device"``.""" -# lock the RNG calls for concurrent access -_legacy_rng_lock = threading.RLock() +_DTYPE_PARAM = """\ + dtype : {None, float32, float64}, optional + The floating-point type of the output. + Default: ``None``, the default floating-point type of the device.""" -def _legacy_rng(func, *args, **kwargs): - """Call a legacy ``dpnp_rng_*`` generator holding `_legacy_rng_lock`.""" - with _legacy_rng_lock: - return func(*args, **kwargs) +def _params_doc(func): + """Fill the placeholders of the parameters common to the functions.""" + + func.__doc__ = ( + func.__doc__.replace(" %(queue)s", _QUEUE_PARAMS) + .replace(" %(usm)s", _USM_PARAM) + .replace(" %(dtype)s", _DTYPE_PARAM) + ) + return func -# Guards the `_dpnp_random_states` cache, so that concurrent callers asking -# for the state of the same queue are guaranteed to get the same instance -# back rather than each building one of their own. -_random_states_lock = threading.RLock() +def _get_random_state(device=None, sycl_queue=None, arrays=()): + """ + The state of the queue of `device` or `sycl_queue`, or else of the common + queue of the arrays of `arrays`, or else of the default queue. -def _get_random_state(device=None, sycl_queue=None): - global _dpnp_random_states + """ + if device is None and sycl_queue is None: + queues = [ + x.sycl_queue for x in arrays if dpnp.is_supported_array_type(x) + ] + if queues: + sycl_queue = dpt.get_execution_queue(queues) + if sycl_queue is None: + raise ExecutionPlacementError( + "Input arrays have incompatible allocation queues" + ) sycl_queue = dpnp.get_normalized_queue_device( device=device, sycl_queue=sycl_queue ) with _random_states_lock: - if not isinstance(_dpnp_random_states, dict): - _dpnp_random_states = {} - 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( - f"Normalized SYCL queue {sycl_queue} mismatched with one " - f"returned by RandmoState {rs.get_sycl_queue()}" - ) - return _dpnp_random_states[sycl_queue] + rs = _dpnp_random_states.get(sycl_queue) + if rs is None: + rs = RandomState(sycl_queue=sycl_queue) + _dpnp_random_states[sycl_queue] = rs + return rs -def _is_type_supported(obj_type): - """Return True if type is supported by dpnp.random""" +@_params_doc +def seed(seed=None, *, device=None, sycl_queue=None): + # pylint: disable=redefined-outer-name + """ + Reseed the state of a queue. + + For full documentation refer to :obj:`numpy.random.seed`. - if obj_type in (dpnp.float64, dpnp.float32, dpnp.int64, dpnp.int32): - return True - return False + Parameters + ---------- + %(queue)s + Notes + ----- + A bit generator set by :func:`dpnp.random.set_bit_generator` other than + :class:`dpnp.random.Philox4x3210` is reseeded in place with the state a + new one of its type would have for `seed`, as in NumPy. -def beta(a, b, size=None): """ - Draw samples from a Beta distribution. + # pylint: disable=protected-access + rs = _get_random_state(device, sycl_queue) + bit_generator = rs._generator.bit_generator + if type(bit_generator) is Philox4x3210: + rs.seed(seed) + else: + _reseed_in_place( + bit_generator, + type(bit_generator)(seed, sycl_queue=bit_generator.sycl_queue), + ) - For full documentation refer to :obj:`numpy.random.beta`. + +@_params_doc +def get_state(legacy=True, *, device=None, sycl_queue=None): + """ + Return the state of a queue. + + For full documentation refer to :obj:`numpy.random.get_state`. + + Parameters + ---------- + %(queue)s Limitations ----------- - Parameters `a` and `b` are supported as scalar. - Otherwise, :obj:`numpy.random.beta(a, b, size)` samples are drawn. - Output array data type is :obj:`dpnp.float64`. + See :meth:`dpnp.random.RandomState.get_state`. - Examples - -------- - Draw samples from the distribution: + """ + return _get_random_state(device, sycl_queue).get_state(legacy) - >>> a, b = .4, .5 # alpha, beta - >>> s = dpnp.random.beta(a, b, 1000) +@_params_doc +def set_state(state, *, device=None, sycl_queue=None): """ + Set the state of a queue. + + For full documentation refer to :obj:`numpy.random.set_state`. - if not use_origin_backend(a): - if dpnp.is_cuda_backend(): # pragma: no cover - raise NotImplementedError( - "Running on CUDA is currently not supported" - ) + Parameters + ---------- + %(queue)s - # TODO: - # array_like of floats for `a`, `b` - if not dpnp.isscalar(a): - pass - elif not dpnp.isscalar(b): - pass - elif a <= 0: - pass - elif b <= 0: - pass - else: - return _legacy_rng(dpnp_rng_beta, a, b, size).get_pyobj() + Limitations + ----------- + See :meth:`dpnp.random.RandomState.set_state`. - return call_origin(numpy.random.beta, a, b, size) + """ + _get_random_state(device, sycl_queue).set_state(state) -def binomial(n, p, size=None): +@_params_doc +def get_bit_generator(*, device=None, sycl_queue=None): """ - Draw samples from a binomial distribution. + Return the bit generator of the state of a queue, which the + :mod:`dpnp.random` functions draw from on that queue. - For full documentation refer to :obj:`numpy.random.binomial`. + For full documentation refer to :obj:`numpy.random.get_bit_generator`. - Limitations - ----------- - Output array data type is :obj:`dpnp.int32`. - Parameters `n` and `p` are supported as scalar. - Otherwise, :obj:`numpy.random.binomial(n, p, size)` samples are drawn. + Parameters + ---------- + %(queue)s + + Returns + ------- + out : BitGenerator + The bit generator, a :class:`dpnp.random.Philox4x3210` unless set + by :func:`dpnp.random.set_bit_generator`. + + See Also + -------- + :obj:`dpnp.random.set_bit_generator` : Set the bit generator of a queue. + + """ + # pylint: disable=protected-access + return _get_random_state(device, sycl_queue)._generator.bit_generator + + +def set_bit_generator(bitgen): + """ + Set the bit generator of the state of the queue of `bitgen`, which the + :mod:`dpnp.random` functions then draw from on that queue. + + For full documentation refer to :obj:`numpy.random.set_bit_generator`. + + Parameters + ---------- + bitgen : BitGenerator + The bit generator. It is used itself, not a copy, so the + :mod:`dpnp.random` functions and a :class:`dpnp.random.Generator` + of `bitgen` share its stream. + + See Also + -------- + :obj:`dpnp.random.get_bit_generator` : Return the bit generator of a + queue. Examples -------- - Draw samples from the distribution: + >>> import dpnp as np + >>> bg = np.random.PCG64DXSM(42) + >>> np.random.set_bit_generator(bg) + >>> np.random.get_bit_generator() is bg + True + + """ + if isinstance(bitgen, type) and issubclass(bitgen, BitGenerator): + raise ValueError( + "Invalid bit generator. The bit generator must be instantiated." + ) + if not isinstance(bitgen, BitGenerator): + raise TypeError( + "bitgen must be an instance of dpnp.random.BitGenerator" + ) + # pylint: disable=protected-access + _get_random_state(sycl_queue=bitgen.sycl_queue)._set_bit_generator(bitgen) + + +@_params_doc +def beta( + a, + b, + size=None, + dtype=None, + *, + device=None, + usm_type="device", + sycl_queue=None, +): + """ + Draw samples from a Beta distribution. + + For full documentation refer to :obj:`numpy.random.beta`. + + Parameters + ---------- + %(dtype)s + %(queue)s + %(usm)s + + See Also + -------- + :obj:`dpnp.random.RandomState.beta` + + """ + rs = _get_random_state(device, sycl_queue, (a, b)) + return rs.beta(a, b, size, dtype, usm_type=usm_type) - >>> n, p = 10, .5 # number of trials, probability of each trial - >>> s = dpnp.random.binomial(n, p, 1000) - # result of flipping a coin 10 times, tested 1000 times. - A real world example. A company drills 9 wild-cat oil exploration - wells, each with an estimated probability of success of 0.1. All nine - wells fail. What is the probability of that happening? - Let's do 20,000 trials of the model, and count the number that - generate zero positive results. - >>> sum(dpnp.random.binomial(9, 0.1, 20000) == 0)/20000. - # answer = 0.38885, or 38%. +@_params_doc +def binomial( + n, p, size=None, *, device=None, usm_type="device", sycl_queue=None +): """ + Draw samples from a binomial distribution. + + For full documentation refer to :obj:`numpy.random.binomial`. - if not use_origin_backend(n): - if dpnp.is_cuda_backend(): # pragma: no cover - raise NotImplementedError( - "Running on CUDA is currently not supported" - ) + Parameters + ---------- + %(queue)s + %(usm)s - # TODO: - # array_like of floats for `p` param - if not dpnp.isscalar(n): - pass - elif not dpnp.isscalar(p): - pass - elif p > 1 or p < 0: - pass - elif n < 0: - pass - else: - return _legacy_rng(dpnp_rng_binomial, int(n), p, size).get_pyobj() + See Also + -------- + :obj:`dpnp.random.RandomState.binomial` - return call_origin(numpy.random.binomial, n, p, size) + """ + rs = _get_random_state(device, sycl_queue, (n, p)) + return rs.binomial(n, p, size, usm_type=usm_type) -def bytes(length): +@_params_doc +def bytes(length, *, device=None, sycl_queue=None): """ Return random bytes. For full documentation refer to :obj:`numpy.random.bytes`. - Notes - ----- - The function uses `numpy.random.bytes` on the backend and will be - executed on fallback backend. + Parameters + ---------- + %(queue)s """ + return _get_random_state(device, sycl_queue).bytes(length) - return call_origin(numpy.random.bytes, length) - -def chisquare(df, size=None): +@_params_doc +def chisquare( + df, + size=None, + dtype=None, + *, + device=None, + usm_type="device", + sycl_queue=None, +): """ Draw samples from a chi-square distribution. For full documentation refer to :obj:`numpy.random.chisquare`. - Limitations - ----------- - Parameter `df` is supported as a scalar. - Otherwise, :obj:`numpy.random.chisquare(df, size)` samples are drawn. - Output array data type is default float type. + Parameters + ---------- + %(dtype)s + %(queue)s + %(usm)s - Examples + See Also -------- - >>> dpnp.random.chisquare(2, 4) - array([ 1.89920014, 9.00867716, 3.13710533, 5.62318272]) # random + :obj:`dpnp.random.RandomState.chisquare` """ + rs = _get_random_state(device, sycl_queue, (df,)) + return rs.chisquare(df, size, dtype, usm_type=usm_type) - if not use_origin_backend(df): - if dpnp.is_cuda_backend(): # pragma: no cover - raise NotImplementedError( - "Running on CUDA is currently not supported" - ) - # TODO: - # array_like of floats for `df` - if not dpnp.isscalar(df): - pass - elif df <= 0: - pass - else: - # TODO: - # float to int, safe - return _legacy_rng(dpnp_rng_chisquare, int(df), size).get_pyobj() - - return call_origin(numpy.random.chisquare, df, size) - - -def choice(a, size=None, replace=True, p=None): +@_params_doc +def choice( + a, + size=None, + replace=True, + p=None, + *, + device=None, + usm_type="device", + sycl_queue=None, +): """ - Generates a random sample from a given 1-D array. + Generate a random sample from a given 1-D array. For full documentation refer to :obj:`numpy.random.choice`. - Notes - ----- - The function uses `numpy.random.choice` on the backend and will be - executed on fallback backend. + Parameters + ---------- + %(queue)s + %(usm)s - """ + See Also + -------- + :obj:`dpnp.random.RandomState.choice` - return call_origin(numpy.random.choice, a, size, replace, p) + """ + rs = _get_random_state(device, sycl_queue, (a, p)) + return rs.choice(a, size, replace, p, usm_type=usm_type) -def dirichlet(alpha, size=None): +@_params_doc +def dirichlet( + alpha, + size=None, + dtype=None, + *, + device=None, + usm_type="device", + sycl_queue=None, +): """ Draw samples from the Dirichlet distribution. For full documentation refer to :obj:`numpy.random.dirichlet`. - Notes - ----- - The function uses `numpy.random.dirichlet` on the backend and will be - executed on fallback backend. + Parameters + ---------- + %(dtype)s + %(queue)s + %(usm)s - """ + See Also + -------- + :obj:`dpnp.random.RandomState.dirichlet` - return call_origin(numpy.random.dirichlet, alpha, size) + """ + rs = _get_random_state(device, sycl_queue, (alpha,)) + return rs.dirichlet(alpha, size, dtype, usm_type=usm_type) -def exponential(scale=1.0, size=None): +@_params_doc +def exponential( + scale=1.0, + size=None, + dtype=None, + *, + device=None, + usm_type="device", + sycl_queue=None, +): """ Draw samples from an exponential distribution. For full documentation refer to :obj:`numpy.random.exponential`. - Limitations - ----------- - Parameter `scale` is supported as a scalar. - Otherwise, :obj:`numpy.random.exponential(scale, size)` samples are drawn. - Output array data type is :obj:`dpnp.float64`. + Parameters + ---------- + %(dtype)s + %(queue)s + %(usm)s - Examples + See Also -------- - Draw samples from the distribution: - - >>> scale = .5 # alpha - >>> s = dpnp.random.exponential(scale, 1000) + :obj:`dpnp.random.RandomState.exponential` """ + rs = _get_random_state(device, sycl_queue, (scale,)) + return rs.exponential(scale, size, dtype, usm_type=usm_type) - if not use_origin_backend(scale): - if dpnp.is_cuda_backend(): # pragma: no cover - raise NotImplementedError( - "Running on CUDA is currently not supported" - ) - - # TODO: - # array_like of floats for `scale` - if not dpnp.isscalar(scale): - pass - elif scale < 0: - pass - else: - return _legacy_rng(dpnp_rng_exponential, scale, size).get_pyobj() - - return call_origin(numpy.random.exponential, scale, size) - -def f(dfnum, dfden, size=None): +@_params_doc +def f( + dfnum, + dfden, + size=None, + dtype=None, + *, + device=None, + usm_type="device", + sycl_queue=None, +): """ Draw samples from an F distribution. For full documentation refer to :obj:`numpy.random.f`. - Limitations - ----------- - Parameters `dfnum` and `dfden` are supported as scalar. - Otherwise, :obj:`numpy.random.f(dfnum, dfden, size)` samples are drawn. - Output array data type is :obj:`dpnp.float64`. + Parameters + ---------- + %(dtype)s + %(queue)s + %(usm)s - Examples + See Also -------- - >>> dfnum, dfden = 3., 2. - >>> s = dpnp.random.f(dfnum, dfden, size) + :obj:`dpnp.random.RandomState.f` """ + rs = _get_random_state(device, sycl_queue, (dfnum, dfden)) + return rs.f(dfnum, dfden, size, dtype, usm_type=usm_type) - if not use_origin_backend(dfnum): - if dpnp.is_cuda_backend(): # pragma: no cover - raise NotImplementedError( - "Running on CUDA is currently not supported" - ) - # TODO: - # array_like of floats for `dfnum` and `dfden` - if not dpnp.isscalar(dfnum): - pass - elif not dpnp.isscalar(dfden): - pass - elif dfnum <= 0: - pass - elif dfden <= 0: - pass - else: - return _legacy_rng(dpnp_rng_f, dfnum, dfden, size).get_pyobj() - - return call_origin(numpy.random.f, dfnum, dfden, size) - - -def gamma(shape, scale=1.0, size=None): +@_params_doc +def gamma( + shape, + scale=1.0, + size=None, + dtype=None, + *, + device=None, + usm_type="device", + sycl_queue=None, +): """ Draw samples from a Gamma distribution. For full documentation refer to :obj:`numpy.random.gamma`. - Limitations - ----------- - Parameters `shape` and `scale` are supported as scalar. - Otherwise, :obj:`numpy.random.gamma(shape, scale, size)` samples are drawn. - Output array data type is :obj:`dpnp.float64`. + Parameters + ---------- + %(dtype)s + %(queue)s + %(usm)s - Examples + See Also -------- - Draw samples from the distribution: - - >>> shape, scale = 0, 0.1 # shape and scale - >>> s = dpnp.random.gamma(shape, scale, 1000) + :obj:`dpnp.random.RandomState.gamma` """ + rs = _get_random_state(device, sycl_queue, (shape, scale)) + return rs.gamma(shape, scale, size, dtype, usm_type=usm_type) - if not use_origin_backend(scale): - if dpnp.is_cuda_backend(): # pragma: no cover - raise NotImplementedError( - "Running on CUDA is currently not supported" - ) - # TODO: - # array_like of floats for `scale` and `shape` - if not dpnp.isscalar(scale): - pass - elif not dpnp.isscalar(shape): - pass - elif scale < 0: - pass - elif shape < 0: - pass - else: - return _legacy_rng(dpnp_rng_gamma, shape, scale, size).get_pyobj() - - return call_origin(numpy.random.gamma, shape, scale, size) - - -def geometric(p, size=None): +@_params_doc +def geometric(p, size=None, *, device=None, usm_type="device", sycl_queue=None): """ Draw samples from the geometric distribution. For full documentation refer to :obj:`numpy.random.geometric`. - Limitations - ----------- - Parameter `p` is supported as a scalar. - Otherwise, :obj:`numpy.random.geometric(p, size)` samples are drawn. - Output array data type is :obj:`dpnp.int32`. + Parameters + ---------- + %(queue)s + %(usm)s - Examples + See Also -------- - Draw ten thousand values from the geometric distribution, - with the probability of an individual success equal to 0.35: - - >>> z = dpnp.random.geometric(p=0.35, size=10000) + :obj:`dpnp.random.RandomState.geometric` """ + rs = _get_random_state(device, sycl_queue, (p,)) + return rs.geometric(p, size, usm_type=usm_type) - if not use_origin_backend(p): - if dpnp.is_cuda_backend(): # pragma: no cover - raise NotImplementedError( - "Running on CUDA is currently not supported" - ) - - # TODO: - # array_like of floats for `p` param - if not dpnp.isscalar(p): - pass - elif p > 1 or p <= 0: - pass - else: - return _legacy_rng(dpnp_rng_geometric, p, size).get_pyobj() - - return call_origin(numpy.random.geometric, p, size) - -def gumbel(loc=0.0, scale=1.0, size=None): +@_params_doc +def gumbel( + loc=0.0, + scale=1.0, + size=None, + dtype=None, + *, + device=None, + usm_type="device", + sycl_queue=None, +): """ Draw samples from a Gumbel distribution. For full documentation refer to :obj:`numpy.random.gumbel`. - Limitations - ----------- - Parameters `loc` and `scale` are supported as scalar. - Otherwise, :obj:`numpy.random.gumbel(loc, scale, size)` samples are drawn. - Output array data type is :obj:`dpnp.float64`. + Parameters + ---------- + %(dtype)s + %(queue)s + %(usm)s - Examples + See Also -------- - Draw samples from the distribution: - - >>> mu, beta = 0, 0.1 # location and scale - >>> s = dpnp.random.gumbel(mu, beta, 1000) + :obj:`dpnp.random.RandomState.gumbel` """ + rs = _get_random_state(device, sycl_queue, (loc, scale)) + return rs.gumbel(loc, scale, size, dtype, usm_type=usm_type) - if not use_origin_backend(loc): - if dpnp.is_cuda_backend(): # pragma: no cover - raise NotImplementedError( - "Running on CUDA is currently not supported" - ) - - # TODO: - # array_like of floats for `loc` and `scale` params - if not dpnp.isscalar(scale): - pass - elif not dpnp.isscalar(loc): - pass - elif scale < 0: - pass - else: - return _legacy_rng(dpnp_rng_gumbel, loc, scale, size).get_pyobj() - return call_origin(numpy.random.gumbel, loc, scale, size) - - -def hypergeometric(ngood, nbad, nsample, size=None): +@_params_doc +def hypergeometric( + ngood, + nbad, + nsample, + size=None, + *, + device=None, + usm_type="device", + sycl_queue=None, +): """ - Draw samples from a Hypergeometric distribution. + Draw samples from a hypergeometric distribution. For full documentation refer to :obj:`numpy.random.hypergeometric`. - Limitations - ----------- - Parameters `ngood`, `nbad` and `nsample` are supported as scalar. - Otherwise, :obj:`numpy.random.hypergeometric(shape, scale, size)` samples - are drawn. - Output array data type is :obj:`dpnp.int32`. + Parameters + ---------- + %(queue)s + %(usm)s - Examples + See Also -------- - Draw samples from the distribution: - - >>> ngood, nbad, nsamp = 100, 2, 10 - # number of good, number of bad, and number of samples - >>> s = dpnp.random.hypergeometric(ngood, nbad, nsamp, 1000) - - """ - - if not use_origin_backend(ngood): - if dpnp.is_cuda_backend(): # pragma: no cover - raise NotImplementedError( - "Running on CUDA is currently not supported" - ) - - # TODO: - # array_like of ints for `ngood`, `nbad`, `nsample` param - if not dpnp.isscalar(ngood): - pass - elif not dpnp.isscalar(nbad): - pass - elif not dpnp.isscalar(nsample): - pass - elif ngood < 0: - pass - elif nbad < 0: - pass - elif nsample < 0: - pass - elif ngood + nbad < nsample: - pass - elif nsample < 1: - pass - else: - _m = int(ngood) - _l = int(ngood) + int(nbad) - _s = int(nsample) - return _legacy_rng( - dpnp_rng_hypergeometric, _l, _s, _m, size - ).get_pyobj() - - return call_origin(numpy.random.hypergeometric, ngood, nbad, nsample, size) - - -def laplace(loc=0.0, scale=1.0, size=None): - """ - Draw samples from the Laplace or double exponential distribution with - specified location (or mean) and scale (decay). - - For full documentation refer to :obj:`numpy.random.laplace`. + :obj:`dpnp.random.RandomState.hypergeometric` - Limitations - ----------- - Parameters `loc` and `scale` are supported as scalar. - Otherwise, :obj:`numpy.random.laplace(loc, scale, size)` samples are drawn. - Output array data type is :obj:`dpnp.float64`. + """ + rs = _get_random_state(device, sycl_queue, (ngood, nbad, nsample)) + return rs.hypergeometric(ngood, nbad, nsample, size, usm_type=usm_type) - Examples - -------- - >>> loc, scale = 0., 1. - >>> s = dpnp.random.laplace(loc, scale, 1000) +@_params_doc +def laplace( + loc=0.0, + scale=1.0, + size=None, + dtype=None, + *, + device=None, + usm_type="device", + sycl_queue=None, +): """ + Draw samples from the Laplace or double exponential distribution. - if not use_origin_backend(loc): - if dpnp.is_cuda_backend(): # pragma: no cover - raise NotImplementedError( - "Running on CUDA is currently not supported" - ) - - # TODO: - # array_like of floats for `loc` and `scale` - if not dpnp.isscalar(loc): - pass - elif not dpnp.isscalar(scale): - pass - elif scale < 0: - pass - else: - return _legacy_rng(dpnp_rng_laplace, loc, scale, size).get_pyobj() + For full documentation refer to :obj:`numpy.random.laplace`. - return call_origin(numpy.random.laplace, loc, scale, size) + Parameters + ---------- + %(dtype)s + %(queue)s + %(usm)s + See Also + -------- + :obj:`dpnp.random.RandomState.laplace` -def logistic(loc=0.0, scale=1.0, size=None): """ - Draw samples from a logistic distribution. + rs = _get_random_state(device, sycl_queue, (loc, scale)) + return rs.laplace(loc, scale, size, dtype, usm_type=usm_type) - For full documentation refer to :obj:`numpy.random.logistic`. - - Limitations - ----------- - Parameters `loc` and `scale` are supported as scalar. - Otherwise, :obj:`numpy.random.logistic(loc, scale, size)` samples are drawn. - Output array data type is :obj:`dpnp.float64`. - - Examples - -------- - >>> loc, scale = 0., 1. - >>> s = dpnp.random.logistic(loc, scale, 1000) +@_params_doc +def logistic( + loc=0.0, + scale=1.0, + size=None, + dtype=None, + *, + device=None, + usm_type="device", + sycl_queue=None, +): """ + Draw samples from a logistic distribution. + + For full documentation refer to :obj:`numpy.random.logistic`. - if not use_origin_backend(loc): - if dpnp.is_cuda_backend(): # pragma: no cover - raise NotImplementedError( - "Running on CUDA is currently not supported" - ) + Parameters + ---------- + %(dtype)s + %(queue)s + %(usm)s - # TODO: - # array_like of floats for `loc` and `scale` - if not dpnp.isscalar(loc): - pass - elif not dpnp.isscalar(scale): - pass - elif scale < 0: - pass - else: - result = _legacy_rng( - dpnp_rng_logistic, loc, scale, size - ).get_pyobj() - if size is None or size == 1: - return result[0] - else: - return result + See Also + -------- + :obj:`dpnp.random.RandomState.logistic` - return call_origin(numpy.random.logistic, loc, scale, size) + """ + rs = _get_random_state(device, sycl_queue, (loc, scale)) + return rs.logistic(loc, scale, size, dtype, usm_type=usm_type) -def lognormal(mean=0.0, sigma=1.0, size=None): +@_params_doc +def lognormal( + mean=0.0, + sigma=1.0, + size=None, + dtype=None, + *, + device=None, + usm_type="device", + sycl_queue=None, +): """ Draw samples from a log-normal distribution. For full documentation refer to :obj:`numpy.random.lognormal`. - Limitations - ----------- - Parameters `mean` and `sigma` are supported as scalar. - Otherwise, :obj:`numpy.random.lognormal(mean, sigma, size)` samples - are drawn. - Output array data type is :obj:`dpnp.float64`. + Parameters + ---------- + %(dtype)s + %(queue)s + %(usm)s - Examples + See Also -------- - Draw samples from the distribution: - - >>> mu, sigma = 3., 1. # mean and standard deviation - >>> s = dpnp.random.lognormal(mu, sigma, 1000) + :obj:`dpnp.random.RandomState.lognormal` """ + rs = _get_random_state(device, sycl_queue, (mean, sigma)) + return rs.lognormal(mean, sigma, size, dtype, usm_type=usm_type) - if not use_origin_backend(mean): - if dpnp.is_cuda_backend(): # pragma: no cover - raise NotImplementedError( - "Running on CUDA is currently not supported" - ) - - # TODO: - # array_like of floats for `mean` and `sigma` params - if not dpnp.isscalar(mean): - pass - elif not dpnp.isscalar(sigma): - pass - elif sigma < 0: - pass - else: - return _legacy_rng( - dpnp_rng_lognormal, mean, sigma, size - ).get_pyobj() - return call_origin(numpy.random.lognormal, mean, sigma, size) - - -def logseries(p, size=None): +@_params_doc +def logseries(p, size=None, *, device=None, usm_type="device", sycl_queue=None): """ Draw samples from a logarithmic series distribution. For full documentation refer to :obj:`numpy.random.logseries`. - Notes - ----- - The function uses `numpy.random.logseries` on the backend and will be - executed on fallback backend. + Parameters + ---------- + %(queue)s + %(usm)s - """ + See Also + -------- + :obj:`dpnp.random.RandomState.logseries` - return call_origin(numpy.random.logseries, p, size) + """ + rs = _get_random_state(device, sycl_queue, (p,)) + return rs.logseries(p, size, usm_type=usm_type) -def multinomial(n, pvals, size=None): +@_params_doc +def multinomial( + n, pvals, size=None, *, device=None, usm_type="device", sycl_queue=None +): """ Draw samples from a multinomial distribution. For full documentation refer to :obj:`numpy.random.multinomial`. - Limitations - ----------- - Parameter `n` limited with int32 max. See, `numpy.iinfo(numpy.int32).max`. - Sum of ``pvals``, `sum(pvals)` should be between (0, 1). - Otherwise, :obj:`numpy.random.multinomial(n, pvals, size)` - samples are drawn. + Parameters + ---------- + %(queue)s + %(usm)s - Examples + See Also -------- - Throw a dice 20 times: - - >>> s = dpnp.random.multinomial(20, [1/6.]*6, size=1) - >>> s.shape - (1, 6) + :obj:`dpnp.random.RandomState.multinomial` """ + rs = _get_random_state(device, sycl_queue, (n, pvals)) + return rs.multinomial(n, pvals, size, usm_type=usm_type) - if not use_origin_backend(n): - pvals_sum = sum(pvals) - pvals_desc = dpnp.get_dpnp_descriptor(dpnp.array(pvals)) - d = len(pvals) - if dpnp.is_cuda_backend(pvals_desc.get_array()): # pragma: no cover - raise NotImplementedError( - "Running on CUDA is currently not supported" - ) - - if n < 0: - pass - elif n > dpnp.iinfo(dpnp.int32).max: - pass - elif pvals_sum > 1.0: - pass - elif pvals_sum < 0.0: - pass - else: - if size is None: - shape = (d,) - else: - try: - shape = (operator.index(size), d) - except Exception: - shape = tuple(size) + (d,) - - return _legacy_rng( - dpnp_rng_multinomial, int(n), pvals_desc, shape - ).get_pyobj() - return call_origin(numpy.random.multinomial, n, pvals, size) - - -def multivariate_normal(mean, cov, size=None, check_valid="warn", tol=1e-8): +@_params_doc +def multivariate_normal( + mean, + cov, + size=None, + check_valid="warn", + tol=1e-8, + *, + dtype=None, + device=None, + usm_type="device", + sycl_queue=None, +): """ Draw random samples from a multivariate normal distribution. For full documentation refer to :obj:`numpy.random.multivariate_normal`. - Limitations - ----------- - Parameters `check_valid` and `tol` are not supported. - Otherwise, :obj:`numpy.random.multivariate_normal(mean, cov, size, check_valid, tol)` - samples are drawn. + Parameters + ---------- + %(dtype)s + %(queue)s + %(usm)s - Examples + See Also -------- - >>> mean = (1, 2) - >>> cov = [[1, 0], [0, 1]] - >>> x = dpnp.random.multivariate_normal(mean, cov, (3, 3)) - >>> x.shape - (3, 3, 2) - - """ - - if not use_origin_backend(mean): - mean_ = dpnp.get_dpnp_descriptor(dpnp.array(mean, dtype=dpnp.float64)) - cov_ = dpnp.get_dpnp_descriptor(dpnp.array(cov, dtype=dpnp.float64)) - if dpnp.is_cuda_backend(mean_.get_array()) or dpnp.is_cuda_backend( - cov_.get_array() - ): # pragma: no cover - raise NotImplementedError( - "Running on CUDA is currently not supported" - ) - - if size is None: - shape = [] - elif isinstance(size, (int, dpnp.integer)): - shape = [size] - else: - shape = size - if len(mean_.shape) != 1: - pass - elif (len(cov_.shape) != 2) or (cov_.shape[0] != cov_.shape[1]): - pass - elif mean_.shape[0] != cov_.shape[0]: - pass - else: - final_shape = list(shape[:]) - final_shape.append(mean_.shape[0]) - return _legacy_rng( - dpnp_rng_multivariate_normal, mean_, cov_, final_shape - ).get_pyobj() - - return call_origin( - numpy.random.multivariate_normal, mean, cov, size, check_valid, tol + :obj:`dpnp.random.RandomState.multivariate_normal` + + """ + # pylint: disable=protected-access + rs = _get_random_state(device, sycl_queue, (mean, cov)) + return rs._multivariate_normal( + mean, cov, size, check_valid, tol, dtype, usm_type, stacklevel=3 ) -def negative_binomial(n, p, size=None): +@_params_doc +def negative_binomial( + n, p, size=None, *, device=None, usm_type="device", sycl_queue=None +): """ Draw samples from a negative binomial distribution. For full documentation refer to :obj:`numpy.random.negative_binomial`. - Limitations - ----------- - Parameters `n` and `p` are supported as scalar. - Otherwise, :obj:`numpy.random.negative_binomial(n, p, size)` samples - are drawn. - Output array data type is :obj:`dpnp.int32`. + Parameters + ---------- + %(queue)s + %(usm)s - Examples + See Also -------- - Draw samples from the distribution: - A real world example. A company drills wild-cat oil - exploration wells, each with an estimated probability of - success of 0.1. What is the probability of having one success - for each successive well, that is what is the probability of a - single success after drilling 5 wells, after 6 wells, etc.? - - >>> s = dpnp.random.negative_binomial(1, 0.1, 100000) - >>> for i in range(1, 11): - ... probability = sum(s 1 or p < 0: - pass - elif n <= 0: - pass - else: - return _legacy_rng( - dpnp_rng_negative_binomial, n, p, size - ).get_pyobj() - - return call_origin(numpy.random.negative_binomial, n, p, size) + :obj:`dpnp.random.RandomState.negative_binomial` + + """ + rs = _get_random_state(device, sycl_queue, (n, p)) + return rs.negative_binomial(n, p, size, usm_type=usm_type) -def normal( - loc=0.0, - scale=1.0, +@_params_doc +def noncentral_chisquare( + df, + nonc, size=None, + dtype=None, + *, device=None, usm_type="device", sycl_queue=None, ): """ - Draw random samples from a normal (Gaussian) distribution. + Draw samples from a noncentral chi-square distribution. - For full documentation refer to :obj:`numpy.random.normal`. + For full documentation refer to :obj:`numpy.random.noncentral_chisquare`. Parameters ---------- - device : {None, string, SyclDevice, SyclQueue, Device}, optional - An array API concept of device where the output array is created. - `device` can be ``None``, a 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 - :class:`dpnp.tensor.Device` object returned by - :attr:`dpnp.ndarray.device`. + %(dtype)s + %(queue)s + %(usm)s - Default: ``None``. - usm_type : {"device", "shared", "host"}, optional - The type of SYCL USM allocation for the output array. - - Default: ``"device"``. - sycl_queue : {None, SyclQueue}, optional - A SYCL queue to use for output array allocation and copying. The - `sycl_queue` can be passed as ``None`` (the default), which means - to get the SYCL queue from `device` keyword if present or to use - a default queue. - - Default: ``None``. - - 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. - Otherwise, :obj:`numpy.random.normal(loc, scale, size)` samples are drawn. - Parameter `dtype` is supported only as :obj:`dpnp.float32`, :obj:`dpnp.float64` or ``None``. - - Examples + See Also -------- - Draw samples from the distribution: - - >>> mu, sigma = 0, 0.1 # mean and standard deviation - >>> s = dpnp.random.normal(mu, sigma, 1000) + :obj:`dpnp.random.RandomState.noncentral_chisquare` """ - - 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 - ) + rs = _get_random_state(device, sycl_queue, (df, nonc)) + return rs.noncentral_chisquare(df, nonc, size, dtype, usm_type=usm_type) -def noncentral_chisquare(df, nonc, size=None): +@_params_doc +def noncentral_f( + dfnum, + dfden, + nonc, + size=None, + dtype=None, + *, + device=None, + usm_type="device", + sycl_queue=None, +): """ - Draw samples from a non-central chi-square distribution. + Draw samples from the noncentral F distribution. - For full documentation refer to :obj:`numpy.random.noncentral_chisquare`. - - TODO - - """ + For full documentation refer to :obj:`numpy.random.noncentral_f`. - if not use_origin_backend(df): - if dpnp.is_cuda_backend(): # pragma: no cover - raise NotImplementedError( - "Running on CUDA is currently not supported" - ) + Parameters + ---------- + %(dtype)s + %(queue)s + %(usm)s - # TODO: - # array_like of floats for `mean` and `scale` - if not dpnp.isscalar(df): - pass - elif not dpnp.isscalar(nonc): - pass - elif df <= 0: - pass - elif nonc < 0: - pass - else: - return _legacy_rng( - dpnp_rng_noncentral_chisquare, df, nonc, size - ).get_pyobj() + See Also + -------- + :obj:`dpnp.random.RandomState.noncentral_f` - return call_origin(numpy.random.noncentral_chisquare, df, nonc, size) + """ + rs = _get_random_state(device, sycl_queue, (dfnum, dfden, nonc)) + return rs.noncentral_f(dfnum, dfden, nonc, size, dtype, usm_type=usm_type) -def noncentral_f(dfnum, dfden, nonc, size=None): +@_params_doc +def normal( + loc=0.0, + scale=1.0, + size=None, + dtype=None, + *, + device=None, + usm_type="device", + sycl_queue=None, +): """ - Draw samples from the non-central F distribution. + Draw random samples from a normal (Gaussian) distribution. - For full documentation refer to :obj:`numpy.random.noncentral_f`. + For full documentation refer to :obj:`numpy.random.normal`. - Notes - ----- - The function uses `numpy.random.noncentral_f` on the backend and - will be executed on fallback backend. + Parameters + ---------- + %(dtype)s + %(queue)s + %(usm)s - """ + See Also + -------- + :obj:`dpnp.random.RandomState.normal` - return call_origin(numpy.random.noncentral_f, dfnum, dfden, nonc, size) + """ + rs = _get_random_state(device, sycl_queue, (loc, scale)) + return rs.normal(loc, scale, size, dtype, usm_type=usm_type) -def pareto(a, size=None): +@_params_doc +def pareto( + a, size=None, dtype=None, *, device=None, usm_type="device", sycl_queue=None +): """ - Draw samples from a Pareto II or Lomax distribution with specified shape. + Draw samples from a Pareto II or Lomax distribution with specified + shape. For full documentation refer to :obj:`numpy.random.pareto`. - Limitations - ----------- - Parameter `a` is supported as a scalar. - Otherwise, :obj:`numpy.random.pareto(a, size)` samples are drawn. - Output array data type is :obj:`dpnp.float64`. + Parameters + ---------- + %(dtype)s + %(queue)s + %(usm)s - Examples + See Also -------- - Draw samples from the distribution: - - >>> a = .5 # alpha - >>> s = dpnp.random.pareto(a, 1000) + :obj:`dpnp.random.RandomState.pareto` """ + rs = _get_random_state(device, sycl_queue, (a,)) + return rs.pareto(a, size, dtype, usm_type=usm_type) - if not use_origin_backend(a): - if dpnp.is_cuda_backend(): # pragma: no cover - raise NotImplementedError( - "Running on CUDA is currently not supported" - ) - - # TODO: - # array_like of floats for `a` - if not dpnp.isscalar(a): - pass - elif a <= 0: - pass - else: - return _legacy_rng(dpnp_rng_pareto, a, size).get_pyobj() - return call_origin(numpy.random.pareto, a, size) - - -def permutation(x): +@_params_doc +def permutation(x, *, device=None, sycl_queue=None): """ Randomly permute a sequence, or return a permuted range. For full documentation refer to :obj:`numpy.random.permutation`. - Examples - -------- - >>> arr = dpnp.random.permutation(10) - >>> print(arr) - [3 8 7 9 0 6 1 2 4 5] # random - - >>> arr = dpnp.random.permutation([1, 4, 9, 12, 15]) - >>> print(arr) - [12 1 4 9 15] # random + Parameters + ---------- + %(queue)s - >>> arr = dpnp.arange(9).reshape((3, 3)) - >>> dpnp.random.permutation(arr) - >>> print(arr) - [[0 1 2] - [3 4 5] - [6 7 8]] # random + See Also + -------- + :obj:`dpnp.random.RandomState.permutation` """ - if not use_origin_backend(x): - if isinstance(x, (int, dpnp.integer)): - arr = dpnp.arange(x) - else: - arr = dpnp.array(x) - shuffle(arr) - return arr + return _get_random_state(device, sycl_queue, (x,)).permutation(x) - return call_origin(numpy.random.permutation, x) - -def poisson(lam=1.0, size=None): +@_params_doc +def poisson( + lam=1.0, size=None, *, device=None, usm_type="device", sycl_queue=None +): """ Draw samples from a Poisson distribution. For full documentation refer to :obj:`numpy.random.poisson`. - Limitations - ----------- - Parameter `lam` is supported as a scalar. - Otherwise, :obj:`numpy.random.poisson(lam, size)` samples are drawn. - Output array data type is :obj:`dpnp.int32`. + Parameters + ---------- + %(queue)s + %(usm)s - Examples + See Also -------- - Draw samples from the distribution: - - >>> import numpy as np - >>> s = dpnp.random.poisson(5, 10000) + :obj:`dpnp.random.RandomState.poisson` """ + rs = _get_random_state(device, sycl_queue, (lam,)) + return rs.poisson(lam, size, usm_type=usm_type) - if not use_origin_backend(lam): - if dpnp.is_cuda_backend(): # pragma: no cover - raise NotImplementedError( - "Running on CUDA is currently not supported" - ) - - # TODO: - # array_like of floats for `lam` param - if not dpnp.isscalar(lam): - pass - elif lam < 0: - pass - else: - return _legacy_rng(dpnp_rng_poisson, lam, size).get_pyobj() - - return call_origin(numpy.random.poisson, lam, size) - -def power(a, size=None): +@_params_doc +def power( + a, size=None, dtype=None, *, device=None, usm_type="device", sycl_queue=None +): """ Draws samples in [0, 1] from a power distribution with positive exponent a - 1. For full documentation refer to :obj:`numpy.random.power`. - Limitations - ----------- - Parameter `a` is supported as a scalar. - Otherwise, :obj:`numpy.random.power(a, size)` samples are drawn. - Output array data type is :obj:`dpnp.float64`. + Parameters + ---------- + %(dtype)s + %(queue)s + %(usm)s - Examples + See Also -------- - Draw samples from the distribution: - - >>> a = .5 # alpha - >>> s = dpnp.random.power(a, 1000) + :obj:`dpnp.random.RandomState.power` """ - - if not use_origin_backend(a): - if dpnp.is_cuda_backend(): # pragma: no cover - raise NotImplementedError( - "Running on CUDA is currently not supported" - ) - - # TODO: - # array_like of floats for `a` - if not dpnp.isscalar(a): - pass - elif a <= 0: - pass - else: - return _legacy_rng(dpnp_rng_power, a, size).get_pyobj() - - return call_origin(numpy.random.power, a, size) + rs = _get_random_state(device, sycl_queue, (a,)) + return rs.power(a, size, dtype, usm_type=usm_type) -def rand(*args, device=None, usm_type="device", sycl_queue=None): +@_params_doc +def rand(*args, dtype=None, device=None, usm_type="device", sycl_queue=None): """ - Random values in a given shape. - - Create an array of the given shape and populate it with random samples from - a uniform distribution over ``[0, 1)``. + Random values in a given shape, from a uniform distribution over [0, + 1). For full documentation refer to :obj:`numpy.random.rand`. Parameters ---------- - *args : sequence of ints, optional - The dimensions of the returned array, must be non-negative. - If no argument is given a single Python float is returned. - device : {None, string, SyclDevice, SyclQueue, Device}, optional - An array API concept of device where the output array is created. - `device` can be ``None``, a 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 - :class:`dpnp.tensor.Device` object returned by - :attr:`dpnp.ndarray.device`. - - Default: ``None``. - usm_type : {"device", "shared", "host"}, optional - The type of SYCL USM allocation for the output array. - - Default: ``"device"``. - sycl_queue : {None, SyclQueue}, optional - A SYCL queue to use for output array allocation and copying. The - `sycl_queue` can be passed as ``None`` (the default), which means - to get the SYCL queue from `device` keyword if present or to use - a default queue. - - Default: ``None``. - - Returns - ------- - out : dpnp.ndarray - Random values in a given shape ``(d0, d1, ..., dn)``. - Output array data type is :obj:`dpnp.float64` if a device supports it, - or :obj:`dpnp.float32` type otherwise. + %(dtype)s + %(queue)s + %(usm)s See Also -------- - :obj:`dpnp.random.random` : Return random floats in the half-open interval - ``[0.0, 1.0)``. - :obj:`dpnp.random.random_sample` : Return random floats in the half-open - interval ``[0.0, 1.0)``. - :obj:`dpnp.random.uniform` : Draw samples from a uniform distribution. - - Examples - -------- - >>> import dpnp as np - >>> s = np.random.rand(3, 2) + :obj:`dpnp.random.RandomState.rand` """ - - rs = _get_random_state(device=device, sycl_queue=sycl_queue) - return rs.rand(*args, usm_type=usm_type) + rs = _get_random_state(device, sycl_queue) + return rs.random_sample(args or None, dtype, usm_type=usm_type) +@_params_doc def randint( low, high=None, size=None, dtype=int, + *, device=None, usm_type="device", sycl_queue=None, @@ -1189,1006 +1017,513 @@ def randint( Parameters ---------- - device : {None, string, SyclDevice, SyclQueue, Device}, optional - An array API concept of device where the output array is created. - `device` can be ``None``, a 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 - :class:`dpnp.tensor.Device` object returned by - :attr:`dpnp.ndarray.device`. - - Default: ``None``. - usm_type : {"device", "shared", "host"}, optional - The type of SYCL USM allocation for the output array. - - Default: ``"device"``. - sycl_queue : {None, SyclQueue}, optional - A SYCL queue to use for output array allocation and copying. The - `sycl_queue` can be passed as ``None`` (the default), which means - to get the SYCL queue from `device` keyword if present or to use - a default queue. - - Default: ``None``. - - 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 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 - -------- - Draw samples from the distribution: - - >>> low, high = 3, 11 # low and high - >>> s = dpnp.random.randint(low, high, 1000, dtype=dpnp.int32) + %(queue)s + %(usm)s See Also -------- - :obj:`dpnp.random.random_integers` : similar to `randint`, only for the closed - interval [`low`, `high`], and 1 is the - lowest value if `high` is omitted. + :obj:`dpnp.random.RandomState.randint` """ - - 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 - ) + rs = _get_random_state(device, sycl_queue, (low, high)) + return rs.randint(low, high, size, dtype, usm_type=usm_type) -def randn(d0, *dn, device=None, usm_type="device", sycl_queue=None): +@_params_doc +def randn(*args, dtype=None, device=None, usm_type="device", sycl_queue=None): """ - Return a sample (or samples) from the "standard normal" distribution. + Return a sample (or samples) from the standard normal distribution. For full documentation refer to :obj:`numpy.random.randn`. Parameters ---------- - device : {None, string, SyclDevice, SyclQueue, Device}, optional - An array API concept of device where the output array is created. - `device` can be ``None``, a 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 - :class:`dpnp.tensor.Device` object returned by - :attr:`dpnp.ndarray.device`. - - Default: ``None``. - usm_type : {"device", "shared", "host"}, optional - The type of SYCL USM allocation for the output array. - - Default: ``"device"``. - sycl_queue : {None, SyclQueue}, optional - A SYCL queue to use for output array allocation and copying. The - `sycl_queue` can be passed as ``None`` (the default), which means - to get the SYCL queue from `device` keyword if present or to use - a default queue. - - Default: ``None``. - - 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 - -------- - >>> dpnp.random.randn() - 2.1923875335537315 # random - - Two-by-four array of samples from N(3, 6.25): - - >>> s = 3 + 2.5 * dpnp.random.randn(2, 4) - - See Also - -------- - :obj:`dpnp.random.standard_normal` - :obj:`dpnp.random.normal` - - """ - - rs = _get_random_state(device=device, sycl_queue=sycl_queue) - return rs.randn(d0, *dn, usm_type=usm_type) - - -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`. - - Parameters - ---------- - device : {None, string, SyclDevice, SyclQueue, Device}, optional - An array API concept of device where the output array is created. - `device` can be ``None``, a 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 - :class:`dpnp.tensor.Device` object returned by - :attr:`dpnp.ndarray.device`. - - Default: ``None``. - usm_type : {"device", "shared", "host"}, optional - The type of SYCL USM allocation for the output array. - - Default: ``"device"``. - sycl_queue : {None, SyclQueue}, optional - A SYCL queue to use for output array allocation and copying. The - `sycl_queue` can be passed as ``None`` (the default), which means - to get the SYCL queue from `device` keyword if present or to use - a default queue. - - Default: ``None``. - - 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 - -------- - >>> s = dpnp.random.random(1000) + %(dtype)s + %(queue)s + %(usm)s See Also -------- - :obj:`dpnp.random.rand` - :obj:`dpnp.random.random_sample` - :obj:`dpnp.random.uniform` + :obj:`dpnp.random.RandomState.randn` """ - - return random_sample( - size=size, device=device, usm_type=usm_type, sycl_queue=sycl_queue - ) + rs = _get_random_state(device, sycl_queue) + return rs.standard_normal(args or None, dtype, usm_type=usm_type) -def random_integers( - low, high=None, size=None, device=None, usm_type="device", sycl_queue=None +@_params_doc +def random( + size=None, dtype=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, Device}, optional - An array API concept of device where the output array is created. - `device` can be ``None``, a 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 - :class:`dpnp.tensor.Device` object returned by - :attr:`dpnp.ndarray.device`. - - Default: ``None``. - usm_type : {"device", "shared", "host"}, optional - The type of SYCL USM allocation for the output array. - - Default: ``"device"``. - sycl_queue : {None, SyclQueue}, optional - A SYCL queue to use for output array allocation and copying. The - `sycl_queue` can be passed as ``None`` (the default), which means - to get the SYCL queue from `device` keyword if present or to use - a default queue. - - Default: ``None``. - - 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. - - See Also - -------- - :obj:`dpnp.random.randint` - - """ - - if high is None: - high = low - low = 0 - - # TODO: - # array_like of floats for `low` and `high` params - if not dpnp.isscalar(low): - pass - elif not dpnp.isscalar(high): - pass - else: - 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, device=None, usm_type="device", sycl_queue=None): - """ - Return random floats in the half-open interval [0.0, 1.0). - - Results are from the “continuous uniform” distribution over the interval. - - For full documentation refer to :obj:`numpy.random.random_sample`. - - Parameters - ---------- - device : {None, string, SyclDevice, SyclQueue, Device}, optional - An array API concept of device where the output array is created. - `device` can be ``None``, a 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 - :class:`dpnp.tensor.Device` object returned by - :attr:`dpnp.ndarray.device`. - - Default: ``None``. - usm_type : {"device", "shared", "host"}, optional - The type of SYCL USM allocation for the output array. - - Default: ``"device"``. - sycl_queue : {None, SyclQueue}, optional - A SYCL queue to use for output array allocation and copying. The - `sycl_queue` can be passed as ``None`` (the default), which means - to get the SYCL queue from `device` keyword if present or to use - a default queue. - - Default: ``None``. - - 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 - -------- - >>> s = dpnp.random.random_sample((5,)) - - See Also - -------- - :obj:`dpnp.random.rand` - :obj:`dpnp.random.random` - :obj:`dpnp.random.uniform` - - """ - - rs = _get_random_state(device=device, sycl_queue=sycl_queue) - return rs.random_sample(size=size, usm_type=usm_type) - - -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`. - - Parameters - ---------- - device : {None, string, SyclDevice, SyclQueue, Device}, optional - An array API concept of device where the output array is created. - `device` can be ``None``, a 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 - :class:`dpnp.tensor.Device` object returned by - :attr:`dpnp.ndarray.device`. - - Default: ``None``. - usm_type : {"device", "shared", "host"}, optional - The type of SYCL USM allocation for the output array. - - Default: ``"device"``. - sycl_queue : {None, SyclQueue}, optional - A SYCL queue to use for output array allocation and copying. The - `sycl_queue` can be passed as ``None`` (the default), which means - to get the SYCL queue from `device` keyword if present or to use - a default queue. - - Default: ``None``. - - 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. + For full documentation refer to :obj:`numpy.random.random`. - Examples - -------- - >>> s = dpnp.random.ranf(1000) + Parameters + ---------- + %(dtype)s + %(queue)s + %(usm)s See Also -------- - :obj:`dpnp.random.rand` - :obj:`dpnp.random.random` - :obj:`dpnp.random.random_sample` - :obj:`dpnp.random.uniform` + :obj:`dpnp.random.RandomState.random_sample` """ - - return random_sample( - size=size, device=device, usm_type=usm_type, sycl_queue=sycl_queue - ) + rs = _get_random_state(device, sycl_queue) + return rs.random_sample(size, dtype, usm_type=usm_type) -def rayleigh(scale=1.0, size=None): +@_params_doc +def random_integers( + low, + high=None, + size=None, + *, + device=None, + usm_type="device", + sycl_queue=None, +): """ - Draw samples from a Rayleigh distribution. + Random integers between `low` and `high`, inclusive. - For full documentation refer to :obj:`numpy.random.rayleigh`. + For full documentation refer to :obj:`numpy.random.random_integers`. - Limitations - ----------- - Parameter `scale` is supported as a scalar. - Otherwise, :obj:`numpy.random.rayleigh(scale, size)` samples are drawn. - Output array data type is :obj:`dpnp.float64`. + Parameters + ---------- + %(queue)s + %(usm)s - Examples + See Also -------- - Draw samples from the distribution: - - >>> import numpy as np - >>> s = dpnp.random.rayleigh(1.0, 10000) + :obj:`dpnp.random.RandomState.random_integers` """ + # pylint: disable=protected-access + rs = _get_random_state(device, sycl_queue, (low, high)) + return rs._random_integers(low, high, size, usm_type, stacklevel=3) - if not use_origin_backend(scale): - if dpnp.is_cuda_backend(): # pragma: no cover - raise NotImplementedError( - "Running on CUDA is currently not supported" - ) - - # TODO: - # array_like of floats for `scale` params - if not dpnp.isscalar(scale): - pass - elif scale < 0: - pass - else: - return _legacy_rng(dpnp_rng_rayleigh, scale, size).get_pyobj() - return call_origin(numpy.random.rayleigh, scale, size) - - -def sample(size=None, device=None, usm_type="device", sycl_queue=None): +@_params_doc +def random_sample( + size=None, dtype=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`. + For full documentation refer to :obj:`numpy.random.random_sample`. Parameters ---------- - device : {None, string, SyclDevice, SyclQueue, Device}, optional - An array API concept of device where the output array is created. - `device` can be ``None``, a 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 - :class:`dpnp.tensor.Device` object returned by - :attr:`dpnp.ndarray.device`. + %(dtype)s + %(queue)s + %(usm)s - Default: ``None``. - usm_type : {"device", "shared", "host"}, optional - The type of SYCL USM allocation for the output array. + See Also + -------- + :obj:`dpnp.random.RandomState.random_sample` - Default: ``"device"``. - sycl_queue : {None, SyclQueue}, optional - A SYCL queue to use for output array allocation and copying. The - `sycl_queue` can be passed as ``None`` (the default), which means - to get the SYCL queue from `device` keyword if present or to use - a default queue. + """ + rs = _get_random_state(device, sycl_queue) + return rs.random_sample(size, dtype, usm_type=usm_type) - Default: ``None``. - 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. +@_params_doc +def ranf( + size=None, dtype=None, *, device=None, usm_type="device", sycl_queue=None +): + """ + Return random floats in the half-open interval [0.0, 1.0). An alias of + :obj:`dpnp.random.random_sample`. - Examples - -------- - >>> s = dpnp.random.sample(1000) + For full documentation refer to :obj:`numpy.random.ranf`. + + Parameters + ---------- + %(dtype)s + %(queue)s + %(usm)s See Also -------- - :obj:`dpnp.random.rand` - :obj:`dpnp.random.random` - :obj:`dpnp.random.random_sample` - :obj:`dpnp.random.uniform` - - """ - - return random_sample( - size=size, device=device, usm_type=usm_type, sycl_queue=sycl_queue - ) - + :obj:`dpnp.random.RandomState.random_sample` -def shuffle(x1): """ - Modify a sequence in-place by shuffling its contents. + rs = _get_random_state(device, sycl_queue) + return rs.random_sample(size, dtype, usm_type=usm_type) - For full documentation refer to :obj:`numpy.random.shuffle`. - - Limitations - ----------- - Otherwise, the function will use :obj:`numpy.random.shuffle` on the backend - and will be executed on fallback backend. +@_params_doc +def rayleigh( + scale=1.0, + size=None, + dtype=None, + *, + device=None, + usm_type="device", + sycl_queue=None, +): """ + Draw samples from a Rayleigh distribution. - x1_desc = dpnp.get_dpnp_descriptor(x1, copy_when_strides=False) - if x1_desc: + For full documentation refer to :obj:`numpy.random.rayleigh`. - if dpnp.is_cuda_backend(x1_desc.get_array()): # pragma: no cover - raise NotImplementedError( - "Running on CUDA is currently not supported" - ) + Parameters + ---------- + %(dtype)s + %(queue)s + %(usm)s - if not _is_type_supported(x1_desc.dtype): - pass - else: - _legacy_rng(dpnp_rng_shuffle, x1_desc).get_pyobj() - return + See Also + -------- + :obj:`dpnp.random.RandomState.rayleigh` - call_origin(numpy.random.shuffle, x1, dpnp_inplace=True) - return + """ + rs = _get_random_state(device, sycl_queue, (scale,)) + return rs.rayleigh(scale, size, dtype, usm_type=usm_type) -def seed(seed=None, device=None, sycl_queue=None): +@_params_doc +def sample( + size=None, dtype=None, *, device=None, usm_type="device", sycl_queue=None +): """ - Reseed a legacy MT19937 random number generator engine. + Return random floats in the half-open interval [0.0, 1.0). An alias of + :obj:`dpnp.random.random_sample`. + + For full documentation refer to :obj:`numpy.random.sample`. Parameters ---------- - device : {None, string, SyclDevice, SyclQueue, Device}, optional - An array API concept of device where the output array is created. - `device` can be ``None``, a 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 - :class:`dpnp.tensor.Device` object returned by - :attr:`dpnp.ndarray.device`. + %(dtype)s + %(queue)s + %(usm)s - Default: ``None``. - sycl_queue : {None, SyclQueue}, optional - A SYCL queue to use for an array with generated numbers. + See Also + -------- + :obj:`dpnp.random.RandomState.random_sample` - Default: ``None``. + """ + rs = _get_random_state(device, sycl_queue) + return rs.random_sample(size, dtype, usm_type=usm_type) - Limitations - ----------- - The `seed` parameter is supported as a scalar or an array of at most three - integer scalars. +def shuffle(x): """ + Modify an array in place by shuffling its contents along the first axis. - # update a mt19937 random number for both RandomState and legacy functionality - global _dpnp_random_states # noqa: F824 - - sycl_queue = dpnp.get_normalized_queue_device( - device=device, sycl_queue=sycl_queue - ) - with _random_states_lock: - _dpnp_random_states[sycl_queue] = RandomState( - seed=seed, sycl_queue=sycl_queue - ) + For full documentation refer to :obj:`numpy.random.shuffle`. - if not use_origin_backend(seed): - if dpnp.is_cuda_backend(): # pragma: no cover - raise NotImplementedError( - "Running on CUDA is currently not supported" - ) + The state of the queue of `x` is used. - # TODO: - # array_like of ints for `seed` - if seed is None: - seed = 1 - if not isinstance(seed, int): - pass - elif seed < 0: - pass - else: - # TODO: - # migrate to a single approach with RandomState class - _legacy_rng(dpnp_rng_srand, seed) + See Also + -------- + :obj:`dpnp.random.RandomState.shuffle` - # always reseed numpy engine also - return call_origin(numpy.random.seed, seed, allow_fallback=True) + """ + _get_random_state(arrays=(x,)).shuffle(x) -def standard_cauchy(size=None): +@_params_doc +def standard_cauchy( + size=None, dtype=None, *, device=None, usm_type="device", sycl_queue=None +): """ Draw samples from a standard Cauchy distribution with mode = 0. - Also known as the Lorentz distribution. + For full documentation refer to :obj:`numpy.random.standard_cauchy`. - Limitations - ----------- - Output array data type is default float type. + Parameters + ---------- + %(dtype)s + %(queue)s + %(usm)s - Examples + See Also -------- - Draw samples and plot the distribution: - - >>> import matplotlib.pyplot as plt - >>> s = dpnp.random.standard_cauchy(1000000) - >>> s = s[(s>-25) & (s<25)] # truncate distribution so it plots well - >>> plt.hist(s, bins=100) - >>> plt.show() + :obj:`dpnp.random.RandomState.standard_cauchy` """ + rs = _get_random_state(device, sycl_queue, ()) + return rs.standard_cauchy(size, dtype, usm_type=usm_type) - if not use_origin_backend(size): - if dpnp.is_cuda_backend(): # pragma: no cover - raise NotImplementedError( - "Running on CUDA is currently not supported" - ) - return _legacy_rng(dpnp_rng_standard_cauchy, size).get_pyobj() - - return call_origin(numpy.random.standard_cauchy, size) - -def standard_exponential(size=None): +@_params_doc +def standard_exponential( + size=None, dtype=None, *, device=None, usm_type="device", sycl_queue=None +): """ Draw samples from the standard exponential distribution. - `standard_exponential` is identical to the exponential distribution - with a scale parameter of 1. + For full documentation refer to :obj:`numpy.random.standard_exponential`. - Limitations - ----------- - Output array data type is default float type. + Parameters + ---------- + %(dtype)s + %(queue)s + %(usm)s - Examples + See Also -------- - Output a 3x8000 array: - - >>> n = dpnp.random.standard_exponential((3, 8000)) + :obj:`dpnp.random.RandomState.standard_exponential` """ + rs = _get_random_state(device, sycl_queue, ()) + return rs.standard_exponential(size, dtype, usm_type=usm_type) - if not use_origin_backend(size): - if dpnp.is_cuda_backend(): # pragma: no cover - raise NotImplementedError( - "Running on CUDA is currently not supported" - ) - return _legacy_rng(dpnp_rng_standard_exponential, size).get_pyobj() - - return call_origin(numpy.random.standard_exponential, size) - -def standard_gamma(shape, size=None): +@_params_doc +def standard_gamma( + shape, + size=None, + dtype=None, + *, + device=None, + usm_type="device", + sycl_queue=None, +): """ Draw samples from a standard Gamma distribution. For full documentation refer to :obj:`numpy.random.standard_gamma`. - Limitations - ----------- - Parameter `shape` is supported as a scalar. - Otherwise, :obj:`numpy.random.standard_gamma(shape, size)` samples - are drawn. - Output array data type is :obj:`dpnp.float64`. + Parameters + ---------- + %(dtype)s + %(queue)s + %(usm)s - Examples + See Also -------- - Draw samples from the distribution: - - >>> shape = 2. - >>> s = dpnp.random.standard_gamma(shape, 1000000) + :obj:`dpnp.random.RandomState.standard_gamma` """ - - if not use_origin_backend(shape): - if dpnp.is_cuda_backend(): # pragma: no cover - raise NotImplementedError( - "Running on CUDA is currently not supported" - ) - - # TODO: - # array_like of floats for `shape` - if not dpnp.isscalar(shape): - pass - elif shape < 0: - pass - else: - return _legacy_rng(dpnp_rng_standard_gamma, shape, size).get_pyobj() - - return call_origin(numpy.random.standard_gamma, shape, size) + rs = _get_random_state(device, sycl_queue, (shape,)) + return rs.standard_gamma(shape, size, dtype, usm_type=usm_type) -def standard_normal(size=None, device=None, usm_type="device", sycl_queue=None): +@_params_doc +def standard_normal( + size=None, dtype=None, *, device=None, usm_type="device", sycl_queue=None +): """ - Draw samples from a standard Normal distribution ``(mean=0, stdev=1)``. + Draw samples from a standard Normal distribution (mean=0, stdev=1). For full documentation refer to :obj:`numpy.random.standard_normal`. Parameters ---------- - device : {None, string, SyclDevice, SyclQueue, Device}, optional - An array API concept of device where the output array is created. - `device` can be ``None``, a 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 - :class:`dpnp.tensor.Device` object returned by - :attr:`dpnp.ndarray.device`. - - Default: ``None``. - usm_type : {"device", "shared", "host"}, optional - The type of SYCL USM allocation for the output array. - - Default: ``"device"``. - sycl_queue : {None, SyclQueue}, optional - A SYCL queue to use for output array allocation and copying. The - `sycl_queue` can be passed as ``None`` (the default), which means - to get the SYCL queue from `device` keyword if present or to use - a default queue. - - Default: ``None``. + %(dtype)s + %(queue)s + %(usm)s - 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 + See Also -------- - Draw samples from the distribution: - - >>> s = dpnp.random.standard_normal(1000) + :obj:`dpnp.random.RandomState.standard_normal` """ + rs = _get_random_state(device, sycl_queue, ()) + return rs.standard_normal(size, dtype, 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): +@_params_doc +def standard_t( + df, + size=None, + dtype=None, + *, + device=None, + usm_type="device", + sycl_queue=None, +): """ - Draw samples from a standard Student’s t distribution with - `df` degrees of freedom. + Draw samples from a standard Student's t distribution with `df` degrees + of freedom. For full documentation refer to :obj:`numpy.random.standard_t`. - Limitations - ----------- - Parameter `df` is supported as a scalar. - Otherwise, :obj:`numpy.random.standard_t(df, size)` samples - are drawn. - Output array data type is :obj:`dpnp.float64`. + Parameters + ---------- + %(dtype)s + %(queue)s + %(usm)s - Examples + See Also -------- - Draw samples from the distribution: - - >>> df = 2. - >>> s = dpnp.random.standard_t(df, 1000000) + :obj:`dpnp.random.RandomState.standard_t` """ + rs = _get_random_state(device, sycl_queue, (df,)) + return rs.standard_t(df, size, dtype, usm_type=usm_type) - if not use_origin_backend(df): - if dpnp.is_cuda_backend(): # pragma: no cover - raise NotImplementedError( - "Running on CUDA is currently not supported" - ) - - # TODO: - # array_like of floats for `df` - if not dpnp.isscalar(df): - pass - elif df <= 0: - pass - else: - return _legacy_rng(dpnp_rng_standard_t, df, size).get_pyobj() - return call_origin(numpy.random.standard_t, df, size) - - -def triangular(left, mode, right, size=None): +@_params_doc +def triangular( + left, + mode, + right, + size=None, + dtype=None, + *, + device=None, + usm_type="device", + sycl_queue=None, +): """ - Draw samples from the triangular distribution over the interval - [left, right]. + Draw samples from the triangular distribution over the interval [left, + right]. For full documentation refer to :obj:`numpy.random.triangular`. - Limitations - ----------- - Parameters `left`, `mode` and `right` are supported as scalar. - Otherwise, :obj:`numpy.random.triangular(left, mode, right, size)` - samples are drawn. - Output array data type is :obj:`dpnp.float64`. + Parameters + ---------- + %(dtype)s + %(queue)s + %(usm)s - Examples + See Also -------- - Draw samples from the distribution: - - >>> df = 2. - >>> s = dpnp.random.triangular(-3, 0, 8, 1000000) + :obj:`dpnp.random.RandomState.triangular` """ - - if not use_origin_backend(left): - if dpnp.is_cuda_backend(): # pragma: no cover - raise NotImplementedError( - "Running on CUDA is currently not supported" - ) - - # TODO: - # array_like of floats for `left`, `mode`, `right`. - if not dpnp.isscalar(left): - pass - elif not dpnp.isscalar(mode): - pass - elif not dpnp.isscalar(right): - pass - elif left > mode: - pass - elif mode > right: - pass - elif left == right: - pass - else: - return _legacy_rng( - dpnp_rng_triangular, left, mode, right, size - ).get_pyobj() - - return call_origin(numpy.random.triangular, left, mode, right, size) + rs = _get_random_state(device, sycl_queue, (left, mode, right)) + return rs.triangular(left, mode, right, size, dtype, usm_type=usm_type) +@_params_doc def uniform( low=0.0, high=1.0, size=None, + dtype=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. + Draw samples from a uniform distribution over [low, high). For full documentation refer to :obj:`numpy.random.uniform`. Parameters ---------- - device : {None, string, SyclDevice, SyclQueue, Device}, optional - An array API concept of device where the output array is created. - `device` can be ``None``, a 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 - :class:`dpnp.tensor.Device` object returned by - :attr:`dpnp.ndarray.device`. - - Default: ``None``. - usm_type : {"device", "shared", "host"}, optional - The type of SYCL USM allocation for the output array. - - Default: ``"device"``. - sycl_queue : {None, SyclQueue}, optional - A SYCL queue to use for output array allocation and copying. The - `sycl_queue` can be passed as ``None`` (the default), which means - to get the SYCL queue from `device` keyword if present or to use - a default queue. - - Default: ``None``. - - 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 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 - -------- - Draw samples from the distribution: - - >>> low, high = 0, 0.1 # low and high - >>> s = dpnp.random.uniform(low, high, 10000) + %(dtype)s + %(queue)s + %(usm)s See Also -------- - :obj:`dpnp.random.random` : Floats uniformly distributed over ``[0, 1)``. + :obj:`dpnp.random.RandomState.uniform` """ - - 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 - ) + rs = _get_random_state(device, sycl_queue, (low, high)) + return rs.uniform(low, high, size, dtype, usm_type=usm_type) -def vonmises(mu, kappa, size=None): +@_params_doc +def vonmises( + mu, + kappa, + size=None, + dtype=None, + *, + device=None, + usm_type="device", + sycl_queue=None, +): """ Draw samples from a von Mises distribution. For full documentation refer to :obj:`numpy.random.vonmises`. - Limitations - ----------- - Parameters `mu` and `kappa` are supported as scalar. - Otherwise, :obj:`numpy.random.vonmises(mu, kappa, size)` - samples are drawn. - Output array data type is :obj:`dpnp.float64`. + Parameters + ---------- + %(dtype)s + %(queue)s + %(usm)s - Examples + See Also -------- - Draw samples from the distribution: - - >>> mu, kappa = 0.0, 4.0 # mean and dispersion - >>> s = dpnp.random.vonmises(mu, kappa, 1000) + :obj:`dpnp.random.RandomState.vonmises` """ - - if not use_origin_backend(mu): - if dpnp.is_cuda_backend(): # pragma: no cover - raise NotImplementedError( - "Running on CUDA is currently not supported" - ) - - # TODO: - # array_like of floats for `mu`, `kappa`. - if not dpnp.isscalar(mu): - pass - elif not dpnp.isscalar(kappa): - pass - elif numpy.isnan(kappa): - return dpnp.nan - elif kappa < 0: - pass - else: - return _legacy_rng(dpnp_rng_vonmises, mu, kappa, size).get_pyobj() - - return call_origin(numpy.random.vonmises, mu, kappa, size) + rs = _get_random_state(device, sycl_queue, (mu, kappa)) + return rs.vonmises(mu, kappa, size, dtype, usm_type=usm_type) -def wald(mean, scale, size=None): +@_params_doc +def wald( + mean, + scale, + size=None, + dtype=None, + *, + device=None, + usm_type="device", + sycl_queue=None, +): """ Draw samples from a Wald, or inverse Gaussian, distribution. For full documentation refer to :obj:`numpy.random.wald`. - Limitations - ----------- - Parameters `mean` and `scale` are supported as scalar. - Otherwise, :obj:`numpy.random.wald(mean, scale, size)` samples are drawn. - Output array data type is :obj:`dpnp.float64`. + Parameters + ---------- + %(dtype)s + %(queue)s + %(usm)s - Examples + See Also -------- - >>> loc, scale = 3., 2. - >>> s = dpnp.random.wald(loc, scale, 1000) + :obj:`dpnp.random.RandomState.wald` """ + rs = _get_random_state(device, sycl_queue, (mean, scale)) + return rs.wald(mean, scale, size, dtype, usm_type=usm_type) - if not use_origin_backend(mean): - if dpnp.is_cuda_backend(): # pragma: no cover - raise NotImplementedError( - "Running on CUDA is currently not supported" - ) - - # TODO: - # array_like of floats for `mean` and `scale` - if not dpnp.isscalar(mean): - pass - elif not dpnp.isscalar(scale): - pass - elif mean <= 0: - pass - elif scale <= 0: - pass - else: - return _legacy_rng(dpnp_rng_wald, mean, scale, size).get_pyobj() - return call_origin(numpy.random.wald, mean, scale, size) - - -def weibull(a, size=None): +@_params_doc +def weibull( + a, size=None, dtype=None, *, device=None, usm_type="device", sycl_queue=None +): """ Draw samples from a Weibull distribution. For full documentation refer to :obj:`numpy.random.weibull`. - Limitations - ----------- - Parameter `a` is supported as a scalar. - Otherwise, :obj:`numpy.random.weibull(a, size)` samples are drawn. - Output array data type is :obj:`dpnp.float64`. + Parameters + ---------- + %(dtype)s + %(queue)s + %(usm)s - Examples + See Also -------- - >>> a = 5. # shape - >>> s = np.random.weibull(a, 1000) + :obj:`dpnp.random.RandomState.weibull` """ - - if not use_origin_backend(a): - if dpnp.is_cuda_backend(): # pragma: no cover - raise NotImplementedError( - "Running on CUDA is currently not supported" - ) - - # TODO: - # array_like of floats for `a` param - if not dpnp.isscalar(a): - pass - elif a < 0: - pass - else: - return _legacy_rng(dpnp_rng_weibull, a, size).get_pyobj() - - return call_origin(numpy.random.weibull, a, size) + rs = _get_random_state(device, sycl_queue, (a,)) + return rs.weibull(a, size, dtype, usm_type=usm_type) -def zipf(a, size=None): +@_params_doc +def zipf(a, size=None, *, device=None, usm_type="device", sycl_queue=None): """ - Returns an array of samples drawn from the Zipf distribution. + Draw samples from a Zipf distribution. For full documentation refer to :obj:`numpy.random.zipf`. - Limitations - ----------- - Parameter `a`` is supported as a scalar. - Otherwise, :obj:`numpy.zipf.weibull(a, size)` samples are drawn. - Output array data type is :obj:`dpnp.float64`. + Parameters + ---------- + %(queue)s + %(usm)s - Examples + See Also -------- - >>> a = 2. # parameter - >>> s = np.random.zipf(a, 1000) + :obj:`dpnp.random.RandomState.zipf` """ - - if not use_origin_backend(a): - if dpnp.is_cuda_backend(): # pragma: no cover - raise NotImplementedError( - "Running on CUDA is currently not supported" - ) - - # TODO: - # array_like of floats for `a` param - if not dpnp.isscalar(a): - pass - elif a <= 1: - pass - else: - return _legacy_rng(dpnp_rng_zipf, a, size).get_pyobj() - - return call_origin(numpy.random.zipf, a, size) - - -_dpnp_random_states = {} + rs = _get_random_state(device, sycl_queue, (a,)) + return rs.zipf(a, size, usm_type=usm_type) diff --git a/dpnp/random/dpnp_random_state.py b/dpnp/random/dpnp_random_state.py index d762c299c1f3..d5a41810d891 100644 --- a/dpnp/random/dpnp_random_state.py +++ b/dpnp/random/dpnp_random_state.py @@ -1,4 +1,3 @@ -# cython: language_level=3 # ***************************************************************************** # Copyright (c) 2016, Intel Corporation # All rights reserved. @@ -28,38 +27,138 @@ # ***************************************************************************** """ -Module Intel NumPy RandomState +The legacy random number generation API modelled on +:class:`numpy.random.RandomState`. -Set of functions to implement NumPy random module API - - .. seealso:: :obj:`numpy.random.RandomState` +A :class:`RandomState` draws from a :class:`dpnp.random.Philox4x3210` bit +generator, and samples every distribution on the device by the algorithms of +:class:`dpnp.random.Generator`, with the parameter checks of NumPy's legacy +API. Neither the values nor the state are those of NumPy's MT19937. """ +# pylint: disable=protected-access +# pylint: disable=too-many-public-methods + +import operator +import warnings + import numpy import dpnp -from dpnp.dpnp_utils.dpnp_algo_utils import ( - call_origin, - map_dtype_to_device, - use_origin_backend, +import dpnp.libtensor._rng_impl as ri # pylint: disable=no-name-in-module + +from ._bit_generator import BitGenerator, Philox4x3210 +from ._generator import ( + _CONS_BOUNDED_0_1, + _CONS_GTE_1, + _CONS_NON_NEGATIVE, + _CONS_POSITIVE, + _HYPERGEOM_MAX, + _INT64_MAX, + Generator, + _as_int64, + _check_arrays, + _check_constraint, + _int64, + _is_array, + _is_scalar_path, + _normalize_size, + _uniform_range, ) -from dpnp.random.dpnp_algo_random import MCG59, MT19937 -from dpnp.tensor import validate_usm_type + +__all__ = ["RandomState"] + +# the messages of RandomState.choice +_CHOICE_MSGS = { + "a_type": "a must be 1-dimensional or an integer", + "a_int": "a must be greater than 0 unless no samples are taken", + "a_1d": "a must be 1-dimensional", + "a_empty": "'a' cannot be empty unless no samples are taken", + "p_1d": "'p' must be 1-dimensional", + "p_size": "'a' and 'p' must have same size", + "p_nan": "probabilities contain NaN", + "p_neg": "probabilities are not non-negative", + "p_sum": "probabilities do not sum to 1", + "too_large": ( + "Cannot take a larger sample than population when 'replace=False'" + ), +} + +_SEED_MAX = 2**32 - 1 + + +class _LegacyGenerator(Generator): + """ + The generator of a :class:`RandomState`, which checks the parameters on + the device as NumPy's legacy API checks all parameters, at the cost of + waiting for the device. + + """ + + _check_device = True + + +def _legacy_seed(seed): + """ + Check `seed` as NumPy's legacy seeding does, and return it in a form + :class:`numpy.random.SeedSequence` takes. + + """ + + if seed is None: + return None + if dpnp.is_supported_array_type(seed): + seed = dpnp.asnumpy(seed) + + msg = "Seed must be between 0 and 2**32 - 1" + try: + if hasattr(seed, "squeeze"): + seed = seed.squeeze() + idx = operator.index(seed) + except TypeError: + obj = numpy.asarray(seed) + if obj.size == 0: + raise ValueError("Seed must be non-empty") from None + obj = obj.astype(numpy.int64, casting="safe") + if obj.ndim != 1: + raise ValueError("Seed array must be 1-d") from None + if ((obj > _SEED_MAX) | (obj < 0)).any(): + raise ValueError(msg) from None + return obj + if idx > _SEED_MAX or idx < 0: + raise ValueError(msg) + return idx + + +def _reseed_in_place(bit_generator, seeded): + """ + Give `bit_generator` the state and seed sequence of `seeded`, a new bit + generator of the same type, so that every user of `bit_generator` sees + the new seed, as NumPy reseeds its bit generators in place. + + """ + + # pylint: disable=protected-access + bit_generator.state = seeded.state + bit_generator._seed_seq = seeded.seed_seq class RandomState: """ - A container for the Mersenne Twister pseudo-random number generator. + A container of a pseudo-random number generator on a SYCL device, with + the legacy API of NumPy. For full documentation refer to :obj:`numpy.random.RandomState`. Parameters ---------- - seed : {None, int, array_like}, optional - A random seed to initialize the pseudo-random number generator. - The `seed` can be ``None`` (the default), an integer scalar, or - an array of at most three integer scalars. + seed : {None, int, array_like[ints], BitGenerator}, optional + A random seed to initialize the pseudo-random number generator, as + for :obj:`numpy.random.RandomState`: an integer in [0, 2**32 - 1] or + a 1-D array of such integers. With ``None``, fresh entropy is pulled + from the operating system. A :class:`dpnp.random.BitGenerator` is + used as the bit generator, on its own queue. Default: ``None``. device : {None, string, SyclDevice, SyclQueue, Device}, optional @@ -79,602 +178,809 @@ class RandomState: Default: ``None``. + Limitations + ----------- + Unless `seed` is a :class:`dpnp.random.BitGenerator`, the bit generator + is :class:`dpnp.random.Philox4x3210` rather than MT19937, so the values + drawn differ from NumPy's, and the state is that of + :class:`dpnp.random.Philox4x3210`. `device` and `sycl_queue` cannot be + given with a :class:`dpnp.random.BitGenerator`. The values for a seed + are the same on every device, and those of + ``dpnp.random.default_rng(seed)`` for the distributions whose checks + agree. + + Every method returns a :class:`dpnp.ndarray`, zero-dimensional when + `size` is ``None`` and the parameters are scalars, rather than a Python + scalar. The floating-point methods take a `dtype`, which defaults to the + default floating-point type of the device, and every method a + `usm_type`, the type of USM allocation of the output. Parameters that + are on the device are checked as NumPy checks all parameters, so a call + with such parameters waits for the device, unlike the methods of + :class:`dpnp.random.Generator`. + """ def __init__(self, seed=None, device=None, sycl_queue=None): + if isinstance(seed, BitGenerator): + if device is not None or sycl_queue is not None: + raise ValueError( + "device and sycl_queue cannot be given with a " + "BitGenerator, whose queue is used" + ) + self._sycl_queue = seed.sycl_queue + self._generator = _LegacyGenerator(seed) + return + self._sycl_queue = dpnp.get_normalized_queue_device( device=device, sycl_queue=sycl_queue ) + self._generator = _LegacyGenerator(self._make_bit_generator(seed)) - self._sycl_device = self._sycl_queue.sycl_device - - is_cpu = self._sycl_device.is_cpu - if seed is None: - low = 0 - high = dpnp.iinfo(numpy.int32).max + 1 - - if is_cpu: - # ask NumPy to generate an array of three random integers as default seed value - self._seed = numpy.random.randint(low=low, high=high, size=3) - else: - # ask NumPy to generate a random 32-bit integer as default seed value - self._seed = numpy.random.randint(low=low, high=high, size=1)[0] - else: - self._seed = seed - - # 'float32' is default floating data type if device doesn't support 'float64' - self._def_float_type = map_dtype_to_device( - dpnp.float64, self._sycl_device - ) - - # TODO: rework through pybind11 extension for OneMKL engine and distribution classes - if is_cpu: - self._random_state = MT19937(self._seed, self._sycl_queue) - else: - # MCG59 is assumed to provide a better performance on GPU than MT19937 - self._random_state = MCG59(self._seed, self._sycl_queue) - - self._fallback_random_state = call_origin( - numpy.random.RandomState, seed, allow_fallback=True - ) + def _make_bit_generator(self, seed): + return Philox4x3210(_legacy_seed(seed), sycl_queue=self._sycl_queue) def __repr__(self): return self.__str__() + f" at 0x{id(self):X}" def __str__(self): - _str = self.__class__.__name__ - _str += "(" + self._random_state.__class__.__name__ + ")" - return _str + bit_generator = self._generator.bit_generator + return f"{self.__class__.__name__}({type(bit_generator).__name__})" - def __getstate__(self): - return self.get_state() + def _set_bit_generator(self, bit_generator): + """Draw from `bit_generator`, which is on the queue of the state.""" + self._generator.bit_generator = bit_generator - def _is_finite_scalar(self, x): - """Test a scalar for finiteness (not infinity and not Not a Number).""" - - # TODO: replace with dpnp.isfinite() once function is available in DPNP, - # but for now use direct numpy calls without call_origin() wrapper, since data is a scalar - return numpy.isfinite(x) + def seed(self, seed=None): + """ + Reseed the generator. - def _is_signbit_scalar(self, x): - """Test a scalar if sign bit is set for it (less than zero).""" + For full documentation refer to :obj:`numpy.random.RandomState.seed`. - # TODO: replace with dpnp.signbit() once function is available in DPNP, - # but for now use direct numpy calls without call_origin() wrapper, since data is a scalar - return numpy.signbit(x) + Limitations + ----------- + As NumPy reseeds only its legacy MT19937, only a + :class:`dpnp.random.Philox4x3210` bit generator can be reseeded. - def _validate_float_dtype(self, dtype, supported_types): """ - Validate an input floating type. + bit_generator = self._generator.bit_generator + if type(bit_generator) is not Philox4x3210: + raise TypeError("can only re-seed a Philox4x3210 BitGenerator") + _reseed_in_place(bit_generator, self._make_bit_generator(seed)) - Test an input floating type if it is listed in `supported_types` and - if it is supported by the used SYCL device. - If `dtype` is ``None``, default floating type will be validating. - Return the examined floating type if it follows all validation checks. + def get_state(self, legacy=True): """ + Return the state of the generator. - if dtype is None: - dtype = self._def_float_type + For full documentation refer to + :obj:`numpy.random.RandomState.get_state`. - if dtype not in supported_types: - raise TypeError(f"dtype={dtype} is unsupported.") - elif dtype != map_dtype_to_device(dtype, self._sycl_device): - raise RuntimeError( - f"dtype={dtype} is not supported by SYCL device '{self._sycl_device}'" - ) - return dtype + Limitations + ----------- + The state is always the dictionary of the + :attr:`dpnp.random.BitGenerator.state` of the bit generator, + whatever `legacy` is. - def get_state(self): """ - Return an internal state of the generator. + # pylint: disable=unused-argument + return self._generator.bit_generator.state - For full documentation refer to :obj:`numpy.random.RandomState.get_state`. + def set_state(self, state): + """ + Set the state of the generator. - Returns - ------- - out : object - An object representing the internal state of the generator. + For full documentation refer to + :obj:`numpy.random.RandomState.set_state`. + + Limitations + ----------- + `state` must be a state of the bit generator, as returned by + :meth:`get_state`. - Notes - ----- - Unlike :obj:`numpy.random.RandomState.get_state`, which returns a - snapshot of the state as plain data, this returns the live engine the - generator draws from. Generating from the returned engine advances the - state seen by this :class:`RandomState`, and does so safely if other - threads are drawing from it at the same time. """ - return self._random_state + bit_generator = self._generator.bit_generator + if not isinstance(state, dict): + raise ValueError( + f"state must be for a {type(bit_generator).__name__} PRNG" + ) + bit_generator.state = state def get_sycl_queue(self): """ - Return an instance of :class:`dpctl.SyclQueue` used within the generator for data allocation. + Return the :class:`dpctl.SyclQueue` the generator allocates data on. Returns ------- queue : dpctl.SyclQueue A SYCL queue used for data allocation. + """ return self._sycl_queue def get_sycl_device(self): """ - Return an instance of :class:`dpctl.SyclDevice` used within the generator to allocate data on. + Return the :class:`dpctl.SyclDevice` the generator allocates data on. Returns ------- device : dpctl.SyclDevice A SYCL device used to allocate data on. + """ - return self._sycl_device + return self._sycl_queue.sycl_device - def normal( - self, loc=0.0, scale=1.0, size=None, dtype=None, usm_type="device" + # Simple random data + + def rand(self, *args, dtype=None, usm_type="device"): + """ + Random values in a given shape, from a uniform distribution over + [0, 1). + + For full documentation refer to :obj:`numpy.random.RandomState.rand`. + + """ + return self.random_sample(args or None, dtype, usm_type=usm_type) + + def randn(self, *args, dtype=None, usm_type="device"): + """ + Samples of the standard normal distribution in a given shape. + + For full documentation refer to :obj:`numpy.random.RandomState.randn`. + + """ + return self.standard_normal(args or None, dtype, usm_type=usm_type) + + def randint( + self, low, high=None, size=None, dtype=int, *, usm_type="device" ): """ - Draw random samples from a normal (Gaussian) distribution. + Random integers from `low` (inclusive) to `high` (exclusive). - For full documentation refer to :obj:`numpy.random.RandomState.normal`. + For full documentation refer to + :obj:`numpy.random.RandomState.randint`. - Parameters - ---------- - usm_type : {"device", "shared", "host"}, optional - The type of SYCL USM allocation for the output array. + Limitations + ----------- + ``dtype=int`` gives ``int64`` values, not a C ``long``, which is + ``int32`` on Windows. - Default: ``"device"``. + """ + return self._generator._integers( + low, high, size, dtype, False, usm_type, "randint" + ) - 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. + def random_integers(self, low, high=None, size=None, *, usm_type="device"): + """ + Random integers from `low` to `high`, both inclusive. + + For full documentation refer to + :obj:`numpy.random.RandomState.random_integers`. Limitations ----------- - Parameters `loc` and `scale` are supported as a scalar. Otherwise, - :obj:`numpy.random.RandomState.normal(loc, scale, size)` samples are drawn. - Parameter `dtype` is supported only as :obj:`dpnp.float32`, :obj:`dpnp.float64` or ``None``. + The values are ``int64``, not a C ``long``, which is ``int32`` on + Windows. + + """ + return self._random_integers(low, high, size, usm_type, stacklevel=3) + + def _random_integers(self, low, high, size, usm_type, stacklevel): + if high is None: + warnings.warn( + "This function is deprecated. Please call " + f"randint(1, {low} + 1) instead", + DeprecationWarning, + stacklevel=stacklevel, + ) + high = low + low = 1 + else: + warnings.warn( + "This function is deprecated. Please call " + f"randint({low}, {high} + 1) instead", + DeprecationWarning, + stacklevel=stacklevel, + ) + if dpnp.is_supported_array_type(high): + high = high + 1 + elif _is_array(high): + high = numpy.array(high) + 1 + else: + high = int(high) + 1 + return self.randint(low, high, size, _int64, usm_type=usm_type) + + def random_sample(self, size=None, dtype=None, *, usm_type="device"): + """ + Random floats in the half-open interval [0.0, 1.0). - Examples - -------- - >>> s = dpnp.random.RandomState().normal(loc=3.7, scale=2.5, size=(2, 4)) - >>> print(s) - [[ 1.58997253 -0.84288406 2.33836967 4.16394577] - [ 4.40882036 5.39295758 6.48927254 6.74921661]] + For full documentation refer to + :obj:`numpy.random.RandomState.random_sample`. - See Also - -------- - :obj:`dpnp.random.RandomState.randn` - :obj:`dpnp.random.RandomState.standard_normal` + """ + return self._generator.random(size, dtype, usm_type=usm_type) + def random(self, size=None, dtype=None, *, usm_type="device"): """ + Random floats in the half-open interval [0.0, 1.0). - if not use_origin_backend(): - if dpnp.is_cuda_backend(self): # pragma: no cover - raise NotImplementedError( - "Running on CUDA is currently not supported" - ) + For full documentation refer to :obj:`numpy.random.RandomState.random`. - if not dpnp.isscalar(loc): - pass - elif not dpnp.isscalar(scale): - pass - else: - dtype = self._validate_float_dtype( - dtype, (dpnp.float32, dpnp.float64) - ) - min_floating = dpnp.finfo(dtype).min - max_floating = dpnp.finfo(dtype).max - - if ( - loc >= max_floating or loc <= min_floating - ) and self._is_finite_scalar(loc): - raise OverflowError( - f"Range of loc={loc} exceeds valid bounds" - ) - - if (scale >= max_floating) and self._is_finite_scalar(scale): - raise OverflowError( - f"Range of scale={scale} exceeds valid bounds" - ) - # scale = -0.0 is cosidered as negative - elif scale < 0 or scale == 0 and self._is_signbit_scalar(scale): - raise ValueError( - f"scale={scale}, but must be non-negative." - ) - - validate_usm_type(usm_type, allow_none=False) - return self._random_state.normal( - loc=loc, - scale=scale, - size=size, - dtype=dtype, - usm_type=usm_type, - ).get_pyobj() - - return call_origin( - self._fallback_random_state.normal, - loc=loc, - scale=scale, - size=size, - sycl_queue=self._sycl_queue, + """ + return self._generator.random(size, dtype, usm_type=usm_type) + + def tomaxint(self, size=None, *, usm_type="device"): + """ + Random integers from 0 to the largest ``int64``, both inclusive. + + For full documentation refer to + :obj:`numpy.random.RandomState.tomaxint`. + + Limitations + ----------- + The values are ``int64``, not a C ``long``, which is ``int32`` on + Windows. + + """ + return self._generator._integers( + 0, _INT64_MAX, size, _int64, True, usm_type, "tomaxint" ) - def rand(self, *args, usm_type="device"): + def choice(self, a, size=None, replace=True, p=None, *, usm_type="device"): """ - Draw random values in a given shape. + Generate a random sample from a given 1-D array. - Create an array of the given shape and populate it with random samples - from a uniform distribution over [0, 1). + For full documentation refer to :obj:`numpy.random.RandomState.choice`. - For full documentation refer to :obj:`numpy.random.RandomState.rand`. + """ + return self._generator._choice( + a, size, replace, p, 0, usm_type, _CHOICE_MSGS + ) - Parameters - ---------- - usm_type : {"device", "shared", "host"}, optional - The type of SYCL USM allocation for the output array. + def bytes(self, length): + """ + Return random bytes. - Default: ``"device"``. + For full documentation refer to :obj:`numpy.random.RandomState.bytes`. - 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. + """ + return self._generator.bytes(length) - Examples - -------- - >>> s = dpnp.random.RandomState().rand(5, 2) - >>> print(s) - [[0.13436424 0.56920387] - [0.84743374 0.80226506] - [0.76377462 0.06310682] - [0.25506903 0.1179187 ] - [0.49543509 0.76096244]] + # Permutations - See Also - -------- - :obj:`dpnp.random.RandomState.random_sample` - :obj:`dpnp.random.RandomState.uniform` + def shuffle(self, x): + """ + Modify an array in place by shuffling its contents along the first + axis. + + For full documentation refer to + :obj:`numpy.random.RandomState.shuffle`. + + Limitations + ----------- + As in CuPy, `x` must be a :class:`dpnp.ndarray`. """ + self._generator.shuffle(x) - if len(args) == 0: - return self.random_sample(usm_type=usm_type) - else: - return self.random_sample(size=args, usm_type=usm_type) + def permutation(self, x): + """ + Randomly permute a sequence, or return a permuted range. + + For full documentation refer to + :obj:`numpy.random.RandomState.permutation`. - def randint(self, low, high=None, size=None, dtype=int, usm_type="device"): """ - Draw random integers from `low` (inclusive) to `high` (exclusive). + if not isinstance(x, (int, numpy.integer)) and numpy.ndim(x) == 0: + raise IndexError("x must be an integer or at least 1-dimensional") + return self._generator.permutation(x) - Return random integers from the “discrete uniform” distribution of the specified type - in the “half-open” interval [low, high). + # Distributions - For full documentation refer to :obj:`numpy.random.RandomState.randint`. + def beta(self, a, b, size=None, dtype=None, *, usm_type="device"): + """ + Draw samples from a Beta distribution. - Parameters - ---------- - usm_type : {"device", "shared", "host"}, optional - The type of SYCL USM allocation for the output array. + For full documentation refer to :obj:`numpy.random.RandomState.beta`. - Default: ``"device"``. + """ + return self._generator.beta(a, b, size, dtype, usm_type=usm_type) - 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`. + def binomial(self, n, p, size=None, *, usm_type="device"): + """ + Draw samples from a binomial distribution. + + For full documentation refer to + :obj:`numpy.random.RandomState.binomial`. + + """ + return self._generator.binomial(n, p, size, usm_type=usm_type) + + def chisquare(self, df, size=None, dtype=None, *, usm_type="device"): + """ + Draw samples from a chi-square distribution. + + For full documentation refer to + :obj:`numpy.random.RandomState.chisquare`. + + """ + return self._generator.chisquare(df, size, dtype, usm_type=usm_type) + + def dirichlet(self, alpha, size=None, dtype=None, *, usm_type="device"): + """ + Draw samples from the Dirichlet distribution. + + For full documentation refer to + :obj:`numpy.random.RandomState.dirichlet`. + + """ + self._generator._check_queues(alpha) + if dpnp.is_supported_array_type(alpha): + # the Generator copies alpha to the host anyway + alpha = dpnp.asnumpy(alpha) + if numpy.ndim(alpha) == 1: + if numpy.any(numpy.asarray(alpha, dtype=numpy.float64) <= 0): + raise ValueError("alpha <= 0") + return self._generator.dirichlet(alpha, size, dtype, usm_type=usm_type) + + def exponential( + self, scale=1.0, size=None, dtype=None, *, usm_type="device" + ): + """ + Draw samples from an exponential distribution. + + For full documentation refer to + :obj:`numpy.random.RandomState.exponential`. + + """ + return self._generator.exponential( + scale, size, dtype, usm_type=usm_type + ) + + def f(self, dfnum, dfden, size=None, dtype=None, *, usm_type="device"): + """ + Draw samples from an F distribution. + + For full documentation refer to :obj:`numpy.random.RandomState.f`. + + """ + return self._generator.f(dfnum, dfden, size, dtype, usm_type=usm_type) + + def gamma( + self, shape, scale=1.0, size=None, dtype=None, *, usm_type="device" + ): + """ + Draw samples from a Gamma distribution. + + For full documentation refer to :obj:`numpy.random.RandomState.gamma`. + + """ + return self._generator.gamma( + shape, scale, size, dtype, usm_type=usm_type + ) + + def geometric(self, p, size=None, *, usm_type="device"): + """ + Draw samples from the geometric distribution. + + For full documentation refer to + :obj:`numpy.random.RandomState.geometric`. + + """ + return self._generator.geometric(p, size, usm_type=usm_type) + + def gumbel( + self, loc=0.0, scale=1.0, size=None, dtype=None, *, usm_type="device" + ): + """ + Draw samples from a Gumbel distribution. + + For full documentation refer to :obj:`numpy.random.RandomState.gumbel`. + + """ + return self._generator.gumbel( + loc, scale, size, dtype, usm_type=usm_type + ) + + def hypergeometric( + self, ngood, nbad, nsample, size=None, *, usm_type="device" + ): + """ + Draw samples from a hypergeometric distribution. + + For full documentation refer to + :obj:`numpy.random.RandomState.hypergeometric`. Limitations ----------- - 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. + As in :meth:`dpnp.random.Generator.hypergeometric`, `ngood` and + `nbad` must be less than 10**9. - Examples - -------- - >>> s = dpnp.random.RandomState().randint(2, size=10) - >>> print(s) - [0 1 1 1 1 0 0 0 0 1] + """ + self._generator._check_queues(ngood, nbad, nsample) + params = tuple(_as_int64(x) for x in (ngood, nbad, nsample)) + xp, (good, bad, sample) = _check_arrays(params, True) + if xp.any(good + bad < sample): + raise ValueError("ngood + nbad < nsample") + scalar = _is_scalar_path(*params) + for x, name, cons in zip( + params, + ("ngood", "nbad", "nsample"), + (_CONS_NON_NEGATIVE, _CONS_NON_NEGATIVE, _CONS_GTE_1), + ): + _check_constraint(x, name, cons, scalar, device=True) + if xp.any(good >= _HYPERGEOM_MAX) or xp.any(bad >= _HYPERGEOM_MAX): + raise ValueError( + f"both ngood and nbad must be less than {_HYPERGEOM_MAX}" + ) + return self._generator._discrete_sample( + ri._hypergeometric, + params, + size, + usm_type, + param_types=(_int64,) * 3, + ) - See Also - -------- - :obj:`dpnp.random.RandomState.random_integers` : similar to `randint`, only for the closed - interval [`low`, `high`], and 1 is the lowest value if `high` is omitted. + def laplace( + self, loc=0.0, scale=1.0, size=None, dtype=None, *, usm_type="device" + ): + """ + Draw samples from the Laplace or double exponential distribution. + + For full documentation refer to + :obj:`numpy.random.RandomState.laplace`. """ + return self._generator.laplace( + loc, scale, size, dtype, usm_type=usm_type + ) - if not use_origin_backend(low): - if dpnp.is_cuda_backend(self): # pragma: no cover - raise NotImplementedError( - "Running on CUDA is currently not supported" - ) + def logistic( + self, loc=0.0, scale=1.0, size=None, dtype=None, *, usm_type="device" + ): + """ + Draw samples from a logistic distribution. + + For full documentation refer to + :obj:`numpy.random.RandomState.logistic`. - if not dpnp.isscalar(low): - pass - elif not (high is None or dpnp.isscalar(high)): - pass - else: - _dtype = dpnp.int32 if dtype is int else dpnp.dtype(dtype) - if _dtype != dpnp.int32: - pass - else: - if high is None: - high = low - low = 0 - - min_int = dpnp.iinfo("int32").min - max_int = dpnp.iinfo("int32").max - - if ( - not self._is_finite_scalar(low) - or low > max_int - or low < min_int - ): - raise OverflowError( - f"Range of low={low} exceeds valid bounds" - ) - elif ( - not self._is_finite_scalar(high) - or high > max_int - or high < min_int - ): - raise OverflowError( - f"Range of high={high} exceeds valid bounds" - ) - - low = int(low) - high = int(high) - if low >= high: - raise ValueError(f"low={low} >= high={high}") - - return self.uniform( - low=low, - high=high, - size=size, - dtype=_dtype, - usm_type=usm_type, - ) - - return call_origin( - self._fallback_random_state.randint, - low=low, - high=high, - size=size, - dtype=dtype, - sycl_queue=self._sycl_queue, + """ + return self._generator.logistic( + loc, scale, size, dtype, usm_type=usm_type ) - def randn(self, *args, usm_type="device"): + def lognormal( + self, mean=0.0, sigma=1.0, size=None, dtype=None, *, usm_type="device" + ): """ - Return a sample (or samples) from the "standard normal" distribution. + Draw samples from a log-normal distribution. - For full documentation refer to :obj:`numpy.random.RandomState.randn`. + For full documentation refer to + :obj:`numpy.random.RandomState.lognormal`. - Parameters - ---------- - usm_type : {"device", "shared", "host"}, optional - The type of SYCL USM allocation for the output array. + """ + return self._generator.lognormal( + mean, sigma, size, dtype, usm_type=usm_type + ) - Default: ``"device"``. + def logseries(self, p, size=None, *, usm_type="device"): + """ + Draw samples from a logarithmic series distribution. - 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. + For full documentation refer to + :obj:`numpy.random.RandomState.logseries`. + + """ + return self._generator.logseries(p, size, usm_type=usm_type) + + def multinomial(self, n, pvals, size=None, *, usm_type="device"): + """ + Draw samples from a multinomial distribution. - Examples - -------- - >>> s = dpnp.random.RandomState().randn() - >>> print(s) - -0.84401099 + For full documentation refer to + :obj:`numpy.random.RandomState.multinomial`. - Two-by-four array of samples from the normal distribution with - mean 3 and standard deviation 2.5: + """ + self._generator._check_queues(n, pvals) + t = type(n) + if _is_array(n) or not ( + hasattr(t, "__int__") or hasattr(t, "__index__") + ): + raise TypeError("an integer is required") + n = int(n) + if not dpnp.is_supported_array_type(pvals): + pvals = numpy.asarray(pvals, dtype=numpy.float64) + ndim = pvals.ndim + if ndim == 0: + raise TypeError("pvals must be a 1-d sequence") + if ndim > 1: + raise ValueError( + "setting an array element with a sequence. The requested " + "array would exceed the maximum number of dimension of 1." + ) + if len(pvals) == 0: + size = _normalize_size(size) + shape = (() if size is None else size) + (0,) + return dpnp.empty( + shape, + dtype=_int64, + usm_type=usm_type, + sycl_queue=self._sycl_queue, + ) + return self._generator.multinomial(n, pvals, size, usm_type=usm_type) + + def multivariate_normal( + self, + mean, + cov, + size=None, + check_valid="warn", + tol=1e-8, + *, + dtype=None, + usm_type="device", + ): + """ + Draw random samples from a multivariate normal distribution. - >>> s = dpnp.random.RandomState().randn(2, 4) - >>> print(s) - [[ 0.88997253 -1.54288406 1.63836967 3.46394577] - [ 3.70882036 4.69295758 5.78927254 6.04921661]] + For full documentation refer to + :obj:`numpy.random.RandomState.multivariate_normal`. - See Also - -------- - :obj:`dpnp.random.normal` - :obj:`dpnp.random.standard_normal` + Limitations + ----------- + The covariance matrix is factorized as in + :meth:`dpnp.random.Generator.multivariate_normal`. """ + return self._multivariate_normal( + mean, cov, size, check_valid, tol, dtype, usm_type, stacklevel=3 + ) - if len(args) == 0: - return self.standard_normal(usm_type=usm_type) - return self.standard_normal(size=args, usm_type=usm_type) + def _multivariate_normal( + self, mean, cov, size, check_valid, tol, dtype, usm_type, stacklevel + ): + return self._generator._multivariate_normal( + mean, + cov, + size, + check_valid, + tol, + "svd", + dtype, + usm_type, + stacklevel=stacklevel + 1, + ) - def random_sample(self, size=None, usm_type="device"): + def negative_binomial(self, n, p, size=None, *, usm_type="device"): """ - Draw random floats in the half-open interval [0.0, 1.0). + Draw samples from a negative binomial distribution. - Results are from the “continuous uniform” distribution over the interval. + For full documentation refer to + :obj:`numpy.random.RandomState.negative_binomial`. - For full documentation refer to :obj:`numpy.random.RandomState.random_sample`. + Limitations + ----------- + As in NumPy, the values are undefined when ``(1 - p) / p * n`` is + too large for the Poisson distribution, as for ``p == 0``. - Parameters - ---------- - usm_type : {"device", "shared", "host"}, optional - The type of SYCL USM allocation for the output array. + """ + self._generator._check_queues(n, p) + scalar = _is_scalar_path(n, p) + _check_constraint(n, "n", _CONS_POSITIVE, scalar, device=True) + _check_constraint(p, "p", _CONS_BOUNDED_0_1, scalar, device=True) + return self._generator._discrete_sample( + ri._negative_binomial, (n, p), size, usm_type + ) - Default: ``"device"``. + def noncentral_chisquare( + self, df, nonc, size=None, dtype=None, *, usm_type="device" + ): + """ + Draw samples from a noncentral chi-square distribution. - 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. + For full documentation refer to + :obj:`numpy.random.RandomState.noncentral_chisquare`. + + """ + return self._generator.noncentral_chisquare( + df, nonc, size, dtype, usm_type=usm_type + ) + + def noncentral_f( + self, dfnum, dfden, nonc, size=None, dtype=None, *, usm_type="device" + ): + """ + Draw samples from the noncentral F distribution. + + For full documentation refer to + :obj:`numpy.random.RandomState.noncentral_f`. + + """ + return self._generator.noncentral_f( + dfnum, dfden, nonc, size, dtype, usm_type=usm_type + ) + + def normal( + self, loc=0.0, scale=1.0, size=None, dtype=None, *, usm_type="device" + ): + """ + Draw random samples from a normal (Gaussian) distribution. + + For full documentation refer to :obj:`numpy.random.RandomState.normal`. + + """ + return self._generator.normal( + loc, scale, size, dtype, usm_type=usm_type + ) + + def pareto(self, a, size=None, dtype=None, *, usm_type="device"): + """ + Draw samples from a Pareto II or Lomax distribution with specified + shape. + + For full documentation refer to :obj:`numpy.random.RandomState.pareto`. + + """ + return self._generator.pareto(a, size, dtype, usm_type=usm_type) + + def poisson(self, lam=1.0, size=None, *, usm_type="device"): + """ + Draw samples from a Poisson distribution. + + For full documentation refer to + :obj:`numpy.random.RandomState.poisson`. + + """ + return self._generator.poisson(lam, size, usm_type=usm_type) - Examples - -------- - >>> s = dpnp.random.RandomState().random_sample(size=(4,)) - >>> print(s) - [0.13436424 0.56920387 0.84743374 0.80226506] + def power(self, a, size=None, dtype=None, *, usm_type="device"): + """ + Draws samples in [0, 1] from a power distribution with positive + exponent a - 1. + + For full documentation refer to :obj:`numpy.random.RandomState.power`. + + """ + return self._generator.power(a, size, dtype, usm_type=usm_type) + + def rayleigh(self, scale=1.0, size=None, dtype=None, *, usm_type="device"): + """ + Draw samples from a Rayleigh distribution. + + For full documentation refer to + :obj:`numpy.random.RandomState.rayleigh`. + + """ + return self._generator.rayleigh(scale, size, dtype, usm_type=usm_type) - See Also - -------- - :obj:`dpnp.random.RandomState.rand` - :obj:`dpnp.random.RandomState.uniform` + def standard_cauchy(self, size=None, dtype=None, *, usm_type="device"): + """ + Draw samples from a standard Cauchy distribution with mode = 0. + + For full documentation refer to + :obj:`numpy.random.RandomState.standard_cauchy`. """ + return self._generator.standard_cauchy(size, dtype, usm_type=usm_type) + + def standard_exponential(self, size=None, dtype=None, *, usm_type="device"): + """ + Draw samples from the standard exponential distribution. + + For full documentation refer to + :obj:`numpy.random.RandomState.standard_exponential`. - return self.uniform( - low=0.0, high=1.0, size=size, dtype=None, usm_type=usm_type + """ + return self._generator.standard_exponential( + size, dtype, usm_type=usm_type ) - def standard_normal(self, size=None, usm_type="device"): + def standard_gamma( + self, shape, size=None, dtype=None, *, usm_type="device" + ): """ - Draw samples from a standard Normal distribution ``(mean=0, stdev=1)``. + Draw samples from a standard Gamma distribution. - For full documentation refer to :obj:`numpy.random.RandomState.standard_normal`. + For full documentation refer to + :obj:`numpy.random.RandomState.standard_gamma`. - Parameters - ---------- - usm_type : {"device", "shared", "host"}, optional - The type of SYCL USM allocation for the output array. + """ + return self._generator.standard_gamma( + shape, size, dtype, usm_type=usm_type + ) - Default: ``"device"``. + def standard_normal(self, size=None, dtype=None, *, usm_type="device"): + """ + Draw samples from a standard Normal distribution (mean=0, stdev=1). - 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. + For full documentation refer to + :obj:`numpy.random.RandomState.standard_normal`. - Examples - -------- - >>> s = dpnp.random.RandomState().standard_normal(size=(3, 5)) - >>> print(s) - [[-0.84401099 -1.81715362 -0.54465213 0.18557831 0.28352814] - [ 0.67718303 1.11570901 1.21968665 -1.18236388 0.08156915] - [ 0.21941987 -1.24544512 0.63522211 -0.673174 0. ]] + """ + return self._generator.standard_normal(size, dtype, usm_type=usm_type) - See Also - -------- - :obj:`dpnp.random.RandomState.normal` - :obj:`dpnp.random.RandomState.randn` + def standard_t(self, df, size=None, dtype=None, *, usm_type="device"): + """ + Draw samples from a standard Student's t distribution with `df` + degrees of freedom. + For full documentation refer to + :obj:`numpy.random.RandomState.standard_t`. + + """ + return self._generator.standard_t(df, size, dtype, usm_type=usm_type) + + def triangular( + self, left, mode, right, size=None, dtype=None, *, usm_type="device" + ): """ + Draw samples from the triangular distribution over the interval + [left, right]. - return self.normal( - loc=0.0, scale=1.0, size=size, dtype=None, usm_type=usm_type + For full documentation refer to + :obj:`numpy.random.RandomState.triangular`. + + """ + return self._generator.triangular( + left, mode, right, size, dtype, usm_type=usm_type ) def uniform( - self, low=0.0, high=1.0, size=None, dtype=None, usm_type="device" + self, low=0.0, high=1.0, size=None, dtype=None, *, usm_type="device" ): """ - Draw samples from a uniform distribution. + Draw samples from a uniform distribution over [low, high). - 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.RandomState.uniform`. - For full documentation refer to :obj:`numpy.random.RandomState.uniform`. + """ + _uniform_range(low, high, "Range exceeds valid bounds", device=True) + return self._generator._float_sample( + ri._uniform, (low, high), size, dtype, usm_type, "uniform" + ) - Parameters - ---------- - usm_type : {"device", "shared", "host"}, optional - The type of SYCL USM allocation for the output array. + def vonmises(self, mu, kappa, size=None, dtype=None, *, usm_type="device"): + """ + Draw samples from a von Mises distribution. - Default: ``"device"``. + For full documentation refer to + :obj:`numpy.random.RandomState.vonmises`. - 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. + """ + return self._generator.vonmises( + mu, kappa, size, dtype, usm_type=usm_type + ) + + def wald(self, mean, scale, size=None, dtype=None, *, usm_type="device"): + """ + Draw samples from a Wald, or inverse Gaussian, distribution. + + For full documentation refer to :obj:`numpy.random.RandomState.wald`. + + """ + return self._generator.wald(mean, scale, size, dtype, usm_type=usm_type) + + def weibull(self, a, size=None, dtype=None, *, usm_type="device"): + """ + Draw samples from a Weibull distribution. + + For full documentation refer to + :obj:`numpy.random.RandomState.weibull`. + + """ + return self._generator.weibull(a, size, dtype, usm_type=usm_type) + + def zipf(self, a, size=None, *, usm_type="device"): + """ + Draw samples from a Zipf distribution. + + For full documentation refer to :obj:`numpy.random.RandomState.zipf`. Limitations ----------- - Parameters `low` and `high` are supported as a scalar. Otherwise, - :obj:`numpy.random.RandomState.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 - -------- - >>> low, high = 1.23, 10.54 # low and high - >>> s = dpnp.random.RandomState().uniform(low, high, 5) - >>> print(s) - [2.48093112 6.52928804 9.1196081 8.6990877 8.34074171] - - See Also - -------- - :obj:`dpnp.random.RandomState.randint` : Discrete uniform distribution, yielding integers. - :obj:`dpnp.random.RandomState.random_integers` : Discrete uniform distribution over the closed interval ``[low, high]``. - :obj:`dpnp.random.RandomState.random_sample` : Floats uniformly distributed over ``[0, 1)``. - :obj:`dpnp.random.RandomState.random` : Alias for :obj:`dpnp.random.RandomState.random_sample`. - :obj:`dpnp.random.RandomState.rand` : Convenience function that accepts dimensions as input, e.g., - ``rand(2, 2)`` would generate a 2-by-2 array of floats, uniformly distributed over ``[0, 1)``. - - """ - - if not use_origin_backend(): - if dpnp.is_cuda_backend(self): # pragma: no cover - raise NotImplementedError( - "Running on CUDA is currently not supported" - ) + The samples follow the Zipf distribution truncated to the largest + ``int64``, while NumPy's rejection test rounds to accepting every + sample above ``2**53``, which makes its tail too heavy for `a` close + to 1. - if not dpnp.isscalar(low): - pass - elif not dpnp.isscalar(high): - pass - else: - min_double = dpnp.finfo("double").min - max_double = dpnp.finfo("double").max - - if ( - not self._is_finite_scalar(low) - or low >= max_double - or low <= min_double - ): - raise OverflowError( - f"Range of low={low} exceeds valid bounds" - ) - elif ( - not self._is_finite_scalar(high) - or high >= max_double - or high <= min_double - ): - raise OverflowError( - f"Range of high={high} exceeds valid bounds" - ) - - if low > high: - low, high = high, low - - dtype = self._validate_float_dtype( - dtype, (dpnp.int32, dpnp.float32, dpnp.float64) - ) - validate_usm_type(usm_type, allow_none=False) - - return self._random_state.uniform( - low=low, - high=high, - size=size, - dtype=dtype, - usm_type=usm_type, - ).get_pyobj() - - return call_origin( - self._fallback_random_state.uniform, - low=low, - high=high, - size=size, - sycl_queue=self._sycl_queue, - ) + """ + return self._generator.zipf(a, size, usm_type=usm_type) diff --git a/dpnp/tests/skipped_tests.tbl b/dpnp/tests/skipped_tests.tbl index 5ea97fa7977f..e69de29bb2d1 100644 --- a/dpnp/tests/skipped_tests.tbl +++ b/dpnp/tests/skipped_tests.tbl @@ -1,10 +0,0 @@ -tests/test_random.py::TestDistributionsMultivariateNormal::test_moments -tests/test_random.py::TestDistributionsMultivariateNormal::test_output_shape_check -tests/test_random.py::TestDistributionsMultivariateNormal::test_seed -tests/test_random.py::TestPermutationsTestShuffle::test_shuffle1[lambda x: dpnp.asarray(x).astype(dpnp.complex64)] -tests/test_random.py::TestPermutationsTestShuffle::test_shuffle1[lambda x: dpnp.astype(dpnp.asarray(x), dpnp.int8)] -tests/test_random.py::TestPermutationsTestShuffle::test_shuffle1[lambda x: dpnp.astype(dpnp.asarray(x), object)] -tests/test_random.py::TestPermutationsTestShuffle::test_shuffle1[lambda x: dpnp.vstack([x, x]).T] -tests/test_random.py::TestPermutationsTestShuffle::test_shuffle1[lambda x: (dpnp.asarray([(i, i) for i in x], [("a", int), ("b", int)]).view(dpnp.recarray))] -tests/test_random.py::TestPermutationsTestShuffle::test_shuffle1[lambda x: dpnp.asarray([(i, i) for i in x], [("a", object), ("b", dpnp.int32)])]] -tests/test_random.py::TestPermutationsTestShuffle::test_shuffle1[lambda x: dpnp.asarray(x).astype(dpnp.int8)] diff --git a/dpnp/tests/skipped_tests_cuda.tbl b/dpnp/tests/skipped_tests_cuda.tbl index e8415a1ae410..e69de29bb2d1 100644 --- a/dpnp/tests/skipped_tests_cuda.tbl +++ b/dpnp/tests/skipped_tests_cuda.tbl @@ -1,662 +0,0 @@ -# NotImplementedError - -# random -tests/test_random_state.py::TestNormal::test_distr[host-float32] -tests/test_random_state.py::TestNormal::test_distr[host-float64] -tests/test_random_state.py::TestNormal::test_distr[host-None] -tests/test_random_state.py::TestNormal::test_distr[device-float32] -tests/test_random_state.py::TestNormal::test_distr[device-float64] -tests/test_random_state.py::TestNormal::test_distr[device-None] -tests/test_random_state.py::TestNormal::test_distr[shared-float32] -tests/test_random_state.py::TestNormal::test_distr[shared-float64] -tests/test_random_state.py::TestNormal::test_distr[shared-None] -tests/test_random_state.py::TestNormal::test_scale[host-float32] -tests/test_random_state.py::TestNormal::test_scale[host-float64] -tests/test_random_state.py::TestNormal::test_scale[host-None] -tests/test_random_state.py::TestNormal::test_scale[device-float32] -tests/test_random_state.py::TestNormal::test_scale[device-float64] -tests/test_random_state.py::TestNormal::test_scale[device-None] -tests/test_random_state.py::TestNormal::test_scale[shared-float32] -tests/test_random_state.py::TestNormal::test_scale[shared-float64] -tests/test_random_state.py::TestNormal::test_scale[shared-None] -tests/test_random_state.py::TestNormal::test_inf_loc[numpy.inf] -tests/test_random_state.py::TestNormal::test_inf_loc[-numpy.inf] -tests/test_random_state.py::TestNormal::test_inf_loc[nextafter(max, 0)] -tests/test_random_state.py::TestNormal::test_inf_loc[nextafter(min, 0)] -tests/test_random_state.py::TestNormal::test_inf_scale -tests/test_random_state.py::TestNormal::test_inf_loc_scale[numpy.inf] -tests/test_random_state.py::TestNormal::test_inf_loc_scale[-numpy.inf] -tests/test_random_state.py::TestNormal::test_extreme_bounds -tests/test_random_state.py::TestNormal::test_fallback[[2]-dpnp.array([3])] -tests/test_random_state.py::TestNormal::test_fallback[[2]-numpy.array([3])] -tests/test_random_state.py::TestNormal::test_fallback[dpnp.array([2])-dpnp.array([3])] -tests/test_random_state.py::TestNormal::test_fallback[dpnp.array([2])-numpy.array([3])] -tests/test_random_state.py::TestNormal::test_fallback[numpy.array([2])-dpnp.array([3])] -tests/test_random_state.py::TestNormal::test_fallback[numpy.array([2])-numpy.array([3])] -tests/test_random_state.py::TestNormal::test_invalid_dtype[dpnp.float16] -tests/test_random_state.py::TestNormal::test_invalid_dtype[float] -tests/test_random_state.py::TestNormal::test_invalid_dtype[dpnp.int64] -tests/test_random_state.py::TestNormal::test_invalid_dtype[dpnp.int32] -tests/test_random_state.py::TestNormal::test_invalid_dtype[dpnp.int] -tests/test_random_state.py::TestNormal::test_invalid_dtype[int] -tests/test_random_state.py::TestNormal::test_invalid_dtype[numpy.clongdouble] -tests/test_random_state.py::TestNormal::test_invalid_dtype[dpnp.complex128] -tests/test_random_state.py::TestNormal::test_invalid_dtype[dpnp.complex64] -tests/test_random_state.py::TestNormal::test_invalid_dtype[dpnp.bool] -tests/test_random_state.py::TestNormal::test_invalid_dtype[dpnp.bool_] -tests/test_random_state.py::TestNormal::test_invalid_usm_type[Empty] -tests/test_random_state.py::TestNormal::test_invalid_usm_type[Unknown] -tests/test_random_state.py::TestRand::test_distr[host] -tests/test_random_state.py::TestRand::test_distr[device] -tests/test_random_state.py::TestRand::test_distr[shared] -tests/test_random_state.py::TestRand::test_zero_dims[(0,)] -tests/test_random_state.py::TestRand::test_zero_dims[(3, 0)] -tests/test_random_state.py::TestRand::test_zero_dims[(3, 0, 10)] -tests/test_random_state.py::TestRand::test_zero_dims[()] -tests/test_random_state.py::TestRand::test_wrong_dims -tests/test_random_state.py::TestRandInt::test_distr[host-int] -tests/test_random_state.py::TestRandInt::test_distr[host-dpnp.int32] -tests/test_random_state.py::TestRandInt::test_distr[device-int] -tests/test_random_state.py::TestRandInt::test_distr[device-dpnp.int32] -tests/test_random_state.py::TestRandInt::test_distr[shared-int] -tests/test_random_state.py::TestRandInt::test_distr[shared-dpnp.int32] -tests/test_random_state.py::TestRandInt::test_float_bounds -tests/test_random_state.py::TestRandInt::test_full_range -tests/test_random_state.py::TestRandInt::test_negative_bounds -tests/test_random_state.py::TestRandInt::test_negative_interval -tests/test_random_state.py::TestRandInt::test_bounds_checking -tests/test_random_state.py::TestRandInt::test_rng_zero_and_extremes -tests/test_random_state.py::TestRandInt::test_full_range -tests/test_random_state.py::TestRandInt::test_in_bounds_fuzz -tests/test_random_state.py::TestRandInt::test_zero_size[(3, 0, 4)] -tests/test_random_state.py::TestRandInt::test_zero_size[0] -tests/test_random_state.py::TestRandInt::test_zero_size[(0,)] -tests/test_random_state.py::TestRandInt::test_zero_size[()] -tests/test_random_state.py::TestRandInt::test_bounds_fallback[[2]-dpnp.array([3])] -tests/test_random_state.py::TestRandInt::test_bounds_fallback[[2]-numpy.array([3])] -tests/test_random_state.py::TestRandInt::test_bounds_fallback[dpnp.array([2])-dpnp.array([3])] -tests/test_random_state.py::TestRandInt::test_bounds_fallback[dpnp.array([2])-numpy.array([3])] -tests/test_random_state.py::TestRandInt::test_bounds_fallback[numpy.array([2])-dpnp.array([3])] -tests/test_random_state.py::TestRandInt::test_bounds_fallback[numpy.array([2])-numpy.array([3])] -tests/test_random_state.py::TestRandInt::test_dtype_fallback[dpnp.int64] -tests/test_random_state.py::TestRandInt::test_dtype_fallback[dpnp.int] -tests/test_random_state.py::TestRandInt::test_dtype_fallback[dpnp.bool] -tests/test_random_state.py::TestRandInt::test_dtype_fallback[dpnp.bool_] -tests/test_random_state.py::TestRandInt::test_dtype_fallback[bool] -tests/test_random_state.py::TestRandInt::test_invalid_usm_type[Empty] -tests/test_random_state.py::TestRandInt::test_invalid_usm_type[Unknown] -tests/test_random_state.py::TestRandN::test_distr[host] -tests/test_random_state.py::TestRandN::test_distr[device] -tests/test_random_state.py::TestRandN::test_distr[shared] -tests/test_random_state.py::TestRandN::test_zero_dims[(0,)] -tests/test_random_state.py::TestRandN::test_zero_dims[(3, 0)] -tests/test_random_state.py::TestRandN::test_zero_dims[(3, 0, 10)] -tests/test_random_state.py::TestRandN::test_zero_dims[()] -tests/test_random_state.py::TestRandN::test_wrong_dims -tests/test_random_state.py::TestSeed::test_scalar[normal] -tests/test_random_state.py::TestSeed::test_scalar[standard_normal] -tests/test_random_state.py::TestSeed::test_scalar[random_sample] -tests/test_random_state.py::TestSeed::test_scalar[uniform] -tests/test_random_state.py::TestStandardNormal::test_distr[host] -tests/test_random_state.py::TestStandardNormal::test_distr[device] -tests/test_random_state.py::TestStandardNormal::test_distr[shared] -tests/test_random_state.py::TestStandardNormal::test_wrong_dims -tests/test_random_state.py::TestRandSample::test_distr[host] -tests/test_random_state.py::TestRandSample::test_distr[device] -tests/test_random_state.py::TestRandSample::test_distr[shared] -tests/test_random_state.py::TestRandSample::test_wrong_dims -tests/test_random_state.py::TestUniform::test_distr[host-float32-(low, high)=[1.23, 10.54]] -tests/test_random_state.py::TestUniform::test_distr[host-float32-(low, high)=[10.54, 1.23]] -tests/test_random_state.py::TestUniform::test_distr[host-float64-(low, high)=[1.23, 10.54]] -tests/test_random_state.py::TestUniform::test_distr[host-float64-(low, high)=[10.54, 1.23]] -tests/test_random_state.py::TestUniform::test_distr[host-int32-(low, high)=[1.23, 10.54]] -tests/test_random_state.py::TestUniform::test_distr[host-int32-(low, high)=[10.54, 1.23]] -tests/test_random_state.py::TestUniform::test_distr[host-None-(low, high)=[1.23, 10.54]] -tests/test_random_state.py::TestUniform::test_distr[host-None-(low, high)=[10.54, 1.23]] -tests/test_random_state.py::TestUniform::test_distr[device-float32-(low, high)=[1.23, 10.54]] -tests/test_random_state.py::TestUniform::test_distr[device-float32-(low, high)=[10.54, 1.23]] -tests/test_random_state.py::TestUniform::test_distr[device-float64-(low, high)=[1.23, 10.54]] -tests/test_random_state.py::TestUniform::test_distr[device-float64-(low, high)=[10.54, 1.23]] -tests/test_random_state.py::TestUniform::test_distr[device-int32-(low, high)=[1.23, 10.54]] -tests/test_random_state.py::TestUniform::test_distr[device-int32-(low, high)=[10.54, 1.23]] -tests/test_random_state.py::TestUniform::test_distr[device-None-(low, high)=[1.23, 10.54]] -tests/test_random_state.py::TestUniform::test_distr[device-None-(low, high)=[10.54, 1.23]] -tests/test_random_state.py::TestUniform::test_distr[shared-float32-(low, high)=[1.23, 10.54]] -tests/test_random_state.py::TestUniform::test_distr[shared-float32-(low, high)=[10.54, 1.23]] -tests/test_random_state.py::TestUniform::test_distr[shared-float64-(low, high)=[1.23, 10.54]] -tests/test_random_state.py::TestUniform::test_distr[shared-float64-(low, high)=[10.54, 1.23]] -tests/test_random_state.py::TestUniform::test_distr[shared-int32-(low, high)=[1.23, 10.54]] -tests/test_random_state.py::TestUniform::test_distr[shared-int32-(low, high)=[10.54, 1.23]] -tests/test_random_state.py::TestUniform::test_distr[shared-None-(low, high)=[1.23, 10.54]] -tests/test_random_state.py::TestUniform::test_distr[shared-None-(low, high)=[10.54, 1.23]] -tests/test_random_state.py::TestUniform::test_low_high_equal[host-float32] -tests/test_random_state.py::TestUniform::test_low_high_equal[host-float64] -tests/test_random_state.py::TestUniform::test_low_high_equal[host-int32] -tests/test_random_state.py::TestUniform::test_low_high_equal[host-None] -tests/test_random_state.py::TestUniform::test_low_high_equal[device-float32] -tests/test_random_state.py::TestUniform::test_low_high_equal[device-float64] -tests/test_random_state.py::TestUniform::test_low_high_equal[device-int32] -tests/test_random_state.py::TestUniform::test_low_high_equal[device-None] -tests/test_random_state.py::TestUniform::test_low_high_equal[shared-float32] -tests/test_random_state.py::TestUniform::test_low_high_equal[shared-float64] -tests/test_random_state.py::TestUniform::test_low_high_equal[shared-int32] -tests/test_random_state.py::TestUniform::test_low_high_equal[shared-None] -tests/test_random_state.py::TestUniform::test_range_bounds -tests/test_random_state.py::TestUniform::test_fallback[[2]-dpnp.array([3])] -tests/test_random_state.py::TestUniform::test_fallback[[2]-numpy.array([3])] -tests/test_random_state.py::TestUniform::test_fallback[dpnp.array([2])-dpnp.array([3])] -tests/test_random_state.py::TestUniform::test_fallback[dpnp.array([2])-numpy.array([3])] -tests/test_random_state.py::TestUniform::test_fallback[numpy.array([2])-dpnp.array([3])] -tests/test_random_state.py::TestUniform::test_fallback[numpy.array([2])-numpy.array([3])] -tests/test_random_state.py::TestUniform::test_invalid_dtype[dpnp.float16] -tests/test_random_state.py::TestUniform::test_invalid_dtype[float] -tests/test_random_state.py::TestUniform::test_invalid_dtype[dpnp.int64] -tests/test_random_state.py::TestUniform::test_invalid_dtype[dpnp.int] -tests/test_random_state.py::TestUniform::test_invalid_dtype[int] -tests/test_random_state.py::TestUniform::test_invalid_dtype[numpy.clongdouble] -tests/test_random_state.py::TestUniform::test_invalid_dtype[dpnp.complex128] -tests/test_random_state.py::TestUniform::test_invalid_dtype[dpnp.complex64] -tests/test_random_state.py::TestUniform::test_invalid_dtype[dpnp.bool] -tests/test_random_state.py::TestUniform::test_invalid_dtype[dpnp.bool_] -tests/test_random_state.py::TestUniform::test_invalid_usm_type[Empty] -tests/test_random_state.py::TestUniform::test_invalid_usm_type[Unknown] - -tests/test_random.py::test_input_size[chisquare] -tests/test_random.py::test_input_size[rand] -tests/test_random.py::test_input_size[randn] -tests/test_random.py::test_input_shape[chisquare] -tests/test_random.py::test_input_shape[random] -tests/test_random.py::test_input_shape[random_sample] -tests/test_random.py::test_input_shape[ranf] -tests/test_random.py::test_input_shape[sample] -tests/test_random.py::test_check_output[random] -tests/test_random.py::test_check_output[random_sample] -tests/test_random.py::test_check_output[ranf] -tests/test_random.py::test_check_output[sample] -tests/test_random.py::test_check_output[rand] -tests/test_random.py::test_seed[random] -tests/test_random.py::test_seed[random_sample] -tests/test_random.py::test_seed[ranf] -tests/test_random.py::test_seed[sample] -tests/test_random.py::test_seed[rand] -tests/test_random.py::test_randn_normal_distribution -tests/test_random.py::TestDistributionsBeta::test_invalid_args -tests/test_random.py::TestDistributionsBeta::test_moments -tests/test_random.py::TestDistributionsBeta::test_seed -tests/test_random.py::TestDistributionsBinomial::test_extreme_value -tests/test_random.py::TestDistributionsBinomial::test_invalid_args -tests/test_random.py::TestDistributionsBinomial::test_moments -tests/test_random.py::TestDistributionsBinomial::test_seed -tests/test_random.py::TestDistributionsChisquare::test_invalid_args -tests/test_random.py::TestDistributionsChisquare::test_seed -tests/test_random.py::TestDistributionsExponential::test_invalid_args -tests/test_random.py::TestDistributionsExponential::test_seed -tests/test_random.py::TestDistributionsF::test_invalid_args -tests/test_random.py::TestDistributionsF::test_moments -tests/test_random.py::TestDistributionsF::test_seed -tests/test_random.py::TestDistributionsGamma::test_invalid_args -tests/test_random.py::TestDistributionsGamma::test_moments -tests/test_random.py::TestDistributionsGamma::test_seed -tests/test_random.py::TestDistributionsGeometric::test_extreme_value -tests/test_random.py::TestDistributionsGeometric::test_invalid_args -tests/test_random.py::TestDistributionsGeometric::test_moments -tests/test_random.py::TestDistributionsGeometric::test_seed -tests/test_random.py::TestDistributionsGumbel::test_extreme_value -tests/test_random.py::TestDistributionsGumbel::test_invalid_args -tests/test_random.py::TestDistributionsGumbel::test_moments -tests/test_random.py::TestDistributionsGumbel::test_seed -tests/test_random.py::TestDistributionsHypergeometric::test_extreme_value -tests/test_random.py::TestDistributionsHypergeometric::test_invalid_args -tests/test_random.py::TestDistributionsHypergeometric::test_moments -tests/test_random.py::TestDistributionsHypergeometric::test_seed -tests/test_random.py::TestDistributionsLaplace::test_extreme_value -tests/test_random.py::TestDistributionsLaplace::test_invalid_args -tests/test_random.py::TestDistributionsLaplace::test_moments -tests/test_random.py::TestDistributionsLaplace::test_seed -tests/test_random.py::TestDistributionsLogistic::test_invalid_args -tests/test_random.py::TestDistributionsLogistic::test_moments -tests/test_random.py::TestDistributionsLogistic::test_seed -tests/test_random.py::TestDistributionsLognormal::test_extreme_value -tests/test_random.py::TestDistributionsLognormal::test_invalid_args -tests/test_random.py::TestDistributionsLognormal::test_moments -tests/test_random.py::TestDistributionsLognormal::test_seed -tests/test_random.py::TestDistributionsMultinomial::test_check_sum -tests/test_random.py::TestDistributionsMultinomial::test_extreme_value -tests/test_random.py::TestDistributionsMultinomial::test_invalid_args -tests/test_random.py::TestDistributionsMultinomial::test_moments -tests/test_random.py::TestDistributionsMultinomial::test_seed -tests/test_random.py::TestDistributionsMultinomial::test_seed1 -tests/test_random.py::TestDistributionsMultivariateNormal::test_invalid_args -tests/test_random.py::TestDistributionsNegativeBinomial::test_extreme_value -tests/test_random.py::TestDistributionsNegativeBinomial::test_invalid_args -tests/test_random.py::TestDistributionsNegativeBinomial::test_seed -tests/test_random.py::TestDistributionsNormal::test_extreme_value -tests/test_random.py::TestDistributionsNormal::test_invalid_args -tests/test_random.py::TestDistributionsNormal::test_moments -tests/test_random.py::TestDistributionsNormal::test_seed -tests/test_random.py::TestDistributionsNoncentralChisquare::test_moments[df_grt_1] -tests/test_random.py::TestDistributionsNoncentralChisquare::test_moments[df_eq_1] -tests/test_random.py::TestDistributionsNoncentralChisquare::test_moments[df_less_1] -tests/test_random.py::TestDistributionsNoncentralChisquare::test_invalid_args -tests/test_random.py::TestDistributionsNoncentralChisquare::test_seed[df_grt_1] -tests/test_random.py::TestDistributionsNoncentralChisquare::test_seed[df_eq_1] -tests/test_random.py::TestDistributionsNoncentralChisquare::test_seed[df_less_1] -tests/test_random.py::TestDistributionsPareto::test_invalid_args -tests/test_random.py::TestDistributionsPareto::test_moments -tests/test_random.py::TestDistributionsPareto::test_seed -tests/test_random.py::TestDistributionsPoisson::test_extreme_value -tests/test_random.py::TestDistributionsPoisson::test_invalid_args -tests/test_random.py::TestDistributionsPoisson::test_moments -tests/test_random.py::TestDistributionsPoisson::test_seed -tests/test_random.py::TestDistributionsPower::test_invalid_args -tests/test_random.py::TestDistributionsPower::test_moments -tests/test_random.py::TestDistributionsPower::test_seed -tests/test_random.py::TestDistributionsRayleigh::test_extreme_value -tests/test_random.py::TestDistributionsRayleigh::test_invalid_args -tests/test_random.py::TestDistributionsRayleigh::test_moments -tests/test_random.py::TestDistributionsRayleigh::test_seed -tests/test_random.py::TestDistributionsStandardCauchy::test_seed -tests/test_random.py::TestDistributionsStandardExponential::test_moments -tests/test_random.py::TestDistributionsStandardExponential::test_seed -tests/test_random.py::TestDistributionsStandardGamma::test_extreme_value -tests/test_random.py::TestDistributionsStandardGamma::test_invalid_args -tests/test_random.py::TestDistributionsStandardGamma::test_moments -tests/test_random.py::TestDistributionsStandardGamma::test_seed -tests/test_random.py::TestDistributionsStandardNormal::test_moments -tests/test_random.py::TestDistributionsStandardNormal::test_seed -tests/test_random.py::TestDistributionsStandardT::test_invalid_args -tests/test_random.py::TestDistributionsStandardT::test_moments -tests/test_random.py::TestDistributionsStandardT::test_seed -tests/test_random.py::TestDistributionsTriangular::test_invalid_args -tests/test_random.py::TestDistributionsTriangular::test_moments -tests/test_random.py::TestDistributionsTriangular::test_seed -tests/test_random.py::TestDistributionsUniform::test_extreme_value -tests/test_random.py::TestDistributionsUniform::test_moments -tests/test_random.py::TestDistributionsUniform::test_seed -tests/test_random.py::TestDistributionsVonmises::test_moments[large_kappa] -tests/test_random.py::TestDistributionsVonmises::test_moments[small_kappa] -tests/test_random.py::TestDistributionsVonmises::test_invalid_args -tests/test_random.py::TestDistributionsVonmises::test_seed[large_kappa] -tests/test_random.py::TestDistributionsVonmises::test_seed[small_kappa] -tests/test_random.py::TestDistributionsWald::test_invalid_args -tests/test_random.py::TestDistributionsWald::test_moments -tests/test_random.py::TestDistributionsWald::test_seed -tests/test_random.py::TestDistributionsWeibull::test_extreme_value -tests/test_random.py::TestDistributionsWeibull::test_invalid_args -tests/test_random.py::TestDistributionsWeibull::test_seed -tests/test_random.py::TestDistributionsZipf::test_invalid_args -tests/test_random.py::TestDistributionsZipf::test_seed -tests/test_random.py::TestPermutationsTestShuffle::test_shuffle1[lambda x: dpnp.array([])] -tests/test_random.py::TestPermutationsTestShuffle::test_shuffle1[lambda x: dpnp.astype(dpnp.asarray(x), dpnp.float32)] -tests/test_random.py::TestPermutationsTestShuffle::test_shuffle1[lambda x: dpnp.asarray([[i, i] for i in x])] -tests/test_random.py::TestPermutationsTestShuffle::test_shuffle1_fallback[lambda x: x] -tests/test_random.py::TestPermutationsTestShuffle::test_shuffle1_fallback[lambda x: [(i, i) for i in x]] - -tests/test_sycl_queue.py::test_random[host-cuda:gpu:0-normal-args0-kwargs0] -tests/test_sycl_queue.py::test_random[host-cuda:gpu:0-rand-args1-kwargs1] -tests/test_sycl_queue.py::test_random[host-cuda:gpu:0-randint-args2-kwargs2] -tests/test_sycl_queue.py::test_random[host-cuda:gpu:0-randn-args3-kwargs3] -tests/test_sycl_queue.py::test_random[host-cuda:gpu:0-random-args4-kwargs4] -tests/test_sycl_queue.py::test_random[host-cuda:gpu:0-random_integers-args5-kwargs5] -tests/test_sycl_queue.py::test_random[host-cuda:gpu:0-random_sample-args6-kwargs6] -tests/test_sycl_queue.py::test_random[host-cuda:gpu:0-ranf-args7-kwargs7] -tests/test_sycl_queue.py::test_random[host-cuda:gpu:0-sample-args8-kwargs8] -tests/test_sycl_queue.py::test_random[host-cuda:gpu:0-standard_normal-args9-kwargs9] -tests/test_sycl_queue.py::test_random[host-cuda:gpu:0-uniform-args10-kwargs10] -tests/test_sycl_queue.py::test_random[device-cuda:gpu:0-normal-args0-kwargs0] -tests/test_sycl_queue.py::test_random[device-cuda:gpu:0-rand-args1-kwargs1] -tests/test_sycl_queue.py::test_random[device-cuda:gpu:0-randint-args2-kwargs2] -tests/test_sycl_queue.py::test_random[device-cuda:gpu:0-randn-args3-kwargs3] -tests/test_sycl_queue.py::test_random[device-cuda:gpu:0-random-args4-kwargs4] -tests/test_sycl_queue.py::test_random[device-cuda:gpu:0-random_integers-args5-kwargs5] -tests/test_sycl_queue.py::test_random[device-cuda:gpu:0-random_sample-args6-kwargs6] -tests/test_sycl_queue.py::test_random[device-cuda:gpu:0-ranf-args7-kwargs7] -tests/test_sycl_queue.py::test_random[device-cuda:gpu:0-sample-args8-kwargs8] -tests/test_sycl_queue.py::test_random[device-cuda:gpu:0-standard_normal-args9-kwargs9] -tests/test_sycl_queue.py::test_random[device-cuda:gpu:0-uniform-args10-kwargs10] -tests/test_sycl_queue.py::test_random[shared-cuda:gpu:0-normal-args0-kwargs0] -tests/test_sycl_queue.py::test_random[shared-cuda:gpu:0-rand-args1-kwargs1] -tests/test_sycl_queue.py::test_random[shared-cuda:gpu:0-randint-args2-kwargs2] -tests/test_sycl_queue.py::test_random[shared-cuda:gpu:0-randn-args3-kwargs3] -tests/test_sycl_queue.py::test_random[shared-cuda:gpu:0-random-args4-kwargs4] -tests/test_sycl_queue.py::test_random[shared-cuda:gpu:0-random_integers-args5-kwargs5] -tests/test_sycl_queue.py::test_random[shared-cuda:gpu:0-random_sample-args6-kwargs6] -tests/test_sycl_queue.py::test_random[shared-cuda:gpu:0-ranf-args7-kwargs7] -tests/test_sycl_queue.py::test_random[shared-cuda:gpu:0-sample-args8-kwargs8] -tests/test_sycl_queue.py::test_random[shared-cuda:gpu:0-standard_normal-args9-kwargs9] -tests/test_sycl_queue.py::test_random[shared-cuda:gpu:0-uniform-args10-kwargs10] -tests/test_sycl_queue.py::test_random_state[host-cuda:gpu:0-normal-args0-kwargs0] -tests/test_sycl_queue.py::test_random_state[host-cuda:gpu:0-rand-args1-kwargs1] -tests/test_sycl_queue.py::test_random_state[host-cuda:gpu:0-randint-args2-kwargs2] -tests/test_sycl_queue.py::test_random_state[host-cuda:gpu:0-randn-args3-kwargs3] -tests/test_sycl_queue.py::test_random_state[host-cuda:gpu:0-random_sample-args4-kwargs4] -tests/test_sycl_queue.py::test_random_state[host-cuda:gpu:0-standard_normal-args5-kwargs5] -tests/test_sycl_queue.py::test_random_state[host-cuda:gpu:0-uniform-args6-kwargs6] -tests/test_sycl_queue.py::test_random_state[device-cuda:gpu:0-normal-args0-kwargs0] -tests/test_sycl_queue.py::test_random_state[device-cuda:gpu:0-rand-args1-kwargs1] -tests/test_sycl_queue.py::test_random_state[device-cuda:gpu:0-randint-args2-kwargs2] -tests/test_sycl_queue.py::test_random_state[device-cuda:gpu:0-randn-args3-kwargs3] -tests/test_sycl_queue.py::test_random_state[device-cuda:gpu:0-random_sample-args4-kwargs4] -tests/test_sycl_queue.py::test_random_state[device-cuda:gpu:0-standard_normal-args5-kwargs5] -tests/test_sycl_queue.py::test_random_state[device-cuda:gpu:0-uniform-args6-kwargs6] -tests/test_sycl_queue.py::test_random_state[shared-cuda:gpu:0-normal-args0-kwargs0] -tests/test_sycl_queue.py::test_random_state[shared-cuda:gpu:0-rand-args1-kwargs1] -tests/test_sycl_queue.py::test_random_state[shared-cuda:gpu:0-randint-args2-kwargs2] -tests/test_sycl_queue.py::test_random_state[shared-cuda:gpu:0-randn-args3-kwargs3] -tests/test_sycl_queue.py::test_random_state[shared-cuda:gpu:0-random_sample-args4-kwargs4] -tests/test_sycl_queue.py::test_random_state[shared-cuda:gpu:0-standard_normal-args5-kwargs5] -tests/test_sycl_queue.py::test_random_state[shared-cuda:gpu:0-uniform-args6-kwargs6] - -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsBeta::test_beta[_param_0_{a_shape=(), b_shape=(), dtype=None, shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsBeta::test_beta[_param_1_{a_shape=(), b_shape=(), dtype=None, shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsBeta::test_beta[_param_2_{a_shape=(), b_shape=(3, 2), dtype=None, shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsBeta::test_beta[_param_3_{a_shape=(), b_shape=(3, 2), dtype=None, shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsBeta::test_beta[_param_4_{a_shape=(3, 2), b_shape=(), dtype=None, shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsBeta::test_beta[_param_5_{a_shape=(3, 2), b_shape=(), dtype=None, shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsBeta::test_beta[_param_6_{a_shape=(3, 2), b_shape=(3, 2), dtype=None, shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsBeta::test_beta[_param_7_{a_shape=(3, 2), b_shape=(3, 2), dtype=None, shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsChisquare::test_chisquare[_param_0_{df_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsChisquare::test_chisquare[_param_1_{df_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsChisquare::test_chisquare[_param_2_{df_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsChisquare::test_chisquare[_param_3_{df_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsExponential::test_exponential[_param_0_{scale_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsExponential::test_exponential[_param_1_{scale_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsExponential::test_exponential[_param_2_{scale_shape=(), shape=None}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsExponential::test_exponential[_param_3_{scale_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsExponential::test_exponential[_param_4_{scale_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsExponential::test_exponential[_param_5_{scale_shape=(3, 2), shape=None}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsExponentialError::test_negative_scale -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsF::test_f[_param_0_{dfden_shape=(), dfnum_shape=(), dtype=None, shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsF::test_f[_param_1_{dfden_shape=(), dfnum_shape=(), dtype=None, shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsF::test_f[_param_2_{dfden_shape=(), dfnum_shape=(3, 2), dtype=None, shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsF::test_f[_param_3_{dfden_shape=(), dfnum_shape=(3, 2), dtype=None, shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsF::test_f[_param_4_{dfden_shape=(3, 2), dfnum_shape=(), dtype=None, shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsF::test_f[_param_5_{dfden_shape=(3, 2), dfnum_shape=(), dtype=None, shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsF::test_f[_param_6_{dfden_shape=(3, 2), dfnum_shape=(3, 2), dtype=None, shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsF::test_f[_param_7_{dfden_shape=(3, 2), dfnum_shape=(3, 2), dtype=None, shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsGamma::test_gamma_legacy[_param_0_{dtype=None, scale_shape=(), shape=(4, 3, 2), shape_shape=()}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsGamma::test_gamma_legacy[_param_1_{dtype=None, scale_shape=(), shape=(4, 3, 2), shape_shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsGamma::test_gamma_legacy[_param_2_{dtype=None, scale_shape=(), shape=(3, 2), shape_shape=()}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsGamma::test_gamma_legacy[_param_3_{dtype=None, scale_shape=(), shape=(3, 2), shape_shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsGamma::test_gamma_legacy[_param_4_{dtype=None, scale_shape=(), shape=None, shape_shape=()}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsGamma::test_gamma_legacy[_param_5_{dtype=None, scale_shape=(), shape=None, shape_shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsGamma::test_gamma_legacy[_param_6_{dtype=None, scale_shape=(3, 2), shape=(4, 3, 2), shape_shape=()}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsGamma::test_gamma_legacy[_param_7_{dtype=None, scale_shape=(3, 2), shape=(4, 3, 2), shape_shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsGamma::test_gamma_legacy[_param_8_{dtype=None, scale_shape=(3, 2), shape=(3, 2), shape_shape=()}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsGamma::test_gamma_legacy[_param_9_{dtype=None, scale_shape=(3, 2), shape=(3, 2), shape_shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsGamma::test_gamma_legacy[_param_10_{dtype=None, scale_shape=(3, 2), shape=None, shape_shape=()}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsGamma::test_gamma_legacy[_param_11_{dtype=None, scale_shape=(3, 2), shape=None, shape_shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsGeometric::test_geometric[_param_0_{dtype=None, p_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsGeometric::test_geometric[_param_1_{dtype=None, p_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsGeometric::test_geometric[_param_2_{dtype=None, p_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsGeometric::test_geometric[_param_3_{dtype=None, p_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsGumbel::test_gumbel[_param_0_{loc_shape=(), scale_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsGumbel::test_gumbel[_param_1_{loc_shape=(), scale_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsGumbel::test_gumbel[_param_2_{loc_shape=(), scale_shape=(), shape=None}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsGumbel::test_gumbel[_param_3_{loc_shape=(), scale_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsGumbel::test_gumbel[_param_4_{loc_shape=(), scale_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsGumbel::test_gumbel[_param_5_{loc_shape=(), scale_shape=(3, 2), shape=None}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsGumbel::test_gumbel[_param_6_{loc_shape=(3, 2), scale_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsGumbel::test_gumbel[_param_7_{loc_shape=(3, 2), scale_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsGumbel::test_gumbel[_param_8_{loc_shape=(3, 2), scale_shape=(), shape=None}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsGumbel::test_gumbel[_param_9_{loc_shape=(3, 2), scale_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsGumbel::test_gumbel[_param_10_{loc_shape=(3, 2), scale_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsGumbel::test_gumbel[_param_11_{loc_shape=(3, 2), scale_shape=(3, 2), shape=None}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsHyperGeometric::test_hypergeometric[_param_0_{dtype=None, nbad_shape=(), ngood_shape=(), nsample_dtype=int32, nsample_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsHyperGeometric::test_hypergeometric[_param_1_{dtype=None, nbad_shape=(), ngood_shape=(), nsample_dtype=int32, nsample_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsHyperGeometric::test_hypergeometric[_param_2_{dtype=None, nbad_shape=(), ngood_shape=(), nsample_dtype=int32, nsample_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsHyperGeometric::test_hypergeometric[_param_3_{dtype=None, nbad_shape=(), ngood_shape=(), nsample_dtype=int32, nsample_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsHyperGeometric::test_hypergeometric[_param_4_{dtype=None, nbad_shape=(), ngood_shape=(), nsample_dtype=int64, nsample_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsHyperGeometric::test_hypergeometric[_param_5_{dtype=None, nbad_shape=(), ngood_shape=(), nsample_dtype=int64, nsample_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsHyperGeometric::test_hypergeometric[_param_6_{dtype=None, nbad_shape=(), ngood_shape=(), nsample_dtype=int64, nsample_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsHyperGeometric::test_hypergeometric[_param_7_{dtype=None, nbad_shape=(), ngood_shape=(), nsample_dtype=int64, nsample_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsHyperGeometric::test_hypergeometric[_param_8_{dtype=None, nbad_shape=(), ngood_shape=(3, 2), nsample_dtype=int32, nsample_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsHyperGeometric::test_hypergeometric[_param_9_{dtype=None, nbad_shape=(), ngood_shape=(3, 2), nsample_dtype=int32, nsample_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsHyperGeometric::test_hypergeometric[_param_10_{dtype=None, nbad_shape=(), ngood_shape=(3, 2), nsample_dtype=int32, nsample_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsHyperGeometric::test_hypergeometric[_param_11_{dtype=None, nbad_shape=(), ngood_shape=(3, 2), nsample_dtype=int32, nsample_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsHyperGeometric::test_hypergeometric[_param_12_{dtype=None, nbad_shape=(), ngood_shape=(3, 2), nsample_dtype=int64, nsample_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsHyperGeometric::test_hypergeometric[_param_13_{dtype=None, nbad_shape=(), ngood_shape=(3, 2), nsample_dtype=int64, nsample_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsHyperGeometric::test_hypergeometric[_param_14_{dtype=None, nbad_shape=(), ngood_shape=(3, 2), nsample_dtype=int64, nsample_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsHyperGeometric::test_hypergeometric[_param_15_{dtype=None, nbad_shape=(), ngood_shape=(3, 2), nsample_dtype=int64, nsample_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsHyperGeometric::test_hypergeometric[_param_16_{dtype=None, nbad_shape=(3, 2), ngood_shape=(), nsample_dtype=int32, nsample_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsHyperGeometric::test_hypergeometric[_param_17_{dtype=None, nbad_shape=(3, 2), ngood_shape=(), nsample_dtype=int32, nsample_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsHyperGeometric::test_hypergeometric[_param_18_{dtype=None, nbad_shape=(3, 2), ngood_shape=(), nsample_dtype=int32, nsample_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsHyperGeometric::test_hypergeometric[_param_19_{dtype=None, nbad_shape=(3, 2), ngood_shape=(), nsample_dtype=int32, nsample_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsHyperGeometric::test_hypergeometric[_param_20_{dtype=None, nbad_shape=(3, 2), ngood_shape=(), nsample_dtype=int64, nsample_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsHyperGeometric::test_hypergeometric[_param_21_{dtype=None, nbad_shape=(3, 2), ngood_shape=(), nsample_dtype=int64, nsample_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsHyperGeometric::test_hypergeometric[_param_22_{dtype=None, nbad_shape=(3, 2), ngood_shape=(), nsample_dtype=int64, nsample_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsHyperGeometric::test_hypergeometric[_param_23_{dtype=None, nbad_shape=(3, 2), ngood_shape=(), nsample_dtype=int64, nsample_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsHyperGeometric::test_hypergeometric[_param_24_{dtype=None, nbad_shape=(3, 2), ngood_shape=(3, 2), nsample_dtype=int32, nsample_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsHyperGeometric::test_hypergeometric[_param_25_{dtype=None, nbad_shape=(3, 2), ngood_shape=(3, 2), nsample_dtype=int32, nsample_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsHyperGeometric::test_hypergeometric[_param_26_{dtype=None, nbad_shape=(3, 2), ngood_shape=(3, 2), nsample_dtype=int32, nsample_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsHyperGeometric::test_hypergeometric[_param_27_{dtype=None, nbad_shape=(3, 2), ngood_shape=(3, 2), nsample_dtype=int32, nsample_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsHyperGeometric::test_hypergeometric[_param_28_{dtype=None, nbad_shape=(3, 2), ngood_shape=(3, 2), nsample_dtype=int64, nsample_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsHyperGeometric::test_hypergeometric[_param_29_{dtype=None, nbad_shape=(3, 2), ngood_shape=(3, 2), nsample_dtype=int64, nsample_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsHyperGeometric::test_hypergeometric[_param_30_{dtype=None, nbad_shape=(3, 2), ngood_shape=(3, 2), nsample_dtype=int64, nsample_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsHyperGeometric::test_hypergeometric[_param_31_{dtype=None, nbad_shape=(3, 2), ngood_shape=(3, 2), nsample_dtype=int64, nsample_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsuLaplace::test_laplace[_param_0_{loc_shape=(), scale_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsuLaplace::test_laplace[_param_1_{loc_shape=(), scale_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsuLaplace::test_laplace[_param_2_{loc_shape=(), scale_shape=(), shape=None}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsuLaplace::test_laplace[_param_3_{loc_shape=(), scale_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsuLaplace::test_laplace[_param_4_{loc_shape=(), scale_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsuLaplace::test_laplace[_param_5_{loc_shape=(), scale_shape=(3, 2), shape=None}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsuLaplace::test_laplace[_param_6_{loc_shape=(3, 2), scale_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsuLaplace::test_laplace[_param_7_{loc_shape=(3, 2), scale_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsuLaplace::test_laplace[_param_8_{loc_shape=(3, 2), scale_shape=(), shape=None}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsuLaplace::test_laplace[_param_9_{loc_shape=(3, 2), scale_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsuLaplace::test_laplace[_param_10_{loc_shape=(3, 2), scale_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsuLaplace::test_laplace[_param_11_{loc_shape=(3, 2), scale_shape=(3, 2), shape=None}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsLogistic::test_logistic[_param_0_{loc_shape=(), scale_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsLogistic::test_logistic[_param_1_{loc_shape=(), scale_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsLogistic::test_logistic[_param_2_{loc_shape=(), scale_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsLogistic::test_logistic[_param_3_{loc_shape=(), scale_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsLogistic::test_logistic[_param_4_{loc_shape=(3, 2), scale_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsLogistic::test_logistic[_param_5_{loc_shape=(3, 2), scale_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsLogistic::test_logistic[_param_6_{loc_shape=(3, 2), scale_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsLogistic::test_logistic[_param_7_{loc_shape=(3, 2), scale_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsLognormal::test_lognormal[_param_0_{mean_shape=(), shape=(4, 3, 2), sigma_shape=()}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsLognormal::test_lognormal[_param_1_{mean_shape=(), shape=(4, 3, 2), sigma_shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsLognormal::test_lognormal[_param_2_{mean_shape=(), shape=(3, 2), sigma_shape=()}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsLognormal::test_lognormal[_param_3_{mean_shape=(), shape=(3, 2), sigma_shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsLognormal::test_lognormal[_param_4_{mean_shape=(), shape=None, sigma_shape=()}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsLognormal::test_lognormal[_param_5_{mean_shape=(), shape=None, sigma_shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsLognormal::test_lognormal[_param_6_{mean_shape=(3, 2), shape=(4, 3, 2), sigma_shape=()}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsLognormal::test_lognormal[_param_7_{mean_shape=(3, 2), shape=(4, 3, 2), sigma_shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsLognormal::test_lognormal[_param_8_{mean_shape=(3, 2), shape=(3, 2), sigma_shape=()}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsLognormal::test_lognormal[_param_9_{mean_shape=(3, 2), shape=(3, 2), sigma_shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsLognormal::test_lognormal[_param_10_{mean_shape=(3, 2), shape=None, sigma_shape=()}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsLognormal::test_lognormal[_param_11_{mean_shape=(3, 2), shape=None, sigma_shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsNegativeBinomial::test_negative_binomial[_param_0_{dtype=None, n_shape=(), p_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsNegativeBinomial::test_negative_binomial[_param_1_{dtype=None, n_shape=(), p_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsNegativeBinomial::test_negative_binomial[_param_2_{dtype=None, n_shape=(), p_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsNegativeBinomial::test_negative_binomial[_param_3_{dtype=None, n_shape=(), p_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsNegativeBinomial::test_negative_binomial[_param_4_{dtype=None, n_shape=(3, 2), p_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsNegativeBinomial::test_negative_binomial[_param_5_{dtype=None, n_shape=(3, 2), p_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsNegativeBinomial::test_negative_binomial[_param_6_{dtype=None, n_shape=(3, 2), p_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsNegativeBinomial::test_negative_binomial[_param_7_{dtype=None, n_shape=(3, 2), p_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsNegativeBinomial::test_negative_binomial_for_noninteger_n[_param_0_{dtype=None, n_shape=(), p_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsNegativeBinomial::test_negative_binomial_for_noninteger_n[_param_1_{dtype=None, n_shape=(), p_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsNegativeBinomial::test_negative_binomial_for_noninteger_n[_param_2_{dtype=None, n_shape=(), p_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsNegativeBinomial::test_negative_binomial_for_noninteger_n[_param_3_{dtype=None, n_shape=(), p_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsNegativeBinomial::test_negative_binomial_for_noninteger_n[_param_4_{dtype=None, n_shape=(3, 2), p_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsNegativeBinomial::test_negative_binomial_for_noninteger_n[_param_5_{dtype=None, n_shape=(3, 2), p_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsNegativeBinomial::test_negative_binomial_for_noninteger_n[_param_6_{dtype=None, n_shape=(3, 2), p_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsNegativeBinomial::test_negative_binomial_for_noninteger_n[_param_7_{dtype=None, n_shape=(3, 2), p_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsNoncentralChisquare::test_noncentral_chisquare[_param_0_{df_shape=(), dtype=None, nonc_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsNoncentralChisquare::test_noncentral_chisquare[_param_1_{df_shape=(), dtype=None, nonc_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsNoncentralChisquare::test_noncentral_chisquare[_param_2_{df_shape=(), dtype=None, nonc_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsNoncentralChisquare::test_noncentral_chisquare[_param_3_{df_shape=(), dtype=None, nonc_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsNoncentralChisquare::test_noncentral_chisquare[_param_4_{df_shape=(3, 2), dtype=None, nonc_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsNoncentralChisquare::test_noncentral_chisquare[_param_5_{df_shape=(3, 2), dtype=None, nonc_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsNoncentralChisquare::test_noncentral_chisquare[_param_6_{df_shape=(3, 2), dtype=None, nonc_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsNoncentralChisquare::test_noncentral_chisquare[_param_7_{df_shape=(3, 2), dtype=None, nonc_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsNoncentralChisquare::test_noncentral_chisquare_for_invalid_params[_param_0_{df_shape=(), dtype=None, nonc_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsNoncentralChisquare::test_noncentral_chisquare_for_invalid_params[_param_1_{df_shape=(), dtype=None, nonc_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsNoncentralChisquare::test_noncentral_chisquare_for_invalid_params[_param_2_{df_shape=(), dtype=None, nonc_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsNoncentralChisquare::test_noncentral_chisquare_for_invalid_params[_param_3_{df_shape=(), dtype=None, nonc_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsNoncentralChisquare::test_noncentral_chisquare_for_invalid_params[_param_4_{df_shape=(3, 2), dtype=None, nonc_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsNoncentralChisquare::test_noncentral_chisquare_for_invalid_params[_param_5_{df_shape=(3, 2), dtype=None, nonc_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsNoncentralChisquare::test_noncentral_chisquare_for_invalid_params[_param_6_{df_shape=(3, 2), dtype=None, nonc_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsNoncentralChisquare::test_noncentral_chisquare_for_invalid_params[_param_7_{df_shape=(3, 2), dtype=None, nonc_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsNormal::test_normal[_param_0_{loc_shape=(), scale_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsNormal::test_normal[_param_1_{loc_shape=(), scale_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsNormal::test_normal[_param_2_{loc_shape=(), scale_shape=(), shape=None}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsNormal::test_normal[_param_3_{loc_shape=(), scale_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsNormal::test_normal[_param_4_{loc_shape=(), scale_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsNormal::test_normal[_param_5_{loc_shape=(), scale_shape=(3, 2), shape=None}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsNormal::test_normal[_param_6_{loc_shape=(3, 2), scale_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsNormal::test_normal[_param_7_{loc_shape=(3, 2), scale_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsNormal::test_normal[_param_8_{loc_shape=(3, 2), scale_shape=(), shape=None}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsNormal::test_normal[_param_9_{loc_shape=(3, 2), scale_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsNormal::test_normal[_param_10_{loc_shape=(3, 2), scale_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsNormal::test_normal[_param_11_{loc_shape=(3, 2), scale_shape=(3, 2), shape=None}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsPareto::test_pareto[_param_0_{a_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsPareto::test_pareto[_param_1_{a_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsPareto::test_pareto[_param_2_{a_shape=(), shape=None}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsPareto::test_pareto[_param_3_{a_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsPareto::test_pareto[_param_4_{a_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsPareto::test_pareto[_param_5_{a_shape=(3, 2), shape=None}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsPoisson::test_poisson_legacy[_param_0_{lam_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsPoisson::test_poisson_legacy[_param_1_{lam_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsPoisson::test_poisson_legacy[_param_2_{lam_shape=(), shape=None}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsPoisson::test_poisson_legacy[_param_3_{lam_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsPoisson::test_poisson_legacy[_param_4_{lam_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsPoisson::test_poisson_legacy[_param_5_{lam_shape=(3, 2), shape=None}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsPoissonInvalid::test_none_lam_legacy -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsPower::test_power[_param_0_{a_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsPower::test_power[_param_1_{a_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsPower::test_power_for_negative_a[_param_0_{a_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsPower::test_power_for_negative_a[_param_1_{a_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsRayleigh::test_rayleigh[_param_0_{scale_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsRayleigh::test_rayleigh[_param_1_{scale_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsRayleigh::test_rayleigh[_param_2_{scale_shape=(), shape=None}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsRayleigh::test_rayleigh[_param_3_{scale_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsRayleigh::test_rayleigh[_param_4_{scale_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsRayleigh::test_rayleigh[_param_5_{scale_shape=(3, 2), shape=None}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsRayleigh::test_rayleigh_for_zero_scale[_param_0_{scale_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsRayleigh::test_rayleigh_for_zero_scale[_param_1_{scale_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsRayleigh::test_rayleigh_for_zero_scale[_param_2_{scale_shape=(), shape=None}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsRayleigh::test_rayleigh_for_zero_scale[_param_3_{scale_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsRayleigh::test_rayleigh_for_zero_scale[_param_4_{scale_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsRayleigh::test_rayleigh_for_zero_scale[_param_5_{scale_shape=(3, 2), shape=None}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsRayleigh::test_rayleigh_for_negative_scale[_param_0_{scale_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsRayleigh::test_rayleigh_for_negative_scale[_param_1_{scale_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsRayleigh::test_rayleigh_for_negative_scale[_param_2_{scale_shape=(), shape=None}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsRayleigh::test_rayleigh_for_negative_scale[_param_3_{scale_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsRayleigh::test_rayleigh_for_negative_scale[_param_4_{scale_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsRayleigh::test_rayleigh_for_negative_scale[_param_5_{scale_shape=(3, 2), shape=None}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsStandardCauchy::test_standard_cauchy[_param_0_{shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsStandardCauchy::test_standard_cauchy[_param_1_{shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsStandardExponential::test_standard_exponential[_param_0_{shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsStandardExponential::test_standard_exponential[_param_1_{shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsStandardExponential::test_standard_exponential[_param_2_{shape=None}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsStandardGamma::test_standard_gamma_legacy[_param_0_{shape=(4, 3, 2), shape_shape=()}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsStandardGamma::test_standard_gamma_legacy[_param_1_{shape=(4, 3, 2), shape_shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsStandardGamma::test_standard_gamma_legacy[_param_2_{shape=(3, 2), shape_shape=()}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsStandardGamma::test_standard_gamma_legacy[_param_3_{shape=(3, 2), shape_shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsStandardGamma::test_standard_gamma_legacy[_param_4_{shape=None, shape_shape=()}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsStandardGamma::test_standard_gamma_legacy[_param_5_{shape=None, shape_shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsStandardGammaInvalid::test_none_shape_legacy -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsStandardNormal::test_standard_normal[_param_0_{shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsStandardNormal::test_standard_normal[_param_1_{shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsStandardNormal::test_standard_normal[_param_2_{shape=None}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsStandardT::test_standard_t[_param_0_{df_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsStandardT::test_standard_t[_param_1_{df_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsStandardT::test_standard_t[_param_2_{df_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsStandardT::test_standard_t[_param_3_{df_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsTriangular::test_triangular[_param_0_{dtype=None, left_shape=(), mode_shape=(), right_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsTriangular::test_triangular[_param_1_{dtype=None, left_shape=(), mode_shape=(), right_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsTriangular::test_triangular[_param_2_{dtype=None, left_shape=(), mode_shape=(), right_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsTriangular::test_triangular[_param_3_{dtype=None, left_shape=(), mode_shape=(), right_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsTriangular::test_triangular[_param_4_{dtype=None, left_shape=(), mode_shape=(3, 2), right_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsTriangular::test_triangular[_param_5_{dtype=None, left_shape=(), mode_shape=(3, 2), right_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsTriangular::test_triangular[_param_6_{dtype=None, left_shape=(), mode_shape=(3, 2), right_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsTriangular::test_triangular[_param_7_{dtype=None, left_shape=(), mode_shape=(3, 2), right_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsTriangular::test_triangular[_param_8_{dtype=None, left_shape=(3, 2), mode_shape=(), right_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsTriangular::test_triangular[_param_9_{dtype=None, left_shape=(3, 2), mode_shape=(), right_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsTriangular::test_triangular[_param_10_{dtype=None, left_shape=(3, 2), mode_shape=(), right_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsTriangular::test_triangular[_param_11_{dtype=None, left_shape=(3, 2), mode_shape=(), right_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsTriangular::test_triangular[_param_12_{dtype=None, left_shape=(3, 2), mode_shape=(3, 2), right_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsTriangular::test_triangular[_param_13_{dtype=None, left_shape=(3, 2), mode_shape=(3, 2), right_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsTriangular::test_triangular[_param_14_{dtype=None, left_shape=(3, 2), mode_shape=(3, 2), right_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsTriangular::test_triangular[_param_15_{dtype=None, left_shape=(3, 2), mode_shape=(3, 2), right_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsTriangular::test_triangular_for_invalid_params[_param_0_{dtype=None, left_shape=(), mode_shape=(), right_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsTriangular::test_triangular_for_invalid_params[_param_1_{dtype=None, left_shape=(), mode_shape=(), right_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsTriangular::test_triangular_for_invalid_params[_param_2_{dtype=None, left_shape=(), mode_shape=(), right_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsTriangular::test_triangular_for_invalid_params[_param_3_{dtype=None, left_shape=(), mode_shape=(), right_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsTriangular::test_triangular_for_invalid_params[_param_4_{dtype=None, left_shape=(), mode_shape=(3, 2), right_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsTriangular::test_triangular_for_invalid_params[_param_5_{dtype=None, left_shape=(), mode_shape=(3, 2), right_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsTriangular::test_triangular_for_invalid_params[_param_6_{dtype=None, left_shape=(), mode_shape=(3, 2), right_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsTriangular::test_triangular_for_invalid_params[_param_7_{dtype=None, left_shape=(), mode_shape=(3, 2), right_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsTriangular::test_triangular_for_invalid_params[_param_8_{dtype=None, left_shape=(3, 2), mode_shape=(), right_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsTriangular::test_triangular_for_invalid_params[_param_9_{dtype=None, left_shape=(3, 2), mode_shape=(), right_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsTriangular::test_triangular_for_invalid_params[_param_10_{dtype=None, left_shape=(3, 2), mode_shape=(), right_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsTriangular::test_triangular_for_invalid_params[_param_11_{dtype=None, left_shape=(3, 2), mode_shape=(), right_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsTriangular::test_triangular_for_invalid_params[_param_12_{dtype=None, left_shape=(3, 2), mode_shape=(3, 2), right_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsTriangular::test_triangular_for_invalid_params[_param_13_{dtype=None, left_shape=(3, 2), mode_shape=(3, 2), right_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsTriangular::test_triangular_for_invalid_params[_param_14_{dtype=None, left_shape=(3, 2), mode_shape=(3, 2), right_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsTriangular::test_triangular_for_invalid_params[_param_15_{dtype=None, left_shape=(3, 2), mode_shape=(3, 2), right_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsUniform::test_uniform[_param_0_{high_shape=(), low_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsUniform::test_uniform[_param_1_{high_shape=(), low_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsUniform::test_uniform[_param_2_{high_shape=(), low_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsUniform::test_uniform[_param_3_{high_shape=(), low_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsUniform::test_uniform[_param_4_{high_shape=(3, 2), low_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsUniform::test_uniform[_param_5_{high_shape=(3, 2), low_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsUniform::test_uniform[_param_6_{high_shape=(3, 2), low_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsUniform::test_uniform[_param_7_{high_shape=(3, 2), low_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsVonmises::test_vonmises[_param_0_{dtype=None, kappa_shape=(), mu_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsVonmises::test_vonmises[_param_1_{dtype=None, kappa_shape=(), mu_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsVonmises::test_vonmises[_param_2_{dtype=None, kappa_shape=(), mu_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsVonmises::test_vonmises[_param_3_{dtype=None, kappa_shape=(), mu_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsVonmises::test_vonmises[_param_4_{dtype=None, kappa_shape=(3, 2), mu_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsVonmises::test_vonmises[_param_5_{dtype=None, kappa_shape=(3, 2), mu_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsVonmises::test_vonmises[_param_6_{dtype=None, kappa_shape=(3, 2), mu_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsVonmises::test_vonmises[_param_7_{dtype=None, kappa_shape=(3, 2), mu_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsWald::test_wald[_param_0_{dtype=None, mean_shape=(), scale_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsWald::test_wald[_param_1_{dtype=None, mean_shape=(), scale_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsWald::test_wald[_param_2_{dtype=None, mean_shape=(), scale_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsWald::test_wald[_param_3_{dtype=None, mean_shape=(), scale_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsWald::test_wald[_param_4_{dtype=None, mean_shape=(3, 2), scale_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsWald::test_wald[_param_5_{dtype=None, mean_shape=(3, 2), scale_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsWald::test_wald[_param_6_{dtype=None, mean_shape=(3, 2), scale_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsWald::test_wald[_param_7_{dtype=None, mean_shape=(3, 2), scale_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsWeibull::test_weibull[_param_0_{a_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsWeibull::test_weibull[_param_1_{a_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsWeibull::test_weibull[_param_2_{a_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsWeibull::test_weibull[_param_3_{a_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsWeibull::test_weibull_for_inf_a[_param_0_{a_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsWeibull::test_weibull_for_inf_a[_param_1_{a_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsWeibull::test_weibull_for_inf_a[_param_2_{a_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsWeibull::test_weibull_for_inf_a[_param_3_{a_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsWeibull::test_weibull_for_negative_a[_param_0_{a_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsWeibull::test_weibull_for_negative_a[_param_1_{a_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsWeibull::test_weibull_for_negative_a[_param_2_{a_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsWeibull::test_weibull_for_negative_a[_param_3_{a_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsZipf::test_zipf[_param_0_{a_shape=(), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsZipf::test_zipf[_param_1_{a_shape=(), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsZipf::test_zipf[_param_2_{a_shape=(3, 2), shape=(4, 3, 2)}] -tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsZipf::test_zipf[_param_3_{a_shape=(3, 2), shape=(3, 2)}] -tests/third_party/cupy/random_tests/test_permutations.py::TestPermutations_param_0_{seed=None}::test_permutation_seed1 -tests/third_party/cupy/random_tests/test_permutations.py::TestPermutations_param_0_{seed=None}::test_permutation_sort_1dim -tests/third_party/cupy/random_tests/test_permutations.py::TestPermutations_param_0_{seed=None}::test_permutation_sort_ndim -tests/third_party/cupy/random_tests/test_permutations.py::TestShuffle::test_shuffle_seed1 -tests/third_party/cupy/random_tests/test_permutations.py::TestShuffle::test_shuffle_sort_1dim -tests/third_party/cupy/random_tests/test_permutations.py::TestShuffle::test_shuffle_sort_ndim -tests/third_party/cupy/random_tests/test_permutations.py::TestPermutationSoundness_param_0_{num=0}::test_permutation_soundness -tests/third_party/cupy/random_tests/test_permutations.py::TestPermutationSoundness_param_1_{num=1}::test_permutation_soundness -tests/third_party/cupy/random_tests/test_permutations.py::TestPermutationSoundness_param_2_{num=100}::test_permutation_soundness -tests/third_party/cupy/random_tests/test_sample.py::TestRandint::test_lo_hi_equal -tests/third_party/cupy/random_tests/test_sample.py::TestRandint::test_lo_hi_nonrandom -tests/third_party/cupy/random_tests/test_sample.py::TestRandint::test_lo_hi_reversed -tests/third_party/cupy/random_tests/test_sample.py::TestRandint::test_zero_sizes -tests/third_party/cupy/random_tests/test_sample.py::TestRandint2::test_bound_1 -tests/third_party/cupy/random_tests/test_sample.py::TestRandint2::test_bound_2 -tests/third_party/cupy/random_tests/test_sample.py::TestRandint2::test_bound_float1 -tests/third_party/cupy/random_tests/test_sample.py::TestRandint2::test_bound_float2 -tests/third_party/cupy/random_tests/test_sample.py::TestRandint2::test_bound_overflow -tests/third_party/cupy/random_tests/test_sample.py::TestRandint2::test_goodness_of_fit -tests/third_party/cupy/random_tests/test_sample.py::TestRandint2::test_goodness_of_fit_2 -tests/third_party/cupy/random_tests/test_sample.py::TestRandomIntegers2::test_bound_1 -tests/third_party/cupy/random_tests/test_sample.py::TestRandomIntegers2::test_bound_2 -tests/third_party/cupy/random_tests/test_sample.py::TestRandomIntegers2::test_goodness_of_fit -tests/third_party/cupy/random_tests/test_sample.py::TestRandomIntegers2::test_goodness_of_fit_2 diff --git a/dpnp/tests/skipped_tests_gpu.tbl b/dpnp/tests/skipped_tests_gpu.tbl index c67e09ad8e23..e69de29bb2d1 100644 --- a/dpnp/tests/skipped_tests_gpu.tbl +++ b/dpnp/tests/skipped_tests_gpu.tbl @@ -1,18 +0,0 @@ -tests/test_random.py::TestDistributionsMultivariateNormal::test_moments -tests/test_random.py::TestDistributionsMultivariateNormal::test_output_shape_check -tests/test_random.py::TestDistributionsMultivariateNormal::test_seed -tests/test_random.py::TestPermutationsTestShuffle::test_shuffle[float32] -tests/test_random.py::TestPermutationsTestShuffle::test_shuffle[float64] -tests/test_random.py::TestPermutationsTestShuffle::test_shuffle[int32] -tests/test_random.py::TestPermutationsTestShuffle::test_shuffle[int64] -tests/test_random.py::TestPermutationsTestShuffle::test_no_miss_numbers[float32] -tests/test_random.py::TestPermutationsTestShuffle::test_no_miss_numbers[float64] -tests/test_random.py::TestPermutationsTestShuffle::test_no_miss_numbers[int32] -tests/test_random.py::TestPermutationsTestShuffle::test_no_miss_numbers[int64] -tests/test_random.py::TestPermutationsTestShuffle::test_shuffle1[lambda x: dpnp.asarray(x).astype(dpnp.complex64)] -tests/test_random.py::TestPermutationsTestShuffle::test_shuffle1[lambda x: dpnp.astype(dpnp.asarray(x), dpnp.int8)] -tests/test_random.py::TestPermutationsTestShuffle::test_shuffle1[lambda x: dpnp.astype(dpnp.asarray(x), object)] -tests/test_random.py::TestPermutationsTestShuffle::test_shuffle1[lambda x: dpnp.vstack([x, x]).T] -tests/test_random.py::TestPermutationsTestShuffle::test_shuffle1[lambda x: (dpnp.asarray([(i, i) for i in x], [("a", int), ("b", int)]).view(dpnp.recarray))] -tests/test_random.py::TestPermutationsTestShuffle::test_shuffle1[lambda x: dpnp.asarray([(i, i) for i in x], [("a", object), ("b", dpnp.int32)])]] -tests/test_random.py::TestPermutationsTestShuffle::test_shuffle1[lambda x: dpnp.asarray(x).astype(dpnp.int8)] diff --git a/dpnp/tests/test_random.py b/dpnp/tests/test_random.py index 656ffe67e2fe..373eef5fc560 100644 --- a/dpnp/tests/test_random.py +++ b/dpnp/tests/test_random.py @@ -6,7 +6,7 @@ import dpnp.random -from .helper import has_support_aspect64 +from .helper import get_all_dtypes, has_support_aspect64 class TestDistribution(unittest.TestCase): @@ -16,7 +16,7 @@ def check_extreme_value(self, dist_name, val, params): dpnp.random.seed(seed) res = dpnp.asnumpy(getattr(dpnp.random, dist_name)(size=size, **params)) assert len(numpy.unique(res)) == 1 - assert numpy.unique(res)[0] == val + assert numpy.isclose(numpy.unique(res)[0], val, rtol=1e-15, atol=0) def check_moments( self, dist_name, expected_mean, expected_var, params, size=10**5 @@ -151,7 +151,6 @@ def test_randn_normal_distribution(): @pytest.mark.skipif(not has_support_aspect64(), reason="Failed on Iris Xe") -@pytest.mark.usefixtures("allow_fall_back_on_numpy") class TestDistributionsBeta(TestDistribution): def test_moments(self): a = 2.56 @@ -177,7 +176,6 @@ def test_seed(self): @pytest.mark.skipif(not has_support_aspect64(), reason="Failed on Iris Xe") -@pytest.mark.usefixtures("allow_fall_back_on_numpy") class TestDistributionsBinomial(TestDistribution): def test_extreme_value(self): n = 5 @@ -216,7 +214,6 @@ def test_seed(self): @pytest.mark.skipif(not has_support_aspect64(), reason="Failed on Iris Xe") -@pytest.mark.usefixtures("allow_fall_back_on_numpy") class TestDistributionsChisquare(TestDistribution): def test_invalid_args(self): df = -1 # positive `df` is expected @@ -228,7 +225,6 @@ def test_seed(self): @pytest.mark.skipif(not has_support_aspect64(), reason="Failed on Iris Xe") -@pytest.mark.usefixtures("allow_fall_back_on_numpy") class TestDistributionsExponential(TestDistribution): def test_invalid_args(self): scale = -1 # non-negative `scale` is expected @@ -240,7 +236,6 @@ def test_seed(self): @pytest.mark.skipif(not has_support_aspect64(), reason="Failed on Iris Xe") -@pytest.mark.usefixtures("allow_fall_back_on_numpy") class TestDistributionsF(TestDistribution): def test_moments(self): dfnum = 12.56 @@ -274,7 +269,6 @@ def test_seed(self): @pytest.mark.skipif(not has_support_aspect64(), reason="Failed on Iris Xe") -@pytest.mark.usefixtures("allow_fall_back_on_numpy") class TestDistributionsGamma(TestDistribution): def test_moments(self): shape = 2.56 @@ -301,7 +295,6 @@ def test_seed(self): self.check_seed("gamma", {"shape": shape}) -@pytest.mark.usefixtures("allow_fall_back_on_numpy") class TestDistributionsGeometric(TestDistribution): def test_extreme_value(self): p = 1.0 @@ -310,7 +303,8 @@ def test_extreme_value(self): def test_moments(self): p = 0.8 - expected_mean = (1 - p) / p + # the number of trials up to and including the first success + expected_mean = 1 / p expected_var = (1 - p) / (p**2) self.check_moments("geometric", expected_mean, expected_var, {"p": p}) @@ -325,7 +319,6 @@ def test_seed(self): @pytest.mark.skipif(not has_support_aspect64(), reason="Failed on Iris Xe") -@pytest.mark.usefixtures("allow_fall_back_on_numpy") class TestDistributionsGumbel(TestDistribution): def test_extreme_value(self): loc = 5 @@ -357,7 +350,6 @@ def test_seed(self): @pytest.mark.skipif(not has_support_aspect64(), reason="Failed on Iris Xe") -@pytest.mark.usefixtures("allow_fall_back_on_numpy") class TestDistributionsHypergeometric(TestDistribution): def test_extreme_value(self): ngood = 100 @@ -444,12 +436,11 @@ def test_seed(self): @pytest.mark.skipif(not has_support_aspect64(), reason="Failed on Iris Xe") -@pytest.mark.usefixtures("allow_fall_back_on_numpy") class TestDistributionsLaplace(TestDistribution): def test_extreme_value(self): loc = 5 scale = 0.0 - expected_val = scale + expected_val = loc self.check_extreme_value( "laplace", expected_val, {"loc": loc, "scale": scale} ) @@ -475,7 +466,6 @@ def test_seed(self): @pytest.mark.skipif(not has_support_aspect64(), reason="Failed on Iris Xe") -@pytest.mark.usefixtures("allow_fall_back_on_numpy") class TestDistributionsLogistic(TestDistribution): def test_moments(self): loc = 2.56 @@ -501,7 +491,6 @@ def test_seed(self): @pytest.mark.skipif(not has_support_aspect64(), reason="Failed on Iris Xe") -@pytest.mark.usefixtures("allow_fall_back_on_numpy") class TestDistributionsLognormal(TestDistribution): def test_extreme_value(self): mean = 0.5 @@ -537,7 +526,6 @@ def test_seed(self): @pytest.mark.skipif(not has_support_aspect64(), reason="Failed on Iris Xe") -@pytest.mark.usefixtures("allow_fall_back_on_numpy") class TestDistributionsMultinomial(TestDistribution): def test_extreme_value(self): n = 0 @@ -586,7 +574,6 @@ def test_seed1(self): self.check_seed("multinomial", {"n": n, "pvals": pvals}) -@pytest.mark.usefixtures("allow_fall_back_on_numpy") class TestDistributionsMultivariateNormal(TestDistribution): def test_moments(self): seed = 2804183 @@ -595,8 +582,8 @@ def test_moments(self): cov = [[1, 0], [0, 1]] size = 10**5 res = dpnp.random.multivariate_normal(mean=mean, cov=cov, size=size) - res_mean = [dpnp.mean(res.T[0]), dpnp.mean(res.T[1])] - assert dpnp.allclose(res_mean, mean) + # six standard deviations of the sample mean + assert_allclose(dpnp.mean(res, axis=0), mean, atol=6 / size**0.5) def test_invalid_args(self): mean = [2.56, 3.23] # OK @@ -632,7 +619,6 @@ def test_seed(self): @pytest.mark.skipif(not has_support_aspect64(), reason="Failed on Iris Xe") -@pytest.mark.usefixtures("allow_fall_back_on_numpy") class TestDistributionsNegativeBinomial(TestDistribution): def test_extreme_value(self): seed = 28041990 @@ -694,7 +680,6 @@ def test_seed(self): @pytest.mark.skipif(not has_support_aspect64(), reason="Failed on Iris Xe") -@pytest.mark.usefixtures("allow_fall_back_on_numpy") class TestDistributionsNoncentralChisquare: @pytest.mark.parametrize( "df", [5.0, 1.0, 0.5], ids=["df_grt_1", "df_eq_1", "df_less_1"] @@ -738,11 +723,11 @@ def test_seed(self, df): @pytest.mark.skipif(not has_support_aspect64(), reason="Failed on Iris Xe") -@pytest.mark.usefixtures("allow_fall_back_on_numpy") class TestDistributionsPareto(TestDistribution): def test_moments(self): + # Pareto II (Lomax) a = 30.0 - expected_mean = a / (a - 1) + expected_mean = 1 / (a - 1) expected_var = a / (((a - 1) ** 2) * (a - 2)) self.check_moments("pareto", expected_mean, expected_var, {"a": a}) @@ -757,7 +742,6 @@ def test_seed(self): @pytest.mark.skipif(not has_support_aspect64(), reason="Failed on Iris Xe") -@pytest.mark.usefixtures("allow_fall_back_on_numpy") class TestDistributionsPoisson(TestDistribution): def test_extreme_value(self): lam = 0.0 @@ -779,7 +763,6 @@ def test_seed(self): @pytest.mark.skipif(not has_support_aspect64(), reason="Failed on Iris Xe") -@pytest.mark.usefixtures("allow_fall_back_on_numpy") class TestDistributionsPower(TestDistribution): def test_moments(self): a = 30.0 @@ -799,7 +782,6 @@ def test_seed(self): @pytest.mark.skipif(not has_support_aspect64(), reason="Failed on Iris Xe") -@pytest.mark.usefixtures("allow_fall_back_on_numpy") class TestDistributionsRayleigh(TestDistribution): def test_extreme_value(self): scale = 0.0 @@ -841,7 +823,6 @@ def test_seed(self): @pytest.mark.skipif(not has_support_aspect64(), reason="Failed on Iris Xe") -@pytest.mark.usefixtures("allow_fall_back_on_numpy") class TestDistributionsStandardGamma(TestDistribution): def test_extreme_value(self): self.check_extreme_value("standard_gamma", 0.0, {"shape": 0.0}) @@ -873,7 +854,6 @@ def test_seed(self): @pytest.mark.skipif(not has_support_aspect64(), reason="Failed on Iris Xe") -@pytest.mark.usefixtures("allow_fall_back_on_numpy") class TestDistributionsStandardT(TestDistribution): def test_moments(self): df = 300.0 @@ -892,7 +872,6 @@ def test_seed(self): @pytest.mark.skipif(not has_support_aspect64(), reason="Failed on Iris Xe") -@pytest.mark.usefixtures("allow_fall_back_on_numpy") class TestDistributionsTriangular(TestDistribution): def test_moments(self): left = 1.0 @@ -964,7 +943,6 @@ def test_seed(self): @pytest.mark.skipif(not has_support_aspect64(), reason="Failed on Iris Xe") -@pytest.mark.usefixtures("allow_fall_back_on_numpy") class TestDistributionsVonmises: @pytest.mark.parametrize( "kappa", [5.0, 0.5], ids=["large_kappa", "small_kappa"] @@ -1005,7 +983,6 @@ def test_seed(self, kappa): @pytest.mark.skipif(not has_support_aspect64(), reason="Failed on Iris Xe") -@pytest.mark.usefixtures("allow_fall_back_on_numpy") class TestDistributionsWald(TestDistribution): def test_moments(self): size = 5 * 10**6 @@ -1037,7 +1014,6 @@ def test_seed(self): @pytest.mark.skipif(not has_support_aspect64(), reason="Failed on Iris Xe") -@pytest.mark.usefixtures("allow_fall_back_on_numpy") class TestDistributionsWeibull(TestDistribution): def test_extreme_value(self): a = 0.0 @@ -1054,7 +1030,6 @@ def test_seed(self): @pytest.mark.skipif(not has_support_aspect64(), reason="Failed on Iris Xe") -@pytest.mark.usefixtures("allow_fall_back_on_numpy") class TestDistributionsZipf(TestDistribution): def test_invalid_args(self): a = 1.0 # parameter `a` is expected greater than 1. @@ -1067,7 +1042,7 @@ def test_seed(self): class TestPermutationsTestShuffle: @pytest.mark.parametrize( - "dtype", [dpnp.float32, dpnp.float64, dpnp.int32, dpnp.int64] + "dtype", get_all_dtypes(no_bool=True, no_complex=True, no_none=True) ) def test_shuffle(self, dtype): seed = 28041990 @@ -1084,7 +1059,7 @@ def test_shuffle(self, dtype): assert_array_equal(actual_x, desired_x) @pytest.mark.parametrize( - "dtype", [dpnp.float32, dpnp.float64, dpnp.int32, dpnp.int64] + "dtype", get_all_dtypes(no_bool=True, no_complex=True, no_none=True) ) def test_no_miss_numbers(self, dtype): seed = 28041990 @@ -1104,29 +1079,16 @@ def test_no_miss_numbers(self, dtype): lambda x: dpnp.astype(dpnp.asarray(x), dpnp.int8), lambda x: dpnp.astype(dpnp.asarray(x), dpnp.float32), lambda x: dpnp.asarray(x).astype(dpnp.complex64), - lambda x: dpnp.astype(dpnp.asarray(x), object), lambda x: dpnp.asarray([[i, i] for i in x]), - lambda x: dpnp.vstack([x, x]).T, - lambda x: ( - dpnp.asarray( - [(i, i) for i in x], [("a", int), ("b", int)] - ).view(dpnp.recarray) - ), - lambda x: dpnp.asarray( - [(i, i) for i in x], [("a", object), ("b", dpnp.int32)] - ), + lambda x: dpnp.vstack([dpnp.asarray(x), dpnp.asarray(x)]).T, ], ids=[ "lambda x: dpnp.array([])", "lambda x: dpnp.astype(dpnp.asarray(x), dpnp.int8)", "lambda x: dpnp.astype(dpnp.asarray(x), dpnp.float32)", "lambda x: dpnp.asarray(x).astype(dpnp.complex64)", - "lambda x: dpnp.astype(dpnp.asarray(x), object)", "lambda x: dpnp.asarray([[i, i] for i in x])", "lambda x: dpnp.vstack([x, x]).T", - "lambda x: (dpnp.asarray([(i, i) for i in x], [" - '("a", int), ("b", int)]).view(dpnp.recarray))', - 'lambda x: dpnp.asarray([(i, i) for i in x], [("a", object), ("b", dpnp.int32)])]', ], ) def test_shuffle1(self, conv): @@ -1156,25 +1118,10 @@ def test_shuffle1(self, conv): desired = conv(dpnp_1d) assert_array_equal(actual, desired) - @pytest.mark.usefixtures("allow_fall_back_on_numpy") @pytest.mark.parametrize( - "conv", - [lambda x: x, lambda x: [(i, i) for i in x]], - ids=[ - "lambda x: x", - "lambda x: [(i, i) for i in x]", - ], + "x", [[1, 2, 3], numpy.arange(3)], ids=["list", "numpy.ndarray"] ) - def test_shuffle1_fallback(self, conv): - # This is parameterized version of original tests of `numpy.random` (both the same): - # * tests/test_random.py::TestRandomDist::test_shuffle - # * tests/test_randomstate.py::TestRandomDist::test_shuffle - - seed = 1234567890 - - dpnp.random.seed(seed) - alist = conv([1, 2, 3, 4, 5, 6, 7, 8, 9, 0]) - dpnp.random.shuffle(alist) - actual = alist - desired = conv([0, 1, 9, 6, 2, 4, 5, 8, 7, 3]) - assert_array_equal(actual, desired) + def test_shuffle_not_dpnp_array(self, x): + # unlike NumPy, only a dpnp.ndarray is shuffled, like in CuPy + with pytest.raises(TypeError): + dpnp.random.shuffle(x) diff --git a/dpnp/tests/test_random_state.py b/dpnp/tests/test_random_state.py index 0c9c0a8b6017..5772cc218abf 100644 --- a/dpnp/tests/test_random_state.py +++ b/dpnp/tests/test_random_state.py @@ -1,1145 +1,837 @@ -from unittest import mock +import warnings import dpctl import numpy import pytest from numpy.testing import ( - assert_array_almost_equal, + assert_allclose, assert_array_equal, assert_equal, assert_raises, ) import dpnp -from dpnp.dpnp_array import dpnp_array from dpnp.random import RandomState -from .helper import ( - assert_dtype_allclose, - get_array, - is_cpu_device, - is_gpu_device, -) -from .third_party.cupy import testing - -# aspects of default device: -_def_device = dpctl.SyclQueue().sycl_device -_def_dev_has_fp64 = _def_device.has_aspect_fp64 +from .helper import get_all_dtypes, get_float_dtypes +from .test_random_generator import _assert_same_error +float_dtypes = get_float_dtypes(no_float16=True) list_of_usm_types = ["host", "device", "shared"] - -def assert_cfd(data, exp_sycl_queue, exp_usm_type=None): - assert exp_sycl_queue == data.sycl_queue - if exp_usm_type: - assert exp_usm_type == data.usm_type - - -def get_default_floating(): - if not _def_dev_has_fp64: - return dpnp.float32 - return dpnp.float64 - - -class TestNormal: - @pytest.mark.parametrize("dtype", [dpnp.float32, dpnp.float64, None]) - @pytest.mark.parametrize("usm_type", list_of_usm_types) - def test_distr(self, dtype, usm_type): - seed = 1234567 - sycl_queue = dpctl.SyclQueue() - func = lambda: RandomState(seed, sycl_queue=sycl_queue).normal( - loc=0.12345, scale=2.71, size=(3, 2), dtype=dtype, usm_type=usm_type - ) - - if dtype is dpnp.float64 and not _def_dev_has_fp64: - # default device doesn't support 'float64' type - assert_raises(RuntimeError, func) - return - - dpnp_data = func() - - # default dtype depends on fp64 support by the device - dtype = get_default_floating() if dtype is None else dtype - if sycl_queue.sycl_device.is_cpu: - expected = numpy.array( - [ - [0.428205496031286, -0.55383273779227], - [2.027017795643378, 4.318888073163015], - [2.69080893259102, -1.047967253719708], - ], - dtype=dtype, - ) - else: - if dtype == dpnp.float64: - expected = numpy.array( - [ - [-15.73532523, -11.84163022], - [0.548032, 1.41296207], - [-2.63250381, 2.77542322], - ], - dtype=dtype, - ) - else: - expected = numpy.array( - [ - [-15.735329, -11.841626], - [0.548032, 1.4129621], - [-2.6325033, 2.7754242], - ], - dtype=dtype, - ) - # TODO: discuss with oneMKL: there is a difference between CPU and GPU - # generated samples since 9 digit while precision=15 for float64 - # precision = dpnp.finfo(dtype).precision - precision = 8 if dtype == dpnp.float64 else dpnp.finfo(dtype).precision - assert_array_almost_equal(dpnp_data, expected, decimal=precision) - - # check if compute follows data isn't broken - assert_cfd(dpnp_data, sycl_queue, usm_type) - - @pytest.mark.parametrize("dtype", [dpnp.float32, dpnp.float64, None]) - @pytest.mark.parametrize("usm_type", list_of_usm_types) - def test_scale(self, dtype, usm_type): - mean = dtype(7.0) if dtype == dpnp.float32 else 7.0 - rs = RandomState(39567) - func = lambda scale: rs.normal( - loc=mean, scale=scale, dtype=dtype, usm_type=usm_type - ) - - if dtype is dpnp.float64 and not _def_dev_has_fp64: - # default device doesn't support 'float64' type - assert_raises(RuntimeError, func, scale=0) - return - - # zero scale means full ndarray of mean values - assert_equal(func(scale=0), mean) - - # scale must be non-negative ('-0.0' is negative value) - assert_raises(ValueError, func, scale=-0.0) - assert_raises(ValueError, func, scale=-3.71) - - @pytest.mark.parametrize( - "loc", - [ - numpy.inf, - -numpy.inf, - numpy.nextafter(dpnp.finfo(get_default_floating()).max, 0), - numpy.nextafter(dpnp.finfo(get_default_floating()).min, 0), - ], - ids=[ - "numpy.inf", - "-numpy.inf", - "nextafter(max, 0)", - "nextafter(min, 0)", - ], - ) - def test_inf_loc(self, loc): - a = RandomState(6531).normal(loc=loc, scale=1, size=1000) - assert_equal(a, get_default_floating()(loc), strict=False) - - def test_inf_scale(self): - a = RandomState().normal(0, numpy.inf, size=1000) - assert not dpnp.isnan(a).any() - assert dpnp.isinf(a).all() - assert_equal(a.max(), numpy.inf) - assert_equal(a.min(), -numpy.inf) - - @pytest.mark.parametrize("loc", [numpy.inf, -numpy.inf]) - def test_inf_loc_scale(self, loc): - a = RandomState().normal(loc=loc, scale=numpy.inf, size=1000) - assert not dpnp.isnan(a).all() - assert_equal(dpnp.nanmin(a), loc) - assert_equal(dpnp.nanmax(a), loc) - - def test_extreme_bounds(self): - dtype = get_default_floating() - fmin = dpnp.finfo(dtype).min - fmax = dpnp.finfo(dtype).max - - size = 1000 - func = RandomState(34567).normal - - assert_raises(OverflowError, func, fmin, 1) - assert_raises(OverflowError, func, fmax, 1) - assert_raises(OverflowError, func, 1, fmax) - assert_raises(OverflowError, func, fmin, fmax) - assert_raises(OverflowError, func, fmax, fmax) - - try: - # acceptable extreme range: -fmin < loc < fmax and 0 <= scale < fmax - func(loc=1, scale=numpy.nextafter(fmax, 0), size=size) - func( - loc=numpy.nextafter(fmin, 0), - scale=numpy.nextafter(fmax, 0), - size=size, - ) - func( - loc=numpy.nextafter(fmax, 0), - scale=numpy.nextafter(fmax, 0), - size=size, - ) - except Exception as e: - raise AssertionError( - "No error should have been raised, but one was " - "with the following message:\n\n%s" % str(e) - ) - - @pytest.mark.usefixtures("allow_fall_back_on_numpy") - @pytest.mark.parametrize( - "scale", - [dpnp.array([3]), numpy.array([3])], - ids=["dpnp.array([3])", "numpy.array([3])"], - ) - @pytest.mark.parametrize( - "loc", - [[2], dpnp.array([2]), numpy.array([2])], - ids=["[2]", "dpnp.array([2])", "numpy.array([2])"], - ) - def test_fallback(self, loc, scale): - seed = 15 - size = (3, 2, 5) - - sycl_queue = dpctl.SyclQueue() - data = RandomState(seed, sycl_queue=sycl_queue).normal( - loc=loc, scale=scale, size=size - ) - - # dpnp accepts only scalar as low and/or high, in other cases it will be a fallback to numpy - expected = numpy.random.RandomState(seed).normal( - loc=get_array(numpy, loc), scale=get_array(numpy, scale), size=size - ) - - precision = dpnp.finfo(get_default_floating()).precision - assert_array_almost_equal(data, expected, decimal=precision) - - # check if compute follows data isn't broken - assert_cfd(data, sycl_queue) - - @pytest.mark.parametrize( - "dtype", - [ - dpnp.float16, - float, - dpnp.int64, - dpnp.int32, - dpnp.int_, - int, - numpy.clongdouble, - dpnp.complex128, - dpnp.complex64, - dpnp.bool, - dpnp.bool_, - ], - ids=[ - "dpnp.float16", - "float", - "dpnp.int64", - "dpnp.int32", - "dpnp.int_", - "int", - "numpy.clongdouble", - "dpnp.complex128", - "dpnp.complex64", - "dpnp.bool", - "dpnp.bool_", - ], - ) - def test_invalid_dtype(self, dtype): - # dtype must be float32 or float64 - assert_raises(TypeError, RandomState().normal, dtype=dtype) - - @pytest.mark.parametrize( - "usm_type", ["", "unknown"], ids=["Empty", "Unknown"] - ) - def test_invalid_usm_type(self, usm_type): - # dtype must be float32 or float64 - assert_raises(ValueError, RandomState().normal, usm_type=usm_type) - - -class TestRand: - @pytest.mark.parametrize("usm_type", list_of_usm_types) - def test_distr(self, usm_type): - seed = 28042 - sycl_queue = dpctl.SyclQueue() - dtype = get_default_floating() - - data = RandomState(seed, sycl_queue=sycl_queue).rand( - 3, 2, usm_type=usm_type - ) - if sycl_queue.sycl_device.is_cpu: - expected = numpy.array( - [ - [0.7592552667483687, 0.5937560645397753], - [0.257010098779574, 0.749422621447593], - [0.6316644293256104, 0.7411410815548152], - ], - dtype=dtype, - ) - else: - expected = numpy.array( - [ - [4.864511571334162e-14, 7.333946068708259e-01], - [8.679067575689537e-01, 5.627257087965376e-01], - [4.413379518222594e-01, 4.334482843514076e-01], - ], - dtype=dtype, - ) - - precision = dpnp.finfo(dtype).precision - assert_array_almost_equal(data, expected, decimal=precision) - assert_cfd(data, sycl_queue, usm_type) - - # call with the same seed has to draw the same values - data = RandomState(seed, sycl_queue=sycl_queue).rand( - 3, 2, usm_type=usm_type - ) - assert_array_almost_equal(data, expected, decimal=precision) - assert_cfd(data, sycl_queue, usm_type) - - # call with omitted dimensions has to draw the first element from expected - data = RandomState(seed, sycl_queue=sycl_queue).rand(usm_type=usm_type) - assert_array_almost_equal(data, expected[0, 0], decimal=precision) - assert_cfd(data, sycl_queue, usm_type) - - # rand() is an alias on random_sample(), map arguments - with mock.patch("dpnp.random.RandomState.random_sample") as m: - RandomState(seed).rand(3, 2, usm_type=usm_type) - m.assert_called_once_with(size=(3, 2), usm_type=usm_type) - - @pytest.mark.parametrize( - "dims", - [(), (5,), (10, 2, 7), (0,)], - ids=["()", "(5,)", "(10, 2, 7)", "(0,)"], - ) - def test_dims(self, dims): - size = None if len(dims) == 0 else dims - - with mock.patch("dpnp.random.RandomState.uniform") as m: - RandomState().rand(*dims) - m.assert_called_once_with( - low=0.0, high=1.0, size=size, dtype=None, usm_type="device" - ) - - @pytest.mark.parametrize( - "zero_dims", - [(0,), (3, 0), (3, 0, 10), ()], - ids=["(0,)", "(3, 0)", "(3, 0, 10)", "()"], - ) - def test_zero_dims(self, zero_dims): - assert_equal(RandomState().rand(*zero_dims).shape, zero_dims) - - def test_wrong_dims(self): - # non-positive number in size - assert_raises(ValueError, RandomState().rand, 2, -1) - - # non-integer number in size - assert_raises(TypeError, RandomState().rand, 3.5, 2) - - -class TestRandInt: - @pytest.mark.parametrize( - "dtype", - [int, dpnp.int32, dpnp.int_], - ids=["int", "dpnp.int32", "dpnp.int_"], - ) - @pytest.mark.parametrize("usm_type", list_of_usm_types) - def test_distr(self, dtype, usm_type): - seed = 9864 - low = 1 - high = 10 - - if dtype == dpnp.int_ and dtype != dpnp.dtype("int32"): - pytest.skip( - "dtype isn't alias on dpnp.int32 on the target OS, so there will be a fallback" - ) - - sycl_queue = dpctl.SyclQueue() - data = RandomState(seed, sycl_queue=sycl_queue).randint( - low=low, high=high, size=(3, 2), dtype=dtype, usm_type=usm_type - ) - if sycl_queue.sycl_device.is_cpu: - expected = numpy.array([[4, 1], [5, 3], [5, 7]], dtype=numpy.int32) - else: - expected = numpy.array([[1, 2], [1, 5], [3, 7]], dtype=numpy.int32) - assert_array_equal(data, expected) - assert_cfd(data, sycl_queue, usm_type) - - # call with the same seed has to draw the same values - data = RandomState(seed, sycl_queue=sycl_queue).randint( - low=low, high=high, size=(3, 2), dtype=dtype, usm_type=usm_type - ) - assert_array_equal(data, expected) - assert_cfd(data, sycl_queue, usm_type) - - # call with omitted dimensions has to draw the first element from expected - data = RandomState(seed, sycl_queue=sycl_queue).randint( - low=low, high=high, dtype=dtype, usm_type=usm_type - ) - assert_array_equal(data, expected[0, 0]) - assert_cfd(data, sycl_queue, usm_type) - - # rand() is an alias on random_sample(), map arguments - with mock.patch("dpnp.random.RandomState.uniform") as m: - RandomState(seed).randint( - low=low, high=high, size=(3, 2), dtype=dtype, usm_type=usm_type - ) - m.assert_called_once_with( - low=low, - high=high, - size=(3, 2), - dtype=dpnp.int32, - usm_type=usm_type, - ) - - def test_float_bounds(self): - actual = RandomState(365852).randint( - low=0.6, high=6.789102534, size=(7,) - ) - if actual.sycl_device.is_cpu: - expected = numpy.array([4, 4, 3, 3, 1, 0, 3], dtype=numpy.int32) - else: - expected = numpy.array([0, 1, 4, 0, 3, 3, 3], dtype=numpy.int32) - assert_array_equal(actual, expected) - - def test_negative_bounds(self): - actual = RandomState(5143).randint(low=-15.74, high=-3, size=(2, 7)) - if actual.sycl_device.is_cpu: - expected = numpy.array( - [ - [-9, -12, -4, -12, -5, -13, -9], - [-4, -6, -13, -9, -9, -6, -15], - ], - dtype=numpy.int32, - ) - else: - expected = numpy.array( - [ - [-15, -7, -12, -5, -10, -11, -11], - [-14, -7, -7, -10, -14, -9, -6], - ], - dtype=numpy.int32, - ) - assert_array_equal(actual, expected) - - def test_negative_interval(self): - rs = RandomState(3567) - - assert -5 <= rs.randint(-5, -1) < -1 - - x = rs.randint(-7, -1, 5) - assert_equal(-7 <= x, True, strict=False) - assert_equal(x < -1, True, strict=False) - - def test_bounds_checking(self): - dtype = dpnp.int32 - func = RandomState().randint - low = dpnp.iinfo(dtype).min - high = dpnp.iinfo(dtype).max - - # inf can't be converted to int boundary - assert_raises(OverflowError, func, -numpy.inf, 0) - assert_raises(OverflowError, func, 0, numpy.inf) - assert_raises(OverflowError, func, -numpy.inf, numpy.inf) - - # either low < min_int or high > max_int is prohibeted - assert_raises(OverflowError, func, low - 1, 0, dtype=dtype) - assert_raises(OverflowError, func, -1, high + 1, dtype=dtype) - assert_raises(OverflowError, func, low - 1, high + 1, dtype=dtype) - - # low >= high is prohibeted - assert_raises(ValueError, func, 1, 1, dtype=dtype) - assert_raises(ValueError, func, high, low, dtype=dtype) - assert_raises(ValueError, func, 1, 0, dtype=dtype) - assert_raises(ValueError, func, high, low / 2, dtype=dtype) - - def test_rng_zero_and_extremes(self): - dtype = dpnp.int32 - func = RandomState().randint - low = dpnp.iinfo(dtype).min - high = dpnp.iinfo(dtype).max - - sycl_device = dpctl.SyclQueue().sycl_device - if sycl_device.has_aspect_gpu and not sycl_device.has_aspect_fp64: - # TODO: discuss with oneMKL - pytest.skip( - f"Due to some reason, oneMKL wrongly returns high value instead of low" - ) - - tgt = high - 1 - assert_equal(func(tgt, tgt + 1, size=1000), tgt, strict=False) - - tgt = low - assert_equal(func(tgt, tgt + 1, size=1000), tgt, strict=False) - - tgt = (low + high) // 2 - assert_equal(func(tgt, tgt + 1, size=1000), tgt, strict=False) - - def test_full_range(self): - dtype = dpnp.int32 - low = dpnp.iinfo(dtype).min - high = dpnp.iinfo(dtype).max - - try: - RandomState().randint(low, high) - except Exception as e: - raise AssertionError( - "No error should have been raised, but one was " - "with the following message:\n\n%s" % str(e) - ) - - @pytest.mark.usefixtures("allow_fall_back_on_numpy") - def test_in_bounds_fuzz(self): - for high in [4, 8, 16]: - vals = RandomState().randint(2, high, size=2**16) - assert vals.max() < high - assert vals.min() >= 2 - - @pytest.mark.parametrize( - "zero_size", - [(3, 0, 4), 0, (0,), ()], - ids=["(3, 0, 4)", "0", "(0,)", "()"], - ) - def test_zero_size(self, zero_size): - exp_shape = zero_size if zero_size != 0 else (0,) - assert_equal( - RandomState().randint(0, 10, size=zero_size).shape, exp_shape - ) - - @pytest.mark.usefixtures("allow_fall_back_on_numpy") - @pytest.mark.parametrize( - "high", - [dpnp.array([3]), numpy.array([3])], - ids=["dpnp.array([3])", "numpy.array([3])"], - ) - @pytest.mark.parametrize( - "low", - [[2], dpnp.array([2]), numpy.array([2])], - ids=["[2]", "dpnp.array([2])", "numpy.array([2])"], - ) - def test_bounds_fallback(self, low, high): - if isinstance(high, dpnp_array) and high.dtype == numpy.int32: - pytest.skip("NumPy fails: 'high' is out of bounds for int32") - - seed = 15 - size = (3, 2, 5) - - # dpnp accepts only scalar as low and/or high, in other cases it will be a fallback to numpy - actual = RandomState(seed).randint(low=low, high=high, size=size) - expected = numpy.random.RandomState(seed).randint( - low=get_array(numpy, low), high=get_array(numpy, high), size=size - ) - assert_equal(actual, expected) - - @pytest.mark.usefixtures("allow_fall_back_on_numpy") - @pytest.mark.parametrize( - "dtype", - [dpnp.int64, dpnp.int_, dpnp.bool, dpnp.bool_, bool], - ids=[ - "dpnp.int64", - "dpnp.int_", - "dpnp.bool", - "dpnp.bool_", - "bool", - ], - ) - def test_dtype_fallback(self, dtype): - seed = 157 - low = -3 if not dtype in {dpnp.bool_, bool} else 0 - high = 37 if not dtype in {dpnp.bool_, bool} else 2 - size = (3, 2, 5) - - if dtype == dpnp.int_ and dtype == dpnp.dtype("int32"): - pytest.skip( - "dtype is alias on dpnp.int32 on the target OS, so no fallback here" - ) - - # dtype must be int or dpnp.int32, in other cases it will be a fallback to numpy - actual = RandomState(seed).randint( - low=low, high=high, size=size, dtype=dtype - ) - expected = numpy.random.RandomState(seed).randint( - low=low, high=high, size=size, dtype=dtype - ) - assert_array_equal(actual, expected) - assert_raises(TypeError, RandomState().randint, dtype=dtype) - - @pytest.mark.parametrize( - "usm_type", ["", "unknown"], ids=["Empty", "Unknown"] - ) - def test_invalid_usm_type(self, usm_type): - # dtype must be float32 or float64 - assert_raises(ValueError, RandomState().uniform, usm_type=usm_type) - - -class TestRandN: - @pytest.mark.parametrize("usm_type", list_of_usm_types) - def test_distr(self, usm_type): - seed = 3649 - sycl_queue = dpctl.SyclQueue() - dtype = get_default_floating() - - data = RandomState(seed, sycl_queue=sycl_queue).randn( - 3, 2, usm_type=usm_type - ) - if sycl_queue.sycl_device.is_cpu: - expected = numpy.array( - [ - [-0.862485623762009, 1.169492612490272], - [-0.405876118480338, 0.939006537666719], - [-0.615075625641019, 0.555260469834381], - ], - dtype=dtype, - ) - else: - expected = numpy.array( - [ - [-4.019566117504177, 7.016412093100934], - [-1.044015254820266, -0.839721616192757], - [0.545079768980527, 0.380676324099473], - ], - dtype=dtype, - ) - - # TODO: discuss with oneMKL: there is a difference between CPU and GPU - # generated samples since 9 digit while precision=15 for float64 - # precision = dpnp.finfo(numpy.float64).precision - precision = dpnp.finfo(numpy.float32).precision - assert_array_almost_equal(data, expected, decimal=precision) - - # call with the same seed has to draw the same values - data = RandomState(seed, sycl_queue=sycl_queue).randn( - 3, 2, usm_type=usm_type - ) - assert_array_almost_equal(data, expected, decimal=precision) - - # call with omitted dimensions has to draw the first element from expected - actual = RandomState(seed).randn(usm_type=usm_type) - assert_array_almost_equal(actual, expected[0, 0], decimal=precision) - - # randn() is an alias on standard_normal(), map arguments - with mock.patch("dpnp.random.RandomState.standard_normal") as m: - RandomState(seed).randn(2, 7, usm_type=usm_type) - m.assert_called_once_with(size=(2, 7), usm_type=usm_type) - - @pytest.mark.parametrize( - "dims", - [(), (5,), (10, 2, 7), (0,)], - ids=["()", "(5,)", "(10, 2, 7)", "(0,)"], - ) - def test_dims(self, dims): - size = None if len(dims) == 0 else dims - - with mock.patch("dpnp.random.RandomState.normal") as m: - RandomState().randn(*dims) - m.assert_called_once_with( - loc=0.0, scale=1.0, size=size, dtype=None, usm_type="device" - ) - - @pytest.mark.parametrize( - "zero_dims", - [(0,), (3, 0), (3, 0, 10), ()], - ids=["(0,)", "(3, 0)", "(3, 0, 10)", "()"], - ) - def test_zero_dims(self, zero_dims): - assert_equal(RandomState().randn(*zero_dims).shape, zero_dims) - - def test_wrong_dims(self): - # non-positive number in size - assert_raises(ValueError, RandomState().randn, 2, -1) - - # non-integer number in size - assert_raises(TypeError, RandomState().randn, 3.5, 2) +# method name, positional parameters, whether the samples are floats +distributions = [ + ("beta", (0.5, 2.0), True), + ("binomial", (10, 0.3), False), + ("chisquare", (3.0,), True), + ("exponential", (2.0,), True), + ("f", (5.0, 7.0), True), + ("gamma", (3.0, 2.0), True), + ("geometric", (0.3,), False), + ("gumbel", (1.0, 2.0), True), + ("hypergeometric", (10, 5, 7), False), + ("laplace", (1.0, 2.0), True), + ("logistic", (1.0, 2.0), True), + ("lognormal", (0.0, 0.5), True), + ("logseries", (0.6,), False), + ("negative_binomial", (3.0, 0.4), False), + ("noncentral_chisquare", (3.0, 2.0), True), + ("noncentral_f", (5.0, 7.0, 2.0), True), + ("normal", (1.0, 2.0), True), + ("pareto", (5.0,), True), + ("poisson", (4.0,), False), + ("power", (3.0,), True), + ("rayleigh", (2.0,), True), + ("standard_cauchy", (), True), + ("standard_exponential", (), True), + ("standard_gamma", (0.5,), True), + ("standard_normal", (), True), + ("standard_t", (5.0,), True), + ("triangular", (0.0, 1.0, 3.0), True), + ("uniform", (-1.0, 2.0), True), + ("vonmises", (0.5, 2.0), True), + ("wald", (1.0, 2.0), True), + ("weibull", (2.0,), True), + ("zipf", (3.0,), False), + ("random_sample", (), True), + ("randint", (-3, 7), False), + ("tomaxint", (), False), +] +float_distributions = [d[:2] for d in distributions if d[2]] + + +def _all_devices(): + return [ + dev for dev in dpctl.get_devices() if not dev.has_aspect_accelerator + ] + + +def _device_id(device): + # str() holds the address, which differs between pytest-xdist workers + return device.filter_string + + +class TestAPI: + def test_methods(self): + public = lambda c: {n for n in dir(c) if not n.startswith("_")} + missing = public(numpy.random.RandomState) - public(RandomState) + assert not missing + + def test_module_functions(self): + # NumPy's other bit generators are not provided + bit_generators = {"MT19937", "PCG64", "Philox", "SFC64"} + missing = set(numpy.random.__all__) - set(dpnp.random.__all__) + assert missing == bit_generators class TestSeed: - @pytest.mark.parametrize( - "func", ["normal", "standard_normal", "random_sample", "uniform"] - ) - def test_scalar(self, func): - seed = 28041997 - size = (3, 2, 4) - - rs = RandomState(seed) - a1 = getattr(rs, func)(size=size) - - rs = RandomState(seed) - a2 = getattr(rs, func)(size=size) - - precision = dpnp.finfo(numpy.float64).precision - assert_array_almost_equal(a1, a2, decimal=precision) - - @pytest.mark.usefixtures("allow_fall_back_on_numpy") @pytest.mark.parametrize( "seed", [ - range(3), - numpy.arange(3, dtype=numpy.int32), - dpnp.arange(3, dtype=numpy.int32), + 0, + 4294967295, + numpy.uint32(5), [0], [4294967295], [2, 7, 15], - (1,), + [4, 3, 2, 1], (85, 6, 17), - ], - ids=[ - "range(2)", - "numpy.arange(2)", - "dpnp.arange(2)", - "[0]", - "[4294967295]", - "[2, 7, 15]", - "(1,)", - "(85, 6, 17)", + range(3), + numpy.arange(3, dtype=numpy.int32), + dpnp.arange(3, dtype=dpnp.int32), ], ) - def test_array_range(self, seed): - if is_gpu_device(): - pytest.skip("seed as a scalar is only supported on GPU") + def test_reproducible(self, seed): + a1 = RandomState(seed).random_sample(15) + a2 = RandomState(seed).random_sample(15) + assert_array_equal(a1, a2) + + def test_distinct(self): + a1 = RandomState(1).random_sample(8) + a2 = RandomState(2).random_sample(8) + assert not (a1 == a2).any() - size = 15 - a1 = RandomState(seed).uniform(size=size) - a2 = RandomState(seed).uniform(size=size) - assert dpnp.allclose(a1, a2) + def test_none(self): + a1 = RandomState().random_sample(8) + a2 = RandomState(None).random_sample(8) + assert not (a1 == a2).any() @pytest.mark.parametrize( "seed", [ + -1, + 4294967296, + [-3, 7], + (1, 7, 4294967296), + [], + (), + [[1, 2, 3]], + [[1, 2, 3], [4, 5, 6]], + numpy.array([], dtype=numpy.int64), 0.5, -1.5, [-0.3], (1.7, 3), "text", numpy.arange(0, 1, 0.5), - dpnp.arange(3, dtype=numpy.float32), - dpnp.arange(3, dtype=numpy.complex64), - ], - ids=[ - "0.5", - "-1.5", - "[-0.3]", - "(1.7, 3)", - "text", - "numpy.arange(0, 1, 0.5)", - "dpnp.arange(3, dtype=numpy.float32)", - "dpnp.arange(3, dtype=numpy.complex64)", ], ) - def test_invalid_type(self, seed): - # seed must be an unsigned 32-bit integer - assert_raises(TypeError, RandomState, seed) - - @pytest.mark.usefixtures("allow_fall_back_on_numpy") - @pytest.mark.parametrize( - "seed", - [ - -1, - [-3, 7], - (17, 3, -5), - [4, 3, 2, 1], - (7, 6, 5, 1), - range(-1, -11, -1), - numpy.arange(4, dtype=numpy.int32), - dpnp.arange(-3, 3, dtype=numpy.int32), - dpnp.iinfo(numpy.uint32).max + 1, - (1, 7, dpnp.iinfo(numpy.uint32).max + 1), - ], - ids=[ - "-1", - "[-3, 7]", - "(17, 3, -5)", - "[4, 3, 2, 1]", - "(7, 6, 5, 1)", - "range(-1, -11, -1)", - "numpy.arange(4, dtype=numpy.int32)", - "dpnp.arange(-3, 3, dtype=numpy.int32)", - "dpnp.iinfo(numpy.uint32).max + 1", - "(1, 7, dpnp.iinfo(numpy.uint32).max + 1)", - ], - ) - def test_invalid_value(self, seed): - if is_cpu_device(): - # seed must be an unsigned 32-bit integer - assert_raises(ValueError, RandomState, seed) - else: - if dpnp.isscalar(seed): - # seed must be an unsigned 64-bit integer - assert_raises(ValueError, RandomState, seed) - else: - # seed must be a scalar - assert_raises(TypeError, RandomState, seed) + def test_invalid(self, seed): + _assert_same_error( + lambda: numpy.random.RandomState(seed), + lambda: RandomState(seed), + ) @pytest.mark.parametrize( "seed", [ - [], - (), - [[1, 2, 3]], - [[1, 2, 3], [4, 5, 6]], - numpy.array([], dtype=numpy.int64), - dpnp.array([], dtype=numpy.int64), - ], - ids=[ - "[]", - "()", - "[[1, 2, 3]]", - "[[1, 2, 3], [4, 5, 6]]", - "numpy.array([], dtype=numpy.int64)", - "dpnp.array([], dtype=numpy.int64)", + dpnp.arange(3, dtype=dpnp.float32), + dpnp.array([], dtype=dpnp.int64), + dpnp.arange(-3, 3), ], ) - def test_invalid_shape(self, seed): - if is_cpu_device(): - # seed must be an unsigned or 1-D array - assert_raises(ValueError, RandomState, seed) - else: - if dpnp.isscalar(seed): - # seed must be an unsigned 64-bit scalar - assert_raises(ValueError, RandomState, seed) - else: - # seed must be a scalar - assert_raises(TypeError, RandomState, seed) + def test_invalid_dpnp_array(self, seed): + np_seed = dpnp.asnumpy(seed) + _assert_same_error( + lambda: numpy.random.RandomState(np_seed), + lambda: RandomState(seed), + ) + def test_reseed(self): + rs = RandomState(3) + rs.random_sample(5) + rs.seed(7) + assert_array_equal(rs.random_sample(5), RandomState(7).random_sample(5)) + + def test_module_seed(self): + dpnp.random.seed(7) + a1 = dpnp.random.random_sample(5) + a2 = dpnp.random.random_sample(5) + dpnp.random.seed(7) + assert_array_equal(dpnp.random.random_sample(5), a1) + assert_array_equal(dpnp.random.random_sample(5), a2) + assert_array_equal(a1, RandomState(7).random_sample(5)) + + +class TestState: + def test_roundtrip(self): + rs = RandomState(12) + rs.normal(size=3) + state = rs.get_state() + a1 = rs.normal(size=7) + rs.random_sample(3) + rs.set_state(state) + assert_array_equal(rs.normal(size=7), a1) + + def test_legacy_false(self): + rs = RandomState(12) + assert rs.get_state(legacy=False) == rs.get_state() + + def test_restore_on_new_instance(self): + rs = RandomState(12) + rs.poisson(3.0, size=10) + state = rs.get_state() + a1 = rs.poisson(3.0, size=10) + rs2 = RandomState() + rs2.set_state(state) + assert_array_equal(rs2.poisson(3.0, size=10), a1) + + def test_module_state(self): + dpnp.random.seed(5) + state = dpnp.random.get_state() + a1 = dpnp.random.random_sample(5) + dpnp.random.set_state(state) + assert_array_equal(dpnp.random.random_sample(5), a1) + + def test_numpy_state(self): + state = numpy.random.RandomState(3).get_state() + assert_raises(ValueError, RandomState().set_state, state) + + def test_not_a_state(self): + assert_raises(ValueError, RandomState().set_state, 1) + + +@pytest.fixture +def restore_bit_generator(): + saved = dpnp.random.get_bit_generator() + yield + dpnp.random.set_bit_generator(saved) + + +@pytest.mark.usefixtures("restore_bit_generator") +class TestBitGenerator: + def test_get_same_object(self): + bg = dpnp.random.get_bit_generator() + assert isinstance(bg, dpnp.random.Philox4x3210) + assert dpnp.random.get_bit_generator() is bg + + def test_module_seed_keeps_object(self): + bg = dpnp.random.get_bit_generator() + dpnp.random.seed(3) + assert dpnp.random.get_bit_generator() is bg + assert_array_equal( + dpnp.random.random_sample(5), RandomState(3).random_sample(5) + ) -class TestStandardNormal: + def test_set(self): + bg = dpnp.random.PCG64DXSM(5) + dpnp.random.set_bit_generator(bg) + assert dpnp.random.get_bit_generator() is bg + ref = dpnp.random.Generator(dpnp.random.PCG64DXSM(5)).random(6) + assert_array_equal(dpnp.random.random_sample(6), ref) + + def test_shared_stream(self): + bg = dpnp.random.PCG64DXSM(5) + dpnp.random.set_bit_generator(bg) + a = dpnp.random.random_sample(3) + b = dpnp.random.Generator(bg).random(3) + ref = dpnp.random.Generator(dpnp.random.PCG64DXSM(5)).random(6) + assert_array_equal(dpnp.concatenate((a, b)), ref) + + def test_module_seed_reseeds_in_place(self): + bg = dpnp.random.PCG64DXSM(5) + dpnp.random.set_bit_generator(bg) + dpnp.random.random_sample(3) + dpnp.random.seed(9) + assert dpnp.random.get_bit_generator() is bg + assert bg.state == dpnp.random.PCG64DXSM(9).state + ref = dpnp.random.Generator(dpnp.random.PCG64DXSM(9)).random(4) + assert_array_equal(dpnp.random.random_sample(4), ref) + + def test_queue(self): + queue = dpctl.SyclQueue() + bg = dpnp.random.PCG64DXSM(1, sycl_queue=queue) + dpnp.random.set_bit_generator(bg) + assert dpnp.random.get_bit_generator(sycl_queue=queue) is bg + assert dpnp.random.get_bit_generator() is not bg + + res = dpnp.random.random_sample(4, sycl_queue=queue) + assert res.sycl_queue == queue + gen = dpnp.random.Generator(dpnp.random.PCG64DXSM(1, sycl_queue=queue)) + assert_array_equal(res, gen.random(4)) + + @pytest.mark.parametrize("xp", [dpnp, numpy]) + def test_class(self, xp): + # NumPy keeps the class as its global bit generator after raising + saved = numpy.random.get_bit_generator() + bg_type = xp.random.PCG64DXSM + try: + assert_raises(ValueError, xp.random.set_bit_generator, bg_type) + finally: + numpy.random.set_bit_generator(saved) + + @pytest.mark.parametrize("bitgen", [None, 5, numpy.random.PCG64DXSM(1)]) + def test_not_a_bit_generator(self, bitgen): + assert_raises(TypeError, dpnp.random.set_bit_generator, bitgen) + + +class TestBitGeneratorSeed: + def test_random_state(self): + bg = dpnp.random.PCG64DXSM(7) + rs = RandomState(bg) + assert str(rs) == "RandomState(PCG64DXSM)" + assert rs.get_sycl_queue() == bg.sycl_queue + ref = dpnp.random.Generator(dpnp.random.PCG64DXSM(7)).random(5) + assert_array_equal(rs.random_sample(5), ref) + + def test_state(self): + rs = RandomState(dpnp.random.PCG64DXSM(7)) + state = rs.get_state() + assert state["bit_generator"] == "PCG64DXSM" + a1 = rs.random_sample(5) + rs.set_state(state) + assert_array_equal(rs.random_sample(5), a1) + philox_state = RandomState(7).get_state() + assert_raises(ValueError, rs.set_state, philox_state) + + @pytest.mark.parametrize("xp", [dpnp, numpy]) + def test_reseed(self, xp): + # only the legacy bit generator can be reseeded + rs = xp.random.RandomState(xp.random.PCG64DXSM(7)) + assert_raises(TypeError, rs.seed, 3) + + @pytest.mark.parametrize("kw", ["device", "sycl_queue"]) + def test_queue_kwarg(self, kw): + bg = dpnp.random.PCG64DXSM(7) + queue = dpctl.SyclQueue() + assert_raises(ValueError, RandomState, bg, **{kw: queue}) + + +class TestQueue: + @pytest.mark.parametrize("device", _all_devices(), ids=_device_id) + def test_device(self, device): + rs = RandomState(1, device=device) + assert rs.get_sycl_device() == device + res = rs.normal(size=5) + assert res.sycl_device == device + + @pytest.mark.parametrize("device", _all_devices(), ids=_device_id) + def test_sycl_queue(self, device): + queue = dpctl.SyclQueue(device) + rs = RandomState(1, sycl_queue=queue) + assert rs.get_sycl_queue() == queue + assert rs.normal(size=5).sycl_queue == queue + + @pytest.mark.parametrize("name, params, is_float", distributions) + def test_device_independent(self, name, params, is_float): + devices = _all_devices() + if len(devices) < 2: + pytest.skip("a single device") + + results = [] + for device in devices: + rs = RandomState(1234, device=device) + kw = {"dtype": dpnp.float32} if is_float else {} + results.append(dpnp.asnumpy(getattr(rs, name)(*params, 64, **kw))) + for dev, res in zip(devices[1:], results[1:]): + if is_float: + # the streams match, but the math functions of the devices + # round differently, which e.g. vonmises amplifies + assert_allclose(res, results[0], rtol=1e-3, atol=1e-5) + elif dev.has_aspect_fp64 == devices[0].has_aspect_fp64: + # the discrete samplers compute in float32 without fp64, + # and a float rounding may rarely take a rejection sampler + # down another path + assert numpy.mean(res != results[0]) < 0.05 + + def test_follows_param_queue(self): + queue = dpctl.SyclQueue() + lam = dpnp.asarray([1.0, 2.0], sycl_queue=queue) + res = dpnp.random.poisson(lam) + assert res.sycl_queue == queue + + x = dpnp.arange(5, sycl_queue=queue) + assert dpnp.random.permutation(x).sycl_queue == queue + assert dpnp.random.choice(x, 3).sycl_queue == queue + + +class TestDistributions: @pytest.mark.parametrize("usm_type", list_of_usm_types) - def test_distr(self, usm_type): - seed = 1234567 - sycl_queue = dpctl.SyclQueue() - dtype = get_default_floating() - - data = RandomState(seed, sycl_queue=sycl_queue).standard_normal( - size=(4, 2), usm_type=usm_type - ) - if sycl_queue.sycl_device.is_cpu: - expected = numpy.array( - [ - [0.112455902594571, -0.249919829443642], - [0.702423540827815, 1.548132130318456], - [0.947364919775284, -0.432257289195464], - [0.736848611436872, 1.557284323302839], - ], - dtype=dtype, - ) + @pytest.mark.parametrize("name, params, is_float", distributions) + def test_shape_dtype(self, name, params, is_float, usm_type): + rs = RandomState(0) + meth = getattr(rs, name) + + res = meth(*params, size=(3, 4), usm_type=usm_type) + assert isinstance(res, dpnp.ndarray) + assert res.shape == (3, 4) + assert res.usm_type == usm_type + if is_float: + assert res.dtype == dpnp.default_float_type() else: - expected = numpy.array( - [ - [-5.851946579836138, -4.415158753007455], - [0.156672323326223, 0.475834711471613], - [-1.016957125278234, 0.978587902851975], - [-0.295425067084912, 1.438622345507964], - ], - dtype=dtype, - ) + assert res.dtype == dpnp.int64 - # TODO: discuss with oneMKL: there is a difference between CPU and GPU - # generated samples since 9 digit while precision=15 for float64 - # precision = dpnp.finfo(numpy.float64).precision - precision = dpnp.finfo(numpy.float32).precision - assert_array_almost_equal(data, expected, decimal=precision) + assert meth(*params).shape == () + assert meth(*params, size=0).shape == (0,) - # call with the same seed has to draw the same values - data = RandomState(seed, sycl_queue=sycl_queue).standard_normal( - size=(4, 2), usm_type=usm_type - ) - assert_array_almost_equal(data, expected, decimal=precision) + @pytest.mark.parametrize("dtype", float_dtypes) + @pytest.mark.parametrize("name, params", float_distributions) + def test_dtype(self, name, params, dtype): + res = getattr(RandomState(0), name)(*params, size=5, dtype=dtype) + assert res.dtype == dtype - # call with omitted dimensions has to draw the first element from expected - actual = RandomState(seed).standard_normal(usm_type=usm_type) - assert_array_almost_equal(actual, expected[0, 0], decimal=precision) + @pytest.mark.parametrize( + "dtype", [dpnp.float16, dpnp.int32, dpnp.complex64, dpnp.bool] + ) + @pytest.mark.parametrize("name, params", float_distributions) + def test_bad_dtype(self, name, params, dtype): + meth = getattr(RandomState(0), name) + assert_raises(TypeError, meth, *params, size=5, dtype=dtype) + + @pytest.mark.parametrize("usm_type", ["", "unknown"]) + def test_bad_usm_type(self, usm_type): + assert_raises(ValueError, RandomState().normal, usm_type=usm_type) - # random_sample() is an alias on uniform(), map arguments - with mock.patch("dpnp.random.RandomState.normal") as m: - RandomState(seed).standard_normal((4, 2), usm_type=usm_type) - m.assert_called_once_with( - loc=0.0, scale=1.0, size=(4, 2), dtype=None, usm_type=usm_type + @pytest.mark.parametrize("name, params, is_float", distributions) + def test_moments(self, name, params, is_float): + # the sample means agree with the ones of NumPy within six standard + # deviations + n = 2**16 + np_res = getattr(numpy.random.RandomState(0), name)(*params, n) + if name == "tomaxint" and numpy.dtype("l").itemsize < 8: + # NumPy draws C longs, which are 32-bit on Windows + np_res = numpy.random.RandomState(0).randint( + 0, 2**63 - 1, n, dtype=numpy.int64 ) + res = dpnp.asnumpy(getattr(RandomState(0), name)(*params, n)) + if name == "standard_cauchy": + np_res, res = numpy.median(np_res), numpy.median(res) + assert abs(res - np_res) < 0.05 + return + tol = 6 * numpy.sqrt(np_res.var() / n + res.var() / n) + assert abs(res.mean() - np_res.mean()) <= tol @pytest.mark.parametrize( - "size", - [(), (5,), (10, 2, 7), (0,)], - ids=["()", "(5,)", "(10, 2, 7)", "(0,)"], + "name, args", + [ + ("dirichlet", ([1.0, 2.0, 3.0],)), + ("multinomial", (10, [0.2, 0.3, 0.5])), + ("multivariate_normal", ([0.0, 1.0], [[2.0, 0.5], [0.5, 1.0]])), + ], ) - def test_sizes(self, size): - with mock.patch("dpnp.random.RandomState.normal") as m: - RandomState().standard_normal(size) - m.assert_called_once_with( - loc=0.0, scale=1.0, size=size, dtype=None, usm_type="device" - ) - - def test_wrong_dims(self): - # non-positive number in size - assert_raises(ValueError, RandomState().standard_normal, (2, -1)) + @pytest.mark.parametrize("size", [None, 4, (2, 3)]) + def test_multivariate_shape(self, name, args, size): + np_res = getattr(numpy.random.RandomState(0), name)(*args, size) + res = getattr(RandomState(0), name)(*args, size) + assert res.shape == np_res.shape - # non-integer number in size - assert_raises(TypeError, RandomState().standard_normal, (3.5, 2)) + @pytest.mark.parametrize("name, params, is_float", distributions) + def test_module_function(self, name, params, is_float): + if name == "tomaxint": + pytest.skip("not a module function") + dpnp.random.seed(11) + res = getattr(dpnp.random, name)(*params, size=5, usm_type="shared") + assert res.usm_type == "shared" + assert_array_equal(res, getattr(RandomState(11), name)(*params, 5)) -class TestRandSample: - @pytest.mark.parametrize("usm_type", list_of_usm_types) - def test_distr(self, usm_type): - seed = 12657 - sycl_queue = dpctl.SyclQueue() - dtype = get_default_floating() - data = RandomState(seed, sycl_queue=sycl_queue).random_sample( - size=(4, 2), usm_type=usm_type - ) - if sycl_queue.sycl_device.is_cpu: - expected = numpy.array( - [ - [0.1887628440745175, 0.2763057765550911], - [0.3973943444434553, 0.2975987731479108], - [0.4144027342554182, 0.2636592474300414], - [0.6129623607266694, 0.2596735346596688], - ], - dtype=dtype, - ) - else: - expected = numpy.array( - [ - [0.219563950354e-13, 0.6500454867400344], - [0.8847833902913576, 0.9030532521302965], - [0.2943803743033427, 0.2688879158061396], - [0.2730219631925900, 0.8695396883048091], - ], - dtype=dtype, - ) - - precision = dpnp.finfo(dtype).precision - assert_array_almost_equal(data, expected, decimal=precision) - - # call with omitted dimensions has to draw the first element from expected - data = RandomState(seed, sycl_queue=sycl_queue).random_sample( - usm_type=usm_type +class TestSize: + @pytest.mark.parametrize( + "size", + [ + True, + [True], + numpy.bool_(True), + numpy.array(True), + numpy.array([True]), + -1, + (2, -1), + 2.0, + (3.5, 2), + numpy.array([[2]]), + ], + ) + def test_invalid(self, size): + _assert_same_error( + lambda: numpy.random.RandomState(0).uniform(size=size), + lambda: RandomState(0).uniform(size=size), ) - assert_array_almost_equal(data, expected[0, 0], decimal=precision) - # random_sample() is an alias on uniform(), map arguments - with mock.patch("dpnp.random.RandomState.uniform") as m: - RandomState(seed).random_sample((4, 2), usm_type=usm_type) - m.assert_called_once_with( - low=0.0, high=1.0, size=(4, 2), dtype=None, usm_type=usm_type - ) @pytest.mark.parametrize( "size", - [(), (5,), (10, 2, 7), (0,)], - ids=["()", "(5,)", "(10, 2, 7)", "(0,)"], + [ + (numpy.int64(31), 63), + (numpy.int64(31), numpy.int64(31)), + numpy.array(1), + numpy.array([2]), + dpnp.array(3), + ], ) - def test_sizes(self, size): - with mock.patch("dpnp.random.RandomState.uniform") as m: - RandomState().random_sample(size) - m.assert_called_once_with( - low=0.0, high=1.0, size=size, dtype=None, usm_type="device" - ) - - def test_wrong_dims(self): - # non-positive number in size - assert_raises(ValueError, RandomState().random_sample, (2, -1)) + def test_castable_to_integer(self, size): + res = RandomState().uniform(size=size) + exp = numpy.random.RandomState().uniform(size=dpnp.asnumpy(size)) + assert res.shape == exp.shape + + @pytest.mark.parametrize("dims", [(), (5,), (10, 2, 7), (0,), (3, 0)]) + @pytest.mark.parametrize("name", ["rand", "randn"]) + def test_rand_dims(self, name, dims): + res = getattr(RandomState(), name)(*dims) + assert res.shape == dims + + @pytest.mark.parametrize("dims", [(2, -1), (3.5, 2)]) + @pytest.mark.parametrize("name", ["rand", "randn"]) + def test_rand_bad_dims(self, name, dims): + _assert_same_error( + lambda: getattr(numpy.random.RandomState(), name)(*dims), + lambda: getattr(RandomState(), name)(*dims), + ) - # non-integer number in size - assert_raises(TypeError, RandomState().random_sample, (3.5, 2)) + @pytest.mark.parametrize("dtype", float_dtypes) + def test_rand_dtype(self, dtype): + assert RandomState().rand(2, 3, dtype=dtype).dtype == dtype + assert RandomState().randn(2, 3, dtype=dtype).dtype == dtype -class TestUniform: - @pytest.mark.parametrize( - "bounds", - [[1.23, 10.54], [10.54, 1.23]], - ids=["(low, high)=[1.23, 10.54]", "(low, high)=[10.54, 1.23]"], - ) +class TestIntegers: @pytest.mark.parametrize( - "dtype", [dpnp.float32, dpnp.float64, dpnp.int32, None] + "dtype", get_all_dtypes(no_float16=True, no_none=True, no_complex=True) ) - @pytest.mark.parametrize("usm_type", list_of_usm_types) - def test_distr(self, bounds, dtype, usm_type): - seed = 28041997 - low = bounds[0] - high = bounds[1] - - sycl_queue = dpctl.SyclQueue() - func = lambda: RandomState(seed, sycl_queue=sycl_queue).uniform( - low=low, high=high, size=(3, 2), dtype=dtype, usm_type=usm_type - ) - - if dtype is dpnp.float64 and not _def_dev_has_fp64: - # default device doesn't support 'float64' type - assert_raises(RuntimeError, func) + def test_full_range(self, dtype): + if dpnp.issubdtype(dtype, dpnp.floating): + assert_raises(TypeError, RandomState().randint, 5, dtype=dtype) return - # get drawn samples by dpnp - actual = func() - - # default dtype depends on fp64 support by the device - dtype = get_default_floating() if dtype is None else dtype - if sycl_queue.sycl_device.is_cpu: - if dtype != dpnp.int32: - data = [ - [4.023770128630567, 8.87456423597643], - [2.888630247435067, 4.823004481580574], - [2.030351535445079, 4.533497077834326], - ] - expected = numpy.array(data, dtype=dtype) - precision = dpnp.finfo(dtype).precision - assert_array_almost_equal(actual, expected, decimal=precision) - else: - expected = numpy.array([[3, 8], [2, 4], [1, 4]], dtype=dtype) - assert_array_equal(actual, expected) - else: - if dtype != dpnp.int32: - data = [ - [1.230000000452886, 4.889115418092382], - [6.084098950993071, 1.682066500463302], - [3.316473517549554, 8.428297791221597], - ] - expected = numpy.array(data, dtype=dtype) - precision = dpnp.finfo(dtype).precision - assert_array_almost_equal(actual, expected, decimal=precision) - else: - expected = numpy.array([[1, 4], [5, 1], [3, 7]], dtype=dtype) - assert_array_equal(actual, expected) - - # check if compute follows data isn't broken - assert_cfd(actual, sycl_queue, usm_type) + info = numpy.iinfo(dtype) if dtype != dpnp.bool else None + low, high = (0, 2) if info is None else (info.min, info.max + 1) + res = RandomState(0).randint(low, high, size=2**12, dtype=dtype) + assert res.dtype == dtype + assert int(res.min()) >= low + assert int(res.max()) < high + assert len(numpy.unique(dpnp.asnumpy(res))) > 1 + + def test_default_dtype(self): + assert RandomState().randint(5).dtype == dpnp.int64 + assert RandomState().randint(5, dtype=int).dtype == dpnp.int64 + + @pytest.mark.parametrize("low, high", [(2, 4), (-7, -1), (0.6, 6.78)]) + def test_bounds(self, low, high): + res = dpnp.asnumpy(RandomState(0).randint(low, high, 2**12)) + exp = numpy.random.RandomState(0).randint(low, high, 2**12) + # NumPy's default is a C long, which is int32 on Windows + assert_equal(numpy.unique(res), numpy.unique(exp), strict=False) + + def test_one_bound(self): + res = dpnp.asnumpy(RandomState(0).randint(5, size=2**12)) + assert_equal(numpy.unique(res), numpy.arange(5)) + + def test_zero_range(self): + res = RandomState(0).randint(-3, -2, size=100) + assert (res == -3).all() + + def test_array_bounds(self): + low = dpnp.asarray([0, 10]) + res = RandomState(0).randint(low, numpy.array([2, 12]), size=(64, 2)) + res = dpnp.asnumpy(res) + assert_equal(numpy.unique(res[:, 0]), [0, 1]) + assert_equal(numpy.unique(res[:, 1]), [10, 11]) @pytest.mark.parametrize( - "dtype", [dpnp.float32, dpnp.float64, dpnp.int32, None] + "args, kwargs", + [ + ((-numpy.inf, 0), {}), + ((0, numpy.inf), {}), + ((1, 1), {}), + ((5, 2), {}), + ((-(2**31) - 1, 0), {"dtype": numpy.int32}), + ((0, 2**31 + 1), {"dtype": numpy.int32}), + ((0, 3), {"dtype": numpy.bool_}), + ((5,), {"dtype": numpy.float64}), + ((0,), {}), + ((1, [0, 1]), {}), + ((0, [0, 1]), {}), + (([-1], 3), {"dtype": numpy.uint8}), + (([0], 257), {"dtype": numpy.uint8}), + ], ) - @pytest.mark.parametrize("usm_type", list_of_usm_types) - def test_low_high_equal(self, dtype, usm_type): - seed = 28045 - low = high = 3.75 - shape = (7, 6, 20) - - func = lambda: RandomState(seed).uniform( - low=low, high=high, size=shape, dtype=dtype, usm_type=usm_type + def test_errors(self, args, kwargs): + _assert_same_error( + lambda: numpy.random.RandomState().randint(*args, **kwargs), + lambda: RandomState().randint(*args, **kwargs), ) - if dtype is dpnp.float64 and not _def_dev_has_fp64: - # default device doesn't support 'float64' type - assert_raises(RuntimeError, func) - return + def test_random_integers_none(self): + with pytest.warns(DeprecationWarning): + _assert_same_error( + lambda: numpy.random.RandomState().random_integers(None), + lambda: RandomState().random_integers(None), + ) - # get drawn samples by dpnp - actual = func() + @pytest.mark.parametrize("args", [(5,), (-2, 3)]) + def test_random_integers(self, args): + with pytest.warns(DeprecationWarning) as np_warn: + exp = numpy.random.RandomState(0).random_integers(*args, size=2**12) + with pytest.warns(DeprecationWarning) as dp_warn: + res = RandomState(0).random_integers(*args, size=2**12) + assert str(dp_warn[0].message) == str(np_warn[0].message) + assert dp_warn[0].filename == __file__ + assert res.dtype == dpnp.int64 + # NumPy returns C longs, which are int32 on Windows + assert_equal( + numpy.unique(dpnp.asnumpy(res)), numpy.unique(exp), strict=False + ) - # default dtype depends on fp64 support by the device - dtype = get_default_floating() if dtype is None else dtype - expected = numpy.full(shape=shape, fill_value=low, dtype=dtype) + @pytest.mark.parametrize("args", [(5,), (-2, 3)]) + def test_random_integers_module_warning(self, args): + with pytest.warns(DeprecationWarning, match="randint") as w: + dpnp.random.random_integers(*args) + assert len(w) == 1 + assert w[0].filename == __file__ - assert_dtype_allclose(actual, expected) + def test_tomaxint(self): + res = RandomState(0).tomaxint(2**12) + assert res.dtype == dpnp.int64 + assert (res >= 0).all() + # the high bit is random too + assert (res > 2**62).any() - @pytest.mark.usefixtures("allow_fall_back_on_numpy") - def test_range_bounds(self): - fmin = dpnp.finfo("double").min - fmax = dpnp.finfo("double").max - func = RandomState().uniform - assert_raises(OverflowError, func, -numpy.inf, 0) - assert_raises(OverflowError, func, 0, numpy.inf) - assert_raises(OverflowError, func, -numpy.inf, numpy.inf) - assert_raises(OverflowError, func, fmin, fmax) - assert_raises(OverflowError, func, [-numpy.inf], [0]) - assert_raises(OverflowError, func, [0], [numpy.inf]) +class TestLegacy: + """The behaviors of RandomState that differ from the ones of Generator.""" - func(low=numpy.nextafter(fmin, 0), high=numpy.nextafter(fmax, 0)) + nan = numpy.nan - @pytest.mark.usefixtures("allow_fall_back_on_numpy") - @pytest.mark.parametrize( - "high", - [dpnp.array([3]), numpy.array([3])], - ids=["dpnp.array([3])", "numpy.array([3])"], - ) @pytest.mark.parametrize( - "low", - [[2], dpnp.array([2]), numpy.array([2])], - ids=["[2]", "dpnp.array([2])", "numpy.array([2])"], + "name, args", + [ + ("uniform", (-numpy.inf, 0.0)), + ("uniform", (0.0, numpy.inf)), + ("uniform", (-1e308, 1e308)), + ("uniform", ([-numpy.inf], [0.0])), + ("uniform", ([0.0], nan)), + ("normal", (0.0, -1.0)), + ("normal", (0.0, -0.0)), + ("exponential", ([-1.0],)), + ("gamma", (1.0, -1.0)), + ("chisquare", (0.0,)), + ("beta", (0.0, 1.0)), + ("wald", (1.0, 0.0)), + ("triangular", (1.0, 0.0, 2.0)), + ("vonmises", (0.0, -1.0)), + ("poisson", (-1.0,)), + ("poisson", (nan,)), + ("poisson", (1e19,)), + ("binomial", (-1, 0.5)), + ("binomial", (5, 1.5)), + ("binomial", (5, nan)), + ("negative_binomial", (0.0, 0.5)), + ("negative_binomial", (-1.0, 0.5)), + ("negative_binomial", (1.0, 1.5)), + ("negative_binomial", (1.0, nan)), + ("negative_binomial", ([1.0], [nan])), + ("geometric", (0.0,)), + ("logseries", (1.0,)), + ("zipf", (1.0,)), + ("hypergeometric", (1, 2, 4)), + ("hypergeometric", ([1], 2, 4)), + ("hypergeometric", (-1, 5, 3)), + ("hypergeometric", (5, -1, 3)), + ("hypergeometric", (5, 3, 0)), + ("hypergeometric", (5, 3, -1)), + ("hypergeometric", ([5], [3], [0])), + ("dirichlet", ([-1.0, 1.0],)), + ("dirichlet", ([0.0, 1.0],)), + ("multinomial", ([5], [0.5, 0.5])), + ("multinomial", (5, 0.5)), + ("multinomial", (5, [[0.5, 0.5]])), + ("multinomial", (5, [0.7, 0.7, 0.1])), + ("multinomial", (-1, [0.2, 0.8])), + ("multinomial", (5, [-0.1, 1.1])), + ("multivariate_normal", ([[0.0, 0.0]], numpy.eye(2))), + ("multivariate_normal", ([0.0, 0.0], numpy.eye(3))), + ( + "multivariate_normal", + ([0.0, 0.0], [[1.0, 2.0], [2.0, 1.0]], None, "raise"), + ), + ("permutation", (1.5,)), + ("permutation", (numpy.zeros(()),)), + ("choice", (0,)), + ("choice", (-1,)), + ("choice", (1.5,)), + ("choice", ([],)), + ("choice", ([[1, 2]],)), + ("choice", (3, 4, False)), + ("choice", (3, None, True, [0.5, 0.6, -0.1])), + ("choice", (3, None, True, [0.5, 0.6, 0.1])), + ("choice", (3, None, True, [0.5, nan, 0.5])), + ("choice", (3, None, True, [0.5, 0.5])), + ("choice", (3, None, True, [[0.5, 0.5, 0.0]])), + ("choice", (3, 2, False, [1.0, 0.0, 0.0])), + ("poisson", (None,)), + ("normal", (0.0, None)), + ("uniform", (None, 1.0)), + ("negative_binomial", (None, 0.5)), + ("exponential", ("x",)), + ("multinomial", (None, [0.5, 0.5])), + ("multinomial", ("5", [0.5, 0.5])), + ("multinomial", (5, "x")), + ], ) - def test_fallback(self, low, high): - seed = 15 - size = (3, 2, 5) - - sycl_queue = dpctl.SyclQueue() - data = RandomState(seed, sycl_queue=sycl_queue).uniform( - low=low, high=high, size=size + @pytest.mark.filterwarnings("ignore:overflow encountered:RuntimeWarning") + def test_same_error_as_numpy(self, name, args): + _assert_same_error( + lambda: getattr(numpy.random.RandomState(0), name)(*args), + lambda: getattr(RandomState(0), name)(*args), ) - # dpnp accepts only scalar as low and/or high, in other cases it will be a fallback to numpy - expected = numpy.random.RandomState(seed).uniform( - low=get_array(numpy, low), high=get_array(numpy, high), size=size - ) - - precision = dpnp.finfo(get_default_floating()).precision - assert_array_almost_equal(data, expected, decimal=precision) - - # check if compute follows data isn't broken - assert_cfd(data, sycl_queue) - @pytest.mark.parametrize( - "dtype", + "name, args", [ - dpnp.float16, - float, - dpnp.int64, - dpnp.int_, - int, - numpy.clongdouble, - dpnp.complex128, - dpnp.complex64, - dpnp.bool, - dpnp.bool_, - ], - ids=[ - "dpnp.float16", - "float", - "dpnp.int64", - "dpnp.int_", - "int", - "numpy.clongdouble", - "dpnp.complex128", - "dpnp.complex64", - "dpnp.bool", - "dpnp.bool_", + ("beta", ([1.0, -1.0], 1.0)), + ("binomial", ([3, -1], 0.5)), + ("binomial", (3, [0.5, 1.5])), + ("exponential", ([1.0, -1.0],)), + ("geometric", ([0.5, 0.0],)), + ("logseries", ([0.5, 1.0],)), + ("negative_binomial", ([1.0, 0.0], 0.5)), + ("noncentral_f", (1.0, [1.0, 0.0], 1.0)), + ("normal", (0.0, [1.0, -1.0])), + ("poisson", ([1.0, 1e19],)), + ("poisson", ([1.0, nan],)), + ("standard_gamma", ([1.0, -1.0],)), + ("zipf", ([2.0, 1.0],)), + ("hypergeometric", ([3, -1], 3, 2)), + ("hypergeometric", ([3, 1], 3, [2, 5])), + ("hypergeometric", ([3, 1], 3, [2, 0])), + ("triangular", ([0.0, 2.0], 1.0, 3.0)), + ("triangular", ([0.0, 3.0], 3.0, 3.0)), + ("uniform", ([0.0, -numpy.inf], 1.0)), + ("randint", ([0, 5], [3, 4])), + ("randint", ([0, -1], 3, None, "uint8")), + ("randint", (0, [3, 300], None, "uint8")), + ("choice", (3, 2, True, [0.5, 0.5, 0.5])), + ("choice", (3, 2, True, [0.5, -0.5, 1.0])), + ("choice", (3, 2, True, [0.5, nan, 0.5])), + ("choice", (3, 3, False, [0.5, 0.5, 0.0])), + ("multinomial", (3, [0.5, 1.5])), + ("multinomial", (3, [0.7, 0.7, 0.0])), + ("dirichlet", ([1.0, 0.0],)), ], ) - def test_invalid_dtype(self, dtype): - if dtype == dpnp.int_ and dtype == dpnp.dtype("int32"): - pytest.skip( - "dtype is alias on dpnp.int32 on the target OS, so no error here" - ) - - # dtype must be int32, float32 or float64 - assert_raises(TypeError, RandomState().uniform, dtype=dtype) + def test_same_error_as_numpy_on_device(self, name, args): + # unlike Generator, RandomState checks the parameters on the device + dp_args = [dpnp.asarray(a) if isinstance(a, list) else a for a in args] + _assert_same_error( + lambda: getattr(numpy.random.RandomState(0), name)(*args), + lambda: getattr(RandomState(0), name)(*dp_args), + ) + def test_uniform_reversed(self): + res = RandomState(0).uniform(2.0, 1.0, size=100) + assert ((res > 1.0) & (res <= 2.0)).all() + + def test_negative_binomial_accepted(self): + # NumPy's legacy checks allow p == 0 and a NaN n + rs = RandomState(0) + rs.negative_binomial(1.0, 0.0, size=4) + rs.negative_binomial(self.nan, 0.5, size=4) + + def test_hypergeometric_limit(self): + # unlike NumPy's legacy checks, the ones of Generator apply + assert_raises(ValueError, RandomState().hypergeometric, 10**9, 1, 1) + + def test_multinomial_empty(self): + res = RandomState(0).multinomial(5, [], size=3) + exp = numpy.random.RandomState(0).multinomial(5, [], size=3) + assert res.shape == exp.shape + assert res.dtype == dpnp.int64 + + def test_multinomial_float_n(self): + res = RandomState(0).multinomial(5.7, [0.5, 0.5], size=10) + assert (res.sum(axis=-1) == 5).all() + + def test_dirichlet_nan(self): + RandomState(0).dirichlet([self.nan, 1.0]) + + def test_multivariate_normal_svd(self): + cov = [[2.0, 1.0], [1.0, 2.0]] + res = RandomState(0).multivariate_normal([1.0, -1.0], cov, 2**16) + assert_allclose(dpnp.mean(res, axis=0), [1.0, -1.0], atol=0.05) + assert_allclose(numpy.cov(dpnp.asnumpy(res).T), cov, atol=0.05) + + def test_not_positive_semidefinite_warns(self): + cov = [[1.0, 2.0], [2.0, 1.0]] + with pytest.warns(RuntimeWarning, match="positive-semidefinite") as w: + RandomState(0).multivariate_normal([0.0, 0.0], cov) + assert w[0].filename == __file__ + with pytest.warns(RuntimeWarning, match="positive-semidefinite") as w: + dpnp.random.multivariate_normal([0.0, 0.0], cov) + assert w[0].filename == __file__ + + +class TestPermutations: @pytest.mark.parametrize( - "usm_type", ["", "unknown"], ids=["Empty", "Unknown"] + "dtype", get_all_dtypes(no_bool=True, no_none=True, no_complex=True) ) - def test_invalid_usm_type(self, usm_type): - # dtype must be float32 or float64 - assert_raises(ValueError, RandomState().uniform, usm_type=usm_type) - - def test_size_castable_to_integer(self): - M = numpy.int64(31) - N = numpy.int64(31) - K = 63 # plain Python int - - sizes = [(M, K), (M, N), (K, N)] - for size in sizes: - result = RandomState().uniform(size=size) - assert result.shape == size - - @testing.with_requires("numpy>=2.3.2") - @pytest.mark.parametrize("xp", [numpy, dpnp]) + def test_shuffle(self, dtype): + x = dpnp.arange(10, dtype=dtype) + RandomState(0).shuffle(x) + assert not (x == dpnp.arange(10, dtype=dtype)).all() + assert_array_equal(dpnp.sort(x), dpnp.arange(10, dtype=dtype)) + + def test_shuffle_reproducible(self): + x1 = dpnp.arange(10) + x2 = dpnp.arange(10) + RandomState(4).shuffle(x1) + RandomState(4).shuffle(x2) + assert_array_equal(x1, x2) + + def test_shuffle_rows(self): + x = dpnp.arange(20).reshape(10, 2) + RandomState(0).shuffle(x) + x = dpnp.asnumpy(x) + assert (x[:, 1] - x[:, 0] == 1).all() + assert_array_equal(numpy.sort(x[:, 0]), numpy.arange(0, 20, 2)) + @pytest.mark.parametrize( - "size", - [True, [True], dpnp.bool(True), numpy.array(True), numpy.array([True])], + "x", [[1, 2, 3], numpy.arange(3)], ids=["list", "numpy.ndarray"] ) - def test_bool_size(self, xp, size): - rs = xp.random.RandomState() - assert_raises(TypeError, rs.uniform, size=size) - - @pytest.mark.parametrize("size", [numpy.array(1), numpy.array([2])]) - def test_numpy_ndarray_size(self, size): - result = RandomState().uniform(size=size) - assert result.shape == size - - def test_dpnp_ndarray_size(self): - assert_raises(ValueError, RandomState().uniform, size=dpnp.array(1)) + def test_shuffle_not_dpnp_array(self, x): + # unlike NumPy, only a dpnp.ndarray is shuffled, like in CuPy + assert_raises(TypeError, RandomState().shuffle, x) + + def test_permutation_int(self): + res = RandomState(0).permutation(10) + assert res.dtype == dpnp.int64 + assert_array_equal(dpnp.sort(res), dpnp.arange(10)) + + def test_permutation_array(self): + x = dpnp.arange(20).reshape(10, 2) + res = RandomState(0).permutation(x) + assert_array_equal(x, dpnp.arange(20).reshape(10, 2)) + assert_array_equal(dpnp.sort(res[:, 0]), dpnp.arange(0, 20, 2)) + + def test_choice(self): + res = RandomState(0).choice(5, 2**12) + assert_equal(numpy.unique(dpnp.asnumpy(res)), numpy.arange(5)) + + res = RandomState(0).choice(5, 5, replace=False) + assert_array_equal(dpnp.sort(res), dpnp.arange(5)) + + res = RandomState(0).choice(5, 2**12, p=[0.0, 0.5, 0.0, 0.5, 0.0]) + assert_equal(numpy.unique(dpnp.asnumpy(res)), [1, 3]) + + def test_bytes(self): + res = RandomState(0).bytes(13) + assert isinstance(res, bytes) + assert len(res) == 13 diff --git a/dpnp/tests/test_sycl_queue.py b/dpnp/tests/test_sycl_queue.py index a315c6ff6bbe..77e05b8b401f 100644 --- a/dpnp/tests/test_sycl_queue.py +++ b/dpnp/tests/test_sycl_queue.py @@ -852,10 +852,15 @@ def test_vecmat(device, shape1, shape2): [], {"low": 2, "high": 15, "size": (4, 8, 16), "dtype": dpnp.int32}, ), - pytest.param("randn", [], {"d0": 20}), + pytest.param("randn", [20], {}), pytest.param("random", [], {"size": (35, 45)}), pytest.param( - "random_integers", [], {"low": -17, "high": 3, "size": (12, 16)} + "random_integers", + [], + {"low": -17, "high": 3, "size": (12, 16)}, + marks=pytest.mark.filterwarnings( + "ignore:This function is deprecated:DeprecationWarning" + ), ), pytest.param("random_sample", [], {"size": (7, 7)}), pytest.param("ranf", [], {"size": (10, 7, 12)}), @@ -1016,6 +1021,30 @@ def test_generator_permutations(func, device): assert_sycl_queue_equal(res.sycl_queue, sycl_queue) +@pytest.mark.parametrize( + "func, args", + [ + pytest.param("normal", ["f"]), + pytest.param("permutation", ["f"]), + pytest.param("poisson", ["f"]), + pytest.param("randint", ["i"]), + pytest.param("shuffle", ["f"]), + ], +) +@pytest.mark.parametrize("device", valid_dev, ids=dev_ids) +def test_random_param_queue(func, args, device): + # with no device given, the functions use the queue of the parameters + sycl_queue = dpctl.SyclQueue(device) + x = { + "f": dpnp.full(4, 2.0, sycl_queue=sycl_queue), + "i": dpnp.full(4, 5, sycl_queue=sycl_queue), + } + res = getattr(dpnp.random, func)(*[x[a] for a in args]) + if res is None: + res = x[args[0]] + assert_sycl_queue_equal(res.sycl_queue, sycl_queue) + + # "f", "i" and "p" stand for float, integer and probability arrays on another # queue than the generator's _diff_queue_methods = [ @@ -1074,6 +1103,44 @@ def test_generator_diff_queue(func, args, device): getattr(rng, func)(*args, **kwargs) +@pytest.mark.parametrize( + "func, args", _diff_queue_methods + [pytest.param("randint", ["i"])] +) +@pytest.mark.parametrize("device", valid_dev, ids=dev_ids) +def test_random_state_diff_queue(func, args, device): + rs = dpnp.random.RandomState(1, device=device) + args = _diff_queue_args(args, device) + with assert_raises(ExecutionPlacementError): + getattr(rs, func)(*args) + if func != "shuffle": # shuffle has no device keyword, as in NumPy + with assert_raises(ExecutionPlacementError): + getattr(dpnp.random, func)(*args, device=device) + + +@pytest.mark.parametrize( + "func, args", + [ + pytest.param("binomial", ["i", "p"]), + pytest.param("choice", ["f", None, True, "p"]), + pytest.param("hypergeometric", ["i", "i", 1]), + pytest.param("normal", ["f", "f"]), + pytest.param("triangular", [0.0, "f", "f"]), + pytest.param("uniform", ["f", "f"]), + ], +) +@pytest.mark.parametrize("device", valid_dev, ids=dev_ids) +def test_random_func_params_diff_queue(func, args, device): + # each array on its own queue + args = [ + _diff_queue_args([a], device)[0] if isinstance(a, str) else a + for a in args + ] + n_states = len(dpnp.random.dpnp_iface_random._dpnp_random_states) + with assert_raises(ExecutionPlacementError): + getattr(dpnp.random, func)(*args) + assert len(dpnp.random.dpnp_iface_random._dpnp_random_states) == n_states + + @pytest.mark.parametrize("device", valid_dev, ids=dev_ids) def test_einsum(device): array_list = [] diff --git a/dpnp/tests/test_usm_type.py b/dpnp/tests/test_usm_type.py index 6550d1f2e3dc..ffc2c52742b6 100644 --- a/dpnp/tests/test_usm_type.py +++ b/dpnp/tests/test_usm_type.py @@ -1866,7 +1866,7 @@ def test_tensorsolve(self, usm_type, usm_type_other): ) @pytest.mark.parametrize("usm_type", list_of_usm_types) def test_generator(func, args, kwargs, usm_type): - for rng in (dpnp.random.default_rng(1),): + for rng in (dpnp.random.default_rng(1), dpnp.random.RandomState(1)): meth = getattr(rng, func, None) if meth is None: # a Generator method RandomState doesn't have continue @@ -1894,6 +1894,7 @@ def test_generator_permutations(usm_type): assert rng.permutation(x, axis=1).usm_type == usm_type assert rng.permuted(x).usm_type == usm_type assert rng.permuted(x, axis=1).usm_type == usm_type + assert dpnp.random.RandomState(1).permutation(x).usm_type == usm_type rng.shuffle(x) assert x.usm_type == usm_type diff --git a/dpnp/tests/third_party/cupy/random_tests/common_distributions.py b/dpnp/tests/third_party/cupy/random_tests/common_distributions.py index c7f7f9776316..e62044636451 100644 --- a/dpnp/tests/third_party/cupy/random_tests/common_distributions.py +++ b/dpnp/tests/third_party/cupy/random_tests/common_distributions.py @@ -2,11 +2,17 @@ import unittest import numpy +import pytest import dpnp as cupy +from dpnp.tests.helper import has_support_aspect64 from dpnp.tests.third_party.cupy import testing from dpnp.tests.third_party.cupy.testing import _condition +_requires_fp64 = pytest.mark.skipif( + not has_support_aspect64(), reason="fp64 is required" +) + def two_sample_Kolmogorov_Smirnov_test(observed1, observed2): """Computes the Kolmogorov-Smirnov statistic on 2 samples @@ -158,6 +164,7 @@ def test_uniform(self): assert cupy.all(result >= cupy.asarray(low).min()) assert cupy.all(result < cupy.asarray(high).max()) + @_requires_fp64 @_condition.repeat_with_success_at_least(10, 3) def test_uniform_ks(self): if isinstance(self.low, list) or isinstance(self.high, list): @@ -187,6 +194,7 @@ def test_beta(self): b = cupy.array(self.b) self.generate(a, b, size=(3, 5)) + @_requires_fp64 @_condition.repeat_with_success_at_least(10, 3) def test_beta_ks(self): if isinstance(self.a, list) or isinstance(self.b, list): @@ -259,6 +267,7 @@ class Exponential: def test_exponential(self): self.generate(scale=self.scale, size=(3, 2)) + @_requires_fp64 @_condition.repeat_with_success_at_least(10, 3) def test_exponential_ks(self): self.check_ks(0.05)(self.scale, size=2000) @@ -305,6 +314,7 @@ def test_gamma_1(self): def test_gamma_2(self): self.generate(shape=self.shape, size=(3, 2)) + @_requires_fp64 @_condition.repeat_with_success_at_least(10, 3) def test_gamma_ks(self): self.check_ks(0.05)(self.shape, self.scale, size=2000) @@ -416,6 +426,7 @@ def test_power(self): a = cupy.array(self.a) self.generate(a=a) + @_requires_fp64 @_condition.repeat_with_success_at_least(10, 3) def test_power_ks(self): if not isinstance(self.a, float): @@ -466,6 +477,7 @@ def test_chisquare(self): df = cupy.array(self.df) self.generate(df=df) + @_requires_fp64 @_condition.repeat_with_success_at_least(10, 3) def test_chisquare_ks(self): if not isinstance(self.df, float): @@ -493,6 +505,7 @@ def test_f(self): dfden = cupy.array(self.dfden) self.generate(dfnum, dfden) + @_requires_fp64 @_condition.repeat_with_success_at_least(10, 3) def test_f_ks(self): if isinstance(self.dfnum, list) or isinstance(self.dfden, list): diff --git a/dpnp/tests/third_party/cupy/random_tests/test_bit_generator.py b/dpnp/tests/third_party/cupy/random_tests/test_bit_generator.py index 339b2457c490..d5f5d1bdeaa4 100644 --- a/dpnp/tests/third_party/cupy/random_tests/test_bit_generator.py +++ b/dpnp/tests/third_party/cupy/random_tests/test_bit_generator.py @@ -7,8 +7,6 @@ from dpnp import random from dpnp.tests.third_party.cupy import testing -pytest.skip("bit generator is not supported yet", allow_module_level=True) - class BitGeneratorTestCase: @@ -49,6 +47,7 @@ def test_array_seed(self): @testing.with_requires("numpy>=1.17.0") @testing.fix_random() +@pytest.mark.skip("XORWOW is not provided") class TestBitGeneratorXORWOW(BitGeneratorTestCase, unittest.TestCase): def setUp(self): super().setUp() diff --git a/dpnp/tests/third_party/cupy/random_tests/test_distributions.py b/dpnp/tests/third_party/cupy/random_tests/test_distributions.py index b72edc4c90c9..7a3a03e20a79 100644 --- a/dpnp/tests/third_party/cupy/random_tests/test_distributions.py +++ b/dpnp/tests/third_party/cupy/random_tests/test_distributions.py @@ -83,7 +83,6 @@ def test_beta(self, a_dtype, b_dtype): ) class TestDistributionsBinomial(RandomDistributionsTestCase): - @pytest.mark.skip("n and p params as arrays are not supported") @testing.for_signed_dtypes("n_dtype") @testing.for_float_dtypes("p_dtype") def test_binomial(self, n_dtype, p_dtype): @@ -230,7 +229,6 @@ def test_gamma_legacy(self, shape_dtype, scale_dtype): _distributions.gamma, shape_dtype, scale_dtype, self.dtype ) - @pytest.mark.skip("no support of generator yet") @testing.for_dtypes_combination( _float_dtypes, names=["shape_dtype", "scale_dtype"] ) @@ -434,7 +432,6 @@ def test_logseries_for_invalid_p(self, p_dtype): } ) ) -@pytest.mark.skip("multivariate_normal is not fully supported yet") class TestDistributionsMultivariateNormal: def check_distribution(self, dist_func, mean_dtype, cov_dtype, dtype): @@ -648,7 +645,6 @@ def check_distribution(self, dist_func, lam_dtype, dtype=None): def test_poisson_legacy(self, lam_dtype): self.check_distribution(_distributions.poisson, lam_dtype) - @pytest.mark.skip("no support of generator yet") @testing.for_float_dtypes("lam_dtype") def test_poisson_generator(self, lam_dtype): self.check_distribution(cupy.random.default_rng(0).poisson, lam_dtype) @@ -656,7 +652,6 @@ def test_poisson_generator(self, lam_dtype): class TestDistributionsPoissonInvalid: - @pytest.mark.skip("no support of generator yet") def test_none_lam_generator(self): with pytest.raises(TypeError): cupy.random.default_rng(0).poisson(None) @@ -770,7 +765,7 @@ def test_standard_gamma_legacy(self, shape_dtype): shape = numpy.ones(self.shape_shape, dtype=shape_dtype) self.check_distribution("standard_gamma", {"shape": shape}) - @pytest.mark.skip("no support of generator yet") + @pytest.mark.skipif(not has_support_aspect64(), reason="fp64 is required") @testing.for_float_dtypes("dtype", no_float16=True) @testing.for_float_dtypes("shape_dtype") def test_standard_gamma_generator(self, shape_dtype, dtype): @@ -782,7 +777,6 @@ def test_standard_gamma_generator(self, shape_dtype, dtype): class TestDistributionsStandardGammaInvalid(RandomDistributionsTestCase): - @pytest.mark.skip("no support of generator yet") def test_none_shape_generator(self): with pytest.raises(TypeError): cupy.random.default_rng(0).standard_gamma(None) diff --git a/dpnp/tests/third_party/cupy/random_tests/test_generator.py b/dpnp/tests/third_party/cupy/random_tests/test_generator.py index af33a006b52e..09c33dd28d48 100644 --- a/dpnp/tests/third_party/cupy/random_tests/test_generator.py +++ b/dpnp/tests/third_party/cupy/random_tests/test_generator.py @@ -18,7 +18,10 @@ from . import common_distributions -pytest.skip("random.generator() is not supported yet", allow_module_level=True) +pytest.skip( + "tests the internals of CuPy's legacy random generator", + allow_module_level=True, +) def test_get_indices_preserves_uint64_cumsum_values(): diff --git a/dpnp/tests/third_party/cupy/random_tests/test_generator_api.py b/dpnp/tests/third_party/cupy/random_tests/test_generator_api.py index 4f7a5d9783b4..081667f0e481 100644 --- a/dpnp/tests/third_party/cupy/random_tests/test_generator_api.py +++ b/dpnp/tests/third_party/cupy/random_tests/test_generator_api.py @@ -8,12 +8,15 @@ import dpnp as cupy from dpnp import random +from dpnp.tests.helper import has_support_aspect64 from dpnp.tests.third_party.cupy import testing from dpnp.tests.third_party.cupy.testing import _condition from . import common_distributions -pytest.skip("random.Generator() is not supported yet", allow_module_level=True) +_requires_fp64 = pytest.mark.skipif( + not has_support_aspect64(), reason="fp64 is required" +) class GeneratorTestCase(common_distributions.BaseGeneratorTestCase): @@ -49,12 +52,15 @@ def invalid_shape(self, **kwargs): with pytest.raises(ValueError): self.generate(size=(3, 2), out=out, **kwargs) + @_requires_fp64 def test_invalid_dtype_out(self): self.invalid_dtype_out() + @_requires_fp64 def test_invalid_contiguity(self): self.invalid_contiguity() + @_requires_fp64 def test_invalid_shape(self): self.invalid_shape() @@ -127,9 +133,11 @@ class TestStandardGammaInvalid(InvalidOutsMixin, GeneratorTestCase): target_method = "standard_gamma" + @_requires_fp64 def test_invalid_dtype_out(self): self.invalid_dtype_out(shape=1.0) + @_requires_fp64 def test_invalid_contiguity(self): self.invalid_contiguity(shape=1.0) @@ -137,6 +145,7 @@ def test_invalid_contiguity(self): with pytest.raises(ValueError): self.generate(size=(4, 6), out=out, shape=1.0) + @_requires_fp64 def test_invalid_shape(self): self.invalid_shape(shape=1.0) @@ -338,6 +347,7 @@ def test_hypergeometric_nsample_equals_total(self): out = self.gen.hypergeometric(5, 10, 15, size=10) testing.assert_array_equal(out, cupy.full(10, 5, dtype=cupy.int64)) + @pytest.mark.skip("NumPy raises ValueError for nsample > ngood + nbad") def test_hypergeometric_nsample_exceeds_total(self): # nsample > ngood + nbad would previously cause an infinite # loop in the HRUA kernel. The kernel now routes this through @@ -361,13 +371,14 @@ class TestPower(common_distributions.Power, GeneratorTestCase): @testing.with_requires("numpy>=1.17.0") -@pytest.mark.skipif( - cupy.cuda.runtime.is_hip - and (int(str(cupy.cuda.runtime.runtimeGetVersion())[:3]) < 403), - reason="HIP<4.3 not supported ", -) +# @pytest.mark.skipif( +# cupy.cuda.runtime.is_hip +# and (int(str(cupy.cuda.runtime.runtimeGetVersion())[:3]) < 403), +# reason="HIP<4.3 not supported ", +# ) class TestRandomStateThreadSafe(unittest.TestCase): + @pytest.mark.skip("uses cupy.cuda.Device") def test_default_rng_thread_safe(self): def _f(func, args=()): cupy.cuda.Device().use() @@ -416,11 +427,16 @@ class TestF(common_distributions.F, GeneratorTestCase): @testing.parameterize(*common_distributions.dirichlet_params) @testing.fix_random() +@pytest.mark.skip( + "dpnp raises TypeError for a scalar alpha, as NumPy does, and two of " + "the alpha params are scalars" +) class TestDrichlet(common_distributions.Dirichlet, GeneratorTestCase): pass @testing.slow +@pytest.mark.skip("XORWOW is not provided") class TestLarge: # @pytest.mark.thread_unsafe(reason="allocates large memory") def test_large(self): diff --git a/dpnp/tests/third_party/cupy/random_tests/test_permutations.py b/dpnp/tests/third_party/cupy/random_tests/test_permutations.py index ac36d985b2c0..12c8da030bf2 100644 --- a/dpnp/tests/third_party/cupy/random_tests/test_permutations.py +++ b/dpnp/tests/third_party/cupy/random_tests/test_permutations.py @@ -20,13 +20,12 @@ def _xp_random(self, xp): if self.seed is None: return xp.random else: - pytest.skip("random.RandomState.permutation() is not supported yet") return xp.random.RandomState(seed=self.seed) # Test ranks # TODO(niboshi): Fix xfail - @pytest.mark.xfail(reason="Explicit error types required") + # @pytest.mark.xfail(reason="Explicit error types required") def test_permutation_zero_dim(self): for xp in (numpy, cupy): xp_random = self._xp_random(xp) @@ -38,11 +37,6 @@ def test_permutation_zero_dim(self): @testing.for_all_dtypes(no_float16=True, no_bool=True, no_complex=True) def test_permutation_sort_1dim(self, dtype): - flag = cupy.issubdtype(dtype, cupy.unsignedinteger) - if flag or dtype in [cupy.int8, cupy.int16]: - pytest.skip( - "dpnp.random.permutation() does not support new integer dtypes." - ) cupy_random = self._xp_random(cupy) a = cupy.arange(10, dtype=dtype) b = cupy.copy(a) @@ -52,11 +46,6 @@ def test_permutation_sort_1dim(self, dtype): @testing.for_all_dtypes(no_float16=True, no_bool=True, no_complex=True) def test_permutation_sort_ndim(self, dtype): - flag = cupy.issubdtype(dtype, cupy.unsignedinteger) - if flag or dtype in [cupy.int8, cupy.int16]: - pytest.skip( - "dpnp.random.permutation() does not support new integer dtypes." - ) cupy_random = self._xp_random(cupy) a = cupy.arange(15, dtype=dtype).reshape(5, 3) b = cupy.copy(a) @@ -70,11 +59,6 @@ def test_permutation_sort_ndim(self, dtype): # @pytest.mark.thread_unsafe(reason="relies on global random state") @testing.for_all_dtypes() def test_permutation_seed1(self, dtype): - flag = cupy.issubdtype(dtype, cupy.unsignedinteger) - if flag or dtype in [cupy.int8, cupy.int16]: - pytest.skip( - "dpnp.random.permutation() does not support new integer dtypes." - ) a = testing.shaped_random((10,), cupy, dtype) b = cupy.copy(a) @@ -95,7 +79,6 @@ class TestShuffle(unittest.TestCase): # Test ranks - @pytest.mark.skip("no proper validation yet") def test_shuffle_zero_dim(self): for xp in (numpy, cupy): a = testing.shaped_random((), xp) @@ -106,11 +89,6 @@ def test_shuffle_zero_dim(self): @testing.for_all_dtypes(no_float16=True, no_bool=True, no_complex=True) def test_shuffle_sort_1dim(self, dtype): - flag = cupy.issubdtype(dtype, cupy.unsignedinteger) - if flag or dtype in [cupy.int8, cupy.int16]: - pytest.skip( - "dpnp.random.shuffle() does not support new integer dtypes." - ) a = cupy.arange(10, dtype=dtype) b = cupy.copy(a) cupy.random.shuffle(a) @@ -118,11 +96,6 @@ def test_shuffle_sort_1dim(self, dtype): @testing.for_all_dtypes(no_float16=True, no_bool=True, no_complex=True) def test_shuffle_sort_ndim(self, dtype): - flag = cupy.issubdtype(dtype, cupy.unsignedinteger) - if flag or dtype in [cupy.int8, cupy.int16]: - pytest.skip( - "dpnp.random.shuffle() does not support new integer dtypes." - ) a = cupy.arange(15, dtype=dtype).reshape(5, 3) b = cupy.copy(a) cupy.random.shuffle(a) @@ -134,11 +107,6 @@ def test_shuffle_sort_ndim(self, dtype): # @pytest.mark.thread_unsafe(reason="relies on global random state") @testing.for_all_dtypes() def test_shuffle_seed1(self, dtype): - flag = cupy.issubdtype(dtype, cupy.unsignedinteger) - if flag or dtype in [cupy.int8, cupy.int16]: - pytest.skip( - "dpnp.random.shuffle() does not support new integer dtypes." - ) a = testing.shaped_random((10,), cupy, dtype) b = cupy.copy(a) cupy.random.seed(0) @@ -204,7 +172,7 @@ def setUp(self): # Note that this is not an established method to check randomness. # TODO(anaruse): implement randomness check using some established methods. @_condition.repeat_with_success_at_least(5, 3) - @pytest.mark.skip("no support of index as numpy array") + @pytest.mark.skip("numpy.count_nonzero does not accept a dpnp.ndarray") def test_permutation_randomness(self): if self.mask > self.num_half: return diff --git a/dpnp/tests/third_party/cupy/random_tests/test_random.py b/dpnp/tests/third_party/cupy/random_tests/test_random.py index 994667bdcde8..9f0db6bd5f36 100644 --- a/dpnp/tests/third_party/cupy/random_tests/test_random.py +++ b/dpnp/tests/third_party/cupy/random_tests/test_random.py @@ -6,7 +6,7 @@ from dpnp.tests.third_party.cupy import testing -@pytest.mark.skip("random.get_random_state() is not supported yet") +@pytest.mark.skip("random.get_random_state() is CuPy-only API") class TestResetSeed(unittest.TestCase): # thread_unsafe marker requires pytest-run-parallel, not used by dpnp diff --git a/dpnp/tests/third_party/cupy/random_tests/test_sample.py b/dpnp/tests/third_party/cupy/random_tests/test_sample.py index 645d6a252ad5..aae85ca68aa8 100644 --- a/dpnp/tests/third_party/cupy/random_tests/test_sample.py +++ b/dpnp/tests/third_party/cupy/random_tests/test_sample.py @@ -105,7 +105,6 @@ def test_goodness_of_fit_2(self): assert _hypothesis.chi_square_test(counts, expected) -@pytest.mark.skip("high=(max+1) is not supported") class TestRandintDtype(unittest.TestCase): @testing.with_requires("numpy>=2.0") @@ -120,6 +119,7 @@ def test_dtype(self, dtype): assert low <= min(x) assert max(x) <= high + @pytest.mark.skip("dpnp.ndarray has no get()") @testing.for_int_dtypes(no_bool=True) @testing.for_dtypes([numpy.int32]) def test_dtype2(self, dtype): @@ -146,6 +146,10 @@ def test_dtype2(self, dtype): random.randint(iinfo.max - 10, iinfo.max + 2, size, dtype) +@pytest.mark.skip( + "dpnp passes the arguments of randint positionally, and low=1 for " + "high=None as NumPy does" +) class TestRandomIntegers(unittest.TestCase): def test_normal(self): @@ -171,6 +175,9 @@ def test_size_is_not_none(self): @testing.fix_random() +@pytest.mark.filterwarnings( + "ignore:This function is deprecated:DeprecationWarning" +) class TestRandomIntegers2(unittest.TestCase): @_condition.repeat(3, 10) @@ -207,7 +214,7 @@ def test_goodness_of_fit_2(self): assert _hypothesis.chi_square_test(counts, expected) -@pytest.mark.skip("random.choice() is not supported yet") +@pytest.mark.skip("mocks CuPy internals (random._generator._random_states)") class TestChoice(unittest.TestCase): def setUp(self): @@ -255,11 +262,13 @@ def test_no_none(self): class TestRandomSample(unittest.TestCase): + @pytest.mark.skip("dpnp passes size and dtype positionally") def test_rand(self): with mock.patch("dpnp.random.RandomState.random_sample") as m: random.rand(1, 2, 3) m.assert_called_once_with(size=(1, 2, 3), usm_type="device") + @pytest.mark.skip("dpnp passes size and dtype positionally") def test_rand_default_dtype(self): with mock.patch("dpnp.random.RandomState.random_sample") as m: random.rand(1, 2, 3) @@ -269,11 +278,13 @@ def test_rand_invalid_argument(self): with self.assertRaises(TypeError): random.rand(1, 2, 3, unnecessary="unnecessary_argument") + @pytest.mark.skip("dpnp passes size and dtype positionally") def test_randn(self): with mock.patch("dpnp.random.RandomState.standard_normal") as m: random.randn(1, 2, 3) m.assert_called_once_with(size=(1, 2, 3), usm_type="device") + @pytest.mark.skip("dpnp passes size and dtype positionally") def test_randn_default_dtype(self): with mock.patch("dpnp.random.RandomState.standard_normal") as m: random.randn(1, 2, 3) @@ -292,7 +303,10 @@ def test_randn_invalid_argument(self): {"size": (1, 0)}, ) @testing.fix_random() -@pytest.mark.skip("random.multinomial() is not fully supported") +@pytest.mark.skip( + "tests CuPy's internal _sample._multinominal_kernel, and asserts " + 'dtype.kind == "l", which fails for NumPy as well' +) class TestMultinomial(unittest.TestCase): def test_kernel_accepts_large_n(self):