Optimization

Optimization problems can be solved with driver Optimizer.

Optimizer seeks a user-defined parameter set that minimizes a scalar objective.

Define an optimization problem

Optimization problems are defined using three driver methods:

  • set_minimum or set_maximum (as required)

  • add_unknown

  • add_constraints

Add driver

from cosapp.drivers import Optimizer

s = SomeSystem('s')
optim = s.add_driver(Optimizer('optim'))

Set minimization or maximization objective

The argument passed to set_minimum (resp. set_maximum) must be a scalar expression evaluable in the context of owner system:

optim.set_minimum("a**2 + b.x * exp(c.p_out.y / 2)")

Define optimization parameters

Optimization parameters are declared with method add_unknown, akin to nonlinear problem unknowns:

optim.add_unknown(['u', 'v'])
optim.add_unknown('alpha', lower_bound=0, upper_bound=1)

When specified, lower and upper bounds are used as linear constraints during resolution.

Define constraints

General constraints are given as plain strings (or a list thereof) in add_constraints. Each constraint can either be an equality or an inequality. Inequalities are translated into non-negative constraints, whether the inequality is strict or not. For instance, x < y will translate into y - x >= 0.

Note that multiple constraints can be expressed in a single expression, as in: "a > b > c".

optim.add_constraints("0 <= b.y <= 2 * c.x")  # yields two constraints
optim.add_constraints([
    "0.1 <= h == sqrt(A)",  # h >= 0.1 and h == sqrt(A)
    "a + b < c",  # interpreted as c - (a + b) >= 0
])

Options

Driver Optimizer encapsulates function scipy.optimize.minimize. All methods implemented in minimize (SLSQP, Conjugate Gradient, Nelder-Mead, etc.) are available, through optional argument method.

The list of available methods is given by:

[1]:
from cosapp.drivers import Optimizer

Optimizer.available_methods()
[1]:
['Nelder-Mead',
 'Powell',
 'CG',
 'BFGS',
 'Newton-CG',
 'L-BFGS-B',
 'TNC',
 'COBYLA',
 'SLSQP',
 'dogleg',
 'trust-constr',
 'trust-ncg',
 'trust-exact',
 'trust-krylov']

Other options are:

  • tol [float]: Relative tolerance on objective value between two iterations (default: 1.5e-8).

  • eps [float]: Relative step size used for numerical approximation of the Jacobian (default: 2^(-26) ~ 1.49e-8).

  • max_iter [int]: Maximum number of iterations (default: 100).

  • monitor [bool]: If True, data are recorded into driver recorder (if any) at all iterations; if False (default), only the final state is recorded.

Options may be set at driver construction (as keyword arguments), or by setting the desired key in dict attribute options, as in:

optim.options['tol'] = 1e-9
optim.options['max_iter'] = 50

Examples