Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Continuous Optimization: Nonlinear Programming

# This code cell installs packages on Colab

import sys

if "google.colab" in sys.modules:
    !wget "https://raw.githubusercontent.com/ndcbe/optimization/main/notebooks/helper.py"
    import helper

    helper.easy_install()
else:
    sys.path.insert(0, "../")
    import helper
helper.set_plotting_style()
import random

import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import pyomo.environ as pyo

# Seed the random number generator so this notebook is reproducible
# (Pyomo style guide, section 8).
random.seed(0)

Nonlinear Programs: Circle Packing Example

What is the smallest rectangle you can use to enclose three given circles? Reference: Example 4.4 in Biegler (2010).

picture

Propose an Optimization Model

The following optimization model is given in Biegler (2010):

min2(A+B)s.t.A0,B0,x1,y1R1,x1BR1,y1AR1,x2,y2R2,x2BR2,y2AR2,x3,y3R3,x3BR3,y3AR3,(x1x2)2+(y1y2)2(R1+R2)2,(x1x3)2+(y1y3)2(R1+R3)2,(x2x3)2+(y2y3)2(R2+R3)2,\begin{align} \text{min} \quad & 2(A + B) \\ \text{s.t.} \quad & A \geq 0, \quad B \geq 0, \\ & x_1, y_1 \geq R_1, \quad x_1 \leq B - R_1, \quad y_1 \leq A - R_1, \\ & x_2, y_2 \geq R_2, \quad x_2 \leq B - R_2, \quad y_2 \leq A - R_2, \\ & x_3, y_3 \geq R_3, \quad x_3 \leq B - R_3, \quad y_3 \leq A - R_3, \\ & (x_1 - x_2)^2 + (y_1 - y_2)^2 \geq (R_1 + R_2)^2, \\ & (x_1 - x_3)^2 + (y_1 - y_3)^2 \geq (R_1 + R_3)^2, \\ & (x_2 - x_3)^2 + (y_2 - y_3)^2 \geq (R_2 + R_3)^2, \end{align}

How can we more compactly represent this using sets?

Activity

Identify the sets, parameters, variables, and constraints.

Sets

Click to expand

C={1,2,3}\mathcal{C} = \{1, 2, 3\}: circles

Parameters

Click to expand

RiR_i: radius of circle ii

Variables

Click to expand

xix_i, yiy_i: coordinates for circle ii

AA, BB: dimensions of the bounding rectangle

Objective

Click to expand

2(A+B)2(A + B): perimeter of the bounding rectangle

Constraints

Click to expand

circle ii cannot overlap with sides of bounding rectangle:

xi,yiRi,xiBRi,yiARi,iCx_i, y_i \geq R_i, \quad x_i \leq B - R_i, \quad y_i \leq A - R_i, \forall i \in \mathcal{C}

no overlap between circles ii and jj:

(xixj)2+(yiyj)2(Ri+Rj)2,i,j{iC,jC:i<j}(x_i - x_j)^2 + (y_i - y_j)^2 \geq (R_i + R_j)^2, \forall i,j \in \{i \in \mathcal{C}, j \in \mathcal{C}: i < j\}

non-negative rectangle lengths:

A,B0A, B \geq 0

Complete Optimization Formulation

Click to see the solution to the activity
minx,y,A,B2(A+B)perimeters.t.A0,B0non-negative bounds,xi,yiRi,xiBRi,yiARi,iCcircles cannot overlap with perimeter(xixj)2+(yiyj)2(Ri+Rj)2,i,j{iC,jC:i<j}circles cannot overlap with each other\begin{align*} \text{min}_{x,y,A,B} \quad & 2(A + B) & \text{perimeter} \\ \text{s.t.} \quad & A \geq 0, \quad B \geq 0 & \text{non-negative bounds}, \\ & x_i, y_i \geq R_i, \quad x_i \leq B - R_i, \quad y_i \leq A - R_i, \forall i \in \mathcal{C} & \text{circles cannot overlap with perimeter} \\ & (x_i - x_j)^2 + (y_i - y_j)^2 \geq (R_i + R_j)^2, \forall i,j \in \{i \in \mathcal{C}, j \in \mathcal{C}: i < j\} & \text{circles cannot overlap with each other} \end{align*}

Activity

Perform degree of freedom analysis.

Degree of Freedom Analysis

Click to expand

Continuous variables: 2+2C2 + 2 | \mathcal{C} |   (the box dimensions AA and BB, plus a center (xi,yi)(x_i, y_i) for each circle)

Inequality constraints: 2+4C+(C2)2 + 4 | \mathcal{C} | + {| \mathcal{C} | \choose 2}

Implement in Pyomo

First, we will define a function that builds the model.

def create_circle_model(circle_radii):
    """Create circle optimization model in Pyomo

    Arguments:
        circle_radii: dictionary with keys=circle name and value=radius (float)

    Returns:
        model: Pyomo model
    """

    # Create a concrete Pyomo model.
    model = pyo.ConcreteModel()

    # Set of circles to pack, C in the notes
    model.CIRCLES = pyo.Set(initialize=circle_radii.keys())

    # Radius of each circle, R_i in the notes [m]
    model.R = pyo.Param(
        model.CIRCLES,
        domain=pyo.PositiveReals,
        initialize=circle_radii,
        units=pyo.units.m,
    )

    # Height of the enclosing box, A in the notes [m]
    model.box_height = pyo.Var(domain=pyo.PositiveReals, units=pyo.units.m)

    # Width of the enclosing box, B in the notes [m]
    model.box_width = pyo.Var(domain=pyo.PositiveReals, units=pyo.units.m)

    # Center of circle i, (x_i, y_i) in the notes [m]
    model.x = pyo.Var(model.CIRCLES, domain=pyo.PositiveReals, units=pyo.units.m)
    model.y = pyo.Var(model.CIRCLES, domain=pyo.PositiveReals, units=pyo.units.m)

    # Minimize the perimeter of the box [m]
    model.obj = pyo.Objective(
        expr=2 * (model.box_height + model.box_width), sense=pyo.minimize
    )

    # "In the box" constraints. The decorated rule receives the block as its
    # first argument, so `b` is the model being built.
    @model.Constraint(model.CIRCLES)
    def left_x_con(b, c):
        return b.x[c] >= b.R[c]

    @model.Constraint(model.CIRCLES)
    def left_y_con(b, c):
        return b.y[c] >= b.R[c]

    @model.Constraint(model.CIRCLES)
    def right_x_con(b, c):
        return b.x[c] <= b.box_width - b.R[c]

    @model.Constraint(model.CIRCLES)
    def right_y_con(b, c):
        return b.y[c] <= b.box_height - b.R[c]

    # No overlap constraints. The rule is declared over CIRCLES x CIRCLES and
    # skips every pair with c1 >= c2, which leaves one constraint per pair.
    @model.Constraint(model.CIRCLES, model.CIRCLES)
    def no_overlap_con(b, c1, c2):
        if c1 < c2:
            return (b.x[c1] - b.x[c2]) ** 2 + (b.y[c1] - b.y[c2]) ** 2 >= (
                b.R[c1] + b.R[c2]
            ) ** 2
        else:
            return pyo.Constraint.Skip

    return model

Next, we will define a function that initializes the model. Notice this is separate from the function above: the model and the initial point are two different things, and for a nonconvex problem the initial point is part of the specification of what you solved.

def initialize_circle_model(model, height_init=25, width_init=25):
    """Initialize the x and y coordinates using uniform distribution

    Arguments:
        model: Pyomo model
        height_init: initial value for box_height (default=25)
        width_init: initial value for box_width (default=25)

    Returns:
        Nothing. But per Pyomo scoping rules, the input argument `model`
        can be modified in this function.

    """
    # Initialize
    model.box_height = height_init
    model.box_width = width_init

    for i in model.CIRCLES:
        # Adding circle radii ensures the circle remains in the >0, >0 quadrant
        model.x[i] = random.uniform(0, 10) + pyo.value(model.R[i])
        model.y[i] = random.uniform(0, 10) + pyo.value(model.R[i])

Next, we will create a dictionary containing the circle names and radii values.

# Create dictionary with circle data
circle_data = {"A": 10.0, "B": 5.0, "C": 3.0}
circle_data
{'A': 10.0, 'B': 5.0, 'C': 3.0}
# Access the keys
circle_data.keys()
dict_keys(['A', 'B', 'C'])

Now let’s create the model.

# Create model
model = create_circle_model(circle_data)
model.pprint()
1 Set Declarations
    CIRCLES : Size=1, Index=None, Ordered=Insertion
        Key  : Dimen : Domain : Size : Members
        None :     1 :    Any :    3 : {'A', 'B', 'C'}

1 Param Declarations
    R : Size=3, Index=CIRCLES, Domain=PositiveReals, Default=None, Mutable=True, Units=m
        Key : Value
          A :  10.0
          B :   5.0
          C :   3.0

4 Var Declarations
    box_height : Size=1, Index=None, Units=m
        Key  : Lower : Value : Upper : Fixed : Stale : Domain
        None :     0 :  None :  None : False :  True : PositiveReals
    box_width : Size=1, Index=None, Units=m
        Key  : Lower : Value : Upper : Fixed : Stale : Domain
        None :     0 :  None :  None : False :  True : PositiveReals
    x : Size=3, Index=CIRCLES, Units=m
        Key : Lower : Value : Upper : Fixed : Stale : Domain
          A :     0 :  None :  None : False :  True : PositiveReals
          B :     0 :  None :  None : False :  True : PositiveReals
          C :     0 :  None :  None : False :  True : PositiveReals
    y : Size=3, Index=CIRCLES, Units=m
        Key : Lower : Value : Upper : Fixed : Stale : Domain
          A :     0 :  None :  None : False :  True : PositiveReals
          B :     0 :  None :  None : False :  True : PositiveReals
          C :     0 :  None :  None : False :  True : PositiveReals

1 Objective Declarations
    obj : Size=1, Index=None, Active=True
        Key  : Active : Sense    : Expression
        None :   True : minimize : 2*(box_height + box_width)

5 Constraint Declarations
    left_x_con : Size=3, Index=CIRCLES, Active=True
        Key : Lower : Body : Upper : Active
          A :  R[A] : x[A] :  +Inf :   True
          B :  R[B] : x[B] :  +Inf :   True
          C :  R[C] : x[C] :  +Inf :   True
    left_y_con : Size=3, Index=CIRCLES, Active=True
        Key : Lower : Body : Upper : Active
          A :  R[A] : y[A] :  +Inf :   True
          B :  R[B] : y[B] :  +Inf :   True
          C :  R[C] : y[C] :  +Inf :   True
    no_overlap_con : Size=3, Index=CIRCLES*CIRCLES, Active=True
        Key        : Lower            : Body                                : Upper : Active
        ('A', 'B') : (R[A] + R[B])**2 : (x[A] - x[B])**2 + (y[A] - y[B])**2 :  +Inf :   True
        ('A', 'C') : (R[A] + R[C])**2 : (x[A] - x[C])**2 + (y[A] - y[C])**2 :  +Inf :   True
        ('B', 'C') : (R[B] + R[C])**2 : (x[B] - x[C])**2 + (y[B] - y[C])**2 :  +Inf :   True
    right_x_con : Size=3, Index=CIRCLES, Active=True
        Key : Lower : Body                      : Upper : Active
          A :  -Inf : x[A] - (box_width - R[A]) :   0.0 :   True
          B :  -Inf : x[B] - (box_width - R[B]) :   0.0 :   True
          C :  -Inf : x[C] - (box_width - R[C]) :   0.0 :   True
    right_y_con : Size=3, Index=CIRCLES, Active=True
        Key : Lower : Body                       : Upper : Active
          A :  -Inf : y[A] - (box_height - R[A]) :   0.0 :   True
          B :  -Inf : y[B] - (box_height - R[B]) :   0.0 :   True
          C :  -Inf : y[C] - (box_height - R[C]) :   0.0 :   True

12 Declarations: CIRCLES R box_height box_width x y obj left_x_con left_y_con right_x_con right_y_con no_overlap_con

The radii and the coordinates are declared in metres with units=pyo.units.m, so Pyomo can check that every constraint and the objective are dimensionally consistent. Run that check before handing the model to a solver: it catches a whole class of modeling mistake that a solver will happily converge on.

from pyomo.util.check_units import assert_units_consistent

# Raises InconsistentUnitsError if any constraint or the objective mixes units
assert_units_consistent(model)
print("Units are consistent.")
Units are consistent.

And let’s initialize the model.

# Initialize model
initialize_circle_model(model)
model.pprint()
1 Set Declarations
    CIRCLES : Size=1, Index=None, Ordered=Insertion
        Key  : Dimen : Domain : Size : Members
        None :     1 :    Any :    3 : {'A', 'B', 'C'}

1 Param Declarations
    R : Size=3, Index=CIRCLES, Domain=PositiveReals, Default=None, Mutable=True, Units=m
        Key : Value
          A :  10.0
          B :   5.0
          C :   3.0

4 Var Declarations
    box_height : Size=1, Index=None, Units=m
        Key  : Lower : Value : Upper : Fixed : Stale : Domain
        None :     0 :    25 :  None : False : False : PositiveReals
    box_width : Size=1, Index=None, Units=m
        Key  : Lower : Value : Upper : Fixed : Stale : Domain
        None :     0 :    25 :  None : False : False : PositiveReals
    x : Size=3, Index=CIRCLES, Units=m
        Key : Lower : Value              : Upper : Fixed : Stale : Domain
          A :     0 : 18.444218515250483 :  None : False : False : PositiveReals
          B :     0 :  9.205715808308451 :  None : False : False : PositiveReals
          C :     0 :  8.112747213686085 :  None : False : False : PositiveReals
    y : Size=3, Index=CIRCLES, Units=m
        Key : Lower : Value              : Upper : Fixed : Stale : Domain
          A :     0 : 17.579544029403024 :  None : False : False : PositiveReals
          B :     0 :  7.589167502929634 :  None : False : False : PositiveReals
          C :     0 :  7.049341374504143 :  None : False : False : PositiveReals

1 Objective Declarations
    obj : Size=1, Index=None, Active=True
        Key  : Active : Sense    : Expression
        None :   True : minimize : 2*(box_height + box_width)

5 Constraint Declarations
    left_x_con : Size=3, Index=CIRCLES, Active=True
        Key : Lower : Body : Upper : Active
          A :  R[A] : x[A] :  +Inf :   True
          B :  R[B] : x[B] :  +Inf :   True
          C :  R[C] : x[C] :  +Inf :   True
    left_y_con : Size=3, Index=CIRCLES, Active=True
        Key : Lower : Body : Upper : Active
          A :  R[A] : y[A] :  +Inf :   True
          B :  R[B] : y[B] :  +Inf :   True
          C :  R[C] : y[C] :  +Inf :   True
    no_overlap_con : Size=3, Index=CIRCLES*CIRCLES, Active=True
        Key        : Lower            : Body                                : Upper : Active
        ('A', 'B') : (R[A] + R[B])**2 : (x[A] - x[B])**2 + (y[A] - y[B])**2 :  +Inf :   True
        ('A', 'C') : (R[A] + R[C])**2 : (x[A] - x[C])**2 + (y[A] - y[C])**2 :  +Inf :   True
        ('B', 'C') : (R[B] + R[C])**2 : (x[B] - x[C])**2 + (y[B] - y[C])**2 :  +Inf :   True
    right_x_con : Size=3, Index=CIRCLES, Active=True
        Key : Lower : Body                      : Upper : Active
          A :  -Inf : x[A] - (box_width - R[A]) :   0.0 :   True
          B :  -Inf : x[B] - (box_width - R[B]) :   0.0 :   True
          C :  -Inf : x[C] - (box_width - R[C]) :   0.0 :   True
    right_y_con : Size=3, Index=CIRCLES, Active=True
        Key : Lower : Body                       : Upper : Active
          A :  -Inf : y[A] - (box_height - R[A]) :   0.0 :   True
          B :  -Inf : y[B] - (box_height - R[B]) :   0.0 :   True
          C :  -Inf : y[C] - (box_height - R[C]) :   0.0 :   True

12 Declarations: CIRCLES R box_height box_width x y obj left_x_con left_y_con right_x_con right_y_con no_overlap_con

Activity

Compare the initial values for x and y with and without initialization. What is the default initial value in Pyomo?

Visualize Initial Point

Next, we’ll define a function to plot the solution (or initial point)

# Plot initial point


def plot_circles(m):
    """Plot circles using data in Pyomo model

    Arguments:
        m: Pyomo concrete model

    Returns:
        Nothing (but makes a figure)

    """

    # Create figure
    fig, ax = plt.subplots(1, figsize=(6, 6))

    # Adjust axes
    l = max(m.box_height.value, m.box_width.value) + 1
    ax.set_xlim(0, l)
    ax.set_ylim(0, l)

    # Draw box
    art = mpatches.Rectangle(
        (0, 0), width=m.box_width.value, height=m.box_height.value, fill=False
    )
    ax.add_patch(art)

    # Draw circles and mark center
    for i in m.CIRCLES:
        art2 = mpatches.Circle(
            (m.x[i].value, m.y[i].value),
            radius=pyo.value(m.R[i]),
            fill=True,
            alpha=0.25,
        )
        ax.add_patch(art2)

        plt.scatter(m.x[i].value, m.y[i].value, color="black")

    # Show plot
    plt.show()


plot_circles(model)
<Figure size 600x600 with 1 Axes>

Solve and Inspect the Solution

# Specify the solver
solver = pyo.SolverFactory("ipopt")

# Solve the model
results = solver.solve(model, tee=True)
assert pyo.check_optimal_termination(results), (
    f"Solve failed: status={results.solver.status}, "
    f"termination={results.solver.termination_condition}"
)
Ipopt 3.14.19: 

******************************************************************************
This program contains Ipopt, a library for large-scale nonlinear optimization.
 Ipopt is released as open source code under the Eclipse Public License (EPL).
         For more information visit https://github.com/coin-or/Ipopt
******************************************************************************

This is Ipopt version 3.14.19, running with linear solver MUMPS 5.8.2.

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

Total number of variables............................:        8
                     variables with only lower bounds:        8
                variables with lower and upper bounds:        0
                     variables with only upper bounds:        0
Total number of equality constraints.................:        0
Total number of inequality constraints...............:       15
        inequality constraints with only lower bounds:        9
   inequality constraints with lower and upper bounds:        0
        inequality constraints with only upper bounds:        6

iter    objective    inf_pr   inf_du lg(mu)  ||d||  lg(rg) alpha_du alpha_pr  ls
   0  1.0000000e+02 6.25e+01 1.05e+00  -1.0 0.00e+00    -  0.00e+00 0.00e+00   0
   1  1.0046267e+02 4.59e+01 1.05e+01  -1.0 2.67e+01   0.0 1.52e-01 5.64e-02h  1
   2  1.0446269e+02 2.46e+01 2.54e+00  -1.0 5.43e+00  -0.5 5.62e-01 3.57e-01h  1
   3  1.1075999e+02 0.00e+00 4.40e+00  -1.0 4.83e+00  -1.0 6.87e-01 1.00e+00h  1
   4  1.0931790e+02 0.00e+00 4.22e+00  -1.0 6.13e+01  -1.4 3.27e-01 2.76e-02f  3
   5  1.0505265e+02 0.00e+00 8.83e-01  -1.0 2.84e+00  -1.0 1.00e+00 9.20e-01f  1
   6  1.0163361e+02 0.00e+00 1.15e+00  -1.0 1.96e+00  -1.5 4.90e-01 9.10e-01h  1
   7  9.9775211e+01 0.00e+00 1.90e-01  -1.0 2.12e+00  -1.1 1.00e+00 8.60e-01f  1
   8  9.8947266e+01 0.00e+00 8.86e-01  -1.0 1.23e+02    -  3.86e-01 5.70e-02f  1
   9  9.8937271e+01 0.00e+00 2.06e-02  -1.0 7.04e-01  -1.5 1.00e+00 1.00e+00h  1
iter    objective    inf_pr   inf_du lg(mu)  ||d||  lg(rg) alpha_du alpha_pr  ls
  10  9.8325956e+01 0.00e+00 6.43e-03  -2.5 3.75e+00    -  9.93e-01 9.37e-01f  1
  11  9.8301250e+01 0.00e+00 2.66e-03  -2.5 4.81e+01    -  4.81e-01 1.00e+00h  1
  12  9.8301257e+01 0.00e+00 5.36e-04  -2.5 2.99e+01    -  1.00e+00 1.00e+00h  1
  13  9.8301256e+01 0.00e+00 2.96e-05  -2.5 2.59e+01    -  1.00e+00 1.00e+00h  1
  14  9.8301256e+01 0.00e+00 1.40e-06  -2.5 2.48e+00    -  1.00e+00 1.00e+00h  1
  15  9.8285159e+01 0.00e+00 2.69e-07  -3.8 3.80e-02    -  1.00e+00 1.00e+00h  1
  16  9.8284281e+01 0.00e+00 9.89e-10  -5.7 2.05e-03    -  1.00e+00 1.00e+00h  1
  17  9.8284270e+01 0.00e+00 9.89e-13  -8.6 1.62e-04    -  1.00e+00 1.00e+00h  1

Number of Iterations....: 17

                                   (scaled)                 (unscaled)
Objective...............:   9.8284270438747257e+01    9.8284270438747257e+01
Dual infeasibility......:   9.8878042171958667e-13    9.8878042171958667e-13
Constraint violation....:   0.0000000000000000e+00    0.0000000000000000e+00
Variable bound violation:   0.0000000000000000e+00    0.0000000000000000e+00
Complementarity.........:   2.5165074041745097e-09    2.5165074041745097e-09
Overall NLP error.......:   2.5165074041745097e-09    2.5165074041745097e-09


Number of objective function evaluations             = 22
Number of objective gradient evaluations             = 18
Number of equality constraint evaluations            = 0
Number of inequality constraint evaluations          = 22
Number of equality constraint Jacobian evaluations   = 0
Number of inequality constraint Jacobian evaluations = 18
Number of Lagrangian Hessian evaluations             = 17
Total seconds in IPOPT                               = 0.222

EXIT: Optimal Solution Found.


Next, we can inspect the solution. Because Pyomo is a Python extension, we can use Python (for loops, etc.) to programmatically inspect the solution.

# Print variable values
print("Name\tValue")
for c in model.component_data_objects(pyo.Var):
    print(c.name, "\t", pyo.value(c))

# Plot solution
plot_circles(model)
Name	Value
box_height 	 19.999999803189603
box_width 	 29.14213541618403
x[A] 	 19.14213551493119
x[B] 	 4.999999951252128
x[C] 	 5.517274811159313
y[A] 	 9.999999901937443
y[B] 	 4.999999953543125
y[C] 	 15.729315741741795
<Figure size 600x600 with 1 Axes>
# Print constraints
for c in model.component_data_objects(pyo.Constraint):
    print(
        c.name,
        "\t",
        pyo.value(c.lower),
        "\t",
        pyo.value(c.body),
        "\t",
        pyo.value(c.upper),
    )
left_x_con[A] 	 10.0 	 19.14213551493119 	 None
left_x_con[B] 	 5.0 	 4.999999951252128 	 None
left_x_con[C] 	 3.0 	 5.517274811159313 	 None
left_y_con[A] 	 10.0 	 9.999999901937443 	 None
left_y_con[B] 	 5.0 	 4.999999953543125 	 None
left_y_con[C] 	 3.0 	 15.729315741741795 	 None
right_x_con[A] 	 None 	 9.87471615587765e-08 	 0.0
right_x_con[B] 	 None 	 -19.1421354649319 	 0.0
right_x_con[C] 	 None 	 -20.624860605024715 	 0.0
right_y_con[A] 	 None 	 9.874784012708915e-08 	 0.0
right_y_con[B] 	 None 	 -9.999999849646478 	 0.0
right_y_con[C] 	 None 	 -1.2706840614478079 	 0.0
no_overlap_con[A,B] 	 225.0 	 224.99999778541928 	 None
no_overlap_con[A,C] 	 169.0 	 218.46188918942016 	 None
no_overlap_con[B,C] 	 64.0 	 115.38579056358121 	 None

Reinitialize and Resolve

Activity

Reinitialize the model, plot the initial point, resolve, and plot the solution. Is there more than one solution?
# Initialize and print the model

# Add your solution here
# Plot initial point
# Add your solution here
# Solve the model
# Add your solution here
# Plot solution
# Add your solution here

Take Away Messages

  • Nonlinear programs may be nonconvex. For nonconvex problems, there often exist many local optima that are not also global optima.

  • We will learn how to mathematically define convexity and analyze this property.

  • Initialization is really important in optimization problems with nonlinear objectives or constraints!

  • There are specialized solvers for linear programs, quadratic programs, and convex programs. In this class, we will focus on more general algorithms for (non)convex nonlinear programs including the algorithms used by the ipopt solver.