[OpenBLAS] Port the LAPACK factorisations to a native managed C# backend
Nobody has claimed this yet.
- Dominant language
- C#
- Stars
- 1.5k
- Forks
- 205
- Avg merge
- 7d 7h
- Merged PRs (30d)
- 2
Description
Overview
NumSharp's matrix products are fully managed and value-gated, but the factorisations NumPy computes through OpenBLAS's bundled LAPACK (inv, solve, svd, qr, eig, det, cholesky, lstsq, …) currently throw NotSupportedException. This tracks implementing them as a pure-managed C# backend behind the existing IBlasBackend seam — no native dependency, correctness-not-byte-parity. NumSharp.Core stays 100% managed.
Problem
NumSharp.Core ships no managed LU/QR/SVD/eigensolver, so 18 np.linalg.* entry points + norm matrix orders {2, -2, 'nuc'} + matrix_power(n<0) have complete API / validation / error-parity scaffolding (gated by LinAlgSignatureParityTests and LinAlgErrorParityTests) but zero numerics — every real call raises.
Verified by three independent techniques:
- Static throw-site classification: every factorisation file carries a
NoLapack(...)numerics throw; the product files carry none. - Test contract:
LinAlgEngineSeamTestsasserts each throwsNotSupportedException("delete a case as each implementation lands"). - Live execution (no backend installed): 17 products/shape ops compute; 18/18 factorisations throw
NotSupported.
Proposal
Implement managed LAPACK, filling the 15 default-false Try* members in Backends/IBlasBackend.LinearAlgebra.cs (validation and verbatim errors already run before the seam, so only algorithms are needed). Phased so each lands independently:
- Phase 1 — LU (
getrf/getrs/getri/gesv) →solve,inv,det,slogdet,matrix_power(<0),tensorinv,tensorsolve— ~2.5k C# - Phase 2 — Cholesky + QR (
potrf,geqrf/orgqr) →cholesky,qr— ~2.95k C# - Phase 3 — SVD (
gesdd,gelsd) →svd,svdvals,pinv,matrix_rank,cond,norm{2,-2,'nuc'},lstsq— ~9k C# - Phase 4 — Eigen (
syevd/heevd,geev) →eigh,eigvalsh,eig,eigvals— ~10.2k C# - Kernels — add managed IL/SIMD
trsm/syrk/trmm(the ~690 IL-hot lines;gemm/gemv/dotalready exist) - Complex (c/z) paths for complex
eig/eigh/svd— +10–13k C# - Gate — tolerance-based
linalgdifferential-fuzz tier (factorisations are not byte-parity-gated)
Evidence — verified completeness audit
| Surface | Count | Completeness | Confidence |
|---|---|---|---|
Products / CBLAS (dot, matmul, inner, tensordot, vdot, vecdot, matvec, vecmat, outer, multi_dot, matrix_power≥0, norm non-SVD, trace, diagonal, cross, …) |
17 | ~99% (managed + value-gated) | high (static + live + products.jsonl 287 cases) |
Partial (norm, matrix_power, einsum) |
3 | ~65% | high (live-verified split) |
| Factorisations / LAPACK | 18 | ~30% (validation only) | high (3 techniques agree) |
LOC estimate (reference-LAPACK dependency closure, code-only Fortran × ~1.2 → C#): ~24.7k for float32/float64, +10–13k for complex. Only ~690 lines (~3%) are IL/SIMD-hot leaves (and gemm is already implemented in SimdMatMul); the remaining ~24k is scalar driver code where IL codegen buys nothing — its speed comes entirely from the Level-3 kernels underneath.
Reuse lever: MIT-licensed MathNet.Numerics ships managed LU/QR/SVD/Cholesky/Eigen. Adapting it behind the seam could cut net-new to glue + gaps rather than a full Fortran translation (its results aren't byte-identical to NumPy either — fine, since factorisations aren't parity-gated).
Scope / Non-goals
- ❌ Byte-parity with NumPy's OpenBLAS float output — out of scope. That is
NumSharp.Interop.OpenBLAS's job (a route-for-route port that calls the same binary). Factorisation results aren't parity-gated, and NumPy's own LAPACK bits aren't reproducible across builds/CPUs/thread-counts anyway. - ❌ Byte-perfect managed GEMM port — reproducing OpenBLAS's DYNAMIC_ARCH accumulation order is months of empirical reverse-engineering per CPU arch and inherently fragile to CPU/thread/version; not this issue.
- ❌ Products — already managed-implemented and value-gated; not re-opened here.
- ❌
np.einsumcontraction — a summation kernel + path planner, NumSharp's own work, not LAPACK; tracked separately. - ✅ Keep
NumSharp.Core100% managed — this backend is pure C#, no native dependency; it plugs into the sameTensorEngine.Blasproperty the OpenBLAS package uses.
Related issues
- #145 — Add LAPACK functionality (historical, closed) — this is the modern, scoped version
- #144 — Implement linalg.lstsq (closed)
- #497 — np.linalg.pinv not supported
- #239 / #441 / #485 — np.linalg.norm (matrix 2/-2/nuc orders land in Phase 3)
- #626 — NumSharp.Interop.OpenBLAS (the byte-parity products path; complementary, not superseded)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading Backends/IBlasBackend.LinearAlgebra.cs and the existing LinAlgEngineSeamTests, LinAlgSignatureParityTests, and LinAlgErrorParityTests. Implementations are expected to fill the default-false Try* members in phases, with managed numerical results replacing NotSupportedException while preserving the existing validation and error behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- backend
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 20/100