Skip to content

Fix durable fingerprints for GETTSIM-generated JAX models - #447

Draft
timmens wants to merge 1 commit into
mainfrom
codex/gettsim-fingerprint
Draft

timmens wants to merge 1 commit into
mainfrom
codex/gettsim-fingerprint

Conversation

@timmens

@timmens timmens commented Sep 11, 2026

Copy link
Copy Markdown
Member

What problem do you want to solve?

PyLCM rejects valid GETTSIM-generated JAX callable graphs while constructing a model's durable fingerprint. This prevents a downstream labor-supply model from reaching solution or simulation.

Support these graphs through a bounded external-library contract. Generated functions, policy bodies, closures, defaults, and model data retain recursive hashing. Authenticated fixed infrastructure functions bind their executable code, defaults, and dependency versions. Exact GETTSIM/ttsim declarations, foreign-key semantics, rounding rules, and JAX lookup/polynomial carriers bind their relevant contents. Dictionary annotation schemas and additional public NumPy primitives are handled consistently.

Opaque dependencies, forged library identities, unsupported mutable carriers, and cyclic annotation schemas remain rejected. GETTSIM and ttsim remain optional dependencies. The implementation contract assumes unmodified installed libraries; runtime library monkeypatching and in-place model-data mutation remain outside the supported contract. The structure fingerprint schema advances to version 8, so existing structure fingerprints require regeneration.

Validation

  • 185 focused fingerprint, binding, and model-seal tests pass in each of fp32 and fp64.
  • The actual downstream labor-supply build_model() succeeds in both precisions with this checkout loaded: 42 periods, working and retired regimes, GETTSIM 1.2, ttsim-backend 1.2.1, and JAX 0.11.1 on CPU.
  • Independent processes and distinct hash seeds produce matching identities within each precision.
  • Tests cover numerical GETTSIM output, archived solution replay into an equivalent model, rejection after policy changes, and opaque-dependency rejection.
  • A basic PyLCM model still constructs in an environment without GETTSIM or ttsim.
  • Focused lint, type, and keyword-only convention checks pass.

Todo

  • Target main and choose a title describing the repair.
  • Review the supported external-library boundary and CI results.

@read-the-docs-community

Copy link
Copy Markdown

Documentation build overview

📚 pylcm | 🛠️ Build #34511698 | 📁 Comparing ec5e28f against latest (1aaa87b)

  🔍 Preview build  

4 files changed
± beta-delta/index.html
± iskhakov-et-al-2017/index.html
± tiny-example/index.html
± transitions/index.html

@codecov

codecov Bot commented Sep 11, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 76.21359% with 49 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.69%. Comparing base (1aaa87b) to head (ec5e28f).

Files with missing lines Patch % Lines
src/_lcm/solution/external_fingerprint.py 69.92% 40 Missing ⚠️
src/_lcm/solution/fingerprint.py 87.67% 9 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #447      +/-   ##
==========================================
- Coverage   90.74%   90.69%   -0.06%     
==========================================
  Files         380      381       +1     
  Lines       51383    51583     +200     
==========================================
+ Hits        46627    46781     +154     
- Misses       4756     4802      +46     
Flag Coverage Δ
cpu-python 90.69% <76.21%> (-0.06%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions

Copy link
Copy Markdown

Benchmark comparison (main → HEAD)

Comparing 1aaa87bd (main) → ec5e28f1 (HEAD)

Benchmark Statistic before after Ratio Alert
aca-baseline execution time 15.192 s 15.285 s 1.01
peak GPU mem 776 MB 776 MB 1.00
compilation time 686.33 s 701.16 s 1.02
peak CPU mem 12.63 GB 12.38 GB 0.98
aca-baseline-debug execution time 44.557 s 45.068 s 1.01
peak GPU mem 775 MB 775 MB 1.00
compilation time 731.66 s 714.85 s 0.98
peak CPU mem 12.23 GB 11.22 GB 0.92
Mahler-Yum execution time 12.759 s 12.804 s 1.00
peak GPU mem 765 MB 765 MB 1.00
compilation time 47.71 s 49.02 s 1.03
peak CPU mem 1.78 GB 1.78 GB 1.00
Precautionary Savings - Solve execution time 44.1 ms 46.7 ms 1.06
peak GPU mem 4 MB 4 MB 1.00
compilation time 4.53 s 4.72 s 1.04
peak CPU mem 1.15 GB 1.16 GB 1.00
Precautionary Savings - Simulate execution time 69.0 ms 78.2 ms 1.13
peak GPU mem 389 MB 389 MB 1.00
compilation time 7.03 s 7.03 s 1.00
peak CPU mem 1.30 GB 1.30 GB 1.00
Precautionary Savings - Solve & Simulate execution time 140.7 ms 152.0 ms 1.08
peak GPU mem 1.70 GB 1.70 GB 1.00
compilation time 11.42 s 11.45 s 1.00
peak CPU mem 1.36 GB 1.36 GB 1.00
Precautionary Savings - Solve & Simulate (irreg) execution time 268.9 ms 279.3 ms 1.04
peak GPU mem 2.20 GB 2.20 GB 1.00
compilation time 11.69 s 11.75 s 1.01
peak CPU mem 1.36 GB 1.36 GB 0.99
Iskhakov et al. (2017) - GridSearch Solve execution time 111.4 ms 112.9 ms 1.01
peak GPU mem 67 MB 67 MB 1.00
compilation time 3.28 s 3.27 s 1.00
peak CPU mem 1.17 GB 1.17 GB 1.00
Iskhakov et al. (2017) - DC-EGM Solve execution time 1.916 s 2.198 s 1.15
peak GPU mem 1 MB 1 MB 1.00
compilation time 7.54 s 8.30 s 1.10
peak CPU mem 1.39 GB 1.39 GB 1.00
Iskhakov et al. (2017) - GridSearch Simulate execution time 253.4 ms 255.3 ms 1.01
peak GPU mem 442 MB 442 MB 1.00
compilation time 10.65 s 10.75 s 1.01
peak CPU mem 1.31 GB 1.31 GB 1.00
Iskhakov et al. (2017) - DC-EGM Simulate execution time 247.9 ms 271.6 ms 1.10
peak GPU mem 442 MB 442 MB 1.00
compilation time 11.00 s 11.30 s 1.03
peak CPU mem 1.51 GB 1.50 GB 0.99
Collective Household - Construct execution time 551.0 ms 589.3 ms 1.07
peak CPU mem 1.01 GB 1.01 GB 1.00
Collective Household - Solve execution time 145.7 ms 158.3 ms 1.09
peak GPU mem 0 MB 0 MB 1.00
compilation time 4.87 s 5.03 s 1.03
peak CPU mem 1.26 GB 1.26 GB 1.00
Collective Household - Simulate (1000) execution time 265.1 ms 266.2 ms 1.00
compilation time 12.15 s 13.09 s 1.08
peak CPU mem 1.37 GB 1.37 GB 1.00
Collective Household - Simulate (10000) execution time 266.4 ms 258.4 ms 0.97
compilation time 12.53 s 12.51 s 1.00
peak CPU mem 1.38 GB 1.38 GB 1.00
Collective Household - Simulate (100000) execution time 255.1 ms 269.0 ms 1.05
peak GPU mem 97 MB 97 MB 1.00
compilation time 12.55 s 13.49 s 1.08
peak CPU mem 1.39 GB 1.39 GB 1.00
Reference Chain - Solve (1) execution time 26.1 ms 27.4 ms 1.05
compilation time 1.74 s 1.80 s 1.03
peak CPU mem 1.06 GB 1.06 GB 1.00
Reference Chain - Solve (2) execution time 48.0 ms 49.8 ms 1.04
compilation time 2.20 s 2.20 s 1.00
peak CPU mem 1.10 GB 1.10 GB 1.01
Reference Chain - Solve (4) execution time 91.5 ms 100.0 ms 1.09
compilation time 3.08 s 3.24 s 1.05
peak CPU mem 1.17 GB 1.17 GB 1.00
Reference Chain - Solve (8) execution time 183.9 ms 192.2 ms 1.04
peak GPU mem 0 MB 0 MB 1.00
compilation time 5.06 s 5.11 s 1.01
peak CPU mem 1.28 GB 1.29 GB 1.01

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant