feat: add multi-genome SNP pseudo-alignment and CLI export
Introduces a `SnpAlignment` struct and helper methods to construct per-genome SNP pseudo-alignments from sibling k-mer data, filtering monomorphic families and encoding bases as IUPAC ambiguity codes. Exposes the type at the crate root for simplified imports. Adds a `--snp` CLI flag to compute and export these alignments as an IUPAC-coded FASTA file. Updates theory documentation to propose a multi-genome framing approach for joint phylogenetic inference, resolving pairwise correspondence ambiguities through positional homology and partial coverage thresholds. Bumps crate version to 1.1.40.
This commit is contained in:
@@ -146,6 +146,63 @@ A once multiplicity > 1 on either side. Any pairing rule invents a
|
||||
correspondence the data cannot support. Multiplicity > 1 is treated as
|
||||
non-identifiable, not as a puzzle to solve with a heuristic.
|
||||
|
||||
## Multi-genome framing: family as pseudo-alignment column
|
||||
|
||||
**Idea.** Instead of resolving locus eligibility and correspondence one
|
||||
genome pair at a time, treat a family as a column of a pseudo multiple
|
||||
alignment across *all* genomes simultaneously: for each family, each genome
|
||||
has either a net single-copy state (`A`/`C`/`G`/`T`, when the genome carries
|
||||
exactly one of the 4 forms) or "missing" (`?`, multi-copy or absent). Flank
|
||||
conservation (the `2m` bases fixed by construction) supplies positional
|
||||
homology for free — the same role a real MSA would play, without alignment
|
||||
software, gap penalties, or progressive-alignment approximations. Stacking
|
||||
one such column per family, genomes as rows, produces a genuine SNP
|
||||
pseudo-alignment matrix, not just a bag of pairwise distances.
|
||||
|
||||
**Precedent.** This is the same principle behind reference-free
|
||||
k-mer-based phylogenomics tools — SKA (Split K-mer Analysis, Harris 2018) and
|
||||
kSNP: split the k-mer around a variable center, use flank identity to call
|
||||
homologous columns across arbitrarily many genomes with no reference and no
|
||||
MSA step, then feed the resulting pseudo-alignment to standard phylogenetic
|
||||
tools. Landing on the same design independently is a good sign, not a
|
||||
coincidence.
|
||||
|
||||
**Resolves the pairwise-correspondence problem, properly.** The "Rejected:
|
||||
parsimony-based multiset pairing" case above failed because, with only two
|
||||
genomes' cardinalities to look at, there is no external constraint to justify
|
||||
picking one correspondence between leftover alleles over another — `min(a,b)`
|
||||
is a lower bound dressed up as a point estimate (see the follow-up discussion
|
||||
on Felsenstein-style parsimony inconsistency: minimum-event explanations are
|
||||
systematically biased low whenever homoplasy/multiplicity is real, not
|
||||
noise-cancelling). With `N` genomes and many families jointly, the same
|
||||
question can be answered the way real phylogenetics answers it: ancestral
|
||||
state reconstruction / ML mapping over a tree estimated from the whole
|
||||
column set. The tree supplies the missing constraint that two isolated
|
||||
columns cannot — this is the principled way out, not a heuristic replacement
|
||||
for one.
|
||||
|
||||
**Relation to what's already implemented.** `KmerIndex::raw_snp_distance`
|
||||
already computes, internally, per family, exactly this row — `single_form:
|
||||
Vec<Option<u8>>`, one entry per genome, `None` where ambiguous/absent —
|
||||
before immediately collapsing it into pairwise `snp[i,j]`/`shared[i,j]`
|
||||
tallies. The pivot this section proposes is small at the implementation
|
||||
level: stop collapsing early, and surface the per-family row as a first-class
|
||||
artifact (a `families x genomes` matrix). Pairwise raw p-distance becomes one
|
||||
projection of that matrix (what's computed today), not the primary object;
|
||||
downstream, the matrix itself could feed real phylogenetic tools (parsimony/
|
||||
ML, e.g. RAxML/IQ-TREE-style) instead of only NJ/UPGMA on a homemade
|
||||
pairwise-distance matrix.
|
||||
|
||||
**Caveat: column completeness shrinks with `N`.** The probability that a
|
||||
family's flanks stay intact simultaneously across all `N` genomes decays with
|
||||
`N` (same ascertainment-bias mechanism as Bias 1 above, compounded over more
|
||||
genomes) — fully-resolved columns (no `?` anywhere) become rare as more
|
||||
genomes are added. Same missing-data situation any real multi-species
|
||||
alignment faces, and phylogenetic tools already handle it well; the practical
|
||||
implication is that columns should be allowed partial coverage (>=2 resolved
|
||||
genomes, not unanimous) rather than requiring every genome to be net
|
||||
single-copy at that locus.
|
||||
|
||||
## Heterozygosity, ploidy, and consensus-assembly inputs
|
||||
|
||||
A within-genome multiplicity signal (more than one of the 4 central forms
|
||||
|
||||
Reference in New Issue
Block a user