Skip to content

mcsamplerNFlow: return (p_s, p_prior, rv), and give it a sampling_density - #358

Draft
oshaughnessy-junior wants to merge 1 commit into
rift_O4dfrom
claude/nflow-portfolio-member
Draft

oshaughnessy-junior wants to merge 1 commit into
rift_O4dfrom
claude/nflow-portfolio-member

Conversation

@oshaughnessy-junior

Copy link
Copy Markdown
Owner

mcsamplerNFlow could not be a mcsamplerPortfolio member. Two causes, both fixed.

Return order. draw_simplified returned (rv, p_s, p_prior). MCSamplerGeneric and every other implementation return (p_s, p_prior, rv). mcsamplerPortfolio.draw() unpacks that order, so an NFlow member had its samples assigned to joint_p_s. --sampler-portfolio NFlow is offered by util_ConstructIntrinsicPosterior_GenericCoordinates and util_ConstructEOSPosterior.

The failure is not always loud. An [AV, NFlow] portfolio on a unit Gaussian in [-5,5]^d:

d result
2 ValueError: could not broadcast input array from shape (2,100) into shape (100,)
1 completes, ln Z = -4.458 against a true -1.384
1, control AV+AV completes, ln Z = -1.273

At d=1 the (1,n) sample array broadcasts into the (n,) density slot, and the run returns a number 3.07 nats low with no error.

Missing sampling_density. The portfolio builds q_mix = sum_m frac_m q_m from member.sampling_density(X). Added, modelled on the mcsamplerEnsemble and mcsamplerAdaptiveVolume versions: 1/V on the box while nf_flow is None, exp(flow.log_prob(X)) once a flow is trained. On a trained 2-D flow it matches the p_s reported for the same draws to 1.2e-7.

Reaching either needed one more fix: nflows type-checks its sample count with isinstance(n, int), which the numpy int64 the portfolio passes fails.

Verification

nflows and torch are absent from the CIT IGWN conda python. Real-dependency runs used ~/.conda/envs/myigwn-py310-testing (python 3.10.14, torch 2.1.2, numpy 1.24.4) on ldas-grid, no cupy.

check result
test_NF_reuse.py --as-test (OPTDEP, real nflows) PASS
new gate, real torch + nflows 4 passed
new gate, IGWN python, no nflows 4 passed
.travis/test-ci-roster.py PASS
5 mutations in an isolated worktree each caught, control green either side

The new gate needs neither package: it drives the untrained uniform branch and a strict in-file flow stand-in, and stubs both at import when absent. Registered in .travis/test-integrate.sh with a collection-count guard.

Two things this does not fix

Both follow from one root: draw_simplified truncates to the box without renormalizing.

  1. Short chunks. A trained flow returns fewer samples than requested (acceptance 0.18 to 0.31) and mcsamplerPortfolio.draw copies into a fixed-width slice, so a real NFlow member still dies: could not broadcast input array from shape (45,) into shape (114,). portfolio.draw() passes no kwargs, so enforce_bounds=False is unreachable from there.
  2. Missing 1/A. Reported p_s is the undivided q(x) while accepted draws are distributed as q(x)/A. With the short-chunk problem patched out in the harness, the [AV, NFlow] portfolio runs and lands +0.093 nats high over 5 seeds, against +0.012 for an AV+AV control.

Fixing these changes how draw_simplified samples, which also moves NFlow's own integrate(). Your call, so I left them.

The brief for this work said PR #356 (claude/portfolio-ps-contract) was merged. It is open.

🤖 Generated with Claude Code

…sity

draw_simplified returned (rv, p_s, p_prior) while MCSamplerGeneric and every
other implementation return (p_s, p_prior, rv).  mcsamplerPortfolio.draw()
unpacks the latter, so an NFlow member had the samples assigned to joint_p_s.
--sampler-portfolio NFlow is offered by both
util_ConstructIntrinsicPosterior_GenericCoordinates and
util_ConstructEOSPosterior, so the broken configuration is reachable.

The failure is not reliably loud.  On an [AV, NFlow] portfolio over a unit
Gaussian in [-5,5]^d, d=2 raises a broadcast ValueError out of the portfolio,
but d=1 completes and returns ln Z = -4.458 against a true -1.384 -- 3.07 nats
low, silently, because the (1,n) sample array broadcasts into the (n,) density
slot.  Control with the NFlow member replaced by a second AV: -1.273.

Also adds sampling_density(X), which mcsamplerPortfolio needs to build its
balance-heuristic mixture denominator q_mix = sum_m frac_m q_m, and coerces
n_to_get to a python int (nflows type-checks it with isinstance(n, int), which
a numpy int fails, and the portfolio hands members a numpy int64).

Verified against a real nflows install; the new gate needs neither nflows nor
torch.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@oshaughnessy-junior
oshaughnessy-junior deployed to private-review-dispatch-rift September 16, 2026 14:29 — with GitHub Actions Active
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.

1 participant