From 6a3321004a7a8f461325f11f4f427a3a7e85232d Mon Sep 17 00:00:00 2001 From: jorenham Date: Mon, 9 Sep 2024 02:42:48 +0200 Subject: [PATCH 01/11] initial `scipy.optimize.minimize*` annotations --- scipy-stubs/optimize/_linesearch.pyi | 70 ++++++--- scipy-stubs/optimize/_minimize.pyi | 113 +++++++++++--- scipy-stubs/optimize/_optimize.pyi | 216 +++++++++++++++++---------- 3 files changed, 281 insertions(+), 118 deletions(-) diff --git a/scipy-stubs/optimize/_linesearch.pyi b/scipy-stubs/optimize/_linesearch.pyi index fb4938d8..235e154b 100644 --- a/scipy-stubs/optimize/_linesearch.pyi +++ b/scipy-stubs/optimize/_linesearch.pyi @@ -1,17 +1,26 @@ -from scipy._typing import Untyped +from scipy._typing import Untyped, UntypedCallable from ._dcsrch import DCSRCH as DCSRCH +__all__ = [ + "LineSearchWarning", + "line_search_armijo", + "line_search_wolfe1", + "line_search_wolfe2", + "scalar_search_wolfe1", + "scalar_search_wolfe2", +] + class LineSearchWarning(RuntimeWarning): ... def line_search_wolfe1( - f, - fprime, - xk, - pk, + f: UntypedCallable, + fprime: Untyped, + xk: Untyped, + pk: Untyped, gfk: Untyped | None = None, old_fval: Untyped | None = None, old_old_fval: Untyped | None = None, - args=(), + args: Untyped = (), c1: float = 0.0001, c2: float = 0.9, amax: int = 50, @@ -19,8 +28,8 @@ def line_search_wolfe1( xtol: float = 1e-14, ) -> Untyped: ... def scalar_search_wolfe1( - phi, - derphi, + phi: Untyped, + derphi: Untyped, phi0: Untyped | None = None, old_phi0: Untyped | None = None, derphi0: Untyped | None = None, @@ -34,14 +43,14 @@ def scalar_search_wolfe1( line_search = line_search_wolfe1 def line_search_wolfe2( - f, - myfprime, - xk, - pk, + f: UntypedCallable, + myfprime: Untyped, + xk: Untyped, + pk: Untyped, gfk: Untyped | None = None, old_fval: Untyped | None = None, old_old_fval: Untyped | None = None, - args=(), + args: Untyped = (), c1: float = 0.0001, c2: float = 0.9, amax: Untyped | None = None, @@ -49,8 +58,8 @@ def line_search_wolfe2( maxiter: int = 10, ) -> Untyped: ... def scalar_search_wolfe2( - phi, - derphi, + phi: Untyped, + derphi: Untyped, phi0: Untyped | None = None, old_phi0: Untyped | None = None, derphi0: Untyped | None = None, @@ -60,6 +69,31 @@ def scalar_search_wolfe2( extra_condition: Untyped | None = None, maxiter: int = 10, ) -> Untyped: ... -def line_search_armijo(f, xk, pk, gfk, old_fval, args=(), c1: float = 0.0001, alpha0: int = 1) -> Untyped: ... -def line_search_BFGS(f, xk, pk, gfk, old_fval, args=(), c1: float = 0.0001, alpha0: int = 1) -> Untyped: ... -def scalar_search_armijo(phi, phi0, derphi0, c1: float = 0.0001, alpha0: int = 1, amin: int = 0) -> Untyped: ... +def line_search_armijo( + f: UntypedCallable, + xk: Untyped, + pk: Untyped, + gfk: Untyped, + old_fval: Untyped, + args: Untyped = (), + c1: float = 0.0001, + alpha0: int = 1, +) -> Untyped: ... +def line_search_BFGS( + f: UntypedCallable, + xk: Untyped, + pk: Untyped, + gfk: Untyped, + old_fval: Untyped, + args: Untyped = (), + c1: float = 0.0001, + alpha0: int = 1, +) -> Untyped: ... +def scalar_search_armijo( + phi: Untyped, + phi0: Untyped, + derphi0: Untyped, + c1: float = 0.0001, + alpha0: int = 1, + amin: int = 0, +) -> Untyped: ... diff --git a/scipy-stubs/optimize/_minimize.pyi b/scipy-stubs/optimize/_minimize.pyi index 5d5712b9..d68348e1 100644 --- a/scipy-stubs/optimize/_minimize.pyi +++ b/scipy-stubs/optimize/_minimize.pyi @@ -1,29 +1,98 @@ +from collections.abc import Callable, Mapping, Sequence +from typing import Any, Concatenate, Final, Literal, Protocol, TypeAlias, type_check_only + +import numpy as np +import optype.numpy as onpt from scipy._typing import Untyped +from ._constraints import Bounds, LinearConstraint, NonlinearConstraint +from ._hessian_update_strategy import HessianUpdateStrategy +from ._optimize import OptimizeResult __all__ = ["minimize", "minimize_scalar"] +_Array_f_1d: TypeAlias = onpt.Array[tuple[int], np.floating[Any]] +_ArrayLike_f_1d: TypeAlias = Sequence[float | np.floating[Any]] | onpt.CanArray[tuple[int], np.dtype[np.floating[Any]]] +_ArrayLike_f_2d: TypeAlias = Sequence[_ArrayLike_f_1d] | onpt.CanArray[tuple[int], np.dtype[np.floating[Any]]] + +_MimimizeMethod: TypeAlias = Literal[ + "Nelder-Mead", + "nelder-mead", + "Powell", + "powell", + "CG", + "cg", + "BFGS", + "cfgs", + "Newton-CG", + "newton-cg", + "L-BFGS-B", + "l-bfgs-c", + "TNC", + "tnc" "COBYLA", + "cobyla", + "COBYQA", + "cobyqa", + "SLSQP", + "slsqp", + "trust-constr", + "dogleg", + "trust-ncg", + "trust-exact", + "trust-krylov", +] +_MinimizeScalarMethod: TypeAlias = Literal["Brent", "brent", "Golden", "golden", "Bounded", "bounded"] +_GradMethod: TypeAlias = Literal["2-point", "3-point", "cs"] + +_Bound: TypeAlias = tuple[float | None, float | None] +# TODO: Use a `TypedDict` here +_Constraint: TypeAlias = LinearConstraint | NonlinearConstraint | dict[str, object] + +@type_check_only +class _MinimizeCallback(Protocol): + def __call__(self, /, intermediate_result: OptimizeResult) -> None: ... + +@type_check_only +class _MinimizeCallbackXk(Protocol): + def __call__(self, /, xk: _Array_f_1d) -> None: ... + +### + +MINIMIZE_METHODS: Final[Sequence[_MimimizeMethod]] = ... +MINIMIZE_METHODS_NEW_CB: Final[Sequence[_MimimizeMethod]] = ... +MINIMIZE_SCALAR_METHODS: Final[Sequence[_MinimizeScalarMethod]] = ... + def minimize( - fun, - x0, - args=(), - method: Untyped | None = None, - jac: Untyped | None = None, - hess: Untyped | None = None, - hessp: Untyped | None = None, - bounds: Untyped | None = None, - constraints=(), - tol: Untyped | None = None, - callback: Untyped | None = None, - options: Untyped | None = None, -) -> Untyped: ... + fun: Callable[Concatenate[_Array_f_1d, ...], float | np.floating[Any]], + x0: _ArrayLike_f_1d, + args: tuple[object, ...] = (), + method: _MimimizeMethod | Callable[..., OptimizeResult] | None = None, + jac: _GradMethod | Callable[Concatenate[float, ...], _ArrayLike_f_1d] | None = None, + # TODO: also allow the callable to return a `LinearOperator` or a sparse matrix + hess: _GradMethod | HessianUpdateStrategy | Callable[Concatenate[float, ...], _ArrayLike_f_2d] | None = None, + hessp: Callable[Concatenate[_Array_f_1d, _Array_f_1d, ...], _ArrayLike_f_1d] | None = None, + bounds: Sequence[_Bound] | Bounds | None = None, + constraints: _Constraint | Sequence[_Constraint] = (), + tol: float | None = None, + callback: _MinimizeCallback | _MinimizeCallbackXk | None = None, + # TODO: TypedDict (dependent on `method`) + options: Mapping[str, object] | None = None, +) -> OptimizeResult: ... def minimize_scalar( - fun, - bracket: Untyped | None = None, - bounds: Untyped | None = None, - args=(), - method: Untyped | None = None, - tol: Untyped | None = None, - options: Untyped | None = None, + fun: Callable[Concatenate[float, ...], float | np.floating[Any]], + bracket: Sequence[tuple[float, float] | tuple[float, float, float]] | None = None, + bounds: Sequence[_Bound] | None = None, + args: tuple[object, ...] = (), + method: _MinimizeScalarMethod | Callable[..., OptimizeResult] | None = None, + tol: float | None = None, + options: Mapping[str, object] | None = None, ) -> Untyped: ... -def standardize_bounds(bounds, x0, meth) -> Untyped: ... -def standardize_constraints(constraints, x0, meth) -> Untyped: ... +def standardize_bounds( # undocumented + bounds: Sequence[_Bound] | Bounds, + x0: _ArrayLike_f_1d, + meth: _MimimizeMethod, +) -> Bounds | list[_Bound]: ... +def standardize_constraints( # undocumented + constraints: _Constraint | Sequence[_Constraint], + x0: _ArrayLike_f_1d, + meth: object, # unused +) -> list[_Constraint]: ... diff --git a/scipy-stubs/optimize/_optimize.pyi b/scipy-stubs/optimize/_optimize.pyi index 15b0ecee..347eac98 100644 --- a/scipy-stubs/optimize/_optimize.pyi +++ b/scipy-stubs/optimize/_optimize.pyi @@ -1,5 +1,9 @@ -from scipy._lib._util import MapWrapper, _RichResult -from scipy._typing import Untyped +from typing import Any, Final, Literal + +import numpy as np +import optype.numpy as onpt +from scipy._lib._util import _RichResult +from scipy._typing import Untyped, UntypedCallable, UntypedTuple from ._linesearch import line_search_wolfe2 as line_search __all__ = [ @@ -25,30 +29,74 @@ __all__ = [ "show_options", ] +class _LineSearchError(RuntimeError): ... +class _MaxFuncCallError(RuntimeError): ... +class BracketError(RuntimeError): ... +class OptimizeWarning(UserWarning): ... + +class _Brute_Wrapper: + f: UntypedCallable + args: Untyped + def __init__(self, f: UntypedCallable, args: Untyped) -> None: ... + def __call__(self, x: Untyped) -> Untyped: ... + class MemoizeJac: - fun: Untyped + fun: UntypedCallable jac: Untyped x: Untyped - def __init__(self, fun) -> None: ... - def __call__(self, x, *args) -> Untyped: ... - def derivative(self, x, *args) -> Untyped: ... - -class OptimizeResult(_RichResult): ... -class OptimizeWarning(UserWarning): ... + def __init__(self, fun: UntypedCallable) -> None: ... + def __call__(self, x: Untyped, *args: Untyped) -> Untyped: ... + def derivative(self, x: Untyped, *args: Untyped) -> Untyped: ... -def is_finite_scalar(x) -> Untyped: ... -def vecnorm(x, ord: int = 2) -> Untyped: ... -def rosen(x) -> Untyped: ... -def rosen_der(x) -> Untyped: ... -def rosen_hess(x) -> Untyped: ... -def rosen_hess_prod(x, p) -> Untyped: ... +class Brent: + func: UntypedCallable + args: Untyped + tol: float + maxiter: int + xmin: Untyped + fval: Untyped + iter: int + funcalls: int + disp: bool | Literal[0, 1] + brack: Untyped + def __init__( + self, + func: UntypedCallable, + args: Untyped = (), + tol: float = 1.48e-08, + maxiter: int = 500, + full_output: int = 0, + disp: bool | Literal[0, 1] = 0, + ) -> None: ... + def set_bracket(self, brack: Untyped | None = None) -> None: ... + def get_bracket_info(self) -> Untyped: ... + def optimize(self) -> None: ... + def get_result(self, full_output: bool = False) -> Untyped: ... -class _MaxFuncCallError(RuntimeError): ... +class OptimizeResult(_RichResult): + x: Final[onpt.Array[tuple[int], np.floating[Any]]] + success: Final[bool] + status: int + message: str + fun: float | np.floating[Any] + jac: onpt.Array[tuple[int, ...], np.floating[Any]] + hess: onpt.Array[tuple[int, ...], np.floating[Any]] + nfev: int + njev: int + nhev: int + nit: int + maxcv: float +def is_finite_scalar(x: Untyped) -> Untyped: ... +def vecnorm(x: Untyped, ord: int = 2) -> Untyped: ... +def rosen(x: Untyped) -> Untyped: ... +def rosen_der(x: Untyped) -> Untyped: ... +def rosen_hess(x: Untyped) -> Untyped: ... +def rosen_hess_prod(x: Untyped, p: Untyped) -> Untyped: ... def fmin( - func, - x0, - args=(), + func: UntypedCallable, + x0: Untyped, + args: Untyped = (), xtol: float = 0.0001, ftol: float = 0.0001, maxiter: Untyped | None = None, @@ -59,20 +107,25 @@ def fmin( callback: Untyped | None = None, initial_simplex: Untyped | None = None, ) -> Untyped: ... -def approx_fprime(xk, f, epsilon=..., *args) -> Untyped: ... -def check_grad(func, grad, x0, *args, epsilon=..., direction: str = "all", seed: Untyped | None = None) -> Untyped: ... -def approx_fhess_p(x0, p, fprime, epsilon, *args) -> Untyped: ... - -class _LineSearchError(RuntimeError): ... - +def approx_fprime(xk: Untyped, f: UntypedCallable, epsilon: float = ..., *args: Untyped) -> Untyped: ... +def check_grad( + func: UntypedCallable, + grad: Untyped, + x0: Untyped, + *args: Untyped, + epsilon: float = ..., + direction: str = "all", + seed: Untyped | None = None, +) -> Untyped: ... +def approx_fhess_p(x0: Untyped, p: Untyped, fprime: Untyped, epsilon: float, *args: Untyped) -> Untyped: ... def fmin_bfgs( - f, - x0, + f: UntypedCallable, + x0: Untyped, fprime: Untyped | None = None, - args=(), + args: Untyped = (), gtol: float = 1e-05, - norm=..., - epsilon=..., + norm: float = ..., + epsilon: float = ..., maxiter: Untyped | None = None, full_output: int = 0, disp: int = 1, @@ -84,13 +137,13 @@ def fmin_bfgs( hess_inv0: Untyped | None = None, ) -> Untyped: ... def fmin_cg( - f, - x0, + f: UntypedCallable, + x0: Untyped, fprime: Untyped | None = None, - args=(), + args: Untyped = (), gtol: float = 1e-05, - norm=..., - epsilon=..., + norm: float = ..., + epsilon: float = ..., maxiter: Untyped | None = None, full_output: int = 0, disp: int = 1, @@ -100,14 +153,14 @@ def fmin_cg( c2: float = 0.4, ) -> Untyped: ... def fmin_ncg( - f, - x0, - fprime, + f: UntypedCallable, + x0: Untyped, + fprime: Untyped, fhess_p: Untyped | None = None, fhess: Untyped | None = None, - args=(), + args: Untyped = (), avextol: float = 1e-05, - epsilon=..., + epsilon: float = ..., maxiter: Untyped | None = None, full_output: int = 0, disp: int = 1, @@ -116,37 +169,44 @@ def fmin_ncg( c1: float = 0.0001, c2: float = 0.9, ) -> Untyped: ... -def fminbound(func, x1, x2, args=(), xtol: float = 1e-05, maxfun: int = 500, full_output: int = 0, disp: int = 1) -> Untyped: ... - -class Brent: - func: Untyped - args: Untyped - tol: Untyped - maxiter: Untyped - xmin: Untyped - fval: Untyped - iter: int - funcalls: int - disp: Untyped - def __init__(self, func, args=(), tol: float = 1.48e-08, maxiter: int = 500, full_output: int = 0, disp: int = 0): ... - brack: Untyped - def set_bracket(self, brack: Untyped | None = None): ... - def get_bracket_info(self) -> Untyped: ... - def optimize(self): ... - def get_result(self, full_output: bool = False) -> Untyped: ... - +def fminbound( + func: UntypedCallable, + x1: Untyped, + x2: Untyped, + args: Untyped = (), + xtol: float = 1e-05, + maxfun: int = 500, + full_output: int = 0, + disp: int = 1, +) -> Untyped: ... def brent( - func, args=(), brack: Untyped | None = None, tol: float = 1.48e-08, full_output: int = 0, maxiter: int = 500 + func: UntypedCallable, + args: Untyped = (), + brack: Untyped | None = None, + tol: float = 1.48e-08, + full_output: int = 0, + maxiter: int = 500, +) -> Untyped: ... +def golden( + func: UntypedCallable, + args: Untyped = (), + brack: Untyped | None = None, + tol: float = ..., + full_output: int = 0, + maxiter: int = 5000, +) -> Untyped: ... +def bracket( + func: UntypedCallable, + xa: float = 0.0, + xb: float = 1.0, + args: Untyped = (), + grow_limit: float = 110.0, + maxiter: int = 1000, ) -> Untyped: ... -def golden(func, args=(), brack: Untyped | None = None, tol=..., full_output: int = 0, maxiter: int = 5000) -> Untyped: ... -def bracket(func, xa: float = 0.0, xb: float = 1.0, args=(), grow_limit: float = 110.0, maxiter: int = 1000) -> Untyped: ... - -class BracketError(RuntimeError): ... - def fmin_powell( - func, - x0, - args=(), + func: UntypedCallable, + x0: Untyped, + args: Untyped = (), xtol: float = 0.0001, ftol: float = 0.0001, maxiter: Untyped | None = None, @@ -154,17 +214,17 @@ def fmin_powell( full_output: int = 0, disp: int = 1, retall: int = 0, - callback: Untyped | None = None, + callback: UntypedCallable | None = None, direc: Untyped | None = None, ) -> Untyped: ... def brute( - func, ranges, args=(), Ns: int = 20, full_output: int = 0, finish=..., disp: bool = False, workers: int = 1 + func: UntypedCallable, + ranges: Untyped, + args: UntypedTuple = (), + Ns: int = 20, + full_output: int = 0, + finish: Untyped = ..., + disp: bool = False, + workers: int = 1, ) -> Untyped: ... - -class _Brute_Wrapper: - f: Untyped - args: Untyped - def __init__(self, f, args) -> None: ... - def __call__(self, x) -> Untyped: ... - -def show_options(solver: Untyped | None = None, method: Untyped | None = None, disp: bool = True) -> Untyped: ... +def show_options(solver: str | None = None, method: str | None = None, disp: bool = True) -> str | None: ... From a939313eb2a6b11f849b8035ab78dbdf2092d8ae Mon Sep 17 00:00:00 2001 From: jorenham Date: Mon, 9 Sep 2024 15:40:03 +0200 Subject: [PATCH 02/11] remove most `scipy.optimize` entries from the allowlist --- tests/stubtest/allowlist.txt | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/tests/stubtest/allowlist.txt b/tests/stubtest/allowlist.txt index 145c1f02..139a7da5 100644 --- a/tests/stubtest/allowlist.txt +++ b/tests/stubtest/allowlist.txt @@ -30,7 +30,6 @@ scipy.linalg.tests.* scipy.misc.tests.* scipy.ndimage.tests.* scipy.odr.tests.* -scipy.optimize._trlib._trlib.__test__ scipy.optimize._trustregion_constr.tests.* scipy.optimize.tests.* scipy.signal.tests.* @@ -94,15 +93,6 @@ scipy.linalg.decomp.* scipy.linalg.matfuncs.* scipy.linalg.misc.* scipy.linalg.special_matrices.* -scipy.optimize.cobyla.* -scipy.optimize.lbfgsb.* -scipy.optimize.linesearch.* -scipy.optimize.minpack.* -scipy.optimize.nonlin.* -scipy.optimize.optimize.* -scipy.optimize.slsqp.* -scipy.optimize.tnc.* -scipy.optimize.zeros.* scipy.linalg.basic scipy.stats.kde.* scipy.stats.morestats.* @@ -127,10 +117,6 @@ scipy._lib._ccallback.__all__ scipy._lib.array_api_compat.__all__ scipy._lib.array_api_compat.common.__all__ scipy.integrate._ivp.__all__ -scipy.optimize._constraints.__all__ -scipy.optimize._lsap.__all__ -scipy.optimize._remove_redundancy.__all__ -scipy.optimize._trlib._trlib.__all__ scipy.signal._signaltools.__all__ scipy.spatial.ckdtree.__all__ scipy.spatial.kdtree.__all__ From cbc0b92ef70b3a7c6239753640fd96b6a849c615 Mon Sep 17 00:00:00 2001 From: jorenham Date: Mon, 9 Sep 2024 15:52:35 +0200 Subject: [PATCH 03/11] type-hint `scipy.optimize._tnc` --- scipy-stubs/optimize/_tnc.pyi | 83 +++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 38 deletions(-) diff --git a/scipy-stubs/optimize/_tnc.pyi b/scipy-stubs/optimize/_tnc.pyi index 017afe09..be9807f7 100644 --- a/scipy-stubs/optimize/_tnc.pyi +++ b/scipy-stubs/optimize/_tnc.pyi @@ -1,46 +1,53 @@ -from scipy._typing import Untyped +from collections.abc import Callable, Sequence +from typing import Any, Final, Literal, TypeAlias + +import numpy as np +import numpy.typing as npt __all__ = ["fmin_tnc"] -MSG_NONE: int -MSG_ITER: int -MSG_INFO: int -MSG_VERS: int -MSG_EXIT: int -MSG_ALL: Untyped -MSGS: Untyped -INFEASIBLE: int -LOCALMINIMUM: int -FCONVERGED: int -XCONVERGED: int -MAXFUN: int -LSFAIL: int -CONSTANT: int -NOPROGRESS: int -USERABORT: int -RCSTRINGS: Untyped +_ReturnCode: TypeAlias = Literal[-1, 0, 1, 2, 3, 4, 5, 6, 7] + +MSG_NONE: Final = 0 +MSG_ITER: Final = 1 +MSG_INFO: Final = 2 +MSG_VERS: Final = 4 +MSG_EXIT: Final = 8 +MSG_ALL: Final = 15 +MSGS: Final[dict[Literal[0, 1, 2, 4, 8, 15], str]] + +INFEASIBLE: Final = -1 +LOCALMINIMUM: Final = 0 +FCONVERGED: Final = 1 +XCONVERGED: Final = 2 +MAXFUN: Final = 3 +LSFAIL: Final = 4 +CONSTANT: Final = 5 +NOPROGRESS: Final = 6 +USERABORT: Final = 7 +RCSTRINGS: Final[dict[_ReturnCode, str]] def fmin_tnc( - func, - x0, - fprime: Untyped | None = None, - args=(), + func: Callable[..., float | np.floating[Any]] | Callable[..., tuple[float | np.floating[Any], float | np.floating[Any]]], + x0: npt.ArrayLike, + fprime: Callable[..., float | np.floating[Any]] | None = None, + args: tuple[object, ...] = (), approx_grad: int = 0, - bounds: Untyped | None = None, + bounds: Sequence[tuple[float | None, float | None]] | None = None, epsilon: float = 1e-08, - scale: Untyped | None = None, - offset: Untyped | None = None, - messages=..., + scale: npt.ArrayLike | None = None, + offset: npt.ArrayLike | None = None, + messages: int = ..., maxCGit: int = -1, - maxfun: Untyped | None = None, - eta: int = -1, - stepmx: int = 0, - accuracy: int = 0, - fmin: int = 0, - ftol: int = -1, - xtol: int = -1, - pgtol: int = -1, - rescale: int = -1, - disp: Untyped | None = None, - callback: Untyped | None = None, -) -> Untyped: ... + maxfun: int | None = None, + eta: float = -1, + stepmx: float = 0, + accuracy: float = 0, + fmin: float = 0, + ftol: float = -1, + xtol: float = -1, + pgtol: float = -1, + rescale: float = -1, + disp: bool | None = None, + callback: Callable[[npt.NDArray[np.floating[Any]]], None] | None = None, +) -> tuple[npt.NDArray[np.floating[Any]], int, _ReturnCode]: ... From 3e5705497e1a766ee532608016b7e405c6109d58 Mon Sep 17 00:00:00 2001 From: jorenham Date: Mon, 9 Sep 2024 15:53:01 +0200 Subject: [PATCH 04/11] cleanup of `scipy.optimize._minimize` --- scipy-stubs/optimize/_minimize.pyi | 58 ++++++++---------------------- scipy-stubs/optimize/_typing.pyi | 35 ++++++++++++++++++ 2 files changed, 49 insertions(+), 44 deletions(-) create mode 100644 scipy-stubs/optimize/_typing.pyi diff --git a/scipy-stubs/optimize/_minimize.pyi b/scipy-stubs/optimize/_minimize.pyi index d68348e1..df7dac75 100644 --- a/scipy-stubs/optimize/_minimize.pyi +++ b/scipy-stubs/optimize/_minimize.pyi @@ -1,12 +1,13 @@ from collections.abc import Callable, Mapping, Sequence -from typing import Any, Concatenate, Final, Literal, Protocol, TypeAlias, type_check_only +from typing import Any, Concatenate, Final, Protocol, TypeAlias, type_check_only import numpy as np import optype.numpy as onpt from scipy._typing import Untyped -from ._constraints import Bounds, LinearConstraint, NonlinearConstraint +from ._constraints import Bounds from ._hessian_update_strategy import HessianUpdateStrategy from ._optimize import OptimizeResult +from ._typing import Constraint, GradMethod, MimimizeMethod, MinimizeScalarMethod __all__ = ["minimize", "minimize_scalar"] @@ -14,38 +15,7 @@ _Array_f_1d: TypeAlias = onpt.Array[tuple[int], np.floating[Any]] _ArrayLike_f_1d: TypeAlias = Sequence[float | np.floating[Any]] | onpt.CanArray[tuple[int], np.dtype[np.floating[Any]]] _ArrayLike_f_2d: TypeAlias = Sequence[_ArrayLike_f_1d] | onpt.CanArray[tuple[int], np.dtype[np.floating[Any]]] -_MimimizeMethod: TypeAlias = Literal[ - "Nelder-Mead", - "nelder-mead", - "Powell", - "powell", - "CG", - "cg", - "BFGS", - "cfgs", - "Newton-CG", - "newton-cg", - "L-BFGS-B", - "l-bfgs-c", - "TNC", - "tnc" "COBYLA", - "cobyla", - "COBYQA", - "cobyqa", - "SLSQP", - "slsqp", - "trust-constr", - "dogleg", - "trust-ncg", - "trust-exact", - "trust-krylov", -] -_MinimizeScalarMethod: TypeAlias = Literal["Brent", "brent", "Golden", "golden", "Bounded", "bounded"] -_GradMethod: TypeAlias = Literal["2-point", "3-point", "cs"] - _Bound: TypeAlias = tuple[float | None, float | None] -# TODO: Use a `TypedDict` here -_Constraint: TypeAlias = LinearConstraint | NonlinearConstraint | dict[str, object] @type_check_only class _MinimizeCallback(Protocol): @@ -57,21 +27,21 @@ class _MinimizeCallbackXk(Protocol): ### -MINIMIZE_METHODS: Final[Sequence[_MimimizeMethod]] = ... -MINIMIZE_METHODS_NEW_CB: Final[Sequence[_MimimizeMethod]] = ... -MINIMIZE_SCALAR_METHODS: Final[Sequence[_MinimizeScalarMethod]] = ... +MINIMIZE_METHODS: Final[Sequence[MimimizeMethod]] = ... +MINIMIZE_METHODS_NEW_CB: Final[Sequence[MimimizeMethod]] = ... +MINIMIZE_SCALAR_METHODS: Final[Sequence[MinimizeScalarMethod]] = ... def minimize( fun: Callable[Concatenate[_Array_f_1d, ...], float | np.floating[Any]], x0: _ArrayLike_f_1d, args: tuple[object, ...] = (), - method: _MimimizeMethod | Callable[..., OptimizeResult] | None = None, - jac: _GradMethod | Callable[Concatenate[float, ...], _ArrayLike_f_1d] | None = None, + method: MimimizeMethod | Callable[..., OptimizeResult] | None = None, + jac: GradMethod | Callable[Concatenate[float, ...], _ArrayLike_f_1d] | None = None, # TODO: also allow the callable to return a `LinearOperator` or a sparse matrix - hess: _GradMethod | HessianUpdateStrategy | Callable[Concatenate[float, ...], _ArrayLike_f_2d] | None = None, + hess: GradMethod | HessianUpdateStrategy | Callable[Concatenate[float, ...], _ArrayLike_f_2d] | None = None, hessp: Callable[Concatenate[_Array_f_1d, _Array_f_1d, ...], _ArrayLike_f_1d] | None = None, bounds: Sequence[_Bound] | Bounds | None = None, - constraints: _Constraint | Sequence[_Constraint] = (), + constraints: Constraint | Sequence[Constraint] = (), tol: float | None = None, callback: _MinimizeCallback | _MinimizeCallbackXk | None = None, # TODO: TypedDict (dependent on `method`) @@ -82,17 +52,17 @@ def minimize_scalar( bracket: Sequence[tuple[float, float] | tuple[float, float, float]] | None = None, bounds: Sequence[_Bound] | None = None, args: tuple[object, ...] = (), - method: _MinimizeScalarMethod | Callable[..., OptimizeResult] | None = None, + method: MinimizeScalarMethod | Callable[..., OptimizeResult] | None = None, tol: float | None = None, options: Mapping[str, object] | None = None, ) -> Untyped: ... def standardize_bounds( # undocumented bounds: Sequence[_Bound] | Bounds, x0: _ArrayLike_f_1d, - meth: _MimimizeMethod, + meth: MimimizeMethod, ) -> Bounds | list[_Bound]: ... def standardize_constraints( # undocumented - constraints: _Constraint | Sequence[_Constraint], + constraints: Constraint | Sequence[Constraint], x0: _ArrayLike_f_1d, meth: object, # unused -) -> list[_Constraint]: ... +) -> list[Constraint]: ... diff --git a/scipy-stubs/optimize/_typing.pyi b/scipy-stubs/optimize/_typing.pyi new file mode 100644 index 00000000..f3926b8c --- /dev/null +++ b/scipy-stubs/optimize/_typing.pyi @@ -0,0 +1,35 @@ +from typing import Literal, TypeAlias + +from ._constraints import LinearConstraint, NonlinearConstraint + +MimimizeMethod: TypeAlias = Literal[ + "Nelder-Mead", + "nelder-mead", + "Powell", + "powell", + "CG", + "cg", + "BFGS", + "cfgs", + "Newton-CG", + "newton-cg", + "L-BFGS-B", + "l-bfgs-c", + "TNC", + "tnc" "COBYLA", + "cobyla", + "COBYQA", + "cobyqa", + "SLSQP", + "slsqp", + "trust-constr", + "dogleg", + "trust-ncg", + "trust-exact", + "trust-krylov", +] +MinimizeScalarMethod: TypeAlias = Literal["Brent", "brent", "Golden", "golden", "Bounded", "bounded"] +GradMethod: TypeAlias = Literal["2-point", "3-point", "cs"] + +# TODO: Use a `TypedDict` here +Constraint: TypeAlias = LinearConstraint | NonlinearConstraint | dict[str, object] From e86c6ac6ce4e629bf94eeef7290353a05296f083 Mon Sep 17 00:00:00 2001 From: jorenham Date: Mon, 9 Sep 2024 16:08:30 +0200 Subject: [PATCH 05/11] type-hint the deprecated `scipy.optimize` submodules --- scipy-stubs/optimize/_constraints.pyi | 16 ++------------ scipy-stubs/optimize/_slsqp_py.pyi | 5 +++++ scipy-stubs/optimize/cobyla.pyi | 8 ++++--- scipy-stubs/optimize/lbfgsb.pyi | 9 +++++--- scipy-stubs/optimize/linesearch.pyi | 7 ++++--- scipy-stubs/optimize/minpack.pyi | 10 ++++++--- scipy-stubs/optimize/minpack2.pyi | 5 ++--- scipy-stubs/optimize/moduleTNC.pyi | 5 ++--- scipy-stubs/optimize/nonlin.pyi | 18 +++++++++++++--- scipy-stubs/optimize/optimize.pyi | 30 ++++++++++++++++++++++++--- scipy-stubs/optimize/slsqp.pyi | 9 +++++--- scipy-stubs/optimize/tnc.pyi | 9 +++++--- scipy-stubs/optimize/zeros.pyi | 7 ++++--- tests/stubtest/allowlist.txt | 1 + 14 files changed, 92 insertions(+), 47 deletions(-) diff --git a/scipy-stubs/optimize/_constraints.pyi b/scipy-stubs/optimize/_constraints.pyi index e0dc718a..b512530e 100644 --- a/scipy-stubs/optimize/_constraints.pyi +++ b/scipy-stubs/optimize/_constraints.pyi @@ -1,19 +1,7 @@ -from scipy._typing import Untyped - -__all__ = ( - "Bounds", - "LinearConstraint", - "NonlinearConstraint", - "PreparedConstraint", - "new_bounds_to_old", - "new_constraint_to_old", - "old_bound_to_new", - "old_constraint_to_new", - "strict_bounds", -) +from scipy._typing import Untyped, UntypedCallable class NonlinearConstraint: - fun: Untyped + fun: UntypedCallable lb: Untyped ub: Untyped finite_diff_rel_step: Untyped diff --git a/scipy-stubs/optimize/_slsqp_py.pyi b/scipy-stubs/optimize/_slsqp_py.pyi index 237adcad..1d2926f7 100644 --- a/scipy-stubs/optimize/_slsqp_py.pyi +++ b/scipy-stubs/optimize/_slsqp_py.pyi @@ -1,3 +1,5 @@ +from collections.abc import Callable + from scipy._typing import Untyped __all__ = ["approx_jacobian", "fmin_slsqp"] @@ -23,3 +25,6 @@ def fmin_slsqp( epsilon: Untyped = ..., callback: Untyped | None = None, ) -> Untyped: ... + +# from scopy.optimize._slsqp +slsqp: Callable[..., object] diff --git a/scipy-stubs/optimize/cobyla.pyi b/scipy-stubs/optimize/cobyla.pyi index bc0eb39c..0b878c48 100644 --- a/scipy-stubs/optimize/cobyla.pyi +++ b/scipy-stubs/optimize/cobyla.pyi @@ -1,4 +1,6 @@ -from scipy._typing import Untyped +# This file is not meant for public use and will be removed in SciPy v2.0.0. -def __dir__() -> Untyped: ... -def __getattr__(name) -> Untyped: ... +from ._cobyla_py import fmin_cobyla +from ._optimize import OptimizeResult + +__all__ = ["OptimizeResult", "fmin_cobyla"] diff --git a/scipy-stubs/optimize/lbfgsb.pyi b/scipy-stubs/optimize/lbfgsb.pyi index bc0eb39c..b4e0fc14 100644 --- a/scipy-stubs/optimize/lbfgsb.pyi +++ b/scipy-stubs/optimize/lbfgsb.pyi @@ -1,4 +1,7 @@ -from scipy._typing import Untyped +# This file is not meant for public use and will be removed in SciPy v2.0.0. -def __dir__() -> Untyped: ... -def __getattr__(name) -> Untyped: ... +from numpy import zeros # noqa: ICN003 +from ._lbfgsb_py import LbfgsInvHessProduct, fmin_l_bfgs_b +from ._optimize import OptimizeResult + +__all__ = ["LbfgsInvHessProduct", "OptimizeResult", "fmin_l_bfgs_b", "zeros"] diff --git a/scipy-stubs/optimize/linesearch.pyi b/scipy-stubs/optimize/linesearch.pyi index bc0eb39c..9b4ed820 100644 --- a/scipy-stubs/optimize/linesearch.pyi +++ b/scipy-stubs/optimize/linesearch.pyi @@ -1,4 +1,5 @@ -from scipy._typing import Untyped +# This file is not meant for public use and will be removed in SciPy v2.0.0. -def __dir__() -> Untyped: ... -def __getattr__(name) -> Untyped: ... +from ._linesearch import line_search + +__all__ = ["line_search"] diff --git a/scipy-stubs/optimize/minpack.pyi b/scipy-stubs/optimize/minpack.pyi index bc0eb39c..63446c8c 100644 --- a/scipy-stubs/optimize/minpack.pyi +++ b/scipy-stubs/optimize/minpack.pyi @@ -1,4 +1,8 @@ -from scipy._typing import Untyped +# This file is not meant for public use and will be removed in SciPy v2.0.0. -def __dir__() -> Untyped: ... -def __getattr__(name) -> Untyped: ... +from numpy import zeros # noqa: ICN003 +from ._lsq.least_squares import least_squares +from ._minpack_py import * +from ._optimize import OptimizeResult, OptimizeWarning + +__all__ = ["OptimizeResult", "OptimizeWarning", "curve_fit", "fixed_point", "fsolve", "least_squares", "leastsq", "zeros"] diff --git a/scipy-stubs/optimize/minpack2.pyi b/scipy-stubs/optimize/minpack2.pyi index bc0eb39c..9ed281ed 100644 --- a/scipy-stubs/optimize/minpack2.pyi +++ b/scipy-stubs/optimize/minpack2.pyi @@ -1,4 +1,3 @@ -from scipy._typing import Untyped +# This file is not meant for public use and will be removed in SciPy v2.0.0. -def __dir__() -> Untyped: ... -def __getattr__(name) -> Untyped: ... +__all__: list[str] = [] diff --git a/scipy-stubs/optimize/moduleTNC.pyi b/scipy-stubs/optimize/moduleTNC.pyi index bc0eb39c..9ed281ed 100644 --- a/scipy-stubs/optimize/moduleTNC.pyi +++ b/scipy-stubs/optimize/moduleTNC.pyi @@ -1,4 +1,3 @@ -from scipy._typing import Untyped +# This file is not meant for public use and will be removed in SciPy v2.0.0. -def __dir__() -> Untyped: ... -def __getattr__(name) -> Untyped: ... +__all__: list[str] = [] diff --git a/scipy-stubs/optimize/nonlin.pyi b/scipy-stubs/optimize/nonlin.pyi index bc0eb39c..fbaa8f3a 100644 --- a/scipy-stubs/optimize/nonlin.pyi +++ b/scipy-stubs/optimize/nonlin.pyi @@ -1,4 +1,16 @@ -from scipy._typing import Untyped +# This file is not meant for public use and will be removed in SciPy v2.0.0. -def __dir__() -> Untyped: ... -def __getattr__(name) -> Untyped: ... +from ._nonlin import * + +__all__ = [ + "BroydenFirst", + "InverseJacobian", + "KrylovJacobian", + "anderson", + "broyden1", + "broyden2", + "diagbroyden", + "excitingmixing", + "linearmixing", + "newton_krylov", +] diff --git a/scipy-stubs/optimize/optimize.pyi b/scipy-stubs/optimize/optimize.pyi index bc0eb39c..783978d9 100644 --- a/scipy-stubs/optimize/optimize.pyi +++ b/scipy-stubs/optimize/optimize.pyi @@ -1,4 +1,28 @@ -from scipy._typing import Untyped +# This file is not meant for public use and will be removed in SciPy v2.0.0. -def __dir__() -> Untyped: ... -def __getattr__(name) -> Untyped: ... +from numpy import zeros # noqa: ICN003 +from ._optimize import * + +__all__ = [ + "OptimizeResult", + "OptimizeWarning", + "approx_fprime", + "bracket", + "brent", + "brute", + "check_grad", + "fmin", + "fmin_bfgs", + "fmin_cg", + "fmin_ncg", + "fmin_powell", + "fminbound", + "golden", + "line_search", + "rosen", + "rosen_der", + "rosen_hess", + "rosen_hess_prod", + "show_options", + "zeros", +] diff --git a/scipy-stubs/optimize/slsqp.pyi b/scipy-stubs/optimize/slsqp.pyi index bc0eb39c..5dd368c8 100644 --- a/scipy-stubs/optimize/slsqp.pyi +++ b/scipy-stubs/optimize/slsqp.pyi @@ -1,4 +1,7 @@ -from scipy._typing import Untyped +# This file is not meant for public use and will be removed in SciPy v2.0.0. -def __dir__() -> Untyped: ... -def __getattr__(name) -> Untyped: ... +from numpy import zeros # noqa: ICN003 +from ._optimize import OptimizeResult +from ._slsqp_py import fmin_slsqp, slsqp + +__all__ = ["OptimizeResult", "fmin_slsqp", "slsqp", "zeros"] diff --git a/scipy-stubs/optimize/tnc.pyi b/scipy-stubs/optimize/tnc.pyi index bc0eb39c..d73f5149 100644 --- a/scipy-stubs/optimize/tnc.pyi +++ b/scipy-stubs/optimize/tnc.pyi @@ -1,4 +1,7 @@ -from scipy._typing import Untyped +# This file is not meant for public use and will be removed in SciPy v2.0.0. -def __dir__() -> Untyped: ... -def __getattr__(name) -> Untyped: ... +from numpy import zeros # noqa: ICN003 +from ._optimize import OptimizeResult +from ._tnc import fmin_tnc + +__all__ = ["OptimizeResult", "fmin_tnc", "zeros"] diff --git a/scipy-stubs/optimize/zeros.pyi b/scipy-stubs/optimize/zeros.pyi index bc0eb39c..cf716b4a 100644 --- a/scipy-stubs/optimize/zeros.pyi +++ b/scipy-stubs/optimize/zeros.pyi @@ -1,4 +1,5 @@ -from scipy._typing import Untyped +# This file is not meant for public use and will be removed in SciPy v2.0.0. -def __dir__() -> Untyped: ... -def __getattr__(name) -> Untyped: ... +from ._zeros_py import * + +__all__ = ["RootResults", "bisect", "brenth", "brentq", "newton", "ridder", "toms748"] diff --git a/tests/stubtest/allowlist.txt b/tests/stubtest/allowlist.txt index 139a7da5..eeb54540 100644 --- a/tests/stubtest/allowlist.txt +++ b/tests/stubtest/allowlist.txt @@ -1,6 +1,7 @@ # typecheck-only helper types scipy._typing scipy.integrate._typing +scipy.optimize._typing # internal testing scipy._lib.test From 1f61d8c14f94033c5379aa6a5090ad8a63149340 Mon Sep 17 00:00:00 2001 From: jorenham Date: Mon, 9 Sep 2024 17:17:07 +0200 Subject: [PATCH 06/11] fix `scipy.sparse.linalg.LinearOperator` stubtest errors --- scipy-stubs/sparse/linalg/_interface.pyi | 47 +++++++++++++----------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/scipy-stubs/sparse/linalg/_interface.pyi b/scipy-stubs/sparse/linalg/_interface.pyi index 920e33f5..5ba83c82 100644 --- a/scipy-stubs/sparse/linalg/_interface.pyi +++ b/scipy-stubs/sparse/linalg/_interface.pyi @@ -1,11 +1,14 @@ +# pyright: reportInconsistentConstructor=false + from collections.abc import Sequence -from typing import ClassVar, Final, Literal +from typing import ClassVar, Literal +from typing_extensions import Self import numpy as np import numpy.typing as npt import optype.numpy as onpt import scipy._typing as spt -from scipy._typing import Untyped, UntypedArray +from scipy._typing import Untyped, UntypedArray, UntypedTuple __all__ = ["LinearOperator", "aslinearoperator"] @@ -15,17 +18,18 @@ class LinearOperator: shape: tuple[int] | tuple[int, int] ndim: Literal[1, 2] - @property - def dtype(self) -> np.dtype[np.generic]: ... - def __init__(self, dtype: npt.DTypeLike, shape: spt.AnyInt | Sequence[spt.AnyInt]) -> None: ... - def matvec(self, x: npt.ArrayLike, /) -> UntypedArray: ... - def rmatvec(self, x: npt.ArrayLike, /) -> UntypedArray: ... - def matmat(self, X: npt.ArrayLike, /) -> UntypedArray: ... - def rmatmat(self, X: npt.ArrayLike, /) -> UntypedArray: ... - def __call__(self, x: npt.ArrayLike | LinearOperator, /) -> _ProductLinearOperator | _ScaledLinearOperator | UntypedArray: ... + dtype: np.dtype[np.generic] + + def __new__(cls, *args: Untyped, **kwargs: Untyped) -> Self: ... + def __init__(self, /, dtype: npt.DTypeLike, shape: spt.AnyInt | Sequence[spt.AnyInt]) -> None: ... + def matvec(self, /, x: npt.ArrayLike) -> UntypedArray: ... + def rmatvec(self, /, x: npt.ArrayLike) -> UntypedArray: ... + def matmat(self, /, X: npt.ArrayLike) -> UntypedArray: ... + def rmatmat(self, /, X: npt.ArrayLike) -> UntypedArray: ... + def __call__(self, /, x: npt.ArrayLike | LinearOperator) -> _ProductLinearOperator | _ScaledLinearOperator | UntypedArray: ... def __mul__(self, x: LinearOperator | npt.ArrayLike, /) -> _ProductLinearOperator | _ScaledLinearOperator | UntypedArray: ... def __truediv__(self, other: spt.AnyScalar, /) -> _ScaledLinearOperator: ... - def dot(self, x: LinearOperator | npt.ArrayLike, /) -> _ProductLinearOperator | _ScaledLinearOperator | UntypedArray: ... + def dot(self, /, x: LinearOperator | npt.ArrayLike) -> _ProductLinearOperator | _ScaledLinearOperator | UntypedArray: ... def __matmul__( self, other: LinearOperator | onpt.CanArray[tuple[int, ...], np.dtype[np.generic]], @@ -41,24 +45,25 @@ class LinearOperator: def __add__(self, x: LinearOperator, /) -> _SumLinearOperator: ... def __neg__(self, /) -> _ScaledLinearOperator: ... def __sub__(self, x: LinearOperator, /) -> _SumLinearOperator: ... - def adjoint(self) -> _AdjointLinearOperator: ... + def adjoint(self, /) -> _AdjointLinearOperator: ... @property - def H(self) -> _AdjointLinearOperator: ... - def transpose(self) -> _TransposedLinearOperator: ... + def H(self, /) -> _AdjointLinearOperator: ... + def transpose(self, /) -> _TransposedLinearOperator: ... @property def T(self) -> _TransposedLinearOperator: ... class _CustomLinearOperator(LinearOperator): - args: Untyped + args: UntypedTuple def __init__( self, - shape, - matvec, + /, + shape: Untyped, + matvec: Untyped, rmatvec: Untyped | None = None, matmat: Untyped | None = None, dtype: Untyped | None = None, rmatmat: Untyped | None = None, - ): ... + ) -> None: ... class _AdjointLinearOperator(LinearOperator): A: LinearOperator @@ -94,10 +99,10 @@ class MatrixLinearOperator(LinearOperator): class _AdjointMatrixOperator(MatrixLinearOperator): A: LinearOperator args: tuple[LinearOperator] - shape: tuple[int, int] + shape: tuple[int, int] # pyright: ignore[reportIncompatibleVariableOverride] def __init__(self, adjoint: LinearOperator) -> None: ... class IdentityOperator(LinearOperator): - def __init__(self, shape, dtype: Untyped | None = None): ... + def __init__(self, shape: Untyped, dtype: Untyped | None = None) -> None: ... -def aslinearoperator(A) -> Untyped: ... +def aslinearoperator(A: Untyped) -> Untyped: ... From 701bb3f29702099aa428e526a6272babe554907f Mon Sep 17 00:00:00 2001 From: jorenham Date: Tue, 10 Sep 2024 02:37:36 +0200 Subject: [PATCH 07/11] fix & improve `scipy.optimize` --- scipy-stubs/optimize/_constraints.pyi | 40 +- scipy-stubs/optimize/_elementwise.pyi | 31 - scipy-stubs/optimize/_group_columns.pyi | 9 +- scipy-stubs/optimize/_highs/__init__.pyi | 0 .../optimize/_highs/cython/__init__.pyi | 0 .../optimize/_highs/cython/src/__init__.pyi | 0 scipy-stubs/optimize/_lbfgsb_py.pyi | 4 +- scipy-stubs/optimize/_linesearch.pyi | 1 - scipy-stubs/optimize/_linprog.pyi | 45 +- scipy-stubs/optimize/_linprog_highs.pyi | 1 + scipy-stubs/optimize/_linprog_ip.pyi | 3 - scipy-stubs/optimize/_linprog_rs.pyi | 1 + scipy-stubs/optimize/_linprog_simplex.pyi | 2 +- scipy-stubs/optimize/_linprog_util.pyi | 15 +- scipy-stubs/optimize/_lsap.pyi | 3 - .../optimize/_lsq/givens_elimination.pyi | 14 + scipy-stubs/optimize/_lsq/least_squares.pyi | 57 +- scipy-stubs/optimize/_minimize.pyi | 18 +- scipy-stubs/optimize/_nonlin.pyi | 122 ++-- scipy-stubs/optimize/_numdiff.pyi | 24 +- scipy-stubs/optimize/_optimize.pyi | 558 ++++++++++++------ scipy-stubs/optimize/_remove_redundancy.pyi | 2 - scipy-stubs/optimize/_trlib/_trlib.pyi | 10 +- .../optimize/_trustregion_constr/__init__.pyi | 3 + .../minimize_trustregion_constr.pyi | 86 +-- .../_trustregion_constr/projections.pyi | 26 +- .../_trustregion_constr/tr_interior_point.pyi | 122 ++-- scipy-stubs/optimize/_trustregion_exact.pyi | 29 +- scipy-stubs/optimize/_trustregion_krylov.pyi | 15 +- scipy-stubs/optimize/_typing.pyi | 147 +++-- .../optimize/cython_optimize/__init__.pyi | 1 + scipy-stubs/optimize/minpack.pyi | 2 +- scipy-stubs/optimize/nonlin.pyi | 13 +- 33 files changed, 903 insertions(+), 501 deletions(-) delete mode 100644 scipy-stubs/optimize/_elementwise.pyi delete mode 100644 scipy-stubs/optimize/_highs/__init__.pyi delete mode 100644 scipy-stubs/optimize/_highs/cython/__init__.pyi delete mode 100644 scipy-stubs/optimize/_highs/cython/src/__init__.pyi create mode 100644 scipy-stubs/optimize/_lsq/givens_elimination.pyi diff --git a/scipy-stubs/optimize/_constraints.pyi b/scipy-stubs/optimize/_constraints.pyi index b512530e..37560726 100644 --- a/scipy-stubs/optimize/_constraints.pyi +++ b/scipy-stubs/optimize/_constraints.pyi @@ -11,40 +11,48 @@ class NonlinearConstraint: keep_feasible: Untyped def __init__( self, - fun, - lb, - ub, + /, + fun: UntypedCallable, + lb: Untyped, + ub: Untyped, jac: str = "2-point", - hess: Untyped | None = None, + hess: Untyped = ..., keep_feasible: bool = False, finite_diff_rel_step: Untyped | None = None, finite_diff_jac_sparsity: Untyped | None = None, - ): ... + ) -> None: ... class LinearConstraint: A: Untyped lb: Untyped ub: Untyped keep_feasible: Untyped - def __init__(self, A, lb=..., ub=..., keep_feasible: bool = False): ... - def residual(self, x) -> Untyped: ... + def __init__(self, /, A: Untyped, lb: Untyped = ..., ub: Untyped = ..., keep_feasible: bool = False) -> None: ... + def residual(self, /, x: Untyped) -> Untyped: ... class Bounds: lb: Untyped ub: Untyped keep_feasible: Untyped - def __init__(self, lb=..., ub=..., keep_feasible: bool = False): ... - def residual(self, x) -> Untyped: ... + def __init__(self, /, lb: Untyped = ..., ub: Untyped = ..., keep_feasible: bool = False) -> None: ... + def residual(self, /, x: Untyped) -> Untyped: ... class PreparedConstraint: fun: Untyped bounds: Untyped keep_feasible: Untyped - def __init__(self, constraint, x0, sparse_jacobian: Untyped | None = None, finite_diff_bounds=...): ... - def violation(self, x) -> Untyped: ... + def __init__( + self, + /, + constraint: Untyped, + x0: Untyped, + sparse_jacobian: Untyped | None = None, + finite_diff_bounds: Untyped = ..., + ) -> None: ... + def violation(self, x: Untyped) -> Untyped: ... -def new_bounds_to_old(lb, ub, n) -> Untyped: ... -def old_bound_to_new(bounds) -> Untyped: ... -def strict_bounds(lb, ub, keep_feasible, n_vars) -> Untyped: ... -def new_constraint_to_old(con, x0) -> Untyped: ... -def old_constraint_to_new(ic, con) -> Untyped: ... +def new_bounds_to_old(lb: Untyped, ub: Untyped, n: Untyped) -> Untyped: ... +def old_bound_to_new(bounds: Untyped) -> Untyped: ... +def strict_bounds(lb: Untyped, ub: Untyped, keep_feasible: Untyped, n_vars: Untyped) -> Untyped: ... +def new_constraint_to_old(con: Untyped, x0: Untyped) -> Untyped: ... +def old_constraint_to_new(ic: Untyped, con: Untyped) -> Untyped: ... diff --git a/scipy-stubs/optimize/_elementwise.pyi b/scipy-stubs/optimize/_elementwise.pyi deleted file mode 100644 index e253b2bd..00000000 --- a/scipy-stubs/optimize/_elementwise.pyi +++ /dev/null @@ -1,31 +0,0 @@ -from scipy._typing import Untyped - -def find_root( - f, init, /, *, args=(), tolerances: Untyped | None = None, maxiter: Untyped | None = None, callback: Untyped | None = None -) -> Untyped: ... -def find_minimum( - f, init, /, *, args=(), tolerances: Untyped | None = None, maxiter: int = 100, callback: Untyped | None = None -) -> Untyped: ... -def bracket_root( - f, - xl0, - xr0: Untyped | None = None, - *, - xmin: Untyped | None = None, - xmax: Untyped | None = None, - factor: Untyped | None = None, - args=(), - maxiter: int = 1000, -) -> Untyped: ... -def bracket_minimum( - f, - xm0, - *, - xl0: Untyped | None = None, - xr0: Untyped | None = None, - xmin: Untyped | None = None, - xmax: Untyped | None = None, - factor: Untyped | None = None, - args=(), - maxiter: int = 1000, -) -> Untyped: ... diff --git a/scipy-stubs/optimize/_group_columns.pyi b/scipy-stubs/optimize/_group_columns.pyi index e4792093..eeadaf31 100644 --- a/scipy-stubs/optimize/_group_columns.pyi +++ b/scipy-stubs/optimize/_group_columns.pyi @@ -1,4 +1,9 @@ +from typing import Final +from typing_extensions import LiteralString + from scipy._typing import Untyped -def group_dense(m, n, A) -> Untyped: ... -def group_sparse(m, n, indices, indptr) -> Untyped: ... +__pythran__: Final[tuple[LiteralString, LiteralString]] + +def group_dense(m: Untyped, n: Untyped, A: Untyped) -> Untyped: ... +def group_sparse(m: Untyped, n: Untyped, indices: Untyped, indptr: Untyped) -> Untyped: ... diff --git a/scipy-stubs/optimize/_highs/__init__.pyi b/scipy-stubs/optimize/_highs/__init__.pyi deleted file mode 100644 index e69de29b..00000000 diff --git a/scipy-stubs/optimize/_highs/cython/__init__.pyi b/scipy-stubs/optimize/_highs/cython/__init__.pyi deleted file mode 100644 index e69de29b..00000000 diff --git a/scipy-stubs/optimize/_highs/cython/src/__init__.pyi b/scipy-stubs/optimize/_highs/cython/src/__init__.pyi deleted file mode 100644 index e69de29b..00000000 diff --git a/scipy-stubs/optimize/_lbfgsb_py.pyi b/scipy-stubs/optimize/_lbfgsb_py.pyi index 81b7ca92..517b9878 100644 --- a/scipy-stubs/optimize/_lbfgsb_py.pyi +++ b/scipy-stubs/optimize/_lbfgsb_py.pyi @@ -1,7 +1,5 @@ from scipy._typing import Untyped -from scipy.sparse.linalg import LinearOperator as LinearOperator -from ._constraints import old_bound_to_new as old_bound_to_new -from ._optimize import MemoizeJac as MemoizeJac, OptimizeResult as OptimizeResult +from scipy.sparse.linalg import LinearOperator def fmin_l_bfgs_b( func, diff --git a/scipy-stubs/optimize/_linesearch.pyi b/scipy-stubs/optimize/_linesearch.pyi index 235e154b..f8733a0a 100644 --- a/scipy-stubs/optimize/_linesearch.pyi +++ b/scipy-stubs/optimize/_linesearch.pyi @@ -1,5 +1,4 @@ from scipy._typing import Untyped, UntypedCallable -from ._dcsrch import DCSRCH as DCSRCH __all__ = [ "LineSearchWarning", diff --git a/scipy-stubs/optimize/_linprog.pyi b/scipy-stubs/optimize/_linprog.pyi index 5fc5f371..704de86d 100644 --- a/scipy-stubs/optimize/_linprog.pyi +++ b/scipy-stubs/optimize/_linprog.pyi @@ -1,21 +1,30 @@ -from scipy._typing import Untyped -from ._optimize import OptimizeResult as OptimizeResult, OptimizeWarning as OptimizeWarning +from collections.abc import Callable, Mapping, Sequence +from typing import Final -__docformat__: str -LINPROG_METHODS: Untyped +import numpy.typing as npt +from ._optimize import OptimizeResult +from ._typing import Bound, MethodLinprog -def linprog_verbose_callback(res) -> Untyped: ... -def linprog_terse_callback(res): ... +__all__ = ["linprog", "linprog_terse_callback", "linprog_verbose_callback"] + +__docformat__: Final[str] = ... +LINPROG_METHODS: Final[Sequence[MethodLinprog]] = ... + +def linprog_verbose_callback(res: OptimizeResult) -> None: ... +def linprog_terse_callback(res: OptimizeResult) -> None: ... + +# TODO: Tighen these array-like types def linprog( - c, - A_ub: Untyped | None = None, - b_ub: Untyped | None = None, - A_eq: Untyped | None = None, - b_eq: Untyped | None = None, - bounds=(0, None), - method: str = "highs", - callback: Untyped | None = None, - options: Untyped | None = None, - x0: Untyped | None = None, - integrality: Untyped | None = None, -) -> Untyped: ... + c: npt.ArrayLike, + A_ub: npt.ArrayLike | None = None, + b_ub: npt.ArrayLike | None = None, + A_eq: npt.ArrayLike | None = None, + b_eq: npt.ArrayLike | None = None, + bounds: Bound = (0, None), + method: MethodLinprog = "highs", + callback: Callable[[OptimizeResult], None] | None = None, + # TODO: `TypedDict` + options: Mapping[str, object] | None = None, + x0: npt.ArrayLike | None = None, + integrality: npt.ArrayLike | None = None, +) -> OptimizeResult: ... diff --git a/scipy-stubs/optimize/_linprog_highs.pyi b/scipy-stubs/optimize/_linprog_highs.pyi index e69de29b..f93c5705 100644 --- a/scipy-stubs/optimize/_linprog_highs.pyi +++ b/scipy-stubs/optimize/_linprog_highs.pyi @@ -0,0 +1 @@ +# nothing to see here diff --git a/scipy-stubs/optimize/_linprog_ip.pyi b/scipy-stubs/optimize/_linprog_ip.pyi index 25e77744..42f5125c 100644 --- a/scipy-stubs/optimize/_linprog_ip.pyi +++ b/scipy-stubs/optimize/_linprog_ip.pyi @@ -1,5 +1,2 @@ -from scipy.linalg import LinAlgError as LinAlgError -from ._optimize import OptimizeResult as OptimizeResult, OptimizeWarning as OptimizeWarning - has_umfpack: bool has_cholmod: bool diff --git a/scipy-stubs/optimize/_linprog_rs.pyi b/scipy-stubs/optimize/_linprog_rs.pyi index e69de29b..f93c5705 100644 --- a/scipy-stubs/optimize/_linprog_rs.pyi +++ b/scipy-stubs/optimize/_linprog_rs.pyi @@ -0,0 +1 @@ +# nothing to see here diff --git a/scipy-stubs/optimize/_linprog_simplex.pyi b/scipy-stubs/optimize/_linprog_simplex.pyi index 7f381c54..f93c5705 100644 --- a/scipy-stubs/optimize/_linprog_simplex.pyi +++ b/scipy-stubs/optimize/_linprog_simplex.pyi @@ -1 +1 @@ -from ._optimize import OptimizeResult as OptimizeResult, OptimizeWarning as OptimizeWarning +# nothing to see here diff --git a/scipy-stubs/optimize/_linprog_util.pyi b/scipy-stubs/optimize/_linprog_util.pyi index a31feb29..f93c5705 100644 --- a/scipy-stubs/optimize/_linprog_util.pyi +++ b/scipy-stubs/optimize/_linprog_util.pyi @@ -1,14 +1 @@ -from typing import NamedTuple - -from scipy._typing import Untyped -from ._optimize import OptimizeWarning as OptimizeWarning - -class _LPProblem(NamedTuple): - c: Untyped - A_ub: Untyped - b_ub: Untyped - A_eq: Untyped - b_eq: Untyped - bounds: Untyped - x0: Untyped - integrality: Untyped +# nothing to see here diff --git a/scipy-stubs/optimize/_lsap.pyi b/scipy-stubs/optimize/_lsap.pyi index 0c80dbfa..5cc33f4d 100644 --- a/scipy-stubs/optimize/_lsap.pyi +++ b/scipy-stubs/optimize/_lsap.pyi @@ -1,6 +1,3 @@ -# TODO from scipy._typing import Untyped -__all__ = ["linear_sum_assignment"] - def linear_sum_assignment(*args: Untyped, **kwargs: Untyped) -> Untyped: ... diff --git a/scipy-stubs/optimize/_lsq/givens_elimination.pyi b/scipy-stubs/optimize/_lsq/givens_elimination.pyi new file mode 100644 index 00000000..93580bac --- /dev/null +++ b/scipy-stubs/optimize/_lsq/givens_elimination.pyi @@ -0,0 +1,14 @@ +from collections.abc import Mapping +from typing import Final +from typing_extensions import Never + +import numpy as np +import optype.numpy as onpt + +__test__: Final[Mapping[Never, Never]] + +def givens_elimination( + S: onpt.Array[tuple[int, int], np.float64], + v: onpt.Array[tuple[int], np.float64], + diag: onpt.Array[tuple[int], np.float64], +) -> None: ... diff --git a/scipy-stubs/optimize/_lsq/least_squares.pyi b/scipy-stubs/optimize/_lsq/least_squares.pyi index f60f4642..95a786b0 100644 --- a/scipy-stubs/optimize/_lsq/least_squares.pyi +++ b/scipy-stubs/optimize/_lsq/least_squares.pyi @@ -1,25 +1,38 @@ -from scipy._typing import Untyped +from collections.abc import Callable +from typing import Final, Literal + +from scipy._typing import Untyped, UntypedCallable from scipy.optimize import OptimizeResult -TERMINATION_MESSAGES: Untyped -FROM_MINPACK_TO_COMMON: Untyped -IMPLEMENTED_LOSSES: Untyped +TERMINATION_MESSAGES: Final[dict[Literal[-1, 0, 1, 2, 3, 4], str]] +FROM_MINPACK_TO_COMMON: Final[dict[Literal[0, 1, 2, 3, 4, 5], Literal[-1, 2, 3, 4, 1, 0]]] +IMPLEMENTED_LOSSES: Final[dict[str, Callable[[Untyped, Untyped, bool], None] | None]] -def call_minpack(fun, x0, jac, ftol, xtol, gtol, max_nfev, x_scale, diff_step) -> Untyped: ... -def prepare_bounds(bounds, n) -> Untyped: ... -def check_tolerance(ftol, xtol, gtol, method) -> Untyped: ... -def check_x_scale(x_scale, x0) -> Untyped: ... -def check_jac_sparsity(jac_sparsity, m, n) -> Untyped: ... -def huber(z, rho, cost_only): ... -def soft_l1(z, rho, cost_only): ... -def cauchy(z, rho, cost_only): ... -def arctan(z, rho, cost_only): ... -def construct_loss_function(m, loss, f_scale) -> Untyped: ... +def call_minpack( + fun: UntypedCallable, + x0: Untyped, + jac: Untyped, + ftol: float, + xtol: float, + gtol: float, + max_nfev: int, + x_scale: Untyped, + diff_step: Untyped, +) -> Untyped: ... +def prepare_bounds(bounds: Untyped, n: Untyped) -> Untyped: ... +def check_tolerance(ftol: float, xtol: float, gtol: float, method: Untyped) -> Untyped: ... +def check_x_scale(x_scale: Untyped, x0: Untyped) -> Untyped: ... +def check_jac_sparsity(jac_sparsity: Untyped, m: Untyped, n: Untyped) -> Untyped: ... +def huber(z: Untyped, rho: Untyped, cost_only: bool) -> None: ... +def soft_l1(z: Untyped, rho: Untyped, cost_only: bool) -> None: ... +def cauchy(z: Untyped, rho: Untyped, cost_only: bool) -> None: ... +def arctan(z: Untyped, rho: Untyped, cost_only: bool) -> None: ... +def construct_loss_function(m: Untyped, loss: Untyped, f_scale: Untyped) -> Untyped: ... def least_squares( - fun, - x0, + fun: UntypedCallable, + x0: Untyped, jac: str = "2-point", - bounds=..., + bounds: tuple[float, float] = ..., method: str = "trf", ftol: float = 1e-08, xtol: float = 1e-08, @@ -29,10 +42,10 @@ def least_squares( f_scale: float = 1.0, diff_step: Untyped | None = None, tr_solver: Untyped | None = None, - tr_options: Untyped | None = None, + tr_options: dict[str, object] = ..., jac_sparsity: Untyped | None = None, - max_nfev: Untyped | None = None, - verbose: int = 0, - args=(), - kwargs: Untyped | None = None, + max_nfev: int | None = None, + verbose: Literal[False, 0, True, 1] = 0, + args: tuple[object, ...] = (), + kwargs: dict[str, object] = ..., ) -> OptimizeResult: ... diff --git a/scipy-stubs/optimize/_minimize.pyi b/scipy-stubs/optimize/_minimize.pyi index df7dac75..2a988fe3 100644 --- a/scipy-stubs/optimize/_minimize.pyi +++ b/scipy-stubs/optimize/_minimize.pyi @@ -7,7 +7,7 @@ from scipy._typing import Untyped from ._constraints import Bounds from ._hessian_update_strategy import HessianUpdateStrategy from ._optimize import OptimizeResult -from ._typing import Constraint, GradMethod, MimimizeMethod, MinimizeScalarMethod +from ._typing import Constraint, MethodJac, MethodMimimize, MethodMinimizeScalar __all__ = ["minimize", "minimize_scalar"] @@ -27,18 +27,18 @@ class _MinimizeCallbackXk(Protocol): ### -MINIMIZE_METHODS: Final[Sequence[MimimizeMethod]] = ... -MINIMIZE_METHODS_NEW_CB: Final[Sequence[MimimizeMethod]] = ... -MINIMIZE_SCALAR_METHODS: Final[Sequence[MinimizeScalarMethod]] = ... +MINIMIZE_METHODS: Final[Sequence[MethodMimimize]] = ... +MINIMIZE_METHODS_NEW_CB: Final[Sequence[MethodMimimize]] = ... +MINIMIZE_SCALAR_METHODS: Final[Sequence[MethodMinimizeScalar]] = ... def minimize( fun: Callable[Concatenate[_Array_f_1d, ...], float | np.floating[Any]], x0: _ArrayLike_f_1d, args: tuple[object, ...] = (), - method: MimimizeMethod | Callable[..., OptimizeResult] | None = None, - jac: GradMethod | Callable[Concatenate[float, ...], _ArrayLike_f_1d] | None = None, + method: MethodMimimize | Callable[..., OptimizeResult] | None = None, + jac: MethodJac | Callable[Concatenate[float, ...], _ArrayLike_f_1d] | None = None, # TODO: also allow the callable to return a `LinearOperator` or a sparse matrix - hess: GradMethod | HessianUpdateStrategy | Callable[Concatenate[float, ...], _ArrayLike_f_2d] | None = None, + hess: MethodJac | HessianUpdateStrategy | Callable[Concatenate[float, ...], _ArrayLike_f_2d] | None = None, hessp: Callable[Concatenate[_Array_f_1d, _Array_f_1d, ...], _ArrayLike_f_1d] | None = None, bounds: Sequence[_Bound] | Bounds | None = None, constraints: Constraint | Sequence[Constraint] = (), @@ -52,14 +52,14 @@ def minimize_scalar( bracket: Sequence[tuple[float, float] | tuple[float, float, float]] | None = None, bounds: Sequence[_Bound] | None = None, args: tuple[object, ...] = (), - method: MinimizeScalarMethod | Callable[..., OptimizeResult] | None = None, + method: MethodMinimizeScalar | Callable[..., OptimizeResult] | None = None, tol: float | None = None, options: Mapping[str, object] | None = None, ) -> Untyped: ... def standardize_bounds( # undocumented bounds: Sequence[_Bound] | Bounds, x0: _ArrayLike_f_1d, - meth: MimimizeMethod, + meth: MethodMimimize, ) -> Bounds | list[_Bound]: ... def standardize_constraints( # undocumented constraints: Constraint | Sequence[Constraint], diff --git a/scipy-stubs/optimize/_nonlin.pyi b/scipy-stubs/optimize/_nonlin.pyi index 1473a39c..ddd4d969 100644 --- a/scipy-stubs/optimize/_nonlin.pyi +++ b/scipy-stubs/optimize/_nonlin.pyi @@ -1,6 +1,7 @@ from typing_extensions import override -from scipy._typing import Untyped +import numpy as np +from scipy._typing import Untyped, UntypedCallable __all__ = [ "BroydenFirst", @@ -18,10 +19,10 @@ __all__ = [ class NoConvergence(Exception): ... -def maxnorm(x) -> Untyped: ... +def maxnorm(x: Untyped) -> Untyped: ... def nonlin_solve( - F, - x0, + F: Untyped, + x0: Untyped, jacobian: str = "krylov", iter: Untyped | None = None, verbose: bool = False, @@ -53,40 +54,42 @@ class TerminationCondition: x_tol: Untyped | None = None, x_rtol: Untyped | None = None, iter: Untyped | None = None, - norm=..., + norm: Untyped = ..., ) -> None: ... - def check(self, f, x, dx) -> Untyped: ... + def check(self, f: Untyped, x: Untyped, dx: Untyped) -> Untyped: ... class Jacobian: func: Untyped - @property - def shape(self) -> Untyped: ... - @property - def dtype(self) -> Untyped: ... - def __init__(self, **kw) -> None: ... + shape: tuple[int, ...] + dtype: np.dtype[np.generic] + def __init__(self, **kw: Untyped) -> None: ... def aspreconditioner(self) -> Untyped: ... - def solve(self, v, /, tol: float = 0) -> Untyped: ... - def update(self, x, F) -> None: ... - def setup(self, x, F, func) -> None: ... + def solve(self, v: Untyped, tol: float = 0) -> Untyped: ... + def update(self, x: Untyped, F: Untyped) -> None: ... + def setup(self, x: Untyped, F: Untyped, func: Untyped) -> None: ... class InverseJacobian: jacobian: Untyped - matvec: Untyped - update: Untyped - setup: Untyped - rmatvec: Untyped - def __init__(self, jacobian) -> None: ... + matvec: UntypedCallable + rmatvec: UntypedCallable + update: UntypedCallable + setup: UntypedCallable + def __init__(self, jacobian: Untyped) -> None: ... @property - def shape(self) -> Untyped: ... + def shape(self) -> tuple[int, ...]: ... @property - def dtype(self) -> Untyped: ... + def dtype(self) -> np.dtype[np.generic]: ... -def asjacobian(J) -> Untyped: ... +def asjacobian(J: Untyped) -> Untyped: ... class GenericBroyden(Jacobian): last_f: Untyped last_x: Untyped alpha: Untyped + @override + def update(self, x0: Untyped, f0: Untyped) -> None: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] + @override + def setup(self, x0: Untyped, f0: Untyped, func: Untyped) -> None: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] class LowRankMatrix: alpha: Untyped @@ -95,29 +98,34 @@ class LowRankMatrix: n: Untyped dtype: Untyped collapsed: Untyped - def __init__(self, alpha, n, dtype) -> None: ... - def matvec(self, v) -> Untyped: ... - def rmatvec(self, v) -> Untyped: ... - def solve(self, v, tol: float = 0) -> Untyped: ... - def rsolve(self, v, tol: float = 0) -> Untyped: ... - def append(self, c, d): ... + def __init__(self, alpha: Untyped, n: Untyped, dtype: Untyped) -> None: ... + def matvec(self, v: Untyped) -> Untyped: ... + def rmatvec(self, v: Untyped) -> Untyped: ... + def solve(self, v: Untyped, tol: float = 0) -> Untyped: ... + def rsolve(self, v: Untyped, tol: float = 0) -> Untyped: ... + def append(self, c: Untyped, d: Untyped) -> None: ... def __array__(self, dtype: Untyped | None = None, copy: Untyped | None = None) -> Untyped: ... - def collapse(self): ... - def restart_reduce(self, rank): ... - def simple_reduce(self, rank): ... - def svd_reduce(self, max_rank, to_retain: Untyped | None = None): ... + def collapse(self) -> None: ... + def restart_reduce(self, rank: Untyped) -> None: ... + def simple_reduce(self, rank: Untyped) -> None: ... + def svd_reduce(self, max_rank: Untyped, to_retain: Untyped | None = None) -> None: ... class BroydenFirst(GenericBroyden): alpha: Untyped Gm: Untyped max_rank: Untyped - def __init__(self, alpha: Untyped | None = None, reduction_method: str = "restart", max_rank: Untyped | None = None): ... + def __init__( + self, + alpha: Untyped | None = None, + reduction_method: str = "restart", + max_rank: Untyped | None = None, + ) -> None: ... def todense(self) -> Untyped: ... @override - def solve(self, f, /, tol: float = 0) -> Untyped: ... - def matvec(self, f) -> Untyped: ... - def rsolve(self, f, tol: float = 0) -> Untyped: ... - def rmatvec(self, f) -> Untyped: ... + def solve(self, f: Untyped, tol: float = 0) -> Untyped: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] + def matvec(self, f: Untyped) -> Untyped: ... + def rsolve(self, f: Untyped, tol: float = 0) -> Untyped: ... + def rmatvec(self, f: Untyped) -> Untyped: ... class BroydenSecond(BroydenFirst): ... @@ -128,30 +136,30 @@ class Anderson(GenericBroyden): df: Untyped gamma: Untyped w0: Untyped - def __init__(self, alpha: Untyped | None = None, w0: float = 0.01, M: int = 5): ... + def __init__(self, alpha: Untyped | None = None, w0: float = 0.01, M: int = 5) -> None: ... @override - def solve(self, f, tol: float = 0) -> Untyped: ... - def matvec(self, f) -> Untyped: ... + def solve(self, f: Untyped, tol: float = 0) -> Untyped: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] + def matvec(self, f: Untyped) -> Untyped: ... class DiagBroyden(GenericBroyden): alpha: Untyped d: Untyped def __init__(self, alpha: Untyped | None = None) -> None: ... @override - def solve(self, f, /, tol: float = 0) -> Untyped: ... - def matvec(self, f) -> Untyped: ... - def rsolve(self, f, tol: float = 0) -> Untyped: ... - def rmatvec(self, f) -> Untyped: ... + def solve(self, f: Untyped, tol: float = 0) -> Untyped: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] + def matvec(self, f: Untyped) -> Untyped: ... + def rsolve(self, f: Untyped, tol: float = 0) -> Untyped: ... + def rmatvec(self, f: Untyped) -> Untyped: ... def todense(self) -> Untyped: ... class LinearMixing(GenericBroyden): alpha: Untyped def __init__(self, alpha: Untyped | None = None) -> None: ... @override - def solve(self, f, /, tol: float = 0) -> Untyped: ... - def matvec(self, f) -> Untyped: ... - def rsolve(self, f, tol: float = 0) -> Untyped: ... - def rmatvec(self, f) -> Untyped: ... + def solve(self, f: Untyped, tol: float = 0) -> Untyped: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] + def matvec(self, f: Untyped) -> Untyped: ... + def rsolve(self, f: Untyped, tol: float = 0) -> Untyped: ... + def rmatvec(self, f: Untyped) -> Untyped: ... def todense(self) -> Untyped: ... class ExcitingMixing(GenericBroyden): @@ -160,10 +168,10 @@ class ExcitingMixing(GenericBroyden): beta: Untyped def __init__(self, alpha: Untyped | None = None, alphamax: float = 1.0) -> None: ... @override - def solve(self, f, /, tol: float = 0) -> Untyped: ... - def matvec(self, f) -> Untyped: ... - def rsolve(self, f, tol: float = 0) -> Untyped: ... - def rmatvec(self, f) -> Untyped: ... + def solve(self, f: Untyped, tol: float = 0) -> Untyped: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] + def matvec(self, f: Untyped) -> Untyped: ... + def rsolve(self, f: Untyped, tol: float = 0) -> Untyped: ... + def rmatvec(self, f: Untyped) -> Untyped: ... def todense(self) -> Untyped: ... class KrylovJacobian(Jacobian): @@ -181,11 +189,15 @@ class KrylovJacobian(Jacobian): inner_maxiter: int = 20, inner_M: Untyped | None = None, outer_k: int = 10, - **kw, + **kw: Untyped, ) -> None: ... - def matvec(self, v) -> Untyped: ... + def matvec(self, v: Untyped) -> Untyped: ... + @override + def solve(self, rhs: Untyped, tol: float = 0) -> Untyped: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] + @override + def update(self, x: Untyped, f: Untyped) -> None: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] @override - def solve(self, rhs, /, tol: float = 0) -> Untyped: ... + def setup(self, x: Untyped, f: Untyped, func: Untyped) -> None: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] broyden1: Untyped broyden2: Untyped diff --git a/scipy-stubs/optimize/_numdiff.pyi b/scipy-stubs/optimize/_numdiff.pyi index 7d5ce02f..52094e46 100644 --- a/scipy-stubs/optimize/_numdiff.pyi +++ b/scipy-stubs/optimize/_numdiff.pyi @@ -1,18 +1,24 @@ -from scipy._typing import Untyped -from ._group_columns import group_dense as group_dense, group_sparse as group_sparse +from scipy._typing import Untyped, UntypedCallable, UntypedTuple -def group_columns(A, order: int = 0) -> Untyped: ... +def group_columns(A: Untyped, order: int = 0) -> Untyped: ... def approx_derivative( - fun, - x0, + fun: UntypedCallable, + x0: Untyped, method: str = "3-point", rel_step: Untyped | None = None, abs_step: Untyped | None = None, f0: Untyped | None = None, - bounds=..., + bounds: Untyped = ..., sparsity: Untyped | None = None, as_linear_operator: bool = False, - args=(), - kwargs: Untyped | None = None, + args: UntypedTuple = (), + kwargs: Untyped = ..., +) -> Untyped: ... +def check_derivative( + fun: UntypedCallable, + jac: UntypedCallable, + x0: Untyped, + bounds: Untyped = ..., + args: UntypedTuple = (), + kwargs: Untyped = ..., ) -> Untyped: ... -def check_derivative(fun, jac, x0, bounds=..., args=(), kwargs: Untyped | None = None) -> Untyped: ... diff --git a/scipy-stubs/optimize/_optimize.pyi b/scipy-stubs/optimize/_optimize.pyi index 347eac98..fe78a005 100644 --- a/scipy-stubs/optimize/_optimize.pyi +++ b/scipy-stubs/optimize/_optimize.pyi @@ -1,10 +1,15 @@ -from typing import Any, Final, Literal +from collections.abc import Callable +from typing import Any, Final, Generic, Literal, TypeAlias, overload +from typing_extensions import TypeVar, TypeVarTuple, Unpack import numpy as np import optype.numpy as onpt +from numpy._typing import _ArrayLikeFloat_co +import scipy._typing as spt from scipy._lib._util import _RichResult -from scipy._typing import Untyped, UntypedCallable, UntypedTuple +from scipy._typing import Untyped, UntypedCallable from ._linesearch import line_search_wolfe2 as line_search +from ._typing import Brack, MethodAll, ObjectiveFunc, Solver __all__ = [ "OptimizeResult", @@ -29,202 +34,423 @@ __all__ = [ "show_options", ] -class _LineSearchError(RuntimeError): ... -class _MaxFuncCallError(RuntimeError): ... -class BracketError(RuntimeError): ... -class OptimizeWarning(UserWarning): ... +_Ts = TypeVarTuple("_Ts", default=Unpack[tuple[object, ...]]) +_SCT_f = TypeVar("_SCT_f", bound=np.floating[Any], default=np.float32 | np.float64) + +_Float_co: TypeAlias = float | np.floating[Any] | np.integer[Any] +_FloatND_co: TypeAlias = onpt.Array[tuple[int, ...], np.floating[Any] | np.integer[Any]] + +_Float: TypeAlias = float | np.float64 +_Float0D: TypeAlias = _Float | onpt.Array[tuple[()], np.float64] +_Float1D: TypeAlias = onpt.Array[tuple[int], np.float64] +_Float2D: TypeAlias = onpt.Array[tuple[int, int], np.float64] + +# undocumented + +def is_finite_scalar(x: complex | np.generic) -> bool | np.bool_: ... # undocumented +def vecnorm(x: _ArrayLikeFloat_co, ord: _Float_co | np.integer[Any] = 2) -> _Float_co: ... # undocumented +def approx_fhess_p( # undocumented + x0: _ArrayLikeFloat_co, + p: _Float_co, + fprime: ObjectiveFunc[_Float1D, Unpack[_Ts], _FloatND_co], + epsilon: _Float_co | _FloatND_co, + *args: Unpack[_Ts], +) -> _Float1D: ... + +class MemoizeJac(Generic[Unpack[_Ts]]): # undocumented + fun: ObjectiveFunc[_ArrayLikeFloat_co, Unpack[_Ts], tuple[_Float_co, _FloatND_co]] + jac: float | None + x: onpt.Array[onpt.AtMost1D, np.floating[Any]] | None + _value: float + def __init__(self, /, fun: ObjectiveFunc[_ArrayLikeFloat_co, Unpack[_Ts], tuple[_Float_co, _FloatND_co]]) -> None: ... + def _compute_if_needed(self, /, x: _ArrayLikeFloat_co, *args: Unpack[_Ts]) -> None: ... + def __call__(self, /, x: _ArrayLikeFloat_co, *args: Unpack[_Ts]) -> _Float0D: ... + def derivative(self, /, x: _ArrayLikeFloat_co, *args: Unpack[_Ts]) -> _Float1D: ... -class _Brute_Wrapper: - f: UntypedCallable - args: Untyped - def __init__(self, f: UntypedCallable, args: Untyped) -> None: ... - def __call__(self, x: Untyped) -> Untyped: ... - -class MemoizeJac: - fun: UntypedCallable - jac: Untyped - x: Untyped - def __init__(self, fun: UntypedCallable) -> None: ... - def __call__(self, x: Untyped, *args: Untyped) -> Untyped: ... - def derivative(self, x: Untyped, *args: Untyped) -> Untyped: ... - -class Brent: - func: UntypedCallable - args: Untyped +class Brent(Generic[Unpack[_Ts]]): # undocumented + _mintol: float + _cg: float + func: ObjectiveFunc[float, Unpack[_Ts], float] + args: tuple[Unpack[_Ts]] tol: float maxiter: int - xmin: Untyped - fval: Untyped + xmin: float | None + fval: float | None iter: int funcalls: int - disp: bool | Literal[0, 1] - brack: Untyped + disp: spt.AnyBool + brack: tuple[float, float] | tuple[float, float, float] + @overload + def __init__( + self: Brent[Unpack[tuple[()]]], + /, + func: ObjectiveFunc[float, Unpack[tuple[()]], float], + args: tuple[()] = (), + tol: float = 1.48e-08, + maxiter: int = 500, + full_output: spt.AnyBool = 0, + disp: spt.AnyBool = 0, + ) -> None: ... + @overload def __init__( self, - func: UntypedCallable, - args: Untyped = (), + /, + func: ObjectiveFunc[float, Unpack[_Ts], float], + args: tuple[Unpack[_Ts]] = ..., tol: float = 1.48e-08, maxiter: int = 500, - full_output: int = 0, - disp: bool | Literal[0, 1] = 0, + full_output: spt.AnyBool = 0, + disp: spt.AnyBool = 0, ) -> None: ... - def set_bracket(self, brack: Untyped | None = None) -> None: ... - def get_bracket_info(self) -> Untyped: ... - def optimize(self) -> None: ... - def get_result(self, full_output: bool = False) -> Untyped: ... + def set_bracket(self, /, brack: tuple[float, float] | tuple[float, float, float] | None = None) -> None: ... + def get_bracket_info(self, /) -> tuple[float, float, float, float, float, float, int]: ... + def optimize(self, /) -> None: ... + def get_result(self, /, full_output: bool = False) -> float | tuple[float, float, int, int]: ... -class OptimizeResult(_RichResult): - x: Final[onpt.Array[tuple[int], np.floating[Any]]] - success: Final[bool] - status: int - message: str - fun: float | np.floating[Any] - jac: onpt.Array[tuple[int, ...], np.floating[Any]] - hess: onpt.Array[tuple[int, ...], np.floating[Any]] - nfev: int - njev: int - nhev: int - nit: int - maxcv: float - -def is_finite_scalar(x: Untyped) -> Untyped: ... -def vecnorm(x: Untyped, ord: int = 2) -> Untyped: ... -def rosen(x: Untyped) -> Untyped: ... -def rosen_der(x: Untyped) -> Untyped: ... -def rosen_hess(x: Untyped) -> Untyped: ... -def rosen_hess_prod(x: Untyped, p: Untyped) -> Untyped: ... +# minimize + +@overload def fmin( - func: UntypedCallable, - x0: Untyped, - args: Untyped = (), - xtol: float = 0.0001, - ftol: float = 0.0001, - maxiter: Untyped | None = None, - maxfun: Untyped | None = None, - full_output: int = 0, - disp: int = 1, - retall: int = 0, - callback: Untyped | None = None, - initial_simplex: Untyped | None = None, -) -> Untyped: ... -def approx_fprime(xk: Untyped, f: UntypedCallable, epsilon: float = ..., *args: Untyped) -> Untyped: ... -def check_grad( - func: UntypedCallable, - grad: Untyped, - x0: Untyped, - *args: Untyped, - epsilon: float = ..., - direction: str = "all", - seed: Untyped | None = None, -) -> Untyped: ... -def approx_fhess_p(x0: Untyped, p: Untyped, fprime: Untyped, epsilon: float, *args: Untyped) -> Untyped: ... + func: ObjectiveFunc[_Float1D, Unpack[tuple[()]], _Float_co], + x0: _ArrayLikeFloat_co, + args: tuple[()] = (), + xtol: float = 1e-4, + ftol: float = 1e-4, + maxiter: int | None = None, + maxfun: int | None = None, + full_output: spt.AnyBool = 0, + disp: spt.AnyBool = 1, + retall: spt.AnyBool = 0, + callback: Callable[[_Float1D], None] | None = None, + initial_simplex: _ArrayLikeFloat_co | None = None, +) -> _Float1D | tuple[_Float1D, _Float_co] | tuple[_Float1D, _Float_co, int, int, int, list[_Float1D]]: ... +@overload +def fmin( + func: ObjectiveFunc[_Float1D, Unpack[_Ts], _Float_co], + x0: _ArrayLikeFloat_co, + args: tuple[Unpack[_Ts]], + xtol: float = 1e-4, + ftol: float = 1e-4, + maxiter: int | None = None, + maxfun: int | None = None, + full_output: spt.AnyBool = 0, + disp: spt.AnyBool = 1, + retall: spt.AnyBool = 0, + callback: Callable[[_Float1D], None] | None = None, + initial_simplex: _ArrayLikeFloat_co | None = None, +) -> _Float1D | tuple[_Float1D, _Float_co] | tuple[_Float1D, _Float_co, int, int, int, list[_Float1D]]: ... +@overload def fmin_bfgs( - f: UntypedCallable, - x0: Untyped, - fprime: Untyped | None = None, - args: Untyped = (), + f: ObjectiveFunc[_Float1D, Unpack[tuple[()]], _Float_co], + x0: _ArrayLikeFloat_co, + fprime: ObjectiveFunc[_Float1D, Unpack[_Ts], _FloatND_co] | None = None, + args: tuple[()] = (), gtol: float = 1e-05, norm: float = ..., - epsilon: float = ..., - maxiter: Untyped | None = None, - full_output: int = 0, - disp: int = 1, - retall: int = 0, - callback: Untyped | None = None, - xrtol: int = 0, - c1: float = 0.0001, + epsilon: _Float_co | _FloatND_co = ..., + maxiter: int | None = None, + full_output: spt.AnyBool = 0, + disp: spt.AnyBool = 1, + retall: spt.AnyBool = 0, + callback: Callable[[_Float1D], None] | None = None, + xrtol: float = 0, + c1: float = 1e-4, c2: float = 0.9, - hess_inv0: Untyped | None = None, -) -> Untyped: ... + hess_inv0: _ArrayLikeFloat_co | None = None, +) -> ( + _Float1D + | tuple[_Float1D, _Float0D] + | tuple[_Float1D, _Float0D, _Float1D, _Float2D, int, int, int] + | tuple[_Float1D, _Float0D, _Float1D, _Float2D, int, int, int, list[_Float1D]] +): ... +@overload +def fmin_bfgs( + f: ObjectiveFunc[_Float1D, Unpack[_Ts], _Float_co], + x0: _ArrayLikeFloat_co, + fprime: ObjectiveFunc[_Float1D, Unpack[_Ts], _FloatND_co] | None = None, + args: tuple[Unpack[_Ts]] = ..., + gtol: float = 1e-05, + norm: float = ..., + epsilon: _Float_co | _FloatND_co = ..., + maxiter: int | None = None, + full_output: spt.AnyBool = 0, + disp: spt.AnyBool = 1, + retall: spt.AnyBool = 0, + callback: Callable[[_Float1D], None] | None = None, + xrtol: float = 0, + c1: float = 1e-4, + c2: float = 0.9, + hess_inv0: _ArrayLikeFloat_co | None = None, +) -> ( + _Float1D + | tuple[_Float1D, _Float0D] + | tuple[_Float1D, _Float0D, _Float1D, _Float2D, int, int, int] + | tuple[_Float1D, _Float0D, _Float1D, _Float2D, int, int, int, list[_Float1D]] +): ... +@overload def fmin_cg( - f: UntypedCallable, - x0: Untyped, - fprime: Untyped | None = None, - args: Untyped = (), + f: ObjectiveFunc[_Float1D, Unpack[tuple[()]], _Float_co], + x0: _ArrayLikeFloat_co, + fprime: ObjectiveFunc[_Float1D, Unpack[_Ts], _FloatND_co] | None = None, + args: tuple[()] = (), gtol: float = 1e-05, norm: float = ..., - epsilon: float = ..., - maxiter: Untyped | None = None, - full_output: int = 0, - disp: int = 1, - retall: int = 0, - callback: Untyped | None = None, - c1: float = 0.0001, + epsilon: _Float_co | _FloatND_co = ..., + maxiter: int | None = None, + full_output: spt.AnyBool = 0, + disp: spt.AnyBool = 1, + retall: spt.AnyBool = 0, + callback: Callable[[_Float1D], None] | None = None, + c1: float = 1e-4, c2: float = 0.4, -) -> Untyped: ... +) -> ( + _Float1D + | tuple[_Float1D, _Float0D] + | tuple[_Float1D, _Float0D, int, int, int] + | tuple[_Float1D, _Float0D, int, int, int, list[_Float1D]] +): ... +@overload +def fmin_cg( + f: ObjectiveFunc[_Float1D, Unpack[_Ts], _Float_co], + x0: _ArrayLikeFloat_co, + fprime: ObjectiveFunc[_Float1D, Unpack[_Ts], _FloatND_co] | None = None, + args: tuple[Unpack[_Ts]] = ..., + gtol: float = 1e-05, + norm: float = ..., + epsilon: _Float_co | _FloatND_co = ..., + maxiter: int | None = None, + full_output: spt.AnyBool = 0, + disp: spt.AnyBool = 1, + retall: spt.AnyBool = 0, + callback: Callable[[_Float1D], None] | None = None, + c1: float = 1e-4, + c2: float = 0.4, +) -> ( + _Float1D + | tuple[_Float1D, _Float0D] + | tuple[_Float1D, _Float0D, int, int, int] + | tuple[_Float1D, _Float0D, int, int, int, list[_Float1D]] +): ... +@overload def fmin_ncg( - f: UntypedCallable, - x0: Untyped, - fprime: Untyped, - fhess_p: Untyped | None = None, - fhess: Untyped | None = None, - args: Untyped = (), + f: ObjectiveFunc[_Float1D, Unpack[tuple[()]], _Float_co], + x0: _ArrayLikeFloat_co, + fprime: ObjectiveFunc[_Float1D, Unpack[_Ts], _FloatND_co], + fhess_p: ObjectiveFunc[_Float1D, _Float1D, Unpack[_Ts], _FloatND_co] | None = None, + fhess: ObjectiveFunc[_Float1D, Unpack[_Ts], _FloatND_co] | None = None, + args: tuple[()] = (), avextol: float = 1e-05, - epsilon: float = ..., - maxiter: Untyped | None = None, - full_output: int = 0, - disp: int = 1, - retall: int = 0, - callback: Untyped | None = None, - c1: float = 0.0001, + epsilon: _Float_co | _FloatND_co = ..., + maxiter: int | None = None, + full_output: spt.AnyBool = 0, + disp: spt.AnyBool = 1, + retall: spt.AnyBool = 0, + callback: Callable[[_Float1D], None] | None = None, + c1: float = 1e-4, c2: float = 0.9, -) -> Untyped: ... +) -> ( + _Float1D + | tuple[_Float1D, _Float0D] + | tuple[_Float1D, _Float0D, int, int, int, int] + | tuple[_Float1D, _Float0D, int, int, int, int, list[_Float1D]] +): ... +@overload +def fmin_ncg( + f: ObjectiveFunc[_Float1D, Unpack[_Ts], _Float_co], + x0: _ArrayLikeFloat_co, + fprime: ObjectiveFunc[_Float1D, Unpack[_Ts], _FloatND_co], + fhess_p: ObjectiveFunc[_Float1D, _Float1D, Unpack[_Ts], _FloatND_co] | None = None, + fhess: ObjectiveFunc[_Float1D, Unpack[_Ts], _FloatND_co] | None = None, + args: tuple[Unpack[_Ts]] = ..., + avextol: float = 1e-05, + epsilon: _Float_co | _FloatND_co = ..., + maxiter: int | None = None, + full_output: spt.AnyBool = 0, + disp: spt.AnyBool = 1, + retall: spt.AnyBool = 0, + callback: Callable[[_Float1D], None] | None = None, + c1: float = 1e-4, + c2: float = 0.9, +) -> ( + _Float1D + | tuple[_Float1D, _Float0D] + | tuple[_Float1D, _Float0D, int, int, int, int] + | tuple[_Float1D, _Float0D, int, int, int, int, list[_Float1D]] +): ... +@overload +def fmin_powell( + func: ObjectiveFunc[_Float1D, Unpack[tuple[()]], _Float_co], + x0: _ArrayLikeFloat_co, + args: tuple[()] = (), + xtol: float = 1e-4, + ftol: float = 1e-4, + maxiter: int | None = None, + maxfun: int | None = None, + full_output: spt.AnyBool = 0, + disp: spt.AnyBool = 1, + retall: spt.AnyBool = 0, + callback: Callable[[_Float1D], None] | None = None, + direc: _ArrayLikeFloat_co | None = None, +) -> ( + _Float1D + | tuple[_Float1D, _Float0D] + | tuple[_Float1D, _Float0D, _Float2D, int, int, int] + | tuple[_Float1D, _Float0D, _Float2D, int, int, int, list[_Float1D]] +): ... +@overload +def fmin_powell( + func: ObjectiveFunc[_Float1D, Unpack[_Ts], _Float_co], + x0: _ArrayLikeFloat_co, + args: tuple[Unpack[_Ts]] = ..., + xtol: float = 1e-4, + ftol: float = 1e-4, + maxiter: int | None = None, + maxfun: int | None = None, + full_output: spt.AnyBool = 0, + disp: spt.AnyBool = 1, + retall: spt.AnyBool = 0, + callback: Callable[[_Float1D], None] | None = None, + direc: _ArrayLikeFloat_co | None = None, +) -> ( + _Float1D + | tuple[_Float1D, _Float0D] + | tuple[_Float1D, _Float0D, _Float2D, int, int, int] + | tuple[_Float1D, _Float0D, _Float2D, int, int, int, list[_Float1D]] +): ... +@overload def fminbound( - func: UntypedCallable, - x1: Untyped, - x2: Untyped, - args: Untyped = (), + func: ObjectiveFunc[float, Unpack[tuple[()]], _Float_co], + x1: _Float_co, + x2: _Float_co, + args: tuple[()] = (), xtol: float = 1e-05, maxfun: int = 500, - full_output: int = 0, - disp: int = 1, -) -> Untyped: ... -def brent( - func: UntypedCallable, - args: Untyped = (), - brack: Untyped | None = None, - tol: float = 1.48e-08, - full_output: int = 0, - maxiter: int = 500, -) -> Untyped: ... -def golden( - func: UntypedCallable, - args: Untyped = (), - brack: Untyped | None = None, - tol: float = ..., - full_output: int = 0, - maxiter: int = 5000, -) -> Untyped: ... -def bracket( - func: UntypedCallable, - xa: float = 0.0, - xb: float = 1.0, - args: Untyped = (), - grow_limit: float = 110.0, - maxiter: int = 1000, -) -> Untyped: ... -def fmin_powell( - func: UntypedCallable, - x0: Untyped, - args: Untyped = (), - xtol: float = 0.0001, - ftol: float = 0.0001, - maxiter: Untyped | None = None, - maxfun: Untyped | None = None, - full_output: int = 0, - disp: int = 1, - retall: int = 0, - callback: UntypedCallable | None = None, - direc: Untyped | None = None, -) -> Untyped: ... + full_output: spt.AnyBool = 0, + disp: Literal[0, 1, 2, 3] = 1, +) -> float | tuple[float, _Float0D, Literal[0, 1], int]: ... +@overload +def fminbound( + func: ObjectiveFunc[float, Unpack[_Ts], _Float_co], + x1: _Float_co, + x2: _Float_co, + args: tuple[Unpack[_Ts]] = ..., + xtol: float = 1e-05, + maxfun: int = 500, + full_output: spt.AnyBool = 0, + disp: Literal[0, 1, 2, 3] = 1, +) -> float | tuple[float, _Float0D, Literal[0, 1], int]: ... + +# global minimization: TODO + def brute( func: UntypedCallable, ranges: Untyped, - args: UntypedTuple = (), + args: Untyped = (), Ns: int = 20, full_output: int = 0, finish: Untyped = ..., disp: bool = False, workers: int = 1, ) -> Untyped: ... -def show_options(solver: str | None = None, method: str | None = None, disp: bool = True) -> str | None: ... + +# minimize scalar + +@overload +def brent( + func: ObjectiveFunc[float, Unpack[tuple[()]], _Float_co], + args: tuple[()] = (), + brack: Brack | None = None, + tol: float = 1.48e-08, + full_output: spt.AnyBool = 0, + maxiter: int = 500, +) -> float | tuple[float, _Float0D, int, int]: ... +@overload +def brent( + func: ObjectiveFunc[float, Unpack[_Ts], _Float_co], + args: tuple[Unpack[_Ts]], + brack: Brack | None = None, + tol: float = 1.48e-08, + full_output: spt.AnyBool = 0, + maxiter: int = 500, +) -> float | tuple[float, _Float0D, int, int]: ... +@overload +def golden( + func: ObjectiveFunc[float, Unpack[tuple[()]], _Float_co], + args: tuple[()] = (), + brack: Brack | None = None, + tol: float = ..., + full_output: spt.AnyBool = 0, + maxiter: int = 5_000, +) -> float | tuple[float, _Float0D, int]: ... +@overload +def golden( + func: ObjectiveFunc[float, Unpack[_Ts], _Float_co], + args: tuple[Unpack[_Ts]], + brack: Brack | None = None, + tol: float = ..., + full_output: spt.AnyBool = 0, + maxiter: int = 5_000, +) -> float | tuple[float, _Float0D, int]: ... +@overload +def bracket( + func: ObjectiveFunc[float, Unpack[tuple[()]], _Float_co], + xa: _Float_co = 0.0, + xb: _Float_co = 1.0, + args: tuple[()] = (), + grow_limit: float = 110.0, + maxiter: int = 1_000, +) -> tuple[float, float, float, _Float0D, _Float0D, _Float0D, int]: ... +@overload +def bracket( + func: ObjectiveFunc[float, Unpack[_Ts], _Float_co], + xa: _Float_co = 0.0, + xb: _Float_co = 1.0, + args: tuple[Unpack[_Ts]] = ..., + grow_limit: float = 110.0, + maxiter: int = 1_000, +) -> tuple[float, float, float, _Float0D, _Float0D, _Float0D, int]: ... + +# rosenbrock function + +def rosen(x: _ArrayLikeFloat_co) -> _Float_co: ... +def rosen_der(x: _ArrayLikeFloat_co) -> _Float1D: ... +def rosen_hess(x: _ArrayLikeFloat_co) -> _Float2D: ... +def rosen_hess_prod(x: _ArrayLikeFloat_co, p: _ArrayLikeFloat_co) -> _Float1D: ... + +# meta + +@overload +def show_options(solver: Solver | None, method: MethodAll | None, disp: Literal[False, 0, None]) -> str: ... +@overload +def show_options(solver: Solver | None = None, method: MethodAll | None = None, *, disp: Literal[False, 0, None]) -> str: ... +@overload +def show_options(solver: Solver | None = None, method: MethodAll | None = None, disp: Literal[True, 1] = True) -> None: ... + +class BracketError(RuntimeError): ... +class OptimizeWarning(UserWarning): ... + +class OptimizeResult(_RichResult, Generic[_SCT_f]): + x: onpt.Array[onpt.AtMost1D, _SCT_f] + fun: _SCT_f | float + success: Final[bool] + status: Final[int] + message: Final[str] + nit: Final[int] + +# miscellaneous + +def approx_fprime( + xk: _ArrayLikeFloat_co, + f: ObjectiveFunc[_Float1D, Unpack[_Ts], _Float_co], + epsilon: _ArrayLikeFloat_co = ..., + *args: Unpack[_Ts], +) -> _Float1D: ... +def check_grad( + func: ObjectiveFunc[_Float1D, Unpack[_Ts], _Float_co], + grad: ObjectiveFunc[_Float1D, Unpack[_Ts], _FloatND_co], + x0: _ArrayLikeFloat_co, + *args: tuple[Unpack[_Ts]], + epsilon: float = ..., + direction: Literal["all", "random"] = "all", + seed: spt.Seed | None = None, +) -> _Float: ... diff --git a/scipy-stubs/optimize/_remove_redundancy.pyi b/scipy-stubs/optimize/_remove_redundancy.pyi index 19cf0599..da923bf0 100644 --- a/scipy-stubs/optimize/_remove_redundancy.pyi +++ b/scipy-stubs/optimize/_remove_redundancy.pyi @@ -1,5 +1,3 @@ from scipy._typing import Untyped -__all__ = ["bg_update_dense"] - def bg_update_dense(plu: Untyped, perm_r: Untyped, v: Untyped, j: Untyped) -> Untyped: ... diff --git a/scipy-stubs/optimize/_trlib/_trlib.pyi b/scipy-stubs/optimize/_trlib/_trlib.pyi index 666f9a0c..68713791 100644 --- a/scipy-stubs/optimize/_trlib/_trlib.pyi +++ b/scipy-stubs/optimize/_trlib/_trlib.pyi @@ -1,17 +1,19 @@ -from typing_extensions import override +from collections.abc import Mapping +from typing import Final +from typing_extensions import Never, override import numpy as np import numpy.typing as npt -from scipy._typing import UntypedCallable +from scipy._typing import Untyped, UntypedCallable from scipy.optimize._trustregion import BaseQuadraticSubproblem -__all__ = ["TRLIBQuadraticSubproblem"] +__test__: Final[Mapping[Never, Never]] class TRLIBQuadraticSubproblem(BaseQuadraticSubproblem): def __init__( self, /, - x, + x: Untyped, fun: UntypedCallable, jac: UntypedCallable, hess: UntypedCallable | None, diff --git a/scipy-stubs/optimize/_trustregion_constr/__init__.pyi b/scipy-stubs/optimize/_trustregion_constr/__init__.pyi index e69de29b..7396f845 100644 --- a/scipy-stubs/optimize/_trustregion_constr/__init__.pyi +++ b/scipy-stubs/optimize/_trustregion_constr/__init__.pyi @@ -0,0 +1,3 @@ +from .minimize_trustregion_constr import _minimize_trustregion_constr + +__all__ = ["_minimize_trustregion_constr"] diff --git a/scipy-stubs/optimize/_trustregion_constr/minimize_trustregion_constr.pyi b/scipy-stubs/optimize/_trustregion_constr/minimize_trustregion_constr.pyi index b13866da..d09dc4c9 100644 --- a/scipy-stubs/optimize/_trustregion_constr/minimize_trustregion_constr.pyi +++ b/scipy-stubs/optimize/_trustregion_constr/minimize_trustregion_constr.pyi @@ -1,51 +1,67 @@ -from scipy._typing import Untyped -from scipy.optimize._constraints import ( - Bounds as Bounds, - LinearConstraint as LinearConstraint, - NonlinearConstraint as NonlinearConstraint, - PreparedConstraint as PreparedConstraint, - strict_bounds as strict_bounds, -) -from scipy.optimize._differentiable_functions import ScalarFunction as ScalarFunction, VectorFunction as VectorFunction -from scipy.optimize._hessian_update_strategy import BFGS as BFGS -from scipy.optimize._optimize import OptimizeResult as OptimizeResult -from scipy.sparse.linalg import LinearOperator as LinearOperator -from .canonical_constraint import ( - CanonicalConstraint as CanonicalConstraint, - initial_constraints_as_canonical as initial_constraints_as_canonical, -) -from .equality_constrained_sqp import equality_constrained_sqp as equality_constrained_sqp -from .report import BasicReport as BasicReport, IPReport as IPReport, SQPReport as SQPReport -from .tr_interior_point import tr_interior_point as tr_interior_point +from scipy._typing import Untyped, UntypedCallable +from scipy.optimize._optimize import OptimizeResult TERMINATION_MESSAGES: Untyped class HessianLinearOperator: hessp: Untyped n: Untyped - def __init__(self, hessp, n) -> None: ... - def __call__(self, x, *args) -> Untyped: ... + def __init__(self, hessp: UntypedCallable, n: int) -> None: ... + def __call__(self, x: Untyped, *args: object) -> Untyped: ... class LagrangianHessian: n: Untyped objective_hess: Untyped constraints_hess: Untyped - def __init__(self, n, objective_hess, constraints_hess) -> None: ... - def __call__(self, x, v_eq, v_ineq: Untyped | None = None) -> Untyped: ... + def __init__(self, n: int, objective_hess: UntypedCallable, constraints_hess: UntypedCallable) -> None: ... + def __call__(self, x: Untyped, v_eq: Untyped, v_ineq: Untyped) -> Untyped: ... def update_state_sqp( - state, x, last_iteration_failed, objective, prepared_constraints, start_time, tr_radius, constr_penalty, cg_info + state: Untyped, + x: Untyped, + last_iteration_failed: Untyped, + objective: Untyped, + prepared_constraints: Untyped, + start_time: Untyped, + tr_radius: Untyped, + constr_penalty: Untyped, + cg_info: Untyped, ) -> Untyped: ... def update_state_ip( - state, - x, - last_iteration_failed, - objective, - prepared_constraints, - start_time, - tr_radius, - constr_penalty, - cg_info, - barrier_parameter, - barrier_tolerance, + state: Untyped, + x: Untyped, + last_iteration_failed: Untyped, + objective: Untyped, + prepared_constraints: Untyped, + start_time: Untyped, + tr_radius: Untyped, + constr_penalty: Untyped, + cg_info: Untyped, + barrier_parameter: Untyped, + barrier_tolerance: Untyped, ) -> Untyped: ... + +def _minimize_trustregion_constr( + fun: UntypedCallable, + x0: Untyped, + args: Untyped, + grad: Untyped, + hess: Untyped, + hessp: Untyped, + bounds: Untyped, + constraints: Untyped, + xtol: float = 1e-8, + gtol: float = 1e-8, + barrier_tol: float = 1e-8, + sparse_jacobian: bool | None = None, + callback: UntypedCallable | None = None, + maxiter: int = 1000, + verbose: Untyped = 0, + finite_diff_rel_step: Untyped | None = None, + initial_constr_penalty: float = 1.0, + initial_tr_radius: float = 1.0, + initial_barrier_parameter: float = 0.1, + initial_barrier_tolerance: float = 0.1, + factorization_method: str | None = None, + disp: bool = False, +) -> OptimizeResult: ... diff --git a/scipy-stubs/optimize/_trustregion_constr/projections.pyi b/scipy-stubs/optimize/_trustregion_constr/projections.pyi index de8788d0..fc3ccb47 100644 --- a/scipy-stubs/optimize/_trustregion_constr/projections.pyi +++ b/scipy-stubs/optimize/_trustregion_constr/projections.pyi @@ -1,12 +1,20 @@ +from typing import Final + from scipy._typing import Untyped -from scipy.sparse import bmat as bmat, csc_matrix as csc_matrix, eye as eye, issparse as issparse -from scipy.sparse.linalg import LinearOperator as LinearOperator -sksparse_available: bool +__all__ = ["orthogonality", "projections"] + +sksparse_available: Final[bool] = ... -def orthogonality(A, g) -> Untyped: ... -def normal_equation_projections(A, m, n, orth_tol, max_refin, tol) -> Untyped: ... -def augmented_system_projections(A, m, n, orth_tol, max_refin, tol) -> Untyped: ... -def qr_factorization_projections(A, m, n, orth_tol, max_refin, tol) -> Untyped: ... -def svd_factorization_projections(A, m, n, orth_tol, max_refin, tol) -> Untyped: ... -def projections(A, method: Untyped | None = None, orth_tol: float = 1e-12, max_refin: int = 3, tol: float = 1e-15) -> Untyped: ... +def orthogonality(A: Untyped, g: Untyped) -> Untyped: ... +def normal_equation_projections(A: Untyped, m: int, n: int, orth_tol: Untyped, max_refin: int, tol: float) -> Untyped: ... +def augmented_system_projections(A: Untyped, m: int, n: int, orth_tol: Untyped, max_refin: int, tol: float) -> Untyped: ... +def qr_factorization_projections(A: Untyped, m: int, n: int, orth_tol: Untyped, max_refin: int, tol: float) -> Untyped: ... +def svd_factorization_projections(A: Untyped, m: int, n: int, orth_tol: Untyped, max_refin: int, tol: float) -> Untyped: ... +def projections( + A: Untyped, + method: Untyped | None = None, + orth_tol: float = 1e-12, + max_refin: int = 3, + tol: float = 1e-15, +) -> Untyped: ... diff --git a/scipy-stubs/optimize/_trustregion_constr/tr_interior_point.pyi b/scipy-stubs/optimize/_trustregion_constr/tr_interior_point.pyi index f449e4e5..7802596e 100644 --- a/scipy-stubs/optimize/_trustregion_constr/tr_interior_point.pyi +++ b/scipy-stubs/optimize/_trustregion_constr/tr_interior_point.pyi @@ -1,6 +1,6 @@ from scipy._typing import Untyped -from scipy.sparse.linalg import LinearOperator as LinearOperator -from .equality_constrained_sqp import equality_constrained_sqp as equality_constrained_sqp + +__all__ = ["tr_interior_point"] class BarrierSubproblem: n_vars: Untyped @@ -25,64 +25,72 @@ class BarrierSubproblem: terminate: bool def __init__( self, - x0, - s0, - fun, - grad, - lagr_hess, - n_vars, - n_ineq, - n_eq, - constr, - jac, - barrier_parameter, - tolerance, - enforce_feasibility, - global_stop_criteria, - xtol, - fun0, - grad0, - constr_ineq0, - jac_ineq0, - constr_eq0, - jac_eq0, + x0: Untyped, + s0: Untyped, + fun: Untyped, + grad: Untyped, + lagr_hess: Untyped, + n_vars: Untyped, + n_ineq: Untyped, + n_eq: Untyped, + constr: Untyped, + jac: Untyped, + barrier_parameter: Untyped, + tolerance: Untyped, + enforce_feasibility: Untyped, + global_stop_criteria: Untyped, + xtol: Untyped, + fun0: Untyped, + grad0: Untyped, + constr_ineq0: Untyped, + jac_ineq0: Untyped, + constr_eq0: Untyped, + jac_eq0: Untyped, ) -> None: ... - def update(self, barrier_parameter, tolerance): ... - def get_slack(self, z) -> Untyped: ... - def get_variables(self, z) -> Untyped: ... - def function_and_constraints(self, z) -> Untyped: ... - def scaling(self, z) -> Untyped: ... - def gradient_and_jacobian(self, z) -> Untyped: ... - def lagrangian_hessian_x(self, z, v) -> Untyped: ... - def lagrangian_hessian_s(self, z, v) -> Untyped: ... - def lagrangian_hessian(self, z, v) -> Untyped: ... + def update(self, barrier_parameter: Untyped, tolerance: Untyped) -> None: ... + def get_slack(self, z: Untyped) -> Untyped: ... + def get_variables(self, z: Untyped) -> Untyped: ... + def function_and_constraints(self, z: Untyped) -> Untyped: ... + def scaling(self, z: Untyped) -> Untyped: ... + def gradient_and_jacobian(self, z: Untyped) -> Untyped: ... + def lagrangian_hessian_x(self, z: Untyped, v: Untyped) -> Untyped: ... + def lagrangian_hessian_s(self, z: Untyped, v: Untyped) -> Untyped: ... + def lagrangian_hessian(self, z: Untyped, v: Untyped) -> Untyped: ... def stop_criteria( - self, state, z, last_iteration_failed, optimality, constr_violation, trust_radius, penalty, cg_info + self, + state: Untyped, + z: Untyped, + last_iteration_failed: Untyped, + optimality: Untyped, + constr_violation: Untyped, + trust_radius: Untyped, + penalty: Untyped, + cg_info: Untyped, ) -> Untyped: ... def tr_interior_point( - fun, - grad, - lagr_hess, - n_vars, - n_ineq, - n_eq, - constr, - jac, - x0, - fun0, - grad0, - constr_ineq0, - jac_ineq0, - constr_eq0, - jac_eq0, - stop_criteria, - enforce_feasibility, - xtol, - state, - initial_barrier_parameter, - initial_tolerance, - initial_penalty, - initial_trust_radius, - factorization_method, + fun: Untyped, + grad: Untyped, + lagr_hess: Untyped, + n_vars: Untyped, + n_ineq: Untyped, + n_eq: Untyped, + constr: Untyped, + jac: Untyped, + x0: Untyped, + fun0: Untyped, + grad0: Untyped, + constr_ineq0: Untyped, + jac_ineq0: Untyped, + constr_eq0: Untyped, + jac_eq0: Untyped, + stop_criteria: Untyped, + enforce_feasibility: Untyped, + xtol: Untyped, + state: Untyped, + initial_barrier_parameter: Untyped, + initial_tolerance: Untyped, + initial_penalty: Untyped, + initial_trust_radius: Untyped, + factorization_method: Untyped, ) -> Untyped: ... diff --git a/scipy-stubs/optimize/_trustregion_exact.pyi b/scipy-stubs/optimize/_trustregion_exact.pyi index 464a303f..d225b0fe 100644 --- a/scipy-stubs/optimize/_trustregion_exact.pyi +++ b/scipy-stubs/optimize/_trustregion_exact.pyi @@ -2,12 +2,22 @@ from typing_extensions import override import numpy as np import numpy.typing as npt -from scipy._typing import Untyped +from scipy._typing import Untyped, UntypedCallable, UntypedTuple from ._trustregion import BaseQuadraticSubproblem -def estimate_smallest_singular_value(U) -> Untyped: ... -def gershgorin_bounds(H) -> Untyped: ... -def singular_leading_submatrix(A, U, k) -> Untyped: ... +__all__ = ["IterativeSubproblem", "_minimize_trustregion_exact", "estimate_smallest_singular_value", "singular_leading_submatrix"] + +def _minimize_trustregion_exact( + fun: UntypedCallable, + x0: Untyped, + args: UntypedTuple = (), + jac: Untyped | None = None, + hess: Untyped | None = None, + **trust_region_options: Untyped, +) -> Untyped: ... +def estimate_smallest_singular_value(U: Untyped) -> Untyped: ... +def gershgorin_bounds(H: Untyped) -> Untyped: ... +def singular_leading_submatrix(A: Untyped, U: Untyped, k: Untyped) -> Untyped: ... class IterativeSubproblem(BaseQuadraticSubproblem): UPDATE_COEFF: float @@ -21,7 +31,16 @@ class IterativeSubproblem(BaseQuadraticSubproblem): hess_inf: Untyped hess_fro: Untyped CLOSE_TO_ZERO: Untyped - def __init__(self, x, fun, jac, hess, hessp: Untyped | None = None, k_easy: float = 0.1, k_hard: float = 0.2) -> None: ... lambda_current: Untyped + def __init__( + self, + x: Untyped, + fun: UntypedCallable, + jac: Untyped, + hess: Untyped, + hessp: Untyped | None = None, + k_easy: float = 0.1, + k_hard: float = 0.2, + ) -> None: ... @override def solve(self, trust_radius: float | np.float64) -> tuple[npt.NDArray[np.float64], bool]: ... diff --git a/scipy-stubs/optimize/_trustregion_krylov.pyi b/scipy-stubs/optimize/_trustregion_krylov.pyi index f21b72f8..1a4e996b 100644 --- a/scipy-stubs/optimize/_trustregion_krylov.pyi +++ b/scipy-stubs/optimize/_trustregion_krylov.pyi @@ -1 +1,14 @@ -from ._trlib import get_trlib_quadratic_subproblem as get_trlib_quadratic_subproblem +__all__ = ["_minimize_trust_krylov"] + +from scipy._typing import Untyped, UntypedCallable, UntypedTuple + +def _minimize_trust_krylov( + fun: UntypedCallable, + x0: Untyped, + args: UntypedTuple = (), + jac: Untyped | None = None, + hess: Untyped | None = None, + hessp: Untyped | None = None, + inexact: bool = True, + **trust_region_options: Untyped, +) -> Untyped: ... diff --git a/scipy-stubs/optimize/_typing.pyi b/scipy-stubs/optimize/_typing.pyi index f3926b8c..75ad1e87 100644 --- a/scipy-stubs/optimize/_typing.pyi +++ b/scipy-stubs/optimize/_typing.pyi @@ -1,35 +1,116 @@ -from typing import Literal, TypeAlias - -from ._constraints import LinearConstraint, NonlinearConstraint - -MimimizeMethod: TypeAlias = Literal[ - "Nelder-Mead", - "nelder-mead", - "Powell", - "powell", - "CG", - "cg", - "BFGS", - "cfgs", - "Newton-CG", - "newton-cg", - "L-BFGS-B", - "l-bfgs-c", - "TNC", - "tnc" "COBYLA", - "cobyla", - "COBYQA", - "cobyqa", - "SLSQP", - "slsqp", - "trust-constr", - "dogleg", - "trust-ncg", - "trust-exact", - "trust-krylov", +from collections.abc import Sequence +from typing import Any, Final, Generic, Literal, Protocol, TypeAlias, type_check_only +from typing_extensions import NotRequired, TypedDict, TypeVar, TypeVarTuple, Unpack + +import numpy as np +import optype.numpy as onpt +from ._constraints import Bounds as _Bounds, LinearConstraint, NonlinearConstraint +from ._optimize import OptimizeResult as _OptimizeResult + +_Ts = TypeVarTuple("_Ts") +_Ts0 = TypeVarTuple("_Ts0", default=Unpack[tuple[()]]) +_T_co = TypeVar("_T_co", covariant=True) +_T_contra = TypeVar("_T_contra", contravariant=True) + +_SCT_f = TypeVar("_SCT_f", bound=np.floating[Any], default=np.float32 | np.float64) +_ScalarLike_f: TypeAlias = float | np.floating[Any] +_ScalarLike_f_co: TypeAlias = float | np.floating[Any] | np.integer[Any] + +# any objective function +@type_check_only +class ObjectiveFunc(Protocol[_T_contra, Unpack[_Ts], _T_co]): + def __call__(self, x: _T_contra, /, *args: Unpack[_Ts]) -> _T_co: ... + +# bounds +Bound: TypeAlias = tuple[_ScalarLike_f_co | None, _ScalarLike_f_co | None] +Bounds: TypeAlias = Sequence[Bound] | _Bounds + +# constaints +@type_check_only +class ConstraintDict(TypedDict, Generic[Unpack[_Ts0]]): + type: Literal["eq", "ineq"] + fun: ObjectiveFunc[onpt.Array[tuple[int], np.floating[Any]], Unpack[_Ts0], _ScalarLike_f_co] + jac: NotRequired[ + ObjectiveFunc[ + onpt.Array[tuple[int], np.floating[Any]], + Unpack[_Ts0], + Sequence[_ScalarLike_f] | onpt.CanArray[tuple[int, ...], np.dtype[np.floating[Any]]], + ] + ] + args: NotRequired[tuple[Unpack[_Ts0]]] + +Constraint: TypeAlias = LinearConstraint | NonlinearConstraint | ConstraintDict +Constraints: TypeAlias = Constraint | Sequence[Constraint] + +Brack: TypeAlias = tuple[_ScalarLike_f_co, _ScalarLike_f_co] | tuple[_ScalarLike_f_co, _ScalarLike_f_co, _ScalarLike_f_co] + +Solver: TypeAlias = Literal["minimize", "minimize_scalar", "root", "root_salar", "linprog", "quadratic_assignment"] +MethodJac: TypeAlias = Literal["2-point", "3-point", "cs"] +MethodMimimize: TypeAlias = Literal[ + "NELDER-MEAD", "Nelder-Mead", "nelder-mead", + "POWELL", "Powell", "powell", + "CG", "Cg", "cg", + "BFGS", "Bfgs", "bfgs", + "NEWTON-CG", "Newton-CG", "newton-cg", + "L-BFGS-B", "L-Bfgs-B", "l-bfgs-b", + "TNC", "Tnc", "tnc", + "COBYLA", "Cobyla", "cobyla", + "COBYQA", "Cobyqa", "cobyqa", + "SLSQP", "Slsqp", "slsqp", + "TRUST-CONSTR", "Trust-Constr", "trust-constr", + "DOGLEG", "Dogleg", "dogleg", + "TRUST-NCG", "Trust-NCG", "trust-ncg", + "TRUST-EXACT", "Trust-Exact", "trust-exact", + "TRUST-KRYLOV", "Trust-Krylov", "trust-krylov", +] # fmt: skip +MethodRoot: TypeAlias = Literal[ + "hybr", + "lm", + "broyden1", + "broyden2", + "anderson", + "linearmixing", + "diagbroyden", + "excitingmixing", + "krylov", + "df-sane", ] -MinimizeScalarMethod: TypeAlias = Literal["Brent", "brent", "Golden", "golden", "Bounded", "bounded"] -GradMethod: TypeAlias = Literal["2-point", "3-point", "cs"] +MethodMinimizeScalar: TypeAlias = Literal["brent", "golden", "bounded"] +MethodRootScalar: TypeAlias = Literal["bisect", "brentq", "brenth", "ridder", "toms748", "newton", "secant", "halley"] +MethodLinprog: TypeAlias = Literal["highs", "highs-ds", "highs-ipm"] # Literal["interior-point", "revised simplex", "simplex"] +MethodQuadraticAssignment: TypeAlias = Literal["faq", "2opt"] +MethodAll: TypeAlias = Literal[ + MethodMimimize, + MethodRoot, + MethodMinimizeScalar, + MethodRootScalar, + MethodLinprog, + MethodQuadraticAssignment, +] + +@type_check_only +class OptimizeResultMinimize(_OptimizeResult[_SCT_f], Generic[_SCT_f]): + jac: onpt.Array[tuple[int], _SCT_f] + nfev: Final[int] + njev: Final[int] + nhev: Final[int] + +@type_check_only +class OptimizeResultMinimizeHess(OptimizeResultMinimize[_SCT_f], Generic[_SCT_f]): + hess: onpt.Array[tuple[int, int], _SCT_f] + hess_inv: onpt.Array[tuple[int, int], _SCT_f] + +@type_check_only +class OptimizeResultMinimizeConstr(OptimizeResultMinimize[_SCT_f], Generic[_SCT_f]): + maxcv: Final[float] + +@type_check_only +class OptimizeResultMinimizeHessConstr(OptimizeResultMinimize[_SCT_f], Generic[_SCT_f]): + hess: onpt.Array[tuple[int, int], _SCT_f] + hess_inv: onpt.Array[tuple[int, int], _SCT_f] + maxcv: Final[float] -# TODO: Use a `TypedDict` here -Constraint: TypeAlias = LinearConstraint | NonlinearConstraint | dict[str, object] +@type_check_only +class OptimizeResultLinprog(Generic[_SCT_f]): + slack: onpt.Array[tuple[int], _SCT_f] + con: onpt.Array[tuple[int], _SCT_f] diff --git a/scipy-stubs/optimize/cython_optimize/__init__.pyi b/scipy-stubs/optimize/cython_optimize/__init__.pyi index e69de29b..f93c5705 100644 --- a/scipy-stubs/optimize/cython_optimize/__init__.pyi +++ b/scipy-stubs/optimize/cython_optimize/__init__.pyi @@ -0,0 +1 @@ +# nothing to see here diff --git a/scipy-stubs/optimize/minpack.pyi b/scipy-stubs/optimize/minpack.pyi index 63446c8c..a3075593 100644 --- a/scipy-stubs/optimize/minpack.pyi +++ b/scipy-stubs/optimize/minpack.pyi @@ -2,7 +2,7 @@ from numpy import zeros # noqa: ICN003 from ._lsq.least_squares import least_squares -from ._minpack_py import * +from ._minpack_py import curve_fit, fixed_point, fsolve, leastsq from ._optimize import OptimizeResult, OptimizeWarning __all__ = ["OptimizeResult", "OptimizeWarning", "curve_fit", "fixed_point", "fsolve", "least_squares", "leastsq", "zeros"] diff --git a/scipy-stubs/optimize/nonlin.pyi b/scipy-stubs/optimize/nonlin.pyi index fbaa8f3a..f871521a 100644 --- a/scipy-stubs/optimize/nonlin.pyi +++ b/scipy-stubs/optimize/nonlin.pyi @@ -1,6 +1,17 @@ # This file is not meant for public use and will be removed in SciPy v2.0.0. -from ._nonlin import * +from ._nonlin import ( + BroydenFirst, + InverseJacobian, + KrylovJacobian, + anderson, + broyden1, + broyden2, + diagbroyden, + excitingmixing, + linearmixing, + newton_krylov, +) __all__ = [ "BroydenFirst", From 9cee3d3c743cb664f2537eb959ed4a0be8790984 Mon Sep 17 00:00:00 2001 From: jorenham Date: Tue, 10 Sep 2024 02:48:28 +0200 Subject: [PATCH 08/11] fix `scipy.optimize` mypy errors --- .../optimize/_hessian_update_strategy.pyi | 42 +++++++++++-------- scipy-stubs/optimize/_trustregion.pyi | 2 +- scipy-stubs/optimize/_trustregion_dogleg.pyi | 8 +++- scipy-stubs/optimize/_trustregion_ncg.pyi | 8 +++- 4 files changed, 38 insertions(+), 22 deletions(-) diff --git a/scipy-stubs/optimize/_hessian_update_strategy.pyi b/scipy-stubs/optimize/_hessian_update_strategy.pyi index 9176159d..1d6f21b9 100644 --- a/scipy-stubs/optimize/_hessian_update_strategy.pyi +++ b/scipy-stubs/optimize/_hessian_update_strategy.pyi @@ -1,11 +1,14 @@ -from scipy._typing import Untyped -from scipy.linalg import get_blas_funcs as get_blas_funcs, issymmetric as issymmetric +from typing import Final, Literal + +from scipy._typing import Untyped, UntypedArray + +__all__ = ["BFGS", "SR1", "HessianUpdateStrategy"] class HessianUpdateStrategy: - def initialize(self, n, approx_type): ... - def update(self, delta_x, delta_grad): ... - def dot(self, p): ... - def get_matrix(self): ... + def initialize(self, /, n: int, approx_type: Literal["hess", "inv_hess"]) -> None: ... + def update(self, /, delta_x: UntypedArray, delta_grad: UntypedArray) -> None: ... + def dot(self, /, p: Untyped) -> UntypedArray: ... + def get_matrix(self, /) -> UntypedArray: ... class FullHessianUpdateStrategy(HessianUpdateStrategy): init_scale: Untyped @@ -13,20 +16,25 @@ class FullHessianUpdateStrategy(HessianUpdateStrategy): approx_type: Untyped B: Untyped H: Untyped - def __init__(self, init_scale: str = "auto"): ... n: Untyped - def initialize(self, n, approx_type): ... - def update(self, delta_x, delta_grad): ... - def dot(self, p) -> Untyped: ... - def get_matrix(self) -> Untyped: ... + def __init__(self, /, init_scale: Literal["auto"] | float | UntypedArray = "auto") -> None: ... class BFGS(FullHessianUpdateStrategy): - min_curvature: Untyped - exception_strategy: Untyped + min_curvature: Final[float] + exception_strategy: Final[Literal["skip_update", "damp_update"]] def __init__( - self, exception_strategy: str = "skip_update", min_curvature: Untyped | None = None, init_scale: str = "auto" - ): ... + self, + /, + exception_strategy: Literal["skip_update", "damp_update"] = "skip_update", + min_curvature: float | None = None, + init_scale: Literal["auto"] | float | UntypedArray = "auto", + ) -> None: ... class SR1(FullHessianUpdateStrategy): - min_denominator: Untyped - def __init__(self, min_denominator: float = 1e-08, init_scale: str = "auto"): ... + min_denominator: Final[float] + def __init__( + self, + /, + min_denominator: float = 1e-08, + init_scale: Literal["auto"] | float | UntypedArray = "auto", + ) -> None: ... diff --git a/scipy-stubs/optimize/_trustregion.pyi b/scipy-stubs/optimize/_trustregion.pyi index 5e6351a4..13de3e08 100644 --- a/scipy-stubs/optimize/_trustregion.pyi +++ b/scipy-stubs/optimize/_trustregion.pyi @@ -8,7 +8,7 @@ from scipy.optimize._hessian_update_strategy import HessianUpdateStrategy as Hes __all__: list[str] = [] class BaseQuadraticSubproblem: - def __init__(self, x, fun, jac, hess: Untyped | None = None, hessp: Untyped | None = None): ... + def __init__(self, x, fun, jac, hess: Untyped | None = None, hessp: Untyped | None = None) -> None: ... def __call__(self, p) -> Untyped: ... @property def fun(self) -> Untyped: ... diff --git a/scipy-stubs/optimize/_trustregion_dogleg.pyi b/scipy-stubs/optimize/_trustregion_dogleg.pyi index 4a3c2dbf..bb363c02 100644 --- a/scipy-stubs/optimize/_trustregion_dogleg.pyi +++ b/scipy-stubs/optimize/_trustregion_dogleg.pyi @@ -1,7 +1,11 @@ +from typing_extensions import override + +import numpy as np from scipy._typing import Untyped -from ._trustregion import BaseQuadraticSubproblem as BaseQuadraticSubproblem +from ._trustregion import BaseQuadraticSubproblem class DoglegSubproblem(BaseQuadraticSubproblem): def cauchy_point(self) -> Untyped: ... def newton_point(self) -> Untyped: ... - def solve(self, trust_radius) -> Untyped: ... + @override + def solve(self, trust_radius: float | np.float64) -> Untyped: ... diff --git a/scipy-stubs/optimize/_trustregion_ncg.pyi b/scipy-stubs/optimize/_trustregion_ncg.pyi index 15085fb3..7c744b86 100644 --- a/scipy-stubs/optimize/_trustregion_ncg.pyi +++ b/scipy-stubs/optimize/_trustregion_ncg.pyi @@ -1,5 +1,9 @@ +from typing_extensions import override + +import numpy as np from scipy._typing import Untyped -from ._trustregion import BaseQuadraticSubproblem as BaseQuadraticSubproblem +from ._trustregion import BaseQuadraticSubproblem class CGSteihaugSubproblem(BaseQuadraticSubproblem): - def solve(self, trust_radius) -> Untyped: ... + @override + def solve(self, trust_radius: float | np.float64) -> Untyped: ... From 94cb93cdd16a758f77f80314fc67be3294c4bab6 Mon Sep 17 00:00:00 2001 From: jorenham Date: Tue, 10 Sep 2024 13:18:45 +0200 Subject: [PATCH 09/11] fix pyright errors in `scipy.optimize._trustregion_constr` --- .../canonical_constraint.pyi | 55 ++++++- .../equality_constrained_sqp.pyi | 49 +++--- .../_trustregion_constr/qp_subproblem.pyi | 151 +++++++++++++++--- .../optimize/_trustregion_constr/report.pyi | 12 +- 4 files changed, 210 insertions(+), 57 deletions(-) diff --git a/scipy-stubs/optimize/_trustregion_constr/canonical_constraint.pyi b/scipy-stubs/optimize/_trustregion_constr/canonical_constraint.pyi index 00b6ed21..ae1ebd21 100644 --- a/scipy-stubs/optimize/_trustregion_constr/canonical_constraint.pyi +++ b/scipy-stubs/optimize/_trustregion_constr/canonical_constraint.pyi @@ -1,18 +1,59 @@ +from collections.abc import Callable +from typing import TypeAlias, TypeVar +from typing_extensions import Self + +import numpy as np +import optype as op +import optype.numpy as onpt from scipy._typing import Untyped +from scipy.optimize._constraints import PreparedConstraint +from scipy.sparse import csr_matrix +from scipy.sparse.linalg._interface import LinearOperator + +_T = TypeVar("_T") +_Tuple2: TypeAlias = tuple[_T, _T] + +_FunConstr: TypeAlias = Callable[[onpt.Array[tuple[int], np.float64]], _Tuple2[onpt.Array[tuple[int], np.float64]]] +_FunJac: TypeAlias = Callable[[onpt.Array[tuple[int], np.float64]], _Tuple2[onpt.Array[tuple[int, int], np.float64] | csr_matrix]] +_FunHess: TypeAlias = Callable[ + [onpt.Array[tuple[int], np.float64], onpt.Array[tuple[int], np.float64], onpt.Array[tuple[int], np.float64]], + _Tuple2[onpt.Array[tuple[int, int], np.float64] | csr_matrix | LinearOperator], +] + +# tighter than `Iterable[PreparedConstraint]` ;) +_PreparedConstraints: TypeAlias = op.CanIter[op.CanNext[CanonicalConstraint]] class CanonicalConstraint: - n_eq: Untyped - n_ineq: Untyped + n_eq: int + n_ineq: int fun: Untyped jac: Untyped hess: Untyped keep_feasible: Untyped - def __init__(self, n_eq, n_ineq, fun, jac, hess, keep_feasible) -> None: ... + def __init__( + self, + /, + n_eq: int, + n_ineq: int, + fun: _FunConstr, + jac: _FunJac, + hess: _FunHess, + keep_feasible: onpt.Array[tuple[int], np.bool_], + ) -> None: ... @classmethod - def from_PreparedConstraint(cls, constraint) -> Untyped: ... + def from_PreparedConstraint(cls, constraint: PreparedConstraint) -> Self: ... @classmethod - def empty(cls, n) -> Untyped: ... + def empty(cls, n: op.CanIndex) -> Self: ... @classmethod - def concatenate(cls, canonical_constraints, sparse_jacobian) -> Untyped: ... + def concatenate(cls, canonical_constraints: _PreparedConstraints, sparse_jacobian: bool | np.bool_) -> Self: ... -def initial_constraints_as_canonical(n, prepared_constraints, sparse_jacobian) -> Untyped: ... +def initial_constraints_as_canonical( + n: op.CanIndex, + prepared_constraints: _PreparedConstraints, + sparse_jacobian: bool | np.bool_, +) -> tuple[ + onpt.Array[onpt.AtMost2D, np.float64], + onpt.Array[onpt.AtMost2D, np.float64], + onpt.Array[tuple[int, int], np.float64] | csr_matrix, + onpt.Array[tuple[int, int], np.float64] | csr_matrix, +]: ... diff --git a/scipy-stubs/optimize/_trustregion_constr/equality_constrained_sqp.pyi b/scipy-stubs/optimize/_trustregion_constr/equality_constrained_sqp.pyi index fe490b25..979fd523 100644 --- a/scipy-stubs/optimize/_trustregion_constr/equality_constrained_sqp.pyi +++ b/scipy-stubs/optimize/_trustregion_constr/equality_constrained_sqp.pyi @@ -1,27 +1,30 @@ -from scipy._typing import Untyped -from .projections import projections as projections -from .qp_subproblem import ( - box_intersections as box_intersections, - modified_dogleg as modified_dogleg, - projected_cg as projected_cg, -) +from typing import Any, TypeVar -def default_scaling(x) -> Untyped: ... +import numpy as np +import optype.numpy as onpt +from scipy._typing import Untyped, UntypedCallable +from scipy.sparse import dia_matrix + +__all__ = ["equality_constrained_sqp"] + +_StateT = TypeVar("_StateT") + +def default_scaling(x: onpt.Array[tuple[int]]) -> dia_matrix: ... def equality_constrained_sqp( - fun_and_constr, - grad_and_jac, - lagr_hess, - x0, - fun0, - grad0, - constr0, - jac0, - stop_criteria, - state, - initial_penalty, - initial_trust_radius, - factorization_method, + fun_and_constr: Untyped, + grad_and_jac: Untyped, + lagr_hess: Untyped, + x0: onpt.Array[tuple[int], np.floating[Any]], + fun0: Untyped, + grad0: Untyped, + constr0: Untyped, + jac0: Untyped, + stop_criteria: Untyped, + state: _StateT, + initial_penalty: Untyped, + initial_trust_radius: Untyped, + factorization_method: Untyped, trust_lb: Untyped | None = None, trust_ub: Untyped | None = None, - scaling=..., -) -> Untyped: ... + scaling: UntypedCallable = ..., +) -> tuple[onpt.Array[tuple[int], np.floating[Any]], _StateT]: ... diff --git a/scipy-stubs/optimize/_trustregion_constr/qp_subproblem.pyi b/scipy-stubs/optimize/_trustregion_constr/qp_subproblem.pyi index 0b7fd5f6..b3675113 100644 --- a/scipy-stubs/optimize/_trustregion_constr/qp_subproblem.pyi +++ b/scipy-stubs/optimize/_trustregion_constr/qp_subproblem.pyi @@ -1,24 +1,129 @@ -from scipy._typing import Untyped -from scipy.sparse import bmat as bmat, csc_matrix as csc_matrix, linalg as linalg - -def eqp_kktfact(H, c, A, b) -> Untyped: ... -def sphere_intersections(z, d, trust_radius, entire_line: bool = False) -> Untyped: ... -def box_intersections(z, d, lb, ub, entire_line: bool = False) -> Untyped: ... -def box_sphere_intersections(z, d, lb, ub, trust_radius, entire_line: bool = False, extra_info: bool = False) -> Untyped: ... -def inside_box_boundaries(x, lb, ub) -> Untyped: ... -def reinforce_box_boundaries(x, lb, ub) -> Untyped: ... -def modified_dogleg(A, Y, b, trust_radius, lb, ub) -> Untyped: ... +from collections.abc import Sequence +from typing import Any, Literal, TypeAlias, TypedDict, overload +from typing_extensions import NotRequired, TypeVar + +import numpy as np +import optype.numpy as onpt +from scipy.sparse import sparray, spmatrix +from scipy.sparse.linalg import LinearOperator + +__all__ = [ + "box_intersections", + "box_sphere_intersections", + "eqp_kktfact", + "inside_box_boundaries", + "modified_dogleg", + "projected_cg", + "sphere_intersections", +] + +_ScalarB1: TypeAlias = bool | np.bool_ +_ScalarF8: TypeAlias = float | np.float64 +_VectorF8: TypeAlias = onpt.Array[tuple[int], np.float64] + +_ScalarInt_co: TypeAlias = np.integer[Any] +_ScalarFloat_co: TypeAlias = np.floating[Any] | _ScalarInt_co + +_ScalarLikeInt_co: TypeAlias = int | _ScalarInt_co +_ScalarLikeFloat_co: TypeAlias = float | _ScalarFloat_co +_VectorLikeFloat_co: TypeAlias = Sequence[_ScalarLikeFloat_co] | onpt.CanArray[tuple[int], np.dtype[_ScalarFloat_co]] + +_ShapeT = TypeVar("_ShapeT", bound=tuple[int, ...]) +_SCT_float = TypeVar("_SCT_float", bound=_ScalarFloat_co) + +_SparseArray: TypeAlias = sparray | spmatrix + +class _SphereInfoDict(TypedDict): + ta: _ScalarF8 + tb: _ScalarF8 + intersect: bool + +class _ProjectedCGDict(TypedDict): + niter: int + stop_cond: Literal[1, 2, 3, 4] + hits_boundary: bool + allvecs: NotRequired[Sequence[_VectorF8]] + +def eqp_kktfact( + H: _SparseArray, + c: _VectorLikeFloat_co, + A: _SparseArray, + b: _VectorLikeFloat_co, +) -> tuple[_VectorF8, _VectorF8]: ... +def sphere_intersections( + z: _VectorLikeFloat_co, + d: _VectorLikeFloat_co, + trust_radius: _ScalarLikeFloat_co, + entire_line: _ScalarB1 = False, +) -> tuple[_ScalarF8, _ScalarF8, _ScalarB1]: ... +def box_intersections( + z: _VectorLikeFloat_co, + d: _VectorLikeFloat_co, + lb: _VectorLikeFloat_co, + ub: _VectorLikeFloat_co, + entire_line: _ScalarB1 = False, +) -> tuple[_ScalarF8, _ScalarF8, _ScalarB1]: ... +@overload +def box_sphere_intersections( + z: _VectorLikeFloat_co, + d: _VectorLikeFloat_co, + lb: _VectorLikeFloat_co, + ub: _VectorLikeFloat_co, + trust_radius: _ScalarLikeFloat_co, + entire_line: _ScalarB1 = False, + extra_info: Literal[False, 0, None] = False, +) -> tuple[_ScalarF8, _ScalarF8, _ScalarB1]: ... +@overload +def box_sphere_intersections( + z: _VectorLikeFloat_co, + d: _VectorLikeFloat_co, + lb: _VectorLikeFloat_co, + ub: _VectorLikeFloat_co, + trust_radius: _ScalarLikeFloat_co, + entire_line: _ScalarB1, + extra_info: Literal[True, 1], +) -> tuple[_ScalarF8, _ScalarF8, _ScalarB1, _SphereInfoDict, _SphereInfoDict]: ... +@overload +def box_sphere_intersections( + z: _VectorLikeFloat_co, + d: _VectorLikeFloat_co, + lb: _VectorLikeFloat_co, + ub: _VectorLikeFloat_co, + trust_radius: _ScalarLikeFloat_co, + entire_line: _ScalarB1 = False, + *, + extra_info: Literal[True, 1], +) -> tuple[_ScalarF8, _ScalarF8, _ScalarB1, _SphereInfoDict, _SphereInfoDict]: ... + +def inside_box_boundaries( + x: onpt.Array[_ShapeT, _ScalarFloat_co], + lb: onpt.Array[_ShapeT, _ScalarFloat_co], + ub: onpt.Array[_ShapeT, _ScalarFloat_co], +) -> np.bool_: ... +def reinforce_box_boundaries( + x: onpt.Array[_ShapeT, _SCT_float], + lb: onpt.Array[_ShapeT, _SCT_float], + ub: onpt.Array[_ShapeT, _SCT_float], +) -> onpt.Array[_ShapeT, _SCT_float]: ... +def modified_dogleg( + A: LinearOperator | _SparseArray | onpt.Array[tuple[int, ...], _ScalarFloat_co], + Y: LinearOperator | _SparseArray | onpt.Array[tuple[int, ...], _ScalarFloat_co], + b: _VectorLikeFloat_co, + trust_radius: _ScalarLikeFloat_co, + lb: _VectorLikeFloat_co, + ub: _VectorLikeFloat_co, +) -> _VectorF8: ... def projected_cg( - H, - c, - Z, - Y, - b, - trust_radius=..., - lb: Untyped | None = None, - ub: Untyped | None = None, - tol: Untyped | None = None, - max_iter: Untyped | None = None, - max_infeasible_iter: Untyped | None = None, - return_all: bool = False, -) -> Untyped: ... + H: LinearOperator | _SparseArray | onpt.Array[tuple[int, ...], _ScalarFloat_co], + c: _VectorLikeFloat_co, + Z: LinearOperator | _SparseArray | onpt.Array[tuple[int, ...], _ScalarFloat_co], + Y: LinearOperator | _SparseArray | onpt.Array[tuple[int, ...], _ScalarFloat_co], + b: _VectorLikeFloat_co, + trust_radius: _ScalarLikeFloat_co = ..., + lb: _ScalarLikeFloat_co | None = None, + ub: _ScalarLikeFloat_co | None = None, + tol: _ScalarLikeFloat_co | None = None, + max_iter: _ScalarLikeInt_co | None = None, + max_infeasible_iter: _ScalarLikeInt_co | np.integer[Any] | None = None, + return_all: _ScalarB1 = False, +) -> tuple[_VectorF8, _ProjectedCGDict]: ... diff --git a/scipy-stubs/optimize/_trustregion_constr/report.pyi b/scipy-stubs/optimize/_trustregion_constr/report.pyi index 750e564b..b42e7015 100644 --- a/scipy-stubs/optimize/_trustregion_constr/report.pyi +++ b/scipy-stubs/optimize/_trustregion_constr/report.pyi @@ -1,11 +1,15 @@ +from collections.abc import Sequence +from typing import ClassVar + class ReportBase: - COLUMN_NAMES: list[str] - COLUMN_WIDTHS: list[int] - ITERATION_FORMATS: list[str] + COLUMN_NAMES: ClassVar[Sequence[str]] = ... + COLUMN_WIDTHS: ClassVar[Sequence[int]] = ... + ITERATION_FORMATS: ClassVar[Sequence[str]] = ... + @classmethod def print_header(cls) -> None: ... @classmethod - def print_iteration(cls, *args) -> None: ... + def print_iteration(cls, /, *args: object) -> None: ... @classmethod def print_footer(cls) -> None: ... From f4964ae5632b5a4da2a38508a335c2b68ad2b0ea Mon Sep 17 00:00:00 2001 From: jorenham Date: Tue, 10 Sep 2024 16:41:54 +0200 Subject: [PATCH 10/11] fix pyright errors in `scipy.optimize._shgo_lib` --- scipy-stubs/optimize/_shgo_lib/_complex.pyi | 129 +++++++---- scipy-stubs/optimize/_shgo_lib/_vertex.pyi | 223 +++++++++++--------- 2 files changed, 217 insertions(+), 135 deletions(-) diff --git a/scipy-stubs/optimize/_shgo_lib/_complex.pyi b/scipy-stubs/optimize/_shgo_lib/_complex.pyi index 225a663c..a3ee7b46 100644 --- a/scipy-stubs/optimize/_shgo_lib/_complex.pyi +++ b/scipy-stubs/optimize/_shgo_lib/_complex.pyi @@ -1,50 +1,97 @@ -from collections.abc import Generator +from collections.abc import Generator, Sequence +from typing import Any, TypeAlias -from scipy._typing import Untyped -from ._vertex import VertexCacheField as VertexCacheField, VertexCacheIndex as VertexCacheIndex +import numpy as np +import optype as op +import optype.numpy as onpt +from scipy._typing import Untyped, UntypedCallable, UntypedTuple +from ._vertex import VertexBase, VertexCacheBase + +_Location: TypeAlias = Sequence[float] +_Bounds: TypeAlias = Sequence[tuple[float, float]] +_Constraints: TypeAlias = dict[str, object] | Sequence[dict[str, object]] # TODO: TypedDict +_Symmetry: TypeAlias = op.CanGetitem[int, op.CanIndex] +_CyclicProduct: TypeAlias = Generator[tuple[float, ...], None, tuple[float, ...]] class Complex: - dim: Untyped - domain: Untyped - bounds: Untyped - symmetry: Untyped - sfield: Untyped - sfield_args: Untyped - min_cons: Untyped - g_cons: Untyped - g_args: Untyped + dim: int + domain: _Bounds + bounds: _Bounds + symmetry: _Symmetry + sfield: UntypedCallable + sfield_args: UntypedTuple + min_cons: _Constraints # only set if `constraints` is not None + g_cons: UntypedTuple | None + g_args: UntypedTuple | None gen: int perm_cycle: int - H: Untyped - V: Untyped - V_non_symm: Untyped + + H: list[Untyped] + V: VertexCacheBase + V_non_symm: list[VertexBase] + origin: list[float] + supremum: list[float] + cp: _CyclicProduct + triangulated_vectors: list[tuple[tuple[float, ...], tuple[float, ...]]] + rls: Untyped def __init__( self, - dim, - domain: Untyped | None = None, - sfield: Untyped | None = None, - sfield_args=(), - symmetry: Untyped | None = None, - constraints: Untyped | None = None, + /, + dim: int, + domain: _Bounds | None = None, + sfield: UntypedCallable | None = None, + sfield_args: UntypedTuple = (), + symmetry: _Symmetry | None = None, + constraints: _Constraints | None = None, workers: int = 1, - ): ... - def __call__(self) -> Untyped: ... - def cyclic_product(self, bounds, origin, supremum, centroid: bool = True) -> Generator[Untyped, None, Untyped]: ... - origin: Untyped - supremum: Untyped - cp: Untyped - triangulated_vectors: Untyped + ) -> None: ... + def __call__(self, /) -> Untyped: ... + def cyclic_product( + self, + /, + bounds: _Bounds, + origin: _Location, + supremum: _Location, + centroid: bool = True, + ) -> _CyclicProduct: ... def triangulate( - self, n: Untyped | None = None, symmetry: Untyped | None = None, centroid: bool = True, printout: bool = False - ): ... - rls: Untyped - def refine(self, n: int = 1): ... - def refine_all(self, centroids: bool = True): ... - def refine_local_space(self, origin, supremum, bounds, centroid: int = 1) -> Generator[Untyped, None, None]: ... - def refine_star(self, v): ... - def split_edge(self, v1, v2) -> Untyped: ... - def vpool(self, origin, supremum) -> Untyped: ... - def vf_to_vv(self, vertices, simplices): ... - def connect_vertex_non_symm(self, v_x, near: Untyped | None = None) -> Untyped: ... - def in_simplex(self, S, v_x, A_j0: Untyped | None = None) -> Untyped: ... - def deg_simplex(self, S, proj: Untyped | None = None) -> Untyped: ... + self, + /, + n: int | None = None, + symmetry: _Symmetry | None = None, + centroid: bool = True, + printout: bool = False, + ) -> None: ... + def refine(self, /, n: int = 1) -> None: ... + def refine_all(self, /, centroids: bool = True) -> None: ... + def refine_local_space( + self, + /, + origin: _Location, + supremum: _Location, + bounds: _Bounds, + centroid: int = 1, + ) -> Generator[VertexBase | tuple[float, ...], None, None]: ... + def refine_star(self, /, v: VertexBase) -> None: ... + def split_edge(self, /, v1: VertexBase, v2: VertexBase) -> VertexBase: ... + def vpool(self, /, origin: _Location, supremum: _Location) -> set[VertexBase]: ... + def vf_to_vv(self, /, vertices: Sequence[VertexBase], simplices: Sequence[Untyped]) -> None: ... + def connect_vertex_non_symm( + self, + /, + v_x: tuple[float | np.floating[Any]] | onpt.Array[tuple[int], np.floating[Any]], + near: set[VertexBase] | list[VertexBase] | None = None, + ) -> bool | None: ... + def in_simplex( + self, + /, + S: Sequence[float | np.floating[Any]] | onpt.Array[tuple[int, ...], np.floating[Any]], + v_x: onpt.Array[tuple[int], np.floating[Any]], + A_j0: onpt.Array[tuple[int, ...], np.floating[Any]] | None = None, + ) -> Untyped: ... + def deg_simplex( + self, + /, + S: onpt.Array[tuple[int, ...], np.floating[Any]], + proj: onpt.Array[tuple[int, ...], np.floating[Any]] | None = None, + ) -> Untyped: ... diff --git a/scipy-stubs/optimize/_shgo_lib/_vertex.pyi b/scipy-stubs/optimize/_shgo_lib/_vertex.pyi index 5da68ba2..a36625a8 100644 --- a/scipy-stubs/optimize/_shgo_lib/_vertex.pyi +++ b/scipy-stubs/optimize/_shgo_lib/_vertex.pyi @@ -1,117 +1,152 @@ import abc -from typing_extensions import override +from collections import OrderedDict +from collections.abc import Callable, Iterable, Iterator, Sequence +from typing import Any, Final, Generic, TypeAlias +from typing_extensions import Self, TypeVar, override +import numpy as np +import optype.numpy as onpt from scipy._lib._util import MapWrapper as MapWrapper -from scipy._typing import Untyped - -class VertexBase(abc.ABC): - x: Untyped - hash: Untyped - nn: Untyped - index: Untyped - def __init__(self, x, nn: Untyped | None = None, index: Untyped | None = None): ... - x_a: Untyped - def __getattr__(self, item) -> Untyped: ... +from scipy._typing import Untyped, UntypedTuple + +_SCT = TypeVar("_SCT", bound=np.number[Any], default=np.floating[Any]) +_SCT_co = TypeVar("_SCT_co", bound=np.number[Any], covariant=True, default=np.floating[Any]) + +_Vector: TypeAlias = onpt.Array[tuple[int], _SCT] +_VectorLike: TypeAlias = tuple[float | _SCT, ...] | _Vector[_SCT] + +_ScalarField: TypeAlias = Callable[[_Vector[_SCT]], float | _SCT] +_VectorField: TypeAlias = Callable[[_Vector[_SCT]], _Vector[_SCT]] +_ScalarFieldCons: TypeAlias = Callable[[_Vector[_SCT]], Untyped] # TODO + +class VertexBase(Generic[_SCT_co], metaclass=abc.ABCMeta): + x: _VectorLike[_SCT_co] + x_a: _Vector[_SCT_co] # lazy + hash: Final[int] + index: Final[int | None] + nn: set[Self] + + st: set[Self] # might not be set + feasible: bool # might not be set + + def __init__(self, /, x: _VectorLike[_SCT_co], nn: Iterable[Self] | None = None, index: int | None = None) -> None: ... @abc.abstractmethod - def connect(self, v) -> Untyped: ... + def connect(self, /, v: Self) -> None: ... @abc.abstractmethod - def disconnect(self, v) -> Untyped: ... - st: Untyped - def star(self) -> Untyped: ... + def disconnect(self, /, v: Self) -> None: ... + def star(self, /) -> set[Self]: ... -class VertexScalarField(VertexBase): +class VertexScalarField(VertexBase[_SCT_co], Generic[_SCT_co]): check_min: bool check_max: bool + # TODO: Support non-empty `field_args` and `g_cons_args` def __init__( self, - x, - field: Untyped | None = None, - nn: Untyped | None = None, - index: Untyped | None = None, - field_args=(), - g_cons: Untyped | None = None, - g_cons_args=(), - ): ... + /, + x: _VectorLike[_SCT_co], + field: _ScalarField[_SCT_co] | None = None, + nn: Iterable[Self] | None = None, + index: int | None = None, + field_args: tuple[()] = (), + g_cons: _ScalarFieldCons[_SCT_co] | None = None, + g_cons_args: tuple[()] = (), + ) -> None: ... @override - def connect(self, v) -> Untyped: ... + def connect(self, /, v: Self) -> None: ... @override - def disconnect(self, v) -> Untyped: ... - def minimiser(self) -> Untyped: ... - def maximiser(self) -> Untyped: ... + def disconnect(self, /, v: Self) -> None: ... + def minimiser(self, /) -> bool: ... + def maximiser(self, /) -> bool: ... -class VertexVectorField(VertexBase, metaclass=abc.ABCMeta): +class VertexVectorField(VertexBase[_SCT_co], Generic[_SCT_co], metaclass=abc.ABCMeta): + # NOTE: The implementaiton is a WIP + # TODO: Support non-empty `field_args`, `vfield_args`, and `g_cons_args` def __init__( self, - x, - sfield: Untyped | None = None, - vfield: Untyped | None = None, - field_args=(), - vfield_args=(), - g_cons: Untyped | None = None, - g_cons_args=(), - nn: Untyped | None = None, - index: Untyped | None = None, - ): ... - -class VertexCacheBase: - cache: Untyped - nfev: int - index: int - def __init__(self) -> None: ... - def __iter__(self) -> Untyped: ... - def size(self) -> Untyped: ... - def print_out(self): ... + /, + x: _VectorLike[_SCT_co], + sfield: _ScalarField[_SCT_co] | None = None, + vfield: _VectorField[_SCT_co] | None = None, + field_args: tuple[()] = (), + vfield_args: tuple[()] = (), + g_cons: _ScalarFieldCons[_SCT_co] | None = None, + g_cons_args: tuple[()] = (), + nn: Iterable[Self] | None = None, + index: int | None = None, + ) -> None: ... + @override + def connect(self, /, v: Self) -> None: ... + @override + def disconnect(self, /, v: Self) -> None: ... -class VertexCube(VertexBase): - def __init__(self, x, nn: Untyped | None = None, index: Untyped | None = None): ... +class VertexCube(VertexBase[_SCT_co], Generic[_SCT_co]): + def __init__(self, /, x: _VectorLike[_SCT_co], nn: Iterable[Self] | None = None, index: int | None = None) -> None: ... @override - def connect(self, v) -> Untyped: ... + def connect(self, /, v: Self) -> None: ... @override - def disconnect(self, v) -> Untyped: ... + def disconnect(self, /, v: Self) -> None: ... + +_KT = TypeVar("_KT", default=Untyped) # TODO: Select a decent default +_VT = TypeVar("_VT", bound=VertexBase, default=VertexBase) + +class VertexCacheBase(Generic[_KT, _VT]): + cache: OrderedDict[_KT, _VT] + nfev: int + index: int + def __init__(self, /) -> None: ... + def __iter__(self, /) -> Iterator[_VT]: ... + def size(self, /) -> int: ... + def print_out(self, /) -> None: ... -class VertexCacheIndex(VertexCacheBase): - Vertex: Untyped - def __init__(self) -> None: ... - def __getitem__(self, x, nn: Untyped | None = None) -> Untyped: ... +class VertexCacheIndex(VertexCacheBase[_KT, _VT], Generic[_KT, _VT]): + Vertex: type[_VT] + def __getitem__(self, x: _KT, /, nn: None = None) -> _VT: ... -class VertexCacheField(VertexCacheBase): +class VertexCacheField(VertexCacheBase[_KT, _VT], Generic[_KT, _VT, _SCT_co]): index: int - Vertex: Untyped - field: Untyped - field_args: Untyped - wfield: Untyped - g_cons: Untyped - g_cons_args: Untyped - wgcons: Untyped - gpool: Untyped - fpool: Untyped + Vertex: type[_VT] + field: _ScalarField[_SCT_co] + field_args: tuple[()] + wfield: FieldWrapper[_SCT_co] + g_cons: Sequence[_ScalarFieldCons[_SCT_co]] + g_cons_args: tuple[()] + wgcons: ConstraintWrapper[_SCT_co] + gpool: set[UntypedTuple] + fpool: set[UntypedTuple] sfc_lock: bool - workers: Untyped - process_gpool: Untyped - process_fpool: Untyped + workers: int + process_gpool: Callable[[], None] + process_fpool: Callable[[], None] def __init__( - self, field: Untyped | None = None, field_args=(), g_cons: Untyped | None = None, g_cons_args=(), workers: int = 1 - ): ... - def __getitem__(self, x, nn: Untyped | None = None) -> Untyped: ... - def process_pools(self): ... - def feasibility_check(self, v): ... - def compute_sfield(self, v): ... - def proc_gpool(self): ... - def pproc_gpool(self): ... - def proc_fpool_g(self): ... - def proc_fpool_nog(self): ... - def pproc_fpool_g(self): ... - def pproc_fpool_nog(self): ... - def proc_minimisers(self): ... - -class ConstraintWrapper: - g_cons: Untyped - g_cons_args: Untyped - def __init__(self, g_cons, g_cons_args) -> None: ... - def gcons(self, v_x_a) -> Untyped: ... - -class FieldWrapper: - field: Untyped - field_args: Untyped - def __init__(self, field, field_args) -> None: ... - def func(self, v_x_a) -> Untyped: ... + self, + /, + field: Untyped | None = None, + field_args: tuple[()] = (), + g_cons: Sequence[_ScalarFieldCons[_SCT_co]] | None = None, + g_cons_args: tuple[()] = (), + workers: int = 1, + ) -> None: ... + def __getitem__(self, x: _KT, /, nn: Iterable[_VT] | None = None) -> _VT: ... + def process_pools(self, /) -> None: ... + def feasibility_check(self, /, v: _VT) -> bool: ... + def compute_sfield(self, /, v: _VT) -> None: ... + def proc_gpool(self, /) -> None: ... + def pproc_gpool(self, /) -> None: ... + def proc_fpool_g(self, /) -> None: ... + def proc_fpool_nog(self, /) -> None: ... + def pproc_fpool_g(self, /) -> None: ... + def pproc_fpool_nog(self, /) -> None: ... + def proc_minimisers(self, /) -> None: ... + +class ConstraintWrapper(Generic[_SCT]): + g_cons: Sequence[_ScalarFieldCons[_SCT]] + g_cons_args: Sequence[UntypedTuple] + def __init__(self, /, g_cons: Sequence[_ScalarFieldCons[_SCT]], g_cons_args: Sequence[UntypedTuple]) -> None: ... + def gcons(self, /, v_x_a: _Vector[_SCT]) -> bool: ... + +class FieldWrapper(Generic[_SCT]): + # TODO: Support non-empty `g_cons_args` + field: _ScalarField[_SCT] | _VectorField[_SCT] + field_args: tuple[()] + def __init__(self, /, field: _ScalarField[_SCT] | _VectorField[_SCT], field_args: tuple[()]) -> None: ... + def func(self, /, v_x_a: _Vector[_SCT]) -> _SCT: ... From 9e97f5695c8e27ed521a24d71f9723e458ccf643 Mon Sep 17 00:00:00 2001 From: jorenham Date: Wed, 2 Oct 2024 16:44:50 +0200 Subject: [PATCH 11/11] complete `scipy.optimize._lsq` stubs --- scipy-stubs/_typing.pyi | 2 + scipy-stubs/optimize/_lsq/bvls.pyi | 25 +++- scipy-stubs/optimize/_lsq/common.pyi | 181 +++++++++++++++++++---- scipy-stubs/optimize/_lsq/dogbox.pyi | 99 ++++++++++--- scipy-stubs/optimize/_lsq/lsq_linear.pyi | 42 ++++-- scipy-stubs/optimize/_lsq/trf.pyi | 118 ++++++++++----- scipy-stubs/optimize/_optimize.pyi | 18 ++- scipy-stubs/optimize/_typing.pyi | 43 ++++-- 8 files changed, 400 insertions(+), 128 deletions(-) diff --git a/scipy-stubs/_typing.pyi b/scipy-stubs/_typing.pyi index 203d55ed..3f322976 100644 --- a/scipy-stubs/_typing.pyi +++ b/scipy-stubs/_typing.pyi @@ -17,6 +17,7 @@ __all__ = [ "AnyScalar", "AnyShape", "Array0D", + "Casting", "CorrelateMode", "NanPolicy", "Seed", @@ -54,6 +55,7 @@ AnyShape: TypeAlias = op.CanIndex | Sequence[op.CanIndex] # numpy literals RNG: TypeAlias = np.random.Generator | np.random.RandomState Seed: TypeAlias = int | RNG +Casting: TypeAlias = Literal["no", "equiv", "safe", "same_kind", "unsafe"] CorrelateMode: TypeAlias = Literal["valid", "same", "full"] # scipy literals diff --git a/scipy-stubs/optimize/_lsq/bvls.pyi b/scipy-stubs/optimize/_lsq/bvls.pyi index e41e16fb..b8ce693e 100644 --- a/scipy-stubs/optimize/_lsq/bvls.pyi +++ b/scipy-stubs/optimize/_lsq/bvls.pyi @@ -1,6 +1,21 @@ -from scipy._typing import Untyped -from scipy.optimize import OptimizeResult as OptimizeResult -from .common import print_header_linear as print_header_linear, print_iteration_linear as print_iteration_linear +from typing import Any, Literal -def compute_kkt_optimality(g, on_bound) -> Untyped: ... -def bvls(A, b, x_lsq, lb, ub, tol, max_iter, verbose, rcond: Untyped | None = None) -> Untyped: ... +import numpy as np +import numpy.typing as npt +import scipy._typing as spt +from scipy.optimize import OptimizeResult + +def compute_kkt_optimality(g: npt.NDArray[np.floating[Any]] | spt.AnyReal, on_bound: spt.AnyReal) -> np.floating[Any] | float: ... + +# TODO(jorenham): custom `OptimizeResult` return type +def bvls( + A: npt.NDArray[np.floating[Any]], + b: npt.NDArray[np.floating[Any]], + x_lsq: npt.NDArray[np.floating[Any]], + lb: npt.NDArray[np.floating[Any]], + ub: npt.NDArray[np.floating[Any]], + tol: spt.AnyReal, + max_iter: spt.AnyInt, + verbose: Literal[0, 1, 2], + rcond: spt.AnyReal | None = None, +) -> OptimizeResult: ... diff --git a/scipy-stubs/optimize/_lsq/common.pyi b/scipy-stubs/optimize/_lsq/common.pyi index 549bc924..e1eaadd8 100644 --- a/scipy-stubs/optimize/_lsq/common.pyi +++ b/scipy-stubs/optimize/_lsq/common.pyi @@ -1,35 +1,152 @@ -from scipy._typing import Untyped -from scipy.linalg import LinAlgError as LinAlgError, cho_factor as cho_factor, cho_solve as cho_solve -from scipy.sparse import issparse as issparse -from scipy.sparse.linalg import LinearOperator as LinearOperator, aslinearoperator as aslinearoperator +from typing import Any, Final, Literal, TypeAlias -EPS: Untyped +import numpy as np +import numpy.typing as npt +import optype.numpy as onpt +import scipy._typing as spt +from scipy.sparse import sparray, spmatrix +from scipy.sparse.linalg import LinearOperator -def intersect_trust_region(x, s, Delta) -> Untyped: ... +_SparseArray: TypeAlias = sparray | spmatrix + +EPS: Final[float] + +def intersect_trust_region( + x: npt.ArrayLike, + s: npt.ArrayLike, + Delta: spt.AnyReal, +) -> tuple[float | np.float64, float | np.float64]: ... def solve_lsq_trust_region( - n, m, uf, s, V, Delta, initial_alpha: Untyped | None = None, rtol: float = 0.01, max_iter: int = 10 -) -> Untyped: ... -def solve_trust_region_2d(B, g, Delta) -> Untyped: ... -def update_tr_radius(Delta, actual_reduction, predicted_reduction, step_norm, bound_hit) -> Untyped: ... -def build_quadratic_1d(J, g, s, diag: Untyped | None = None, s0: Untyped | None = None) -> Untyped: ... -def minimize_quadratic_1d(a, b, lb, ub, c: int = 0) -> Untyped: ... -def evaluate_quadratic(J, g, s, diag: Untyped | None = None) -> Untyped: ... -def in_bounds(x, lb, ub) -> Untyped: ... -def step_size_to_bound(x, s, lb, ub) -> Untyped: ... -def find_active_constraints(x, lb, ub, rtol: float = 1e-10) -> Untyped: ... -def make_strictly_feasible(x, lb, ub, rstep: float = 1e-10) -> Untyped: ... -def CL_scaling_vector(x, g, lb, ub) -> Untyped: ... -def reflective_transformation(y, lb, ub) -> Untyped: ... -def print_header_nonlinear(): ... -def print_iteration_nonlinear(iteration, nfev, cost, cost_reduction, step_norm, optimality): ... -def print_header_linear(): ... -def print_iteration_linear(iteration, cost, cost_reduction, step_norm, optimality): ... -def compute_grad(J, f) -> Untyped: ... -def compute_jac_scale(J, scale_inv_old: Untyped | None = None) -> Untyped: ... -def left_multiplied_operator(J, d) -> Untyped: ... -def right_multiplied_operator(J, d) -> Untyped: ... -def regularized_lsq_operator(J, diag) -> Untyped: ... -def right_multiply(J, d, copy: bool = True) -> Untyped: ... -def left_multiply(J, d, copy: bool = True) -> Untyped: ... -def check_termination(dF, F, dx_norm, x_norm, ratio, ftol, xtol) -> Untyped: ... -def scale_for_robust_loss_function(J, f, rho) -> Untyped: ... + n: int, + m: int, + uf: npt.NDArray[np.floating[Any]], + s: npt.NDArray[np.floating[Any]], + V: npt.NDArray[np.floating[Any]], + Delta: spt.AnyReal, + initial_alpha: spt.AnyReal | None = None, + rtol: spt.AnyReal = 0.01, + max_iter: spt.AnyInt = 10, +) -> tuple[onpt.Array[tuple[int], np.float64], float, int]: ... +def solve_trust_region_2d( + B: npt.ArrayLike, + g: npt.ArrayLike, + Delta: spt.AnyReal, +) -> tuple[onpt.Array[tuple[Literal[2]], np.float64], bool]: ... +def update_tr_radius( + Delta: spt.AnyReal, + actual_reduction: spt.AnyReal, + predicted_reduction: spt.AnyReal, + step_norm: spt.AnyReal, + bound_hit: spt.AnyBool, +) -> tuple[float, float]: ... +def build_quadratic_1d( + J: npt.NDArray[np.floating[Any]] | _SparseArray | LinearOperator, + g: npt.NDArray[np.floating[Any]], + s: npt.NDArray[np.floating[Any]], + diag: npt.NDArray[np.floating[Any]] | None = None, + s0: npt.NDArray[np.floating[Any]] | None = None, +) -> tuple[float, float, float]: ... +def minimize_quadratic_1d( + a: spt.AnyReal, + b: spt.AnyReal, + lb: npt.ArrayLike, + ub: npt.ArrayLike, + c: spt.AnyReal = 0, +) -> tuple[float, float]: ... +def evaluate_quadratic( + J: npt.NDArray[np.floating[Any]] | _SparseArray | LinearOperator, + g: npt.NDArray[np.floating[Any]], + s: npt.NDArray[np.floating[Any]], + diag: npt.NDArray[np.floating[Any]] | None = None, +) -> np.float64 | onpt.Array[tuple[int], np.float64]: ... +def in_bounds(x: npt.NDArray[np.floating[Any]], lb: npt.ArrayLike, ub: npt.ArrayLike) -> np.bool_: ... +def step_size_to_bound( + x: npt.ArrayLike, + s: npt.ArrayLike, + lb: npt.ArrayLike, + ub: npt.ArrayLike, +) -> tuple[float, npt.NDArray[np.int_]]: ... +def find_active_constraints( + x: npt.ArrayLike, + lb: npt.ArrayLike, + ub: npt.ArrayLike, + rtol: spt.AnyReal = 1e-10, +) -> npt.NDArray[np.int_]: ... +def make_strictly_feasible( + x: npt.NDArray[np.floating[Any]], + lb: npt.ArrayLike, + ub: npt.ArrayLike, + rstep: spt.AnyReal = 1e-10, +) -> npt.NDArray[np.floating[Any]]: ... +def CL_scaling_vector( + x: npt.NDArray[np.floating[Any]], + g: npt.NDArray[np.floating[Any]], + lb: npt.ArrayLike, + ub: npt.ArrayLike, +) -> tuple[npt.NDArray[np.floating[Any]], npt.NDArray[np.floating[Any]]]: ... +def reflective_transformation( + y: npt.NDArray[np.floating[Any]], + lb: npt.ArrayLike, + ub: npt.ArrayLike, +) -> tuple[npt.NDArray[np.floating[Any]], npt.NDArray[np.floating[Any]]]: ... +def print_header_nonlinear() -> None: ... +def print_iteration_nonlinear( + iteration: int, + nfev: int, + cost: float, + cost_reduction: float, + step_norm: float, + optimality: float, +) -> None: ... +def print_header_linear() -> None: ... +def print_iteration_linear( + iteration: int, + cost: float, + cost_reduction: float, + step_norm: float, + optimality: float, +) -> None: ... +def compute_grad( + J: npt.NDArray[np.floating[Any]] | _SparseArray | LinearOperator, + f: npt.NDArray[np.floating[Any]], +) -> npt.NDArray[np.floating[Any]] | _SparseArray: ... +def compute_jac_scale( + J: npt.NDArray[np.floating[Any]] | _SparseArray | LinearOperator, + scale_inv_old: npt.NDArray[np.floating[Any]] | spt.AnyReal | None = None, +) -> tuple[npt.NDArray[np.floating[Any]], npt.NDArray[np.floating[Any]]]: ... +def left_multiplied_operator( + J: npt.NDArray[np.floating[Any]] | _SparseArray | LinearOperator, + d: npt.NDArray[np.floating[Any]], +) -> LinearOperator: ... +def right_multiplied_operator( + J: npt.NDArray[np.floating[Any]] | _SparseArray | LinearOperator, + d: npt.NDArray[np.floating[Any]], +) -> LinearOperator: ... +def regularized_lsq_operator( + J: npt.NDArray[np.floating[Any]] | _SparseArray | LinearOperator, + diag: npt.NDArray[np.floating[Any]], +) -> LinearOperator: ... +def right_multiply( + J: npt.NDArray[np.floating[Any]] | _SparseArray | LinearOperator, + d: npt.NDArray[np.floating[Any]], + copy: bool = True, +) -> npt.NDArray[np.floating[Any]] | _SparseArray | LinearOperator: ... +def left_multiply( + J: npt.NDArray[np.floating[Any]] | _SparseArray | LinearOperator, + d: npt.NDArray[np.floating[Any]], + copy: bool = True, +) -> npt.NDArray[np.floating[Any]] | _SparseArray | LinearOperator: ... +def check_termination( + dF: spt.AnyReal, + F: spt.AnyReal, + dx_norm: spt.AnyReal, + x_norm: spt.AnyReal, + ratio: spt.AnyReal, + ftol: spt.AnyReal, + xtol: spt.AnyReal, +) -> Literal[2, 3, 4] | None: ... +def scale_for_robust_loss_function( + J: npt.NDArray[np.floating[Any]] | _SparseArray | LinearOperator, + f: spt.AnyReal, + rho: npt.NDArray[np.floating[Any]], +) -> tuple[npt.NDArray[np.floating[Any]] | _SparseArray | LinearOperator, spt.AnyReal]: ... diff --git a/scipy-stubs/optimize/_lsq/dogbox.pyi b/scipy-stubs/optimize/_lsq/dogbox.pyi index 5f9a5df9..eb4c38d4 100644 --- a/scipy-stubs/optimize/_lsq/dogbox.pyi +++ b/scipy-stubs/optimize/_lsq/dogbox.pyi @@ -1,24 +1,77 @@ -from scipy._typing import Untyped -from scipy.optimize import OptimizeResult as OptimizeResult -from scipy.sparse.linalg import LinearOperator as LinearOperator, aslinearoperator as aslinearoperator, lsmr as lsmr -from .common import ( - build_quadratic_1d as build_quadratic_1d, - check_termination as check_termination, - compute_grad as compute_grad, - compute_jac_scale as compute_jac_scale, - evaluate_quadratic as evaluate_quadratic, - in_bounds as in_bounds, - minimize_quadratic_1d as minimize_quadratic_1d, - print_header_nonlinear as print_header_nonlinear, - print_iteration_nonlinear as print_iteration_nonlinear, - scale_for_robust_loss_function as scale_for_robust_loss_function, - step_size_to_bound as step_size_to_bound, - update_tr_radius as update_tr_radius, -) - -def lsmr_operator(Jop, d, active_set) -> Untyped: ... -def find_intersection(x, tr_bounds, lb, ub) -> Untyped: ... -def dogleg_step(x, newton_step, g, a, b, tr_bounds, lb, ub) -> Untyped: ... +from collections.abc import Callable, Mapping +from typing import Any, Literal, TypeAlias +from typing_extensions import TypeVar + +import numpy as np +import optype.numpy as onpt +from scipy.optimize import OptimizeResult +from scipy.optimize._typing import SolverLSQ +from scipy.sparse import sparray, spmatrix +from scipy.sparse.linalg import LinearOperator + +# TODO: custom `OptimizeResult`` + +_SCT_i = TypeVar("_SCT_i", bound=np.integer[Any], default=np.int_) +_SCT_f = TypeVar("_SCT_f", bound=np.floating[Any], default=np.float64) + +_N_x = TypeVar("_N_x", bound=int, default=int) +_N_f = TypeVar("_N_f", bound=int, default=int) + +_ValueFloat: TypeAlias = float | _SCT_f + +_VectorBool: TypeAlias = onpt.Array[tuple[_N_x], np.bool_] +_VectorInt: TypeAlias = onpt.Array[tuple[_N_x], _SCT_i] +_VectorFloat: TypeAlias = onpt.Array[tuple[_N_x], _SCT_f] +_MatrixFloat: TypeAlias = onpt.Array[tuple[_N_x, _N_f], _SCT_f] | sparray | spmatrix | LinearOperator + +_FunResid: TypeAlias = Callable[[_VectorFloat[_N_x]], _VectorFloat[_N_f]] +# this type-alias is a workaround to get the correct oder of type params +_FunJac: TypeAlias = Callable[[_VectorFloat[_N_x], _VectorFloat[_N_f]], _MatrixFloat[_N_f, _N_x]] +_FunLoss: TypeAlias = Callable[[_VectorFloat[_N_x]], _ValueFloat] + +def lsmr_operator( + Jop: LinearOperator, + d: _VectorFloat[_N_x, _SCT_f], + active_set: _VectorBool[_N_x], +) -> LinearOperator: ... +def find_intersection( + x: _VectorFloat[_N_x], + tr_bounds: _VectorFloat[_N_x], + lb: _VectorFloat[_N_x], + ub: _VectorFloat[_N_x], +) -> tuple[ + _VectorFloat[_N_x], + _VectorFloat[_N_x], + _VectorBool[_N_x], + _VectorBool[_N_x], + _VectorBool[_N_x], + _VectorBool[_N_x], +]: ... +def dogleg_step( + x: _VectorFloat[_N_x], + newton_step: _VectorFloat[_N_x], + g: _VectorFloat[_N_x], + a: _ValueFloat, + b: _ValueFloat, + tr_bounds: _VectorFloat[_N_x], + lb: _VectorFloat[_N_x], + ub: _VectorFloat[_N_x], +) -> tuple[_VectorFloat[_N_x], _VectorInt[_N_x], np.bool_]: ... def dogbox( - fun, jac, x0, f0, J0, lb, ub, ftol, xtol, gtol, max_nfev, x_scale, loss_function, tr_solver, tr_options, verbose -) -> Untyped: ... + fun: _FunResid[_N_x, _N_f], + jac: _FunJac[_N_x, _N_f], + x0: _VectorFloat[_N_x], + f0: _VectorFloat[_N_f], + J0: _MatrixFloat[_N_f, _N_x], + lb: _VectorFloat[_N_x], + ub: _VectorFloat[_N_x], + ftol: _ValueFloat, + xtol: _ValueFloat, + gtol: _ValueFloat, + max_nfev: int, + x_scale: Literal["jac"] | _ValueFloat | _VectorFloat[_N_f], + loss_function: _FunLoss[_N_x], + tr_solver: SolverLSQ, + tr_options: Mapping[str, object], + verbose: bool, +) -> OptimizeResult: ... diff --git a/scipy-stubs/optimize/_lsq/lsq_linear.pyi b/scipy-stubs/optimize/_lsq/lsq_linear.pyi index f973b659..71474a66 100644 --- a/scipy-stubs/optimize/_lsq/lsq_linear.pyi +++ b/scipy-stubs/optimize/_lsq/lsq_linear.pyi @@ -1,21 +1,39 @@ -from typing import Final +from collections.abc import Sequence +from typing import Any, Final, Literal, TypeAlias -from scipy._typing import Untyped +import numpy as np +import optype.numpy as onpt from scipy.optimize import OptimizeResult +from scipy.optimize._typing import Bound +from scipy.sparse import sparray, spmatrix +from scipy.sparse.linalg import LinearOperator + +_ScalarB1: TypeAlias = bool | np.bool_ +_ScalarF8: TypeAlias = float | np.float64 +_VectorF8: TypeAlias = onpt.Array[tuple[int], np.float64] + +_ScalarInt_co: TypeAlias = np.integer[Any] +_ScalarFloat_co: TypeAlias = np.floating[Any] | _ScalarInt_co + +_ScalarLikeFloat_co: TypeAlias = float | _ScalarFloat_co +_VectorLikeFloat_co: TypeAlias = Sequence[_ScalarLikeFloat_co] | onpt.CanArray[tuple[int], np.dtype[_ScalarFloat_co]] +_MatrixLikeFloat_co: TypeAlias = Sequence[_VectorLikeFloat_co] | onpt.CanArray[tuple[int, int], np.dtype[_ScalarFloat_co]] + +_SparseArray: TypeAlias = sparray | spmatrix TERMINATION_MESSAGES: Final[dict[int, str]] -def prepare_bounds(bounds, n) -> Untyped: ... +def prepare_bounds(bounds: Bound, n: int) -> tuple[_ScalarF8, _ScalarF8] | tuple[_VectorF8, _VectorF8]: ... def lsq_linear( - A, - b, - bounds=..., - method: str = "trf", + A: LinearOperator | _SparseArray | _MatrixLikeFloat_co, + b: _VectorLikeFloat_co, + bounds: Bound = ..., + method: Literal["trf", "bvls"] = "trf", tol: float = 1e-10, - lsq_solver: Untyped | None = None, - lsmr_tol: Untyped | None = None, - max_iter: Untyped | None = None, - verbose: int = 0, + lsq_solver: Literal["exact", "lsmr"] | None = None, + lsmr_tol: Literal["auto"] | float | None = None, + max_iter: int | None = None, + verbose: Literal[0, 1] | _ScalarB1 = 0, *, - lsmr_maxiter: Untyped | None = None, + lsmr_maxiter: int | None = None, ) -> OptimizeResult: ... diff --git a/scipy-stubs/optimize/_lsq/trf.pyi b/scipy-stubs/optimize/_lsq/trf.pyi index ee19d72e..2a55d5f0 100644 --- a/scipy-stubs/optimize/_lsq/trf.pyi +++ b/scipy-stubs/optimize/_lsq/trf.pyi @@ -1,37 +1,89 @@ -from scipy._typing import Untyped -from scipy.linalg import qr as qr, svd as svd -from scipy.optimize import OptimizeResult as OptimizeResult -from scipy.sparse.linalg import lsmr as lsmr -from .common import ( - CL_scaling_vector as CL_scaling_vector, - build_quadratic_1d as build_quadratic_1d, - check_termination as check_termination, - compute_grad as compute_grad, - compute_jac_scale as compute_jac_scale, - evaluate_quadratic as evaluate_quadratic, - find_active_constraints as find_active_constraints, - in_bounds as in_bounds, - intersect_trust_region as intersect_trust_region, - make_strictly_feasible as make_strictly_feasible, - minimize_quadratic_1d as minimize_quadratic_1d, - print_header_nonlinear as print_header_nonlinear, - print_iteration_nonlinear as print_iteration_nonlinear, - regularized_lsq_operator as regularized_lsq_operator, - right_multiplied_operator as right_multiplied_operator, - scale_for_robust_loss_function as scale_for_robust_loss_function, - solve_lsq_trust_region as solve_lsq_trust_region, - solve_trust_region_2d as solve_trust_region_2d, - step_size_to_bound as step_size_to_bound, - update_tr_radius as update_tr_radius, -) +from collections.abc import Callable, Mapping +from typing import Literal, TypeAlias +from typing_extensions import TypeVar + +import numpy as np +import optype.numpy as onpt +from scipy.optimize import OptimizeResult +from scipy.optimize._typing import SolverLSQ +from scipy.sparse import sparray, spmatrix +from scipy.sparse.linalg import LinearOperator + +_ShapeT = TypeVar("_ShapeT", bound=tuple[int, ...], default=tuple[int, ...]) + +_ValueFloat: TypeAlias = float | np.float64 + +_ArrayFloat: TypeAlias = onpt.Array[_ShapeT, np.float64] +_MatrixFloat: TypeAlias = onpt.Array[_ShapeT, np.float64] | sparray | spmatrix | LinearOperator + +_FunObj: TypeAlias = Callable[[_ArrayFloat[tuple[int]], _ValueFloat], _MatrixFloat] +_FunJac: TypeAlias = Callable[[_ArrayFloat[tuple[int]], _ValueFloat], _MatrixFloat] +_FunLoss: TypeAlias = Callable[[_ValueFloat], _ValueFloat] + +# TODO: custom `OptimizeResult`` def trf( - fun, jac, x0, f0, J0, lb, ub, ftol, xtol, gtol, max_nfev, x_scale, loss_function, tr_solver, tr_options, verbose -) -> Untyped: ... -def select_step(x, J_h, diag_h, g_h, p, p_h, d, Delta, lb, ub, theta) -> Untyped: ... + fun: _FunObj, + jac: _FunJac, + x0: _ArrayFloat, + f0: _ValueFloat, + J0: _MatrixFloat, + lb: _ArrayFloat, + ub: _ArrayFloat, + ftol: _ValueFloat, + xtol: _ValueFloat, + gtol: _ValueFloat, + max_nfev: int, + x_scale: Literal["jac"] | _ValueFloat | _ArrayFloat, + loss_function: _FunLoss, + tr_solver: SolverLSQ, + tr_options: Mapping[str, object], + verbose: bool, +) -> OptimizeResult: ... def trf_bounds( - fun, jac, x0, f0, J0, lb, ub, ftol, xtol, gtol, max_nfev, x_scale, loss_function, tr_solver, tr_options, verbose -) -> Untyped: ... + fun: _FunObj, + jac: _FunJac, + x0: _ArrayFloat, + f0: _ValueFloat, + J0: _MatrixFloat, + lb: _ArrayFloat, + ub: _ArrayFloat, + ftol: _ValueFloat, + xtol: _ValueFloat, + gtol: _ValueFloat, + max_nfev: int, + x_scale: Literal["jac"] | _ValueFloat | _ArrayFloat, + loss_function: _FunLoss, + tr_solver: SolverLSQ, + tr_options: Mapping[str, object], + verbose: bool, +) -> OptimizeResult: ... def trf_no_bounds( - fun, jac, x0, f0, J0, ftol, xtol, gtol, max_nfev, x_scale, loss_function, tr_solver, tr_options, verbose -) -> Untyped: ... + fun: _FunObj, + jac: _FunJac, + x0: _ArrayFloat, + f0: _ValueFloat, + J0: _MatrixFloat, + ftol: _ValueFloat, + xtol: _ValueFloat, + gtol: _ValueFloat, + max_nfev: int, + x_scale: Literal["jac"] | _ValueFloat | _ArrayFloat, + loss_function: _FunLoss, + tr_solver: SolverLSQ, + tr_options: Mapping[str, object], + verbose: bool, +) -> OptimizeResult: ... +def select_step( + x: _ArrayFloat, + J_h: _MatrixFloat, + diag_h: _ArrayFloat, + g_h: _ArrayFloat, + p: _ArrayFloat, + p_h: _ArrayFloat, + d: _ArrayFloat, + Delta: _ValueFloat, + lb: _ArrayFloat, + ub: _ArrayFloat, + theta: _ValueFloat, +) -> tuple[_ArrayFloat, _ArrayFloat, _ValueFloat]: ... diff --git a/scipy-stubs/optimize/_optimize.pyi b/scipy-stubs/optimize/_optimize.pyi index fe78a005..c91d51b4 100644 --- a/scipy-stubs/optimize/_optimize.pyi +++ b/scipy-stubs/optimize/_optimize.pyi @@ -1,5 +1,5 @@ from collections.abc import Callable -from typing import Any, Final, Generic, Literal, TypeAlias, overload +from typing import Any, Generic, Literal, TypeAlias, overload from typing_extensions import TypeVar, TypeVarTuple, Unpack import numpy as np @@ -429,13 +429,15 @@ def show_options(solver: Solver | None = None, method: MethodAll | None = None, class BracketError(RuntimeError): ... class OptimizeWarning(UserWarning): ... -class OptimizeResult(_RichResult, Generic[_SCT_f]): - x: onpt.Array[onpt.AtMost1D, _SCT_f] - fun: _SCT_f | float - success: Final[bool] - status: Final[int] - message: Final[str] - nit: Final[int] +_NT = TypeVar("_NT", bound=int, default=int) + +class OptimizeResult(_RichResult, Generic[_NT, _SCT_f]): + x: onpt.Array[tuple[_NT], _SCT_f] + fun: float | _SCT_f + success: bool + status: int + message: str + nit: int # miscellaneous diff --git a/scipy-stubs/optimize/_typing.pyi b/scipy-stubs/optimize/_typing.pyi index 75ad1e87..a7b852af 100644 --- a/scipy-stubs/optimize/_typing.pyi +++ b/scipy-stubs/optimize/_typing.pyi @@ -1,5 +1,5 @@ from collections.abc import Sequence -from typing import Any, Final, Generic, Literal, Protocol, TypeAlias, type_check_only +from typing import Any, Generic, Literal, Protocol, TypeAlias, type_check_only from typing_extensions import NotRequired, TypedDict, TypeVar, TypeVarTuple, Unpack import numpy as np @@ -45,6 +45,7 @@ Constraints: TypeAlias = Constraint | Sequence[Constraint] Brack: TypeAlias = tuple[_ScalarLike_f_co, _ScalarLike_f_co] | tuple[_ScalarLike_f_co, _ScalarLike_f_co, _ScalarLike_f_co] Solver: TypeAlias = Literal["minimize", "minimize_scalar", "root", "root_salar", "linprog", "quadratic_assignment"] + MethodJac: TypeAlias = Literal["2-point", "3-point", "cs"] MethodMimimize: TypeAlias = Literal[ "NELDER-MEAD", "Nelder-Mead", "nelder-mead", @@ -88,29 +89,41 @@ MethodAll: TypeAlias = Literal[ MethodQuadraticAssignment, ] +SolverLSQ: TypeAlias = Literal["exact", "lsmr", None] +MethodLSQ: TypeAlias = Literal["trf", "dogbox", "lm"] + +_NT = TypeVar("_NT", bound=int, default=int) + @type_check_only -class OptimizeResultMinimize(_OptimizeResult[_SCT_f], Generic[_SCT_f]): - jac: onpt.Array[tuple[int], _SCT_f] - nfev: Final[int] - njev: Final[int] - nhev: Final[int] +class OptimizeResultMinimize(_OptimizeResult[_NT, _SCT_f], Generic[_NT, _SCT_f]): + jac: onpt.Array[tuple[_NT], _SCT_f] + nfev: int + njev: int @type_check_only -class OptimizeResultMinimizeHess(OptimizeResultMinimize[_SCT_f], Generic[_SCT_f]): +class OptimizeResultMinimizeHess(OptimizeResultMinimize[_NT, _SCT_f], Generic[_NT, _SCT_f]): hess: onpt.Array[tuple[int, int], _SCT_f] hess_inv: onpt.Array[tuple[int, int], _SCT_f] + nhev: int @type_check_only -class OptimizeResultMinimizeConstr(OptimizeResultMinimize[_SCT_f], Generic[_SCT_f]): - maxcv: Final[float] +class OptimizeResultMinimizeConstr(OptimizeResultMinimize[_NT, _SCT_f], Generic[_NT, _SCT_f]): + maxcv: float @type_check_only -class OptimizeResultMinimizeHessConstr(OptimizeResultMinimize[_SCT_f], Generic[_SCT_f]): - hess: onpt.Array[tuple[int, int], _SCT_f] - hess_inv: onpt.Array[tuple[int, int], _SCT_f] - maxcv: Final[float] +class OptimizeResultMinimizeHessConstr(OptimizeResultMinimize[_NT, _SCT_f], Generic[_NT, _SCT_f]): + hess: onpt.Array[tuple[_NT, _NT], _SCT_f] + hess_inv: onpt.Array[tuple[_NT, _NT], _SCT_f] + maxcv: float @type_check_only -class OptimizeResultLinprog(Generic[_SCT_f]): - slack: onpt.Array[tuple[int], _SCT_f] +class OptimizeResultLinprog(OptimizeResultMinimize[_NT, _SCT_f], Generic[_NT, _SCT_f]): + slack: onpt.Array[tuple[_NT], _SCT_f] con: onpt.Array[tuple[int], _SCT_f] + +@type_check_only +class OptimizeResultLSQ(OptimizeResultMinimize[_NT, _SCT_f], Generic[_NT, _SCT_f]): + cost: float | _SCT_f + optimality: float | _SCT_f + grad: onpt.Array[tuple[_NT], _SCT_f] + active_mask: onpt.Array[tuple[int], np.bool_]