From 5c427d6a597f62352e9baf870e1b2edde58bee45 Mon Sep 17 00:00:00 2001 From: melissawm Date: Fri, 15 Jul 2022 15:08:32 -0300 Subject: DOC: How to partition domains --- numpy/lib/function_base.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'numpy/lib/function_base.py') diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index a0c94114a..1a840669c 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -4956,16 +4956,25 @@ def meshgrid(*xi, copy=True, sparse=False, indexing='xy'): >>> yv array([[0., 0., 0.], [1., 1., 1.]]) - >>> xv, yv = np.meshgrid(x, y, sparse=True) # make sparse output arrays + + The result of `meshgrid` is a coordinate grid: + + >>> import matplotlib.pyplot as plt + >>> plt.plot(xv, yv, marker='o', color='k', linestyle='none') + >>> plt.show() + + You can create sparse output arrays to save memory and computation time. + + >>> xv, yv = np.meshgrid(x, y, sparse=True) >>> xv array([[0. , 0.5, 1. ]]) >>> yv array([[0.], [1.]]) - `meshgrid` is very useful to evaluate functions on a grid. If the - function depends on all coordinates, you can use the parameter - ``sparse=True`` to save memory and computation time. + `meshgrid` is very useful to evaluate functions on a grid. If the + function depends on all coordinates, both dense and sparse outputs can be + used. >>> x = np.linspace(-5, 5, 101) >>> y = np.linspace(-5, 5, 101) @@ -4982,7 +4991,6 @@ def meshgrid(*xi, copy=True, sparse=False, indexing='xy'): >>> np.array_equal(zz, zs) True - >>> import matplotlib.pyplot as plt >>> h = plt.contourf(x, y, zs) >>> plt.axis('scaled') >>> plt.colorbar() -- cgit v1.2.1 From 6fac305a8b62e40aa7a353d4cf72688939c0e0a4 Mon Sep 17 00:00:00 2001 From: melissawm Date: Tue, 11 Oct 2022 17:23:29 -0300 Subject: DOC: Improve how-to-partition contents. Also add links to this document from the functions' docstrings. --- numpy/lib/function_base.py | 1 + 1 file changed, 1 insertion(+) (limited to 'numpy/lib/function_base.py') diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index 1a840669c..1cd5c92f2 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -4943,6 +4943,7 @@ def meshgrid(*xi, copy=True, sparse=False, indexing='xy'): mgrid : Construct a multi-dimensional "meshgrid" using indexing notation. ogrid : Construct an open multi-dimensional "meshgrid" using indexing notation. + how-to-index Examples -------- -- cgit v1.2.1 From 7c361420b4f81713f593ebbb5c924121c1f2d19d Mon Sep 17 00:00:00 2001 From: Sebastian Berg Date: Fri, 18 Nov 2022 15:11:25 +0100 Subject: MAINT: Move set_module to numpy.core to use without C import --- numpy/lib/function_base.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'numpy/lib/function_base.py') diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index 5f59254b6..0ab49fa11 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -4,6 +4,7 @@ import re import sys import warnings +from .._utils import set_module import numpy as np import numpy.core.numeric as _nx from numpy.core import transpose @@ -19,7 +20,6 @@ from numpy.core.fromnumeric import ( ravel, nonzero, partition, mean, any, sum ) from numpy.core.numerictypes import typecodes -from numpy.core.overrides import set_module from numpy.core import overrides from numpy.core.function_base import add_newdoc from numpy.lib.twodim_base import diag @@ -4017,7 +4017,7 @@ def percentile(a, since Python uses 0-based indexing, the code subtracts another 1 from the index internally. - The following formula determines the virtual index ``i + g``, the location + The following formula determines the virtual index ``i + g``, the location of the percentile in the sorted sample: .. math:: @@ -4306,7 +4306,7 @@ def quantile(a, since Python uses 0-based indexing, the code subtracts another 1 from the index internally. - The following formula determines the virtual index ``i + g``, the location + The following formula determines the virtual index ``i + g``, the location of the quantile in the sorted sample: .. math:: -- cgit v1.2.1 From 91432a36a3611c2374ea9e2d45592f0ac5e71adb Mon Sep 17 00:00:00 2001 From: Roy Smart Date: Fri, 2 Dec 2022 16:09:33 -0700 Subject: BUG: `keepdims=True` is ignored if `out` is not `None` in `numpy.median()`, `numpy.percentile()`, and `numpy.quantile()`. Closes #22714, #22544. --- numpy/lib/function_base.py | 51 ++++++++++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 18 deletions(-) (limited to 'numpy/lib/function_base.py') diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index 0ab49fa11..35a3b3543 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -3689,7 +3689,7 @@ def msort(a): return b -def _ureduce(a, func, **kwargs): +def _ureduce(a, func, keepdims=False, **kwargs): """ Internal Function. Call `func` with `a` as first argument swapping the axes to use extended @@ -3717,13 +3717,20 @@ def _ureduce(a, func, **kwargs): """ a = np.asanyarray(a) axis = kwargs.get('axis', None) + out = kwargs.get('out', None) + + if keepdims is np._NoValue: + keepdims = False + + nd = a.ndim if axis is not None: - keepdim = list(a.shape) - nd = a.ndim axis = _nx.normalize_axis_tuple(axis, nd) - for ax in axis: - keepdim[ax] = 1 + if keepdims: + if out is not None: + index_out = tuple( + 0 if i in axis else slice(None) for i in range(nd)) + kwargs['out'] = out[(Ellipsis, ) + index_out] if len(axis) == 1: kwargs['axis'] = axis[0] @@ -3736,12 +3743,27 @@ def _ureduce(a, func, **kwargs): # merge reduced axis a = a.reshape(a.shape[:nkeep] + (-1,)) kwargs['axis'] = -1 - keepdim = tuple(keepdim) else: - keepdim = (1,) * a.ndim + if keepdims: + if out is not None: + index_out = (0, ) * nd + kwargs['out'] = out[(Ellipsis, ) + index_out] r = func(a, **kwargs) - return r, keepdim + + if out is not None: + return out + + if keepdims: + if axis is None: + index_r = (np.newaxis, ) * nd + else: + index_r = tuple( + np.newaxis if i in axis else slice(None) + for i in range(nd)) + r = r[(Ellipsis, ) + index_r] + + return r def _median_dispatcher( @@ -3831,12 +3853,8 @@ def median(a, axis=None, out=None, overwrite_input=False, keepdims=False): >>> assert not np.all(a==b) """ - r, k = _ureduce(a, func=_median, axis=axis, out=out, + return _ureduce(a, func=_median, keepdims=keepdims, axis=axis, out=out, overwrite_input=overwrite_input) - if keepdims: - return r.reshape(k) - else: - return r def _median(a, axis=None, out=None, overwrite_input=False): @@ -4452,17 +4470,14 @@ def _quantile_unchecked(a, method="linear", keepdims=False): """Assumes that q is in [0, 1], and is an ndarray""" - r, k = _ureduce(a, + return _ureduce(a, func=_quantile_ureduce_func, q=q, + keepdims=keepdims, axis=axis, out=out, overwrite_input=overwrite_input, method=method) - if keepdims: - return r.reshape(q.shape + k) - else: - return r def _quantile_is_valid(q): -- cgit v1.2.1 From b3c0960a54c81a26bd07912dda96db9e356b34d1 Mon Sep 17 00:00:00 2001 From: Matteo Raso <33975162+MatteoRaso@users.noreply.github.com> Date: Thu, 8 Dec 2022 07:01:59 -0500 Subject: BUG: Quantile function on complex number now throws an error (#22652) (#22703) Since percentile is more or less identical to quantile, I also made it throw an error if it receives a complex input. I also made nanquantile and nanpercentile throw errors as well. * Made the changes recommended by seberg * Fixed a test for PR 22703 * Fixed tests for quantile * Shortened some more lines * Fixup more lines Co-authored-by: Sebastian Berg --- numpy/lib/function_base.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'numpy/lib/function_base.py') diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index 35a3b3543..9989e9759 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -3934,7 +3934,7 @@ def percentile(a, Parameters ---------- - a : array_like + a : array_like of real numbers Input array or object that can be converted to an array. q : array_like of float Percentile or sequence of percentiles to compute, which must be between @@ -4198,6 +4198,11 @@ def percentile(a, if interpolation is not None: method = _check_interpolation_as_method( method, interpolation, "percentile") + + a = np.asanyarray(a) + if a.dtype.kind == "c": + raise TypeError("a must be an array of real numbers") + q = np.true_divide(q, 100) q = asanyarray(q) # undo any decay that the ufunc performed (see gh-13105) if not _quantile_is_valid(q): @@ -4228,7 +4233,7 @@ def quantile(a, Parameters ---------- - a : array_like + a : array_like of real numbers Input array or object that can be converted to an array. q : array_like of float Quantile or sequence of quantiles to compute, which must be between @@ -4455,6 +4460,10 @@ def quantile(a, method = _check_interpolation_as_method( method, interpolation, "quantile") + a = np.asanyarray(a) + if a.dtype.kind == "c": + raise TypeError("a must be an array of real numbers") + q = np.asanyarray(q) if not _quantile_is_valid(q): raise ValueError("Quantiles must be in the range [0, 1]") -- cgit v1.2.1 From 4ca8204c5c13b3a5c9482772813e67184f3f47c8 Mon Sep 17 00:00:00 2001 From: Manuchehr Aminian Date: Thu, 8 Dec 2022 04:03:55 -0800 Subject: DOC: add numerical integration of x^2 to trapz (#22681) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Examples in documentation for trapz goes straight from integrating random arrays to parametric curves. I think it's worth pointing out one can integrate something they'd see in Calculus 1 and get the answer they'd expect. Also add some more guidance text to the existing examples (and style fixes) Co-authored-by: Sebastian Berg Co-authored-by: Melissa Weber Mendonça --- numpy/lib/function_base.py | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) (limited to 'numpy/lib/function_base.py') diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index 9989e9759..5e666c17e 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -4836,26 +4836,42 @@ def trapz(y, x=None, dx=1.0, axis=-1): Examples -------- - >>> np.trapz([1,2,3]) + Use the trapezoidal rule on evenly spaced points: + + >>> np.trapz([1, 2, 3]) 4.0 - >>> np.trapz([1,2,3], x=[4,6,8]) + + The spacing between sample points can be selected by either the + ``x`` or ``dx`` arguments: + + >>> np.trapz([1, 2, 3], x=[4, 6, 8]) 8.0 - >>> np.trapz([1,2,3], dx=2) + >>> np.trapz([1, 2, 3], dx=2) 8.0 - Using a decreasing `x` corresponds to integrating in reverse: + Using a decreasing ``x`` corresponds to integrating in reverse: - >>> np.trapz([1,2,3], x=[8,6,4]) + >>> np.trapz([1, 2, 3], x=[8, 6, 4]) -8.0 - More generally `x` is used to integrate along a parametric curve. - This finds the area of a circle, noting we repeat the sample which closes + More generally ``x`` is used to integrate along a parametric curve. We can + estimate the integral :math:`\int_0^1 x^2 = 1/3` using: + + >>> x = np.linspace(0, 1, num=50) + >>> y = x**2 + >>> np.trapz(y, x) + 0.33340274885464394 + + Or estimate the area of a circle, noting we repeat the sample which closes the curve: >>> theta = np.linspace(0, 2 * np.pi, num=1000, endpoint=True) >>> np.trapz(np.cos(theta), x=np.sin(theta)) 3.141571941375841 + ``np.trapz`` can be applied along a specified axis to do multiple + computations in one call: + >>> a = np.arange(6).reshape(2, 3) >>> a array([[0, 1, 2], -- cgit v1.2.1 From 8d2af2eb69fceb7663f39af3307fff45ee636a45 Mon Sep 17 00:00:00 2001 From: Eero Vaher Date: Mon, 12 Dec 2022 23:37:48 +0100 Subject: DOC: Fix legend placement in `percentile` docs A plot is meant to demonstrate the different methods of estimating the percentile that `numpy.percentile()` supports, but previously the legend covered a large fraction of it. Now the legend is drawn next to the plot. --- numpy/lib/function_base.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'numpy/lib/function_base.py') diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index 5e666c17e..0e9a26228 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -4185,7 +4185,8 @@ def percentile(a, xlabel='Percentile', ylabel='Estimated percentile value', yticks=a) - ax.legend() + ax.legend(bbox_to_anchor=(1.03, 1)) + plt.tight_layout() plt.show() References -- cgit v1.2.1 From 68d7aadd30cb7a4f6f32e76715b38b644df18602 Mon Sep 17 00:00:00 2001 From: Matthew Muresan Date: Thu, 29 Dec 2022 21:00:10 -0500 Subject: DOC: Add blurb about rotation direction to rot90 docstring (#22880) * DOC: Add a note to the documentation of the rot90 The note added indicates that rotation is counter clockwise with the default argumemnts. Co-authored-by: Ross Barnowski --- numpy/lib/function_base.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'numpy/lib/function_base.py') diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index 0e9a26228..7a69c3c81 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -161,6 +161,8 @@ def rot90(m, k=1, axes=(0, 1)): Rotate an array by 90 degrees in the plane specified by axes. Rotation direction is from the first towards the second axis. + This means for a 2D array with the default `k` and `axes`, the + rotation will be counterclockwise. Parameters ---------- -- cgit v1.2.1 From 3f00488871ac169b1fd2f40495ad85cb581cc02b Mon Sep 17 00:00:00 2001 From: Sebastian Berg Date: Mon, 16 Jan 2023 14:13:21 +0100 Subject: MAINT: Fix stacklevels for the new C dispatcher not adding one --- numpy/lib/function_base.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'numpy/lib/function_base.py') diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index 7a69c3c81..11a5a3ad0 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -2695,7 +2695,7 @@ def cov(m, y=None, rowvar=True, bias=False, ddof=None, fweights=None, if fact <= 0: warnings.warn("Degrees of freedom <= 0 for slice", - RuntimeWarning, stacklevel=3) + RuntimeWarning, stacklevel=2) fact = 0.0 X -= avg[:, None] @@ -2844,7 +2844,7 @@ def corrcoef(x, y=None, rowvar=True, bias=np._NoValue, ddof=np._NoValue, *, if bias is not np._NoValue or ddof is not np._NoValue: # 2015-03-15, 1.10 warnings.warn('bias and ddof have no effect and are deprecated', - DeprecationWarning, stacklevel=3) + DeprecationWarning, stacklevel=2) c = cov(x, y, rowvar, dtype=dtype) try: d = diag(c) @@ -3684,7 +3684,7 @@ def msort(a): warnings.warn( "msort is deprecated, use np.sort(a, axis=0) instead", DeprecationWarning, - stacklevel=3, + stacklevel=2, ) b = array(a, subok=True, copy=True) b.sort(0) @@ -5398,7 +5398,7 @@ def insert(arr, obj, values, axis=None): warnings.warn( "in the future insert will treat boolean arrays and " "array-likes as a boolean index instead of casting it to " - "integer", FutureWarning, stacklevel=3) + "integer", FutureWarning, stacklevel=2) indices = indices.astype(intp) # Code after warning period: #if obj.ndim != 1: -- cgit v1.2.1 From 88cdaa21aea87ec7d56d1d583500ab2659a5e65e Mon Sep 17 00:00:00 2001 From: Matteo Raso Date: Wed, 18 Jan 2023 02:25:00 -0500 Subject: BUG: Added __name__ atribute to vectorize class (#23021) --- numpy/lib/function_base.py | 1 + 1 file changed, 1 insertion(+) (limited to 'numpy/lib/function_base.py') diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index 7a69c3c81..27ed79044 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -2273,6 +2273,7 @@ class vectorize: self.pyfunc = pyfunc self.cache = cache self.signature = signature + self.__name__ = pyfunc.__name__ self._ufunc = {} # Caching to improve default performance if doc is None: -- cgit v1.2.1 From 8334d57785997b6a3f6a3bae0ffea273632c65f1 Mon Sep 17 00:00:00 2001 From: Sebastian Berg Date: Wed, 18 Jan 2023 13:13:45 +0100 Subject: API: Allow SciPy to get away with assuming `trapz` is a Python function This wraps `trapz` into a proper python function and then copies all attributes expected on a Python function over from the "fake" version to the real one. This allows SciPy to pretend `trapz` is a Python function to create their own version. --- numpy/lib/function_base.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'numpy/lib/function_base.py') diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index 11a5a3ad0..d494aed0f 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -4912,6 +4912,25 @@ def trapz(y, x=None, dx=1.0, axis=-1): return ret +if overrides.ARRAY_FUNCTION_ENABLED: + # If array-function is enabled (normal), we wrap everything into a C + # callable, which has no __code__ or other attributes normal Python funcs + # have. SciPy however, tries to "clone" `trapz` into a new Python function + # which requires `__code__` and a few other attributes. + # So we create a dummy clone and copy over its attributes allowing + # SciPy <= 1.10 to work: https://github.com/scipy/scipy/issues/17811 + assert not hasattr(trapz, "__code__") + + def _fake_trapz(y, x=None, dx=1.0, axis=-1): + return trapz(y, x=x, dx=dx, axis=axis) + + trapz.__code__ = _fake_trapz.__code__ + trapz.__globals__ = _fake_trapz.__globals__ + trapz.__defaults__ = _fake_trapz.__defaults__ + trapz.__closure__ = _fake_trapz.__closure__ + trapz.__kwdefaults__ = _fake_trapz.__kwdefaults__ + + def _meshgrid_dispatcher(*xi, copy=None, sparse=None, indexing=None): return xi -- cgit v1.2.1 From ade008bf5fba3cbc43ffbdf5ee261953a8a71a3a Mon Sep 17 00:00:00 2001 From: Matteo Raso Date: Sat, 21 Jan 2023 20:20:30 -0500 Subject: ENH: Enabled use of numpy.vectorize as decorator (#9477) Most of this code comes from PR-9593, but with the default value for pyfunc being numpy._NoValue instead of None, no override of __new__, and no effort to make subclassing possible. Co-Authored-By: Michael Lamparski --- numpy/lib/function_base.py | 58 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 46 insertions(+), 12 deletions(-) (limited to 'numpy/lib/function_base.py') diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index 27ed79044..cba04765a 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -2119,8 +2119,8 @@ def _create_arrays(broadcast_shape, dim_sizes, list_of_core_dims, dtypes, @set_module('numpy') class vectorize: """ - vectorize(pyfunc, otypes=None, doc=None, excluded=None, cache=False, - signature=None) + vectorize(pyfunc=np._NoValue, otypes=None, doc=None, excluded=None, + cache=False, signature=None) Generalized function class. @@ -2136,8 +2136,9 @@ class vectorize: Parameters ---------- - pyfunc : callable + pyfunc : callable, optional A python function or method. + Can be omitted to produce a decorator with keyword arguments. otypes : str or list of dtypes, optional The output data type. It must be specified as either a string of typecode characters or a list of data type specifiers. There should @@ -2169,8 +2170,9 @@ class vectorize: Returns ------- - vectorized : callable - Vectorized function. + out : callable + A vectorized function if ``pyfunc`` was provided, + a decorator otherwise. See Also -------- @@ -2267,19 +2269,36 @@ class vectorize: [0., 0., 1., 2., 1., 0.], [0., 0., 0., 1., 2., 1.]]) + Decorator syntax is supported. The decorator can be called as + a function to provide keyword arguments. + >>>@np.vectorize + ...def identity(x): + ... return x + ... + >>>identity([0, 1, 2]) + array([0, 1, 2]) + >>>@np.vectorize(otypes=[float]) + ...def as_float(x): + ... return x + ... + >>>as_float([0, 1, 2]) + array([0., 1., 2.]) """ - def __init__(self, pyfunc, otypes=None, doc=None, excluded=None, - cache=False, signature=None): + def __init__(self, pyfunc=np._NoValue, otypes=None, doc=None, + excluded=None, cache=False, signature=None): self.pyfunc = pyfunc self.cache = cache self.signature = signature - self.__name__ = pyfunc.__name__ - self._ufunc = {} # Caching to improve default performance + if pyfunc != np._NoValue: + self.__name__ = pyfunc.__name__ + self._ufunc = {} # Caching to improve default performance + self._doc = None + self.__doc__ = doc if doc is None: self.__doc__ = pyfunc.__doc__ else: - self.__doc__ = doc + self._doc = doc if isinstance(otypes, str): for char in otypes: @@ -2301,7 +2320,15 @@ class vectorize: else: self._in_and_out_core_dims = None - def __call__(self, *args, **kwargs): + def _init_stage_2(self, pyfunc, *args, **kwargs): + self.__name__ = pyfunc.__name__ + self.pyfunc = pyfunc + if self._doc is None: + self.__doc__ = pyfunc.__doc__ + else: + self.__doc__ = self._doc + + def _call_as_normal(self, *args, **kwargs): """ Return arrays with the results of `pyfunc` broadcast (vectorized) over `args` and `kwargs` not in `excluded`. @@ -2331,6 +2358,13 @@ class vectorize: return self._vectorize_call(func=func, args=vargs) + def __call__(self, *args, **kwargs): + if self.pyfunc is np._NoValue: + self._init_stage_2(*args, **kwargs) + return self + + return self._call_as_normal(*args, **kwargs) + def _get_ufunc_and_otypes(self, func, args): """Return (ufunc, otypes).""" # frompyfunc will fail if args is empty @@ -2457,7 +2491,7 @@ class vectorize: if outputs is None: for result, core_dims in zip(results, output_core_dims): - _update_dim_sizes(dim_sizes, result, core_dims) + _update_dim_sizes(dim_sizes, result, core_dims) outputs = _create_arrays(broadcast_shape, dim_sizes, output_core_dims, otypes, results) -- cgit v1.2.1 From 4bb56c412d0841dadf642cc1e5027084231c68e1 Mon Sep 17 00:00:00 2001 From: Matteo Raso Date: Sat, 21 Jan 2023 20:54:32 -0500 Subject: Fixed lint error --- numpy/lib/function_base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'numpy/lib/function_base.py') diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index cba04765a..a49394c47 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -2491,7 +2491,7 @@ class vectorize: if outputs is None: for result, core_dims in zip(results, output_core_dims): - _update_dim_sizes(dim_sizes, result, core_dims) + _update_dim_sizes(dim_sizes, result, core_dims) outputs = _create_arrays(broadcast_shape, dim_sizes, output_core_dims, otypes, results) -- cgit v1.2.1 From 172a1942893b5ce55abccd836fdd9f00235a6767 Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Mon, 23 Jan 2023 18:58:02 +0100 Subject: ENH: Convert methods to vectorcall conversions (#23018) Convert several methods to the vectorcall convention. The conversions give a performance improvement, see #20790 (comment) Some notes: * For vdot the METH_KEYWORDS was removed, as the C vdot method was positional only. * The add_docstring is converted with an additional check. It was parsed as if (!PyArg_ParseTuple(args, "OO!:add_docstring", &obj, &PyUnicode_Type, &str)), but there is no support for the ! in the npy_parse_arguments * CI was complaining about coverage of _get_ndarray_c_version. A test was added, but only to provide coverage * In function_base.py a redundant check in def place was removed Co-authored-by: Sebastian Berg --- numpy/lib/function_base.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'numpy/lib/function_base.py') diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index d494aed0f..0ca3c21c1 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -24,7 +24,7 @@ from numpy.core import overrides from numpy.core.function_base import add_newdoc from numpy.lib.twodim_base import diag from numpy.core.multiarray import ( - _insert, add_docstring, bincount, normalize_axis_index, _monotonicity, + _place, add_docstring, bincount, normalize_axis_index, _monotonicity, interp as compiled_interp, interp_complex as compiled_interp_complex ) from numpy.core.umath import _add_newdoc_ufunc as add_newdoc_ufunc @@ -1949,11 +1949,7 @@ def place(arr, mask, vals): [44, 55, 44]]) """ - if not isinstance(arr, np.ndarray): - raise TypeError("argument 1 must be numpy.ndarray, " - "not {name}".format(name=type(arr).__name__)) - - return _insert(arr, mask, vals) + return _place(arr, mask, vals) def disp(mesg, device=None, linefeed=True): -- cgit v1.2.1 From d961af2f8006657e5309f8c91d50bad8a2b9b0c5 Mon Sep 17 00:00:00 2001 From: Matteo Raso Date: Tue, 24 Jan 2023 18:37:14 -0500 Subject: Changed documentation for numpy.vectorize Previous definition implies that vectorize returns generalized functions, which is not true. --- numpy/lib/function_base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'numpy/lib/function_base.py') diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index a49394c47..f7bc09166 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -2122,7 +2122,7 @@ class vectorize: vectorize(pyfunc=np._NoValue, otypes=None, doc=None, excluded=None, cache=False, signature=None) - Generalized function class. + Returns an object that acts like pyfunc, but takes arrays as input. Define a vectorized function which takes a nested sequence of objects or numpy arrays as inputs and returns a single numpy array or a tuple of numpy -- cgit v1.2.1 From 7a2ded1522305cfbab4e34a18198f3cbcae7755c Mon Sep 17 00:00:00 2001 From: Matteo Raso Date: Wed, 8 Feb 2023 20:39:55 -0500 Subject: Added a test for positional args (PR-23061) --- numpy/lib/function_base.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'numpy/lib/function_base.py') diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index f7bc09166..30349f9e5 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -2286,6 +2286,25 @@ class vectorize: """ def __init__(self, pyfunc=np._NoValue, otypes=None, doc=None, excluded=None, cache=False, signature=None): + + if not callable(pyfunc): + p_temp = pyfunc + pyfunc = np._NoValue + if p_temp is not None and p_temp is not np._NoValue: + o_temp = otypes + otypes = p_temp + if o_temp is not None: + d_temp = doc + doc = o_temp + if d_temp is not None: + e_temp = excluded + excluded = d_temp + if e_temp is True or e_temp is False: + c_temp = cache + cache = e_temp + if c_temp is not None: + signature = c_temp + self.pyfunc = pyfunc self.cache = cache self.signature = signature -- cgit v1.2.1 From 4b82e29a18cd2c17b258bab0e2d937ab2157377b Mon Sep 17 00:00:00 2001 From: Matteo Raso Date: Thu, 9 Feb 2023 22:59:46 -0500 Subject: @vectorize now requires arguments to specify keywords This reverses commit 7a2ded1522305 --- numpy/lib/function_base.py | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) (limited to 'numpy/lib/function_base.py') diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index 30349f9e5..6009b0e4b 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -2287,23 +2287,12 @@ class vectorize: def __init__(self, pyfunc=np._NoValue, otypes=None, doc=None, excluded=None, cache=False, signature=None): - if not callable(pyfunc): - p_temp = pyfunc - pyfunc = np._NoValue - if p_temp is not None and p_temp is not np._NoValue: - o_temp = otypes - otypes = p_temp - if o_temp is not None: - d_temp = doc - doc = o_temp - if d_temp is not None: - e_temp = excluded - excluded = d_temp - if e_temp is True or e_temp is False: - c_temp = cache - cache = e_temp - if c_temp is not None: - signature = c_temp + if (pyfunc != np._NoValue) and (not callable(pyfunc)): + #Splitting the error message to keep + #the length below 79 characters. + part1 = "When used as a decorator, " + part2 = "only accepts keyword arguments." + raise TypeError(part1 + part2) self.pyfunc = pyfunc self.cache = cache -- cgit v1.2.1 From c03e84044a05f0b2358a1cbfc4158e83cba4b835 Mon Sep 17 00:00:00 2001 From: Sebastian Berg Date: Thu, 26 Jan 2023 12:16:23 +0100 Subject: API: Modify `gradient` to return a tuple rather than a list This change is staged for NumPy 2.0, I assume we could get away with it otherwise, but it is a nice example and probably not pressing. --- numpy/lib/function_base.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'numpy/lib/function_base.py') diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index 0ca3c21c1..1f39ebc71 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -1311,6 +1311,8 @@ def gradient(f, *varargs, axis=None, edge_order=1): if len_axes == 1: return outvals[0] + elif np._numpy2_behavior: + return tuple(outvals) else: return outvals -- cgit v1.2.1 From 9d5eafe596e75e30a85c01ed62bb5bea9389adc8 Mon Sep 17 00:00:00 2001 From: Sebastian Berg Date: Fri, 10 Feb 2023 15:51:57 +0100 Subject: MAINT: Use `np._using_numpy2_behavior()` and initialize it in C --- numpy/lib/function_base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'numpy/lib/function_base.py') diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index 1f39ebc71..f5af314b5 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -1311,7 +1311,7 @@ def gradient(f, *varargs, axis=None, edge_order=1): if len_axes == 1: return outvals[0] - elif np._numpy2_behavior: + elif np._using_numpy2_behavior(): return tuple(outvals) else: return outvals -- cgit v1.2.1 From 6b0b97adc8b726ebc5e95643b21c175c0a71a7f4 Mon Sep 17 00:00:00 2001 From: Miki Watanabe <105326591+MikiPWata@users.noreply.github.com> Date: Wed, 1 Mar 2023 19:09:50 -0500 Subject: DOC: Fixed meshgrid docstring return type (#23310) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Meshgrid returns a list of ndarrays. Co-authored-by: 渡邉 美希 --- numpy/lib/function_base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'numpy/lib/function_base.py') diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index f5af314b5..405790025 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -4937,7 +4937,7 @@ def _meshgrid_dispatcher(*xi, copy=None, sparse=None, indexing=None): @array_function_dispatch(_meshgrid_dispatcher) def meshgrid(*xi, copy=True, sparse=False, indexing='xy'): """ - Return coordinate matrices from coordinate vectors. + Return a list of coordinate matrices from coordinate vectors. Make N-D coordinate arrays for vectorized evaluations of N-D scalar/vector fields over N-D grids, given @@ -4978,7 +4978,7 @@ def meshgrid(*xi, copy=True, sparse=False, indexing='xy'): Returns ------- - X1, X2,..., XN : ndarray + X1, X2,..., XN : list of ndarrays For vectors `x1`, `x2`,..., `xn` with lengths ``Ni=len(xi)``, returns ``(N1, N2, N3,..., Nn)`` shaped arrays if indexing='ij' or ``(N2, N1, N3,..., Nn)`` shaped arrays if indexing='xy' -- cgit v1.2.1 From 1da1663196c95b3811ca84d9e335f32cfeb05e32 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Sun, 12 Mar 2023 22:01:22 +0000 Subject: MAINT: remove `NUMPY_EXPERIMENTAL_ARRAY_FUNCTION` env var As discussed in https://mail.python.org/archives/list/numpy-discussion@python.org/thread/UKZJACAP5FUG7KP2AQDPE4P5ADNWLOHZ/ This flag was always meant to be temporary, and cleaning it up is long overdue. --- numpy/lib/function_base.py | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) (limited to 'numpy/lib/function_base.py') diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index 405790025..f0f374f97 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -4910,23 +4910,22 @@ def trapz(y, x=None, dx=1.0, axis=-1): return ret -if overrides.ARRAY_FUNCTION_ENABLED: - # If array-function is enabled (normal), we wrap everything into a C - # callable, which has no __code__ or other attributes normal Python funcs - # have. SciPy however, tries to "clone" `trapz` into a new Python function - # which requires `__code__` and a few other attributes. - # So we create a dummy clone and copy over its attributes allowing - # SciPy <= 1.10 to work: https://github.com/scipy/scipy/issues/17811 - assert not hasattr(trapz, "__code__") - - def _fake_trapz(y, x=None, dx=1.0, axis=-1): - return trapz(y, x=x, dx=dx, axis=axis) - - trapz.__code__ = _fake_trapz.__code__ - trapz.__globals__ = _fake_trapz.__globals__ - trapz.__defaults__ = _fake_trapz.__defaults__ - trapz.__closure__ = _fake_trapz.__closure__ - trapz.__kwdefaults__ = _fake_trapz.__kwdefaults__ +# __array_function__ has no __code__ or other attributes normal Python funcs we +# wrap everything into a C callable. SciPy however, tries to "clone" `trapz` +# into a new Python function which requires `__code__` and a few other +# attributes. So we create a dummy clone and copy over its attributes allowing +# SciPy <= 1.10 to work: https://github.com/scipy/scipy/issues/17811 +assert not hasattr(trapz, "__code__") + +def _fake_trapz(y, x=None, dx=1.0, axis=-1): + return trapz(y, x=x, dx=dx, axis=axis) + + +trapz.__code__ = _fake_trapz.__code__ +trapz.__globals__ = _fake_trapz.__globals__ +trapz.__defaults__ = _fake_trapz.__defaults__ +trapz.__closure__ = _fake_trapz.__closure__ +trapz.__kwdefaults__ = _fake_trapz.__kwdefaults__ def _meshgrid_dispatcher(*xi, copy=None, sparse=None, indexing=None): -- cgit v1.2.1 From ed1732410f51293e4c5f63dcf162d9f1d417335a Mon Sep 17 00:00:00 2001 From: Matti Picus Date: Mon, 27 Mar 2023 09:36:25 +0300 Subject: Revert "ENH: Enabled the use of numpy.vectorize as a decorator" --- numpy/lib/function_base.py | 65 ++++++++-------------------------------------- 1 file changed, 11 insertions(+), 54 deletions(-) (limited to 'numpy/lib/function_base.py') diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index 5e1309dfd..f0f374f97 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -2117,10 +2117,10 @@ def _create_arrays(broadcast_shape, dim_sizes, list_of_core_dims, dtypes, @set_module('numpy') class vectorize: """ - vectorize(pyfunc=np._NoValue, otypes=None, doc=None, excluded=None, - cache=False, signature=None) + vectorize(pyfunc, otypes=None, doc=None, excluded=None, cache=False, + signature=None) - Returns an object that acts like pyfunc, but takes arrays as input. + Generalized function class. Define a vectorized function which takes a nested sequence of objects or numpy arrays as inputs and returns a single numpy array or a tuple of numpy @@ -2134,9 +2134,8 @@ class vectorize: Parameters ---------- - pyfunc : callable, optional + pyfunc : callable A python function or method. - Can be omitted to produce a decorator with keyword arguments. otypes : str or list of dtypes, optional The output data type. It must be specified as either a string of typecode characters or a list of data type specifiers. There should @@ -2168,9 +2167,8 @@ class vectorize: Returns ------- - out : callable - A vectorized function if ``pyfunc`` was provided, - a decorator otherwise. + vectorized : callable + Vectorized function. See Also -------- @@ -2267,44 +2265,18 @@ class vectorize: [0., 0., 1., 2., 1., 0.], [0., 0., 0., 1., 2., 1.]]) - Decorator syntax is supported. The decorator can be called as - a function to provide keyword arguments. - >>>@np.vectorize - ...def identity(x): - ... return x - ... - >>>identity([0, 1, 2]) - array([0, 1, 2]) - >>>@np.vectorize(otypes=[float]) - ...def as_float(x): - ... return x - ... - >>>as_float([0, 1, 2]) - array([0., 1., 2.]) """ - def __init__(self, pyfunc=np._NoValue, otypes=None, doc=None, - excluded=None, cache=False, signature=None): - - if (pyfunc != np._NoValue) and (not callable(pyfunc)): - #Splitting the error message to keep - #the length below 79 characters. - part1 = "When used as a decorator, " - part2 = "only accepts keyword arguments." - raise TypeError(part1 + part2) - + def __init__(self, pyfunc, otypes=None, doc=None, excluded=None, + cache=False, signature=None): self.pyfunc = pyfunc self.cache = cache self.signature = signature - if pyfunc != np._NoValue: - self.__name__ = pyfunc.__name__ - self._ufunc = {} # Caching to improve default performance - self._doc = None - self.__doc__ = doc + if doc is None: self.__doc__ = pyfunc.__doc__ else: - self._doc = doc + self.__doc__ = doc if isinstance(otypes, str): for char in otypes: @@ -2326,15 +2298,7 @@ class vectorize: else: self._in_and_out_core_dims = None - def _init_stage_2(self, pyfunc, *args, **kwargs): - self.__name__ = pyfunc.__name__ - self.pyfunc = pyfunc - if self._doc is None: - self.__doc__ = pyfunc.__doc__ - else: - self.__doc__ = self._doc - - def _call_as_normal(self, *args, **kwargs): + def __call__(self, *args, **kwargs): """ Return arrays with the results of `pyfunc` broadcast (vectorized) over `args` and `kwargs` not in `excluded`. @@ -2364,13 +2328,6 @@ class vectorize: return self._vectorize_call(func=func, args=vargs) - def __call__(self, *args, **kwargs): - if self.pyfunc is np._NoValue: - self._init_stage_2(*args, **kwargs) - return self - - return self._call_as_normal(*args, **kwargs) - def _get_ufunc_and_otypes(self, func, args): """Return (ufunc, otypes).""" # frompyfunc will fail if args is empty -- cgit v1.2.1 From dfaa72d72453b8738ec711180e03da824651e46b Mon Sep 17 00:00:00 2001 From: Matteo Raso Date: Sat, 1 Apr 2023 21:45:16 -0400 Subject: Fixed edge case where pyfunc has no attribute `__name__` --- numpy/lib/function_base.py | 105 ++++++++++++++++++++++++++++----------------- 1 file changed, 66 insertions(+), 39 deletions(-) (limited to 'numpy/lib/function_base.py') diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index f0f374f97..b9f0d58d2 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -24,7 +24,7 @@ from numpy.core import overrides from numpy.core.function_base import add_newdoc from numpy.lib.twodim_base import diag from numpy.core.multiarray import ( - _place, add_docstring, bincount, normalize_axis_index, _monotonicity, + _insert, add_docstring, bincount, normalize_axis_index, _monotonicity, interp as compiled_interp, interp_complex as compiled_interp_complex ) from numpy.core.umath import _add_newdoc_ufunc as add_newdoc_ufunc @@ -1311,8 +1311,6 @@ def gradient(f, *varargs, axis=None, edge_order=1): if len_axes == 1: return outvals[0] - elif np._using_numpy2_behavior(): - return tuple(outvals) else: return outvals @@ -1951,7 +1949,11 @@ def place(arr, mask, vals): [44, 55, 44]]) """ - return _place(arr, mask, vals) + if not isinstance(arr, np.ndarray): + raise TypeError("argument 1 must be numpy.ndarray, " + "not {name}".format(name=type(arr).__name__)) + + return _insert(arr, mask, vals) def disp(mesg, device=None, linefeed=True): @@ -2117,10 +2119,10 @@ def _create_arrays(broadcast_shape, dim_sizes, list_of_core_dims, dtypes, @set_module('numpy') class vectorize: """ - vectorize(pyfunc, otypes=None, doc=None, excluded=None, cache=False, - signature=None) + vectorize(pyfunc=np._NoValue, otypes=None, doc=None, excluded=None, + cache=False, signature=None) - Generalized function class. + Returns an object that acts like pyfunc, but takes arrays as input. Define a vectorized function which takes a nested sequence of objects or numpy arrays as inputs and returns a single numpy array or a tuple of numpy @@ -2134,8 +2136,9 @@ class vectorize: Parameters ---------- - pyfunc : callable + pyfunc : callable, optional A python function or method. + Can be omitted to produce a decorator with keyword arguments. otypes : str or list of dtypes, optional The output data type. It must be specified as either a string of typecode characters or a list of data type specifiers. There should @@ -2167,8 +2170,9 @@ class vectorize: Returns ------- - vectorized : callable - Vectorized function. + out : callable + A vectorized function if ``pyfunc`` was provided, + a decorator otherwise. See Also -------- @@ -2265,18 +2269,44 @@ class vectorize: [0., 0., 1., 2., 1., 0.], [0., 0., 0., 1., 2., 1.]]) + Decorator syntax is supported. The decorator can be called as + a function to provide keyword arguments. + >>>@np.vectorize + ...def identity(x): + ... return x + ... + >>>identity([0, 1, 2]) + array([0, 1, 2]) + >>>@np.vectorize(otypes=[float]) + ...def as_float(x): + ... return x + ... + >>>as_float([0, 1, 2]) + array([0., 1., 2.]) """ - def __init__(self, pyfunc, otypes=None, doc=None, excluded=None, - cache=False, signature=None): + def __init__(self, pyfunc=np._NoValue, otypes=None, doc=None, + excluded=None, cache=False, signature=None): + + if (pyfunc != np._NoValue) and (not callable(pyfunc)): + #Splitting the error message to keep + #the length below 79 characters. + part1 = "When used as a decorator, " + part2 = "only accepts keyword arguments." + raise TypeError(part1 + part2) + self.pyfunc = pyfunc self.cache = cache self.signature = signature - self._ufunc = {} # Caching to improve default performance + if pyfunc != np._NoValue and hasattr(pyfunc, '__name__'): + self.__name__ = pyfunc.__name__ + self._ufunc = {} # Caching to improve default performance + self._doc = None + self.__doc__ = doc if doc is None: self.__doc__ = pyfunc.__doc__ else: - self.__doc__ = doc + self._doc = doc if isinstance(otypes, str): for char in otypes: @@ -2298,7 +2328,15 @@ class vectorize: else: self._in_and_out_core_dims = None - def __call__(self, *args, **kwargs): + def _init_stage_2(self, pyfunc, *args, **kwargs): + self.__name__ = pyfunc.__name__ + self.pyfunc = pyfunc + if self._doc is None: + self.__doc__ = pyfunc.__doc__ + else: + self.__doc__ = self._doc + + def _call_as_normal(self, *args, **kwargs): """ Return arrays with the results of `pyfunc` broadcast (vectorized) over `args` and `kwargs` not in `excluded`. @@ -2328,6 +2366,13 @@ class vectorize: return self._vectorize_call(func=func, args=vargs) + def __call__(self, *args, **kwargs): + if self.pyfunc is np._NoValue: + self._init_stage_2(*args, **kwargs) + return self + + return self._call_as_normal(*args, **kwargs) + def _get_ufunc_and_otypes(self, func, args): """Return (ufunc, otypes).""" # frompyfunc will fail if args is empty @@ -2693,7 +2738,7 @@ def cov(m, y=None, rowvar=True, bias=False, ddof=None, fweights=None, if fact <= 0: warnings.warn("Degrees of freedom <= 0 for slice", - RuntimeWarning, stacklevel=2) + RuntimeWarning, stacklevel=3) fact = 0.0 X -= avg[:, None] @@ -2842,7 +2887,7 @@ def corrcoef(x, y=None, rowvar=True, bias=np._NoValue, ddof=np._NoValue, *, if bias is not np._NoValue or ddof is not np._NoValue: # 2015-03-15, 1.10 warnings.warn('bias and ddof have no effect and are deprecated', - DeprecationWarning, stacklevel=2) + DeprecationWarning, stacklevel=3) c = cov(x, y, rowvar, dtype=dtype) try: d = diag(c) @@ -3682,7 +3727,7 @@ def msort(a): warnings.warn( "msort is deprecated, use np.sort(a, axis=0) instead", DeprecationWarning, - stacklevel=2, + stacklevel=3, ) b = array(a, subok=True, copy=True) b.sort(0) @@ -4910,24 +4955,6 @@ def trapz(y, x=None, dx=1.0, axis=-1): return ret -# __array_function__ has no __code__ or other attributes normal Python funcs we -# wrap everything into a C callable. SciPy however, tries to "clone" `trapz` -# into a new Python function which requires `__code__` and a few other -# attributes. So we create a dummy clone and copy over its attributes allowing -# SciPy <= 1.10 to work: https://github.com/scipy/scipy/issues/17811 -assert not hasattr(trapz, "__code__") - -def _fake_trapz(y, x=None, dx=1.0, axis=-1): - return trapz(y, x=x, dx=dx, axis=axis) - - -trapz.__code__ = _fake_trapz.__code__ -trapz.__globals__ = _fake_trapz.__globals__ -trapz.__defaults__ = _fake_trapz.__defaults__ -trapz.__closure__ = _fake_trapz.__closure__ -trapz.__kwdefaults__ = _fake_trapz.__kwdefaults__ - - def _meshgrid_dispatcher(*xi, copy=None, sparse=None, indexing=None): return xi @@ -4936,7 +4963,7 @@ def _meshgrid_dispatcher(*xi, copy=None, sparse=None, indexing=None): @array_function_dispatch(_meshgrid_dispatcher) def meshgrid(*xi, copy=True, sparse=False, indexing='xy'): """ - Return a list of coordinate matrices from coordinate vectors. + Return coordinate matrices from coordinate vectors. Make N-D coordinate arrays for vectorized evaluations of N-D scalar/vector fields over N-D grids, given @@ -4977,7 +5004,7 @@ def meshgrid(*xi, copy=True, sparse=False, indexing='xy'): Returns ------- - X1, X2,..., XN : list of ndarrays + X1, X2,..., XN : ndarray For vectors `x1`, `x2`,..., `xn` with lengths ``Ni=len(xi)``, returns ``(N1, N2, N3,..., Nn)`` shaped arrays if indexing='ij' or ``(N2, N1, N3,..., Nn)`` shaped arrays if indexing='xy' @@ -5414,7 +5441,7 @@ def insert(arr, obj, values, axis=None): warnings.warn( "in the future insert will treat boolean arrays and " "array-likes as a boolean index instead of casting it to " - "integer", FutureWarning, stacklevel=2) + "integer", FutureWarning, stacklevel=3) indices = indices.astype(intp) # Code after warning period: #if obj.ndim != 1: -- cgit v1.2.1 From d25018b84c2844a5eda2b3ab34ed7723bf71daba Mon Sep 17 00:00:00 2001 From: Matteo Raso Date: Fri, 31 Mar 2023 19:24:10 -0400 Subject: Fixed edge case where pyfunc has no attribute `__doc__` [skip circle] [skip azp] [skip cirrus] --- numpy/lib/function_base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'numpy/lib/function_base.py') diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index b9f0d58d2..90caac062 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -2303,7 +2303,7 @@ class vectorize: self._ufunc = {} # Caching to improve default performance self._doc = None self.__doc__ = doc - if doc is None: + if doc is None and hasattr(pyfunc, '__doc__'): self.__doc__ = pyfunc.__doc__ else: self._doc = doc -- cgit v1.2.1 From f283fe07eb302df130c5dafaf07d06a8fb9c34fd Mon Sep 17 00:00:00 2001 From: Matteo Raso Date: Sat, 1 Apr 2023 23:11:26 -0400 Subject: Fixed failing tests --- numpy/lib/function_base.py | 40 ++++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 12 deletions(-) (limited to 'numpy/lib/function_base.py') diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index 90caac062..277ae3dc4 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -24,7 +24,7 @@ from numpy.core import overrides from numpy.core.function_base import add_newdoc from numpy.lib.twodim_base import diag from numpy.core.multiarray import ( - _insert, add_docstring, bincount, normalize_axis_index, _monotonicity, + _place, add_docstring, bincount, normalize_axis_index, _monotonicity, interp as compiled_interp, interp_complex as compiled_interp_complex ) from numpy.core.umath import _add_newdoc_ufunc as add_newdoc_ufunc @@ -1311,6 +1311,8 @@ def gradient(f, *varargs, axis=None, edge_order=1): if len_axes == 1: return outvals[0] + elif np._using_numpy2_behavior(): + return tuple(outvals) else: return outvals @@ -1949,11 +1951,7 @@ def place(arr, mask, vals): [44, 55, 44]]) """ - if not isinstance(arr, np.ndarray): - raise TypeError("argument 1 must be numpy.ndarray, " - "not {name}".format(name=type(arr).__name__)) - - return _insert(arr, mask, vals) + return _place(arr, mask, vals) def disp(mesg, device=None, linefeed=True): @@ -2738,7 +2736,7 @@ def cov(m, y=None, rowvar=True, bias=False, ddof=None, fweights=None, if fact <= 0: warnings.warn("Degrees of freedom <= 0 for slice", - RuntimeWarning, stacklevel=3) + RuntimeWarning, stacklevel=2) fact = 0.0 X -= avg[:, None] @@ -2887,7 +2885,7 @@ def corrcoef(x, y=None, rowvar=True, bias=np._NoValue, ddof=np._NoValue, *, if bias is not np._NoValue or ddof is not np._NoValue: # 2015-03-15, 1.10 warnings.warn('bias and ddof have no effect and are deprecated', - DeprecationWarning, stacklevel=3) + DeprecationWarning, stacklevel=2) c = cov(x, y, rowvar, dtype=dtype) try: d = diag(c) @@ -3727,7 +3725,7 @@ def msort(a): warnings.warn( "msort is deprecated, use np.sort(a, axis=0) instead", DeprecationWarning, - stacklevel=3, + stacklevel=2, ) b = array(a, subok=True, copy=True) b.sort(0) @@ -4955,6 +4953,24 @@ def trapz(y, x=None, dx=1.0, axis=-1): return ret +# __array_function__ has no __code__ or other attributes normal Python funcs we +# wrap everything into a C callable. SciPy however, tries to "clone" `trapz` +# into a new Python function which requires `__code__` and a few other +# attributes. So we create a dummy clone and copy over its attributes allowing +# SciPy <= 1.10 to work: https://github.com/scipy/scipy/issues/17811 +assert not hasattr(trapz, "__code__") + +def _fake_trapz(y, x=None, dx=1.0, axis=-1): + return trapz(y, x=x, dx=dx, axis=axis) + + +trapz.__code__ = _fake_trapz.__code__ +trapz.__globals__ = _fake_trapz.__globals__ +trapz.__defaults__ = _fake_trapz.__defaults__ +trapz.__closure__ = _fake_trapz.__closure__ +trapz.__kwdefaults__ = _fake_trapz.__kwdefaults__ + + def _meshgrid_dispatcher(*xi, copy=None, sparse=None, indexing=None): return xi @@ -4963,7 +4979,7 @@ def _meshgrid_dispatcher(*xi, copy=None, sparse=None, indexing=None): @array_function_dispatch(_meshgrid_dispatcher) def meshgrid(*xi, copy=True, sparse=False, indexing='xy'): """ - Return coordinate matrices from coordinate vectors. + Return a list of coordinate matrices from coordinate vectors. Make N-D coordinate arrays for vectorized evaluations of N-D scalar/vector fields over N-D grids, given @@ -5004,7 +5020,7 @@ def meshgrid(*xi, copy=True, sparse=False, indexing='xy'): Returns ------- - X1, X2,..., XN : ndarray + X1, X2,..., XN : list of ndarrays For vectors `x1`, `x2`,..., `xn` with lengths ``Ni=len(xi)``, returns ``(N1, N2, N3,..., Nn)`` shaped arrays if indexing='ij' or ``(N2, N1, N3,..., Nn)`` shaped arrays if indexing='xy' @@ -5441,7 +5457,7 @@ def insert(arr, obj, values, axis=None): warnings.warn( "in the future insert will treat boolean arrays and " "array-likes as a boolean index instead of casting it to " - "integer", FutureWarning, stacklevel=3) + "integer", FutureWarning, stacklevel=2) indices = indices.astype(intp) # Code after warning period: #if obj.ndim != 1: -- cgit v1.2.1 From 819d92116bd08a3732becd9895d48618588be3ba Mon Sep 17 00:00:00 2001 From: Christian Lorentzen Date: Tue, 4 Apr 2023 23:39:14 +0200 Subject: DOC quantile q is a probability --- numpy/lib/function_base.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'numpy/lib/function_base.py') diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index 405790025..3a2d9b792 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -4237,8 +4237,8 @@ def quantile(a, a : array_like of real numbers Input array or object that can be converted to an array. q : array_like of float - Quantile or sequence of quantiles to compute, which must be between - 0 and 1 inclusive. + Probability or sequence of probabilities for the quantiles to compute. + Values must be between 0 and 1 inclusive. axis : {int, tuple of int, None}, optional Axis or axes along which the quantiles are computed. The default is to compute the quantile(s) along a flattened version of the array. @@ -4292,8 +4292,8 @@ def quantile(a, Returns ------- quantile : scalar or ndarray - If `q` is a single quantile and `axis=None`, then the result - is a scalar. If multiple quantiles are given, first axis of + If `q` is a single probability and `axis=None`, then the result + is a scalar. If multiple probabilies levels are given, first axis of the result corresponds to the quantiles. The other axes are the axes that remain after the reduction of `a`. If the input contains integers or floats smaller than ``float64``, the output -- cgit v1.2.1 From 1947415e4d4f4cb75989e194e052431068dbd772 Mon Sep 17 00:00:00 2001 From: Christian Lorentzen Date: Wed, 26 Apr 2023 23:24:30 +0200 Subject: DOC use percentage for q in percentile --- numpy/lib/function_base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'numpy/lib/function_base.py') diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index 3a2d9b792..964d4e067 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -3937,8 +3937,8 @@ def percentile(a, a : array_like of real numbers Input array or object that can be converted to an array. q : array_like of float - Percentile or sequence of percentiles to compute, which must be between - 0 and 100 inclusive. + Percentage or sequence of percentages for the percentiles to compute. + Values must be between 0 and 100 inclusive. axis : {int, tuple of int, None}, optional Axis or axes along which the percentiles are computed. The default is to compute the percentile(s) along a flattened -- cgit v1.2.1 From 89486a335a478aac46be91b92e69267f9409b1be Mon Sep 17 00:00:00 2001 From: Sebastian Berg Date: Wed, 3 May 2023 12:36:43 +0200 Subject: MAINT: Reorganize the way windowing functions ensure float64 result This roughly changes things so that we ensure a float64 working values up-front. There is a tiny chance of precision changes if the input was not float64 or error changes on bad input. I don't think this should matter in practice, precision changes (as far as I can tell) should happen rather the other way around. Since float64 has 53bits mantissa, I think the arange should give the correct result reliably for any sensible inputs. There is an argument to be made that the windowing functions could return float32 for float32 input, but I somewhat think this is OK and users can be expected to just cast manually after the fact. The result type is tested, but this ensures the tests pass also when enabling weak promotion. --- numpy/lib/function_base.py | 48 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 10 deletions(-) (limited to 'numpy/lib/function_base.py') diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index 22371a038..02e141920 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -2999,10 +2999,15 @@ def blackman(M): >>> plt.show() """ + # Ensures at least float64 via 0.0. M should be an integer, but conversion + # to double is safe for a range. + values = np.array([0.0, M]) + M = values[1] + if M < 1: - return array([], dtype=np.result_type(M, 0.0)) + return array([], dtype=values.dtype) if M == 1: - return ones(1, dtype=np.result_type(M, 0.0)) + return ones(1, dtype=values.dtype) n = arange(1-M, M, 2) return 0.42 + 0.5*cos(pi*n/(M-1)) + 0.08*cos(2.0*pi*n/(M-1)) @@ -3107,10 +3112,15 @@ def bartlett(M): >>> plt.show() """ + # Ensures at least float64 via 0.0. M should be an integer, but conversion + # to double is safe for a range. + values = np.array([0.0, M]) + M = values[1] + if M < 1: - return array([], dtype=np.result_type(M, 0.0)) + return array([], dtype=values.dtype) if M == 1: - return ones(1, dtype=np.result_type(M, 0.0)) + return ones(1, dtype=values.dtype) n = arange(1-M, M, 2) return where(less_equal(n, 0), 1 + n/(M-1), 1 - n/(M-1)) @@ -3211,10 +3221,15 @@ def hanning(M): >>> plt.show() """ + # Ensures at least float64 via 0.0. M should be an integer, but conversion + # to double is safe for a range. + values = np.array([0.0, M]) + M = values[1] + if M < 1: - return array([], dtype=np.result_type(M, 0.0)) + return array([], dtype=values.dtype) if M == 1: - return ones(1, dtype=np.result_type(M, 0.0)) + return ones(1, dtype=values.dtype) n = arange(1-M, M, 2) return 0.5 + 0.5*cos(pi*n/(M-1)) @@ -3311,10 +3326,15 @@ def hamming(M): >>> plt.show() """ + # Ensures at least float64 via 0.0. M should be an integer, but conversion + # to double is safe for a range. + values = np.array([0.0, M]) + M = values[1] + if M < 1: - return array([], dtype=np.result_type(M, 0.0)) + return array([], dtype=values.dtype) if M == 1: - return ones(1, dtype=np.result_type(M, 0.0)) + return ones(1, dtype=values.dtype) n = arange(1-M, M, 2) return 0.54 + 0.46*cos(pi*n/(M-1)) @@ -3590,11 +3610,19 @@ def kaiser(M, beta): >>> plt.show() """ + # Ensures at least float64 via 0.0. M should be an integer, but conversion + # to double is safe for a range. (Simplified result_type with 0.0 + # strongly typed. result-type is not/less order sensitive, but that mainly + # matters for integers anyway.) + values = np.array([0.0, M, beta]) + M = values[1] + beta = values[2] + if M == 1: - return np.ones(1, dtype=np.result_type(M, 0.0)) + return np.ones(1, dtype=values.dtype) n = arange(0, M) alpha = (M-1)/2.0 - return i0(beta * sqrt(1-((n-alpha)/alpha)**2.0))/i0(float(beta)) + return i0(beta * sqrt(1-((n-alpha)/alpha)**2.0))/i0(beta) def _sinc_dispatcher(x): -- cgit v1.2.1