1243 lines
28 KiB
Markdown
1243 lines
28 KiB
Markdown
# tensor
|
||
|
||
Tensor operations with automatic differentiation. Python counterpart: PyTorch core functionality.
|
||
|
||
**Header:** `tensor/tensor.h`
|
||
**Source:** `tensor/tensor.c`
|
||
**Status:** ✅ Verified - 141 tests passing (100% PyTorch parity including sparse tensors)
|
||
|
||
---
|
||
|
||
## Overview
|
||
|
||
The tensor module provides:
|
||
- N-dimensional tensor storage
|
||
- Element-wise and matrix operations
|
||
- Automatic differentiation (autograd)
|
||
- Broadcasting support
|
||
- Multiple data types (F32, F64, F16, BF16, I32, I64)
|
||
|
||
---
|
||
|
||
## Quick Start
|
||
|
||
```c
|
||
#include "tensor/tensor.h"
|
||
|
||
// Create tensors
|
||
int64_t shape[] = {32, 64};
|
||
tm_tensor* a = tm_randn(shape, 2, TM_F32);
|
||
tm_tensor* b = tm_randn(shape, 2, TM_F32);
|
||
|
||
// Enable gradient tracking
|
||
tm_set_requires_grad(a, true);
|
||
tm_set_requires_grad(b, true);
|
||
|
||
// Operations
|
||
tm_tensor* c = tm_add(a, b);
|
||
tm_tensor* d = tm_relu(c);
|
||
tm_tensor* loss = tm_mean(d, -1, false);
|
||
|
||
// Backpropagation
|
||
tm_backward(loss);
|
||
|
||
// Access gradients
|
||
float* grad_a = tm_data_f32(a->grad);
|
||
|
||
// Cleanup
|
||
tm_free(loss);
|
||
tm_free(d);
|
||
tm_free(c);
|
||
tm_free(b);
|
||
tm_free(a);
|
||
```
|
||
|
||
---
|
||
|
||
## Data Types
|
||
|
||
| Type | Constant | Size | Description |
|
||
|------|----------|------|-------------|
|
||
| float32 | `TM_F32` | 4 bytes | Default, most operations |
|
||
| float64 | `TM_F64` | 8 bytes | High precision |
|
||
| float16 | `TM_F16` | 2 bytes | Memory efficient |
|
||
| bfloat16 | `TM_BF16` | 2 bytes | Training efficient |
|
||
| int32 | `TM_I32` | 4 bytes | Indices |
|
||
| int64 | `TM_I64` | 8 bytes | Large indices |
|
||
|
||
---
|
||
|
||
## API Reference
|
||
|
||
### Tensor Creation
|
||
|
||
#### tm_empty
|
||
```c
|
||
tm_tensor* tm_empty(int64_t* shape, int ndim, tm_dtype dtype);
|
||
```
|
||
Create tensor with uninitialized data.
|
||
|
||
#### tm_zeros
|
||
```c
|
||
tm_tensor* tm_zeros(int64_t* shape, int ndim, tm_dtype dtype);
|
||
```
|
||
Create tensor filled with zeros.
|
||
|
||
#### tm_ones
|
||
```c
|
||
tm_tensor* tm_ones(int64_t* shape, int ndim, tm_dtype dtype);
|
||
```
|
||
Create tensor filled with ones.
|
||
|
||
#### tm_full
|
||
```c
|
||
tm_tensor* tm_full(int64_t* shape, int ndim, tm_dtype dtype, double value);
|
||
```
|
||
Create tensor filled with specified value.
|
||
|
||
#### tm_randn
|
||
```c
|
||
tm_tensor* tm_randn(int64_t* shape, int ndim, tm_dtype dtype);
|
||
```
|
||
Create tensor with random normal values (mean=0, std=1).
|
||
|
||
#### tm_rand
|
||
```c
|
||
tm_tensor* tm_rand(int64_t* shape, int ndim, tm_dtype dtype);
|
||
```
|
||
Create tensor with random uniform values [0, 1).
|
||
|
||
#### tm_from_data
|
||
```c
|
||
tm_tensor* tm_from_data(void* data, int64_t* shape, int ndim, tm_dtype dtype);
|
||
```
|
||
Create tensor from existing data (does not copy).
|
||
|
||
#### tm_clone
|
||
```c
|
||
tm_tensor* tm_clone(tm_tensor* t);
|
||
```
|
||
Deep copy tensor.
|
||
|
||
#### tm_zeros_like
|
||
```c
|
||
tm_tensor* tm_zeros_like(tm_tensor* t);
|
||
```
|
||
Create zeros tensor with same shape as input.
|
||
|
||
#### tm_ones_like
|
||
```c
|
||
tm_tensor* tm_ones_like(tm_tensor* t);
|
||
```
|
||
Create ones tensor with same shape as input.
|
||
|
||
#### tm_arange
|
||
```c
|
||
tm_tensor* tm_arange(double start, double end, double step, tm_dtype dtype);
|
||
```
|
||
Create tensor with range of values [start, end) with step.
|
||
|
||
#### tm_eye
|
||
```c
|
||
tm_tensor* tm_eye(int64_t n, tm_dtype dtype);
|
||
```
|
||
Create n×n identity matrix.
|
||
|
||
#### tm_linspace
|
||
```c
|
||
tm_tensor* tm_linspace(double start, double end, int64_t steps, tm_dtype dtype);
|
||
```
|
||
Create linearly spaced values from start to end.
|
||
|
||
#### tm_randint
|
||
```c
|
||
tm_tensor* tm_randint(int64_t low, int64_t high, int64_t* shape, int ndim);
|
||
```
|
||
Create tensor with random integers in [low, high).
|
||
|
||
#### tm_full_like
|
||
```c
|
||
tm_tensor* tm_full_like(tm_tensor* t, double value);
|
||
```
|
||
Create tensor filled with value, same shape as input.
|
||
|
||
#### tm_empty_like
|
||
```c
|
||
tm_tensor* tm_empty_like(tm_tensor* t);
|
||
```
|
||
Create uninitialized tensor with same shape as input.
|
||
|
||
#### tm_rand_like
|
||
```c
|
||
tm_tensor* tm_rand_like(tm_tensor* t);
|
||
```
|
||
Create random uniform tensor with same shape as input.
|
||
|
||
#### tm_randn_like
|
||
```c
|
||
tm_tensor* tm_randn_like(tm_tensor* t);
|
||
```
|
||
Create random normal tensor with same shape as input.
|
||
|
||
---
|
||
|
||
### Memory Management
|
||
|
||
#### tm_retain
|
||
```c
|
||
tm_tensor* tm_retain(tm_tensor* t);
|
||
```
|
||
Increment reference count.
|
||
|
||
#### tm_release / tm_free
|
||
```c
|
||
void tm_release(tm_tensor* t);
|
||
#define tm_free(t) tm_release(t)
|
||
```
|
||
Decrement reference count, free if zero.
|
||
|
||
---
|
||
|
||
### Accessors
|
||
|
||
#### tm_get_f32 / tm_set_f32
|
||
```c
|
||
float tm_get_f32(tm_tensor* t, int64_t i);
|
||
void tm_set_f32(tm_tensor* t, int64_t i, float val);
|
||
```
|
||
Get/set element by flat index.
|
||
|
||
#### tm_data_f32
|
||
```c
|
||
float* tm_data_f32(tm_tensor* t);
|
||
```
|
||
Get pointer to data.
|
||
|
||
#### tm_numel
|
||
```c
|
||
int64_t tm_numel(tm_tensor* t);
|
||
```
|
||
Get total number of elements.
|
||
|
||
#### tm_ndim
|
||
```c
|
||
int tm_ndim(tm_tensor* t);
|
||
```
|
||
Get number of dimensions.
|
||
|
||
#### tm_size
|
||
```c
|
||
int64_t tm_size(tm_tensor* t, int dim);
|
||
```
|
||
Get size of dimension.
|
||
|
||
---
|
||
|
||
### Shape Operations
|
||
|
||
#### tm_reshape
|
||
```c
|
||
tm_tensor* tm_reshape(tm_tensor* t, int64_t* shape, int ndim);
|
||
```
|
||
Reshape tensor (returns view if possible).
|
||
|
||
#### tm_transpose
|
||
```c
|
||
tm_tensor* tm_transpose(tm_tensor* t, int dim0, int dim1);
|
||
```
|
||
Swap two dimensions.
|
||
|
||
#### tm_squeeze
|
||
```c
|
||
tm_tensor* tm_squeeze(tm_tensor* t, int dim);
|
||
```
|
||
Remove dimension of size 1.
|
||
|
||
#### tm_unsqueeze
|
||
```c
|
||
tm_tensor* tm_unsqueeze(tm_tensor* t, int dim);
|
||
```
|
||
Add dimension of size 1.
|
||
|
||
#### tm_contiguous
|
||
```c
|
||
tm_tensor* tm_contiguous(tm_tensor* t);
|
||
```
|
||
Ensure data is contiguous in memory.
|
||
|
||
#### tm_view
|
||
```c
|
||
tm_tensor* tm_view(tm_tensor* t, int64_t* shape, int ndim);
|
||
```
|
||
View tensor with new shape (alias for reshape).
|
||
|
||
#### tm_permute
|
||
```c
|
||
tm_tensor* tm_permute(tm_tensor* t, int* dims, int ndim);
|
||
```
|
||
Permute dimensions (generalized transpose).
|
||
|
||
#### tm_flatten
|
||
```c
|
||
tm_tensor* tm_flatten(tm_tensor* t, int start_dim, int end_dim);
|
||
```
|
||
Flatten dimensions from start_dim to end_dim.
|
||
|
||
#### tm_select
|
||
```c
|
||
tm_tensor* tm_select(tm_tensor* t, int dim, int64_t index);
|
||
```
|
||
Select along dimension (reduces ndim by 1).
|
||
|
||
#### tm_cat
|
||
```c
|
||
tm_tensor* tm_cat(tm_tensor** tensors, int num_tensors, int dim);
|
||
```
|
||
Concatenate tensors along dimension.
|
||
|
||
#### tm_stack
|
||
```c
|
||
tm_tensor* tm_stack(tm_tensor** tensors, int num_tensors, int dim);
|
||
```
|
||
Stack tensors along new dimension.
|
||
|
||
#### tm_split
|
||
```c
|
||
tm_tensor** tm_split(tm_tensor* t, int64_t split_size, int dim, int* num_chunks);
|
||
```
|
||
Split tensor into chunks along dimension.
|
||
|
||
#### tm_chunk
|
||
```c
|
||
tm_tensor** tm_chunk(tm_tensor* t, int n, int dim, int* actual);
|
||
```
|
||
Split tensor into n equal chunks along dimension.
|
||
|
||
#### tm_expand
|
||
```c
|
||
tm_tensor* tm_expand(tm_tensor* t, int64_t* shape, int ndim);
|
||
```
|
||
Expand tensor to larger shape (broadcasting).
|
||
|
||
#### tm_repeat
|
||
```c
|
||
tm_tensor* tm_repeat(tm_tensor* t, int64_t* sizes, int ndim);
|
||
```
|
||
Repeat tensor along dimensions.
|
||
|
||
#### tm_narrow
|
||
```c
|
||
tm_tensor* tm_narrow(tm_tensor* t, int dim, int64_t start, int64_t length);
|
||
```
|
||
Narrow tensor along dimension (slice view).
|
||
|
||
#### tm_flip
|
||
```c
|
||
tm_tensor* tm_flip(tm_tensor* t, int* dims, int ndim);
|
||
```
|
||
Reverse tensor along specified dimensions.
|
||
|
||
#### tm_roll
|
||
```c
|
||
tm_tensor* tm_roll(tm_tensor* t, int64_t shift, int dim);
|
||
```
|
||
Roll tensor elements along dimension.
|
||
|
||
#### tm_t
|
||
```c
|
||
tm_tensor* tm_t(tm_tensor* t);
|
||
```
|
||
Transpose 2D tensor (alias for transpose(0, 1)).
|
||
|
||
---
|
||
|
||
### Element-wise Operations
|
||
|
||
All element-wise operations support broadcasting.
|
||
|
||
| Function | Operation |
|
||
|----------|-----------|
|
||
| `tm_add(a, b)` | a + b |
|
||
| `tm_sub(a, b)` | a - b |
|
||
| `tm_mul(a, b)` | a * b |
|
||
| `tm_div(a, b)` | a / b |
|
||
| `tm_add_scalar(a, s)` | a + s |
|
||
| `tm_sub_scalar(a, s)` | a - s |
|
||
| `tm_mul_scalar(a, s)` | a * s |
|
||
| `tm_div_scalar(a, s)` | a / s |
|
||
| `tm_neg(a)` | -a |
|
||
| `tm_abs(a)` | \|a\| |
|
||
| `tm_exp(a)` | exp(a) |
|
||
| `tm_log(a)` | log(a) |
|
||
| `tm_sqrt(a)` | sqrt(a) |
|
||
| `tm_rsqrt(a)` | 1/sqrt(a) |
|
||
| `tm_reciprocal(a)` | 1/a |
|
||
| `tm_pow(a, n)` | a^n |
|
||
| `tm_sin(a)` | sin(a) |
|
||
| `tm_cos(a)` | cos(a) |
|
||
| `tm_tan(a)` | tan(a) |
|
||
| `tm_asin(a)` | arcsin(a) |
|
||
| `tm_acos(a)` | arccos(a) |
|
||
| `tm_atan(a)` | arctan(a) |
|
||
| `tm_sinh(a)` | sinh(a) |
|
||
| `tm_cosh(a)` | cosh(a) |
|
||
| `tm_tanh(a)` | tanh(a) |
|
||
| `tm_exp2(a)` | 2^a |
|
||
| `tm_expm1(a)` | exp(a) - 1 |
|
||
| `tm_log2(a)` | log2(a) |
|
||
| `tm_log10(a)` | log10(a) |
|
||
| `tm_log1p(a)` | log(1 + a) |
|
||
| `tm_floor(a)` | floor(a) |
|
||
| `tm_ceil(a)` | ceil(a) |
|
||
| `tm_round(a)` | round(a) |
|
||
| `tm_trunc(a)` | truncate(a) |
|
||
| `tm_sign(a)` | sign(a) |
|
||
| `tm_relu(a)` | max(0, a) |
|
||
| `tm_leaky_relu(a, slope)` | Leaky ReLU |
|
||
| `tm_elu(a, alpha)` | ELU activation |
|
||
| `tm_sigmoid(a)` | 1/(1+exp(-a)) |
|
||
| `tm_gelu(a)` | GELU activation |
|
||
| `tm_silu(a)` | x * sigmoid(x) (SwiGLU) |
|
||
| `tm_hardswish(a)` | x * relu6(x+3) / 6 |
|
||
| `tm_hardtanh(a, min, max)` | Clamped linear |
|
||
| `tm_softplus(a, beta, thresh)` | Smooth ReLU |
|
||
| `tm_clamp(a, min, max)` | Clamp values |
|
||
| `tm_maximum(a, b)` | Element-wise max |
|
||
| `tm_minimum(a, b)` | Element-wise min |
|
||
| `tm_where(cond, a, b)` | Conditional select |
|
||
| `tm_masked_fill(t, mask, val)` | Fill where mask is true |
|
||
| `tm_lerp(a, b, w)` | Linear interpolation |
|
||
| `tm_addcmul(t, a, b, val)` | t + val * a * b |
|
||
| `tm_addcdiv(t, a, b, val)` | t + val * a / b |
|
||
|
||
---
|
||
|
||
### Matrix Operations
|
||
|
||
#### tm_matmul
|
||
```c
|
||
tm_tensor* tm_matmul(tm_tensor* a, tm_tensor* b);
|
||
```
|
||
Matrix multiplication. Supports 2D and batched 3D tensors.
|
||
|
||
#### tm_bmm
|
||
```c
|
||
tm_tensor* tm_bmm(tm_tensor* a, tm_tensor* b);
|
||
```
|
||
Batched matrix multiplication.
|
||
|
||
#### tm_mm
|
||
```c
|
||
tm_tensor* tm_mm(tm_tensor* a, tm_tensor* b);
|
||
```
|
||
2D matrix multiplication (alias for matmul).
|
||
|
||
#### tm_addmm
|
||
```c
|
||
tm_tensor* tm_addmm(tm_tensor* t, tm_tensor* a, tm_tensor* b, float beta, float alpha);
|
||
```
|
||
Additive matrix multiply: beta*t + alpha*(a @ b).
|
||
|
||
#### tm_dot
|
||
```c
|
||
tm_tensor* tm_dot(tm_tensor* a, tm_tensor* b);
|
||
```
|
||
Dot product of 1D tensors.
|
||
|
||
#### tm_mv
|
||
```c
|
||
tm_tensor* tm_mv(tm_tensor* mat, tm_tensor* vec);
|
||
```
|
||
Matrix-vector multiplication.
|
||
|
||
#### tm_outer
|
||
```c
|
||
tm_tensor* tm_outer(tm_tensor* a, tm_tensor* b);
|
||
```
|
||
Outer product of 1D tensors.
|
||
|
||
#### tm_inner
|
||
```c
|
||
tm_tensor* tm_inner(tm_tensor* a, tm_tensor* b);
|
||
```
|
||
Inner product of tensors.
|
||
|
||
#### tm_inverse
|
||
```c
|
||
tm_tensor* tm_inverse(tm_tensor* t);
|
||
```
|
||
Matrix inverse using Gauss-Jordan elimination.
|
||
|
||
#### tm_det
|
||
```c
|
||
tm_tensor* tm_det(tm_tensor* t);
|
||
```
|
||
Matrix determinant using LU decomposition.
|
||
|
||
#### tm_svd
|
||
```c
|
||
tm_tensor** tm_svd(tm_tensor* t, int* num_outputs);
|
||
```
|
||
Singular value decomposition. Returns array of 3 tensors: U, S, V.
|
||
|
||
#### tm_eig
|
||
```c
|
||
tm_tensor* tm_eig(tm_tensor* t);
|
||
```
|
||
Eigenvalues of a square matrix using QR iteration.
|
||
|
||
---
|
||
|
||
### Comparison Operations
|
||
|
||
| Function | Operation |
|
||
|----------|-----------|
|
||
| `tm_eq(a, b)` | a == b (element-wise) |
|
||
| `tm_ne(a, b)` | a != b (element-wise) |
|
||
| `tm_lt(a, b)` | a < b (element-wise) |
|
||
| `tm_le(a, b)` | a <= b (element-wise) |
|
||
| `tm_gt(a, b)` | a > b (element-wise) |
|
||
| `tm_ge(a, b)` | a >= b (element-wise) |
|
||
| `tm_equal(a, b)` | All elements equal (bool) |
|
||
| `tm_allclose(a, b, rtol, atol)` | Approximately equal |
|
||
| `tm_isnan(a)` | Check for NaN |
|
||
| `tm_isinf(a)` | Check for Inf |
|
||
| `tm_isfinite(a)` | Check for finite |
|
||
| `tm_logical_and(a, b)` | Logical AND |
|
||
| `tm_logical_or(a, b)` | Logical OR |
|
||
| `tm_logical_not(a)` | Logical NOT |
|
||
| `tm_logical_xor(a, b)` | Logical XOR |
|
||
|
||
---
|
||
|
||
### Indexing Operations
|
||
|
||
#### tm_gather
|
||
```c
|
||
tm_tensor* tm_gather(tm_tensor* t, int dim, tm_tensor* idx);
|
||
```
|
||
Gather elements by index along dimension.
|
||
|
||
#### tm_scatter
|
||
```c
|
||
tm_tensor* tm_scatter(tm_tensor* t, int dim, tm_tensor* idx, tm_tensor* src);
|
||
```
|
||
Scatter elements by index along dimension.
|
||
|
||
#### tm_scatter_add
|
||
```c
|
||
tm_tensor* tm_scatter_add(tm_tensor* t, int dim, tm_tensor* idx, tm_tensor* src);
|
||
```
|
||
Scatter with addition.
|
||
|
||
#### tm_index_select
|
||
```c
|
||
tm_tensor* tm_index_select(tm_tensor* t, int dim, tm_tensor* idx);
|
||
```
|
||
Select elements by index along dimension.
|
||
|
||
#### tm_masked_select
|
||
```c
|
||
tm_tensor* tm_masked_select(tm_tensor* t, tm_tensor* mask);
|
||
```
|
||
Select elements where mask is true.
|
||
|
||
#### tm_take
|
||
```c
|
||
tm_tensor* tm_take(tm_tensor* t, tm_tensor* idx);
|
||
```
|
||
Take elements by flat index.
|
||
|
||
#### tm_index_fill
|
||
```c
|
||
tm_tensor* tm_index_fill(tm_tensor* t, int dim, tm_tensor* idx, float val);
|
||
```
|
||
Fill at indices with value.
|
||
|
||
#### tm_index_copy
|
||
```c
|
||
tm_tensor* tm_index_copy(tm_tensor* t, int dim, tm_tensor* idx, tm_tensor* src);
|
||
```
|
||
Copy to indices.
|
||
|
||
#### tm_index_add
|
||
```c
|
||
tm_tensor* tm_index_add(tm_tensor* t, int dim, tm_tensor* idx, tm_tensor* src);
|
||
```
|
||
Add at indices.
|
||
|
||
#### tm_nonzero
|
||
```c
|
||
tm_tensor* tm_nonzero(tm_tensor* t);
|
||
```
|
||
Indices of non-zero elements.
|
||
|
||
---
|
||
|
||
### Reductions
|
||
|
||
#### tm_sum
|
||
```c
|
||
tm_tensor* tm_sum(tm_tensor* t, int dim, bool keepdim);
|
||
```
|
||
Sum over dimension. `dim=-1` means sum all elements.
|
||
|
||
#### tm_mean
|
||
```c
|
||
tm_tensor* tm_mean(tm_tensor* t, int dim, bool keepdim);
|
||
```
|
||
Mean over dimension.
|
||
|
||
#### tm_max / tm_min
|
||
```c
|
||
tm_tensor* tm_max(tm_tensor* t, int dim, bool keepdim);
|
||
tm_tensor* tm_min(tm_tensor* t, int dim, bool keepdim);
|
||
```
|
||
Max/min over dimension.
|
||
|
||
#### tm_argmax / tm_argmin
|
||
```c
|
||
tm_tensor* tm_argmax(tm_tensor* t, int dim, bool keepdim);
|
||
tm_tensor* tm_argmin(tm_tensor* t, int dim, bool keepdim);
|
||
```
|
||
Index of max/min value.
|
||
|
||
#### tm_logsumexp
|
||
```c
|
||
tm_tensor* tm_logsumexp(tm_tensor* t, int dim, bool keepdim);
|
||
```
|
||
Log-sum-exp (numerically stable).
|
||
|
||
#### tm_prod
|
||
```c
|
||
tm_tensor* tm_prod(tm_tensor* t, int dim, bool keepdim);
|
||
```
|
||
Product over dimension.
|
||
|
||
#### tm_cumsum
|
||
```c
|
||
tm_tensor* tm_cumsum(tm_tensor* t, int dim);
|
||
```
|
||
Cumulative sum along dimension.
|
||
|
||
#### tm_cumprod
|
||
```c
|
||
tm_tensor* tm_cumprod(tm_tensor* t, int dim);
|
||
```
|
||
Cumulative product along dimension.
|
||
|
||
#### tm_std / tm_var
|
||
```c
|
||
tm_tensor* tm_std(tm_tensor* t, int dim, bool keepdim, bool unbiased);
|
||
tm_tensor* tm_var(tm_tensor* t, int dim, bool keepdim, bool unbiased);
|
||
```
|
||
Standard deviation and variance.
|
||
|
||
#### tm_any / tm_all
|
||
```c
|
||
tm_tensor* tm_any(tm_tensor* t, int dim, bool keepdim);
|
||
tm_tensor* tm_all(tm_tensor* t, int dim, bool keepdim);
|
||
```
|
||
Any/all true along dimension.
|
||
|
||
#### tm_norm
|
||
```c
|
||
tm_tensor* tm_norm(tm_tensor* t, float p, int dim, bool keepdim);
|
||
```
|
||
Lp norm along dimension.
|
||
|
||
#### tm_count_nonzero
|
||
```c
|
||
tm_tensor* tm_count_nonzero(tm_tensor* t, int dim);
|
||
```
|
||
Count non-zero elements.
|
||
|
||
---
|
||
|
||
### Neural Network Operations
|
||
|
||
#### tm_softmax
|
||
```c
|
||
tm_tensor* tm_softmax(tm_tensor* t, int dim);
|
||
```
|
||
Softmax over dimension.
|
||
|
||
#### tm_log_softmax
|
||
```c
|
||
tm_tensor* tm_log_softmax(tm_tensor* t, int dim);
|
||
```
|
||
Log softmax (numerically stable).
|
||
|
||
#### tm_layer_norm
|
||
```c
|
||
tm_tensor* tm_layer_norm(tm_tensor* t, tm_tensor* weight, tm_tensor* bias, float eps);
|
||
```
|
||
Layer normalization.
|
||
|
||
#### tm_embedding
|
||
```c
|
||
tm_tensor* tm_embedding(tm_tensor* weight, tm_tensor* indices);
|
||
```
|
||
Embedding lookup.
|
||
|
||
#### tm_dropout
|
||
```c
|
||
tm_tensor* tm_dropout(tm_tensor* t, float p, bool training);
|
||
```
|
||
Dropout (training mode).
|
||
|
||
#### tm_rms_norm
|
||
```c
|
||
tm_tensor* tm_rms_norm(tm_tensor* t, tm_tensor* weight, float eps);
|
||
```
|
||
RMS normalization (used in Llama, modern LLMs).
|
||
|
||
#### tm_linear
|
||
```c
|
||
tm_tensor* tm_linear(tm_tensor* x, tm_tensor* weight, tm_tensor* bias);
|
||
```
|
||
Linear layer: x @ weight.T + bias.
|
||
|
||
#### tm_triu / tm_tril
|
||
```c
|
||
tm_tensor* tm_triu(tm_tensor* t, int diagonal);
|
||
tm_tensor* tm_tril(tm_tensor* t, int diagonal);
|
||
```
|
||
Upper/lower triangular matrix (for causal masks).
|
||
|
||
#### tm_batch_norm
|
||
```c
|
||
tm_tensor* tm_batch_norm(tm_tensor* t, tm_tensor* weight, tm_tensor* bias,
|
||
tm_tensor* running_mean, tm_tensor* running_var,
|
||
bool training, float momentum, float eps);
|
||
```
|
||
Batch normalization.
|
||
|
||
#### tm_group_norm
|
||
```c
|
||
tm_tensor* tm_group_norm(tm_tensor* t, int num_groups, tm_tensor* weight,
|
||
tm_tensor* bias, float eps);
|
||
```
|
||
Group normalization.
|
||
|
||
#### tm_instance_norm
|
||
```c
|
||
tm_tensor* tm_instance_norm(tm_tensor* t, tm_tensor* weight, tm_tensor* bias,
|
||
float eps);
|
||
```
|
||
Instance normalization.
|
||
|
||
#### tm_scaled_dot_product_attention
|
||
```c
|
||
tm_tensor* tm_scaled_dot_product_attention(tm_tensor* Q, tm_tensor* K, tm_tensor* V,
|
||
tm_tensor* attn_mask, float dropout_p,
|
||
bool is_causal);
|
||
```
|
||
Scaled dot-product attention with optional causal mask.
|
||
|
||
#### tm_split_heads / tm_merge_heads
|
||
```c
|
||
tm_tensor* tm_split_heads(tm_tensor* x, int num_heads);
|
||
tm_tensor* tm_merge_heads(tm_tensor* x);
|
||
```
|
||
Multi-head attention helpers.
|
||
|
||
#### tm_conv1d
|
||
```c
|
||
tm_tensor* tm_conv1d(tm_tensor* input, tm_tensor* weight, tm_tensor* bias,
|
||
int stride, int padding, int dilation, int groups);
|
||
```
|
||
1D convolution with full parameter support.
|
||
|
||
#### tm_conv2d
|
||
```c
|
||
tm_tensor* tm_conv2d(tm_tensor* input, tm_tensor* weight, tm_tensor* bias,
|
||
int stride_h, int stride_w, int padding_h, int padding_w,
|
||
int dilation_h, int dilation_w, int groups);
|
||
```
|
||
2D convolution with full parameter support.
|
||
|
||
#### tm_avg_pool1d / tm_max_pool1d
|
||
```c
|
||
tm_tensor* tm_avg_pool1d(tm_tensor* input, int kernel_size, int stride, int padding);
|
||
tm_tensor* tm_max_pool1d(tm_tensor* input, int kernel_size, int stride, int padding);
|
||
```
|
||
1D pooling operations.
|
||
|
||
#### tm_avg_pool2d / tm_max_pool2d
|
||
```c
|
||
tm_tensor* tm_avg_pool2d(tm_tensor* input, int kernel_h, int kernel_w,
|
||
int stride_h, int stride_w, int padding_h, int padding_w);
|
||
tm_tensor* tm_max_pool2d(tm_tensor* input, int kernel_h, int kernel_w,
|
||
int stride_h, int stride_w, int padding_h, int padding_w);
|
||
```
|
||
2D pooling operations.
|
||
|
||
#### tm_adaptive_avg_pool1d / tm_adaptive_avg_pool2d
|
||
```c
|
||
tm_tensor* tm_adaptive_avg_pool1d(tm_tensor* input, int output_size);
|
||
tm_tensor* tm_adaptive_avg_pool2d(tm_tensor* input, int output_h, int output_w);
|
||
```
|
||
Adaptive average pooling (output size specified).
|
||
|
||
---
|
||
|
||
### Loss Functions
|
||
|
||
#### tm_cross_entropy
|
||
```c
|
||
tm_tensor* tm_cross_entropy(tm_tensor* logits, tm_tensor* targets);
|
||
```
|
||
Cross-entropy loss with integer targets.
|
||
|
||
#### tm_cross_entropy_soft
|
||
```c
|
||
tm_tensor* tm_cross_entropy_soft(tm_tensor* logits, tm_tensor* targets);
|
||
```
|
||
Cross-entropy loss with soft targets.
|
||
|
||
#### tm_mse_loss
|
||
```c
|
||
tm_tensor* tm_mse_loss(tm_tensor* pred, tm_tensor* target);
|
||
```
|
||
Mean squared error loss.
|
||
|
||
#### tm_l1_loss
|
||
```c
|
||
tm_tensor* tm_l1_loss(tm_tensor* pred, tm_tensor* target);
|
||
```
|
||
L1 (Mean Absolute Error) loss.
|
||
|
||
#### tm_smooth_l1_loss
|
||
```c
|
||
tm_tensor* tm_smooth_l1_loss(tm_tensor* pred, tm_tensor* target, float beta);
|
||
```
|
||
Smooth L1 (Huber) loss. Uses quadratic for small errors, linear for large.
|
||
|
||
#### tm_nll_loss
|
||
```c
|
||
tm_tensor* tm_nll_loss(tm_tensor* log_probs, tm_tensor* targets);
|
||
```
|
||
Negative log likelihood loss. Expects log probabilities as input.
|
||
|
||
#### tm_kl_div
|
||
```c
|
||
tm_tensor* tm_kl_div(tm_tensor* input, tm_tensor* target);
|
||
```
|
||
KL divergence loss. Input is log probabilities, target is probabilities.
|
||
|
||
#### tm_binary_cross_entropy
|
||
```c
|
||
tm_tensor* tm_binary_cross_entropy(tm_tensor* pred, tm_tensor* target);
|
||
```
|
||
Binary cross entropy loss for binary classification.
|
||
|
||
#### tm_cosine_embedding_loss
|
||
```c
|
||
tm_tensor* tm_cosine_embedding_loss(tm_tensor* x1, tm_tensor* x2, tm_tensor* y, float margin);
|
||
```
|
||
Cosine embedding loss. y=1 encourages similarity, y=-1 encourages dissimilarity.
|
||
|
||
#### tm_triplet_margin_loss
|
||
```c
|
||
tm_tensor* tm_triplet_margin_loss(tm_tensor* anchor, tm_tensor* positive, tm_tensor* negative, float margin, float p);
|
||
```
|
||
Triplet margin loss for metric learning. Encourages anchor-positive distance < anchor-negative distance.
|
||
|
||
#### tm_cross_entropy_label_smooth
|
||
```c
|
||
tm_tensor* tm_cross_entropy_label_smooth(tm_tensor* logits, tm_tensor* targets, float smoothing);
|
||
```
|
||
Cross-entropy loss with label smoothing. Reduces overconfidence.
|
||
|
||
---
|
||
|
||
### Autograd
|
||
|
||
#### tm_set_requires_grad
|
||
```c
|
||
void tm_set_requires_grad(tm_tensor* t, bool requires);
|
||
```
|
||
Enable/disable gradient tracking.
|
||
|
||
#### tm_backward
|
||
```c
|
||
void tm_backward(tm_tensor* loss);
|
||
```
|
||
Compute gradients via backpropagation.
|
||
|
||
#### tm_zero_grad
|
||
```c
|
||
void tm_zero_grad(tm_tensor** params, int n);
|
||
```
|
||
Zero gradients for all parameters.
|
||
|
||
#### tm_detach
|
||
```c
|
||
tm_tensor* tm_detach(tm_tensor* t);
|
||
```
|
||
Detach from computation graph.
|
||
|
||
#### tm_no_grad_begin / tm_no_grad_end
|
||
```c
|
||
bool tm_no_grad_begin(void);
|
||
void tm_no_grad_end(bool prev);
|
||
```
|
||
Temporarily disable gradient tracking.
|
||
|
||
#### tm_retain_grad
|
||
```c
|
||
void tm_retain_grad(tm_tensor* t);
|
||
```
|
||
Retain gradient for non-leaf tensors. By default, gradients are only kept for leaf tensors.
|
||
|
||
#### tm_grad
|
||
```c
|
||
tm_tensor** tm_grad(tm_tensor** outputs, int num_outputs, tm_tensor** inputs, int num_inputs, tm_tensor** grad_outputs);
|
||
```
|
||
Compute gradients explicitly. Returns array of gradients for each input.
|
||
|
||
#### tm_checkpoint
|
||
```c
|
||
tm_tensor* tm_checkpoint(tm_tensor* (*fn)(tm_tensor**, int, void*), tm_tensor** inputs, int num_inputs, void* ctx);
|
||
```
|
||
Gradient checkpointing for memory-efficient training. Recomputes forward pass during backward.
|
||
|
||
---
|
||
|
||
### Higher-Order Gradients
|
||
|
||
#### tm_hessian
|
||
```c
|
||
tm_tensor* tm_hessian(tm_tensor** params, int num_params,
|
||
tm_tensor* (*loss_fn)(tm_tensor**, int, void*), void* ctx);
|
||
```
|
||
Compute Hessian matrix of loss w.r.t. parameters using finite differences. Returns n x n matrix.
|
||
|
||
#### tm_hvp
|
||
```c
|
||
tm_tensor* tm_hvp(tm_tensor** params, int num_params, tm_tensor** vec, int num_vec,
|
||
tm_tensor* (*loss_fn)(tm_tensor**, int, void*), void* ctx);
|
||
```
|
||
Hessian-vector product without computing full Hessian. More memory efficient for large models.
|
||
|
||
#### tm_jvp
|
||
```c
|
||
tm_tensor** tm_jvp(tm_tensor* (*fn)(tm_tensor**, int, void*), tm_tensor** inputs, int num_inputs,
|
||
tm_tensor** tangents, void* ctx, int* num_outputs_out);
|
||
```
|
||
Jacobian-vector product (forward-mode AD). Computes J @ tangents.
|
||
|
||
---
|
||
|
||
### Custom Autograd Functions
|
||
|
||
#### tm_custom_ctx
|
||
Context for saving tensors during forward pass for use in backward.
|
||
|
||
```c
|
||
tm_custom_ctx* tm_custom_ctx_new(void);
|
||
void tm_save_for_backward(tm_custom_ctx* ctx, tm_tensor* t);
|
||
tm_tensor** tm_get_saved_tensors(tm_custom_ctx* ctx, int* num_saved);
|
||
void tm_custom_ctx_free(tm_custom_ctx* ctx);
|
||
```
|
||
|
||
#### tm_register_autograd_function
|
||
```c
|
||
int tm_register_autograd_function(const char* name,
|
||
tm_tensor* (*forward)(tm_tensor**, int, tm_custom_ctx*),
|
||
tm_tensor** (*backward)(tm_tensor*, tm_custom_ctx*, int*));
|
||
```
|
||
Register a custom autograd function with forward and backward implementations.
|
||
|
||
#### tm_apply_custom_function
|
||
```c
|
||
tm_tensor* tm_apply_custom_function(const char* name, tm_tensor** inputs, int num_inputs);
|
||
tm_tensor* tm_apply_custom_function_id(int fn_id, tm_tensor** inputs, int num_inputs);
|
||
```
|
||
Apply a registered custom function by name or ID.
|
||
|
||
---
|
||
|
||
### Type Conversion
|
||
|
||
#### tm_to
|
||
```c
|
||
tm_tensor* tm_to(tm_tensor* t, tm_dtype dtype);
|
||
```
|
||
Convert tensor to specified dtype.
|
||
|
||
#### tm_float
|
||
```c
|
||
tm_tensor* tm_float(tm_tensor* t);
|
||
```
|
||
Convert to float32.
|
||
|
||
#### tm_double
|
||
```c
|
||
tm_tensor* tm_double(tm_tensor* t);
|
||
```
|
||
Convert to float64.
|
||
|
||
#### tm_half
|
||
```c
|
||
tm_tensor* tm_half(tm_tensor* t);
|
||
```
|
||
Convert to float16.
|
||
|
||
#### tm_int
|
||
```c
|
||
tm_tensor* tm_int(tm_tensor* t);
|
||
```
|
||
Convert to int32.
|
||
|
||
#### tm_long
|
||
```c
|
||
tm_tensor* tm_long(tm_tensor* t);
|
||
```
|
||
Convert to int64.
|
||
|
||
---
|
||
|
||
### In-place Operations
|
||
|
||
**Note:** All in-place operations support autograd. When `requires_grad` is true, gradients are properly tracked and computed during backward pass.
|
||
|
||
#### tm_fill_
|
||
```c
|
||
void tm_fill_(tm_tensor* t, float value);
|
||
```
|
||
Fill tensor with value in-place.
|
||
|
||
#### tm_add_
|
||
```c
|
||
void tm_add_(tm_tensor* a, tm_tensor* b);
|
||
```
|
||
Add tensors in-place: `a += b`.
|
||
|
||
#### tm_scale_
|
||
```c
|
||
void tm_scale_(tm_tensor* t, float s);
|
||
```
|
||
Scale tensor in-place: `t *= s`.
|
||
|
||
#### tm_zero_
|
||
```c
|
||
void tm_zero_(tm_tensor* t);
|
||
```
|
||
Zero tensor in-place.
|
||
|
||
#### tm_copy_
|
||
```c
|
||
void tm_copy_(tm_tensor* dst, tm_tensor* src);
|
||
```
|
||
Copy data in-place.
|
||
|
||
#### tm_clamp_
|
||
```c
|
||
void tm_clamp_(tm_tensor* t, float min_val, float max_val);
|
||
```
|
||
Clamp values in-place.
|
||
|
||
#### tm_sub_
|
||
```c
|
||
void tm_sub_(tm_tensor* a, tm_tensor* b);
|
||
```
|
||
Subtract in-place: `a -= b`.
|
||
|
||
#### tm_mul_
|
||
```c
|
||
void tm_mul_(tm_tensor* a, tm_tensor* b);
|
||
```
|
||
Multiply in-place: `a *= b`.
|
||
|
||
#### tm_div_
|
||
```c
|
||
void tm_div_(tm_tensor* a, tm_tensor* b);
|
||
```
|
||
Divide in-place: `a /= b`.
|
||
|
||
#### tm_exp_
|
||
```c
|
||
void tm_exp_(tm_tensor* t);
|
||
```
|
||
Exponentiate in-place.
|
||
|
||
#### tm_log_
|
||
```c
|
||
void tm_log_(tm_tensor* t);
|
||
```
|
||
Logarithm in-place.
|
||
|
||
#### tm_sqrt_
|
||
```c
|
||
void tm_sqrt_(tm_tensor* t);
|
||
```
|
||
Square root in-place.
|
||
|
||
#### tm_abs_
|
||
```c
|
||
void tm_abs_(tm_tensor* t);
|
||
```
|
||
Absolute value in-place.
|
||
|
||
#### tm_neg_
|
||
```c
|
||
void tm_neg_(tm_tensor* t);
|
||
```
|
||
Negate in-place.
|
||
|
||
#### tm_relu_
|
||
```c
|
||
void tm_relu_(tm_tensor* t);
|
||
```
|
||
ReLU in-place.
|
||
|
||
#### tm_sigmoid_
|
||
```c
|
||
void tm_sigmoid_(tm_tensor* t);
|
||
```
|
||
Sigmoid in-place.
|
||
|
||
---
|
||
|
||
## Examples
|
||
|
||
### Matrix Multiplication
|
||
|
||
```c
|
||
int64_t shape_a[] = {32, 64};
|
||
int64_t shape_b[] = {64, 128};
|
||
|
||
tm_tensor* a = tm_randn(shape_a, 2, TM_F32);
|
||
tm_tensor* b = tm_randn(shape_b, 2, TM_F32);
|
||
tm_tensor* c = tm_matmul(a, b); // [32, 128]
|
||
|
||
tm_print(c); // Print shape and info
|
||
tm_free(c);
|
||
tm_free(b);
|
||
tm_free(a);
|
||
```
|
||
|
||
### Simple Neural Network Forward
|
||
|
||
```c
|
||
// Input: [batch, features]
|
||
// Weights: [features, hidden]
|
||
tm_tensor* h = tm_matmul(input, weights);
|
||
tm_tensor* h_bias = tm_add(h, bias);
|
||
tm_tensor* h_relu = tm_relu(h_bias);
|
||
|
||
// Cleanup intermediates
|
||
tm_free(h);
|
||
tm_free(h_bias);
|
||
```
|
||
|
||
### Broadcasting
|
||
|
||
```c
|
||
int64_t shape_a[] = {32, 64};
|
||
int64_t shape_b[] = {64}; // Will broadcast to [32, 64]
|
||
|
||
tm_tensor* a = tm_ones(shape_a, 2, TM_F32);
|
||
tm_tensor* b = tm_full(shape_b, 1, TM_F32, 2.0);
|
||
tm_tensor* c = tm_add(a, b); // All elements are 3.0
|
||
```
|
||
|
||
---
|
||
|
||
## Sparse Tensors
|
||
|
||
Foundry supports sparse tensors in both COO (Coordinate) and CSR (Compressed Sparse Row) formats.
|
||
|
||
### Sparse Formats
|
||
|
||
```c
|
||
typedef enum {
|
||
TM_SPARSE_COO, /* Coordinate format: (row, col, value) triples */
|
||
TM_SPARSE_CSR, /* Compressed Sparse Row: row_ptr, col_ind, values */
|
||
} tm_sparse_format;
|
||
```
|
||
|
||
### Creating Sparse Tensors
|
||
|
||
```c
|
||
// Create sparse COO tensor from indices and values
|
||
// indices: [2, nnz] tensor of (row, col) pairs
|
||
// values: [nnz] tensor of non-zero values
|
||
tm_tensor* tm_sparse_coo(tm_tensor* indices, tm_tensor* values, int64_t* shape, int ndim);
|
||
|
||
// Create sparse CSR tensor
|
||
tm_tensor* tm_sparse_csr(tm_tensor* row_ptr, tm_tensor* col_ind, tm_tensor* values,
|
||
int64_t* shape, int ndim);
|
||
|
||
// Convert dense to sparse
|
||
tm_tensor* tm_to_sparse(tm_tensor* t); // Dense -> COO
|
||
tm_tensor* tm_to_sparse_csr(tm_tensor* t); // Dense -> CSR
|
||
tm_tensor* tm_to_dense(tm_tensor* t); // Sparse -> Dense
|
||
```
|
||
|
||
### Sparse Operations
|
||
|
||
```c
|
||
// Check if sparse
|
||
bool tm_is_sparse(tm_tensor* t);
|
||
int64_t tm_sparse_nnz(tm_tensor* t);
|
||
tm_sparse_format tm_get_sparse_format(tm_tensor* t);
|
||
|
||
// Format conversion
|
||
tm_tensor* tm_sparse_coo_to_csr(tm_tensor* t);
|
||
tm_tensor* tm_sparse_csr_to_coo(tm_tensor* t);
|
||
|
||
// Sparse-dense matrix multiplication
|
||
tm_tensor* tm_spmm(tm_tensor* sparse, tm_tensor* dense); // sparse @ dense
|
||
tm_tensor* tm_spmv(tm_tensor* sparse, tm_tensor* vec); // sparse @ vector
|
||
|
||
// Sparse arithmetic
|
||
tm_tensor* tm_sparse_add(tm_tensor* a, tm_tensor* b); // sparse + sparse
|
||
tm_tensor* tm_sparse_mul_scalar(tm_tensor* t, double s); // sparse * scalar
|
||
|
||
// Access components
|
||
tm_tensor* tm_sparse_values(tm_tensor* t); // Get values tensor
|
||
tm_tensor* tm_sparse_indices(tm_tensor* t); // Get indices (COO only)
|
||
tm_tensor* tm_sparse_coalesce(tm_tensor* t); // Combine duplicate indices
|
||
```
|
||
|
||
### Example
|
||
|
||
```c
|
||
// Create sparse identity matrix
|
||
tm_tensor* dense_eye = tm_eye(1000, TM_F32); // 1000x1000 identity
|
||
tm_tensor* sparse = tm_to_sparse(dense_eye); // Only 1000 non-zeros stored
|
||
|
||
// Sparse-dense multiplication (efficient for large sparse matrices)
|
||
int64_t shape[] = {1000, 64};
|
||
tm_tensor* x = tm_randn(shape, 2, TM_F32);
|
||
tm_tensor* result = tm_spmm(sparse, x); // I @ x = x
|
||
|
||
tm_free(result);
|
||
tm_free(x);
|
||
tm_free(sparse);
|
||
tm_free(dense_eye);
|
||
```
|
||
|
||
---
|
||
|
||
## Differences from PyTorch
|
||
|
||
| Feature | PyTorch | Foundry | Why |
|
||
|---------|---------|---------|-----|
|
||
| Device | CPU/CUDA/MPS | CPU only | GPU requires writing CUDA/Metal kernels for every op. Planned. |
|
||
| Autocast | Yes | No | Mixed-precision casting. Planned after GPU support. |
|
||
| torch.compile | Yes | N/A | PyTorch's JIT for Python. Foundry is already compiled C code. |
|
||
| In-place grad | Yes | **Yes** | All in-place ops (add_, mul_, exp_, relu_, etc.) support autograd. |
|
||
| Sparse | Yes | **Yes** | COO and CSR formats with spmm, spmv, and sparse arithmetic. |
|
||
|
||
---
|
||
|
||
## See Also
|
||
|
||
- [optim](optim.md) - Optimizers for training
|
||
- [attention](attention.md) - Attention with tensor operations
|
||
- [Examples](examples.md) - Complete training examples
|