diff --git a/class02/class02_constrained_min.jl b/class02/class02_constrained_min.jl new file mode 100644 index 0000000..23a99a2 --- /dev/null +++ b/class02/class02_constrained_min.jl @@ -0,0 +1,264 @@ +### A Pluto.jl notebook ### +# v0.20.17 + +using Markdown +using InteractiveUtils + +# ╔═╡ a509f9d8-9c6d-11f0-3db9-cb5fe2e85d64 +md"""# Constrained Optimization (Equality & Inequality KKT) + +[⬅ Back to Class 02 Overview](class02_overview.jl) + +[⬅ Previous: Unconstrained Minimization](class02_unconstrained_min.jl) + +[➡ Next: Methods (Penalty/ALM/IPM)](class02_methods_barrier_alm.jl) + +**In this section you will:** + +* Build the **geometry** of equality constraints and the **KKT** conditions. +* See the **Newton-on-KKT** linear system (saddle point) and when it’s well-posed. +* Contrast **full Newton** vs. **Gauss–Newton** on the KKT system. +* Extend to **inequality constraints** and understand **complementarity**. + +""" + +# ╔═╡ 57cd6d88-ea7e-4f5c-bc17-7fc65fb78e95 +md"""## Equality-constrained minimization: geometry and conditions + +**Problem:** +[ +\min_{x\in\mathbb{R}^n} f(x) \quad \text{s.t.}\quad C(x)=0,\ \ C:\mathbb{R}^n\to\mathbb{R}^m. +] + +**Geometric picture.** At an optimum on the manifold (C(x)=0), the negative gradient must lie in the tangent space: +[ +\nabla f(x^\star)\ \perp\ \mathcal{T}_{x^\star}={p:\ J_C(x^\star)p=0}. +] +Equivalently, the gradient is a linear combination of the constraint normals: +[ +\nabla f(x^\star)+J_C(x^\star)^{!T}\lambda^\star=0,\qquad C(x^\star)=0\quad(\lambda^\star\in\mathbb{R}^m). +] + +**Lagrangian.** (L(x,\lambda)=f(x)+\lambda^{!T}C(x)). +""" + +# ╔═╡ b7763163-fc68-4c56-bac9-c37de527858f +md""" +## Equality constraints: picture first + +**Goal.** Minimize (f(x)) while staying on the surface (C(x)=0). + +* **Feasible set as a surface.** Think of (C(x)=0) as a smooth surface embedded in (\mathbb{R}^n) (a manifold). +* **Move without breaking the constraint.** Tangent directions are the “along-the-surface” moves keeping (C(x)) unchanged to first order. +* **What must be true at the best point.** At (x^\star), there’s no downhill direction within the tangent space. +* **Normals enter the story.** If the gradient can’t point along the surface, it must be balanced by the normals ({J_C(x^\star)_{i:}^{!T}}), producing multipliers (\lambda^\star). +""" + +# ╔═╡ 8a08b045-3a1b-4601-a081-27a6a22d05e6 +md""" +## From the picture to KKT (equality only) + +For a regular local minimum: + +1. **Feasibility:** (C(x^\star)=0). +2. **Stationarity:** (\nabla f(x^\star) + J_C(x^\star)^{!T}\lambda^\star = 0). + +**Lagrangian viewpoint.** Define (L(x,\lambda)=f(x)+\lambda^{!T}C(x)). At a solution, (x^\star) is stationary for (L) w.r.t. (x), while (C(x^\star)=0) ensures feasibility. + +**Interpreting (\lambda^\star).** Each (\lambda_i^\star) reflects how strongly the (i)-th constraint “pushes back”; it’s also a sensitivity of the optimal value to perturbations in (C_i). +""" + +# ╔═╡ 907459d1-4a09-441c-a989-71ff687da873 +md""" +## KKT system for equalities (first order) & Newton on KKT + +**KKT (FOC):** +[ +\nabla_x L(x,\lambda)=\nabla f(x)+J_C(x)^{!T}\lambda=0,\qquad C(x)=0. +] + +**Newton on KKT (linearize both blocks):** +[ +\begin{bmatrix} +\nabla^2 f(x) + \sum_{i=1}^{m}\lambda_i,\nabla^2 C_i(x) & ; J_C(x)^{!T}[2pt] +J_C(x) & ; 0 +\end{bmatrix} +\begin{bmatrix}\Delta x\ \Delta\lambda\end{bmatrix} +=- +\begin{bmatrix} +\nabla f(x)+J_C(x)^{!T}\lambda[2pt] C(x) +\end{bmatrix}. +] + +**Notes.** This is a symmetric **saddle-point** system. Practical solves use block elimination (Schur complement) and sparse factorizations. + """ + +# ╔═╡ aec59d16-c254-43b6-aee2-6261823fb7c3 +md""" +## Newton on KKT: practice & safeguards + +**Works best when:** + +* (J_C(x^\star)) has **full row rank** (regularity). +* The **reduced Hessian** is **positive definite**. +* A **globalization** (e.g., merit/penalty line search) and mild **regularization** are present. + +**Common safeguards:** + +* **Regularize** the ((1,1)) block (e.g., (+\beta I)) to ensure a good search direction. +* **Merit/penalty line search** balancing feasibility vs. optimality. +* **Scaling** constraints to improve conditioning of the KKT system. +""" + +# ╔═╡ a14a100c-5c92-42cc-899d-8c6eb0619368 +md""" +## Gauss–Newton vs. full Newton (equality case) + +* **Full Newton Lagrangian Hessian:** + [ + \nabla_{xx}^2 L(x,\lambda)=\nabla^2 f(x)+\sum_{i=1}^m \lambda_i,\nabla^2 C_i(x). + ] +* **Gauss–Newton approximation:** drop the constraint-curvature term: + [ + H_{\text{GN}}(x)\approx \nabla^2 f(x). + ] + +**Trade-offs.** + +* **Full Newton:** fewer iterations near the solution; costlier steps; less robust far away. +* **Gauss–Newton:** cheaper per step and often more stable; may need more iterations but competitive in wall-clock on many problems. +""" + +# ╔═╡ 300c917e-e61c-4881-82d0-bc79ace66795 +md""" +## Solving the KKT system: Schur complement (intuition) + +Given +[ +\begin{bmatrix} H & A^{!T}\ A & 0\end{bmatrix} +\begin{bmatrix}\Delta x\ \Delta\lambda\end{bmatrix} +=- +\begin{bmatrix} g\ c\end{bmatrix}, +] +with (H\approx \nabla_{xx}^2 L), (A=J_C(x)), (g=\nabla f+J_C^{!T}\lambda), (c=C(x)). + +* Eliminate (\Delta x): (\Delta x = -H^{-1}(g + A^{!T}\Delta\lambda)). +* Schur system in (\Delta\lambda): + [ + (A H^{-1} A^{!T}),\Delta\lambda = c + A H^{-1} g. + ] +* Then recover (\Delta x). + Exploit **sparsity**: factor (H) once per iteration; reuse structure across iterations. + +""" + +# ╔═╡ 28a43bca-618a-4fec-a7eb-ad7a734ceac5 +md""" +## Inequality-constrained minimization and KKT + +**Problem:** (\min f(x)\ \text{s.t.}\ c(x)\ge 0,\ \ c:\mathbb{R}^n\to\mathbb{R}^p). + +**KKT (FOC):** +[ +\begin{aligned} +&\text{Stationarity:} && \nabla f(x)-J_c(x)^{!T}\lambda=0,\ +&\text{Primal feasibility:} && c(x)\ge 0,\ +&\text{Dual feasibility:} && \lambda\ge 0,\ +&\text{Complementarity:} && \lambda^{!T}c(x)=0\quad(\lambda_i c_i(x)=0,\ \forall i). +\end{aligned} +] + +**Interpretation.** + +* **Active** constraints: (c_i(x)=0\Rightarrow \lambda_i) can be nonzero (acts like an equality). +* **Inactive** constraints: (c_i(x)>0\Rightarrow \lambda_i=0) (no influence on stationarity). +""" + +# ╔═╡ 3b6300c0-d69f-4004-9b91-41116d0ce832 +md""" +## Complementarity: intuition & Newton’s challenge + +**What (\lambda_i c_i(x)=0) means.** + +* Tight constraint ((c_i=0)) → can press back ((\lambda_i\ge 0)). +* Loose constraint ((c_i>0)) → no force ((\lambda_i=0)). + +**Why naïve Newton struggles.** + +* Complementarity brings **nonsmoothness** and **inequalities** ((\lambda\ge 0), (c(x)\ge 0)). +* Equality-style Newton can violate nonnegativity or bounce across the boundary. + +**Two main strategies (preview).** + +* **Active-set:** guess actives → solve equality-constrained subproblem → update the set. +* **Barrier / PDIP / ALM:** smooth or relax complementarity, use damped Newton, and drive the relaxation to zero. + +""" + +# ╔═╡ ab782dbb-5f3c-404f-87b7-091b4382b0aa +md""" +## Globalization with constraints: merit functions + +To balance feasibility and optimality during updates ((x,\lambda)\to(x+\alpha\Delta x,\lambda+\alpha\Delta\lambda)), use a **merit/penalty** function, e.g. +[ +\Phi_\mu(x) = f(x) + \mu,|C(x)|*1 \quad \text{(equality case)}, +] +or for inequalities, a penalty on **violation** (v(x)=\sum_i \max(0,-c_i(x))). +Do a **backtracking line search** on (\Phi*\mu) to ensure robust progress. + +*(You’ll see barrier and ALM variants in the next section.)* + +""" + +# ╔═╡ 0f722888-d66c-47ae-a1ee-1e2b7c9b4a58 +md""" +## Conditioning & scaling + +* **Scale constraints** so rows of (J_C) have comparable norms → better KKT conditioning. +* **Regularize** (H) when indefinite/ill-conditioned (modified Cholesky or (+\beta I)). +* **Exploit structure:** block-banded, sparse patterns common in trajectory problems. +* **Warm-starts** from previous solves (e.g., along continuation or time steps) improve robustness. +""" + +# ╔═╡ f4d85409-9095-4bc0-b515-ae283e43f344 +md""" +## Where to next + +* Proceed to **Methods: Penalty vs. Augmented Lagrangian vs. Interior-Point** to see practical algorithms that *enforce* the KKT conditions reliably, including complementarity handling for inequalities. +* Later, we’ll assemble these pieces into **SQP**. + +[➡ Methods (Penalty/ALM/IPM) (next)](class02_methods_barrier_alm.jl) · [⬅ Back to overview](class02_overview.jl) +""" + +# ╔═╡ 00000000-0000-0000-0000-000000000001 +PLUTO_PROJECT_TOML_CONTENTS = """ +[deps] +""" + +# ╔═╡ 00000000-0000-0000-0000-000000000002 +PLUTO_MANIFEST_TOML_CONTENTS = """ +# This file is machine-generated - editing it directly is not advised + +julia_version = "1.10.0" +manifest_format = "2.0" +project_hash = "da39a3ee5e6b4b0d3255bfef95601890afd80709" + +[deps] +""" + +# ╔═╡ Cell order: +# ╠═a509f9d8-9c6d-11f0-3db9-cb5fe2e85d64 +# ╠═57cd6d88-ea7e-4f5c-bc17-7fc65fb78e95 +# ╠═b7763163-fc68-4c56-bac9-c37de527858f +# ╠═8a08b045-3a1b-4601-a081-27a6a22d05e6 +# ╠═907459d1-4a09-441c-a989-71ff687da873 +# ╠═aec59d16-c254-43b6-aee2-6261823fb7c3 +# ╠═a14a100c-5c92-42cc-899d-8c6eb0619368 +# ╠═300c917e-e61c-4881-82d0-bc79ace66795 +# ╠═28a43bca-618a-4fec-a7eb-ad7a734ceac5 +# ╠═3b6300c0-d69f-4004-9b91-41116d0ce832 +# ╠═ab782dbb-5f3c-404f-87b7-091b4382b0aa +# ╠═0f722888-d66c-47ae-a1ee-1e2b7c9b4a58 +# ╠═f4d85409-9095-4bc0-b515-ae283e43f344 +# ╟─00000000-0000-0000-0000-000000000001 +# ╟─00000000-0000-0000-0000-000000000002 diff --git a/class02/class02_methods_barrier.jl b/class02/class02_methods_barrier.jl new file mode 100644 index 0000000..973c921 --- /dev/null +++ b/class02/class02_methods_barrier.jl @@ -0,0 +1,308 @@ +### A Pluto.jl notebook ### +# v0.20.17 + +using Markdown +using InteractiveUtils + +# ╔═╡ 8f4c1994-9c6a-11f0-2d1d-296c30c0d0ed +md""" +# Unconstrained Minimization (Newton + Globalization) + +*(Class 02 — interactive chapter section)* + +[⬅ Back to Class 02 Overview](class02_overview.jl) · [⬅ Previous: Root-Finding](class02_root_finding.jl) + +**In this section you will:** + +* Review first/second-order optimality conditions. +* Derive **Newton’s method for minimization** from the quadratic model. +* Make Newton **robust** with **line search** (Armijo/Wolfe) and **trust regions**. +* See when/why to use **quasi-Newton (BFGS/L-BFGS)**. +* Practice on the **Rosenbrock** test problem (path & convergence diagnostics). + +""" + +# ╔═╡ db452cd5-1c97-40b5-9836-ac74ec96e950 +md""" +## Big picture + +We often recast tasks as +[ +\min_{x\in\mathbb{R}^n} f(x), +] +then solve for a stationary point. Compared to generic root-finding (f(x)=0), minimization gives us **objective structure** (descent directions, merit functions, curvature) that we can exploit for **globalization** and **diagnostics**. + +""" + + +# ╔═╡ fa119b30-970f-41a3-8ac6-2d132123d8c7 +md""" + +## First- and second-order conditions + +Let (f:\mathbb{R}^n\to\mathbb{R}) be twice continuously differentiable. + +* **First order (necessary):** at a local minimizer (x^\star), + [ + \nabla f(x^\star)=0. + ] +* **Second order:** + + * **Necessary:** (\nabla^2 f(x^\star)\succeq 0) (positive semidefinite). + * **Sufficient (strict local min):** (\nabla^2 f(x^\star)\succ 0) (positive definite). + +These are **local** conditions; nonconvex problems can have multiple minima/saddles. + +""" + +# ╔═╡ 44366de6-1152-45bb-b300-c766d64e85f8 +md""" +## Quadratic Taylor model at (x) + +The second-order Taylor expansion around (x) is +[ +m_x(d) ;=; f(x) + \nabla f(x)^{!T}d + \tfrac12 d^{!T}\nabla^2 f(x),d. +] +Newton-type methods “approximately” minimize this model to choose the step (d). + +* If (\nabla^2 f(x)\succ 0), (m_x) is strictly convex and has a unique minimizer. + +""" + +# ╔═╡ fe5dfe3c-f4d4-426f-a840-dc950c816222 +md""" +## Derivation of the Newton step + +Set (\nabla_d m_x(d)=0): +[ +\nabla f(x) + \nabla^2 f(x),d ;=; 0 +\quad\Longrightarrow\quad +d_{\text{N}} ;=; -\big(\nabla^2 f(x)\big)^{-1},\nabla f(x). +] +Update (x \leftarrow x + d_{\text{N}}) and repeat. + +* **Quadratic convergence** near a nondegenerate minimizer ((\nabla^2 f(x^\star)) nonsingular). +* Each iteration requires solving a linear system with (\nabla^2 f(x)). + +""" + +# ╔═╡ 39bbcd3b-7ab7-45e3-ab27-eb94a25f507f +md""" +## Indefiniteness, overshooting, and saddles + +* If (\nabla^2 f(x)) is **indefinite**, (d_{\text{N}}) may not be a **descent direction** ((\nabla f(x)^{!T} d < 0)). +* Even with (\nabla^2 f(x)\succ 0), a full step can **overshoot**; objective can increase. +* Newton may converge to a **saddle** if started in the wrong basin. + +We fix this with **regularization** and **globalization**. + +""" + +# ╔═╡ 16b72035-3c8b-4c46-a1e7-35b062851422 +md""" +## Positive-definite Hessian via regularization + +If (\nabla^2 f(x)) is not PD, make it so: +[ +H(x) \leftarrow \nabla^2 f(x) + \lambda I,\quad \lambda>0, +] +or use a **modified Cholesky** factorization to obtain (H(x)\succ 0). Then solve +[ +H(x),d ;=; -\nabla f(x). +] +This ensures the **Newton direction is descent**: (\nabla f(x)^{!T} d < 0). + +> In practice, (\lambda) is reduced toward (0) as we approach a minimizer. + +""" + +# ╔═╡ 50a7ea9f-72ad-4050-89c6-b3c7d02d07d8 +md""" +Globalization I: line search + +## Backtracking with Armijo / Wolfe + +Given a descent direction (d), pick a step length (\alpha\in(0,1]). + +* **Armijo (sufficient decrease):** find smallest (\alpha=c^j) (e.g., (c=\frac12)) such that + [ + f(x+\alpha d) ;\le; f(x) + c_1,\alpha,\nabla f(x)^{!T} d, \quad 00)) + [ + s_k = x_{k+1}-x_k,\quad y_k=\nabla f(x_{k+1})-\nabla f(x_k), + ] + [ + B_{k+1} = B_k - \frac{B_k s_k s_k^{!T} B_k}{s_k^{!T} B_k s_k} + + \frac{y_k y_k^{!T}}{y_k^{!T} s_k}. + ] +* **L-BFGS** stores only a few ( (s_k, y_k) ) pairs → great for large-scale problems. + +Use a **Wolfe line search** to satisfy the curvature condition (s_k^{!T}y_k>0). + +""" + +# ╔═╡ 1f90d0e6-8d3e-4aed-9cbb-748243e3a25a +md""" +Stopping criteria + +## When to stop + +Typical checks (use more than one): + +* **Gradient norm:** (|\nabla f(x)| \le \varepsilon_g\cdot \max(1,|\nabla f(x_0)|)). +* **Step norm:** (|x_{k+1}-x_k| \le \varepsilon_x\cdot \max(1,|x_k|)). +* **Objective change:** (|f(x_{k+1})-f(x_k)| \le \varepsilon_f\cdot \max(1,|f(x_k)|)). +* **Iteration/time** limits. + +Report **status** (converged, maxiter, failed-descent) and basic **history** for debugging. + +""" + +# ╔═╡ 5e586027-baa1-463b-a032-1b25f87fe270 +md""" + +Example: Rosenbrock function + +## The Rosenbrock “banana” + +[ +f(x,y) = (1-x)^2 + 100,(y-x^2)^2. +] + +* Narrow, curved valley; poor conditioning away from the minimizer (x^\star=(1,1)). +* Great to illustrate **line search**, **Hessian PD-repair**, and **path plots**. + +**What to try (when you add code):** + +* Start at ((-1.2,1.0)). Compare **pure Newton**, **regularized Newton**, **BFGS**. +* Plot contour lines and the **iterate path**. Track (|\nabla f|) on a **log scale**. + + +""" + +# ╔═╡ ffe2800b-add1-4817-adeb-efc7660ead61 +md""" +Conditioning & scaling + +## Make life easier with scaling + +Poor scaling slows convergence and breaks line searches. + +* **Variable scaling:** change variables (x=S z) to make typical curvature similar. +* **Preconditioning:** solve (\tilde H d = -\tilde g) with (\tilde H = P^{-1/2} H P^{-1/2}). +* **Hessian-vector products:** Newton-CG/trust-region methods avoid forming (H) explicitly. +* **Automatic differentiation** gives accurate gradients/Hessians (or Hessian-vector products) cheaply. + +""" + +# ╔═╡ 0bb5977b-889d-408a-a073-c9a9b4e1eabc +md""" +Practical recipe (putting it together) + +## A robust Newton-type solver (sketch) + +1. Compute (g=\nabla f(x)). If (|g|) small → **stop**. +2. Compute/approximate (H=\nabla^2 f(x)) or (B\approx H). +3. **Make PD** (modified Cholesky or (+\lambda I)) to get a descent direction (d) from (H d=-g). +4. **Line search** (Armijo/Wolfe) or use a **trust region** to pick the step length/size. +5. Update (x\leftarrow x+\alpha d). +6. If quasi-Newton, update (B) via **BFGS**. +7. Repeat until stopping criteria met; record diagnostics. + +""" + +# ╔═╡ 2ef96814-04d3-466a-9d91-a43a3ae1f069 +md""" +Check your understanding + +1. **Newton direction is descent when (H\succ 0).** Show that if (H\succ 0) and (H d = -g\neq 0), then (g^{!T} d < 0). +2. **Rosenbrock Hessian.** Derive (\nabla f) and (\nabla^2 f) for Rosenbrock. Where is (H) poorly conditioned? +3. **Armijo parameter sensitivity.** Experiment (mentally or later in code) with (c_1\in[10^{-4},10^{-1}]) and backtracking factor (c\in{1/2,2/3}). How do step counts and robustness trade-off? +4. **BFGS curvature condition.** Explain why enforcing Wolfe guarantees (s^{!T}y>0) for smooth (f). + +""" + +# ╔═╡ 1dece802-261f-4f0e-a681-dbc6fcde5bbc +md""" +## Where to next + +* Proceed to **Constrained Minimization & KKT** to extend Newton-type ideas to equality/inequality constraints and saddle-point systems. +* Keep the Rosenbrock notebook handy to test different globalization and quasi-Newton settings. + +[⬅ Back to overview](class02_overview.jl) + +[➡ Constrained minimization & KKT (next)](class02_constrained_min.jl) +""" + +# ╔═╡ 00000000-0000-0000-0000-000000000001 +PLUTO_PROJECT_TOML_CONTENTS = """ +[deps] +""" + +# ╔═╡ 00000000-0000-0000-0000-000000000002 +PLUTO_MANIFEST_TOML_CONTENTS = """ +# This file is machine-generated - editing it directly is not advised + +julia_version = "1.10.0" +manifest_format = "2.0" +project_hash = "da39a3ee5e6b4b0d3255bfef95601890afd80709" + +[deps] +""" + +# ╔═╡ Cell order: +# ╠═8f4c1994-9c6a-11f0-2d1d-296c30c0d0ed +# ╠═db452cd5-1c97-40b5-9836-ac74ec96e950 +# ╠═fa119b30-970f-41a3-8ac6-2d132123d8c7 +# ╠═44366de6-1152-45bb-b300-c766d64e85f8 +# ╠═fe5dfe3c-f4d4-426f-a840-dc950c816222 +# ╠═39bbcd3b-7ab7-45e3-ab27-eb94a25f507f +# ╠═16b72035-3c8b-4c46-a1e7-35b062851422 +# ╠═50a7ea9f-72ad-4050-89c6-b3c7d02d07d8 +# ╠═b4a652af-1fda-455c-b6d2-7e818120fdf2 +# ╠═49f460a5-e70e-472f-8149-f7dd6cf9e481 +# ╠═1f90d0e6-8d3e-4aed-9cbb-748243e3a25a +# ╠═5e586027-baa1-463b-a032-1b25f87fe270 +# ╠═ffe2800b-add1-4817-adeb-efc7660ead61 +# ╠═0bb5977b-889d-408a-a073-c9a9b4e1eabc +# ╠═2ef96814-04d3-466a-9d91-a43a3ae1f069 +# ╠═1dece802-261f-4f0e-a681-dbc6fcde5bbc +# ╟─00000000-0000-0000-0000-000000000001 +# ╟─00000000-0000-0000-0000-000000000002 diff --git a/class02/class02_overview.jl b/class02/class02_overview.jl new file mode 100644 index 0000000..4f8c880 --- /dev/null +++ b/class02/class02_overview.jl @@ -0,0 +1,420 @@ +### A Pluto.jl notebook ### +# v0.20.17 + +using Markdown +using InteractiveUtils + +# ╔═╡ f656fd22-6dce-40da-b67a-febcee9bff08 +using PlutoUI + +# ╔═╡ a89a5e16-9c64-11f0-3c6f-772fd0a68437 +md""" +## Sections +- [Root finding](class02_root_finding.jl) +- [Unconstrained minimization](class02_unconstrained_min.jl) +- [Constrained minimization](class02_constrained_min.jl) +- [Barrier vs. ALM](class02_methods_barrier_alm.jl) +- [Sequential Quadratic Programming](class02_sqp.jl) +""" + + +# ╔═╡ 46558377-74bc-4453-b2c2-273ccaf3d2d7 +md""" +### How to read / run + +1. Skim the **learning goals** below. +2. Open each subsection (links above). Read the short prose, then **run the cells top-to-bottom**. +3. Use the **sliders and toggles** to see how stepsizes, conditioning, and feasibility affect convergence. +4. Try at least **one “Check your understanding”** box per subsection. +""" + +# ╔═╡ 61fc1519-10c9-4b57-ac8f-4b660c08b39d +md"""## Learning goals (what you’ll be able to do) + +* **Pick and configure** an optimizer for small control problems (unconstrained & constrained). +* **Derive KKT conditions** and form the **QP/SQP subproblem** for a nonlinear program. +* **Explain differences** between **penalty**, **augmented Lagrangian (ALM)**, and **interior-point** methods, and when to prefer each. + +**Why this matters.** It lets us map classic control tasks—LQR, MPC, trajectory optimization—into QPs/NLPs, exploit sparsity/warm starts, and choose a robust globalization strategy. +""" + +# ╔═╡ 82c39021-20d1-4605-b10a-b1c6a29029e5 +md"""## Big picture: why optimization for control? + +* **Controller synthesis as optimization.** Many controllers are designed or run by solving optimization problems repeatedly. +* **MPC** solves a QP/NLP online each step—**warm-starts** and **sparsity** drive speed. +* **Trajectory optimization** uses nonlinear programming (often with collocation); robust **globalization** prevents solver stalls. +* **Learning-based control** wraps optimizers inside training loops (differentiable programming), so smoothness and convergence matter. + +**Mental model (any time step (k))** +State (x_k) → **optimizer** solves a small problem → control (u_k) → plant evolves (x_{k+1}=f(x_k,u_k)). +The solver is part of the loop; reliability and speed translate directly to control performance. +""" + +# ╔═╡ 515f280d-70e8-4b98-ba81-3861433594b3 +md""" +## Notation I: derivatives & Jacobians + +We keep **dimensions explicit** so shapes are clear. + +* **Scalar-valued** (f:\mathbb{R}^n\to\mathbb{R}) + + * Row-derivative (row gradient): (\dfrac{\partial f}{\partial x}\in\mathbb{R}^{1\times n}) + * Column gradient (our default): (\nabla f(x):=\left(\dfrac{\partial f}{\partial x}\right)^{!T}\in\mathbb{R}^{n}) + + **First-order model:** + [ + f(x+\Delta x)\approx f(x)+\nabla f(x)^{!T}\Delta x. + ] + +* **Vector-valued** (g:\mathbb{R}^m\to\mathbb{R}^n) + + * **Jacobian:** (\dfrac{\partial g}{\partial y}\in\mathbb{R}^{n\times m}) + + **First-order model:** + [ + g(y+\Delta y)\approx g(y)+\frac{\partial g}{\partial y},\Delta y. + ] +""" + +# ╔═╡ ad3d636c-571f-4671-a049-d7c4a9546058 +md""" +## Notation II: gradient, Hessian & Taylor + +* **Gradient (column):** (\nabla f(x)\in\mathbb{R}^{n}). +* **Hessian:** (\nabla^{2}f(x)\in\mathbb{R}^{n\times n}). +* **Shape check:** (\Delta x^{!T}\nabla^{2}f(x)\Delta x\in\mathbb{R}). + +**Second-order Taylor expansion (near (x))** +[ +f(x+\Delta x)\approx f(x)+\nabla f(x)^{!T}\Delta x+\tfrac{1}{2},\Delta x^{!T}\nabla^{2}f(x),\Delta x. +] + +**Conventions in this chapter** + +* We use the **column-gradient** convention in derivations. +* For constraints (g(x)=0) and (h(x)\le 0), Jacobians are stacked by rows so shapes align in KKT systems. +""" + +# ╔═╡ 333765ac-6dc9-40fd-9b14-5905cd95cb30 +md""" +KKT snapshot (for reference) + +For +[ +\min_x f(x)\quad \text{s.t.}\quad g(x)=0,\ \ h(x)\le 0, +] +the (informal) KKT conditions at a candidate (x^\star) are: + +* **Stationarity:** (\nabla f(x^\star)+\nabla g(x^\star)^{!T}\lambda^\star+\nabla h(x^\star)^{!T}\mu^\star=0). +* **Primal feasibility:** (g(x^\star)=0,\ \ h(x^\star)\le 0). +* **Dual feasibility:** (\mu^\star\ge 0). +* **Complementarity:** (\mu_i^\star,h_i(x^\star)=0) for each inequality (i). + +You’ll see how penalty/ALM/interior-point handle these conditions differently (explicitly, indirectly, or via barriers). +""" + +# ╔═╡ a65e8de6-8f17-4adb-8359-cbe8a349eff8 +md""" + +""" + +# ╔═╡ 12cbe2ab-9a12-4db6-a044-de0578bb49f3 + + +# ╔═╡ 00000000-0000-0000-0000-000000000001 +PLUTO_PROJECT_TOML_CONTENTS = """ +[deps] +PlutoUI = "7f904dfe-b85e-4ff6-b463-dae2292396a8" + +[compat] +PlutoUI = "~0.7.71" +""" + +# ╔═╡ 00000000-0000-0000-0000-000000000002 +PLUTO_MANIFEST_TOML_CONTENTS = """ +# This file is machine-generated - editing it directly is not advised + +julia_version = "1.10.0" +manifest_format = "2.0" +project_hash = "984046fe41e3da5a07991eff195bd989ad3f9484" + +[[deps.AbstractPlutoDingetjes]] +deps = ["Pkg"] +git-tree-sha1 = "6e1d2a35f2f90a4bc7c2ed98079b2ba09c35b83a" +uuid = "6e696c72-6542-2067-7265-42206c756150" +version = "1.3.2" + +[[deps.ArgTools]] +uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" +version = "1.1.1" + +[[deps.Artifacts]] +uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" + +[[deps.Base64]] +uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" + +[[deps.ColorTypes]] +deps = ["FixedPointNumbers", "Random"] +git-tree-sha1 = "67e11ee83a43eb71ddc950302c53bf33f0690dfe" +uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f" +version = "0.12.1" + + [deps.ColorTypes.extensions] + StyledStringsExt = "StyledStrings" + + [deps.ColorTypes.weakdeps] + StyledStrings = "f489334b-da3d-4c2e-b8f0-e476e12c162b" + +[[deps.CompilerSupportLibraries_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" +version = "1.0.5+1" + +[[deps.Dates]] +deps = ["Printf"] +uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" + +[[deps.Downloads]] +deps = ["ArgTools", "FileWatching", "LibCURL", "NetworkOptions"] +uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6" +version = "1.6.0" + +[[deps.FileWatching]] +uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee" + +[[deps.FixedPointNumbers]] +deps = ["Statistics"] +git-tree-sha1 = "05882d6995ae5c12bb5f36dd2ed3f61c98cbb172" +uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93" +version = "0.8.5" + +[[deps.Hyperscript]] +deps = ["Test"] +git-tree-sha1 = "179267cfa5e712760cd43dcae385d7ea90cc25a4" +uuid = "47d2ed2b-36de-50cf-bf87-49c2cf4b8b91" +version = "0.0.5" + +[[deps.HypertextLiteral]] +deps = ["Tricks"] +git-tree-sha1 = "7134810b1afce04bbc1045ca1985fbe81ce17653" +uuid = "ac1192a8-f4b3-4bfe-ba22-af5b92cd3ab2" +version = "0.9.5" + +[[deps.IOCapture]] +deps = ["Logging", "Random"] +git-tree-sha1 = "b6d6bfdd7ce25b0f9b2f6b3dd56b2673a66c8770" +uuid = "b5f81e59-6552-4d32-b1f0-c071b021bf89" +version = "0.2.5" + +[[deps.InteractiveUtils]] +deps = ["Markdown"] +uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" + +[[deps.JSON]] +deps = ["Dates", "Mmap", "Parsers", "Unicode"] +git-tree-sha1 = "31e996f0a15c7b280ba9f76636b3ff9e2ae58c9a" +uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" +version = "0.21.4" + +[[deps.LibCURL]] +deps = ["LibCURL_jll", "MozillaCACerts_jll"] +uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21" +version = "0.6.4" + +[[deps.LibCURL_jll]] +deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"] +uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" +version = "8.4.0+0" + +[[deps.LibGit2]] +deps = ["Base64", "LibGit2_jll", "NetworkOptions", "Printf", "SHA"] +uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" + +[[deps.LibGit2_jll]] +deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll"] +uuid = "e37daf67-58a4-590a-8e99-b0245dd2ffc5" +version = "1.6.4+0" + +[[deps.LibSSH2_jll]] +deps = ["Artifacts", "Libdl", "MbedTLS_jll"] +uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" +version = "1.11.0+1" + +[[deps.Libdl]] +uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" + +[[deps.LinearAlgebra]] +deps = ["Libdl", "OpenBLAS_jll", "libblastrampoline_jll"] +uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" + +[[deps.Logging]] +uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" + +[[deps.MIMEs]] +git-tree-sha1 = "c64d943587f7187e751162b3b84445bbbd79f691" +uuid = "6c6e2e6c-3030-632d-7369-2d6c69616d65" +version = "1.1.0" + +[[deps.Markdown]] +deps = ["Base64"] +uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" + +[[deps.MbedTLS_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" +version = "2.28.2+1" + +[[deps.Mmap]] +uuid = "a63ad114-7e13-5084-954f-fe012c677804" + +[[deps.MozillaCACerts_jll]] +uuid = "14a3606d-f60d-562e-9121-12d972cd8159" +version = "2023.1.10" + +[[deps.NetworkOptions]] +uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" +version = "1.2.0" + +[[deps.OpenBLAS_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] +uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" +version = "0.3.23+2" + +[[deps.Parsers]] +deps = ["Dates", "PrecompileTools", "UUIDs"] +git-tree-sha1 = "7d2f8f21da5db6a806faf7b9b292296da42b2810" +uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" +version = "2.8.3" + +[[deps.Pkg]] +deps = ["Artifacts", "Dates", "Downloads", "FileWatching", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"] +uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" +version = "1.10.0" + +[[deps.PlutoUI]] +deps = ["AbstractPlutoDingetjes", "Base64", "ColorTypes", "Dates", "Downloads", "FixedPointNumbers", "Hyperscript", "HypertextLiteral", "IOCapture", "InteractiveUtils", "JSON", "Logging", "MIMEs", "Markdown", "Random", "Reexport", "URIs", "UUIDs"] +git-tree-sha1 = "8329a3a4f75e178c11c1ce2342778bcbbbfa7e3c" +uuid = "7f904dfe-b85e-4ff6-b463-dae2292396a8" +version = "0.7.71" + +[[deps.PrecompileTools]] +deps = ["Preferences"] +git-tree-sha1 = "5aa36f7049a63a1528fe8f7c3f2113413ffd4e1f" +uuid = "aea7be01-6a6a-4083-8856-8a6e6704d82a" +version = "1.2.1" + +[[deps.Preferences]] +deps = ["TOML"] +git-tree-sha1 = "0f27480397253da18fe2c12a4ba4eb9eb208bf3d" +uuid = "21216c6a-2e73-6563-6e65-726566657250" +version = "1.5.0" + +[[deps.Printf]] +deps = ["Unicode"] +uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" + +[[deps.REPL]] +deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"] +uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" + +[[deps.Random]] +deps = ["SHA"] +uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" + +[[deps.Reexport]] +git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b" +uuid = "189a3867-3050-52da-a836-e630ba90ab69" +version = "1.2.2" + +[[deps.SHA]] +uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" +version = "0.7.0" + +[[deps.Serialization]] +uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" + +[[deps.Sockets]] +uuid = "6462fe0b-24de-5631-8697-dd941f90decc" + +[[deps.SparseArrays]] +deps = ["Libdl", "LinearAlgebra", "Random", "Serialization", "SuiteSparse_jll"] +uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" +version = "1.10.0" + +[[deps.Statistics]] +deps = ["LinearAlgebra", "SparseArrays"] +uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" +version = "1.10.0" + +[[deps.SuiteSparse_jll]] +deps = ["Artifacts", "Libdl", "libblastrampoline_jll"] +uuid = "bea87d4a-7f5b-5778-9afe-8cc45184846c" +version = "7.2.1+1" + +[[deps.TOML]] +deps = ["Dates"] +uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76" +version = "1.0.3" + +[[deps.Tar]] +deps = ["ArgTools", "SHA"] +uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e" +version = "1.10.0" + +[[deps.Test]] +deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] +uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[[deps.Tricks]] +git-tree-sha1 = "372b90fe551c019541fafc6ff034199dc19c8436" +uuid = "410a4b4d-49e4-4fbc-ab6d-cb71b17b3775" +version = "0.1.12" + +[[deps.URIs]] +git-tree-sha1 = "bef26fb046d031353ef97a82e3fdb6afe7f21b1a" +uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4" +version = "1.6.1" + +[[deps.UUIDs]] +deps = ["Random", "SHA"] +uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" + +[[deps.Unicode]] +uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" + +[[deps.Zlib_jll]] +deps = ["Libdl"] +uuid = "83775a58-1f1d-513f-b197-d71354ab007a" +version = "1.2.13+1" + +[[deps.libblastrampoline_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "8e850b90-86db-534c-a0d3-1478176c7d93" +version = "5.8.0+1" + +[[deps.nghttp2_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" +version = "1.52.0+1" + +[[deps.p7zip_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" +version = "17.4.0+2" +""" + +# ╔═╡ Cell order: +# ╠═f656fd22-6dce-40da-b67a-febcee9bff08 +# ╠═a89a5e16-9c64-11f0-3c6f-772fd0a68437 +# ╠═46558377-74bc-4453-b2c2-273ccaf3d2d7 +# ╠═61fc1519-10c9-4b57-ac8f-4b660c08b39d +# ╠═82c39021-20d1-4605-b10a-b1c6a29029e5 +# ╠═515f280d-70e8-4b98-ba81-3861433594b3 +# ╠═ad3d636c-571f-4671-a049-d7c4a9546058 +# ╠═333765ac-6dc9-40fd-9b14-5905cd95cb30 +# ╠═a65e8de6-8f17-4adb-8359-cbe8a349eff8 +# ╠═12cbe2ab-9a12-4db6-a044-de0578bb49f3 +# ╟─00000000-0000-0000-0000-000000000001 +# ╟─00000000-0000-0000-0000-000000000002 diff --git a/class02/class02_root_finding.jl b/class02/class02_root_finding.jl new file mode 100644 index 0000000..806b8aa --- /dev/null +++ b/class02/class02_root_finding.jl @@ -0,0 +1,646 @@ +### A Pluto.jl notebook ### +# v0.20.17 + +using Markdown +using InteractiveUtils + +# ╔═╡ cc19c250-9c64-11f0-069e-a1b411d0212b +md"[⬅ Back to Class 02 Overview](class02_overview.jl)" + +# ╔═╡ c268beac-c0b0-4be1-b34e-bc5294751df9 +md"# Root Finding and Fixed Points + +In the first subsection of Chapter 2, we will be covering root finding and fixed points. We want to build an intuition for root-finding and fixed-point iteration. We also want to understand when/why simple fixed-point iteration converges. We will also derive Newton’s method from first principles. Apply it to an implicit Backward Euler step. Learn practical globalization (damping / line search on residual)." + +# ╔═╡ 8a457e90-7526-4d5a-89d7-63588be4690d +md""" +## Root-Finding and Fixed Points (big picture) + +* **Root-finding:** given $f:\mathbb{R}^n!\to!\mathbb{R}^n$, find ($x^\star$) with ($f(x^\star)=0$). + Examples: steady states, solving nonlinear equations, implicit time-stepping. +* **Fixed point:** ($x^\star$) is a fixed point of (g) if ($g(x^\star)=x^\star$). +* **Bridge:** pick ($g(x)=x-\alpha f(x)$) with ($\alpha>0$). Then + $$f(x^\star)=0 \quad\Longleftrightarrow\quad g(x^\star)=x^\star$$ . +* **Mindset:** start at ($x_0$) and iterate ($x_{k+1}=g(x_k)$) until nothing changes (within tolerance). +""" + +# ╔═╡ 164e269d-21c7-4466-915f-95f5bcad08c9 +md""" +Nuni - add a small julia visualization for 1d or 2d motion +""" + +# ╔═╡ 30bb23ab-1ba1-4222-859d-bd095cc231f8 +md"""## When does fixed-point iteration converge? + +* Near $(x^\star)$, (g) behaves like its Jacobian ($J_g(x^\star)$) (linearization). +* **Contraction test:** + + * Scalar: ($|g'(x^\star)|<1$) + * Vector: spectral radius ($\rho!\left(J_g(x^\star)\right)<1$) +* Smaller contraction ($\Rightarrow$) faster (linear) convergence. +* If the contraction fails ($(\ge 1)$), expect divergence or oscillations. +* Convergence is **local**: you need to start in the **basin of attraction**. +""" + +# ╔═╡ 8336a88f-7a6b-473f-a3cf-711df97d2297 +md""" +## Fixed-Point Iteration: minimal recipe + +1. Choose ($g$) (often ($g(x)=x-\alpha f(x))$) and an initial guess ($x_0$). +2. Loop: ($x_{k+1}\leftarrow g(x_k)$). +3. Stop when either + + * **residual** ($|f(x_{k+1})|$) is small, or + * **step size** ($|x_{k+1}-x_k|$) is small, or + * **max iterations** hit. +4. **Report both** residual and step size to diagnose false convergence. + +**Diagnostics tip.** Small step but large residual ($\Rightarrow$) stagnation (bad $(g)/(\alpha))$. Large step but small residual $(\Rightarrow)$ near solution but overshooting. +""" + +# ╔═╡ 192e2d28-c502-4cc5-b365-21086d7e1bd4 +md""" +## Tuning the simple iteration + +* **Step size ($\alpha$):** too small $(\Rightarrow)$ slow; too large $(\Rightarrow)$ divergence/oscillation. Start modest, adjust cautiously. +* **Damping / relaxation:** $(x_{k+1}\gets (1-\beta)x_k+\beta,g(x_k))$, with $(0<\beta\le 1)$ stabilizes updates. +* **Rescaling/preconditioning:** choose $(g(x)=x-P,f(x))$ with a good matrix (P) (approx $(J_f(x^\star)^{-1})$) to speed convergence. +* **Better initial guesses** shrink the “distance to the basin”. + +**Optimization link.** Gradient descent is fixed-point iteration on (\nabla F): +$(g(x)=x-\eta\nabla F(x))$ solves $(\nabla F(x^\star)=0)$. + +""" + +# ╔═╡ a8ab5084-6fb4-4f54-8a60-831c0a77e660 +md""" +## Newton’s Method Derived (from linearization) + +**TL;DR.** Instead of solving $(f(x)=0)$ directly, at the current $(x)$ solve a **linearized** system for a correction $(\Delta x)$. + +* Linearize $(f)$ near (x): + $$f(x+\Delta x);\approx; f(x) + J_f(x),\Delta x$$ . + +* Set the approximation to zero and solve for ($\Delta x$): + $$f(x) + J_f(x),\Delta x = 0 + \quad\Longrightarrow\quad + \Delta x = -J_f(x)^{-1} f(x)$$ +* Update and repeat: $(x \leftarrow x + \Delta x)$. + +""" + +# ╔═╡ 8658738a-b448-4aa9-9a1c-5a913cd3ceb1 +md""" +## Newton: local behavior & requirements + +* If (f) is smooth, (J_f(x^\star)) is **nonsingular**, and (x_0) is close enough to (x^\star), Newton converges **quadratically**: + (|x_{k+1}-x^\star| \approx C |x_k-x^\star|^2). +* If (J_f(x^\star)) is singular or poorly conditioned, expect slow or erratic progress. +* Good **initialization** matters; Newton is a **local** method. + +**Cost.** Each iteration solves a linear system with (J_f(x)): naive dense (O(n^3)), but real problems exploit **sparsity/structure** and reuse factorizations. +""" + + +# ╔═╡ 81832b4c-f010-41d9-8b62-3924bcb3669d +md"""## Globalization for Newton (residual line search) + +Pure Newton can overshoot. A classic fix is a **line search on the residual norm**: + +* Define merit (\phi(x)=\tfrac12 |f(x)|_2^2). +* Compute Newton step (\Delta x=-J_f(x)^{-1}f(x)). +* **Backtrack** on (\alpha\in(0,1]) until + [ + \phi(x+\alpha\Delta x) ;\le; \phi(x) + c,\alpha,\nabla\phi(x)^{!T}\Delta x, + \quad 00), **Backward Euler** seeks (x_{n+1}) via +[ +x_{n+1} = x_n + h,f(x_{n+1}). +] +Define the residual in the unknown (x_{n+1}): +[ +r(z) ;=; z - x_n - h,f(z) . +] +We solve the **root-finding** problem (r(z)=0) for (z=x_{n+1}). + +* Newton step: solve (J_r(z),\Delta = -r(z)) with + (J_r(z)=I - h,J_f(z)). +* **Fast local convergence** (often quadratic) once close. +* **Cost driver:** the linear solve; exploit **sparsity** in (J_f), reuse factorizations across timesteps, and **warm-start** with (z\approx x_n). + +**Try it (when you add code).** + +* Slider for (h) and initial guess (z_0). +* Compare pure Newton vs. residual line search. +* Plot (|r(z_k)|) per iteration (log scale). +""" + +# ╔═╡ 060606a5-aca5-449e-a614-57b79b78a462 +md""" +## Root-Finding via Minimization (and vice-versa) + +* **Solve (f(x)=0)** by minimizing the least-squares objective + (\min_x \tfrac12 |f(x)|_2^2). + + * **Gauss–Newton** uses (J_f(x)^{!T}J_f(x)\Delta = -J_f(x)^{!T} f(x)). + * Good when (f) is a residual from data/physics (sum of squares). +* **Solve (\nabla F(x)=0)** (unconstrained minimization) with **Newton for gradients**: + [ + \Delta x = -(\nabla^2 F(x))^{-1}\nabla F(x),\qquad x\gets x+\Delta x. + ] + This is “Newton for optimization” and appears in the next section. +""" + +# ╔═╡ cb3d5657-0ef6-44bf-8818-95c48ad5595e +md""" +## Diagnostics & Pitfalls + +* **Stagnation:** ($|x_{k+1}-x_k|\to 0$) but ($|f(x_k)|\not\to 0$). + *Fix:* better (g)/preconditioner (P), damping, or switch to Newton. +* **Oscillation/divergence:** step too aggressive. + *Fix:* relaxation ($\beta<1$), backtracking on residual, smaller ($\alpha$). +* **Singular/ill-conditioned Jacobian:** Newton step unstable. + *Fix:* regularize (e.g., add ($\gamma I$)), trust-region, or switch to Gauss–Newton if least-squares. +* **Bad initial guess:** outside basin. + *Fix:* problem-specific heuristics, continuation (homotopy), or multiple restarts. + +""" + +# ╔═╡ 44d93a6b-6575-438a-911f-6913d0ca02b5 +md""" +## Ensuring descent / stability (regularization) + +If the linear system for $(\Delta x)$ is unstable or poorly conditioned, **regularize**: + $$\big(J_f(x) + \gamma I\big),\Delta = -f(x),\qquad \gamma>0$$ +Then backtrack on ($\alpha$) and update ($x\gets x+\alpha\Delta$). + +* Often called **damped Newton** (shrinks steps). +* Stabilizes solves and helps ensure decrease in the residual merit. +* Choose ($\gamma$) adaptively (smaller as the residual shrinks). +""" + +# ╔═╡ a7af3229-b2ee-4dc1-991b-2196273a38db +md""" +## Where to go next + +* Head to **Unconstrained Minimization (Newton + globalization)** to see how solving (\nabla F(x)=0) ties in and how to make Newton **reliably decrease** an objective. +* Later, we’ll re-use these ideas inside **KKT systems** for constrained problems. + +[⬅ Back to overview](class02_overview.jl) + +[➡ Unconstrained minimization (next)](class02_unconstrained_min.jl) +""" + + +# ╔═╡ 00000000-0000-0000-0000-000000000001 +PLUTO_PROJECT_TOML_CONTENTS = """ +[deps] +ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" +LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +PlutoUI = "7f904dfe-b85e-4ff6-b463-dae2292396a8" +PyPlot = "d330b81b-6aea-500a-939a-2ce795aea3ee" + +[compat] +ForwardDiff = "~1.2.1" +PlutoUI = "~0.7.71" +PyPlot = "~2.11.6" +""" + +# ╔═╡ 00000000-0000-0000-0000-000000000002 +PLUTO_MANIFEST_TOML_CONTENTS = """ +# This file is machine-generated - editing it directly is not advised + +julia_version = "1.10.0" +manifest_format = "2.0" +project_hash = "90979212c71af3628dde6dc6c3039482aed6d33b" + +[[deps.AbstractPlutoDingetjes]] +deps = ["Pkg"] +git-tree-sha1 = "6e1d2a35f2f90a4bc7c2ed98079b2ba09c35b83a" +uuid = "6e696c72-6542-2067-7265-42206c756150" +version = "1.3.2" + +[[deps.ArgTools]] +uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" +version = "1.1.1" + +[[deps.Artifacts]] +uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" + +[[deps.Base64]] +uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" + +[[deps.ColorTypes]] +deps = ["FixedPointNumbers", "Random"] +git-tree-sha1 = "67e11ee83a43eb71ddc950302c53bf33f0690dfe" +uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f" +version = "0.12.1" + + [deps.ColorTypes.extensions] + StyledStringsExt = "StyledStrings" + + [deps.ColorTypes.weakdeps] + StyledStrings = "f489334b-da3d-4c2e-b8f0-e476e12c162b" + +[[deps.Colors]] +deps = ["ColorTypes", "FixedPointNumbers", "Reexport"] +git-tree-sha1 = "37ea44092930b1811e666c3bc38065d7d87fcc74" +uuid = "5ae59095-9a9b-59fe-a467-6f913c188581" +version = "0.13.1" + +[[deps.CommonSubexpressions]] +deps = ["MacroTools"] +git-tree-sha1 = "cda2cfaebb4be89c9084adaca7dd7333369715c5" +uuid = "bbf7d656-a473-5ed7-a52c-81e309532950" +version = "0.3.1" + +[[deps.CompilerSupportLibraries_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" +version = "1.0.5+1" + +[[deps.Conda]] +deps = ["Downloads", "JSON", "VersionParsing"] +git-tree-sha1 = "b19db3927f0db4151cb86d073689f2428e524576" +uuid = "8f4d0f93-b110-5947-807f-2305c1781a2d" +version = "1.10.2" + +[[deps.Dates]] +deps = ["Printf"] +uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" + +[[deps.DiffResults]] +deps = ["StaticArraysCore"] +git-tree-sha1 = "782dd5f4561f5d267313f23853baaaa4c52ea621" +uuid = "163ba53b-c6d8-5494-b064-1a9d43ac40c5" +version = "1.1.0" + +[[deps.DiffRules]] +deps = ["IrrationalConstants", "LogExpFunctions", "NaNMath", "Random", "SpecialFunctions"] +git-tree-sha1 = "23163d55f885173722d1e4cf0f6110cdbaf7e272" +uuid = "b552c78f-8df3-52c6-915a-8e097449b14b" +version = "1.15.1" + +[[deps.DocStringExtensions]] +git-tree-sha1 = "7442a5dfe1ebb773c29cc2962a8980f47221d76c" +uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" +version = "0.9.5" + +[[deps.Downloads]] +deps = ["ArgTools", "FileWatching", "LibCURL", "NetworkOptions"] +uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6" +version = "1.6.0" + +[[deps.FileWatching]] +uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee" + +[[deps.FixedPointNumbers]] +deps = ["Statistics"] +git-tree-sha1 = "05882d6995ae5c12bb5f36dd2ed3f61c98cbb172" +uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93" +version = "0.8.5" + +[[deps.ForwardDiff]] +deps = ["CommonSubexpressions", "DiffResults", "DiffRules", "LinearAlgebra", "LogExpFunctions", "NaNMath", "Preferences", "Printf", "Random", "SpecialFunctions"] +git-tree-sha1 = "dc41303865a16274ecb8450c220021ce1e0cf05f" +uuid = "f6369f11-7733-5829-9624-2563aa707210" +version = "1.2.1" + + [deps.ForwardDiff.extensions] + ForwardDiffStaticArraysExt = "StaticArrays" + + [deps.ForwardDiff.weakdeps] + StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" + +[[deps.Hyperscript]] +deps = ["Test"] +git-tree-sha1 = "179267cfa5e712760cd43dcae385d7ea90cc25a4" +uuid = "47d2ed2b-36de-50cf-bf87-49c2cf4b8b91" +version = "0.0.5" + +[[deps.HypertextLiteral]] +deps = ["Tricks"] +git-tree-sha1 = "7134810b1afce04bbc1045ca1985fbe81ce17653" +uuid = "ac1192a8-f4b3-4bfe-ba22-af5b92cd3ab2" +version = "0.9.5" + +[[deps.IOCapture]] +deps = ["Logging", "Random"] +git-tree-sha1 = "b6d6bfdd7ce25b0f9b2f6b3dd56b2673a66c8770" +uuid = "b5f81e59-6552-4d32-b1f0-c071b021bf89" +version = "0.2.5" + +[[deps.InteractiveUtils]] +deps = ["Markdown"] +uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" + +[[deps.IrrationalConstants]] +git-tree-sha1 = "e2222959fbc6c19554dc15174c81bf7bf3aa691c" +uuid = "92d709cd-6900-40b7-9082-c6be49f344b6" +version = "0.2.4" + +[[deps.JLLWrappers]] +deps = ["Artifacts", "Preferences"] +git-tree-sha1 = "0533e564aae234aff59ab625543145446d8b6ec2" +uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210" +version = "1.7.1" + +[[deps.JSON]] +deps = ["Dates", "Mmap", "Parsers", "Unicode"] +git-tree-sha1 = "31e996f0a15c7b280ba9f76636b3ff9e2ae58c9a" +uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" +version = "0.21.4" + +[[deps.LaTeXStrings]] +git-tree-sha1 = "dda21b8cbd6a6c40d9d02a73230f9d70fed6918c" +uuid = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" +version = "1.4.0" + +[[deps.LibCURL]] +deps = ["LibCURL_jll", "MozillaCACerts_jll"] +uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21" +version = "0.6.4" + +[[deps.LibCURL_jll]] +deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"] +uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" +version = "8.4.0+0" + +[[deps.LibGit2]] +deps = ["Base64", "LibGit2_jll", "NetworkOptions", "Printf", "SHA"] +uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" + +[[deps.LibGit2_jll]] +deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll"] +uuid = "e37daf67-58a4-590a-8e99-b0245dd2ffc5" +version = "1.6.4+0" + +[[deps.LibSSH2_jll]] +deps = ["Artifacts", "Libdl", "MbedTLS_jll"] +uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" +version = "1.11.0+1" + +[[deps.Libdl]] +uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" + +[[deps.LinearAlgebra]] +deps = ["Libdl", "OpenBLAS_jll", "libblastrampoline_jll"] +uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" + +[[deps.LogExpFunctions]] +deps = ["DocStringExtensions", "IrrationalConstants", "LinearAlgebra"] +git-tree-sha1 = "13ca9e2586b89836fd20cccf56e57e2b9ae7f38f" +uuid = "2ab3a3ac-af41-5b50-aa03-7779005ae688" +version = "0.3.29" + + [deps.LogExpFunctions.extensions] + LogExpFunctionsChainRulesCoreExt = "ChainRulesCore" + LogExpFunctionsChangesOfVariablesExt = "ChangesOfVariables" + LogExpFunctionsInverseFunctionsExt = "InverseFunctions" + + [deps.LogExpFunctions.weakdeps] + ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" + ChangesOfVariables = "9e997f8a-9a97-42d5-a9f1-ce6bfc15e2c0" + InverseFunctions = "3587e190-3f89-42d0-90ee-14403ec27112" + +[[deps.Logging]] +uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" + +[[deps.MIMEs]] +git-tree-sha1 = "c64d943587f7187e751162b3b84445bbbd79f691" +uuid = "6c6e2e6c-3030-632d-7369-2d6c69616d65" +version = "1.1.0" + +[[deps.MacroTools]] +git-tree-sha1 = "1e0228a030642014fe5cfe68c2c0a818f9e3f522" +uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" +version = "0.5.16" + +[[deps.Markdown]] +deps = ["Base64"] +uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" + +[[deps.MbedTLS_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" +version = "2.28.2+1" + +[[deps.Mmap]] +uuid = "a63ad114-7e13-5084-954f-fe012c677804" + +[[deps.MozillaCACerts_jll]] +uuid = "14a3606d-f60d-562e-9121-12d972cd8159" +version = "2023.1.10" + +[[deps.NaNMath]] +deps = ["OpenLibm_jll"] +git-tree-sha1 = "9b8215b1ee9e78a293f99797cd31375471b2bcae" +uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" +version = "1.1.3" + +[[deps.NetworkOptions]] +uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" +version = "1.2.0" + +[[deps.OpenBLAS_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] +uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" +version = "0.3.23+2" + +[[deps.OpenLibm_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "05823500-19ac-5b8b-9628-191a04bc5112" +version = "0.8.1+2" + +[[deps.OpenSpecFun_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl"] +git-tree-sha1 = "1346c9208249809840c91b26703912dff463d335" +uuid = "efe28fd5-8261-553b-a9e1-b2916fc3738e" +version = "0.5.6+0" + +[[deps.Parsers]] +deps = ["Dates", "PrecompileTools", "UUIDs"] +git-tree-sha1 = "7d2f8f21da5db6a806faf7b9b292296da42b2810" +uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" +version = "2.8.3" + +[[deps.Pkg]] +deps = ["Artifacts", "Dates", "Downloads", "FileWatching", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"] +uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" +version = "1.10.0" + +[[deps.PlutoUI]] +deps = ["AbstractPlutoDingetjes", "Base64", "ColorTypes", "Dates", "Downloads", "FixedPointNumbers", "Hyperscript", "HypertextLiteral", "IOCapture", "InteractiveUtils", "JSON", "Logging", "MIMEs", "Markdown", "Random", "Reexport", "URIs", "UUIDs"] +git-tree-sha1 = "8329a3a4f75e178c11c1ce2342778bcbbbfa7e3c" +uuid = "7f904dfe-b85e-4ff6-b463-dae2292396a8" +version = "0.7.71" + +[[deps.PrecompileTools]] +deps = ["Preferences"] +git-tree-sha1 = "5aa36f7049a63a1528fe8f7c3f2113413ffd4e1f" +uuid = "aea7be01-6a6a-4083-8856-8a6e6704d82a" +version = "1.2.1" + +[[deps.Preferences]] +deps = ["TOML"] +git-tree-sha1 = "0f27480397253da18fe2c12a4ba4eb9eb208bf3d" +uuid = "21216c6a-2e73-6563-6e65-726566657250" +version = "1.5.0" + +[[deps.Printf]] +deps = ["Unicode"] +uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" + +[[deps.PyCall]] +deps = ["Conda", "Dates", "Libdl", "LinearAlgebra", "MacroTools", "Serialization", "VersionParsing"] +git-tree-sha1 = "9816a3826b0ebf49ab4926e2b18842ad8b5c8f04" +uuid = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0" +version = "1.96.4" + +[[deps.PyPlot]] +deps = ["Colors", "LaTeXStrings", "PyCall", "Sockets", "Test", "VersionParsing"] +git-tree-sha1 = "d2c2b8627bbada1ba00af2951946fb8ce6012c05" +uuid = "d330b81b-6aea-500a-939a-2ce795aea3ee" +version = "2.11.6" + +[[deps.REPL]] +deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"] +uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" + +[[deps.Random]] +deps = ["SHA"] +uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" + +[[deps.Reexport]] +git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b" +uuid = "189a3867-3050-52da-a836-e630ba90ab69" +version = "1.2.2" + +[[deps.SHA]] +uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" +version = "0.7.0" + +[[deps.Serialization]] +uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" + +[[deps.Sockets]] +uuid = "6462fe0b-24de-5631-8697-dd941f90decc" + +[[deps.SparseArrays]] +deps = ["Libdl", "LinearAlgebra", "Random", "Serialization", "SuiteSparse_jll"] +uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" +version = "1.10.0" + +[[deps.SpecialFunctions]] +deps = ["IrrationalConstants", "LogExpFunctions", "OpenLibm_jll", "OpenSpecFun_jll"] +git-tree-sha1 = "41852b8679f78c8d8961eeadc8f62cef861a52e3" +uuid = "276daf66-3868-5448-9aa4-cd146d93841b" +version = "2.5.1" + + [deps.SpecialFunctions.extensions] + SpecialFunctionsChainRulesCoreExt = "ChainRulesCore" + + [deps.SpecialFunctions.weakdeps] + ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" + +[[deps.StaticArraysCore]] +git-tree-sha1 = "192954ef1208c7019899fbf8049e717f92959682" +uuid = "1e83bf80-4336-4d27-bf5d-d5a4f845583c" +version = "1.4.3" + +[[deps.Statistics]] +deps = ["LinearAlgebra", "SparseArrays"] +uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" +version = "1.10.0" + +[[deps.SuiteSparse_jll]] +deps = ["Artifacts", "Libdl", "libblastrampoline_jll"] +uuid = "bea87d4a-7f5b-5778-9afe-8cc45184846c" +version = "7.2.1+1" + +[[deps.TOML]] +deps = ["Dates"] +uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76" +version = "1.0.3" + +[[deps.Tar]] +deps = ["ArgTools", "SHA"] +uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e" +version = "1.10.0" + +[[deps.Test]] +deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] +uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[[deps.Tricks]] +git-tree-sha1 = "372b90fe551c019541fafc6ff034199dc19c8436" +uuid = "410a4b4d-49e4-4fbc-ab6d-cb71b17b3775" +version = "0.1.12" + +[[deps.URIs]] +git-tree-sha1 = "bef26fb046d031353ef97a82e3fdb6afe7f21b1a" +uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4" +version = "1.6.1" + +[[deps.UUIDs]] +deps = ["Random", "SHA"] +uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" + +[[deps.Unicode]] +uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" + +[[deps.VersionParsing]] +git-tree-sha1 = "58d6e80b4ee071f5efd07fda82cb9fbe17200868" +uuid = "81def892-9a0e-5fdd-b105-ffc91e053289" +version = "1.3.0" + +[[deps.Zlib_jll]] +deps = ["Libdl"] +uuid = "83775a58-1f1d-513f-b197-d71354ab007a" +version = "1.2.13+1" + +[[deps.libblastrampoline_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "8e850b90-86db-534c-a0d3-1478176c7d93" +version = "5.8.0+1" + +[[deps.nghttp2_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" +version = "1.52.0+1" + +[[deps.p7zip_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" +version = "17.4.0+2" +""" + +# ╔═╡ Cell order: +# ╠═cc19c250-9c64-11f0-069e-a1b411d0212b +# ╠═c268beac-c0b0-4be1-b34e-bc5294751df9 +# ╠═8a457e90-7526-4d5a-89d7-63588be4690d +# ╠═164e269d-21c7-4466-915f-95f5bcad08c9 +# ╠═30bb23ab-1ba1-4222-859d-bd095cc231f8 +# ╠═8336a88f-7a6b-473f-a3cf-711df97d2297 +# ╠═192e2d28-c502-4cc5-b365-21086d7e1bd4 +# ╠═a8ab5084-6fb4-4f54-8a60-831c0a77e660 +# ╠═8658738a-b448-4aa9-9a1c-5a913cd3ceb1 +# ╠═81832b4c-f010-41d9-8b62-3924bcb3669d +# ╠═24cd83da-feae-4da0-9604-83767615c017 +# ╠═060606a5-aca5-449e-a614-57b79b78a462 +# ╠═cb3d5657-0ef6-44bf-8818-95c48ad5595e +# ╠═44d93a6b-6575-438a-911f-6913d0ca02b5 +# ╠═a7af3229-b2ee-4dc1-991b-2196273a38db +# ╟─00000000-0000-0000-0000-000000000001 +# ╟─00000000-0000-0000-0000-000000000002 diff --git a/class02/class02_sqp.jl b/class02/class02_sqp.jl new file mode 100644 index 0000000..17c83fd --- /dev/null +++ b/class02/class02_sqp.jl @@ -0,0 +1,269 @@ +### A Pluto.jl notebook ### +# v0.20.17 + +using Markdown +using InteractiveUtils + +# ╔═╡ cb245a30-f64e-4f2c-91f4-a50371b201a2 +md""" +*(Class 02 — interactive chapter section)* + +[⬅ Back to Class 02 Overview](class02_overview.jl) · [⬅ Previous: Methods (Penalty/ALM/IPM)](class02_methods_barrier_alm.jl) + +**In this section you will:** + +* Build the SQP **local model** (quadratic Lagrangian + linearized constraints). +* See the **QP subproblem** and how it relates to Newton on the KKT system. +* Learn **globalization** (merit / filter / trust-region) and **Hessian updates** (BFGS). +* Work through a small **toy example** and practical tips for control problems. + +""" + +# ╔═╡ 1adff7b2-d86b-4311-9626-22d52057f551 +md""" +## Cell 2 — What is SQP? + +## What is SQP? + +**Idea.** Solve a nonlinear constrained problem by repeatedly solving a **quadratic program (QP)** built from local models. + +* Linearize constraints; build a quadratic model of the **Lagrangian/objective**. +* Each iteration: solve a QP to get a step (d), then update (x \leftarrow x+\alpha d). +* With good Hessian information, SQP enjoys **strong local convergence** (often **superlinear**). + + +""" + +# ╔═╡ 3d685462-e495-4c33-a2de-470e109bff78 +md""" + +## Cell 3 — Target problem & KKT recap + +## Target NLP + +[ +\min_{x \in \mathbb{R}^n} \ f(x) +\quad\text{s.t.}\quad +g(x)=0,\quad h(x)\le 0, +] +with (g:\mathbb{R}^n!\to!\mathbb{R}^{m}) and (h:\mathbb{R}^n!\to!\mathbb{R}^{p}). + +**KKT at a candidate optimum (x^\star):** there exist (\lambda\in\mathbb{R}^m), (\mu\in\mathbb{R}^p_{\ge 0}) with +[ +\nabla f(x^\star)+ \nabla g(x^\star)^{!T}\lambda + \nabla h(x^\star)^{!T}\mu = 0, \quad +g(x^\star)=0, \quad +h(x^\star)\le 0, \quad +\mu\ge 0, \quad +\mu \odot h(x^\star)=0. +] + +""" + +# ╔═╡ 40e0acdf-f870-4ef6-9656-e909d5fb2e25 +md""" + +## Cell 4 — Local models at (x_k) + +## From NLP to local models + +At iterate (x_k) (with multipliers ((\lambda_k,\mu_k))): + +**Quadratic model of the Lagrangian** +[ +m_k(d) ;=; \nabla f(x_k)^{!T} d ;+; \tfrac{1}{2}, d^{!T} B_k, d, +] +with (B_k \approx \nabla^2_{xx}\mathcal{L}(x_k,\lambda_k,\mu_k)). + +**Linearized constraints** +[ +g(x_k)+\nabla g(x_k),d=0, +\qquad +h(x_k)+\nabla h(x_k),d \le 0. +] + +""" + +# ╔═╡ b23e9ac3-192d-41e6-9411-99214b612ab9 +md""" + +## Cell 5 — The SQP QP subproblem + +## SQP subproblem (QP) + +[ +\begin{aligned} +\min_{d \in \mathbb{R}^n}\quad & \nabla f(x_k)^{!T} d + \tfrac12 d^{!T} B_k d\ +\text{s.t.}\quad & \nabla g(x_k), d + g(x_k) = 0,\ +& \nabla h(x_k), d + h(x_k) \le 0. +\end{aligned} +] + +* Solve the QP (\Rightarrow) get step (d_k) and updated multipliers ((\lambda_{k+1},\mu_{k+1})). +* Update (x_{k+1} = x_k + \alpha_k d_k) (line search, **filter**, or **trust-region**). + +""" + +# ╔═╡ 64d7aa02-a814-4d0d-b365-90d70814932a +md""" + +## Cell 6 — Algorithm sketch + +## SQP: high-level algorithm + +1. Initialize (x_0), multipliers ((\lambda_0,\mu_0)), and (B_0 \succ 0). +2. Form the QP at (x_k) using (B_k) and the linearized constraints. +3. Solve the QP (\Rightarrow) obtain (d_k), ((\lambda_{k+1},\mu_{k+1})). +4. **Globalize** (merit/filter/TR) to choose (\alpha_k) (and possibly restrict (d_k)). +5. Set (x_{k+1}=x_k+\alpha_k d_k); update (B_{k+1}) (e.g., **BFGS**). +6. Check convergence (stationarity, feasibility, complementarity) or continue. + +""" + +# ╔═╡ a725c268-9c6a-11f0-059f-fdcd96af48e3 +md""" + +## Cell 7 — Why this QP? (Newton–KKT connection) + +## Newton–KKT connection + +The QP KKT system is a **linearized** KKT system for the NLP. + +* If (B_k) equals the exact (\nabla_{xx}^2\mathcal{L}(x_k,\lambda_k,\mu_k)), the SQP step is a **Newton step** (on the KKT equations). +* With **BFGS** (properly updated), SQP attains **superlinear** local convergence under standard assumptions (LICQ, strict complementarity, SOSC, Wolfe conditions on the merit). +""" + +# ╔═╡ ddb74901-0efe-4d4f-9c14-fc5098aaeced +md""" +## Cell 8 — Globalization I: (L_1) merit function + +## Merit function line search + +Define +[ +\Phi_\mu(x)= f(x) + \mu\Big(,|g(x)|_1 + |h(x)^-|_1\Big),\quad +h^-_i(x)=\max(0,,h_i(x)). +] + +* Choose (\mu) large enough to ensure **descent coupling** of feasibility and optimality. +* Backtrack on (\alpha\in(0,1]) to achieve an **Armijo** decrease in (\Phi_\mu). + +**Caveat.** Large (\mu) can cause the **Maratos effect** (over-penalizing curvature, step rejection). See SOC below. + +""" + +# ╔═╡ af20e5bb-dc3e-4d13-af71-f44e23c4c544 +md""" +## Cell 9 — Globalization II: filter (alternative to a big penalty) + +## Filter method (accept if you improve *either* objective or feasibility) + +Track pairs ((f,\theta)) with (\theta=|g(x)|_1+|h(x)^-|_1). + +* Accept (x_{k+1}) if it **dominates** the filter: it reduces (f) for similar (\theta), or reduces (\theta) sufficiently. +* If the step doesn’t pass, try a **feasibility restoration** phase (focus on decreasing (\theta)). + Filter avoids tuning a huge (\mu) and is widely used in practical SQP codes. + +""" + +# ╔═╡ 19da3f74-83da-4d6f-8bf0-55102050a58a +md""" +## Cell 10 — Trust-region SQP & step decomposition + +## Trust-region SQP (TRSQP) + +* Add (|d|\le \Delta) to the QP or use a **normal/tangential** split: first reduce constraint violation (normal step), then reduce (f) in the tangent space (tangential step). +* Adjust (\Delta) based on the ratio of **actual vs. predicted** improvement (as in unconstrained TR methods). +""" + +# ╔═╡ 6b101d4e-7eff-4b91-8721-bd7bb7fafa17 +md""" +## Cell 11 — Hessian models & updates + +## Choosing (B_k): exact vs. quasi-Newton + +* **Exact Lagrangian Hessian:** (B_k=\nabla^2_{xx}\mathcal{L}(x_k,\lambda_k,\mu_k)) (best local rate, expensive/less robust far away). +* **Gauss–Newton / curvature drop:** drop (\sum \mu_i \nabla^2 h_i) and (\sum \lambda_j \nabla^2 g_j) if residual-type; cheaper and often more stable. +* **BFGS / damped BFGS:** update (B_k\succ 0) with curvature condition (s_k^{!T}y_k>0) (enforce with Wolfe or damping). +* **Projected / null-space BFGS:** maintain positive definiteness on the **tangent space** to constraints. +""" + +# ╔═╡ 7923cfd5-cd33-4001-9b71-ec8c17318ae8 +md""" +## Cell 12 — The QP solver: structure matters + +## Solving the QP efficiently + +* **KKT structure:** sparse, block-saddle systems; use **Schur complements** or sparse symmetric indefinite factorizations. +* **Active-set QP solvers** (great with warm-starts; common in fast MPC). +* **Primal–dual IPM QP solvers** (robust for large QPs; excellent for dense inequality sets). +* **Warm-starting** ((x,\lambda,\mu)) and reusing factorizations across SQP iterations (and across time steps in MPC) is key. + +""" + +# ╔═╡ c1711266-ecab-4a93-af4b-7c1b0691a6a9 +md""" +## Cell 13 — Toy example (local models) + +## Toy example: local models + +[ +\min_{x\in\mathbb{R}^2}\ \tfrac12|x|^2 +\quad\text{s.t.}\quad +g(x)=x_1^2+x_2-1=0,\quad +h(x)=x_2-0.2\le 0. +] + +At (x_k): +[ +\nabla f(x_k)=x_k,\quad B_k=I,\quad +\nabla g(x_k)=\begin{bmatrix}2x_{k,1} & 1\end{bmatrix},\quad +\nabla h(x_k)=\begin{bmatrix}0 & 1\end{bmatrix}. +] +Solve the QP for (d_k), then set (x_{k+1}=x_k+\alpha_k d_k) using a merit/filter/trust-region globalization. + +*(When you add code: plot feasibility (|g|), violation (|h^-|), and objective vs. iteration.)* +""" + +# ╔═╡ 03af9cf2-4ba7-4c31-9f36-88efe8e9eb37 +md""" +## Where to next + +* You now have the full pipeline: **KKT modeling → methods (Penalty/ALM/IPM) → SQP assembly**. +* In a control context (NMPC/trajectory optimization), plug in system sparsity and warm-starts to hit real-time targets. + +[⬅ Back to overview](class02_overview.jl) +""" + +# ╔═╡ 00000000-0000-0000-0000-000000000001 +PLUTO_PROJECT_TOML_CONTENTS = """ +[deps] +""" + +# ╔═╡ 00000000-0000-0000-0000-000000000002 +PLUTO_MANIFEST_TOML_CONTENTS = """ +# This file is machine-generated - editing it directly is not advised + +julia_version = "1.10.0" +manifest_format = "2.0" +project_hash = "da39a3ee5e6b4b0d3255bfef95601890afd80709" + +[deps] +""" + +# ╔═╡ Cell order: +# ╠═cb245a30-f64e-4f2c-91f4-a50371b201a2 +# ╠═1adff7b2-d86b-4311-9626-22d52057f551 +# ╠═3d685462-e495-4c33-a2de-470e109bff78 +# ╠═40e0acdf-f870-4ef6-9656-e909d5fb2e25 +# ╠═b23e9ac3-192d-41e6-9411-99214b612ab9 +# ╠═64d7aa02-a814-4d0d-b365-90d70814932a +# ╠═a725c268-9c6a-11f0-059f-fdcd96af48e3 +# ╠═ddb74901-0efe-4d4f-9c14-fc5098aaeced +# ╠═af20e5bb-dc3e-4d13-af71-f44e23c4c544 +# ╠═19da3f74-83da-4d6f-8bf0-55102050a58a +# ╠═6b101d4e-7eff-4b91-8721-bd7bb7fafa17 +# ╠═7923cfd5-cd33-4001-9b71-ec8c17318ae8 +# ╠═c1711266-ecab-4a93-af4b-7c1b0691a6a9 +# ╠═03af9cf2-4ba7-4c31-9f36-88efe8e9eb37 +# ╟─00000000-0000-0000-0000-000000000001 +# ╟─00000000-0000-0000-0000-000000000002 diff --git a/class02/class02_unconstrained_min.jl b/class02/class02_unconstrained_min.jl new file mode 100644 index 0000000..6493a8d --- /dev/null +++ b/class02/class02_unconstrained_min.jl @@ -0,0 +1,31 @@ +### A Pluto.jl notebook ### +# v0.20.17 + +using Markdown +using InteractiveUtils + +# ╔═╡ 573d73d6-9c6a-11f0-28fb-83e9ff22e922 +md""" +hgdks +""" + +# ╔═╡ 00000000-0000-0000-0000-000000000001 +PLUTO_PROJECT_TOML_CONTENTS = """ +[deps] +""" + +# ╔═╡ 00000000-0000-0000-0000-000000000002 +PLUTO_MANIFEST_TOML_CONTENTS = """ +# This file is machine-generated - editing it directly is not advised + +julia_version = "1.10.0" +manifest_format = "2.0" +project_hash = "da39a3ee5e6b4b0d3255bfef95601890afd80709" + +[deps] +""" + +# ╔═╡ Cell order: +# ╠═573d73d6-9c6a-11f0-28fb-83e9ff22e922 +# ╟─00000000-0000-0000-0000-000000000001 +# ╟─00000000-0000-0000-0000-000000000002