unpleasant#
Series: lecture-python-intro
File:
lectures/unpleasant.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.5/10 |
|
Math |
8/10 |
|
Code |
7.5/10 |
|
JAX |
out of scope |
JAX rules target |
Figures |
6/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: 370, 452, 546, 574, 628. Example: the exponentiation operator is spaced almost everywhere the rule says it should not be:
R_tilde ** T * Bm1and(1 - R_tilde ** T)at 370 and 440,λ ** Tat 380 and 655,λ ** (T - t)at 453-454,model_T.R_tilde ** T_valat 556-557,R_tilde ** Tat 644-645 - while 648 writes(γ1 + γ2 - g_bar)**2in 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:
^Ttranspose inR^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 itS(358) andS_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 Rat 28, 147, 277, 312, 531 and 586; and \(\overline g\) at 140, 147, 169, 183, 192 and 240 against\bar gat 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 theun_ex2solution:T_staris assigned insideif np.any(feasible):(695-696) and then read unconditionally at 707 and 711, so on any parameterisation with no feasible \(T\) the cell raisesNameErrorinstead 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 overm0_arrand callsax.plot(paths[i])at 481 with nolabeland 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 withax.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\)”, andun_ex2is 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, andun_ex2plots \(\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_ex2solution handles the failure mode the exercise is about:S_with_g_barcomputes the discriminant explicitly and returns areal_rootsflag when it is negative (648-650), andcompute_fixed_point_and_g_barpropagates that flag and caps the iteration atmax_iter(659-676) - so the search for \(T^*\) degrades tonanrather 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-003correctly reports one hit, not four: the threeax.set_titlecalls at 569, 574 and 701 sit inside{solution-start}regions and are exempt under the rule, and only the one inplot_pathat 482 is in the lecture body.
Recommended actions#
The
qe-math-002finding at 271 is a false positive - do not change it.\widetilde R^Tis \(\widetilde R\) raised to the power \(T\), the \(T\)-period compounding of the gross bond rate, as the code confirms at 370 (R_tilde ** T * Bm1). Line 82 declares it a scalar: “Let \(\widetilde R > 1\) be a time-invariant gross real rate of return”. Writing\widetilde R^\tophere would be wrong (see scanner_doubts).Give
{numref}`fig:unpl1`a legend:plot_path(473-486) plots one curve per \(m_0\) with no label, so the two experiments at 496 are indistinguishable, and the four claims at 501-505 are all about which curve is which. Passlabel=f'$m_0={m0}$'at 481 and callax.legend()once. While there, say in the prose what the dashed red line at 484-485 is.Rewrite or delete bullet 507: \(R\) with no subscript is not a symbol in this lecture, and “a larger \(R\) might be chosen” inverts the result of the three bullets above it, where \(R_u\) is determined by \(\bar g\) rather than chosen.
Move the interpretation at 403-407 after the figure cell at 414-421 - as written the reader is told to “notice that the slope of \(p_0\) as a function of \(m_0\) is constant” before the plot exists - and give that cell mystnb
caption/namemetadata so the sentence can cite it by{numref}.Make
T_stardefined on all paths in theun_ex2solution: it is assigned only insideif np.any(feasible):at 695-696 and read at 707 and 711, so a parameterisation with no feasible \(T\) raisesNameErrorrather than reporting the fiscal limit is below 1.Cut the Overview’s repetition: 19, 21, 39, 41, 48 and 50 all point the reader at
{doc}`money_inflation`, and 39 (“That lecture described supplies and demands for money that appear in that lecture”) says nothing at all. Also trim the thirty-three-word preamble at 251-253.Settle the emphasis: open market operation is bolded at 115, 157, 262 and 322 and defined at 157, so keep the bold only there; bold the whole term at 30 and 32 rather than the hyphenated modifier (“gross-of-interest deficit”, “money-to-bonds ratio”); bold rather than italicise the two first-mention definitions at 21 and 43; and drop the bold sentences that duplicate the exercise headings at 514 and 600.
Draw the seigniorage Laffer curve once, in the body: 588-589 and the whole of
un_ex2reason about a reader’s mental picture of it, and the closest the lecture comes is a horizontal line at \(g_{\max}\) in the exercise 2 figure (693-694).Fix the code style: unspace
**at 370, 380, 440, 453-454, 556-557, 644-645 and 655 to match 648; drop the backslash continuations at 452 and 554 in favour of bracket continuation; un-align the assignments at 546-547, 554-556 and 628-629; and use raw strings consistently for the LaTeX labels at 574, 694 and 701.Normalise the source notation: one of
\widetilde R/\tilde R(28, 147, 277, 312, 531, 586 differ from the other nine sites), one of\overline g/\bar g, plain \(S\) instead of{\mathcal S}at 289-297 to match the code’sS, and\mathrm{}or_{\max}instead of{\rm max}at 604 and 610-611.Sweep the mechanical items: the two Title Case H2s at 78 (“Monetary-Fiscal Policy”) and 303 (“Example Calculations”), the caption “Unpleasant Arithmetic” at 493 (qe-fig-004), the two-sentence block at 525 (qe-writing-001), the 31 internal double spaces, mystnb metadata for the three un-named figure cells (414, 542, 624),
lw=2on the five line plots (415, 481, 566, 571, 692), and the twofigsizeoverrides at 475 and 564.