CasADi

Define a problem in CasADi

This example does not intend to cover all the features of CasADi. For more details and tutorials on CasADi, please refer to CasADi’s documentation. For more details on the CasadiProblem class, please see the API Reference. In this example, we solve a constrained problem given by

\[ \begin{align}\begin{aligned} \underset{x_1, x_2 \in \mathbb{R}}{\text{minimize}} \quad x_1^2 + x_2^2\\\newline \text{subject to} \quad x_1 \geq 0 \newline \quad \quad \quad \quad x_1 + x_2 = 1 \newline \quad \quad \quad \quad x_1 - x_2 \geq 1 \end{aligned}\end{align} \]

We know the solution of this problem is \(x_1=1\), and \(x_2=0\). However, we start from an initial guess of \(x_1=500.0\), and \(x_2=5.0\) for the purposes of this tutorial.

The problem functions are written using CasADi expressions as follows:

import casadi as ca

# minimize x^2 + y^2 subject to x>=0, x+y=1, x-y>=1.

ca_obj = lambda x: ca.sum1(x**2)
ca_con = lambda x: ca.vertcat(x[0] + x[1], x[0] - x[1])

modOpt will auto-generate the gradient, Jacobian, and objective Hessian, as well as the Lagrangian, its gradient, and Hessian. Users do not need to manually generate these functions or their derivatives using CasADi and then wrap them. Once the problem functions are defined as CasADi expressions, create a CasadiProblem object for modOpt by passing the above expressions along with other problem constants, such as initial guesses, variable bounds, and constraint bounds.

import numpy as np
import modopt as mo

prob = mo.CasadiProblem(x0=np.array([500., 5.]), ca_obj=ca_obj, ca_con=ca_con, 
                        cl=np.array([1., 1.]), cu=np.array([1., np.inf]), 
                        xl=np.array([0., -np.inf]), xu=np.array([np.inf, np.inf]),
                        name='quadratic_casadi', order=1)
/Users/modopt/modopt/core/problem_lite.py:198: UserWarning: Objective Hessian function "obj_hess" not provided. Finite differences will be used if objective Hessian computation is necessary.
  warnings.warn('Objective Hessian function "obj_hess" not provided. Finite differences will be used if objective Hessian computation is necessary.')
/Users/modopt/modopt/core/problem_lite.py:209: UserWarning: Lagrangian Hessian function "lag_hess" not provided. Finite differences will be used if Lagrangian Hessian computation is necessary.
  warnings.warn('Lagrangian Hessian function "lag_hess" not provided. Finite differences will be used if Lagrangian Hessian computation is necessary.')

Solve your problem using an optimizer

Once your problem model is wrapped for modOpt, import your preferred optimizer from modOpt and solve it, following the standard procedure. Here we will use the SLSQP optimizer from the SciPy library.

# Setup your preferred optimizer (SLSQP) with the Problem object 
# Pass in the options for your chosen optimizer
optimizer = mo.SLSQP(prob, solver_options={'maxiter':20})

# Check first derivatives at the initial guess, if needed
optimizer.check_first_derivatives(prob.x0)

# Solve your optimization problem
optimizer.solve()

# Print results of optimization
optimizer.print_results()
----------------------------------------------------------------------------
Derivative type | Calc norm  | FD norm    | Abs error norm | Rel error norm 
----------------------------------------------------------------------------

Gradient        | 1.0000e+03 | 1.0000e+03 | 1.5473e-05     | 1.5472e-08    
Jacobian        | 2.0000e+00 | 2.0000e+00 | 5.0495e-09     | 2.5248e-09    
----------------------------------------------------------------------------


	Solution from Scipy SLSQP:
	----------------------------------------------------------------------------------------------------
	Problem                  : quadratic_casadi
	Solver                   : scipy-slsqp
	Success                  : True
	Message                  : Optimization terminated successfully
	Status                   : 0
	Total time               : 0.002165079116821289
	Objective                : 1.0000000068019972
	Gradient norm            : 2.000000006801997
	Total function evals     : 2
	Total gradient evals     : 2
	Major iterations         : 2
	Total callbacks          : 17
	Reused callbacks         : 0
	obj callbacks            : 5
	grad callbacks           : 3
	hess callbacks           : 0
	con callbacks            : 6
	jac callbacks            : 3
	----------------------------------------------------------------------------------------------------

Scaling API

Please refer to the code snippet below as a guide for scaling the design variables, objective, and constraints independent of their definitions.

Warning

The results provided by the optimizer will always be scaled, while the values from the models will remain unscaled.

prob = mo.CasadiProblem(x0=np.array([500., 5.]), ca_obj=ca_obj, ca_con=ca_con, 
                        cl=np.array([1., 1.]), cu=np.array([1., np.inf]), 
                        xl=np.array([0., -np.inf]), xu=np.array([np.inf, np.inf]),
                        x_scaler=2., # constant to scale all variables
                        # x_scaler=np.array([1., 2.]), # scaler to scale each variable differently
                        o_scaler=5., # objective function scaler
                        # c_scaler=10., # constant to scale all constraints
                        c_scaler=np.array([10., 100.]), # scaler to scale each constraint differently
                        name='quadratic_casadi_scaled', order=1)

optimizer = mo.SLSQP(prob, solver_options={'maxiter':20})
optimizer.solve()
optimizer.print_results()
	Solution from Scipy SLSQP:
	----------------------------------------------------------------------------------------------------
	Problem                  : quadratic_casadi_scaled
	Solver                   : scipy-slsqp
	Success                  : True
	Message                  : Optimization terminated successfully
	Status                   : 0
	Total time               : 0.0031080245971679688
	Objective                : 4.999999999999996
	Gradient norm            : 4.999999878155281
	Total function evals     : 3
	Total gradient evals     : 2
	Major iterations         : 2
	Total callbacks          : 11
	Reused callbacks         : 0
	obj callbacks            : 3
	grad callbacks           : 2
	hess callbacks           : 0
	con callbacks            : 4
	jac callbacks            : 2
	----------------------------------------------------------------------------------------------------