toxsim — a testbed for the TransTissue / ToxCompl / GenTox program

Runnable code for the claims in ../14_RESEARCH_AGENDA.md. Pure numpy + scipy + pandas. No torch, no GPU, no real data required.

Why synthetic data

Most Tier-0 questions are of the form “does a trivial baseline beat the deep model?” — and that can be asked of any dataset with the right shape, real access or not.

More importantly: on real data, if the mean predictor beats TransTissueFormer, you cannot tell whether the model is bad or whether translation is impossible. Here that knob is set explicitly.

The simulator is not a claim about biology. It’s a place to test claims about algorithms. exp02 is the clearest case: it tests a property of Funk-SVD’s output, which is pure algebra, so the toy setting doesn’t threaten the conclusion.

Setup

pip install numpy scipy scikit-learn pandas --break-system-packages

Run

python toxsim/simulate.py            # sanity-check vs the real Tables 1 and 3
python toxsim/metrics.py             # what do trivial/adversarial models score?
python toxsim/fit_panels.py          # fit study panels to Table 3
python experiments/exp01_baselines.py   # the mean/zero/identity/ridge baselines
python experiments/exp02_rank_test.py   # is the augmented task secretly linear?

Layout

toxsim/
  simulate.py      synthetic DrugMatrix; matches Tables 1 & 3
  metrics.py       MAE, rare MAE, MaxAE, sign-flip, row/col PCC
  completion.py    Funk-SVD (= ToxCompl), Algorithm 1's split, and a strict split
  baselines.py     zero, mean, identity, scaled identity, ridge
  fit_panels.py    NNLS fit of study panels to Table 3
experiments/
  exp01_baselines.py   what do the baselines score?
  exp02_rank_test.py   is the augmented task secretly linear?
results/             CSVs

What the simulator matches

propertysyntheticreal (TransTissue)
extremely-under0.03%0.03%
under4.03%4.09%
normal92.00%91.94%
over3.91%3.88%
extremely-over0.03%0.04%
Table 3 pair countsmean abs err 5.4
structural zeros24 / 24

Rows are (tissue, gene), columns are treatments. Missingness comes from study panels fitted to Table 3, so the structural zeros are reproduced exactly — including BR–LI = 0, which is the zero-shot case.

The generative model

is the knob. , .

  • → mean predictor wins; “translation” is an illusion
  • → translation requires genuinely recovering

We don’t know where real DrugMatrix sits. That’s the point of exp01.

Findings

exp01 — the mean predictor (which never looks at the source) scores in the “mostly generic” regime. TransTissueFormer reports 0.793. Not proof of anything about real data — proof that 0.793 is consistent with a model that learned nothing drug-specific.

Also: the mean predictor’s row-wise PCC is undefined (constant rows). Row-wise PCC is exactly the metric that exposes it. GenTox §2.3 argues for row-wise metrics; TransTissue doesn’t report them.

exp02 — the Funk-SVD-augmented translation task is exactly affine. Ridge scores , MAE . The analytic construction , with no fitting at all, also scores . recovers at correlation .

fit_panels — Table 3 decomposes exactly into 24 study panels (residual 0.0, all 24 structural zeros). Strong evidence missingness is study-design block structure, i.e. MNAR, contra TransTissue §5’s stated MAR assumption.

Bugs found along the way (kept on purpose)

Two real bugs, documented rather than quietly fixed, because both are easy to repeat:

  1. Column-normalizing shrank the drug-specific term by , making translation impossible by accident. The bug produced a plausible-looking result — Funk-SVD “worked,” baselines “ran,” nothing crashed. Check your normalizations.

  2. Deriving tissue coverage from Table 2 (endpoint counts) instead of Table 3’s diagonal (treatment counts). Endpoints = treatments × probes, so it’s the wrong denominator. Produced BM–SP = 0 pairs where the real data has 161.

And one wrong prediction, in exp02: the original claim was . It’s , flat in . is an upper bound; Funk-SVD doesn’t use its capacity. The corrected version is stronger — the augmented task can be nearly rank-one. See ../16_MATH_NOTES.md §2.5.

The compare_tissue_pairs_confounded function in exp01 is also deliberately wrong — it’s the confounded comparison, kept next to the controlled one, because the confound is the same one lurking in the real HE–TM vs LI–KI observation.

Swapping in real DrugMatrix

Everything downstream needs only:

sim.truth[tissue]   # (n_genes, n_treatments) values
sim.mask[tissue]    # (n_genes, n_treatments) bool, True = measured
sim.stacked()       # -> (G, mask, row_tissue) in DrugMatrix layout

Write a loader exposing those three and every experiment runs unchanged.

Honest limits

  • Linear-Gaussian plus spikes. Real biology is not. Anything that only works here is unproven.
  • 500 genes, ≤2700 treatments. Real is 8,565 × 2,700 (CodeLink) and 375,000 rows stacked across platforms.
  • No platform axis. One platform only; TransPlatformer’s problem isn’t modelled.
  • The panel decomposition isn’t unique (36 equations, 47 candidates). It’s a valid decomposition of Table 3, not the study design. The original study metadata would settle it.
  • The tissue families are invented. HE/TM sharing 85% of their loadings is my encoding of the paper’s biological argument, not a measurement.