use crate::{MattenError, Tensor};
#[test]
fn norm_vector_3_4_is_5() {
assert_eq!(Tensor::from_vec(vec![3.0, 4.0]).norm(), 5.0);
}
#[test]
fn norm_matrix_uses_all_elements() {
let m = Tensor::new(vec![1.0, 2.0, 2.0, 4.0], &[2, 2]);
assert!((m.norm() - 5.0).abs() < 1e-12);
}
#[test]
fn norm_scalar() {
assert_eq!(Tensor::scalar(-7.0).norm(), 7.0);
}
#[test]
fn norm_nan_propagates() {
assert!(Tensor::from_vec(vec![1.0, f64::NAN, 2.0]).norm().is_nan());
}
#[test]
fn trace_square() {
let m = Tensor::new(vec![1.0, 2.0, 3.0, 4.0], &[2, 2]);
assert_eq!(m.trace(), 5.0); }
#[test]
fn trace_rectangular_rows_lt_cols() {
let m = Tensor::new(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0], &[2, 3]);
assert_eq!(m.trace(), 6.0);
}
#[test]
fn trace_rectangular_rows_gt_cols() {
let m = Tensor::new(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0], &[3, 2]);
assert_eq!(m.trace(), 5.0);
}
#[test]
fn trace_rank1_is_shape() {
let v = Tensor::from_vec(vec![1.0, 2.0, 3.0]);
assert!(matches!(
v.try_trace().unwrap_err(),
MattenError::Shape {
operation: "trace",
..
}
));
}
#[test]
fn trace_rank3_is_shape() {
let t = Tensor::new(vec![1.0; 8], &[2, 2, 2]);
assert!(matches!(
t.try_trace().unwrap_err(),
MattenError::Shape {
operation: "trace",
..
}
));
}
#[test]
fn outer_basic_values() {
let a = Tensor::from_vec(vec![1.0, 2.0, 3.0]);
let b = Tensor::from_vec(vec![4.0, 5.0]);
let o = a.outer(&b);
assert_eq!(o.shape(), &[3, 2]);
assert_eq!(o.as_slice(), &[4.0, 5.0, 8.0, 10.0, 12.0, 15.0]);
}
#[test]
fn outer_non_square_shape() {
let a = Tensor::from_vec(vec![2.0, 3.0, 4.0, 5.0]); let b = Tensor::from_vec(vec![10.0, 20.0]); let o = a.outer(&b);
assert_eq!(o.shape(), &[4, 2]);
assert_eq!(
o.as_slice(),
&[20.0, 40.0, 30.0, 60.0, 40.0, 80.0, 50.0, 100.0]
);
}
#[test]
fn outer_rejects_non_rank1_lhs() {
let m = Tensor::new(vec![1.0, 2.0, 3.0, 4.0], &[2, 2]);
let v = Tensor::from_vec(vec![1.0, 2.0]);
assert!(matches!(
m.try_outer(&v).unwrap_err(),
MattenError::Shape {
operation: "outer",
..
}
));
}
#[test]
fn outer_rejects_non_rank1_rhs() {
let v = Tensor::from_vec(vec![1.0, 2.0]);
let m = Tensor::new(vec![1.0, 2.0, 3.0, 4.0], &[2, 2]);
assert!(matches!(
v.try_outer(&m).unwrap_err(),
MattenError::Shape {
operation: "outer",
..
}
));
}
#[test]
fn outer_respects_allocation_limit() {
let a = Tensor::from_vec(vec![1.0; 1025]);
let b = Tensor::from_vec(vec![1.0; 1025]);
assert!(matches!(
a.try_outer(&b).unwrap_err(),
MattenError::Allocation { .. }
));
}
#[cfg(feature = "dynamic")]
#[test]
fn trace_and_outer_reject_dynamic() {
use crate::dynamic::Element;
let dynamic = Tensor::from_elements(
vec![
Element::Float(1.0),
Element::Float(2.0),
Element::Float(3.0),
Element::Float(4.0),
],
&[2, 2],
);
assert!(dynamic.is_dynamic());
assert!(matches!(
dynamic.try_trace().unwrap_err(),
MattenError::Unsupported {
operation: "trace",
..
}
));
let v = Tensor::from_elements(vec![Element::Float(1.0), Element::Float(2.0)], &[2]);
let numeric = Tensor::from_vec(vec![3.0, 4.0]);
assert!(matches!(
numeric.try_outer(&v).unwrap_err(),
MattenError::Unsupported {
operation: "outer",
..
}
));
}
#[cfg(feature = "dynamic")]
#[test]
#[should_panic(expected = "dynamic")]
fn norm_panics_on_dynamic() {
use crate::dynamic::Element;
let dynamic = Tensor::from_elements(vec![Element::Float(3.0), Element::Float(4.0)], &[2]);
let _ = dynamic.norm();
}