22t: two-factor laws REFUTED by descent (quad Q->0, resrp rp->0 — geometry already in lvl=am/res); real render of sim-optimum 7.6/1.694 = 1.898 with group regressions, canon stays; error budget: dual = 62% of corpus abs-error -> inter-band acc/f6f8 consumer is priority #1

This commit is contained in:
2026-08-23 15:10:06 +03:00
parent 3857205a6b
commit 376bd955c9
3 changed files with 173 additions and 53 deletions
+107 -53
View File
@@ -91,10 +91,14 @@ def collect():
store = {}
traj_bin = '/tmp/opencode/lawfit_traj.bin'
resp_bin = '/tmp/opencode/lawfit_res.bin'
for key, u in sorted(uniq.items()):
if os.path.exists(traj_bin):
os.remove(traj_bin)
env = {**os.environ, **BASE_ENV, 'RT_DUMP_ALL': traj_bin}
if os.path.exists(resp_bin):
os.remove(resp_bin)
env = {**os.environ, **BASE_ENV, 'RT_DUMP_ALL': traj_bin,
'RT_DUMPRESPATH': resp_bin}
subprocess.run([corpus.RB, u['inp'], '/tmp/opencode/lawfit_out.wav'] + u['args'],
capture_output=True, text=True, env=env,
cwd='/home/m/re-tools')
@@ -104,9 +108,26 @@ def collect():
continue
lvl = arr.reshape(-1, u['nb'], RBIN) # [frame][band][bin]
store[key] = lvl
print(f'{key}: {lvl.shape[0]} frames x {u["nb"]} bands')
# static twin-response spectra per band ({i32 band, i32 nbin, f32[nbin]})
res = None
if os.path.exists(resp_bin):
raw = open(resp_bin, 'rb').read()
off = 0
bands = []
while off < len(raw):
bi, nb = struct.unpack_from('<ii', raw, off)
off += 8
r = np.frombuffer(raw, dtype='<f4', count=nb, offset=off)
off += 4 * nb
bands.append(r.astype(np.float32))
if len(bands) == u['nb'] and all(b.size == RBIN for b in bands):
res = np.stack(bands)
if res is not None:
store[key + '|res'] = res
print(f'{key}: {lvl.shape[0]} frames x {u["nb"]} bands'
+ (' +res' if res is not None else ' NORES'))
np.savez_compressed(TRAJ, **store)
print(f'\nwrote {len(store)} trajectories -> {TRAJ}')
print(f'\nwrote {len(store)} entries -> {TRAJ}')
def load_traj():
@@ -135,16 +156,24 @@ class CaseInput:
return lvl.shape[0] == self.nf
def masks_from_lvl(lvl, nb, A, S):
"""Per-frame lower-half mask exactly as bare chain + LAWAFFINE produces."""
def masks_from_lvl(lvl, nb, A, S, Q=0.0, res=None, rp=0.0):
"""Per-frame lower-half mask exactly as bare chain + LAWAFFINE produces.
Law families (22t): scalar cut=A+S*log2(lvl); quad adds curvature Q*x^2;
resrp multiplies per-band mask by res^rp (decomp warp-cascade factor,
applied BEFORE cross-band min like the C++ warp section).
"""
nf = lvl.shape[0]
lv64 = lvl.astype(np.float64)
mm = np.exp2(-((A + S * np.log2(np.maximum(lv64, 1e-12))) / 6.0174))
x = np.log2(np.maximum(lv64, 1e-12))
mm = np.exp2(-((A + S * x + Q * x * x) / 6.0174))
low = lv64 <= 1e-6 # C++ fallback: exp2(-level)
if low.any():
mm[low] = np.exp2(-lv64[low])
if res is not None and rp:
mm = mm * res[None].astype(np.float64) ** rp
if nb > 1:
lo = np.min(mm, axis=1)
lo = np.min(mm, axis=1) # min across bands
else:
lo = mm[:, 0, :]
full = np.ones((nf, NFFT))
@@ -153,10 +182,10 @@ def masks_from_lvl(lvl, nb, A, S):
return full
def replay(ci, lvl, nb, A, S):
"""Return trimmed 44.1k output for law (A,S) on prepared CaseInput ci."""
def replay(ci, lvl, nb, A, S, Q=0.0, res=None, rp=0.0):
"""Return trimmed 44.1k output for law params on prepared CaseInput ci."""
assert ci.frames_ok(lvl), f'traj {lvl.shape[0]} != frames {ci.nf}'
full = masks_from_lvl(lvl, nb, A, S)
full = masks_from_lvl(lvl, nb, A, S, Q, res, rp)
segs = ci.xext[ci.offs[:, None] + np.arange(NFFT)[None, :]] * _WIN[None, :]
yspec = np.fft.fft(segs, axis=1) * full
td = np.real(np.fft.ifft(yspec, axis=1))
@@ -203,20 +232,18 @@ def build_eval_index(trajs):
return idx
def sim_errors(trajs, idx, A, S, ref_cache=None):
def sim_errors(trajs, idx, A, S, Q=0.0, rp=0.0):
errs = {}
ycache = {}
for e in idx:
ck = (e['key'], e['nb'])
ck = (e['key'], e['nb'], round(Q, 6), round(rp, 6))
if ck not in ycache:
ci = case_input(e['key'], e['inp'])
ycache[ck] = replay(ci, trajs[e['key']], e['nb'], A, S)
ycache[ck] = replay(ci, trajs[e['key']], e['nb'], A, S,
Q, trajs.get(e['key'] + '|res'), rp)
y44 = ycache[ck]
if ref_cache is None:
errs[e['name']] = corpus.db(corpus.ta(y44, e['f'])) - \
corpus.db(corpus.ta(corpus.load_mono(e['ref']), e['f']))
else:
errs[e['name']] = corpus.db(corpus.ta(y44, e['f'])) - ref_cache[e['name']]
errs[e['name']] = corpus.db(corpus.ta(y44, e['f'])) - \
corpus.db(corpus.ta(corpus.load_mono(e['ref']), e['f']))
return errs
@@ -250,45 +277,72 @@ def sanity(A, S, json_path):
def fit(A0, S0):
trajs = load_traj()
idx = build_eval_index(trajs)
fit2(trajs, idx, A0, S0)
def objective(A, S, sub=None):
def fit2(trajs, idx, A0, S0):
"""Law-family comparison: scalar / quad / resrp / quad+resrp (NOTES 22t)."""
def objective(p, sub=None):
A, S, Q, rp = p
ii = idx if sub is None else sub
return group_stats(sim_errors(trajs, ii, A, S))
return group_stats(sim_errors(trajs, ii, A, S, Q, rp))
best = (A0, S0)
bst = objective(*best)
print(f'start A={A0} S={S0}: TOTAL={bst["TOTAL"]:.3f}')
stepA, stepS = 0.8, 0.25
for it in range(4):
moved = False
for A, S in [(best[0] + stepA, best[1]), (best[0] - stepA, best[1]),
(best[0], best[1] + stepS), (best[0], best[1] - stepS)]:
st = objective(A, S)
mark = ''
if st['TOTAL'] < bst['TOTAL'] - 1e-4:
best, bst = (A, S), st
moved = True
mark = ' *'
print(f' [{it}] A={A:+7.3f} S={S:+6.3f}: TOTAL={st["TOTAL"]:.3f}{mark}')
if not moved:
stepA /= 2
stepS /= 2
if stepA < 0.05:
break
print(f'\nBEST global: A={best[0]:.3f} S={best[1]:.3f} TOTAL={bst["TOTAL"]:.3f}')
for k, v in bst.items():
print(f' {k:>6}: {v:.3f}')
def descend(p0, steps, sub=None, label=''):
best = list(p0)
bst = objective(tuple(best), sub)
print(f'{label} start {[round(v, 4) for v in best]}: '
f'TOTAL={bst["TOTAL"]:.3f}', flush=True)
while all(s > 1e-4 for s in steps.values()):
moved = False
for i, nm in enumerate(['A', 'S', 'Q', 'rp']):
if nm not in steps:
continue
st = steps[nm]
for d in (+st, -st):
cand = list(best)
cand[i] = round(cand[i] + d, 6)
if cand[3] < 0 or (nm == 'Q' and abs(cand[2]) > 3):
continue
s2 = objective(tuple(cand), sub)
if s2['TOTAL'] < bst['TOTAL'] - 1e-4:
best, bst = cand, s2
moved = True
print(f' {label} {nm}{d:+.4g}: TOTAL={s2["TOTAL"]:.3f} '
f'{[round(v, 4) for v in best]}', flush=True)
if not moved:
for nm in steps:
steps[nm] /= 2
return best, bst
print('\n=== per-group greedy optima (grid around global best) ===')
for g in ['t1kq', 't1k', 'al', 'res', 'dual', 'comb']:
sub = [e for e in idx if e['grp'] == g]
bA, bS, bval = None, None, 1e9
for A in np.arange(best[0] - 2.5, best[0] + 2.51, 0.5):
for S in np.arange(max(0.25, best[1] - 1.0), best[1] + 1.01, 0.25):
st = objective(float(A), float(S), sub)
if st[g] < bval:
bA, bS, bval = float(A), float(S), st[g]
print(f'{g:>6}: A={bA:6.2f} S={bS:5.2f} mean|e|={bval:.3f}', flush=True)
res_all = {}
b, t = descend([A0, S0, 0.0, 0.0], {'A': 0.4, 'S': 0.15}, label='[scalar]')
res_all['scalar'] = (list(b), dict(t))
bA, bS, _, _ = res_all['scalar'][0]
b, t = descend([bA, bS, 0.0, 0.0], {'A': 0.3, 'S': 0.15, 'Q': 0.06},
label='[quad]')
res_all['quad'] = (list(b), dict(t))
b, t = descend([bA, bS, 0.0, 0.03], {'A': 0.3, 'S': 0.15, 'rp': 0.01},
label='[resrp]')
res_all['resrp'] = (list(b), dict(t))
bA, bS, bQ, _ = res_all['quad'][0]
b, t = descend([bA, bS, bQ, 0.03], {'A': 0.25, 'S': 0.12, 'Q': 0.05,
'rp': 0.008}, label='[quad+resrp]')
res_all['quad+resrp'] = (list(b), dict(t))
print('\n================ LAW FAMILY SUMMARY ================')
for fam, (p, st) in res_all.items():
gs = ' '.join(f'{g}={st[g]:.3f}' for g in
['t1kq', 't1k', 'al', 'res', 'dual', 'comb'])
print(f'{fam:>12}: A={p[0]:7.3f} S={p[1]:6.3f} Q={p[2]:+6.3f} '
f'rp={p[3]:5.3f} TOTAL={st["TOTAL"]:.3f}\n{"":>14}{gs}')
json.dump({f: {'params': p, 'groups': s} for f, (p, s) in res_all.items()},
open('/tmp/opencode/lawfit_fit2.json', 'w'), indent=1)
print('\nwrote /tmp/opencode/lawfit_fit2.json')
def freq_of(name):