Skip to content

feat(adr-001 #6): phase-2B — single-entry Neumann + SubLinear orchestrator - #27

Merged
ruvnet merged 1 commit into
mainfrom
adr/single-entry-neumann
May 19, 2026
Merged

ruvnet merged 1 commit into
mainfrom
adr/single-entry-neumann

Conversation

@ruvnet

@ruvnet ruvnet commented May 19, 2026

Copy link
Copy Markdown
Owner

Summary

Lands the terminal SubLinear form of the contrastive solve. Phase-2A was Adaptive { Linear, Linear } because its inner solve_on_change materialised the full solution vector even when only |closure| ≪ n rows mattered. Phase-2B replaces that with per-entry sublinear-Neumann queries scoped to the closure, and the orchestrator now declares end-to-end SubLinear.

What's new

  • src/entry.rs (new) — solve_single_entry_neumann(matrix, b, target, max_terms, tolerance): computes x[i] = e_iᵀ A⁻¹ b by truncated Neumann iteration restricted to closure(i, max_terms). Never materialises x. Cost O(max_terms · |closure| · branching) — independent of n. Op marker SolveSingleEntryNeumannOp declares SubLinear. Batched variant solve_single_entries_neumann for fan-out at orchestrator time.
  • src/contrastive.rs (+143 LOC) — contrastive_solve_on_change_sublinear(matrix, prev, b_new, delta, closure_depth, max_terms, tolerance, k): end-to-end SubLinear orchestrator. Empty-delta / zero-k short-circuit before any solve work — the "no event, no work" path is free.
  • ADR-001 roadmap updated: item Fix psycho-symbolic-reasoner npm package MODULE_NOT_FOUND error #6 now has its terminal form. All six items SubLinear-or-stronger end-to-end.
  • complexity-baseline.txt regenerated.

Correctness gate

entry::tests::matches_full_solve_on_chain — single-entry estimate agrees with a full NeumannSolver solve at every row of an 8×8 strict-DD chain within 1e-6. contrastive::tests::sublinear_orchestrator_finds_changed_rows_on_chain — perturbing b[2] and asking for top-3 anomalies returns a top-k that includes row 2 (the change epicentre) with anomaly scores ordered descending.

Test plan

  • cargo test --lib → 188/188 pass (was 176 pre-phase-2A; +12 entry + orchestrator tests)
  • cargo check --lib clean
  • Full CI (cargo audit, cargo deny, complexity-baseline, joules smoke, fmt + clippy, all unit tests on ubuntu + macos)

🤖 Generated with claude-flow

…rator

Lands the terminal SubLinear form of the contrastive solve. The
phase-2A orchestrator was Adaptive {Linear, Linear} because its
inner solve_on_change materialised the full solution vector even
when only |closure| ≪ n rows mattered. Phase-2B replaces that with
per-entry sublinear-Neumann queries scoped to the closure, and the
orchestrator now declares end-to-end SubLinear.

Lands:

  src/entry.rs (new, 381 LOC)
    solve_single_entry_neumann(matrix, b, target, max_terms, tolerance)
      Computes x[i] = e_iᵀ A⁻¹ b for strict-DD A by truncated Neumann
      series restricted to closure(i, max_terms). Never materialises x.
      O(max_terms · |closure| · branching) — independent of n for
      sparse DD matrices with bounded depth. Op marker
      SolveSingleEntryNeumannOp declares SubLinear.

    solve_single_entries_neumann(matrix, b, targets, max_terms, tolerance)
      Batched variant returning sorted (idx, val) pairs — the natural
      feed for find_anomalous_rows_in_subset.

  src/contrastive.rs (+143 LOC)
    contrastive_solve_on_change_sublinear(matrix, prev, b_new, delta,
                                          closure_depth, max_terms, tolerance, k)
      End-to-end SubLinear: closure (SubLinear) → per-entry Neumann
      (SubLinear) → top-k-in-subset (SubLinear). Empty delta / zero-k
      short-circuit before any solve work — the "no event, no work"
      path is free, which is the gating discipline the ADR turns on.
      Op marker ContrastiveSolveOnChangeSublinearOp declares SubLinear.

  src/lib.rs
    Re-exports solve_single_entry{,ies}_neumann, SolveSingleEntryNeumannOp,
    contrastive_solve_on_change_sublinear, ContrastiveSolveOnChangeSublinearOp.

  docs/adr/ADR-001-complexity-as-architecture.md
    Item #6 status updated to "phase-2B landed — end-to-end SubLinear".
    Status preamble notes that the change-driven activation primitive
    is now fully realised.

  .github/complexity-baseline.txt
    Adds SolveSingleEntryNeumannOp (SubLinear) and
    ContrastiveSolveOnChangeSublinearOp (SubLinear) so the regression
    guard knows the new declarations.

Tests: 188 lib tests pass (was 176 before phase-2A; +12 across entry
+ contrastive). Critical correctness test: entry::tests::
matches_full_solve_on_chain verifies the single-entry estimate
agrees with a full NeumannSolver solve at every row of an 8×8 DD
chain within 1e-6.

Co-Authored-By: claude-flow <ruv@ruv.net>
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.

2 participants