pub struct Matrix<T> { /* private fields */ }Expand description
A 2D matrix with row-major storage
Data is stored in row-major format (C-style), where consecutive elements in memory belong to the same row. This is compatible with NumPy’s default layout and optimal for cache locality when accessing rows.
§Storage Layout
For a 2x3 matrix:
[[a, b, c],
[d, e, f]]Data is stored as: [a, b, c, d, e, f]
§Example
use trueno::Matrix;
let m = Matrix::from_vec(2, 2, vec![1.0, 2.0, 3.0, 4.0]).unwrap();
assert_eq!(m.get(0, 0), Some(&1.0));
assert_eq!(m.get(0, 1), Some(&2.0));
assert_eq!(m.get(1, 0), Some(&3.0));
assert_eq!(m.get(1, 1), Some(&4.0));Implementations§
Source§impl Matrix<f32>
impl Matrix<f32>
Sourcepub fn from_vec(
rows: usize,
cols: usize,
data: Vec<f32>,
) -> Result<Matrix<f32>, TruenoError>
pub fn from_vec( rows: usize, cols: usize, data: Vec<f32>, ) -> Result<Matrix<f32>, TruenoError>
Creates a matrix from a vector of data
§Arguments
rows- Number of rowscols- Number of columnsdata- Vector containing matrix elements in row-major order
§Errors
Returns InvalidInput if data.len() != rows * cols
§Example
use trueno::Matrix;
let m = Matrix::from_vec(2, 2, vec![1.0, 2.0, 3.0, 4.0]).unwrap();
assert_eq!(m.rows(), 2);
assert_eq!(m.cols(), 2);Sourcepub fn from_slice(
rows: usize,
cols: usize,
data: &[f32],
) -> Result<Matrix<f32>, TruenoError>
pub fn from_slice( rows: usize, cols: usize, data: &[f32], ) -> Result<Matrix<f32>, TruenoError>
Creates a matrix from a slice by copying the data
This is a convenience method that copies the slice into an owned vector.
For zero-copy scenarios, consider using the data directly with from_vec
if you already have an owned Vec.
§Arguments
rows- Number of rowscols- Number of columnsdata- Slice containing matrix elements in row-major order
§Errors
Returns InvalidInput if data.len() != rows * cols
§Example
use trueno::Matrix;
let data = [1.0, 2.0, 3.0, 4.0];
let m = Matrix::from_slice(2, 2, &data).unwrap();
assert_eq!(m.get(0, 0), Some(&1.0));Sourcepub fn zeros(rows: usize, cols: usize) -> Matrix<f32>
pub fn zeros(rows: usize, cols: usize) -> Matrix<f32>
Creates a matrix filled with zeros
§Example
use trueno::Matrix;
let m = Matrix::zeros(3, 3);
assert_eq!(m.get(1, 1), Some(&0.0));Sourcepub fn identity(n: usize) -> Matrix<f32>
pub fn identity(n: usize) -> Matrix<f32>
Creates an identity matrix (square matrix with 1s on diagonal)
§Example
use trueno::Matrix;
let m = Matrix::identity(3);
assert_eq!(m.get(0, 0), Some(&1.0));
assert_eq!(m.get(0, 1), Some(&0.0));
assert_eq!(m.get(1, 1), Some(&1.0));Sourcepub fn get(&self, row: usize, col: usize) -> Option<&f32>
pub fn get(&self, row: usize, col: usize) -> Option<&f32>
Gets a reference to an element at (row, col)
Returns None if indices are out of bounds
Sourcepub fn get_mut(&mut self, row: usize, col: usize) -> Option<&mut f32>
pub fn get_mut(&mut self, row: usize, col: usize) -> Option<&mut f32>
Gets a mutable reference to an element at (row, col)
Returns None if indices are out of bounds
Sourcepub fn matmul(&self, other: &Matrix<f32>) -> Result<Matrix<f32>, TruenoError>
pub fn matmul(&self, other: &Matrix<f32>) -> Result<Matrix<f32>, TruenoError>
Matrix multiplication (matmul)
Computes C = A × B where A is m×n, B is n×p, and C is m×p.
§Arguments
other- The matrix to multiply with (right operand)
§Returns
A new matrix containing the result of matrix multiplication
§Errors
Returns InvalidInput if matrix dimensions are incompatible
(i.e., self.cols != other.rows)
§Example
use trueno::Matrix;
let a = Matrix::from_vec(2, 2, vec![1.0, 2.0, 3.0, 4.0]).unwrap();
let b = Matrix::from_vec(2, 2, vec![5.0, 6.0, 7.0, 8.0]).unwrap();
let c = a.matmul(&b).unwrap();
// [[1, 2], [[5, 6], [[19, 22],
// [3, 4]] × [7, 8]] = [43, 50]]
assert_eq!(c.get(0, 0), Some(&19.0));
assert_eq!(c.get(0, 1), Some(&22.0));
assert_eq!(c.get(1, 0), Some(&43.0));
assert_eq!(c.get(1, 1), Some(&50.0));Sourcepub fn batched_matmul(
a_data: &[f32],
b_data: &[f32],
batch: usize,
m: usize,
k: usize,
n: usize,
) -> Result<Vec<f32>, TruenoError>
pub fn batched_matmul( a_data: &[f32], b_data: &[f32], batch: usize, m: usize, k: usize, n: usize, ) -> Result<Vec<f32>, TruenoError>
Batched matrix multiplication for 3D tensors.
Computes [batch, m, k] @ [batch, k, n] -> [batch, m, n] using SIMD for each batch.
This is critical for transformer attention performance.
§Arguments
a_data- Flattened input A with shape [batch, m, k]b_data- Flattened input B with shape [batch, k, n]batch- Batch dimensionm- Rows of A (and output)k- Columns of A / Rows of Bn- Columns of B (and output)
§Returns
Flattened output with shape [batch, m, n]
§Performance
Uses SIMD matmul for each batch slice, achieving ~50 GFLOPS vs ~0.1 GFLOPS naive. See Williams et al., 2009 (Roofline model) for theoretical analysis.
Sourcepub fn batched_matmul_4d(
a_data: &[f32],
b_data: &[f32],
batch: usize,
heads: usize,
m: usize,
k: usize,
n: usize,
) -> Result<Vec<f32>, TruenoError>
pub fn batched_matmul_4d( a_data: &[f32], b_data: &[f32], batch: usize, heads: usize, m: usize, k: usize, n: usize, ) -> Result<Vec<f32>, TruenoError>
Batched matrix multiplication for 4D tensors (attention pattern).
Computes [batch, heads, m, k] @ [batch, heads, k, n] -> [batch, heads, m, n]
This is the exact pattern used in multi-head attention: Q @ K^T and attn @ V.
§Arguments
a_data- Flattened input A with shape [batch, heads, m, k]b_data- Flattened input B with shape [batch, heads, k, n]batch- Batch dimensionheads- Number of attention headsm- Rows (sequence length for Q)k- Columns of A / Rows of B (head dimension)n- Columns of B (sequence length for K^T, or head dim for V)
§Performance
Processes batch×heads independent matmuls using SIMD. For Qwen2-0.5B: batch=1, heads=14, m=seq, k=64, n=seq
Sourcepub fn transpose(&self) -> Matrix<f32>
pub fn transpose(&self) -> Matrix<f32>
Transpose the matrix (swap rows and columns)
Returns a new matrix where element (i, j) of the original becomes
element (j, i) in the result.
§Returns
A new matrix with dimensions swapped: if input is m×n, output is n×m
§Example
use trueno::Matrix;
let m = Matrix::from_vec(2, 3, vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]).unwrap();
let t = m.transpose();
// [[1, 2, 3], [[1, 4],
// [4, 5, 6]] → [2, 5],
// [3, 6]]
assert_eq!(t.rows(), 3);
assert_eq!(t.cols(), 2);
assert_eq!(t.get(0, 0), Some(&1.0));
assert_eq!(t.get(0, 1), Some(&4.0));
assert_eq!(t.get(1, 0), Some(&2.0));Sourcepub fn matvec(&self, v: &Vector<f32>) -> Result<Vector<f32>, TruenoError>
pub fn matvec(&self, v: &Vector<f32>) -> Result<Vector<f32>, TruenoError>
Matrix-vector multiplication (column vector): A × v
Multiplies this matrix by a column vector, computing A × v where the result
is a column vector with length equal to the number of rows in A.
§Mathematical Definition
For an m×n matrix A and an n-dimensional vector v:
result[i] = Σ(j=0 to n-1) A[i,j] × v[j]§Arguments
v- Column vector with length equal toself.cols()
§Returns
A new vector with length self.rows()
§Errors
Returns InvalidInput if v.len() != self.cols()
§Example
use trueno::{Matrix, Vector};
let m = Matrix::from_vec(2, 3, vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]).unwrap();
let v = Vector::from_slice(&[1.0, 2.0, 3.0]);
let result = m.matvec(&v).unwrap();
// [[1, 2, 3] [1] [1×1 + 2×2 + 3×3] [14]
// [4, 5, 6]] × [2] = [4×1 + 5×2 + 6×3] = [32]
// [3]
assert_eq!(result.as_slice(), &[14.0, 32.0]);Sourcepub fn vecmat(
v: &Vector<f32>,
m: &Matrix<f32>,
) -> Result<Vector<f32>, TruenoError>
pub fn vecmat( v: &Vector<f32>, m: &Matrix<f32>, ) -> Result<Vector<f32>, TruenoError>
Vector-matrix multiplication (row vector): v^T × A
Multiplies a row vector by this matrix, computing v^T × A where the result
is a row vector with length equal to the number of columns in A.
§Mathematical Definition
For an m-dimensional vector v and an m×n matrix A:
result[j] = Σ(i=0 to m-1) v[i] × A[i,j]§Arguments
v- Row vector with length equal tom.rows()m- Matrix to multiply
§Returns
A new vector with length m.cols()
§Errors
Returns InvalidInput if v.len() != m.rows()
§Example
use trueno::{Matrix, Vector};
let m = Matrix::from_vec(2, 3, vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]).unwrap();
let v = Vector::from_slice(&[1.0, 2.0]);
let result = Matrix::vecmat(&v, &m).unwrap();
// [1, 2] × [[1, 2, 3] = [1×1 + 2×4, 1×2 + 2×5, 1×3 + 2×6]
// [4, 5, 6]]
// = [9, 12, 15]
assert_eq!(result.as_slice(), &[9.0, 12.0, 15.0]);Sourcepub fn convolve2d(
&self,
kernel: &Matrix<f32>,
) -> Result<Matrix<f32>, TruenoError>
pub fn convolve2d( &self, kernel: &Matrix<f32>, ) -> Result<Matrix<f32>, TruenoError>
Perform 2D convolution with a kernel
Applies a 2D convolution operation using “valid” padding (no padding), resulting in an output smaller than the input.
§Arguments
kernel- Convolution kernel (filter) to apply
§Returns
Convolved matrix with dimensions:
- rows:
input.rows - kernel.rows + 1 - cols:
input.cols - kernel.cols + 1
§Errors
Returns InvalidInput if:
- Kernel is larger than input in any dimension
- Kernel has even dimensions (center pixel ambiguous)
§Example
use trueno::Matrix;
// 5x5 input image
let input = Matrix::from_vec(
5, 5,
vec![
0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 9.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0,
]
).unwrap();
// 3x3 averaging kernel
let kernel_val = 1.0 / 9.0;
let kernel = Matrix::from_vec(
3, 3,
vec![kernel_val; 9]
).unwrap();
let result = input.convolve2d(&kernel).unwrap();
assert_eq!(result.rows(), 3); // 5 - 3 + 1
assert_eq!(result.cols(), 3);Sourcepub fn embedding_lookup(
&self,
indices: &[usize],
) -> Result<Matrix<f32>, TruenoError>
pub fn embedding_lookup( &self, indices: &[usize], ) -> Result<Matrix<f32>, TruenoError>
Lookup embeddings by indices (Issue #61: ML primitives)
Performs embedding lookup where self is the embedding table with shape
[vocab_size, embed_dim] and indices specify which rows to select.
§Arguments
indices- Slice of indices into the embedding table
§Returns
A matrix with shape [indices.len(), embed_dim] containing the selected rows
§Errors
Returns InvalidInput if any index is out of bounds
§Example
use trueno::Matrix;
// Create embedding table: 4 words, 3-dimensional embeddings
let embeddings = Matrix::from_vec(4, 3, vec![
1.0, 2.0, 3.0, // word 0
4.0, 5.0, 6.0, // word 1
7.0, 8.0, 9.0, // word 2
10.0, 11.0, 12.0 // word 3
]).unwrap();
// Lookup embeddings for indices [1, 3, 0]
let result = embeddings.embedding_lookup(&[1, 3, 0]).unwrap();
assert_eq!(result.rows(), 3);
assert_eq!(result.cols(), 3);
assert_eq!(result.get(0, 0), Some(&4.0)); // word 1
assert_eq!(result.get(1, 0), Some(&10.0)); // word 3
assert_eq!(result.get(2, 0), Some(&1.0)); // word 0Sourcepub fn embedding_lookup_sparse(
&self,
indices: &[usize],
) -> Result<(Matrix<f32>, Vec<usize>), TruenoError>
pub fn embedding_lookup_sparse( &self, indices: &[usize], ) -> Result<(Matrix<f32>, Vec<usize>), TruenoError>
Lookup embeddings with gradient tracking support (for training)
Returns both the embeddings and a sparse gradient accumulator. This is useful for sparse gradient updates in training.
§Arguments
indices- Slice of indices into the embedding table
§Returns
Tuple of (embeddings, unique_indices) where unique_indices can be used for sparse gradient updates
§Errors
Returns InvalidInput if any index is out of bounds
Trait Implementations§
impl<T> StructuralPartialEq for Matrix<T>
Auto Trait Implementations§
impl<T> Freeze for Matrix<T>
impl<T> RefUnwindSafe for Matrix<T>where
T: RefUnwindSafe,
impl<T> Send for Matrix<T>where
T: Send,
impl<T> Sync for Matrix<T>where
T: Sync,
impl<T> Unpin for Matrix<T>where
T: Unpin,
impl<T> UnwindSafe for Matrix<T>where
T: UnwindSafe,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more