Repository navigation
feat(sandbox): two copies of every chromosome, and the carrier state - #35
Merged
Merged
Conversation
The trait layer stated its own limit in prose. Sickle cell carried a note saying "this models one copy" because it had to: one variant copy gives sickle cell trait, two give the disease, and a model with one copy cannot tell the difference. Reporting a carrier as affected and reporting one as unaffected are both wrong, and those were the only options available. DiploidGenome is composition. A diploid genome is not a kind of haploid one, and a haploid one is not a diploid with a piece missing, so neither subclasses the other. MendelianTrait takes a DiploidGenome and is deliberately not interchangeable with Trait, because a diploid trait handed a haploid genome would have to invent a second copy, and inventing one is how a carrier gets reported as clear. The Punnett square is a result here rather than a rule. `cross` samples offspring from one coin flip per chromosome per parent, and 1:2:1 falls out at 24.1 / 51.6 / 24.3 over four thousand children. A hardcoded ratio would make that test worthless; arriving at it by sampling is what makes it evidence the model does meiosis. `inherit` draws a single child, so a student who crosses two carriers and gets an unaffected one sees why a one in four risk is not a promise in either direction. Malaria resistance ships on the same locus, which is the other half of the lesson. A student who sees only the disease learns this variant is a defect. One who sees both learns why it is common where malaria is common, which is a fact about selection rather than about defects. A missing copy returns Zygosity.UNKNOWN rather than counting as a reference copy. That is the one place here where the wrong default is silently wrong in the direction that matters, turning "we do not know" into "you are fine". What is still absent is named: no recombination, so linkage is absolute rather than partial; no sex chromosomes, imprinting or mitochondrial inheritance, so the two parental copies are interchangeable in a way they are not in a person. Both documented examples were corrected after being run. One had an import that would not have worked and one abridged the output it claimed to show.
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.
The trait layer was stating its own limit in prose. Sickle cell carried a note reading "this models one copy" because it had to: one variant copy gives sickle cell trait, two give the disease, and a one-copy model cannot tell the difference.
Reporting a carrier as affected and reporting one as unaffected are both wrong, and those were the only two options available. Now:
The Punnett square as a result, not a rule
crosssamples offspring from one coin flip per chromosome per parent. The classic ratio falls out:A hardcoded ratio would make
test_two_carriers_produce_the_classic_one_two_one_ratioworthless. Arriving at it by sampling is what makes it evidence the model does meiosis rather than reciting an answer.inheritdraws a single child instead, so a student who crosses two carriers and gets an unaffected one has seen why a one in four risk is not a promise in either direction. A square drawn on a board does not show that.One variant, two consequences
Malaria resistance ships on the same locus, evaluated as a separate trait:
A student who sees only the disease learns this variant is a defect. One who sees both learns why it is common where malaria is common, which is a fact about selection rather than about defects. The output says so: a variant is not good or bad on its own; whether it helps depends on where you live and what you are exposed to.
Design notes
DiploidGenomeis composition. A diploid genome is not a kind of haploid one, and a haploid one is not a diploid with a piece missing, so neither subclasses the other.MendelianTraittakes aDiploidGenomeand is deliberately not interchangeable withTrait. A diploid trait handed a haploid genome would have to invent a second copy, and inventing one is exactly how a carrier gets reported as clear.A missing copy returns
Zygosity.UNKNOWNrather than counting as reference. That is the one place here where the wrong default is silently wrong in the direction that matters: it turns "we do not know" into "you are fine".test_a_missing_copy_is_unknown_and_not_a_reference_copyguards it.What is absent, and named
No recombination: meiosis is one coin flip per chromosome, so two genes on the same chromosome are always inherited together where a real genome separates them in proportion to distance. Partial linkage is how gene mapping works and it is not here.
No sex chromosomes, imprinting, or mitochondrial inheritance. All three are real, and their absence makes the two parental copies interchangeable in a way they are not in a person.
Both are in the docs' simplifications list and in
TODO.md.Self-review
mypy --strict, ruff and the voice check clean. Rust untouched, 165 still passing.test_homozygous_builds_two_independent_copiesexists because sharing oneGenomeobject between both copies would make every edit appear on both, which looks like working code until a student edits one allele.