Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Operators and broadcasting

matten implements element-wise arithmetic for borrowed tensors with NumPy-style right-aligned broadcasting. All results are new owned tensors; operands are never mutated.

Element-wise operators

#![allow(unused)]
fn main() {
use matten::Tensor;

let a = Tensor::new(vec![1.0, 2.0, 3.0, 4.0], &[2, 2]);
let b = Tensor::full(&[2, 2], 10.0);

let c = &a + &b;  // [11.0, 12.0, 13.0, 14.0]
let d = &a - &b;  // [-9.0, -8.0, -7.0, -6.0]
let e = &a * &b;  // [10.0, 20.0, 30.0, 40.0]  ← element-wise, not matmul
let f = &a / &b;  // [0.1,  0.2,  0.3,  0.4]
let g = -&a;       // [-1.0, -2.0, -3.0, -4.0]
}

* is always element-wise. Matrix multiplication is explicit via matmul / dot.

Scalar operators

All eight scalar forms are supported:

#![allow(unused)]
fn main() {
let t = Tensor::new(vec![1.0, 2.0, 3.0], &[3]);

// tensor on left
let r = &t + 10.0;   // [11.0, 12.0, 13.0]
let r = &t * 2.0;    // [2.0, 4.0, 6.0]

// scalar on left
let r = 10.0 + &t;   // [11.0, 12.0, 13.0]
let r = 2.0 * &t;    // [2.0, 4.0, 6.0]
}

Broadcasting rules

Shapes are compatible when aligned from the right and each dimension pair satisfies one of:

  • dimensions are equal;
  • one dimension is 1 (it broadcasts to match the other);
  • one operand has fewer dimensions (the missing leading axes are treated as 1).
LeftRightResult
[][3, 4][3, 4] — scalar broadcasts everywhere
[4][3, 4][3, 4] — row vector broadcasts across rows
[3, 1][1, 4][3, 4] — outer product pattern
[2, 3][2]incompatible — panics
#![allow(unused)]
fn main() {
// bias addition: add a [3] bias vector to every row of a [2, 3] matrix
let matrix = Tensor::new(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0], &[2, 3]);
let bias   = Tensor::new(vec![10.0, 20.0, 30.0], &[3]);
let result = &matrix + &bias;
// [[11.0, 22.0, 33.0],
//  [14.0, 25.0, 36.0]]
}

Incompatible shapes

Incompatible shapes panic in operator code with an actionable message:

matten broadcast error in add: shapes [2, 3] and [2] are not compatible

IEEE 754 semantics

matten does not intercept NaN or inf:

  • Division by zero produces inf, -inf, or NaN per IEEE 754.
  • NaN propagates through all arithmetic.
  • No silent sanitisation.

No intermediate copies

The broadcast implementation maps result coordinates directly to source element indices using zero-stride tricks. No expanded broadcast copies of the operands are allocated.

Elementwise comfort math (RFC-038)

Beyond the operators above, Tensor provides a few familiar elementwise transforms. Each preserves shape, follows ordinary f64 NaN/Inf behavior, and panics on dynamic tensors (call try_numeric() first):

MethodEffect
abs()absolute value
sqrt()square root (negative → NaN)
exp()e^x
ln()natural log (ln(0.0)-inf, negative → NaN)
clip(min, max)clamp each element into [min, max]
#![allow(unused)]
fn main() {
use matten::Tensor;
let t = Tensor::from_vec(vec![-5.0, 0.5, 9.0]);
assert_eq!(t.clip(0.0, 1.0).as_slice(), &[0.0, 0.5, 1.0]);
}

clip panics if min > max; try_clip(min, max) returns MattenError::InvalidArgument instead (or MattenError::Unsupported on a dynamic tensor).