field.rs
2.5 kB · rust · 83 lines
1use crate::core::error::{shape_error, Result};2use serde::{Deserialize, Serialize};34/// A square grid of f32 samples.5#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]6pub struct Field {7 /// The samples in row-major order.8 pub data: Vec<f32>,9 /// The side length in samples.10 pub size: usize,11}1213impl Field {14 /// Builds a zeroed field of the given side.15 pub fn new(size: usize) -> Field {16 Field {17 data: vec![0.0; size * size],18 size,19 }20 }21 /// Wraps row-major samples of the given side.22 ///23 /// # Errors24 ///25 /// Errors when the count is not the side squared.26 pub fn from_data(data: Vec<f32>, size: usize) -> Result<Field> {27 if data.len() != size * size {28 return shape_error(format!(29 "a field of side {size} needs {} samples, got {}.",30 size * size,31 data.len()32 ));33 }34 Ok(Field { data, size })35 }36 /// Returns the smallest sample.37 pub fn min(&self) -> f32 {38 self.data.iter().cloned().fold(f32::INFINITY, f32::min)39 }40 /// Returns the largest sample.41 pub fn max(&self) -> f32 {42 self.data.iter().cloned().fold(f32::NEG_INFINITY, f32::max)43 }44 /// Returns the mean sample, or zero for an empty field.45 pub fn mean(&self) -> f64 {46 if self.data.is_empty() {47 return 0.0;48 }49 self.data.iter().map(|&v| v as f64).sum::<f64>() / self.data.len() as f6450 }51 /// Returns the samples widened to f64.52 pub fn as_f64(&self) -> Vec<f64> {53 self.data.iter().map(|&v| v as f64).collect()54 }55 /// Returns the samples scaled into 0..1, symmetric about zero on request.56 pub fn normalized(&self, symmetric: bool) -> Vec<f32> {57 if symmetric {58 let m = self59 .data60 .iter()61 .fold(0.0f32, |acc, &v| acc.max(v.abs()))62 .max(f32::EPSILON);63 self.data.iter().map(|&v| (v / m + 1.0) / 2.0).collect()64 } else {65 let lo = self.min();66 let hi = self.max();67 let span = (hi - lo).max(f32::EPSILON);68 self.data.iter().map(|&v| (v - lo) / span).collect()69 }70 }71}7273#[cfg(test)]74mod tests {75 use super::*;7677 #[test]78 fn refuses_a_count_that_is_not_the_side_squared() {79 assert!(Field::from_data(vec![0.0; 3], 2).is_err());80 assert!(Field::from_data(vec![0.0; 5], 2).is_err());81 assert!(Field::from_data(vec![0.0; 4], 2).is_ok());82 }83}