Interface IBlasBackend
An external BLAS/LAPACK a TensorEngine may delegate its matrix products and factorisations to.
public interface IBlasBackend
Remarks
NumSharp is 100 % managed C#: it has no native dependency and computes every matrix product with its own SIMD kernels. This interface is the ONE place an optional package can offer an alternative — it is a seam, not a requirement. With Blas left null (the default) nothing here is ever consulted.
Every member is Try-shaped on purpose: a backend answers only for the operand
combinations it actually implements (an external CBLAS covers float32/
float64 and nothing else) and returns false for the rest, which the engine then
computes with its own kernels. So installing a backend can change WHICH implementation
runs, never WHETHER NumSharp can compute the product.
The reason to want one is not only speed. Two correct matrix products that sum in
different orders give different bits, so a workload that must agree with another stack
to the last bit — e.g. training a network twice and byte-comparing the weights — has to
call that stack's own BLAS. See NumSharp.Interop.OpenBLAS and
docs/stale-docs/GEMM_PARITY.md.
Reading the operands. An implementation needs raw pointers and strides, and
NumSharp's public surface offers two spellings that are NOT interchangeable. Use
(T*)a.GetData().Address + a.Shape.Offset together with a.Shape.Strides —
that pair is consistent for every layout. Do NOT use a.GetData<T>().Address:
for a non-contiguous view it returns a DENSIFIED COPY, so combining it with
Shape.Strides reads outside the buffer and yields wrong numbers on exactly the
sliced and transposed operands a matrix product is most often handed. Element strides,
not bytes. Nothing here requires access to NumSharp's internals — a backend can live in
any assembly.
The linear-algebra members below (the CBLAS product family and the LAPACK
factorisations) are DEFAULT implementations returning false. That is what lets them be
added without breaking the one backend that ships today
(NumSharp.Interop.OpenBLAS's OpenBlasBackend, which answers only for
dot/matmul at float32/float64) and any third-party implementation — a
backend mentions only the members it serves, exactly as with
TryMatMulBatched(NDArray, NDArray, NDArray).
Those two groups differ in one important way, and it is not their shape. The
product family (inner/vdot/vecdot/matvec/vecmat) keeps
the invariant the rest of this interface states: NumSharp computes them with its own
managed kernels, so a backend changes WHICH implementation runs, never WHETHER the answer
can be produced. The factorisation family CANNOT keep it — NumSharp.Core ships no managed
LU, QR, SVD or eigensolver, so with no backend installed (or one that declines) the engine
has nothing to fall back to and raises OpenBlasMissingBackendException.
Callers of np.linalg must expect that; callers of the product family need not.
LAPACK operands. The operand-reading rule above applies unchanged, but LAPACK additionally wants column-major input, so an implementation will usually transpose or ask LAPACKE for row-major order; the engine hands over the operands untouched rather than guessing which a backend prefers.
Stacked operands. NumPy's linalg entry points are gufuncs over the trailing one or two axes, so every operand in the factorisation family may carry leading batch dimensions. A backend that only serves a single matrix returns false for a stacked one.
Properties
Info
A one-line description of the underlying library (path, symbols, thread count), for diagnostics. Never null.
string Info { get; }
Property Value
Methods
TryCholesky(NDArray, bool, out NDArray)
Computes np.linalg.cholesky (LAPACK potrf).
bool TryCholesky(NDArray a, bool upper, out NDArray result)
Parameters
Returns
- bool
False when this backend does not serve these operands.
TryDet(NDArray, out NDArray)
Computes np.linalg.det (LAPACK getrf).
bool TryDet(NDArray a, out NDArray result)
Parameters
Returns
- bool
False when this backend does not serve these operands.
TryDot(NDArray, NDArray, out NDArray)
Computes np.dot(left, right), allocating the result.
bool TryDot(NDArray left, NDArray right, out NDArray result)
Parameters
Returns
- bool
False when this backend does not serve these operands — the caller must then fall back to its own kernels, and
resultis meaningless.
Remarks
dot is a separate entry point from TryMatMul2D(NDArray, NDArray, NDArray) because the two
are not the same operation for every shape: NumPy implements them with two different
dispatchers, which disagree on some non-contiguous operands, and a backend claiming
bit-parity has to reproduce that.
TryEig(NDArray, bool, out NDArray, out NDArray)
Computes np.linalg.eig / np.linalg.eigvals (LAPACK geev) for a
general, not necessarily symmetric, matrix.
bool TryEig(NDArray a, bool computeVectors, out NDArray eigenvalues, out NDArray eigenvectors)
Parameters
aNDArraycomputeVectorsboolFalse for
eigvals—eigenvectorsis then null.eigenvaluesNDArrayeigenvectorsNDArray
Returns
- bool
False when this backend does not serve these operands.
TryEigh(NDArray, char, bool, out NDArray, out NDArray)
Computes np.linalg.eigh / np.linalg.eigvalsh (LAPACK syevd for a
real symmetric operand, heevd for a complex Hermitian one).
bool TryEigh(NDArray a, char uplo, bool computeVectors, out NDArray eigenvalues, out NDArray eigenvectors)
Parameters
aNDArrayuplochar'L' or 'U' — which triangle holds the data.
computeVectorsboolFalse for
eigvalsh.eigenvaluesNDArrayeigenvectorsNDArray
Returns
- bool
False when this backend does not serve these operands.
TryInner(NDArray, NDArray, out NDArray)
Computes np.inner(a, b) — a sum product over the LAST axis of both operands.
bool TryInner(NDArray a, NDArray b, out NDArray result)
Parameters
Returns
- bool
False when this backend does not serve these operands.
TryInv(NDArray, out NDArray)
Computes np.linalg.inv — NumPy solves a x = I with gesv rather
than calling an explicit inversion routine.
bool TryInv(NDArray a, out NDArray result)
Parameters
Returns
- bool
False when this backend does not serve these operands.
TryLstsq(NDArray, NDArray, double, out NDArray, out NDArray, out NDArray, out NDArray)
Computes np.linalg.lstsq (LAPACK gelsd) — the least-squares solution
plus residuals, the effective rank and the singular values.
bool TryLstsq(NDArray a, NDArray b, double rcond, out NDArray solution, out NDArray residuals, out NDArray rank, out NDArray singularValues)
Parameters
aNDArraybNDArrayrconddoubleSingular-value cutoff, relative to the largest singular value.
solutionNDArrayresidualsNDArrayrankNDArraysingularValuesNDArray
Returns
- bool
False when this backend does not serve these operands.
TryMatMul2D(NDArray, NDArray, NDArray)
Computes the 2-D matrix product left @ right INTO result —
the core of np.matmul, of @, and of every element of a stacked product.
bool TryMatMul2D(NDArray left, NDArray right, NDArray result)
Parameters
leftNDArrayrightNDArrayresultNDArrayA pre-allocated
(M, N)array of the promoted dtype. Written in full when this returns true; left untouched when it returns false.
Returns
- bool
False when this backend does not serve these operands.
TryMatMulBatched(NDArray, NDArray, NDArray)
Computes a STACKED matrix product — the whole of np.matmul for operands of
three dimensions or more — INTO result.
bool TryMatMulBatched(NDArray left, NDArray right, NDArray result)
Parameters
leftNDArrayAlready broadcast to
(batch…, M, K).rightNDArrayAlready broadcast to
(batch…, K, N).resultNDArrayA pre-allocated
(batch…, M, N)array of the promoted dtype.
Returns
- bool
False when this backend does not serve these operands.
Remarks
Optional. The default returns false and the engine calls TryMatMul2D(NDArray, NDArray, NDArray) once per batch element instead, so a backend that does not care about stacked products need not mention this member at all — which is the point of it being a default implementation rather than a new required one.
Implement it when per-product setup can be amortised. The trailing two strides of each operand are the SAME for every element of a stack, so any route decision or scratch allocation derived from them is computed once — which is exactly why NumPy hoists that work out of its matmul gufunc's outer loop. Doing it per element instead costs more than the product itself once the matrices are small: measured on 2000 stacked 8×8 float32 products, per-element setup made an external OpenBLAS 20 % SLOWER than NumSharp's own managed GEMM.
TryMatvec(NDArray, NDArray, out NDArray)
Computes the np.matvec gufunc (m,n),(n)->(m), allocating the result —
NumPy's gemv route.
bool TryMatvec(NDArray x1, NDArray x2, out NDArray result)
Parameters
Returns
- bool
False when this backend does not serve these operands.
TryQr(NDArray, string, out NDArray, out NDArray)
Computes np.linalg.qr (LAPACK geqrf plus orgqr/ungqr).
bool TryQr(NDArray a, string mode, out NDArray q, out NDArray r)
Parameters
aNDArraymodestringAlready validated to one of "reduced", "complete", "r", "raw". For "r" only
ris produced; for "raw" the pair is LAPACK's packed (h,tau) rather than (Q, R).qNDArrayrNDArray
Returns
- bool
False when this backend does not serve these operands.
TrySlogdet(NDArray, out NDArray, out NDArray)
Computes np.linalg.slogdet (LAPACK getrf) — the sign of the determinant
and the natural log of its absolute value, which stays finite where det
overflows.
bool TrySlogdet(NDArray a, out NDArray sign, out NDArray logabsdet)
Parameters
Returns
- bool
False when this backend does not serve these operands.
TrySolve(NDArray, NDArray, bool, out NDArray)
Computes np.linalg.solve (LAPACK gesv).
bool TrySolve(NDArray a, NDArray b, bool oneDimensionalRhs, out NDArray result)
Parameters
aNDArraybNDArrayoneDimensionalRhsboolTrue when
bentered as a single vector — NumPy dispatches that to itssolve1gufunc(m,m),(m)->(m)rather than(m,m),(m,n)->(m,n).resultNDArray
Returns
- bool
False when this backend does not serve these operands.
TrySvd(NDArray, bool, bool, out NDArray, out NDArray, out NDArray)
Computes np.linalg.svd / np.linalg.svdvals (LAPACK gesdd).
bool TrySvd(NDArray a, bool fullMatrices, bool computeUv, out NDArray u, out NDArray s, out NDArray vh)
Parameters
aNDArrayfullMatricesboolcomputeUvboolFalse for the singular values alone —
uandvhare then null.uNDArraysNDArrayvhNDArray
Returns
- bool
False when this backend does not serve these operands.
TryVdot(NDArray, NDArray, out NDArray)
Computes np.vdot(a, b) — both operands flattened to 1-D, a
conjugated when complex, then a vector dot product. Always a 0-d result.
bool TryVdot(NDArray a, NDArray b, out NDArray result)
Parameters
Returns
- bool
False when this backend does not serve these operands.
TryVecdot(NDArray, NDArray, out NDArray)
Computes the np.vecdot gufunc (n),(n)->(), allocating the result —
x1 conjugated when complex.
bool TryVecdot(NDArray x1, NDArray x2, out NDArray result)
Parameters
Returns
- bool
False when this backend does not serve these operands.
Remarks
Allocating rather than filling a caller-provided buffer (the shape TryMatMul2D(NDArray, NDArray, NDArray) takes) is deliberate for the three gufuncs: the loop shape is the broadcast of the operands' leading axes, and making the engine derive it up front would compute it twice on the path where the backend declines.
TryVecmat(NDArray, NDArray, out NDArray)
Computes the np.vecmat gufunc (n),(n,m)->(m), allocating the result —
x1 conjugated when complex.
bool TryVecmat(NDArray x1, NDArray x2, out NDArray result)
Parameters
Returns
- bool
False when this backend does not serve these operands.