Skip to content

Commit 9000a11

Browse files
[pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
1 parent bb31430 commit 9000a11

7 files changed

Lines changed: 33 additions & 41 deletions

File tree

dev-scripts/quadratic_constraints_remaining_tasks.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,16 +46,19 @@ def Qc(self) -> list[scipy.sparse.csc_matrix]:
4646
# Each quadratic constraint has its own Q matrix
4747
pass
4848

49+
4950
@property
5051
def qc_linear(self) -> scipy.sparse.csc_matrix:
5152
"""Return linear coefficients for quadratic constraints."""
5253
pass
5354

55+
5456
@property
5557
def qc_sense(self) -> np.ndarray:
5658
"""Return sense array for quadratic constraints."""
5759
pass
5860

61+
5962
@property
6063
def qc_rhs(self) -> np.ndarray:
6164
"""Return RHS values for quadratic constraints."""
@@ -109,10 +112,7 @@ Example API:
109112
```python
110113
# Should work with coordinates
111114
m.add_quadratic_constraints(
112-
x * x + y * y, # where x, y have dims=['time', 'node']
113-
"<=",
114-
100,
115-
name="qc"
115+
x * x + y * y, "<=", 100, name="qc" # where x, y have dims=['time', 'node']
116116
)
117117
```
118118

@@ -124,6 +124,7 @@ Add methods to `QuadraticConstraint`:
124124
def modify_rhs(self, new_rhs: ConstantLike) -> None:
125125
"""Modify the right-hand side of the constraint."""
126126

127+
127128
def modify_coeffs(self, new_coeffs: xr.DataArray) -> None:
128129
"""Modify coefficients of the constraint."""
129130
```

dev-scripts/quadratic_constraints_status.md

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,25 +26,22 @@ import linopy
2626
m = linopy.Model()
2727

2828
# Variables
29-
x = m.add_variables(lower=0, name='x')
30-
y = m.add_variables(lower=0, name='y')
29+
x = m.add_variables(lower=0, name="x")
30+
y = m.add_variables(lower=0, name="y")
3131

3232
# Linear constraint (existing)
33-
m.add_constraints(x + y <= 10, name='budget')
33+
m.add_constraints(x + y <= 10, name="budget")
3434

3535
# Quadratic constraint (NEW!)
3636
m.add_quadratic_constraints(
37-
x*x + 2*x*y + y*y + 3*x + 4*y,
38-
"<=",
39-
100,
40-
name='quadratic_budget'
37+
x * x + 2 * x * y + y * y + 3 * x + 4 * y, "<=", 100, name="quadratic_budget"
4138
)
4239

4340
# Objective
44-
m.add_objective(x + 2*y)
41+
m.add_objective(x + 2 * y)
4542

4643
# Solve (with Gurobi, MOSEK, CPLEX, etc.)
47-
m.solve(solver_name='gurobi')
44+
m.solve(solver_name="gurobi")
4845
```
4946

5047
## What Was Implemented

examples/quadratic-constraints.ipynb

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,9 @@
2424
},
2525
"outputs": [],
2626
"source": [
27-
"import linopy\n",
28-
"import numpy as np"
27+
"import numpy as np\n",
28+
"\n",
29+
"import linopy"
2930
]
3031
},
3132
{
@@ -300,7 +301,12 @@
300301
"y = m2.add_variables(lower=0, coords=[range(3)], name=\"y\")\n",
301302
"\n",
302303
"# This creates 3 quadratic constraints, one for each coordinate\n",
303-
"m2.add_quadratic_constraints(x * x * np.array([1, 1.1, 1.2]) + y * y, \"<=\", np.array([20, 25, 30]), name=\"circles\")"
304+
"m2.add_quadratic_constraints(\n",
305+
" x * x * np.array([1, 1.1, 1.2]) + y * y,\n",
306+
" \"<=\",\n",
307+
" np.array([20, 25, 30]),\n",
308+
" name=\"circles\",\n",
309+
")"
304310
]
305311
},
306312
{

linopy/io.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -823,8 +823,9 @@ def to_mosek(
823823
# MOSEK uses 0.5 * x'Qx convention, and our Q matrix is already
824824
# built with doubled diagonal terms for this convention.
825825
# So we pass Q directly without dividing.
826-
task.putqconk(con_idx, list(Q_lower.row), list(Q_lower.col),
827-
list(Q_lower.data))
826+
task.putqconk(
827+
con_idx, list(Q_lower.row), list(Q_lower.col), list(Q_lower.data)
828+
)
828829

829830
return task
830831

linopy/matrices.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212

1313
import numpy as np
1414
import pandas as pd
15-
import scipy.sparse
1615
from numpy import ndarray
1716
from pandas.core.indexes.base import Index
1817
from pandas.core.series import Series
@@ -321,9 +320,7 @@ def Qc(self) -> list[csc_matrix]:
321320
cols.extend([j, i])
322321
data.extend([coeff, coeff])
323322

324-
Q = csc_matrix(
325-
(data, (rows, cols)), shape=(n_vars, n_vars)
326-
)
323+
Q = csc_matrix((data, (rows, cols)), shape=(n_vars, n_vars))
327324
matrices.append(Q)
328325

329326
return matrices
@@ -386,6 +383,4 @@ def qc_linear(self) -> csc_matrix | None:
386383
"between flat_qcons and the global variable/constraint indexing."
387384
)
388385

389-
return csc_matrix(
390-
(data, (rows, cols)), shape=(n_cons, n_vars)
391-
)
386+
return csc_matrix((data, (rows, cols)), shape=(n_cons, n_vars))

linopy/solvers.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1200,9 +1200,7 @@ def get_solver_solution() -> Solution:
12001200
try:
12011201
qcs = m.getQConstrs()
12021202
if qcs:
1203-
qc_dual = pd.Series(
1204-
{qc.QCName: qc.QCPi for qc in qcs}, dtype=float
1205-
)
1203+
qc_dual = pd.Series({qc.QCName: qc.QCPi for qc in qcs}, dtype=float)
12061204
except (AttributeError, gurobipy.GurobiError):
12071205
# QCPi not available (non-convex or QCPDual=0)
12081206
pass

test/test_quadratic_constraint.py

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,9 @@ def test_highs_rejects_quadratic_constraints(
325325
from linopy.solvers import quadratic_constraint_solvers
326326

327327
if "highs" not in quadratic_constraint_solvers:
328-
with pytest.raises(ValueError, match="does not support quadratic constraints"):
328+
with pytest.raises(
329+
ValueError, match="does not support quadratic constraints"
330+
):
329331
m.solve(solver_name="highs")
330332

331333
def test_highs_accepts_quadratic_objective(
@@ -434,9 +436,7 @@ def test_empty_container_repr(self) -> None:
434436
class TestMatrixAccessor:
435437
"""Tests for matrix accessor with quadratic constraints."""
436438

437-
def test_qclabels(
438-
self, m: Model, x: linopy.Variable, y: linopy.Variable
439-
) -> None:
439+
def test_qclabels(self, m: Model, x: linopy.Variable, y: linopy.Variable) -> None:
440440
"""Test qclabels property."""
441441
m.add_objective(x + y)
442442
m.add_quadratic_constraints(x * x, "<=", 25, name="qc1")
@@ -447,9 +447,7 @@ def test_qclabels(
447447
assert labels[0] == 0
448448
assert labels[1] == 1
449449

450-
def test_qc_sense(
451-
self, m: Model, x: linopy.Variable, y: linopy.Variable
452-
) -> None:
450+
def test_qc_sense(self, m: Model, x: linopy.Variable, y: linopy.Variable) -> None:
453451
"""Test qc_sense property."""
454452
m.add_objective(x + y)
455453
m.add_quadratic_constraints(x * x, "<=", 25, name="qc1")
@@ -460,9 +458,7 @@ def test_qc_sense(
460458
assert senses[0] == "<="
461459
assert senses[1] == ">="
462460

463-
def test_qc_rhs(
464-
self, m: Model, x: linopy.Variable, y: linopy.Variable
465-
) -> None:
461+
def test_qc_rhs(self, m: Model, x: linopy.Variable, y: linopy.Variable) -> None:
466462
"""Test qc_rhs property."""
467463
m.add_objective(x + y)
468464
m.add_quadratic_constraints(x * x, "<=", 25, name="qc1")
@@ -504,9 +500,7 @@ def test_Qc_cross_terms(
504500
assert Q[0, 0] == 0.0 # No x^2 term
505501
assert Q[1, 1] == 0.0 # No y^2 term
506502

507-
def test_qc_linear(
508-
self, m: Model, x: linopy.Variable, y: linopy.Variable
509-
) -> None:
503+
def test_qc_linear(self, m: Model, x: linopy.Variable, y: linopy.Variable) -> None:
510504
"""Test qc_linear property."""
511505
m.add_objective(x + y)
512506
m.add_quadratic_constraints(x * x + 3 * x + 4 * y, "<=", 25, name="mixed")

0 commit comments

Comments
 (0)