dendritic_ndarray/ops/
aggregate.rs

1use crate::ops::unary::UnaryOps; 
2use crate::ops::scalar::ScalarOps; 
3use crate::ndarray::NDArray;
4
5pub trait AggregateOps {
6    fn avg(&self) -> f64;
7    fn length(&self) -> f64;
8    fn square(&self) -> Result<NDArray<f64>, String>;
9    fn sum(&self) -> Result<NDArray<f64>, String>; 
10    fn abs(&self) -> Result<NDArray<f64>, String>;
11    fn sort(&self) -> Vec<f64>;
12    fn unique(&self) -> Vec<f64>;
13    fn mean(&self, axis: usize) -> Result<Vec<f64>, String>;
14    fn stdev(&self, axis: usize) -> Result<Vec<f64>, String>; 
15    fn stdev_sample(&self, axis: usize) -> Result<Vec<f64>, String>;
16}
17
18
19impl AggregateOps for NDArray<f64> {
20
21    /// Take the average of all elements in ndarray structure
22    fn avg(&self) -> f64 {
23        let sum: f64 = self.values().iter().sum();
24        sum / self.size() as f64
25    }
26
27    /// Computes the length or magnitude of vector
28    fn length(&self) -> f64 {
29        let mut sum: f64 = 0.0;
30        for index in 0..self.size() {
31            let value = self.values()[index]; 
32            let raised = value.powf(2.0);
33            sum += raised;
34        }
35
36        sum.sqrt()
37    }
38
39
40    /// Raise all elements to the second power
41    fn square(&self) -> Result<NDArray<f64>, String> {
42
43        let mut result = NDArray::new(self.shape().values()).unwrap();
44        for index in 0..self.size() {
45            let value = self.values()[index]; 
46            let raised = value.powf(2.0); 
47            let _ = result.set_idx(index, raised);
48        }
49
50        Ok(result)
51    }
52
53
54    /// sum all elements in ndarray structure
55    fn sum(&self) -> Result<NDArray<f64>, String> {
56
57        let sum_val = self.values().iter().sum();
58        let result = NDArray::array(
59            vec![1, 1],
60            vec![sum_val]
61        ).unwrap();
62
63        Ok(result)
64
65    }
66
67
68    /// Get the absolute value of each element in ndarray
69    fn abs(&self) -> Result<NDArray<f64>, String> {
70
71        let abs: Vec<f64> = self.values().into_iter().map(
72            |val| val.abs()
73        ).collect();
74
75        let result = NDArray::array(
76            self.shape().values(), abs
77        ).unwrap();
78
79        Ok(result)
80    }
81
82
83    /// Sort values in ndarray on specific axis
84    fn sort(&self) -> Vec<f64> {
85        let mut values = self.values().clone();
86        values.sort_by(|a, b| a.partial_cmp(b).unwrap());
87        values.to_vec()
88    }
89
90
91    /// Get unique values in ndarray
92    fn unique(&self) -> Vec<f64> {
93        let mut values = self.values().clone();
94        values.sort_by(|a, b| a.partial_cmp(b).unwrap());
95        values.dedup();
96        values.to_vec()
97    }
98
99
100    /// Calculate the mean of values along a specific axis
101    fn mean(&self, axis: usize) -> Result<Vec<f64>, String> {
102
103        let mut results: Vec<f64> = Vec::new(); 
104        let shape_axis = self.shape().dim(axis);
105        for item in 0..shape_axis {
106            let axis_vals = self.axis(axis, item).unwrap();  
107            let sum_vals: f64 = axis_vals.values().iter().sum(); 
108            let avg: f64 = sum_vals / axis_vals.values().len() as f64;
109            results.push(avg); 
110        }
111
112        Ok(results)
113    }
114
115    /// Calculate the mean of values along a specific axis
116    fn stdev(&self, axis: usize) -> Result<Vec<f64>, String> {
117
118        if axis >= self.shape().values().len() {
119            let msg = "stdev: Axis too large for current array";
120            return Err(msg.to_string());
121        }
122
123        let mut results: Vec<f64> = Vec::new(); 
124        let mean_axis = self.mean(axis).unwrap();
125        let shape_axis = self.shape().dim(axis);
126        for shape in 0..shape_axis {
127            let axis_vals = self.axis(axis, shape).unwrap();
128            let mean_axis_val = mean_axis[shape];
129            let subtract_mean = axis_vals.scalar_subtract(mean_axis_val).unwrap();
130            let squared = subtract_mean.norm(2).unwrap();
131            let sum: f64 = squared.values().iter().sum();
132            let avg = sum / axis_vals.size() as f64;
133            results.push(avg.sqrt()); 
134        }
135
136        Ok(results)
137    }
138
139
140    /// Calculate the mean of values along a specific axis
141    fn stdev_sample(&self, axis: usize) -> Result<Vec<f64>, String> {
142
143        if axis >= self.shape().values().len() {
144            let msg = "stdev sample: Axis too large for current array";
145            return Err(msg.to_string());
146        }
147
148        let mut results: Vec<f64> = Vec::new(); 
149        let mean_axis = self.mean(axis).unwrap();
150        let shape_axis = self.shape().dim(axis);
151        for shape in 0..shape_axis {
152            let axis_vals = self.axis(axis, shape).unwrap();
153            let mean_axis_val = mean_axis[shape];
154            let subtract_mean = axis_vals.scalar_subtract(mean_axis_val).unwrap();
155            let squared = subtract_mean.norm(2).unwrap();
156            let sum: f64 = squared.values().iter().sum();
157            let avg = sum / (axis_vals.size() - 1) as f64;
158            results.push(avg.sqrt()); 
159        }
160
161        Ok(results)
162    }
163
164
165}