Skip to content

aa: make rank tolerance dim-independent (len·ε·|R₁₁|)#46

Merged
bodono merged 1 commit intomasterfrom
aa-rank-tol-dim-independent
Apr 22, 2026
Merged

aa: make rank tolerance dim-independent (len·ε·|R₁₁|)#46
bodono merged 1 commit intomasterfrom
aa-rank-tol-dim-independent

Conversation

@bodono
Copy link
Copy Markdown
Member

@bodono bodono commented Apr 22, 2026

Summary

  • The pivoted-QR rank tolerance was aug_rows·ε·|R₁₁| with aug_rows = dim + mem, following LAPACK's max(m,n)·ε·σ₁ convention. For AA this conflates two different dimensions: dim is the caller's state vector length, while the inner LS we're rank-revealing has only len columns (len ≤ mem, typically 5–20).
  • Switching to len·ε·|R₁₁| decouples the tolerance from dim. Principled argument: the rank question is about the len columns of [A; √r I_len]; the tall dim rows are the caller's state, not part of the LS's algorithmic dimension.
  • Practical consequence: at large state dim the old floor can exceed the noise floor the regularizer itself enforces. With reg=1e-12 and dim=1e6, old tol ≈ 2e-10·|R₁₁| sits well above the √r floor (1e-6·|R₁₁|) that the augmented √r·I rows guarantee by construction — columns the regularizer certifies as healthy could be silently dropped.

Test plan

  • Full C suite passes (make LDLIBS="-framework Accelerate" test)
  • Full Python suite passes (31/31)
  • Bench matches master byte-for-byte on all 14 configs (iter counts, applied/aa_rej/sg_rej, final_err) — at bench's dim range (50–2000) both tolerances are well below |R₁₁|, so no observable change, as expected. This is a large-dim robustness fix, not a perf change.

🤖 Generated with Claude Code

The pivoted-QR rank tolerance was aug_rows·ε·|R₁₁| with
aug_rows = dim + mem, following LAPACK's max(m,n)·ε·σ₁ convention.
For AA this conflates two different dimensions: `dim` is the caller's
state vector length, while the inner LS that we're rank-revealing has
only `len` columns (where len ≤ mem, typically 5–20). The worst-case
Wilkinson bound does grow with row count, but when the row count is
the user's fixed-point state — not the algorithmic size of the LS —
scaling the tolerance by it is a category error.

Concrete consequence: at large state dim the old floor can exceed the
noise floor the regularizer itself enforces. With reg=1e-12 and
dim=1e6 the old tolerance (~2e-10 × |R₁₁|) sits well above the √r
floor (1e-6 × |R₁₁|) that the augmented √r·I rows guarantee by
construction. Columns the regularizer certifies as healthy could be
silently dropped.

Switching to len·ε·|R₁₁| decouples the tolerance from dim while
remaining tiny in absolute terms (len ≤ mem ≤ ~20 in practice). No
observable change on the existing bench (all 14 configs identical
iteration counts and final errors); this is a large-dim robustness
fix, not a perf change.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@bodono bodono merged commit 9afbd2d into master Apr 22, 2026
28 checks passed
@bodono bodono deleted the aa-rank-tol-dim-independent branch April 22, 2026 11:51
bodono added a commit that referenced this pull request Apr 22, 2026
Since 0.0.2:
 - Pivoted-QR solver hygiene: warn on mem>dim, slim aa_reset (#44)
 - Runtime min_len knob to gate when AA starts extrapolating (#45)
 - Dim-independent rank tolerance (len·ε·|R₁₁|) (#46)
 - Lifetime diagnostics API: aa_get_stats + AaStats struct with split
   rejection-cause counters (#47)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant