mojolearn.linalg#
Float32 linear algebra: a bit-identical matrix product, low-bit products and NumPy-named decompositions.
matmul computes op(a) @ op(b) in float32 under the profile
mojolearn.identical.gemm.fp32.v1: the same bits on NVIDIA and AMD for the same
inputs. It supports the NN, NT and TN products; asking for both transposes raises
ValueError. By default it requires the identical build and raises when another
build is loaded; identical=False uses whichever build is loaded, with no
identity guarantee. numeric_mode, profile and require_identical report and
check what this process loaded.
matmul_bf16, matmul_int8 and matmul_int15 are the low-bit profiles, with
to_bf16, from_bf16, quantize_int8, dequantize_int8, quantize_int15 and
dequantize_int15 to prepare and recover their operands.
qr, eigh, svdvals and svd carry NumPy’s names and meanings for the modes
they support (note that qr defaults to mode='r'); unsupported modes are refused
by name rather than approximated. They run on the device on a GPU install and on the
host binding on a CPU-only install, with the same bits. Cholesky factors a
symmetric positive-definite matrix and solves with the factor.
Importing this module does not load the extension or run any computation.
Examples
>>> import numpy as np
>>> from mojolearn import linalg
>>> a = np.random.default_rng(0).random((256, 64), dtype=np.float32)
>>> b = np.random.default_rng(1).random((64, 32), dtype=np.float32)
>>> c = np.asarray(linalg.matmul(a, b))
Functions
|
Float32 matrix product |
The numeric mode of the linalg extension this process loaded. |
|
|
Describe the matrix-product profile this process loaded, as a dict. |
Raise |
|
|
QR decomposition, as |
|
Eigenvalues and eigenvectors of a symmetric matrix, as |
|
Singular values in descending order, as |
|
Singular value decomposition, as |
|
Matrix product with bfloat16 operands, under the profile |
|
Matrix product |
|
Convert float32 to bfloat16 bits. |
|
Convert bfloat16 bits (a uint16 buffer) to float32, exactly. |
Quantize a 2-D float32 matrix to int8 codes with one power-of-two exponent per row. |
|
|
Recover float32 values |
|
Matrix product |
Quantize a 2-D float32 matrix to fifteen-bit codes stored as two int8 planes. |
|
|
Recover float32 values |
Classes
|
Cholesky factorization |
- mojolearn.linalg.matmul(a, b, *, transpose_a=False, transpose_b=False, out=None, identical=True)[source]#
Float32 matrix product
op(a) @ op(b)with the same bits on NVIDIA and AMD.Computes under the profile
mojolearn.identical.gemm.fp32.v1. Each output cell accumulates itskproducts in a fixed order that depends only on the input bits,kand the profile: not onm,n, the launch geometry, the batch or the vendor. The order is chosen for reproducibility, not accuracy, so the result does not match NumPy’sa @ bbit for bit.- Parameters:
a, b (float32 buffer, 2-D) – Any object exporting a 2-D float32 buffer: a NumPy array, an
array.array('f'), amojolearn.Array, and so on. NumPy is not required. Other dtypes raiseTypeErrorrather than being cast. Non-contiguous input is copied; C-contiguous input is used without a copy.transpose_a, transpose_b (bool, default False) – Whether the stored array is the transpose of the operand. Three combinations are supported:
transpose_a
transpose_b
C
a.shape
b.shape
False
False
a @ b(m, k)
(k, n)
False
True
a @ b.T(m, k)
(n, k)
True
False
a.T @ b(k, m)
(k, n)
Both True raises
ValueError; compute(b @ a).Tinstead, for examplenp.ascontiguousarray(np.asarray(matmul(b, a)).T).out (writable float32 buffer, optional) – Destination, C-contiguous with shape (m, n). A new
mojolearn.Arrayis allocated when None.identical (bool, default True) – Require the identical build: raises
RuntimeErrorwhen another build is loaded. False uses whichever build is loaded, with no identity guarantee.
- Returns:
mojolearn.Array or out – The (m, n) float32 result;
numpy.asarrayon it is zero-copy. Whenoutis given, that same object is returned.- Raises:
ValueError – Both transpose flags set, mismatched contracted extents, or a wrong
outshape or layout.TypeError – A non-float32 operand or
out.
Notes
Compare NaN cells with “is NaN”, not by bits: NaN payloads are not guaranteed. A
min,maxorargminyou take over the output can depend on order, because-0.0 == +0.0; make such reductions order-independent yourself.Examples
>>> import numpy as np >>> from mojolearn import linalg >>> a = np.random.default_rng(0).random((128, 64), dtype=np.float32) >>> b = np.random.default_rng(1).random((32, 64), dtype=np.float32) >>> c = np.asarray(linalg.matmul(a, b, transpose_b=True))
- mojolearn.linalg.numeric_mode()[source]#
The numeric mode of the linalg extension this process loaded.
Returns ‘identical’, ‘deterministic’ or ‘fast’, read back from the loaded binary itself rather than from the environment, and checked against the directory it was loaded from and the binary’s profile version.
- Returns:
str
- Raises:
RuntimeError – When the binary is in the wrong directory, its profile version is unknown, or the extension is stale.
- mojolearn.linalg.profile()[source]#
Describe the matrix-product profile this process loaded, as a dict.
Keys include
profile(the profile name, for example'mojolearn.identical.gemm.fp32.v1'),profile_version,numeric_mode,identity_claimed,dtype,opsandbinary(the loaded file). Quote the profile name with any result you publish.identity_claimedis True only when the identical build is loaded; in any other mode the remaining fields describe the computation but guarantee nothing about the bits.- Returns:
dict
- mojolearn.linalg.require_identical()[source]#
Raise
RuntimeErrorunless this process loaded the identical build.Call it once at start-up when your program depends on bit-identical results, so a wrong build fails immediately rather than at the first product.
matmulcalls it for you unless you passidentical=False.
- mojolearn.linalg.qr(a, mode='r')[source]#
QR decomposition, as
numpy.linalg.qr.- Parameters:
a (float32 buffer, shape (M, N)) – Non-float32 input raises
TypeErrorrather than being cast.mode ({‘r’, ‘reduced’, ‘complete’, ‘raw’}, default ‘r’) – Unlike NumPy, the default is ‘r’ (R only); pass
mode='reduced'for NumPy’s default(Q, R). ‘reduced’ returns Q (M, K) and R (K, N), ‘complete’ Q (M, M) and R (M, N), ‘raw’ h (N, M) and tau (K,), with K = min(M, N), following LAPACK’s conventions. Any other mode raisesValueError.
- Returns:
R (mojolearn.Array, shape (N, N), for mode=’r’) – Upper triangular, with
R.T @ Requal toa.T @ ato float32 rounding. For M >= N its rows can differ in sign fromqr(a, mode='reduced')[1].(Q, R) or (h, tau) – For the other modes.
Notes
Runs on the device on a GPU install and on the host binding on a CPU-only install, with the same bits.
- mojolearn.linalg.eigh(a, UPLO='L')[source]#
Eigenvalues and eigenvectors of a symmetric matrix, as
numpy.linalg.eigh.- Parameters:
a (float32 buffer, shape (N, N)) – Read as symmetric from one triangle; the other is never read. A non-square matrix raises
ValueError.UPLO ({‘L’, ‘U’}, default ‘L’) – Which triangle to read.
- Returns:
w (mojolearn.Array, shape (N,)) – Eigenvalues in ascending order.
v (mojolearn.Array, shape (N, N)) –
v[:, i]is the unit eigenvector ofw[i]. Each vector’s sign is fixed by a deterministic rule, so the result depends only on the matrix.
- Raises:
RuntimeError – When the Jacobi iteration does not converge, or the device kernel did not run.
Notes
Uses a round-robin Jacobi method, on the device on a GPU install and on the host binding on a CPU-only install, with the same bits.
- mojolearn.linalg.svdvals(a)[source]#
Singular values in descending order, as
numpy.linalg.svdvals.Computed as the singular values of R from a Householder QR of
a, which equal those ofa; a wide matrix (M < N) is read through its transpose.- Parameters:
a (float32 buffer, shape (M, N))
- Returns:
mojolearn.Array, shape (min(M, N),)
- mojolearn.linalg.svd(a, full_matrices=True, compute_uv=True, hermitian=False)[source]#
Singular value decomposition, as
numpy.linalg.svd.Returns
SVDResult(U, S, Vh)withSdescending. The signs of the columns ofUandVare deterministic but need not match LAPACK’s (NumPy promises no sign either).compute_uv=Falsereturnssvdvals.hermitian=Truegoes througheigh(lower triangle) as NumPy does and needs a square matrix, otherwiseValueError.- Parameters:
a (float32 buffer, shape (M, N))
full_matrices (bool, default True) – Return U (M, M) and Vh (N, N) instead of the reduced shapes.
compute_uv (bool, default True) – Return U and Vh as well as S.
hermitian (bool, default False) – Treat
aas symmetric.
- Returns:
SVDResult or mojolearn.Array
- class mojolearn.linalg.Cholesky(jitter=None)[source]#
Bases:
NumericModeMixinCholesky factorization
A + jitter * I = L @ L.Tof a symmetric positive-definite matrix, then solves.fitfactors a given float32 matrix once;solveanswersA X = Bfrom the factor andlogdet_gives the log-determinant. A failed factorization is not an exception: checkinfo_(0 means success); a failed factor’ssolveandlogdet_refuse. The factor can be saved withsaveand loaded withload, including on a CPU-only install, wherefitandsolvealso run.- Parameters:
jitter (float or None, default None) – Ridge added to the diagonal before factoring. None uses the profile’s fixed ridge (see
profile_jitter); 0.0 adds none. Any other value is refused, because the identical mode fixes the ridge to those two values. A non-number raisesTypeError.- Variables:
L_ (mojolearn.Array, shape (n, n), float32) – Lower-triangular factor, strict upper triangle zero. Meaningful only when
info_ == 0.info_ (int) – LAPACK-style status: 0 for a complete factor;
k > 0means the leading minor of order k is not positive definite andL_is partial.nb_ (int) – Panel width used by the factorization.
logdet_ (float) –
log |A + jitter * I|. RaisesValueErrorafter a failed fit.jitter_ (float) – The ridge that was added.
n_ (int) – Matrix size.
Notes
A non-square
Aor a right-hand side whose row count is not n raisesValueError; non-finite or non-symmetric matrices are refused before any work.Examples
>>> import numpy as np, mojolearn >>> rng = np.random.default_rng(0) >>> M = rng.random((64, 64), dtype=np.float32) >>> A = (M @ M.T + 64 * np.eye(64, dtype=np.float32)).astype(np.float32) >>> chol = mojolearn.Cholesky(jitter=0.0).fit(A) >>> x = np.asarray(chol.solve(np.ones(64, dtype=np.float32)))
- vendor_used()[source]#
Accelerator API of the loaded binary, read back from it; “cpu” on a CPU-only install.
- fit(A)[source]#
Factor
A + jitter * I; returns self.Ais a square 2-D float32 matrix, otherwiseValueError. A failed factorization setsinfo_ != 0instead of raising.
- property logdet_#
log |A + jitter * I|; raisesValueErrorafter a failed fit.
- solve(B)[source]#
Solve
A X = Bfrom the factor.- Parameters:
B (float32 array, shape (n,) or (n, nrhs))
- Returns:
X (float32 array, the shape of
B)- Raises:
ValueError – Before
fit, or whenBhas the wrong row count or no columns. Solving against a failed factor is also refused.
- mojolearn.linalg.matmul_bf16(a, b, *, transpose_a=False, transpose_b=False, out=None)[source]#
Matrix product with bfloat16 operands, under the profile
mojolearn.identical.gemm.bf16f32.v1.bis bfloat16 bits (a uint16 buffer fromto_bf16);ais float32 or bfloat16 bits too. The output is float32: the operands are widened exactly and multiplied withmatmul’s arithmetic, somatmul(from_bf16(a_bits), from_bf16(b_bits))gives the same bits.transpose_a,transpose_bandoutbehave as inmatmul. Requires the identical build.
- mojolearn.linalg.matmul_int8(a, b, *, out=None)[source]#
Matrix product
a @ b.Twith int8 operands, under the profilemojolearn.identical.gemm.int8i32.v1.Each of
a(m, k) andb(n, k) is either a float32 matrix, quantized by the profile’s rule, or a(codes, exponents)pair fromquantize_int8. The output is float32: the exact int32 sum of the code products, scaled by a power of two. It is the product of the rounded operands, not the float32 product.outbehaves as inmatmul. Requires the identical build.
- mojolearn.linalg.to_bf16(x)[source]#
Convert float32 to bfloat16 bits.
Subnormals are flushed, then each value is rounded to nearest even. Returns a uint16
mojolearn.Arrayof the same shape, the input format ofmatmul_bf16.
- mojolearn.linalg.from_bf16(bits)[source]#
Convert bfloat16 bits (a uint16 buffer) to float32, exactly.
Returns a float32
mojolearn.Arrayof the same shape.
- mojolearn.linalg.quantize_int8(x)[source]#
Quantize a 2-D float32 matrix to int8 codes with one power-of-two exponent per row.
- Returns:
codes (mojolearn.Array of int8) – The shape of
x.exponents (mojolearn.Array of int32) – One per row;
row = codes * 2**exponent.
- mojolearn.linalg.dequantize_int8(codes, exponents)[source]#
Recover float32 values
codes * 2**exponents[row]exactly fromquantize_int8output.
- mojolearn.linalg.matmul_int15(a, b, *, out=None)[source]#
Matrix product
a @ b.Twith fifteen-bit operands, under the profilemojolearn.identical.gemm.int15i64.v1.Each of
a(m, k) andb(n, k) is either a float32 matrix, quantized by the profile’s rule, or a(hi, lo, exponents)triple fromquantize_int15. The output is float32: the exact integer sum of the code products, rounded to nearest even and scaled by a power of two. It is the product of the rounded operands, not the float32 product.kmay be at most 65536 (INT15_MAX_K); larger values raiseValueError.outbehaves as inmatmul. Requires the identical build.
- mojolearn.linalg.quantize_int15(x)[source]#
Quantize a 2-D float32 matrix to fifteen-bit codes stored as two int8 planes.
Per row,
e = floor(log2(absmax)) - 13so the largest magnitude lands in [8192, 16384); each code isclamp(round_half_even(x * 2**-e), -16383, 16383), split ashi = code >> 7andlo = code & 127socode = hi * 128 + lo. The same planes and exponents on every vendor.- Returns:
hi, lo (mojolearn.Array of int8) – The shape of
x.exponents (mojolearn.Array of int32) – One per row.