Introduction to Condor

We wanted to have an API that looks as much like a mathematical description as possible with as little distraction from programming cruft as possible. For example, an arbitrary system of equations like from Sellar [sellar],

y1=x02+x1+x20.2y2y2=y1+x0+x1

should be writable as

y1 == x[0] ** 2 + x[1] + x[2] - 0.2 * y2
y2 == y1**0.5 + x[0] + x[1]

Of course, in both the mathematical and programmatic description, the source of each symbol must be defined. In an engineering memo, we might say “where y1,y2 are the variables to solve and xR3 parameterizes the system of equations,” which suggests the API for an algebraic system of equations as

import condor

class Coupling(condor.AlgebraicSystem):
    x = parameter(shape=3)
    y1 = variable(initializer=1.)
    y2 = variable(initializer=1.)

    residual(y1 == x[0] ** 2 + x[1] + x[2] - 0.2 * y2)
    residual(y2 == y1**0.5 + x[0] + x[1])

which can be evaluated by instantiating the model with numerical values for the parameters:

coupling = Coupling([5., 2., 1])

Once the model is finished running, the model binds the numerical results from the iterative solver to the named element and field attributes on the instance. That is, elements of fields accessible directly:

print(coupling.y1, coupling.y2)
[25.58830237] [12.05848815]

Fields are bound as dataclasses

print(coupling.variable)
CouplingVariable(y1=array([25.58830237]), y2=array([12.05848815]))

Models can be used recursively, building up more sophisticated models by embedding models within another. However, system encapsulation is enforced so only elements from input and output fields are accessible after the model has been defined. For example, we may wish to optimize Sellar’s algebraic system of equations. Mathematically, we can define the optimization as

minimizexR3x22+x1+y1+ey2subject to3.16y1y224.0

where y1 and y2 are the solution to the system of algebraic equations described above. In condor, we can write this as

from condor.backend import operators as ops

class Sellar(condor.OptimizationProblem):
    x = variable(shape=3, lower_bound=0, upper_bound=10)
    coupling = Coupling(x)
    y1, y2 = coupling

    objective = x[2]**2 + x[1] + y1 + ops.exp(-y2)
    constraint(y1 >= 3.16)
    constraint(24. >= y2)

As with the system of algebraic equations, we can numerically solve this optimization problem by providing an initial value for the variables and instantiating the model.

Sellar.set_initial(x=[5,2,1])
sellar = Sellar()
This is Ipopt version 3.14.11, running with linear solver MUMPS 5.4.1.

Number of nonzeros in equality constraint Jacobian...:        0
Number of nonzeros in inequality constraint Jacobian.:        6
Number of nonzeros in Lagrangian Hessian.............:        6

Total number of variables............................:        3
                     variables with only lower bounds:        0
                variables with lower and upper bounds:        3
                     variables with only upper bounds:        0
Total number of equality constraints.................:        0
Total number of inequality constraints...............:        2
        inequality constraints with only lower bounds:        1
   inequality constraints with lower and upper bounds:        0
        inequality constraints with only upper bounds:        1

iter    objective    inf_pr   inf_du lg(mu)  ||d||  lg(rg) alpha_du alpha_pr  ls
   0  2.8588308e+01 0.00e+00 9.61e+00  -1.0 0.00e+00    -  0.00e+00 0.00e+00   0
   1  2.5032242e+01 0.00e+00 9.60e+00  -1.0 1.90e+03    -  4.74e-03 1.12e-03f  1
   2  1.6557725e+01 0.00e+00 4.45e+00  -1.0 3.81e+01    -  1.00e+00 5.42e-01f  1
   3  1.5031940e+01 0.00e+00 3.92e+00  -1.0 6.87e+00    -  1.00e+00 1.15e-01f  1
   4  4.5491414e+00 0.00e+00 6.34e-01  -1.0 6.04e+00    -  1.00e+00 1.00e+00f  1
   5  3.4782092e+00 0.00e+00 5.17e-02  -1.7 9.99e-01    -  1.00e+00 8.87e-01f  1
   6  3.2369916e+00 0.00e+00 2.15e-03  -1.7 2.29e-01    -  1.00e+00 1.00e+00f  1
   7  3.1867988e+00 0.00e+00 3.56e-05  -3.8 5.09e-02    -  1.00e+00 1.00e+00h  1
   8  3.1845411e+00 0.00e+00 8.40e-07  -3.8 2.55e-02    -  1.00e+00 1.00e+00h  1
   9  3.1836276e+00 0.00e+00 3.86e-07  -5.7 1.34e-02    -  1.00e+00 1.00e+00h  1
iter    objective    inf_pr   inf_du lg(mu)  ||d||  lg(rg) alpha_du alpha_pr  ls
  10  3.1834622e+00 0.00e+00 8.19e-08  -5.7 6.64e-03    -  1.00e+00 1.00e+00h  1
  11  3.1834161e+00 0.00e+00 1.91e-08  -5.7 3.20e-03    -  1.00e+00 1.00e+00h  1
  12  3.1834029e+00 0.00e+00 3.60e-09  -5.7 1.39e-03    -  1.00e+00 1.00e+00h  1
  13  3.1833947e+00 0.00e+00 7.48e-10  -8.6 6.21e-04    -  1.00e+00 1.00e+00h  1
  14  3.1833939e+00 0.00e+00 2.48e-11  -8.6 1.15e-04    -  1.00e+00 1.00e+00h  1
  15  3.1833939e+00 0.00e+00 3.38e-14  -8.6 4.25e-06    -  1.00e+00 1.00e+00h  1

Number of Iterations....: 15

                                   (scaled)                 (unscaled)
Objective...............:   3.1833939181332549e+00    3.1833939181332549e+00
Dual infeasibility......:   3.3805821765621465e-14    3.3805821765621465e-14
Constraint violation....:   0.0000000000000000e+00    0.0000000000000000e+00
Variable bound violation:   7.4470968355807926e-09    7.4470968355807926e-09
Complementarity.........:   2.5421361853922688e-09    2.5421361853922688e-09
Overall NLP error.......:   2.5421361853922688e-09    2.5421361853922688e-09


Number of objective function evaluations             = 16
Number of objective gradient evaluations             = 16
Number of equality constraint evaluations            = 0
Number of inequality constraint evaluations          = 16
Number of equality constraint Jacobian evaluations   = 0
Number of inequality constraint Jacobian evaluations = 16
Number of Lagrangian Hessian evaluations             = 15
Total seconds in IPOPT                               = 0.062

EXIT: Optimal Solution Found.

The resulting object will have a dot-able data structure with the bound results, including the embedded Coupling model:

print("objective value:", sellar.objective) # scalar value
print(sellar.constraint) # field
print(sellar.coupling.y1) # embedded-model element
objective value: 3.183393918133255
SellarConstraint(Sellar_constraint_0=array([3.16]), Sellar_constraint_1=array([3.75527764]))
[3.15999998]

References

[sellar]

Sellar, R., Batill, S., and Renaud, J., “Response Surface Based, Concurrent Subspace Optimization for Multidisciplinary System Design,” 1996. https://doi.org/10.2514/6.1996-714

Total running time of the script: (0 minutes 0.154 seconds)

Gallery generated by Sphinx-Gallery