QuantEcon / QuantEcon/QuantEcon.py
WASM: JupyterLite proof-of-concept deployment and browser smoke suite
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 2.4k
- Forks
- 2.3k
- Avg merge
- 3d 3h
- Merged PRs (30d)
- 3
Description
[!NOTE]
Updated 2026-08-21. Phase 0 was overtaken by ad-hoc browser runs: the_LAPACKquestion (#927) was answered on the public numba-ecosystem demo, theintpquestion (#929) was settled in the #942 review, and PR #938 (merged as 481947d) has landed the deployment config and smoke suite underci/wasm/. The checklist below is reworded to match those findings and the upstream Numba change that removed the expectedgini_coefficientfailure (patch 0010, emscripten-forge/recipes#6293); items with recorded browser evidence are ticked and a results table is maintained in the comments. The original text is preserved in the edit history.
Part of #925 (Phase 0). This issue was meant to gate #927 and calibrate #929 and #930; #927 was resolved by ad-hoc browser runs and #929 by the #942 review instead (see the checklist), so its remaining gating value is the cold/warm import timing for #930 and the first full-suite browser run via #933.
Goal
Prove the stack end-to-end with zero code changes, and convert every "should work" in the audit into a known. Because quantecon is noarch: python on conda-forge, there is a real chance it installs and imports in JupyterLite today with no packaging work.
Setup
Build a minimal JupyterLite deployment with jupyterlite-xeus:
name: qe-lite
channels:
- https://prefix.dev/emscripten-forge-4x
- https://prefix.dev/conda-forge
dependencies:
- xeus-python
- numba
- quantecon
This file is now committed as ci/wasm/environment.yml (PR #938). numba is unpinned, so a fresh build resolves the current emscripten-forge-4x build — numba 0.67.0 build 1 as of 2026-08-18, which carries patch 0010 (emscripten-forge/recipes#6293) forcing @njit(parallel=True) to the serial pipeline on Emscripten. Note that the browser results recorded so far did not come from this deployment: they came from the public numba-ecosystem demo (Numba 0.66.0) and the #942 review, so the versions per result are recorded in the table.
Smoke checklist
One representative function per Numba feature class used in the library:
-
import quantecon— works (implicitly confirmed by the_numba_linalg_solvereproducer in #927 and thesimplex_gridreproducer in #942; no timing recorded) -
import quantecon— timed, cold cache and warm cache (feeds #930; #930's "measure first" gate and PR #943 are currently proceeding without this number) -
qe.tauchen— plain lazy@njit(_fill_tauchen);qe.rouwenhorstis pure NumPy with no Numba at all, kept as a no-JIT control case -
MarkovChain.simulate— lazy@njitkernel writing into a Python-allocated array (NRT allocation inside jitted code is exercised bysimplex_gridandnelder_meadbelow) -
qe.random.probvec— exercises the parallel-ufunc → cpu fallback (emscripten patch 0007) -
qe.random.sample_without_replacement— eagerguvectorize, expliciti8signature -
optimize:nelder_mead,brent_max,newton -
game_theory.lemke_howson -
game_theory.vertex_enumeration—numba.typed.Dict; also a jitted generator (_vertex_enumeration_gen), so expected to hang for the same reason assupport_enumeration(#927) — not yet run -
game_theory.support_enumeration— FAILS: first call never returns. The_LAPACKquestion is answered (LAPACK works, see the next two items); the cause is the jitted generator_support_enumeration_gen— emscripten-forge patch 0002 exports onlyNumba_make_generator, not the lowercasenumba_make_generatorthe generator wrapper imports (#927, not yet reported upstream) - minimal
@njitgenerator (for i in range(n): yield i) — FAILS (hangs on first call), recorded 2026-08-19 in #927; isolates the generator mechanism from quantecon's code -
np.linalg.solveinside a scratch@njit— works (correct result on Numba 0.66.0;_numba_linalg_solvealso works), recorded in #927 on 2026-08-15 and 2026-08-19 -
qe.gini_coefficient— expected to work, serially, on emscripten-forge numba ≥ 0.67.0 build 1 (patch 0010, emscripten-forge/recipes#6293, 2026-08-18); the@njit(parallel=True)failure mode this item originally expected no longer exists. Confirm it runs and time it — the serial O(n²) path is why the O(n log n) rewrite in #926 / PR #937 still matters. No browser run of gini is recorded anywhere yet -
simplex_grid— FAILS on a warm persistent cache:RuntimeError: no compiled object yet for <Library 'comb_jit'>atqe.simplex_grid(3, 4)(#944; upstream emscripten-forge/recipes#6309, open). The 32-bitintpboundary is now a documentation question (#929 is doc-only); left unticked because the boundary check itself was never reached and stays blocked behind #944 -
quantecon.util.array.searchsorted— the deprecatedobjmode()shim
Deliverables
- Results recorded in this issue as a table: function → works / fails / notes — started in the comments on 2026-08-21 with the rows that already had evidence (import,
np.linalg.solve,support_enumeration, bare generator,simplex_grid); the remaining items are not yet run - The deployment config committed somewhere reusable — done:
ci/wasm/environment.ymlplus the suiteci/wasm/smoke_test.py(16 tests mapping onto the 13 checklist items, all passing natively), the Playwright harnessci/wasm/test_jupyterlite.pyand a native gate in.github/workflows/ci_wasm_smoke.yml(PR #938, merged 2026-08-21 as 481947d). The Emscripten runner job is parked in #933
Coverage of the browser harness
What actually runs on Emscripten today is test_jupyterlite.py (driven by the job parked in #933), and it covers 5 of the 13 checklist items: import quantecon (untimed), tauchen, bare np.linalg.solve in @njit, support_enumeration and gini_coefficient. smoke_test.py is not yet shipped into the kernel, so rouwenhorst, MarkovChain.simulate, probvec, sample_without_replacement, the three optimize routines, lemke_howson, vertex_enumeration, simplex_grid, searchsorted and the import timing have no browser test until #933 wires in-kernel execution of smoke_test.py. A first green run of the parked job therefore fills at most 5 rows of the table, not 13.
Several of the committed tests also encode expectations that are already out of date; #933 (the runner job) currently notes only the test_support_enumeration hang, so the rest are being handed to it as follow-ups: test_gini_coefficient (xfail(IS_EMSCRIPTEN, strict=True)) and test_gini_fails_on_emscripten expect a failure that patch 0010 has removed; test_support_enumeration and test_vertex_enumeration have no hang guard; test_simplex_grid cites #929 where it should cite #944.
Related
- #927 — jitted-generator hang (
support_enumeration,vertex_enumeration);_LAPACKverified working - #944 —
simplex_gridfails withno compiled object yet for comb_jiton a warm cache; decision is to wait for upstream (emscripten-forge/recipes#6309) - #926 / PR #937 —
gini_coefficientO(n log n) rewrite; the browser confirmation of gini belongs here, not in #926's acceptance criteria - #930 / PR #943 — import-time eager compilation; #930's gate still calls for the cold/warm import timing from this checklist, and PR #943 is proceeding without it
- #933 — Emscripten runner job; the test fixes listed above are to be recorded there
- PR #938 — merged 481947d; delivered the config, suite and harness
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with ci/wasm/test_jupyterlite.py, ci/wasm/smoke_test.py, ci/wasm/environment.yml, and .github/workflows/ci_wasm_smoke.yml, then follow the parked runner work in #933. The deployment and native suite are already delivered by merged PR #938; remaining browser coverage, timing, results, and outdated expectations are split across #933, #930, and #944.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- github-actions, playwright, python, wasm
- Domain
- ci-cd, testing-qa, web-dev
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 20/100