From 5593447fa3059e2c35d53a0a60a7fd849114af4f Mon Sep 17 00:00:00 2001 From: jorenham Date: Mon, 16 Dec 2024 05:08:19 +0100 Subject: [PATCH 1/3] =?UTF-8?q?=E2=9C=A8=20`differentiate`:=20preliminary?= =?UTF-8?q?=20(yet=20complete)=20stubs=20for=20`scipy.differentiate`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scipy-stubs/__init__.pyi | 3 + scipy-stubs/differentiate/__init__.pyi | 3 + scipy-stubs/differentiate/_differentiate.pyi | 165 +++++++++++++++++++ 3 files changed, 171 insertions(+) create mode 100644 scipy-stubs/differentiate/__init__.pyi create mode 100644 scipy-stubs/differentiate/_differentiate.pyi diff --git a/scipy-stubs/__init__.pyi b/scipy-stubs/__init__.pyi index ae6ab3a8..35f54aab 100644 --- a/scipy-stubs/__init__.pyi +++ b/scipy-stubs/__init__.pyi @@ -7,6 +7,7 @@ from . import ( cluster, constants, datasets, + differentiate, fft, fftpack, integrate, @@ -34,6 +35,7 @@ __all__ = [ "cluster", "constants", "datasets", + "differentiate", "fft", "fftpack", "integrate", @@ -62,6 +64,7 @@ submodules: Final[ "cluster", "constants", "datasets", + "differentiate", "fft", "fftpack", "integrate", diff --git a/scipy-stubs/differentiate/__init__.pyi b/scipy-stubs/differentiate/__init__.pyi new file mode 100644 index 00000000..77c7f7b0 --- /dev/null +++ b/scipy-stubs/differentiate/__init__.pyi @@ -0,0 +1,3 @@ +from ._differentiate import derivative, hessian, jacobian + +__all__ = ["derivative", "hessian", "jacobian"] diff --git a/scipy-stubs/differentiate/_differentiate.pyi b/scipy-stubs/differentiate/_differentiate.pyi new file mode 100644 index 00000000..7705dc5e --- /dev/null +++ b/scipy-stubs/differentiate/_differentiate.pyi @@ -0,0 +1,165 @@ +from collections.abc import Callable +from typing import Any, Concatenate, Generic, TypeAlias, TypedDict, overload, type_check_only +from typing_extensions import TypeVar + +import numpy as np +import optype.numpy as onp +import optype.typing as opt +from scipy._lib._util import _RichResult + +_FloatT = TypeVar("_FloatT", bound=np.floating[Any], default=np.floating[Any]) +_FloatT_co = TypeVar("_FloatT_co", bound=np.floating[Any], default=np.floating[Any], covariant=True) +_ShapeT = TypeVar("_ShapeT", bound=onp.AtLeast1D, default=onp.AtLeast1D) +_ShapeT_co = TypeVar("_ShapeT_co", bound=onp.AtLeast1D, default=onp.AtLeast1D, covariant=True) +_ShapeT2_co = TypeVar("_ShapeT2_co", bound=onp.AtLeast2D, default=onp.AtLeast2D, covariant=True) + +_Ignored: TypeAlias = object + +_Function00: TypeAlias = Callable[Concatenate[_FloatT, ...], onp.ToFloat] +_Function11: TypeAlias = Callable[Concatenate[onp.Array1D[_FloatT], ...], onp.ToFloat1D] +_FunctionNN: TypeAlias = Callable[Concatenate[onp.ArrayND[_FloatT, Any], ...], onp.ToFloatND] + +@type_check_only +class _Tolerances(TypedDict, total=False): + rtol: onp.ToFloat + atol: onp.ToFloat + +@type_check_only +class _DerivativeResult0D(_RichResult, Generic[_FloatT_co]): + success: np.bool_ + status: np.int32 + nfev: np.int32 + nit: np.int32 + x: _FloatT_co + df: _FloatT_co + error: _FloatT_co + +@type_check_only +class _DerivativeResultND(_RichResult, Generic[_FloatT_co, _ShapeT_co]): + success: onp.Array[_ShapeT_co, np.bool_] + status: onp.Array[_ShapeT_co, np.int32] + nfev: onp.Array[_ShapeT_co, np.int32] + nit: onp.Array[_ShapeT_co, np.int32] + x: onp.Array[_ShapeT_co, _FloatT_co] + df: onp.Array[_ShapeT_co, _FloatT_co] + error: onp.Array[_ShapeT_co, _FloatT_co] + +@type_check_only +class _JacobianResult(_RichResult, Generic[_FloatT_co, _ShapeT_co]): + status: onp.Array[_ShapeT_co, np.int32] + df: onp.Array[_ShapeT_co, _FloatT_co] + error: onp.Array[_ShapeT_co, _FloatT_co] + nit: onp.Array[_ShapeT_co, np.int32] + nfev: onp.Array[_ShapeT_co, np.int32] + success: onp.Array[_ShapeT_co, np.bool_] + +@type_check_only +class _HessianResult(_RichResult, Generic[_FloatT_co, _ShapeT2_co]): + status: onp.Array[_ShapeT2_co, np.int32] + error: onp.Array[_ShapeT2_co, _FloatT_co] + nfev: onp.Array[_ShapeT2_co, np.int32] + success: onp.Array[_ShapeT2_co, np.bool_] + ddf: onp.Array[_ShapeT2_co, _FloatT_co] + +### + +@overload # 0-d float64 +def derivative( + f: _Function00[np.float64], + x: float | np.float64 | np.integer[Any] | onp.CanArray0D[np.float64 | np.integer[Any]], + *, + args: tuple[onp.ToScalar, ...] = (), + tolerances: _Tolerances | None = None, + maxiter: opt.AnyInt = 10, + order: opt.AnyInt = 8, + initial_step: onp.ToFloat = 0.5, + step_factor: onp.ToFloat = 2.0, + step_direction: onp.ToJustInt = 0, + preserve_shape: bool = False, + callback: Callable[[_DerivativeResult0D[np.float64]], _Ignored] | None = None, +) -> _DerivativeResult0D[np.float64]: ... +@overload # 0-d +def derivative( + f: _Function00[_FloatT], + x: _FloatT | onp.CanArray0D[_FloatT], + *, + args: tuple[onp.ToScalar, ...] = (), + tolerances: _Tolerances | None = None, + maxiter: opt.AnyInt = 10, + order: opt.AnyInt = 8, + initial_step: onp.ToFloat = 0.5, + step_factor: onp.ToFloat = 2.0, + step_direction: onp.ToJustInt = 0, + preserve_shape: bool = False, + callback: Callable[[_DerivativeResult0D[_FloatT]], _Ignored] | None = None, +) -> _DerivativeResult0D[_FloatT]: ... +@overload # n-d +def derivative( + f: _FunctionNN[_FloatT], + x: onp.CanArrayND[_FloatT, _ShapeT], + *, + args: tuple[onp.ToScalar | onp.ToArray1D | onp.CanArray[_ShapeT], ...] = (), + tolerances: _Tolerances | None = None, + maxiter: opt.AnyInt = 10, + order: opt.AnyInt = 8, + initial_step: onp.ToFloat | onp.ToFloat1D | onp.CanArrayND[np.floating[Any], _ShapeT] = 0.5, + step_factor: onp.ToFloat = 2.0, + step_direction: onp.ToJustInt | onp.ToJustInt1D | onp.CanArrayND[np.integer[Any], _ShapeT] = 0, + preserve_shape: bool = False, + callback: Callable[[_DerivativeResultND[_FloatT, _ShapeT]], _Ignored] | None = None, +) -> _DerivativeResultND[_FloatT, _ShapeT]: ... +@overload # 1-d +def derivative( + f: _Function11[_FloatT], + x: onp.ToFloatStrict1D, + *, + args: tuple[onp.ToScalar | onp.ToArrayStrict1D, ...] = (), + tolerances: _Tolerances | None = None, + maxiter: opt.AnyInt = 10, + order: opt.AnyInt = 8, + initial_step: onp.ToFloat | onp.ToFloatStrict1D = 0.5, + step_factor: onp.ToFloat = 2.0, + step_direction: onp.ToJustInt | onp.ToJustIntStrict1D = 0, + preserve_shape: bool = False, + callback: Callable[[_DerivativeResultND[_FloatT, tuple[int]]], _Ignored] | None = None, +) -> _DerivativeResultND[_FloatT, tuple[int]]: ... +@overload # n-d +def derivative( + f: _FunctionNN[_FloatT], + x: onp.ToFloatND, + *, + args: tuple[onp.ToScalar | onp.ToArrayND, ...] = (), + tolerances: _Tolerances | None = None, + maxiter: opt.AnyInt = 10, + order: opt.AnyInt = 8, + initial_step: onp.ToFloat | onp.ToFloatND = 0.5, + step_factor: onp.ToFloat = 2.0, + step_direction: onp.ToJustInt | onp.ToJustIntND = 0, + preserve_shape: bool = False, + callback: Callable[[_DerivativeResultND[_FloatT, _ShapeT]], _Ignored] | None = None, +) -> _DerivativeResultND[_FloatT, _ShapeT]: ... + +# TODO(jorenham): shape overloads +def jacobian( + f: Callable[[onp.Array[Any, _FloatT]], onp.ToFloat | onp.ToFloatND], + x: onp.ToFloatND, + *, + tolerances: _Tolerances | None = None, + maxiter: opt.AnyInt = 10, + order: opt.AnyInt = 8, + initial_step: onp.ToFloat | onp.ToFloatND = 0.5, + step_factor: onp.ToFloat = 2.0, + step_direction: onp.ToJustInt | onp.ToJustIntND = 0, +) -> _JacobianResult[_FloatT, onp.AtLeast1D]: ... + +# TODO(jorenham): shape overloads +def hessian( + f: Callable[[onp.Array[Any, _FloatT]], onp.ToFloat | onp.ToFloatND], + x: onp.ToFloatND, + *, + tolerances: _Tolerances | None = None, + maxiter: opt.AnyInt = 10, + order: opt.AnyInt = 8, + initial_step: onp.ToFloat | onp.ToFloatND = 0.5, + step_factor: onp.ToFloat = 2.0, +) -> _HessianResult[_FloatT, onp.AtLeast2D]: ... From 373d1a990e0f1cfa9c055693f1a5a026902bb275 Mon Sep 17 00:00:00 2001 From: jorenham Date: Mon, 16 Dec 2024 05:09:15 +0100 Subject: [PATCH 2/3] =?UTF-8?q?=F0=9F=99=88=20stop=20ignoring=20stubtest?= =?UTF-8?q?=20errors=20in=20`scipy.differentiate`=20and=20`scipy.=5F=5Fall?= =?UTF-8?q?=5F=5F`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .mypyignore-todo | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.mypyignore-todo b/.mypyignore-todo index 0b7df743..48cf963f 100644 --- a/.mypyignore-todo +++ b/.mypyignore-todo @@ -1,5 +1,3 @@ -scipy\.__all__ - scipy\._lib\.array_api_extra scipy\._lib\._array_api\.__all__ scipy\._lib\._array_api\.SCIPY_(ARRAY_API|DEVICE) @@ -33,8 +31,6 @@ scipy\.constants\._codata\.exact_values scipy\.constants\._codata\.(epsilon|mu)0 scipy\.constants\._codata\.parse_constants_(2002to2014|2018toXXXX) -scipy\.differentiate - scipy\.fft\._basic_backend\.complex_funcs scipy\.fftpack\.(_pseudo_diffs\.)?diff From b088c6703c0b5be1816ab83cc9f3a778743e5374 Mon Sep 17 00:00:00 2001 From: jorenham Date: Mon, 16 Dec 2024 05:10:16 +0100 Subject: [PATCH 3/3] =?UTF-8?q?=F0=9F=93=9D=20include=20`differentiate`=20?= =?UTF-8?q?in=20the=20`README.md`=20progress=20table?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index aae28b5d..5b22e27b 100644 --- a/README.md +++ b/README.md @@ -161,26 +161,27 @@ In those cases static type-checkers won't do any type-checking, and won't bother The following table shows the (subjective) proportion of `scipy-stubs` that is(n't) annotated with `Untyped`, ranging from 🌑 (100% `Untyped`) to 🌕 (0% `Untyped`). -| `scipy._` | `ruff` & `flake8-pyi` | `stubtest` | `basedmypy` | `basedpyright` | phase | -| :------------ | :-------------------: | :--------: | :---------: | :------------: | :---: | -| `cluster` | ✔️ | ✔️ | ✔️ | ✔️ | 🌕 | -| `constants` | ✔️ | ✔️ | ✔️ | ✔️ | 🌝 | -| `datasets` | ✔️ | ✔️ | ✔️ | ✔️ | 🌝 | -| `fft` | ✔️ | ✔️ | ✔️ | ✔️ | 🌕 | -| `fftpack` | ✔️ | ✔️ | ✔️ | ✔️ | 🌕 | -| `integrate` | ✔️ | ✔️ | ✔️ | ✔️ | 🌕 | -| `interpolate` | ✔️ | ✔️ | ✔️ | ✔️ | 🌕 | -| `io` | ✔️ | ✔️ | ✔️ | ✔️ | 🌕 | -| `linalg` | ✔️ | ✔️ | ✔️ | ✔️ | 🌕 | -| `ndimage` | ✔️ | ✔️ | ✔️ | ✔️ | 🌕 | -| `odr` | ✔️ | ✔️ | ✔️ | ✔️ | 🌕 | -| `optimize` | ✔️ | ✔️ | ✔️ | ✔️ | 🌕 | -| `signal` | ✔️ | ✔️ | ✔️ | ✔️ | 🌔 | -| `sparse` | ✔️ | ✔️ | ✔️ | ✔️ | 🌕 | -| `spatial` | ✔️ | ✔️ | ✔️ | ✔️ | 🌕 | -| `special` | ✔️ | ✔️ | ✔️ | ✔️ | 🌕 | -| `stats` | ✔️ | ✔️ | ✔️ | ✔️ | 🌕 | -| *`_lib`* | ✔️ | ✔️ | ✔️ | ✔️ | 🌕 | +| `scipy._` | `ruff` & `flake8-pyi` | `stubtest` | `basedmypy` | `basedpyright` | phase | +| :-------------- | :-------------------: | :--------: | :---------: | :------------: | :---: | +| `cluster` | ✔️ | ✔️ | ✔️ | ✔️ | 🌕 | +| `constants` | ✔️ | ✔️ | ✔️ | ✔️ | 🌝 | +| `datasets` | ✔️ | ✔️ | ✔️ | ✔️ | 🌝 | +| `differentiate` | ✔️ | ✔️ | ✔️ | ✔️ | 🌕 | +| `fft` | ✔️ | ✔️ | ✔️ | ✔️ | 🌕 | +| `fftpack` | ✔️ | ✔️ | ✔️ | ✔️ | 🌕 | +| `integrate` | ✔️ | ✔️ | ✔️ | ✔️ | 🌕 | +| `interpolate` | ✔️ | ✔️ | ✔️ | ✔️ | 🌕 | +| `io` | ✔️ | ✔️ | ✔️ | ✔️ | 🌕 | +| `linalg` | ✔️ | ✔️ | ✔️ | ✔️ | 🌕 | +| `ndimage` | ✔️ | ✔️ | ✔️ | ✔️ | 🌕 | +| `odr` | ✔️ | ✔️ | ✔️ | ✔️ | 🌕 | +| `optimize` | ✔️ | ✔️ | ✔️ | ✔️ | 🌕 | +| `signal` | ✔️ | ✔️ | ✔️ | ✔️ | 🌔 | +| `sparse` | ✔️ | ✔️ | ✔️ | ✔️ | 🌕 | +| `spatial` | ✔️ | ✔️ | ✔️ | ✔️ | 🌕 | +| `special` | ✔️ | ✔️ | ✔️ | ✔️ | 🌕 | +| `stats` | ✔️ | ✔️ | ✔️ | ✔️ | 🌕 | +| *`_lib`* | ✔️ | ✔️ | ✔️ | ✔️ | 🌕 | Currently, only `scipy.signal` contains `Untyped` annotations; all other submodules have complete typing coverage.