SciSharp / SciSharp/NumSharp

[OpenBLAS] Port the LAPACK factorisations to a native managed C# backend

Open
#627 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

architecture enhancement NumPy 2.x Compliance
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: LinAlgEngineSeamTests asserts each throws NotSupportedException ("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/dot already exist)
  • Complex (c/z) paths for complex eig/eigh/svd — +10–13k C#
  • Gate — tolerance-based linalg differential-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.einsum contraction — a summation kernel + path planner, NumSharp's own work, not LAPACK; tracked separately.
  • Keep NumSharp.Core 100% managed — this backend is pure C#, no native dependency; it plugs into the same TensorEngine.Blas property 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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.