Foundry/tensor/tensor.h

857 lines
31 KiB
C

/* SPDX-License-Identifier: AGPL-3.0-or-later */
/* Copyright (C) 2026 David (Corey) Herrera */
#ifndef FOUNDRY_TENSOR_H
#define FOUNDRY_TENSOR_H
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* Tensor operations with automatic differentiation.
* Replaces PyTorch core functionality.
*/
#define TM_MAX_DIMS 8
/* Data types */
typedef enum {
TM_F32, /* float32 - default */
TM_F64, /* float64 */
TM_F16, /* float16 */
TM_BF16, /* bfloat16 */
TM_I32, /* int32 */
TM_I64, /* int64 */
} tm_dtype;
/* Sparse formats */
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;
/* Forward declarations */
typedef struct tm_tensor tm_tensor;
typedef struct tm_grad_fn tm_grad_fn;
/* Gradient function - computes gradients during backward pass */
struct tm_grad_fn {
void (*backward)(tm_tensor* out); /* Backward function */
tm_tensor* inputs[2]; /* Input tensors (for binary ops) */
int num_inputs;
void* ctx; /* Optional context */
};
/* Tensor structure */
struct tm_tensor {
void* data; /* Raw data pointer */
int64_t shape[TM_MAX_DIMS]; /* Shape of each dimension */
int64_t strides[TM_MAX_DIMS]; /* Strides in elements */
int ndim; /* Number of dimensions */
int64_t numel; /* Total number of elements */
tm_dtype dtype; /* Data type */
/* Autograd */
bool requires_grad; /* Track gradients? */
tm_tensor* grad; /* Gradient tensor */
tm_grad_fn* grad_fn; /* How to compute gradient */
/* Memory management */
int refcount; /* Reference count */
bool owns_data; /* Do we own the data? */
/* Sparse tensor support */
bool is_sparse; /* Is this a sparse tensor? */
tm_sparse_format sparse_format; /* COO or CSR */
int64_t nnz; /* Number of non-zero elements */
int64_t* indices; /* COO: [2, nnz] for 2D (row, col indices) */
int64_t* row_ptr; /* CSR: [rows + 1] row pointers */
int64_t* col_ind; /* CSR: [nnz] column indices */
};
/* ============================================================= */
/* Tensor Creation */
/* ============================================================= */
/* Create tensor with uninitialized data */
tm_tensor* tm_empty(int64_t* shape, int ndim, tm_dtype dtype);
/* Create tensor filled with zeros */
tm_tensor* tm_zeros(int64_t* shape, int ndim, tm_dtype dtype);
/* Create tensor filled with ones */
tm_tensor* tm_ones(int64_t* shape, int ndim, tm_dtype dtype);
/* Create tensor filled with value */
tm_tensor* tm_full(int64_t* shape, int ndim, tm_dtype dtype, double value);
/* Create tensor from existing data (does not copy) */
tm_tensor* tm_from_data(void* data, int64_t* shape, int ndim, tm_dtype dtype);
/* Create tensor with random normal values */
tm_tensor* tm_randn(int64_t* shape, int ndim, tm_dtype dtype);
/* Create tensor with random uniform values [0, 1) */
tm_tensor* tm_rand(int64_t* shape, int ndim, tm_dtype dtype);
/* Clone tensor (deep copy) */
tm_tensor* tm_clone(tm_tensor* t);
/* Create tensor with range of values [start, end) with step */
tm_tensor* tm_arange(double start, double end, double step, tm_dtype dtype);
/* Create tensor with random integers in [low, high) */
tm_tensor* tm_randint(int64_t low, int64_t high, int64_t* shape, int ndim);
/* Create identity matrix */
tm_tensor* tm_eye(int64_t n, tm_dtype dtype);
/* Create linearly spaced values */
tm_tensor* tm_linspace(double start, double end, int64_t steps, tm_dtype dtype);
/* Like functions - create tensor with same shape/dtype as input */
tm_tensor* tm_full_like(tm_tensor* t, double value);
tm_tensor* tm_empty_like(tm_tensor* t);
tm_tensor* tm_rand_like(tm_tensor* t);
tm_tensor* tm_randn_like(tm_tensor* t);
/* ============================================================= */
/* Memory Management */
/* ============================================================= */
/* Increment reference count */
tm_tensor* tm_retain(tm_tensor* t);
/* Decrement reference count, free if zero */
void tm_release(tm_tensor* t);
/* Convenience alias */
#define tm_free(t) tm_release(t)
/* ============================================================= */
/* Accessors */
/* ============================================================= */
/* Get element at index (1D) */
float tm_get_f32(tm_tensor* t, int64_t i);
double tm_get_f64(tm_tensor* t, int64_t i);
int32_t tm_get_i32(tm_tensor* t, int64_t i);
/* Set element at index (1D) */
void tm_set_f32(tm_tensor* t, int64_t i, float val);
void tm_set_f64(tm_tensor* t, int64_t i, double val);
void tm_set_i32(tm_tensor* t, int64_t i, int32_t val);
/* Get pointer to data */
float* tm_data_f32(tm_tensor* t);
double* tm_data_f64(tm_tensor* t);
/* Get size info */
int64_t tm_numel(tm_tensor* t);
int tm_ndim(tm_tensor* t);
int64_t tm_size(tm_tensor* t, int dim);
size_t tm_dtype_size(tm_dtype dtype);
/* ============================================================= */
/* Shape Operations */
/* ============================================================= */
/* Reshape (returns new view if possible, otherwise copies) */
tm_tensor* tm_reshape(tm_tensor* t, int64_t* shape, int ndim);
/* View (alias for reshape, for PyTorch compatibility) */
tm_tensor* tm_view(tm_tensor* t, int64_t* shape, int ndim);
/* Transpose (swap two dimensions) */
tm_tensor* tm_transpose(tm_tensor* t, int dim0, int dim1);
/* Permute dimensions (generalized transpose) */
tm_tensor* tm_permute(tm_tensor* t, int* dims, int ndim);
/* Squeeze (remove dimensions of size 1) */
tm_tensor* tm_squeeze(tm_tensor* t, int dim);
/* Unsqueeze (add dimension of size 1) */
tm_tensor* tm_unsqueeze(tm_tensor* t, int dim);
/* Flatten dimensions from start_dim to end_dim (inclusive) */
tm_tensor* tm_flatten(tm_tensor* t, int start_dim, int end_dim);
/* Select along dimension (reduces ndim by 1) */
tm_tensor* tm_select(tm_tensor* t, int dim, int64_t index);
/* Contiguous (ensure data is contiguous in memory) */
tm_tensor* tm_contiguous(tm_tensor* t);
/* Check if contiguous */
bool tm_is_contiguous(tm_tensor* t);
/* Concatenate tensors along dimension */
tm_tensor* tm_cat(tm_tensor** tensors, int num_tensors, int dim);
/* Stack tensors along new dimension */
tm_tensor* tm_stack(tm_tensor** tensors, int num_tensors, int dim);
/* Split tensor into chunks along dimension */
tm_tensor** tm_split(tm_tensor* t, int64_t split_size, int dim, int* num_chunks);
/* Split tensor into n equal chunks along dimension */
tm_tensor** tm_chunk(tm_tensor* t, int num_chunks, int dim, int* actual_chunks);
/* Narrow (slice) along dimension */
tm_tensor* tm_narrow(tm_tensor* t, int dim, int64_t start, int64_t length);
/* Expand tensor to new shape (broadcasting) */
tm_tensor* tm_expand(tm_tensor* t, int64_t* shape, int ndim);
/* Repeat tensor along dimensions */
tm_tensor* tm_repeat(tm_tensor* t, int64_t* repeats, int ndim);
/* Flip tensor along dimensions */
tm_tensor* tm_flip(tm_tensor* t, int* dims, int ndim);
/* Roll (circular shift) tensor */
tm_tensor* tm_roll(tm_tensor* t, int64_t shift, int dim);
/* 2D transpose alias */
tm_tensor* tm_t(tm_tensor* t);
/* ============================================================= */
/* Indexing Operations */
/* ============================================================= */
/* Gather elements along dimension using index tensor */
tm_tensor* tm_gather(tm_tensor* t, int dim, tm_tensor* index);
/* Scatter elements along dimension using index tensor */
tm_tensor* tm_scatter(tm_tensor* t, int dim, tm_tensor* index, tm_tensor* src);
/* Select elements along dimension using index tensor */
tm_tensor* tm_index_select(tm_tensor* t, int dim, tm_tensor* index);
/* Scatter with addition */
tm_tensor* tm_scatter_add(tm_tensor* t, int dim, tm_tensor* index, tm_tensor* src);
/* Select elements where mask is true */
tm_tensor* tm_masked_select(tm_tensor* t, tm_tensor* mask);
/* Get indices of non-zero elements */
tm_tensor* tm_nonzero(tm_tensor* t);
/* Fill at indices */
tm_tensor* tm_index_fill(tm_tensor* t, int dim, tm_tensor* index, float value);
/* Copy to indices */
tm_tensor* tm_index_copy(tm_tensor* t, int dim, tm_tensor* index, tm_tensor* src);
/* Add at indices */
tm_tensor* tm_index_add(tm_tensor* t, int dim, tm_tensor* index, tm_tensor* src);
/* Take elements by flat indices */
tm_tensor* tm_take(tm_tensor* t, tm_tensor* indices);
/* ============================================================= */
/* Element-wise Operations */
/* ============================================================= */
/* Binary ops */
tm_tensor* tm_add(tm_tensor* a, tm_tensor* b);
tm_tensor* tm_sub(tm_tensor* a, tm_tensor* b);
tm_tensor* tm_mul(tm_tensor* a, tm_tensor* b);
tm_tensor* tm_div(tm_tensor* a, tm_tensor* b);
/* Scalar ops */
tm_tensor* tm_add_scalar(tm_tensor* a, double s);
tm_tensor* tm_sub_scalar(tm_tensor* a, double s);
tm_tensor* tm_mul_scalar(tm_tensor* a, double s);
tm_tensor* tm_div_scalar(tm_tensor* a, double s);
/* Unary ops */
tm_tensor* tm_neg(tm_tensor* a);
tm_tensor* tm_abs(tm_tensor* a);
tm_tensor* tm_exp(tm_tensor* a);
tm_tensor* tm_log(tm_tensor* a);
tm_tensor* tm_sqrt(tm_tensor* a);
tm_tensor* tm_rsqrt(tm_tensor* a);
tm_tensor* tm_pow(tm_tensor* a, double exponent);
tm_tensor* tm_sin(tm_tensor* a);
tm_tensor* tm_cos(tm_tensor* a);
tm_tensor* tm_tanh(tm_tensor* a);
tm_tensor* tm_relu(tm_tensor* a);
tm_tensor* tm_sigmoid(tm_tensor* a);
tm_tensor* tm_gelu(tm_tensor* a);
tm_tensor* tm_silu(tm_tensor* a);
/* Clamp values */
tm_tensor* tm_clamp(tm_tensor* a, double min_val, double max_val);
/* Conditional operations */
tm_tensor* tm_where(tm_tensor* condition, tm_tensor* a, tm_tensor* b);
tm_tensor* tm_masked_fill(tm_tensor* t, tm_tensor* mask, float value);
/* Element-wise max/min */
tm_tensor* tm_maximum(tm_tensor* a, tm_tensor* b);
tm_tensor* tm_minimum(tm_tensor* a, tm_tensor* b);
/* Comparison operations (return boolean tensors as TM_I32) */
tm_tensor* tm_eq(tm_tensor* a, tm_tensor* b);
tm_tensor* tm_ne(tm_tensor* a, tm_tensor* b);
tm_tensor* tm_lt(tm_tensor* a, tm_tensor* b);
tm_tensor* tm_le(tm_tensor* a, tm_tensor* b);
tm_tensor* tm_gt(tm_tensor* a, tm_tensor* b);
tm_tensor* tm_ge(tm_tensor* a, tm_tensor* b);
/* Check for special values */
tm_tensor* tm_isnan(tm_tensor* t);
tm_tensor* tm_isinf(tm_tensor* t);
/* Leaky ReLU activation */
tm_tensor* tm_leaky_relu(tm_tensor* a, float negative_slope);
/* ELU activation */
tm_tensor* tm_elu(tm_tensor* a, float alpha);
/* Rounding operations */
tm_tensor* tm_floor(tm_tensor* a);
tm_tensor* tm_ceil(tm_tensor* a);
tm_tensor* tm_round(tm_tensor* a);
tm_tensor* tm_trunc(tm_tensor* a);
/* Sign and reciprocal */
tm_tensor* tm_sign(tm_tensor* a);
tm_tensor* tm_reciprocal(tm_tensor* a);
/* Additional math functions */
tm_tensor* tm_log2(tm_tensor* a);
tm_tensor* tm_log10(tm_tensor* a);
tm_tensor* tm_exp2(tm_tensor* a);
tm_tensor* tm_expm1(tm_tensor* a);
tm_tensor* tm_log1p(tm_tensor* a);
tm_tensor* tm_tan(tm_tensor* a);
tm_tensor* tm_asin(tm_tensor* a);
tm_tensor* tm_acos(tm_tensor* a);
tm_tensor* tm_atan(tm_tensor* a);
tm_tensor* tm_sinh(tm_tensor* a);
tm_tensor* tm_cosh(tm_tensor* a);
/* Fused operations */
tm_tensor* tm_addcmul(tm_tensor* t, tm_tensor* a, tm_tensor* b, double value);
tm_tensor* tm_addcdiv(tm_tensor* t, tm_tensor* a, tm_tensor* b, double value);
tm_tensor* tm_lerp(tm_tensor* a, tm_tensor* b, double weight);
/* Logical operations */
tm_tensor* tm_logical_and(tm_tensor* a, tm_tensor* b);
tm_tensor* tm_logical_or(tm_tensor* a, tm_tensor* b);
tm_tensor* tm_logical_not(tm_tensor* a);
tm_tensor* tm_logical_xor(tm_tensor* a, tm_tensor* b);
/* Check functions */
tm_tensor* tm_isfinite(tm_tensor* t);
bool tm_equal(tm_tensor* a, tm_tensor* b);
bool tm_allclose(tm_tensor* a, tm_tensor* b, double rtol, double atol);
/* ============================================================= */
/* Matrix Operations */
/* ============================================================= */
/* Matrix multiplication */
tm_tensor* tm_matmul(tm_tensor* a, tm_tensor* b);
/* Batched matrix multiplication */
tm_tensor* tm_bmm(tm_tensor* a, tm_tensor* b);
/* Matrix multiplication aliases */
tm_tensor* tm_mm(tm_tensor* a, tm_tensor* b);
/* Fused t + a @ b */
tm_tensor* tm_addmm(tm_tensor* t, tm_tensor* a, tm_tensor* b, double beta, double alpha);
/* Vector operations */
tm_tensor* tm_dot(tm_tensor* a, tm_tensor* b);
tm_tensor* tm_mv(tm_tensor* mat, tm_tensor* vec);
tm_tensor* tm_outer(tm_tensor* a, tm_tensor* b);
tm_tensor* tm_inner(tm_tensor* a, tm_tensor* b);
/* ============================================================= */
/* Reduction Operations */
/* ============================================================= */
/* Sum over dimension (dim=-1 means all) */
tm_tensor* tm_sum(tm_tensor* t, int dim, bool keepdim);
/* Mean over dimension */
tm_tensor* tm_mean(tm_tensor* t, int dim, bool keepdim);
/* Max over dimension */
tm_tensor* tm_max(tm_tensor* t, int dim, bool keepdim);
/* Min over dimension */
tm_tensor* tm_min(tm_tensor* t, int dim, bool keepdim);
/* Argmax - index of maximum value */
tm_tensor* tm_argmax(tm_tensor* t, int dim, bool keepdim);
/* Argmin - index of minimum value */
tm_tensor* tm_argmin(tm_tensor* t, int dim, bool keepdim);
/* Log-sum-exp (numerically stable) */
tm_tensor* tm_logsumexp(tm_tensor* t, int dim, bool keepdim);
/* Cumulative sum along dimension */
tm_tensor* tm_cumsum(tm_tensor* t, int dim);
/* Standard deviation and variance */
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);
/* Product over dimension */
tm_tensor* tm_prod(tm_tensor* t, int dim, bool keepdim);
/* Cumulative product along dimension */
tm_tensor* tm_cumprod(tm_tensor* t, int dim);
/* Any/all along dimension */
tm_tensor* tm_any(tm_tensor* t, int dim, bool keepdim);
tm_tensor* tm_all(tm_tensor* t, int dim, bool keepdim);
/* Lp norm */
tm_tensor* tm_norm(tm_tensor* t, double p, int dim, bool keepdim);
/* Count non-zero elements */
tm_tensor* tm_count_nonzero(tm_tensor* t, int dim);
/* ============================================================= */
/* Type Conversion */
/* ============================================================= */
/* Convert tensor to different dtype */
tm_tensor* tm_to(tm_tensor* t, tm_dtype dtype);
/* Convenience type conversion functions */
tm_tensor* tm_float(tm_tensor* t); /* Convert to TM_F32 */
tm_tensor* tm_double(tm_tensor* t); /* Convert to TM_F64 */
tm_tensor* tm_half(tm_tensor* t); /* Convert to TM_F16 */
tm_tensor* tm_int(tm_tensor* t); /* Convert to TM_I32 */
tm_tensor* tm_long(tm_tensor* t); /* Convert to TM_I64 */
/* ============================================================= */
/* Neural Network Operations */
/* ============================================================= */
/* Softmax over dimension */
tm_tensor* tm_softmax(tm_tensor* t, int dim);
/* Log softmax */
tm_tensor* tm_log_softmax(tm_tensor* t, int dim);
/* Layer normalization */
tm_tensor* tm_layer_norm(tm_tensor* t, tm_tensor* weight, tm_tensor* bias, float eps);
/* Embedding lookup */
tm_tensor* tm_embedding(tm_tensor* weight, tm_tensor* indices);
/* Dropout (training mode) */
tm_tensor* tm_dropout(tm_tensor* t, float p, bool training);
/* RMS Normalization (used in Llama, modern LLMs) */
tm_tensor* tm_rms_norm(tm_tensor* t, tm_tensor* weight, float eps);
/* Linear layer: x @ weight.T + bias */
tm_tensor* tm_linear(tm_tensor* x, tm_tensor* weight, tm_tensor* bias);
/* Upper triangular matrix (for causal masks) */
tm_tensor* tm_triu(tm_tensor* t, int diagonal);
/* Lower triangular matrix */
tm_tensor* tm_tril(tm_tensor* t, int diagonal);
/* Hardswish activation: x * relu6(x + 3) / 6 */
tm_tensor* tm_hardswish(tm_tensor* t);
/* Hardtanh activation: clamp(x, min, max) */
tm_tensor* tm_hardtanh(tm_tensor* t, float min_val, float max_val);
/* GELU approximate (tanh approximation) */
tm_tensor* tm_gelu_approximate(tm_tensor* t);
/* Softplus: log(1 + exp(x)) */
tm_tensor* tm_softplus(tm_tensor* t, float beta, float threshold);
/* Mish activation: x * tanh(softplus(x)) */
tm_tensor* tm_mish(tm_tensor* t);
/* SELU activation: scale * (max(0,x) + min(0, alpha*(exp(x)-1))) */
tm_tensor* tm_selu(tm_tensor* t);
/* CELU activation: max(0,x) + min(0, alpha*(exp(x/alpha)-1)) */
tm_tensor* tm_celu(tm_tensor* t, float alpha);
/* ReLU6 activation: min(max(0,x), 6) */
tm_tensor* tm_relu6(tm_tensor* t);
/* GLU (Gated Linear Unit): a * sigmoid(b) where input split in half */
tm_tensor* tm_glu(tm_tensor* t, int dim);
/* Softsign activation: x / (1 + |x|) */
tm_tensor* tm_softsign(tm_tensor* t);
/* Tanhshrink activation: x - tanh(x) */
tm_tensor* tm_tanhshrink(tm_tensor* t);
/* Hardsigmoid: 0 if x<=-3, 1 if x>=3, else x/6 + 0.5 */
tm_tensor* tm_hardsigmoid(tm_tensor* t);
/* Threshold: x if x > threshold, else value */
tm_tensor* tm_threshold(tm_tensor* t, float threshold, float value);
/* Pad tensor (constant padding) */
tm_tensor* tm_pad(tm_tensor* t, int64_t* padding, int pad_len, float value);
/* Normalize (Lp normalization along dimension) */
tm_tensor* tm_normalize(tm_tensor* t, float p, int dim, float eps);
/* Interpolate/upsample (nearest neighbor) */
tm_tensor* tm_interpolate(tm_tensor* t, int64_t* size, int size_len, const char* mode);
/* Batch normalization: (x - mean) / sqrt(var + eps) * weight + bias */
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);
/* Group normalization */
tm_tensor* tm_group_norm(tm_tensor* t, int num_groups, tm_tensor* weight,
tm_tensor* bias, float eps);
/* Instance normalization */
tm_tensor* tm_instance_norm(tm_tensor* t, tm_tensor* weight, tm_tensor* bias, float eps);
/* Scaled dot-product attention:
* Q: [batch, heads, seq_q, head_dim]
* K: [batch, heads, seq_k, head_dim]
* V: [batch, heads, seq_k, head_dim]
* attn_mask: optional [batch, heads, seq_q, seq_k] or NULL
* Returns: [batch, heads, seq_q, head_dim] */
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);
/* Multi-head attention helper: split heads
* x: [batch, seq, embed_dim] -> [batch, heads, seq, head_dim] */
tm_tensor* tm_split_heads(tm_tensor* x, int num_heads);
/* Multi-head attention helper: merge heads
* x: [batch, heads, seq, head_dim] -> [batch, seq, embed_dim] */
tm_tensor* tm_merge_heads(tm_tensor* x);
/* 1D Convolution */
tm_tensor* tm_conv1d(tm_tensor* input, tm_tensor* weight, tm_tensor* bias,
int stride, int padding, int dilation, int groups);
/* 2D Convolution */
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);
/* 1D Average Pooling */
tm_tensor* tm_avg_pool1d(tm_tensor* input, int kernel_size, int stride, int padding);
/* 1D Max Pooling */
tm_tensor* tm_max_pool1d(tm_tensor* input, int kernel_size, int stride, int padding);
/* 2D Average Pooling */
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);
/* 2D Max Pooling */
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);
/* Adaptive Average Pooling 1D: output has shape [batch, channels, output_size] */
tm_tensor* tm_adaptive_avg_pool1d(tm_tensor* input, int output_size);
/* Adaptive Average Pooling 2D: output has shape [batch, channels, output_h, output_w] */
tm_tensor* tm_adaptive_avg_pool2d(tm_tensor* input, int output_h, int output_w);
/* ============================================================= */
/* Loss Functions */
/* ============================================================= */
/* Cross-entropy loss: logits [batch, classes], targets [batch] (class indices)
* Returns scalar loss tensor */
tm_tensor* tm_cross_entropy(tm_tensor* logits, tm_tensor* targets);
/* Cross-entropy loss with soft targets: both [batch, classes]
* Returns scalar loss tensor */
tm_tensor* tm_cross_entropy_soft(tm_tensor* logits, tm_tensor* targets);
/* Mean squared error loss: pred [*], target [*] (same shape)
* Returns scalar loss tensor */
tm_tensor* tm_mse_loss(tm_tensor* pred, tm_tensor* target);
/* L1 (MAE) loss: sum(|pred - target|) / n */
tm_tensor* tm_l1_loss(tm_tensor* pred, tm_tensor* target);
/* Smooth L1 (Huber) loss: 0.5*x^2/beta if |x| < beta, else |x| - 0.5*beta */
tm_tensor* tm_smooth_l1_loss(tm_tensor* pred, tm_tensor* target, float beta);
/* Negative log likelihood loss: expects log probabilities and class indices */
tm_tensor* tm_nll_loss(tm_tensor* log_probs, tm_tensor* targets);
/* KL divergence: KL(target || input), input is log probs, target is probs */
tm_tensor* tm_kl_div(tm_tensor* input, tm_tensor* target);
/* Binary cross entropy: for binary classification */
tm_tensor* tm_binary_cross_entropy(tm_tensor* pred, tm_tensor* target);
/* Binary cross entropy with logits: applies sigmoid internally */
tm_tensor* tm_binary_cross_entropy_with_logits(tm_tensor* logits, tm_tensor* target);
/* Huber loss: smooth combination of L1 and L2 */
tm_tensor* tm_huber_loss(tm_tensor* pred, tm_tensor* target, float delta);
/* Cosine embedding loss: for similarity/dissimilarity learning */
tm_tensor* tm_cosine_embedding_loss(tm_tensor* x1, tm_tensor* x2, tm_tensor* y, float margin);
/* Triplet margin loss: for metric learning */
tm_tensor* tm_triplet_margin_loss(tm_tensor* anchor, tm_tensor* positive, tm_tensor* negative, float margin, float p);
/* Cross entropy with label smoothing */
tm_tensor* tm_cross_entropy_label_smooth(tm_tensor* logits, tm_tensor* targets, float smoothing);
/* ============================================================= */
/* Linear Algebra */
/* ============================================================= */
/* Matrix inverse (Gauss-Jordan elimination) */
tm_tensor* tm_inverse(tm_tensor* t);
/* Determinant (LU decomposition) */
tm_tensor* tm_det(tm_tensor* t);
/* Singular Value Decomposition: returns [U, S, V] where A = U * diag(S) * V^T */
tm_tensor** tm_svd(tm_tensor* t, int* num_outputs);
/* Eigenvalues (QR iteration, symmetric matrices) */
tm_tensor* tm_eig(tm_tensor* t);
/* ============================================================= */
/* Autograd */
/* ============================================================= */
/* Enable gradient tracking */
void tm_set_requires_grad(tm_tensor* t, bool requires);
/* Compute gradients (backpropagation) */
void tm_backward(tm_tensor* loss);
/* Zero all gradients */
void tm_zero_grad(tm_tensor** params, int n);
/* Detach from computation graph */
tm_tensor* tm_detach(tm_tensor* t);
/* No-grad context (returns previous state) */
bool tm_no_grad_begin(void);
void tm_no_grad_end(bool prev);
/* Retain gradient for non-leaf tensors */
void tm_retain_grad(tm_tensor* t);
/* Compute gradient of outputs w.r.t. inputs explicitly */
tm_tensor** tm_grad(tm_tensor** outputs, int num_outputs, tm_tensor** inputs, int num_inputs,
tm_tensor** grad_outputs);
/* Gradient checkpointing: recompute forward during backward to save memory
* Note: Full memory savings only on GPU; CPU version runs forward directly */
tm_tensor* tm_checkpoint(tm_tensor* (*fn)(tm_tensor**, int, void*),
tm_tensor** inputs, int num_inputs, void* ctx);
/* ============================================================= */
/* Higher-Order Gradients */
/* ============================================================= */
/* Compute Hessian matrix of loss w.r.t. parameters using finite differences
* loss_fn: function that computes scalar loss from parameters
* Returns n x n Hessian matrix where n = total number of parameters */
tm_tensor* tm_hessian(tm_tensor** params, int num_params,
tm_tensor* (*loss_fn)(tm_tensor**, int, void*), void* ctx);
/* Hessian-vector product: H @ v without computing full Hessian
* More memory efficient than tm_hessian for large models
* Returns 1D tensor of length = total parameters */
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);
/* Jacobian-vector product (forward-mode AD)
* Computes J @ tangents where J is Jacobian of fn w.r.t. inputs
* Returns array of output tensors (use num_outputs_out to get count) */
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);
/* ============================================================= */
/* Custom Autograd Functions */
/* ============================================================= */
/* Custom context for saving tensors during forward pass */
typedef struct tm_custom_ctx tm_custom_ctx;
/* Custom autograd function definition */
typedef struct tm_autograd_function tm_autograd_function;
/* Create a new custom context */
tm_custom_ctx* tm_custom_ctx_new(void);
/* Save tensor for backward pass */
void tm_save_for_backward(tm_custom_ctx* ctx, tm_tensor* t);
/* Get saved tensors (returns array, sets num_saved) */
tm_tensor** tm_get_saved_tensors(tm_custom_ctx* ctx, int* num_saved);
/* Set/get user data in context */
void tm_custom_ctx_set_data(tm_custom_ctx* ctx, void* user_data);
void* tm_custom_ctx_get_data(tm_custom_ctx* ctx);
/* Free custom context */
void tm_custom_ctx_free(tm_custom_ctx* ctx);
/* Register a custom autograd function
* forward: takes inputs and context, returns output (save tensors to ctx)
* backward: takes grad_output and context, returns array of input gradients
* Returns function ID (>=0) on success, -1 on failure */
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*));
/* Apply a registered custom function by name */
tm_tensor* tm_apply_custom_function(const char* name, tm_tensor** inputs, int num_inputs);
/* Apply a registered custom function by ID (faster) */
tm_tensor* tm_apply_custom_function_id(int fn_id, tm_tensor** inputs, int num_inputs);
/* Clean up custom function registry */
void tm_cleanup_autograd_registry(void);
/* ============================================================= */
/* In-place Operations */
/* ============================================================= */
/* Create zeros tensor with same shape as input */
tm_tensor* tm_zeros_like(tm_tensor* t);
/* Create ones tensor with same shape as input */
tm_tensor* tm_ones_like(tm_tensor* t);
/* Fill tensor with value (in-place) */
void tm_fill_(tm_tensor* t, float value);
/* Add tensors in-place: a += b */
void tm_add_(tm_tensor* a, tm_tensor* b);
/* Scale tensor in-place: t *= s */
void tm_scale_(tm_tensor* t, float s);
/* Zero tensor in-place */
void tm_zero_(tm_tensor* t);
/* Copy data in-place: dst = src */
void tm_copy_(tm_tensor* dst, tm_tensor* src);
/* Clamp in-place */
void tm_clamp_(tm_tensor* t, float min_val, float max_val);
/* More in-place operations */
void tm_sub_(tm_tensor* a, tm_tensor* b);
void tm_mul_(tm_tensor* a, tm_tensor* b);
void tm_div_(tm_tensor* a, tm_tensor* b);
void tm_exp_(tm_tensor* t);
void tm_log_(tm_tensor* t);
void tm_sqrt_(tm_tensor* t);
void tm_abs_(tm_tensor* t);
void tm_neg_(tm_tensor* t);
void tm_relu_(tm_tensor* t);
void tm_sigmoid_(tm_tensor* t);
/* ============================================================= */
/* Sparse Tensor Operations */
/* ============================================================= */
/* Create sparse COO tensor from indices and values
* indices: [2, nnz] tensor of (row, col) pairs
* values: [nnz] tensor of non-zero values
* shape: dense shape [rows, cols] */
tm_tensor* tm_sparse_coo(tm_tensor* indices, tm_tensor* values, int64_t* shape, int ndim);
/* Create sparse CSR tensor from row_ptr, col_ind, and values
* row_ptr: [rows + 1] row pointers
* col_ind: [nnz] column indices
* values: [nnz] tensor of non-zero values
* shape: dense shape [rows, cols] */
tm_tensor* tm_sparse_csr(tm_tensor* row_ptr, tm_tensor* col_ind, tm_tensor* values,
int64_t* shape, int ndim);
/* Convert dense tensor to sparse COO format */
tm_tensor* tm_to_sparse(tm_tensor* t);
/* Convert dense tensor to sparse CSR format */
tm_tensor* tm_to_sparse_csr(tm_tensor* t);
/* Convert sparse tensor to dense */
tm_tensor* tm_to_dense(tm_tensor* t);
/* Check if tensor is sparse */
bool tm_is_sparse(tm_tensor* t);
/* Get number of non-zero elements */
int64_t tm_sparse_nnz(tm_tensor* t);
/* Get sparse format */
tm_sparse_format tm_get_sparse_format(tm_tensor* t);
/* Convert between sparse formats */
tm_tensor* tm_sparse_coo_to_csr(tm_tensor* t);
tm_tensor* tm_sparse_csr_to_coo(tm_tensor* t);
/* Sparse-dense matrix multiplication: sparse @ dense -> dense */
tm_tensor* tm_spmm(tm_tensor* sparse, tm_tensor* dense);
/* Sparse-sparse addition: sparse + sparse -> sparse */
tm_tensor* tm_sparse_add(tm_tensor* a, tm_tensor* b);
/* Sparse-scalar multiplication: sparse * scalar -> sparse */
tm_tensor* tm_sparse_mul_scalar(tm_tensor* t, double s);
/* Sparse matrix-vector multiplication: sparse @ vector -> vector */
tm_tensor* tm_spmv(tm_tensor* sparse, tm_tensor* vec);
/* Get values tensor from sparse tensor */
tm_tensor* tm_sparse_values(tm_tensor* t);
/* Get indices tensor from sparse COO tensor */
tm_tensor* tm_sparse_indices(tm_tensor* t);
/* Coalesce sparse tensor (combine duplicate indices) */
tm_tensor* tm_sparse_coalesce(tm_tensor* t);
/* ============================================================= */
/* Utility */
/* ============================================================= */
/* Print tensor info */
void tm_print(tm_tensor* t);
/* Print tensor with data */
void tm_print_data(tm_tensor* t);
/* Seed random number generator */
void tm_manual_seed(uint64_t seed);
#ifdef __cplusplus
}
#endif
#endif /* FOUNDRY_TENSOR_H */