Skip to content

aa: add aa_get_stats() for lifetime diagnostic counters#47

Merged
bodono merged 2 commits intomasterfrom
aa-stats
Apr 22, 2026
Merged

aa: add aa_get_stats() for lifetime diagnostic counters#47
bodono merged 2 commits intomasterfrom
aa-stats

Conversation

@bodono
Copy link
Copy Markdown
Member

@bodono bodono commented Apr 22, 2026

Summary

Expose a small public `AaStats` struct and `aa_get_stats()` that reports lifetime counters plus most-recent-solve snapshots: `n_accept`, `n_apply_reject`, `n_safeguard_reject`, `last_rank`, `last_aa_norm`, `last_regularization`. Python gets a read-only `.stats` property returning a dict with the same fields.

Motivation. When AA underperforms on a given fixed-point iteration, callers currently have no programmatic signal to decide whether to tune `max_weight_norm`, `regularization`, `safeguard_factor`, or `mem`. The counters make that diagnosis possible from a single post-hoc read. Example output after a 20-iter GD+AA run:

```
n_accept = 14
n_apply_reject = 0
n_safeguard_reject = 0
last_rank = 5
last_aa_norm = 1.48e+00
last_regularization = 1.16e-20
```

Design choice: single out-param function. One function, one struct, one new Python property — minimum header surface vs. N getters.

Lifetime counters survive aa_reset. `aa_reset` is also called internally on safeguard rejection, and we want the rejection itself to stay visible in the counters. To start counting fresh, re-init the workspace. Explicitly tested.

Test plan

  • 3 new C unit tests: basic counters, survival across internal aa_reset (safeguard path), NULL-safety
  • 3 new Python tests: zero-at-init, counters increment on GD+AA run, reset() doesn't clear
  • Full C suite passes (`make LDLIBS="-framework Accelerate" test`)
  • Full Python suite passes (39/39)

🤖 Generated with Claude Code

bodono and others added 2 commits April 22, 2026 13:05
Expose a small public AaStats struct and aa_get_stats() that reports
lifetime counters and most-recent-solve snapshots:

  - n_accept             : AA steps accepted by aa_apply
  - n_apply_reject       : solves rejected (weight-norm / rank=0 / lapack info)
  - n_safeguard_reject   : safeguard rollbacks
  - last_rank            : numerical rank of most recent LS solve
  - last_aa_norm         : ||γ||₂ of most recent solve
  - last_regularization  : r value used in most recent solve

Motivation: when AA underperforms on a given fixed-point iteration,
callers currently have no programmatic signal to decide whether
max_weight_norm, regularization, safeguard_factor, or mem is the thing
to tune. The counters make that diagnosis possible from a single
post-hoc read.

Lifetime counters are intentionally NOT cleared by aa_reset. That
function is also called internally on safeguard rejection, and we
want the rejection itself to stay visible in n_safeguard_reject. To
start counting fresh, re-init the workspace.

Python exposes a read-only .stats property returning a dict of the
same fields.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Refinements to the diagnostics added in the previous commit:

 - Split the single n_apply_reject counter into four causes so callers
   can tell whether to tune regularization (n_reject_weight_cap,
   n_reject_nonfinite), whether a numerical failure happened in LAPACK
   (n_reject_lapack), or whether the memory simply collapsed to zero
   near convergence (n_reject_rank0, expected). The previous single
   counter conflated all of these.
 - Capture geqp3's info before the rank-0 path overwrites it, so
   lapack_info and rank-0 are attributed correctly.
 - Return AaStats by value from aa_get_stats instead of via an
   out-param. No reason to force callers to pre-allocate the struct.
 - Add an iter field to AaStats (was previously only accessible by
   inference from the counters).
 - Use NaN rather than 0 as the sentinel for "no valid norm yet" in
   last_aa_norm, so callers can distinguish a fresh workspace from
   a legitimate zero-norm solve.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@bodono bodono merged commit e1730aa into master Apr 22, 2026
27 checks passed
@bodono bodono deleted the aa-stats branch April 22, 2026 12:30
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