|
4 | 4 |
|
5 | 5 | import logging |
6 | 6 | from pathlib import Path |
| 7 | +from typing import Literal, TypeAlias |
7 | 8 |
|
8 | 9 | import numpy as np |
9 | 10 | import pandas as pd |
|
40 | 41 | ) |
41 | 42 | from linopy.solver_capabilities import SolverFeature, get_available_solvers_with_feature |
42 | 43 |
|
| 44 | +Sign: TypeAlias = Literal["==", "<=", ">="] |
| 45 | +Method: TypeAlias = Literal["sos2", "incremental", "lp", "auto"] |
| 46 | + |
43 | 47 | _sos2_solvers = get_available_solvers_with_feature( |
44 | 48 | SolverFeature.SOS_CONSTRAINTS, available_solvers |
45 | 49 | ) |
@@ -1633,7 +1637,8 @@ def test_lp_consistency_with_sos2(self) -> None: |
1633 | 1637 | y_pts = [0, 20, 30, 35] # concave |
1634 | 1638 |
|
1635 | 1639 | solutions = {} |
1636 | | - for method in ["lp", "sos2", "incremental"]: |
| 1640 | + methods: list[Method] = ["lp", "sos2", "incremental"] |
| 1641 | + for method in methods: |
1637 | 1642 | m = Model() |
1638 | 1643 | power = m.add_variables(lower=0, upper=30, name="power") |
1639 | 1644 | fuel = m.add_variables(lower=0, upper=40, name="fuel") |
@@ -1686,7 +1691,8 @@ def test_lp_per_entity_nan_padding(self) -> None: |
1686 | 1691 | bp_y = pd.DataFrame([[0, 20, 30, 35], [0, 10, 15, np.nan]], index=["a", "b"]) |
1687 | 1692 | bp_x = pd.DataFrame([[0, 10, 20, 30], [0, 5, 15, np.nan]], index=["a", "b"]) |
1688 | 1693 | results: dict[str, float] = {} |
1689 | | - for method in ["lp", "sos2"]: |
| 1694 | + methods: list[Method] = ["lp", "sos2"] |
| 1695 | + for method in methods: |
1690 | 1696 | m = Model() |
1691 | 1697 | coord = pd.Index(["a", "b"], name="entity") |
1692 | 1698 | x = m.add_variables(lower=0, upper=20, coords=[coord], name="x") |
@@ -1723,7 +1729,7 @@ def test_lp_rejects_decreasing_x_concave_ge(self) -> None: |
1723 | 1729 |
|
1724 | 1730 | @pytest.mark.skipif(not _sos2_solvers, reason="no SOS2-capable solver available") |
1725 | 1731 | @pytest.mark.parametrize("method", ["sos2", "incremental"]) |
1726 | | - def test_active_off_with_sign_le_leaves_lower_open(self, method: str) -> None: |
| 1732 | + def test_active_off_with_sign_le_leaves_lower_open(self, method: Method) -> None: |
1727 | 1733 | """ |
1728 | 1734 | Documents the asymmetry between sign='==' and sign='<=' under |
1729 | 1735 | active=0: equality forces y=0, but '<=' only bounds y ≤ 0 — the |
@@ -1816,7 +1822,8 @@ def test_lp_accepts_linear_curve(self) -> None: |
1816 | 1822 | A linear curve is both convex and concave per detection, so |
1817 | 1823 | LP must accept it with either sign and build the formulation. |
1818 | 1824 | """ |
1819 | | - for sign in ["<=", ">="]: |
| 1825 | + signs: list[Sign] = ["<=", ">="] |
| 1826 | + for sign in signs: |
1820 | 1827 | m = Model() |
1821 | 1828 | x = m.add_variables(lower=0, upper=30, name="x") |
1822 | 1829 | y = m.add_variables(lower=0, upper=60, name="y") |
@@ -1877,7 +1884,8 @@ def test_lp_matches_sos2_on_multi_dim_variables(self) -> None: |
1877 | 1884 | bp_x = pd.DataFrame([[0, 10, 20, 30], [0, 10, 20, 30]], index=["a", "b"]) |
1878 | 1885 | bp_y = pd.DataFrame([[0, 20, 30, 35], [0, 15, 25, 30]], index=["a", "b"]) |
1879 | 1886 | ys: dict[str, xr.DataArray] = {} |
1880 | | - for method in ["lp", "sos2"]: |
| 1887 | + methods: list[Method] = ["lp", "sos2"] |
| 1888 | + for method in methods: |
1881 | 1889 | m = Model() |
1882 | 1890 | x = m.add_variables(lower=0, upper=30, coords=[entities], name="x") |
1883 | 1891 | y = m.add_variables(lower=0, upper=40, coords=[entities], name="y") |
@@ -1905,9 +1913,10 @@ def test_lp_consistency_with_sos2_both_directions(self) -> None: |
1905 | 1913 | """ |
1906 | 1914 | x_pts = [0, 10, 20, 30] |
1907 | 1915 | y_pts = [0, 20, 30, 35] # concave |
| 1916 | + methods: list[Method] = ["lp", "sos2"] |
1908 | 1917 | for obj_sign in [-1.0, +1.0]: |
1909 | 1918 | sols: dict[str, float] = {} |
1910 | | - for method in ["lp", "sos2"]: |
| 1919 | + for method in methods: |
1911 | 1920 | m = Model() |
1912 | 1921 | p = m.add_variables(lower=0, upper=30, name="p") |
1913 | 1922 | f = m.add_variables(lower=0, upper=50, name="f") |
|
0 commit comments