Vectors & Linear Algebra
linaldb gives you two ways to do math on tensors outside of SELECT: functional
keywords and infix operators. (For vector functions used inside SQL, such as
COSINE_SIM and AVG_VEC, see Querying.)
Functional keywords
Section titled “Functional keywords”ADD a b/SUBTRACT a b/MULTIPLY a b/DIVIDE a b: element-wise.MATMUL a b: standard matrix multiplication.TRANSPOSE a: swap dimensions of a matrix/tensor.RESHAPE a TO [dims]: change shape without copying data.FLATTEN a: convert a multidimensional tensor to a 1D vector.NORMALIZE a: scale a vector to unit length (L2 norm).SCALE a BY n: multiply all elements by scalarn.STACK t1 t2 ...: combine tensors along axis 0.SUM a/MEAN a/STDEV a/VARIANCE a/MEDIAN a: reduce to a true scalar (rank-0 tensor, shape[]), so it correctly broadcasts against a longer vector in a laterADD/SUBTRACT/MULTIPLY/DIVIDE(e.g.v - SUM v) instead of being treated as a mismatched same-rank vector.VARIANCEis the population variance: literallySTDEV asquared.QUANTILE a AT p: thep-th quantile ofa’s elements (pin[0.0, 1.0];p=0.5is the median, matchingMEDIAN a). True scalar result.COVARIANCE a WITH b: population covariance between two same-shape tensors, treating each as a flat sample. True scalar result.COVARIANCE MATRIX a: feature covariance matrix ofa(rows = samples, columns = features): aMatrix(k, k)for aMatrix(n, k)input. Uses the standardn - 1(Bessel-corrected) normalization: a different statistic fromCOVARIANCE a WITH b’snnormalization, not a bug.
VECTOR v = [2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0]LET var = VARIANCE v -- 4.0LET med = MEDIAN v -- 4.5LET p90 = QUANTILE v AT 0.9
VECTOR w = [1.0, 3.0, 5.0, 3.0, 1.0, -1.0, -3.0, -5.0]LET cov = COVARIANCE v WITH w -- -8.25 (anti-correlated)
MATRIX samples = [[1.0, 2.0], [3.0, 4.0], [5.0, 8.0]] -- rows = samples, cols = featuresLET cm = COVARIANCE MATRIX samples -- Matrix(2, 2)Lazy evaluation
Section titled “Lazy evaluation”Prefix LET with LAZY (either word order) to defer computation: the expression is
stored as a computation graph and materialized only when SHOW is called:
LAZY LET trend = STDEV sensor_3d -- deferredLET LAZY trend = STDEV sensor_3d -- identical aliasSHOW trend -- triggers materializationInfix operators
Section titled “Infix operators”LET result = (v_a + v_b) / 2.0LET scaled = m_a * 10Advanced operators
Section titled “Advanced operators”CORRELATE a WITH b: Pearson correlation between two vectors.SIMILARITY a WITH b: cosine similarity,[-1.0, 1.0].DISTANCE a TO b: Euclidean distance between points.
Frequency-domain operators
Section titled “Frequency-domain operators”FFT a [WINDOW HANN|HAMMING]: real-to-complex forward FFT.ais a rank-1Vector(N); result is aMatrix(2, N/2+1)(row 0 real, row 1 imaginary; only non-negative frequencies, the standard real-input FFT optimization). The optionalWINDOWclause applies a Hann or Hamming window toabefore transforming, to reduce spectral leakage. Omitting it is the original unwindowed (rectangular) behavior.HANN/HAMMINGare plain identifiers, not reserved keywords.IFFT a: complex-to-real inverse FFT from aMatrix(2, M)spectrum. Assumes the original signal length was even (reconstructs length2*(M-1)). Keep the original vector around if you need an exact odd-length round trip.MAGNITUDE a: power/magnitude spectrum from aMatrix(2, M)spectrum:Vector(M),sqrt(re² + im²)per bin.PSD a WINDOW n [HANN|HAMMING]: power spectral density via averaged periodograms. Splitsainto non-overlappingn-sample chunks, averages each chunk’s power spectrum. The optional trailingHANN/HAMMINGapplies that window to each chunk before its FFT (omitting it is the original unwindowed behavior). Still simplified vs. textbook Welch’s method (no 50% chunk overlap, even with a window applied): good for noise-floor estimation, not research-grade PSD.WHITEN a WITH b: flattensa’s noise spectrum against a PSD estimateb.bmust have exactlya.len()/2+1entries. The standard first step before matched filtering.BANDPASS a FROM low_hz TO high_hz WITH RATE sample_rate: brick-wall bandpass filter (zeros FFT bins outside the range, inverse-transforms back). Simplified vs. a real filter design (IIR/FIR): a hard cutoff introduces ringing at sharp edges.MATCHED_FILTER a WITH b: FFT-based cross-correlation, the standard detection statistic: the peak (by absolute value) marks the best-matching lag betweena(data) andb(template). The peak lag is relative tob’s own reference point, not an absolute location ina. Computes circular correlation (wraps at buffer edges).
VECTOR signal = [0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0]LET spectrum = FFT signalLET recovered = IFFT spectrumLET mag = MAGNITUDE spectrumLET noise_floor = PSD signal WINDOW 8LET whitened = WHITEN signal WITH noise_floorLET filtered = BANDPASS signal FROM 35.0 TO 350.0 WITH RATE 4096.0LET correlation = MATCHED_FILTER whitened WITH templateA complex spectrum (FFT output, and EIGENVALUES_GENERAL below) is an ordinary
Matrix(2, N) by convention (row 0 real, row 1 imaginary) rather than a collection of
scalar Complex values, so SHOW, persistence, TRANSPOSE, and row indexing all
already work on it unmodified. The scalar Complex type (see Data &
Resources) is a separate, deliberately
scalar-only concept: a genuine Tensor<Complex> is out of scope.
Classical linear algebra
Section titled “Classical linear algebra”Built on nalgebra (pure Rust). Every fallible operator here errors loudly on a
singular, non-square, or non-symmetric input: never a silent NaN.
Single-output (bind with a plain LET name = ...):
| Operator | Description |
|---|---|
TRACE a |
Sum of the diagonal. a must be a square Matrix. True scalar result. |
DETERMINANT a |
a must be square. 0.0 for a singular matrix is a legitimate result. |
RANK a |
Numerical rank via SVD. True scalar, integer-valued. |
INVERSE a |
a must be square. Errors if singular. |
SOLVE a b |
Solves a x = b via LU with partial pivoting. Errors if a is singular. |
LSTSQ a b |
Least-squares (minimum-norm) solve of a x = b for any shape of a (over-determined, under-determined, or square-but-singular) via the SVD-based Moore-Penrose pseudo-inverse. Never errors on non-square/singular input, unlike SOLVE: a deliberately distinct keyword, not one polymorphic operator. |
EIGENVALUES a |
Real eigenvalues of a symmetric matrix only. Errors on a non-symmetric input rather than silently guessing. |
EIGENVALUES_GENERAL a |
Eigenvalues of any square matrix, possibly complex (via Schur decomposition). Result: real Matrix(2, N) (row 0 real parts, row 1 imaginary parts) mirroring FFT’s complex-spectrum convention rather than a collection of scalar Complex values. |
CHOLESKY a |
a = L·Lᵗ of a symmetric positive-definite matrix. Errors otherwise. |
PCA a COMPONENTS k |
Projects a’s rows onto their top-k principal components (mean-centered, built on SVD). |
Multi-output (bind with LET a, b[, c] = ...):
| Operator | Outputs |
|---|---|
QR a |
Q, R |
LU a |
P, L, U (square a only): P is included so P @ a == L @ U actually holds |
EIGEN a |
eigenvalues (Vector), eigenvectors (Matrix, as columns); symmetric matrices only |
EIGEN_GENERAL a |
eigenvalues (Vector), eigenvectors (Matrix, as columns); any square matrix, but scoped to the real-eigenvalue case only (nalgebra has no public general complex-eigenvector API). Errors loudly, pointing at EIGENVALUES_GENERAL, if the matrix’s eigenvalues turn out to be genuinely complex: never a silently wrong real approximation. |
SVD a |
U, s (Vector of singular values), Vᵗ |
MATRIX m = [[4, 7], [2, 6]]LET tr = TRACE m -- 10.0LET det = DETERMINANT m -- 10.0LET inv = INVERSE mVECTOR b = [4, 6]LET x = SOLVE m b -- solves m @ x = b
MATRIX overdetermined = [[1, 1], [2, 1], [3, 1]]VECTOR y = [2.1, 3.9, 6.05]LET fit = LSTSQ overdetermined y -- least-squares fit; never errors on non-square/singular input
LET q, r = QR mLET p, l, u = LU mMATRIX sym = [[2, 1], [1, 2]]LET vals, vecs = EIGEN sym -- symmetric matrices: real eigenvalues guaranteedLET u, s, vt = SVD m
-- Non-symmetric matrices: eigenvalues may be complexMATRIX rot = [[0, -1], [1, 0]]LET eigs = EIGENVALUES_GENERAL rot -- Matrix(2,N): row 0 = real parts, row 1 = imaginary partsMulti-output LET
Section titled “Multi-output LET”LET a, b[, c] = <expr> binds more than one name from a single expression: only the
decompositions above with more than one natural output support this. The number of names
must match the expression’s real output count exactly; a mismatch is a clear error, not a
silent truncation. Using a single-output operator with multi-output LET, or vice versa,
is also a clear error pointing at the correct form.

