cheatah
Module

linalg

NumPy-style linear algebra on ndarray, with SIMD-accelerated contiguous kernels.

For the small-and-hot regime — a 3-D direction, a 4×4 transform built and consumed millions of times a second — reach for the sibling fixarray module: the same mathematics with the shape moved into the type (vec3f/mat4f, allocation-free, and faster than GLM across their whole overlap). linalg is the home of the heavy, shape-generic numerics below.

The routines mirror numpy.linalg and operate on ndarray::NDArray (2-D = matrix, 1-D = vector). The general eigensolvers eig/eigvals return a complex spectrum (CNDArray) — a real matrix can have complex conjugate eigenvalue pairs, e.g. a rotation has ±i — while the Hermitian solvers eigh/eigvalsh return a guaranteed-real spectrum (the same split as numpy). Kernels are compiled at -O3 -march=native so the hot loops auto-vectorize.

Usage

import linalg              # auto-links ndarray

let x = linalg.solve(A, b) # A·x = b
let d = linalg.det(A)

Functions

Every routine below returns a fresh array. Each also has an allocation-free out-parameter overload (solve(out, A, b), svd(u, s, vh, A), …) in routines.hpp for hot loops that reuse one scratch buffer per call — same math, caller-owned storage.

Products

  • dot / vdot / inner — vector dot product (Σ aᵢbᵢ).

  • outer — outer product of two vectors → matrix.

  • matmul — matrix multiply.

  • matrix_power — integer matrix power Aⁿ (negative via inv).

  • kron — Kronecker (block) product.

Decompositions

  • cholesky — lower-triangular L with A = L·Lᵀ (SPD only).

  • qr — reduced QR via Householder reflections.

  • svd — singular value decomposition (Golub–Reinsch: bidiagonalization + implicit QR).

  • svdvals — singular values only (the SVD fast path, without forming U/Vᵀ).

Eigenvalues

  • eig / eigvals — general square matrix (complex spectrum + eigenvectors; Hessenberg + shifted QR for the values, inverse iteration for the vectors).

  • eigh / eigvalsh — symmetric or complex Hermitian matrix (real spectrum; real eigenvectors for a real symmetric matrix, complex eigenvectors for a Hermitian one; Householder tridiagonalization + QL, via a real 2n embedding for Hermitian input).

All eigenvalue routines return the spectrum descending (note: numpy's eigvalsh returns ascending), with eigenvector columns reordered to match.

# A real rotation matrix has complex eigenvalues ±i:
let r = ndarray.reshape(ndarray.array([0.0, -1.0, 1.0, 0.0]), [2, 2])
io.print(ndarray.to_string(linalg.eigvals(r)))   # [0+1j, 0-1j]

Complex inner-product spaces

Vectors and matrices can be complex (ndarray.complex(re, im)), so the routines work over complex inner-product spaces — Hermitian operators, complex wavefunctions:

  • dot — bilinear product Σ aᵢbᵢ (complex, no conjugation; matches numpy).

  • vdot — conjugate-linear Hermitian inner product ⟨a, b⟩ = Σ conj(aᵢ)·bᵢ (conjugates the first argument; vdot(a, a) is the real ‖a‖²).

  • matmul — complex matrix multiply.

  • conj_transpose — conjugate transpose (Hermitian adjoint) Aᴴ.

import io
import ndarray
import linalg

# A Hermitian operator H = [[2, 1+i], [1-i, 3]] — real eigenvalues 4, 1:
let re = ndarray.array([2.0, 1.0, 1.0, 3.0])
let im = ndarray.array([0.0, 1.0, -1.0, 0.0])
let H = ndarray.reshape(ndarray.complex(re, im), [2, 2])
io.print(ndarray.to_string(linalg.eigvalsh(H)))   # [4, 1]

# Hermitian inner product ⟨a, a⟩ = ‖a‖² is real:
let a = ndarray.complex(ndarray.array([1.0, 3.0]), ndarray.array([2.0, -1.0]))
io.print(linalg.vdot(a, a))                        # 15+0j

Norms & numbers

  • norm — L2 (vector) / Frobenius (matrix).

  • cond — 2-norm condition number.

  • det / slogdet — determinant (LU); slogdet is overflow-safe.

  • matrix_rank — numerical rank from SVD thresholding.

  • trace — sum of the main diagonal.

Solving & inverses

  • solve — solve A·x = b via LU with partial pivoting.

  • lstsq — least-squares solution min‖A·x − b‖.

  • inv — matrix inverse (LU).

  • pinv — Moore–Penrose pseudo-inverse (SVD, any shape).

SIMD

SIMD here is pure compiler auto-vectorization (no intrinsics): the kernels are contiguous, unit-stride loops compiled at -O3 -march=native. These functions only report the build's capability:

  • simd_features — instruction sets this build targets (e.g. AVX2;FMA, NEON, scalar).

  • simd_lane_doubles — widest SIMD lane width in doubles.

On a build with no SIMD every routine returns identical results, just scalar / slower — SIMD is never a correctness dependency. The full model (and the compile-time-dispatch limitation) is documented in simd.hpp.

Performance vs NumPy

linalg goes head-to-head with NumPy, whose array ops dispatch to BLAS/LAPACK — hand-tuned, vectorized, often multi-threaded Fortran. The scripts/numpy_compare.py harness feeds the same fixed-seed, well-conditioned matrix to both, runs the same op many times with the result consumed, and checks the answers agree. Each function's Performance row above carries its own measurement; the full size-dependence:

What we compared against — read this before the numbers. NumPy's absolute speed, and where every crossover lands, depends far more on which BLAS it links than on which NumPy version it is. The generated stamp below records the resolved library rather than the version string, because "NumPy 1.26.4" does not identify a measurement and the library does.

On this machine that resolves to libblas.so.3 → the reference implementation, not OpenBLAS and not MKL. That matters for how much these wins are worth: reference BLAS is the unoptimized baseline, so a cheatah win over it is a win over untuned Fortran, not over the tuned kernels most NumPy installs actually use. A tuned BLAS would narrow the large-n rows and push the crossovers lower. The small-n wins are a different claim and survive either way — they come from cheatah having no per-call Python and dispatch overhead to pay, which no choice of BLAS changes.

The Eigen comparison is a separate measurement, in the native Google Benchmark harness (tests/benchmarks/eigen_compare_bench.cpp), where cheatah and Eigen 3.4 are both compiled C++ timed identically on one thread — an apples-to-apples per-core comparison.

Two harnesses, two tables — deliberately. These numbers used to share one table, with the cheatah column measured by numpy_compare.py (separate processes) sitting beside an Eigen column measured by Google Benchmark (compiled C++, one process), and a prose warning not to read across. A warning is a weaker fix than a structure: a reader who divides two adjacent columns gets a wrong answer no matter how the caption is worded. Each harness now publishes only what it measured, and neither table contains a column it did not produce.

Both are generated — see docs/performance.md for the methodology (striated, interleaved, medians with dispersion) and the reference machine.

vs NumPy

op

operand dimensions

cheatah

NumPy

winner

band

matmul

4

0.09

0.79

cheatah 8.3x

7.20-8.48

matmul

16

0.54

2.24

cheatah 4.1x

3.56-4.29

matmul

32

3.22

13.43

cheatah 4.2x

3.94-4.60

matmul

64

25.60

116.37

cheatah 4.5x

4.30-4.71

matmul

96

90.65

318.41

cheatah 3.5x

3.38-3.63

solve

4

0.22

2.45

cheatah 11.0x

10.03-11.49

solve

16

1.06

4.34

cheatah 4.1x

3.81-4.35

solve

32

3.69

10.35

cheatah 2.8x

2.55-2.85

solve

64

18.02

50.82

cheatah 2.8x

2.72-3.10

det

4

0.11

2.05

cheatah 22.6x

15.44-28.51

det

16

0.81

3.76

cheatah 4.7x

3.94-5.39

det

32

2.80

9.58

cheatah 3.4x

3.18-3.53

det

64

14.17

47.05

cheatah 3.4x

3.22-3.51

inv

4

0.26

2.18

cheatah 8.2x

7.66-9.08

inv

16

1.56

6.35

cheatah 4.1x

3.18-4.40

inv

32

6.97

25.27

cheatah 3.6x

3.51-3.65

inv

64

46.20

142.12

cheatah 3.1x

2.95-3.51

eigvalsh

2

0.22

2.01

cheatah 9.2x

8.95-9.74

eigvalsh

3

0.48

2.35

cheatah 4.9x

4.67-5.01

eigvalsh

4

0.62

2.66

cheatah 4.3x

3.88-4.37

eigvalsh

6

1.43

3.49

cheatah 2.4x

2.34-2.48

eigvalsh

8

1.91

4.20

cheatah 2.2x

2.10-2.23

eigvalsh

16

6.73

9.20

cheatah 1.4x

1.32-1.39

eigvalsh

32

26.01

25.98

cheatah 1.0x

0.95-1.04

eigvalsh

64

106.80

149.84

cheatah 1.4x

1.26-1.43

dot

64

0.02

0.62

cheatah 34.4x

28.33-46.46

dot

1024

0.09

1.08

cheatah 11.6x

7.28-17.05

dot

16384

2.59

8.16

cheatah 3.1x

2.77-3.54

ndarray.sqrt

64

0.19

0.88

cheatah 4.7x

3.07-4.97

ndarray.sqrt

1024

0.96

1.77

cheatah 1.8x

1.52-2.09

ndarray.sqrt

16384

14.58

14.66

NumPy 1.0x

0.95-1.04

ndarray.exp

64

0.21

1.05

cheatah 5.0x

3.83-5.62

ndarray.exp

1024

1.00

4.03

cheatah 4.0x

2.52-4.76

ndarray.exp

16384

13.52

48.89

cheatah 3.6x

3.40-3.92

ndarray.sin

64

0.22

1.11

cheatah 5.0x

4.08-6.13

ndarray.sin

1024

0.95

5.52

cheatah 5.9x

4.23-6.25

ndarray.sin

16384

13.69

89.32

cheatah 6.5x

5.68-6.84

ndarray.add

64

0.11

0.62

cheatah 5.5x

4.58-6.05

ndarray.add

16384

2.48

2.88

cheatah 1.2x

0.78-1.23

cholesky

8

0.31

2.63

cheatah 8.4x

7.20-9.79

cholesky

32

3.77

7.35

cheatah 2.0x

1.68-2.15

cholesky

64

16.81

25.99

cheatah 1.5x

1.35-1.78

qr

8

1.07

8.88

cheatah 8.3x

7.53-8.64

qr

32

14.79

28.49

cheatah 2.0x

1.72-2.16

qr

64

102.62

137.47

cheatah 1.3x

1.16-1.36

svdvals

8

3.28

6.15

cheatah 1.9x

1.70-1.93

svdvals

32

49.70

42.83

NumPy 1.2x

0.82-0.96

svdvals

64

229.46

208.75

NumPy 1.1x

0.88-0.97

svd (full)

8

3.93

10.53

cheatah 2.7x

2.51-2.85

svd (full)

32

70.11

115.62

cheatah 1.6x

1.50-1.65

svd (full)

64

433.35

739.34

cheatah 1.7x

1.50-1.76

pinv

8

4.63

18.86

cheatah 4.1x

3.37-4.19

pinv

32

100.36

136.64

cheatah 1.4x

1.31-1.47

pinv

64

633.48

800.84

cheatah 1.3x

1.23-1.31

cond

8

3.23

10.21

cheatah 3.2x

3.07-3.31

cond

32

49.56

45.71

NumPy 1.1x

0.89-0.97

cond

64

217.89

195.27

NumPy 1.1x

0.89-0.95

matrix_rank

8

2.98

11.98

cheatah 4.0x

3.86-4.16

matrix_rank

32

46.95

51.17

cheatah 1.1x

0.98-1.12

matrix_rank

64

216.33

194.85

NumPy 1.1x

0.88-0.93

slogdet

8

0.20

3.15

cheatah 15.2x

11.78-17.67

slogdet

32

2.93

10.48

cheatah 3.6x

3.45-3.71

slogdet

64

14.03

48.95

cheatah 3.5x

2.20-3.56

eigh

8

2.48

6.52

cheatah 2.6x

2.32-4.14

eigh

32

37.96

64.51

cheatah 1.7x

1.62-1.72

eigh

64

238.38

401.26

cheatah 1.7x

1.61-1.72

eigvals

8

7.88

14.11

cheatah 1.8x

1.73-1.89

matrix_power

8

0.91

2.49

cheatah 2.7x

2.60-2.79

matrix_power

32

12.27

28.00

cheatah 2.3x

1.96-2.38

matrix_power

64

97.93

214.16

cheatah 2.2x

2.12-2.40

trace

32

0.01

1.20

cheatah 168.1x

120.84-178.23

trace

256

0.08

1.47

cheatah 20.2x

17.90-22.16

norm(matrix)

32

0.09

1.55

cheatah 17.8x

10.01-24.71

norm(matrix)

256

7.38

32.35

cheatah 4.4x

3.92-4.52

outer

64

0.34

4.05

cheatah 11.9x

7.13-13.10

outer

256

9.78

48.77

cheatah 5.0x

4.15-5.25

kron

8

1.71

13.12

cheatah 7.8x

7.24-8.74

kron

16

20.25

72.57

cheatah 3.6x

3.20-4.17

kron

32

347.09

950.98

cheatah 2.7x

2.49-2.81

vs Eigen

case

cheatah

spread

vs

rival

spread

ratio

verdict

BM_dot/16384

1.76 µs

±140.45 ns IQR

eigen

2.54 µs

±29.23 ns IQR

1.44x

faster

BM_dot/64

10.18 ns

±0.71 ns IQR

eigen

6.69 ns

±0.17 ns IQR

0.66x

slower

BM_inv/32

6.76 µs

±1.35 µs IQR

eigen

11.21 µs

±438.60 ns IQR

1.66x

faster

BM_inv/64

38.55 µs

±8.55 µs IQR

eigen

67.44 µs

±2.07 µs IQR

1.75x

faster

BM_matmul/32

3.17 µs

±137.63 ns IQR

eigen

3.80 µs

±49.86 ns IQR

1.20x

faster

BM_matmul/96

87.96 µs

±879.72 ns IQR

eigen

94.93 µs

±3.32 µs IQR

1.08x

parity

BM_solve/32

3.56 µs

±118.70 ns IQR

eigen

4.17 µs

±151.63 ns IQR

1.17x

faster

BM_solve/64

16.47 µs

±372.73 ns IQR

eigen

19.97 µs

±426.11 ns IQR

1.21x

faster

Tally (a difference counts only above 1.15x AND 0.25 ns) — vs eigen: 6 faster / 1 parity / 1 slower.

  • Loss vs eigen: BM_dot/64 — cheatah 10.18 ns vs 6.69 ns (1.52x slower)

After a focused optimization round (hunting a few recurring mistakes across every routine — a heap allocation in a hot predicate, single-accumulator reductions, a column-stride QR walk, and a result buffer that was zero-filled and then thrown away):

  • vs NumPy/LAPACK, cheatah now wins across nearly the whole library — products, the LU family, the SVD, the symmetric eigensolver, outer, qr, kron, and large norm (the last four previously lost). The handful still behind (svdvals/cond/ matrix_rank ~1.1×) are SVD-threshold queries where LAPACK's bidiagonal solver edges it.

  • vs Eigen 3.4 on one core, cheatah matches or beats it on the bulkinv (≈1.7×), svd (≈1.6×), det/matmul/trace (≈1.3–1.4×), outer (≈1.2–1.3×, now that the result buffer is built uninitialized and moved in zero-copy), solve/eigvalsh/eigh/ norm (≈1.1–1.2×). Eigen still leads on its blocked BLAS-3 kernels — qr (1.3–1.8×), cholesky (1.2×), and the eigh eigenvector path (1.1×) — which we flag honestly rather than hide.

cheatah does all of this on one core, by design — single-threaded is a feature, not a shortfall (no hidden threads, no contention, nothing to tune). Both NumPy's and Eigen's remaining edges are the very large or blocked dense problems where threaded/BLAS-3 kernels spread the work — a different operating point. See the Performance guide for the full rationale.


Per-function docs (parameters, complexity, heap behavior) are in routines.hpp. Tested in ../tests/linalg_routines_test.cpp and ../tests/linalg_smoke_test.cpp; ASan + Valgrind clean via the QA gate (security/run-valgrind.sh).

Functions

fn matmul · 2 overloads
Array< T > matmul(const Array< T > &a, const Array< T > &b)source#
void matmul(Array< T > &out, const Array< T > &a, const Array< T > &b)source#

Matrix multiply — the allocating front.

Both operands are Array<T> (so host⊗device / element mixes fail to deduce and are compile errors); requires both to be 2-D with matching inner dimensions — or both 3-D for the BATCHED product [B,M,K] @ [B,K,N] → [B,M,N] (equal batch counts, strict: no broadcast batching). Allocates the result via Array<T>::uninitialized (no throwaway zero-fill) and fills it through the out-parameter kernel — the host SIMD path, or a device shader when Array is a device container (selected by concept at compile time).

Template parameters
T

the element type (double / std::complex<double>),

Array

the container template.

Parameters
a

m×k matrix, or a B×m×k batch of matrices.

b

k×p matrix, or a B×k×p batch.

Returns

m×p product (or the B×m×p batch), an Array<T> of the same container and element.

Complexity

O(n³) (× B for a batch).

Allocation

allocates only the result; operands read in place (a strided host view packs once).

Concurrency

deliberately single-threaded (the fastest-per-core contract); parallelize across independent products in the caller.

Compile-run testLinalgCompileRun.Matmul
Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn std::size_t vector_len(const A &a) source#

The flattened length of a vector-shaped operand — 1-D, or 2-D with a size-1 row/column (throws otherwise).

Reads only host-resident shape metadata, so it is valid for ANY located container, device arrays included; the shared validation step of every vector front below.

Template parameters
A

the (located) container type.

Parameters
a

the operand whose vector length is wanted.

Returns

the element count of the flattened vector.

Complexity

O(1).

Allocation

none.

fn dot · 2 overloads
T dot(const Array< T > &a, const Array< T > &b)source#
void dot(T &out, const Array< T > &a, const Array< T > &b)source#

Dot product: 1-D inner product (vectors flattened) — the bilinear Σ aᵢbᵢ.

ONE two-layer template over the element T and container Array serving real, complex, host and — via a device extension — device operands. Flattens each operand to a vector (1-D, or 2-D with a size-1 row/column) and throws if either is not vector-shaped or the lengths differ. Both operands are Array<T> (the deduction firewall).

Template parameters
T

the element type;

Array

the container template.

Parameters
a, b

same-length vectors.

Returns

Σ aᵢbᵢ as the scalar T.

Complexity

O(n).

Allocation

none for contiguous operands (read in place); a non-contiguous view packs once O(n).

Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn vdot · 2 overloads
T vdot(const Array< T > &a, const Array< T > &b)source#
void vdot(T &out, const Array< T > &a, const Array< T > &b)source#

Vector dot product.

For a REAL element this is the bilinear Σ aᵢbᵢ (identical to dot and inner); for a complex element it is the conjugate-linear Hermitian inner product ⟨a, b⟩ = Σ conj(aᵢ)·bᵢ (numpy's vdot, conjugating the first argument) — one two-layer template, the conjugation chosen at compile time by if constexpr. vdot(a, a) is the real ‖a‖².

Template parameters
T

the element type;

Array

the container template.

Parameters
a, b

same-length vectors.

Returns

Σ aᵢbᵢ (real) or Σ conj(aᵢ)·bᵢ (complex), as the scalar T.

Complexity

O(n).

Allocation

none for contiguous operands; a non-contiguous view packs once O(n).

Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn inner · 2 overloads
T inner(const Array< T > &a, const Array< T > &b)source#
void inner(T &out, const Array< T > &a, const Array< T > &b)source#

Inner product of two vectors — the bilinear Σ aᵢbᵢ (numpy's inner; same as dot for flattened vectors).

One two-layer template over the element and container.

Template parameters
T

the element type;

Array

the container template.

Parameters
a, b

same-length vectors.

Returns

Σ aᵢbᵢ as the scalar T.

Complexity

O(n).

Allocation

none for contiguous operands; a non-contiguous view packs once O(n).

Compile-run testLinalgCompileRun.Inner
System testStdlibE2E.Linalg
Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn trace · 2 overloads
T trace(const Array< T > &a)source#
void trace(T &out, const Array< T > &a)source#

Trace: the sum of the matrix diagonal, as the scalar T.

Requires a 2-D matrix (throws otherwise); rectangular matrices sum min(r, c) diagonal entries.

Template parameters
T

the element type;

Array

the container template.

Parameters
a

a 2-D matrix.

Returns

Σ aᵢᵢ as the scalar T.

Complexity

O(min(r, c)).

Allocation

none (strided diagonal read straight from the buffer).

Compile-run testLinalgCompileRun.Trace
Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn outer · 2 overloads
Array< T > outer(const Array< T > &a, const Array< T > &b)source#
void outer(Array< T > &out, const Array< T > &a, const Array< T > &b)source#

Outer product of two vectors.

Flattens both operands to vectors and forms the full rank-1 matrix; any pair of vector lengths is accepted (no matching constraint). Allocates the result via Array<T>::uninitialized and fills it through the out-parameter kernel — the host SIMD path, or a device shader when Array is a device container (selected by concept).

Parameters
a

length-n vector.

b

length-m vector.

Returns

n×m matrix aᵢbⱼ.

Complexity

O(n·m).

Allocation

allocates only the n×m result; operands read in place when contiguous.

Compile-run testLinalgCompileRun.Outer
System testStdlibE2E.Linalg
Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn conj_transpose · 2 overloads
Array< T > conj_transpose(const Array< T > &a)source#
void conj_transpose(Array< T > &out, const Array< T > &a)source#

Conjugate transpose (Hermitian adjoint) Aᴴ: transpose, then conjugate every entry (a plain transpose for a real element — the conjugation is compiled out).

A matrix is Hermitian iff conj_transpose(A) == A.

Parameters
a

a 2-D matrix.

Returns

the c×r adjoint of an r×c input; throws on non-2-D input.

Complexity

O(r·c).

Allocation

allocates only the c×r result; a non-contiguous operand is packed once into scratch.

Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn kron · 2 overloads
Array< T > kron(const Array< T > &a, const Array< T > &b)source#
void kron(Array< T > &out, const Array< T > &a, const Array< T > &b)source#

Kronecker product.

Requires both operands to be 2-D (throws otherwise) and replaces each entry of a with that scalar times the whole of b, giving the (m·p)×(k·q) block matrix; no dimension matching is needed.

Parameters
a

m×k matrix.

b

p×q matrix.

Returns

(m·p)×(k·q) block product.

Complexity

O(n⁴) in the output area.

Allocation

allocates only the (m·p)×(k·q) result; a non-contiguous operand is packed once into scratch.

Compile-run testLinalgCompileRun.Kron
System testStdlibE2E.Linalg

Requires both operands to be 2-D (throws otherwise) and replaces each entry of a with that scalar times the whole of b, giving the (m·p)×(k·q) block matrix; no dimension matching is needed.

Parameters
a

m×k matrix.

b

p×q matrix.

Returns

(m·p)×(k·q) block product.

Complexity

O(n⁴) in the output area.

Allocation

allocates a new NDArray result; a non-contiguous operand is packed once into scratch.

Compile-run testLinalgCompileRun.Kron
System testStdlibE2E.Linalg
Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn dot< double, ndarray::basic_ndarray > · 2 overloads
template void dot< double, ndarray::basic_ndarray >(double &, const NDArray &, const NDArray &)source#
template double dot< double, ndarray::basic_ndarray >(const NDArray &, const NDArray &)source#
fn dot< Cplx, ndarray::basic_ndarray > · 2 overloads
template void dot< Cplx, ndarray::basic_ndarray >(Cplx &, const CNDArray &, const CNDArray &)source#
template Cplx dot< Cplx, ndarray::basic_ndarray >(const CNDArray &, const CNDArray &)source#
fn vdot< double, ndarray::basic_ndarray > · 2 overloads
template void vdot< double, ndarray::basic_ndarray >(double &, const NDArray &, const NDArray &)source#
template double vdot< double, ndarray::basic_ndarray >(const NDArray &, const NDArray &)source#
fn vdot< Cplx, ndarray::basic_ndarray > · 2 overloads
template void vdot< Cplx, ndarray::basic_ndarray >(Cplx &, const CNDArray &, const CNDArray &)source#
template Cplx vdot< Cplx, ndarray::basic_ndarray >(const CNDArray &, const CNDArray &)source#
fn inner< double, ndarray::basic_ndarray > · 2 overloads
template void inner< double, ndarray::basic_ndarray >(double &, const NDArray &, const NDArray &)source#
template double inner< double, ndarray::basic_ndarray >(const NDArray &, const NDArray &)source#
fn outer< double, ndarray::basic_ndarray > · 2 overloads
template void outer< double, ndarray::basic_ndarray >(NDArray &, const NDArray &, const NDArray &)source#
template NDArray outer< double, ndarray::basic_ndarray >(const NDArray &, const NDArray &)source#
fn matmul< double, ndarray::basic_ndarray > · 2 overloads
template void matmul< double, ndarray::basic_ndarray >(NDArray &, const NDArray &, const NDArray &)source#
template NDArray matmul< double, ndarray::basic_ndarray >(const NDArray &, const NDArray &)source#
fn matmul< Cplx, ndarray::basic_ndarray > · 2 overloads
template void matmul< Cplx, ndarray::basic_ndarray >(CNDArray &, const CNDArray &, const CNDArray &)source#
template CNDArray matmul< Cplx, ndarray::basic_ndarray >(const CNDArray &, const CNDArray &)source#
fn conj_transpose< Cplx, ndarray::basic_ndarray > · 2 overloads
template void conj_transpose< Cplx, ndarray::basic_ndarray >(CNDArray &, const CNDArray &)source#
template CNDArray conj_transpose< Cplx, ndarray::basic_ndarray >(const CNDArray &)source#
fn conj_transpose< double, ndarray::basic_ndarray > · 2 overloads
template void conj_transpose< double, ndarray::basic_ndarray >(NDArray &, const NDArray &)source#
template NDArray conj_transpose< double, ndarray::basic_ndarray >(const NDArray &)source#
fn matrix_power · 2 overloads
void matrix_power(Array< T > &out, const Array< T > &a, long long p)source#
Array< T > matrix_power(const Array< T > &a, long long n)source#

Integer matrix power Aⁿ (negative n via inv).

Requires a square matrix (throws otherwise); n == 0 returns the identity, and negative n first inverts a via inv (so it inherits inv's singular-matrix behavior) before raising to |n|.

Parameters
a

square matrix.

n

exponent.

Returns

Aⁿ.

Complexity

O(n³·log|n|) by binary exponentiation.

Allocation

allocates a new NDArray result; the binary-exponentiation matmul steps allocate their own intermediates.

System testStdlibE2E.Linalg
Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn kron< double, ndarray::basic_ndarray > · 2 overloads
template void kron< double, ndarray::basic_ndarray >(NDArray &, const NDArray &, const NDArray &)source#
template NDArray kron< double, ndarray::basic_ndarray >(const NDArray &, const NDArray &)source#
fn trace< double, ndarray::basic_ndarray > · 2 overloads
template void trace< double, ndarray::basic_ndarray >(double &, const NDArray &)source#
template double trace< double, ndarray::basic_ndarray >(const NDArray &)source#
fn norm · 2 overloads
void norm(T &out, const Array< T > &a)source#
T norm(const Array< T > &a)source#

Norm: L2 for vectors, Frobenius for matrices.

Dispatches on rank: 1-D (or lower) inputs get the Euclidean L2 norm, 2-D inputs the Frobenius norm; either way it is the square root of the sum of squared entries. Two-layer over the element and container like every routine (the scalar-out kernel norm(out, a) is the host/device seam; host double is the shipped instantiation).

Parameters
a

vector or matrix.

Returns

√Σ xᵢ².

Complexity

O(n) for vectors / O(n²) for matrices.

Allocation

none for a contiguous operand (summed in place); a non-contiguous view packs once. Returns a double.

Compile-run testLinalgCompileRun.Norm
Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn norm< double, ndarray::basic_ndarray > · 2 overloads
template void norm< double, ndarray::basic_ndarray >(double &, const NDArray &)source#
template double norm< double, ndarray::basic_ndarray >(const NDArray &)source#
fn solve · 2 overloads
void solve(Array< T > &out, const Array< T > &a, const Array< T > &b)source#
Array< T > solve(const Array< T > &a, const Array< T > &b)source#

Solve A·x = b via LU with partial pivoting.

Factorizes a once then does forward/back substitution against b; requires a square and b a vector of matching length (throws otherwise). A singular a does not throw but yields a garbage/overflowing solution (pivots are nudged off zero rather than detected).

Parameters
a

square coefficient matrix.

b

right-hand-side vector.

Returns

solution x.

Complexity

O(n³).

Allocation

allocates a new NDArray result; the LU factorization allocates its own O(n²) scratch.

Compile-run testLinalgCompileRun.Solve
Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn det · 2 overloads
void det(T &out, const Array< T > &a)source#
T det(const Array< T > &a)source#

Determinant via LU with partial pivoting.

Computes the product of the LU pivots times the permutation sign; requires a square matrix (throws otherwise). A singular matrix yields a determinant of (or extremely near) zero rather than an error.

Parameters
a

square matrix.

Returns

det(A).

Complexity

O(n³).

Allocation

allocates scratch O(n²) for the factorization; returns a double.

Compile-run testLinalgCompileRun.Det
Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn slogdet · 2 overloads
void slogdet(SLogDet &out, const Array< T > &a)source#
SLogDet slogdet(const Array< T > &a)source#

Sign and log|det| via LU (overflow-safe determinant).

Sums the logs of the absolute LU pivots (avoiding the over/underflow of a raw product) and tracks the sign from the pivot signs and permutation parity; requires a square matrix (throws otherwise). A singular matrix gives a hugely negative logabsdet rather than −infinity, since a zero pivot is nudged to a tiny value during factorization.

Parameters
a

square matrix.

Returns

SLogDet.

Complexity

O(n³).

Allocation

allocates scratch O(n²) for the factorization (the struct members are plain doubles).

Compile-run testLinalgCompileRun.Slogdet
System testStdlibE2E.Linalg
Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn inv · 2 overloads
void inv(Array< T > &out, const Array< T > &a)source#
Array< T > inv(const Array< T > &a)source#

Matrix inverse via LU with partial pivoting.

Factorizes a once and back-solves against each identity column; requires a square matrix (throws otherwise). A singular a does not throw but produces garbage/overflowing entries since zero pivots are nudged rather than detected.

Parameters
a

square matrix.

Returns

A⁻¹.

Complexity

O(n³).

Allocation

allocates a new NDArray result; the LU factorization and the whole-identity back-solve allocate their own O(n²) scratch.

Compile-run testLinalgCompileRun.Inv
System testStdlibE2E.Linalg
Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn solve< double, ndarray::basic_ndarray > · 2 overloads
template void solve< double, ndarray::basic_ndarray >(NDArray &, const NDArray &, const NDArray &)source#
template NDArray solve< double, ndarray::basic_ndarray >(const NDArray &, const NDArray &)source#
fn det< double, ndarray::basic_ndarray > · 2 overloads
template void det< double, ndarray::basic_ndarray >(double &, const NDArray &)source#
template double det< double, ndarray::basic_ndarray >(const NDArray &)source#
fn slogdet< double, ndarray::basic_ndarray > · 2 overloads
template void slogdet< double, ndarray::basic_ndarray >(SLogDet &, const NDArray &)source#
template SLogDet slogdet< double, ndarray::basic_ndarray >(const NDArray &)source#
fn inv< double, ndarray::basic_ndarray > · 2 overloads
template void inv< double, ndarray::basic_ndarray >(NDArray &, const NDArray &)source#
template NDArray inv< double, ndarray::basic_ndarray >(const NDArray &)source#
fn lstsq · 2 overloads
void lstsq(Array< T > &out, const Array< T > &a, const Array< T > &b)source#
Array< T > lstsq(const Array< T > &a, const Array< T > &b)source#

Least-squares solution min‖A·x − b‖ (computed as pinv (a)·b).

Forms the Moore–Penrose pseudo-inverse via SVD and multiplies it by b, so it handles over- and under-determined systems and returns the minimum-norm solution for rank-deficient a; b must be conformable for the matmul step.

Parameters
a

m×n matrix.

b

right-hand side.

Returns

minimizing x.

Complexity

iterative O(n³) via SVD.

Allocation

allocates a new NDArray result; plus the intermediate n×m pseudo-inverse and its SVD scratch.

Compile-run testLinalgCompileRun.Lstsq
System testStdlibE2E.Linalg
Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn cholesky · 2 overloads
void cholesky(Array< T > &out, const Array< T > &a)source#
Array< T > cholesky(const Array< T > &a)source#

Cholesky factor of a symmetric positive-definite matrix (throws otherwise).

Requires a square matrix and computes L column by column reading only the lower triangle of a; if any pivot (the diagonal under the square root) is non-positive it throws "matrix is not positive-definite", which also catches non-SPD or non-symmetric input.

Parameters
a

square SPD matrix.

Returns

lower-triangular L with A = L·Lᵀ.

Complexity

O(n³).

Allocation

allocates a new NDArray result; the factor is computed into O(n²) private scratch, then copied in.

System testStdlibE2E.Linalg
Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn qr · 2 overloads
void qr(Array< T > &q, Array< T > &r, const Array< T > &a)source#
QR< Array< T > > qr(const Array< T > &a)source#

Reduced QR via Householder reflections (requires rows ≥ cols).

Applies successive Householder reflectors to triangularize a, returning the thin/reduced factors; throws "qr requires rows >= cols" for wide matrices. Rank-deficient columns (zero pivot norm) are skipped, leaving the corresponding R entries zero.

Parameters
a

m×n matrix.

Returns

QR with q (m×n, orthonormal cols) and r (n×n, upper-triangular).

Complexity

O(n³).

Allocation

allocates both members; the factorization works in O(m²) private scratch (a full m×m Q workspace), then copies the reduced factors in.

Compile-run testLinalgCompileRun.Qr
System testStdlibE2E.Linalg
Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn svd · 2 overloads
void svd(Array< T > &u, Array< T > &sv, Array< T > &vhh, const Array< T > &a)source#
SVD< Array< T > > svd(const Array< T > &a)source#

Singular value decomposition (Golub–Reinsch; requires rows ≥ cols).

Reduces a to upper-bidiagonal form by Householder reflections, then diagonalizes it with implicit-shift QR (accumulating U and V), and sorts the singular values descending — the world-standard dense SVD (what LAPACK's dgesvd reduces to). Throws "svd requires rows >= cols" for wide matrices (transpose first); singular values come out non-negative.

Parameters
a

m×n matrix.

Returns

SVD with u (m×n), s (descending singular values), vh (n×n = Vᵀ).

Complexity

iterative O(n³).

Allocation

allocates all members; the Golub–Reinsch reduction allocates its own O(m·n) workspace.

Compile-run testLinalgCompileRun.Svd
System testStdlibE2E.Linalg
Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn svdvals · 2 overloads
void svdvals(Array< T > &out, const Array< T > &a)source#
Array< T > svdvals(const Array< T > &a)source#

Singular values only (≈ numpy.linalg.svd(a, compute_uv=False) / svdvals).

Runs the same Golub–Reinsch reduction as svd but takes the values-only fast path — it never accumulates U or V, and skips the (dominant) U/V Givens rotations in the QR sweep — so it is several times faster than the full decomposition. Accepts any shape (singular values of a and aᵀ coincide).

Parameters
a

m×n matrix.

Returns

length-min(m,n) vector of singular values, descending.

Complexity

iterative O(n³), but a large constant factor below svd.

Allocation

allocates a new NDArray result; the reduction still allocates its O(m·n) workspace (the values-only path skips the U/V accumulation work and result copies, not the working buffers).

Compile-run testLinalgCompileRun.Svdvals
System testStdlibE2E.Linalg
fn pinv · 2 overloads
void pinv(Array< T > &out, const Array< T > &a)source#
Array< T > pinv(const Array< T > &a)source#

Moore–Penrose pseudo-inverse via SVD (any shape).

Computes V·diag(1/σ)·Uᵀ from a Golub–Reinsch SVD, transposing wide matrices internally so any shape works; singular values at or below a size-scaled tolerance are dropped (treated as zero) so it stays well-defined for rank-deficient input.

Parameters
a

m×n matrix.

Returns

n×m pseudo-inverse.

Complexity

iterative O(n³) via SVD.

Allocation

allocates a new NDArray result; the SVD and the assembly allocate their own O(m·n) scratch.

Compile-run testLinalgCompileRun.Pinv
System testStdlibE2E.Linalg
Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn cond · 2 overloads
void cond(T &out, const Array< T > &a)source#
T cond(const Array< T > &a)source#

2-norm condition number σ_max/σ_min (∞ if singular).

Takes the ratio of largest to smallest singular value from a Golub–Reinsch SVD (transposing internally for wide matrices); returns +infinity when the smallest singular value is exactly zero (singular/rank-deficient).

Parameters
a

matrix.

Returns

condition number.

Complexity

iterative O(n³) via SVD.

Allocation

allocates scratch O(n²) for the factorization; returns a double.

Compile-run testLinalgCompileRun.Cond
System testStdlibE2E.Linalg
Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn matrix_rank · 2 overloads
void matrix_rank(long long &out, const Array< T > &a)source#
long long matrix_rank(const Array< T > &a)source#

Numerical rank from SVD singular-value thresholding.

Counts singular values above a tolerance scaled by the largest singular value and the matrix size (the standard numpy-style threshold); accepts any shape, transposing wide matrices internally.

Parameters
a

matrix.

Returns

rank.

Complexity

iterative O(n³) via SVD.

Allocation

allocates scratch O(n²) for the factorization.

System testStdlibE2E.Linalg
Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn eigh · 2 overloads
void eigh(Array< ndarray::real_base_t< T > > &values, Array< T > &vectors, const Array< T > &a)source#
eigh_result_t< T, Array > eigh(const Array< T > &a)source#

Eigen-decomposition of a symmetric matrix (Householder tridiagonalization + QL).

Reduces a to tridiagonal form by Householder reflections, then diagonalizes it with implicit-shift QL, returning real eigenvalues sorted descending with matching eigenvector columns; it reads the full matrix and assumes symmetry rather than checking it, so asymmetric input yields meaningless results. Throws on a non-square matrix (or if the QL iteration fails to converge).

Parameters
a

square symmetric matrix.

Returns

Eig with descending values and matching eigenvectors.

Complexity

iterative O(n³).

Allocation

allocates both members; the solver allocates its own O(n²) scratch (a complex Hermitian input first embeds into a 2n×2n real matrix).

Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn eigvalsh · 2 overloads
void eigvalsh(Array< ndarray::real_base_t< T > > &out, const Array< T > &a)source#
Array< ndarray::real_base_t< T > > eigvalsh(const Array< T > &a)source#

Eigenvalues of a symmetric matrix, descending (tridiagonal QL).

Same tridiagonalization + QL as eigh but skips the eigenvector accumulation entirely (the bulk of the work), so it is roughly twice as fast as eigh; assumes (does not verify) symmetry and throws on a non-square matrix. ONE two-layer template collapsing the former real and complex (Hermitian) overloads: a real element takes the symmetric path, a complex element the Hermitian path (if constexpr). The spectrum is always REAL, returned as Array<real_base_t<T>>.

Template parameters
T

the element type (double or std::complex<double>);

Array

the container.

Parameters
a

square symmetric (real) / Hermitian (complex) matrix.

Returns

length-n vector of real eigenvalues.

Complexity

iterative O(n³).

Allocation

allocates a new result; the solver allocates its own O(n²) scratch (a complex Hermitian input first embeds into a 2n×2n real matrix).

Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn eigvalsh< double, ndarray::basic_ndarray > · 2 overloads
template void eigvalsh< double, ndarray::basic_ndarray >(NDArray &, const NDArray &)source#
template NDArray eigvalsh< double, ndarray::basic_ndarray >(const NDArray &)source#
fn eigvalsh< Cplx, ndarray::basic_ndarray > · 2 overloads
template void eigvalsh< Cplx, ndarray::basic_ndarray >(NDArray &, const CNDArray &)source#
template NDArray eigvalsh< Cplx, ndarray::basic_ndarray >(const CNDArray &)source#
fn eigh< double, ndarray::basic_ndarray > · 2 overloads
template void eigh< double, ndarray::basic_ndarray >(NDArray &, NDArray &, const NDArray &)source#
template Eig< NDArray > eigh< double, ndarray::basic_ndarray >(const NDArray &)source#
fn eigh< Cplx, ndarray::basic_ndarray > · 2 overloads
template void eigh< Cplx, ndarray::basic_ndarray >(NDArray &, CNDArray &, const CNDArray &)source#
template EighC< NDArray, CNDArray > eigh< Cplx, ndarray::basic_ndarray >(const CNDArray &)source#
fn eig · 2 overloads
void eig(Array< ndarray::complex_of_t< T > > &values, Array< ndarray::complex_of_t< T > > &vectors, const Array< T > &a)source#
EigC< Array< ndarray::complex_of_t< T > > > eig(const Array< T > &a)source#

Eigen-decomposition of a general square matrix (complex spectrum and eigenvectors).

For a symmetric a it delegates to eigh (promoted to complex with zero imaginary part); otherwise it uses Hessenberg reduction + shifted QR for the eigenvalues, then inverse iteration for each eigenvector. A real matrix with a complex conjugate pair (e.g. a rotation) yields those complex eigenvalues and eigenvectors rather than throwing. Throws on a non-square matrix or if the QR iteration fails to converge.

Parameters
a

square matrix.

Returns

EigC with complex values and matching complex eigenvector columns.

Complexity

iterative O(n³) via Hessenberg + shifted QR for the eigenvalues; the general (non-symmetric) eigenvectors add O(n⁴) — one inverse iteration, each with its own O(n³) complex LU factorization, per eigenvalue (a symmetric a stays O(n³) via eigh, which accumulates the vectors in the QL sweep).

Allocation

allocates both members; plus O(n²) factorization scratch (on the non-symmetric path, a fresh complex n×n LU per eigenvalue).

Compile-run testLinalgCompileRun.Eig
System testStdlibE2E.Linalg
Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn eigvals · 2 overloads
void eigvals(Array< ndarray::complex_of_t< T > > &out, const Array< T > &a)source#
Array< ndarray::complex_of_t< T > > eigvals(const Array< T > &a)source#

Eigenvalues of a general square matrix (complex), descending.

Routes symmetric input through tridiagonal QL and everything else through Hessenberg + shifted QR, then sorts the result descending (by real part, then by imaginary part). A real matrix with a complex conjugate pair yields those complex eigenvalues rather than throwing. Throws on a non-square matrix or non-convergence of the QR iteration.

Parameters
a

square matrix.

Returns

length-n complex vector of eigenvalues.

Complexity

iterative O(n³).

Allocation

allocates a new CNDArray result; the iteration allocates its own O(n²) scratch.

Compile-run testLinalgCompileRun.Eigvals
System testStdlibE2E.Linalg
Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn matrix_power< double, ndarray::basic_ndarray > · 2 overloads
template void matrix_power< double, ndarray::basic_ndarray >(NDArray &, const NDArray &, long long)source#
template NDArray matrix_power< double, ndarray::basic_ndarray >(const NDArray &, long long)source#
fn lstsq< double, ndarray::basic_ndarray > · 2 overloads
template void lstsq< double, ndarray::basic_ndarray >(NDArray &, const NDArray &, const NDArray &)source#
template NDArray lstsq< double, ndarray::basic_ndarray >(const NDArray &, const NDArray &)source#
fn cholesky< double, ndarray::basic_ndarray > · 2 overloads
template void cholesky< double, ndarray::basic_ndarray >(NDArray &, const NDArray &)source#
template NDArray cholesky< double, ndarray::basic_ndarray >(const NDArray &)source#
fn svdvals< double, ndarray::basic_ndarray > · 2 overloads
template void svdvals< double, ndarray::basic_ndarray >(NDArray &, const NDArray &)source#
template NDArray svdvals< double, ndarray::basic_ndarray >(const NDArray &)source#
fn pinv< double, ndarray::basic_ndarray > · 2 overloads
template void pinv< double, ndarray::basic_ndarray >(NDArray &, const NDArray &)source#
template NDArray pinv< double, ndarray::basic_ndarray >(const NDArray &)source#
fn cond< double, ndarray::basic_ndarray > · 2 overloads
template void cond< double, ndarray::basic_ndarray >(double &, const NDArray &)source#
template double cond< double, ndarray::basic_ndarray >(const NDArray &)source#
fn matrix_rank< double, ndarray::basic_ndarray > · 2 overloads
template void matrix_rank< double, ndarray::basic_ndarray >(long long &, const NDArray &)source#
template long long matrix_rank< double, ndarray::basic_ndarray >(const NDArray &)source#
fn qr< double, ndarray::basic_ndarray > · 2 overloads
template void qr< double, ndarray::basic_ndarray >(NDArray &, NDArray &, const NDArray &)source#
template QR< NDArray > qr< double, ndarray::basic_ndarray >(const NDArray &)source#
fn svd< double, ndarray::basic_ndarray > · 2 overloads
template void svd< double, ndarray::basic_ndarray >(NDArray &, NDArray &, NDArray &, const NDArray &)source#
template SVD< NDArray > svd< double, ndarray::basic_ndarray >(const NDArray &)source#
fn eig< double, ndarray::basic_ndarray > · 2 overloads
template void eig< double, ndarray::basic_ndarray >(CNDArray &, CNDArray &, const NDArray &)source#
template EigC< CNDArray > eig< double, ndarray::basic_ndarray >(const NDArray &)source#
fn eigvals< double, ndarray::basic_ndarray > · 2 overloads
template void eigvals< double, ndarray::basic_ndarray >(CNDArray &, const NDArray &)source#
template CNDArray eigvals< double, ndarray::basic_ndarray >(const NDArray &)source#
fn std::string simd_features() source#

Instruction sets this build targets, e.g.

"AVX2;FMA" (x86-64), "NEON" (ARM), or "scalar".

Returns

;-separated feature list.

Note

O(1); reflects compile-time target flags (e.g. -march=native), not a runtime CPUID probe. Allocates the returned std::string.

Complexity

O(1).

Allocation

the returned feature string.

Performancequeries CPU SIMD support — not a hot path
fn int simd_lane_doubles() noexcept source#

Width, in doubles, of the widest SIMD lane this build targets (1 = scalar, 2 = SSE2/NEON, 4 = AVX, 8 = AVX-512).

Returns

lane width.

Complexity

O(1).

Allocation

none. Useful for sizing blocked kernels.

Performancequeries CPU SIMD width — not a hot path

Types

enum Conj source#

Whether a reduction conjugates its first operand.

dot/inner are bilinear (Conj::None, Σ aᵢbᵢ); vdot is the conjugate-linear Hermitian inner product (Conj::Conjugate, Σ conj(aᵢ)·bᵢ). For a REAL element the conjugate is the identity, so both fold to the same code via if constexpr (is_complex_v<T> && mode == Conj::Conjugate).

type typename std::remove_cvref_t< A >::value_type element_t source#

element_t: the scalar an array-like stores — its nested value_type, with any reference/cv-qualification on A stripped first so const NDArray& and NDArray yield the same element type.

Undefined for a type with no value_type (which simply makes the concepts below unsatisfied for it, never a hard error).

type typename location_of< std::remove_cvref_t< A > >::type location_t source#

location_t: shorthand for the location tag of A (its location_of ::type), with any reference/cv-qualification stripped from A first.

type std::complex< double > Cplx source#

A complex scalar (std::complex<double>) — the element type of CNDArray and the return type of the complex inner products dot / vdot.

A complex array (basic_ndarray<std::complex<double>>) — what the general eigensolvers return, since a real matrix can have complex eigenvalues.

Prints element-wise as a+bj via cheatah::ndarray::to_string.

type std::conditional_t< ndarray::is_complex_v< T >, EighC< Array< ndarray::real_base_t< T > >, Array< T > >, Eig< Array< T > > > eigh_result_t source#

The result type of the unified eigh: for a real element, Eig<Array<T>> (real values + vectors); for a complex element, EighC<Array<real>, Array<T>> (real values, complex vectors).

eigh's return type differs per element, so it is expressed here (not auto) so the header declaration knows it without seeing the definition.