Skip to content

Verify the assembled gradient against finite differences on every real gntr problem, not just fixtures #535

Description

@wshlavacek

Summary

The gradient path's FD oracles all run on purpose-built fixtures — small SBML/BNGL models written
to exercise one seam each. That suite is green and has been for the whole #385 epic.

The first time an FD check was pointed at a real model from the benchmark corpus, it found a bug
in under an hour: #534, where a free parameter bound by id that reached the trajectory only by seeding
another entity assembled to exactly 0 against a central difference of -10.4, stable at every step
size. No fixture had that shape, because the shape comes from how COPASI exports SBML, not from
anything a hand-written test would think to write.

Eleven slugs in the subset-I corpus run job_type = gntr. One of them has ever had its gradient
compared against finite differences. This issue is to do the other ten.

Why this is worth real time

  • A wrong gradient column does not fail loudly. The objective stays correct, score.py still reports
    a valid OG, and the fit simply searches with less information. Laske solved at OG = 0.104 with a
    dead column and at -1e-06 without one, using an identical budget — the only visible symptom was
    a fit that stopped a bit short.
  • The corpus is a far better generator of shapes than we are. It carries COPASI aliasing, mixed
    natural-log and linear noise, prediction-dependent σ, per-measurement σ sidecars, replicate
    observableParameters, t=0-only experiments, steady-state measurements, and pre-equilibration.
  • Each check is cheap: ~2·k simulations plus one, i.e. a couple of minutes for most slugs.

The work

Run tools/fd_check.py (in the corpus, wshlavacek/BNGL-Models) at each slug's PEtab nominal point
and record the worst relative error per slug. The gntr slugs not yet checked:

  • Armistead_CellDeathDis2024 (k=14) — prediction-dependent σ
  • Blasi_CellSystems2016 (k=9) — steady-state (time = inf) measurements, lnnormal
  • Boehm_JProteomeRes2014 (k=9) — ratio-formula observables
  • Bruno_JExpBot2016 (k=13) — all 13 parameters routed through condition parameter references
  • Crauste_CellSystems2017 (k=12) — fixed per-point σ
  • Fiedler_BMCSystBiol2016 (k=22) — replicate observableParameters
  • Rahman_MBS2016 (k=9)
  • Raia_CancerResearch2011 (k=39) — prediction-dependent σ, largest k
  • SalazarCavazos_MBoC2020 (k=6)
  • Sneyd_PNAS2002 (k=15)
  • Zhao_QuantBiol2020 (k=28) — per-measurement σ sidecars (ADR-0083)

(Laske_PLOSComputBiol2019 is done: worst 2.5e-03 across 13 columns, after #534.)

Anything that turns up gets its own issue and fix here; the corpus side is tracked at
wshlavacek/BNGL-Models#38.

Doing it correctly

tools/README.md in the corpus records two failure modes that both produce a plausible wrong
answer
rather than an error, and I hit both:

  • Score the Result before assembling. Otherwise the objective's _pset_values is unbound and its
    measurement layer unmaterialized, and every free parameter living in an observable formula or a
    noise scale reads back as exactly 0.0 — indistinguishable from a real defect.
  • Sweep the step size. On a stiff model h = 1e-7 is pure roundoff. A real defect does not move
    with h; FD noise does.

Longer term

If this sweep finds more than one further bug, a standing FD gate over a handful of real models —
rather than only fixtures — is probably worth adding to the recovery tier.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions