NatLabRockies / NatLabRockies/ninterp

Channel subsetting for `Strategy*Multi`

Open
#47 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
17
Forks
13
Avg merge
44m
Merged PRs (30d)
2

Description

#19's multi-channel interpolate_into always evaluates every channel. A caller wanting
one channel out of many (the gluon from a 13-flavor PDF set, the green channel of an RGB
image) pays for all of them. Add a way to request a subset.

API changes

Additive, defaulted, so it does not disturb #19's required-method story. 2D shown:

/// Interpolate only the channels listed in `channels`, writing channel
/// `channels[i]` into `out[i]`. `out.len()` must equal `channels.len()`.
///
/// Default evaluates all channels into a scratch buffer and gathers. Override
/// when the strategy can skip the unrequested channels outright, which is every
/// strategy whose per-channel work is a lookup or blend against a shared locate
/// result, i.e. all of them in this crate.
fn interpolate_channels_into(
    &self,
    data: &InterpData2DMulti<D>,
    point: &[D::Elem; 2],
    channels: &[usize],
    out: &mut [D::Elem],
) -> Result<(), InterpolateError> { /* default: evaluate all, gather */ }

Plus the batch equivalent, and a matching method on Interp2DMulti and
DynInterpolatorMulti. Out-of-range indices in channels are an error
(InterpolateError::Other, or a dedicated variant), not silently skipped.

Why not in #19

Purely additive on top of #19's trait, since the default body is expressible in terms of
the required interpolate_into. Splitting it keeps #19's reviewable surface to the
shared-grid mechanism itself.

But it should not drift far behind #19, because of an interaction worth stating
explicitly.

The duplication it resolves

Without subsetting, a consumer that has both single-channel and all-channel access
patterns has to choose:

Keep per-channel Interp2D and Interp2DMulti Interp2DMulti only
All-channel call One locate, all channels One locate, all channels
Single-channel call One locate, one channel One locate, all channels, discard n-1
Grid axis storage n_channels + 1 copies 1 copy
Values storage 2 copies 1 copy

Neither column is acceptable, and #19's memory win only materializes in the right-hand
one. Subsetting makes the right-hand column strictly better than the left on both axes.

#19's InterpData2DMulti::channel_view(k) is a partial escape hatch: it hands back an
InterpData2DViewed that a plain Strategy2D can interpolate against, giving
single-channel cost with single-copy storage. Two caveats keep it from closing this
issue:

  • The view is strided, not contiguous (values.index_axis(Axis(2), k) over a
    channel-last layout has stride n_channels). Any strategy reaching for
    data.values.as_slice().unwrap() panics on it. That is not hypothetical: several of
    QCDLab/neopdf's strategies do exactly that (LogChebyshevInterpolation's
    Strategy1D/2D/3D/ND impls, AlphaSCubicInterpolation).
  • It only covers exactly one channel, not an arbitrary subset or reordering.

Downstream motivation

QCDLab/neopdf's all-flavor evaluators take pid_slots: &[Option<usize>], an arbitrary
subset and permutation of channels, with None meaning "requested flavor absent from
this set, yield 0.0". The subset and permutation half is what this issue covers. The
None sentinel is PDF-domain logic and should stay in neopdf: it maps cleanly onto
partitioning the request before the call.

Both of its evaluation paths (InterleavedHermite::eval_allpids,
ChebyshevAllPids::eval_allpids) and both of its public entry points
(GridPDF::xfxq2_allpids, xfxq2_allpids_with_slots) thread pid_slots through, and
neopdf_pdf_xfxq2_allpids exposes it across the C ABI.

Dependencies

  • #19: defines Strategy*Multi and channel_view. Must land first.
  • #45: the _into convention these signatures follow.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the StrategyMulti trait and channel_view from #19, then read the _into convention from #45. Add the point and batch subset methods described for StrategyMulti, Interp2DMulti, and DynInterpolatorMulti, including out-of-range validation and default behavior. Done means arbitrary channel subsets and permutations work without changing the required-method story.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
api, data
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.