Skip to content

fix(#182): linear-algebra API was unconstructible and SVD returned wrong results - #195

Merged
mivertowski merged 1 commit into
mainfrom
fix/issue-182-linalg-api-docs
Jul 21, 2026
Merged

fix(#182): linear-algebra API was unconstructible and SVD returned wrong results#195
mivertowski merged 1 commit into
mainfrom
fix/issue-182-linalg-api-docs

Conversation

@mivertowski

Copy link
Copy Markdown
Owner

Round 8 of #182. The reporter fixed their N-body data race, moved on to SVD, and found the linear-algebra API unusable. Every observation was a real defect — including one that silently returned wrong math.

1. GPULinearAlgebraProvider was impossible to construct

Its constructor required an IKernelManageran interface with no implementation anywhere in the repo — so the README's headline example could never compile. Worse, AddDotComputeAlgorithms() registered GpuMatrixOperations, which had the same required dependency, so that registration could not be resolved either.

IKernelManager is now optional on both (it is only needed for custom GPU kernel execution). The two GPU kernel call sites raise a descriptive error, which the provider already catches to fall back to CPU. Both types are registered via factories that resolve IKernelManager optionally.

2. SVD returned mathematically wrong results 🔴

GpuMatrixOperations.SVDAsync and GpuOptimizationStrategies.FallbackSVDAsync each carried their own "simplified eigendecomposition of A^T·A" — its own comment admitted "not numerically stable". On a 6×6 matrix:

singular values ‖U·S·Vᵀ − A‖
before 0.6724, 0.0517, 0.4761 (unsorted, wrong) 2.8
after 4.6418, 3.2217, 2.8212 1.7e-6

Both now delegate to the existing, correct one-sided Jacobi SVD (MatrixDecomposition.ComputeJacobiSVD), so every entry point shares one implementation. MatrixMath.SVDAsync was already correct — the two now agree.

3. The README documented APIs that do not exist

  • IAcceleratorService — no such type anywhere.
  • LinearAlgebraKernels.GetKernelSource — the type is LinearAlgebraKernelLibrary.
  • AdvancedLinearAlgebraKernels — no such file or type.
  • GetOptimizedParametersinternal, not usable.

Usage sections rewritten against the current build, and they now answer the reporter's actual question: how to get an IAccelerator (from DI — a kernel name is only needed for IComputeOrchestrator, which runs user [Kernel] methods).

Verification

Everything documented was executed first: provider SVD reconstruction 1.7e-6, Multiply 1.2e-7, QR 3.0e-8, Solve 5.6e-8, and provider ≡ MatrixMath. New regression tests cover constructibility, DI resolution, SVD reconstruction, descending singular values, and provider/MatrixMath agreement. 262 Algorithms tests pass; solution builds clean.

Known remaining inconsistency (not addressed here)

The reporter also noticed duplication, and they're right: there are two Matrix classes (…LinearAlgebra.Matrix and …Types.LinearAlgebra.Matrix) and two LinearAlgebraOperation enums (…Algorithms and …Types). Consolidating those is a public-API breaking change and deserves its own issue rather than being bundled into a bug fix.

🤖 Generated with Claude Code

…ed wrong results)

The reporter moved on to SVD and found the documented linear-algebra API unusable. Every
one of their observations was a real defect:

1. GPULinearAlgebraProvider was IMPOSSIBLE TO CONSTRUCT. Its constructor required an
   IKernelManager — an interface with no implementation anywhere in the repo — so the
   README's headline example could never compile. Worse, AddDotComputeAlgorithms()
   registered GpuMatrixOperations, which had the same required dependency, so that
   registration could not be resolved either. IKernelManager is now optional on both
   (it is only needed for custom GPU kernel execution); the GPU kernel paths raise a
   descriptive error which the provider already catches to fall back to CPU. Both types
   are now registered via factories that resolve IKernelManager optionally.

2. SVD RETURNED MATHEMATICALLY WRONG RESULTS. GpuMatrixOperations.SVDAsync and
   GpuOptimizationStrategies.FallbackSVDAsync each carried their own "simplified
   eigendecomposition of A^T*A" (its own comment: "not numerically stable"). On a 6x6
   matrix it produced unsorted singular values (0.6724, 0.0517, 0.4761 vs the true
   4.6418, 3.2217, 2.8212) and a factorization that did not reconstruct the input at all
   (|U*S*V^T - A| = 2.8). Both now delegate to the existing, correct one-sided Jacobi SVD
   (MatrixDecomposition.ComputeJacobiSVD), so every entry point shares one implementation.

3. The README documented APIs that do not exist: IAcceleratorService (no such type),
   LinearAlgebraKernels.GetKernelSource (the type is LinearAlgebraKernelLibrary),
   AdvancedLinearAlgebraKernels (no such file/type), and GetOptimizedParameters (internal).
   The usage sections are rewritten against the current build and now also answer the
   reporter's actual question — how to obtain an IAccelerator (from DI; a kernel name is
   only needed for IComputeOrchestrator, which runs user [Kernel] methods).

Verified: provider SVD reconstruction 1.7e-6 (was 2.8), Multiply 1.2e-7, QR 3.0e-8,
Solve 5.6e-8; provider and MatrixMath now agree. New regression tests cover
constructibility, DI resolution, SVD reconstruction, descending singular values, and
provider/MatrixMath agreement. 262 Algorithms tests pass; solution builds clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mivertowski
mivertowski merged commit 1273719 into main Jul 21, 2026
17 of 18 checks passed
@mivertowski
mivertowski deleted the fix/issue-182-linalg-api-docs branch July 21, 2026 18:00
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