diff --git a/doc/known_words.txt b/doc/known_words.txt index 10a1cc5e6fe8..128bcd759d06 100644 --- a/doc/known_words.txt +++ b/doc/known_words.txt @@ -1,4 +1,5 @@ al +ary backend bitwise boolean @@ -31,6 +32,7 @@ Fortran Frobenius fs getter +Golub Hadamard Hypergeometric iinfo @@ -51,8 +53,10 @@ ndim Nj Nk normed +nuc Nyquist oneAPI +ord orthonormal Penrose Polyutils diff --git a/doc/reference/binary.rst b/doc/reference/binary.rst index 8313d91aaa25..61382a6ef6d9 100644 --- a/doc/reference/binary.rst +++ b/doc/reference/binary.rst @@ -1,7 +1,7 @@ -Binary Operations +Bit-wise operations ================= -.. https://docs.scipy.org/doc/numpy/reference/routines.bitwise.html +.. https://numpy.org/doc/stable/reference/routines.bitwise.html Element-wise bit operations --------------------------- @@ -15,8 +15,12 @@ Element-wise bit operations dpnp.bitwise_or dpnp.bitwise_xor dpnp.invert + dpnp.bitwise_invert dpnp.left_shift + dpnp.bitwise_left_shift dpnp.right_shift + dpnp.bitwise_right_shift + dpnp.bitwise_count Bit packing diff --git a/doc/reference/creation.rst b/doc/reference/creation.rst index 7937073408e2..4721ec5ff018 100644 --- a/doc/reference/creation.rst +++ b/doc/reference/creation.rst @@ -3,7 +3,7 @@ Array creation routines ======================= -.. https://docs.scipy.org/doc/numpy/reference/routines.array-creation.html +.. https://numpy.org/doc/stable/reference/routines.array-creation.html From shape or value ----------------------- diff --git a/doc/reference/dtype.rst b/doc/reference/dtype.rst index 93593455f902..a6e200662797 100644 --- a/doc/reference/dtype.rst +++ b/doc/reference/dtype.rst @@ -3,7 +3,7 @@ Data type routines ================== -.. https://docs.scipy.org/doc/numpy/reference/routines.dtype.html +.. https://numpy.org/doc/stable/reference/routines.dtype.html .. autosummary:: :toctree: generated/ diff --git a/doc/reference/fft.rst b/doc/reference/fft.rst index 1c2708aae5e4..fca6e583b014 100644 --- a/doc/reference/fft.rst +++ b/doc/reference/fft.rst @@ -1,9 +1,7 @@ -.. module:: dpnp.fft - FFT Functions ============= -.. https://docs.scipy.org/doc/numpy/reference/routines.fft.html +.. https://numpy.org/doc/stable/reference/routines.fft.html Standard FFTs ------------- @@ -12,12 +10,12 @@ Standard FFTs :toctree: generated/ :nosignatures: - fft - ifft - fft2 - ifft2 - fftn - ifftn + dpnp.fft.fft + dpnp.fft.ifft + dpnp.fft.fft2 + dpnp.fft.ifft2 + dpnp.fft.fftn + dpnp.fft.ifftn Real FFTs @@ -27,12 +25,12 @@ Real FFTs :toctree: generated/ :nosignatures: - rfft - irfft - rfft2 - irfft2 - rfftn - irfftn + dpnp.fft.rfft + dpnp.fft.irfft + dpnp.fft.rfft2 + dpnp.fft.irfft2 + dpnp.fft.rfftn + dpnp.fft.irfftn Hermitian FFTs @@ -42,8 +40,8 @@ Hermitian FFTs :toctree: generated/ :nosignatures: - hfft - ihfft + dpnp.fft.hfft + dpnp.fft.ihfft Helper routines @@ -53,10 +51,10 @@ Helper routines :toctree: generated/ :nosignatures: - fftfreq - rfftfreq - fftshift - ifftshift + dpnp.fft.fftfreq + dpnp.fft.rfftfreq + dpnp.fft.fftshift + dpnp.fft.ifftshift .. fft.config module is not implemented yet .. dpnp.fft.config.set_cufft_callbacks diff --git a/doc/reference/linalg.rst b/doc/reference/linalg.rst index 0bb48a04cd9b..0a5d166e5a8e 100644 --- a/doc/reference/linalg.rst +++ b/doc/reference/linalg.rst @@ -1,7 +1,7 @@ Linear Algebra ============== -.. https://docs.scipy.org/doc/numpy/reference/routines.linalg.html +.. https://numpy.org/doc/stable/reference/routines.linalg.html Matrix and vector products -------------------------- @@ -13,14 +13,19 @@ Matrix and vector products dpnp.dot dpnp.linalg.multi_dot dpnp.vdot + dpnp.vecdot + dpnp.linalg.vecdot (Array API compatible) dpnp.inner dpnp.outer dpnp.matmul + dpnp.linalg.matmul (Array API compatible) dpnp.tensordot + dpnp.linalg.tensordot (Array API compatible) dpnp.einsum dpnp.einsum_path dpnp.linalg.matrix_power dpnp.kron + dpnp.linalg.cross (Array API compatible) Decompositions -------------- @@ -55,11 +60,14 @@ Norms and other numbers :nosignatures: dpnp.linalg.norm + dpnp.linalg.matrix_norm (Array API compatible) + dpnp.linalg.vector_norm (Array API compatible) dpnp.linalg.cond dpnp.linalg.det dpnp.linalg.matrix_rank dpnp.linalg.slogdet dpnp.trace + dpnp.linalg.trace (Array API compatible) Solving linear equations @@ -75,3 +83,19 @@ Solving linear equations dpnp.linalg.inv dpnp.linalg.pinv dpnp.linalg.tensorinv + +Other matrix operations +----------------------- +.. autosummary:: + :toctree: generated/ + + dpnp.diagonal + dpnp.linalg.diagonal (Array API compatible) + dpnp.linalg.matrix_tranpose (Array API compatible) + +Exceptions +---------- +.. autosummary:: + :toctree: generated/ + + dpnp.linalg.linAlgError diff --git a/doc/reference/logic.rst b/doc/reference/logic.rst index 5cd7066b4524..472e1364efbe 100644 --- a/doc/reference/logic.rst +++ b/doc/reference/logic.rst @@ -1,7 +1,7 @@ Logic Functions =============== -.. https://docs.scipy.org/doc/numpy/reference/routines.logic.html +.. https://numpy.org/doc/stable/reference/routines.logic.html Truth value testing ------------------- diff --git a/doc/reference/manipulation.rst b/doc/reference/manipulation.rst index a9682c488bf4..2fb9e21bb622 100644 --- a/doc/reference/manipulation.rst +++ b/doc/reference/manipulation.rst @@ -1,7 +1,7 @@ Array Manipulation Routines =========================== -.. https://docs.scipy.org/doc/numpy/reference/routines.array-manipulation.html +.. https://numpy.org/doc/stable/reference/routines.array-manipulation.html Basic operations ---------------- diff --git a/doc/reference/math.rst b/doc/reference/math.rst index 522d046299e7..d1ef78d4544a 100644 --- a/doc/reference/math.rst +++ b/doc/reference/math.rst @@ -1,7 +1,7 @@ Mathematical functions ====================== -.. https://docs.scipy.org/doc/numpy/reference/routines.math.html +.. https://numpy.org/doc/stable/reference/routines.math.html Trigonometric functions ----------------------- diff --git a/doc/reference/misc.rst b/doc/reference/misc.rst index 413aace06ccf..6a9f03fc4dae 100644 --- a/doc/reference/misc.rst +++ b/doc/reference/misc.rst @@ -1,7 +1,7 @@ Miscellaneous routines ====================== -.. https://docs.scipy.org/doc/numpy/reference/routines.other.html +.. https://numpy.org/doc/stable/reference/routines.other.html Utility ------- @@ -13,6 +13,4 @@ Utility dpnp.get_include dpnp.show_config dpnp.show_runtime - dpnp.deprecate - dpnp.deprecate_with_doc dpnp.broadcast_shapes diff --git a/doc/reference/pad.rst b/doc/reference/pad.rst deleted file mode 100644 index 0724a6d66f66..000000000000 --- a/doc/reference/pad.rst +++ /dev/null @@ -1,10 +0,0 @@ -Padding -================================ - -.. https://docs.scipy.org/doc/numpy/reference/routines.padding.html - -.. autosummary:: - :toctree: generated/ - :nosignatures: - - dpnp.pad diff --git a/doc/reference/random.rst b/doc/reference/random.rst index db7b76b8bd41..875cc7f7feb1 100644 --- a/doc/reference/random.rst +++ b/doc/reference/random.rst @@ -1,9 +1,7 @@ -.. module:: dpnp.random - Random Sampling (``dpnp.random``) ================================= -.. https://docs.scipy.org/doc/numpy/reference/random/legacy.html +.. https://numpy.org/doc/stable/reference/random/legacy.html Simple random data @@ -13,16 +11,16 @@ Simple random data :toctree: generated/ :nosignatures: - rand - randn - randint - random_integers - random_sample - random - ranf - sample - choice - bytes + dpnp.random.rand + dpnp.random.randn + dpnp.random.randint + dpnp.random.random_integers + dpnp.random.random_sample + dpnp.random.random + dpnp.random.ranf + dpnp.random.sample + dpnp.random.choice + dpnp.random.bytes Permutations @@ -32,8 +30,8 @@ Permutations :toctree: generated/ :nosignatures: - shuffle - permutation + dpnp.random.shuffle + dpnp.random.permutation Distributions @@ -43,41 +41,41 @@ Distributions :toctree: generated/ :nosignatures: - beta - binomial - chisquare - dirichlet - exponential - f - gamma - geometric - gumbel - hypergeometric - laplace - logistic - lognormal - logseries - multinomial - multivariate_normal - negative_binomial - noncentral_chisquare - noncentral_f - normal - pareto - poisson - power - rayleigh - standard_cauchy - standard_exponential - standard_gamma - standard_normal - standard_t - triangular - uniform - vonmises - wald - weibull - zipf + dpnp.random.beta + dpnp.random.binomial + dpnp.random.chisquare + dpnp.random.dirichlet + dpnp.random.exponential + dpnp.random.f + dpnp.random.gamma + dpnp.random.geometric + dpnp.random.gumbel + dpnp.random.hypergeometric + dpnp.random.laplace + dpnp.random.logistic + dpnp.random.lognormal + dpnp.random.logseries + dpnp.random.multinomial + dpnp.random.multivariate_normal + dpnp.random.negative_binomial + dpnp.random.noncentral_chisquare + dpnp.random.noncentral_f + dpnp.random.normal + dpnp.random.pareto + dpnp.random.poisson + dpnp.random.power + dpnp.random.rayleigh + dpnp.random.standard_cauchy + dpnp.random.standard_exponential + dpnp.random.standard_gamma + dpnp.random.standard_normal + dpnp.random.standard_t + dpnp.random.triangular + dpnp.random.uniform + dpnp.random.vonmises + dpnp.random.wald + dpnp.random.weibull + dpnp.random.zipf Random generator @@ -87,7 +85,7 @@ Random generator :toctree: generated/ :nosignatures: - RandomState - seed - get_random_state - set_random_state + dpnp.random.RandomState + dpnp.random.seed + dpnp.random.get_random_state + dpnp.random.set_random_state diff --git a/doc/reference/routines.rst b/doc/reference/routines.rst index 645d1a6be5d2..96f86a71f4af 100644 --- a/doc/reference/routines.rst +++ b/doc/reference/routines.rst @@ -20,7 +20,6 @@ These functions cover a subset of linalg logic math - .. pad .. polynomials random sorting diff --git a/doc/reference/sorting.rst b/doc/reference/sorting.rst index 42179debd0fa..a9c840003d03 100644 --- a/doc/reference/sorting.rst +++ b/doc/reference/sorting.rst @@ -1,7 +1,7 @@ Sorting, Searching, and Counting ================================ -.. https://docs.scipy.org/doc/numpy/reference/routines.sort.html +.. https://numpy.org/doc/stable/reference/routines.sort.html Sorting ------- diff --git a/doc/reference/statistics.rst b/doc/reference/statistics.rst index 540b6e314a62..e0a8a355fb1b 100644 --- a/doc/reference/statistics.rst +++ b/doc/reference/statistics.rst @@ -1,7 +1,7 @@ Statistical Functions ===================== -.. https://docs.scipy.org/doc/numpy/reference/routines.statistics.html +.. https://numpy.org/doc/stable/reference/routines.statistics.html Order statistics ---------------- @@ -29,9 +29,10 @@ Averages and variances dpnp.mean dpnp.std dpnp.var + dpnp.nanmedian dpnp.nanmean - dpnp.nanvar dpnp.nanstd + dpnp.nanvar Correlations @@ -42,8 +43,8 @@ Correlations :nosignatures: dpnp.corrcoef - dpnp.cov dpnp.correlate + dpnp.cov Histograms diff --git a/doc/reference/ufunc.rst b/doc/reference/ufunc.rst index 5c76da99d8e6..4691c65b1b32 100644 --- a/doc/reference/ufunc.rst +++ b/doc/reference/ufunc.rst @@ -3,7 +3,7 @@ Universal Functions (ufunc) =========================== -.. https://docs.scipy.org/doc/numpy/reference/ufuncs.html +.. https://numpy.org/doc/stable/reference/ufuncs.html DPNP provides universal functions (a.k.a. ufuncs) to support various element-wise operations. @@ -29,6 +29,7 @@ Math operations dpnp.negative dpnp.positive dpnp.power + dpnp.pow dpnp.float_power dpnp.remainder dpnp.mod @@ -82,16 +83,23 @@ The ratio of degrees to radians is :math:`180^{\circ}/\pi.` dpnp.cos dpnp.tan dpnp.arcsin + dpnp.asin dpnp.arccos + dpnp.acos dpnp.arctan + dpnp.atan dpnp.arctan2 + dpnp.atan2 dpnp.hypot dpnp.sinh dpnp.cosh dpnp.tanh dpnp.arcsinh + dpnp.asinh dpnp.arccosh + dpnp.acosh dpnp.arctanh + dpnp.atanh dpnp.degrees dpnp.radians dpnp.deg2rad @@ -106,11 +114,16 @@ Bit-twiddling functions :nosignatures: dpnp.bitwise_and + dpnp.bitwise_not dpnp.bitwise_or dpnp.bitwise_xor dpnp.invert + dpnp.bitwise_invert dpnp.left_shift + dpnp.bitwise_left_shift dpnp.right_shift + dpnp.bitwise_right_shift + dpnp.bitwise_count Comparison functions diff --git a/dpnp/dpnp_iface_arraycreation.py b/dpnp/dpnp_iface_arraycreation.py index 0083bca966e5..1affd3210493 100644 --- a/dpnp/dpnp_iface_arraycreation.py +++ b/dpnp/dpnp_iface_arraycreation.py @@ -231,7 +231,7 @@ def arange( Limitations ----------- Parameter `like` is supported only with default value ``None``. - Otherwise, the function raises `NotImplementedError` exception. + Otherwise, the function raises ``NotImplementedError`` exception. See Also -------- @@ -347,7 +347,7 @@ def array( Parameter `subok` is supported only with default value ``False``. Parameter `ndmin` is supported only with default value ``0``. Parameter `like` is supported only with default value ``None``. - Otherwise, the function raises `NotImplementedError` exception. + Otherwise, the function raises ``NotImplementedError`` exception. See Also -------- @@ -469,7 +469,7 @@ def asanyarray( Limitations ----------- Parameter `like` is supported only with default value ``None``. - Otherwise, the function raises `NotImplementedError` exception. + Otherwise, the function raises ``NotImplementedError`` exception. See Also -------- @@ -581,7 +581,7 @@ def asarray( Limitations ----------- Parameter `like` is supported only with default value ``None``. - Otherwise, the function raises `NotImplementedError` exception. + Otherwise, the function raises ``NotImplementedError`` exception. See Also -------- @@ -675,7 +675,7 @@ def ascontiguousarray( Limitations ----------- Parameter `like` is supported only with default value ``None``. - Otherwise, the function raises `NotImplementedError` exception. + Otherwise, the function raises ``NotImplementedError`` exception. See Also -------- @@ -788,7 +788,7 @@ def asfortranarray( Limitations ----------- Parameter `like` is supported only with default value ``None``. - Otherwise, the function raises `NotImplementedError` exception. + Otherwise, the function raises ``NotImplementedError`` exception. See Also -------- @@ -900,7 +900,7 @@ def copy( Limitations ----------- Parameter `subok` is supported only with default value ``False``. - Otherwise, the function raises `NotImplementedError` exception. + Otherwise, the function raises ``NotImplementedError`` exception. Returns ------- @@ -1230,7 +1230,7 @@ def empty( Limitations ----------- Parameter `like` is supported only with default value ``None``. - Otherwise, the function raises `NotImplementedError` exception. + Otherwise, the function raises ``NotImplementedError`` exception. See Also -------- @@ -1334,7 +1334,7 @@ def empty_like( Limitations ----------- Parameter `subok` is supported only with default value ``False``. - Otherwise, the function raises `NotImplementedError` exception. + Otherwise, the function raises ``NotImplementedError`` exception. See Also -------- @@ -1445,7 +1445,7 @@ def eye( Limitations ----------- Parameter `like` is supported only with default value ``None``. - Otherwise, the function raises `NotImplementedError` exception. + Otherwise, the function raises ``NotImplementedError`` exception. See Also -------- @@ -1554,7 +1554,7 @@ def frombuffer( Limitations ----------- Parameter `like` is supported only with default value ``None``. - Otherwise, the function raises `NotImplementedError` exception. + Otherwise, the function raises ``NotImplementedError`` exception. Notes ----- @@ -1668,7 +1668,7 @@ def fromfile( Limitations ----------- Parameter `like` is supported only with default value ``None``. - Otherwise, the function raises `NotImplementedError` exception. + Otherwise, the function raises ``NotImplementedError`` exception. Notes ----- @@ -1789,7 +1789,7 @@ def fromfunction( Limitations ----------- Parameter `like` is supported only with default value ``None``. - Otherwise, the function raises `NotImplementedError` exception. + Otherwise, the function raises ``NotImplementedError`` exception. Notes ----- @@ -1896,7 +1896,7 @@ def fromiter( Limitations ----------- Parameter `like` is supported only with default value ``None``. - Otherwise, the function raises `NotImplementedError` exception. + Otherwise, the function raises ``NotImplementedError`` exception. Notes ----- @@ -1996,7 +1996,7 @@ def fromstring( Limitations ----------- Parameter `like` is supported only with default value ``None``. - Otherwise, the function raises `NotImplementedError` exception. + Otherwise, the function raises ``NotImplementedError`` exception. Notes ----- @@ -2083,7 +2083,7 @@ def full( Limitations ----------- Parameter `like` is supported only with default value ``None``. - Otherwise, the function raises `NotImplementedError` exception. + Otherwise, the function raises ``NotImplementedError`` exception. See Also -------- @@ -2190,7 +2190,7 @@ def full_like( Limitations ----------- Parameter `subok` is supported only with default value ``False``. - Otherwise, the function raises `NotImplementedError` exception. + Otherwise, the function raises ``NotImplementedError`` exception. See Also -------- @@ -2414,7 +2414,7 @@ def identity( Limitations ----------- Parameter `like` is currently not supported. - Otherwise, the function raises `NotImplementedError` exception. + Otherwise, the function raises ``NotImplementedError`` exception. See Also -------- @@ -2638,7 +2638,7 @@ def loadtxt( Limitations ----------- Parameter `like` is supported only with default value ``None``. - Otherwise, the function raises `NotImplementedError` exception. + Otherwise, the function raises ``NotImplementedError`` exception. Notes ----- @@ -3120,7 +3120,7 @@ def ones( Limitations ----------- Parameter `like` is supported only with default value ``None``. - Otherwise, the function raises `NotImplementedError` exception. + Otherwise, the function raises ``NotImplementedError`` exception. See Also -------- @@ -3230,7 +3230,7 @@ def ones_like( Limitations ----------- Parameter `subok` is supported only with default value ``False``. - Otherwise, the function raises `NotImplementedError` exception. + Otherwise, the function raises ``NotImplementedError`` exception. See Also -------- @@ -3320,6 +3320,7 @@ def trace(a, offset=0, axis1=0, axis2=1, dtype=None, out=None): See Also -------- + :obj:`dpnp.linalg.trace` : Array API compatible version. :obj:`dpnp.diag` : Extract a diagonal or construct a diagonal array. :obj:`dpnp.diagonal` : Return specified diagonals. :obj:`dpnp.diagflat` : Create a 2-D array with the flattened input as @@ -3764,7 +3765,7 @@ def zeros( Limitations ----------- Parameter `like` is supported only with default value ``None``. - Otherwise, the function raises `NotImplementedError` exception. + Otherwise, the function raises ``NotImplementedError`` exception. See Also -------- @@ -3874,7 +3875,7 @@ def zeros_like( Limitations ----------- Parameter `subok` is supported only with default value ``False``. - Otherwise, the function raises `NotImplementedError` exception. + Otherwise, the function raises ``NotImplementedError`` exception. See Also -------- diff --git a/dpnp/dpnp_iface_indexing.py b/dpnp/dpnp_iface_indexing.py index 3c94c7091ec9..d616ebfcc9cb 100644 --- a/dpnp/dpnp_iface_indexing.py +++ b/dpnp/dpnp_iface_indexing.py @@ -405,6 +405,7 @@ def diagonal(a, offset=0, axis1=0, axis2=1): See Also -------- + :obj:`dpnp.linalg.diagonal` : Array API compatible version. :obj:`dpnp.diag` : Extract a diagonal or construct a diagonal array. :obj:`dpnp.diagflat` : Create a two-dimensional array with the flattened input as a diagonal. @@ -448,7 +449,7 @@ def diagonal(a, offset=0, axis1=0, axis2=1): [5, 7]]) The anti-diagonal can be obtained by reversing the order of elements - using either `dpnp.flipud` or `dpnp.fliplr`. + using either :obj:`dpnp.flipud` or :obj:`dpnp.fliplr`. >>> a = np.arange(9).reshape(3, 3) >>> a diff --git a/dpnp/dpnp_iface_linearalgebra.py b/dpnp/dpnp_iface_linearalgebra.py index bc821be545d2..924099ad2369 100644 --- a/dpnp/dpnp_iface_linearalgebra.py +++ b/dpnp/dpnp_iface_linearalgebra.py @@ -780,6 +780,7 @@ def matmul( See Also -------- + :obj:`dpnp.linalg.matmul` : Array API compatible version. :obj:`dpnp.vdot` : Complex-conjugating dot product. :obj:`dpnp.tensordot` : Sum products over arbitrary axes. :obj:`dpnp.einsum` : Einstein summation convention. @@ -874,15 +875,17 @@ def outer(a, b, out=None): b : {dpnp.ndarray, usm_ndarray} Second input vector. Input is flattened if not already 1-dimensional. out : {None, dpnp.ndarray, usm_ndarray}, optional - A location where the result is stored + A location where the result is stored. + Default: ``None``. Returns ------- out : dpnp.ndarray - out[i, j] = a[i] * b[j] + ``out[i, j] = a[i] * b[j]`` See Also -------- + :obj:`dpnp.linalg.outer` : Array API compatible version. :obj:`dpnp.einsum` : Evaluates the Einstein summation convention on the operands. :obj:`dpnp.inner` : Returns the inner product of two arrays. @@ -899,6 +902,30 @@ def outer(a, b, out=None): [1, 2, 3], [1, 2, 3]]) + Make a (*very* coarse) grid for computing a Mandelbrot set: + + >>> rl = np.outer(np.ones((5,)), np.linspace(-2, 2, 5)) + >>> rl + array([[-2., -1., 0., 1., 2.], + [-2., -1., 0., 1., 2.], + [-2., -1., 0., 1., 2.], + [-2., -1., 0., 1., 2.], + [-2., -1., 0., 1., 2.]]) + >>> im = np.outer(1j*np.linspace(2, -2, 5), np.ones((5,))) + >>> im + array([[0.+2.j, 0.+2.j, 0.+2.j, 0.+2.j, 0.+2.j], + [0.+1.j, 0.+1.j, 0.+1.j, 0.+1.j, 0.+1.j], + [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], + [0.-1.j, 0.-1.j, 0.-1.j, 0.-1.j, 0.-1.j], + [0.-2.j, 0.-2.j, 0.-2.j, 0.-2.j, 0.-2.j]]) + >>> grid = rl + im + >>> grid + array([[-2.+2.j, -1.+2.j, 0.+2.j, 1.+2.j, 2.+2.j], + [-2.+1.j, -1.+1.j, 0.+1.j, 1.+1.j, 2.+1.j], + [-2.+0.j, -1.+0.j, 0.+0.j, 1.+0.j, 2.+0.j], + [-2.-1.j, -1.-1.j, 0.-1.j, 1.-1.j, 2.-1.j], + [-2.-2.j, -1.-2.j, 0.-2.j, 1.-2.j, 2.-2.j]]) + """ dpnp.check_supported_arrays_type(a, b, scalar_type=True, all_scalars=False) @@ -919,6 +946,13 @@ def tensordot(a, b, axes=2): r""" Compute tensor dot product along specified axes. + Given two tensors, `a` and `b`, and an array_like object containing + two array_like objects, ``(a_axes, b_axes)``, sum the products of + `a`'s and `b`'s elements (components) over the axes specified by + ``a_axes`` and ``b_axes``. The third argument can be a single non-negative + integer_like scalar, ``N``; if it is such, then the last ``N`` dimensions + of `a` and the first ``N`` dimensions of `b` are summed over. + For full documentation refer to :obj:`numpy.tensordot`. Parameters @@ -944,6 +978,7 @@ def tensordot(a, b, axes=2): See Also -------- + :obj:`dpnp.linalg.tensordot` : Equivalent function. :obj:`dpnp.dot` : Returns the dot product. :obj:`dpnp.einsum` : Evaluates the Einstein summation convention on the operands. diff --git a/dpnp/dpnp_iface_manipulation.py b/dpnp/dpnp_iface_manipulation.py index 6082fffebe65..dfc7e2a6e3d4 100644 --- a/dpnp/dpnp_iface_manipulation.py +++ b/dpnp/dpnp_iface_manipulation.py @@ -3365,7 +3365,7 @@ def vsplit(ary, indices_or_sections): Split an array into multiple sub-arrays vertically (row-wise). Please refer to the :obj:`dpnp.split` documentation. ``vsplit`` - is equivalent to ``split`` with ``axis=0``(default), the array + is equivalent to ``split`` with ``axis=0`` (default), the array is always split along the first axis regardless of the array dimension. For full documentation refer to :obj:`numpy.vsplit`. diff --git a/dpnp/dpnp_iface_mathematical.py b/dpnp/dpnp_iface_mathematical.py index 8e0faf5d79d3..8198f24bb3cc 100644 --- a/dpnp/dpnp_iface_mathematical.py +++ b/dpnp/dpnp_iface_mathematical.py @@ -42,6 +42,8 @@ # pylint: disable=no-name-in-module +import warnings + import dpctl.tensor as dpt import dpctl.tensor._tensor_elementwise_impl as ti import dpctl.tensor._type_utils as dtu @@ -842,9 +844,17 @@ def convolve(a, v, mode="full"): def cross(a, b, axisa=-1, axisb=-1, axisc=-1, axis=None): - """ + r""" Return the cross product of two (arrays of) vectors. + The cross product of `a` and `b` in :math:`R^3` is a vector perpendicular + to both `a` and `b`. If `a` and `b` are arrays of vectors, the vectors + are defined by the last axis of `a` and `b` by default, and these axes + can have dimensions 2 or 3. Where the dimension of either `a` or `b` is + 2, the third component of the input vector is assumed to be zero and the + cross product calculated accordingly. In cases where both input vectors + have dimension 2, the z-component of the cross product is returned. + For full documentation refer to :obj:`numpy.cross`. Parameters @@ -854,16 +864,17 @@ def cross(a, b, axisa=-1, axisb=-1, axisc=-1, axis=None): b : {dpnp.ndarray, usm_ndarray} Second input array. axisa : int, optional - Axis of `a` that defines the vector(s). By default, the last axis. + Axis of `a` that defines the vector(s). By default, the last axis. axisb : int, optional - Axis of `b` that defines the vector(s). By default, the last axis. + Axis of `b` that defines the vector(s). By default, the last axis. axisc : int, optional - Axis of `c` containing the cross product vector(s). Ignored if + Axis of `c` containing the cross product vector(s). Ignored if both input vectors have dimension 2, as the return is scalar. By default, the last axis. axis : {int, None}, optional If defined, the axis of `a`, `b` and `c` that defines the vector(s) - and cross product(s). Overrides `axisa`, `axisb` and `axisc`. + and cross product(s). Overrides `axisa`, `axisb` and `axisc`. + Default: ``None``. Returns ------- @@ -872,6 +883,7 @@ def cross(a, b, axisa=-1, axisb=-1, axisc=-1, axis=None): See Also -------- + :obj:`dpnp.linalg.cross` : Array API compatible version. :obj:`dpnp.inner` : Inner product. :obj:`dpnp.outer` : Outer product. @@ -961,6 +973,14 @@ def cross(a, b, axisa=-1, axisb=-1, axisc=-1, axis=None): "(the dimension of vector used in cross product must be 2 or 3)" ) + if a.shape[-1] == 2 or b.shape[-1] == 2: + warnings.warn( + "Arrays of 2-dimensional vectors are deprecated. Use arrays of " + "3-dimensional vectors instead. (deprecated in dpnp 0.17.0)", + DeprecationWarning, + stacklevel=2, + ) + # Modify the shape of input arrays if necessary a_shape = a.shape b_shape = b.shape diff --git a/dpnp/linalg/dpnp_iface_linalg.py b/dpnp/linalg/dpnp_iface_linalg.py index 712e8c5ba666..e8ab733ec5fc 100644 --- a/dpnp/linalg/dpnp_iface_linalg.py +++ b/dpnp/linalg/dpnp_iface_linalg.py @@ -40,6 +40,7 @@ # pylint: disable=no-member import numpy +from dpctl.tensor._numpy_helper import normalize_axis_tuple import dpnp @@ -67,7 +68,9 @@ __all__ = [ "cholesky", "cond", + "cross", "det", + "diagonal", "eig", "eigh", "eigvals", @@ -75,18 +78,23 @@ "inv", "lstsq", "matmul", + "matrix_norm", "matrix_power", "matrix_rank", "multi_dot", "norm", + "outer", "pinv", "qr", "solve", "svd", "svdvals", "slogdet", + "tensordot", "tensorinv", "tensorsolve", + "trace", + "vector_norm", ] @@ -210,6 +218,81 @@ def cond(x, p=None): return dpnp_cond(x, p) +def cross(x1, x2, /, *, axis=-1): + """ + Returns the cross product of 3-element vectors. + + If `x1` and/or `x2` are multi-dimensional arrays, then + the cross-product of each pair of corresponding 3-element vectors + is independently computed. + + This function is Array API compatible, contrary to :obj:`dpnp.cross`. + + For full documentation refer to :obj:`numpy.linalg.cross`. + + Parameters + ---------- + a : {dpnp.ndarray, usm_ndarray} + First input array. + b : {dpnp.ndarray, usm_ndarray} + Second input array. Must be compatible with `x1` for all + non-compute axes. The size of the axis over which to compute + the cross-product must be the same size as the respective axis + in `x1`. + axis : int, optional + The axis (dimension) of `x1` and `x2` containing the vectors for + which to compute the cross-product. + Default: ``-1``. + + Returns + ------- + out : dpnp.ndarray + An array containing the cross products. + + See Also + -------- + :obj:`dpnp.cross` : Similar function with support for more + keyword arguments. + + Examples + -------- + Vector cross-product. + + >>> import dpnp as np + >>> x = np.array([1, 2, 3]) + >>> y = np.array([4, 5, 6]) + >>> np.linalg.cross(x, y) + array([-3, 6, -3]) + + Multiple vector cross-products. Note that the direction of the cross + product vector is defined by the *right-hand rule*. + + >>> x = np.array([[1, 2, 3], [4, 5, 6]]) + >>> y = np.array([[4, 5, 6], [1, 2, 3]]) + >>> np.linalg.cross(x, y) + array([[-3, 6, -3], + [ 3, -6, 3]]) + + >>> x = np.array([[1, 2], [3, 4], [5, 6]]) + >>> y = np.array([[4, 5], [6, 1], [2, 3]]) + >>> np.linalg.cross(x, y, axis=0) + array([[-24, 6], + [ 18, 24], + [-6, -18]]) + + """ + + dpnp.check_supported_arrays_type(x1, x2) + if x1.shape[axis] != 3 or x2.shape[axis] != 3: + raise ValueError( + "Both input arrays must be (arrays of) 3-dimensional vectors, " + f"but they are {x1.shape[axis]} and {x2.shape[axis]} " + "dimensional instead." + ) + + return dpnp.cross(x1, x2, axis=axis) + + def det(a): """ Compute the determinant of an array. @@ -257,6 +340,101 @@ def det(a): return dpnp_det(a) +def diagonal(x, /, *, offset=0): + """ + Returns specified diagonals of a matrix (or a stack of matrices) `x`. + + This function is Array API compatible, contrary to :obj:`dpnp.diagonal` + the matrix is assumed to be defined by the last two dimensions. + + For full documentation refer to :obj:`numpy.linalg.diagonal`. + + Parameters + ---------- + x : (...,M,N) {dpnp.ndarray, usm_ndarray} + Input array having shape (..., M, N) and whose innermost two + dimensions form ``MxN`` matrices. + offset : int, optional + Offset specifying the off-diagonal relative to the main diagonal, + where: + + * offset = 0: the main diagonal. + * offset > 0: off-diagonal above the main diagonal. + * offset < 0: off-diagonal below the main diagonal. + + Default: ``0``. + + Returns + ------- + out : (...,min(N,M)) dpnp.ndarray + An array containing the diagonals and whose shape is determined by + removing the last two dimensions and appending a dimension equal to + the size of the resulting diagonals. The returned array must have + the same data type as `x`. + + See Also + -------- + :obj:`dpnp.diagonal` : Similar function with support for more + keyword arguments. + + Examples + -------- + >>> import dpnp as np + >>> a = np.arange(4).reshape(2,2); a + array([[0, 1], + [2, 3]]) + >>> np.linalg.diagonal(a) + array([0, 3]) + + A 3-D example: + + >>> a = np.arange(8).reshape(2,2,2); a + array([[[0, 1], + [2, 3]], + [[4, 5], + [6, 7]]]) + >>> np.linalg.diagonal(a) + array([[0, 3], + [4, 7]]) + + Diagonals adjacent to the main diagonal can be obtained by using the + `offset` argument: + + >>> a = np.arange(9).reshape(3, 3) + >>> a + array([[0, 1, 2], + [3, 4, 5], + [6, 7, 8]]) + >>> np.linalg.diagonal(a, offset=1) # First superdiagonal + array([1, 5]) + >>> np.linalg.diagonal(a, offset=2) # Second superdiagonal + array([2]) + >>> np.linalg.diagonal(a, offset=-1) # First subdiagonal + array([3, 7]) + >>> np.linalg.diagonal(a, offset=-2) # Second subdiagonal + array([6]) + + The anti-diagonal can be obtained by reversing the order of elements + using either :obj:`dpnp.flipud` or :obj:`dpnp.fliplr`. + + >>> a = np.arange(9).reshape(3, 3) + >>> a + array([[0, 1, 2], + [3, 4, 5], + [6, 7, 8]]) + >>> np.linalg.diagonal(np.fliplr(a)) # Horizontal flip + array([2, 4, 6]) + >>> np.linalg.diagonal(np.flipud(a)) # Vertical flip + array([6, 4, 2]) + + Note that the order in which the diagonal is retrieved varies depending + on the flip function. + + """ + + return dpnp.diagonal(x, offset, axis1=-2, axis2=-1) + + def eig(a): """ Compute the eigenvalues and right eigenvectors of a square array. @@ -705,8 +883,8 @@ def matmul(x1, x2, /): See Also -------- - :obj:`dpnp.matmul` : similar function with support for more - kwyeord arguments. + :obj:`dpnp.matmul` : Similar function with support for more + keyword arguments. Examples -------- @@ -752,6 +930,73 @@ def matmul(x1, x2, /): return dpnp.matmul(x1, x2) +def matrix_norm(x, /, *, keepdims=False, ord="fro"): + """ + Computes the matrix norm of a matrix (or a stack of matrices) `x`. + + This function is Array API compatible. + + For full documentation refer to :obj:`numpy.linalg.matrix_norm`. + + Parameters + ---------- + x : {dpnp.ndarray, usm_ndarray} + Input array having shape (..., M, N) and whose two innermost + dimensions form ``MxN`` matrices. + 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`. + Default: ``False``. + ord : {None, 1, -1, 2, -2, dpnp.inf, -dpnp.inf, 'fro', 'nuc'}, optional + The order of the norm. For details see the table under ``Notes`` + section in :obj:`dpnp.linalg.norm`. + Default: ``"fro"``. + + Returns + ------- + out : dpnp.ndarray + Norm of the matrix. + + See Also + -------- + :obj:`dpnp.linalg.norm` : Generic norm function. + + 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.matrix_norm(b) + array(7.74596669) + >>> np.linalg.matrix_norm(b, ord='fro') + array(7.74596669) + >>> np.linalg.matrix_norm(b, ord=np.inf) + array(9.) + >>> np.linalg.matrix_norm(b, ord=-np.inf) + array(2.) + + >>> np.linalg.matrix_norm(b, ord=1) + array(7.) + >>> np.linalg.matrix_norm(b, ord=-1) + array(6.) + >>> np.linalg.matrix_norm(b, ord=2) + array(7.34846923) + >>> np.linalg.matrix_norm(b, ord=-2) + array(4.35106603e-18) # may vary + + """ + + return dpnp.linalg.norm(x, axis=(-2, -1), keepdims=keepdims, ord=ord) + + def matrix_power(a, n): """ Raise a square matrix to the (integer) power `n`. @@ -939,9 +1184,13 @@ def multi_dot(arrays, *, out=None): def norm(x, ord=None, axis=None, keepdims=False): - """ + r""" 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 @@ -951,14 +1200,15 @@ def norm(x, ord=None, axis=None, keepdims=False): `ord` is ``None``. If both `axis` and `ord` are ``None``, the 2-norm of ``x.ravel`` will be returned. ord : {int, float, inf, -inf, "fro", "nuc"}, optional - Norm type. inf means dpnp's `inf` object. The default is ``None``. + Norm type. inf means dpnp's `inf` object. + Default: ``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 + 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. - Default: ``False``. + Default: ``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 @@ -970,6 +1220,49 @@ def norm(x, ord=None, axis=None, keepdims=False): out : dpnp.ndarray Norm of the matrix or vector(s). + See Also + -------- + :obj:`dpnp.linalg.matrix_norm` : Computes the matrix norm of a matrix. + :obj:`dpnp.linalg.vector_norm` : Computes the vector norm of a vector. + + Notes + ----- + For values of ``ord < 1``, the result is, strictly speaking, not a + mathematical 'norm', but it may still be useful for various numerical + purposes. + + The following norms can be calculated: + + ===== ============================ ========================== + ord norm for matrices norm for vectors + ===== ============================ ========================== + None Frobenius norm 2-norm + 'fro' Frobenius norm -- + 'nuc' nuclear norm -- + inf max(sum(abs(x), axis=1)) max(abs(x)) + -inf min(sum(abs(x), axis=1)) min(abs(x)) + 0 -- sum(x != 0) + 1 max(sum(abs(x), axis=0)) as below + -1 min(sum(abs(x), axis=0)) as below + 2 2-norm (largest sing. value) as below + -2 smallest singular value as below + other -- sum(abs(x)**ord)**(1./ord) + ===== ============================ ========================== + + The Frobenius norm is given by [1]_: + + :math:`||A||_F = [\sum_{i,j} abs(a_{i,j})^2]^{1/2}` + + The nuclear norm is the sum of the singular values. + + Both the Frobenius and nuclear norm orders are only defined for + matrices and raise a ValueError when ``x.ndim != 2``. + + References + ---------- + .. [1] G. H. Golub and C. F. Van Loan, *Matrix Computations*, + Baltimore, MD, Johns Hopkins University Press, 1985, pg. 15 + Examples -------- >>> import dpnp as np @@ -1044,6 +1337,80 @@ def norm(x, ord=None, axis=None, keepdims=False): return dpnp_norm(x, ord, axis, keepdims) +def outer(x1, x2, /): + """ + Compute the outer product of two vectors. + + This function is Array API compatible. Compared to :obj:`dpnp.outer`, + it accepts 1-dimensional inputs only. + + For full documentation refer to :obj:`numpy.linalg.outer`. + + Parameters + ---------- + a : (M,) {dpnp.ndarray, usm_ndarray} + One-dimensional input array of size ``M``. + Must have a numeric data type. + b : (N,) {dpnp.ndarray, usm_ndarray} + One-dimensional input array of size ``N``. + Must have a numeric data type. + + Returns + ------- + out : (M, N) dpnp.ndarray + ``out[i, j] = a[i] * b[j]`` + + See Also + -------- + :obj:`dpnp.outer` : Similar function with support for more + keyword arguments. + + Examples + -------- + >>> import dpnp as np + >>> a = np.array([1, 1, 1]) + >>> b = np.array([1, 2, 3]) + >>> np.linalg.outer(a, b) + array([[1, 2, 3], + [1, 2, 3], + [1, 2, 3]]) + + Make a (*very* coarse) grid for computing a Mandelbrot set: + + >>> rl = np.linalg.outer(np.ones((5,)), np.linspace(-2, 2, 5)) + >>> rl + array([[-2., -1., 0., 1., 2.], + [-2., -1., 0., 1., 2.], + [-2., -1., 0., 1., 2.], + [-2., -1., 0., 1., 2.], + [-2., -1., 0., 1., 2.]]) + >>> im = np.linalg.outer(1j*np.linspace(2, -2, 5), np.ones((5,))) + >>> im + array([[0.+2.j, 0.+2.j, 0.+2.j, 0.+2.j, 0.+2.j], + [0.+1.j, 0.+1.j, 0.+1.j, 0.+1.j, 0.+1.j], + [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], + [0.-1.j, 0.-1.j, 0.-1.j, 0.-1.j, 0.-1.j], + [0.-2.j, 0.-2.j, 0.-2.j, 0.-2.j, 0.-2.j]]) + >>> grid = rl + im + >>> grid + array([[-2.+2.j, -1.+2.j, 0.+2.j, 1.+2.j, 2.+2.j], + [-2.+1.j, -1.+1.j, 0.+1.j, 1.+1.j, 2.+1.j], + [-2.+0.j, -1.+0.j, 0.+0.j, 1.+0.j, 2.+0.j], + [-2.-1.j, -1.-1.j, 0.-1.j, 1.-1.j, 2.-1.j], + [-2.-2.j, -1.-2.j, 0.-2.j, 1.-2.j, 2.-2.j]]) + + """ + + dpnp.check_supported_arrays_type(x1, x2) + if x1.ndim != 1 or x2.ndim != 1: + raise ValueError( + "Input arrays must be one-dimensional, but they are " + f"{x1.ndim=} and {x2.ndim=}." + ) + + return dpnp.outer(x1, x2) + + def pinv(a, rcond=1e-15, hermitian=False): """ Compute the (Moore-Penrose) pseudo-inverse of a matrix. @@ -1428,6 +1795,106 @@ def slogdet(a): return dpnp_slogdet(a) +def tensordot(a, b, /, *, axes=2): + r""" + Compute tensor dot product along specified axes. + + Given two tensors, `a` and `b`, and an array_like object containing + two array_like objects, ``(a_axes, b_axes)``, sum the products of + `a`'s and `b`'s elements (components) over the axes specified by + ``a_axes`` and ``b_axes``. The third argument can be a single non-negative + integer_like scalar, ``N``; if it is such, then the last ``N`` dimensions + of `a` and the first ``N`` dimensions of `b` are summed over. + + For full documentation refer to :obj:`numpy.linalg.tensordot`. + + Parameters + ---------- + a : {dpnp.ndarray, usm_ndarray, scalar} + First input array. Both inputs `a` and `b` can not be scalars + at the same time. + b : {dpnp.ndarray, usm_ndarray, scalar} + Second input array. Both inputs `a` and `b` can not be scalars + at the same time. + axes : int or (2,) array_like + * integer_like: If an int `N`, sum over the last `N` axes of `a` and + the first `N` axes of `b` in order. The sizes of the corresponding + axes must match. + * (2,) array_like: A list of axes to be summed over, first sequence + applying to `a`, second to `b`. Both elements array_like must be of + the same length. + + Returns + ------- + out : dpnp.ndarray + Returns the tensor dot product of `a` and `b`. + + See Also + -------- + :obj:`dpnp.tensordot` : Equivalent function. + :obj:`dpnp.dot` : Returns the dot product. + :obj:`dpnp.einsum` : Evaluates the Einstein summation convention + on the operands. + + Notes + ----- + Three common use cases are: + * ``axes = 0`` : tensor product :math:`a \otimes b` + * ``axes = 1`` : tensor dot product :math:`a \cdot b` + * ``axes = 2`` : (default) tensor double contraction :math:`a:b` + + When `axes` is integer, the sequence for evaluation will be: first + the -Nth axis in `a` and 0th axis in `b`, and the -1th axis in `a` and + Nth axis in `b` last. + + When there is more than one axis to sum over - and they are not the last + (first) axes of `a` (`b`) - the argument `axes` should consist of + two sequences of the same length, with the first axis to sum over given + first in both sequences, the second axis second, and so forth. + + The shape of the result consists of the non-contracted axes of the + first tensor, followed by the non-contracted axes of the second. + + Examples + -------- + >>> import dpnp as np + >>> a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) + >>> b = np.array([1, 2, 3]) + >>> np.linalg.tensordot(a, b, axes=1) + array([14, 32, 50]) + + >>> a = np.arange(60.).reshape(3,4,5) + >>> b = np.arange(24.).reshape(4,3,2) + >>> c = np.linalg.tensordot(a,b, axes=([1,0],[0,1])) + >>> c.shape + (5, 2) + >>> c + array([[4400., 4730.], + [4532., 4874.], + [4664., 5018.], + [4796., 5162.], + [4928., 5306.]]) + + A slower but equivalent way of computing the same... + + >>> d = np.zeros((5,2)) + >>> for i in range(5): + ... for j in range(2): + ... for k in range(3): + ... for n in range(4): + ... d[i,j] += a[k,n,i] * b[n,k,j] + >>> c == d + array([[ True, True], + [ True, True], + [ True, True], + [ True, True], + [ True, True]]) + + """ + + return dpnp.tensordot(a, b, axes=axes) + + def tensorinv(a, ind=2): """ Compute the 'inverse' of an N-dimensional array. @@ -1560,3 +2027,197 @@ def tensorsolve(a, b, axes=None): b = dpnp.ravel(b) res = solve(a, b) return res.reshape(old_shape) + + +def trace(x, /, *, offset=0, dtype=None): + """ + Returns the sum along the specified diagonals of a matrix + (or a stack of matrices) `x`. + + This function is Array API compatible, contrary to :obj:`dpnp.trace`. + + For full documentation refer to :obj:`numpy.linalg.trace`. + + Parameters + ---------- + x : (...,M,N) {dpnp.ndarray, usm_ndarray} + Input array having shape (..., M, N) and whose innermost two + dimensions form ``MxN`` matrices. + offset : int, optional + Offset specifying the off-diagonal relative to the main diagonal, + where: + + * offset = 0: the main diagonal. + * offset > 0: off-diagonal above the main diagonal. + * offset < 0: off-diagonal below the main diagonal. + + Default: ``0``. + dtype : dtype, optional + Determines the data-type of the returned array and of the accumulator + where the elements are summed. If `dtype` has the value ``None`` and + `a` is of integer type of precision less than the default integer + precision, then the default integer precision is used. Otherwise, the + precision is the same as that of `a`. + Default: ``None``. + + Returns + ------- + out : dpnp.ndarray + An array containing the traces and whose shape is determined by + removing the last two dimensions and storing the traces in the last + array dimension. For example, if x has rank k and shape: + (I, J, K, ..., L, M, N), then an output array has rank k-2 and shape: + (I, J, K, ..., L) where: + ``out[i, j, k, ..., l] = dpnp.linalg.trace(a[i, j, k, ..., l, :, :])`` + + The returned array must have a data type as described by the dtype + parameter above. + + See Also + -------- + :obj:`dpnp.trace` : Similar function with support for more + keyword arguments. + + Examples + -------- + >>> import dpnp as np + >>> np.linalg.trace(np.eye(3)) + array(3.) + >>> a = np.arange(8).reshape((2, 2, 2)) + >>> np.linalg.trace(a) + array([3, 11]) + + Trace is computed with the last two axes as the 2-d sub-arrays. + This behavior differs from :obj:`dpnp.trace` which uses the first two + axes by default. + + >>> a = np.arange(24).reshape((3, 2, 2, 2)) + >>> np.linalg.trace(a).shape + (3, 2) + + Traces adjacent to the main diagonal can be obtained by using the + `offset` argument: + + >>> a = np.arange(9).reshape((3, 3)); a + array([[0, 1, 2], + [3, 4, 5], + [6, 7, 8]]) + >>> np.linalg.trace(a, offset=1) # First superdiagonal + array(6) + >>> np.linalg.trace(a, offset=2) # Second superdiagonal + array(2) + >>> np.linalg.trace(a, offset=-1) # First subdiagonal + array(10) + >>> np.linalg.trace(a, offset=-2) # Second subdiagonal + array(6) + + """ + + return dpnp.trace(x, offset, axis1=-2, axis2=-1, dtype=dtype) + + +def vector_norm(x, /, *, axis=None, keepdims=False, ord=2): + """ + Computes the vector norm of a vector (or batch of vectors) `x`. + + This function is Array API compatible. + + For full documentation refer to :obj:`numpy.linalg.vector_norm`. + + Parameters + ---------- + x : {dpnp.ndarray, usm_ndarray} + Input array. + axis : {None, int, n-tuple of ints}, optional + If an integer, `axis` specifies the axis (dimension) along which + to compute vector norms. If an n-tuple, `axis` specifies the axes + (dimensions) along which to compute batched vector norms. If ``None``, + the vector norm must be computed over all array values (i.e., + equivalent to computing the vector norm of a flattened array). + Default: ``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`. + Default: ``False``. + ord : {int, float, inf, -inf, 'fro', 'nuc'}, optional + The order of the norm. For details see the table under ``Notes`` + section in :obj:`dpnp.linalg.norm`. + Default: ``2``. + + Returns + ------- + out : dpnp.ndarray + Norm of the vector. + + See Also + -------- + :obj:`dpnp.linalg.norm` : Generic norm function. + + Examples + -------- + >>> import dpnp as np + >>> a = np.arange(9) + 1 + >>> a + array([1, 2, 3, 4, 5, 6, 7, 8, 9]) + >>> b = a.reshape((3, 3)) + >>> b + array([[1, 2, 3], + [4, 5, 6], + [7, 8, 9]]) + + >>> np.linalg.vector_norm(b) + array(16.88194302) + >>> np.linalg.vector_norm(b, ord=np.inf) + array(9.) + >>> np.linalg.vector_norm(b, ord=-np.inf) + array(1.) + + >>> np.linalg.vector_norm(b, ord=1) + array(45.) + >>> np.linalg.vector_norm(b, ord=-1) + array(0.35348576) + >>> np.linalg.vector_norm(b, ord=2) + array(16.881943016134134) + >>> np.linalg.vector_norm(b, ord=-2) + array(0.8058837395885292) + + """ + + dpnp.check_supported_arrays_type(x) + x_shape = list(x.shape) + x_ndim = x.ndim + if axis is None: + # Note: dpnp.linalg.norm() doesn't handle 0-D arrays + x = dpnp.ravel(x) + _axis = 0 + elif isinstance(axis, tuple): + # Note: The axis argument supports any number of axes, whereas + # dpnp.linalg.norm() only supports a single axis or two axes + # for vector norm. + normalized_axis = normalize_axis_tuple(axis, x_ndim) + rest = tuple(i for i in range(x_ndim) if i not in normalized_axis) + newshape = axis + rest + x = dpnp.transpose(x, newshape).reshape( + ( + numpy.prod([x_shape[i] for i in axis], dtype=int), + *[x_shape[i] for i in rest], + ) + ) + _axis = 0 + else: + _axis = axis + + res = dpnp.linalg.norm(x, axis=_axis, ord=ord) + + if keepdims: + # We can't reuse dpnp.linalg.norm(keepdims) because of the reshape hacks + # above to avoid matrix norm logic. + _axis = normalize_axis_tuple( + range(len(x_shape)) if axis is None else axis, len(x_shape) + ) + for i in _axis: + x_shape[i] = 1 + res = res.reshape(tuple(x_shape)) + + return res diff --git a/tests/test_arraycreation.py b/tests/test_arraycreation.py index 8d913151f3a4..147b92ebce9e 100644 --- a/tests/test_arraycreation.py +++ b/tests/test_arraycreation.py @@ -12,6 +12,7 @@ ) import dpnp +from tests.third_party.cupy import testing from .helper import ( assert_dtype_allclose, @@ -66,6 +67,18 @@ def test_out(self): assert_equal(result, expected) assert result is iout + @testing.with_requires("numpy>=2.0") + @pytest.mark.parametrize( + "dtype", get_all_dtypes(no_none=True, no_bool=True) + ) + @pytest.mark.parametrize("offset", [0, 1, -1]) + def test_linalg_trace(self, dtype, offset): + a = numpy.arange(12, dtype=dtype).reshape(3, 4) + ia = dpnp.array(a) + result = dpnp.linalg.trace(ia, offset=offset, dtype=dtype) + expected = numpy.linalg.trace(a, offset=offset, dtype=dtype) + assert_equal(result, expected) + @pytest.mark.parametrize( "func, args", diff --git a/tests/test_indexing.py b/tests/test_indexing.py index cf694ff0357a..ecefc34773ec 100644 --- a/tests/test_indexing.py +++ b/tests/test_indexing.py @@ -14,6 +14,7 @@ import dpnp from dpnp.dpnp_array import dpnp_array +from tests.third_party.cupy import testing from .helper import get_all_dtypes, get_integer_dtypes, has_support_aspect64 @@ -72,6 +73,15 @@ def test_diagonal_axes(self, shape, axis_pairs, dtype): result = dpnp.diagonal(a_dp, axis1=axis1, axis2=axis2) assert_array_equal(expected, result) + @testing.with_requires("numpy>=2.0") + @pytest.mark.parametrize("offset", [-3, -1, 0, 1, 3]) + def test_linalg_diagonal(self, offset): + a = numpy.arange(24).reshape(2, 2, 2, 3) + a_dp = dpnp.array(a) + expected = numpy.linalg.diagonal(a, offset=offset) + result = dpnp.linalg.diagonal(a_dp, offset=offset) + assert_array_equal(expected, result) + def test_diagonal_errors(self): a = dpnp.arange(12).reshape(3, 4) diff --git a/tests/test_linalg.py b/tests/test_linalg.py index d10f610e51c7..92251da6276c 100644 --- a/tests/test_linalg.py +++ b/tests/test_linalg.py @@ -2115,15 +2115,11 @@ def setup_method(self): @pytest.mark.usefixtures("suppress_divide_numpy_warnings") @pytest.mark.parametrize( - "shape", [(0,), (5, 0), (2, 0, 3)], ids=["(0,)", "(5,0)", "(2, 0, 3)"] + "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"]) + @pytest.mark.parametrize("ord", [None, -2, -1, 0, 1, 2, 3]) + @pytest.mark.parametrize("axis", [0, None]) + @pytest.mark.parametrize("keepdims", [True, False]) def test_norm_empty(self, shape, ord, axis, keepdims): a = numpy.empty(shape) ia = inp.array(a) @@ -2153,11 +2149,9 @@ def test_norm_empty(self, shape, ord, axis, keepdims): assert_dtype_allclose(result, expected) @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"], + "ord", [None, -inp.inf, -2, -1, 0, 1, 2, 3, inp.inf] ) - @pytest.mark.parametrize("axis", [0, None], ids=["0", "None"]) + @pytest.mark.parametrize("axis", [0, None]) def test_norm_0D(self, ord, axis): a = numpy.array(2) ia = inp.array(a) @@ -2176,12 +2170,10 @@ def test_norm_0D(self, ord, axis): @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"], + "ord", [None, -inp.inf, -2, -1, 0, 1, 2, 3.5, inp.inf] ) - @pytest.mark.parametrize("axis", [0, None], ids=["0", "None"]) - @pytest.mark.parametrize("keepdims", [True, False], ids=["True", "False"]) + @pytest.mark.parametrize("axis", [0, None]) + @pytest.mark.parametrize("keepdims", [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) @@ -2193,12 +2185,10 @@ def test_norm_1D(self, dtype, ord, axis, keepdims): @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"], + "ord", [None, -inp.inf, -2, -1, 0, 1, 2, 3.5, inp.inf] ) - @pytest.mark.parametrize("axis", [0, None], ids=["0", "None"]) - @pytest.mark.parametrize("keepdims", [True, False], ids=["True", "False"]) + @pytest.mark.parametrize("axis", [0, None]) + @pytest.mark.parametrize("keepdims", [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) @@ -2212,25 +2202,12 @@ def test_norm_1D_complex(self, dtype, ord, axis, keepdims): @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"', - ], + "ord", [None, -inp.inf, -2, -1, 1, 2, 3, inp.inf, "fro", "nuc"] ) @pytest.mark.parametrize( "axis", [0, 1, (1, 0), None], ids=["0", "1", "(1, 0)", "None"] ) - @pytest.mark.parametrize("keepdims", [True, False], ids=["True", "False"]) + @pytest.mark.parametrize("keepdims", [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 @@ -2252,25 +2229,12 @@ def test_norm_2D(self, dtype, ord, axis, keepdims): @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"', - ], + "ord", [None, -inp.inf, -2, -1, 1, 2, 3, inp.inf, "fro", "nuc"] ) @pytest.mark.parametrize( "axis", [0, 1, (1, 0), None], ids=["0", "1", "(1, 0)", "None"] ) - @pytest.mark.parametrize("keepdims", [True, False], ids=["True", "False"]) + @pytest.mark.parametrize("keepdims", [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) @@ -2292,27 +2256,14 @@ def test_norm_2D_complex(self, dtype, ord, axis, keepdims): @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"', - ], + "ord", [None, -inp.inf, -2, -1, 1, 2, 3, inp.inf, "fro", "nuc"] ) @pytest.mark.parametrize( "axis", [-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"]) + @pytest.mark.parametrize("keepdims", [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 @@ -2338,27 +2289,14 @@ def test_norm_ND(self, dtype, ord, axis, keepdims): @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"', - ], + "ord", [None, -inp.inf, -2, -1, 1, 2, 3, inp.inf, "fro", "nuc"] ) @pytest.mark.parametrize( "axis", [-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"]) + @pytest.mark.parametrize("keepdims", [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) @@ -2384,27 +2322,14 @@ def test_norm_ND_complex(self, dtype, ord, axis, keepdims): @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"', - ], + "ord", [None, -inp.inf, -2, -1, 1, 2, 3, inp.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"]) + @pytest.mark.parametrize("keepdims", [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 @@ -2427,7 +2352,7 @@ def test_norm_usm_ndarray(self, dtype, ord, axis, keepdims): ) assert_dtype_allclose(result, expected) - @pytest.mark.parametrize("stride", [3, -1, -5], ids=["3", "-1", "-5"]) + @pytest.mark.parametrize("stride", [3, -1, -5]) def test_norm_strided_1D(self, stride): a = numpy.arange(25) ia = inp.array(a) @@ -2478,6 +2403,73 @@ def test_norm_strided_ND(self, axis, stride): expected = numpy.linalg.norm(a, axis=axis) assert_dtype_allclose(result, expected) + @testing.with_requires("numpy>=2.0") + @pytest.mark.parametrize( + "ord", + [None, -inp.inf, -2, -1, 1, 2, inp.inf, "fro", "nuc"], + ) + @pytest.mark.parametrize("keepdims", [True, False]) + def test_matrix_norm(self, ord, keepdims): + a = numpy.array(numpy.random.uniform(-5, 5, 15)).reshape(3, 5) + ia = inp.array(a) + + result = inp.linalg.matrix_norm(ia, ord=ord, keepdims=keepdims) + expected = numpy.linalg.matrix_norm(a, ord=ord, keepdims=keepdims) + assert_dtype_allclose(result, expected) + + @testing.with_requires("numpy>=2.0") + @pytest.mark.parametrize( + "ord", [None, -inp.inf, -2, -1, 0, 1, 2, 3.5, inp.inf] + ) + def test_vector_norm_0D(self, ord): + a = numpy.array(2) + ia = inp.array(a) + + result = inp.linalg.vector_norm(ia, ord=ord) + expected = numpy.linalg.vector_norm(a, ord=ord) + assert_dtype_allclose(result, expected) + + @testing.with_requires("numpy>=2.0") + @pytest.mark.parametrize( + "ord", [None, -inp.inf, -2, -1, 0, 1, 2, 3.5, inp.inf] + ) + @pytest.mark.parametrize("axis", [0, None]) + @pytest.mark.parametrize("keepdims", [True, False]) + def test_vector_norm_1D(self, ord, axis, keepdims): + a = numpy.array(numpy.random.uniform(-5, 5, 10)) + ia = inp.array(a) + + result = inp.linalg.vector_norm( + ia, ord=ord, axis=axis, keepdims=keepdims + ) + expected = numpy.linalg.vector_norm( + a, ord=ord, axis=axis, keepdims=keepdims + ) + assert_dtype_allclose(result, expected) + + @testing.with_requires("numpy>=2.0") + @pytest.mark.usefixtures("suppress_divide_numpy_warnings") + @pytest.mark.parametrize( + "ord", [None, -inp.inf, -2, -1, 1, 2, 3.5, inp.inf] + ) + @pytest.mark.parametrize( + "axis", + [-1, 0, (0, 1), (-1, -2), (0, 1, -2, -1), None], + ids=["-1", "0", "(0, 1)", "(-1, -2)", "(0, 1, -2, -1)", "None"], + ) + @pytest.mark.parametrize("keepdims", [True, False]) + def test_vector_norm_ND(self, ord, axis, keepdims): + a = numpy.arange(120).reshape(2, 3, 4, 5) + ia = inp.array(a) + + result = inp.linalg.vector_norm( + ia, ord=ord, axis=axis, keepdims=keepdims + ) + expected = numpy.linalg.vector_norm( + a, ord=ord, axis=axis, keepdims=keepdims + ) + assert_dtype_allclose(result, expected) + def test_norm_error(self): ia = inp.arange(120).reshape(2, 3, 4, 5) diff --git a/tests/test_mathematical.py b/tests/test_mathematical.py index 52677b0403bb..0fa3309763fd 100644 --- a/tests/test_mathematical.py +++ b/tests/test_mathematical.py @@ -3874,13 +3874,16 @@ def test_matmul_large(self, shape_pair): expected = numpy.matmul(a, b) assert_dtype_allclose(result, expected, factor=24) - def test_matmul_alias(self): - a = dpnp.ones((3, 4)) - b = dpnp.ones((4, 5)) + @testing.with_requires("numpy>=2.0") + def test_linalg_matmul(self): + a = numpy.ones((3, 4)) + b = numpy.ones((4, 5)) + ia = dpnp.array(a) + ib = dpnp.array(b) - result1 = dpnp.matmul(a, b) - result2 = dpnp.linalg.matmul(a, b) - assert_array_equal(result1, result2) + result = dpnp.linalg.matmul(ia, ib) + expected = numpy.linalg.matmul(a, b) + assert_array_equal(result, expected) class TestMatmulInvalidCases: diff --git a/tests/test_outer.py b/tests/test_outer.py index 3df5f4f4100c..39e8146fdadc 100644 --- a/tests/test_outer.py +++ b/tests/test_outer.py @@ -37,6 +37,21 @@ def test_the_same_matrix(self, xp, dtype): a = xp.arange(27, dtype=dtype).reshape(3, 3, 3) return xp.outer(a, a) + @testing.with_requires("numpy>=2.0") + @testing.numpy_cupy_allclose() + def test_linalg_outer(self, xp): + a = xp.arange(10) + b = xp.arange(10) - 5 + + return xp.linalg.outer(a, b) + + @testing.with_requires("numpy>=2.0") + def test_linalg_outer_error(self): + for xp in (np, dp): + a = xp.arange(9).reshape(3, 3) + with pytest.raises(ValueError): + xp.linalg.outer(a, a) + class TestScalarOuter(unittest.TestCase): @testing.for_all_dtypes() diff --git a/tests/test_product.py b/tests/test_product.py index 7fa26b13bc60..6c199b070d25 100644 --- a/tests/test_product.py +++ b/tests/test_product.py @@ -5,6 +5,7 @@ from numpy.testing import assert_raises import dpnp +from tests.third_party.cupy import testing from .helper import assert_dtype_allclose, get_all_dtypes, get_complex_dtypes @@ -50,6 +51,7 @@ def test_cross_3x3(self, x1, x2, axisa, axisb, axisc, axis): expected = numpy.cross(np_x1, np_x2, axisa, axisb, axisc, axis) assert_dtype_allclose(result, expected) + @pytest.mark.filterwarnings("ignore::DeprecationWarning") @pytest.mark.parametrize( "dtype", get_all_dtypes(no_bool=True, no_complex=True) ) @@ -77,6 +79,7 @@ def test_cross(self, dtype, shape1, shape2, axis_a, axis_b, axis_c): expected = numpy.cross(a, b, axis_a, axis_b, axis_c) assert_dtype_allclose(result, expected) + @pytest.mark.filterwarnings("ignore::DeprecationWarning") @pytest.mark.parametrize("dtype", get_complex_dtypes()) @pytest.mark.parametrize( "shape1, shape2, axis_a, axis_b, axis_c", @@ -102,6 +105,7 @@ def test_cross_complex(self, dtype, shape1, shape2, axis_a, axis_b, axis_c): expected = numpy.cross(a, b, axis_a, axis_b, axis_c) assert_dtype_allclose(result, expected) + @pytest.mark.filterwarnings("ignore::DeprecationWarning") @pytest.mark.parametrize("dtype", get_all_dtypes(no_bool=True)) @pytest.mark.parametrize( "shape1, shape2, axis", @@ -138,6 +142,7 @@ def test_cross_input_dtype_matrix(self, dtype1, dtype2): expected = numpy.cross(a, b) assert_dtype_allclose(result, expected) + @pytest.mark.filterwarnings("ignore::DeprecationWarning") @pytest.mark.parametrize( "dtype", get_all_dtypes(no_bool=True, no_complex=True) ) @@ -168,7 +173,7 @@ def test_cross_broadcast( assert_dtype_allclose(result, expected) @pytest.mark.parametrize("dtype", get_all_dtypes(no_bool=True)) - @pytest.mark.parametrize("stride", [3, -3], ids=["3", "-3"]) + @pytest.mark.parametrize("stride", [3, -3]) def test_cross_strided(self, dtype, stride): a = numpy.arange(1, 10, dtype=dtype) b = numpy.arange(1, 10, dtype=dtype) @@ -179,6 +184,18 @@ def test_cross_strided(self, dtype, stride): expected = numpy.cross(a[::stride], b[::stride]) assert_dtype_allclose(result, expected) + @testing.with_requires("numpy>=2.0") + @pytest.mark.parametrize("axis", [0, 1, -1]) + def test_linalg_cross(self, axis): + a = numpy.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) + b = numpy.array([[7, 8, 9], [4, 5, 6], [1, 2, 3]]) + ia = dpnp.array(a) + ib = dpnp.array(b) + + result = dpnp.linalg.cross(ia, ib, axis=axis) + expected = numpy.linalg.cross(a, b, axis=axis) + assert_dtype_allclose(result, expected) + def test_cross_error(self): a = dpnp.arange(3) b = dpnp.arange(4) @@ -197,6 +214,14 @@ def test_cross_error(self): with pytest.raises(TypeError): dpnp.cross(a, a) + @testing.with_requires("numpy>=2.0") + def test_linalg_cross_error(self): + a = dpnp.arange(4) + b = dpnp.arange(4) + # Both input arrays must be (arrays of) 3-dimensional vectors + with pytest.raises(ValueError): + dpnp.linalg.cross(a, b) + class TestDot: def setup_method(self): @@ -1093,7 +1118,7 @@ def test_tensordot_input_dtype_matrix(self, dtype1, dtype2): result = dpnp.tensordot(ia, ib) expected = numpy.tensordot(a, b) - assert_dtype_allclose(result, expected) + assert_dtype_allclose(result, expected, factor=16) @pytest.mark.parametrize( "stride", @@ -1113,6 +1138,21 @@ def test_tensordot_strided(self, stride): expected = numpy.tensordot(a, a, axes=axes) assert_dtype_allclose(result, expected) + @testing.with_requires("numpy>=2.0") + @pytest.mark.parametrize( + "axes", + [([0, 1]), ([0, 1], [1, 2]), ([-2, -3], [3, 2])], + ) + def test_linalg_tensordot(self, axes): + a = numpy.array(numpy.random.uniform(-10, 10, 120)).reshape(2, 5, 3, 4) + b = numpy.array(numpy.random.uniform(-10, 10, 120)).reshape(4, 2, 5, 3) + ia = dpnp.array(a) + ib = dpnp.array(b) + + result = dpnp.linalg.tensordot(ia, ib, axes=axes) + expected = numpy.linalg.tensordot(a, b, axes=axes) + assert_dtype_allclose(result, expected) + def test_tensordot_error(self): a = 5 b = 2