Source code for genvarloader._dataset._insertion_fill

from __future__ import annotations

from collections.abc import Sequence
from dataclasses import dataclass

import numpy as np
from numpy.typing import NDArray

REPEAT_5P = 0
REPEAT_5P_NORM = 1
CONSTANT = 2
FLANK_SAMPLE = 3
INTERPOLATE = 4

MAX_PARAMS = 1  # widest strategy uses 1 slot


[docs] class InsertionFill: """Base class for track insertion fill strategies. Do not instantiate directly."""
[docs] def __init__(self): if type(self) is InsertionFill: raise TypeError("InsertionFill is abstract; instantiate a subclass.")
[docs] @dataclass(slots=True) class Repeat5p(InsertionFill): """Repeat the value at the variant POS across the entire inserted region. Current default behavior."""
[docs] @dataclass(slots=True) class Repeat5pNormalized(InsertionFill): """Repeat track[v_rel_pos] / (v_diff + 1) across the inserted region. Preserves the sum: when the full insertion stretch is written, the total written value equals track[v_rel_pos]. If the insertion is truncated at the output boundary, the sum is reduced proportionally. """
[docs] @dataclass(slots=True) class Constant(InsertionFill): """Write a fixed value at every inserted position. Args: value: Value to write. Defaults to NaN. """ value: float = float("nan")
[docs] @dataclass(slots=True) class FlankSample(InsertionFill): """Sample (with replacement) from the 2*flank_width+1 reference values centered at the variant POS. Each inserted position samples independently. Out-of-bounds neighbors are clamped to in-bounds values. Args: flank_width: Half-width of the flanking pool. Must be >= 0. """ flank_width: int = 5 def __post_init__(self) -> None: if self.flank_width < 0: raise ValueError(f"flank_width must be >= 0, got {self.flank_width}")
[docs] @dataclass(slots=True) class Interpolate(InsertionFill): """Polynomial interpolation across the inserted region. order=1: linear between track[v_rel_pos] and track[v_rel_pos + 1]. order=2,3: Lagrange polynomial through ceil((order+1)/2) reference values on each side of the variant, clamped at boundaries. Args: order: Polynomial order. Must be in {1, 2, 3}. """ order: int = 1 def __post_init__(self) -> None: if self.order not in (1, 2, 3): raise ValueError(f"Interpolate order must be 1, 2, or 3 (got {self.order})")
def lower( strategies: Sequence[InsertionFill], ) -> tuple[NDArray[np.int8], NDArray[np.float64]]: """Pack strategy instances into numba-friendly arrays. Returns: strategy_ids: Shape (n,), int8. One enum value per strategy. params: Shape (n, MAX_PARAMS), float64. Per-strategy parameter slots: - Repeat5p / Repeat5pNormalized: unused (all zeros). - Constant: [value]. - FlankSample: [flank_width]. - Interpolate: [order]. """ n = len(strategies) ids = np.empty(n, dtype=np.int8) params = np.zeros((n, MAX_PARAMS), dtype=np.float64) for i, s in enumerate(strategies): if isinstance(s, Repeat5p): ids[i] = REPEAT_5P elif isinstance(s, Repeat5pNormalized): ids[i] = REPEAT_5P_NORM elif isinstance(s, Constant): ids[i] = CONSTANT params[i, 0] = s.value elif isinstance(s, FlankSample): ids[i] = FLANK_SAMPLE params[i, 0] = float(s.flank_width) elif isinstance(s, Interpolate): ids[i] = INTERPOLATE params[i, 0] = float(s.order) else: raise TypeError(f"Unknown InsertionFill subclass: {type(s).__name__}") return ids, params