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
impl Tensor
Sourcepub fn linspace(start: f64, end: f64, count: usize) -> Tensor
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?
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
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}Sourcepub fn try_linspace(
start: f64,
end: f64,
count: usize,
) -> Result<Tensor, MattenError>
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());Sourcepub fn eye(n: usize) -> Tensor
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]);Sourcepub fn try_eye(n: usize) -> Result<Tensor, MattenError>
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
impl Tensor
Sourcepub fn try_zeros(shape: &[usize]) -> Result<Tensor, MattenError>
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?
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}Sourcepub fn try_zeros_with_limits(
shape: &[usize],
limits: &MattenLimits,
) -> Result<Tensor, MattenError>
pub fn try_zeros_with_limits( shape: &[usize], limits: &MattenLimits, ) -> Result<Tensor, MattenError>
Creates a zero tensor with explicit limits.
Examples found in repository?
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}Sourcepub fn try_ones(shape: &[usize]) -> Result<Tensor, MattenError>
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?
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}Sourcepub fn try_ones_with_limits(
shape: &[usize],
limits: &MattenLimits,
) -> Result<Tensor, MattenError>
pub fn try_ones_with_limits( shape: &[usize], limits: &MattenLimits, ) -> Result<Tensor, MattenError>
Creates a ones tensor with explicit limits.
Sourcepub fn try_full(shape: &[usize], value: f64) -> Result<Tensor, MattenError>
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?
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}Sourcepub fn try_full_with_limits(
shape: &[usize],
value: f64,
limits: &MattenLimits,
) -> Result<Tensor, MattenError>
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
impl Tensor
Sourcepub fn sum(&self) -> f64
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?
More examples
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}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}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}Sourcepub fn mean(&self) -> f64
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?
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
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}Sourcepub fn min(&self) -> f64
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?
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}Sourcepub fn max(&self) -> f64
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?
More examples
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}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
impl Tensor
Sourcepub fn sum_axis(&self, axis: usize) -> Tensor
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?
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
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}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}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}Sourcepub fn mean_axis(&self, axis: usize) -> Tensor
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?
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
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 = (¢red * ¢red).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}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}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 = ¢red * ¢red;
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 = ¢red / &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}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
impl Tensor
Sourcepub fn min_axis(&self, axis: usize) -> Tensor
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?
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 = (¢red * ¢red).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
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) / ⦥
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}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}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}Sourcepub fn max_axis(&self, axis: usize) -> Tensor
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?
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 = (¢red * ¢red).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
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) / ⦥
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}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}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
impl Tensor
Sourcepub fn dot(&self, rhs: &Tensor) -> Tensor
pub fn dot(&self, rhs: &Tensor) -> Tensor
Vector/matrix multiplication.
Supported forms:
self shape | rhs shape | result 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?
More examples
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}Sourcepub fn matmul(&self, rhs: &Tensor) -> Tensor
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?
More examples
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
impl Tensor
Sourcepub fn abs(&self) -> Tensor
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]);Sourcepub fn sqrt(&self) -> Tensor
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]);Sourcepub fn exp(&self) -> Tensor
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);Sourcepub fn ln(&self) -> Tensor
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);Sourcepub fn clip(&self, min: f64, max: f64) -> Tensor
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]);Sourcepub fn try_clip(&self, min: f64, max: f64) -> Result<Tensor, MattenError>
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
impl Tensor
Sourcepub fn argmin(&self) -> usize
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.0sExamples found in repository?
More examples
Sourcepub fn argmax(&self) -> usize
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.0sSourcepub fn try_argmin(&self) -> Result<usize, MattenError>
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());Sourcepub fn try_argmax(&self) -> Result<usize, MattenError>
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
impl Tensor
Sourcepub fn reshape(&self, new_shape: &[usize]) -> Tensor
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?
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
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}Sourcepub fn try_reshape(&self, new_shape: &[usize]) -> Result<Tensor, MattenError>
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?
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}Sourcepub fn flatten(&self) -> Tensor
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?
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
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}Sourcepub fn transpose(&self) -> Tensor
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?
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
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}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}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}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}Sourcepub fn t(&self) -> Tensor
pub fn t(&self) -> Tensor
Alias for transpose.
Examples found in repository?
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}Sourcepub fn swap_axes(&self, axis1: usize, axis2: usize) -> Tensor
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?
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}Sourcepub fn squeeze(&self) -> Tensor
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]);Sourcepub fn expand_dims(&self, axis: usize) -> Tensor
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]);Sourcepub fn try_expand_dims(&self, axis: usize) -> Result<Tensor, MattenError>
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());Sourcepub fn get(&self, coord: &[usize]) -> Option<f64>
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?
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
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}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}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}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}Sourcepub fn get_flat(&self, index: usize) -> Option<f64>
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);Sourcepub fn slice(&self) -> SliceBuilder<'_>
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?
More examples
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}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}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}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}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) / ⦥
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}Sourcepub fn slice_str(&self, spec: &str) -> Result<Tensor, MattenError>
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?
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
impl Tensor
Sourcepub fn from_json(input: &str) -> Result<Tensor, MattenError>
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?
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
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}Sourcepub fn from_csv(input: &str) -> Result<Tensor, MattenError>
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?
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}Sourcepub fn load_json(path: impl AsRef<Path>) -> Result<Tensor, MattenError>
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?
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
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}Sourcepub fn load_csv(path: impl AsRef<Path>) -> Result<Tensor, MattenError>
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?
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
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
impl Tensor
Sourcepub fn new(data: Vec<f64>, shape: &[usize]) -> Tensor
pub fn new(data: Vec<f64>, shape: &[usize]) -> Tensor
Examples found in repository?
More examples
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}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}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}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}- examples/21_matrix_vector_product.rs
- examples/07_transpose_swap_axes.rs
- examples/38_nearest_neighbor_classification.rs
- examples/22_matrix_multiplication.rs
- examples/gram_matrix.rs
- examples/rowwise_scoring.rs
- examples/08_slicing_builder.rs
- examples/column_summary.rs
- examples/30_magic_square_checker.rs
- examples/23_sum_mean.rs
- examples/09_slice_str.rs
- examples/06_broadcasting.rs
- examples/pairwise_distance.rs
- examples/02_shape_and_size.rs
- examples/minmax_scaling.rs
- examples/01_create_tensor.rs
- examples/35_linear_regression_gradient_descent.rs
- examples/33_markov_chain_weather.rs
- examples/32_graph_path_counting.rs
- examples/standardize_columns.rs
- examples/36_heat_equation_1d.rs
- examples/28_column_statistics.rs
- examples/10_json_roundtrip.rs
- examples/34_tiny_pagerank.rs
- examples/27_axis_reductions.rs
- examples/37_kmeans_small.rs
- examples/12_boundary_error_handling.rs
Sourcepub fn try_new(data: Vec<f64>, shape: &[usize]) -> Result<Tensor, MattenError>
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?
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
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}Sourcepub fn scalar(value: f64) -> Tensor
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?
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
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}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}Sourcepub fn zeros(shape: &[usize]) -> Tensor
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?
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
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}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}Sourcepub fn ones(shape: &[usize]) -> Tensor
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?
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
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}Sourcepub fn full(shape: &[usize], value: f64) -> Tensor
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?
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
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}Sourcepub fn from_vec(data: Vec<f64>) -> Tensor
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?
More examples
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}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}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}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}- examples/35_linear_regression_gradient_descent.rs
- examples/21_matrix_vector_product.rs
- examples/26_cosine_similarity.rs
- examples/moving_average.rs
- examples/24_min_max.rs
- examples/23_sum_mean.rs
- examples/02_shape_and_size.rs
- examples/01_create_tensor.rs
- examples/33_markov_chain_weather.rs
- examples/36_heat_equation_1d.rs
Sourcepub fn arange(start: f64, end: f64, step: f64) -> Tensor
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?
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}Sourcepub fn try_arange(
start: f64,
end: f64,
step: f64,
) -> Result<Tensor, MattenError>
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.
Sourcepub fn try_from_rows(rows: Vec<Vec<f64>>) -> Result<Tensor, MattenError>
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.
Sourcepub fn shape(&self) -> &[usize]
pub fn shape(&self) -> &[usize]
The shape as a slice of dimension lengths. Non-allocating.
Examples found in repository?
More examples
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}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}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/22_matrix_multiplication.rs
- examples/gram_matrix.rs
- examples/rowwise_scoring.rs
- examples/column_summary.rs
- examples/06_broadcasting.rs
- examples/pairwise_distance.rs
- examples/02_shape_and_size.rs
- examples/11_csv_numeric_loading.rs
- examples/minmax_scaling.rs
- examples/30_magic_square_checker.rs
- examples/standardize_columns.rs
- examples/10_json_roundtrip.rs
- examples/27_axis_reductions.rs
- examples/37_kmeans_small.rs
- examples/13_resource_limits.rs
Sourcepub fn ndim(&self) -> usize
pub fn ndim(&self) -> usize
The rank (number of dimensions): shape().len().
Examples found in repository?
More examples
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}Sourcepub fn len(&self) -> usize
pub fn len(&self) -> usize
The logical element count: the product of the shape.
Examples found in repository?
More examples
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}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}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}Sourcepub fn is_scalar(&self) -> bool
pub fn is_scalar(&self) -> bool
Returns true for a rank-0 scalar tensor (shape []).
Examples found in repository?
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
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}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}Sourcepub fn is_vector(&self) -> bool
pub fn is_vector(&self) -> bool
Returns true for a rank-1 tensor.
Examples found in repository?
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}Sourcepub fn is_matrix(&self) -> bool
pub fn is_matrix(&self) -> bool
Returns true for a rank-2 tensor.
Examples found in repository?
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}Sourcepub fn is_dynamic(&self) -> bool
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
dynamicis off, no dynamic tensor can be constructed, so this always returnsfalse. - When
dynamicis on, it returnstruefor tensors built via the dynamic API (e.g. [Tensor::from_elements]) andfalsefor 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.
Sourcepub fn as_slice(&self) -> &[f64]
pub fn as_slice(&self) -> &[f64]
The flat, row-major data as a slice.
Examples found in repository?
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
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}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}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/rolling_windows_basic.rs
- examples/20_dot_product.rs
- examples/35_linear_regression_gradient_descent.rs
- examples/03_reshape_flatten.rs
- examples/21_matrix_vector_product.rs
- examples/22_matrix_multiplication.rs
- examples/moving_average.rs
- examples/40_trapezoidal_integration.rs
- examples/rowwise_scoring.rs
- examples/column_summary.rs
- examples/23_sum_mean.rs
- examples/06_broadcasting.rs
- examples/pairwise_distance.rs
- examples/11_csv_numeric_loading.rs
- examples/minmax_scaling.rs
- examples/39_finite_difference_derivative.rs
- examples/33_markov_chain_weather.rs
- examples/standardize_columns.rs
- examples/36_heat_equation_1d.rs
- examples/27_axis_reductions.rs
- examples/37_kmeans_small.rs
- examples/13_resource_limits.rs
Trait Implementations§
Source§impl Add for &Tensor
impl Add for &Tensor
Source§fn add(self, rhs: &Tensor) -> Tensor
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§impl Add<&Tensor> for f64
impl Add<&Tensor> for f64
Source§impl<'de> Deserialize<'de> for Tensor
Available on crate feature serde only.
impl<'de> Deserialize<'de> for Tensor
serde only.Source§fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error>
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error>
Source§impl Div for &Tensor
impl Div for &Tensor
Source§fn div(self, rhs: &Tensor) -> Tensor
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§impl Div<&Tensor> for f64
impl Div<&Tensor> for f64
Source§impl Div<f64> for &Tensor
impl Div<f64> for &Tensor
Source§impl From<Vec<Vec<f64>>> for Tensor
impl From<Vec<Vec<f64>>> for Tensor
Source§fn from(rows: Vec<Vec<f64>>) -> Self
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 Mul for &Tensor
impl Mul for &Tensor
Source§fn mul(self, rhs: &Tensor) -> Tensor
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§impl Mul<&Tensor> for f64
impl Mul<&Tensor> for f64
Source§impl Sub for &Tensor
impl Sub for &Tensor
Source§impl Sub<&Tensor> for f64
impl Sub<&Tensor> for f64
Source§impl TryFrom<Tensor> for Vec<Vec<f64>>
impl TryFrom<Tensor> for Vec<Vec<f64>>
Source§fn try_from(t: Tensor) -> Result<Vec<Vec<f64>>, MattenError>
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.