feat(scripts): structural-path full-corpus harness + first honest 62-case numbers

corpus_structural.py drives render48k (48k/4096 structural chain) across the
full corpus with bridge-compare mode. Results: comb 6.12 vs bridge 10.15
(structural wins multiband already), res better, single-band worse; dual@500
constant -6.7dB q-independent over-cut exposes missing reduction saturation.
Param sweep (gamma x MULT, verified builds) confirms current optimum; curve
SHAPE is the gap -> Step 7 capture or bigkernel input re-examination.
This commit is contained in:
2026-08-21 13:12:53 +03:00
parent a9d5581ad8
commit b2cb9235be
2 changed files with 93 additions and 0 deletions
+43
View File
@@ -1253,3 +1253,46 @@ ctx+0x188 writers to replace MULT placeholder with decomp value.
6e40+15060 thunks, then bigkernel exp2 in-place on band (line 805-832). 6e40+15060 thunks, then bigkernel exp2 in-place on band (line 805-832).
### Commits: 9ffe60e (IIR3 fwd-only + retune), 1a616e1 (bidirectional + decode). ### Commits: 9ffe60e (IIR3 fwd-only + retune), 1a616e1 (bidirectional + decode).
## ============ UPDATE 2026-08-21c: FULL STRUCTURAL CORPUS (first honest numbers) ============
### Harness: scripts/corpus_structural.py (render48k x all 62 cases, bridge-compare mode)
Structural chain (48k/4096, LUT level-domain g=0.344 m=4.2, IIR3 bidi) vs bridge:
group n bridge struct delta
t1kq 7 0.226 0.768 +0.54 worse
t1k 11 1.801 2.114 +0.31 worse
al 6 0.638 0.986 +0.35 worse
res 11 0.628 0.437 -0.19 BETTER
dual 22 0.726 3.264 +2.54 MUCH worse
comb 5 10.149 6.116 -4.03 MUCH BETTER
TOTAL 62 1.594 2.286 +0.69 worse
### KEY FINDINGS:
1. **comb: structural ALREADY beats bridge by 4 dB** (6.1 vs 10.1) WITHOUT acc
wiring — per-band structural min() + warp closes part of the multiband gap.
Plan's "combine closes comb" partially pre-empted by the chain itself.
2. **dual_*_500: constant -6.7 dB over-cut for ALL q** (q-independent!).
res[center] is q-independent (0.117) => systematic LEVEL offset at band
center on two-tone input, not shape. dual_*_2000 (off-center bin) BETTER
than bridge (-0.1..-0.4 vs +0.1..+2.3). At same xv, bridge-LUT cut ~-9.3 dB,
our exp2 path cuts ~-20 dB: real reduction SATURATES (~C_max~0.70 per
extracted LUT pts), exp2(-lvl) does not.
3. al level-sweep error is MONOTONE in level (+0.88@lv3 -> -1.82@lv24): our
level->cut curve too steep mid-range; but t1k (loudest) flips back to
under-cut (+1.8) => NON-monotonic overall, no monotone LUT fixes all groups.
4. gamma/MULT sweep (g in {0.15,0.22,0.30} x m in {4.2,5.0,5.8}, fresh builds,
12-case subset incl. dual/res/comb): ALL points worse than current
g=0.344/m=4.2; gradient points BACK to current optimum. Blind param space
EXHAUSTED around this parametrization.
### CONCLUSION (Step 1 status): criterion "structural >= bridge on single-band"
NOT met globally (regress on t1kq/t1k/al/dual; better on res). The missing
piece is the REAL reduction curve saturation — needs either:
(a) Step 7 BandConfig ctx+0x188 live capture (A/B/gamma per config), or
(b) re-examination of bigkernel INPUT: maybe level into exp2 carries an
additional transform (log-domain offset / per-band depth scalar
0x540888 / offline 0x5e80+FUN_180323f20 ops) that saturates the cut.
Do NOT tune MULT further — it is calibrated; the CURVE SHAPE is wrong.
### FFT-conv priority DOWNGRADED: NOTES:18c shows window 0x540658 tail is
near-flat (0.8->1.0 plateau at N/2>=2048), FIR-construction effect on mask
shape minimal for N=4096. Step 4 stays P3.
+50
View File
@@ -0,0 +1,50 @@
#!/usr/bin/env python3
"""Structural-path full-corpus harness (render48k, 48000/4096 internal grid).
Mirrors scripts/corpus.py but drives dsp/build/render48k (structural
FUN_180529fe0 chain on the internal grid) instead of framed_test (bridge).
Purpose: honest per-group comparison of the structural chain against the
committed bridge baseline (BITEXACT_PLAN step-1 criterion: structural must
not regress below bridge on single-band groups).
Usage:
python3 scripts/corpus_structural.py [--out results.json]
python3 scripts/corpus_structural.py --vs-bridge scripts/baseline_bridge.json
"""
import json, sys
sys.path.insert(0, 'scripts')
import corpus
corpus.RB = '/home/m/re-tools/dsp/build/render48k'
_orig_build_cases = corpus.build_cases
def build_cases_structural():
cases = []
for name, inp, args, ref, f in _orig_build_cases():
# render48k parses only comma-form band args; join split dual args.
joined = [','.join(args)] if len(args) == 3 else args
cases.append((name, inp, joined, ref, f))
return cases
corpus.build_cases = build_cases_structural
if __name__ == '__main__':
a = sys.argv[1:]
if a and a[0] == '--vs-bridge':
base = json.load(open(a[1]))
res, _ = corpus.run_all()
bs, cs = corpus.group_stats(base), corpus.group_stats(res)
print(f'{"group":>12} {"n":>3} {"bridge":>8} {"struct":>8} {"d":>8} {"max":>7}')
for g in ['t1kq', 't1k', 'al', 'res', 'dual', 'comb', 'TOTAL']:
if g not in cs:
continue
b = bs.get(g, {'mean_abs': float('nan')})['mean_abs']
s = cs[g]
print(f'{g:>12} {s["n"]:>3} {b:>8.3f} {s["mean_abs"]:>8.3f} '
f'{s["mean_abs"] - b:>+8.3f} {s["max_abs"]:>7.3f}')
sys.exit(0)
sys.exit(corpus.main())