Skip to content

Commit 42d3330

Browse files
committed
Deploying to gh-pages from @ a3ec6d7 🚀
1 parent 7866e21 commit 42d3330

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+1268
-360
lines changed

_sources/attribute/copt.md.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,12 @@
9191
* - Name
9292
- ✅
9393
- ✅
94+
* - IISLowerBound
95+
- ✅
96+
- ❌
97+
* - IISUpperBound
98+
- ✅
99+
- ❌
94100
:::
95101

96102
### Supported [constraint attribute](#pyoptinterface.ConstraintAttribute)
@@ -110,5 +116,8 @@
110116
* - Dual
111117
- ✅
112118
- ❌
119+
* - IIS
120+
- ✅
121+
- ❌
113122
:::
114123

_sources/attribute/gurobi.md.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,12 @@
9191
* - Name
9292
- ✅
9393
- ✅
94+
* - IISLowerBound
95+
- ✅
96+
- ❌
97+
* - IISUpperBound
98+
- ✅
99+
- ❌
94100
:::
95101

96102
### Supported [constraint attribute](#pyoptinterface.ConstraintAttribute)
@@ -110,5 +116,8 @@
110116
* - Dual
111117
- ✅
112118
- ❌
119+
* - IIS
120+
- ✅
121+
- ❌
113122
:::
114123

_sources/attribute/highs.md.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,12 @@
9191
* - Name
9292
- ✅
9393
- ✅
94+
* - IISLowerBound
95+
- ❌
96+
- ❌
97+
* - IISUpperBound
98+
- ❌
99+
- ❌
94100
:::
95101

96102
### Supported [constraint attribute](#pyoptinterface.ConstraintAttribute)
@@ -110,5 +116,8 @@
110116
* - Dual
111117
- ✅
112118
- ❌
119+
* - IIS
120+
- ❌
121+
- ❌
113122
:::
114123

_sources/attribute/ipopt.md.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,12 @@
9191
* - Name
9292
- ✅
9393
- ✅
94+
* - IISLowerBound
95+
- ❌
96+
- ❌
97+
* - IISUpperBound
98+
- ❌
99+
- ❌
94100
:::
95101

96102
### Supported [constraint attribute](#pyoptinterface.ConstraintAttribute)
@@ -110,5 +116,8 @@
110116
* - Dual
111117
- ✅
112118
- ❌
119+
* - IIS
120+
- ❌
121+
- ❌
113122
:::
114123

_sources/attribute/mosek.md.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,12 @@
9191
* - Name
9292
- ✅
9393
- ✅
94+
* - IISLowerBound
95+
- ❌
96+
- ❌
97+
* - IISUpperBound
98+
- ❌
99+
- ❌
94100
:::
95101

96102
### Supported [constraint attribute](#pyoptinterface.ConstraintAttribute)
@@ -110,5 +116,8 @@
110116
* - Dual
111117
- ✅
112118
- ❌
119+
* - IIS
120+
- ❌
121+
- ❌
113122
:::
114123

_sources/changelog.md.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
# Changelog
22

3-
## Unreleased
3+
## 0.4.0
44
- Add `model.add_m_variables` and `model.add_m_linear_constraints` matrix modeling API
55
- Add `model.computeIIS` and IIS related attributes for constraint and variable
66
- Implement constraint based on compare operators, now you can use `model.add_linear_constraint(x + y <= 1.0)` directly
7+
- Drop support for Python 3.8
8+
- Add wheels for Linux ARM64
9+
- Supports HiGHS 1.9.0 and Mosek 11
710

811
## 0.3.0
912
- Add `model.set_variable_bounds(variable, lb, ub)` to make it easier to change variable bounds

_sources/common_model_interface.md.txt

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,11 @@ continuous
3939
:return: the handle of the variable
4040
```
4141

42-
### Add multi-dimensional variables to the model as <project:#pyoptinterface.tupledict>
42+
### Add multidimensional variables to the model as <project:#pyoptinterface.tupledict>
4343

4444
```{py:function} model.add_variables(*coords, [lb=-inf, ub=+inf, domain=pyoptinterface.VariableDomain.Continuous, name=""])
4545

46-
add a multi-dimensional variable to the model
46+
add a multidimensional variable to the model
4747

4848
:param coords: the coordinates of the variable, can be a list of Iterables
4949
:param float lb: the lower bound of the variable, optional, defaults to $-\infty$
@@ -55,6 +55,22 @@ continuous
5555
:rtype: pyoptinterface.tupledict
5656
```
5757

58+
### Add multidimensional variables to the model as `numpy.ndarray`
59+
60+
```{py:function} model.add_m_variables(shape, [lb=-inf, ub=+inf, domain=pyoptinterface.VariableDomain.Continuous, name=""])
61+
62+
add a multidimensional variable to the model as `numpy.ndarray`
63+
64+
:param shape: the shape of the variable, can be a tuple of integers or an integer
65+
:param float lb: the lower bound of the variable, optional, defaults to $-\infty$
66+
:param float ub: the upper bound of the variable, optional, defaults to $+\infty$
67+
:param pyoptinterface.VariableDomain domain: the domain of the variable, optional, defaults to
68+
continuous
69+
:param str name: the name of the variable, optional
70+
:return: the multidimensional variable
71+
:rtype: numpy.ndarray
72+
```
73+
5874
### Get/set variable attributes
5975

6076
```{py:function} model.set_variable_attribute(var, attr, value)
@@ -137,6 +153,20 @@ pretty print an expression in a human-readable format
137153
- <project:#model.add_second_order_cone_constraint>
138154
- <project:#model.add_sos_constraint>
139155

156+
### Add linear constraints as matrix form to the model
157+
158+
```{py:function} model.add_m_linear_constraints(A, vars, sense, b, [name=""])
159+
160+
add linear constraints as matrix form to the model $Ax \le b$ or $Ax = b$ or $Ax \ge b$
161+
162+
:param A: the matrix of coefficients, can be a dense `numpy.ndarray` or a sparse matrix `scipy.sparse.sparray`
163+
:param vars: the variables in the constraints, can be a list or a 1-d `numpy.ndarray` returned by `add_m_variables`
164+
:param pyoptinterface.ConstraintSense sense: the sense of the constraints
165+
:param b: the right-hand side of the constraints, should be a 1-d `numpy.ndarray`
166+
:param str name: the name of the constraints, optional
167+
:return: the handles of linear constraints
168+
:rtype: numpy.ndarray
169+
```
140170

141171
### Get/set constraint attributes
142172

_sources/constraint.md.txt

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,16 @@ from pyoptinterface import copt
2525
model = copt.Model()
2626
```
2727

28+
## Constraint Sense
29+
30+
The sense of a constraint can be one of the following:
31+
32+
- `poi.Eq`: equal
33+
- `poi.Leq`: less than or equal
34+
- `poi.Geq`: greater than or equal
35+
36+
They are the abbreviations of `poi.ConstraintSense.Equal`, `poi.ConstraintSense.LessEqual` or `poi.ConstraintSense.GreaterEqual` and can be used in the `sense` argument of the constraint creation functions.
37+
2838
## Linear Constraint
2939
It is defined as:
3040

@@ -42,16 +52,15 @@ It can be added to the model using the `add_linear_constraint` method of the `Mo
4252
x = model.add_variable(name="x")
4353
y = model.add_variable(name="y")
4454

45-
con = model.add_linear_constraint(2.0*x + 3.0*y, poi.ConstraintSense.LessEqual, 1.0)
55+
con = model.add_linear_constraint(2.0*x + 3.0*y, poi.Leq, 1.0)
4656
```
4757

4858
```{py:function} model.add_linear_constraint(expr, sense, rhs, [name=""])
4959

5060
add a linear constraint to the model
5161

5262
:param expr: the expression of the constraint
53-
:param pyoptinterface.ConstraintSense sense: the sense
54-
of the constraint, which can be `GreaterEqual`, `Equal`, or `LessEqual`
63+
:param pyoptinterface.ConstraintSense sense: the sense of the constraint
5564
:param float rhs: the right-hand side of the constraint
5665
:param str name: the name of the constraint, optional
5766
:return: the handle of the constraint
@@ -88,8 +97,7 @@ con = model.add_quadratic_constraint(expr, poi.ConstraintSense.LessEqual, 1.0)
8897
add a quadratic constraint to the model
8998

9099
:param expr: the expression of the constraint
91-
:param pyoptinterface.ConstraintSense sense: the sense
92-
of the constraint, which can be `GreaterEqual`, `Equal`, or `LessEqual`
100+
:param pyoptinterface.ConstraintSense sense: the sense of the constraint, which can be `GreaterEqual`, `Equal`, or `LessEqual`
93101
:param float rhs: the right-hand side of the constraint
94102
:param str name: the name of the constraint, optional
95103
:return: the handle of the constraint
@@ -193,6 +201,8 @@ standard [constraint attributes](#pyoptinterface.ConstraintAttribute):
193201
- float
194202
* - Dual
195203
- float
204+
* - IIS
205+
- bool
196206
:::
197207

198208
The most common attribute we will use is the `Dual` attribute, which represents the dual multiplier of the constraint after optimization.
@@ -235,3 +245,26 @@ model.set_normalized_rhs(con, 2.0)
235245
# modify the coefficient of the linear part of the constraint
236246
model.set_normalized_coefficient(con, x, 2.0)
237247
```
248+
249+
## Create constraint with comparison operator
250+
251+
In other modeling languages, we can create a constraint with a comparison operator, like:
252+
253+
```python
254+
model.addConsr(x + y <= 1)
255+
```
256+
257+
This is quite convenient, so PyOptInterface now supports to create constraint with comparison operators `<=`, `==`, `>=` as a shortcut to create a linear or quadratic constraint.
258+
259+
```{code-cell}
260+
model.add_linear_constraint(x + y <= 1)
261+
model.add_linear_constraint(x <= y)
262+
model.add_quadratic_constraint(x*x + y*y <= 1)
263+
```
264+
265+
:::{note}
266+
267+
Creating constraint with comparison operator may cause performance issue especially the left-hand side and right-hand side of the constraint are complex expressions. PyOptInterface needs to create a new expression by subtracting the right-hand side from the left-hand side, which may be time-consuming.
268+
269+
If that becomes the bottleneck of performance, it is recommended to construct the left-hand side expression with `ExprBuilder` and call `add_linear_constraint` or `add_quadratic_constraint` method to create constraints explicitly.
270+
:::

_sources/faq.md.txt

Lines changed: 1 addition & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -34,110 +34,4 @@ model = gurobi.Model(env)
3434

3535
In YALMIP, you can use the matrix form $Ax \leq b$ to add linear constraints, which is quite convenient.
3636

37-
In PyOptInterface, you can use the following code to add linear constraints in matrix form:
38-
39-
```python
40-
import pyoptinterface as poi
41-
from pyoptinterface import gurobi
42-
43-
import numpy as np
44-
from scipy.sparse import csr_array, sparray, eye_array
45-
46-
47-
def iterate_sparse_matrix_rows(A):
48-
"""
49-
Iterate over rows of a sparse matrix and get non-zero elements for each row.
50-
51-
A is a 2-dimensional scipy sparse matrix
52-
isinstance(A, scipy.sparse.sparray) = True and A.ndim = 2
53-
"""
54-
if not isinstance(A, csr_array):
55-
A = csr_array(A) # Convert to CSR format if not already
56-
57-
for i in range(A.shape[0]):
58-
row_start = A.indptr[i]
59-
row_end = A.indptr[i + 1]
60-
row_indices = A.indices[row_start:row_end]
61-
row_data = A.data[row_start:row_end]
62-
yield row_indices, row_data
63-
64-
65-
def add_matrix_constraints(model, A, x, sense, b):
66-
"""
67-
add constraints Ax <= / = / >= b
68-
69-
A is a 2-dimensional numpy array or scipy sparse matrix
70-
x is an iterable of variables
71-
sense is one of (poi.Leq, poi.Eq, poi.Geq)
72-
b is an iterable of values or a single scalar
73-
"""
74-
75-
is_ndarray = isinstance(A, np.ndarray)
76-
is_sparse = isinstance(A, sparray)
77-
78-
if not is_ndarray and not is_sparse:
79-
raise ValueError("A must be a numpy array or scipy.sparse array")
80-
81-
ndim = A.ndim
82-
if ndim != 2:
83-
raise ValueError("A must be a 2-dimensional array")
84-
85-
M, N = A.shape
86-
87-
# turn x into a list if x is an iterable
88-
if isinstance(x, poi.tupledict):
89-
x = x.values()
90-
x = list(x)
91-
92-
if len(x) != N:
93-
raise ValueError("x must have length equal to the number of columns of A")
94-
95-
# check b
96-
if np.isscalar(b):
97-
b = np.full(M, b)
98-
elif len(b) != M:
99-
raise ValueError("b must have length equal to the number of rows of A")
100-
101-
constraints = []
102-
103-
if is_ndarray:
104-
for i in range(M):
105-
expr = poi.ScalarAffineFunction()
106-
row = A[i]
107-
for coef, var in zip(row, x):
108-
expr.add_term(var, coef)
109-
con = model.add_linear_constraint(expr, sense, b[i])
110-
constraints.append(con)
111-
elif is_sparse:
112-
for (row_indices, row_data), rhs in zip(iterate_sparse_matrix_rows(A), b):
113-
expr = poi.ScalarAffineFunction()
114-
for j, coef in zip(row_indices, row_data):
115-
expr.add_term(x[j], coef)
116-
con = model.add_linear_constraint(expr, sense, rhs)
117-
constraints.append(con)
118-
119-
return constraints
120-
121-
122-
def main():
123-
model = gurobi.Model()
124-
N = 200
125-
x = model.add_variables(range(N))
126-
A = np.eye(N)
127-
ub = 3.0
128-
lb = 1.0
129-
A_sparse = eye_array(N)
130-
add_matrix_constraints(model, A, x, poi.Leq, ub)
131-
add_matrix_constraints(model, A_sparse, x, poi.Geq, lb)
132-
133-
obj = poi.quicksum(x)
134-
model.set_objective(obj)
135-
model.optimize()
136-
137-
obj_value = model.get_model_attribute(poi.ModelAttribute.ObjectiveValue)
138-
print("Objective value: ", obj_value)
139-
140-
141-
if __name__ == "__main__":
142-
main()
143-
```
37+
In PyOptInterface, you can use [`model.add_m_linear_constraints`](<project:#model.add_m_linear_constraints>) to add linear constraints in matrix form.

_sources/getting_started.md.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ con = model.add_linear_constraint(x1+x2, poi.ConstraintSense.Equal, 1, name="con
245245
```
246246
`model.add_linear_constraint` adds a linear constraint to the model.
247247
- The first argument `x1+x2` is the left-hand side of the constraint.
248-
- The second argument is the sense of the constraint. It can be `poi.ConstraintSense.Equal`, `poi.ConstraintSense.LessEqual` or `poi.ConstraintSense.GreaterEqual`.
248+
- The second argument is the sense of the constraint. It can be `poi.ConstraintSense.Equal`, `poi.ConstraintSense.LessEqual` or `poi.ConstraintSense.GreaterEqual` which can also be written as `poi.Eq`, `poi.Leq`, and `poi.Geq`.
249249
- The third argument is the right-hand side of the constraint. It must be a constant.
250250
- The fourth argument is optional and can be used to specify the name of the constraint.
251251

0 commit comments

Comments
 (0)