fix: COI correctly calculates parent×offspring and direct-relation pairings #47

Merged
jason merged 1 commits from fix/coi-direct-relation into master 2026-03-10 15:09:46 -05:00
Owner

Problem

calculateCOI was returning 0.00% for parent×offspring pairings (e.g. River × Dog2 where River is Dog2's sire).

Root Cause

The commonIds filter had:

.filter(id => damMap.has(id) && id !== sid && id !== did)

Because getAncestorMap includes the dog itself at gen 0, River (the sire, sid) appears in Dog2's damMap at generation 1 — exactly the signal we want. But id !== sid was filtering it out, silently zeroing the COI.

Fix

Removed id !== sid from the filter. Only id !== did is kept to prevent the dam itself appearing as its own common ancestor on the sire's side (a genuine reflexive loop).

// Before
const commonIds = [...sireMap.keys()].filter(
  id => damMap.has(id) && id !== sid && id !== did
);

// After
const commonIds = [...sireMap.keys()].filter(
  id => damMap.has(id) && id !== did
);

Expected Results

Pairing Before After
River × Dog2 (parent×offspring) 0.00% ~25.00%
Unrelated dogs 0.00% 0.00% (unchanged)
Normal shared ancestor correct correct (unchanged)

Testing

  • Restart server after merge and test River × Dog2 in Trial Pairing Simulator
  • Verify COI shows ~25% and River appears in Common Ancestors at gen 1
## Problem `calculateCOI` was returning `0.00%` for parent×offspring pairings (e.g. River × Dog2 where River is Dog2's sire). ## Root Cause The `commonIds` filter had: ```js .filter(id => damMap.has(id) && id !== sid && id !== did) ``` Because `getAncestorMap` includes the dog itself at `gen 0`, River (the sire, `sid`) appears in Dog2's `damMap` at generation 1 — **exactly the signal we want**. But `id !== sid` was filtering it out, silently zeroing the COI. ## Fix Removed `id !== sid` from the filter. Only `id !== did` is kept to prevent the dam itself appearing as its own common ancestor on the sire's side (a genuine reflexive loop). ```js // Before const commonIds = [...sireMap.keys()].filter( id => damMap.has(id) && id !== sid && id !== did ); // After const commonIds = [...sireMap.keys()].filter( id => damMap.has(id) && id !== did ); ``` ## Expected Results | Pairing | Before | After | |---|---|---| | River × Dog2 (parent×offspring) | 0.00% | ~25.00% | | Unrelated dogs | 0.00% | 0.00% (unchanged) | | Normal shared ancestor | correct | correct (unchanged) | ## Testing - Restart server after merge and test River × Dog2 in Trial Pairing Simulator - Verify COI shows ~25% and River appears in Common Ancestors at gen 1
jason added 1 commit 2026-03-10 15:09:23 -05:00
- Remove blanket `id !== sid && id !== did` exclusion from commonIds filter
  which was silently zeroing out COI for parent×offspring pairings because
  the sire (sid) IS the common ancestor in damMap but was being filtered out.
- Instead: exclude `did` from sireMap keys (sire can't be its own common
  ancestor with the dam) and exclude `sid` from damMap keys (same logic).
- Parent×offspring pairing now correctly yields ~25% COI as expected by
  Wright's path coefficient method.
- All other normal pairings are unaffected.
jason merged commit af9398ec0f into master 2026-03-10 15:09:46 -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#47