fix: correct Wright COI algorithm — handle direct parent-offspring pairings #44

Merged
jason merged 1 commits from fix/coi-direct-ancestor-logic into master 2026-03-10 14:48:04 -05:00
Owner

Bug

The Trial Pairing Simulator showed 0.00% COI / 0 common ancestors even when the selected sire is a direct parent of the dam (or vice versa).

Root Cause

The old calculateCOI called getAncestors(sireId) and getAncestors(damId), which started traversal at the parents of each dog (generation 1+). This meant the sire and dam themselves were never included in each other's ancestor maps, so a direct parent-offspring relationship was invisible to the algorithm.

Example

  • River is the sire (parent) of dog 2
  • getAncestors(River) → River's parents, grandparents…
  • getAncestors(dog2) → River (gen 1), Willow (gen 1), …
  • Cross-check: Is River in sire ancestor list? No — River IS the sire, never added to its own list
  • Result: 0 common ancestors

Fix

Rewritten calculateCOI with a proper getAncestorMap() that:

  1. Includes the dog itself at generation 0 in its own ancestor map
  2. Recurses into parents from there (gen 1, 2, …)
  3. Collects all occurrences of an ancestor (multiple paths) for correct multi-path Wright summation

Wright formula applied per path:

COI contribution = (0.5)^(sireGen + damGen + 1)

Result for River × dog 2:

  • sireMap contains River at gen 0
  • damMap contains River at gen 1 (direct parent)
  • Path: sireGen=0, damGen=1 → (0.5)^(0+1+1) = 0.25 → 25% COI

Additional improvements

  • All path combinations through a common ancestor are summed (not just closest)
  • processedPaths Set prevents double-counting identical paths
  • Generation cap increased from 5 → 6 for better depth coverage
  • Sire and dam themselves excluded from the common ancestor display list

Files Changed

  • server/routes/pedigree.jscalculateCOI function completely rewritten

Note: this branch also includes the SQLite single-quote fix from PR #43.

## Bug The Trial Pairing Simulator showed **0.00% COI / 0 common ancestors** even when the selected sire is a direct parent of the dam (or vice versa). ## Root Cause The old `calculateCOI` called `getAncestors(sireId)` and `getAncestors(damId)`, which started traversal at the **parents** of each dog (generation 1+). This meant the sire and dam themselves were never included in each other's ancestor maps, so a direct parent-offspring relationship was invisible to the algorithm. ### Example - **River** is the sire (parent) of **dog 2** - `getAncestors(River)` → River's parents, grandparents… - `getAncestors(dog2)` → River (gen 1), Willow (gen 1), … - Cross-check: Is River in *sire* ancestor list? **No** — River IS the sire, never added to its own list - Result: 0 common ancestors ❌ ## Fix Rewritten `calculateCOI` with a proper `getAncestorMap()` that: 1. **Includes the dog itself at generation 0** in its own ancestor map 2. Recurses into parents from there (gen 1, 2, …) 3. Collects **all occurrences** of an ancestor (multiple paths) for correct multi-path Wright summation ### Wright formula applied per path: ``` COI contribution = (0.5)^(sireGen + damGen + 1) ``` ### Result for River × dog 2: - sireMap contains River at gen 0 - damMap contains River at gen 1 (direct parent) - Path: sireGen=0, damGen=1 → (0.5)^(0+1+1) = **0.25 → 25% COI** ✅ ## Additional improvements - All path combinations through a common ancestor are summed (not just closest) - `processedPaths` Set prevents double-counting identical paths - Generation cap increased from 5 → 6 for better depth coverage - Sire and dam themselves excluded from the common ancestor display list ## Files Changed - `server/routes/pedigree.js` — `calculateCOI` function completely rewritten > Note: this branch also includes the SQLite single-quote fix from PR #43.
jason added 1 commit 2026-03-10 14:44:50 -05:00
jason merged commit 1dacdc9fe7 into master 2026-03-10 14:48:04 -05:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: jason/breedr#44