alpaqa cmake-targets
Nonconvex constrained optimization
Loading...
Searching...
No Matches
Python/simple_optimization/rosenbrock.py

This is a minimal example of an optimization problem that can be built and solved using the alpaqa Python interface.

This is a minimal example of an optimization problem that can be built and solved using the alpaqa Python interface. It includes visualization of the iterates.

1# %% Build the problem (CasADi code, independent of alpaqa)
2import casadi as cs
3import numpy as np
4
5# Make symbolic decision variables
6x1, x2 = cs.SX.sym("x1"), cs.SX.sym("x2")
7x = cs.vertcat(x1, x2) # Collect decision variables into one vector
8# Make a parameter symbol
9p = cs.SX.sym("p")
10
11# Objective function f and the constraints function g
12f = (1 - x1) ** 2 + p * (x2 - x1**2) ** 2
13g = cs.vertcat(
14 (x1 - 0.5) ** 3 - x2 + 1,
15 x1 + x2 - 1.5,
16)
17
18# Define the bounds
19C = [-0.25, -0.5], [1.5, 2.5] # -0.25 <= x1 <= 1.5, -0.5 <= x2 <= 2.5
20D = [-np.inf, -np.inf], [0, 0] # g1 <= 0, g2 <= 0
21
22# %% Generate and compile C-code for the objective and constraints using alpaqa
23from alpaqa import minimize
24
25problem = (
26 minimize(f, x) # Objective function f(x)
27 .subject_to_box(C) # Box constraints x ∊ C
28 .subject_to(g, D) # General ALM constraints g(x) ∊ D
29 .with_param(p, [10]) # Parameter with default value (can be changed later)
30).compile()
31
32# %% Build a solver with the default parameters
33import alpaqa as pa
34
35inner_solver = pa.PANOCSolver()
36solver = pa.ALMSolver(inner_solver)
37
38# %% Build a solver with custom parameters
39inner_solver = pa.PANOCSolver(
40 dict(
41 max_iter=50,
42 stop_crit=pa.PANOCStopCrit.ApproxKKT,
43 print_interval=1,
44 ),
45 dict(memory=10),
46)
47
48# You can attach a callback that is called on each iteration, and keeps track of
49# the iterates so they can be plotted later
50iterates = []
51def callback(it: pa.PANOCProgressInfo):
52 if it.k == 0:
53 iterates.append([])
54 iterates[-1].append(np.copy(it.x))
55# Note: the iterate values like it.x are only valid within the callback, if you
56# want to save them for later, you have to make a copy.
57inner_solver.set_progress_callback(callback)
58
59alm_params = pa.ALMParams(
60 tolerance=1e-8,
61 dual_tolerance=1e-8,
62 initial_penalty=50,
63 penalty_update_factor=20,
64 print_interval=1,
65)
66solver = pa.ALMSolver(
67 alm_params,
68 inner_solver,
69)
70
71# %% Compute a solution
72
73x0 = [0.1, 1.8] # Initial guess for decision variables
74y0 = [0.0, 0.0] # Initial guess for Lagrange multipliers of g(x)
75
76# Solve the problem
77x_sol, y_sol, stats = solver(problem, x0, y0)
78
79# Print the results
80print(solver)
81print(stats["status"])
82print(f"Solution: {x_sol}")
83print(f"Multipliers: {y_sol}")
84print(f"Cost: {problem.eval_f(x_sol)}")
85from pprint import pprint
86pprint(stats)
87
88# %% Plot the results
89
90import matplotlib.pyplot as plt
91from matplotlib import patheffects
92
93cost_function_v = np.vectorize(problem.eval_f, signature="(n)->()")
94constr_function_v = np.vectorize(problem.eval_g, signature="(n)->(m)")
95
96x = np.linspace(-1.5, 1.5, 256)
97y = np.linspace(-0.5, 2.5, 256)
98X, Y = np.meshgrid(x, y)
99XY = np.vstack([[X], [Y]]).T
100
101plt.figure(figsize=(10, 6))
102# Draw objective function contours
103Zf = cost_function_v(XY).T
104plt.contourf(X, Y, Zf, 32)
105plt.colorbar()
106# Draw constraints
107Zgc, Zgl = constr_function_v(XY).T
108line_opts = dict(colors="black", linewidths=0.8, linestyles="-")
109fx = [patheffects.withTickedStroke(spacing=7, linewidth=0.8)]
110cgc = plt.contour(X, Y, Zgc, [0], **line_opts)
111plt.setp(cgc.collections, path_effects=fx)
112cgl = plt.contour(X, Y, Zgl, [0], **line_opts)
113plt.setp(cgl.collections, path_effects=fx)
114xl = plt.contour(X, Y, -X, [-problem.C.lowerbound[0]], **line_opts)
115plt.setp(xl.collections, path_effects=fx)
116
117plt.title("PANOC+ALM Rosenbrock example")
118plt.xlabel("$x_1$")
119plt.ylabel("$x_2$")
120
121# Draw iterates and solution
122for xy in map(np.array, iterates):
123 plt.plot(xy[:, 0], xy[:, 1], "r:.", markersize=4, linewidth=1)
124plt.plot(x_sol[0], x_sol[1], "ro", markersize=10, fillstyle="none")
125
126plt.tight_layout()
127plt.show()