Skip to content

Commit 5d4cc49

Browse files
committed
Deploying to gh-pages from @ 36d8c46 🚀
1 parent 9de0249 commit 5d4cc49

Some content is hidden

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

58 files changed

+1890
-1745
lines changed
20.4 KB
Loading

_sources/constraint.md.txt

Lines changed: 48 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,31 @@ add a linear constraint to the model
7171
PyOptInterface provides <project:#pyoptinterface.Eq>, <project:#pyoptinterface.Leq>, and <project:#pyoptinterface.Geq> as alias of <project:#pyoptinterface.ConstraintSense> to represent the sense of the constraint with a shorter name.
7272
:::
7373

74+
The linear constraint can also be created with a comparison operator, like `<=`, `==`, or `>=`:
75+
76+
```{code-cell}
77+
model.add_linear_constraint(2.0*x + 3.0*y <= 1.0)
78+
model.add_linear_constraint(2.0*x + 3.0*y == 1.0)
79+
model.add_linear_constraint(2.0*x + 3.0*y >= 1.0)
80+
```
81+
82+
If you want to express a two-sided linear constraint, you can use the `add_linear_constraint` method with a tuple to represent the left-hand side and right-hand side of the constraint like:
83+
84+
```{code-cell}
85+
model.add_linear_constraint(2.0*x + 3.0*y, (1.0, 2.0))
86+
```
87+
88+
which is equivalent to:
89+
```{code-cell}
90+
model.add_linear_constraint(2.0*x + 3.0*y, poi.Leq, 2.0)
91+
model.add_linear_constraint(2.0*x + 3.0*y, poi.Geq, 1.0)
92+
```
93+
94+
:::{note}
95+
96+
The two-sided linear constraint is not implemented for Gurobi because of its [special handling of range constraints](https://docs.gurobi.com/projects/optimizer/en/12.0/reference/c/model.html#c.GRBaddrangeconstr).
97+
:::
98+
7499
## Quadratic Constraint
75100
Like the linear constraint, it is defined as:
76101

@@ -103,6 +128,29 @@ add a quadratic constraint to the model
103128
:return: the handle of the constraint
104129
```
105130

131+
Similarly, the quadratic constraint can also be created with a comparison operator, like `<=`, `==`, or `>=`:
132+
133+
```python
134+
model.add_quadratic_constraint(x*x + 2.0*x*y + 4.0*y*y <= 1.0)
135+
model.add_quadratic_constraint(x*x + 2.0*x*y + 4.0*y*y == 1.0)
136+
model.add_quadratic_constraint(x*x + 2.0*x*y + 4.0*y*y >= 1.0)
137+
```
138+
139+
:::{note}
140+
141+
Some solvers like COPT (as of 7.2.9) only supports convex quadratic constraints, which means the quadratic term must be positive semidefinite. If you try to add a non-convex quadratic constraint, an exception will be raised.
142+
:::
143+
144+
The two-sided quadratic constraint can also be created with a tuple to represent the left-hand side and right-hand side of the constraint like:
145+
146+
```python
147+
model.add_quadratic_constraint(x*x + 2.0*x*y + 4.0*y*y, (1.0, 2.0))
148+
```
149+
:::{note}
150+
151+
Currently, two-sided quadratic constraint is only implemented for IPOPT.
152+
:::
153+
106154
## Second-Order Cone Constraint
107155
It is defined as:
108156

@@ -245,26 +293,3 @@ model.set_normalized_rhs(con, 2.0)
245293
# modify the coefficient of the linear part of the constraint
246294
model.set_normalized_coefficient(con, x, 2.0)
247295
```
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/examples/optimal_control_rocket.md.txt

Lines changed: 49 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -42,69 +42,76 @@ where $h_t$, $v_t$, and $m_t$ are the altitude, velocity, and mass at time $t$,
4242
In the discretized optimal control problem, the variables at two adjacent time points share the same algebraic relationship.
4343

4444
```{code-cell}
45-
from math import sqrt
45+
import math
4646
import pyoptinterface as poi
47-
from pyoptinterface import nlfunc, ipopt
47+
from pyoptinterface import nl, ipopt
4848

4949
model = ipopt.Model()
5050

51-
h_0 = 1 # Initial height
52-
v_0 = 0 # Initial velocity
53-
m_0 = 1.0 # Initial mass
54-
m_T = 0.6 # Final mass
55-
g_0 = 1 # Gravity at the surface
56-
h_c = 500 # Used for drag
57-
c = 0.5 * sqrt(g_0 * h_0) # Thrust-to-fuel mass
58-
D_c = 0.5 * 620 * m_0 / g_0 # Drag scaling
59-
u_t_max = 3.5 * g_0 * m_0 # Maximum thrust
60-
T_max = 0.2 # Number of seconds
61-
T = 1_000 # Number of time steps
62-
delta_t = 0.2 / T; # Time per discretized step
63-
64-
def rocket_dynamics(vars, params):
65-
m2, m1 = vars.m2, vars.m1
66-
h2, h1 = vars.h2, vars.h1
67-
v2, v1 = vars.v2, vars.v1
68-
u = vars.u
69-
70-
h_eq = (h2 - h1) - delta_t * v1
71-
v_eq = (v2 - v1) - delta_t * (-g_0 * (h_0 / h1)**2 + (u - D_c * v1**2 * nlfunc.exp(-h_c * (h1 - h_0) / h_0)) / m1)
72-
m_eq = (m2 - m1) - delta_t * (-u / c)
73-
74-
return [h_eq, v_eq, m_eq]
75-
76-
rd = model.register_function(rocket_dynamics)
51+
h_0 = 1.0
52+
v_0 = 0.0
53+
m_0 = 1.0
54+
g_0 = 1.0
55+
T_c = 3.5
56+
h_c = 500.0
57+
v_c = 620.0
58+
m_c = 0.6
59+
60+
c = 0.5 * math.sqrt(g_0 * h_0)
61+
m_f = m_c * m_0
62+
D_c = 0.5 * v_c * (m_0 / g_0)
63+
T_max = T_c * m_0 * g_0
64+
65+
nh = 1000
7766
```
7867

7968
Then, we declare variables and set boundary conditions.
8069

8170
```{code-cell}
82-
v = model.add_variables(range(T), name="v", lb=0.0, start=v_0)
83-
h = model.add_variables(range(T), name="h", lb=0.0, start=h_0)
84-
m = model.add_variables(range(T), name="m", lb=m_T, ub=m_0, start=m_0)
85-
u = model.add_variables(range(T), name="u", lb=0.0, ub=u_t_max, start=0.0)
71+
h = model.add_m_variables(nh, lb=1.0)
72+
v = model.add_m_variables(nh, lb=0.0)
73+
m = model.add_m_variables(nh, lb=m_f, ub=m_0)
74+
T = model.add_m_variables(nh, lb=0.0, ub=T_max)
75+
step = model.add_variable(lb=0.0)
8676

87-
model.set_variable_bounds(v[0], v_0, v_0)
77+
# Boundary conditions
8878
model.set_variable_bounds(h[0], h_0, h_0)
79+
model.set_variable_bounds(v[0], v_0, v_0)
8980
model.set_variable_bounds(m[0], m_0, m_0)
90-
model.set_variable_bounds(u[T-1], 0.0, 0.0)
81+
model.set_variable_bounds(m[-1], m_f, m_f)
9182
```
9283

9384
Next, we add the dynamics constraints.
9485

9586
```{code-cell}
96-
for t in range(T-1):
97-
model.add_nl_constraint(
98-
rd,
99-
vars=nlfunc.Vars(h2=h[t+1], h1=h[t], v2=v[t+1], v1=v[t], m2=m[t+1], m1=m[t], u=u[t]),
100-
eq=0.0,
101-
)
87+
for i in range(nh - 1):
88+
with nl.graph():
89+
h1 = h[i]
90+
h2 = h[i + 1]
91+
v1 = v[i]
92+
v2 = v[i + 1]
93+
m1 = m[i]
94+
m2 = m[i + 1]
95+
T1 = T[i]
96+
T2 = T[i + 1]
97+
98+
model.add_nl_constraint(h2 - h1 - 0.5 * step * (v1 + v2) == 0)
99+
100+
D1 = D_c * v1 * v1 * nl.exp(-h_c * (h1 - h_0)) / h_0
101+
D2 = D_c * v2 * v2 * nl.exp(-h_c * (h2 - h_0)) / h_0
102+
g1 = g_0 * h_0 * h_0 / (h1 * h1)
103+
g2 = g_0 * h_0 * h_0 / (h2 * h2)
104+
dv1 = (T1 - D1) / m1 - g1
105+
dv2 = (T2 - D2) / m2 - g2
106+
107+
model.add_nl_constraint(v2 - v1 - 0.5 * step * (dv1 + dv2) == 0)
108+
model.add_nl_constraint(m2 - m1 + 0.5 * step * (T1 + T2) / c == 0)
102109
```
103110

104111
Finally, we add the objective function. We want to maximize the altitude at the final time, so we set the objective function to be the negative of the altitude at the final time.
105112

106113
```{code-cell}
107-
model.set_objective(-h[T-1])
114+
model.set_objective(-h[-1])
108115
```
109116

110117
After solving the problem, we can plot the results.
@@ -115,7 +122,7 @@ model.optimize()
115122

116123
```{code-cell}
117124
h_value = []
118-
for i in range(T):
125+
for i in range(nh):
119126
h_value.append(model.get_value(h[i]))
120127

121128
print("Optimal altitude: ", h_value[-1])

0 commit comments

Comments
 (0)