From a7b0183cceb402c0cc98e659897c44e4b846de80 Mon Sep 17 00:00:00 2001 From: boulea7 Date: Fri, 16 Oct 2026 01:39:32 +0800 Subject: [PATCH] fix: reject empty tensor variance Fixes #47. --- src/tensor/ops/reduce.rs | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/tensor/ops/reduce.rs b/src/tensor/ops/reduce.rs index 119f891..8f68325 100644 --- a/src/tensor/ops/reduce.rs +++ b/src/tensor/ops/reduce.rs @@ -102,7 +102,10 @@ impl Tensor { } /// Population variance of every element. + /// + /// Panics if the tensor is empty. pub fn variance(&self) -> f32 { + assert!(self.numel() > 0, "variance() of an empty tensor"); let data = self.to_vec(); let mean = data.iter().sum::() / data.len() as f32; data.iter().map(|&x| (x - mean).powi(2)).sum::() / data.len() as f32 @@ -135,3 +138,35 @@ impl Tensor { fn single(buf: crate::cuda::CudaBuffer) -> f32 { buf.to_vec().expect("cuda download")[0] } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[should_panic(expected = "variance() of an empty tensor")] + fn variance_rejects_an_empty_vector() { + let tensor = Tensor::from_vec(vec![], &[0]); + assert_eq!(tensor.numel(), 0); + tensor.variance(); + } + + #[test] + #[should_panic(expected = "variance() of an empty tensor")] + fn variance_rejects_a_zero_sized_dimension() { + let tensor = Tensor::from_vec(vec![], &[2, 0]); + assert_eq!(tensor.numel(), 0); + tensor.variance(); + } + + #[test] + fn variance_of_a_singleton_is_zero() { + assert_eq!(Tensor::from_vec(vec![3.0], &[1]).variance(), 0.0); + } + + #[test] + fn variance_uses_the_population_denominator() { + let tensor = Tensor::from_vec(vec![1.0, 2.0, 3.0, 4.0], &[2, 2]); + assert_eq!(tensor.variance(), 1.25); + } +}