Linalg — 线性代数¶
概述¶
基础逐元素矩阵运算。TinyMath 依赖链中的 第 1 层——所有更高级的模块(decomp、eigen、iterative)都依赖这些原语。
头文件: #include "tiny_linalg.h"
架构¶
该模块提供三个层次的运算:
| 层次 | 函数 | 复杂度 |
|---|---|---|
| 逐元素算术 | add / sub / mult ± 常数(支持 padding 和 stride) | \(O(r \cdot c)\) |
| 矩阵乘法 | mult / mult_ex / matvec | \(O(m \cdot n \cdot k)\) |
| 工具函数 | transpose / eye / zero / fill / diag / frob_norm / has_nan / has_inf / residual_norm | \(O(r \cdot c)\) |
平台分发¶
所有函数在编译时自动选择最快的可用实现:
- ESP32 平台: 将向量化运算委托给 ESP-DSP 库(
dsps_*、dspm_*) - 通用平台: 回退到纯 C 循环
通过 tiny_math_config.h 中的 MCU_PLATFORM_SELECTED 控制。
Padding 与 Stride 对性能的影响
padding = 0 且 stride = 1 时使用 ESP-DSP 加速路径。任何非零 padding 或非单位 stride 都会强制使用可能慢 10 倍 的通用 C 回退实现。
逐元素算术¶
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(/* 相同签名 */);
tiny_error_t tiny_mat_mult_f32(/* 相同签名 */);
\(C_{ij} = A_{ij} \pm B_{ij}\) 或 \(C_{ij} = A_{ij} \cdot B_{ij}\)
| 参数 | 说明 |
|---|---|
a, b, c | 输入/输出矩阵 |
rows, cols | 逻辑矩阵维度 |
pa, pb, pc | 行填充(每行不属于数据的元素数) |
sa, sb, sc | 列步长(通常为 1) |
矩阵乘法¶
\(C_{m \times n} = A_{m \times k} \cdot B_{k \times n}\)
所有矩阵必须是 连续的(无 padding)。ESP32 上使用 ESP-DSP dspm_mult_f32。
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);
相同乘法但每个操作数可以有 行 padding——适用于从较大矩阵中提取的子块相乘。
| 参数 | 说明 |
|---|---|
Ar, Ac | A 的行数、A 的列数(= B 的行数) |
Bc | B 的列数 |
Ap, Bp, Cp | 每个操作数的行填充 |
\(y_{rows} = A_{rows \times cols} \cdot x_{cols}\)——假设连续存储,无 padding。
工具函数¶
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);
- 转置: \(A^T\),缓存友好的逐行迭代,\(O(m \cdot n)\)
- Frobenius 范数: \(\|A\|_F = \sqrt{\sum a_{ij}^2}\)
返回值¶
所有函数返回 tiny_error_t:
| 代码 | 含义 |
|---|---|
TINY_OK | 成功 |
TINY_ERR_MATH_NULL_POINTER | 传入了空指针 |
TINY_ERR_MATH_INVALID_LENGTH | 维度 ≤ 0 或不匹配 |
TINY_ERR_MATH_ZERO_DIVISION | 除零(如果适用) |