OpEn

OpEn

  • Docs
  • Blog
  • Rust API
  • Opengen API
  • Chat
  • Github

›Python

OpEn Guide

  • Introduction
  • Installation

Python

  • Opengen basics
  • Advanced options
  • C/C++ Bindings
  • Direct interface
  • TCP Sockets
  • ROS packages
  • Examples

MATLAB

  • MATLAB
  • Examples

Rust

  • Introduction
  • ALM/PM
  • Features

Docker

  • Docker

Extras

  • Algorithm
  • FAQ
  • Cite OpEn
  • Contributing

C/C++ Bindings

When using any of the tools to auto-generate a solver it is directly supported to also generate C/C++ bindings for integrating the solver from any language which supports a C or C++ application binary interface (ABI). This is a powerful feature when packaging a solver for distribution, or including it into a larger project.

Generating bindings

Generating bindings is as easy as adding with_build_c_bindings() to your build configuration. Here is a full example configuration for creating a solver. We will create an optimizer for the Rosenbrock function with equality and bound constraints on the decision variables:

import casadi.casadi as cs
import opengen as og

u = cs.SX.sym("u", 5)  # Decision variabels
p = cs.SX.sym("p", 2)  # Parameters

phi = og.functions.rosenbrock(u, p)  # Cost function

# Equality constraints: 1.5 * u[0] = u[1] and u[2] = u[3]
# Can also be inequality constratins using max{c(u, p), 0}, where c(u, p) < 0.
c = cs.vertcat(1.5*u[0] - u[1], u[2] - u[3])

# Bounds constraints on u
umin = [-2.0] * 5  # shorthand notation
umax = [ 2.0] * 5

# Bounds on u: (umin <= u <= umax)
bounds = og.constraints.Rectangle(umin, umax)

# Define the problem
problem = og.builder.Problem(u, p, phi)                 \
    .with_penalty_constraints(c)                        \
    .with_constraints(bounds)

# Meta information for the solver
meta = og.config.OptimizerMeta()                        \
    .with_version("1.0.0")                              \
    .with_authors(["P. Sopasakis", "E. Fresk"])         \
    .with_optimizer_name("the_optimizer")

# Lets build in release mode with C bindings
build_config = og.config.BuildConfiguration()           \
    .with_build_mode("release")                         \
    .with_build_c_bindings()            # <--- The important setting

# Solver settings
solver_config = og.config.SolverConfiguration()         \
    .with_tolerance(1e-5)                               \
    .with_constraints_tolerance(1e-4)                   \
    .with_max_outer_iterations(15)                      \
    .with_penalty_weight_update_factor(8.0)             \
    .with_initial_penalty_weights([20.0, 5.0])

# Create the solver!
builder = og.builder.OpEnOptimizerBuilder(problem,
                                          metadata=meta,
                                          build_configuration=build_config,
                                          solver_configuration=solver_config)

builder.build()

The generated C/C++ bindings are in the auto-generated solver library. In particular

  • The header files are at the_optimizer/the_optimizer_bindings.{h,hpp}
  • The static and dynamical library files are located in the_optimizer/target/{debug,release} (depending on whether it was a debug or release build)

Note that the_optimizer is the name given to the optimizer in the Python codegen above.

Matlab generation will come soon.

Bindings API

The generated API has the following functions available (for complete definitions see the generated header files) for a solver entitled "example":

/* Contents of header file: example_bindings.h */

#define EXAMPLE_N1 0
#define EXAMPLE_N2 2
#define EXAMPLE_NUM_DECISION_VARIABLES 5
#define EXAMPLE_NUM_PARAMETERS 2

typedef enum {
  exampleConverged,
  exampleNotConvergedIterations,
  exampleNotConvergedOutOfTime,
  exampleNotConvergedCost,
  exampleNotConvergedNotFiniteComputation,
} exampleExitStatus;

typedef struct exampleCache exampleCache;

typedef struct {
  exampleExitStatus exit_status;
  unsigned long num_outer_iterations;
  unsigned long num_inner_iterations;
  double last_problem_norm_fpr;  
  unsigned long long solve_time_ns;
  double penalty;
  double delta_y_norm_over_c;
  double f2_norm;
  const double *lagrange;
} exampleSolverStatus;

void example_free(exampleCache *instance);

exampleCache *example_new(void);

exampleSolverStatus example_solve(exampleCache *instance,
                                  double *u,
                                  const double *params,
                                  const double *y0,
                                  const double *c0);

This is designed to follow a new-use-free pattern.

Function {optimizer-name}_new will allocate memory and setup a new solver instance and can be used to create as many solvers as necessary. Each solver instance can be used with {optimizer-name}_solve to solve the corresponding problem as many times as needed.

Parameter u is the starting guess and also the return of the decision variables and params is the array of static parameters. The size of u and params are {optimizer-name}_NUM_DECISION_VARIABLES and {optimizer-name}_NUM_PARAMETERS respectively.

Finally, when done with the solver, use {optimizer-name}_free to release the memory allocated by {optimizer-name}_new.

Using the bindings in an app

Suppose that you have compiled your optimizer using the option with_build_c_bindings() and you have generated C/C++ bindings. OpEn will generate an example C file that you can use as a starting point to build your application. This example file is stored in the directory containing all other files of your optimizer and is called example_optimizer.c. The auto-generated example has the following form:

/* File: the_optimizer/example_optimizer.c  */

#include <stdio.h>
#include "example_bindings.h"

int main() {
    double p[EXAMPLE_NUM_PARAMETERS] = {1.0, 10.0};  // parameter
    double u[EXAMPLE_NUM_DECISION_VARIABLES] = {0};  // initial guess

    exampleCache *cache = example_new();
    exampleSolverStatus status = example_solve(cache, u, p);
    example_free(cache);

    for (int i = 0; i < EXAMPLE_NUM_DECISION_VARIABLES; ++i) {
        printf("u[%d] = %g\n", i, u[i]);
    }

    printf("exit status = %d\n", status.exit_status);
    printf("iterations = %lu\n", status.num_inner_iterations);
    printf("outer iterations = %lu\n", status.num_outer_iterations);
    printf("solve time = %f ms\n", (double)status.solve_time_ns / 1e6);

    return 0;
}

Compiling and linking

Using cmake

To compile your C program you need to link to the auto-generated C bindings (see next section). However, OpEn generates automatically a CMakeLists.txt file to facilitate the compilation/linking procedure. To build the auto-generated example run

cmake .
make

once you build your optimizer you can run the executable (optimizer) with

make run

Compile your own code

When building and running an application based on the generated libraries it is good to know that GCC is a bit temperamental when linking libraries, so when linking the static library the following can be used as reference:

gcc example_optimizer.c -l:libthe_optimizer.a \
  -L./target/release -pthread -lm -ldl -o optimizer

Or using direct linking (this is the only thing that works with clang):

gcc example_optimizer.c ./target/release/libthe_optimizer.a \
  -pthread -lm -ldl -o optimizer

While the following can be used when using the shared library:

gcc example_optimizer.c -lthe_optimizer \
  -L./target/release -pthread -lm -ldl -o optimizer

Running

Which will solve the problem and output the following when run:

# When linking with static lib
./optimizer
# When linking with dynamic lib
LD_LIBRARY_PATH=./target/release ./optimizer

u[0] = 0.654738
u[1] = 0.982045
u[2] = 0.98416
u[3] = 0.984188
u[4] = 0.969986
exit status = 0
iterations = 69
outer iterations = 5
solve time = 0.140401 ms
← Advanced optionsDirect interface →
  • Generating bindings
  • Bindings API
  • Using the bindings in an app
    • Compiling and linking
    • Running
OpEn
Docs
Getting StartedPython interfaceMATLAB interfaceDocker
Community
User ShowcaseDiscord communityChat on GitterTwitter
More
BlogGitHubOpenhubStar

Tweet
Copyright © 2025 Pantelis Sopasakis and Emil Fresk
Box Icon made by Freepik from www.flaticon.com