Skip to content

feat: covariate-requirement introspection (#266)#293

Open
seabbs-bot wants to merge 1 commit into
mainfrom
feat/covariate-requirements-266
Open

feat: covariate-requirement introspection (#266)#293
seabbs-bot wants to merge 1 commit into
mainfrom
feat/covariate-requirements-266

Conversation

@seabbs-bot

Copy link
Copy Markdown
Collaborator

Summary

  • required_covariates(tree) lists the covariate names a tree's
    Varying leaves and data-selected Choose disjunctions
    will read, keyed to the node paths that read them (Dict{Symbol, Vector{Symbol}}), so a caller can validate a data source's columns up
    front instead of discovering a gap reactively, one covariate at a time,
    mid-instantiate.
  • required_parameters(tree) is the symmetric sibling: the unpinned
    (estimated) parameters a tree's params_table still needs, as (edge, param) pairs (every row whose prior is not nothing).
  • missing_covariates(tree, ctx) checks a Context against
    required_covariates, returning the (possibly empty) vector of names the
    context is missing, reporting every gap at once rather than the first one
    instantiate happens to reach.
  • A Choose's own selector requirement is labelled with a :selector
    suffix (mirroring how params_table labels a Resolve's own
    branch_probs row), so a root-level Choose reports a real edge name
    instead of an empty path.
  • Lives in varying.jl alongside the existing has_varying guard:
    introspection.jl loads before Varying/Shared/Choose exist, so the
    new tree walk (which needs those types for its per-node dispatch) can't
    live there without a forward-reference load error.

Closes #266.

Test plan

  • New @testitem "required_covariates / required_parameters / missing_covariates (#266)": a stationary tree (empty), a single
    Varying leaf, two leaves sharing one covariate name, a Varying
    nested inside a Resolve outcome, a root-level and nested Choose
    selector requirement (plus a Choose alternative that itself
    contains a Varying leaf), and an uncertain leaf's estimated
    parameter.
  • task test-fast — 1543/1543 passed.

This was opened by a bot. Please ping @seabbs for any questions.

@github-actions

Copy link
Copy Markdown
Contributor

📖 Documentation preview is ready!

View the docs for this PR at: https://EpiAware.github.io/ComposedDistributions.jl/previews/PR293/

This preview will be updated automatically when you push new commits.

@codecov

codecov Bot commented Jul 21, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 85.29412% with 5 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/composers/varying.jl 85.29% 5 Missing ⚠️
Flag Coverage Δ
ad-enzyme-forward 0.00% <0.00%> (ø)
ad-enzyme-reverse 24.30% <0.00%> (-1.09%) ⬇️
ad-forwarddiff 22.57% <0.00%> (-1.02%) ⬇️
ad-mooncake-forward 0.00% <0.00%> (ø)
ad-mooncake-reverse 22.62% <0.00%> (-1.02%) ⬇️
ad-reversediff 22.57% <0.00%> (-1.02%) ⬇️
unit 86.63% <87.87%> (+0.50%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
src/composers/varying.jl 75.00% <85.29%> (+6.48%) ⬆️

... and 3 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Adds required_covariates(tree), listing the covariate names a tree's
Varying leaves and data-selected Choose disjunctions will read, keyed to
the node paths that read them; required_parameters(tree), the symmetric
sibling over unpinned (estimated) parameters read off params_table; and
missing_covariates(tree, ctx), checking a Context against the former so a
caller can validate a data source's columns up front instead of
discovering a gap reactively, one covariate at a time, mid-instantiate.

Lives in varying.jl alongside the existing has_varying guard (introspection.jl
loads before Varying/Shared/Choose exist, so the walk needs their types
already defined).

Co-authored-by: Sam Abbott <contact@samabbott.co.uk>
@github-actions

Copy link
Copy Markdown
Contributor

Try this Pull Request!

Option 1: Julia Package Manager

Open Julia and type:

import Pkg
Pkg.activate(temp=true)
Pkg.add(url="https://github.com/EpiAware/ComposedDistributions.jl", rev="feat/covariate-requirements-266")
using ComposedDistributions

Option 2: Local Checkout

If you have the repo locally:

git checkout feat/covariate-requirements-266
julia --project=. -e "using Pkg; Pkg.instantiate()"

@github-actions

Copy link
Copy Markdown
Contributor

Benchmark comparison vs base

Minimum time per call. Buckets are PR time as a % of base, so lower is faster (🟢 faster, ⚪ within 5%, 🔴 slower). Counts of benchmarks per bucket:

Group 🟢 <50% 🟢 50–75% 🟢 75–95% ⚪ 95–105% 🔴 105–125% 🔴 125–150% 🔴 >150%
Evaluation · 3 3 10 1 · ·
ForwardDiff · · 2 4 1 · ·
ReverseDiff (tape) · · 1 5 1 · ·
Mooncake reverse · · · 1 3 3 ·
Enzyme reverse · · · 6 1 · ·
Evaluation — 17 benchmarks (by time change)
Benchmark base PR time memory
Composition / Parallel / construct 2.23 μs 1.46 μs 🟢 0.65× ⚪ 1.0×
Composition / Sequential / construct 2.0 μs 1.46 μs 🟢 0.73× ⚪ 1.0×
Composition / Parallel / rand 1.72 μs 1.28 μs 🟢 0.74× ⚪ 1.0×
Composition / Sequential / rand 1.72 μs 1.31 μs 🟢 0.76× ⚪ 1.0×
Composition / Nested / rand 5.69 μs 4.35 μs 🟢 0.76× ⚪ 1.0×
Composition / Resolve / logpdf 130.0 ns 140.0 ns 🔴 1.08×
Composition / Nested / compose 5.49 μs 5.17 μs 🟢 0.94× ⚪ 1.0×
Composition / Compete / rand 520.0 ns 541.0 ns ⚪ 1.04× ⚪ 1.0×
Composition / Resolve / rand 501.0 ns 520.0 ns ⚪ 1.04× ⚪ 1.0×
Composition / Compete / logccdf 320.0 ns 330.0 ns ⚪ 1.03×
Composition / Nested / logpdf 1.58 μs 1.6 μs ⚪ 1.01× ⚪ 1.0×
Composition / Choose / construct 20.0 ns 20.0 ns ⚪ 1.0×
Composition / Choose / logpdf 49.0 ns 49.0 ns ⚪ 1.0×
Composition / Compete / construct 20.0 ns 20.0 ns ⚪ 1.0×
Composition / Parallel / logpdf 100.0 ns 100.0 ns ⚪ 1.0× ⚪ 1.0×
Composition / Resolve / construct 29.0 ns 29.0 ns ⚪ 1.0×
Composition / Sequential / logpdf 100.0 ns 100.0 ns ⚪ 1.0× ⚪ 1.0×
AD gradients — 28 benchmarks (by time change)
Benchmark base PR time memory
AD gradients / Compete racing-hazard marginal logpdf / Mooncake reverse 60.29 μs 79.92 μs 🔴 1.33× ⚪ 1.0×
AD gradients / Resolve mixture marginal logpdf / Mooncake reverse 97.09 μs 123.2 μs 🔴 1.27× ⚪ 1.0×
AD gradients / Choose selected-branch logpdf / Mooncake reverse 20.16 μs 25.45 μs 🔴 1.26× ⚪ 1.0×
AD gradients / Sequential Gamma+LogNormal logpdf / ForwardDiff 13.4 μs 10.53 μs 🟢 0.79× ⚪ 1.0×
AD gradients / Pool non-centred reconstruction logpdf / ForwardDiff 1.04 μs 1.24 μs 🔴 1.19× ⚪ 1.0×
AD gradients / Censored leaf marginal logpdf / ForwardDiff 13.62 μs 11.46 μs 🟢 0.84× ⚪ 1.0×
AD gradients / Pool non-centred reconstruction logpdf / Mooncake reverse 30.21 μs 34.06 μs 🔴 1.13× ⚪ 1.0×
AD gradients / Censored leaf marginal logpdf / Mooncake reverse 454.07 μs 498.77 μs 🔴 1.1× ⚪ 1.0×
AD gradients / Resolve stick-breaking branch-prob logpdf / Mooncake reverse 115.29 μs 126.2 μs 🔴 1.09× ⚪ 1.0×
AD gradients / Censored leaf marginal logpdf / Enzyme reverse 161.27 μs 172.89 μs 🔴 1.07× ⚪ 1.0×
AD gradients / Sequential Gamma+LogNormal logpdf / ReverseDiff (tape) 29.88 μs 28.19 μs 🟢 0.94× ⚪ 1.0×
AD gradients / Resolve mixture marginal logpdf / ReverseDiff (tape) 62.37 μs 65.82 μs 🔴 1.06× ⚪ 1.0×
AD gradients / Choose selected-branch logpdf / ReverseDiff (tape) 13.76 μs 14.44 μs ⚪ 1.05× ⚪ 1.0×
AD gradients / Censored leaf marginal logpdf / ReverseDiff (tape) 30.38 μs 28.91 μs ⚪ 0.95× ⚪ 1.0×
AD gradients / Compete racing-hazard marginal logpdf / ReverseDiff (tape) 49.24 μs 51.51 μs ⚪ 1.05× ⚪ 1.0×
AD gradients / Resolve stick-breaking branch-prob logpdf / ReverseDiff (tape) 53.96 μs 56.11 μs ⚪ 1.04× ⚪ 1.0×
AD gradients / Pool non-centred reconstruction logpdf / Enzyme reverse 2.01 μs 1.94 μs ⚪ 0.97× ⚪ 1.0×
AD gradients / Choose selected-branch logpdf / Enzyme reverse 3.23 μs 3.31 μs ⚪ 1.02× ⚪ 1.0×
AD gradients / Sequential Gamma+LogNormal logpdf / Mooncake reverse 392.29 μs 400.74 μs ⚪ 1.02× ⚪ 1.0×
AD gradients / Sequential Gamma+LogNormal logpdf / Enzyme reverse 107.93 μs 105.63 μs ⚪ 0.98× ⚪ 1.0×
AD gradients / Resolve stick-breaking branch-prob logpdf / Enzyme reverse 21.9 μs 21.45 μs ⚪ 0.98× ⚪ 1.0×
AD gradients / Pool non-centred reconstruction logpdf / ReverseDiff (tape) 25.51 μs 26.02 μs ⚪ 1.02× ⚪ 1.0×
AD gradients / Resolve stick-breaking branch-prob logpdf / ForwardDiff 6.77 μs 6.9 μs ⚪ 1.02× ⚪ 1.0×
AD gradients / Resolve mixture marginal logpdf / Enzyme reverse 21.71 μs 21.46 μs ⚪ 0.99× ⚪ 1.0×
AD gradients / Resolve mixture marginal logpdf / ForwardDiff 6.69 μs 6.74 μs ⚪ 1.01× ⚪ 1.0×
AD gradients / Choose selected-branch logpdf / ForwardDiff 752.0 ns 751.0 ns ⚪ 1.0× ⚪ 1.0×
AD gradients / Compete racing-hazard marginal logpdf / Enzyme reverse 9.91 μs 9.9 μs ⚪ 1.0× ⚪ 1.0×
AD gradients / Compete racing-hazard marginal logpdf / ForwardDiff 7.74 μs 7.73 μs ⚪ 1.0× ⚪ 1.0×

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Covariate-requirement introspection

1 participant