Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

differentiate: preliminary (yet complete) stubs #329

Merged
merged 3 commits into from
Dec 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions .mypyignore-todo
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
scipy\.__all__

scipy\._lib\.array_api_extra
scipy\._lib\._array_api\.__all__
scipy\._lib\._array_api\.SCIPY_(ARRAY_API|DEVICE)
Expand Down Expand Up @@ -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
Expand Down
41 changes: 21 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
3 changes: 3 additions & 0 deletions scipy-stubs/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ from . import (
cluster,
constants,
datasets,
differentiate,
fft,
fftpack,
integrate,
Expand Down Expand Up @@ -34,6 +35,7 @@ __all__ = [
"cluster",
"constants",
"datasets",
"differentiate",
"fft",
"fftpack",
"integrate",
Expand Down Expand Up @@ -62,6 +64,7 @@ submodules: Final[
"cluster",
"constants",
"datasets",
"differentiate",
"fft",
"fftpack",
"integrate",
Expand Down
3 changes: 3 additions & 0 deletions scipy-stubs/differentiate/__init__.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from ._differentiate import derivative, hessian, jacobian

__all__ = ["derivative", "hessian", "jacobian"]
165 changes: 165 additions & 0 deletions scipy-stubs/differentiate/_differentiate.pyi
Original file line number Diff line number Diff line change
@@ -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 <known>
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 <known>
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 <unknown>
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 <unknown>
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]: ...
Loading