perm_income_cons#
Series: lecture-python.myst
File:
lectures/perm_income_cons.mdAudit date: 2026-08-26
Corpus snapshot:
e25fdf2345Categories audited: writing, math, code, figures, references, links (JAX out of scope)
Overall score: 6.5 / 10
Priority: HIGH
Score breakdown#
Category |
Score |
One-line note |
|---|---|---|
Writing |
3/10 |
|
Math |
4/10 |
|
Code |
7.5/10 |
|
JAX |
out of scope |
JAX rules target |
Figures |
5.5/10 |
|
References |
10/10 |
no mechanical violations detected. |
Links |
9/10 |
|
Admonitions |
N/A |
no admonitions, exercises or solutions. |
Issues#
Critical#
None found.
High severity#
[qe-code-001] (reviewer) — Follow PEP8 unless closer to mathematical notation. Count: 6. Lines: 368, 404, 553, 556, 560, 598. Example: 368, 379, 380, 548 and 549 omit the space after a comma -
np.zeros((3,1)),.reshape(4,1)twice,μ_y[1,0],μ_x[3,0](E231) - while the same cells writenp.zeros((3, 3))andΣ_y[1, 1]correctly two lines away. 556 and 583 both writeT = bsim.shape[1]with two spaces after the operator (E222). 553 and 580 begin a top-leveldefone blank line after the previous function’sreturnrather than two (E302). 598-599 leaves two blank lines inside a function body (E303). 560 assignsxvals = np.arange(T)inconsumption_income_debt_figureand never uses it, and 593 assignsdmean = np.mean(debt_mean)and never uses it, while its partnercmeanat 586 is used at 610 (F841 twice). 404 writes the inline comment as# Form closed loop systemwith two spaces after the hash (E262). And 334 names the AR coefficientsρ1, ρ2without underscores, against \(\rho_1,\rho_2\) in the algebra at 170 and against the underscore convention the rest of the file keeps (μ_z,Σ_z,β_LQ,A_LSS,C_LSS).[qe-fig-005] — Descriptive figure names for cross-referencing. Count: 6. Lines: 625, 635, 716, 759, 769, 788. Example: code-cell figure without mystnb figure metadata.
[qe-fig-008] — Use lw=2 for line charts. Count: 12. Lines: 563, 564, 565, 566, 572, 573, 605, 606, 613, 614, …. Example: plot() without lw=.
[qe-math-002] — Use \top for transpose notation. Count: 8. Lines: 244, 247, 249, 298. Example: apostrophe transpose
x'.[qe-math-010 (proposed)] — Blackboard \mathbb{P}, \mathbb{E}, \mathbb{V} with braces. Count: 2. Lines: 227, 240. Example: missing braces:
\mathbb E.[qe-writing-002] (reviewer) — Keep writing clear, concise, and valuable. Count: 5. Lines: 51, 210, 664, 666, 745. Example: 745-755 spends five consecutive one-sentence paragraphs on one fact: “This rigs a closed economy in which people are borrowing and lending with each other at a gross risk-free interest rate of \(R=\beta^{-1}\)” / “Across the group of people being analyzed, risk-free loans are in zero excess supply” / “We have arranged primitives so that \(R = \beta^{-1}\) clears the market for risk-free loans at zero aggregate excess supply” / “So the risk-free loans are being made from one person to another within our closed set of agents” / “There is no need for foreigners to lend to our group”. 664-674 does the same for the debt build-up, with 670-674 restating 664-666. 51-57 states the Barro isomorphism in four sentences, and then 137-163 restates the whole thing as its own subsection, with 161 repeating 55. 210-212 asks a question and answers it with nothing: “Why solve a model in two distinct ways? / Because by doing so we gather insights about the structure of the model” - the real answer follows at 214-219 and would stand on its own. And 666 changes pronoun mid-sentence: “he or she incurs so much debt that eventually, in the stochastic steady state, he consumes less each period than his nonfinancial income”.
[qe-writing-003] (reviewer) — Maintain logical flow. Count: 6. Lines: 341, 399, 482, 500, 659, 678. Example: 659 is broken: “So at time \(0\) we have \(c_0 = (1-\beta) E_0 \sum_{t=0}^\infty \beta^j y_{t}\)” - the sum runs over \(t\) but the discount factor is \(\beta^j\) and the summand is \(y_t\), so the index does not close. It is meant to be the \(t=0\) instance of
{eq}`old12`six lines above, which has \(\sum_{j=0}^\infty \beta^j y_{t+j}\) correctly. 341 renames a matrix silently: the algebra writes the observation equation \(y_t = U z_t\) with \(U = [0\ 1\ 0]\) (131, 198, 423-425) and the code calls the same objectG(341, 433-434, 445), with no sentence connecting the two. 482 says the second economy draws initial income “from the invariant distribution of financial income” - it is nonfinancial income, as 743 says correctly, and the distinction between the two is the lecture’s subject. 500 promises “the population distribution that we extract from theLinearStateSpaceinstanceLSS”: there is noLSS, the cell at 505 builds alss, and that object is then never used, becauseincome_consumption_debt_seriesconstructs its own instance at 525 - so 505 is a dead cell described by a sentence naming a variable that does not exist. 678 says “The following figure plots realizations of the left side of{eq}`old12`” and then four paragraphs intervene, including the figure’s own interpretation at 685-689, before the plotting function appears at 701. And 399-400 is ungrammatical with a dangling pronoun: “We’ll save the implied optimal policy function soon compare them with what we get by employing an alternative solution method”.[qe-writing-006] — Capitalize lecture titles properly. Count: 12. Lines: 137, 165, 201, 221, 253, 328, 407, 472, 494, 508, …. Example: H3 Title Case: ‘Digression on a Useful Isomorphism’ (Useful, Isomorphism).
[qe-writing-008] — Remove excessive whitespace between words. Count: 19. Lines: 53, 55, 89, 149, 156, 157, 174, 203, 219, 296, …. Example: 2 spaces.
Medium severity#
[qe-fig-001] — Do not set figure size unless necessary. Count: 3. Lines: 559, 601, 707. Example: figsize=.
[qe-fig-003] — No matplotlib embedded titles. Count: 3. Lines: 568, 609, 711. Example: .set(title=.
[qe-link-002] — Use doc links for cross-series references. Count: 1. Lines: 163. Example: raw link to python-advanced.quantecon.org.
[qe-math-009] (reviewer) — Choose simplicity in mathematical notation. Count: 4. Lines: 247, 273, 653, 729. Example: 247 writes the trace as
{\rm trace}(P \tilde C \tilde C')where\operatorname{tr}or\mathrm{tr}is the standard form and shorter. 273 defines \(U_\gamma := \begin{bmatrix}\gamma & 0 & 0\end{bmatrix}\), whose subscript implies a family of \(U\)’s that does not exist - \(U = [0\ 1\ 0]\) selects \(y_t\) from the state, \(U_\gamma = [\gamma\ 0\ 0]\) selects the constant, so the two vectors have nothing in common but their shape. \(R\) carries two meanings: the LQ criterion matrix at 228, 298, 301 and 310, and the gross interest rate at 729, 747 and 751 - and even the interest-rate meaning is written two ways, “\(R = r+1\)” (729) and “\(R = \beta^{-1}\)” (747, 751), with the code adding a third name,RLQ(373), to disambiguate what the prose does not. And the annuity value \((1-\beta) E_t \sum_{j=0}^\infty \beta^j y_{t+j}\) is spelled out in full four times (653, 659, 683, 687) and described in words twice more (662, 681-683) instead of being given a name once - naming it would shorten the whole 648-699 argument.[qe-writing-005] (reviewer) — Use bold for definitions, italic for emphasis. Count: 4. Lines: 648, 693, 724, 736. Example: the file bolds only two terms in 791 lines, and they are the same term spelled two ways: co-integrating relationship at 648 and cointegrating residual at 679, with “cointegration” unhyphenated again at 676, 711 and 786. Meanwhile emphasis is carried by double quotes rather than italic in six places - debt “head north” (724), a “small open economy” (728), “foreigner lenders” (736), a “poor man’s Bewley model” (738), the section title “Borrowers and Lenders” (721), and “stochastic steady state” is left unmarked at 666. 693 italicises both halves of a contrast, “the cointegrating residual is asymptotically covariance stationary, not covariance stationary”, so the reader cannot tell which italic is the emphasis and which is the term. The four ex-ante italics (481, 483, 670, 780) are the file’s only correct use of the marker.
[qe-writing-007] (reviewer) — Use visual elements to enhance understanding. Count: 4. Lines: 137, 568, 646, 776. Example: the six figures come from three functions called twice each, and the titles are hardcoded inside those functions - “Nonfinancial Income, Consumption, and Debt” (568), “Consumption/Debt over time” (609), “Cointegration of Assets and Consumption” (711) - so the transient economy’s figures (630, 636, 717) and the Bewley economy’s figures (764, 770, 789) are pixel-for-pixel identically labelled and nothing on the page says which is which. That matters because 776-784 asks the reader to compare them (“Unlike before, the average level of debt stays at zero”) across 150 lines of intervening text, with no side-by-side panel and no marker on either figure. 646 and 674 describe the transient in words - “\(y_t\) starts far below its stationary mean \(\mu_{y,\infty}\) and rises early in each simulation” - without drawing \(\mu_{y,\infty}\) on the income panel, although
μ_yis already computed at 347. 137-163 presents a four-way variable dictionary between two models as four long bulleted sentences where a two-column table is the natural form and is the section’s entire content. And the file has no admonition at all, though 303-314 introduces a deliberate approximation - a penalty \(\epsilon\) standing in for the no-Ponzi condition, “a (hopefully) small approximation error” - which is exactly what a{note}is for.
Low severity#
None found.
Strengths#
The lecture solves one model twice and then checks the two answers against each other in code rather than asserting agreement: 457 prints
ABF - A_LSS, the closed-loop transition matrix from the LQ solution minus the one assembled from the difference-equation formulas at 433-447, and 463 printsc_polbeside-F, so the claim at 466 is visible in the output.The two economies differ in exactly one input and the lecture arranges the code so that this is verifiable: 476-490 states that only the initial state changes, 626 passes
μ_0, Σ_0(everyone at zero income and zero debt) and 760 passesmxbewley, sxbewley, built at 350-362 out of the stationary moments computed at 347 - and the same three plotting functions are reused unchanged, so every difference across the six figures is attributable to the initial condition.303-314 is candid about an approximation instead of burying it: it says outright that the no-Ponzi condition
{eq}`old42`cannot be expressed inside the LQ framework, names the workaround (a small \(\epsilon\) in the \((4,4)\) entry of \(R\), implemented as1e-9at 376), calls it a trick, and concedes the induced error is only “hopefully” small.The economics of the first economy is derived rather than read off the plot: 648-668 goes from the cointegrating relationship
{eq}`old12`to \(c_0\) as an annuity on expected discounted income, then to heavy early borrowing, then to a steady state in which consumption sits below nonfinancial income, and finally to the interest service that accounts for the gap.The fan charts at 580-620 put the analytic 90% and 95% cross-sectional bands, taken from the
moment_sequence()generator at 547-549, behind the 25 simulated paths on the same axes - so the population distribution and the sample are compared at every date, which is exactly what 502 says the exercise is for.137-163 makes the Barro isomorphism operational rather than gestural: four explicit variable substitutions (\(T_t \leftrightarrow c_t\), \(G_t \leftrightarrow y_t\), \(B_t \leftrightarrow b_t\), \(R \leftrightarrow 1+r\)), the consequence stated at 161, and a pointer to the advanced lecture that exploits it.
Recommended actions#
Fix the display at 659: the sum runs over \(t\), the discount factor is \(\beta^j\), and the summand is \(y_t\), so the equation does not close - from
{eq}`old12`at 653 it should be \(c_0 = (1-\beta)E_0\sum_{j=0}^\infty \beta^j y_j\).Reconcile the output matrix name: the algebra uses \(U\) (131, 198, 423-425), the code uses
G(341, 433, 445), and no sentence links them. Do the same for \(R\), which is the LQ penalty matrix at 228, 298, 301 and 310 and the gross interest rate at 336, 729, 747 and 751.Correct “financial income” to “nonfinancial income” at 482 - 743 already has it right, and the distinction is the lecture’s subject.
Delete the dead cell at 505 and the sentence at 500 that describes its non-existent instance
LSS; the figures build their ownLinearStateSpaceinsideincome_consumption_debt_seriesat 525.Distinguish the six figures. The three plotting functions hardcode their titles (568, 609, 711), so the transient economy’s figures and the Bewley economy’s are identically labelled; pass a title or label through, and add the
mystnbcaption/name metadata the six figure cells are missing (625, 635, 716, 759, 769, 788) so the comparison at 776-784 can be made with cross-references instead of memory.Move the cointegration figure (701-719) up to just after 678, which announces it, so its interpretation at 685-689 follows the picture rather than preceding it; and draw the stationary mean \(\mu_{y,\infty}\) (already available as
μ_yfrom 347) on the income panel that 646 describes in relation to it.Turn the isomorphism at 152-159 into a two-column table - it is four parallel substitutions and currently reads as four sentences of 20-30 words each.
Code cleanup: the E231 commas at 368, 379, 380, 548, 549; the double spaces at 556, 583 and 404; the one-blank-line
defs at 553 and 580; the double blank line at 598; the unusedxvals(560) anddmean(593); andρ1, ρ2at 334 renamedρ_1, ρ_2to match both the algebra at 170 and the file’s ownμ_z/Σ_z/β_LQconvention.Sweep the mechanical remainder: the twelve title-case headings (137, 165, 201, 221, 253, 328, 407, 472, 494, 508 and two more), the nineteen double spaces, the three
set(title=)calls (568, 609, 711) moved into figure captions,lw=2on the twelve bareplot()calls, the threefigsizeoverrides (559, 601, 707), the rawpython-advanced.quantecon.orgURL at 163 turned into a{doc}reference, and the three spellings of the expectation operator -E_0(94, 115),\mathbb E(227, 240) andE_t(653, 683, 687).