From 03bccc1e292b8f1a46e8dd628332f77c41bfd657 Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Wed, 12 Aug 2026 13:08:34 +1000 Subject: [PATCH 1/2] short_path: write the graph with %%file, as every other repo does MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BLOCKED on QuantEcon/lecture-wasm#64 — do not merge yet. See that issue and the diagnostic in QuantEcon/lecture-wasm#65. This PR is the intended END STATE; what is unproven is whether this runtime can run it. This lecture executes in the reader's browser (`lite: true`) and was the only repo in the family fetching this graph across repos on every page view: import requests file_url = "https://raw.githubusercontent.com/QuantEcon/lecture-python-intro/main/lectures/graph.txt" graph_file_response = requests.get(file_url) Every sibling — lecture-python-intro, lecture-dp, lecture-jax, lecture-intro.zh-cn and test-actions-lecture-intro — writes the data with a `%%file graph.txt` cell and reads it back with `open(in_file)`. This repo now does the same, so all six are identical on this exercise, and the divergent string-splitting helper `map_graph_to_distance_matrix(in_file_data)` returns to the canonical filename form. It also retires a cross-repo dependency: that `requests.get` was the only thing reading lecture-python-intro's committed `lectures/graph.txt` anywhere in the organisation, so intro could not delete its copy while this line stood. This repo's own byte-identical `lectures/graph.txt`, which nothing read, is deleted here too. WHY THIS IS BLOCKED, and what is NOT known. `short_path` cannot be completed in-browser today, and this PR does not change that. `myst-ext-exercise` nests a gated `{exercise-start}` body as children of the `exercise` node — `exercise-start` is an ALIAS for `exercise`, not a hoist — and thebe only wires up cells at the top-level block layer. So the data cell sits at ['root','block','exercise','block'] and never executes, whichever form it takes. On `main` two cells are stranded there; with this change it is one. A second bug currently masks a worse version of that one. `short_path.md:480` is a bare ```{solution}``` closer that mystmd rejects, so the solution node is empty and its five cells spill to root level — which is the ONLY reason they are runnable. Correcting it to the gated pair was tried and rebuilt: the error clears, the cells correctly re-nest, and the page would go from one dead cell to six. So that fix is deliberately NOT included here. RETRACTED, and recorded so it is not repeated: an earlier revision of this PR asserted that `%%file` does not fire under thebe-lite. That was wrong. The evidence was a cell producing no output and a later FileNotFoundError, both of which are equally explained by the cell never having executed — which is what was happening. `%%file` under thebe-lite has never been tested. #65 tests it at top level, where nesting cannot confound the result. Equivalence of the data itself is measured, not assumed: intro's canonical filename-based helper over the file written by this cell gives 286 finite entries, Q[99,99]=0.0 and J[0]=160.5500, identical to the network path this replaces, and the written file is byte-identical at 4,691 bytes, sha256 046759fb... graph.txt is not migrating to QuantEcon/data-lectures: it is synthetic teaching data with null provenance, the exercise prose depends on it being visible, and that repo is a cache for upstream sources rather than a host for our examples. --- lectures/graph.txt | 100 ----------------------------- lectures/short_path.md | 141 +++++++++++++++++++++++++++++++++-------- 2 files changed, 115 insertions(+), 126 deletions(-) delete mode 100644 lectures/graph.txt diff --git a/lectures/graph.txt b/lectures/graph.txt deleted file mode 100644 index 9cb9e2e..0000000 --- a/lectures/graph.txt +++ /dev/null @@ -1,100 +0,0 @@ -node0, node1 0.04, node8 11.11, node14 72.21 -node1, node46 1247.25, node6 20.59, node13 64.94 -node2, node66 54.18, node31 166.80, node45 1561.45 -node3, node20 133.65, node6 2.06, node11 42.43 -node4, node75 3706.67, node5 0.73, node7 1.02 -node5, node45 1382.97, node7 3.33, node11 34.54 -node6, node31 63.17, node9 0.72, node10 13.10 -node7, node50 478.14, node9 3.15, node10 5.85 -node8, node69 577.91, node11 7.45, node12 3.18 -node9, node70 2454.28, node13 4.42, node20 16.53 -node10, node89 5352.79, node12 1.87, node16 25.16 -node11, node94 4961.32, node18 37.55, node20 65.08 -node12, node84 3914.62, node24 34.32, node28 170.04 -node13, node60 2135.95, node38 236.33, node40 475.33 -node14, node67 1878.96, node16 2.70, node24 38.65 -node15, node91 3597.11, node17 1.01, node18 2.57 -node16, node36 392.92, node19 3.49, node38 278.71 -node17, node76 783.29, node22 24.78, node23 26.45 -node18, node91 3363.17, node23 16.23, node28 55.84 -node19, node26 20.09, node20 0.24, node28 70.54 -node20, node98 3523.33, node24 9.81, node33 145.80 -node21, node56 626.04, node28 36.65, node31 27.06 -node22, node72 1447.22, node39 136.32, node40 124.22 -node23, node52 336.73, node26 2.66, node33 22.37 -node24, node66 875.19, node26 1.80, node28 14.25 -node25, node70 1343.63, node32 36.58, node35 45.55 -node26, node47 135.78, node27 0.01, node42 122.00 -node27, node65 480.55, node35 48.10, node43 246.24 -node28, node82 2538.18, node34 21.79, node36 15.52 -node29, node64 635.52, node32 4.22, node33 12.61 -node30, node98 2616.03, node33 5.61, node35 13.95 -node31, node98 3350.98, node36 20.44, node44 125.88 -node32, node97 2613.92, node34 3.33, node35 1.46 -node33, node81 1854.73, node41 3.23, node47 111.54 -node34, node73 1075.38, node42 51.52, node48 129.45 -node35, node52 17.57, node41 2.09, node50 78.81 -node36, node71 1171.60, node54 101.08, node57 260.46 -node37, node75 269.97, node38 0.36, node46 80.49 -node38, node93 2767.85, node40 1.79, node42 8.78 -node39, node50 39.88, node40 0.95, node41 1.34 -node40, node75 548.68, node47 28.57, node54 53.46 -node41, node53 18.23, node46 0.28, node54 162.24 -node42, node59 141.86, node47 10.08, node72 437.49 -node43, node98 2984.83, node54 95.06, node60 116.23 -node44, node91 807.39, node46 1.56, node47 2.14 -node45, node58 79.93, node47 3.68, node49 15.51 -node46, node52 22.68, node57 27.50, node67 65.48 -node47, node50 2.82, node56 49.31, node61 172.64 -node48, node99 2564.12, node59 34.52, node60 66.44 -node49, node78 53.79, node50 0.51, node56 10.89 -node50, node85 251.76, node53 1.38, node55 20.10 -node51, node98 2110.67, node59 23.67, node60 73.79 -node52, node94 1471.80, node64 102.41, node66 123.03 -node53, node72 22.85, node56 4.33, node67 88.35 -node54, node88 967.59, node59 24.30, node73 238.61 -node55, node84 86.09, node57 2.13, node64 60.80 -node56, node76 197.03, node57 0.02, node61 11.06 -node57, node86 701.09, node58 0.46, node60 7.01 -node58, node83 556.70, node64 29.85, node65 34.32 -node59, node90 820.66, node60 0.72, node71 0.67 -node60, node76 48.03, node65 4.76, node67 1.63 -node61, node98 1057.59, node63 0.95, node64 4.88 -node62, node91 132.23, node64 2.94, node76 38.43 -node63, node66 4.43, node72 70.08, node75 56.34 -node64, node80 47.73, node65 0.30, node76 11.98 -node65, node94 594.93, node66 0.64, node73 33.23 -node66, node98 395.63, node68 2.66, node73 37.53 -node67, node82 153.53, node68 0.09, node70 0.98 -node68, node94 232.10, node70 3.35, node71 1.66 -node69, node99 247.80, node70 0.06, node73 8.99 -node70, node76 27.18, node72 1.50, node73 8.37 -node71, node89 104.50, node74 8.86, node91 284.64 -node72, node76 15.32, node84 102.77, node92 133.06 -node73, node83 52.22, node76 1.40, node90 243.00 -node74, node81 1.07, node76 0.52, node78 8.08 -node75, node92 68.53, node76 0.81, node77 1.19 -node76, node85 13.18, node77 0.45, node78 2.36 -node77, node80 8.94, node78 0.98, node86 64.32 -node78, node98 355.90, node81 2.59 -node79, node81 0.09, node85 1.45, node91 22.35 -node80, node92 121.87, node88 28.78, node98 264.34 -node81, node94 99.78, node89 39.52, node92 99.89 -node82, node91 47.44, node88 28.05, node93 11.99 -node83, node94 114.95, node86 8.75, node88 5.78 -node84, node89 19.14, node94 30.41, node98 121.05 -node85, node97 94.51, node87 2.66, node89 4.90 -node86, node97 85.09 -node87, node88 0.21, node91 11.14, node92 21.23 -node88, node93 1.31, node91 6.83, node98 6.12 -node89, node97 36.97, node99 82.12 -node90, node96 23.53, node94 10.47, node99 50.99 -node91, node97 22.17 -node92, node96 10.83, node97 11.24, node99 34.68 -node93, node94 0.19, node97 6.71, node99 32.77 -node94, node98 5.91, node96 2.03 -node95, node98 6.17, node99 0.27 -node96, node98 3.32, node97 0.43, node99 5.87 -node97, node98 0.30 -node98, node99 0.33 -node99, diff --git a/lectures/short_path.md b/lectures/short_path.md index 2bab559..ba87348 100644 --- a/lectures/short_path.md +++ b/lectures/short_path.md @@ -251,7 +251,7 @@ But, importantly, we now have a methodology for tackling large graphs. :label: short_path_ex1 ``` -The file data below describes a weighted directed graph. +The text below describes a weighted directed graph. The line `node0, node1 0.04, node8 11.11, node14 72.21` means that from node0 we can go to @@ -271,15 +271,107 @@ integers, so consider replacing `np.equal()` with `np.allclose()`. ``` ```{code-cell} ipython3 -import requests - -file_url = "https://raw.githubusercontent.com/QuantEcon/lecture-python-intro/main/lectures/graph.txt" -graph_file_response = requests.get(file_url) -``` - -```{code-cell} ipython3 -graph_file_data = str(graph_file_response.content, 'utf-8') -print(graph_file_data) +%%file graph.txt +node0, node1 0.04, node8 11.11, node14 72.21 +node1, node46 1247.25, node6 20.59, node13 64.94 +node2, node66 54.18, node31 166.80, node45 1561.45 +node3, node20 133.65, node6 2.06, node11 42.43 +node4, node75 3706.67, node5 0.73, node7 1.02 +node5, node45 1382.97, node7 3.33, node11 34.54 +node6, node31 63.17, node9 0.72, node10 13.10 +node7, node50 478.14, node9 3.15, node10 5.85 +node8, node69 577.91, node11 7.45, node12 3.18 +node9, node70 2454.28, node13 4.42, node20 16.53 +node10, node89 5352.79, node12 1.87, node16 25.16 +node11, node94 4961.32, node18 37.55, node20 65.08 +node12, node84 3914.62, node24 34.32, node28 170.04 +node13, node60 2135.95, node38 236.33, node40 475.33 +node14, node67 1878.96, node16 2.70, node24 38.65 +node15, node91 3597.11, node17 1.01, node18 2.57 +node16, node36 392.92, node19 3.49, node38 278.71 +node17, node76 783.29, node22 24.78, node23 26.45 +node18, node91 3363.17, node23 16.23, node28 55.84 +node19, node26 20.09, node20 0.24, node28 70.54 +node20, node98 3523.33, node24 9.81, node33 145.80 +node21, node56 626.04, node28 36.65, node31 27.06 +node22, node72 1447.22, node39 136.32, node40 124.22 +node23, node52 336.73, node26 2.66, node33 22.37 +node24, node66 875.19, node26 1.80, node28 14.25 +node25, node70 1343.63, node32 36.58, node35 45.55 +node26, node47 135.78, node27 0.01, node42 122.00 +node27, node65 480.55, node35 48.10, node43 246.24 +node28, node82 2538.18, node34 21.79, node36 15.52 +node29, node64 635.52, node32 4.22, node33 12.61 +node30, node98 2616.03, node33 5.61, node35 13.95 +node31, node98 3350.98, node36 20.44, node44 125.88 +node32, node97 2613.92, node34 3.33, node35 1.46 +node33, node81 1854.73, node41 3.23, node47 111.54 +node34, node73 1075.38, node42 51.52, node48 129.45 +node35, node52 17.57, node41 2.09, node50 78.81 +node36, node71 1171.60, node54 101.08, node57 260.46 +node37, node75 269.97, node38 0.36, node46 80.49 +node38, node93 2767.85, node40 1.79, node42 8.78 +node39, node50 39.88, node40 0.95, node41 1.34 +node40, node75 548.68, node47 28.57, node54 53.46 +node41, node53 18.23, node46 0.28, node54 162.24 +node42, node59 141.86, node47 10.08, node72 437.49 +node43, node98 2984.83, node54 95.06, node60 116.23 +node44, node91 807.39, node46 1.56, node47 2.14 +node45, node58 79.93, node47 3.68, node49 15.51 +node46, node52 22.68, node57 27.50, node67 65.48 +node47, node50 2.82, node56 49.31, node61 172.64 +node48, node99 2564.12, node59 34.52, node60 66.44 +node49, node78 53.79, node50 0.51, node56 10.89 +node50, node85 251.76, node53 1.38, node55 20.10 +node51, node98 2110.67, node59 23.67, node60 73.79 +node52, node94 1471.80, node64 102.41, node66 123.03 +node53, node72 22.85, node56 4.33, node67 88.35 +node54, node88 967.59, node59 24.30, node73 238.61 +node55, node84 86.09, node57 2.13, node64 60.80 +node56, node76 197.03, node57 0.02, node61 11.06 +node57, node86 701.09, node58 0.46, node60 7.01 +node58, node83 556.70, node64 29.85, node65 34.32 +node59, node90 820.66, node60 0.72, node71 0.67 +node60, node76 48.03, node65 4.76, node67 1.63 +node61, node98 1057.59, node63 0.95, node64 4.88 +node62, node91 132.23, node64 2.94, node76 38.43 +node63, node66 4.43, node72 70.08, node75 56.34 +node64, node80 47.73, node65 0.30, node76 11.98 +node65, node94 594.93, node66 0.64, node73 33.23 +node66, node98 395.63, node68 2.66, node73 37.53 +node67, node82 153.53, node68 0.09, node70 0.98 +node68, node94 232.10, node70 3.35, node71 1.66 +node69, node99 247.80, node70 0.06, node73 8.99 +node70, node76 27.18, node72 1.50, node73 8.37 +node71, node89 104.50, node74 8.86, node91 284.64 +node72, node76 15.32, node84 102.77, node92 133.06 +node73, node83 52.22, node76 1.40, node90 243.00 +node74, node81 1.07, node76 0.52, node78 8.08 +node75, node92 68.53, node76 0.81, node77 1.19 +node76, node85 13.18, node77 0.45, node78 2.36 +node77, node80 8.94, node78 0.98, node86 64.32 +node78, node98 355.90, node81 2.59 +node79, node81 0.09, node85 1.45, node91 22.35 +node80, node92 121.87, node88 28.78, node98 264.34 +node81, node94 99.78, node89 39.52, node92 99.89 +node82, node91 47.44, node88 28.05, node93 11.99 +node83, node94 114.95, node86 8.75, node88 5.78 +node84, node89 19.14, node94 30.41, node98 121.05 +node85, node97 94.51, node87 2.66, node89 4.90 +node86, node97 85.09 +node87, node88 0.21, node91 11.14, node92 21.23 +node88, node93 1.31, node91 6.83, node98 6.12 +node89, node97 36.97, node99 82.12 +node90, node96 23.53, node94 10.47, node99 50.99 +node91, node97 22.17 +node92, node96 10.83, node97 11.24, node99 34.68 +node93, node94 0.19, node97 6.71, node99 32.77 +node94, node98 5.91, node96 2.03 +node95, node98 6.17, node99 0.27 +node96, node98 3.32, node97 0.43, node99 5.87 +node97, node98 0.30 +node98, node99 0.33 +node99, ``` ```{exercise-end} @@ -295,26 +387,23 @@ First let's write a function that reads in the graph data above and builds a dis num_nodes = 100 destination_node = 99 -def map_graph_to_distance_matrix(in_file_data): +def map_graph_to_distance_matrix(in_file): # First let's set of the distance matrix Q with inf everywhere Q = np.full((num_nodes, num_nodes), np.inf) # Now we read in the data and modify Q - lines = in_file_data.split('\n') - for line_ in lines: - line = line_.strip() - if line == '': - continue - elements = line.split(',') - node = elements.pop(0) - node = int(node[4:]) # convert node description to integer - if node != destination_node: - for element in elements: - destination, cost = element.split() - destination = int(destination[4:]) - Q[node, destination] = float(cost) - Q[destination_node, destination_node] = 0 + with open(in_file) as infile: + for line in infile: + elements = line.split(',') + node = elements.pop(0) + node = int(node[4:]) # convert node description to integer + if node != destination_node: + for element in elements: + destination, cost = element.split() + destination = int(destination[4:]) + Q[node, destination] = float(cost) + Q[destination_node, destination_node] = 0 return Q ``` @@ -373,7 +462,7 @@ def print_best_path(J, Q): Okay, now we have the necessary functions, let's call them to do the job we were assigned. ```{code-cell} ipython3 -Q = map_graph_to_distance_matrix(graph_file_data) +Q = map_graph_to_distance_matrix('graph.txt') J = compute_cost_to_go(Q) print_best_path(J, Q) ``` From bdabaf1c8a26f774591efb2d549a2ca7dcfdca96 Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Wed, 12 Aug 2026 15:11:33 +1000 Subject: [PATCH 2/2] short_path: move the graph data cell out of the exercise so it can run MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A code cell nested in any directive is never registered with the kernel by @myst-theme/jupyter, so inside `{exercise-start}` this cell renders a run button that does nothing, and the solution then fails with FileNotFoundError. It is the only cell on the page in that position — every other cell is already top level and runs. Moving it below `{exercise-end}` makes the whole lecture runnable in the browser for the first time. Reading order is unchanged: the prose still says "The text below describes a weighted directed graph" and the data still appears directly beneath it, just outside the exercise's box. The solution's "reads in the graph data above" is likewise still accurate. A comment records why it sits there, so nobody tidies it back in — that would silently break the page again, with no error and no CI signal. Root cause and the general fix: QuantEcon/lecture-wasm#64 and QuantEcon/quantecon-theme.mystmd#117. Verified the move did not touch the data: 9 cells, 100 data lines, reconstitutes to 4,691 bytes / sha256 046759fb..., and the cell now sits strictly between `{exercise-end}` and the solution. --- lectures/short_path.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/lectures/short_path.md b/lectures/short_path.md index ba87348..40a8c27 100644 --- a/lectures/short_path.md +++ b/lectures/short_path.md @@ -270,6 +270,16 @@ You will be dealing with floating point numbers now, rather than integers, so consider replacing `np.equal()` with `np.allclose()`. ``` + +```{exercise-end} +``` + +% The graph data cell sits OUTSIDE the exercise deliberately. A code cell nested +% in any directive is never registered with the kernel by @myst-theme/jupyter, so +% inside the exercise it renders a run button that does nothing and the solution +% then fails with FileNotFoundError. See QuantEcon/lecture-wasm#64 and +% QuantEcon/quantecon-theme.mystmd#117. Move it back only once that is fixed. + ```{code-cell} ipython3 %%file graph.txt node0, node1 0.04, node8 11.11, node14 72.21 @@ -374,9 +384,6 @@ node98, node99 0.33 node99, ``` -```{exercise-end} -``` - ```{solution} short_path_ex1 :class: dropdown ```