ls_learning#

  • Series: lecture-python.myst

  • File: lectures/ls_learning.md

  • Audit date: 2026-08-26

  • Corpus snapshot: e25fdf2345

  • Categories audited: writing, math, code, figures, references, links, admonitions (JAX out of scope)

  • Overall score: 7.8 / 10

  • Priority: LOW

Score breakdown#

Category

Score

One-line note

Writing

4.5/10

qe-writing-005 ×6; qe-writing-002 ×5; qe-writing-003 ×4, +1 more.

Math

5/10

qe-math-002 ×6; qe-math-014 (proposed) ×5; qe-math-009 ×3.

Code

8.5/10

qe-code-001 ×4.

JAX

out of scope

JAX rules target lecture-jax.

Figures

6.5/10

qe-fig-006 ×2; qe-fig-005 ×3; qe-fig-001 ×8.

References

10/10

no mechanical violations detected.

Links

10/10

no mechanical violations detected.

Admonitions

10/10

no mechanical violations detected.

Issues#

Critical#

None found.

High severity#

  • [qe-fig-001] — Do not set figure size unless necessary. Count: 8. Lines: 779, 871, 1010, 1193, 1340, 1476, 1522, 1609. Example: figsize=.

  • [qe-math-002] — Use \top for transpose notation. Count: 6. Lines: 314, 315, 342, 522, 538, 539. Example: apostrophe transpose D'.

  • [qe-math-014 (proposed)] (reviewer) — Braces {…} for events, parentheses (…) for sets. Count: 5. Lines: 395, 398, 492, 1506. Example: every probability of an event in the file is written with parentheses, and the file itself shows the correct contrast. 298 writes \(\mathbb{P}(\Omega_0) = 1\) for a named subset of the sample space - parentheses, correct. But 395 \(\mathbb{P}(\beta_t \to \hat\beta) = 0\), 398 \(\mathbb{P}(\beta_t \to \beta_f) = 0\), 492 \(\mathbb{P}(\beta_t \to \beta_f) + \mathbb{P}\bigl(\beta_{t_k} \to (D_1 \setminus D_2)\bigr) = 1\) (two sites on one line) and 1506 \(\mathbb{P}(\beta_t \to \hat\beta) = 0\) all take a convergence statement about a random sequence - a logical condition, not a named set - so each should be \(\mathbb{P}\{\beta_t \to \beta_f\}\). The 492 case is the clearest, because the second term’s argument already needs its own parentheses for the set difference \((D_1 \setminus D_2)\), so braces on the event would also disambiguate the display.

  • [qe-writing-002] (reviewer) — Keep writing clear, concise, and valuable. Count: 5. Lines: 548, 419, 432, 1106, 1412. Example: §“The projection facility” (419-477) is roughly half restatement: 421-427 repeats 411-417, 432-433 repeats 289-290 nearly word for word (“Ljung’s theorem requires the relevant sample path to return to a bounded region infinitely often” becomes “Ljung’s theorem requires the learning process and the relevant regressors to return to bounded regions with probability one”), 466-467 repeats 435-436, and 469-471 repeats 324. Then 548-554 spends four consecutive paragraphs saying that \(D_1\) and \(D_2\) will not be used - “\(D_1\) and \(D_2\) are therefore not economic primitives in the examples below” (550) and “the examples no longer need to display them” (554) are the same sentence twice - after a 37-word opening sentence at 548. 1106-1107 and 1109 are also a redundant pair (“The code simulates the autoregressive fundamental \(x_t\) and updates an OLS regression of \(y_t\) on \(x_{t-1}\)” / “The next cell simulates the autoregressive fundamental and the matching RLS update”). And 1412, “Yet it is a compelling rule”, has to reach back across a block quote for its subject.

  • [qe-writing-005] (reviewer) — Use bold for definitions, italic for emphasis. Count: 6. Lines: 220, 224, 160, 1399, 1459, 183. Example: the file bolds most of its definitions - least squares learning and self-referential (38), perceived law of motion (89), rational expectations equilibrium (125), recursive least squares (129), ordinary least squares (155), E-stability (412), projection facility (435) - and then italicises the rest of them. The small ODE (220) and the full ODE (224) are introduced in italic on the lines that define them and are then referred to by those names eleven times (174, 377, 594, 637, 1087, 1279, 1383, 1429, 1446, 1465, 1495); lagged information (160), contemporaneous-data (163), stochastic difference equation (192) and the boundedness conditions (287) are the same pattern. 1399 sets the whole term in bold and nests italic inside it, **Learning *about* an REE**, while the identical distinction is carried by plain italic at 1389-1390 and 1434. 183 double-marks with italic and quotation marks together, *"irrational"*. And 1459, 1465, 1469, 1519, 1591, 1606 use italic as a structural label (Part 1., Parts 2 and 3.), which is neither definition nor emphasis.

Medium severity#

  • [qe-code-001] (reviewer) — Follow PEP8 unless closer to mathematical notation. Count: 4. Lines: 664, 1323, 874, 1600. Example: flake8 is completely silent on this file - no spacing, line-length, naming or unused-name findings at all, which is a real result and matches the drafted 10/10 - so the remaining items are the ones a linter cannot see. 664 names the gain sequence a_seq and 680 then reads it into α_t, so one object gets a Roman and a Unicode spelling two lines apart in a file that otherwise uses Unicode Greek throughout (β, σ_u, λ, ρ, τ, ε_t); α_seq would settle it. 1323 passes lambda b: T_invest(b, **params) - b where b is the belief vector, while T_invest’s own signature two lines earlier (1306) binds b=0.95 as the discount factor and 1308 unpacks b1, b2 = β - so b is a belief on one line and a discount factor on the next, and b is separately the Bray feedback parameter (653) and the comprehension variable over the \(\beta\) grid (777, 866, 1008, 1191). 874 hard-codes range(min(30, 50)) where N_paths=50 was passed seventeen lines earlier (857), and 1531 and 1548 hard-code range(40) and range(50) against N_paths=100 and N_paths=50 at 1529 and 1546. 1600 guards with if abs(lv * ρ_ex) < 1 else float('inf') on a list where the largest product is \(0.99 \times 0.9 = 0.891\), so the else branch is unreachable.

  • [qe-fig-005] — Descriptive figure names for cross-referencing. Count: 3. Lines: 1471, 1521, 1608. Example: code-cell figure without mystnb figure metadata.

  • [qe-fig-006] — Lowercase axis labels. Count: 2. Lines: 1217, 1658. Example: axis label Accumulated step size $\\tau$.

  • [qe-math-009] (reviewer) — Choose simplicity in mathematical notation. Count: 3. Lines: 356, 360, 314. Example: three collisions that a change of letter would remove. (1) \(\mathcal{M}\) is the Jacobian (356, 411, 594, 646, 936, 1093) and \(M\) is the limiting second-moment matrix, \(E(z_{2t}z_{2t}^\top) = M_{z_2}(\beta) \equiv M\) (504, 526) - two different objects separated only by a calligraphic font - and the code then flattens the Jacobian to plain M at 1335 and prints “Jacobian M” at 814, 903, 1045 and 1228, so in the output the two are the same character. (2) \(T\) is the central operator (121, 629, 930, 1081) and the sample length: “simulate \(N = 200\) paths of length \(T = 500\)” (1448), repeated at 1508 and 1578, with the code carrying both as T_map/T_bray/T_bs/T_pv/T_invest and T_periods/T_sim/T_ex. (3) The primed set and constant names \(D'\) (314, 315, 342) and \(K'\) (522, 538, 539) are the only primes in a file that otherwise writes transpose as ^\top seventeen times; a subscript (\(D_0\), \(K_0\)) would be simpler, would not read as a transpose, and would avoid the ambiguity that made the scanner report all six of them as transposes (see scanner_doubts).

  • [qe-writing-003] (reviewer) — Maintain logical flow. Count: 4. Lines: 313, 187, 429, 577. Example: (1) 313 declares \(D_1 = D_2 = \mathbb{R}^{n_1 \times (n_2)^3}\), but \(D_1\) and \(D_2\) are sets in \((\beta, R)\)-space everywhere else - 441 “a constraint set \(D_1 \supset D_2\) in \((\beta, R)\)-space”, 448-451 projects the pair \((\tilde\beta_t, \tilde R_t)\), 537-538 defines them as \(\{(\beta, R) : |\beta - \beta_f| < K\}\) - and that space has dimension \(n_1 n_2 + (n_2)^2\), which is exactly the count 369-370 gives for the eigenvalues of \(h(\beta_f, R_f)\). \((n_2)^3\) matches nothing in the lecture. Worse, 393 then writes \(\hat\beta \in \mathrm{int}(D_2)\), treating \(D_2\) as a set of \(\beta\)’s, so the same symbol lives in two different spaces four sections apart. (2) 187-188 opens “Thus, any state variable that matters for the actual law of motion must appear among the regressors in the perceived law” - a genuine and important claim, but the paragraph immediately before it is the {note} at 176-185 about RLS not being derivable from Bayes’ rule, which does not imply it; the “Thus” points at nothing. (3) 429-430 (“Conversely, a strictly positive eigenvalue rules out convergence to the REE, while boundary cases with zero real parts are not covered”) re-states 383-384 and 406-409, dropped into the middle of the projection-facility section where the subject is boundedness. (4) 560 announces that “Each substantive learning example follows the same template”, 566 makes step 5 “Plot the RLS paths, the small ODE … and the drift”, and 574-575 promises “the simulation figure appears immediately after the model description” - but Example 1 (577-601), the control case the other four are meant to be compared against, has no code and no figure at all.

  • [qe-writing-007] (reviewer) — Use visual elements to enhance understanding. Count: 3. Lines: 85, 419, 577. Example: the lecture’s title concept - the loop in which beliefs generate the data that revise the beliefs - is presented only as prose and a partitioned block matrix (105-125). One diagram, \(\beta_t \to\) actions \(\to\) actual law of motion \(\to\) data \(\to\) OLS \(\to \beta_{t+1}\), would carry the whole of §“The self-referential structure”, and it is precisely what the rule’s reference example does for a comparable abstraction. Second, the projection facility (419-477, sixty lines and a cases display at 448) is a purely geometric device - an outer admissible set \(D_1\), an inner safe set \(D_2\), a retraction between them - and is neither drawn nor exercised: 550 says the sets “are not economic primitives in the examples below” and 554 that “the examples no longer need to display them”, so a reader gets sixty lines of theory with no picture and no simulation, in a lecture that already has the streamplot machinery at 1356-1357 to draw one. Third, Example 1 (577-601) has no figure, so the no-feedback benchmark that would calibrate the eye for the four figures that follow is missing.

Low severity#

None found.

Strengths#

  • The five-step template is stated once at 560-566 - write the economic equations, substitute the perceived law, read off \(T\), check \(\mathcal M = dT/d\beta - I\), plot the three panels - and Examples 2 to 5 then genuinely follow it, so §“Five examples” reads as one exercise repeated rather than five unrelated models.

  • Every scalar example gets the identical three-panel figure through one shared helper, plot_scalar_drift (716-738), so the Bray (745-815), unstable-Bray (839-904), Bray-Savin (977-1046) and present-value (1146-1229) panels are directly comparable rather than four separately styled plots.

  • The drift panel is unusually well built for the point it has to make: 722-725 shades the sign of \(T(\beta) - \beta\) and 727-734 draws seven arrows in the direction beliefs are revised, so the sign of a Jacobian eigenvalue becomes something a reader sees - and it is what makes the counterexample at 822-904 legible without any new algebra.

  • The counterexample is built by changing one number and saying so: 846 sets b_unstable = 1.4 and reuses simulate_rls_scalar unchanged (855), while 830-833 gives the mechanism in two sentences - “If agents start with a forecast that is too high, the market outcome induced by that forecast is higher still, so least squares raises the forecast. The same logic works in reverse below the REE”.

  • Every formal result is a labelled prf: block that is actually referenced where it is used: the seven assumptions (255-322) at 324, 326, 335-337, 389-390 and 482-484; both propositions (332, 386) at 349, 380 and 1506; both corollaries (479, 516) at 498, 548 and 597.

  • Each simulation cell prints the diagnostic that the surrounding prose claims - Jacobian M = b - 1 = -0.4000  (< 0: E-stable) at 814, and the same at 903, 1045 and 1228, plus the numerically differentiated Jacobian and its eigenvalues at 1326-1338 - so the stability claims are confirmed in the output rather than asserted.

  • 176-185 is the right admonition in the right place: a {note} recording that RLS cannot be derived from Bayes’ rule because beliefs shift the equilibrium which shifts the data, placed immediately after the timing discussion and before the ODE argument that depends on it.

  • The one genuinely unfamiliar device is explained and then implemented exactly as explained: 208-210 defines accumulated-gain time \(\tau_t = \sum_{s=1}^t \alpha_s / s \approx \log t\), 1104 says which panel switches to it, solve_ode_calendar (695-713) evaluates the ODE at precisely np.cumsum(a_seq / np.arange(1, T+1)), and the axis is relabelled 'Accumulated step size $\tau$' at 1217 where the switch happens.

  • The examples are ordered by feedback strength and then dimension - none (577), scalar below one (603), the same scalar above one (822), a conditional slope (906), a forward-looking discount (1053), and finally a two-dimensional nonlinear map with a phase portrait (1238-1375) - so each one adds a single ingredient.

  • Five of the seven figure cells carry mystnb caption and name metadata (745-751, 839-845, 977-983, 1146-1152, 1299-1305), which is why qe-fig-005 reports only the three exercise-solution cells.