"""The similarity family for the NLMS step size, and what it settled. Two corrections came from outside and both were right: 1. mu should be a SIMILARITY, not a variance estimate. The filter can only remove what correlates with its input, so the quantity is the cosine between the error and the filtered reference. It beats the variance formulation on eleven of twelve cells. 2. Testing one similarity function is as incomplete here as it would have been in the root-finding work. The whole family must be run, and when it is, the best member is not the cosine. And the law of the first domain - that the slope of (1 - S) at the origin decides, not the shape of S - orders this family too, monotonically and without exception. That is a prediction made in one domain and confirmed in another. What it did not settle: even the best member loses to a constant tuned per scenario, on all twelve cells. """ from __future__ import annotations import math import os import sys import pytest sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from anc.rules import CosineSimilarity, Fixed, Measured from simroot.pure import PURE_SIMS from stage20_prediction import FLAT_15, FLAT_30, STEP_25, sig_cabin, sig_tonal, \ score SEEDS = 3 CELLS = [(sig_tonal, FLAT_30), (sig_tonal, STEP_25), (sig_cabin, FLAT_15), (sig_cabin, STEP_25)] def make(name): r = CosineSimilarity() r.S = None if name is None else PURE_SIMS[name] return r def mean(rule): vals = [score(rule, gen, prof, seeds=SEEDS) for gen, prof in CELLS] return sum(vals) / len(vals) def test_the_similarity_formulation_beats_the_variance_one(): """Correction 1. mu as 'how much of the error resembles what the filter can remove' against mu as 'one minus the noise-power fraction'. Stated carefully, because the first version of this test was not: what beats the variance rule on eleven of twelve cells is the best member of the FAMILY, not the raw cosine. The raw cosine can lose to it - on this subset it does, 14.04 against 14.32 - which is precisely why correction 2 (run the whole family) was needed before the claim could be made at all. """ best_member = max(mean(make(n)) for n in (None, "ratio", "exp_abs", "rational", "ratio_soft", "sqrt", "cbrt")) assert best_member > mean(Measured()), best_member def test_the_raw_cosine_is_not_the_best_member(): """Correction 2. A single member is not the family: the identity S(d) = 1 - d is beaten by members with a steeper approach to 1.""" raw = mean(make(None)) best = max(mean(make(n)) for n in ("sqrt", "cbrt", "ratio_soft")) assert best > raw, (best, raw) def test_two_code_paths_for_the_same_function_agree(): """S = None takes mu = |cos| directly; S = ratio computes max(0, 1 - d) with d = 1 - |cos|. They are the same function on [0,1] and reach it by different code, so they must score identically.""" a = mean(make(None)) b = mean(make("ratio")) assert abs(a - b) < 1e-9, (a, b) def test_the_law_of_the_first_domain_orders_this_family_too(): """The prediction carried across domains: slope of (1 - S) at 0 decides. Every slope-1 member must beat every slope-0 member.""" slope1 = [mean(make(n)) for n in ("ratio", "exp_abs", "rational")] slope0 = [mean(make(n)) for n in ("rat_sq", "exp_sq", "cosine")] assert min(slope1) > max(slope0), (slope1, slope0) def test_and_it_still_loses_to_a_tuned_constant(): """The half that did not work, pinned so the claim is never overstated. The competitor knows the scenario; no deployable controller does - and it is still ahead.""" losses = 0 for gen, prof in CELLS: best_member = max(score(make(n), gen, prof, seeds=SEEDS) for n in (None, "cbrt", "sqrt", "ratio")) oracle = max(score(Fixed(mu), gen, prof, seeds=SEEDS) for mu in (0.05, 0.1, 0.2, 0.5, 1.0)) losses += best_member < oracle assert losses == len(CELLS), losses