money_inflation_nonlinear#
Series: lecture-python-intro
File:
lectures/money_inflation_nonlinear.mdAudit date: 2026-08-26
Corpus snapshot:
a12d17c0efCategories audited: writing, math, code, figures, references, links, admonitions (JAX out of scope)
Overall score: 7.9 / 10
Priority: HIGH
Score breakdown#
Category |
Score |
One-line note |
|---|---|---|
Writing |
3/10 |
|
Math |
9.5/10 |
|
Code |
6.5/10 |
|
JAX |
out of scope |
JAX rules target |
Figures |
6.5/10 |
|
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: 128, 273, 385, 500, 666. Example: 273 assigns a lambda to a name -
eq_g = lambda x: np.exp(-model.α * x) - np.exp(-(1 + model.α) * x)- where PEP8 asks for adef, and the file already hascompute_seign(175) computing exactly that expression, so the lambda is both a style violation and a duplicate. Three continuation lines miss their visual indent:CaganLaffer = namedtuple('CaganLaffer',opens its parenthesis at column 24 and continues at column 24 (128-132, one short),line_params = {'lw': 1.5,opens its brace at column 14 and continues at 14 (408-410, one short), andax.text(at 384 opens at column 19 and continues at column 25 (five past). 132 also leaves a space before the closing bracket,"g" ]). 500 runs to 90 characters. And the exercise cells pad before=to align blocks of assignments at 666-667, 692-694 and 722-724 (x_star_α =,g_max_α =,m_temp =,p0_l_α =), which PEP8 lists under Pet Peeves. One item that is not spacing: 492 importsminimize_scalarin the middle of the lecture when 115-120 is the import cell.[qe-fig-008] — Use lw=2 for line charts. Count: 9. Lines: 188, 362, 365, 368, 371, 509, 585, 586, 668. Example: plot() without lw=.
[qe-writing-006] — Capitalize lecture titles properly. Count: 6. Lines: 48, 78, 162, 206, 278, 339. Example: H2 Title Case: ‘The Model’ (Model).
[qe-writing-008] — Remove excessive whitespace between words. Count: 37. Lines: 20, 27, 29, 33, 38, 40, 46, 82, 106, 108, …. Example: 2 spaces.
Medium severity#
[qe-code-002] — Use Unicode symbols for Greek letters in code. Count: 3. Lines: 664, 691, 717. Example: spelled-out
alpha.[qe-fig-004] — Caption formatting conventions. Count: 2. Lines: 166, 394. Example: caption of 15 words.
[qe-fig-005] — Descriptive figure names for cross-referencing. Count: 4. Lines: 504, 568, 659, 713. Example: code-cell figure without mystnb figure metadata.
[qe-math-009] (reviewer) — Choose simplicity in mathematical notation. Count: 3. Lines: 85, 451, 464. Example: the steady-state inflation rate carries four names and the lecture never says they are the same object. 80 announces “the two prospective limiting values for \(\overline \pi\)”; 85-88 introduces \(x\) as “a common rate of growth of logarithms of the money supply and price level” and states the defining equation
{eq}`eq:steadypi`in \(x\); 155-157 solves it and stores the answers as \(\pi_l\) and \(\pi_u\) (labelled that way on the figure at 170 and 190); and the exercises add \(x^*\) (457) whilemni_ex2reverts to \(\pi_l(g), \pi_u(g)\) (553-554) with its own solution labelling the axis “steady-state inflation rate \(x\)” (516, 673). Not one sentence connects \(x\) to \(\overline\pi\) to \(\pi_l\). The same function is spelled three ways too:\exp(-\alpha x) - \exp(-(1+\alpha)x)at 93 and 99, \(L(x) = e^{-\alpha x} - e^{-(1+\alpha)x}\) at 451, andcompute_seignin code at 175 - so the reader matching the exercise’s \(L\) against the body’s display has to notice they are the same. And the lower/upper distinction is marked two different ways in adjacent paragraphs: \(\underline p(m_0)\) and \(\overline p(m_0)\) by under- and overline (208-213), \(\pi_l\) and \(\pi_u\) by subscript.{\rm max}for a subscript recurs at 464, 468, 511, 553, 558, 609, 641 and 669 where\mathrm{max}or_{\max}is the LaTeX form.[qe-writing-001] — Use one sentence per paragraph. Count: 1. Lines: 73. Example: 2 sentences in one paragraph.
[qe-writing-002] (reviewer) — Keep writing clear, concise, and valuable. Count: 3. Lines: 29, 33, 421. Example: 29-33 takes three sentences to say “as in the linear lecture”, and the middle one is circular in the same way its predecessor was: “That lecture presented a linear version of the model in this lecture” (31). The third then puts the lecture’s own contents in the past tense - “As in that lecture, we discussed these topics:” (33) - for four topics that are discussed below, not above. The same material then arrives a second time at 417-439, where 425-427’s
{note}restates 29-31 and the bullets restate 35-46. 421 is a 78-word single sentence with two quoted terms and a colon, copied verbatim from{doc}`money_inflation`:962, and it is the longest sentence in a lecture whose house style is otherwise one short sentence per paragraph. Smaller: 27 opens a quotation with two apostrophes,''method 2'', which renders as two straight marks rather than a quote, and the two+++ {"user_expressions": []}markers at 123 and 141 are leftover jupytext metadata in the published source.[qe-writing-003] (reviewer) — Maintain logical flow. Count: 3. Lines: 106, 417, 429. Example: 104-106 says the same thing about both sides of the same equation.
{eq}`eq:steadypi`is \(\exp(-\alpha x) - \exp(-(1+\alpha)x) = g\); 104 correctly calls the left side “steady state revenue raised by printing money”, and then 106 calls the right side “the quantity of time \(t\) goods that the government raises by printing money” - which is the left side again. The counterpart passage in{doc}`money_inflation`(its lines 212-214) gets it right: left side seigniorage, right side government expenditures. 417 is a broken sentence with a full stop in the middle: “almost all paths converge to the higher inflation tax rate displayed in the stationary state Laffer curve. displayed in figure{numref}`laffer_curve_nonlinear`.” And 429 opens “We discovered that” with a bulleted conclusion, immediately after a{note}about the linear lecture and under no heading of its own - the material is lifted from the “Equilibrium selection” section of{doc}`money_inflation`without the section, so a reader reaching 429 has just been told about a different model and is then handed “we discovered”.[qe-writing-005] (reviewer) — Use bold for definitions, italic for emphasis. Count: 4. Lines: 82, 284, 300, 446. Example: no term in this lecture is bolded at its definition. 35-36 bolds inflation tax and Laffer curve in the Overview, both imported from
{doc}`money_inflation`and neither defined here; after that, bold is used only for structural labels - Pseudo-code (300), the three exercise titles (446, 548, 631) and the Part a. / Part b. / Part c. markers (476, 523, 596, 612, 657, 684, 711). Meanwhile the definitions that do occur are marked three other ways: steady state is italicised at 82, and 284 sets two concepts in inline code - “we’ll treat \(m_t\) as anatural state variableand \(p_t\) as ajumpvariable” - which renders them as monospace, the formatting reserved for identifiers; the counterpart sentence in{doc}`money_inflation`(line 795) bolds state and jump correctly. Names are italicised too, at 18 (Laffer curves) and 280 (Method 2).[qe-writing-007] (reviewer) — Use visual elements to enhance understanding. Count: 3. Lines: 191, 368, 382. Example:
{numref}`p0_path_nonlin`(394-415) plots every path with**line_paramsand nolabel, anddraw_iterationsnever callsax.legend(), so the figure shows however many curvesnp.arange(p0_l, p0_u, 0.1)happens to produce with nothing identifying any of them. Worse, the \(\pi_l\) and \(\pi_u\) reference lines are drawn only on the bottom two panels -for ax in axes[2:]at 382 - while 417 tells the reader to stare at “the paths of price levels” to see the convergence, i.e. at the second panel, which carries no marker for either steady state. On the Laffer-curve figure the two labels are placed atplt.gca().get_ylim()[0]*2(191), a y-coordinate defined as twice the lower axis limit: for a curve whose values sit just above zero that is an arbitrary height, and it lands off the axes whenever the lower limit is negative, whereax.annotatewithxycoords=('data', 'axes fraction')would pin them. Two smaller gaps: the pseudo-code at 300-336 is thirty-six lines of nested bullets restating a two-line recursion that the two displayed equations already give, andmni_ex3part a asks for the closed form \(g_{\max}(\alpha) = \alpha^\alpha/(1+\alpha)^{1+\alpha}\) (641) which its own solution never evaluates - 667 computescompute_seign(x_star_α, α)instead and the two are never compared.
Low severity#
[qe-fig-001] — Do not set figure size unless necessary. Count: 1. Lines: 348. Example: figsize=.
Strengths#
The lecture is honest about what the non-linearity costs and says so in the one place a reader would otherwise be confused: the
{prf:remark}at 71-74 points out that{eq}`eq:mdemand`is linear in logs while{eq}`eq:msupply`is linear in levels, and that this is what forces the computation method to change - which is the whole reason this lecture exists alongside{doc}`money_inflation`.The claim that a particular \(p_0\) pins the inflation rate forever is verified in code rather than asserted: 262-276 simulates 150 periods from
p0_land then checks three separate things - that \(\pi\) and \(\mu\) agree at the end, that the log increments of \(m\) and \(p\) are equal, and that the resulting increment satisfies the steady-state equation \(\exp(-\alpha x) - \exp(-(1+\alpha)x) = g\) tonp.isclose.The pseudo-code at 302-336 is written as a mapping from \((m_t, p_t)\) to \((m_{t+1}, p_{t+1})\) with the equation to solve named at each step, and the implementation at 247-259 follows it line for line, including the correctly inverted form \(p_{t+1} = \lambda^{-1}p_t + (1-\lambda^{-1})m_{t+1}\) that 310 derives from
{eq}`eq:mdemand2`.The three exercises form a genuine progression and each one ends somewhere the body does not:
mni_ex1derives the analytic peak \(x^* = \ln((1+\alpha)/\alpha)\) and cross-checks it againstminimize_scalar(491-501);mni_ex2traces both roots as \(g\) varies and states the two limits (\(\pi_l \to 0\), \(\pi_u \to \infty\) as \(g \to 0^+\); the roots merging at \(x^*\)) with a numerical check of each (598-610);mni_ex3varies the money-demand elasticity and finds a genuinely new result - that \(\alpha = 0.8\) pushes \(g_{\max}\) below the benchmark deficit, so no steady state exists (706-709).mni_ex3part c is the right closing experiment: it starts each feasible \(\alpha\) from the midpoint of \([\underline p, \overline p]\) and shows every path converging to \(\pi_u\) (713-741), which establishes that the perverse dynamics are not an artefact of the benchmark calibration - a claim the body makes only for one \(\alpha\).The Laffer-curve figure (166-203) does what the corresponding figure in
{doc}`money_inflation`does not: it marks both stationary inflation rates with labelled vertical lines and draws the deficit \(g\) as a horizontal line, so the two intersections the whole lecture turns on are visible in the figure the prose cites.The lecture reports zero mechanical Math and Code violations, and that is earned rather than accidental - Greek identifiers throughout (
α,λ,π_l,π_u,μ_seq),bmatrixnever needed, no\tag, no bold vectors, and every display either labelled and cited ({eq}`eq:mdemand`,{eq}`eq:msupply`,{eq}`eq:steadypi`,{eq}`eq:revmax`,{eq}`eq:mdemand2`) or genuinely used once.
Recommended actions#
Fix the description of
{eq}`eq:steadypi`at 104-106: as written both sentences say the government raises the quantity in question. The right side is government expenditure financed by printing money, as the counterpart passage in{doc}`money_inflation`(212-214) says.Say once, near line 88, that \(x\), \(\overline\pi\) and the pair \(\pi_l, \pi_u\) are the same object - the lecture switches between them across 80, 85, 111, 155-157, 170, 209 and the exercises without ever connecting them - and pick one spelling for the seigniorage function (\(L\), or
\exp(...), not both at 93/99 and 451).Repair the sentence at 417, which has a full stop in the middle (“…the stationary state Laffer curve. displayed in figure
{numref}`laffer_curve_nonlinear`”).Give
{numref}`p0_path_nonlin`a legend and extend the steady-state reference lines to all four panels:draw_iterationslabels no path (362-371) and draws the \(\pi_l\)/\(\pi_u\) lines only onaxes[2:](382), yet 417 asks the reader to read the convergence off the price level panel, which has no reference line at all.Replace the label placement at 191 -
plt.text(π, plt.gca().get_ylim()[0]*2, ...)puts the \(\pi_l\) and \(\pi_u\) labels at twice the lower y-limit, which is arbitrary for a curve near zero and off-axes if that limit is negative - withax.annotate(..., xycoords=('data', 'axes fraction'))orax.get_xaxis_transform().Bold the terms this lecture defines rather than the labels around them: steady state at 82, and the two concepts set in inline code at 284 (
natural state variable,jump), which{doc}`money_inflation`bolds correctly at its line 795. Bold currently marks only Pseudo-code (300), the exercise titles (446, 548, 631) and the part labels.Cut the duplicated framing: 29-33 says “as in the linear lecture” three times and puts this lecture’s own contents in the past tense at 33; 417-439 then repeats the Overview bullets (35-46) and the note at 425-427 repeats 29-31. Give 429-439 a heading of its own (“Equilibrium selection”, as in
{doc}`money_inflation`) or fold it into the preceding paragraph.Sweep the Title Case headings, which are the largest mechanical finding: “The Model” (48), “Limiting Values of Inflation Rate” (78), “Steady State Laffer curve” (162), “Initial Price Levels” (206), “Computing an Equilibrium Sequence” (278) and “Slippery Side of Laffer Curve Dynamics” (339) - six of the lecture’s seven H2s (qe-writing-006).
Fix the code style: replace the
eq_glambda at 273 with a call to the existingcompute_seign(175), correct the continuation indents at 128-132, 384-385 and 408-410, remove the space before])at 132, wrap line 500 (90 characters), un-align the padded assignments at 666-667, 692-694 and 722-724, and move theminimize_scalarimport at 492 up to the import cell at 115-120.Have
mni_ex3verify the closed form it asks for: part a gives \(g_{\max}(\alpha) = \alpha^\alpha/(1+\alpha)^{1+\alpha}\) (641) and the solution computescompute_seign(x_star_α, α)instead (667), so the formula the exercise poses is never checked. Also reconcile thefsolvestarting guesses - the body usesx0=0.6for \(\pi_l\) (155) and the exercises usex0=0.3(578, 616, 696) - so part c’s “confirm they agree withπ_landπ_ucomputed in the lecture” compares results from different initial guesses.Finish the smaller items: the 37 internal double spaces, the two-sentence
{prf:remark}at 73 (qe-writing-001), mystnbcaption/namemetadata on the four un-named figure cells (504, 568, 659, 713),lw=2on the nine line plots, thefigsizeoverride at 348 (qe-fig-001), the two over-long captions at 170 and 398 (qe-fig-004), the''method 2''quotation at 27, the two leftover+++ {"user_expressions": []}markers at 123 and 141, and the “integar” typo at 387.