Skip to content

Commit 8a7c817

Browse files
committed
add tests
1 parent 9aa1832 commit 8a7c817

File tree

1 file changed

+74
-0
lines changed

1 file changed

+74
-0
lines changed

test/test_sos_constraints.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
from __future__ import annotations
2+
3+
import pandas as pd
4+
import pytest
5+
6+
from linopy import Model, available_solvers
7+
8+
9+
def test_add_sos_constraints_registers_variable() -> None:
10+
m = Model()
11+
locations = pd.Index([0, 1, 2], name="locations")
12+
build = m.add_variables(coords=[locations], name="build")
13+
14+
m.add_sos_constraints(build, sos_type=1, sos_dim="locations")
15+
16+
assert build.attrs["sos_type"] == 1
17+
assert build.attrs["sos_dim"] == "locations"
18+
assert list(m.variables.sos) == ["build"]
19+
20+
m.remove_sos_constraints(build)
21+
assert "sos_type" not in build.attrs
22+
assert "sos_dim" not in build.attrs
23+
24+
25+
def test_add_sos_constraints_validation() -> None:
26+
m = Model()
27+
strings = pd.Index(["a", "b"], name="strings")
28+
with pytest.raises(ValueError, match="sos_type"):
29+
m.add_sos_constraints(m.add_variables(name="x"), sos_type=3, sos_dim="i")
30+
31+
variable = m.add_variables(coords=[strings], name="string_var")
32+
33+
with pytest.raises(ValueError, match="dimension"):
34+
m.add_sos_constraints(variable, sos_type=1, sos_dim="missing")
35+
36+
with pytest.raises(ValueError, match="numeric"):
37+
m.add_sos_constraints(variable, sos_type=1, sos_dim="strings")
38+
39+
numeric = m.add_variables(coords=[pd.Index([0, 1], name="dim")], name="num")
40+
m.add_sos_constraints(numeric, sos_type=1, sos_dim="dim")
41+
with pytest.raises(ValueError, match="already has"):
42+
m.add_sos_constraints(numeric, sos_type=1, sos_dim="dim")
43+
44+
45+
def test_sos_constraints_written_to_lp(tmp_path) -> None:
46+
m = Model()
47+
breakpoints = pd.Index([0.0, 1.5, 3.5], name="bp")
48+
lambdas = m.add_variables(coords=[breakpoints], name="lambda")
49+
m.add_sos_constraints(lambdas, sos_type=2, sos_dim="bp")
50+
51+
fn = tmp_path / "sos.lp"
52+
m.to_file(fn, io_api="lp")
53+
content = fn.read_text()
54+
55+
assert "\nsos\n" in content
56+
assert "S2 ::" in content
57+
assert "3.5" in content
58+
59+
60+
@pytest.mark.skipif("gurobi" not in available_solvers, reason="Gurobipy not installed")
61+
def test_to_gurobipy_emits_sos_constraints() -> None:
62+
gurobipy = pytest.importorskip("gurobipy")
63+
64+
m = Model()
65+
segments = pd.Index([0.0, 0.5, 1.0], name="seg")
66+
var = m.add_variables(coords=[segments], name="lambda")
67+
m.add_sos_constraints(var, sos_type=1, sos_dim="seg")
68+
69+
try:
70+
model = m.to_gurobipy()
71+
except gurobipy.GurobiError as exc: # pragma: no cover - depends on license setup
72+
pytest.skip(f"Gurobi environment unavailable: {exc}")
73+
74+
assert model.NumSOS == 1

0 commit comments

Comments
 (0)