Skip to content

Bar scoring by divergence: per-row abPOA and per-pair pecan models, trained per pair of genomes (prototype) - #2024

Closed
glennhickey wants to merge 10 commits into
lastz-score-modelsfrom
bar-row-models
Closed

glennhickey wants to merge 10 commits into
lastz-score-modelsfrom
bar-row-models

Conversation

@glennhickey

@glennhickey glennhickey commented Sep 30, 2026 •

Copy link
Copy Markdown
Collaborator

Prototype for scoring bar by divergence, with models trained automatically per pair of genomes, plus a pangenome last-train speed-up. Draft.

Stacked on #2027 (lastz scoring by divergence, which trains a model per pair of genomes in the blast step), so the base is lastz-score-models. It should be retargeted to master once #2027 merges. Trained bar models are on by default (<bar trainedModels="1">), as is #2027's lastz training. So the shipped config now trains a model per pair of genomes and scores both lastz and bar with it. On evolver mammals that takes the shipped config from 0.816 / 0.739 to 0.836 / 0.742 (pooled leaf pairs). abPOA's trained rows cost up to 0.9 points of ancestor recall against lastz training alone. trainedModels="0" keeps bar's own scoring.

What it adds

Trained bar models (<bar trainedModels>, on by default). The blast step's last-train run on each pair of genomes it aligns also produces that pair's model for bar.

  • Same training as lastz: it's the same run Optional lastz scoring by divergence: a table, or per-pair last-train models (prototype) #2027 uses for lastz. With this switch on, the blast step trains even if lastz doesn't use the models.
  • abPOA: each row is scored with the model for its genome and the nearest ingroup, which is always a pair blast trained. The model is on HOXD70's scale like the shipped matrix, with the trained gap as the first piece and a long-gap piece built the way the pangenome code builds it.
  • pecan: each pair of sequences is scored with the model for its two genomes: a five-state pair HMM made from the trained probabilities.
  • Untrained pairs: pairs blast never trains, such as pecan's outgroup–outgroup pairs, take the model trained nearest their distance in log terms, on the reconstruction tree.
  • Carrying the models: in a single cactus run they go straight from blast to the consolidated job. cactus-blast leaves them next to its PAF as <paf>.models.json, where cactus-align picks them up. cactus-align --trainedModels gives another path; cactus-prepare's WDL and Toil workflows use it. Pangenome alignments come from minigraph, so cactus-align doesn't look for them there.

What the models plug into:

  • Per-row abPOA models: <poa partialOrderAlignmentRowModels="N"> with <rowModelK> children.
  • Per-pair pecan models: <pecan pecanPairModels="N"> with <pairModelK> children.
  • Selection: each model can name a pair of genomes (genomes="A B"), and that pair uses it. Otherwise a model applies to the distances its maxDistance covers. Tables can be written by hand too.
  • abPOA per-read scoring: the row models rely on a new abPOA field, abpoa_para_t.read_abpt, which lets each read be scored with its own parameters.
  • pecan per-pair scoring: the pair models rely on a per-pair callback added to cPecan's multiple aligner.

Deterministic cPecan multiple aligner. The same sequences and models now always give the same alignment, independent of the random generator's state and of memory addresses.

  • Effect in cactus: an end's alignment no longer depends on how many random draws the ends aligned before it used.
  • Evolver mammals: two runs were identical on every genome, and accuracy was unchanged to four decimals.

Pangenome last-train (lastdb -c, -C2). These are LAST's own genome-to-genome recipe; without them each lastal pass spends most of its time aligning tandem repeats. Per pass, CHM13 against GRCh38 chr17 went from 2,831 to 207 CPU-s on the first pass and from about 350 to 60 after it, with the same model.

Evolver mammals

Pooled leaf-pair precision / recall. Rows marked * are from the same harness on this branch before its restack onto the latest master (which added indel placement; the shipped baseline moved by under 0.001):

lastz bar P / R
HOXD70 abPOA, shipped 0.816 / 0.739
HOXD70 abPOA, trained per pair 0.824 / 0.736
HOXD70 abPOA, hand-built per-row table* 0.827 / 0.734
HOXD70 pecan, built-in model* 0.838 / 0.752
HOXD70 pecan, trained per pair 0.841 / 0.754
HOXD70 pecan, hand-built per-pair table* 0.841 / 0.755
trained per pair (#2027) abPOA, trained per pair 0.836 / 0.742
trained per pair pecan, trained per pair 0.855 / 0.760
trained per pair pecan, hand-built table* 0.855 / 0.760
  • Automatic training matches hand-built tables: the per-pair models do as well as tables built from an evolver last-train ladder, with nothing to build.
  • abPOA's trained rows gain precision and lose a little recall, ancestor recall included.
  • pecan's per-pair models gain about 0.3–0.4 points of precision and 0.2 of recall over its built-in model. The hand-built table's gain held on every one of the 10 leaf pairs.
  • Combined: with lastz also trained, pecan reaches 0.855 / 0.760.
  • Both run modes work: cactus-prepare's separate steps and a single cactus run both applied every ancestor's models, and agreed to within 0.0014. With the new defaults, the shipped config reproduces the explicitly switched-on run byte for byte.
  • Tests: the bar and cPecan unit tests pass.
  • cactus-prepare's WDL and Toil workflows: CI showed the WDL passing <paf>.models.json to cactus-align as a second alignment file, and the Toil workflow did the same. Both now pass it with --trainedModels.
    • Local runs: both workflows applied every ancestor's models. Both passed the evolver tests' accuracy check at about 0.874 / 0.654, against a baseline of 0.895 / 0.707 with tolerances of 0.05 / 0.13. A single cactus run of the config shipped before this work scores 0.853 / 0.655 on the same check.
    • WDL: it ran under cromwell 49 with this branch's binaries instead of the docker image.

Submodules

Those should merge first, and these pins then move to the merge commits.

Not in this PR

  • Real-data validation. The 577-way pilot would test whether trained bar scoring is worth it beyond evolver's simulated sequence.

🤖 Generated with Claude Code

@glennhickey glennhickey changed the title Per-row bar scoring models by divergence; faster last-train (prototype) Per-row abPOA and per-pair pecan scoring models by divergence; faster pangenome last-train (prototype) Oct 4, 2026
@glennhickey
glennhickey changed the base branch from last-train-fixes to master October 4, 2026 18:10
@glennhickey glennhickey changed the title Per-row abPOA and per-pair pecan scoring models by divergence; faster pangenome last-train (prototype) Bar scoring by divergence: per-row abPOA and per-pair pecan models, trained per pair of genomes (prototype) Oct 5, 2026
@glennhickey
glennhickey changed the base branch from master to lastz-score-models October 5, 2026 18:11
glennhickey and others added 10 commits October 9, 2026 08:03
Without them each lastal pass spends most of its time aligning tandem
repeats every which way.  On chr17 (4 threads, 1 Mb sample): CHM13 vs
GRCh38 went from 2831 to 207 CPU seconds for the first pass and ~350 to
~60 for each one after; human vs mouse chr11 from ~440 to ~105 a pass.
The trained model is the same to within last-train's own iteration jitter.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pins the fork's main-per-read-params: abPOA as master has it (the fork's
main, v1.5.7 with ai-optimization) plus one commit, an optional
abpoa_para_t.read_abpt, so a caller can score each read against the graph
with its own parameters.  Unset, abPOA is unchanged (identical CLI output
over its test data).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
One matrix scores every row of a POA, but the rows are genomes at very
different distances: two close ingroups and more distant outgroups.  With
<poa partialOrderAlignmentRowModels="N"> and <rowModel0..N-1> children
(each a maxDistance plus its own substitution matrix and gap penalties),
each row is scored with the model for the distance from its genome to the
nearest other genome in the alignment (or the nearest ingroup, with
partialOrderAlignmentRowModelDistance="ingroup"), measured on the
unscaled reconstructionTree.  Off unless configured: with no row models,
evolver mammals aligns exactly as before (identical hal2maf output).

On evolver mammals it keeps the ingroup-distance model's mouse-rat
precision while recovering half the ancestor recall that model loses,
but overall it is within 0.1 F1 of a single matrix at the ingroup
distance.  Evolver primates can't tell them apart.  Needs harder data.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With partialOrderAlignmentRowModelDistance="ingroup", a row with no other
ingroup genome among the rows of its alignment (only one child present,
or only outgroups) was given the default <poa> scoring, which mixes the
shipped matrix into an otherwise trained alignment.  It now takes the
model for its nearest genome of any kind instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
pecan aligns the sequences of an end in pairs, so each pair can be scored
with the model for the distance between its two genomes.  With
<pecan pecanPairModels="N"> and <pairModel0..N-1> children (each a
maxDistance and an hmm: a five-state pair HMM in the JSON hmm_jsonParse
reads), a pair is aligned with the first model whose maxDistance covers
its distance on the reconstruction tree.  Pairs within one genome, and
pairs beyond the last model, keep pecan's built-in model.  Off unless
configured.

The genome distances the abPOA row models used are now shared
(BarDistances, in endAligner).  cPecan moves to pecan-params, which adds
the per-pair callback (makeAlignmentWithPairStateMachines) to the multiple
aligner.

Re-aligning two evolver mammals nodes from fixed lastz output, against the
truth: the ingroup-distance model alone gives the best mouse-rat precision
(+0.29 points over pecan's own) but loses 0.46 points of ancestor recall;
per pair keeps the recall (0.9478 vs 0.9481) and +0.17 of the precision.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
cPecan 2ec01d1 makes the multiple aligner a function of its inputs
alone: the tie-breaking jitter and the spanning-tree tie-break are
hashes rather than draws from sonLib's generator, and nothing is
ordered by address.  Cactus already reseeds the generator per flower,
so its runs were reproducible before.  What changes is that an end's
alignment no longer depends on how many draws the ends aligned before
it in the flower used -- which a change of scoring model alters -- so
comparing two configurations is not confounded by it.

On evolver mammals with stock pecan, two runs are identical on every
genome; against the previous pin, 17 of 4.5 million leaf-pair
alignments change, and accuracy is the same to four decimals.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A <poa> row model or <pecan> pair model can now name the pair of genomes
it is for (genomes="A B"), as one trained on them would, in place of or
as well as a maxDistance.  A pecan pair of sequences uses the model for
their two genomes if there is one, else the first whose maxDistance
covers their distance, as before.  An abPOA row's partner is now kept
along with its distance -- the nearest other genome, or ingroup -- and the
row uses the model for it and its partner, else the distance bins.  The
models with a maxDistance must still come in ascending order of it.
Configs with only maxDistance models behave as they did.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With <bar trainedModels="1">, the blast step's last-train run on each
pair of genomes it aligns (see <blast lastzTrain>, which it now runs
whether or not lastz uses the models) also makes the pair's model for
bar: abPOA's scoring, on HOXD70's scale like the shipped matrix, with the
trained gap as the first piece and a long-gap piece made as the pangenome
makes one; and pecan's five-state pair HMM, from the trained
probabilities.  The consolidated job writes them into bar's config, in
place of any row or pair models there: abPOA scores each row with the
model for its genome and the nearest ingroup (always a pair blast
trained), and pecan each pair of sequences with the model for its two
genomes.  Pairs blast did not train, as pecan's outgroup pairs, take the
model trained nearest their distance in log terms on the reconstruction
tree.  In one cactus run the models pass straight from blast to
consolidated; cactus-blast leaves them next to its PAF, as
<paf>.models.json, for cactus-align.

On evolver mammals (pooled leaf-pair precision/recall), against the
shipped config's 0.816/0.739:
  bar abPOA trained, lastz HOXD70          0.824/0.736 (hand-built per-row table: 0.827/0.734)
  bar pecan trained, lastz HOXD70          0.841/0.754 (hand-built per-pair table: 0.841/0.755)
  lastz and abPOA trained                  0.836/0.742
  lastz and pecan trained                  0.855/0.760 (hand-built pecan table: 0.855/0.760)
cactus-prepare's steps and a single cactus run both applied every
ancestor's models; they agreed to within 0.0014.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
<bar trainedModels> is now on, so with <blast lastzTrain> (on in the
lastz scoring branch) progressive cactus trains a model per pair of
genomes and scores both lastz and bar with it.  cactus-align no longer
looks for trained models next to pangenome alignments, which come from
minigraph, and the consolidated job no longer warns for an ancestor
without them: cactus-align says when a models file it expected is
missing.  Whether lastz uses the models is decided once per ancestor,
so a KegAlign run warns once rather than for every chunk.

On evolver mammals the shipped config now gives the same alignment,
byte for byte, as the earlier run with both switched on: pooled
leaf-pair precision/recall 0.836/0.742, against 0.830/0.744 with lastz
alone trained, and 0.816/0.739 with neither.  abPOA's trained rows
cost up to 0.9 points of ancestor recall there, against 0.830/0.744's;
with pecan, training both gave 0.855/0.760.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
cactus-prepare's WDL and Toil workflows gave cactus-align everything
cactus-blast wrote whose name starts with the PAF's, as alignments.
With <bar trainedModels> on by default, that took in the trained models
file, <paf>.models.json, and cactus-align stopped with a usage error.

cactus-align now takes the models file with --trainedModels (still the
file next to the PAF by default), and both workflows give it that way.
The WDL's blast task names its two outputs, out_paf and out_models:
cromwell puts the two in different directories, so cactus-align could
not have found the models next to the PAF by itself.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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