Skip to content

Pedigrees And Ainv ​

HSquared.jl now has the first Phase 1 engine utility: pedigree normalization and direct sparse inverse additive relationship matrix construction.

Pedigree Contract ​

Input is three equal-length vectors:

  • ids: animal identifiers;

  • sire: sire identifiers or unknown-parent markers;

  • dam: dam identifiers or unknown-parent markers.

By default, unknown parents are represented by missing, nothing, "", "0", or 0.

normalize_pedigree checks that:

  • IDs are present and unique;

  • parent labels are either unknown or listed in ids;

  • an animal is not its own parent;

  • sire and dam are not the same known parent;

  • the parent graph has no cycle.

It returns a Pedigree whose rows are topologically sorted and whose sire and dam fields are integer parent indices. 0 means unknown parent.

The exported Pedigree(ids, sire, dam, original_order) constructor accepts already-indexed data and checks equal lengths, unique IDs, parent indices that refer only to earlier rows (or 0), and a valid permutation for original_order. Use normalize_pedigree for raw parent labels and sorting.

Direct Sparse Inverse ​

pedigree_inverse applies Henderson's direct contribution pattern. Each animal adds a scaled outer product over itself and its known parents. Founder animals therefore contribute a single diagonal term; offspring with two known parents contribute to the animal, parent, and parent-offspring entries.

julia
using HSquared

ped = normalize_pedigree(
    ["calf", "sire", "dam"],
    ["sire", "0", "0"],
    ["dam", "0", "0"],
)

Matrix(pedigree_inverse(ped))
3×3 Matrix{Float64}:
  1.5   0.5  -1.0
  0.5   1.5  -1.0
 -1.0  -1.0   2.0

The implementation computes parental inbreeding values through a bounded relationship cache. That is adequate for validation and initial engine work. It is not a huge-pedigree performance claim.

Validation Boundary ​

Covered now:

  • founder, one-known-parent, and two-known-parent hand checks;

  • reordering where offspring appear before parents in the input;

  • inbreeding coefficient check on a tiny pedigree;

  • external R-side optional comparator evidence: nadiv::Mrode9 plus nadiv::makeAinv() agrees with Julia pedigree_inverse() at tolerance 1e-10 in the R twin's live validation test;

  • duplicate ID, unknown parent, self-parent, same known sire/dam, cycle, and cache-limit errors.

Still planned:

  • production-scale pedigree algorithms;

  • unknown parent groups;

  • further inbreeding and relationship-matrix comparator checks against packages such as AGHmatrix;

  • Gaussian animal-model fitting.