Skip to content

Linalg — Linear Algebra

Overview

Basic element-wise matrix operations. Level 1 in the TinyMath dependency chain — all higher modules (decomp, eigen, iterative) depend on these primitives.

Header: #include "tiny_linalg.h"


Architecture

The module provides three tiers of operations:

Tier Functions Complexity
Element-wise arithmetic add / sub / mult ± constant (with padding & stride) \(O(r \cdot c)\)
Matrix multiply mult / mult_ex / matvec \(O(m \cdot n \cdot k)\)
Utility transpose / eye / zero / fill / diag / frob_norm / has_nan / has_inf / residual_norm \(O(r \cdot c)\)

Platform Dispatch

All functions automatically select the fastest available implementation at compile time:

  • ESP32 platform: delegates vectorised operations to ESP-DSP library (dsps_*, dspm_*)
  • Generic platform: falls back to plain C loops

The selection is controlled by MCU_PLATFORM_SELECTED in tiny_math_config.h.

Padding & Stride for Performance

When padding = 0 and stride = 1, the ESP-DSP accelerated path is used. Any non-zero padding or non-unit stride forces a generic C fallback that can be 10× slower.


Element-wise Arithmetic

tiny_error_t tiny_mat_add_f32(const float *a, const float *b, float *c,
                               int rows, int cols,
                               int pa, int pb, int pc,
                               int sa, int sb, int sc);
tiny_error_t tiny_mat_sub_f32(/* same signature */);
tiny_error_t tiny_mat_mult_f32(/* same signature */);

\(C_{ij} = A_{ij} \pm B_{ij}\) or \(C_{ij} = A_{ij} \cdot B_{ij}\)

Param Description
a, b, c Input / output matrices
rows, cols Logical matrix dimensions
pa, pb, pc Row padding (elements per row not part of data)
sa, sb, sc Column stride (typically 1)
tiny_error_t tiny_mat_addc_f32(const float *in, float *out, float C,
                                int rows, int cols,
                                int pi, int po, int si, int so);
tiny_error_t tiny_mat_subc_f32(/* same signature */);
tiny_error_t tiny_mat_multc_f32(/* same signature */);

\(Out_{ij} = In_{ij} \pm C\) or \(Out_{ij} = In_{ij} \cdot C\)


Matrix Multiply

tiny_error_t tiny_mat_mult_f32(const float *A, const float *B, float *C,
                                int m, int n, int k);

\(C_{m \times n} = A_{m \times k} \cdot B_{k \times n}\)

All matrices must be contiguous (no padding). Uses ESP-DSP dspm_mult_f32 on ESP32.

tiny_error_t tiny_mat_mult_ex_f32(const float *A, const float *B, float *C,
                                   int Ar, int Ac, int Bc,
                                   int Ap, int Bp, int Cp);

Same multiply but each operand may have row padding — useful when multiplying sub-blocks extracted from larger matrices.

Param Description
Ar, Ac Rows of A, columns of A (= rows of B)
Bc Columns of B
Ap, Bp, Cp Row padding per operand
tiny_error_t tiny_mat_matvec_f32(const float *A, const float *x, float *y,
                                  int rows, int cols);

\(y_{rows} = A_{rows \times cols} \cdot x_{cols}\) — contiguous storage assumed, no padding.

float A[6] = {1,2,3,4,5,6};  // 2×3 matrix
float x[3] = {1,0,1};
float y[2];
tiny_mat_matvec_f32(A, x, y, 2, 3);
// y = {1*1 + 2*0 + 3*1, 4*1 + 5*0 + 6*1} = {4, 10}

Utility Functions

tiny_error_t tiny_mat_eye_f32(float *A, int n);     // Iₙ identity
tiny_error_t tiny_mat_zero_f32(float *A, int r, int c); // all zeros
tiny_error_t tiny_mat_fill_f32(float *A, int r, int c, float val); // constant
tiny_error_t tiny_mat_diag_f32(const float *A, float *d, int n); // extract diagonal
float I[9];
tiny_mat_eye_f32(I, 3);
// I = [1 0 0; 0 1 0; 0 0 1]
tiny_error_t tiny_mat_transpose_f32(const float *A, float *At, int rows, int cols);
float tiny_mat_frob_norm_f32(const float *A, int rows, int cols);
  • Transpose: \(A^T\), cache-friendly row-by-row iteration, \(O(m \cdot n)\)
  • Frobenius norm: \(\|A\|_F = \sqrt{\sum a_{ij}^2}\)
int tiny_mat_has_nan_f32(const float *A, int rows, int cols);  // returns 1 if NaN found
int tiny_mat_has_inf_f32(const float *A, int rows, int cols);  // returns 1 if Inf found
float tiny_mat_residual_norm_f32(const float *A, const float *B, int rows, int cols);

residual_norm computes \(\|A - B\|_F\) — useful for convergence checks in iterative solvers.

// Check if a matrix has invalid entries after computation
if (tiny_mat_has_nan_f32(result, 10, 10)) {
    // Division by zero or overflow occurred
}

Return Values

All functions return tiny_error_t:

Code Meaning
TINY_OK Success
TINY_ERR_MATH_NULL_POINTER Null pointer passed
TINY_ERR_MATH_INVALID_LENGTH Dimension ≤ 0 or mismatch
TINY_ERR_MATH_ZERO_DIVISION Division by zero (if applicable)