Matrix

Struct Matrix 

Source
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>

Source

pub fn new(rows: usize, cols: usize) -> Matrix<f32>

Creates a new matrix with uninitialized values

§Arguments
  • rows - Number of rows
  • cols - Number of columns
§Returns

A new matrix with dimensions rows x cols containing uninitialized values

§Example
use trueno::Matrix;

let m = Matrix::new(3, 4);
assert_eq!(m.rows(), 3);
assert_eq!(m.cols(), 4);
Source

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 rows
  • cols - Number of columns
  • data - 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);
Source

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 rows
  • cols - Number of columns
  • data - 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));
Source

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));
Source

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));
Source

pub fn rows(&self) -> usize

Returns the number of rows

Source

pub fn cols(&self) -> usize

Returns the number of columns

Source

pub fn shape(&self) -> (usize, usize)

Returns the shape as (rows, cols)

Source

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

Source

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

Source

pub fn as_slice(&self) -> &[f32]

Returns a reference to the underlying data

Source

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));
Source

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 dimension
  • m - Rows of A (and output)
  • k - Columns of A / Rows of B
  • n - 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.

Source

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 dimension
  • heads - Number of attention heads
  • m - 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

Source

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));
Source

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 to self.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]);
Source

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 to m.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]);
Source

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);
Source

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 0
Source

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§

Source§

impl<T> Clone for Matrix<T>
where T: Clone,

Source§

fn clone(&self) -> Matrix<T>

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<T> Debug for Matrix<T>
where T: Debug,

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl<T> PartialEq for Matrix<T>
where T: PartialEq,

Source§

fn eq(&self, other: &Matrix<T>) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

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> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V