Score-based Levenberg Marquardt

#12
.cache/known_methods_snapshot.json CHANGED
@@ -137,6 +137,32 @@
137
  "gboed",
138
  "boed"
139
  ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
140
  }
141
  },
142
  "observed_methods": [
@@ -146,6 +172,8 @@
146
  "hm",
147
  "iekf",
148
  "lm",
 
 
149
  "teki",
150
  "uki"
151
  ],
 
137
  "gboed",
138
  "boed"
139
  ]
140
+ },
141
+ "lm-kgmm": {
142
+ "abbreviation": "LM-KGMM",
143
+ "Method": "Score-based Levenberg-Marquardt (KGMM)",
144
+ "parallelism": "serial",
145
+ "update_type": "gradient",
146
+ "method_goal": "optimization",
147
+ "emulator_use": "none",
148
+ "aliases": [
149
+ "lm-kgmm",
150
+ "score-based lm (gfdt, kgmm) (extended window)",
151
+ "score-based lm (gfdt, kgmm) (parallel branches)"
152
+ ]
153
+ },
154
+ "lm-dsm": {
155
+ "abbreviation": "LM-DSM",
156
+ "Method": "Score-based Levenberg-Marquardt (DSM)",
157
+ "parallelism": "serial",
158
+ "update_type": "gradient",
159
+ "method_goal": "optimization",
160
+ "emulator_use": "none",
161
+ "aliases": [
162
+ "lm-dsm",
163
+ "score-based lm (gfdt, dsm) (extended window)",
164
+ "score-based lm (gfdt, dsm) (parallel branches)"
165
+ ]
166
  }
167
  },
168
  "observed_methods": [
 
172
  "hm",
173
  "iekf",
174
  "lm",
175
+ "lm-dsm",
176
+ "lm-kgmm",
177
  "teki",
178
  "uki"
179
  ],
CLAUDE.md CHANGED
@@ -51,7 +51,9 @@ calibration_benchmark/
51
  │ ├── common/
52
  │ │ ├── leaderboard.py render_leaderboard() — shared scored-table + chart pipeline
53
  │ │ │ _render_suitability_table() — method × benchmark suitability grid
54
- │ │ │ optional budget_store param adds budget/iters chart section
 
 
55
  │ │ └── method_registry.py KNOWN_METHODS registry + name canonicalization
56
  │ └── pages/
57
  │ ├── UQLeaderboard.py 🎯 UQ Leaderboard — calls render_leaderboard(load_uq_store())
@@ -63,6 +65,8 @@ calibration_benchmark/
63
  │ ├── UKI_results/ UKI results
64
  │ ├── adam_results/ ADAM gradient optimizer results (per-benchmark files)
65
  │ ├── levenberg_marquardt_results/ LM gradient optimizer results (per-benchmark files)
 
 
66
  │ ├── ces-eki-dmc_results/ CES-EKI-DMC ensemble-results files (UQ source)
67
  │ ├── gboed-uq_results/ GBOED ensemble-results files (UQ source)
68
  │ └── gnki-uq_results/ IEKF (a.k.a GNKI) ensemble-results files (UQ source)
@@ -182,6 +186,8 @@ A quick taxonomy tree is rendered on the home page (`src/streamlit_app.py`).
182
  | `adam` | ADAM | serial | gradient | optimization | none | — |
183
  | `lm` | LM | serial | gradient | optimization | none | gradient_descent |
184
  | `gboed` | GBOED | parallel-interacting | general | uq | within-optimize | boed |
 
 
185
 
186
  ## How to extend
187
 
 
51
  │ ├── common/
52
  │ │ ├── leaderboard.py render_leaderboard() — shared scored-table + chart pipeline
53
  │ │ │ _render_suitability_table() — method × benchmark suitability grid
54
+ │ │ │ optional budget_store param adds budget/iters chart section (UQ)
55
+ │ │ │ when budget_store is None (Optimization board), instead renders a
56
+ │ │ │ "Mean Iterations to Reach Target" chart derived as metric/ensemble_size
57
  │ │ └── method_registry.py KNOWN_METHODS registry + name canonicalization
58
  │ └── pages/
59
  │ ├── UQLeaderboard.py 🎯 UQ Leaderboard — calls render_leaderboard(load_uq_store())
 
65
  │ ├── UKI_results/ UKI results
66
  │ ├── adam_results/ ADAM gradient optimizer results (per-benchmark files)
67
  │ ├── levenberg_marquardt_results/ LM gradient optimizer results (per-benchmark files)
68
+ │ ├── opt_kgmm_score_lm/ Score-based LM (KGMM score estimator) results (per-benchmark files)
69
+ │ ├── opt_dsm_score_lm/ Score-based LM (DSM score estimator) results (per-benchmark files)
70
  │ ├── ces-eki-dmc_results/ CES-EKI-DMC ensemble-results files (UQ source)
71
  │ ├── gboed-uq_results/ GBOED ensemble-results files (UQ source)
72
  │ └── gnki-uq_results/ IEKF (a.k.a GNKI) ensemble-results files (UQ source)
 
186
  | `adam` | ADAM | serial | gradient | optimization | none | — |
187
  | `lm` | LM | serial | gradient | optimization | none | gradient_descent |
188
  | `gboed` | GBOED | parallel-interacting | general | uq | within-optimize | boed |
189
+ | `lm-kgmm` | LM-KGMM | serial | gradient | optimization | none | — |
190
+ | `lm-dsm` | LM-DSM | serial | gradient | optimization | none | — |
191
 
192
  ## How to extend
193
 
data/opt_dsm_score_lm/leaderboard_sblm_dsm_parallel_l63_2026-08-12.nc ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2feffae1f04a93b97a272ccd5a988fd8fbfea82000584c5ef990ff355e910329
3
+ size 14296
data/opt_dsm_score_lm/leaderboard_sblm_dsm_parallel_l96_const-force_2026-08-12.nc ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c88062bfa5fc7430d9792cc33558356042947971dfe7f0901e540ad2ed4609b2
3
+ size 14296
data/opt_dsm_score_lm/leaderboard_sblm_dsm_parallel_l96_flux-force_2026-08-12.nc ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d8bd767510a24bd7a8d316752b3dc08f39e9eb7a66fd978cfb213574256667d1
3
+ size 14296
data/opt_dsm_score_lm/leaderboard_sblm_dsm_parallel_l96_vec-force_2026-08-12.nc ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e5846b68470f28ff4b94fe910bba4017b03486ed71a396c6e41dd9218bbc641d
3
+ size 14296
data/opt_kgmm_score_lm/leaderboard_sblm_kgmm_parallel_l63_2026-08-12.nc ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:8210335c139334983b3499ed7a2f626194cabf5904991e8b5eeadfcc04403d68
3
+ size 14296
data/opt_kgmm_score_lm/leaderboard_sblm_kgmm_parallel_l96_const-force_2026-08-12.nc ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:018c3f7b5d59d661cb62c7f4f861ecd38f39c7d8eaf0c172dd57e35cfe780a3b
3
+ size 14296
data/opt_kgmm_score_lm/leaderboard_sblm_kgmm_parallel_l96_flux-force_2026-08-12.nc ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:3c0f44cfcc8107a42a91e71d6cdace8ae718ab83663f84d3c1300bf11b9104f1
3
+ size 14296
data/opt_kgmm_score_lm/leaderboard_sblm_kgmm_parallel_l96_vec-force_2026-08-12.nc ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:8038e2250cd08ee938beb19e883a8b29ebcd829a3a03059337b7154c4eff2235
3
+ size 14296
src/common/leaderboard.py CHANGED
@@ -370,27 +370,35 @@ def render_leaderboard(
370
  else:
371
  scored_df["ensemble_score"] = 100.0
372
 
 
 
 
 
373
  if scoring_mode == "Mean Forward Model Runs":
374
  scored_df["Score"] = scored_df["mean_runs_score"]
375
- sort_columns = ["Mean Forward Model Runs", "Optimal Ensemble Size", "abbreviation"]
376
- ascending = [True, True, True]
377
  elif scoring_mode == "Minimum Forward Model Runs":
378
  scored_df["Score"] = scored_df["minimum_runs_score"]
379
- sort_columns = ["Minimum Forward Model Runs", "Optimal Ensemble Size", "abbreviation"]
380
- ascending = [True, True, True]
381
  elif scoring_mode == "Smallest Optimal Ensemble Size":
382
  scored_df["Score"] = scored_df["ensemble_score"]
383
- sort_columns = ["Optimal Ensemble Size", "Mean Forward Model Runs", "abbreviation"]
384
- ascending = [True, True, True]
385
  else:
386
  scored_df["Score"] = (
387
  fwdruns_weight * scored_df["mean_runs_score"]
388
  + ensemble_weight * scored_df["ensemble_score"]
389
  )
390
- sort_columns = ["Score", "Mean Forward Model Runs", "Optimal Ensemble Size", "abbreviation"]
391
- ascending = [False, True, True, True]
392
 
393
- scored_df = scored_df.sort_values(sort_columns, ascending=ascending).reset_index(drop=True)
 
 
 
 
394
 
395
  if add_rank:
396
  scored_df["Rank"] = scored_df.index + 1
 
370
  else:
371
  scored_df["ensemble_score"] = 100.0
372
 
373
+ scored_df["_unreliable"] = (
374
+ scored_df["Mean Failure Rate (%)"].fillna(0.0) >= _RELIABLE_FAILURE_THRESHOLD
375
+ )
376
+
377
  if scoring_mode == "Mean Forward Model Runs":
378
  scored_df["Score"] = scored_df["mean_runs_score"]
379
+ sort_columns = ["_unreliable", "Mean Forward Model Runs", "Optimal Ensemble Size", "abbreviation"]
380
+ ascending = [True, True, True, True]
381
  elif scoring_mode == "Minimum Forward Model Runs":
382
  scored_df["Score"] = scored_df["minimum_runs_score"]
383
+ sort_columns = ["_unreliable", "Minimum Forward Model Runs", "Optimal Ensemble Size", "abbreviation"]
384
+ ascending = [True, True, True, True]
385
  elif scoring_mode == "Smallest Optimal Ensemble Size":
386
  scored_df["Score"] = scored_df["ensemble_score"]
387
+ sort_columns = ["_unreliable", "Optimal Ensemble Size", "Mean Forward Model Runs", "abbreviation"]
388
+ ascending = [True, True, True, True]
389
  else:
390
  scored_df["Score"] = (
391
  fwdruns_weight * scored_df["mean_runs_score"]
392
  + ensemble_weight * scored_df["ensemble_score"]
393
  )
394
+ sort_columns = ["_unreliable", "Score", "Mean Forward Model Runs", "Optimal Ensemble Size", "abbreviation"]
395
+ ascending = [True, False, True, True, True]
396
 
397
+ scored_df = (
398
+ scored_df.sort_values(sort_columns, ascending=ascending)
399
+ .drop(columns="_unreliable")
400
+ .reset_index(drop=True)
401
+ )
402
 
403
  if add_rank:
404
  scored_df["Rank"] = scored_df.index + 1
src/common/method_registry.py CHANGED
@@ -143,19 +143,81 @@ KNOWN_METHODS = {
143
  "emulator_use": "within-optimize",
144
  "aliases": ["gboed", "boed"],
145
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
146
  }
147
 
148
 
149
- # Vega tableau10 palette — one slot per method in KNOWN_METHODS declaration order.
150
- # New methods appended to KNOWN_METHODS get the next slot; existing colors never shift.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
151
  _METHOD_PALETTE = [
152
- "#4c78a8", "#f58518", "#e45756", "#72b7b2", "#54a24b",
153
- "#eeca3b", "#b279a2", "#ff9da6", "#9d755d", "#bab0ac",
154
- "#5254a3", "#8ca252",
 
 
155
  ]
156
 
157
  # Stable abbreviation → hex color mapping. Import this wherever Altair charts are built
158
- # so every plot in the app assigns the same color to each method.
 
 
 
159
  METHOD_COLORS: dict[str, str] = {
160
  meta["abbreviation"]: _METHOD_PALETTE[i % len(_METHOD_PALETTE)]
161
  for i, meta in enumerate(KNOWN_METHODS.values())
 
143
  "emulator_use": "within-optimize",
144
  "aliases": ["gboed", "boed"],
145
  },
146
+ "lm-kgmm": {
147
+ "abbreviation": "LM-KGMM",
148
+ "Method": "Score-based Levenberg-Marquardt (KGMM)",
149
+ "parallelism": "serial",
150
+ "update_type": "gradient",
151
+ "method_goal": "optimization",
152
+ "emulator_use": "none",
153
+ "aliases": [
154
+ "lm-kgmm",
155
+ "score-based lm (gfdt, kgmm) (extended window)",
156
+ "score-based lm (gfdt, kgmm) (parallel branches)",
157
+ ],
158
+ },
159
+ "lm-dsm": {
160
+ "abbreviation": "LM-DSM",
161
+ "Method": "Score-based Levenberg-Marquardt (DSM)",
162
+ "parallelism": "serial",
163
+ "update_type": "gradient",
164
+ "method_goal": "optimization",
165
+ "emulator_use": "none",
166
+ "aliases": [
167
+ "lm-dsm",
168
+ "score-based lm (gfdt, dsm) (extended window)",
169
+ "score-based lm (gfdt, dsm) (parallel branches)",
170
+ ],
171
+ },
172
  }
173
 
174
 
175
+ # One slot per method in KNOWN_METHODS declaration order. New methods appended
176
+ # to KNOWN_METHODS get the next slot.
177
+ #
178
+ # Generated by a greedy farthest-point search in OKLab: each slot was chosen to
179
+ # maximize its minimum distance to every slot before it, simultaneously under
180
+ # normal vision and simulated protan/deutan color-vision deficiency (Machado,
181
+ # Oliveira & Fernandes 2009 severity-1.0 transforms — the same model used by
182
+ # the dataviz skill's validate_palette.js). Because this optimizes the running
183
+ # ALL-PAIRS minimum (not just adjacent-slot pairs), the printed ΔE at slot k
184
+ # below is a genuine worst-case guarantee for any subset of the first k slots
185
+ # shown together — relevant here because any subset of methods can appear
186
+ # together via the "Methods to display in charts" multiselect, not just
187
+ # neighbors in this list.
188
+ #
189
+ # Honest limits (OKLab ΔE x100; CVD = min(protan, deutan)):
190
+ # - Slots 0-15 (16 colors): CVD >= 8.0 — clears the full colorblind-safety
191
+ # target for every pair among any subset of these.
192
+ # - Slots 16-27 : CVD in [6.0, 8.0) — the legal "floor" band per
193
+ # the skill (secondary encoding required). This app already provides it:
194
+ # every legend and tooltip in leaderboard.py shows the method abbreviation
195
+ # as text, so identity is never color-alone even where hue alone is weak.
196
+ # - Slots 28-29 : CVD ~5.8, just under the 6.0 floor for their
197
+ # closest pair — weakest two slots, kept only for the requested headroom.
198
+ # - Normal-vision floor (>=15, a hard gate when checked in isolation): holds
199
+ # for the first ~6 slots against ALL other slots; beyond that, some pairs
200
+ # among 30 simultaneously-distinguishable colors are close even for
201
+ # full-color vision. This is a geometry limit of a finite perceptual
202
+ # space, not a search-quality issue — the reference palette in the dataviz
203
+ # skill's own docs states plainly that no ordering clears all-pairs floors
204
+ # past ~8 categories. 30 slots were requested anyway for growth headroom;
205
+ # rely on the legend/tooltip text labels (already present) for identity,
206
+ # not on hue alone, especially past slot ~16.
207
+ # Re-run the search (seeded with all prior slots fixed) if extending further.
208
  _METHOD_PALETTE = [
209
+ "#d80065", "#007fff", "#ff9700", "#00cae4", "#6d00b8", "#970f00",
210
+ "#007ca4", "#de8580", "#00a0d7", "#fa0000", "#0100ff", "#90006d",
211
+ "#e500a0", "#007656", "#008200", "#006dd1", "#00b7ad", "#47b3ff",
212
+ "#0087d2", "#e97e00", "#ec9f72", "#4b4589", "#00d0ae", "#c87181",
213
+ "#5194ff", "#9c5683", "#0058ff", "#892348", "#e2003d", "#00b5d5",
214
  ]
215
 
216
  # Stable abbreviation → hex color mapping. Import this wherever Altair charts are built
217
+ # so every plot in the app assigns the same color to each method. With 30 palette
218
+ # slots and 14 registered methods, every method gets a unique color — the modulo
219
+ # below only matters as a defensive fallback if KNOWN_METHODS grows past 30 without
220
+ # the palette being extended first (see comment above).
221
  METHOD_COLORS: dict[str, str] = {
222
  meta["abbreviation"]: _METHOD_PALETTE[i % len(_METHOD_PALETTE)]
223
  for i, meta in enumerate(KNOWN_METHODS.values())
src/data_store.py CHANGED
@@ -35,6 +35,8 @@ DATASET_FILES = {
35
  "bayesian/l63_hm.nc",
36
  "adam_results/leaderboard_adam_l63_2026-06-26.nc",
37
  "levenberg_marquardt_results/leaderboard_lm_l63_2026-06-29.nc",
 
 
38
  ],
39
  "L96": [
40
  "l96_ensemble_results.nc",
@@ -42,10 +44,14 @@ DATASET_FILES = {
42
  "bayesian/l96_abc.nc",
43
  "adam_results/leaderboard_adam_l96_const-force_2026-06-26.nc",
44
  "levenberg_marquardt_results/leaderboard_lm_l96_const-force_2026-06-29.nc",
 
 
45
  ],
46
  "L96_NN_FORCING": [
47
  "l96_nn_forcing_ensemble_results.nc",
48
  "UKI_results/uki_l96_nn_forcing_ensemble_results.nc",
 
 
49
  ],
50
  "L96_SPATIAL_FORCING": [
51
  "l96_spatial_forcing_ensemble_results.nc",
@@ -53,6 +59,8 @@ DATASET_FILES = {
53
  "bayesian/l96_varying_abc.nc",
54
  "adam_results/leaderboard_adam_l96_vec-force_2026-06-26.nc",
55
  "levenberg_marquardt_results/leaderboard_lm_l96_vec-force_2026-06-29.nc",
 
 
56
  ],
57
  }
58
 
 
35
  "bayesian/l63_hm.nc",
36
  "adam_results/leaderboard_adam_l63_2026-06-26.nc",
37
  "levenberg_marquardt_results/leaderboard_lm_l63_2026-06-29.nc",
38
+ "opt_kgmm_score_lm/leaderboard_sblm_kgmm_parallel_l63_2026-08-12.nc",
39
+ "opt_dsm_score_lm/leaderboard_sblm_dsm_parallel_l63_2026-08-12.nc",
40
  ],
41
  "L96": [
42
  "l96_ensemble_results.nc",
 
44
  "bayesian/l96_abc.nc",
45
  "adam_results/leaderboard_adam_l96_const-force_2026-06-26.nc",
46
  "levenberg_marquardt_results/leaderboard_lm_l96_const-force_2026-06-29.nc",
47
+ "opt_kgmm_score_lm/leaderboard_sblm_kgmm_parallel_l96_const-force_2026-08-12.nc",
48
+ "opt_dsm_score_lm/leaderboard_sblm_dsm_parallel_l96_const-force_2026-08-12.nc",
49
  ],
50
  "L96_NN_FORCING": [
51
  "l96_nn_forcing_ensemble_results.nc",
52
  "UKI_results/uki_l96_nn_forcing_ensemble_results.nc",
53
+ "opt_kgmm_score_lm/leaderboard_sblm_kgmm_parallel_l96_flux-force_2026-08-12.nc",
54
+ "opt_dsm_score_lm/leaderboard_sblm_dsm_parallel_l96_flux-force_2026-08-12.nc",
55
  ],
56
  "L96_SPATIAL_FORCING": [
57
  "l96_spatial_forcing_ensemble_results.nc",
 
59
  "bayesian/l96_varying_abc.nc",
60
  "adam_results/leaderboard_adam_l96_vec-force_2026-06-26.nc",
61
  "levenberg_marquardt_results/leaderboard_lm_l96_vec-force_2026-06-29.nc",
62
+ "opt_kgmm_score_lm/leaderboard_sblm_kgmm_parallel_l96_vec-force_2026-08-12.nc",
63
+ "opt_dsm_score_lm/leaderboard_sblm_dsm_parallel_l96_vec-force_2026-08-12.nc",
64
  ],
65
  }
66
 
src/pages/MethodDetails.py CHANGED
@@ -22,6 +22,10 @@ st.sidebar.page_link("pages/RawData.py", label="Get Data", icon="🧾")
22
 
23
  st.title("Method Details")
24
  st.caption("Method-level view from NetCDF forward-model-run metrics averaged over random seeds")
 
 
 
 
25
 
26
  # Read selected method from query params
27
  abbr = st.query_params.get("method")
@@ -99,6 +103,16 @@ method_meta = {
99
  "url": "https://arxiv.org/abs/2508.13071",
100
  "summary": "Goal-oriented Bayesian Optimal Experimental Design — selects each batch of forward-model evaluations by maximizing an expected-information-gain criterion targeted at the quantity of interest, refitting the surrogate used by the criterion at every iteration.",
101
  },
 
 
 
 
 
 
 
 
 
 
102
  }
103
 
104
  # Selection UI (defaults to query param if valid)
 
22
 
23
  st.title("Method Details")
24
  st.caption("Method-level view from NetCDF forward-model-run metrics averaged over random seeds")
25
+ st.markdown(
26
+ "For the exact implementation of each algorithm, see "
27
+ "[CalibrationLeaderboard.jl](https://github.com/odunbar/CalibrationLeaderboard.jl)."
28
+ )
29
 
30
  # Read selected method from query params
31
  abbr = st.query_params.get("method")
 
103
  "url": "https://arxiv.org/abs/2508.13071",
104
  "summary": "Goal-oriented Bayesian Optimal Experimental Design — selects each batch of forward-model evaluations by maximizing an expected-information-gain criterion targeted at the quantity of interest, refitting the surrogate used by the criterion at every iteration.",
105
  },
106
+ "LM-KGMM": {
107
+ "citation": "Giorgini, Bischoff & Souza, arXiv:2503.18054, 2025",
108
+ "url": "https://arxiv.org/abs/2503.18054",
109
+ "summary": "Score-based Levenberg-Marquardt using a K-means Gaussian Mixture Model to estimate the score function, which drives the gradient via the generalized fluctuation-dissipation theorem (GFDT).",
110
+ },
111
+ "LM-DSM": {
112
+ "citation": "Giorgini, Bischoff & Souza, arXiv:2509.19660, 2025",
113
+ "url": "https://arxiv.org/abs/2509.19660",
114
+ "summary": "Score-based Levenberg-Marquardt using Denoising Score Matching to estimate the score function, which drives the gradient via the generalized fluctuation-dissipation theorem (GFDT).",
115
+ },
116
  }
117
 
118
  # Selection UI (defaults to query param if valid)
src/streamlit_app.py CHANGED
@@ -28,6 +28,10 @@ st.markdown(
28
  "Methods are ranked by **forward-model run efficiency** — how many forward-model "
29
  "evaluations are needed, on average across random seeds, to reach a target accuracy."
30
  )
 
 
 
 
31
 
32
  st.divider()
33
 
 
28
  "Methods are ranked by **forward-model run efficiency** — how many forward-model "
29
  "evaluations are needed, on average across random seeds, to reach a target accuracy."
30
  )
31
+ st.markdown(
32
+ "The exact implementations of every algorithm benchmarked here are available at "
33
+ "[CalibrationLeaderboard.jl](https://github.com/odunbar/CalibrationLeaderboard.jl)."
34
+ )
35
 
36
  st.divider()
37