diff --git a/doc/index.rst b/doc/index.rst index 3156c37834b3..38c12489636b 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -5,7 +5,7 @@ Data Parallel Extension for NumPy* ================================== .. module:: dpnp - :noindex: + :no-index: .. toctree:: :maxdepth: 2 diff --git a/doc/known_words.txt b/doc/known_words.txt index c68d216ac43a..10a1cc5e6fe8 100644 --- a/doc/known_words.txt +++ b/doc/known_words.txt @@ -29,6 +29,8 @@ finiteness Flannery Fortran Frobenius +fs +getter Hadamard Hypergeometric iinfo @@ -40,11 +42,14 @@ Mersenne meshgrid Mises multinomial +multivalued NaN NaT ndarray ndarrays ndim +Nj +Nk normed Nyquist oneAPI diff --git a/doc/reference/binary.rst b/doc/reference/binary.rst index 2ff447eb8281..8313d91aaa25 100644 --- a/doc/reference/binary.rst +++ b/doc/reference/binary.rst @@ -4,7 +4,7 @@ Binary Operations .. https://docs.scipy.org/doc/numpy/reference/routines.bitwise.html Element-wise bit operations --------------------------- +--------------------------- .. autosummary:: :toctree: generated/ diff --git a/doc/reference/fft.rst b/doc/reference/fft.rst index f055df1204dd..1c2708aae5e4 100644 --- a/doc/reference/fft.rst +++ b/doc/reference/fft.rst @@ -12,12 +12,12 @@ Standard FFTs :toctree: generated/ :nosignatures: - dpnp.fft.fft - dpnp.fft.ifft - dpnp.fft.fft2 - dpnp.fft.ifft2 - dpnp.fft.fftn - dpnp.fft.ifftn + fft + ifft + fft2 + ifft2 + fftn + ifftn Real FFTs @@ -27,12 +27,12 @@ Real FFTs :toctree: generated/ :nosignatures: - dpnp.fft.rfft - dpnp.fft.irfft - dpnp.fft.rfft2 - dpnp.fft.irfft2 - dpnp.fft.rfftn - dpnp.fft.irfftn + rfft + irfft + rfft2 + irfft2 + rfftn + irfftn Hermitian FFTs @@ -42,8 +42,8 @@ Hermitian FFTs :toctree: generated/ :nosignatures: - dpnp.fft.hfft - dpnp.fft.ihfft + hfft + ihfft Helper routines @@ -53,10 +53,10 @@ Helper routines :toctree: generated/ :nosignatures: - dpnp.fft.fftfreq - dpnp.fft.rfftfreq - dpnp.fft.fftshift - dpnp.fft.ifftshift + fftfreq + rfftfreq + fftshift + ifftshift .. fft.config module is not implemented yet .. dpnp.fft.config.set_cufft_callbacks @@ -65,3 +65,4 @@ Helper routines .. dpnp.fft.config.show_plan_cache_info .. automodule:: dpnp.fft + :no-index: diff --git a/doc/reference/random.rst b/doc/reference/random.rst index 1a20e76bf7d8..db7b76b8bd41 100644 --- a/doc/reference/random.rst +++ b/doc/reference/random.rst @@ -13,16 +13,16 @@ Simple random data :toctree: generated/ :nosignatures: - 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 + rand + randn + randint + random_integers + random_sample + random + ranf + sample + choice + bytes Permutations @@ -32,8 +32,8 @@ Permutations :toctree: generated/ :nosignatures: - dpnp.random.shuffle - dpnp.random.permutation + shuffle + permutation Distributions @@ -43,41 +43,41 @@ Distributions :toctree: generated/ :nosignatures: - 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 + 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 Random generator @@ -87,7 +87,7 @@ Random generator :toctree: generated/ :nosignatures: - dpnp.random.RandomState - dpnp.random.seed - dpnp.random.get_random_state - dpnp.random.set_random_state + RandomState + seed + get_random_state + set_random_state diff --git a/dpnp/dpnp_iface_arraycreation.py b/dpnp/dpnp_iface_arraycreation.py index d15f62bda277..2c8f55dd57c9 100644 --- a/dpnp/dpnp_iface_arraycreation.py +++ b/dpnp/dpnp_iface_arraycreation.py @@ -913,9 +913,11 @@ def diag(v, /, k=0, *, device=None, usm_type=None, sycl_queue=None): on the `k`-th diagonal. If `v` is a 2-D array and is an instance of {dpnp.ndarray, usm_ndarray}, then: - - If `device`, `usm_type`, and `sycl_queue` are set to their - default values, returns a read/write view of its k-th diagonal. - - Otherwise, returns a copy of its k-th diagonal. + + - If `device`, `usm_type`, and `sycl_queue` are set to their + default values, returns a read/write view of its k-th diagonal. + - Otherwise, returns a copy of its k-th diagonal. + k : int, optional Diagonal in question. Use k > 0 for diagonals above the main diagonal, and k < 0 for diagonals below the main diagonal. diff --git a/dpnp/dpnp_iface_bitwise.py b/dpnp/dpnp_iface_bitwise.py index a45d61f821ea..97dcc5810feb 100644 --- a/dpnp/dpnp_iface_bitwise.py +++ b/dpnp/dpnp_iface_bitwise.py @@ -46,8 +46,11 @@ __all__ = [ "bitwise_and", + "bitwise_invert", + "bitwise_left_shift", "bitwise_not", "bitwise_or", + "bitwise_right_shift", "bitwise_xor", "invert", "left_shift", @@ -260,6 +263,8 @@ _INVERT_DOCSTRING = """ Inverts (flips) each bit for each element `x_i` of the input array `x`. +Note that :obj:`dpnp.bitwise_invert` is an alias of :obj:`dpnp.invert`. + For full documentation refer to :obj:`numpy.invert`. Parameters @@ -321,13 +326,15 @@ bitwise_not = invert # bitwise_not is an alias for invert - +bitwise_invert = invert # bitwise_invert is an alias for invert _LEFT_SHIFT_DOCSTRING = """ Shifts the bits of each element `x1_i` of the input array x1 to the left by appending `x2_i` (i.e., the respective element in the input array `x2`) zeros to the right of `x1_i`. +Note that :obj:`dpnp.bitwise_left_shift` is an alias of :obj:`dpnp.left_shift`. + For full documentation refer to :obj:`numpy.left_shift`. Parameters @@ -384,11 +391,15 @@ _LEFT_SHIFT_DOCSTRING, ) +bitwise_left_shift = left_shift # bitwise_left_shift is an alias for left_shift + _RIGHT_SHIFT_DOCSTRING = """ Shifts the bits of each element `x1_i` of the input array `x1` to the right according to the respective element `x2_i` of the input array `x2`. +Note that :obj:`dpnp.bitwise_right_shift` is an alias of :obj:`dpnp.right_shift`. + For full documentation refer to :obj:`numpy.right_shift`. Parameters @@ -445,3 +456,6 @@ ti._bitwise_right_shift, _RIGHT_SHIFT_DOCSTRING, ) + +# bitwise_right_shift is an alias for right_shift +bitwise_right_shift = right_shift diff --git a/dpnp/dpnp_iface_logic.py b/dpnp/dpnp_iface_logic.py index 25882da7945b..2f8c40206daf 100644 --- a/dpnp/dpnp_iface_logic.py +++ b/dpnp/dpnp_iface_logic.py @@ -1,5 +1,3 @@ -# cython: language_level=3 -# distutils: language = c++ # -*- coding: utf-8 -*- # ***************************************************************************** # Copyright (c) 2016-2024, Intel Corporation @@ -397,7 +395,7 @@ def array_equal(a1, a2, equal_nan=False): >>> np.array_equal(a, a, equal_nan=True) array(True) - When ``equal_nan`` is ``True``, complex values with nan components are + When ``equal_nan`` is ``True``, complex values with NaN components are considered equal if either the real *or* the imaginary components are ``NaNs``. diff --git a/dpnp/dpnp_iface_manipulation.py b/dpnp/dpnp_iface_manipulation.py index 73127307be4c..ee6812f44c79 100644 --- a/dpnp/dpnp_iface_manipulation.py +++ b/dpnp/dpnp_iface_manipulation.py @@ -59,6 +59,7 @@ "broadcast_to", "can_cast", "column_stack", + "concat", "concatenate", "copyto", "dstack", @@ -69,6 +70,7 @@ "hstack", "moveaxis", "ndim", + "permute_dims", "ravel", "repeat", "reshape", @@ -950,11 +952,13 @@ def concatenate( """ Join a sequence of arrays along an existing axis. + Note that :obj:`dpnp.concat` is an alias of :obj:`dpnp.concatenate`. + For full documentation refer to :obj:`numpy.concatenate`. Parameters ---------- - arrays : {dpnp.ndarray, usm_ndarray} + arrays : {Sequence of dpnp.ndarray or usm_ndarray} The arrays must have the same shape, except in the dimension corresponding to axis (the first, by default). axis : int, optional @@ -1031,6 +1035,9 @@ def concatenate( return res +concat = concatenate # concat is an alias of concatenate + + def copyto(dst, src, casting="same_kind", where=True): """ Copies values from one array to another, broadcasting as necessary. @@ -2309,6 +2316,8 @@ def transpose(a, axes=None): """ Returns an array with axes transposed. + Note that :obj:`dpnp.permute_dims` is an alias of :obj:`dpnp.transpose`. + For full documentation refer to :obj:`numpy.transpose`. Parameters @@ -2375,6 +2384,9 @@ def transpose(a, axes=None): return array.transpose(*axes) +permute_dims = transpose # permute_dims is an alias for transpose + + def trim_zeros(filt, trim="fb"): """ Trim the leading and/or trailing zeros from a 1-D array. @@ -2513,7 +2525,7 @@ def unique( (move the axis to the first dimension to keep the order of the other axes) and then flattening the subarrays in C order. For complex arrays all NaN values are considered equivalent (no matter - whether the NaN is in the real or imaginary part). As the representant for + whether the NaN is in the real or imaginary part). As the representative for the returned array the smallest one in the lexicographical order is chosen. For multi-dimensional inputs, `unique_inverse` is reshaped such that the input can be reconstructed using diff --git a/dpnp/dpnp_iface_mathematical.py b/dpnp/dpnp_iface_mathematical.py index a7a7508eb434..a7eaf65fbabb 100644 --- a/dpnp/dpnp_iface_mathematical.py +++ b/dpnp/dpnp_iface_mathematical.py @@ -111,6 +111,7 @@ "negative", "nextafter", "positive", + "pow", "power", "prod", "proj", @@ -1738,7 +1739,7 @@ def ediff1d(ary, to_end=None, to_begin=None): Compares two input arrays `x1` and `x2` and returns a new array containing the element-wise maxima. -If one of the elements being compared is a NaN, then the non-nan element is +If one of the elements being compared is a NaN, then the non-NaN element is returned. If both elements are NaNs then the first is returned. The latter distinction is important for complex NaNs, which are defined as at least one of the real or imaginary parts being a NaN. The net effect is that NaNs are @@ -1786,7 +1787,7 @@ def ediff1d(ary, to_end=None, to_begin=None): Notes ----- -The fmax is equivalent to ``dpnp.where(x1 >= x2, x1, x2)`` when neither +``fmax(x1, x2)`` is equivalent to ``dpnp.where(x1 >= x2, x1, x2)`` when neither `x1` nor `x2` are NaNs, but it is faster and does proper broadcasting. Examples @@ -1823,7 +1824,7 @@ def ediff1d(ary, to_end=None, to_begin=None): Compares two input arrays `x1` and `x2` and returns a new array containing the element-wise minima. -If one of the elements being compared is a NaN, then the non-nan element is +If one of the elements being compared is a NaN, then the non-NaN element is returned. If both elements are NaNs then the first is returned. The latter distinction is important for complex NaNs, which are defined as at least one of the real or imaginary parts being a NaN. The net effect is that NaNs are @@ -1871,7 +1872,7 @@ def ediff1d(ary, to_end=None, to_begin=None): Notes ----- -The fmin is equivalent to ``dpnp.where(x1 <= x2, x1, x2)`` when neither +``fmin(x1, x2)`` is equivalent to ``dpnp.where(x1 <= x2, x1, x2)`` when neither `x1` nor `x2` are NaNs, but it is faster and does proper broadcasting. Examples @@ -2559,7 +2560,7 @@ def modf(x1, **kwargs): def nan_to_num(x, copy=True, nan=0.0, posinf=None, neginf=None): """ Replace ``NaN`` with zero and infinity with large finite numbers (default - behaviour) or with the numbers defined by the user using the `nan`, + behavior) or with the numbers defined by the user using the `nan`, `posinf` and/or `neginf` keywords. If `x` is inexact, ``NaN`` is replaced by zero or by the user defined value @@ -2869,6 +2870,8 @@ def nan_to_num(x, copy=True, nan=0.0, posinf=None, neginf=None): Calculates `x1_i` raised to `x2_i` for each element `x1_i` of the input array `x1` with the respective element `x2_i` of the input array `x2`. +Note that :obj:`dpnp.pow` is an alias of :obj:`dpnp.power`. + For full documentation refer to :obj:`numpy.power`. Parameters @@ -2952,6 +2955,8 @@ def nan_to_num(x, copy=True, nan=0.0, posinf=None, neginf=None): binary_inplace_fn=ti._pow_inplace, ) +pow = power # pow is an alias for power + def prod( a, diff --git a/dpnp/dpnp_iface_trigonometric.py b/dpnp/dpnp_iface_trigonometric.py index 0dff6fdb2922..f4ecaec355d8 100644 --- a/dpnp/dpnp_iface_trigonometric.py +++ b/dpnp/dpnp_iface_trigonometric.py @@ -59,6 +59,13 @@ "arctan", "arctan2", "arctanh", + "asin", + "asinh", + "acos", + "acosh", + "atan", + "atan2", + "atanh", "cbrt", "cos", "cosh", @@ -101,9 +108,12 @@ def _get_accumulation_res_dt(a, dtype, _out): return dtu._to_device_supported_dtype(dtype, a.sycl_device) -_ACOS_DOCSTRING = """ +_ACOS_DOCSTRING = r""" Computes inverse cosine for each element `x_i` for input array `x`. +The inverse of :obj:`dpnp.cos` so that, if ``y = cos(x)``, then ``x = arccos(y)``. +Note that :obj:`dpnp.acos` is an alias of :obj:`dpnp.arccos`. + For full documentation refer to :obj:`numpy.arccos`. Parameters @@ -138,6 +148,22 @@ def _get_accumulation_res_dt(a, dtype, _out): :obj:`dpnp.arcsin` : Trigonometric inverse sine, element-wise. :obj:`dpnp.arccosh` : Hyperbolic inverse cosine, element-wise. +Notes +----- +:obj:`dpnp.arccos` is a multivalued function: for each `x` there are infinitely +many numbers `z` such that ``cos(z) = x``. The convention is to return the +angle `z` whose real part lies in `[0, pi]`. + +For real-valued input data types, :obj:`dpnp.arccos` always returns real output. +For each value that cannot be expressed as a real number or infinity, it yields +``nan``. + +For complex-valued input, :obj:`dpnp.arccos` is a complex analytic function that +has, by convention, the branch cuts `[-inf, -1]` and `[1, inf]` and is continuous +from above on the former and from below on the latter. + +The inverse cos is also known as :math:`acos` or :math:`cos^{-1}`. + Examples -------- >>> import dpnp as np @@ -155,10 +181,15 @@ def _get_accumulation_res_dt(a, dtype, _out): mkl_impl_fn="_acos", ) +acos = arccos # acos is an alias for arccos + -_ACOSH_DOCSTRING = """ +_ACOSH_DOCSTRING = r""" Computes inverse hyperbolic cosine for each element `x_i` for input array `x`. +The inverse of :obj:`dpnp.cosh` so that, if ``y = cosh(x)``, then ``x = arccosh(y)``. +Note that :obj:`dpnp.acosh` is an alias of :obj:`dpnp.arccosh`. + For full documentation refer to :obj:`numpy.arccosh`. Parameters @@ -189,10 +220,27 @@ def _get_accumulation_res_dt(a, dtype, _out): See Also -------- :obj:`dpnp.cosh` : Hyperbolic cosine, element-wise. -:obj:`dpnp.arctanh` : Hyperbolic inverse tangent, element-wise. :obj:`dpnp.arcsinh` : Hyperbolic inverse sine, element-wise. +:obj:`dpnp.sinh` : Hyperbolic sine, element-wise. +:obj:`dpnp.arctanh` : Hyperbolic inverse tangent, element-wise. +:obj:`dpnp.tanh` : Hyperbolic tangent, element-wise. :obj:`dpnp.arccos` : Trigonometric inverse cosine, element-wise. +Notes +----- +:obj:`dpnp.arccosh` is a multivalued function: for each `x` there are infinitely +many numbers `z` such that ``cosh(z) = x``. The convention is to return the +angle `z` whose real part lies in `[0, inf]`. + +For real-valued input data types, :obj:`dpnp.arccosh` always returns real output. +For each value that cannot be expressed as a real number or infinity, it yields +``nan``. + +For complex-valued input, :obj:`dpnp.arccosh` is a complex analytic function that +has, by convention, the branch cuts `[-inf, 1]` and is continuous from above. + +The inverse hyperbolic cos is also known as :math:`acosh` or :math:`cosh^{-1}`. + Examples -------- >>> import dpnp as np @@ -210,10 +258,15 @@ def _get_accumulation_res_dt(a, dtype, _out): mkl_impl_fn="_acosh", ) +acosh = arccosh # acosh is an alias for arccosh -_ASIN_DOCSTRING = """ + +_ASIN_DOCSTRING = r""" Computes inverse sine for each element `x_i` for input array `x`. +The inverse of :obj:`dpnp.sin`, so that if ``y = sin(x)`` then ``x = arcsin(y)``. +Note that :obj:`dpnp.asin` is an alias of :obj:`dpnp.arcsin`. + For full documentation refer to :obj:`numpy.arcsin`. Parameters @@ -244,10 +297,29 @@ def _get_accumulation_res_dt(a, dtype, _out): See Also -------- :obj:`dpnp.sin` : Trigonometric sine, element-wise. -:obj:`dpnp.arctan` : Trigonometric inverse tangent, element-wise. +:obj:`dpnp.cos` : Trigonometric cosine, element-wise. :obj:`dpnp.arccos` : Trigonometric inverse cosine, element-wise. +:obj:`dpnp.tan` : Trigonometric tangent, element-wise. +:obj:`dpnp.arctan` : Trigonometric inverse tangent, element-wise. +:obj:`dpnp.arctan2` : Element-wise arc tangent of `x1/x2` choosing the quadrant correctly. :obj:`dpnp.arcsinh` : Hyperbolic inverse sine, element-wise. +Notes +----- +:obj:`dpnp.arcsin` is a multivalued function: for each `x` there are infinitely +many numbers `z` such that ``sin(z) = x``. The convention is to return the +angle `z` whose real part lies in `[-pi/2, pi/2]`. + +For real-valued input data types, :obj:`dpnp.arcsin` always returns real output. +For each value that cannot be expressed as a real number or infinity, it yields +``nan``. + +For complex-valued input, :obj:`dpnp.arcsin` is a complex analytic function that +has, by convention, the branch cuts `[-inf, -1]` and `[1, inf]` and is continuous +from above on the former and from below on the latter. + +The inverse sine is also known as :math:`asin` or :math:`sin^{-1}`. + Examples -------- >>> import dpnp as np @@ -265,10 +337,15 @@ def _get_accumulation_res_dt(a, dtype, _out): mkl_impl_fn="_asin", ) +asin = arcsin # asin is an alias for arcsin -_ASINH_DOCSTRING = """ + +_ASINH_DOCSTRING = r""" Computes inverse hyperbolic sine for each element `x_i` for input array `x`. +The inverse of :obj:`dpnp.sinh`, so that if ``y = sinh(x)`` then ``x = arcsinh(y)``. +Note that :obj:`dpnp.asinh` is an alias of :obj:`dpnp.arcsinh`. + For full documentation refer to :obj:`numpy.arcsinh`. Parameters @@ -303,6 +380,23 @@ def _get_accumulation_res_dt(a, dtype, _out): :obj:`dpnp.arccosh` : Hyperbolic inverse cosine, element-wise. :obj:`dpnp.arcsin` : Trigonometric inverse sine, element-wise. +Notes +----- +:obj:`dpnp.arcsinh` is a multivalued function: for each `x` there are infinitely +many numbers `z` such that ``sin(z) = x``. The convention is to return the +angle `z` whose real part lies in `[-pi/2, pi/2]`. + +For real-valued input data types, :obj:`dpnp.arcsinh` always returns real output. +For each value that cannot be expressed as a real number or infinity, it yields +``nan``. + +For complex-valued input, :obj:`dpnp.arcsinh` is a complex analytic function that +has, by convention, the branch cuts `[1j, infj]` and `[`1j, -infj]` and is continuous +from above on the former and from below on the latter. + +The inverse hyperbolic sine is also known as :math:`asinh` or :math:`sinh^{-1}`. + + Examples -------- >>> import dpnp as np @@ -320,10 +414,15 @@ def _get_accumulation_res_dt(a, dtype, _out): mkl_impl_fn="_asinh", ) +asinh = arcsinh # asinh is an alias for arcsinh + -_ATAN_DOCSTRING = """ +_ATAN_DOCSTRING = r""" Computes inverse tangent for each element `x_i` for input array `x`. +The inverse of :obj:`dpnp.tan`, so that if ``y = tan(x)`` then ``x = arctan(y)``. +Note that :obj:`dpnp.atan` is an alias of :obj:`dpnp.arctan`. + For full documentation refer to :obj:`numpy.arctan`. Parameters @@ -360,6 +459,22 @@ def _get_accumulation_res_dt(a, dtype, _out): :obj:`dpnp.arccos` : Trigonometric inverse cosine, element-wise. :obj:`dpnp.arctanh` : Inverse hyperbolic tangent, element-wise. +Notes +----- +:obj:`dpnp.arctan` is a multivalued function: for each `x` there are infinitely +many numbers `z` such that ``tan(z) = x``. The convention is to return the +angle `z` whose real part lies in `[-pi/2, pi/2]`. + +For real-valued input data types, :obj:`dpnp.arctan` always returns real output. +For each value that cannot be expressed as a real number or infinity, it yields +``nan``. + +For complex-valued input, :obj:`dpnp.arctan` is a complex analytic function that +has, by convention, the branch cuts `[1j, infj]` and `[-1j, -infj]` and is continuous +from the left on the former and from the right on the latter. + +The inverse tan is also known as :math:`atan` or :math:`tan^{-1}`. + Examples -------- >>> import dpnp as np @@ -377,12 +492,18 @@ def _get_accumulation_res_dt(a, dtype, _out): mkl_impl_fn="_atan", ) +atan = arctan # atan is an alias for arctan + _ATAN2_DOCSTRING = """ Calculates the inverse tangent of the quotient `x1_i/x2_i` for each element `x1_i` of the input array `x1` with the respective element `x2_i` of the input array `x2`. Each element-wise result is expressed in radians. +Note that :obj:`dpnp.atan2` is an alias of :obj:`dpnp.arctan2`. +This function is not defined for complex-valued arguments; for the so-called +argument of complex values, use :obj:`dpnp.angle`. + For full documentation refer to :obj:`numpy.arctan2`. Parameters @@ -453,10 +574,15 @@ def _get_accumulation_res_dt(a, dtype, _out): mkl_impl_fn="_atan2", ) +atan2 = arctan2 # atan2 is an alias for arctan2 -_ATANH_DOCSTRING = """ + +_ATANH_DOCSTRING = r""" Computes hyperbolic inverse tangent for each element `x_i` for input array `x`. +The inverse of :obj:`dpnp.tanh`, so that if ``y = tanh(x)`` then ``x = arctanh(y)``. +Note that :obj:`dpnp.atanh` is an alias of :obj:`dpnp.arctanh`. + For full documentation refer to :obj:`numpy.arctanh`. Parameters @@ -491,6 +617,22 @@ def _get_accumulation_res_dt(a, dtype, _out): :obj:`dpnp.arccosh` : Hyperbolic inverse cosine, element-wise. :obj:`dpnp.arctan` : Trigonometric inverse tangent, element-wise. +Notes +----- +:obj:`dpnp.arctanh` is a multivalued function: for each `x` there are infinitely +many numbers `z` such that ``tanh(z) = x``. The convention is to return the +angle `z` whose real part lies in `[-pi/2, pi/2]`. + +For real-valued input data types, :obj:`dpnp.arctanh` always returns real output. +For each value that cannot be expressed as a real number or infinity, it yields +``nan``. + +For complex-valued input, :obj:`dpnp.arctanh` is a complex analytic function that +has, by convention, the branch cuts `[-1, -inf]` and `[1, inf]` and is is continuous +from above on the former and from below on the latter. + +The inverse hyperbolic tan is also known as :math:`atanh` or :math:`tanh^{-1}`. + Examples -------- >>> import dpnp as np @@ -508,6 +650,8 @@ def _get_accumulation_res_dt(a, dtype, _out): mkl_impl_fn="_atanh", ) +atanh = arctanh # atanh is an alias for arctanh + _CBRT_DOCSTRING = """ Computes positive cube-root for each element `x_i` for input array `x`. @@ -1383,7 +1527,7 @@ def cumlogsumexp( -------- :obj:`dpnp.log` : Natural logarithm, element-wise. :obj:`dpnp.exp` : Exponential, element-wise. -:obj:`dpnp.logaddexp2`: Logarithm of the sum of exponentiations of inputs in +:obj:`dpnp.logaddexp2`: Logarithm of the sum of exponentiation of inputs in base-2, element-wise. :obj:`dpnp.logsumexp` : Logarithm of the sum of exponents of elements in the input array. @@ -1453,9 +1597,9 @@ def cumlogsumexp( See Also -------- -:obj:`dpnp.logaddexp`: Natural logarithm of the sum of exponentiations of +:obj:`dpnp.logaddexp`: Natural logarithm of the sum of exponentiation of inputs, element-wise. -:obj:`dpnp.logsumexp` : Logarithm of the sum of exponentiations of the inputs. +:obj:`dpnp.logsumexp` : Logarithm of the sum of exponentiation of the inputs. Examples -------- diff --git a/dpnp/fft/__init__.py b/dpnp/fft/__init__.py index ce1af9bdcab2..3346652f87c3 100644 --- a/dpnp/fft/__init__.py +++ b/dpnp/fft/__init__.py @@ -88,11 +88,6 @@ It differs from the forward transform by the sign of the exponential argument and the default normalization by :math:`1/n`. -Type Promotion --------------- -`dpnp.fft` promotes ``float32`` and ``complex64`` arrays to ``float64`` and -``complex128`` arrays respectively. - Normalization ------------- The argument ``norm`` indicates which direction of the pair of direct/inverse diff --git a/dpnp/fft/dpnp_iface_fft.py b/dpnp/fft/dpnp_iface_fft.py index be97dafed170..c41a8d6b5df7 100644 --- a/dpnp/fft/dpnp_iface_fft.py +++ b/dpnp/fft/dpnp_iface_fft.py @@ -590,8 +590,8 @@ def hfft(a, n=None, axis=-1, norm=None, out=None): the frequency domain. So here it's :obj:`dpnp.fft.hfft` for which you must supply the length of the result if it is to be odd. - * even: ``ihfft(hfft(a, 2*len(a) - 2)) == a``, within roundoff error, - * odd: ``ihfft(hfft(a, 2*len(a) - 1)) == a``, within roundoff error. + * even: ``ihfft(hfft(a, 2*len(a) - 2)) == a``, within round-off error, + * odd: ``ihfft(hfft(a, 2*len(a) - 1)) == a``, within round-off error. The correct interpretation of the Hermitian input depends on the length of the original data, as given by `n`. This is because each input shape could @@ -643,7 +643,7 @@ def ifft(a, n=None, axis=-1, norm=None, out=None): * ``a[0]`` should contain the zero frequency term, * ``a[1:n//2]`` should contain the positive-frequency terms, * ``a[n//2 + 1:]`` should contain the negative-frequency terms, in - increasing order starting from the most negative frequency. + increasing order starting from the most negative frequency. For an even number of input points, ``A[n//2]`` represents the sum of the values at the positive and negative Nyquist frequencies, as the two @@ -1017,8 +1017,8 @@ def ihfft(a, n=None, axis=-1, norm=None, out=None): the frequency domain. So here it's :obj:`dpnp.fft.hfft` for which you must supply the length of the result if it is to be odd. - * even: ``ihfft(hfft(a, 2*len(a) - 2)) == a``, within roundoff error, - * odd: ``ihfft(hfft(a, 2*len(a) - 1)) == a``, within roundoff error. + * even: ``ihfft(hfft(a, 2*len(a) - 2)) == a``, within round-off error, + * odd: ``ihfft(hfft(a, 2*len(a) - 1)) == a``, within round-off error. Examples -------- @@ -1108,7 +1108,7 @@ def irfft(a, n=None, axis=-1, norm=None, out=None): If you specify an `n` such that `a` must be zero-padded or truncated, the extra/removed values will be added/removed at high frequencies. One can - thus resample a series to `m` points via Fourier interpolation by: + thus re-sample a series to `m` points via Fourier interpolation by: ``a_resamp = irfft(rfft(a), m)``. The correct interpretation of the Hermitian input depends on the length of @@ -1282,7 +1282,7 @@ def irfftn(a, s=None, axes=None, norm=None, out=None): If provided, the result will be placed in this array. It should be of the appropriate dtype and shape for the last transformation (consistent with the choice of `s`). - Default: ``None``. + Default: ``None``. Returns ------- diff --git a/dpnp/linalg/dpnp_iface_linalg.py b/dpnp/linalg/dpnp_iface_linalg.py index 5342daa17584..69cf31303140 100644 --- a/dpnp/linalg/dpnp_iface_linalg.py +++ b/dpnp/linalg/dpnp_iface_linalg.py @@ -74,6 +74,7 @@ "eigvalsh", "inv", "lstsq", + "matmul", "matrix_power", "matrix_rank", "multi_dot", @@ -680,6 +681,76 @@ def lstsq(a, b, rcond=None): return dpnp_lstsq(a, b, rcond=rcond) +def matmul(x1, x2, /): + """ + Computes the matrix product. + + This function is Array API compatible, contrary to :obj:`dpnp.matmul`. + + For full documentation refer to :obj:`numpy.linalg.matmul`. + + Parameters + ---------- + x1 : {dpnp.ndarray, usm_ndarray} + First input array. + x2 : {dpnp.ndarray, usm_ndarray} + Second input array. + + Returns + ------- + out : dpnp.ndarray + Returns the matrix product of the inputs. + This is a 0-d array only when both `x1`, `x2` are 1-d vectors. + + See Also + -------- + :obj:`dpnp.matmul` : similar function with support for more + kwyeord arguments. + + Examples + -------- + For 2-D arrays it is the matrix product: + + >>> import dpnp as np + >>> a = np.array([[1, 0], [0, 1]]) + >>> b = np.array([[4, 1], [2, 2]]) + >>> np.linalg.matmul(a, b) + array([[4, 1], + [2, 2]]) + + For 2-D mixed with 1-D, the result is the usual. + + >>> a = np.array([[1, 0], [0, 1]]) + >>> b = np.array([1, 2]) + >>> np.linalg.matmul(a, b) + array([1, 2]) + >>> np.linalg.matmul(b, a) + array([1, 2]) + + Broadcasting is conventional for stacks of arrays + + >>> a = np.arange(2 * 2 * 4).reshape((2, 2, 4)) + >>> b = np.arange(2 * 2 * 4).reshape((2, 4, 2)) + >>> np.linalg.matmul(a,b).shape + (2, 2, 2) + >>> np.linalg.matmul(a, b)[0, 1, 1] + array(98) + >>> np.sum(a[0, 1, :] * b[0 , :, 1]) + array(98) + + Vector, vector returns the scalar inner product, but neither argument + is complex-conjugated: + + >>> x1 = np.array([2j, 3j]) + >>> x2 = np.array([2j, 3j]) + >>> np.linalg.matmul(x1, x2) + array(-13+0j) + + """ + + return dpnp.matmul(x1, x2) + + def matrix_power(a, n): """ Raise a square matrix to the (integer) power `n`. diff --git a/tests/test_arraymanipulation.py b/tests/test_arraymanipulation.py index f9ec00dc83e3..1779e87a0d76 100644 --- a/tests/test_arraymanipulation.py +++ b/tests/test_arraymanipulation.py @@ -360,6 +360,15 @@ def test_concatenate_out_dtype(self): with pytest.raises(TypeError): dpnp.concatenate([x], out=out, dtype="i4") + def test_alias(self): + a = dpnp.ones((5, 5)) + b = dpnp.zeros((5, 5)) + + res1 = dpnp.concatenate((a, b)) + res2 = dpnp.concat((a, b)) + + assert_array_equal(res1, res2) + class TestDims: @pytest.mark.parametrize("dt", get_all_dtypes()) diff --git a/tests/test_bitwise.py b/tests/test_bitwise.py index e3393e43beeb..41f10c023543 100644 --- a/tests/test_bitwise.py +++ b/tests/test_bitwise.py @@ -137,6 +137,33 @@ def test_right_shift(self, lhs, rhs, dtype): np_a >>= np_b assert_array_equal(dp_a, np_a) + def test_bitwise_aliase1(self, lhs, rhs, dtype): + if numpy.isscalar(lhs): + pytest.skip("Input can't be scalar") + dp_a = self.array_or_scalar(inp, lhs, dtype=dtype) + result1 = inp.invert(dp_a) + result2 = inp.bitwise_invert(dp_a) + assert_array_equal(result1, result2) + + result2 = inp.bitwise_not(dp_a) + assert_array_equal(result1, result2) + + def test_bitwise_aliase2(self, lhs, rhs, dtype): + if dtype == inp.bool: + pytest.skip("A shift operation isn't implemented for bool type") + elif numpy.isscalar(lhs) and numpy.isscalar(rhs): + pytest.skip("Both inputs can't be scalars") + + dp_a = self.array_or_scalar(inp, lhs, dtype=dtype) + dp_b = self.array_or_scalar(inp, rhs, dtype=dtype) + result1 = inp.left_shift(dp_a, dp_b) + result2 = inp.bitwise_left_shift(dp_a, dp_b) + assert_array_equal(result1, result2) + + result1 = inp.right_shift(dp_a, dp_b) + result2 = inp.bitwise_right_shift(dp_a, dp_b) + assert_array_equal(result1, result2) + @pytest.mark.parametrize("dtype", get_integer_dtypes()) def test_invert_out(dtype): diff --git a/tests/test_manipulation.py b/tests/test_manipulation.py index 3d6d1ec95242..a8e64717b9df 100644 --- a/tests/test_manipulation.py +++ b/tests/test_manipulation.py @@ -497,6 +497,14 @@ def test_ndarray_axes_n_int(self): result = da.transpose(1, 0, 2) assert_array_equal(result, expected) + def test_alias(self): + a = dpnp.ones((5, 3)) + + res1 = dpnp.transpose((a)) + res2 = dpnp.permute_dims((a)) + + assert_array_equal(res1, res2) + class TestTrimZeros: @pytest.mark.parametrize("dtype", get_all_dtypes(no_none=True)) diff --git a/tests/test_mathematical.py b/tests/test_mathematical.py index 7b7bd901c880..dbaab556e0c2 100644 --- a/tests/test_mathematical.py +++ b/tests/test_mathematical.py @@ -2051,21 +2051,6 @@ def test_divide_scalar(shape, dtype): assert_allclose(result, expected, rtol=1e-6) -@pytest.mark.parametrize("shape", [(), (3, 2)], ids=["()", "(3, 2)"]) -@pytest.mark.parametrize("dtype", get_all_dtypes()) -def test_power_scalar(shape, dtype): - np_a = numpy.ones(shape, dtype=dtype) - dpnp_a = dpnp.ones(shape, dtype=dtype) - - result = 4.2**dpnp_a**-1.3 - expected = 4.2**np_a**-1.3 - assert_allclose(result, expected, rtol=1e-6) - - result **= dpnp_a - expected **= np_a - assert_allclose(result, expected, rtol=1e-6) - - @pytest.mark.parametrize( "data", [[[1.0, -1.0], [0.1, -0.1]], [-2, -1, 0, 1, 2]], @@ -2314,39 +2299,6 @@ def test_projection(self, dtype): assert_allclose(result, expected) -@pytest.mark.parametrize("val_type", get_all_dtypes(no_none=True)) -@pytest.mark.parametrize("data_type", get_all_dtypes()) -@pytest.mark.parametrize("val", [1.5, 1, 5], ids=["1.5", "1", "5"]) -@pytest.mark.parametrize( - "array", - [ - [[0, 0], [0, 0]], - [[1, 2], [1, 2]], - [[1, 2], [3, 4]], - [[[1, 2], [3, 4]], [[1, 2], [2, 1]], [[1, 3], [3, 1]]], - [ - [[[1, 2], [3, 4]], [[1, 2], [2, 1]]], - [[[1, 3], [3, 1]], [[0, 1], [1, 3]]], - ], - ], - ids=[ - "[[0, 0], [0, 0]]", - "[[1, 2], [1, 2]]", - "[[1, 2], [3, 4]]", - "[[[1, 2], [3, 4]], [[1, 2], [2, 1]], [[1, 3], [3, 1]]]", - "[[[[1, 2], [3, 4]], [[1, 2], [2, 1]]], [[[1, 3], [3, 1]], [[0, 1], [1, 3]]]]", - ], -) -def test_power(array, val, data_type, val_type): - np_a = numpy.array(array, dtype=data_type) - dpnp_a = dpnp.array(array, dtype=data_type) - val_ = val_type(val) - - result = dpnp.power(dpnp_a, val_) - expected = numpy.power(np_a, val_) - assert_allclose(expected, result, rtol=1e-6) - - class TestRoundingFuncs: @pytest.fixture( params=[ @@ -2998,6 +2950,38 @@ def test_invalid_out(self, out): class TestPower: + @pytest.mark.parametrize("val_type", get_all_dtypes(no_none=True)) + @pytest.mark.parametrize("data_type", get_all_dtypes()) + @pytest.mark.parametrize("val", [1.5, 1, 5], ids=["1.5", "1", "5"]) + @pytest.mark.parametrize( + "array", + [ + [[0, 0], [0, 0]], + [[1, 2], [1, 2]], + [[1, 2], [3, 4]], + [[[1, 2], [3, 4]], [[1, 2], [2, 1]], [[1, 3], [3, 1]]], + [ + [[[1, 2], [3, 4]], [[1, 2], [2, 1]]], + [[[1, 3], [3, 1]], [[0, 1], [1, 3]]], + ], + ], + ids=[ + "[[0, 0], [0, 0]]", + "[[1, 2], [1, 2]]", + "[[1, 2], [3, 4]]", + "[[[1, 2], [3, 4]], [[1, 2], [2, 1]], [[1, 3], [3, 1]]]", + "[[[[1, 2], [3, 4]], [[1, 2], [2, 1]]], [[[1, 3], [3, 1]], [[0, 1], [1, 3]]]]", + ], + ) + def test_basic(self, array, val, data_type, val_type): + np_a = numpy.array(array, dtype=data_type) + dpnp_a = dpnp.array(array, dtype=data_type) + val_ = val_type(val) + + result = dpnp.power(dpnp_a, val_) + expected = numpy.power(np_a, val_) + assert_allclose(expected, result, rtol=1e-6) + @pytest.mark.parametrize("dtype", get_all_dtypes()) def test_power(self, dtype): np_array1, np_array2, expected = _get_numpy_arrays_2in_1out( @@ -3113,6 +3097,27 @@ def test_float_to_inf(self): assert_allclose(numpy_res, dpnp_res.asnumpy()) + @pytest.mark.parametrize("shape", [(), (3, 2)], ids=["()", "(3, 2)"]) + @pytest.mark.parametrize("dtype", get_all_dtypes()) + def test_power_scalar(self, shape, dtype): + np_a = numpy.ones(shape, dtype=dtype) + dpnp_a = dpnp.ones(shape, dtype=dtype) + + result = 4.2**dpnp_a**-1.3 + expected = 4.2**np_a**-1.3 + assert_allclose(result, expected, rtol=1e-6) + + result **= dpnp_a + expected **= np_a + assert_allclose(result, expected, rtol=1e-6) + + def test_alias(self): + a = dpnp.arange(10) + res1 = dpnp.power(a, 3) + res2 = dpnp.pow(a, 3) + + assert_array_equal(res1, res2) + @pytest.mark.parametrize( "dtype", get_all_dtypes(no_bool=True, no_none=True, no_complex=True) @@ -3811,6 +3816,14 @@ 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)) + + result1 = dpnp.matmul(a, b) + result2 = dpnp.linalg.matmul(a, b) + assert_array_equal(result1, result2) + class TestMatmulInvalidCases: @pytest.mark.parametrize( diff --git a/tests/test_umath.py b/tests/test_umath.py index 00919ecb2588..067e212a8a90 100644 --- a/tests/test_umath.py +++ b/tests/test_umath.py @@ -3,6 +3,7 @@ from numpy.testing import ( assert_allclose, assert_almost_equal, + assert_array_equal, assert_equal, assert_raises, ) @@ -71,20 +72,11 @@ def get_id(val): return val.__str__() -# SAT-7247: implement missing umaths and to remove the list +# implement missing umaths and to remove the list +# SAT-7324 vecdot +# SAT-7323 bitwise_count new_umaths_numpy_20 = [ - "acos", - "acosh", - "asin", - "asinh", - "atan", - "atan2", - "atanh", "bitwise_count", - "bitwise_invert", - "bitwise_left_shift", - "bitwise_right_shift", - "pow", "vecdot", ] @@ -99,7 +91,7 @@ def test_umaths(test_cases): if umath == "matmul": sh = (4, 4) - elif umath == "power": + elif umath in ["power", "pow"]: sh = (2, 3) else: sh = (3, 4) @@ -229,6 +221,14 @@ def test_invalid_shape(self, shape): with pytest.raises(ValueError): dpnp.arctan2(dp_array, dp_array, out=dp_out) + def test_alias(self): + x = dpnp.array([-1, +1, +1, -1]) + y = dpnp.array([-1, -1, +1, +1]) + + res1 = dpnp.arctan2(y, x) + res2 = dpnp.atan2(y, x) + assert_array_equal(res1, res2) + class TestCbrt: @pytest.mark.parametrize("dtype", get_all_dtypes(no_complex=True)) @@ -750,3 +750,16 @@ def test_invalid_out(self, func_params, out): a = dpnp.arange(10) assert_raises(TypeError, getattr(dpnp, func_name), a, out) assert_raises(TypeError, getattr(numpy, func_name), a.asnumpy(), out) + + +def test_trigonometric_hyperbolic_aliases(): + a = dpnp.array([-0.5, 0, 0.5]) + + assert_array_equal(dpnp.arcsin(a), dpnp.asin(a)) + assert_array_equal(dpnp.arccos(a), dpnp.acos(a)) + assert_array_equal(dpnp.arctan(a), dpnp.atan(a)) + assert_array_equal(dpnp.arctanh(a), dpnp.atanh(a)) + assert_array_equal(dpnp.arcsinh(a), dpnp.asinh(a)) + + a = dpnp.array([1, 1.5, 2]) + assert_array_equal(dpnp.arccosh(a), dpnp.acosh(a))