# Direct interface

**Info:**The functionality presented here was introduced in

`opengen`

version `0.6.4`

.
The API is still young and is likely to change in versions `0.8.X`

.
As we discussed previously 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:

```
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:

```
sys.path.insert(1, './my_optimizers/rosenbrock')
import rosenbrock
```

Then you will be able to use it as follows:

```
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:

```
optimizers_dir = "my_optimizers"
optimizer_name = "rosenbrock"
sys.path.insert(1, os.path.join(optimizers_dir, optimizer_name))
rosenbrock = __import__(optimizer_name)
```