Repository navigation
Faster DP, an optional convex gap, and a guide-tree fix; includes #1 - #2
Merged
Merged
Conversation
poa() started the traceback at the end-row cell with op = M_OP, but the forward DP sets that cell to max(M, D, I). When the band of every predecessor of the end node stops short of the last query column (e.g. a short branch straight into the sink), the optimum reaches the last column through insertions in the end row itself, M == I there, and the traceback threw "backtrack found no predecessor". Start with ALL_OP, like every other cell. Walking the end row then exposed a second problem: a real query base scored against the end row's virtual N was emitted as a (mis)match to the end node, which corrupted the graph in add_path (double free). Emit it as an insertion instead. Reproducer: 3 sequences 5051/17/1352 bp, the 17 bp one a prefix of the first, -O -600 -E -4 -b 1000 -f 10 (cactus bar settings). Output is byte-identical to before on every input that did not crash. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Speed, with alignments unchanged: - The horizontal gap recurrence, which ran one column at a time and took 63% of poa(), is now a vectorised decaying prefix-max scan, fused with the M/D pass, with a fast path for single-predecessor rows. - DP scratch is kept on the parameter handle between minipoa_msa() calls. A fresh buffer per call faulted its whole matrix in every time: 49M page faults on 8Mb of human/mouse through cactus bar, and more system time than alignment time. - The static band is centred on the edge-weighted mean position of the sequences through each node, not the heaviest path's length, which strings together every sequence's insertions and widened every row. - Gap states are stored as 16-bit saturating distances below M (exact; open + extension penalties of 32768 or more are now rejected), and rows are streamed to the matrices with non-temporal stores while successors read a cache-resident ring of recent rows. The DP is memory-bound: at 8 threads it ran no faster than at 2. - When the traceback finds no path through the band, poa() aligns that query again without one instead of failing. On 8Mb of human/mouse at 8 threads, cactus bar went from 29s and 3.1GB to 10s and 3.5GB, with identical output. Accuracy (opt-in): - An optional second gap piece makes the gap cost convex, as abPOA's is: minipoa_set_gap2(), and --gap_open2/--gap_ext2 on the command line. - The guide tree skipped every minimizer found in more than a quarter of the sequences, so below 8 sequences every similarity was 0 and progressive mode kept the input order. Minimizers in 16 or fewer sequences are now always used. With both, and abPOA's gaps (400/30 and 1200/1), cactus's evolver mammals test goes from 0.846/0.646 to 0.854/0.652 (abPOA 0.853/0.652). Fixes: - mg_chain_backtrack() read t[-1] for an anchor with no predecessor. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The traceback asks only two things of I (and I2): is it the cell's score, and did it open at this column rather than extend from the one before. It is always one or the other, being the larger of the two, so the DP now keeps those two bits, computed from the exact values, in place of a 16-bit value: 8 bytes a cell become 6.25, and 12 become 8.5 with a convex gap. The "opened" bit comes out of the scan a column early and is stored that way, so it costs the DP no shuffles. Alignments are unchanged. On 8Mb of human/mouse at 8 threads, cactus bar goes from 10s and 3.5GB to 9s and 2.8GB, and with the convex gap from 14s and 5.6GB to 12s and 4GB. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The convex traceback had the two problems #1 fixes in the single-piece one. It started from M alone, although the end cell holds the max of all five states, so when the band let the optimum reach the last column only along the end row it found no predecessor. And had it walked the end row, it would have emitted a real query base scored against the end row's virtual N as a match to the end node. Start from ALL2_OP, and emit such a base as an insertion. The unbanded retry had been covering for this: #1's window aligned, but without its band. On inputs shaped like it (a sequence, a short exact prefix of it, then an unrelated one; 150 of them, in input order) the convex traceback now never needs the retry, against 9 before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fixes "backtrack found no predecessor" in the single-piece traceback; the previous commit does the same for the convex one. #1's window now aligns in its band, to #1's exact output, with either gap model. Everywhere else the output is unchanged. 203 runs over the simulated sets (seven parameter sets, bands down to 10, seeding) are identical to the previous version, and so are 1072 of 1080 over random prefix, suffix and internal fragments taken in input order. The other 8 are windows the previous version could only align through the unbanded retry; this aligns them in their band. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Merged
4 tasks done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Makes minipoa a faster and, with the new options, as-accurate alternative to abPOA as cactus bar's base aligner. Used by ComparativeGenomicsToolkit/cactus#2026. This includes #1, merged in and ported to the new convex traceback, so merging this should mark #1 as merged too.
Evolver mammals (mafComparator), with cactus's new
<minipoa>defaults: 0.846 / 0.646 → 0.854 / 0.652 (abPOA 0.853 / 0.652).Speed, with identical alignments (0416daa, 89987e2)
poa(). It is now a vectorised decaying prefix-max scan, fused with the M/D pass, with a fast path for single-predecessor rows.minipoa_msa()calls. A fresh buffer per call faulted the whole matrix in each time: 49 M page faults on the human/mouse run.Accuracy (opt-in; cactus turns both on)
minipoa_set_gap2(), and--gap_open2/--gap_ext2on the command line. This adds a convex traceback.Robustness
poa()retries that query unbanded instead of failing.mg_chain_backtrack()no longer readst[-1]for an anchor with no predecessor.Testing
cactus-integration, and no new ones.cactus builds minipoa only on x86 for now (it is off on ARM), so the ARM path is untested.
Please merge with a merge commit rather than squash/rebase, so the commits cactus pins stay reachable.
🤖 Generated with Claude Code