]> Piment Noir Git Repositories - freqai-strategies.git/commit
feat(label_weighting): add epsilon_gaussian fill_method, fix sub-floor pivot-row...
authorJérôme Benoit <jerome.benoit@piment-noir.org>
Sat, 20 Jun 2026 17:31:46 +0000 (19:31 +0200)
committerGitHub <noreply@github.com>
Sat, 20 Jun 2026 17:31:46 +0000 (19:31 +0200)
commit1db36f00f31f9a1148a556c82ba81c1b3f0e1d54
tree9074f20164e025d02bb4cacdba1d464afaa417c3
parent04372c1e920c060156bd8eec82b5bb94d2818cd3
feat(label_weighting): add epsilon_gaussian fill_method, fix sub-floor pivot-row dip (#84)

Add a fourth off-pivot weighting mode that superposes the epsilon
floor and the gaussian bumps additively, and fix a related defect in
_scatter_weights that allowed pivot rows to sit *below* the off-pivot
field whenever that field at the pivot's index could legitimately
exceed the pivot's raw weight.

Math
----

Define the off-pivot field

    f(i) = phi + max_{p in P} w_p * exp(-(i - p)^2 / (2 * sigma_p^2))

with phi = eps * B(W) (B mean or median, eps in [0, 1]; phi = 0 on
empty pivots or non-finite baseline), and per-pivot sigma_p from
_compute_pivot_sigmas (fixed or k-NN). The combined formulation reuses
both existing closed forms verbatim:

    fill_method = 'zero'             -> f(i) = 0
    fill_method = 'epsilon'          -> f(i) = phi  (constant in i)
    fill_method = 'gaussian'         -> f(i) = max_p w_p * exp(...)
    fill_method = 'epsilon_gaussian' -> f(i) = phi + max_p w_p * exp(...)

Bound: phi <= f(i) <= phi + max_p w_p. The new mode reduces to pure
gaussian when eps = 0 (bit-identical). The reduction is a per-row max
over per-pivot Gaussian bumps; phi is the epsilon floor.

Sub-floor / sub-bump pivot-row dip (bug fix)
--------------------------------------------

Before this change _scatter_weights wrote out[p] = w_p unconditionally,
so a pivot whose raw weight was below the off-pivot field at its
index appeared as a sharp dip relative to its neighbors. Two
manifestations of the same defect class:

- 'epsilon' / 'epsilon_gaussian' (sub-floor): a pivot with
  w_p < phi (e.g. W = (0.001, 1.0, 1.0) with eps = 0.5 and
  B = median, phi = 0.5) sat at 0.001 while neighbor rows sat at phi.
- 'gaussian' / 'epsilon_gaussian' (sub-bump): a weak pivot with a
  strong neighbor (e.g. W = (0.001, 1.0) at indices (0, 1), sigma = 1)
  sat at 0.001 while the off-pivot field at the pivot's own index was
  1.0 * exp(-0.5) ~= 0.6065 (the neighbor's gaussian bump).

Both cases are corrected by a single uniform change: _scatter_weights
now writes out[p] = max(w_p, fill[p]) so pivot rows are never written
below the off-pivot field. 'zero' is bit-identical (fill is always 0,
so max(w_p, 0) = w_p when w_p >= 0). 'gaussian' in the sparse-pivot
regime (the typical configuration, especially with k-NN bandwidth) is
also bit-identical because fill[p] equals w_p when no neighbor's bump
at p exceeds w_p.

Implementation
--------------

- _scatter_weights: pivot rows take np.maximum(weights, fill_weights)
  unconditionally. Off-pivot rows unchanged.
- _compute_epsilon_floor (renamed from _epsilon_floor): extracted
  helper that returns phi (mean / median / fallback). Reused by
  'epsilon' and 'epsilon_gaussian'. Parameter baseline narrowed to
  the FillEpsilonBaseline Literal type.
- _compute_gaussian_bumps (renamed from _gaussian_bumps): extracted
  adapter over _gaussian_fill_weights. Reused by 'gaussian' and
  'epsilon_gaussian'. logger is kwarg-only.
- compute_label_weights: dispatcher gains the FILL_METHODS[3] branch.
  The combined branch computes bumps once and adds phi in-place via
  np.add(out=fill_weights), keeping peak memory at the existing
  (chunk, M) buffer; phi is constant in p so the post-reduction add
  is algebraically identical to adding inside the chunk loop while
  saving O(chunk * M) writes. ValueError messages tightened to
  include 'supported values are ...' for parity with
  _compute_pivot_sigmas and _aggregate_metrics.
- LabelTransformer.py: extends FillMethod Literal and FILL_METHODS
  tuple with 'epsilon_gaussian' at index 3. No new tunables, no new
  validators (the existing _EnumValidator(FILL_METHODS) picks up the
  new value automatically; existing range / type validators on
  fill_epsilon / fill_sigma_* / fill_bandwidth_* apply unchanged).
- QuickAdapterV3.py: logging block refactored from if/elif chain to
  parallel if blocks keyed on tuple membership so epsilon and sigma
  parameter groups emit independently for each mode that uses them.

Documentation
-------------

README cells updated with set-membership 'Ignored when ...' clauses
matching the new index sets (epsilon | epsilon_gaussian for the
floor parameters, gaussian | epsilon_gaussian for the kernel
parameters). The fill_method description names the additive
composition explicitly and the pivot-row lift invariant
(out[p] = max(w_p, f(p))).

Verified manually on the host via AST extraction harness (no automated
test infrastructure exists in quickadapter/):

- zero mode: bit-exact with prior code (fill is 0, max(w_p, 0) = w_p).
- gaussian mode, sparse pivots: bit-identical to prior code (no
  neighbor's bump at p exceeds w_p, so the lift is a no-op).
- gaussian mode, neighbor-dominated regime: pivot rows lifted to the
  local field max, fixing the sub-bump dip. Verified with the
  counterexample W = (0.001, 1.0) at indices (0, 1), sigma = 1:
  legacy out[0] = 0.001, fixed out[0] = 1.0 * exp(-0.5) ~= 0.6065.
- epsilon back-compat (above-floor pivots): phi = eps * mean(W)
  reproduced; pivots above phi unchanged.
- epsilon pivot-dip fix: W = (0.001, 1.0, 1.0), eps = 0.5,
  baseline = median; legacy out[0] = 0.001, fixed out[0] = phi = 0.5.
- epsilon_gaussian with eps = 0: bit-identical to pure gaussian.
- epsilon_gaussian additive decomposition: out_eg - out_g = phi at
  every off-pivot row.
- epsilon_gaussian pivot-row lifted: W = (0.001, 1.0, 1.0) at
  well-separated indices (e.g. (0, 100, 200)), eps = 0.5,
  baseline = median, sigma = 2.0; out[0] = phi + 0.001 ~= 0.501
  (was 0.001 before the scatter fix).
- empty pivots: all four modes return all-zero.
- negative pivot weights still rejected by _gaussian_fill_weights.
- knn bandwidth + epsilon_gaussian: finite, bounded below by phi.
- ValueError messages on invalid fill_method / fill_epsilon_baseline
  include 'supported values are ...'.
README.md
quickadapter/user_data/strategies/LabelTransformer.py
quickadapter/user_data/strategies/QuickAdapterV3.py
quickadapter/user_data/strategies/Utils.py