Akshay Agrawal commited on
Commit
9e55022
·
1 Parent(s): d727016

optimization course start

Browse files
optimization/01_least_squares.py ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # /// script
2
+ # requires-python = ">=3.11"
3
+ # dependencies = [
4
+ # "cvxpy==1.6.0",
5
+ # "marimo",
6
+ # "numpy==2.2.2",
7
+ # ]
8
+ # ///
9
+
10
+ import marimo
11
+
12
+ __generated_with = "0.11.0"
13
+ app = marimo.App()
14
+
15
+
16
+ @app.cell(hide_code=True)
17
+ def _(mo):
18
+ mo.md(
19
+ r"""
20
+ # Least squares
21
+
22
+ In a least-squares problem, we have measurements $A \in \mathcal{R}^{m \times
23
+ n}$ (i.e., $m$ rows and $n$ columns) and $b \in \mathcal{R}^m$. We seek a vector
24
+ $x \in \mathcal{R}^{n}$ such that $Ax$ is close to $b$. The matrices $A$ and $b$ are problem data or constants, and $x$ is the variable we are solving for.
25
+
26
+ Closeness is defined as the sum of the squared differences:
27
+
28
+ \[ \sum_{i=1}^m (a_i^Tx - b_i)^2, \]
29
+
30
+ also known as the $\ell_2$-norm squared, $\|Ax - b\|_2^2$.
31
+
32
+ For example, we might have a dataset of $m$ users, each represented by $n$ features. Each row $a_i^T$ of $A$ is the feature vector for user $i$, while the corresponding entry $b_i$ of $b$ is the measurement we want to predict from $a_i^T$, such as ad spending. The prediction for user $i$ is given by $a_i^Tx$.
33
+
34
+ We find the optimal value of $x$ by solving the optimization problem
35
+
36
+ \[
37
+ \begin{array}{ll}
38
+ \text{minimize} & \|Ax - b\|_2^2.
39
+ \end{array}
40
+ \]
41
+
42
+ Let $x^\star$ denote the optimal $x$. The quantity $r = Ax^\star - b$ is known as the residual. If $\|r\|_2 = 0$, we have a perfect fit.
43
+ """
44
+ )
45
+ return
46
+
47
+
48
+ @app.cell(hide_code=True)
49
+ def _(mo):
50
+ mo.md(
51
+ r"""
52
+ ## Example
53
+
54
+ In this example, we use the Python library [CVXPY](https://github.com/cvxpy/cvxpy) to construct and solve a least-squares problems.
55
+ """
56
+ )
57
+ return
58
+
59
+
60
+ @app.cell
61
+ def _():
62
+ import cvxpy as cp
63
+ import numpy as np
64
+ return cp, np
65
+
66
+
67
+ @app.cell
68
+ def _():
69
+ m = 20
70
+ n = 15
71
+ return m, n
72
+
73
+
74
+ @app.cell
75
+ def _(m, n, np):
76
+ np.random.seed(0)
77
+ A = np.random.randn(m, n)
78
+ b = np.random.randn(m)
79
+ return A, b
80
+
81
+
82
+ @app.cell
83
+ def _(A, b, cp, n):
84
+ x = cp.Variable(n)
85
+ objective = cp.sum_squares(A @ x - b)
86
+ problem = cp.Problem(cp.Minimize(objective))
87
+ optimal_value = problem.solve()
88
+ return objective, optimal_value, problem, x
89
+
90
+
91
+ @app.cell
92
+ def _(A, b, cp, mo, optimal_value, x):
93
+ mo.md(
94
+ f"""
95
+ - The optimal value is **{optimal_value:.04f}**.
96
+ - The optimal value of $x$ is {mo.as_html(list(x.value))}
97
+ - The norm of the residual is **{cp.norm(A @ x - b, p=2).value:0.4f}**
98
+ """
99
+ )
100
+ return
101
+
102
+
103
+ @app.cell(hide_code=True)
104
+ def _(mo):
105
+ mo.md(
106
+ r"""
107
+ ## Further reading
108
+
109
+ For a primer on least squares, with many real-world examples, check out the free book
110
+ [Vectors, Matrices, and Least Squares](https://web.stanford.edu/~boyd/vmls/), which is used for undergraduate linear algebra education at Stanford.
111
+ """
112
+ )
113
+ return
114
+
115
+
116
+ @app.cell
117
+ def _():
118
+ import marimo as mo
119
+ return (mo,)
120
+
121
+
122
+ if __name__ == "__main__":
123
+ app.run()
optimization/02_linear_program.py ADDED
@@ -0,0 +1,269 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # /// script
2
+ # requires-python = ">=3.13"
3
+ # dependencies = [
4
+ # "cvxpy==1.6.0",
5
+ # "marimo",
6
+ # "matplotlib==3.10.0",
7
+ # "numpy==2.2.2",
8
+ # "wigglystuff==0.1.9",
9
+ # ]
10
+ # ///
11
+
12
+ import marimo
13
+
14
+ __generated_with = "0.11.0"
15
+ app = marimo.App()
16
+
17
+
18
+ @app.cell(hide_code=True)
19
+ def _(mo):
20
+ mo.md(
21
+ r"""
22
+ # Linear program
23
+
24
+ A linear program is an optimization problem with a linear objective and affine
25
+ inequality constraints. A common standard form is the following:
26
+
27
+ \[
28
+ \begin{array}{ll}
29
+ \text{minimize} & c^Tx \\
30
+ \text{subject to} & Ax \leq b.
31
+ \end{array}
32
+ \]
33
+
34
+ Here $A \in \mathcal{R}^{m \times n}$, $b \in \mathcal{R}^m$, and $c \in \mathcal{R}^n$ are problem data and $x \in \mathcal{R}^{n}$ is the optimization variable. The inequality constraint $Ax \leq b$ is elementwise.
35
+
36
+ For example, we might have $n$ different products, each constructed out of $m$ components. Each entry $A_{ij}$ is the amount of component $i$ required to build one unit of product $j$. Each entry $b_i$ is the total amount of component $i$ available. We lose $c_j$ for each unit of product $j$ ($c_j < 0$ indicates profit). Our goal then is to choose how many units of each product $j$ to make, $x_j$, in order to minimize loss without exceeding our budget for any component.
37
+
38
+ In addition to a solution $x^\star$, we obtain a dual solution $\lambda^\star$. A positive entry $\lambda^\star_i$ indicates that the constraint $a_i^Tx \leq b_i$ holds with equality for $x^\star$ and suggests that changing $b_i$ would change the optimal value.
39
+
40
+ **Why linear programming?** Linear programming is a way to achieve an optimal outcome, such as maximum utility or lowest cost, subject to a linear objective function and affine constraints. Developed in the 20th century, linear programming is widely used today to solve problems in resource allocation, scheduling, transportation, and more. The discovery of polynomial-time algorithms to solve linear programs was of tremendous worldwide importance and entered the public discourse, even making the front page of the New York Times.
41
+
42
+ In the late 20th and early 21st century, researchers generalized linear programming to a much wider class of problems called convex optimization problems. Nearly all convex optimization problems can be solved efficiently and reliably, and even more difficult problems are readily solved by a sequence of convex optimization problems. Today, convex optimization is used to fit machine learning models, land rockets in real-time at SpaceX, plan trajectories for self-driving cars at Waymo, execute many billions of dollars of financial trades a day, and much more.
43
+
44
+ This marimo learn course uses CVXPY, a modeling language for convex optimization problems developed originally at Stanford, to construct and solve convex programs.
45
+ """
46
+ )
47
+ return
48
+
49
+
50
+ @app.cell(hide_code=True)
51
+ def _(mo):
52
+ mo.md(
53
+ f"""
54
+ {mo.image("https://www.debugmind.com/wp-content/uploads/2020/01/spacex-1.jpg")}
55
+ _SpaceX solves convex optimization problems onboard to land its rockets, using CVXGEN, a code generator for quadratic programming developed at Stephen Boyd’s Stanford lab. Photo by SpaceX, licensed CC BY-NC 2.0._
56
+ """
57
+ )
58
+ return
59
+
60
+
61
+ @app.cell(hide_code=True)
62
+ def _(mo):
63
+ mo.md(
64
+ r"""
65
+ ## Example
66
+
67
+ Here we use CVXPY to construct and solve a linear program.
68
+ """
69
+ )
70
+ return
71
+
72
+
73
+ @app.cell
74
+ def _():
75
+ import cvxpy as cp
76
+ import numpy as np
77
+ return cp, np
78
+
79
+
80
+ @app.cell(hide_code=True)
81
+ def _(np):
82
+ A = np.array(
83
+ [
84
+ [0.76103773, 0.12167502],
85
+ [0.44386323, 0.33367433],
86
+ [1.49407907, -0.20515826],
87
+ [0.3130677, -0.85409574],
88
+ [-2.55298982, 0.6536186],
89
+ [0.8644362, -0.74216502],
90
+ [2.26975462, -1.45436567],
91
+ [0.04575852, -0.18718385],
92
+ [1.53277921, 1.46935877],
93
+ [0.15494743, 0.37816252],
94
+ ]
95
+ )
96
+
97
+ b = np.array(
98
+ [
99
+ 2.05062369,
100
+ 0.94934659,
101
+ 0.89559424,
102
+ 1.04389978,
103
+ 2.45035643,
104
+ -0.95479445,
105
+ -0.83801349,
106
+ -0.26562529,
107
+ 2.35763652,
108
+ 0.98286942,
109
+ ]
110
+ )
111
+ return A, b
112
+
113
+
114
+ @app.cell(hide_code=True)
115
+ def _(mo):
116
+ mo.md(r"""We've randomly generated problem data $A$ and $B$. The vector for $c$ is shown below. Try playing with the value of $c$ by dragging the components, and see how the level curves change in the visualization below.""")
117
+ return
118
+
119
+
120
+ @app.cell
121
+ def _(mo, np):
122
+ from wigglystuff import Matrix
123
+
124
+ c_widget = mo.ui.anywidget(Matrix(matrix=np.array([[0.1, -0.2]]), step=0.01))
125
+ c_widget
126
+ return Matrix, c_widget
127
+
128
+
129
+ @app.cell
130
+ def _(c_widget, np):
131
+ c = np.array(c_widget.value["matrix"][0])
132
+ return (c,)
133
+
134
+
135
+ @app.cell
136
+ def _(A, b, c, cp):
137
+ x = cp.Variable(A.shape[1])
138
+ prob = cp.Problem(cp.Minimize(c.T @ x), [A @ x <= b])
139
+ _ = prob.solve()
140
+ x_star = x.value
141
+ return prob, x, x_star
142
+
143
+
144
+ @app.cell(hide_code=True)
145
+ def _(mo):
146
+ mo.md(r"""Below, we plot the feasible region of the problem — the intersection of the inequalities — and the level curves of the objective function. The optimal value $x^\star$ is the point farthest in the feasible region in the direction $-c$.""")
147
+ return
148
+
149
+
150
+ @app.cell(hide_code=True)
151
+ def _(A, b, c, make_plot, x_star):
152
+ make_plot(A, b, c, x_star)
153
+ return
154
+
155
+
156
+ @app.cell(hide_code=True)
157
+ def _(np):
158
+ import matplotlib.pyplot as plt
159
+
160
+
161
+ def make_plot(A, b, c, x_star):
162
+ # Define a grid over a region that covers the feasible set.
163
+ # You might need to adjust these limits.
164
+ x_vals = np.linspace(-1, 1, 400)
165
+ y_vals = np.linspace(1, 3, 400)
166
+ X, Y = np.meshgrid(x_vals, y_vals)
167
+
168
+ # Flatten the grid points into an (N,2) array.
169
+ points = np.vstack([X.ravel(), Y.ravel()]).T
170
+
171
+ # For each point, check if it satisfies all the constraints: A @ x <= b.
172
+ # A dot product: shape of A @ x.T will be (m, N). We add a little tolerance.
173
+ feasible = np.all(np.dot(A, points.T) <= (b[:, None] + 1e-8), axis=0)
174
+ feasible = feasible.reshape(X.shape)
175
+
176
+ # Create the figure with a white background.
177
+ fig = plt.figure(figsize=(8, 6), facecolor="white")
178
+ ax = fig.add_subplot(111)
179
+ ax.set_facecolor("white")
180
+
181
+ # Plot the feasible region.
182
+ # Since "feasible" is a boolean array (False=0, True=1), we set contour levels so that
183
+ # the region with value 1 (feasible) gets filled.
184
+ ax.contourf(
185
+ X,
186
+ Y,
187
+ feasible.astype(float),
188
+ levels=[-0.5, 0.5, 1.5],
189
+ colors=["white", "gray"],
190
+ alpha=0.5,
191
+ )
192
+
193
+ # Plot level curves of the objective function c^T x.
194
+ # Compute c^T x over the grid:
195
+ Z = c[0] * X + c[1] * Y
196
+ # Choose several levels for the iso-cost lines.
197
+ levels = np.linspace(np.min(Z), np.max(Z), 20)
198
+ contours = ax.contour(
199
+ X, Y, Z, levels=levels, colors="gray", linestyles="--", linewidths=1
200
+ )
201
+
202
+ # Draw the vector -c as an arrow starting at x_star.
203
+ norm_c = np.linalg.norm(c)
204
+ if norm_c > 0:
205
+ head_width = norm_c * 0.1
206
+ head_length = norm_c * 0.1
207
+ # The arrow starts at x_star and points in the -c direction.
208
+ ax.arrow(
209
+ x_star[0],
210
+ x_star[1],
211
+ -c[0],
212
+ -c[1],
213
+ head_width=head_width,
214
+ head_length=head_length,
215
+ fc="black",
216
+ ec="black",
217
+ length_includes_head=True,
218
+ )
219
+ # Label the arrow near its tip.
220
+ ax.text(
221
+ x_star[0] - c[0] * 1.05,
222
+ x_star[1] - c[1] * 1.05,
223
+ r"$-c$",
224
+ color="black",
225
+ fontsize=12,
226
+ )
227
+
228
+ # Optionally, mark and label the point x_star.
229
+ ax.plot(x_star[0], x_star[1], "ko", markersize=5)
230
+ ax.text(
231
+ x_star[0],
232
+ x_star[1],
233
+ r"$\mathbf{x}^\star$",
234
+ color="black",
235
+ fontsize=12,
236
+ verticalalignment="bottom",
237
+ horizontalalignment="right",
238
+ )
239
+ # Label the axes and set title.
240
+ ax.set_xlabel("$x_1$")
241
+ ax.set_ylabel("$x_2$")
242
+ ax.set_title("Feasible Region and Level Curves of $c^Tx$")
243
+ ax.set_xlim(np.min(x_vals), np.max(x_vals))
244
+ ax.set_ylim(np.min(y_vals), np.max(y_vals))
245
+ return ax
246
+ return make_plot, plt
247
+
248
+
249
+ @app.cell(hide_code=True)
250
+ def _(mo, prob, x):
251
+ mo.md(
252
+ f"""
253
+ The optimal value is {prob.value:.04f}.
254
+
255
+ A solution $x$ is {mo.as_html(list(x.value))}
256
+ A dual solution is is {mo.as_html(list(prob.constraints[0].dual_value))}
257
+ """
258
+ )
259
+ return
260
+
261
+
262
+ @app.cell
263
+ def _():
264
+ import marimo as mo
265
+ return (mo,)
266
+
267
+
268
+ if __name__ == "__main__":
269
+ app.run()
optimization/README.md ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Learn optimization
2
+
3
+ 🚧 _This collection is a work in progress. Check back later for new notebooks!_
4
+
5
+ This collection of marimo notebooks teaches you the basics of mathematical
6
+ optimization.
7
+
8
+ After working through these notebooks, you'll understand how to create
9
+ and solve optimization problems using the Python library
10
+ [CVXPY](https://github.com/cvxpy/cvxpy), as well as how to apply what you've
11
+ learned to real-world problems such as portfolio allocation in finance,
12
+ resource allocation, and more.
13
+
14
+ ![SpaceX](https://www.debugmind.com/wp-content/uploads/2020/01/spacex-1.jpg)
15
+
16
+ _SpaceX uses SpaceX solves convex optimization problems onboard to land its rockets, using CVXGEN, a code generator for quadratic programming developed at Stephen Boyd’s Stanford lab. Photo by SpaceX, licensed CC BY-NC 2.0._
17
+
18
+ **Running notebooks.** To run a notebook locally, use
19
+
20
+ ```bash
21
+ uvx marimo edit <URL>
22
+ ```
23
+
24
+ For example, run the least-squares tutorial with
25
+
26
+ ```bash
27
+ uvx marimo edit https://github.com/marimo-team/learn/blob/main/optimization/01_least_squares.py
28
+ ```
29
+
30
+ You can also open notebooks in our online playground by appending `marimo.app/`
31
+ to a notebook's URL: [marimo.app/github.com/marimo-team/learn/blob/main/optimization/01_least_squares.py](https://marimo.app/https://github.com/marimo-team/learn/blob/main/optimization/01_least_squares.py).