From 5574a2264066c19c17cffb7fcae1c5fc460a6865 Mon Sep 17 00:00:00 2001 From: Vahid Tavanashad Date: Sun, 25 Feb 2024 09:46:45 -0600 Subject: [PATCH 1/7] impelement dpnp.norm --- dpnp/backend/extensions/blas/blas_py.cpp | 10 +- dpnp/linalg/dpnp_algo_linalg.pyx | 106 ---- dpnp/linalg/dpnp_iface_linalg.py | 130 +++-- dpnp/linalg/dpnp_utils_linalg.py | 149 ++++++ tests/skipped_tests.tbl | 10 - tests/skipped_tests_gpu_no_fp64.tbl | 7 - tests/test_linalg.py | 471 +++++++++++++++--- tests/test_mathematical.py | 19 +- tests/test_product.py | 133 ++--- tests/test_sycl_queue.py | 50 ++ tests/test_usm_type.py | 40 ++ .../cupy/linalg_tests/test_norms.py | 49 ++ 12 files changed, 834 insertions(+), 340 deletions(-) diff --git a/dpnp/backend/extensions/blas/blas_py.cpp b/dpnp/backend/extensions/blas/blas_py.cpp index d091923e63e..3609cbfc24e 100644 --- a/dpnp/backend/extensions/blas/blas_py.cpp +++ b/dpnp/backend/extensions/blas/blas_py.cpp @@ -52,7 +52,7 @@ PYBIND11_MODULE(_blas_impl, m) { m.def("_dot", &blas_ext::dot, - "Call `dot` from OneMKL LAPACK library to return " + "Call `dot` from OneMKL BLAS library to return " "the dot product of two real-valued vectors.", py::arg("sycl_queue"), py::arg("vectorA"), py::arg("vectorB"), py::arg("result"), py::arg("depends") = py::list()); @@ -60,7 +60,7 @@ PYBIND11_MODULE(_blas_impl, m) { m.def("_dotc", &blas_ext::dotc, - "Call `dotc` from OneMKL LAPACK library to return " + "Call `dotc` from OneMKL BLAS library to return " "the dot product of two complex vectors, " "conjugating the first vector.", py::arg("sycl_queue"), py::arg("vectorA"), py::arg("vectorB"), @@ -69,7 +69,7 @@ PYBIND11_MODULE(_blas_impl, m) { m.def("_dotu", &blas_ext::dotu, - "Call `dotu` from OneMKL LAPACK library to return " + "Call `dotu` from OneMKL BLAS library to return " "the dot product of two complex vectors.", py::arg("sycl_queue"), py::arg("vectorA"), py::arg("vectorB"), py::arg("result"), py::arg("depends") = py::list()); @@ -77,7 +77,7 @@ PYBIND11_MODULE(_blas_impl, m) { m.def("_gemm", &blas_ext::gemm, - "Call `gemm` from OneMKL LAPACK library to return " + "Call `gemm` from OneMKL BLAS library to return " "the matrix-matrix product with 2-D matrices.", py::arg("sycl_queue"), py::arg("matrixA"), py::arg("matrixB"), py::arg("result"), py::arg("depends") = py::list()); @@ -85,7 +85,7 @@ PYBIND11_MODULE(_blas_impl, m) { m.def("_gemm_batch", &blas_ext::gemm_batch, - "Call `gemm_batch` from OneMKL LAPACK library to return " + "Call `gemm_batch` from OneMKL BLAS library to return " "the matrix-matrix product for a batch of 2-D matrices.", py::arg("sycl_queue"), py::arg("matrixA"), py::arg("matrixB"), py::arg("result"), py::arg("batch_size"), py::arg("stridea"), diff --git a/dpnp/linalg/dpnp_algo_linalg.pyx b/dpnp/linalg/dpnp_algo_linalg.pyx index 83597ad7595..126e7bdbea5 100644 --- a/dpnp/linalg/dpnp_algo_linalg.pyx +++ b/dpnp/linalg/dpnp_algo_linalg.pyx @@ -48,7 +48,6 @@ __all__ = [ "dpnp_cond", "dpnp_eig", "dpnp_eigvals", - "dpnp_norm", ] @@ -171,108 +170,3 @@ cpdef utils.dpnp_descriptor dpnp_eigvals(utils.dpnp_descriptor input): c_dpctl.DPCTLEvent_Delete(event_ref) return res_val - - -cpdef object dpnp_norm(object input, ord=None, axis=None): - cdef long size_input = input.size - cdef shape_type_c shape_input = input.shape - - dev = input.get_array().sycl_device - if input.dtype == dpnp.float32 or not dev.has_aspect_fp64: - res_type = dpnp.float32 - else: - res_type = dpnp.float64 - - if size_input == 0: - return dpnp.array([dpnp.nan], dtype=res_type) - - if isinstance(axis, int): - axis_ = tuple([axis]) - else: - axis_ = axis - - ndim = input.ndim - if axis is None: - if ((ord is None) or - (ord in ('f', 'fro') and ndim == 2) or - (ord == 2 and ndim == 1)): - - # TODO: change order='K' when support is implemented - input = dpnp.ravel(input, order='C') - sqnorm = dpnp.dot(input, input) - ret = dpnp.sqrt([sqnorm], dtype=res_type) - return dpnp.array(ret.reshape(1, *ret.shape), dtype=res_type) - - len_axis = 1 if axis is None else len(axis_) - if len_axis == 1: - if ord == dpnp.inf: - return dpnp.array([dpnp.abs(input).max(axis=axis)]) - elif ord == -dpnp.inf: - return dpnp.array([dpnp.abs(input).min(axis=axis)]) - elif ord == 0: - return input.dtype.type(dpnp.count_nonzero(input, axis=axis)) - elif ord is None or ord == 2: - s = input * input - return dpnp.sqrt(dpnp.sum(s, axis=axis), dtype=res_type) - elif isinstance(ord, str): - raise ValueError(f"Invalid norm order '{ord}' for vectors") - else: - absx = dpnp.abs(input) - absx_size = absx.size - absx_power = utils_py.create_output_descriptor_py((absx_size,), absx.dtype, None).get_pyobj() - - absx_flatiter = absx.flat - - for i in range(absx_size): - absx_elem = absx_flatiter[i] - absx_power[i] = absx_elem ** ord - absx_ = dpnp.reshape(absx_power, absx.shape) - ret = dpnp.sum(absx_, axis=axis) - ret_size = ret.size - ret_power = utils_py.create_output_descriptor_py((ret_size,), None, None).get_pyobj() - - ret_flatiter = ret.flat - - for i in range(ret_size): - ret_elem = ret_flatiter[i] - ret_power[i] = ret_elem ** (1 / ord) - ret_ = dpnp.reshape(ret_power, ret.shape) - return ret_ - elif len_axis == 2: - row_axis, col_axis = axis_ - if row_axis == col_axis: - raise ValueError('Duplicate axes given.') - # if ord == 2: - # ret = _multi_svd_norm(input, row_axis, col_axis, amax) - # elif ord == -2: - # ret = _multi_svd_norm(input, row_axis, col_axis, amin) - elif ord == 1: - if col_axis > row_axis: - col_axis -= 1 - dpnp_sum_val = dpnp.sum(dpnp.abs(input), axis=row_axis) - ret = dpnp_sum_val.min(axis=col_axis) - elif ord == dpnp.inf: - if row_axis > col_axis: - row_axis -= 1 - dpnp_sum_val = dpnp.sum(dpnp.abs(input), axis=col_axis) - ret = dpnp_sum_val.max(axis=row_axis) - elif ord == -1: - if col_axis > row_axis: - col_axis -= 1 - dpnp_sum_val = dpnp.sum(dpnp.abs(input), axis=row_axis) - ret = dpnp_sum_val.min(axis=col_axis) - elif ord == -dpnp.inf: - if row_axis > col_axis: - row_axis -= 1 - dpnp_sum_val = dpnp.sum(dpnp.abs(input), axis=col_axis) - ret = dpnp_sum_val.min(axis=row_axis) - elif ord in [None, 'fro', 'f']: - ret = dpnp.sqrt(dpnp.sum(input * input, axis=axis)) - # elif ord == 'nuc': - # ret = _multi_svd_norm(input, row_axis, col_axis, sum) - else: - raise ValueError("Invalid norm order for matrices.") - - return ret - else: - raise ValueError("Improper number of dimensions to norm.") diff --git a/dpnp/linalg/dpnp_iface_linalg.py b/dpnp/linalg/dpnp_iface_linalg.py index 81680cbe028..561c3af5427 100644 --- a/dpnp/linalg/dpnp_iface_linalg.py +++ b/dpnp/linalg/dpnp_iface_linalg.py @@ -53,6 +53,7 @@ dpnp_inv, dpnp_matrix_rank, dpnp_multi_dot, + dpnp_norm, dpnp_pinv, dpnp_qr, dpnp_slogdet, @@ -456,7 +457,7 @@ def multi_dot(arrays, *, out=None): """ Compute the dot product of two or more arrays in a single function call. - For full documentation refer to :obj:`numpy.multi_dot`. + For full documentation refer to :obj:`numpy.linalg.multi_dot`. Parameters ---------- @@ -567,60 +568,109 @@ def pinv(a, rcond=1e-15, hermitian=False): return dpnp_pinv(a, rcond=rcond, hermitian=hermitian) -def norm(x1, ord=None, axis=None, keepdims=False): +def norm(x, ord=None, axis=None, keepdims=False): """ Matrix or vector norm. - This function is able to return one of eight different matrix norms, - or one of an infinite number of vector norms (described below), depending - on the value of the ``ord`` parameter. + For full documentation refer to :obj:`numpy.linalg.norm`. Parameters ---------- - input : array_like - Input array. If `axis` is None, `x` must be 1-D or 2-D, unless `ord` - is None. If both `axis` and `ord` are None, the 2-norm of - ``x.ravel`` will be returned. - ord : optional - Order of the norm (see table under ``Notes``). inf means numpy's - `inf` object. The default is None. - axis : optional. + x : {dpnp.ndarray, usm_ndarray} + Input array. If `axis` is ``None``, `x` must be 1-D or 2-D, unless + `ord` is ``None``. If both `axis` and `ord` are ``None``, the 2-norm + of ``x.ravel`` will be returned. + ord : {non-zero int, inf, -inf, "fro", "nuc"}, optional + Norm type. inf means dpnp's `inf` object. The default is ``None``. + axis : {None, int, 2-tuple of ints}, optional If `axis` is an integer, it specifies the axis of `x` along which to compute the vector norms. If `axis` is a 2-tuple, it specifies the axes that hold 2-D matrices, and the matrix norms of these matrices - are computed. If `axis` is None then either a vector norm (when `x` - is 1-D) or a matrix norm (when `x` is 2-D) is returned. The default - is None. + are computed. If `axis` is ``None`` then either a vector norm (when + `x` is 1-D) or a matrix norm (when `x` is 2-D) is returned. + The default is ``None``. keepdims : bool, optional - If this is set to True, the axes which are normed over are left in the - result as dimensions with size one. With this option the result will - broadcast correctly against the original `x`. + If this is set to ``True``, the axes which are normed over are left in + the result as dimensions with size one. With this option the result + will broadcast correctly against the original `x`. Returns ------- - n : float or ndarray + out : dpnp.ndarray Norm of the matrix or vector(s). - """ - - x1_desc = dpnp.get_dpnp_descriptor(x1, copy_when_nondefault_queue=False) - if x1_desc: - if ( - not isinstance(axis, int) - and not isinstance(axis, tuple) - and axis is not None - ): - pass - elif keepdims is not False: - pass - elif ord not in [None, 0, 3, "fro", "f"]: - pass - else: - result_obj = dpnp_norm(x1, ord=ord, axis=axis) - result = dpnp.convert_single_elem_array_to_scalar(result_obj) - - return result - return call_origin(numpy.linalg.norm, x1, ord, axis, keepdims) + Examples + -------- + >>> import dpnp as np + >>> a = np.arange(9) - 4 + >>> a + array([-4, -3, -2, -1, 0, 1, 2, 3, 4]) + >>> b = a.reshape((3, 3)) + >>> b + array([[-4, -3, -2], + [-1, 0, 1], + [ 2, 3, 4]]) + + >>> np.linalg.norm(a) + array(7.745966692414834) + >>> np.linalg.norm(b) + array(7.745966692414834) + >>> np.linalg.norm(b, 'fro') + array(7.745966692414834) + >>> np.linalg.norm(a, np.inf) + array(4.) + >>> np.linalg.norm(b, np.inf) + array(9.) + >>> np.linalg.norm(a, -np.inf) + array(0.) + >>> np.linalg.norm(b, -np.inf) + array(2.) + + >>> np.linalg.norm(a, 1) + array(20.) + >>> np.linalg.norm(b, 1) + array(7.) + >>> np.linalg.norm(a, -1) + array(0.) + >>> np.linalg.norm(b, -1) + array(6.) + >>> np.linalg.norm(a, 2) + array(7.745966692414834) + >>> np.linalg.norm(b, 2) + array(7.3484692283495345) + + >>> np.linalg.norm(a, -2) + array(0.) + >>> np.linalg.norm(b, -2) + array(1.8570331885190563e-016) # may vary + >>> np.linalg.norm(a, 3) + array(5.8480354764257312) # may vary + >>> np.linalg.norm(a, -3) + array(0.) + + Using the `axis` argument to compute vector norms: + + >>> c = np.array([[ 1, 2, 3], + ... [-1, 1, 4]]) + >>> np.linalg.norm(c, axis=0) + array([ 1.41421356, 2.23606798, 5. ]) + >>> np.linalg.norm(c, axis=1) + array([ 3.74165739, 4.24264069]) + >>> np.linalg.norm(c, ord=1, axis=1) + array([ 6., 6.]) + + Using the `axis` argument to compute matrix norms: + + >>> m = np.arange(8).reshape(2,2,2) + >>> np.linalg.norm(m, axis=(1,2)) + array([ 3.74165739, 11.22497216]) + >>> np.linalg.norm(m[0, :, :]), np.linalg.norm(m[1, :, :]) + (array(3.7416573867739413), array(11.224972160321824)) + + """ + + dpnp.check_supported_arrays_type(x) + return dpnp_norm(x, ord, axis, keepdims) def qr(a, mode="reduced"): diff --git a/dpnp/linalg/dpnp_utils_linalg.py b/dpnp/linalg/dpnp_utils_linalg.py index 0305182389b..71b0f7ffda4 100644 --- a/dpnp/linalg/dpnp_utils_linalg.py +++ b/dpnp/linalg/dpnp_utils_linalg.py @@ -28,6 +28,7 @@ import dpctl.tensor._tensor_impl as ti import numpy from numpy import prod +from numpy.core.numeric import normalize_axis_index import dpnp import dpnp.backend.extensions.lapack._lapack_impl as li @@ -42,6 +43,7 @@ "dpnp_inv", "dpnp_matrix_rank", "dpnp_multi_dot", + "dpnp_norm", "dpnp_pinv", "dpnp_qr", "dpnp_slogdet", @@ -465,6 +467,35 @@ def _multi_dot_three(A, B, C, out=None): return dpnp.dot(A, dpnp.dot(B, C), out=out) +def _multi_svd_norm(x, row_axis, col_axis, op): + """ + Compute a function of the singular values of the 2-D matrices in `x`. + + This is a private utility function used by `dpnp.linalg.norm()`. + + Parameters + ---------- + x : {dpnp.ndarray, usm_ndarray} + row_axis, col_axis : int + The axes of `x` that hold the 2-D matrices. + op : callable + This should be either `dpnp.amin` or `dpnp.amax` or `dpnp.sum`. + + Returns + ------- + out : dpnp.ndarray + If `x` is 2-D, the return values is a 0-d array. + Otherwise, it is an array with ``x.ndim - 2`` dimensions. + The return values are either the minimum or maximum or sum of the + singular values of the matrices, depending on whether `op` + is `dpnp.amin` or `dpnp.amax` or `dpnp.sum`. + + """ + y = dpnp.moveaxis(x, (row_axis, col_axis), (-2, -1)) + result = op(dpnp.linalg.svd(y, compute_uv=False), axis=-1) + return result + + def _real_type(dtype, device=None): """ Returns the real data type corresponding to a given dpnp data type. @@ -1134,6 +1165,124 @@ def dpnp_multi_dot(n, arrays, out=None): return result +def dpnp_norm(x, ord=None, axis=None, keepdims=False): + """Compute matrix or vector norm.""" + + if not dpnp.issubdtype(x.dtype, dpnp.inexact): + x_copy = dpnp.empty_like(x, dtype=dpnp.default_float_type(x.device)) + ht_copy_ev, _ = ti._copy_usm_ndarray_into_usm_ndarray( + src=dpnp.get_usm_ndarray(x), + dst=x_copy.get_array(), + sycl_queue=x.sycl_queue, + ) + ht_copy_ev.wait() + x = x_copy + + ndim = x.ndim + # Immediately handle some default, simple, fast, and common cases. + if axis is None: + if ( + (ord is None) + or (ord in ("f", "fro") and ndim == 2) + or (ord == 2 and ndim == 1) + ): + # TODO: use order="K" when it is supported in dpnp.ravel + x = dpnp.ravel(x) + if dpnp.issubdtype(x.dtype, dpnp.complexfloating): + x_real = x.real + x_imag = x.imag + sqnorm = dpnp.dot(x_real, x_real) + dpnp.dot(x_imag, x_imag) + else: + sqnorm = dpnp.dot(x, x) + ret = dpnp.sqrt(sqnorm) + if keepdims: + ret = ret.reshape((1,) * ndim) + return ret + + # Normalize the `axis` argument to a tuple. + if axis is None: + axis = tuple(range(ndim)) + elif not isinstance(axis, tuple): + try: + axis = int(axis) + except Exception as e: + raise TypeError( + "'axis' must be None, an integer or a tuple of integers" + ) from e + axis = (axis,) + + if len(axis) == 1: + axis = normalize_axis_index(axis[0], ndim) + if ord == dpnp.inf: + return dpnp.abs(x).max(axis=axis, keepdims=keepdims) + elif ord == -dpnp.inf: + return dpnp.abs(x).min(axis=axis, keepdims=keepdims) + elif ord == 0: + # Zero norm + # Convert to Python float in accordance with NumPy + return ( + (x != 0).astype(x.real.dtype).sum(axis=axis, keepdims=keepdims) + ) + elif ord == 1: + # special case for speedup + return dpnp.abs(x).sum(axis=axis, keepdims=keepdims) + elif ord is None or ord == 2: + # special case for speedup + s = (dpnp.conj(x) * x).real + return dpnp.sqrt(dpnp.sum(s, axis=axis, keepdims=keepdims)) + else: + try: + float(ord) + except (TypeError, ValueError): + raise ValueError(f"Invalid norm order '{ord}' for vectors") + + absx = dpnp.abs(x) + absx **= ord + ret = absx.sum(axis=axis, keepdims=keepdims) + ret **= numpy.reciprocal(ord, dtype=ret.dtype) + return ret + elif len(axis) == 2: + row_axis, col_axis = axis + row_axis = normalize_axis_index(row_axis, ndim) + col_axis = normalize_axis_index(col_axis, ndim) + if row_axis == col_axis: + raise ValueError("Duplicate axes given.") + if ord == 2: + ret = _multi_svd_norm(x, row_axis, col_axis, dpnp.amax) + elif ord == -2: + ret = _multi_svd_norm(x, row_axis, col_axis, dpnp.amin) + elif ord == 1: + if col_axis > row_axis: + col_axis -= 1 + ret = dpnp.abs(x).sum(axis=row_axis).max(axis=col_axis) + elif ord == dpnp.inf: + if row_axis > col_axis: + row_axis -= 1 + ret = dpnp.abs(x).sum(axis=col_axis).max(axis=row_axis) + elif ord == -1: + if col_axis > row_axis: + col_axis -= 1 + ret = dpnp.abs(x).sum(axis=row_axis).min(axis=col_axis) + elif ord == -dpnp.inf: + if row_axis > col_axis: + row_axis -= 1 + ret = dpnp.abs(x).sum(axis=col_axis).min(axis=row_axis) + elif ord in [None, "fro", "f"]: + ret = dpnp.sqrt(dpnp.sum((dpnp.conj(x) * x).real, axis=axis)) + elif ord == "nuc": + ret = _multi_svd_norm(x, row_axis, col_axis, dpnp.sum) + else: + raise ValueError("Invalid norm order for matrices.") + if keepdims: + ret_shape = list(x.shape) + ret_shape[axis[0]] = 1 + ret_shape[axis[1]] = 1 + ret = ret.reshape(ret_shape) + return ret + else: + raise ValueError("Improper number of dimensions to norm.") + + def dpnp_pinv(a, rcond=1e-15, hermitian=False): """ dpnp_pinv(a, rcond=1e-15, hermitian=False): diff --git a/tests/skipped_tests.tbl b/tests/skipped_tests.tbl index 182eaf8877a..7d2305a8c06 100644 --- a/tests/skipped_tests.tbl +++ b/tests/skipped_tests.tbl @@ -63,16 +63,6 @@ tests/test_linalg.py::test_matrix_rank[None-[[1, 2], [3, 4]]-float32] tests/test_linalg.py::test_matrix_rank[None-[[1, 2], [3, 4]]-int64] tests/test_linalg.py::test_matrix_rank[None-[[1, 2], [3, 4]]-int32] -tests/test_linalg.py::test_norm1[0-None-[7]] -tests/test_linalg.py::test_norm1[0-None-[1, 2]] -tests/test_linalg.py::test_norm1[0-None-[1, 0]] -tests/test_linalg.py::test_norm1[0-3-[7]] -tests/test_linalg.py::test_norm1[0-3-[1, 2]] -tests/test_linalg.py::test_norm1[0-3-[1, 0]] -tests/test_linalg.py::test_norm1[None-3-[7]] -tests/test_linalg.py::test_norm1[None-3-[1, 2]] -tests/test_linalg.py::test_norm1[None-3-[1, 0]] - tests/test_strides.py::test_strides_1arg[(10,)-None-degrees] tests/test_strides.py::test_strides_1arg[(10,)-None-fabs] tests/test_strides.py::test_strides_1arg[(10,)-None-radians] diff --git a/tests/skipped_tests_gpu_no_fp64.tbl b/tests/skipped_tests_gpu_no_fp64.tbl index d724a6043e5..fc591b36bd6 100644 --- a/tests/skipped_tests_gpu_no_fp64.tbl +++ b/tests/skipped_tests_gpu_no_fp64.tbl @@ -1,10 +1,3 @@ -tests/test_linalg.py::test_norm1[0-3-[7]] -tests/test_linalg.py::test_norm1[0-3-[1, 2]] -tests/test_linalg.py::test_norm1[0-3-[1, 0]] -tests/test_linalg.py::test_norm1[None-3-[7]] -tests/test_linalg.py::test_norm1[None-3-[1, 2]] -tests/test_linalg.py::test_norm1[None-3-[1, 0]] - tests/test_mathematical.py::TestGradient::test_gradient_y1[array0] tests/test_mathematical.py::TestGradient::test_gradient_y1[array1] tests/test_mathematical.py::TestGradient::test_gradient_y1[array2] diff --git a/tests/test_linalg.py b/tests/test_linalg.py index 65cfa949db0..b7e5f38b9ce 100644 --- a/tests/test_linalg.py +++ b/tests/test_linalg.py @@ -1,4 +1,5 @@ import dpctl +import dpctl.tensor as dpt import numpy import pytest from dpctl.utils import ExecutionPlacementError @@ -15,6 +16,7 @@ from .helper import ( assert_dtype_allclose, get_all_dtypes, + get_complex_dtypes, get_float_complex_dtypes, has_support_aspect64, is_cpu_device, @@ -675,83 +677,406 @@ def test_matrix_rank_errors(self): ) -@pytest.mark.usefixtures("allow_fall_back_on_numpy") -@pytest.mark.usefixtures("suppress_divide_numpy_warnings") -@pytest.mark.parametrize( - "array", [[7], [1, 2], [1, 0]], ids=["[7]", "[1, 2]", "[1, 0]"] -) -@pytest.mark.parametrize( - "ord", - [None, -inp.Inf, -2, -1, 0, 1, 2, 3, inp.Inf], - ids=["None", "-dpnp.Inf", "-2", "-1", "0", "1", "2", "3", "dpnp.Inf"], -) -@pytest.mark.parametrize("axis", [0, None], ids=["0", "None"]) -def test_norm1(array, ord, axis): - a = numpy.array(array) - ia = inp.array(a) - result = inp.linalg.norm(ia, ord=ord, axis=axis) - expected = numpy.linalg.norm(a, ord=ord, axis=axis) - assert_allclose(expected, result) +class TestNorm: + def setup_method(self): + numpy.random.seed(42) + @pytest.mark.usefixtures("suppress_divide_numpy_warnings") + @pytest.mark.parametrize( + "shape", [(0,), (5, 0), (2, 0, 3)], ids=["(0,)", "(5,0)", "(2, 0, 3)"] + ) + @pytest.mark.parametrize( + "ord", + [None, -2, -1, 0, 1, 2, 3], + ids=["None", "-2", "-1", "0", "1", "2", "3"], + ) + @pytest.mark.parametrize("axis", [0, None], ids=["0", "None"]) + @pytest.mark.parametrize("keepdims", [True, False], ids=["True", "False"]) + def test_norm_empty(self, shape, ord, axis, keepdims): + a = numpy.empty(shape) + ia = inp.array(a) + if axis is None and a.ndim > 1 and ord in [0, 3]: + # Invalid norm order for matrices (a.ndim == 2) or + # Improper number of dimensions to norm (a.ndim>2) + with pytest.raises(ValueError): + inp.linalg.norm(ia, ord=ord, axis=axis, keepdims=keepdims) + elif axis is None and a.ndim > 2 and ord is not None: + # Improper number of dimensions to norm + with pytest.raises(ValueError): + inp.linalg.norm(ia, ord=ord, axis=axis, keepdims=keepdims) + elif ( + axis is None + and ord is not None + and a.ndim != 1 + and a.shape[-1] == 0 + ): + # reduction cannot be performed over zero-size axes + with pytest.raises(ValueError): + inp.linalg.norm(ia, ord=ord, axis=axis, keepdims=keepdims) + else: + result = inp.linalg.norm(ia, ord=ord, axis=axis, keepdims=keepdims) + expected = numpy.linalg.norm( + a, ord=ord, axis=axis, keepdims=keepdims + ) + assert_dtype_allclose(result, expected) -@pytest.mark.usefixtures("allow_fall_back_on_numpy") -@pytest.mark.parametrize( - "array", - [[[1, 0]], [[1, 2]], [[1, 0], [3, 0]], [[1, 2], [3, 4]]], - ids=["[[1, 0]]", "[[1, 2]]", "[[1, 0], [3, 0]]", "[[1, 2], [3, 4]]"], -) -@pytest.mark.parametrize( - "ord", - [None, -inp.Inf, -2, -1, 1, 2, inp.Inf, "fro", "nuc"], - ids=[ - "None", - "-dpnp.Inf", - "-2", - "-1", - "1", - "2", - "dpnp.Inf", - '"fro"', - '"nuc"', - ], -) -@pytest.mark.parametrize("axis", [(0, 1), None], ids=["(0, 1)", "None"]) -def test_norm2(array, ord, axis): - a = numpy.array(array) - ia = inp.array(a) - result = inp.linalg.norm(ia, ord=ord, axis=axis) - expected = numpy.linalg.norm(a, ord=ord, axis=axis) - assert_allclose(expected, result) + @pytest.mark.parametrize( + "ord", + [None, -inp.Inf, -2, -1, 0, 1, 2, 3, inp.Inf], + ids=["None", "-dpnp.Inf", "-2", "-1", "0", "1", "2", "3", "dpnp.Inf"], + ) + @pytest.mark.parametrize("axis", [0, None], ids=["0", "None"]) + def test_norm_0D(self, ord, axis): + a = numpy.array(2) + ia = inp.array(a) + if axis is None and ord is not None: + # Improper number of dimensions to norm + with pytest.raises(ValueError): + inp.linalg.norm(ia, ord=ord, axis=axis) + elif axis is not None: + with pytest.raises(numpy.AxisError): + inp.linalg.norm(ia, ord=ord, axis=axis) + else: + result = inp.linalg.norm(ia, ord=ord, axis=axis) + expected = numpy.linalg.norm(a, ord=ord, axis=axis) + assert_dtype_allclose(result, expected) + @pytest.mark.usefixtures("suppress_divide_numpy_warnings") + @pytest.mark.parametrize("dtype", get_all_dtypes(no_complex=True)) + @pytest.mark.parametrize( + "ord", + [None, -inp.Inf, -2, -1, 0, 1, 2, 3, inp.Inf], + ids=["None", "-dpnp.Inf", "-2", "-1", "0", "1", "2", "3", "dpnp.Inf"], + ) + @pytest.mark.parametrize("axis", [0, None], ids=["0", "None"]) + @pytest.mark.parametrize("keepdims", [True, False], ids=["True", "False"]) + def test_norm_1D(self, dtype, ord, axis, keepdims): + a = numpy.array(numpy.random.uniform(-5, 5, 10), dtype=dtype) + ia = inp.array(a) + result = inp.linalg.norm(ia, ord=ord, axis=axis, keepdims=keepdims) + expected = numpy.linalg.norm(a, ord=ord, axis=axis, keepdims=keepdims) + # use only type kinds check when dpnp handles complex64 arrays + # since `dpnp.sum()` and `numpy.sum()` return different dtypes + assert_dtype_allclose( + result, expected, check_only_type_kind=(dtype == inp.float32) + ) -@pytest.mark.usefixtures("allow_fall_back_on_numpy") -@pytest.mark.parametrize( - "array", - [ - [[[1, 2], [3, 4]], [[5, 6], [7, 8]]], - [[[1, 0], [3, 0]], [[5, 0], [7, 0]]], - ], - ids=[ - "[[[1, 2], [3, 4]], [[5, 6], [7, 8]]]", - "[[[1, 0], [3, 0]], [[5, 0], [7, 0]]]", - ], -) -@pytest.mark.parametrize( - "ord", - [None, -inp.Inf, -2, -1, 1, 2, inp.Inf], - ids=["None", "-dpnp.Inf", "-2", "-1", "1", "2", "dpnp.Inf"], -) -@pytest.mark.parametrize( - "axis", - [0, 1, 2, (0, 1), (0, 2), (1, 2)], - ids=["0", "1", "2", "(0, 1)", "(0, 2)", "(1, 2)"], -) -def test_norm3(array, ord, axis): - a = numpy.array(array) - ia = inp.array(a) - result = inp.linalg.norm(ia, ord=ord, axis=axis) - expected = numpy.linalg.norm(a, ord=ord, axis=axis) - assert_allclose(expected, result) + @pytest.mark.usefixtures("suppress_divide_numpy_warnings") + @pytest.mark.parametrize("dtype", get_complex_dtypes()) + @pytest.mark.parametrize( + "ord", + [None, -inp.Inf, -2, -1, 0, 1, 2, 3, inp.Inf], + ids=["None", "-dpnp.Inf", "-2", "-1", "0", "1", "2", "3", "dpnp.Inf"], + ) + @pytest.mark.parametrize("axis", [0, None], ids=["0", "None"]) + @pytest.mark.parametrize("keepdims", [True, False], ids=["True", "False"]) + def test_norm_1D_complex(self, dtype, ord, axis, keepdims): + x1 = numpy.random.uniform(-5, 5, 10) + x2 = numpy.random.uniform(-5, 5, 10) + a = numpy.array(x1 + 1j * x2, dtype=dtype) + ia = inp.array(a) + result = inp.linalg.norm(ia, ord=ord, axis=axis, keepdims=keepdims) + expected = numpy.linalg.norm(a, ord=ord, axis=axis, keepdims=keepdims) + assert_dtype_allclose( + result, expected, check_only_type_kind=(dtype == inp.complex64) + ) + + @pytest.mark.usefixtures("suppress_divide_numpy_warnings") + @pytest.mark.parametrize("dtype", get_all_dtypes(no_complex=True)) + @pytest.mark.parametrize( + "ord", + [None, -inp.Inf, -2, -1, 1, 2, 3, inp.Inf, "fro", "nuc"], + ids=[ + "None", + "-dpnp.Inf", + "-2", + "-1", + "1", + "2", + "3", + "dpnp.Inf", + '"fro"', + '"nuc"', + ], + ) + @pytest.mark.parametrize( + "axis", [0, 1, (0, 1), None], ids=["0", "1", "(0, 1)", "None"] + ) + @pytest.mark.parametrize("keepdims", [True, False], ids=["True", "False"]) + def test_norm_2D(self, dtype, ord, axis, keepdims): + a = numpy.array(numpy.random.uniform(-5, 5, 15), dtype=dtype).reshape( + 3, 5 + ) + ia = inp.array(a) + if (axis in [-1, 0, 1] and ord in ["nuc", "fro"]) or ( + (isinstance(axis, tuple) or axis is None) and ord == 3 + ): + # Invalid norm order for vectors + with pytest.raises(ValueError): + inp.linalg.norm(ia, ord=ord, axis=axis, keepdims=keepdims) + else: + result = inp.linalg.norm(ia, ord=ord, axis=axis, keepdims=keepdims) + expected = numpy.linalg.norm( + a, ord=ord, axis=axis, keepdims=keepdims + ) + assert_dtype_allclose( + result, expected, check_only_type_kind=(dtype == inp.float32) + ) + + @pytest.mark.usefixtures("suppress_divide_numpy_warnings") + @pytest.mark.parametrize("dtype", get_complex_dtypes()) + @pytest.mark.parametrize( + "ord", + [None, -inp.Inf, -2, -1, 1, 2, 3, inp.Inf, "fro", "nuc"], + ids=[ + "None", + "-dpnp.Inf", + "-2", + "-1", + "1", + "2", + "3", + "dpnp.Inf", + '"fro"', + '"nuc"', + ], + ) + @pytest.mark.parametrize( + "axis", [0, 1, (0, 1), None], ids=["0", "1", "(0, 1)", "None"] + ) + @pytest.mark.parametrize("keepdims", [True, False], ids=["True", "False"]) + def test_norm_2D_complex(self, dtype, ord, axis, keepdims): + x1 = numpy.random.uniform(-5, 5, 15) + x2 = numpy.random.uniform(-5, 5, 15) + a = numpy.array(x1 + 1j * x2, dtype=dtype).reshape(3, 5) + ia = inp.array(a) + if (axis in [-1, 0, 1] and ord in ["nuc", "fro"]) or ( + (isinstance(axis, tuple) or axis is None) and ord == 3 + ): + # Invalid norm order for vectors + with pytest.raises(ValueError): + inp.linalg.norm(ia, ord=ord, axis=axis, keepdims=keepdims) + else: + result = inp.linalg.norm(ia, ord=ord, axis=axis, keepdims=keepdims) + expected = numpy.linalg.norm( + a, ord=ord, axis=axis, keepdims=keepdims + ) + assert_dtype_allclose( + result, expected, check_only_type_kind=(dtype == inp.complex64) + ) + + @pytest.mark.usefixtures("suppress_divide_numpy_warnings") + @pytest.mark.parametrize("dtype", get_all_dtypes(no_complex=True)) + @pytest.mark.parametrize( + "ord", + [None, -inp.Inf, -2, -1, 1, 2, 3, inp.Inf, "fro", "nuc"], + ids=[ + "None", + "-dpnp.Inf", + "-2", + "-1", + "1", + "2", + "3", + "dpnp.Inf", + '"fro"', + '"nuc"', + ], + ) + @pytest.mark.parametrize( + "axis", + [-1, 0, 1, (0, 1), (-2, -1), None], + ids=["-1", "0", "1", "(0, 1)", "(-2, -1)", "None"], + ) + @pytest.mark.parametrize("keepdims", [True, False], ids=["True", "False"]) + def test_norm_ND(self, dtype, ord, axis, keepdims): + a = numpy.array(numpy.random.uniform(-5, 5, 120), dtype=dtype).reshape( + 2, 3, 4, 5 + ) + ia = inp.array(a) + if (axis in [-1, 0, 1] and ord in ["nuc", "fro"]) or ( + isinstance(axis, tuple) and ord == 3 + ): + # Invalid norm order for vectors + with pytest.raises(ValueError): + inp.linalg.norm(ia, ord=ord, axis=axis, keepdims=keepdims) + elif axis is None and ord is not None: + # Improper number of dimensions to norm + with pytest.raises(ValueError): + inp.linalg.norm(ia, ord=ord, axis=axis, keepdims=keepdims) + else: + result = inp.linalg.norm(ia, ord=ord, axis=axis, keepdims=keepdims) + expected = numpy.linalg.norm( + a, ord=ord, axis=axis, keepdims=keepdims + ) + assert_dtype_allclose( + result, expected, check_only_type_kind=(dtype == inp.float32) + ) + + @pytest.mark.usefixtures("suppress_divide_numpy_warnings") + @pytest.mark.parametrize("dtype", get_complex_dtypes()) + @pytest.mark.parametrize( + "ord", + [None, -inp.Inf, -2, -1, 1, 2, 3, inp.Inf, "fro", "nuc"], + ids=[ + "None", + "-dpnp.Inf", + "-2", + "-1", + "1", + "2", + "3", + "dpnp.Inf", + '"fro"', + '"nuc"', + ], + ) + @pytest.mark.parametrize( + "axis", + [-1, 0, 1, (0, 1), (-2, -1), None], + ids=["-1", "0", "1", "(0, 1)", "(-2, -1)", "None"], + ) + @pytest.mark.parametrize("keepdims", [True, False], ids=["True", "False"]) + def test_norm_ND_complex(self, dtype, ord, axis, keepdims): + x1 = numpy.random.uniform(-5, 5, 120) + x2 = numpy.random.uniform(-5, 5, 120) + a = numpy.array(x1 + 1j * x2, dtype=dtype).reshape(2, 3, 4, 5) + ia = inp.array(a) + if (axis in [-1, 0, 1] and ord in ["nuc", "fro"]) or ( + isinstance(axis, tuple) and ord == 3 + ): + # Invalid norm order for vectors + with pytest.raises(ValueError): + inp.linalg.norm(ia, ord=ord, axis=axis, keepdims=keepdims) + elif axis is None and ord is not None: + # Improper number of dimensions to norm + with pytest.raises(ValueError): + inp.linalg.norm(ia, ord=ord, axis=axis, keepdims=keepdims) + else: + result = inp.linalg.norm(ia, ord=ord, axis=axis, keepdims=keepdims) + expected = numpy.linalg.norm( + a, ord=ord, axis=axis, keepdims=keepdims + ) + assert_dtype_allclose( + result, expected, check_only_type_kind=(dtype == inp.complex64) + ) + + @pytest.mark.usefixtures("suppress_divide_numpy_warnings") + @pytest.mark.parametrize("dtype", get_all_dtypes()) + @pytest.mark.parametrize( + "ord", + [None, -inp.Inf, -2, -1, 1, 2, 3, inp.Inf, "fro", "nuc"], + ids=[ + "None", + "-dpnp.Inf", + "-2", + "-1", + "1", + "2", + "3", + "dpnp.Inf", + '"fro"', + '"nuc"', + ], + ) + @pytest.mark.parametrize( + "axis", + [-1, 0, 1, (0, 1), (-2, -1), None], + ids=["-1", "0", "1", "(0, 1)", "(-2, -1)", "None"], + ) + @pytest.mark.parametrize("keepdims", [True, False], ids=["True", "False"]) + def test_norm_usm_ndarray(self, dtype, ord, axis, keepdims): + a = numpy.array(numpy.random.uniform(-5, 5, 120), dtype=dtype).reshape( + 2, 3, 4, 5 + ) + ia = dpt.asarray(a) + if (axis in [-1, 0, 1] and ord in ["nuc", "fro"]) or ( + isinstance(axis, tuple) and ord == 3 + ): + # Invalid norm order for vectors + with pytest.raises(ValueError): + inp.linalg.norm(ia, ord=ord, axis=axis, keepdims=keepdims) + elif axis is None and ord is not None: + # Improper number of dimensions to norm + with pytest.raises(ValueError): + inp.linalg.norm(ia, ord=ord, axis=axis, keepdims=keepdims) + else: + result = inp.linalg.norm(ia, ord=ord, axis=axis, keepdims=keepdims) + expected = numpy.linalg.norm( + a, ord=ord, axis=axis, keepdims=keepdims + ) + assert_dtype_allclose( + result, + expected, + check_only_type_kind=(dtype in [inp.float32, inp.complex64]), + ) + + @pytest.mark.parametrize("stride", [3, -1, -5], ids=["3", "-1", "-5"]) + def test_norm_strided_1D(self, stride): + a = numpy.arange(25) + ia = inp.array(a) + + result = inp.linalg.norm(ia[::stride]) + expected = numpy.linalg.norm(a[::stride]) + assert_dtype_allclose(result, expected) + + @pytest.mark.parametrize( + "axis", + [-1, 0, (0, 1), None], + ids=["-1", "0", "(0, 1)", "None"], + ) + @pytest.mark.parametrize( + "stride", + [(-2, -4), (2, 4), (-3, 5), (3, -1)], + ids=["(-2, -4)", "(2, 4)", "(-3, 5)", "(3, -1)"], + ) + def test_norm_strided_2D(self, axis, stride): + A = numpy.random.rand(20, 30) + B = inp.asarray(A) + slices = tuple(slice(None, None, stride[i]) for i in range(A.ndim)) + a = A[slices] + b = B[slices] + + result = inp.linalg.norm(b, axis=axis) + expected = numpy.linalg.norm(a, axis=axis) + assert_dtype_allclose(result, expected) + + @pytest.mark.parametrize( + "axis", + [-1, 0, 1, 2, (0, 1), (-2, -1)], + ids=["-1", "0", "1", "2", "(0, 1)", "(-1, -2)"], + ) + @pytest.mark.parametrize( + "stride", + [(-2, -3, -1, -4), (-2, 4, -3, 5), (2, 3, 1, 4)], + ids=["(-2, -3, -1, -4)", "(-2, 4, -3, 5)", "(2, 3, 1, 4)"], + ) + def test_norm_strided_ND(self, axis, stride): + A = numpy.random.rand(12, 16, 20, 24) + B = inp.asarray(A) + slices = tuple(slice(None, None, stride[i]) for i in range(A.ndim)) + a = A[slices] + b = B[slices] + + result = inp.linalg.norm(b, axis=axis) + expected = numpy.linalg.norm(a, axis=axis) + assert_dtype_allclose(result, expected) + + def test_norm_error(self): + a = numpy.arange(120).reshape(2, 3, 4, 5) + ia = inp.array(a) + + # Duplicate axes given + with pytest.raises(ValueError): + inp.linalg.norm(ia, axis=(2, 2)) + + #'axis' must be None, an integer or a tuple of integers + with pytest.raises(TypeError): + inp.linalg.norm(ia, axis=[2]) + + # Invalid norm order for vectors + with pytest.raises(ValueError): + inp.linalg.norm(ia, axis=1, ord=[3]) class TestQr: diff --git a/tests/test_mathematical.py b/tests/test_mathematical.py index 16c2375a803..a4b22d4fa56 100644 --- a/tests/test_mathematical.py +++ b/tests/test_mathematical.py @@ -2884,21 +2884,16 @@ def test_matmul_order(self, order, shape_pair): assert result.flags.f_contiguous == expected.flags.f_contiguous assert_dtype_allclose(result, expected) - def test_matmul_strided(self): + @pytest.mark.parametrize( + "stride", + [(-2, -2, -2, -2), (2, 2, 2, 2), (-2, 2, -2, 2), (2, -2, 2, -2)], + ids=["-2", "2", "(-2, 2)", "(2, -2)"], + ) + def test_matmul_strided(self, stride): for dim in [1, 2, 3, 4]: A = numpy.random.rand(*([20] * dim)) B = dpnp.asarray(A) - # positive stride - slices = tuple(slice(None, None, 2) for _ in range(dim)) - a = A[slices] - b = B[slices] - - result = dpnp.matmul(b, b) - expected = numpy.matmul(a, a) - assert_dtype_allclose(result, expected) - - # negative stride - slices = tuple(slice(None, None, -2) for _ in range(dim)) + slices = tuple(slice(None, None, stride[i]) for i in range(dim)) a = A[slices] b = B[slices] diff --git a/tests/test_product.py b/tests/test_product.py index daeff917762..5661a33b74d 100644 --- a/tests/test_product.py +++ b/tests/test_product.py @@ -1,7 +1,6 @@ import dpctl import numpy import pytest -from numpy.testing import assert_allclose, assert_array_equal import dpnp @@ -162,30 +161,15 @@ def test_cross_broadcast( assert_dtype_allclose(result, expected) @pytest.mark.parametrize("dtype", get_all_dtypes(no_bool=True)) - def test_cross_strided(self, dtype): + @pytest.mark.parametrize("stride", [3, -3], ids=["3", "-3"]) + def test_cross_strided(self, dtype, stride): a = numpy.arange(1, 10, dtype=dtype) b = numpy.arange(1, 10, dtype=dtype) ia = dpnp.array(a) ib = dpnp.array(b) - result = dpnp.cross(ia[::3], ib[::3]) - expected = numpy.cross(a[::3], b[::3]) - assert_dtype_allclose(result, expected) - - a = numpy.arange(1, 4, dtype=dtype) - b = numpy.arange(1, 4, dtype=dtype) - ia = dpnp.array(a) - ib = dpnp.array(b) - result = dpnp.cross(ia, ib[::-1]) - expected = numpy.cross(a, b[::-1]) - assert_dtype_allclose(result, expected) - - a = numpy.arange(1, 7, dtype=dtype) - b = numpy.arange(1, 7, dtype=dtype) - ia = dpnp.array(a) - ib = dpnp.array(b) - result = dpnp.cross(ia[::-2], ib[::-2]) - expected = numpy.cross(a[::-2], b[::-2]) + result = dpnp.cross(ia[::stride], ib[::stride]) + expected = numpy.cross(a[::stride], b[::stride]) assert_dtype_allclose(result, expected) def test_cross_error(self): @@ -380,26 +364,17 @@ def test_dot_ndarray(self, dtype, shape_pair): assert_dtype_allclose(result, expected) @pytest.mark.parametrize("dtype", get_all_dtypes(no_bool=True)) - def test_dot_strided(self, dtype): + @pytest.mark.parametrize( + "stride", [3, -1, -2, -5], ids=["3", "-1", "-2", "-5"] + ) + def test_dot_strided(self, dtype, stride): a = numpy.arange(25, dtype=dtype) b = numpy.arange(25, dtype=dtype) ia = dpnp.array(a) ib = dpnp.array(b) - result = dpnp.dot(ia[::3], ib[::3]) - expected = numpy.dot(a[::3], b[::3]) - assert_dtype_allclose(result, expected) - - result = dpnp.dot(ia, ib[::-1]) - expected = numpy.dot(a, b[::-1]) - assert_dtype_allclose(result, expected) - - result = dpnp.dot(ia[::-2], ib[::-2]) - expected = numpy.dot(a[::-2], b[::-2]) - assert_dtype_allclose(result, expected) - - result = dpnp.dot(ia[::-5], ib[::-5]) - expected = numpy.dot(a[::-5], b[::-5]) + result = dpnp.dot(ia[::stride], ib[::stride]) + expected = numpy.dot(a[::stride], b[::stride]) assert_dtype_allclose(result, expected) @pytest.mark.parametrize("dtype", get_all_dtypes(no_bool=True)) @@ -635,22 +610,17 @@ def test_inner_input_dtype_matrix(self, dtype1, dtype2): assert_dtype_allclose(result, expected) @pytest.mark.parametrize("dtype", get_all_dtypes(no_bool=True)) - def test_inner_strided(self, dtype): + @pytest.mark.parametrize( + "stride", [3, -1, -2, -4], ids=["3", "-1", "-2", "-4"] + ) + def test_inner_strided(self, dtype, stride): a = numpy.arange(20, dtype=dtype) b = numpy.arange(20, dtype=dtype) ia = dpnp.array(a) ib = dpnp.array(b) - result = dpnp.inner(ia[::3], ib[::3]) - expected = numpy.inner(a[::3], b[::3]) - assert_dtype_allclose(result, expected) - - result = dpnp.inner(ia, ib[::-1]) - expected = numpy.inner(a, b[::-1]) - assert_dtype_allclose(result, expected) - - result = dpnp.inner(ia[::-4], ib[::-4]) - expected = numpy.inner(a[::-4], b[::-4]) + result = dpnp.inner(ia[::stride], ib[::stride]) + expected = numpy.inner(a[::stride], b[::stride]) assert_dtype_allclose(result, expected) def test_inner_error(self): @@ -749,22 +719,17 @@ def test_kron_input_dtype_matrix(self, dtype1, dtype2): assert_dtype_allclose(result, expected) @pytest.mark.parametrize("dtype", get_all_dtypes(no_bool=True)) - def test_kron_strided(self, dtype): + @pytest.mark.parametrize( + "stride", [3, -1, -2, -4], ids=["3", "-1", "-2", "-4"] + ) + def test_kron_strided(self, dtype, stride): a = numpy.arange(20, dtype=dtype) b = numpy.arange(20, dtype=dtype) ia = dpnp.array(a) ib = dpnp.array(b) - result = dpnp.kron(ia[::3], ib[::3]) - expected = numpy.kron(a[::3], b[::3]) - assert_dtype_allclose(result, expected) - - result = dpnp.kron(ia, ib[::-1]) - expected = numpy.kron(a, b[::-1]) - assert_dtype_allclose(result, expected) - - result = dpnp.kron(ia[::-4], ib[::-4]) - expected = numpy.kron(a[::-4], b[::-4]) + result = dpnp.kron(ia[::stride], ib[::stride]) + expected = numpy.kron(a[::stride], b[::stride]) assert_dtype_allclose(result, expected) @@ -929,7 +894,12 @@ def test_multi_dot_out(self, shapes, dtype): expected = numpy.linalg.multi_dot(numpy_array_list) assert_dtype_allclose(result, expected) - def test_multi_dot_strides(self): + @pytest.mark.parametrize( + "stride", + [(-2, -2), (2, 2), (-2, 2), (2, -2)], + ids=["(-2, -2)", "(2, 2)", "(-2, 2)", "(2, -2)"], + ) + def test_multi_dot_strided(self, stride): numpy_array_list = [] dpnp_array_list = [] for num_array in [2, 3, 4, 5]: # number of arrays in multi_dot @@ -937,7 +907,10 @@ def test_multi_dot_strides(self): A = numpy.random.rand(20, 20) B = dpnp.array(A) - slices = (slice(None, None, 2), slice(None, None, 2)) + slices = ( + slice(None, None, stride[0]), + slice(None, None, stride[1]), + ) a = A[slices] b = B[slices] @@ -1075,22 +1048,17 @@ def test_tensordot_input_dtype_matrix(self, dtype1, dtype2): expected = numpy.tensordot(a, b) assert_dtype_allclose(result, expected) - def test_tensordot_strided(self): + @pytest.mark.parametrize( + "stride", + [(-2, -2, -2, -2), (2, 2, 2, 2), (-2, 2, -2, 2), (2, -2, 2, -2)], + ids=["-2", "2", "(-2, 2)", "(2, -2)"], + ) + def test_tensordot_strided(self, stride): for dim in [1, 2, 3, 4]: axes = 1 if dim == 1 else 2 - A = numpy.random.rand(*([10] * dim)) + A = numpy.random.rand(*([20] * dim)) B = dpnp.asarray(A) - # positive stride - slices = tuple(slice(None, None, 2) for _ in range(dim)) - a = A[slices] - b = B[slices] - - result = dpnp.tensordot(b, b, axes=axes) - expected = numpy.tensordot(a, a, axes=axes) - assert_dtype_allclose(result, expected) - - # negative stride - slices = tuple(slice(None, None, -2) for _ in range(dim)) + slices = tuple(slice(None, None, stride[i]) for i in range(A.ndim)) a = A[slices] b = B[slices] @@ -1233,26 +1201,17 @@ def test_vdot_complex(self, dtype, shape_pair): assert_dtype_allclose(result, expected) @pytest.mark.parametrize("dtype", get_all_dtypes(no_bool=True)) - def test_vdot_strided(self, dtype): + @pytest.mark.parametrize( + "stride", [3, -1, -2, -4], ids=["3", "-1", "-2", "-4"] + ) + def test_vdot_strided(self, dtype, stride): a = numpy.arange(25, dtype=dtype) b = numpy.arange(25, dtype=dtype) ia = dpnp.array(a) ib = dpnp.array(b) - result = dpnp.vdot(ia[::3], ib[::3]) - expected = numpy.vdot(a[::3], b[::3]) - assert_dtype_allclose(result, expected) - - result = dpnp.vdot(ia, ib[::-1]) - expected = numpy.vdot(a, b[::-1]) - assert_dtype_allclose(result, expected) - - result = dpnp.vdot(ia[::-2], ib[::-2]) - expected = numpy.vdot(a[::-2], b[::-2]) - assert_dtype_allclose(result, expected) - - result = dpnp.vdot(ia[::-5], ib[::-5]) - expected = numpy.vdot(a[::-5], b[::-5]) + result = dpnp.vdot(ia[::stride], ib[::stride]) + expected = numpy.vdot(a[::stride], b[::stride]) assert_dtype_allclose(result, expected) @pytest.mark.parametrize("dtype1", get_all_dtypes()) diff --git a/tests/test_sycl_queue.py b/tests/test_sycl_queue.py index 7dc49af820a..da82f183b1d 100644 --- a/tests/test_sycl_queue.py +++ b/tests/test_sycl_queue.py @@ -1330,6 +1330,56 @@ def test_matrix_rank(data, tol, device): assert_sycl_queue_equal(result_queue, expected_queue) +@pytest.mark.usefixtures("suppress_divide_numpy_warnings") +@pytest.mark.parametrize( + "device", + valid_devices, + ids=[device.filter_string for device in valid_devices], +) +@pytest.mark.parametrize( + "ord", + [None, -dpnp.Inf, -2, -1, 1, 2, 3, dpnp.Inf, "fro", "nuc"], + ids=[ + "None", + "-dpnp.Inf", + "-2", + "-1", + "1", + "2", + "3", + "dpnp.Inf", + '"fro"', + '"nuc"', + ], +) +@pytest.mark.parametrize( + "axis", + [-1, 0, 1, (0, 1), (-2, -1), None], + ids=["-1", "0", "1", "(0, 1)", "(-2, -1)", "None"], +) +def test_norm(device, ord, axis): + a = numpy.arange(120).reshape(2, 3, 4, 5) + ia = dpnp.array(a, device=device) + if (axis in [-1, 0, 1] and ord in ["nuc", "fro"]) or ( + isinstance(axis, tuple) and ord == 3 + ): + # Invalid norm order for vectors + with pytest.raises(ValueError): + dpnp.linalg.norm(ia, ord=ord, axis=axis) + elif axis is None and ord is not None: + # Improper number of dimensions to norm + with pytest.raises(ValueError): + dpnp.linalg.norm(ia, ord=ord, axis=axis) + else: + result = dpnp.linalg.norm(ia, ord=ord, axis=axis) + expected = numpy.linalg.norm(a, ord=ord, axis=axis) + assert_dtype_allclose(result, expected, check_only_type_kind=True) + + expected_queue = ia.get_array().sycl_queue + result_queue = result.get_array().sycl_queue + assert_sycl_queue_equal(result_queue, expected_queue) + + @pytest.mark.parametrize( "shape", [ diff --git a/tests/test_usm_type.py b/tests/test_usm_type.py index 14898c9aee0..df577308bbc 100644 --- a/tests/test_usm_type.py +++ b/tests/test_usm_type.py @@ -463,6 +463,46 @@ def test_meshgrid(usm_type_x, usm_type_y): assert z[1].usm_type == usm_type_y +@pytest.mark.parametrize("usm_type", list_of_usm_types, ids=list_of_usm_types) +@pytest.mark.parametrize( + "ord", + [None, -dp.Inf, -2, -1, 1, 2, 3, dp.Inf, "fro", "nuc"], + ids=[ + "None", + "-dpnp.Inf", + "-2", + "-1", + "1", + "2", + "3", + "dpnp.Inf", + '"fro"', + '"nuc"', + ], +) +@pytest.mark.parametrize( + "axis", + [-1, 0, 1, (0, 1), (-2, -1), None], + ids=["-1", "0", "1", "(0, 1)", "(-2, -1)", "None"], +) +def test_norm(usm_type, ord, axis): + ia = dp.arange(120, usm_type=usm_type).reshape(2, 3, 4, 5) + if (axis in [-1, 0, 1] and ord in ["nuc", "fro"]) or ( + isinstance(axis, tuple) and ord == 3 + ): + # Invalid norm order for vectors + with pytest.raises(ValueError): + dp.linalg.norm(ia, ord=ord, axis=axis) + elif axis is None and ord is not None: + # Improper number of dimensions to norm + with pytest.raises(ValueError): + dp.linalg.norm(ia, ord=ord, axis=axis) + else: + result = dp.linalg.norm(ia, ord=ord, axis=axis) + assert ia.usm_type == usm_type + assert result.usm_type == usm_type + + @pytest.mark.parametrize( "func,data", [ diff --git a/tests/third_party/cupy/linalg_tests/test_norms.py b/tests/third_party/cupy/linalg_tests/test_norms.py index c2ae3fe0dbb..e866d1eb11e 100644 --- a/tests/third_party/cupy/linalg_tests/test_norms.py +++ b/tests/third_party/cupy/linalg_tests/test_norms.py @@ -8,6 +8,55 @@ from tests.third_party.cupy import testing +@testing.parameterize( + *testing.product( + { + "shape": [(1,), (2,)], + "ord": [-numpy.inf, -2, -1, 0, 1, 2, 3, numpy.inf], + "axis": [0, None], + "keepdims": [True, False], + } + ) + + testing.product( + { + "shape": [(1, 2), (2, 2)], + "ord": [-numpy.inf, -2, -1, 1, 2, numpy.inf, "fro", "nuc"], + "axis": [(0, 1), None], + "keepdims": [True, False], + } + ) + + testing.product( + { + "shape": [(2, 2, 2)], + "ord": [-numpy.inf, -2, -1, 0, 1, 2, 3, numpy.inf], + "axis": [0, 1, 2], + "keepdims": [True, False], + } + ) + + testing.product( + { + "shape": [(2, 2, 2)], + "ord": [-numpy.inf, -1, 1, numpy.inf, "fro"], + "axis": [(0, 1), (0, 2), (1, 2)], + "keepdims": [True, False], + } + ) +) +class TestNorm(unittest.TestCase): + @testing.for_all_dtypes(no_float16=True) + @testing.numpy_cupy_allclose(rtol=1e-3, atol=1e-4, type_check=False) + # since dtype of sum is different in dpnp and NumPy, type_check=False + def test_norm(self, xp, dtype): + a = testing.shaped_arange(self.shape, xp, dtype) + res = xp.linalg.norm(a, self.ord, self.axis, self.keepdims) + if xp == numpy and not isinstance(res, numpy.ndarray): + real_dtype = a.real.dtype + if issubclass(real_dtype.type, numpy.inexact): + # Avoid numpy bug. See numpy/numpy#10667 + res = res.astype(a.real.dtype) + return res + + @testing.parameterize( *testing.product( { From 437f10a8e2ddb86e9e15c3e2844ddb937c721826 Mon Sep 17 00:00:00 2001 From: Vahid Tavanashad Date: Thu, 14 Mar 2024 11:24:29 -0500 Subject: [PATCH 2/7] address comments --- dpnp/linalg/dpnp_iface_linalg.py | 2 +- dpnp/linalg/dpnp_utils_linalg.py | 28 ++++++++++------------------ tests/test_sycl_queue.py | 8 ++------ tests/test_usm_type.py | 8 ++------ 4 files changed, 15 insertions(+), 31 deletions(-) diff --git a/dpnp/linalg/dpnp_iface_linalg.py b/dpnp/linalg/dpnp_iface_linalg.py index 561c3af5427..cb2e3ec8d00 100644 --- a/dpnp/linalg/dpnp_iface_linalg.py +++ b/dpnp/linalg/dpnp_iface_linalg.py @@ -580,7 +580,7 @@ def norm(x, ord=None, axis=None, keepdims=False): Input array. If `axis` is ``None``, `x` must be 1-D or 2-D, unless `ord` is ``None``. If both `axis` and `ord` are ``None``, the 2-norm of ``x.ravel`` will be returned. - ord : {non-zero int, inf, -inf, "fro", "nuc"}, optional + ord : {int, inf, -inf, "fro", "nuc"}, optional Norm type. inf means dpnp's `inf` object. The default is ``None``. axis : {None, int, 2-tuple of ints}, optional If `axis` is an integer, it specifies the axis of `x` along which to diff --git a/dpnp/linalg/dpnp_utils_linalg.py b/dpnp/linalg/dpnp_utils_linalg.py index 71b0f7ffda4..bc9d40bb85a 100644 --- a/dpnp/linalg/dpnp_utils_linalg.py +++ b/dpnp/linalg/dpnp_utils_linalg.py @@ -479,7 +479,7 @@ def _multi_svd_norm(x, row_axis, col_axis, op): row_axis, col_axis : int The axes of `x` that hold the 2-D matrices. op : callable - This should be either `dpnp.amin` or `dpnp.amax` or `dpnp.sum`. + This should be either `dpnp.min` or `dpnp.max` or `dpnp.sum`. Returns ------- @@ -488,7 +488,7 @@ def _multi_svd_norm(x, row_axis, col_axis, op): Otherwise, it is an array with ``x.ndim - 2`` dimensions. The return values are either the minimum or maximum or sum of the singular values of the matrices, depending on whether `op` - is `dpnp.amin` or `dpnp.amax` or `dpnp.sum`. + is `dpnp.min` or `dpnp.max` or `dpnp.sum`. """ y = dpnp.moveaxis(x, (row_axis, col_axis), (-2, -1)) @@ -1169,14 +1169,7 @@ def dpnp_norm(x, ord=None, axis=None, keepdims=False): """Compute matrix or vector norm.""" if not dpnp.issubdtype(x.dtype, dpnp.inexact): - x_copy = dpnp.empty_like(x, dtype=dpnp.default_float_type(x.device)) - ht_copy_ev, _ = ti._copy_usm_ndarray_into_usm_ndarray( - src=dpnp.get_usm_ndarray(x), - dst=x_copy.get_array(), - sycl_queue=x.sycl_queue, - ) - ht_copy_ev.wait() - x = x_copy + x = dpnp.astype(x, dtype=dpnp.default_float_type(x.device)) ndim = x.ndim # Immediately handle some default, simple, fast, and common cases. @@ -1230,17 +1223,16 @@ def dpnp_norm(x, ord=None, axis=None, keepdims=False): # special case for speedup s = (dpnp.conj(x) * x).real return dpnp.sqrt(dpnp.sum(s, axis=axis, keepdims=keepdims)) - else: - try: - float(ord) - except (TypeError, ValueError): - raise ValueError(f"Invalid norm order '{ord}' for vectors") - + elif isinstance(ord, (int, float)): absx = dpnp.abs(x) absx **= ord ret = absx.sum(axis=axis, keepdims=keepdims) ret **= numpy.reciprocal(ord, dtype=ret.dtype) return ret + else: + # including str-type keywords for ord ("fro", "nuc") which + # are not valid for vectors + raise ValueError(f"Invalid norm order '{ord}' for vectors") elif len(axis) == 2: row_axis, col_axis = axis row_axis = normalize_axis_index(row_axis, ndim) @@ -1248,9 +1240,9 @@ def dpnp_norm(x, ord=None, axis=None, keepdims=False): if row_axis == col_axis: raise ValueError("Duplicate axes given.") if ord == 2: - ret = _multi_svd_norm(x, row_axis, col_axis, dpnp.amax) + ret = _multi_svd_norm(x, row_axis, col_axis, dpnp.max) elif ord == -2: - ret = _multi_svd_norm(x, row_axis, col_axis, dpnp.amin) + ret = _multi_svd_norm(x, row_axis, col_axis, dpnp.min) elif ord == 1: if col_axis > row_axis: col_axis -= 1 diff --git a/tests/test_sycl_queue.py b/tests/test_sycl_queue.py index da82f183b1d..0b949f5818c 100644 --- a/tests/test_sycl_queue.py +++ b/tests/test_sycl_queue.py @@ -1363,13 +1363,9 @@ def test_norm(device, ord, axis): if (axis in [-1, 0, 1] and ord in ["nuc", "fro"]) or ( isinstance(axis, tuple) and ord == 3 ): - # Invalid norm order for vectors - with pytest.raises(ValueError): - dpnp.linalg.norm(ia, ord=ord, axis=axis) + pytest.skip("Invalid norm order for vectors.") elif axis is None and ord is not None: - # Improper number of dimensions to norm - with pytest.raises(ValueError): - dpnp.linalg.norm(ia, ord=ord, axis=axis) + pytest.skip("Improper number of dimensions to norm") else: result = dpnp.linalg.norm(ia, ord=ord, axis=axis) expected = numpy.linalg.norm(a, ord=ord, axis=axis) diff --git a/tests/test_usm_type.py b/tests/test_usm_type.py index df577308bbc..a010124f1ef 100644 --- a/tests/test_usm_type.py +++ b/tests/test_usm_type.py @@ -490,13 +490,9 @@ def test_norm(usm_type, ord, axis): if (axis in [-1, 0, 1] and ord in ["nuc", "fro"]) or ( isinstance(axis, tuple) and ord == 3 ): - # Invalid norm order for vectors - with pytest.raises(ValueError): - dp.linalg.norm(ia, ord=ord, axis=axis) + pytest.skip("Invalid norm order for vectors.") elif axis is None and ord is not None: - # Improper number of dimensions to norm - with pytest.raises(ValueError): - dp.linalg.norm(ia, ord=ord, axis=axis) + pytest.skip("Improper number of dimensions to norm") else: result = dp.linalg.norm(ia, ord=ord, axis=axis) assert ia.usm_type == usm_type From faf1450cb769a8eb5ec5cb17258d61a580486aeb Mon Sep 17 00:00:00 2001 From: Vahid Tavanashad Date: Thu, 14 Mar 2024 13:27:14 -0500 Subject: [PATCH 3/7] add float ty description --- dpnp/linalg/dpnp_iface_linalg.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dpnp/linalg/dpnp_iface_linalg.py b/dpnp/linalg/dpnp_iface_linalg.py index cb2e3ec8d00..ea83a656d4a 100644 --- a/dpnp/linalg/dpnp_iface_linalg.py +++ b/dpnp/linalg/dpnp_iface_linalg.py @@ -580,7 +580,7 @@ def norm(x, ord=None, axis=None, keepdims=False): Input array. If `axis` is ``None``, `x` must be 1-D or 2-D, unless `ord` is ``None``. If both `axis` and `ord` are ``None``, the 2-norm of ``x.ravel`` will be returned. - ord : {int, inf, -inf, "fro", "nuc"}, optional + ord : {int, float, inf, -inf, "fro", "nuc"}, optional Norm type. inf means dpnp's `inf` object. The default is ``None``. axis : {None, int, 2-tuple of ints}, optional If `axis` is an integer, it specifies the axis of `x` along which to From f614059a0b4d40f355ac19f7aba4ea021a599278 Mon Sep 17 00:00:00 2001 From: Vahid Tavanashad Date: Fri, 15 Mar 2024 10:03:05 -0500 Subject: [PATCH 4/7] improve test coverage --- tests/test_linalg.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_linalg.py b/tests/test_linalg.py index b7e5f38b9ce..212d68ab214 100644 --- a/tests/test_linalg.py +++ b/tests/test_linalg.py @@ -800,7 +800,7 @@ def test_norm_1D_complex(self, dtype, ord, axis, keepdims): ], ) @pytest.mark.parametrize( - "axis", [0, 1, (0, 1), None], ids=["0", "1", "(0, 1)", "None"] + "axis", [0, 1, (1, 0), None], ids=["0", "1", "(1, 0)", "None"] ) @pytest.mark.parametrize("keepdims", [True, False], ids=["True", "False"]) def test_norm_2D(self, dtype, ord, axis, keepdims): @@ -842,7 +842,7 @@ def test_norm_2D(self, dtype, ord, axis, keepdims): ], ) @pytest.mark.parametrize( - "axis", [0, 1, (0, 1), None], ids=["0", "1", "(0, 1)", "None"] + "axis", [0, 1, (1, 0), None], ids=["0", "1", "(1, 0)", "None"] ) @pytest.mark.parametrize("keepdims", [True, False], ids=["True", "False"]) def test_norm_2D_complex(self, dtype, ord, axis, keepdims): @@ -885,8 +885,8 @@ def test_norm_2D_complex(self, dtype, ord, axis, keepdims): ) @pytest.mark.parametrize( "axis", - [-1, 0, 1, (0, 1), (-2, -1), None], - ids=["-1", "0", "1", "(0, 1)", "(-2, -1)", "None"], + [-1, 0, 1, (0, 1), (-1, -2), None], + ids=["-1", "0", "1", "(0, 1)", "(-1, -2)", "None"], ) @pytest.mark.parametrize("keepdims", [True, False], ids=["True", "False"]) def test_norm_ND(self, dtype, ord, axis, keepdims): From 3c9f13b2b3da9a95e2a8aec752b6fd6038c3d923 Mon Sep 17 00:00:00 2001 From: Vahid Tavanashad Date: Fri, 15 Mar 2024 10:05:28 -0500 Subject: [PATCH 5/7] make axis for test_norm_ND and ND_complex similar --- tests/test_linalg.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_linalg.py b/tests/test_linalg.py index 212d68ab214..ffa7af7f6a8 100644 --- a/tests/test_linalg.py +++ b/tests/test_linalg.py @@ -933,8 +933,8 @@ def test_norm_ND(self, dtype, ord, axis, keepdims): ) @pytest.mark.parametrize( "axis", - [-1, 0, 1, (0, 1), (-2, -1), None], - ids=["-1", "0", "1", "(0, 1)", "(-2, -1)", "None"], + [-1, 0, 1, (0, 1), (-1, -2), None], + ids=["-1", "0", "1", "(0, 1)", "(-1, -2)", "None"], ) @pytest.mark.parametrize("keepdims", [True, False], ids=["True", "False"]) def test_norm_ND_complex(self, dtype, ord, axis, keepdims): From f5c4623d229c41c618b9758a337a51fddde34699 Mon Sep 17 00:00:00 2001 From: Vahid Tavanashad Date: Sun, 24 Mar 2024 22:28:44 -0500 Subject: [PATCH 6/7] mute some tests for on windows --- tests/test_linalg.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/test_linalg.py b/tests/test_linalg.py index ffa7af7f6a8..0d8160f0221 100644 --- a/tests/test_linalg.py +++ b/tests/test_linalg.py @@ -20,6 +20,7 @@ get_float_complex_dtypes, has_support_aspect64, is_cpu_device, + is_win_platform, ) @@ -890,6 +891,9 @@ def test_norm_2D_complex(self, dtype, ord, axis, keepdims): ) @pytest.mark.parametrize("keepdims", [True, False], ids=["True", "False"]) def test_norm_ND(self, dtype, ord, axis, keepdims): + # TODO: remove skiping in mkl 2024.1 + if is_win_platform(): + pytest.skip("CPU driver experiences an instability on Windows.") a = numpy.array(numpy.random.uniform(-5, 5, 120), dtype=dtype).reshape( 2, 3, 4, 5 ) @@ -938,6 +942,9 @@ def test_norm_ND(self, dtype, ord, axis, keepdims): ) @pytest.mark.parametrize("keepdims", [True, False], ids=["True", "False"]) def test_norm_ND_complex(self, dtype, ord, axis, keepdims): + # TODO: remove skiping in mkl 2024.1 + if is_win_platform(): + pytest.skip("CPU driver experiences an instability on Windows.") x1 = numpy.random.uniform(-5, 5, 120) x2 = numpy.random.uniform(-5, 5, 120) a = numpy.array(x1 + 1j * x2, dtype=dtype).reshape(2, 3, 4, 5) @@ -986,6 +993,9 @@ def test_norm_ND_complex(self, dtype, ord, axis, keepdims): ) @pytest.mark.parametrize("keepdims", [True, False], ids=["True", "False"]) def test_norm_usm_ndarray(self, dtype, ord, axis, keepdims): + # TODO: remove skiping in mkl 2024.1 + if is_win_platform(): + pytest.skip("CPU driver experiences an instability on Windows.") a = numpy.array(numpy.random.uniform(-5, 5, 120), dtype=dtype).reshape( 2, 3, 4, 5 ) From 3e9c09e107fc5879e658daf2797d36323f1fdc26 Mon Sep 17 00:00:00 2001 From: Vahid Tavanashad Date: Mon, 1 Apr 2024 12:26:33 -0500 Subject: [PATCH 7/7] unmute test on windows --- tests/test_linalg.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/tests/test_linalg.py b/tests/test_linalg.py index 8130c93e639..915082cb326 100644 --- a/tests/test_linalg.py +++ b/tests/test_linalg.py @@ -20,7 +20,6 @@ get_float_complex_dtypes, has_support_aspect64, is_cpu_device, - is_win_platform, ) @@ -941,9 +940,6 @@ def test_norm_2D_complex(self, dtype, ord, axis, keepdims): ) @pytest.mark.parametrize("keepdims", [True, False], ids=["True", "False"]) def test_norm_ND(self, dtype, ord, axis, keepdims): - # TODO: remove skiping in mkl 2024.1 - if is_win_platform(): - pytest.skip("CPU driver experiences an instability on Windows.") a = numpy.array(numpy.random.uniform(-5, 5, 120), dtype=dtype).reshape( 2, 3, 4, 5 ) @@ -992,9 +988,6 @@ def test_norm_ND(self, dtype, ord, axis, keepdims): ) @pytest.mark.parametrize("keepdims", [True, False], ids=["True", "False"]) def test_norm_ND_complex(self, dtype, ord, axis, keepdims): - # TODO: remove skiping in mkl 2024.1 - if is_win_platform(): - pytest.skip("CPU driver experiences an instability on Windows.") x1 = numpy.random.uniform(-5, 5, 120) x2 = numpy.random.uniform(-5, 5, 120) a = numpy.array(x1 + 1j * x2, dtype=dtype).reshape(2, 3, 4, 5) @@ -1043,9 +1036,6 @@ def test_norm_ND_complex(self, dtype, ord, axis, keepdims): ) @pytest.mark.parametrize("keepdims", [True, False], ids=["True", "False"]) def test_norm_usm_ndarray(self, dtype, ord, axis, keepdims): - # TODO: remove skiping in mkl 2024.1 - if is_win_platform(): - pytest.skip("CPU driver experiences an instability on Windows.") a = numpy.array(numpy.random.uniform(-5, 5, 120), dtype=dtype).reshape( 2, 3, 4, 5 )