Skip to main content

Tensor

Struct Tensor 

Source
pub struct Tensor { /* private fields */ }
Expand description

A dense, row-major, owned multidimensional array of f64.

Fields are private. The storage layout is never exposed across the public API. A scalar is shape [] with one element.

§Examples

use matten::Tensor;

// 2×2 matrix
let m = Tensor::new(vec![1.0, 2.0, 3.0, 4.0], &[2, 2]);
assert!(m.is_matrix());

// Fill constructors
let z = Tensor::zeros(&[3]);
assert_eq!(z.as_slice(), &[0.0, 0.0, 0.0]);

// Range constructor
let r = Tensor::arange(0.0, 5.0, 1.0);
assert_eq!(r.len(), 5);

Implementations§

Source§

impl Tensor

Source

pub fn linspace(start: f64, end: f64, count: usize) -> Tensor

Creates a 1-D tensor of count evenly spaced values from start to end (inclusive of both endpoints when count >= 2).

count == 1 returns [start]. Element values follow ordinary f64 behavior, so non-finite bounds propagate.

§Panics

Panics if count == 0 (a zero-sized dimension) or the result exceeds the allocation limit. Use Tensor::try_linspace for the non-panicking form.

use matten::Tensor;
assert_eq!(Tensor::linspace(0.0, 1.0, 5).as_slice(), &[0.0, 0.25, 0.5, 0.75, 1.0]);
assert_eq!(Tensor::linspace(2.0, 9.0, 1).as_slice(), &[2.0]);
Examples found in repository?
examples/40_trapezoidal_integration.rs (line 39)
37fn main() {
38    // Evenly spaced sample grid on [0, 1].
39    let x = Tensor::linspace(0.0, 1.0, 11);
40    let xs = x.as_slice();
41    let h = xs[1] - xs[0];
42
43    // f(x) = x^2, evaluated with elementwise multiplication.
44    let f = &x * &x;
45    let fs = f.as_slice();
46    let n = fs.len();
47
48    // Composite trapezoidal rule: h * (Σ f - (f_first + f_last)/2).
49    let estimate = h * (f.sum() - (fs[0] + fs[n - 1]) / 2.0);
50    let exact = 1.0 / 3.0; // ∫_0^1 x^2 dx = 1/3
51    let err = (estimate - exact).abs();
52
53    println!("trapezoidal estimate: {estimate:.6}");
54    println!("exact integral (1/3): {exact:.6}");
55    println!("abs error:            {err:.6}");
56
57    assert!(err < 0.01);
58    println!("Trapezoidal integration: OK");
59}
More examples
Hide additional examples
examples/39_finite_difference_derivative.rs (line 45)
43fn main() {
44    // Evenly spaced sample grid on [0, 2].
45    let x = Tensor::linspace(0.0, 2.0, 9);
46    let xs = x.as_slice();
47    let h = xs[1] - xs[0];
48
49    // f(x) = x^3, evaluated with elementwise Tensor multiplication.
50    let x2 = &x * &x;
51    let f = &x2 * &x;
52    let fs = f.as_slice();
53
54    println!("h = {h}");
55    println!("   x    f'approx   f'exact");
56    let mut max_err = 0.0f64;
57    for i in 1..xs.len() - 1 {
58        let approx = (fs[i + 1] - fs[i - 1]) / (2.0 * h);
59        let exact = 3.0 * xs[i] * xs[i]; // d/dx x^3 = 3x^2
60        let err = (approx - exact).abs();
61        max_err = max_err.max(err);
62        println!("{:4.2}     {:6.4}    {:6.4}", xs[i], approx, exact);
63        // Central difference of x^3 has error exactly h^2.
64        assert!((approx - (exact + h * h)).abs() < 1e-9);
65    }
66    println!("max abs error = {max_err:.4} (= h^2 = {:.4})", h * h);
67    assert!((max_err - h * h).abs() < 1e-9);
68    println!("Finite-difference derivative: OK");
69}
Source

pub fn try_linspace( start: f64, end: f64, count: usize, ) -> Result<Tensor, MattenError>

Non-panicking Tensor::linspace.

§Errors

Returns MattenError::Shape if count == 0, or MattenError::Allocation if the result exceeds the element limit.

use matten::Tensor;
assert!(Tensor::try_linspace(0.0, 1.0, 0).is_err());
Source

pub fn eye(n: usize) -> Tensor

Creates an n × n identity matrix (1.0 on the diagonal, 0.0 elsewhere).

§Panics

Panics if n == 0 (a zero-sized dimension) or the result exceeds the allocation limit. Use Tensor::try_eye for the non-panicking form.

use matten::Tensor;
let i = Tensor::eye(3);
assert_eq!(i.shape(), &[3, 3]);
assert_eq!(i.as_slice(), &[1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0]);
Source

pub fn try_eye(n: usize) -> Result<Tensor, MattenError>

Non-panicking Tensor::eye.

§Errors

Returns MattenError::Shape if n == 0, or MattenError::Allocation if the result exceeds the element limit.

use matten::Tensor;
assert!(Tensor::try_eye(0).is_err());
Source§

impl Tensor

Source

pub fn try_zeros(shape: &[usize]) -> Result<Tensor, MattenError>

Creates a zero tensor, returning an error instead of panicking.

Uses the default MattenLimits. For a custom budget use try_zeros_with_limits.

§Errors

Returns MattenError for invalid shape, overflow, or exceeding the default element budget.

§Examples
use matten::Tensor;

let t = Tensor::try_zeros(&[3, 4]).unwrap();
assert_eq!(t.shape(), &[3, 4]);
assert_eq!(t.as_slice(), &[0.0f64; 12]);
Examples found in repository?
examples/13_resource_limits.rs (line 22)
11fn main() {
12    // ── Default limits ────────────────────────────────────────────────────
13    let limits = MattenLimits::default();
14    println!("Default max_dimensions: {}", limits.max_dimensions);
15    println!(
16        "Default max_elements:   {} (~{} MiB f64)",
17        limits.max_elements,
18        limits.max_elements * 8 / 1_048_576
19    );
20
21    // ── Boundary-safe constructors ────────────────────────────────────────
22    let t = Tensor::try_zeros(&[100, 100]).unwrap();
23    assert_eq!(t.shape(), &[100, 100]);
24    assert_eq!(t.len(), 10_000);
25    println!("try_zeros([100, 100]): OK, {} elements", t.len());
26
27    let t = Tensor::try_ones(&[50, 20]).unwrap();
28    assert_eq!(t.as_slice().iter().sum::<f64>(), 1000.0);
29    println!("try_ones([50, 20]):    OK, sum = {}", t.sum());
30
31    let t = Tensor::try_full(&[10, 10], -1.0).unwrap();
32    assert_eq!(t.as_slice()[0], -1.0);
33    println!("try_full([10, 10], -1.0): OK");
34
35    // ── Custom limits ─────────────────────────────────────────────────────
36    let tight = MattenLimits {
37        max_elements: 10,
38        ..MattenLimits::default()
39    };
40    let err = Tensor::try_zeros_with_limits(&[100], &tight).unwrap_err();
41    assert!(matches!(err, MattenError::Allocation { .. }));
42    println!("Custom limit (max=10): correctly rejected [100]");
43
44    // ── Panicking variants respect limits too ─────────────────────────────
45    // These delegate to try_zeros/try_ones/try_full internally:
46    let _t = Tensor::zeros(&[10, 10]); // fine — 100 elements
47    println!("zeros([10, 10]):        OK (panicking form, within limit)");
48
49    println!("done.");
50}
Source

pub fn try_zeros_with_limits( shape: &[usize], limits: &MattenLimits, ) -> Result<Tensor, MattenError>

Creates a zero tensor with explicit limits.

Examples found in repository?
examples/13_resource_limits.rs (line 40)
11fn main() {
12    // ── Default limits ────────────────────────────────────────────────────
13    let limits = MattenLimits::default();
14    println!("Default max_dimensions: {}", limits.max_dimensions);
15    println!(
16        "Default max_elements:   {} (~{} MiB f64)",
17        limits.max_elements,
18        limits.max_elements * 8 / 1_048_576
19    );
20
21    // ── Boundary-safe constructors ────────────────────────────────────────
22    let t = Tensor::try_zeros(&[100, 100]).unwrap();
23    assert_eq!(t.shape(), &[100, 100]);
24    assert_eq!(t.len(), 10_000);
25    println!("try_zeros([100, 100]): OK, {} elements", t.len());
26
27    let t = Tensor::try_ones(&[50, 20]).unwrap();
28    assert_eq!(t.as_slice().iter().sum::<f64>(), 1000.0);
29    println!("try_ones([50, 20]):    OK, sum = {}", t.sum());
30
31    let t = Tensor::try_full(&[10, 10], -1.0).unwrap();
32    assert_eq!(t.as_slice()[0], -1.0);
33    println!("try_full([10, 10], -1.0): OK");
34
35    // ── Custom limits ─────────────────────────────────────────────────────
36    let tight = MattenLimits {
37        max_elements: 10,
38        ..MattenLimits::default()
39    };
40    let err = Tensor::try_zeros_with_limits(&[100], &tight).unwrap_err();
41    assert!(matches!(err, MattenError::Allocation { .. }));
42    println!("Custom limit (max=10): correctly rejected [100]");
43
44    // ── Panicking variants respect limits too ─────────────────────────────
45    // These delegate to try_zeros/try_ones/try_full internally:
46    let _t = Tensor::zeros(&[10, 10]); // fine — 100 elements
47    println!("zeros([10, 10]):        OK (panicking form, within limit)");
48
49    println!("done.");
50}
Source

pub fn try_ones(shape: &[usize]) -> Result<Tensor, MattenError>

Creates a ones tensor, returning an error instead of panicking.

Uses the default MattenLimits.

§Examples
use matten::Tensor;

let t = Tensor::try_ones(&[2, 3]).unwrap();
assert_eq!(t.as_slice(), &[1.0f64; 6]);
Examples found in repository?
examples/13_resource_limits.rs (line 27)
11fn main() {
12    // ── Default limits ────────────────────────────────────────────────────
13    let limits = MattenLimits::default();
14    println!("Default max_dimensions: {}", limits.max_dimensions);
15    println!(
16        "Default max_elements:   {} (~{} MiB f64)",
17        limits.max_elements,
18        limits.max_elements * 8 / 1_048_576
19    );
20
21    // ── Boundary-safe constructors ────────────────────────────────────────
22    let t = Tensor::try_zeros(&[100, 100]).unwrap();
23    assert_eq!(t.shape(), &[100, 100]);
24    assert_eq!(t.len(), 10_000);
25    println!("try_zeros([100, 100]): OK, {} elements", t.len());
26
27    let t = Tensor::try_ones(&[50, 20]).unwrap();
28    assert_eq!(t.as_slice().iter().sum::<f64>(), 1000.0);
29    println!("try_ones([50, 20]):    OK, sum = {}", t.sum());
30
31    let t = Tensor::try_full(&[10, 10], -1.0).unwrap();
32    assert_eq!(t.as_slice()[0], -1.0);
33    println!("try_full([10, 10], -1.0): OK");
34
35    // ── Custom limits ─────────────────────────────────────────────────────
36    let tight = MattenLimits {
37        max_elements: 10,
38        ..MattenLimits::default()
39    };
40    let err = Tensor::try_zeros_with_limits(&[100], &tight).unwrap_err();
41    assert!(matches!(err, MattenError::Allocation { .. }));
42    println!("Custom limit (max=10): correctly rejected [100]");
43
44    // ── Panicking variants respect limits too ─────────────────────────────
45    // These delegate to try_zeros/try_ones/try_full internally:
46    let _t = Tensor::zeros(&[10, 10]); // fine — 100 elements
47    println!("zeros([10, 10]):        OK (panicking form, within limit)");
48
49    println!("done.");
50}
Source

pub fn try_ones_with_limits( shape: &[usize], limits: &MattenLimits, ) -> Result<Tensor, MattenError>

Creates a ones tensor with explicit limits.

Source

pub fn try_full(shape: &[usize], value: f64) -> Result<Tensor, MattenError>

Creates a tensor filled with value, returning an error instead of panicking.

Uses the default MattenLimits.

§Examples
use matten::Tensor;

let t = Tensor::try_full(&[2, 2], 7.0).unwrap();
assert_eq!(t.as_slice(), &[7.0f64; 4]);
Examples found in repository?
examples/13_resource_limits.rs (line 31)
11fn main() {
12    // ── Default limits ────────────────────────────────────────────────────
13    let limits = MattenLimits::default();
14    println!("Default max_dimensions: {}", limits.max_dimensions);
15    println!(
16        "Default max_elements:   {} (~{} MiB f64)",
17        limits.max_elements,
18        limits.max_elements * 8 / 1_048_576
19    );
20
21    // ── Boundary-safe constructors ────────────────────────────────────────
22    let t = Tensor::try_zeros(&[100, 100]).unwrap();
23    assert_eq!(t.shape(), &[100, 100]);
24    assert_eq!(t.len(), 10_000);
25    println!("try_zeros([100, 100]): OK, {} elements", t.len());
26
27    let t = Tensor::try_ones(&[50, 20]).unwrap();
28    assert_eq!(t.as_slice().iter().sum::<f64>(), 1000.0);
29    println!("try_ones([50, 20]):    OK, sum = {}", t.sum());
30
31    let t = Tensor::try_full(&[10, 10], -1.0).unwrap();
32    assert_eq!(t.as_slice()[0], -1.0);
33    println!("try_full([10, 10], -1.0): OK");
34
35    // ── Custom limits ─────────────────────────────────────────────────────
36    let tight = MattenLimits {
37        max_elements: 10,
38        ..MattenLimits::default()
39    };
40    let err = Tensor::try_zeros_with_limits(&[100], &tight).unwrap_err();
41    assert!(matches!(err, MattenError::Allocation { .. }));
42    println!("Custom limit (max=10): correctly rejected [100]");
43
44    // ── Panicking variants respect limits too ─────────────────────────────
45    // These delegate to try_zeros/try_ones/try_full internally:
46    let _t = Tensor::zeros(&[10, 10]); // fine — 100 elements
47    println!("zeros([10, 10]):        OK (panicking form, within limit)");
48
49    println!("done.");
50}
Source

pub fn try_full_with_limits( shape: &[usize], value: f64, limits: &MattenLimits, ) -> Result<Tensor, MattenError>

Creates a filled tensor with explicit limits.

Source§

impl Tensor

Source

pub fn sum(&self) -> f64

Returns the sum of all elements.

NaN propagates naturally (IEEE 754).

use matten::Tensor;
assert_eq!(Tensor::from_vec(vec![1.0, 2.0, 3.0]).sum(), 6.0);
assert!(Tensor::from_vec(vec![1.0, f64::NAN]).sum().is_nan());
Examples found in repository?
examples/rolling_windows_basic.rs (line 9)
7fn rolling_sum(t: &Tensor, window: usize) -> Vec<f64> {
8    (0..=(t.len() - window))
9        .map(|i| t.slice().range(i..i + window).build().unwrap().sum())
10        .collect()
11}
More examples
Hide additional examples
examples/40_trapezoidal_integration.rs (line 49)
37fn main() {
38    // Evenly spaced sample grid on [0, 1].
39    let x = Tensor::linspace(0.0, 1.0, 11);
40    let xs = x.as_slice();
41    let h = xs[1] - xs[0];
42
43    // f(x) = x^2, evaluated with elementwise multiplication.
44    let f = &x * &x;
45    let fs = f.as_slice();
46    let n = fs.len();
47
48    // Composite trapezoidal rule: h * (Σ f - (f_first + f_last)/2).
49    let estimate = h * (f.sum() - (fs[0] + fs[n - 1]) / 2.0);
50    let exact = 1.0 / 3.0; // ∫_0^1 x^2 dx = 1/3
51    let err = (estimate - exact).abs();
52
53    println!("trapezoidal estimate: {estimate:.6}");
54    println!("exact integral (1/3): {exact:.6}");
55    println!("abs error:            {err:.6}");
56
57    assert!(err < 0.01);
58    println!("Trapezoidal integration: OK");
59}
examples/23_sum_mean.rs (line 9)
7fn main() {
8    let v = Tensor::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0]);
9    println!("v.sum()  = {}", v.sum()); // 15.0
10    println!("v.mean() = {}", v.mean()); // 3.0
11
12    // Axis reductions on a matrix
13    // [[1,2,3],[4,5,6]]
14    let m = Tensor::new(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0], &[2, 3]);
15    println!("column sums   (axis 0) = {:?}", m.sum_axis(0).as_slice()); // [5,7,9]
16    println!("row sums      (axis 1) = {:?}", m.sum_axis(1).as_slice()); // [6,15]
17    println!("column means  (axis 0) = {:?}", m.mean_axis(0).as_slice()); // [2.5,3.5,4.5]
18    println!("row means     (axis 1) = {:?}", m.mean_axis(1).as_slice()); // [2.0,5.0]
19
20    assert_eq!(m.sum_axis(0).as_slice(), &[5.0, 7.0, 9.0]);
21    assert_eq!(m.mean_axis(1).as_slice(), &[2.0, 5.0]);
22    println!("Assertions passed: OK");
23}
examples/13_resource_limits.rs (line 29)
11fn main() {
12    // ── Default limits ────────────────────────────────────────────────────
13    let limits = MattenLimits::default();
14    println!("Default max_dimensions: {}", limits.max_dimensions);
15    println!(
16        "Default max_elements:   {} (~{} MiB f64)",
17        limits.max_elements,
18        limits.max_elements * 8 / 1_048_576
19    );
20
21    // ── Boundary-safe constructors ────────────────────────────────────────
22    let t = Tensor::try_zeros(&[100, 100]).unwrap();
23    assert_eq!(t.shape(), &[100, 100]);
24    assert_eq!(t.len(), 10_000);
25    println!("try_zeros([100, 100]): OK, {} elements", t.len());
26
27    let t = Tensor::try_ones(&[50, 20]).unwrap();
28    assert_eq!(t.as_slice().iter().sum::<f64>(), 1000.0);
29    println!("try_ones([50, 20]):    OK, sum = {}", t.sum());
30
31    let t = Tensor::try_full(&[10, 10], -1.0).unwrap();
32    assert_eq!(t.as_slice()[0], -1.0);
33    println!("try_full([10, 10], -1.0): OK");
34
35    // ── Custom limits ─────────────────────────────────────────────────────
36    let tight = MattenLimits {
37        max_elements: 10,
38        ..MattenLimits::default()
39    };
40    let err = Tensor::try_zeros_with_limits(&[100], &tight).unwrap_err();
41    assert!(matches!(err, MattenError::Allocation { .. }));
42    println!("Custom limit (max=10): correctly rejected [100]");
43
44    // ── Panicking variants respect limits too ─────────────────────────────
45    // These delegate to try_zeros/try_ones/try_full internally:
46    let _t = Tensor::zeros(&[10, 10]); // fine — 100 elements
47    println!("zeros([10, 10]):        OK (panicking form, within limit)");
48
49    println!("done.");
50}
Source

pub fn mean(&self) -> f64

Returns the arithmetic mean of all elements (sum / len).

NaN propagates. Behaviour on an empty tensor is unspecified (zero-sized dims are rejected by constructors in Phase 1).

use matten::Tensor;
assert_eq!(Tensor::from_vec(vec![1.0, 2.0, 3.0, 4.0]).mean(), 2.5);
Examples found in repository?
examples/moving_average.rs (line 16)
7fn main() {
8    let series = Tensor::from_vec(vec![1.0, 3.0, 5.0, 7.0, 9.0, 11.0, 13.0]);
9    let window = 3usize;
10    let n = series.len();
11
12    // Compute moving averages for windows [0..3], [1..4], ...
13    let mut avgs = Vec::new();
14    for start in 0..=(n - window) {
15        let w = series.slice().range(start..start + window).build().unwrap();
16        avgs.push(w.mean());
17    }
18
19    println!("series = {:?}", series.as_slice());
20    println!("3-pt moving avg = {:?}", avgs);
21    assert_eq!(avgs.len(), n - window + 1);
22    assert!((avgs[0] - 3.0).abs() < 1e-10); // mean(1,3,5) = 3
23    assert!((avgs[1] - 5.0).abs() < 1e-10); // mean(3,5,7) = 5
24    println!("Moving average: OK");
25}
More examples
Hide additional examples
examples/23_sum_mean.rs (line 10)
7fn main() {
8    let v = Tensor::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0]);
9    println!("v.sum()  = {}", v.sum()); // 15.0
10    println!("v.mean() = {}", v.mean()); // 3.0
11
12    // Axis reductions on a matrix
13    // [[1,2,3],[4,5,6]]
14    let m = Tensor::new(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0], &[2, 3]);
15    println!("column sums   (axis 0) = {:?}", m.sum_axis(0).as_slice()); // [5,7,9]
16    println!("row sums      (axis 1) = {:?}", m.sum_axis(1).as_slice()); // [6,15]
17    println!("column means  (axis 0) = {:?}", m.mean_axis(0).as_slice()); // [2.5,3.5,4.5]
18    println!("row means     (axis 1) = {:?}", m.mean_axis(1).as_slice()); // [2.0,5.0]
19
20    assert_eq!(m.sum_axis(0).as_slice(), &[5.0, 7.0, 9.0]);
21    assert_eq!(m.mean_axis(1).as_slice(), &[2.0, 5.0]);
22    println!("Assertions passed: OK");
23}
Source

pub fn min(&self) -> f64

Returns the minimum element.

Returns NaN if any element is NaN (explicit NaN-propagation; do not use f64::min which silently ignores NaN).

use matten::Tensor;
assert_eq!(Tensor::from_vec(vec![3.0, 1.0, 2.0]).min(), 1.0);
assert!(Tensor::from_vec(vec![1.0, f64::NAN, 3.0]).min().is_nan());
Examples found in repository?
examples/24_min_max.rs (line 12)
10fn main() {
11    let v = Tensor::from_vec(vec![3.0, 1.0, 4.0, 1.0, 5.0, 9.0, 2.0]);
12    println!("min = {}", v.min()); // 1.0
13    println!("max = {}", v.max()); // 9.0
14
15    // NaN policy: any NaN -> result is NaN
16    let with_nan = Tensor::from_vec(vec![1.0, f64::NAN, 3.0]);
17    println!("min with NaN = {}", with_nan.min()); // NaN
18    println!("max with NaN = {}", with_nan.max()); // NaN
19    assert!(with_nan.min().is_nan());
20    assert!(with_nan.max().is_nan());
21
22    // Inf is handled normally
23    let with_inf = Tensor::from_vec(vec![1.0, f64::INFINITY, -1.0]);
24    println!("min with +inf = {}", with_inf.min()); // -1.0
25    println!("max with +inf = {}", with_inf.max()); // inf
26
27    println!("NaN policy verified: OK");
28}
Source

pub fn max(&self) -> f64

Returns the maximum element.

Returns NaN if any element is NaN.

use matten::Tensor;
assert_eq!(Tensor::from_vec(vec![3.0, 1.0, 2.0]).max(), 3.0);
assert!(Tensor::from_vec(vec![1.0, f64::NAN, 3.0]).max().is_nan());
Examples found in repository?
examples/rolling_windows_basic.rs (line 15)
13fn rolling_max(t: &Tensor, window: usize) -> Vec<f64> {
14    (0..=(t.len() - window))
15        .map(|i| t.slice().range(i..i + window).build().unwrap().max())
16        .collect()
17}
More examples
Hide additional examples
examples/24_min_max.rs (line 13)
10fn main() {
11    let v = Tensor::from_vec(vec![3.0, 1.0, 4.0, 1.0, 5.0, 9.0, 2.0]);
12    println!("min = {}", v.min()); // 1.0
13    println!("max = {}", v.max()); // 9.0
14
15    // NaN policy: any NaN -> result is NaN
16    let with_nan = Tensor::from_vec(vec![1.0, f64::NAN, 3.0]);
17    println!("min with NaN = {}", with_nan.min()); // NaN
18    println!("max with NaN = {}", with_nan.max()); // NaN
19    assert!(with_nan.min().is_nan());
20    assert!(with_nan.max().is_nan());
21
22    // Inf is handled normally
23    let with_inf = Tensor::from_vec(vec![1.0, f64::INFINITY, -1.0]);
24    println!("min with +inf = {}", with_inf.min()); // -1.0
25    println!("max with +inf = {}", with_inf.max()); // inf
26
27    println!("NaN policy verified: OK");
28}
examples/rowwise_scoring.rs (line 25)
7fn main() {
8    // 3 items × 4 features
9    let features = Tensor::new(
10        vec![0.8, 0.6, 0.9, 0.7, 0.4, 0.9, 0.5, 0.8, 0.7, 0.7, 0.8, 0.6],
11        &[3, 4],
12    );
13
14    // Importance weights per feature: shape [4], broadcast across rows
15    let weights = Tensor::new(vec![0.3, 0.2, 0.4, 0.1], &[4]);
16
17    // Weighted feature matrix: [3,4]
18    let weighted = &features * &weights;
19
20    // Score per item: sum across features (axis 1) -> shape [3]
21    let scores = weighted.sum_axis(1);
22    println!("scores = {:?}", scores.as_slice());
23
24    // Best item (highest score)
25    let best_score = scores.max();
26    println!("best score = {best_score:.3}");
27
28    assert_eq!(scores.shape(), &[3]);
29    println!("Row-wise scoring: OK");
30}
Source§

impl Tensor

Source

pub fn sum_axis(&self, axis: usize) -> Tensor

Reduces along axis by summing, removing that axis from the output shape.

§Panics

Panics if axis >= self.ndim().

use matten::Tensor;
// [[1,2,3],[4,5,6]] summed along axis 0 -> [5,7,9]
let m = Tensor::new(vec![1.0,2.0,3.0,4.0,5.0,6.0], &[2,3]);
let r = m.sum_axis(0);
assert_eq!(r.shape(), &[3]);
assert_eq!(r.as_slice(), &[5.0, 7.0, 9.0]);
Examples found in repository?
examples/rowwise_scoring.rs (line 21)
7fn main() {
8    // 3 items × 4 features
9    let features = Tensor::new(
10        vec![0.8, 0.6, 0.9, 0.7, 0.4, 0.9, 0.5, 0.8, 0.7, 0.7, 0.8, 0.6],
11        &[3, 4],
12    );
13
14    // Importance weights per feature: shape [4], broadcast across rows
15    let weights = Tensor::new(vec![0.3, 0.2, 0.4, 0.1], &[4]);
16
17    // Weighted feature matrix: [3,4]
18    let weighted = &features * &weights;
19
20    // Score per item: sum across features (axis 1) -> shape [3]
21    let scores = weighted.sum_axis(1);
22    println!("scores = {:?}", scores.as_slice());
23
24    // Best item (highest score)
25    let best_score = scores.max();
26    println!("best score = {best_score:.3}");
27
28    assert_eq!(scores.shape(), &[3]);
29    println!("Row-wise scoring: OK");
30}
More examples
Hide additional examples
examples/23_sum_mean.rs (line 15)
7fn main() {
8    let v = Tensor::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0]);
9    println!("v.sum()  = {}", v.sum()); // 15.0
10    println!("v.mean() = {}", v.mean()); // 3.0
11
12    // Axis reductions on a matrix
13    // [[1,2,3],[4,5,6]]
14    let m = Tensor::new(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0], &[2, 3]);
15    println!("column sums   (axis 0) = {:?}", m.sum_axis(0).as_slice()); // [5,7,9]
16    println!("row sums      (axis 1) = {:?}", m.sum_axis(1).as_slice()); // [6,15]
17    println!("column means  (axis 0) = {:?}", m.mean_axis(0).as_slice()); // [2.5,3.5,4.5]
18    println!("row means     (axis 1) = {:?}", m.mean_axis(1).as_slice()); // [2.0,5.0]
19
20    assert_eq!(m.sum_axis(0).as_slice(), &[5.0, 7.0, 9.0]);
21    assert_eq!(m.mean_axis(1).as_slice(), &[2.0, 5.0]);
22    println!("Assertions passed: OK");
23}
examples/pairwise_distance.rs (line 14)
9fn pairwise_euclidean(points: &Tensor) -> Tensor {
10    let n = points.shape()[0];
11
12    // Row-wise squared norms: shape [n]
13    let sq = points * points;
14    let row_sq_norms = sq.sum_axis(1); // [n]
15
16    // Gram matrix: G[i,j] = points[i] · points[j], shape [n,n]
17    let gram = points.matmul(&points.transpose());
18
19    // dist²[i,j] = sq_norm[i] + sq_norm[j] - 2·G[i,j]
20    // Broadcast [n] as column [n,1] + row [1,n]
21    let col = row_sq_norms.reshape(&[n, 1]);
22    let row = row_sq_norms.reshape(&[1, n]);
23    let dist_sq = &(&col + &row) - &(&gram * 2.0);
24
25    // Clamp small negatives from floating-point rounding, then sqrt
26    let dists: Vec<f64> = dist_sq
27        .as_slice()
28        .iter()
29        .map(|&v| if v < 0.0 { 0.0 } else { v.sqrt() })
30        .collect();
31    Tensor::new(dists, &[n, n])
32}
examples/27_axis_reductions.rs (line 23)
11fn main() {
12    // Shape [3, 4]: 3 rows, 4 columns
13    let m = Tensor::new(
14        vec![
15            1.0, 2.0, 3.0, 4.0, // row 0
16            5.0, 6.0, 7.0, 8.0, // row 1
17            9.0, 10.0, 11.0, 12.0, // row 2
18        ],
19        &[3, 4],
20    );
21
22    // Reduce rows → column sums: shape [4]
23    let col_sums = m.sum_axis(0);
24    assert_eq!(col_sums.shape(), &[4]);
25    assert_eq!(col_sums.as_slice(), &[15.0, 18.0, 21.0, 24.0]);
26    println!("col sums  = {:?}", col_sums.as_slice());
27
28    // Reduce columns → row means: shape [3]
29    let row_means = m.mean_axis(1);
30    assert_eq!(row_means.shape(), &[3]);
31    assert_eq!(row_means.as_slice(), &[2.5, 6.5, 10.5]);
32    println!("row means = {:?}", row_means.as_slice());
33
34    // Column-wise min and max
35    let col_min = m.min_axis(0);
36    let col_max = m.max_axis(0);
37    assert_eq!(col_min.as_slice(), &[1.0, 2.0, 3.0, 4.0]);
38    assert_eq!(col_max.as_slice(), &[9.0, 10.0, 11.0, 12.0]);
39    println!("col min   = {:?}", col_min.as_slice());
40    println!("col max   = {:?}", col_max.as_slice());
41
42    // NaN propagation: one NaN contaminates its column's min
43    let with_nan = Tensor::new(vec![1.0, f64::NAN, 3.0, 5.0, 6.0, 7.0], &[2, 3]);
44    let nan_col_min = with_nan.min_axis(0);
45    assert!(nan_col_min.as_slice()[1].is_nan()); // column 1 had a NaN
46    assert_eq!(nan_col_min.as_slice()[0], 1.0); // column 0 clean
47    println!("NaN propagation confirmed");
48
49    println!("done.");
50}
Source

pub fn mean_axis(&self, axis: usize) -> Tensor

Reduces along axis by computing the arithmetic mean.

§Panics

Panics if axis >= self.ndim().

use matten::Tensor;
let m = Tensor::new(vec![1.0,2.0,3.0,4.0,5.0,6.0], &[2,3]);
let r = m.mean_axis(0);
assert_eq!(r.shape(), &[3]);
assert_eq!(r.as_slice(), &[2.5, 3.5, 4.5]);
Examples found in repository?
examples/28_column_statistics.rs (line 16)
12fn column_std(data: &Tensor, col_means: &Tensor) -> Tensor {
13    // Broadcast means over all rows, compute squared deviations
14    let deviations = data - col_means; // [rows, cols] - [cols] → [rows, cols]
15    let sq = &deviations * &deviations;
16    sq.mean_axis(0) // → [cols] mean of squared deviations
17        .as_slice()
18        .iter()
19        .map(|v| v.sqrt())
20        .collect::<Vec<f64>>()
21        .into()
22}
23
24fn main() {
25    // 4 rows, 3 columns (features)
26    let data = Tensor::new(
27        vec![
28            1.0, 10.0, 100.0, 2.0, 20.0, 200.0, 3.0, 30.0, 300.0, 4.0, 40.0, 400.0,
29        ],
30        &[4, 3],
31    );
32
33    let means = data.mean_axis(0);
34    let mins = data.min_axis(0);
35    let maxs = data.max_axis(0);
36    let stds = column_std(&data, &means);
37
38    println!("columns : 0      1      2");
39    println!("mean    : {:?}", means.as_slice());
40    println!("min     : {:?}", mins.as_slice());
41    println!("max     : {:?}", maxs.as_slice());
42    println!("std dev : {:?}", stds.as_slice());
43
44    assert_eq!(means.as_slice(), &[2.5, 25.0, 250.0]);
45    assert_eq!(mins.as_slice(), &[1.0, 10.0, 100.0]);
46    assert_eq!(maxs.as_slice(), &[4.0, 40.0, 400.0]);
47
48    // Std dev: sqrt of mean squared deviation from mean
49    let expected_std0 = {
50        // Column 0 values: 1,2,3,4. Mean=2.5. Deviations: -1.5,-0.5,0.5,1.5
51        let sq_devs = [
52            1.5f64.powi(2),
53            0.5f64.powi(2),
54            0.5f64.powi(2),
55            1.5f64.powi(2),
56        ];
57        (sq_devs.iter().sum::<f64>() / 4.0).sqrt()
58    };
59    assert!((stds.as_slice()[0] - expected_std0).abs() < 1e-10);
60
61    println!("done.");
62}
More examples
Hide additional examples
examples/column_summary.rs (line 15)
7fn main() {
8    let data = Tensor::new(
9        vec![
10            2.0, 5.0, 10.0, 4.0, 7.0, 20.0, 6.0, 3.0, 15.0, 8.0, 11.0, 25.0, 10.0, 9.0, 30.0,
11        ],
12        &[5, 3],
13    );
14
15    let means = data.mean_axis(0);
16    let mins = data.min_axis(0);
17    let maxes = data.max_axis(0);
18    let centred = &data - &means;
19    let variances = (&centred * &centred).mean_axis(0);
20    let stds: Vec<f64> = variances.as_slice().iter().map(|v| v.sqrt()).collect();
21    let stds_t = Tensor::new(stds, &[3]);
22
23    println!("col means = {:?}", means.as_slice());
24    println!("col mins  = {:?}", mins.as_slice());
25    println!("col maxes = {:?}", maxes.as_slice());
26    println!("col stds  = {:?}", stds_t.as_slice());
27
28    assert_eq!(means.shape(), &[3]);
29    println!("Column summary: OK");
30}
examples/23_sum_mean.rs (line 17)
7fn main() {
8    let v = Tensor::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0]);
9    println!("v.sum()  = {}", v.sum()); // 15.0
10    println!("v.mean() = {}", v.mean()); // 3.0
11
12    // Axis reductions on a matrix
13    // [[1,2,3],[4,5,6]]
14    let m = Tensor::new(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0], &[2, 3]);
15    println!("column sums   (axis 0) = {:?}", m.sum_axis(0).as_slice()); // [5,7,9]
16    println!("row sums      (axis 1) = {:?}", m.sum_axis(1).as_slice()); // [6,15]
17    println!("column means  (axis 0) = {:?}", m.mean_axis(0).as_slice()); // [2.5,3.5,4.5]
18    println!("row means     (axis 1) = {:?}", m.mean_axis(1).as_slice()); // [2.0,5.0]
19
20    assert_eq!(m.sum_axis(0).as_slice(), &[5.0, 7.0, 9.0]);
21    assert_eq!(m.mean_axis(1).as_slice(), &[2.0, 5.0]);
22    println!("Assertions passed: OK");
23}
examples/standardize_columns.rs (line 18)
10fn main() {
11    // 4 samples × 3 features
12    let data = Tensor::new(
13        vec![2.0, 4.0, 1.0, 4.0, 6.0, 3.0, 6.0, 8.0, 5.0, 8.0, 10.0, 7.0],
14        &[4, 3],
15    );
16
17    // Column means: shape [3]
18    let means = data.mean_axis(0);
19    // Centre: broadcast [3] across [4, 3]
20    let centred = &data - &means;
21
22    // Column std dev: sqrt(mean of squared deviations)
23    let sq = &centred * &centred;
24    let variance = sq.mean_axis(0);
25    let std_dev_vals: Vec<f64> = variance.as_slice().iter().map(|v| v.sqrt()).collect();
26    let std_dev = Tensor::new(std_dev_vals, &[3]);
27
28    // Standardise
29    let standardised = &centred / &std_dev;
30
31    println!("means    = {:?}", means.as_slice());
32    println!("std devs = {:?}", std_dev.as_slice());
33    println!("result shape = {:?}", standardised.shape());
34
35    // Each column should have mean ≈ 0 and std ≈ 1
36    let col_means = standardised.mean_axis(0);
37    for &m in col_means.as_slice() {
38        assert!(m.abs() < 1e-10, "column mean not zero: {m}");
39    }
40    println!("Column means ≈ 0: OK");
41}
examples/27_axis_reductions.rs (line 29)
11fn main() {
12    // Shape [3, 4]: 3 rows, 4 columns
13    let m = Tensor::new(
14        vec![
15            1.0, 2.0, 3.0, 4.0, // row 0
16            5.0, 6.0, 7.0, 8.0, // row 1
17            9.0, 10.0, 11.0, 12.0, // row 2
18        ],
19        &[3, 4],
20    );
21
22    // Reduce rows → column sums: shape [4]
23    let col_sums = m.sum_axis(0);
24    assert_eq!(col_sums.shape(), &[4]);
25    assert_eq!(col_sums.as_slice(), &[15.0, 18.0, 21.0, 24.0]);
26    println!("col sums  = {:?}", col_sums.as_slice());
27
28    // Reduce columns → row means: shape [3]
29    let row_means = m.mean_axis(1);
30    assert_eq!(row_means.shape(), &[3]);
31    assert_eq!(row_means.as_slice(), &[2.5, 6.5, 10.5]);
32    println!("row means = {:?}", row_means.as_slice());
33
34    // Column-wise min and max
35    let col_min = m.min_axis(0);
36    let col_max = m.max_axis(0);
37    assert_eq!(col_min.as_slice(), &[1.0, 2.0, 3.0, 4.0]);
38    assert_eq!(col_max.as_slice(), &[9.0, 10.0, 11.0, 12.0]);
39    println!("col min   = {:?}", col_min.as_slice());
40    println!("col max   = {:?}", col_max.as_slice());
41
42    // NaN propagation: one NaN contaminates its column's min
43    let with_nan = Tensor::new(vec![1.0, f64::NAN, 3.0, 5.0, 6.0, 7.0], &[2, 3]);
44    let nan_col_min = with_nan.min_axis(0);
45    assert!(nan_col_min.as_slice()[1].is_nan()); // column 1 had a NaN
46    assert_eq!(nan_col_min.as_slice()[0], 1.0); // column 0 clean
47    println!("NaN propagation confirmed");
48
49    println!("done.");
50}
Source§

impl Tensor

Source

pub fn min_axis(&self, axis: usize) -> Tensor

Reduces along axis by taking the minimum, removing that axis from the output shape. Returns NaN if any element along the axis is NaN.

§Panics

Panics if axis >= self.ndim().

use matten::Tensor;
let m = Tensor::new(vec![3.0,1.0,4.0,1.0,5.0,9.0], &[2,3]);
assert_eq!(m.min_axis(0).as_slice(), &[1.0, 1.0, 4.0]);
Examples found in repository?
examples/column_summary.rs (line 16)
7fn main() {
8    let data = Tensor::new(
9        vec![
10            2.0, 5.0, 10.0, 4.0, 7.0, 20.0, 6.0, 3.0, 15.0, 8.0, 11.0, 25.0, 10.0, 9.0, 30.0,
11        ],
12        &[5, 3],
13    );
14
15    let means = data.mean_axis(0);
16    let mins = data.min_axis(0);
17    let maxes = data.max_axis(0);
18    let centred = &data - &means;
19    let variances = (&centred * &centred).mean_axis(0);
20    let stds: Vec<f64> = variances.as_slice().iter().map(|v| v.sqrt()).collect();
21    let stds_t = Tensor::new(stds, &[3]);
22
23    println!("col means = {:?}", means.as_slice());
24    println!("col mins  = {:?}", mins.as_slice());
25    println!("col maxes = {:?}", maxes.as_slice());
26    println!("col stds  = {:?}", stds_t.as_slice());
27
28    assert_eq!(means.shape(), &[3]);
29    println!("Column summary: OK");
30}
More examples
Hide additional examples
examples/minmax_scaling.rs (line 14)
7fn main() {
8    let data = Tensor::new(
9        vec![1.0, 10.0, 100.0, 2.0, 20.0, 200.0, 3.0, 30.0, 300.0],
10        &[3, 3],
11    );
12
13    // Column min and max using axis reductions
14    let col_min = data.min_axis(0);
15    let col_max = data.max_axis(0);
16    let range = &col_max - &col_min;
17
18    // Broadcast: (data - min) / (max - min)
19    let scaled = &(&data - &col_min) / &range;
20
21    println!("col_min  = {:?}", col_min.as_slice());
22    println!("col_max  = {:?}", col_max.as_slice());
23    println!("scaled shape = {:?}", scaled.shape());
24
25    // First row should be all 0.0, last row all 1.0
26    let row0 = scaled.slice().index(0).all().build().unwrap();
27    let row2 = scaled.slice().index(2).all().build().unwrap();
28    assert!(row0.as_slice().iter().all(|&v| (v - 0.0).abs() < 1e-10));
29    assert!(row2.as_slice().iter().all(|&v| (v - 1.0).abs() < 1e-10));
30    println!("Min-max scaling: OK");
31}
examples/28_column_statistics.rs (line 34)
24fn main() {
25    // 4 rows, 3 columns (features)
26    let data = Tensor::new(
27        vec![
28            1.0, 10.0, 100.0, 2.0, 20.0, 200.0, 3.0, 30.0, 300.0, 4.0, 40.0, 400.0,
29        ],
30        &[4, 3],
31    );
32
33    let means = data.mean_axis(0);
34    let mins = data.min_axis(0);
35    let maxs = data.max_axis(0);
36    let stds = column_std(&data, &means);
37
38    println!("columns : 0      1      2");
39    println!("mean    : {:?}", means.as_slice());
40    println!("min     : {:?}", mins.as_slice());
41    println!("max     : {:?}", maxs.as_slice());
42    println!("std dev : {:?}", stds.as_slice());
43
44    assert_eq!(means.as_slice(), &[2.5, 25.0, 250.0]);
45    assert_eq!(mins.as_slice(), &[1.0, 10.0, 100.0]);
46    assert_eq!(maxs.as_slice(), &[4.0, 40.0, 400.0]);
47
48    // Std dev: sqrt of mean squared deviation from mean
49    let expected_std0 = {
50        // Column 0 values: 1,2,3,4. Mean=2.5. Deviations: -1.5,-0.5,0.5,1.5
51        let sq_devs = [
52            1.5f64.powi(2),
53            0.5f64.powi(2),
54            0.5f64.powi(2),
55            1.5f64.powi(2),
56        ];
57        (sq_devs.iter().sum::<f64>() / 4.0).sqrt()
58    };
59    assert!((stds.as_slice()[0] - expected_std0).abs() < 1e-10);
60
61    println!("done.");
62}
examples/27_axis_reductions.rs (line 35)
11fn main() {
12    // Shape [3, 4]: 3 rows, 4 columns
13    let m = Tensor::new(
14        vec![
15            1.0, 2.0, 3.0, 4.0, // row 0
16            5.0, 6.0, 7.0, 8.0, // row 1
17            9.0, 10.0, 11.0, 12.0, // row 2
18        ],
19        &[3, 4],
20    );
21
22    // Reduce rows → column sums: shape [4]
23    let col_sums = m.sum_axis(0);
24    assert_eq!(col_sums.shape(), &[4]);
25    assert_eq!(col_sums.as_slice(), &[15.0, 18.0, 21.0, 24.0]);
26    println!("col sums  = {:?}", col_sums.as_slice());
27
28    // Reduce columns → row means: shape [3]
29    let row_means = m.mean_axis(1);
30    assert_eq!(row_means.shape(), &[3]);
31    assert_eq!(row_means.as_slice(), &[2.5, 6.5, 10.5]);
32    println!("row means = {:?}", row_means.as_slice());
33
34    // Column-wise min and max
35    let col_min = m.min_axis(0);
36    let col_max = m.max_axis(0);
37    assert_eq!(col_min.as_slice(), &[1.0, 2.0, 3.0, 4.0]);
38    assert_eq!(col_max.as_slice(), &[9.0, 10.0, 11.0, 12.0]);
39    println!("col min   = {:?}", col_min.as_slice());
40    println!("col max   = {:?}", col_max.as_slice());
41
42    // NaN propagation: one NaN contaminates its column's min
43    let with_nan = Tensor::new(vec![1.0, f64::NAN, 3.0, 5.0, 6.0, 7.0], &[2, 3]);
44    let nan_col_min = with_nan.min_axis(0);
45    assert!(nan_col_min.as_slice()[1].is_nan()); // column 1 had a NaN
46    assert_eq!(nan_col_min.as_slice()[0], 1.0); // column 0 clean
47    println!("NaN propagation confirmed");
48
49    println!("done.");
50}
Source

pub fn max_axis(&self, axis: usize) -> Tensor

Reduces along axis by taking the maximum, removing that axis from the output shape. Returns NaN if any element along the axis is NaN.

§Panics

Panics if axis >= self.ndim().

use matten::Tensor;
let m = Tensor::new(vec![3.0,1.0,4.0,1.0,5.0,9.0], &[2,3]);
assert_eq!(m.max_axis(0).as_slice(), &[3.0, 5.0, 9.0]);
Examples found in repository?
examples/column_summary.rs (line 17)
7fn main() {
8    let data = Tensor::new(
9        vec![
10            2.0, 5.0, 10.0, 4.0, 7.0, 20.0, 6.0, 3.0, 15.0, 8.0, 11.0, 25.0, 10.0, 9.0, 30.0,
11        ],
12        &[5, 3],
13    );
14
15    let means = data.mean_axis(0);
16    let mins = data.min_axis(0);
17    let maxes = data.max_axis(0);
18    let centred = &data - &means;
19    let variances = (&centred * &centred).mean_axis(0);
20    let stds: Vec<f64> = variances.as_slice().iter().map(|v| v.sqrt()).collect();
21    let stds_t = Tensor::new(stds, &[3]);
22
23    println!("col means = {:?}", means.as_slice());
24    println!("col mins  = {:?}", mins.as_slice());
25    println!("col maxes = {:?}", maxes.as_slice());
26    println!("col stds  = {:?}", stds_t.as_slice());
27
28    assert_eq!(means.shape(), &[3]);
29    println!("Column summary: OK");
30}
More examples
Hide additional examples
examples/minmax_scaling.rs (line 15)
7fn main() {
8    let data = Tensor::new(
9        vec![1.0, 10.0, 100.0, 2.0, 20.0, 200.0, 3.0, 30.0, 300.0],
10        &[3, 3],
11    );
12
13    // Column min and max using axis reductions
14    let col_min = data.min_axis(0);
15    let col_max = data.max_axis(0);
16    let range = &col_max - &col_min;
17
18    // Broadcast: (data - min) / (max - min)
19    let scaled = &(&data - &col_min) / &range;
20
21    println!("col_min  = {:?}", col_min.as_slice());
22    println!("col_max  = {:?}", col_max.as_slice());
23    println!("scaled shape = {:?}", scaled.shape());
24
25    // First row should be all 0.0, last row all 1.0
26    let row0 = scaled.slice().index(0).all().build().unwrap();
27    let row2 = scaled.slice().index(2).all().build().unwrap();
28    assert!(row0.as_slice().iter().all(|&v| (v - 0.0).abs() < 1e-10));
29    assert!(row2.as_slice().iter().all(|&v| (v - 1.0).abs() < 1e-10));
30    println!("Min-max scaling: OK");
31}
examples/28_column_statistics.rs (line 35)
24fn main() {
25    // 4 rows, 3 columns (features)
26    let data = Tensor::new(
27        vec![
28            1.0, 10.0, 100.0, 2.0, 20.0, 200.0, 3.0, 30.0, 300.0, 4.0, 40.0, 400.0,
29        ],
30        &[4, 3],
31    );
32
33    let means = data.mean_axis(0);
34    let mins = data.min_axis(0);
35    let maxs = data.max_axis(0);
36    let stds = column_std(&data, &means);
37
38    println!("columns : 0      1      2");
39    println!("mean    : {:?}", means.as_slice());
40    println!("min     : {:?}", mins.as_slice());
41    println!("max     : {:?}", maxs.as_slice());
42    println!("std dev : {:?}", stds.as_slice());
43
44    assert_eq!(means.as_slice(), &[2.5, 25.0, 250.0]);
45    assert_eq!(mins.as_slice(), &[1.0, 10.0, 100.0]);
46    assert_eq!(maxs.as_slice(), &[4.0, 40.0, 400.0]);
47
48    // Std dev: sqrt of mean squared deviation from mean
49    let expected_std0 = {
50        // Column 0 values: 1,2,3,4. Mean=2.5. Deviations: -1.5,-0.5,0.5,1.5
51        let sq_devs = [
52            1.5f64.powi(2),
53            0.5f64.powi(2),
54            0.5f64.powi(2),
55            1.5f64.powi(2),
56        ];
57        (sq_devs.iter().sum::<f64>() / 4.0).sqrt()
58    };
59    assert!((stds.as_slice()[0] - expected_std0).abs() < 1e-10);
60
61    println!("done.");
62}
examples/27_axis_reductions.rs (line 36)
11fn main() {
12    // Shape [3, 4]: 3 rows, 4 columns
13    let m = Tensor::new(
14        vec![
15            1.0, 2.0, 3.0, 4.0, // row 0
16            5.0, 6.0, 7.0, 8.0, // row 1
17            9.0, 10.0, 11.0, 12.0, // row 2
18        ],
19        &[3, 4],
20    );
21
22    // Reduce rows → column sums: shape [4]
23    let col_sums = m.sum_axis(0);
24    assert_eq!(col_sums.shape(), &[4]);
25    assert_eq!(col_sums.as_slice(), &[15.0, 18.0, 21.0, 24.0]);
26    println!("col sums  = {:?}", col_sums.as_slice());
27
28    // Reduce columns → row means: shape [3]
29    let row_means = m.mean_axis(1);
30    assert_eq!(row_means.shape(), &[3]);
31    assert_eq!(row_means.as_slice(), &[2.5, 6.5, 10.5]);
32    println!("row means = {:?}", row_means.as_slice());
33
34    // Column-wise min and max
35    let col_min = m.min_axis(0);
36    let col_max = m.max_axis(0);
37    assert_eq!(col_min.as_slice(), &[1.0, 2.0, 3.0, 4.0]);
38    assert_eq!(col_max.as_slice(), &[9.0, 10.0, 11.0, 12.0]);
39    println!("col min   = {:?}", col_min.as_slice());
40    println!("col max   = {:?}", col_max.as_slice());
41
42    // NaN propagation: one NaN contaminates its column's min
43    let with_nan = Tensor::new(vec![1.0, f64::NAN, 3.0, 5.0, 6.0, 7.0], &[2, 3]);
44    let nan_col_min = with_nan.min_axis(0);
45    assert!(nan_col_min.as_slice()[1].is_nan()); // column 1 had a NaN
46    assert_eq!(nan_col_min.as_slice()[0], 1.0); // column 0 clean
47    println!("NaN propagation confirmed");
48
49    println!("done.");
50}
Source§

impl Tensor

Source

pub fn dot(&self, rhs: &Tensor) -> Tensor

Vector/matrix multiplication.

Supported forms:

self shaperhs shaperesult shape
[n][n][] scalar
[m, n][n][m]
[n][n, p][p]
[m, n][n, p][m, p]
§Panics

Panics on incompatible shapes or unsupported rank combinations.

use matten::Tensor;

// vector · vector -> scalar
let a = Tensor::from_vec(vec![1.0, 2.0, 3.0]);
let b = Tensor::from_vec(vec![4.0, 5.0, 6.0]);
let d = a.dot(&b);
assert!(d.is_scalar());
assert_eq!(d.as_slice(), &[32.0]); // 1*4 + 2*5 + 3*6

// matrix × vector -> vector
let m = Tensor::new(vec![1.0,2.0,3.0,4.0,5.0,6.0], &[2,3]);
let v = Tensor::from_vec(vec![1.0, 0.0, 1.0]);
let r = m.dot(&v);
assert_eq!(r.shape(), &[2]);
assert_eq!(r.as_slice(), &[4.0, 10.0]);
Examples found in repository?
examples/26_cosine_similarity.rs (line 15)
13fn cosine_similarity(a: &Tensor, b: &Tensor) -> f64 {
14    // a · b is the scalar dot product
15    let dot = a.dot(b).as_slice()[0];
16    dot / (l2_norm(a) * l2_norm(b))
17}
More examples
Hide additional examples
examples/20_dot_product.rs (line 14)
10fn main() {
11    let a = Tensor::from_vec(vec![1.0, 2.0, 3.0]);
12    let b = Tensor::from_vec(vec![4.0, 5.0, 6.0]);
13
14    let d = a.dot(&b); // 1*4 + 2*5 + 3*6 = 32
15    assert!(d.is_scalar());
16    println!("a · b = {}", d.as_slice()[0]); // 32.0
17
18    // Orthogonal vectors have zero dot product
19    let x = Tensor::from_vec(vec![1.0, 0.0]);
20    let y = Tensor::from_vec(vec![0.0, 1.0]);
21    assert_eq!(x.dot(&y).as_slice(), &[0.0]);
22    println!("orthogonal dot = 0: OK");
23}
Source

pub fn matmul(&self, rhs: &Tensor) -> Tensor

Alias for dot for familiarity.

* is always element-wise multiplication; matrix multiplication requires this explicit method.

use matten::Tensor;
let a = Tensor::new(vec![1.0,2.0,3.0,4.0], &[2,2]);
let b = Tensor::new(vec![5.0,6.0,7.0,8.0], &[2,2]);
let c = a.matmul(&b);
assert_eq!(c.shape(), &[2,2]);
assert_eq!(c.as_slice(), &[19.0, 22.0, 43.0, 50.0]);
Examples found in repository?
examples/36_heat_equation_1d.rs (line 38)
37fn step(a: &Tensor, u: &Tensor) -> Tensor {
38    a.matmul(u)
39}
More examples
Hide additional examples
examples/33_markov_chain_weather.rs (line 39)
38fn step(dist: &Tensor, p: &Tensor) -> Tensor {
39    dist.matmul(p)
40}
examples/32_graph_path_counting.rs (line 52)
49fn matrix_power(a: &Tensor, k: u32) -> Tensor {
50    let mut acc = a.clone();
51    for _ in 1..k {
52        acc = acc.matmul(a);
53    }
54    acc
55}
examples/34_tiny_pagerank.rs (line 43)
42fn pagerank_step(m: &Tensor, r: &Tensor, damping: f64, n: usize) -> Tensor {
43    let mr = m.matmul(r); // [n, n] × [n] -> [n]
44    let base = (1.0 - damping) / n as f64;
45    let next: Vec<f64> = mr.as_slice().iter().map(|&x| base + damping * x).collect();
46    Tensor::from_vec(next)
47}
examples/31_fibonacci_matrix_power.rs (line 44)
39fn fib(n: u32) -> u64 {
40    let q = Tensor::new(vec![1.0, 1.0, 1.0, 0.0], &[2, 2]);
41    // Start from the 2×2 identity so that `fib(0)` returns 0.
42    let mut acc = Tensor::new(vec![1.0, 0.0, 0.0, 1.0], &[2, 2]);
43    for _ in 0..n {
44        acc = acc.matmul(&q);
45    }
46    // F(n) is the top-right entry of Q^n.
47    acc.get(&[0, 1]).expect("index in bounds") as u64
48}
examples/35_linear_regression_gradient_descent.rs (line 36)
34fn gd_step(x: &Tensor, xt: &Tensor, theta: &Tensor, y: &[f64], lr: f64) -> Tensor {
35    let n = y.len() as f64;
36    let pred = x.matmul(theta); // [n]
37    let residual: Vec<f64> = pred.as_slice().iter().zip(y).map(|(p, t)| p - t).collect();
38    let grad = xt.matmul(&Tensor::from_vec(residual)); // [features]
39    let updated: Vec<f64> = theta
40        .as_slice()
41        .iter()
42        .zip(grad.as_slice())
43        .map(|(w, g)| w - lr * (2.0 / n) * g)
44        .collect();
45    Tensor::from_vec(updated)
46}
Source§

impl Tensor

Source

pub fn abs(&self) -> Tensor

Elementwise absolute value. Shape is preserved.

use matten::Tensor;
let t = Tensor::new(vec![-1.0, 2.0, -3.0, 4.0], &[2, 2]);
assert_eq!(t.abs().as_slice(), &[1.0, 2.0, 3.0, 4.0]);
Source

pub fn sqrt(&self) -> Tensor

Elementwise square root. Shape is preserved; a negative element yields NaN.

use matten::Tensor;
let t = Tensor::from_vec(vec![1.0, 4.0, 9.0]);
assert_eq!(t.sqrt().as_slice(), &[1.0, 2.0, 3.0]);
Source

pub fn exp(&self) -> Tensor

Elementwise natural exponential e^x. Shape is preserved.

use matten::Tensor;
let t = Tensor::from_vec(vec![0.0, 1.0]);
let r = t.exp();
assert_eq!(r.as_slice()[0], 1.0);
assert!((r.as_slice()[1] - std::f64::consts::E).abs() < 1e-12);
Source

pub fn ln(&self) -> Tensor

Elementwise natural logarithm. Shape is preserved; ln(0.0) is -inf and a negative element yields NaN.

use matten::Tensor;
let t = Tensor::from_vec(vec![1.0, std::f64::consts::E]);
let r = t.ln();
assert_eq!(r.as_slice()[0], 0.0);
assert!((r.as_slice()[1] - 1.0).abs() < 1e-12);
Source

pub fn clip(&self, min: f64, max: f64) -> Tensor

Elementwise clamp into [min, max]. Shape is preserved.

§Panics

Panics if min > max (or either bound is NaN). Use Tensor::try_clip for the non-panicking form.

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

pub fn try_clip(&self, min: f64, max: f64) -> Result<Tensor, MattenError>

Non-panicking Tensor::clip.

Returns MattenError::InvalidArgument if min > max, or MattenError::Unsupported if called on a dynamic tensor.

use matten::Tensor;
let t = Tensor::from_vec(vec![-5.0, 0.5, 9.0]);
assert_eq!(t.try_clip(0.0, 1.0).unwrap().as_slice(), &[0.0, 0.5, 1.0]);
assert!(t.try_clip(1.0, 0.0).is_err());
Source§

impl Tensor

Source

pub fn argmin(&self) -> usize

Flat (row-major) index of the smallest element; first occurrence on ties.

§Panics

Panics if any element is NaN (the index would be ill-defined), or if called on a dynamic tensor. Use Tensor::try_argmin for the non-panicking form.

use matten::Tensor;
let t = Tensor::new(vec![3.0, 1.0, 5.0, 1.0], &[2, 2]);
assert_eq!(t.argmin(), 1); // first of the two 1.0s
Examples found in repository?
examples/37_kmeans_small.rs (line 47)
45fn nearest(point: &[f64], centroids: &[Vec<f64>]) -> usize {
46    let dists: Vec<f64> = centroids.iter().map(|c| sq_dist(point, c)).collect();
47    Tensor::from_vec(dists).argmin()
48}
More examples
Hide additional examples
examples/38_nearest_neighbor_classification.rs (line 47)
41fn classify(query: &[f64], train: &Tensor, labels: &[u8]) -> u8 {
42    let dim = train.shape()[1];
43    let data = train.as_slice();
44    let dists: Vec<f64> = (0..train.shape()[0])
45        .map(|i| sq_dist(query, &data[i * dim..(i + 1) * dim]))
46        .collect();
47    labels[Tensor::from_vec(dists).argmin()]
48}
Source

pub fn argmax(&self) -> usize

Flat (row-major) index of the largest element; first occurrence on ties.

§Panics

Panics if any element is NaN, or if called on a dynamic tensor. Use Tensor::try_argmax for the non-panicking form.

use matten::Tensor;
let t = Tensor::from_vec(vec![3.0, 1.0, 5.0, 5.0]);
assert_eq!(t.argmax(), 2); // first of the two 5.0s
Source

pub fn try_argmin(&self) -> Result<usize, MattenError>

Non-panicking Tensor::argmin.

Returns MattenError::InvalidArgument if any element is NaN, or MattenError::Unsupported if called on a dynamic tensor.

use matten::Tensor;
assert_eq!(Tensor::from_vec(vec![3.0, 1.0, 2.0]).try_argmin().unwrap(), 1);
assert!(Tensor::from_vec(vec![1.0, f64::NAN]).try_argmin().is_err());
Source

pub fn try_argmax(&self) -> Result<usize, MattenError>

Non-panicking Tensor::argmax.

Returns MattenError::InvalidArgument if any element is NaN, or MattenError::Unsupported if called on a dynamic tensor.

use matten::Tensor;
assert_eq!(Tensor::from_vec(vec![3.0, 1.0, 2.0]).try_argmax().unwrap(), 0);
assert!(Tensor::from_vec(vec![1.0, f64::NAN]).try_argmax().is_err());
Source§

impl Tensor

Source

pub fn reshape(&self, new_shape: &[usize]) -> Tensor

Reshapes the tensor to new_shape, returning a new owned tensor.

The total element count must be unchanged. Data order is preserved (row-major flat order).

§Panics

Panics on element-count mismatch or invalid shape. Use try_reshape for recoverable construction.

use matten::Tensor;
let t = Tensor::new(vec![1.0, 2.0, 3.0, 4.0], &[2, 2]);
let flat = t.reshape(&[4]);
assert_eq!(flat.shape(), &[4]);
assert_eq!(flat.as_slice(), &[1.0, 2.0, 3.0, 4.0]);
Examples found in repository?
examples/03_reshape_flatten.rs (line 11)
7fn main() {
8    let t = Tensor::new(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0], &[2, 3]);
9    println!("original  {t:?}");
10
11    let r = t.reshape(&[3, 2]);
12    println!("reshaped  {r:?}");
13
14    let flat = t.flatten();
15    println!("flat      {flat:?}");
16
17    // try_reshape for user-provided shapes
18    let bad = t.try_reshape(&[4, 2]);
19    println!("bad reshape: {}", bad.unwrap_err());
20
21    // Flat data order is preserved through reshape
22    assert_eq!(t.as_slice(), r.as_slice());
23    println!("Flat data order preserved: OK");
24}
More examples
Hide additional examples
examples/pairwise_distance.rs (line 21)
9fn pairwise_euclidean(points: &Tensor) -> Tensor {
10    let n = points.shape()[0];
11
12    // Row-wise squared norms: shape [n]
13    let sq = points * points;
14    let row_sq_norms = sq.sum_axis(1); // [n]
15
16    // Gram matrix: G[i,j] = points[i] · points[j], shape [n,n]
17    let gram = points.matmul(&points.transpose());
18
19    // dist²[i,j] = sq_norm[i] + sq_norm[j] - 2·G[i,j]
20    // Broadcast [n] as column [n,1] + row [1,n]
21    let col = row_sq_norms.reshape(&[n, 1]);
22    let row = row_sq_norms.reshape(&[1, n]);
23    let dist_sq = &(&col + &row) - &(&gram * 2.0);
24
25    // Clamp small negatives from floating-point rounding, then sqrt
26    let dists: Vec<f64> = dist_sq
27        .as_slice()
28        .iter()
29        .map(|&v| if v < 0.0 { 0.0 } else { v.sqrt() })
30        .collect();
31    Tensor::new(dists, &[n, n])
32}
Source

pub fn try_reshape(&self, new_shape: &[usize]) -> Result<Tensor, MattenError>

Reshapes the tensor, returning an error instead of panicking.

§Errors

Returns MattenError::Shape on element-count mismatch or invalid shape.

Examples found in repository?
examples/03_reshape_flatten.rs (line 18)
7fn main() {
8    let t = Tensor::new(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0], &[2, 3]);
9    println!("original  {t:?}");
10
11    let r = t.reshape(&[3, 2]);
12    println!("reshaped  {r:?}");
13
14    let flat = t.flatten();
15    println!("flat      {flat:?}");
16
17    // try_reshape for user-provided shapes
18    let bad = t.try_reshape(&[4, 2]);
19    println!("bad reshape: {}", bad.unwrap_err());
20
21    // Flat data order is preserved through reshape
22    assert_eq!(t.as_slice(), r.as_slice());
23    println!("Flat data order preserved: OK");
24}
Source

pub fn flatten(&self) -> Tensor

Flattens the tensor to a 1-D tensor, preserving row-major order.

A scalar (shape []) is returned as shape [1].

use matten::Tensor;
let t = Tensor::new(vec![1.0, 2.0, 3.0, 4.0], &[2, 2]);
let flat = t.flatten();
assert_eq!(flat.shape(), &[4]);
Examples found in repository?
examples/00_quickstart.rs (line 20)
11fn main() {
12    let a = Tensor::new(vec![1.0, 2.0, 3.0, 4.0], &[2, 2]);
13    let b = Tensor::ones(&[2, 2]);
14
15    let c = &a + &b;
16    println!("a      = {a:?}");
17    println!("b      = {b:?}");
18    println!("a + b  = {c:?}");
19
20    let flat = c.flatten();
21    println!("flat   = {flat:?}");
22
23    assert_eq!(flat.shape(), &[4]);
24    assert_eq!(flat.as_slice(), &[2.0, 3.0, 4.0, 5.0]);
25    println!("All assertions passed.");
26}
More examples
Hide additional examples
examples/03_reshape_flatten.rs (line 14)
7fn main() {
8    let t = Tensor::new(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0], &[2, 3]);
9    println!("original  {t:?}");
10
11    let r = t.reshape(&[3, 2]);
12    println!("reshaped  {r:?}");
13
14    let flat = t.flatten();
15    println!("flat      {flat:?}");
16
17    // try_reshape for user-provided shapes
18    let bad = t.try_reshape(&[4, 2]);
19    println!("bad reshape: {}", bad.unwrap_err());
20
21    // Flat data order is preserved through reshape
22    assert_eq!(t.as_slice(), r.as_slice());
23    println!("Flat data order preserved: OK");
24}
Source

pub fn transpose(&self) -> Tensor

Transposes the tensor by reversing the axis order.

For a rank-2 tensor this swaps rows and columns. For rank > 2 the axis order is reversed: [d0, d1, d2] → [d2, d1, d0].

§Panics

Panics for a rank-0 scalar (no axes to transpose).

use matten::Tensor;
let m = Tensor::new(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0], &[2, 3]);
let mt = m.transpose();
assert_eq!(mt.shape(), &[3, 2]);
assert_eq!(mt.as_slice(), &[1.0, 4.0, 2.0, 5.0, 3.0, 6.0]);
Examples found in repository?
examples/21_matrix_vector_product.rs (line 24)
9fn main() {
10    // [[1,2,3],[4,5,6]] × [1,0,1] = [4, 10]
11    let m = Tensor::new(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0], &[2, 3]);
12    let v = Tensor::from_vec(vec![1.0, 0.0, 1.0]);
13
14    let r = m.matmul(&v);
15    println!("m    = {m:?}");
16    println!("v    = {v:?}");
17    println!("m·v  = {r:?}"); // [4.0, 10.0]
18
19    assert_eq!(r.shape(), &[2]);
20    assert_eq!(r.as_slice(), &[4.0, 10.0]);
21
22    // Vector × matrix: [n] × [n, p] -> [p]
23    let w = Tensor::from_vec(vec![1.0, 2.0]);
24    let r2 = w.matmul(&m.transpose());
25    println!("w·mᵀ = {r2:?}");
26
27    println!("Shapes and values verified: OK");
28}
More examples
Hide additional examples
examples/07_transpose_swap_axes.rs (line 11)
7fn main() {
8    // 2-D transpose: swap rows and columns
9    let m = Tensor::new(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0], &[2, 3]);
10    println!("original  {m:?}");
11    let mt = m.transpose();
12    println!("transposed {mt:?}");
13    assert_eq!(mt.shape(), &[3, 2]);
14
15    // t() is an alias
16    assert_eq!(m.t(), mt);
17
18    // Transpose twice is identity
19    assert_eq!(m.transpose().transpose(), m);
20    println!("transpose twice == identity: OK");
21
22    // swap_axes on rank-3
23    let r3 = Tensor::new((1..=24).map(|x| x as f64).collect(), &[2, 3, 4]);
24    let s = r3.swap_axes(0, 2);
25    println!("rank-3 swap_axes(0,2) shape: {:?}", s.shape()); // [4,3,2]
26}
examples/gram_matrix.rs (line 15)
7fn main() {
8    // 4 data points × 3 features
9    let x = Tensor::new(
10        vec![1.0, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0],
11        &[4, 3],
12    );
13
14    // G = X · Xᵀ: shape [4,4]
15    let g = x.matmul(&x.transpose());
16    println!("Gram matrix shape = {:?}", g.shape()); // [4,4]
17
18    // Diagonal: ||x_i||²
19    for i in 0..4 {
20        let diag = g.get(&[i, i]).unwrap();
21        println!("G[{i},{i}] = {diag:.1}");
22    }
23
24    // Symmetric check
25    for i in 0..4 {
26        for j in 0..4 {
27            assert!((g.get(&[i, j]).unwrap() - g.get(&[j, i]).unwrap()).abs() < 1e-10);
28        }
29    }
30    println!("Gram matrix is symmetric: OK");
31}
examples/pairwise_distance.rs (line 17)
9fn pairwise_euclidean(points: &Tensor) -> Tensor {
10    let n = points.shape()[0];
11
12    // Row-wise squared norms: shape [n]
13    let sq = points * points;
14    let row_sq_norms = sq.sum_axis(1); // [n]
15
16    // Gram matrix: G[i,j] = points[i] · points[j], shape [n,n]
17    let gram = points.matmul(&points.transpose());
18
19    // dist²[i,j] = sq_norm[i] + sq_norm[j] - 2·G[i,j]
20    // Broadcast [n] as column [n,1] + row [1,n]
21    let col = row_sq_norms.reshape(&[n, 1]);
22    let row = row_sq_norms.reshape(&[1, n]);
23    let dist_sq = &(&col + &row) - &(&gram * 2.0);
24
25    // Clamp small negatives from floating-point rounding, then sqrt
26    let dists: Vec<f64> = dist_sq
27        .as_slice()
28        .iter()
29        .map(|&v| if v < 0.0 { 0.0 } else { v.sqrt() })
30        .collect();
31    Tensor::new(dists, &[n, n])
32}
examples/35_linear_regression_gradient_descent.rs (line 62)
48fn main() {
49    // Data generated from the true line y = 2x + 1.
50    // Design matrix X carries a leading bias column, so theta = [b, w].
51    let x = Tensor::new(
52        vec![
53            1.0, 0.0, //
54            1.0, 1.0, //
55            1.0, 2.0, //
56            1.0, 3.0, //
57            1.0, 4.0, //
58        ],
59        &[5, 2],
60    );
61    let y = [1.0, 3.0, 5.0, 7.0, 9.0];
62    let xt = x.transpose(); // [2, 5], formed once and reused each step
63
64    let mut theta = Tensor::from_vec(vec![0.0, 0.0]); // [b, w]
65    let lr = 0.05;
66    for _ in 0..2000 {
67        theta = gd_step(&x, &xt, &theta, &y, lr);
68    }
69
70    let p = theta.as_slice();
71    println!("fitted: y = {:.4}*x + {:.4}", p[1], p[0]);
72    println!("target: y = 2*x + 1");
73
74    assert!((p[0] - 1.0).abs() < 0.05, "intercept ~ 1");
75    assert!((p[1] - 2.0).abs() < 0.05, "slope ~ 2");
76    println!("Linear regression (gradient descent): OK");
77}
Source

pub fn t(&self) -> Tensor

Alias for transpose.

Examples found in repository?
examples/07_transpose_swap_axes.rs (line 16)
7fn main() {
8    // 2-D transpose: swap rows and columns
9    let m = Tensor::new(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0], &[2, 3]);
10    println!("original  {m:?}");
11    let mt = m.transpose();
12    println!("transposed {mt:?}");
13    assert_eq!(mt.shape(), &[3, 2]);
14
15    // t() is an alias
16    assert_eq!(m.t(), mt);
17
18    // Transpose twice is identity
19    assert_eq!(m.transpose().transpose(), m);
20    println!("transpose twice == identity: OK");
21
22    // swap_axes on rank-3
23    let r3 = Tensor::new((1..=24).map(|x| x as f64).collect(), &[2, 3, 4]);
24    let s = r3.swap_axes(0, 2);
25    println!("rank-3 swap_axes(0,2) shape: {:?}", s.shape()); // [4,3,2]
26}
Source

pub fn swap_axes(&self, axis1: usize, axis2: usize) -> Tensor

Returns a new tensor with axis1 and axis2 swapped.

§Panics

Panics if either axis is out of range.

use matten::Tensor;
let t = Tensor::new((1..=24).map(|x| x as f64).collect(), &[2, 3, 4]);
let s = t.swap_axes(0, 2);
assert_eq!(s.shape(), &[4, 3, 2]);
Examples found in repository?
examples/07_transpose_swap_axes.rs (line 24)
7fn main() {
8    // 2-D transpose: swap rows and columns
9    let m = Tensor::new(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0], &[2, 3]);
10    println!("original  {m:?}");
11    let mt = m.transpose();
12    println!("transposed {mt:?}");
13    assert_eq!(mt.shape(), &[3, 2]);
14
15    // t() is an alias
16    assert_eq!(m.t(), mt);
17
18    // Transpose twice is identity
19    assert_eq!(m.transpose().transpose(), m);
20    println!("transpose twice == identity: OK");
21
22    // swap_axes on rank-3
23    let r3 = Tensor::new((1..=24).map(|x| x as f64).collect(), &[2, 3, 4]);
24    let s = r3.swap_axes(0, 2);
25    println!("rank-3 swap_axes(0,2) shape: {:?}", s.shape()); // [4,3,2]
26}
Source

pub fn squeeze(&self) -> Tensor

Removes all axes of length 1, returning a new owned tensor.

Data order is unchanged. A scalar stays a scalar, and a tensor whose every axis is 1 (e.g. [1, 1]) becomes a scalar (shape []).

§Panics

Panics on a dynamic tensor; call try_numeric() first.

use matten::Tensor;
let t = Tensor::new(vec![1.0, 2.0, 3.0], &[1, 3, 1]);
assert_eq!(t.squeeze().shape(), &[3]);
Source

pub fn expand_dims(&self, axis: usize) -> Tensor

Inserts a new axis of length 1 at axis, returning a new owned tensor.

axis may be 0..=ndim (inserting at ndim appends a trailing axis). Data order is unchanged.

§Panics

Panics if axis > ndim, or on a dynamic tensor. Use try_expand_dims for the non-panicking form.

use matten::Tensor;
let t = Tensor::from_vec(vec![1.0, 2.0, 3.0]);
assert_eq!(t.expand_dims(0).shape(), &[1, 3]);
assert_eq!(t.expand_dims(1).shape(), &[3, 1]);
Source

pub fn try_expand_dims(&self, axis: usize) -> Result<Tensor, MattenError>

Non-panicking expand_dims.

§Errors

Returns MattenError::InvalidArgument if axis > ndim, or MattenError::Unsupported on a dynamic tensor.

use matten::Tensor;
let t = Tensor::from_vec(vec![1.0, 2.0, 3.0]);
assert!(t.try_expand_dims(5).is_err());
Source

pub fn get(&self, coord: &[usize]) -> Option<f64>

Returns the element at the multidimensional coord, or None if the coordinate rank doesn’t match or any component is out of bounds.

use matten::Tensor;
let t = Tensor::new(vec![1.0, 2.0, 3.0, 4.0], &[2, 2]);
assert_eq!(t.get(&[0, 1]), Some(2.0));
assert_eq!(t.get(&[5, 0]), None);
Examples found in repository?
examples/32_graph_path_counting.rs (line 63)
58fn print_matrix(label: &str, m: &Tensor) {
59    let (rows, cols) = (m.shape()[0], m.shape()[1]);
60    println!("{label}:");
61    for i in 0..rows {
62        let row: Vec<String> = (0..cols)
63            .map(|j| format!("{:.0}", m.get(&[i, j]).expect("index in bounds")))
64            .collect();
65        println!("  [{}]", row.join(", "));
66    }
67}
68
69fn main() {
70    // Directed graph on 4 nodes:
71    //   0 -> 1, 0 -> 2, 1 -> 2, 1 -> 3, 2 -> 3
72    //
73    //        to: 0  1  2  3
74    //   from 0 [ 0  1  1  0 ]
75    //        1 [ 0  0  1  1 ]
76    //        2 [ 0  0  0  1 ]
77    //        3 [ 0  0  0  0 ]
78    let a = Tensor::new(
79        vec![
80            0.0, 1.0, 1.0, 0.0, //
81            0.0, 0.0, 1.0, 1.0, //
82            0.0, 0.0, 0.0, 1.0, //
83            0.0, 0.0, 0.0, 0.0, //
84        ],
85        &[4, 4],
86    );
87
88    let a2 = matrix_power(&a, 2);
89    let a3 = matrix_power(&a, 3);
90
91    print_matrix("A^2", &a2);
92    print_matrix("A^3", &a3);
93
94    // From node 0 to node 3: two length-2 walks (0->1->3, 0->2->3)
95    // and one length-3 walk (0->1->2->3).
96    let walks2 = a2.get(&[0, 3]).expect("index in bounds");
97    let walks3 = a3.get(&[0, 3]).expect("index in bounds");
98    println!("walks of length 2 from 0 to 3 = {walks2:.0}");
99    println!("walks of length 3 from 0 to 3 = {walks3:.0}");
100
101    assert_eq!(walks2, 2.0);
102    assert_eq!(walks3, 1.0);
103    println!("Graph path counting: OK");
104}
More examples
Hide additional examples
examples/31_fibonacci_matrix_power.rs (line 47)
39fn fib(n: u32) -> u64 {
40    let q = Tensor::new(vec![1.0, 1.0, 1.0, 0.0], &[2, 2]);
41    // Start from the 2×2 identity so that `fib(0)` returns 0.
42    let mut acc = Tensor::new(vec![1.0, 0.0, 0.0, 1.0], &[2, 2]);
43    for _ in 0..n {
44        acc = acc.matmul(&q);
45    }
46    // F(n) is the top-right entry of Q^n.
47    acc.get(&[0, 1]).expect("index in bounds") as u64
48}
examples/pairwise_distance.rs (line 45)
34fn main() {
35    let points = Tensor::new(vec![0.0, 0.0, 3.0, 4.0, 6.0, 0.0], &[3, 2]);
36
37    let dists = pairwise_euclidean(&points);
38    println!("pairwise distances:");
39    for i in 0..3 {
40        let row = dists.slice().index(i).all().build().unwrap();
41        println!("  row {i}: {:?}", row.as_slice());
42    }
43
44    // (0,0)→(3,4) = 5, (3,4)→(6,0) = 5, (0,0)→(6,0) = 6
45    assert!((dists.get(&[0, 1]).unwrap() - 5.0).abs() < 1e-9);
46    assert!((dists.get(&[1, 2]).unwrap() - 5.0).abs() < 1e-9);
47    assert!((dists.get(&[0, 2]).unwrap() - 6.0).abs() < 1e-9);
48    println!("Pairwise distances: OK");
49}
examples/gram_matrix.rs (line 20)
7fn main() {
8    // 4 data points × 3 features
9    let x = Tensor::new(
10        vec![1.0, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0],
11        &[4, 3],
12    );
13
14    // G = X · Xᵀ: shape [4,4]
15    let g = x.matmul(&x.transpose());
16    println!("Gram matrix shape = {:?}", g.shape()); // [4,4]
17
18    // Diagonal: ||x_i||²
19    for i in 0..4 {
20        let diag = g.get(&[i, i]).unwrap();
21        println!("G[{i},{i}] = {diag:.1}");
22    }
23
24    // Symmetric check
25    for i in 0..4 {
26        for j in 0..4 {
27            assert!((g.get(&[i, j]).unwrap() - g.get(&[j, i]).unwrap()).abs() < 1e-10);
28        }
29    }
30    println!("Gram matrix is symmetric: OK");
31}
examples/02_shape_and_size.rs (line 32)
8fn main() {
9    let scalar = Tensor::scalar(1.0);
10    let vec1d = Tensor::from_vec(vec![1.0, 2.0, 3.0]);
11    let mat = Tensor::new(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0], &[2, 3]);
12    let rank3 = Tensor::zeros(&[2, 3, 4]);
13
14    for (name, t) in [
15        ("scalar", &scalar),
16        ("vector", &vec1d),
17        ("matrix", &mat),
18        ("rank-3", &rank3),
19    ] {
20        println!(
21            "{name:6}: shape={:?}  ndim={}  len={}  is_scalar={}  is_vector={}  is_matrix={}",
22            t.shape(),
23            t.ndim(),
24            t.len(),
25            t.is_scalar(),
26            t.is_vector(),
27            t.is_matrix()
28        );
29    }
30
31    // Safe element access: Option<f64>, never panics
32    println!("\nmat.get([0,1]) = {:?}", mat.get(&[0, 1])); // Some(2.0)
33    println!("mat.get([5,0]) = {:?}", mat.get(&[5, 0])); // None
34}
examples/30_magic_square_checker.rs (line 43)
37fn magic_sum(m: &Tensor) -> Option<f64> {
38    let shape = m.shape();
39    if shape.len() != 2 || shape[0] != shape[1] || shape[0] == 0 {
40        return None;
41    }
42    let n = shape[0];
43    let at = |i: usize, j: usize| m.get(&[i, j]).expect("index in bounds");
44
45    // Target is the sum of the first row.
46    let target: f64 = (0..n).map(|j| at(0, j)).sum();
47
48    // Every row must match.
49    for i in 0..n {
50        let row: f64 = (0..n).map(|j| at(i, j)).sum();
51        if row != target {
52            return None;
53        }
54    }
55    // Every column must match.
56    for j in 0..n {
57        let col: f64 = (0..n).map(|i| at(i, j)).sum();
58        if col != target {
59            return None;
60        }
61    }
62    // Both diagonals must match.
63    let main_diag: f64 = (0..n).map(|i| at(i, i)).sum();
64    let anti_diag: f64 = (0..n).map(|i| at(i, n - 1 - i)).sum();
65    if main_diag != target || anti_diag != target {
66        return None;
67    }
68
69    Some(target)
70}
Source

pub fn get_flat(&self, index: usize) -> Option<f64>

Returns the element at flat row-major index, or None if out of bounds.

This is the flat-index companion to get. The index follows the same row-major layout as as_slice.

use matten::Tensor;
let t = Tensor::new(vec![1.0, 2.0, 3.0, 4.0], &[2, 2]);
assert_eq!(t.get_flat(1), Some(2.0));
assert_eq!(t.get_flat(10), None);
Source

pub fn slice(&self) -> SliceBuilder<'_>

Starts a slice builder for this tensor. The builder is the canonical slicing API; slice_str is a convenience wrapper.

use matten::Tensor;
let t = Tensor::new(vec![1.0,2.0,3.0,4.0,5.0,6.0], &[2, 3]);
let row = t.slice().index(0).all().build().unwrap();
assert_eq!(row.as_slice(), &[1.0, 2.0, 3.0]);
Examples found in repository?
examples/rolling_windows_basic.rs (line 9)
7fn rolling_sum(t: &Tensor, window: usize) -> Vec<f64> {
8    (0..=(t.len() - window))
9        .map(|i| t.slice().range(i..i + window).build().unwrap().sum())
10        .collect()
11}
12
13fn rolling_max(t: &Tensor, window: usize) -> Vec<f64> {
14    (0..=(t.len() - window))
15        .map(|i| t.slice().range(i..i + window).build().unwrap().max())
16        .collect()
17}
More examples
Hide additional examples
examples/pairwise_distance.rs (line 40)
34fn main() {
35    let points = Tensor::new(vec![0.0, 0.0, 3.0, 4.0, 6.0, 0.0], &[3, 2]);
36
37    let dists = pairwise_euclidean(&points);
38    println!("pairwise distances:");
39    for i in 0..3 {
40        let row = dists.slice().index(i).all().build().unwrap();
41        println!("  row {i}: {:?}", row.as_slice());
42    }
43
44    // (0,0)→(3,4) = 5, (3,4)→(6,0) = 5, (0,0)→(6,0) = 6
45    assert!((dists.get(&[0, 1]).unwrap() - 5.0).abs() < 1e-9);
46    assert!((dists.get(&[1, 2]).unwrap() - 5.0).abs() < 1e-9);
47    assert!((dists.get(&[0, 2]).unwrap() - 6.0).abs() < 1e-9);
48    println!("Pairwise distances: OK");
49}
examples/moving_average.rs (line 15)
7fn main() {
8    let series = Tensor::from_vec(vec![1.0, 3.0, 5.0, 7.0, 9.0, 11.0, 13.0]);
9    let window = 3usize;
10    let n = series.len();
11
12    // Compute moving averages for windows [0..3], [1..4], ...
13    let mut avgs = Vec::new();
14    for start in 0..=(n - window) {
15        let w = series.slice().range(start..start + window).build().unwrap();
16        avgs.push(w.mean());
17    }
18
19    println!("series = {:?}", series.as_slice());
20    println!("3-pt moving avg = {:?}", avgs);
21    assert_eq!(avgs.len(), n - window + 1);
22    assert!((avgs[0] - 3.0).abs() < 1e-10); // mean(1,3,5) = 3
23    assert!((avgs[1] - 5.0).abs() < 1e-10); // mean(3,5,7) = 5
24    println!("Moving average: OK");
25}
examples/08_slicing_builder.rs (line 14)
9fn main() -> Result<(), Box<dyn std::error::Error>> {
10    let t = Tensor::new((1..=12).map(|x| x as f64).collect(), &[3, 4]);
11    println!("tensor   {t:?}");
12
13    // First row (index 0, axis removed from output shape)
14    let row0 = t.slice().index(0).all().build()?;
15    println!("row 0    {row0:?}"); // shape [4]
16
17    // First two rows, all columns
18    let top2 = t.slice().range(0..2).all().build()?;
19    println!("top 2    {top2:?}"); // shape [2,4]
20
21    // All rows, columns 1..3
22    let cols = t.slice().all().range(1..3).build()?;
23    println!("cols 1:3 {cols:?}"); // shape [3,2]
24
25    // Single element -> scalar
26    let elem = t.slice().index(1).index(2).build()?;
27    assert!(elem.is_scalar());
28    println!("t[1,2]   {elem:?}");
29
30    Ok(())
31}
examples/09_slice_str.rs (line 25)
10fn main() -> Result<(), Box<dyn std::error::Error>> {
11    let t = Tensor::new((1..=12).map(|x| x as f64).collect(), &[3, 4]);
12
13    println!("\"0, :\"    = {:?}", t.slice_str("0, :")?);
14    println!("\"0:2, :\" = {:?}", t.slice_str("0:2, :")?);
15    println!("\":, 1:3\" = {:?}", t.slice_str(":, 1:3")?);
16
17    // Whitespace is ignored
18    let a = t.slice_str("0:2, :")?;
19    let b = t.slice_str(" 0:2 , : ")?;
20    assert_eq!(a, b);
21    println!("whitespace-insensitive: OK");
22
23    // builder and slice_str agree
24    let from_str = t.slice_str("0:2, :")?;
25    let from_builder = t.slice().range(0..2).all().build()?;
26    assert_eq!(from_str, from_builder);
27    println!("builder == slice_str: OK");
28
29    // Malformed specs never panic
30    println!("bad spec: {:?}", t.slice_str("0::")); // Err
31
32    Ok(())
33}
examples/minmax_scaling.rs (line 26)
7fn main() {
8    let data = Tensor::new(
9        vec![1.0, 10.0, 100.0, 2.0, 20.0, 200.0, 3.0, 30.0, 300.0],
10        &[3, 3],
11    );
12
13    // Column min and max using axis reductions
14    let col_min = data.min_axis(0);
15    let col_max = data.max_axis(0);
16    let range = &col_max - &col_min;
17
18    // Broadcast: (data - min) / (max - min)
19    let scaled = &(&data - &col_min) / &range;
20
21    println!("col_min  = {:?}", col_min.as_slice());
22    println!("col_max  = {:?}", col_max.as_slice());
23    println!("scaled shape = {:?}", scaled.shape());
24
25    // First row should be all 0.0, last row all 1.0
26    let row0 = scaled.slice().index(0).all().build().unwrap();
27    let row2 = scaled.slice().index(2).all().build().unwrap();
28    assert!(row0.as_slice().iter().all(|&v| (v - 0.0).abs() < 1e-10));
29    assert!(row2.as_slice().iter().all(|&v| (v - 1.0).abs() < 1e-10));
30    println!("Min-max scaling: OK");
31}
Source

pub fn slice_str(&self, spec: &str) -> Result<Tensor, MattenError>

Slices this tensor using a NumPy-like string specification.

This is a convenience wrapper over the builder API. It always returns Result and never panics on malformed input.

§Errors

Returns MattenError::Slice for any parse or bounds error.

use matten::Tensor;
let t = Tensor::new(vec![1.0,2.0,3.0,4.0,5.0,6.0], &[2, 3]);
let top = t.slice_str("0, :").unwrap();
assert_eq!(top.as_slice(), &[1.0, 2.0, 3.0]);
Examples found in repository?
examples/09_slice_str.rs (line 13)
10fn main() -> Result<(), Box<dyn std::error::Error>> {
11    let t = Tensor::new((1..=12).map(|x| x as f64).collect(), &[3, 4]);
12
13    println!("\"0, :\"    = {:?}", t.slice_str("0, :")?);
14    println!("\"0:2, :\" = {:?}", t.slice_str("0:2, :")?);
15    println!("\":, 1:3\" = {:?}", t.slice_str(":, 1:3")?);
16
17    // Whitespace is ignored
18    let a = t.slice_str("0:2, :")?;
19    let b = t.slice_str(" 0:2 , : ")?;
20    assert_eq!(a, b);
21    println!("whitespace-insensitive: OK");
22
23    // builder and slice_str agree
24    let from_str = t.slice_str("0:2, :")?;
25    let from_builder = t.slice().range(0..2).all().build()?;
26    assert_eq!(from_str, from_builder);
27    println!("builder == slice_str: OK");
28
29    // Malformed specs never panic
30    println!("bad spec: {:?}", t.slice_str("0::")); // Err
31
32    Ok(())
33}
Source§

impl Tensor

Source

pub fn from_json(input: &str) -> Result<Tensor, MattenError>

Parses a JSON string into a Tensor.

Accepts the canonical {"shape":[…],"data":[…]} object form and the convenience nested-array form (rank 1 and 2). Returns MattenError::Parse for any error; never panics.

use matten::Tensor;

// Canonical object form
let t = Tensor::from_json(r#"{"shape":[2,2],"data":[1.0,2.0,3.0,4.0]}"#).unwrap();
assert_eq!(t.shape(), &[2, 2]);

// Nested-array convenience form
let t = Tensor::from_json("[[1.0,2.0],[3.0,4.0]]").unwrap();
assert_eq!(t.shape(), &[2, 2]);
Examples found in repository?
examples/10_json_roundtrip.rs (line 22)
11fn main() -> Result<(), Box<dyn std::error::Error>> {
12    // ── serde round-trip ────────────────────────────────────────────────
13    let original = Tensor::new(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0], &[2, 3]);
14    let json = serde_json::to_string(&original)?;
15    println!("serialised: {json}");
16
17    let restored: Tensor = serde_json::from_str(&json)?;
18    assert_eq!(original, restored);
19    println!("round-trip: OK  shape={:?}", restored.shape());
20
21    // ── from_json: canonical object form ────────────────────────────────
22    let t = Tensor::from_json(r#"{"shape":[2,2],"data":[1.0,2.0,3.0,4.0]}"#)?;
23    println!("object form:  {t:?}");
24
25    // ── from_json: nested-array convenience form ─────────────────────────
26    let t2 = Tensor::from_json("[[1.0,2.0],[3.0,4.0]]")?;
27    println!("nested form:  {t2:?}");
28
29    // ── load_json from file ──────────────────────────────────────────────
30    let t3 = Tensor::load_json("examples/data/tensor_2x2.json")?;
31    println!("from file:    {t3:?}");
32
33    Ok(())
34}
More examples
Hide additional examples
examples/12_boundary_error_handling.rs (line 20)
10fn main() {
11    // ── shape/data mismatch ──────────────────────────────────────────────
12    match Tensor::try_new(vec![1.0, 2.0], &[3]) {
13        Err(MattenError::Shape { operation, message }) => {
14            println!("[Shape]  {operation}: {message}")
15        }
16        other => println!("{other:?}"),
17    }
18
19    // ── malformed JSON ───────────────────────────────────────────────────
20    match Tensor::from_json(r#"[[1.0,"text"]]"#) {
21        Err(MattenError::Parse { format, message }) => println!("[Parse/{format}]  {message}"),
22        other => println!("{other:?}"),
23    }
24
25    // ── ragged JSON array ────────────────────────────────────────────────
26    match Tensor::from_json("[[1.0,2.0],[3.0]]") {
27        Err(MattenError::Parse { format, message }) => println!("[Parse/{format}]  {message}"),
28        other => println!("{other:?}"),
29    }
30
31    // ── non-numeric CSV field ────────────────────────────────────────────
32    match Tensor::load_csv("examples/data/malformed_numeric.csv") {
33        Err(MattenError::Parse { format, message }) => println!("[Parse/{format}]  {message}"),
34        other => println!("{other:?}"),
35    }
36
37    // ── missing file ─────────────────────────────────────────────────────
38    match Tensor::load_json("/no/such/file.json") {
39        Err(MattenError::Io { path, source }) => println!("[Io]  {}: {source}", path.display()),
40        other => println!("{other:?}"),
41    }
42
43    // ── slice out of range ───────────────────────────────────────────────
44    let t = Tensor::new(vec![1.0, 2.0, 3.0, 4.0], &[2, 2]);
45    match t.slice().index(5).all().build() {
46        Err(MattenError::Slice { message, .. }) => println!("[Slice]  {message}"),
47        other => println!("{other:?}"),
48    }
49
50    println!("All boundary errors handled gracefully — no panics.");
51}
Source

pub fn from_csv(input: &str) -> Result<Tensor, MattenError>

Parses a CSV string into a Tensor with shape [rows, cols].

All fields must be valid f64 values. Returns MattenError::Parse for ragged rows or non-numeric fields; never panics.

use matten::Tensor;

let t = Tensor::from_csv("1.0,2.0\n3.0,4.0\n").unwrap();
assert_eq!(t.shape(), &[2, 2]);
assert_eq!(t.as_slice(), &[1.0, 2.0, 3.0, 4.0]);
Examples found in repository?
examples/11_csv_numeric_loading.rs (line 12)
10fn main() -> Result<(), Box<dyn std::error::Error>> {
11    // ── from_csv: inline string ──────────────────────────────────────────
12    let t = Tensor::from_csv("1.0,2.0,3.0\n4.0,5.0,6.0\n")?;
13    println!(
14        "inline CSV:   shape={:?}  data={:?}",
15        t.shape(),
16        t.as_slice()
17    );
18
19    // ── load_csv: from file ──────────────────────────────────────────────
20    let t2 = Tensor::load_csv("examples/data/numeric_2x3.csv")?;
21    println!(
22        "from file:    shape={:?}  data={:?}",
23        t2.shape(),
24        t2.as_slice()
25    );
26
27    let t3 = Tensor::load_csv("examples/data/numeric_3x3.csv")?;
28    println!("3×3 from file: shape={:?}", t3.shape());
29
30    Ok(())
31}
Source

pub fn load_json(path: impl AsRef<Path>) -> Result<Tensor, MattenError>

Loads and parses a JSON file into a Tensor.

Returns MattenError::Io for file errors, MattenError::Parse for parse errors.

§Errors

Returns an error if the file cannot be read or the content is invalid.

Examples found in repository?
examples/10_json_roundtrip.rs (line 30)
11fn main() -> Result<(), Box<dyn std::error::Error>> {
12    // ── serde round-trip ────────────────────────────────────────────────
13    let original = Tensor::new(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0], &[2, 3]);
14    let json = serde_json::to_string(&original)?;
15    println!("serialised: {json}");
16
17    let restored: Tensor = serde_json::from_str(&json)?;
18    assert_eq!(original, restored);
19    println!("round-trip: OK  shape={:?}", restored.shape());
20
21    // ── from_json: canonical object form ────────────────────────────────
22    let t = Tensor::from_json(r#"{"shape":[2,2],"data":[1.0,2.0,3.0,4.0]}"#)?;
23    println!("object form:  {t:?}");
24
25    // ── from_json: nested-array convenience form ─────────────────────────
26    let t2 = Tensor::from_json("[[1.0,2.0],[3.0,4.0]]")?;
27    println!("nested form:  {t2:?}");
28
29    // ── load_json from file ──────────────────────────────────────────────
30    let t3 = Tensor::load_json("examples/data/tensor_2x2.json")?;
31    println!("from file:    {t3:?}");
32
33    Ok(())
34}
More examples
Hide additional examples
examples/12_boundary_error_handling.rs (line 38)
10fn main() {
11    // ── shape/data mismatch ──────────────────────────────────────────────
12    match Tensor::try_new(vec![1.0, 2.0], &[3]) {
13        Err(MattenError::Shape { operation, message }) => {
14            println!("[Shape]  {operation}: {message}")
15        }
16        other => println!("{other:?}"),
17    }
18
19    // ── malformed JSON ───────────────────────────────────────────────────
20    match Tensor::from_json(r#"[[1.0,"text"]]"#) {
21        Err(MattenError::Parse { format, message }) => println!("[Parse/{format}]  {message}"),
22        other => println!("{other:?}"),
23    }
24
25    // ── ragged JSON array ────────────────────────────────────────────────
26    match Tensor::from_json("[[1.0,2.0],[3.0]]") {
27        Err(MattenError::Parse { format, message }) => println!("[Parse/{format}]  {message}"),
28        other => println!("{other:?}"),
29    }
30
31    // ── non-numeric CSV field ────────────────────────────────────────────
32    match Tensor::load_csv("examples/data/malformed_numeric.csv") {
33        Err(MattenError::Parse { format, message }) => println!("[Parse/{format}]  {message}"),
34        other => println!("{other:?}"),
35    }
36
37    // ── missing file ─────────────────────────────────────────────────────
38    match Tensor::load_json("/no/such/file.json") {
39        Err(MattenError::Io { path, source }) => println!("[Io]  {}: {source}", path.display()),
40        other => println!("{other:?}"),
41    }
42
43    // ── slice out of range ───────────────────────────────────────────────
44    let t = Tensor::new(vec![1.0, 2.0, 3.0, 4.0], &[2, 2]);
45    match t.slice().index(5).all().build() {
46        Err(MattenError::Slice { message, .. }) => println!("[Slice]  {message}"),
47        other => println!("{other:?}"),
48    }
49
50    println!("All boundary errors handled gracefully — no panics.");
51}
Source

pub fn load_csv(path: impl AsRef<Path>) -> Result<Tensor, MattenError>

Loads and parses a CSV file into a Tensor with shape [rows, cols].

Returns MattenError::Io for file errors, MattenError::Parse for parse errors.

§Errors

Returns an error if the file cannot be read or the content is invalid.

Examples found in repository?
examples/11_csv_numeric_loading.rs (line 20)
10fn main() -> Result<(), Box<dyn std::error::Error>> {
11    // ── from_csv: inline string ──────────────────────────────────────────
12    let t = Tensor::from_csv("1.0,2.0,3.0\n4.0,5.0,6.0\n")?;
13    println!(
14        "inline CSV:   shape={:?}  data={:?}",
15        t.shape(),
16        t.as_slice()
17    );
18
19    // ── load_csv: from file ──────────────────────────────────────────────
20    let t2 = Tensor::load_csv("examples/data/numeric_2x3.csv")?;
21    println!(
22        "from file:    shape={:?}  data={:?}",
23        t2.shape(),
24        t2.as_slice()
25    );
26
27    let t3 = Tensor::load_csv("examples/data/numeric_3x3.csv")?;
28    println!("3×3 from file: shape={:?}", t3.shape());
29
30    Ok(())
31}
More examples
Hide additional examples
examples/12_boundary_error_handling.rs (line 32)
10fn main() {
11    // ── shape/data mismatch ──────────────────────────────────────────────
12    match Tensor::try_new(vec![1.0, 2.0], &[3]) {
13        Err(MattenError::Shape { operation, message }) => {
14            println!("[Shape]  {operation}: {message}")
15        }
16        other => println!("{other:?}"),
17    }
18
19    // ── malformed JSON ───────────────────────────────────────────────────
20    match Tensor::from_json(r#"[[1.0,"text"]]"#) {
21        Err(MattenError::Parse { format, message }) => println!("[Parse/{format}]  {message}"),
22        other => println!("{other:?}"),
23    }
24
25    // ── ragged JSON array ────────────────────────────────────────────────
26    match Tensor::from_json("[[1.0,2.0],[3.0]]") {
27        Err(MattenError::Parse { format, message }) => println!("[Parse/{format}]  {message}"),
28        other => println!("{other:?}"),
29    }
30
31    // ── non-numeric CSV field ────────────────────────────────────────────
32    match Tensor::load_csv("examples/data/malformed_numeric.csv") {
33        Err(MattenError::Parse { format, message }) => println!("[Parse/{format}]  {message}"),
34        other => println!("{other:?}"),
35    }
36
37    // ── missing file ─────────────────────────────────────────────────────
38    match Tensor::load_json("/no/such/file.json") {
39        Err(MattenError::Io { path, source }) => println!("[Io]  {}: {source}", path.display()),
40        other => println!("{other:?}"),
41    }
42
43    // ── slice out of range ───────────────────────────────────────────────
44    let t = Tensor::new(vec![1.0, 2.0, 3.0, 4.0], &[2, 2]);
45    match t.slice().index(5).all().build() {
46        Err(MattenError::Slice { message, .. }) => println!("[Slice]  {message}"),
47        other => println!("{other:?}"),
48    }
49
50    println!("All boundary errors handled gracefully — no panics.");
51}
Source§

impl Tensor

Source

pub fn new(data: Vec<f64>, shape: &[usize]) -> Tensor

Examples found in repository?
examples/hello_tensor.rs (line 8)
7fn main() {
8    let t = Tensor::new(vec![1.0, 2.0, 3.0, 4.0], &[2, 2]);
9    println!("{t:?}");
10    println!(
11        "shape = {:?}, len = {}, ndim = {}",
12        t.shape(),
13        t.len(),
14        t.ndim()
15    );
16}
More examples
Hide additional examples
examples/31_fibonacci_matrix_power.rs (line 40)
39fn fib(n: u32) -> u64 {
40    let q = Tensor::new(vec![1.0, 1.0, 1.0, 0.0], &[2, 2]);
41    // Start from the 2×2 identity so that `fib(0)` returns 0.
42    let mut acc = Tensor::new(vec![1.0, 0.0, 0.0, 1.0], &[2, 2]);
43    for _ in 0..n {
44        acc = acc.matmul(&q);
45    }
46    // F(n) is the top-right entry of Q^n.
47    acc.get(&[0, 1]).expect("index in bounds") as u64
48}
examples/00_quickstart.rs (line 12)
11fn main() {
12    let a = Tensor::new(vec![1.0, 2.0, 3.0, 4.0], &[2, 2]);
13    let b = Tensor::ones(&[2, 2]);
14
15    let c = &a + &b;
16    println!("a      = {a:?}");
17    println!("b      = {b:?}");
18    println!("a + b  = {c:?}");
19
20    let flat = c.flatten();
21    println!("flat   = {flat:?}");
22
23    assert_eq!(flat.shape(), &[4]);
24    assert_eq!(flat.as_slice(), &[2.0, 3.0, 4.0, 5.0]);
25    println!("All assertions passed.");
26}
examples/04_elementwise_ops.rs (line 8)
7fn main() {
8    let a = Tensor::new(vec![1.0, 2.0, 3.0, 4.0], &[2, 2]);
9    let b = Tensor::full(&[2, 2], 2.0);
10
11    println!("a        = {a:?}");
12    println!("b        = {b:?}");
13    println!("a + b    = {:?}", &a + &b);
14    println!("a - b    = {:?}", &a - &b);
15    println!("a * b    = {:?}", &a * &b); // element-wise, NOT matrix product
16    println!("a / b    = {:?}", &a / &b);
17    println!("-a       = {:?}", -&a);
18}
examples/05_scalar_ops.rs (line 8)
7fn main() {
8    let t = Tensor::new(vec![1.0, 2.0, 3.0, 4.0], &[2, 2]);
9
10    // tensor op scalar
11    println!("t + 10  = {:?}", &t + 10.0);
12    println!("t - 1   = {:?}", &t - 1.0);
13    println!("t * 2   = {:?}", &t * 2.0);
14    println!("t / 2   = {:?}", &t / 2.0);
15
16    // scalar op tensor
17    println!("10 + t  = {:?}", 10.0_f64 + &t);
18    println!("10 - t  = {:?}", 10.0_f64 - &t);
19    println!("2 * t   = {:?}", 2.0_f64 * &t);
20    println!("8 / t   = {:?}", 8.0_f64 / &t);
21}
examples/03_reshape_flatten.rs (line 8)
7fn main() {
8    let t = Tensor::new(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0], &[2, 3]);
9    println!("original  {t:?}");
10
11    let r = t.reshape(&[3, 2]);
12    println!("reshaped  {r:?}");
13
14    let flat = t.flatten();
15    println!("flat      {flat:?}");
16
17    // try_reshape for user-provided shapes
18    let bad = t.try_reshape(&[4, 2]);
19    println!("bad reshape: {}", bad.unwrap_err());
20
21    // Flat data order is preserved through reshape
22    assert_eq!(t.as_slice(), r.as_slice());
23    println!("Flat data order preserved: OK");
24}
Source

pub fn try_new(data: Vec<f64>, shape: &[usize]) -> Result<Tensor, MattenError>

Creates a tensor from row-major data and shape, returning an error instead of panicking.

§Errors

Returns MattenError::Shape for a length mismatch or invalid shape, or MattenError::Allocation on product overflow.

Examples found in repository?
examples/01_create_tensor.rs (line 33)
8fn main() {
9    // From data + shape
10    let t = Tensor::new(vec![1.0, 2.0, 3.0, 4.0], &[2, 2]);
11    println!("new:         {t:?}");
12
13    // Fill constructors
14    println!("zeros [3]:   {:?}", Tensor::zeros(&[3]));
15    println!("ones  [2,2]: {:?}", Tensor::ones(&[2, 2]));
16    println!("full  [3]:   {:?}", Tensor::full(&[3], -1.0));
17    println!("scalar:      {:?}", Tensor::scalar(42.0));
18
19    // From flat vec
20    println!(
21        "from_vec:    {:?}",
22        Tensor::from_vec(vec![10.0, 20.0, 30.0])
23    );
24
25    // Range
26    println!("arange:      {:?}", Tensor::arange(0.0, 5.0, 1.0));
27
28    // From nested rows (convenient for trusted literals)
29    let rows: Tensor = vec![vec![1.0, 2.0], vec![3.0, 4.0]].into();
30    println!("from rows:   {rows:?}");
31
32    // Boundary-safe construction
33    let result = Tensor::try_new(vec![1.0, 2.0], &[3]);
34    println!("try_new err: {}", result.unwrap_err());
35}
More examples
Hide additional examples
examples/12_boundary_error_handling.rs (line 12)
10fn main() {
11    // ── shape/data mismatch ──────────────────────────────────────────────
12    match Tensor::try_new(vec![1.0, 2.0], &[3]) {
13        Err(MattenError::Shape { operation, message }) => {
14            println!("[Shape]  {operation}: {message}")
15        }
16        other => println!("{other:?}"),
17    }
18
19    // ── malformed JSON ───────────────────────────────────────────────────
20    match Tensor::from_json(r#"[[1.0,"text"]]"#) {
21        Err(MattenError::Parse { format, message }) => println!("[Parse/{format}]  {message}"),
22        other => println!("{other:?}"),
23    }
24
25    // ── ragged JSON array ────────────────────────────────────────────────
26    match Tensor::from_json("[[1.0,2.0],[3.0]]") {
27        Err(MattenError::Parse { format, message }) => println!("[Parse/{format}]  {message}"),
28        other => println!("{other:?}"),
29    }
30
31    // ── non-numeric CSV field ────────────────────────────────────────────
32    match Tensor::load_csv("examples/data/malformed_numeric.csv") {
33        Err(MattenError::Parse { format, message }) => println!("[Parse/{format}]  {message}"),
34        other => println!("{other:?}"),
35    }
36
37    // ── missing file ─────────────────────────────────────────────────────
38    match Tensor::load_json("/no/such/file.json") {
39        Err(MattenError::Io { path, source }) => println!("[Io]  {}: {source}", path.display()),
40        other => println!("{other:?}"),
41    }
42
43    // ── slice out of range ───────────────────────────────────────────────
44    let t = Tensor::new(vec![1.0, 2.0, 3.0, 4.0], &[2, 2]);
45    match t.slice().index(5).all().build() {
46        Err(MattenError::Slice { message, .. }) => println!("[Slice]  {message}"),
47        other => println!("{other:?}"),
48    }
49
50    println!("All boundary errors handled gracefully — no panics.");
51}
Source

pub fn scalar(value: f64) -> Tensor

Creates a rank-0 scalar tensor (shape [], length 1).

use matten::Tensor;
let s = Tensor::scalar(3.14);
assert!(s.is_scalar());
assert_eq!(s.len(), 1);
Examples found in repository?
examples/06_broadcasting.rs (line 12)
10fn main() {
11    // Scalar [] + matrix [2,2] -> [2,2]
12    let scalar = Tensor::scalar(10.0);
13    let mat = Tensor::new(vec![1.0, 2.0, 3.0, 4.0], &[2, 2]);
14    println!("scalar + mat = {:?}", &scalar + &mat);
15
16    // Row vector [3] + matrix [2,3] -> [2,3]  (bias addition)
17    let matrix = Tensor::new(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0], &[2, 3]);
18    let bias = Tensor::new(vec![10.0, 20.0, 30.0], &[3]);
19    println!("matrix + bias = {:?}", &matrix + &bias);
20
21    // Column [3,1] + row [1,4] -> [3,4]  (outer product pattern)
22    let col = Tensor::new(vec![1.0, 2.0, 3.0], &[3, 1]);
23    let row = Tensor::new(vec![10.0, 20.0, 30.0, 40.0], &[1, 4]);
24    let result = &col + &row;
25    println!("col + row shape = {:?}", result.shape()); // [3, 4]
26    println!("col + row data  = {:?}", result.as_slice());
27}
More examples
Hide additional examples
examples/02_shape_and_size.rs (line 9)
8fn main() {
9    let scalar = Tensor::scalar(1.0);
10    let vec1d = Tensor::from_vec(vec![1.0, 2.0, 3.0]);
11    let mat = Tensor::new(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0], &[2, 3]);
12    let rank3 = Tensor::zeros(&[2, 3, 4]);
13
14    for (name, t) in [
15        ("scalar", &scalar),
16        ("vector", &vec1d),
17        ("matrix", &mat),
18        ("rank-3", &rank3),
19    ] {
20        println!(
21            "{name:6}: shape={:?}  ndim={}  len={}  is_scalar={}  is_vector={}  is_matrix={}",
22            t.shape(),
23            t.ndim(),
24            t.len(),
25            t.is_scalar(),
26            t.is_vector(),
27            t.is_matrix()
28        );
29    }
30
31    // Safe element access: Option<f64>, never panics
32    println!("\nmat.get([0,1]) = {:?}", mat.get(&[0, 1])); // Some(2.0)
33    println!("mat.get([5,0]) = {:?}", mat.get(&[5, 0])); // None
34}
examples/01_create_tensor.rs (line 17)
8fn main() {
9    // From data + shape
10    let t = Tensor::new(vec![1.0, 2.0, 3.0, 4.0], &[2, 2]);
11    println!("new:         {t:?}");
12
13    // Fill constructors
14    println!("zeros [3]:   {:?}", Tensor::zeros(&[3]));
15    println!("ones  [2,2]: {:?}", Tensor::ones(&[2, 2]));
16    println!("full  [3]:   {:?}", Tensor::full(&[3], -1.0));
17    println!("scalar:      {:?}", Tensor::scalar(42.0));
18
19    // From flat vec
20    println!(
21        "from_vec:    {:?}",
22        Tensor::from_vec(vec![10.0, 20.0, 30.0])
23    );
24
25    // Range
26    println!("arange:      {:?}", Tensor::arange(0.0, 5.0, 1.0));
27
28    // From nested rows (convenient for trusted literals)
29    let rows: Tensor = vec![vec![1.0, 2.0], vec![3.0, 4.0]].into();
30    println!("from rows:   {rows:?}");
31
32    // Boundary-safe construction
33    let result = Tensor::try_new(vec![1.0, 2.0], &[3]);
34    println!("try_new err: {}", result.unwrap_err());
35}
Source

pub fn zeros(shape: &[usize]) -> Tensor

Creates a tensor filled with 0.0.

§Panics

Panics on an invalid shape (same rules as new).

use matten::Tensor;
let z = Tensor::zeros(&[2, 3]);
assert_eq!(z.shape(), &[2, 3]);
assert_eq!(z.len(), 6);
assert!(z.as_slice().iter().all(|&v| v == 0.0));
Examples found in repository?
examples/02_shape_and_size.rs (line 12)
8fn main() {
9    let scalar = Tensor::scalar(1.0);
10    let vec1d = Tensor::from_vec(vec![1.0, 2.0, 3.0]);
11    let mat = Tensor::new(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0], &[2, 3]);
12    let rank3 = Tensor::zeros(&[2, 3, 4]);
13
14    for (name, t) in [
15        ("scalar", &scalar),
16        ("vector", &vec1d),
17        ("matrix", &mat),
18        ("rank-3", &rank3),
19    ] {
20        println!(
21            "{name:6}: shape={:?}  ndim={}  len={}  is_scalar={}  is_vector={}  is_matrix={}",
22            t.shape(),
23            t.ndim(),
24            t.len(),
25            t.is_scalar(),
26            t.is_vector(),
27            t.is_matrix()
28        );
29    }
30
31    // Safe element access: Option<f64>, never panics
32    println!("\nmat.get([0,1]) = {:?}", mat.get(&[0, 1])); // Some(2.0)
33    println!("mat.get([5,0]) = {:?}", mat.get(&[5, 0])); // None
34}
More examples
Hide additional examples
examples/01_create_tensor.rs (line 14)
8fn main() {
9    // From data + shape
10    let t = Tensor::new(vec![1.0, 2.0, 3.0, 4.0], &[2, 2]);
11    println!("new:         {t:?}");
12
13    // Fill constructors
14    println!("zeros [3]:   {:?}", Tensor::zeros(&[3]));
15    println!("ones  [2,2]: {:?}", Tensor::ones(&[2, 2]));
16    println!("full  [3]:   {:?}", Tensor::full(&[3], -1.0));
17    println!("scalar:      {:?}", Tensor::scalar(42.0));
18
19    // From flat vec
20    println!(
21        "from_vec:    {:?}",
22        Tensor::from_vec(vec![10.0, 20.0, 30.0])
23    );
24
25    // Range
26    println!("arange:      {:?}", Tensor::arange(0.0, 5.0, 1.0));
27
28    // From nested rows (convenient for trusted literals)
29    let rows: Tensor = vec![vec![1.0, 2.0], vec![3.0, 4.0]].into();
30    println!("from rows:   {rows:?}");
31
32    // Boundary-safe construction
33    let result = Tensor::try_new(vec![1.0, 2.0], &[3]);
34    println!("try_new err: {}", result.unwrap_err());
35}
examples/13_resource_limits.rs (line 46)
11fn main() {
12    // ── Default limits ────────────────────────────────────────────────────
13    let limits = MattenLimits::default();
14    println!("Default max_dimensions: {}", limits.max_dimensions);
15    println!(
16        "Default max_elements:   {} (~{} MiB f64)",
17        limits.max_elements,
18        limits.max_elements * 8 / 1_048_576
19    );
20
21    // ── Boundary-safe constructors ────────────────────────────────────────
22    let t = Tensor::try_zeros(&[100, 100]).unwrap();
23    assert_eq!(t.shape(), &[100, 100]);
24    assert_eq!(t.len(), 10_000);
25    println!("try_zeros([100, 100]): OK, {} elements", t.len());
26
27    let t = Tensor::try_ones(&[50, 20]).unwrap();
28    assert_eq!(t.as_slice().iter().sum::<f64>(), 1000.0);
29    println!("try_ones([50, 20]):    OK, sum = {}", t.sum());
30
31    let t = Tensor::try_full(&[10, 10], -1.0).unwrap();
32    assert_eq!(t.as_slice()[0], -1.0);
33    println!("try_full([10, 10], -1.0): OK");
34
35    // ── Custom limits ─────────────────────────────────────────────────────
36    let tight = MattenLimits {
37        max_elements: 10,
38        ..MattenLimits::default()
39    };
40    let err = Tensor::try_zeros_with_limits(&[100], &tight).unwrap_err();
41    assert!(matches!(err, MattenError::Allocation { .. }));
42    println!("Custom limit (max=10): correctly rejected [100]");
43
44    // ── Panicking variants respect limits too ─────────────────────────────
45    // These delegate to try_zeros/try_ones/try_full internally:
46    let _t = Tensor::zeros(&[10, 10]); // fine — 100 elements
47    println!("zeros([10, 10]):        OK (panicking form, within limit)");
48
49    println!("done.");
50}
Source

pub fn ones(shape: &[usize]) -> Tensor

Creates a tensor filled with 1.0.

§Panics

Panics on an invalid shape.

use matten::Tensor;
let o = Tensor::ones(&[3]);
assert!(o.as_slice().iter().all(|&v| v == 1.0));
Examples found in repository?
examples/00_quickstart.rs (line 13)
11fn main() {
12    let a = Tensor::new(vec![1.0, 2.0, 3.0, 4.0], &[2, 2]);
13    let b = Tensor::ones(&[2, 2]);
14
15    let c = &a + &b;
16    println!("a      = {a:?}");
17    println!("b      = {b:?}");
18    println!("a + b  = {c:?}");
19
20    let flat = c.flatten();
21    println!("flat   = {flat:?}");
22
23    assert_eq!(flat.shape(), &[4]);
24    assert_eq!(flat.as_slice(), &[2.0, 3.0, 4.0, 5.0]);
25    println!("All assertions passed.");
26}
More examples
Hide additional examples
examples/01_create_tensor.rs (line 15)
8fn main() {
9    // From data + shape
10    let t = Tensor::new(vec![1.0, 2.0, 3.0, 4.0], &[2, 2]);
11    println!("new:         {t:?}");
12
13    // Fill constructors
14    println!("zeros [3]:   {:?}", Tensor::zeros(&[3]));
15    println!("ones  [2,2]: {:?}", Tensor::ones(&[2, 2]));
16    println!("full  [3]:   {:?}", Tensor::full(&[3], -1.0));
17    println!("scalar:      {:?}", Tensor::scalar(42.0));
18
19    // From flat vec
20    println!(
21        "from_vec:    {:?}",
22        Tensor::from_vec(vec![10.0, 20.0, 30.0])
23    );
24
25    // Range
26    println!("arange:      {:?}", Tensor::arange(0.0, 5.0, 1.0));
27
28    // From nested rows (convenient for trusted literals)
29    let rows: Tensor = vec![vec![1.0, 2.0], vec![3.0, 4.0]].into();
30    println!("from rows:   {rows:?}");
31
32    // Boundary-safe construction
33    let result = Tensor::try_new(vec![1.0, 2.0], &[3]);
34    println!("try_new err: {}", result.unwrap_err());
35}
Source

pub fn full(shape: &[usize], value: f64) -> Tensor

Creates a tensor filled with value.

§Panics

Panics on an invalid shape.

use matten::Tensor;
let t = Tensor::full(&[2, 2], 7.0);
assert!(t.as_slice().iter().all(|&v| v == 7.0));
Examples found in repository?
examples/04_elementwise_ops.rs (line 9)
7fn main() {
8    let a = Tensor::new(vec![1.0, 2.0, 3.0, 4.0], &[2, 2]);
9    let b = Tensor::full(&[2, 2], 2.0);
10
11    println!("a        = {a:?}");
12    println!("b        = {b:?}");
13    println!("a + b    = {:?}", &a + &b);
14    println!("a - b    = {:?}", &a - &b);
15    println!("a * b    = {:?}", &a * &b); // element-wise, NOT matrix product
16    println!("a / b    = {:?}", &a / &b);
17    println!("-a       = {:?}", -&a);
18}
More examples
Hide additional examples
examples/01_create_tensor.rs (line 16)
8fn main() {
9    // From data + shape
10    let t = Tensor::new(vec![1.0, 2.0, 3.0, 4.0], &[2, 2]);
11    println!("new:         {t:?}");
12
13    // Fill constructors
14    println!("zeros [3]:   {:?}", Tensor::zeros(&[3]));
15    println!("ones  [2,2]: {:?}", Tensor::ones(&[2, 2]));
16    println!("full  [3]:   {:?}", Tensor::full(&[3], -1.0));
17    println!("scalar:      {:?}", Tensor::scalar(42.0));
18
19    // From flat vec
20    println!(
21        "from_vec:    {:?}",
22        Tensor::from_vec(vec![10.0, 20.0, 30.0])
23    );
24
25    // Range
26    println!("arange:      {:?}", Tensor::arange(0.0, 5.0, 1.0));
27
28    // From nested rows (convenient for trusted literals)
29    let rows: Tensor = vec![vec![1.0, 2.0], vec![3.0, 4.0]].into();
30    println!("from rows:   {rows:?}");
31
32    // Boundary-safe construction
33    let result = Tensor::try_new(vec![1.0, 2.0], &[3]);
34    println!("try_new err: {}", result.unwrap_err());
35}
Source

pub fn from_vec(data: Vec<f64>) -> Tensor

Creates a 1-D tensor from a flat vector; shape is [data.len()].

§Panics

Panics if data is empty (zero-sized dimension).

use matten::Tensor;
let t = Tensor::from_vec(vec![1.0, 2.0, 3.0]);
assert_eq!(t.shape(), &[3]);
Examples found in repository?
examples/37_kmeans_small.rs (line 47)
45fn nearest(point: &[f64], centroids: &[Vec<f64>]) -> usize {
46    let dists: Vec<f64> = centroids.iter().map(|c| sq_dist(point, c)).collect();
47    Tensor::from_vec(dists).argmin()
48}
More examples
Hide additional examples
examples/34_tiny_pagerank.rs (line 46)
42fn pagerank_step(m: &Tensor, r: &Tensor, damping: f64, n: usize) -> Tensor {
43    let mr = m.matmul(r); // [n, n] × [n] -> [n]
44    let base = (1.0 - damping) / n as f64;
45    let next: Vec<f64> = mr.as_slice().iter().map(|&x| base + damping * x).collect();
46    Tensor::from_vec(next)
47}
48
49fn main() {
50    // Directed graph on 4 nodes:
51    //   0 -> 1, 0 -> 2, 1 -> 2, 2 -> 0, 3 -> 2
52    // Column-stochastic link matrix M (M[i, j] = share of j's rank flowing to i):
53    //          from: 0    1   2   3
54    //   to 0 [ 0     0    1   0  ]
55    //   to 1 [ 0.5   0    0   0  ]
56    //   to 2 [ 0.5   1    0   1  ]
57    //   to 3 [ 0     0    0   0  ]
58    let m = Tensor::new(
59        vec![
60            0.0, 0.0, 1.0, 0.0, //
61            0.5, 0.0, 0.0, 0.0, //
62            0.5, 1.0, 0.0, 1.0, //
63            0.0, 0.0, 0.0, 0.0, //
64        ],
65        &[4, 4],
66    );
67
68    let n = 4;
69    let damping = 0.85;
70    let mut r = Tensor::from_vec(vec![0.25, 0.25, 0.25, 0.25]);
71    for _ in 0..50 {
72        r = pagerank_step(&m, &r, damping, n);
73    }
74
75    let ranks = r.as_slice();
76    println!("PageRank after 50 iterations (d = {damping}):");
77    for (i, &rank) in ranks.iter().enumerate() {
78        println!("  node {i}: {rank:.4}");
79    }
80
81    // The best-connected node should win; the link-less node 3 only gets teleport.
82    let top = ranks
83        .iter()
84        .enumerate()
85        .max_by(|a, b| a.1.partial_cmp(b.1).unwrap())
86        .map(|(i, _)| i)
87        .unwrap();
88    println!("highest-ranked node: {top}");
89
90    let total: f64 = ranks.iter().sum();
91    assert!((total - 1.0).abs() < 1e-9, "ranks must sum to 1");
92    assert_eq!(top, 2, "node 2 receives the most links");
93    println!("Tiny PageRank: OK");
94}
examples/38_nearest_neighbor_classification.rs (line 47)
41fn classify(query: &[f64], train: &Tensor, labels: &[u8]) -> u8 {
42    let dim = train.shape()[1];
43    let data = train.as_slice();
44    let dists: Vec<f64> = (0..train.shape()[0])
45        .map(|i| sq_dist(query, &data[i * dim..(i + 1) * dim]))
46        .collect();
47    labels[Tensor::from_vec(dists).argmin()]
48}
examples/25_normalize_vector.rs (line 22)
21fn main() {
22    let v = Tensor::from_vec(vec![3.0, 4.0]);
23    println!("v        = {:?}", v.as_slice());
24    println!("‖v‖      = {}", l2_norm(&v)); // 5.0
25
26    let u = normalize(&v);
27    println!("norm(v)  = {:?}", u.as_slice()); // [0.6, 0.8]
28
29    let norm_u = l2_norm(&u);
30    println!("‖norm(v)‖ = {norm_u:.6}"); // ≈ 1.0
31    assert!((norm_u - 1.0).abs() < 1e-10, "unit vector check failed");
32    println!("Unit vector check: OK");
33}
examples/rolling_windows_basic.rs (line 20)
19fn main() {
20    let series = Tensor::from_vec(vec![3.0, 1.0, 4.0, 1.0, 5.0, 9.0, 2.0, 6.0]);
21    let w = 3;
22
23    let sums = rolling_sum(&series, w);
24    let maxes = rolling_max(&series, w);
25
26    println!("series       = {:?}", series.as_slice());
27    println!("rolling sum  = {:?}", sums);
28    println!("rolling max  = {:?}", maxes);
29
30    assert_eq!(sums[0], 8.0); // 3+1+4
31    assert_eq!(maxes[0], 4.0); // max(3,1,4)
32    println!("Rolling windows: OK");
33}
examples/20_dot_product.rs (line 11)
10fn main() {
11    let a = Tensor::from_vec(vec![1.0, 2.0, 3.0]);
12    let b = Tensor::from_vec(vec![4.0, 5.0, 6.0]);
13
14    let d = a.dot(&b); // 1*4 + 2*5 + 3*6 = 32
15    assert!(d.is_scalar());
16    println!("a · b = {}", d.as_slice()[0]); // 32.0
17
18    // Orthogonal vectors have zero dot product
19    let x = Tensor::from_vec(vec![1.0, 0.0]);
20    let y = Tensor::from_vec(vec![0.0, 1.0]);
21    assert_eq!(x.dot(&y).as_slice(), &[0.0]);
22    println!("orthogonal dot = 0: OK");
23}
Source

pub fn arange(start: f64, end: f64, step: f64) -> Tensor

Creates a 1-D tensor with values start, start + step, ... (half-open, so end is excluded).

This is a panic-zone convenience. Use try_arange when start/end/step come from user input.

§Panics

Panics if step == 0.0, any argument is non-finite, or the computed element count would exceed the allocation limit.

use matten::Tensor;
let r = Tensor::arange(0.0, 5.0, 1.0);
assert_eq!(r.as_slice(), &[0.0, 1.0, 2.0, 3.0, 4.0]);

let r2 = Tensor::arange(1.0, 0.0, -0.5);
assert_eq!(r2.as_slice(), &[1.0, 0.5]);
Examples found in repository?
examples/01_create_tensor.rs (line 26)
8fn main() {
9    // From data + shape
10    let t = Tensor::new(vec![1.0, 2.0, 3.0, 4.0], &[2, 2]);
11    println!("new:         {t:?}");
12
13    // Fill constructors
14    println!("zeros [3]:   {:?}", Tensor::zeros(&[3]));
15    println!("ones  [2,2]: {:?}", Tensor::ones(&[2, 2]));
16    println!("full  [3]:   {:?}", Tensor::full(&[3], -1.0));
17    println!("scalar:      {:?}", Tensor::scalar(42.0));
18
19    // From flat vec
20    println!(
21        "from_vec:    {:?}",
22        Tensor::from_vec(vec![10.0, 20.0, 30.0])
23    );
24
25    // Range
26    println!("arange:      {:?}", Tensor::arange(0.0, 5.0, 1.0));
27
28    // From nested rows (convenient for trusted literals)
29    let rows: Tensor = vec![vec![1.0, 2.0], vec![3.0, 4.0]].into();
30    println!("from rows:   {rows:?}");
31
32    // Boundary-safe construction
33    let result = Tensor::try_new(vec![1.0, 2.0], &[3]);
34    println!("try_new err: {}", result.unwrap_err());
35}
Source

pub fn try_arange( start: f64, end: f64, step: f64, ) -> Result<Tensor, MattenError>

Creates a 1-D tensor with values start, start + step, ... (half-open), returning an error instead of panicking.

§Errors

Returns MattenError::Shape for a zero or non-finite step/bound, or MattenError::Allocation if the computed element count exceeds the allocation limit.

Source

pub fn try_from_rows(rows: Vec<Vec<f64>>) -> Result<Tensor, MattenError>

Creates a 2-D tensor from rectangular row data; shape is [rows, cols].

This is the recoverable version of From<Vec<Vec<f64>>>.

§Errors

Returns MattenError::Shape on an empty outer vector, any zero-length row, or ragged rows.

Source

pub fn shape(&self) -> &[usize]

The shape as a slice of dimension lengths. Non-allocating.

Examples found in repository?
examples/hello_tensor.rs (line 12)
7fn main() {
8    let t = Tensor::new(vec![1.0, 2.0, 3.0, 4.0], &[2, 2]);
9    println!("{t:?}");
10    println!(
11        "shape = {:?}, len = {}, ndim = {}",
12        t.shape(),
13        t.len(),
14        t.ndim()
15    );
16}
More examples
Hide additional examples
examples/38_nearest_neighbor_classification.rs (line 42)
41fn classify(query: &[f64], train: &Tensor, labels: &[u8]) -> u8 {
42    let dim = train.shape()[1];
43    let data = train.as_slice();
44    let dists: Vec<f64> = (0..train.shape()[0])
45        .map(|i| sq_dist(query, &data[i * dim..(i + 1) * dim]))
46        .collect();
47    labels[Tensor::from_vec(dists).argmin()]
48}
examples/32_graph_path_counting.rs (line 59)
58fn print_matrix(label: &str, m: &Tensor) {
59    let (rows, cols) = (m.shape()[0], m.shape()[1]);
60    println!("{label}:");
61    for i in 0..rows {
62        let row: Vec<String> = (0..cols)
63            .map(|j| format!("{:.0}", m.get(&[i, j]).expect("index in bounds")))
64            .collect();
65        println!("  [{}]", row.join(", "));
66    }
67}
examples/00_quickstart.rs (line 23)
11fn main() {
12    let a = Tensor::new(vec![1.0, 2.0, 3.0, 4.0], &[2, 2]);
13    let b = Tensor::ones(&[2, 2]);
14
15    let c = &a + &b;
16    println!("a      = {a:?}");
17    println!("b      = {b:?}");
18    println!("a + b  = {c:?}");
19
20    let flat = c.flatten();
21    println!("flat   = {flat:?}");
22
23    assert_eq!(flat.shape(), &[4]);
24    assert_eq!(flat.as_slice(), &[2.0, 3.0, 4.0, 5.0]);
25    println!("All assertions passed.");
26}
examples/21_matrix_vector_product.rs (line 19)
9fn main() {
10    // [[1,2,3],[4,5,6]] × [1,0,1] = [4, 10]
11    let m = Tensor::new(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0], &[2, 3]);
12    let v = Tensor::from_vec(vec![1.0, 0.0, 1.0]);
13
14    let r = m.matmul(&v);
15    println!("m    = {m:?}");
16    println!("v    = {v:?}");
17    println!("m·v  = {r:?}"); // [4.0, 10.0]
18
19    assert_eq!(r.shape(), &[2]);
20    assert_eq!(r.as_slice(), &[4.0, 10.0]);
21
22    // Vector × matrix: [n] × [n, p] -> [p]
23    let w = Tensor::from_vec(vec![1.0, 2.0]);
24    let r2 = w.matmul(&m.transpose());
25    println!("w·mᵀ = {r2:?}");
26
27    println!("Shapes and values verified: OK");
28}
examples/07_transpose_swap_axes.rs (line 13)
7fn main() {
8    // 2-D transpose: swap rows and columns
9    let m = Tensor::new(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0], &[2, 3]);
10    println!("original  {m:?}");
11    let mt = m.transpose();
12    println!("transposed {mt:?}");
13    assert_eq!(mt.shape(), &[3, 2]);
14
15    // t() is an alias
16    assert_eq!(m.t(), mt);
17
18    // Transpose twice is identity
19    assert_eq!(m.transpose().transpose(), m);
20    println!("transpose twice == identity: OK");
21
22    // swap_axes on rank-3
23    let r3 = Tensor::new((1..=24).map(|x| x as f64).collect(), &[2, 3, 4]);
24    let s = r3.swap_axes(0, 2);
25    println!("rank-3 swap_axes(0,2) shape: {:?}", s.shape()); // [4,3,2]
26}
Source

pub fn ndim(&self) -> usize

The rank (number of dimensions): shape().len().

Examples found in repository?
examples/hello_tensor.rs (line 14)
7fn main() {
8    let t = Tensor::new(vec![1.0, 2.0, 3.0, 4.0], &[2, 2]);
9    println!("{t:?}");
10    println!(
11        "shape = {:?}, len = {}, ndim = {}",
12        t.shape(),
13        t.len(),
14        t.ndim()
15    );
16}
More examples
Hide additional examples
examples/02_shape_and_size.rs (line 23)
8fn main() {
9    let scalar = Tensor::scalar(1.0);
10    let vec1d = Tensor::from_vec(vec![1.0, 2.0, 3.0]);
11    let mat = Tensor::new(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0], &[2, 3]);
12    let rank3 = Tensor::zeros(&[2, 3, 4]);
13
14    for (name, t) in [
15        ("scalar", &scalar),
16        ("vector", &vec1d),
17        ("matrix", &mat),
18        ("rank-3", &rank3),
19    ] {
20        println!(
21            "{name:6}: shape={:?}  ndim={}  len={}  is_scalar={}  is_vector={}  is_matrix={}",
22            t.shape(),
23            t.ndim(),
24            t.len(),
25            t.is_scalar(),
26            t.is_vector(),
27            t.is_matrix()
28        );
29    }
30
31    // Safe element access: Option<f64>, never panics
32    println!("\nmat.get([0,1]) = {:?}", mat.get(&[0, 1])); // Some(2.0)
33    println!("mat.get([5,0]) = {:?}", mat.get(&[5, 0])); // None
34}
Source

pub fn len(&self) -> usize

The logical element count: the product of the shape.

Examples found in repository?
examples/rolling_windows_basic.rs (line 8)
7fn rolling_sum(t: &Tensor, window: usize) -> Vec<f64> {
8    (0..=(t.len() - window))
9        .map(|i| t.slice().range(i..i + window).build().unwrap().sum())
10        .collect()
11}
12
13fn rolling_max(t: &Tensor, window: usize) -> Vec<f64> {
14    (0..=(t.len() - window))
15        .map(|i| t.slice().range(i..i + window).build().unwrap().max())
16        .collect()
17}
More examples
Hide additional examples
examples/hello_tensor.rs (line 13)
7fn main() {
8    let t = Tensor::new(vec![1.0, 2.0, 3.0, 4.0], &[2, 2]);
9    println!("{t:?}");
10    println!(
11        "shape = {:?}, len = {}, ndim = {}",
12        t.shape(),
13        t.len(),
14        t.ndim()
15    );
16}
examples/moving_average.rs (line 10)
7fn main() {
8    let series = Tensor::from_vec(vec![1.0, 3.0, 5.0, 7.0, 9.0, 11.0, 13.0]);
9    let window = 3usize;
10    let n = series.len();
11
12    // Compute moving averages for windows [0..3], [1..4], ...
13    let mut avgs = Vec::new();
14    for start in 0..=(n - window) {
15        let w = series.slice().range(start..start + window).build().unwrap();
16        avgs.push(w.mean());
17    }
18
19    println!("series = {:?}", series.as_slice());
20    println!("3-pt moving avg = {:?}", avgs);
21    assert_eq!(avgs.len(), n - window + 1);
22    assert!((avgs[0] - 3.0).abs() < 1e-10); // mean(1,3,5) = 3
23    assert!((avgs[1] - 5.0).abs() < 1e-10); // mean(3,5,7) = 5
24    println!("Moving average: OK");
25}
examples/02_shape_and_size.rs (line 24)
8fn main() {
9    let scalar = Tensor::scalar(1.0);
10    let vec1d = Tensor::from_vec(vec![1.0, 2.0, 3.0]);
11    let mat = Tensor::new(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0], &[2, 3]);
12    let rank3 = Tensor::zeros(&[2, 3, 4]);
13
14    for (name, t) in [
15        ("scalar", &scalar),
16        ("vector", &vec1d),
17        ("matrix", &mat),
18        ("rank-3", &rank3),
19    ] {
20        println!(
21            "{name:6}: shape={:?}  ndim={}  len={}  is_scalar={}  is_vector={}  is_matrix={}",
22            t.shape(),
23            t.ndim(),
24            t.len(),
25            t.is_scalar(),
26            t.is_vector(),
27            t.is_matrix()
28        );
29    }
30
31    // Safe element access: Option<f64>, never panics
32    println!("\nmat.get([0,1]) = {:?}", mat.get(&[0, 1])); // Some(2.0)
33    println!("mat.get([5,0]) = {:?}", mat.get(&[5, 0])); // None
34}
examples/13_resource_limits.rs (line 24)
11fn main() {
12    // ── Default limits ────────────────────────────────────────────────────
13    let limits = MattenLimits::default();
14    println!("Default max_dimensions: {}", limits.max_dimensions);
15    println!(
16        "Default max_elements:   {} (~{} MiB f64)",
17        limits.max_elements,
18        limits.max_elements * 8 / 1_048_576
19    );
20
21    // ── Boundary-safe constructors ────────────────────────────────────────
22    let t = Tensor::try_zeros(&[100, 100]).unwrap();
23    assert_eq!(t.shape(), &[100, 100]);
24    assert_eq!(t.len(), 10_000);
25    println!("try_zeros([100, 100]): OK, {} elements", t.len());
26
27    let t = Tensor::try_ones(&[50, 20]).unwrap();
28    assert_eq!(t.as_slice().iter().sum::<f64>(), 1000.0);
29    println!("try_ones([50, 20]):    OK, sum = {}", t.sum());
30
31    let t = Tensor::try_full(&[10, 10], -1.0).unwrap();
32    assert_eq!(t.as_slice()[0], -1.0);
33    println!("try_full([10, 10], -1.0): OK");
34
35    // ── Custom limits ─────────────────────────────────────────────────────
36    let tight = MattenLimits {
37        max_elements: 10,
38        ..MattenLimits::default()
39    };
40    let err = Tensor::try_zeros_with_limits(&[100], &tight).unwrap_err();
41    assert!(matches!(err, MattenError::Allocation { .. }));
42    println!("Custom limit (max=10): correctly rejected [100]");
43
44    // ── Panicking variants respect limits too ─────────────────────────────
45    // These delegate to try_zeros/try_ones/try_full internally:
46    let _t = Tensor::zeros(&[10, 10]); // fine — 100 elements
47    println!("zeros([10, 10]):        OK (panicking form, within limit)");
48
49    println!("done.");
50}
Source

pub fn is_scalar(&self) -> bool

Returns true for a rank-0 scalar tensor (shape []).

Examples found in repository?
examples/20_dot_product.rs (line 15)
10fn main() {
11    let a = Tensor::from_vec(vec![1.0, 2.0, 3.0]);
12    let b = Tensor::from_vec(vec![4.0, 5.0, 6.0]);
13
14    let d = a.dot(&b); // 1*4 + 2*5 + 3*6 = 32
15    assert!(d.is_scalar());
16    println!("a · b = {}", d.as_slice()[0]); // 32.0
17
18    // Orthogonal vectors have zero dot product
19    let x = Tensor::from_vec(vec![1.0, 0.0]);
20    let y = Tensor::from_vec(vec![0.0, 1.0]);
21    assert_eq!(x.dot(&y).as_slice(), &[0.0]);
22    println!("orthogonal dot = 0: OK");
23}
More examples
Hide additional examples
examples/08_slicing_builder.rs (line 27)
9fn main() -> Result<(), Box<dyn std::error::Error>> {
10    let t = Tensor::new((1..=12).map(|x| x as f64).collect(), &[3, 4]);
11    println!("tensor   {t:?}");
12
13    // First row (index 0, axis removed from output shape)
14    let row0 = t.slice().index(0).all().build()?;
15    println!("row 0    {row0:?}"); // shape [4]
16
17    // First two rows, all columns
18    let top2 = t.slice().range(0..2).all().build()?;
19    println!("top 2    {top2:?}"); // shape [2,4]
20
21    // All rows, columns 1..3
22    let cols = t.slice().all().range(1..3).build()?;
23    println!("cols 1:3 {cols:?}"); // shape [3,2]
24
25    // Single element -> scalar
26    let elem = t.slice().index(1).index(2).build()?;
27    assert!(elem.is_scalar());
28    println!("t[1,2]   {elem:?}");
29
30    Ok(())
31}
examples/02_shape_and_size.rs (line 25)
8fn main() {
9    let scalar = Tensor::scalar(1.0);
10    let vec1d = Tensor::from_vec(vec![1.0, 2.0, 3.0]);
11    let mat = Tensor::new(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0], &[2, 3]);
12    let rank3 = Tensor::zeros(&[2, 3, 4]);
13
14    for (name, t) in [
15        ("scalar", &scalar),
16        ("vector", &vec1d),
17        ("matrix", &mat),
18        ("rank-3", &rank3),
19    ] {
20        println!(
21            "{name:6}: shape={:?}  ndim={}  len={}  is_scalar={}  is_vector={}  is_matrix={}",
22            t.shape(),
23            t.ndim(),
24            t.len(),
25            t.is_scalar(),
26            t.is_vector(),
27            t.is_matrix()
28        );
29    }
30
31    // Safe element access: Option<f64>, never panics
32    println!("\nmat.get([0,1]) = {:?}", mat.get(&[0, 1])); // Some(2.0)
33    println!("mat.get([5,0]) = {:?}", mat.get(&[5, 0])); // None
34}
Source

pub fn is_vector(&self) -> bool

Returns true for a rank-1 tensor.

Examples found in repository?
examples/02_shape_and_size.rs (line 26)
8fn main() {
9    let scalar = Tensor::scalar(1.0);
10    let vec1d = Tensor::from_vec(vec![1.0, 2.0, 3.0]);
11    let mat = Tensor::new(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0], &[2, 3]);
12    let rank3 = Tensor::zeros(&[2, 3, 4]);
13
14    for (name, t) in [
15        ("scalar", &scalar),
16        ("vector", &vec1d),
17        ("matrix", &mat),
18        ("rank-3", &rank3),
19    ] {
20        println!(
21            "{name:6}: shape={:?}  ndim={}  len={}  is_scalar={}  is_vector={}  is_matrix={}",
22            t.shape(),
23            t.ndim(),
24            t.len(),
25            t.is_scalar(),
26            t.is_vector(),
27            t.is_matrix()
28        );
29    }
30
31    // Safe element access: Option<f64>, never panics
32    println!("\nmat.get([0,1]) = {:?}", mat.get(&[0, 1])); // Some(2.0)
33    println!("mat.get([5,0]) = {:?}", mat.get(&[5, 0])); // None
34}
Source

pub fn is_matrix(&self) -> bool

Returns true for a rank-2 tensor.

Examples found in repository?
examples/02_shape_and_size.rs (line 27)
8fn main() {
9    let scalar = Tensor::scalar(1.0);
10    let vec1d = Tensor::from_vec(vec![1.0, 2.0, 3.0]);
11    let mat = Tensor::new(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0], &[2, 3]);
12    let rank3 = Tensor::zeros(&[2, 3, 4]);
13
14    for (name, t) in [
15        ("scalar", &scalar),
16        ("vector", &vec1d),
17        ("matrix", &mat),
18        ("rank-3", &rank3),
19    ] {
20        println!(
21            "{name:6}: shape={:?}  ndim={}  len={}  is_scalar={}  is_vector={}  is_matrix={}",
22            t.shape(),
23            t.ndim(),
24            t.len(),
25            t.is_scalar(),
26            t.is_vector(),
27            t.is_matrix()
28        );
29    }
30
31    // Safe element access: Option<f64>, never panics
32    println!("\nmat.get([0,1]) = {:?}", mat.get(&[0, 1])); // Some(2.0)
33    println!("mat.get([5,0]) = {:?}", mat.get(&[5, 0])); // None
34}
Source

pub fn is_dynamic(&self) -> bool

Returns true if this tensor uses dynamic ([Element]) storage.

This method is available in all builds, regardless of whether the dynamic feature is enabled:

  • When dynamic is off, no dynamic tensor can be constructed, so this always returns false.
  • When dynamic is on, it returns true for tensors built via the dynamic API (e.g. [Tensor::from_elements]) and false for ordinary numeric tensors.

Companion crates call this unconditionally before numeric conversion so that a dynamic Tensor is rejected with a typed Err rather than reaching internal numeric accessors and panicking — even when Cargo feature unification enables core dynamic while the companion’s own mirror feature is off.

Source

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

The flat, row-major data as a slice.

Examples found in repository?
examples/25_normalize_vector.rs (line 12)
11fn l2_norm(v: &Tensor) -> f64 {
12    v.as_slice().iter().map(|x| x * x).sum::<f64>().sqrt()
13}
14
15/// Returns the L2-normalised version of `v` (unit vector).
16fn normalize(v: &Tensor) -> Tensor {
17    let norm = l2_norm(v);
18    v / norm
19}
20
21fn main() {
22    let v = Tensor::from_vec(vec![3.0, 4.0]);
23    println!("v        = {:?}", v.as_slice());
24    println!("‖v‖      = {}", l2_norm(&v)); // 5.0
25
26    let u = normalize(&v);
27    println!("norm(v)  = {:?}", u.as_slice()); // [0.6, 0.8]
28
29    let norm_u = l2_norm(&u);
30    println!("‖norm(v)‖ = {norm_u:.6}"); // ≈ 1.0
31    assert!((norm_u - 1.0).abs() < 1e-10, "unit vector check failed");
32    println!("Unit vector check: OK");
33}
More examples
Hide additional examples
examples/26_cosine_similarity.rs (line 10)
9fn l2_norm(v: &Tensor) -> f64 {
10    v.as_slice().iter().map(|x| x * x).sum::<f64>().sqrt()
11}
12
13fn cosine_similarity(a: &Tensor, b: &Tensor) -> f64 {
14    // a · b is the scalar dot product
15    let dot = a.dot(b).as_slice()[0];
16    dot / (l2_norm(a) * l2_norm(b))
17}
examples/34_tiny_pagerank.rs (line 45)
42fn pagerank_step(m: &Tensor, r: &Tensor, damping: f64, n: usize) -> Tensor {
43    let mr = m.matmul(r); // [n, n] × [n] -> [n]
44    let base = (1.0 - damping) / n as f64;
45    let next: Vec<f64> = mr.as_slice().iter().map(|&x| base + damping * x).collect();
46    Tensor::from_vec(next)
47}
48
49fn main() {
50    // Directed graph on 4 nodes:
51    //   0 -> 1, 0 -> 2, 1 -> 2, 2 -> 0, 3 -> 2
52    // Column-stochastic link matrix M (M[i, j] = share of j's rank flowing to i):
53    //          from: 0    1   2   3
54    //   to 0 [ 0     0    1   0  ]
55    //   to 1 [ 0.5   0    0   0  ]
56    //   to 2 [ 0.5   1    0   1  ]
57    //   to 3 [ 0     0    0   0  ]
58    let m = Tensor::new(
59        vec![
60            0.0, 0.0, 1.0, 0.0, //
61            0.5, 0.0, 0.0, 0.0, //
62            0.5, 1.0, 0.0, 1.0, //
63            0.0, 0.0, 0.0, 0.0, //
64        ],
65        &[4, 4],
66    );
67
68    let n = 4;
69    let damping = 0.85;
70    let mut r = Tensor::from_vec(vec![0.25, 0.25, 0.25, 0.25]);
71    for _ in 0..50 {
72        r = pagerank_step(&m, &r, damping, n);
73    }
74
75    let ranks = r.as_slice();
76    println!("PageRank after 50 iterations (d = {damping}):");
77    for (i, &rank) in ranks.iter().enumerate() {
78        println!("  node {i}: {rank:.4}");
79    }
80
81    // The best-connected node should win; the link-less node 3 only gets teleport.
82    let top = ranks
83        .iter()
84        .enumerate()
85        .max_by(|a, b| a.1.partial_cmp(b.1).unwrap())
86        .map(|(i, _)| i)
87        .unwrap();
88    println!("highest-ranked node: {top}");
89
90    let total: f64 = ranks.iter().sum();
91    assert!((total - 1.0).abs() < 1e-9, "ranks must sum to 1");
92    assert_eq!(top, 2, "node 2 receives the most links");
93    println!("Tiny PageRank: OK");
94}
examples/38_nearest_neighbor_classification.rs (line 43)
41fn classify(query: &[f64], train: &Tensor, labels: &[u8]) -> u8 {
42    let dim = train.shape()[1];
43    let data = train.as_slice();
44    let dists: Vec<f64> = (0..train.shape()[0])
45        .map(|i| sq_dist(query, &data[i * dim..(i + 1) * dim]))
46        .collect();
47    labels[Tensor::from_vec(dists).argmin()]
48}
examples/28_column_statistics.rs (line 17)
12fn column_std(data: &Tensor, col_means: &Tensor) -> Tensor {
13    // Broadcast means over all rows, compute squared deviations
14    let deviations = data - col_means; // [rows, cols] - [cols] → [rows, cols]
15    let sq = &deviations * &deviations;
16    sq.mean_axis(0) // → [cols] mean of squared deviations
17        .as_slice()
18        .iter()
19        .map(|v| v.sqrt())
20        .collect::<Vec<f64>>()
21        .into()
22}
23
24fn main() {
25    // 4 rows, 3 columns (features)
26    let data = Tensor::new(
27        vec![
28            1.0, 10.0, 100.0, 2.0, 20.0, 200.0, 3.0, 30.0, 300.0, 4.0, 40.0, 400.0,
29        ],
30        &[4, 3],
31    );
32
33    let means = data.mean_axis(0);
34    let mins = data.min_axis(0);
35    let maxs = data.max_axis(0);
36    let stds = column_std(&data, &means);
37
38    println!("columns : 0      1      2");
39    println!("mean    : {:?}", means.as_slice());
40    println!("min     : {:?}", mins.as_slice());
41    println!("max     : {:?}", maxs.as_slice());
42    println!("std dev : {:?}", stds.as_slice());
43
44    assert_eq!(means.as_slice(), &[2.5, 25.0, 250.0]);
45    assert_eq!(mins.as_slice(), &[1.0, 10.0, 100.0]);
46    assert_eq!(maxs.as_slice(), &[4.0, 40.0, 400.0]);
47
48    // Std dev: sqrt of mean squared deviation from mean
49    let expected_std0 = {
50        // Column 0 values: 1,2,3,4. Mean=2.5. Deviations: -1.5,-0.5,0.5,1.5
51        let sq_devs = [
52            1.5f64.powi(2),
53            0.5f64.powi(2),
54            0.5f64.powi(2),
55            1.5f64.powi(2),
56        ];
57        (sq_devs.iter().sum::<f64>() / 4.0).sqrt()
58    };
59    assert!((stds.as_slice()[0] - expected_std0).abs() < 1e-10);
60
61    println!("done.");
62}
examples/00_quickstart.rs (line 24)
11fn main() {
12    let a = Tensor::new(vec![1.0, 2.0, 3.0, 4.0], &[2, 2]);
13    let b = Tensor::ones(&[2, 2]);
14
15    let c = &a + &b;
16    println!("a      = {a:?}");
17    println!("b      = {b:?}");
18    println!("a + b  = {c:?}");
19
20    let flat = c.flatten();
21    println!("flat   = {flat:?}");
22
23    assert_eq!(flat.shape(), &[4]);
24    assert_eq!(flat.as_slice(), &[2.0, 3.0, 4.0, 5.0]);
25    println!("All assertions passed.");
26}
Source

pub fn to_vec(&self) -> Vec<f64>

Returns an owned copy of the flat, row-major data.

Source

pub fn into_vec(self) -> Vec<f64>

Consumes the tensor and returns the flat, row-major data. No copy.

Trait Implementations§

Source§

impl Add for &Tensor

Source§

fn add(self, rhs: &Tensor) -> Tensor

Element-wise addition with NumPy-style broadcasting.

§Panics

Panics with "matten broadcast error in add: ..." if the shapes are incompatible.

use matten::Tensor;
let a = Tensor::new(vec![1.0, 2.0, 3.0, 4.0], &[2, 2]);
let b = Tensor::ones(&[2, 2]);
let c = &a + &b;
assert_eq!(c.as_slice(), &[2.0, 3.0, 4.0, 5.0]);
Source§

type Output = Tensor

The resulting type after applying the + operator.
Source§

impl Add<&Tensor> for f64

Source§

fn add(self, rhs: &Tensor) -> Tensor

Adds every element of the tensor to a scalar (scalar + &tensor).

use matten::Tensor;
let t = Tensor::new(vec![1.0, 2.0, 3.0], &[3]);
let r = 10.0 + &t;
assert_eq!(r.as_slice(), &[11.0, 12.0, 13.0]);
Source§

type Output = Tensor

The resulting type after applying the + operator.
Source§

impl Add<f64> for &Tensor

Source§

fn add(self, rhs: f64) -> Tensor

Adds a scalar to every element.

use matten::Tensor;
let t = Tensor::new(vec![1.0, 2.0, 3.0], &[3]);
let r = &t + 10.0;
assert_eq!(r.as_slice(), &[11.0, 12.0, 13.0]);
Source§

type Output = Tensor

The resulting type after applying the + operator.
Source§

impl Clone for Tensor

Source§

fn clone(&self) -> Tensor

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

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

Performs copy-assignment from source. Read more
Source§

impl Debug for Tensor

Source§

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

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

impl<'de> Deserialize<'de> for Tensor

Available on crate feature serde only.
Source§

fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error>

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Div for &Tensor

Source§

fn div(self, rhs: &Tensor) -> Tensor

Element-wise division with broadcasting. Division by zero follows IEEE 754 f64 behavior (yields inf, -inf, or NaN); no error is produced.

§Panics

Panics on incompatible shapes.

use matten::Tensor;
let a = Tensor::new(vec![4.0, 9.0], &[2]);
let b = Tensor::new(vec![2.0, 3.0], &[2]);
let c = &a / &b;
assert_eq!(c.as_slice(), &[2.0, 3.0]);
Source§

type Output = Tensor

The resulting type after applying the / operator.
Source§

impl Div<&Tensor> for f64

Source§

fn div(self, rhs: &Tensor) -> Tensor

Divides a scalar by each tensor element (scalar / &tensor). Division by zero follows IEEE 754.

use matten::Tensor;
let t = Tensor::new(vec![2.0, 4.0, 8.0], &[3]);
let r = 16.0 / &t;
assert_eq!(r.as_slice(), &[8.0, 4.0, 2.0]);
Source§

type Output = Tensor

The resulting type after applying the / operator.
Source§

impl Div<f64> for &Tensor

Source§

fn div(self, rhs: f64) -> Tensor

Divides every element by a scalar. Division by zero follows IEEE 754.

use matten::Tensor;
let t = Tensor::new(vec![6.0, 4.0, 2.0], &[3]);
let r = &t / 2.0;
assert_eq!(r.as_slice(), &[3.0, 2.0, 1.0]);
Source§

type Output = Tensor

The resulting type after applying the / operator.
Source§

impl From<&Tensor> for Vec<f64>

Source§

fn from(t: &Tensor) -> Vec<f64>

Returns an owned copy of the tensor’s flat, row-major data.

Source§

impl From<Tensor> for Vec<f64>

Source§

fn from(t: Tensor) -> Vec<f64>

Consumes the tensor and returns the flat, row-major data. No copy.

Source§

impl From<Vec<Vec<f64>>> for Tensor

Source§

fn from(rows: Vec<Vec<f64>>) -> Self

Creates a 2-D tensor from rectangular row data; shape is [rows, cols].

This is a convenience for trusted literals and examples. It panics on ragged rows, an empty outer vector, or any row with zero columns. Use Tensor::try_from_rows for recoverable, boundary-safe construction.

§Panics

Panics on ragged rows, an empty outer vector, or any zero-length row.

Source§

impl From<Vec<f64>> for Tensor

Source§

fn from(data: Vec<f64>) -> Self

Creates a 1-D tensor from a flat vector; shape is [len].

§Panics

Panics only if the resulting [len] shape is somehow invalid (not possible for non-empty Vec<f64> unless len is 0, which triggers the zero-sized-dimension policy). An empty vector will panic.

Source§

impl Mul for &Tensor

Source§

fn mul(self, rhs: &Tensor) -> Tensor

Element-wise multiplication with broadcasting (* is not matrix multiply; use matmul for that).

§Panics

Panics on incompatible shapes.

use matten::Tensor;
let a = Tensor::new(vec![1.0, 2.0, 3.0, 4.0], &[2, 2]);
let b = Tensor::full(&[2, 2], 2.0);
let c = &a * &b;
assert_eq!(c.as_slice(), &[2.0, 4.0, 6.0, 8.0]);
Source§

type Output = Tensor

The resulting type after applying the * operator.
Source§

impl Mul<&Tensor> for f64

Source§

fn mul(self, rhs: &Tensor) -> Tensor

Multiplies every element of the tensor by a scalar (scalar * &tensor).

use matten::Tensor;
let t = Tensor::new(vec![1.0, 2.0, 3.0], &[3]);
let r = 3.0 * &t;
assert_eq!(r.as_slice(), &[3.0, 6.0, 9.0]);
Source§

type Output = Tensor

The resulting type after applying the * operator.
Source§

impl Mul<f64> for &Tensor

Source§

fn mul(self, rhs: f64) -> Tensor

Multiplies every element by a scalar.

use matten::Tensor;
let t = Tensor::new(vec![1.0, 2.0, 3.0], &[3]);
let r = &t * 3.0;
assert_eq!(r.as_slice(), &[3.0, 6.0, 9.0]);
Source§

type Output = Tensor

The resulting type after applying the * operator.
Source§

impl Neg for &Tensor

Source§

fn neg(self) -> Tensor

Negates every element.

use matten::Tensor;
let t = Tensor::new(vec![1.0, -2.0, 3.0], &[3]);
let r = -&t;
assert_eq!(r.as_slice(), &[-1.0, 2.0, -3.0]);
Source§

type Output = Tensor

The resulting type after applying the - operator.
Source§

impl PartialEq for Tensor

Source§

fn eq(&self, other: &Self) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 (const: unstable) · 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 Serialize for Tensor

Available on crate feature serde only.
Source§

fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error>

Serialize this value into the given Serde serializer. Read more
Source§

impl Sub for &Tensor

Source§

fn sub(self, rhs: &Tensor) -> Tensor

Element-wise subtraction with broadcasting.

§Panics

Panics on incompatible shapes.

use matten::Tensor;
let a = Tensor::new(vec![5.0, 4.0, 3.0, 2.0], &[2, 2]);
let b = Tensor::ones(&[2, 2]);
let c = &a - &b;
assert_eq!(c.as_slice(), &[4.0, 3.0, 2.0, 1.0]);
Source§

type Output = Tensor

The resulting type after applying the - operator.
Source§

impl Sub<&Tensor> for f64

Source§

fn sub(self, rhs: &Tensor) -> Tensor

Subtracts each tensor element from a scalar (scalar - &tensor).

use matten::Tensor;
let t = Tensor::new(vec![1.0, 2.0, 3.0], &[3]);
let r = 10.0 - &t;
assert_eq!(r.as_slice(), &[9.0, 8.0, 7.0]);
Source§

type Output = Tensor

The resulting type after applying the - operator.
Source§

impl Sub<f64> for &Tensor

Source§

fn sub(self, rhs: f64) -> Tensor

Subtracts a scalar from every element.

use matten::Tensor;
let t = Tensor::new(vec![5.0, 3.0, 1.0], &[3]);
let r = &t - 1.0;
assert_eq!(r.as_slice(), &[4.0, 2.0, 0.0]);
Source§

type Output = Tensor

The resulting type after applying the - operator.
Source§

impl TryFrom<Tensor> for Vec<Vec<f64>>

Source§

fn try_from(t: Tensor) -> Result<Vec<Vec<f64>>, MattenError>

Consumes a 2-D tensor and returns rows of owned data.

§Errors

Returns MattenError::Shape if the tensor is not rank 2.

Source§

type Error = MattenError

The type returned in the event of a conversion error.

Auto Trait Implementations§

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> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

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