-
Notifications
You must be signed in to change notification settings - Fork 55
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #218 from alphaville/feature/pyo3-interface
Python-to-Rust interface using Pyo3
- Loading branch information
Showing
15 changed files
with
504 additions
and
43 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
--- | ||
id: python-bindings | ||
title: Direct interface | ||
description: How to access the auto-generated optimizer from Python | ||
--- | ||
|
||
<script type="text/x-mathjax-config">MathJax.Hub.Config({tex2jax: {inlineMath: [['$','$'], ['\\(','\\)']]}});</script> | ||
<script type="text/javascript" async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script> | ||
|
||
<div class="alert alert-warning"> | ||
<b>Info:</b> The functionality presented here was introduced in <code>opengen</code> version <code>0.6.4</code>. | ||
The API is still young and is likely to change in versions <code>0.7.X</code>. | ||
</div> | ||
|
||
|
||
As we [discussed previously](python-interface#about) there are various ways | ||
you can use the auto-generated optimizer. You can use the generated Rust code, | ||
access it over a TCP socket, and so on. In this section we will focus on | ||
how to access it *directly*. | ||
|
||
The idea is that OpEn can generate a Python module that you can `import`. | ||
|
||
## Generate a Python module for your optimizer | ||
Consider the following [parametric optimization problem](example_rosenbrock_py): | ||
<div class="math"> | ||
\[ | ||
\begin{align} | ||
\operatorname*{Minimize}_{\|u\|\leq r}& \sum_{i=1}^{n_u - 1} b (u_{i+1} - u_{i}^2)^2 + (a-u_i)^2 | ||
\\ | ||
\text{subject to: }& 1.5 u_1 - u_2 = 0 | ||
\\ | ||
&u_3 - u_4 + 0.1 \leq 0 | ||
\end{align} | ||
\]</div> | ||
|
||
```python | ||
import opengen as og | ||
import casadi.casadi as cs | ||
|
||
u = cs.SX.sym("u", 5) | ||
p = cs.SX.sym("p", 2) | ||
phi = og.functions.rosenbrock(u, p) | ||
c = cs.vertcat(1.5 * u[0] - u[1], | ||
cs.fmax(0.0, u[2] - u[3] + 0.1)) | ||
bounds = og.constraints.Ball2(radius=1.5) | ||
problem = og.builder.Problem(u, p, phi) \ | ||
.with_penalty_constraints(c) \ | ||
.with_constraints(bounds) | ||
build_config = og.config.BuildConfiguration() \ | ||
.with_build_directory("my_optimizers") \ | ||
.with_build_mode("debug") \ | ||
.with_build_python_bindings() | ||
meta = og.config.OptimizerMeta() \ | ||
.with_optimizer_name("rosenbrock") | ||
builder = og.builder.OpEnOptimizerBuilder(problem, meta, | ||
build_config) | ||
builder.build() | ||
``` | ||
|
||
Note that we have used `with_build_python_bindings()`. | ||
|
||
This will allow us to **import the auto-generated optimizer** as a Python | ||
module! | ||
|
||
|
||
|
||
## Use the generated module | ||
|
||
The above code generates an optimizer which is stored in `my_optimizers/rosenbrock`. | ||
In that directory you can find a file called `rosenbrock.so` (or `rosenbrock.pyd` on Windows). | ||
This can be loaded as an autogenerated Python module. | ||
However, mind that this directory is most likely not in your Python path, | ||
so you will have to add it before you can import the optimizer. | ||
This can be done very easily: | ||
|
||
```python | ||
sys.path.insert(1, './my_optimizers/rosenbrock') | ||
import rosenbrock | ||
``` | ||
|
||
Then you will be able to use it as follows: | ||
|
||
```python | ||
solver = rosenbrock.solver() | ||
result = solver.run(p=[20., 1.]) | ||
u_star = result.solution | ||
``` | ||
|
||
In the first line, `solver = rosenbrock.solver()`, we obtain an instance of | ||
`Solver`, which can be used to solve parametric optimization problems. | ||
In the second line, `result = solver.run(p=[20., 1.])`, we call the solver | ||
with parameter $p=(20, 1)$. Method `run` accepts another three optional | ||
arguments, namely: | ||
|
||
- `initial_guess` (can be either a list or a numpy array), | ||
- `initial_lagrange_multipliers`, and | ||
- `initial_penalty` | ||
|
||
The solver returns an object of type `OptimizerSolution` with the following | ||
properties: | ||
|
||
|
||
| Property | Explanation | | ||
|--------------------------|---------------------------------------------| | ||
| `exit_status` | Exit status; can be (i) `Converged` or (ii) `NotConvergedIterations`, if the maximum number of iterations was reached, therefore, the algorithm did not converge up to the specified tolerances, or (iii) `NotConvergedOutOfTime`, if the solver did not have enough time to converge | | ||
| `num_outer_iterations` | Number of outer iterations | | ||
| `num_inner_iterations` | Total number of inner iterations (for all inner problems) | | ||
| `last_problem_norm_fpr` | Norm of the fixed-point residual of the last inner problem; this is a measure of the solution quality of the inner problem | | ||
| `f1_infeasibility` | Euclidean norm of $c^{-1}(y^+-y)$, which is equal to the distance between $F_1(u, p)$ and $C$ at the solution | | ||
| `f2_norm` | Euclidean norm of $F_2(u, p)$ at the solution| | ||
| `solve_time_ms` | Total execution time in milliseconds | | ||
| `penalty` | Last value of the penalty parameter | | ||
| `solution` | Solution | | ||
| `cost` | Cost function at solution | | ||
| `lagrange_multipliers` | Vector of Lagrange multipliers (if $n_1 > 0$) or an empty vector, otherwise | | ||
|
||
These are the same properties as those of `opengen.tcp.SolverStatus`. | ||
|
||
|
||
## Importing optimizer with variable name | ||
|
||
Previously we used `import rosenbrock` to import the auto-generated module. | ||
|
||
The limitation of this syntax is that it makes it difficult to change the name of the optimizer, i.e., `rosenbrock` is hard-coded. | ||
|
||
A better syntax would be: | ||
|
||
```python | ||
optimizers_dir = "my_optimizers" | ||
optimizer_name = "rosenbrock" | ||
sys.path.insert(1, os.path.join(optimizers_dir, optimizer_name)) | ||
rosenbrock = __import__(optimizer_name) | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
0.6.3 | ||
0.6.4 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.