Skip to content

feat(adr-001 #3): adaptive Neumann depth from coherence + tolerance - #37

Merged
ruvnet merged 1 commit into
mainfrom
adr/adaptive-neumann-depth
May 19, 2026
Merged

ruvnet merged 1 commit into
mainfrom
adr/adaptive-neumann-depth

Conversation

@ruvnet

@ruvnet ruvnet commented May 19, 2026

Copy link
Copy Markdown
Owner

Summary

Today callers of `solve_on_change_sublinear` / `solve_single_entry_neumann` pick `max_terms` blindly. The closure size scales with depth, so an over-pick wastes work; an under-pick silently misses the tolerance bound. This PR lands the math-driven helper:

```rust
optimal_neumann_terms(coherence, b_inf_norm, min_diag, tolerance) -> Option
```

For strict-DD `A = D - O` with coherence `c`, the Neumann series satisfies `‖y_k‖ ≤ ρ^k · ‖y_0‖` with `ρ ≤ 1 - c`. To hit tolerance:

```
k ≥ log(‖b‖_∞ / (min_diag · tolerance)) / log(1 / (1 - c))
```

Returned `k` is clamped to `[1, 64]` (caller-protective floor + cap).

Composition

  • Cache `(coherence, min_diag)` once at matrix-build time.
  • For each event, compute `auto_terms = optimal_neumann_terms(...)` instead of guessing.
  • Pass `auto_terms` as `max_terms` to `solve_on_change_sublinear`.

Example update

The event-driven example (PR #33, #35) now picks `max_terms` adaptively from the matrix's coherence at startup, removing the last hand-tuned magic number from the canonical inner loop.

Discovery: the prior hand-picked `max_terms=24` was under-tuned for the test matrix's coherence (0.2). The math-driven helper picks 64 (clamped) for the same tolerance. Per-event latency goes from ~2 ms to ~12 ms — that's correctness paying its real cost. Higher-coherence matrices (≥ 0.5) would pick lower term counts, pulling the bench crossover lower.

Test plan

  • 8 new `coherence::optimal_terms_*` tests covering high/low coherence, edge cases, rejection paths
  • 31/31 coherence tests pass
  • `cargo run --release --example event_driven_anomaly` runs end-to-end
  • Full CI

🤖 Generated with claude-flow

Today callers of solve_on_change_sublinear / solve_single_entry_neumann
pick `max_terms` blindly. The closure size scales with depth, so an
over-pick wastes work; an under-pick silently misses the tolerance
bound. This lands the math-driven helper:

  optimal_neumann_terms(coherence, b_inf_norm, min_diag, tolerance)
      → Option<usize>

For strict-DD A = D - O with coherence c, ‖y_k‖ ≤ ρ^k · ‖y_0‖ with
ρ ≤ 1 - c. To hit tolerance:
  k ≥ log(‖b‖_∞ / (min_diag · tolerance)) / log(1 / (1 - c))

Returned k is clamped to [1, 64] (caller-protective floor / cap).

Composition:
  - Cache (coherence, min_diag) once at matrix-build time.
  - For each event, compute auto_terms = optimal_neumann_terms(...)
    instead of guessing.
  - Pass auto_terms as max_terms to solve_on_change_sublinear.

Example update (examples/event_driven_anomaly.rs):
  - Computes auto_terms from coherence + b_inf + tolerance at startup.
  - Uses it as max_terms in every event-handling call.
  - Header line now shows the chosen value alongside coherence /
    min_diag for transparency.

The example's previous hand-picked max_terms=24 was *under-tuned* for
the test matrix's coherence (0.2): the math-driven helper picks 64
(clamped) for the same tolerance. Per-event latency goes from ~2 ms
to ~12 ms — that's correctness paying its real cost. Higher-coherence
matrices (≥ 0.5) would pick lower term counts, pulling the bench
crossover lower.

Tests: 8 new optimal_neumann_terms tests in coherence::tests.
31/31 coherence tests pass.

Co-Authored-By: claude-flow <ruv@ruv.net>
@ruvnet
ruvnet merged commit 186c9ce into main May 19, 2026
11 of 12 checks passed
@ruvnet
ruvnet deleted the adr/adaptive-neumann-depth branch May 19, 2026 14:35
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