unpleasant#

  • Series: lecture-python-intro

  • File: lectures/unpleasant.md

  • Audit date: 2026-08-26

  • Corpus snapshot: a12d17c0ef

  • Categories 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.5/10

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

Math

8/10

qe-math-002 ×1; 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-003 ×1; qe-fig-004 ×1, +2 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: 370, 452, 546, 574, 628. Example: the exponentiation operator is spaced almost everywhere the rule says it should not be: R_tilde ** T * Bm1 and (1 - R_tilde ** T) at 370 and 440, λ ** T at 380 and 655, λ ** (T - t) at 453-454, model_T.R_tilde ** T_val at 556-557, R_tilde ** T at 644-645 - while 648 writes (γ1 + γ2 - g_bar)**2 in the rule’s preferred form, so the file contradicts itself inside one cell. 452-454 uses a backslash continuation whose right-hand side is already fully parenthesised (paths[0, t] = (1 / γ1) * m0 * \), where dropping the backslash and moving the opening bracket up is the PEP8 form; 554-555 does the same. Aligned assignments pad before = at 546-547 (R_u_list  = []), 554-556 (Bm1   =, BTm1  =) and 628-629 (R_max   =, g_max   =), which PEP8 lists under Pet Peeves. And 574, 694 and 701 embed LaTeX in ordinary strings with doubled backslashes ('...raises $\\bar{g}$') while 573, 692 and 700 use raw strings for the same job in the same cells.

  • [qe-fig-008] — Use lw=2 for line charts. Count: 5. Lines: 415, 481, 566, 571, 692. Example: plot() without lw=.

  • [qe-math-002] — Use \top for transpose notation. Count: 1. Lines: 271. Example: ^T transpose in R^T.

  • [qe-writing-006] — Capitalize lecture titles properly. Count: 2. Lines: 78, 303. Example: H2 Title Case: ‘Monetary-Fiscal Policy’ (Monetary-Fiscal, Policy).

  • [qe-writing-008] — Remove excessive whitespace between words. Count: 31. Lines: 21, 24, 26, 28, 39, 41, 91, 115, 123, 153, …. Example: 2 spaces.

Medium severity#

  • [qe-fig-001] — Do not set figure size unless necessary. Count: 2. Lines: 475, 564. Example: figsize=.

  • [qe-fig-003] — No matplotlib embedded titles. Count: 1. Lines: 482. Example: .set_title.

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

  • [qe-math-009] (reviewer) — Choose simplicity in mathematical notation. Count: 3. Lines: 147, 289, 604. Example: 289-297 writes the fixed-point map as {\mathcal S} - “\(\widehat p_0 = {\mathcal S}(p_0)\)”, “a fixed point of \({\mathcal S}\)”, “\(p_{0,j+1} = (1-\theta) {\mathcal S}(p_{0,j}) + \theta p_{0,j}\)” - where plain \(S\) would do, which is this rule’s own worked example; and the implementation calls it S (358) and S_with_g_bar (637), so the calligraphic form is decoration that also breaks the correspondence between the pseudo code and the code. The same symbols are then spelled two ways throughout the source: \(\widetilde R\) at 82, 87, 92, 95, 103, 109, 258, 265 and 271 against \tilde R at 28, 147, 277, 312, 531 and 586; and \(\overline g\) at 140, 147, 169, 183, 192 and 240 against \bar g at 322, 518, 531, 586 and 602. Both pairs render identically, so this is source noise rather than a rendering fault, but it means a reader grepping the source for the object cannot find it. And 604-611 switches to plain-TeX font commands for subscripts - g_{\rm max}, \bar R_{\rm max} - where the rest of the file uses none and \mathrm{} or _{\max} is the LaTeX form.

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

  • [qe-writing-002] (reviewer) — Keep writing clear, concise, and valuable. Count: 3. Lines: 39, 251, 507. Example: 39 is circular and empty: “That lecture described supplies and demands for money that appear in that lecture.” It is also the fourth of six pointers to {doc}`money_inflation` in the first thirty-two lines (19, 21, 39, 41, 48, 50), three of which say the same thing - go read that lecture. 251-253 spends thirty-three words describing what it is about to do: “Now let’s describe a computational algorithm in more detail in the form of a description that constitutes pseudo code because it approaches a set of instructions we could provide to a Python coder”, where the {prf:algorithm} directive that follows announces itself. And 507 is two sentences of content-free hedging (“\(R\) is important in the context of maintaining monetary stability and addressing the consequences of increased inflation due to government deficits”) at the end of an otherwise sharp four-point summary; it is the only bullet of the four that states no result.

  • [qe-writing-003] (reviewer) — Maintain logical flow. Count: 3. Lines: 403, 507, 696. Example: 403-407 interprets a figure four paragraphs before drawing it: “Notice that the slope of \(p_0\) as a function of \(m_0\) is constant” (403) and “This outcome indicates that our model verifies a quantity theory of money outcome” (405-407) come before the cell that plots it at 414-421, so the reader is told what to notice about something not yet on the page. 507 contradicts the model it is summarising. It is the last of four bullets reading {numref}`fig:unpl1` and says “\(R\) is important in the context of maintaining monetary stability … Thus, a larger \(R\) might be chosen to mitigate the negative impacts on the real rate of return caused by inflation” - but \(R\) with no subscript is not a symbol in this lecture (\(R_t\), \(R_u\), \(\bar R\), \(\widetilde R\) all are), and nothing here is chosen: the whole point of the preceding three bullets is that \(R_u\) is pinned down by \(\bar g\), which is pinned down by the open market operation. 696 is a latent failure in the un_ex2 solution: T_star is assigned inside if np.any(feasible): (695-696) and then read unconditionally at 707 and 711, so on any parameterisation with no feasible \(T\) the cell raises NameError instead of reporting that the fiscal limit is below 1 - which is exactly the case part c asks the reader to think about.

  • [qe-writing-005] (reviewer) — Use bold for definitions, italic for emphasis. Count: 4. Lines: 21, 30, 115, 514. Example: bold and italic are both used for definitions, and one term is bolded four times. open market operation(s) is bold at 115, defined at 157, and bold again at 262 and 322 - so the emphasis marks every occurrence rather than the definition, which is the “overuse of emphasis formatting” the rule names. Conversely two terms are defined in italic inside link labels: Laffer curve and fixed point, both first mentions. 30 and 32 bold a hyphenated modifier rather than the term - gross-of-interest government deficit, the critical money-to-bonds ratio - so the bold ends mid-noun-phrase. And 514 and 600 set a whole sentence in bold as an exercise title (**How the length of the tight-money period $T$ amplifies unpleasant arithmetic.**), where the {exercise} directive already supplies a heading slot. The genuinely good uses are all in one place: the three policy definitions at 153-158 (fiscal policy, monetary policy, debt-management policy, open market operation) and the italic nominal / real contrast at 94-95.

  • [qe-writing-007] (reviewer) — Use visual elements to enhance understanding. Count: 3. Lines: 481, 484, 588. Example: the lecture’s central figure cannot show what the lecture says it shows. plot_path (473-486) loops over m0_arr and calls ax.plot(paths[i]) at 481 with no label and no legend, so {numref}`fig:unpl1` renders the two experiments - \(m_0 = 80\) and \(m_0 = 100\) (496) - as two indistinguishable curves in each of four panels. The bullets at 501-505 then make claims that are entirely about which curve is which: “the lower is the post-open-market-operation money supply at time \(0\), lower is the price level at time \(0\)”, and “an open market operation that reduces the post open market operation money supply at time \(0\) also lowers the rate of return on money \(R_u\)”. A reader cannot check either from the figure. 484-485 compounds it: a dashed red horizontal line at \(\check m_0\) is drawn on the \(m_t\) panel and labelled inside the axes with ax.text, and no sentence anywhere in the lecture mentions it. Third, the Laffer curve is the object on which the whole conclusion rests - 588-589 says “a higher \(\bar g\) sits further up the seigniorage Laffer curve, requiring a lower \(R_u\)”, and un_ex2 is built entirely around its peak \(g_{\max}\) (602-616) - and it is never drawn; the lecture sends the reader to Wikipedia for it at 21, and un_ex2 plots \(\bar g(T)\) against a horizontal line at \(g_{\max}\) (691-704) rather than against the curve itself.

Low severity#

  • [qe-fig-004] — Caption formatting conventions. Count: 1. Lines: 489. Example: Title Case caption (Arithmetic).

Strengths#

  • The backward-induction structure is stated as a plan and then followed exactly: 163-197 says the algorithm works backwards from \(t = T\), computes the stationary \(R_u\) from the quadratic {eq}`eq:up_steadyquadratic`, picks the larger root with a reason (174), and derives \(R_T, b_T, p_T\); 200-241 then works back from \(p_T\) to \(p_0\) and reduces the whole telescoped sum {eq}`eq:allts` to the one-line backward recursion at 234 that the code implements.

  • The {prf:remark} at 243-247 anticipates the one thing a reader checking the algebra would stumble on - that {eq}`eq:pTformula` gives two apparently different expressions for the same \(p_T\) - and says exactly why they agree (because \(R_u\) solves the quadratic), rather than leaving the reader to verify it.

  • The {prf:algorithm} block (257-301) is genuinely executable pseudo code: seven numbered steps, each with the display it needs, ending with the fixed-point map \(\widehat p_0 = \mathcal S(p_0)\) and the relaxation iteration - and the Python at 358-397 implements it step for step in the same order, with comments (# open market operation, # compute B_{T-1}, # compute g bar, # solve the quadratic equation, # compute p0) that name the algorithm’s own steps.

  • The two exercises build a real result rather than drilling the code. un_ex1 (511-592) isolates the comparative static in \(T\) and its solution states the mechanism in two sentences at 585-589 - bonds roll over at \(\widetilde R > 1\), compounding \(B_{T-1}\), raising \(\bar g\), pushing further up the Laffer curve - closing with the lecture’s thesis at 591-592: “tighter money today makes the long-run inflation rate higher, not lower”. un_ex2 (597-722) then finds the fiscal limit \(T^*\) at which the implied \(\bar g\) exceeds the peak of the Laffer curve, which is the natural next question.

  • The un_ex2 solution handles the failure mode the exercise is about: S_with_g_bar computes the discriminant explicitly and returns a real_roots flag when it is negative (648-650), and compute_fixed_point_and_g_bar propagates that flag and caps the iteration at max_iter (659-676) - so the search for \(T^*\) degrades to nan rather than raising or looping forever, and 712 prints the flag at \(T^* + 1\) as part c asks.

  • The distinction between nominal and real initial conditions is drawn where it first matters and marked with italic exactly once each: “\(\check m_0\) is a nominal quantity, being measured in dollars, while \(\widetilde R \check B_{-1}\) is a real quantity, being measured in time \(0\) goods” (94-95) - and the open-market constraint {eq}`eq:openmarketconstraint` is then read back in words at 112-113.

  • qe-fig-003 correctly reports one hit, not four: the three ax.set_title calls at 569, 574 and 701 sit inside {solution-start} regions and are exempt under the rule, and only the one in plot_path at 482 is in the lecture body.