|
1 |
| -from collections.abc import Mapping, Sequence |
2 |
| -from typing import Literal, type_check_only |
| 1 | +from collections.abc import Sequence |
| 2 | +from typing import Literal, TypeAlias, TypedDict, type_check_only |
| 3 | +from typing_extensions import LiteralString, TypeAliasType |
3 | 4 |
|
4 | 5 | import numpy as np
|
5 | 6 | import optype.numpy as onp
|
| 7 | +import optype.numpy.compat as npc |
| 8 | +from scipy.sparse._base import _spbase |
6 | 9 | from ._constraints import Bounds, LinearConstraint
|
7 |
| -from ._optimize import OptimizeResult |
| 10 | +from ._optimize import OptimizeResult as _OptimizeResult |
| 11 | + |
| 12 | +### |
| 13 | + |
| 14 | +_Max3: TypeAlias = Literal[0, 1, 2, 3] |
| 15 | +_Max4: TypeAlias = Literal[_Max3, 4] |
| 16 | + |
| 17 | +_Float: TypeAlias = float | np.float64 |
| 18 | +_ToFloat2D: TypeAlias = onp.ToFloat2D | _spbase[np.bool_ | npc.integer | np.float32 | np.float64 | np.longdouble] |
| 19 | +# The `TypeAliasType` helps make error messages less unreadable |
| 20 | +_ToLinearConstraint = TypeAliasType( |
| 21 | + "_ToLinearConstraint", |
| 22 | + LinearConstraint |
| 23 | + | tuple[_ToFloat2D] |
| 24 | + | tuple[_ToFloat2D, onp.ToFloat | onp.ToFloat1D] |
| 25 | + | tuple[_ToFloat2D, onp.ToFloat | onp.ToFloat1D, onp.ToFloat | onp.ToFloat1D], |
| 26 | +) |
| 27 | + |
| 28 | +@type_check_only |
| 29 | +class _OptionsMILP(TypedDict, total=False): |
| 30 | + disp: onp.ToBool # default: False |
| 31 | + presolve: onp.ToBool # default: True |
| 32 | + node_limit: int # default: no limit |
| 33 | + time_limit: onp.ToFloat # default: no limit |
| 34 | + min_rel_gap: onp.ToFloat # default: ? |
| 35 | + |
| 36 | +@type_check_only |
| 37 | +class _OptimizeResultSucess(_OptimizeResult): |
| 38 | + x: onp.Array1D[np.float64] |
| 39 | + fun: _Float |
| 40 | + status: Literal[0] |
| 41 | + message: LiteralString |
| 42 | + success: Literal[True] |
| 43 | + mip_node_count: int |
| 44 | + mip_dual_bound: _Float |
| 45 | + mip_gap: _Float |
8 | 46 |
|
9 | 47 | @type_check_only
|
10 |
| -class _OptimizeResult(OptimizeResult): |
11 |
| - status: Literal[0, 1, 2, 3, 4] |
12 |
| - success: bool |
13 |
| - message: str |
14 |
| - x: onp.ArrayND[np.float64] | None |
15 |
| - fun: float | np.float64 | None |
| 48 | +class _OptimizeResultNoSolution(_OptimizeResult): |
| 49 | + x: None |
| 50 | + fun: None |
| 51 | + status: Literal[1, 2, 3, 4] |
| 52 | + message: LiteralString |
| 53 | + success: Literal[False] |
16 | 54 | mip_node_count: int | None
|
17 |
| - mip_dual_bound: float | np.float64 | None |
18 |
| - mip_gap: float | np.float64 | None |
| 55 | + mip_dual_bound: _Float | None |
| 56 | + mip_gap: _Float | None |
19 | 57 |
|
20 | 58 | ###
|
21 | 59 |
|
| 60 | +# only used as implicit export |
| 61 | +class OptimizeResult(_OptimizeResult): |
| 62 | + x: onp.Array1D[np.float64] | None |
| 63 | + fun: _Float | None |
| 64 | + status: _Max4 |
| 65 | + message: LiteralString |
| 66 | + success: bool # status == 0 |
| 67 | + mip_node_count: int | None |
| 68 | + mip_dual_bound: _Float | None |
| 69 | + mip_gap: _Float | None |
| 70 | + |
22 | 71 | def milp(
|
23 | 72 | c: onp.ToFloat1D,
|
24 | 73 | *,
|
25 |
| - integrality: onp.ToInt1D | None = None, |
| 74 | + integrality: Sequence[_Max3 | npc.integer] | onp.CanArrayND[npc.integer] | None = None, |
26 | 75 | bounds: Bounds | None = None,
|
27 |
| - constraints: Sequence[LinearConstraint] | None = None, |
28 |
| - options: Mapping[str, object] | None = None, |
29 |
| -) -> _OptimizeResult: ... |
| 76 | + constraints: _ToLinearConstraint | Sequence[_ToLinearConstraint] | None = None, |
| 77 | + options: _OptionsMILP | None = None, |
| 78 | +) -> _OptimizeResultSucess | _OptimizeResultNoSolution: ... |
0 commit comments