Skip to content

Commit 5aa8f19

Browse files
committed
optimize: tigher linprog params and method-specific options
1 parent 9c846e2 commit 5aa8f19

File tree

2 files changed

+189
-25
lines changed

2 files changed

+189
-25
lines changed

scipy-stubs/optimize/_linprog.pyi

Lines changed: 186 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,203 @@
1-
from collections.abc import Callable, Mapping, Sequence
2-
from typing import Final, Literal, type_check_only
1+
from collections.abc import Callable, Sequence
2+
from typing import Final, Literal, TypeAlias, TypedDict, overload, type_check_only
3+
from typing_extensions import LiteralString, deprecated
34

45
import numpy as np
56
import optype.numpy as onp
6-
from ._optimize import OptimizeResult
7-
from ._typing import Bound, MethodLinprog
7+
import optype.numpy.compat as npc
8+
from ._optimize import OptimizeResult as _OptimizeResult
9+
from ._typing import Bound, MethodLinprog, MethodLinprogLegacy
810

911
__all__ = ["linprog", "linprog_terse_callback", "linprog_verbose_callback"]
1012

13+
###
14+
15+
_Ignored: TypeAlias = object
16+
_Max3: TypeAlias = Literal[0, 1, 2, 3]
17+
_Max4: TypeAlias = Literal[_Max3, 4]
18+
19+
_Int: TypeAlias = int | np.int32 | np.int64
20+
_Float: TypeAlias = float | np.float64
21+
_Float1D: TypeAlias = onp.Array1D[np.float64]
22+
23+
@type_check_only
24+
class _OptionsCommon(TypedDict, total=False):
25+
maxiter: _Int # default: method-specific
26+
disp: onp.ToBool # default: False
27+
presolve: onp.ToBool # default: True
28+
29+
# highs-ds
1130
@type_check_only
12-
class _OptimizeResult(OptimizeResult):
13-
x: onp.ArrayND[np.float64]
14-
fun: float
15-
slack: onp.ArrayND[np.float64]
16-
con: onp.ArrayND[np.float64]
17-
success: bool
18-
status: Literal[0, 1, 2, 3, 4]
19-
nit: int
20-
message: str
31+
class _OptionsHighsDS(_OptionsCommon, TypedDict, total=False):
32+
time_limit: _Float # default: np.finfo(float).max
33+
dual_feasibility_tolerance: _Float # default: 1e-7
34+
primal_feasibility_tolerance: _Float # default: 1e-7
35+
simplex_dual_edge_weight_strategy: Literal["dantzig", "devex", "steepest", "steepest-devex"] | None # default: None
36+
37+
# highs-ips
38+
@type_check_only
39+
class _OptionsHighsIPM(_OptionsHighsDS, TypedDict, total=False):
40+
ipm_optimality_tolerance: _Float # default: 1e-8
41+
42+
# highs
43+
@type_check_only
44+
class _OptionsHighs(_OptionsHighsIPM, TypedDict, total=False):
45+
min_rel_gap: _Float | None # default: None
46+
47+
@type_check_only
48+
class _OptionsCommonLegacy(_OptionsCommon, TypedDict, total=False):
49+
tol: _Float
50+
autoscale: onp.ToBool # default: False
51+
rr: onp.ToBool # default: True
52+
rr_method: Literal["SVD", "pivot", "ID", "None"] | None # default: None
53+
54+
# interior-point (legacy, see https://github.com/scipy/scipy/issues/15707)
55+
@type_check_only
56+
class _OptionsInteriorPoint(_OptionsCommonLegacy, TypedDict, total=False):
57+
alpha0: _Float # default: 0.99995
58+
beta: _Float # default: 0.1
59+
sparse: onp.ToBool # default: False
60+
lstq: onp.ToBool # default: False
61+
sym_pos: onp.ToBool # default: True
62+
cholsky: onp.ToBool # default: True
63+
pc: onp.ToBool # default: True
64+
ip: onp.ToBool # default: False
65+
perm_spec: Literal["NATURAL", "MMD_ATA", "MMD_AT_PLUS_A", "COLAMD"] | None # default: "MMD_AT_PLUS_A"
66+
67+
# revised simplex (legacy, see https://github.com/scipy/scipy/issues/15707)
68+
@type_check_only
69+
class _OptionsRevisedSimplex(_OptionsCommonLegacy, TypedDict, total=False):
70+
maxupdate: _Int # default: 10
71+
mast: onp.ToBool # default: False
72+
pivot: Literal["mrc", "bland"]
73+
74+
# simplex (legacy, see https://github.com/scipy/scipy/issues/15707)
75+
@type_check_only
76+
class _OptionsSimplex(_OptionsCommonLegacy, TypedDict, total=False):
77+
bland: onp.ToBool # default: False
78+
79+
###
80+
81+
__docformat__: Final = "restructuredtext en" # undocumented
82+
LINPROG_METHODS: Final[Sequence[MethodLinprog | MethodLinprogLegacy]] = ... # undocumented
2183

22-
__docformat__: Final[str] = ...
23-
LINPROG_METHODS: Final[Sequence[MethodLinprog]] = ...
84+
class OptimizeResult(_OptimizeResult):
85+
x: _Float1D # minimizing decision variables w.r.t. the constraints
86+
fun: _Float # optimal objective function value
87+
slack: _Float1D # slack values; nominally positive
88+
con: _Float1D # residuals of equality constraints; nominally zero
89+
status: _Max4
90+
message: LiteralString
91+
nit: int # >=0
92+
success: bool # `success = status == 0`
2493

2594
def linprog_verbose_callback(res: _OptimizeResult) -> None: ...
2695
def linprog_terse_callback(res: _OptimizeResult) -> None: ...
2796

2897
#
98+
@overload # highs (default)
99+
def linprog(
100+
c: onp.ToFloat1D,
101+
A_ub: onp.ToFloat2D | None = None,
102+
b_ub: onp.ToFloat1D | None = None,
103+
A_eq: onp.ToFloat2D | None = None,
104+
b_eq: onp.ToFloat1D | None = None,
105+
bounds: Bound = (0, None),
106+
method: Literal["highs"] = "highs",
107+
callback: Callable[[_OptimizeResult], _Ignored] | None = None,
108+
options: _OptionsHighs | None = None,
109+
x0: onp.ToFloat1D | None = None,
110+
integrality: _Max3 | Sequence[_Max3] | onp.CanArrayND[npc.integer] | None = None,
111+
) -> _OptimizeResult: ...
112+
@overload # highs-ds
113+
def linprog(
114+
c: onp.ToFloat1D,
115+
A_ub: onp.ToFloat2D | None = None,
116+
b_ub: onp.ToFloat1D | None = None,
117+
A_eq: onp.ToFloat2D | None = None,
118+
b_eq: onp.ToFloat1D | None = None,
119+
bounds: Bound = (0, None),
120+
*,
121+
method: Literal["highs-ds"],
122+
callback: Callable[[_OptimizeResult], _Ignored] | None = None,
123+
options: _OptionsHighsDS | None = None,
124+
x0: onp.ToFloat1D | None = None,
125+
integrality: _Max3 | Sequence[_Max3] | onp.CanArrayND[npc.integer] | None = None,
126+
) -> _OptimizeResult: ...
127+
@overload # highs-ipm
128+
def linprog(
129+
c: onp.ToFloat1D,
130+
A_ub: onp.ToFloat2D | None = None,
131+
b_ub: onp.ToFloat1D | None = None,
132+
A_eq: onp.ToFloat2D | None = None,
133+
b_eq: onp.ToFloat1D | None = None,
134+
bounds: Bound = (0, None),
135+
*,
136+
method: Literal["highs-ipm"],
137+
callback: Callable[[_OptimizeResult], _Ignored] | None = None,
138+
options: _OptionsHighsIPM | None = None,
139+
x0: onp.ToFloat1D | None = None,
140+
integrality: _Max3 | Sequence[_Max3] | onp.CanArrayND[npc.integer] | None = None,
141+
) -> _OptimizeResult: ...
142+
@overload # interior-point (legacy, see https://github.com/scipy/scipy/issues/15707)
143+
@deprecated("`method='interior-point'` is deprecated and will be removed in SciPy 1.16.0. Please use one of the HIGHS solvers.")
144+
def linprog(
145+
c: onp.ToFloat1D,
146+
A_ub: onp.ToFloat2D | None = None,
147+
b_ub: onp.ToFloat1D | None = None,
148+
A_eq: onp.ToFloat2D | None = None,
149+
b_eq: onp.ToFloat1D | None = None,
150+
bounds: Bound = (0, None),
151+
*,
152+
method: Literal["interior-point"],
153+
callback: Callable[[_OptimizeResult], _Ignored] | None = None,
154+
options: _OptionsInteriorPoint | None = None,
155+
x0: onp.ToFloat1D | None = None,
156+
integrality: _Max3 | Sequence[_Max3] | onp.CanArrayND[npc.integer] | None = None,
157+
) -> _OptimizeResult: ...
158+
@overload # revised simplex (legacy, see https://github.com/scipy/scipy/issues/15707)
159+
@deprecated("`method='revised simplex'` is deprecated and will be removed in SciPy 1.16.0. Please use one of the HIGHS solvers.")
160+
def linprog(
161+
c: onp.ToFloat1D,
162+
A_ub: onp.ToFloat2D | None = None,
163+
b_ub: onp.ToFloat1D | None = None,
164+
A_eq: onp.ToFloat2D | None = None,
165+
b_eq: onp.ToFloat1D | None = None,
166+
bounds: Bound = (0, None),
167+
*,
168+
method: Literal["revised simplex"],
169+
callback: Callable[[_OptimizeResult], _Ignored] | None = None,
170+
options: _OptionsRevisedSimplex | None = None,
171+
x0: onp.ToFloat1D | None = None,
172+
integrality: _Max3 | Sequence[_Max3] | onp.CanArrayND[npc.integer] | None = None,
173+
) -> _OptimizeResult: ...
174+
@overload # simplex (legacy, see https://github.com/scipy/scipy/issues/15707)
175+
@deprecated("`method='simplex'` is deprecated and will be removed in SciPy 1.16.0. Please use one of the HIGHS solvers.")
176+
def linprog(
177+
c: onp.ToFloat1D,
178+
A_ub: onp.ToFloat2D | None = None,
179+
b_ub: onp.ToFloat1D | None = None,
180+
A_eq: onp.ToFloat2D | None = None,
181+
b_eq: onp.ToFloat1D | None = None,
182+
bounds: Bound = (0, None),
183+
*,
184+
method: Literal["simplex"],
185+
callback: Callable[[_OptimizeResult], _Ignored] | None = None,
186+
options: _OptionsSimplex | None = None,
187+
x0: onp.ToFloat1D | None = None,
188+
integrality: _Max3 | Sequence[_Max3] | onp.CanArrayND[npc.integer] | None = None,
189+
) -> _OptimizeResult: ...
190+
@overload # any "highs"
29191
def linprog(
30-
c: onp.ToScalar | onp.ToArrayND,
31-
A_ub: onp.ToScalar | onp.ToArrayND | None = None,
32-
b_ub: onp.ToScalar | onp.ToArrayND | None = None,
33-
A_eq: onp.ToScalar | onp.ToArrayND | None = None,
34-
b_eq: onp.ToScalar | onp.ToArrayND | None = None,
192+
c: onp.ToFloat1D,
193+
A_ub: onp.ToFloat2D | None = None,
194+
b_ub: onp.ToFloat1D | None = None,
195+
A_eq: onp.ToFloat2D | None = None,
196+
b_eq: onp.ToFloat1D | None = None,
35197
bounds: Bound = (0, None),
36198
method: MethodLinprog = "highs",
37-
callback: Callable[[_OptimizeResult], None] | None = None,
38-
options: Mapping[str, object] | None = None,
39-
x0: onp.ToScalar | onp.ToArrayND | None = None,
40-
integrality: onp.ToScalar | onp.ToArrayND | None = None,
199+
callback: Callable[[_OptimizeResult], _Ignored] | None = None,
200+
options: _OptionsHighs | None = None,
201+
x0: onp.ToFloat1D | None = None,
202+
integrality: _Max3 | Sequence[_Max3] | onp.CanArrayND[npc.integer] | None = None,
41203
) -> _OptimizeResult: ...

scipy-stubs/optimize/_typing.pyi

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ __all__ = [
1616
"Constraints",
1717
"MethodAll",
1818
"MethodLinprog",
19+
"MethodLinprogLegacy",
1920
"MethodMimimize",
2021
"MethodMinimizeScalar",
2122
"MethodRootScalar",
@@ -64,7 +65,8 @@ MethodMimimize: TypeAlias = Literal[
6465
"Trust-Krylov", "trust-krylov",
6566
] # fmt: skip
6667
MethodMinimizeScalar: TypeAlias = Literal["brent", "golden", "bounded"]
67-
MethodLinprog: TypeAlias = Literal["highs", "highs-ds", "highs-ipm"] # Literal["interior-point", "revised simplex", "simplex"]
68+
MethodLinprog: TypeAlias = Literal["highs", "highs-ds", "highs-ipm"]
69+
MethodLinprogLegacy: TypeAlias = Literal["interior-point", "revised simplex", "simplex"]
6870
_MethodRoot: TypeAlias = Literal[
6971
"hybr",
7072
"lm",

0 commit comments

Comments
 (0)