|
| 1 | +### A Pluto.jl notebook ### |
| 2 | +# v0.14.5 |
| 3 | + |
| 4 | +using Markdown |
| 5 | +using InteractiveUtils |
| 6 | + |
| 7 | +# This Pluto notebook uses @bind for interactivity. When running this notebook outside of Pluto, the following 'mock version' of @bind gives bound variables a default value (instead of an error). |
| 8 | +macro bind(def, element) |
| 9 | + quote |
| 10 | + local el = $(esc(element)) |
| 11 | + global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : missing |
| 12 | + el |
| 13 | + end |
| 14 | +end |
| 15 | + |
| 16 | +# ╔═╡ 4ed28d02-f423-4f53-8010-644edacd5b74 |
| 17 | +begin |
| 18 | + import Pkg |
| 19 | + Pkg.activate(mktempdir()) |
| 20 | + Pkg.add([ |
| 21 | + Pkg.PackageSpec(name="PlutoUI", version="0.7"), |
| 22 | + Pkg.PackageSpec(name="Plots", version="1"), |
| 23 | + Pkg.PackageSpec(name="JuMP", version="0.21"), |
| 24 | + Pkg.PackageSpec(name="Ipopt", version="0.6"), |
| 25 | + ]) |
| 26 | + using PlutoUI, Plots, Statistics, JuMP, Ipopt |
| 27 | +end |
| 28 | + |
| 29 | +# ╔═╡ d719e2ed-ade8-4640-82fe-ffcafd204792 |
| 30 | +TableOfContents() |
| 31 | + |
| 32 | +# ╔═╡ d18eaa56-b8ad-11eb-1586-b15a611d773d |
| 33 | +md""" |
| 34 | +# Solving inverse problems: Optimization with JuMP |
| 35 | +""" |
| 36 | + |
| 37 | +# ╔═╡ 5bbd06bd-9191-4d06-84f3-95556afb9125 |
| 38 | +md""" |
| 39 | +## Forward and inverse problems |
| 40 | +""" |
| 41 | + |
| 42 | +# ╔═╡ 3047f39a-a18a-4dea-9d2d-6523d7d0ec4f |
| 43 | +md""" |
| 44 | +In a **forward problem** we provide inputs and calculate what the resulting output is using a model. |
| 45 | +
|
| 46 | +In an [inverse problem](https://en.wikipedia.org/wiki/Inverse_problem) we have a goal *output* and wish to find which *inputs* to the model will produce that goal. To do so we often need to solve an **optimization problem**. |
| 47 | + |
| 48 | +JuMP is a **modeling language** embedded in Julia. It allows us to write down optimization problems in a natural way; these are then converted by JuMP into the correct input format to be sent to different **solvers**, i.e. software programs that choose which optimization algorithms to apply to solve the optimization problem. |
| 49 | +""" |
| 50 | + |
| 51 | +# ╔═╡ a0aeb0c6-0980-4c6a-8736-8eccdf17e561 |
| 52 | +md""" |
| 53 | +## Unconstrained optimization |
| 54 | +""" |
| 55 | + |
| 56 | +# ╔═╡ 3a81aaa1-05c3-4ef4-ab7a-bd913a5dc85e |
| 57 | +md""" |
| 58 | +a = $(@bind a Slider(-3:0.01:3, show_value=true, default=0)) |
| 59 | +""" |
| 60 | + |
| 61 | +# ╔═╡ f488fa22-8ff9-4ea1-84c1-deaf966520d1 |
| 62 | +f(x) = x^2 - a*x + 2 |
| 63 | + |
| 64 | +# ╔═╡ 7d635168-8251-4ee9-8cc5-85ac5d810e21 |
| 65 | +min_value = let |
| 66 | + |
| 67 | + model = Model(Ipopt.Optimizer) |
| 68 | + |
| 69 | + # tell JuMP about our function: |
| 70 | + register(model, :f, 1, f, autodiff=true) |
| 71 | + |
| 72 | + # declare a variable |
| 73 | + @variable(model, -10 ≤ x ≤ 10) |
| 74 | + |
| 75 | + # set the *objective function* to optimize: |
| 76 | + @NLobjective(model, Min, f(x)) |
| 77 | + |
| 78 | + |
| 79 | + |
| 80 | + optimize!(model) |
| 81 | + |
| 82 | + getvalue(x) |
| 83 | +end |
| 84 | + |
| 85 | +# ╔═╡ 9b494263-7fb1-4893-aa15-33ad6b839773 |
| 86 | +begin |
| 87 | + plot(f, size=(400, 300), leg=false) |
| 88 | + plot!(x -> x^2 + 2, ls=:dash, alpha=0.5) |
| 89 | + scatter!([min_value], [f(min_value)], xlims=(-5, 5), ylims=(-10, 20)) |
| 90 | +end |
| 91 | + |
| 92 | +# ╔═╡ 9934adb3-b704-467f-b189-e90fb0c6c1cb |
| 93 | +md""" |
| 94 | +## Constrained optimization |
| 95 | +""" |
| 96 | + |
| 97 | +# ╔═╡ a0c8165a-dd64-46b8-9419-fe3ef2cf39e1 |
| 98 | +md""" |
| 99 | +Often we need to add **constraints**, i.e. restrictions, to the problem. |
| 100 | +""" |
| 101 | + |
| 102 | +# ╔═╡ e9bff1db-a2ce-4821-a237-815793d9cbea |
| 103 | +g(x) = 3x + 4 |
| 104 | + |
| 105 | +# ╔═╡ 696bddde-f5a3-42e6-b5b6-dd25a3fe0782 |
| 106 | +constraint(x, y) = y - x |
| 107 | + |
| 108 | +# ╔═╡ 8dc1fe61-ed8d-4f5a-b200-6269cc89c142 |
| 109 | +k(x, y) = x^2 + y^2 - 1 |
| 110 | + |
| 111 | +# ╔═╡ f58a62aa-f56b-4114-bfef-c57bdbc24e3b |
| 112 | +b_slider = @bind b Slider(-5:0.1:5, show_value=true, default=0) |
| 113 | + |
| 114 | +# ╔═╡ 3ab8f4fe-3842-46ac-8411-37f509c7dfb5 |
| 115 | +minx, miny = let |
| 116 | + |
| 117 | + model = Model(Ipopt.Optimizer) |
| 118 | + |
| 119 | + register(model, :k, 2, k, autodiff=true) |
| 120 | + register(model, :constraint, 2, constraint, autodiff=true) |
| 121 | + |
| 122 | + @variable(model, -10 ≤ x ≤ 10) |
| 123 | + @variable(model, -10 ≤ y ≤ 10) |
| 124 | + |
| 125 | + |
| 126 | + @NLobjective(model, Min, k(x, y)) |
| 127 | + @NLconstraint(model, constraint(x, y) == b) |
| 128 | + |
| 129 | + optimize!(model) |
| 130 | + |
| 131 | + (x = getvalue(x), y = getvalue(y)) |
| 132 | +end |
| 133 | + |
| 134 | +# ╔═╡ 964a440f-e0bf-4cab-a1e7-1976a03127d3 |
| 135 | +md""" |
| 136 | +b = $(b_slider) |
| 137 | +""" |
| 138 | + |
| 139 | +# ╔═╡ 3e87ef34-9d43-4c73-80fd-67c7e2441be8 |
| 140 | +gr() |
| 141 | + |
| 142 | +# ╔═╡ 46ae2fae-5db8-4a43-b31b-a9018a6ff9e2 |
| 143 | +begin |
| 144 | + r = -5:0.1:5 |
| 145 | + |
| 146 | + contour(r, r, k, leg=false) |
| 147 | + contour!(r, r, constraint, levels=[b], ratio=1, lw=3) |
| 148 | + scatter!([minx], [miny]) |
| 149 | +end |
| 150 | + |
| 151 | +# ╔═╡ 64d5dae1-39ee-4bf0-9e27-3f1d54b88a8d |
| 152 | +plotly() |
| 153 | + |
| 154 | +# ╔═╡ 2dd2aefe-7152-4773-b630-5edda439c431 |
| 155 | +surface(-5:0.1:5, -5:0.1:5, k, alpha=0.5) |
| 156 | + |
| 157 | +# ╔═╡ 34e39922-2781-4ef7-9310-b978d08ce727 |
| 158 | +md""" |
| 159 | +$y - x = b$ so $y = x + b$ |
| 160 | +
|
| 161 | +$z = x^2 + y^2 = x^2 + (x + b)^2$ |
| 162 | +
|
| 163 | +""" |
| 164 | + |
| 165 | +# ╔═╡ 9ab39d2f-7d0d-41ec-b4c2-68b27cd15172 |
| 166 | +begin |
| 167 | + xs = -5:0.1:5 |
| 168 | + ys = xs .+ b |
| 169 | +end |
| 170 | + |
| 171 | +# ╔═╡ 9a64168d-ece0-4264-9193-5cb1cdf000ed |
| 172 | +b_slider |
| 173 | + |
| 174 | +# ╔═╡ 3a7decbc-5d45-4f72-95a5-6795391e80a2 |
| 175 | +begin |
| 176 | + surface(-5:0.1:5, -5:0.1:5, k, alpha=0.5) |
| 177 | + |
| 178 | + plot!(xs, ys, k.(xs, ys), lw=3) |
| 179 | + |
| 180 | + scatter!([minx], [miny], [k(minx, miny)], zlim=(-10, 50), xlim=(-5, 5), ylim=(-5, 5)) |
| 181 | + |
| 182 | +end |
| 183 | + |
| 184 | +# ╔═╡ Cell order: |
| 185 | +# ╠═4ed28d02-f423-4f53-8010-644edacd5b74 |
| 186 | +# ╠═d719e2ed-ade8-4640-82fe-ffcafd204792 |
| 187 | +# ╟─d18eaa56-b8ad-11eb-1586-b15a611d773d |
| 188 | +# ╟─5bbd06bd-9191-4d06-84f3-95556afb9125 |
| 189 | +# ╟─3047f39a-a18a-4dea-9d2d-6523d7d0ec4f |
| 190 | +# ╟─a0aeb0c6-0980-4c6a-8736-8eccdf17e561 |
| 191 | +# ╠═f488fa22-8ff9-4ea1-84c1-deaf966520d1 |
| 192 | +# ╠═7d635168-8251-4ee9-8cc5-85ac5d810e21 |
| 193 | +# ╟─3a81aaa1-05c3-4ef4-ab7a-bd913a5dc85e |
| 194 | +# ╠═9b494263-7fb1-4893-aa15-33ad6b839773 |
| 195 | +# ╟─9934adb3-b704-467f-b189-e90fb0c6c1cb |
| 196 | +# ╟─a0c8165a-dd64-46b8-9419-fe3ef2cf39e1 |
| 197 | +# ╠═e9bff1db-a2ce-4821-a237-815793d9cbea |
| 198 | +# ╠═696bddde-f5a3-42e6-b5b6-dd25a3fe0782 |
| 199 | +# ╠═8dc1fe61-ed8d-4f5a-b200-6269cc89c142 |
| 200 | +# ╠═3ab8f4fe-3842-46ac-8411-37f509c7dfb5 |
| 201 | +# ╠═f58a62aa-f56b-4114-bfef-c57bdbc24e3b |
| 202 | +# ╟─964a440f-e0bf-4cab-a1e7-1976a03127d3 |
| 203 | +# ╠═3e87ef34-9d43-4c73-80fd-67c7e2441be8 |
| 204 | +# ╠═46ae2fae-5db8-4a43-b31b-a9018a6ff9e2 |
| 205 | +# ╠═64d5dae1-39ee-4bf0-9e27-3f1d54b88a8d |
| 206 | +# ╠═2dd2aefe-7152-4773-b630-5edda439c431 |
| 207 | +# ╟─34e39922-2781-4ef7-9310-b978d08ce727 |
| 208 | +# ╠═9ab39d2f-7d0d-41ec-b4c2-68b27cd15172 |
| 209 | +# ╠═9a64168d-ece0-4264-9193-5cb1cdf000ed |
| 210 | +# ╠═3a7decbc-5d45-4f72-95a5-6795391e80a2 |
0 commit comments