money_inflation#

  • Series: lecture-python-intro

  • File: lectures/money_inflation.md

  • Audit date: 2026-08-26

  • Corpus snapshot: a12d17c0ef

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

  • Overall score: 8.2 / 10

  • Priority: LOW

Score breakdown#

Category

Score

One-line note

Writing

4.5/10

qe-writing-005 ×3; qe-writing-003 ×4; qe-writing-002 ×4, +4 more.

Math

9.5/10

qe-math-009 ×3.

Code

7.5/10

qe-code-001 ×5.

JAX

out of scope

JAX rules target lecture-jax.

Figures

6/10

qe-fig-005 ×3; qe-fig-004 ×3; qe-fig-008 ×8, +1 more.

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-code-001] (reviewer) — Follow PEP8 unless closer to mathematical notation. Count: 5. Lines: 263, 272, 291, 512, 1068. Example: 263 places from collections import namedtuple after an executable statement (plt.rcParams['figure.dpi'] = 300 at 262), where PEP8 asks for all imports at the top of the block. Two continuation lines are under-indented against their opening delimiter: MoneySupplyModel = namedtuple("MoneySupplyModel", opens its parenthesis at column 29 and continues at column 24 (272-274), and line_params = {'lw': 1.5, opens its brace at column 14 and continues at column 14 (512-514), one short of the visual indent. 291 mixes operator spacing inside one expression and leaves a stray double space - return -γ2/R + (γ1 + γ2)  - γ1 * R, with / unspaced and * spaced - and 495-501 does the same (γ1 - γ2/R0 next to γ1/γ2 - (1 / γ2) * b_values[0]). Five lines run past 79 characters (1049, 1068, 1135, 1140, 1142), 1068 at 96. And LaTeX in matplotlib labels is written with doubled backslashes in ordinary strings at 1048, 1051, 1126, 1211 and 1212 while 518 correctly uses a raw string for the same job.

  • [qe-fig-008] — Use lw=2 for line charts. Count: 8. Lines: 329, 905, 908, 912, 1048, 1121, 1122, 1209. Example: plot() without lw=.

  • [qe-writing-008] — Remove excessive whitespace between words. Count: 89. Lines: 35, 36, 43, 50, 54, 60, 78, 80, 81, 96, …. Example: 3 spaces.

Medium severity#

  • [qe-fig-001] — Do not set figure size unless necessary. Count: 4. Lines: 262, 328, 525, 889. Example: style override.

  • [qe-fig-004] — Caption formatting conventions. Count: 3. Lines: 313, 557, 930. Example: caption of 32 words.

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

  • [qe-math-009] (reviewer) — Choose simplicity in mathematical notation. Count: 3. Lines: 223, 807, 854. Example: 223 introduces \(\overline R\) as the number 1 - “\(\bar R \in [\frac{\gamma_2}{\gamma_1}, 1] \equiv [\underline R, \overline R]\)” - while \(\bar R\) is the steady-state rate of return that ranges over that interval, and \bar R and \overline R render identically. So the constraint at 226-229 reads on the page as \(R_t \in [\underline R, \bar R]\), with the same overbarred \(R\) as both the variable and the upper endpoint. Second, the eigendecomposition section carries four notations for elements of two matrices in fifty lines: \(Q_{ij}\) for an element of \(Q\) (688-698), \(Q^{ij}\) for an element of \(Q^{-1}\) (816-820), \(Q^{\{2\}}\) for the second row of \(Q^{-1}\) (807-810), and then Q^{-1}_{11} at 854 and 877 for the scalar reciprocal \(1/Q_{11}\) - which under the file’s own \(Q^{ij}\) convention reads as element \((1,1)\) of \(Q^{-1}\), a different number, and which 698 and 861 write the other way round as \(Q_{11}^{-1}\). A superscript that means “of the inverse matrix” cannot coexist with a superscript that means “reciprocal”. Third, {\rm max} appears as a subscript at 235, 241, 1008, 1013-1014, 1033 and 1049 where \mathrm{max} or _{\max} is the LaTeX form.

  • [qe-writing-001] — Use one sentence per paragraph. Count: 1. Lines: 410. Example: 2 sentences in one paragraph.

  • [qe-writing-002] (reviewer) — Keep writing clear, concise, and valuable. Count: 4. Lines: 18, 352, 951, 962. Example: the construction “this lecture {doc}`X`” is used seven times to mean that other lecture - “the model in this lecture {doc}`cagan_ree`” (18), “studied in this lecture {doc}`eigen_I`” (43), “this lecture {doc}`money_inflation_nonlinear`” (52 and again in the note at 968), “this lecture {doc}`laffer_adaptive`” (54), “this lecture {doc}`unpleasant`” (62) - while the reader is inside “this lecture”, so every one of them momentarily points at the wrong document. 951-969 restates the Overview: the two bullets at 955-956 are copied word for word from 47-48, and the {note} at 967-969 is line 52 verbatim. The two computation strategies are each described twice at full length - “### Method 1” (360-386) and then “## Computation method 1” (441-458), “### Method 2” (408-439) and then “## Computation method 2” (574-643) - with the same equations restated and the \(\gamma_0\) typo introduced only in the second pass. 352 is an orphan: “Now let’s compute the maximum steady-state amount of seigniorage … and the state-state rate of return on money that attains it” is followed immediately by a new section heading, and the computation it announces was already done at 300-302. And 962 is a 78-word sentence with two nested quoted terms and two {numref} references.

  • [qe-writing-003] (reviewer) — Maintain logical flow. Count: 4. Lines: 455, 665, 760, 867. Example: 665-667 and 772 contradict each other, and the code inherits the contradiction. 665-667 states \(\Lambda = \mathrm{diag}({R_\ell}^{-1}, {R_u}^{-1})\), so with \(R_\ell < R_u\) (308-310) the first diagonal entry is the larger eigenvalue. 767-780 then argues that unless \(y^*_0 = [y^*_{1,0}, 0]^\top\) - i.e. unless the second component is killed - the path grows at \({R_\ell}^{-1}\), and concludes there is a unique \(y_0\) “for which both components forever grow at the lower rate \({R_u}^{-1}\)”. Killing the second component leaves the first mode, which under 665-667 is \({R_\ell}^{-1}\), not \({R_u}^{-1}\); so one of the two statements has the eigenvalues the wrong way round. The code then relies on opposite orderings of one np.linalg.eig call (672): 678-679 reads R_l = 1 / Λ[0], which needs \(\Lambda_0\) to be the larger eigenvalue, while 867 reads p0_bar = (Q[1, 0]/Q[0, 0]) * msm.M0, taking the first column of \(Q\), which needs \(\Lambda_0\) to be the smaller one for p0_bar to be the low-inflation selection. Exactly one of the two is wrong for any given LAPACK ordering, and neither is guarded. The lecture’s own data says which: p0s = [p0_bar, 2.34, 2.5, 3, 4, 7, 30, 100_000] at 940 is an increasing list, so p0_bar is expected just under 2.34, matching the Method 1 value msm.M0 / (msm.γ1 - msm.g - msm.γ2/msm.R_u) at 296 - which makes 665-667 and 678-682 the pair stated backwards. 760 is a plainer slip in the same derivation: {eq}`eq:stardynamics` writes \(y^*_{t+1} = \Lambda^t y^*_t\) where the recursion is \(y^*_{t+1} = \Lambda y^*_t\) (the \(\Lambda^t\) belongs in \(y^*_t = \Lambda^t y^*_0\)). And 455 writes \(b_0 = \gamma_1 - \gamma_0 R_0^{-1}\) using a parameter \(\gamma_0\) that does not exist in the model - 362 gives the same formula correctly as \(b_0 = \gamma_1 - \gamma_2/R_0\).

  • [qe-writing-004] — Avoid unnecessary capitalization in narrative text. Count: 1. Lines: 1180. Example: mid-sentence ‘Method’.

  • [qe-writing-005] (reviewer) — Use bold for definitions, italic for emphasis. Count: 3. Lines: 47, 476, 956. Example: three terms are bolded repeatedly instead of once at their definition. inflation tax is bold in the Overview at 47, before it is defined, and bold again in the recap at 955, while the actual definition - “the quantity \(1 - R_t\) can be interpreted as an inflation tax rate” - is at 473. Laffer curve is bold three times (48, 476, 956) and explained at 478-484. initial condition is bold at 395 and again at 421. The pattern is that the Overview and the recap bold the vocabulary they preview, so by the time the reader reaches the definition the bold has stopped signalling it. The rest of the file is disciplined - equilibrium (117), real balances (135), steady state and invariant (171-173), seigniorage (212), base (483), state and jump (795), incomplete (974) are each bolded exactly once at the point of definition, and italic is used only for genuine emphasis (dynamic 35, sequences 36, reduced / higher 50, ratios 177 and 194, determined 435, don’t 799, complete / selecting 982).

  • [qe-writing-007] (reviewer) — Use visual elements to enhance understanding. Count: 3. Lines: 330, 535, 905. Example: the two time-path figures cannot show what the lecture asks the reader to read off them. draw_paths (523-550) and draw_iterations (887-927) plot every path with **line_params and no label, and neither calls ax.legend(), so {numref}`R0_path` renders ten curves and {numref}`p0_path` eight with nothing to identify them - even though 555 says “each line below shows a path associated with a different \(R_0\)” and 940 lists eight specific \(p_0\) values of which the first, p0_bar, is the unique non-perverse one the whole section exists to isolate. Second, {numref}`infl_tax` (313-336) is the figure 958 and 962 send the reader back to twice in order to see the two stationary rates and the perverse comparative static, and it marks neither: it draws the seigniorage curve and a horizontal line at \(g\) and stops, with no vertical lines at \(R_\ell\), \(R_u\) or \(\bar R_{\max}\) - although annotate_graph (516-521) already does exactly that job for the other two figures and could be reused. Third, the caption at 317 is a 32-word sentence describing the figure element by element (“solid blue curve”, “dotted red line”) and it is wrong about one of them: 330 draws the deficit line with linestyle='--', which is dashed, not dotted.

Low severity#

None found.

Strengths#

  • The lecture computes the same object two independent ways and then proves the two agree. Method 1 indexes the continuum of equilibria by \(R_0\) (360-386), Method 2 by \(p_0\) through the eigendecomposition of \(H\) (574-861), 439 promises that the two selections are “intimately tied”, and mi_ex3 part c (1180-1181, 1219-1222) closes the loop by recovering \(\bar p_0\) from {eq}`eq:p0fromR0` - which is a far stronger check on a numerical method than any single implementation could be.

  • The three {prf:remark} blocks after Method 1 (388-406) isolate the three things a reader needs and would otherwise miss - that the method is indirect, that equilibria are not unique, and that the continuum is indexed by the choice of \(R_0\) from a stated interval - one sentence each, out of the flow of the derivation.

  • The {note} at 478-484 explains the Laffer curve from scratch (hump shape, two rates raising the same revenue, the base shrinking as the rate rises) before the term is asked to carry any weight, which is exactly the right move for an introductory series where the reader may be meeting it for the first time.

  • The lecture states its own incompleteness and then acts on it: 972-993 declares the model incomplete because a continuum of paths satisfies every equilibrium condition, says precisely what has to be chosen to complete it, gives the plausibility ground for the choice, and names both where the choice is used ({doc}`unpleasant`) and where it is defended differently ({doc}`laffer_adaptive`, {cite}`bruno1990seigniorage`).

  • The state/jump distinction is introduced only after the algebra forces it: 787-796 shows that \(Q^{-1}y_0\) must have a zero component, observes that \(m_0\) is given so “\(p_0\) has to do all the adjusting”, and only then names the informal vocabulary - so jump variable arrives as a description of something the reader has just watched happen.

  • 831-864 does not assert that the two formulas for \(p_0\) agree; it derives it, using \(Q^{-1}Q = I\) to turn \(-(Q^{22})^{-1}Q^{21}\) into \(Q_{21}Q_{11}^{-1}\) in four steps, and 866-869 then evaluates it.

  • The three exercises each check a different claim of the body numerically rather than drilling the code: the Laffer peak and the non-existence of a steady state beyond it (997-1078, with the discriminant computed explicitly at 1065), the comparative statics of both roots in \(g\) against analytically stated boundary conditions (1083-1153), and the quantity-theory proportionality of \(\bar p_0\) in \(m_0\) (1158-1230).

  • annotate_graph (516-521) is factored out once and reused on both multi-path figures, drawing \(R_u\), \(R_\ell\) and \(\gamma_2/\gamma_1\) as labelled reference lines placed outside the axes - the figures’ one real strength, and the reason the missing legends stand out.