dendritic_ndarray/ops/
aggregate.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
use crate::ops::unary::UnaryOps; 
use crate::ops::scalar::ScalarOps; 
use crate::ndarray::NDArray;

pub trait AggregateOps {
    fn avg(&self) -> f64;
    fn length(&self) -> f64;
    fn square(&self) -> Result<NDArray<f64>, String>;
    fn sum(&self) -> Result<NDArray<f64>, String>; 
    fn abs(&self) -> Result<NDArray<f64>, String>;
    fn sort(&self) -> Vec<f64>;
    fn unique(&self) -> Vec<f64>;
    fn mean(&self, axis: usize) -> Result<Vec<f64>, String>;
    fn stdev(&self, axis: usize) -> Result<Vec<f64>, String>; 
    fn stdev_sample(&self, axis: usize) -> Result<Vec<f64>, String>;
}


impl AggregateOps for NDArray<f64> {

    /// Take the average of all elements in ndarray structure
    fn avg(&self) -> f64 {
        let sum: f64 = self.values().iter().sum();
        sum / self.size() as f64
    }

    /// Computes the length or magnitude of vector
    fn length(&self) -> f64 {
        let mut sum: f64 = 0.0;
        for index in 0..self.size() {
            let value = self.values()[index]; 
            let raised = value.powf(2.0);
            sum += raised;
        }

        sum.sqrt()
    }


    /// Raise all elements to the second power
    fn square(&self) -> Result<NDArray<f64>, String> {

        let mut result = NDArray::new(self.shape().values()).unwrap();
        for index in 0..self.size() {
            let value = self.values()[index]; 
            let raised = value.powf(2.0); 
            let _ = result.set_idx(index, raised);
        }

        Ok(result)
    }


    /// sum all elements in ndarray structure
    fn sum(&self) -> Result<NDArray<f64>, String> {

        let sum_val = self.values().iter().sum();
        let result = NDArray::array(
            vec![1, 1],
            vec![sum_val]
        ).unwrap();

        Ok(result)

    }


    /// Get the absolute value of each element in ndarray
    fn abs(&self) -> Result<NDArray<f64>, String> {

        let abs: Vec<f64> = self.values().into_iter().map(
            |val| val.abs()
        ).collect();

        let result = NDArray::array(
            self.shape().values(), abs
        ).unwrap();

        Ok(result)
    }


    /// Sort values in ndarray on specific axis
    fn sort(&self) -> Vec<f64> {
        let mut values = self.values().clone();
        values.sort_by(|a, b| a.partial_cmp(b).unwrap());
        values.to_vec()
    }


    /// Get unique values in ndarray
    fn unique(&self) -> Vec<f64> {
        let mut values = self.values().clone();
        values.sort_by(|a, b| a.partial_cmp(b).unwrap());
        values.dedup();
        values.to_vec()
    }


    /// Calculate the mean of values along a specific axis
    fn mean(&self, axis: usize) -> Result<Vec<f64>, String> {

        let mut results: Vec<f64> = Vec::new(); 
        let shape_axis = self.shape().dim(axis);
        for item in 0..shape_axis {
            let axis_vals = self.axis(axis, item).unwrap();  
            let sum_vals: f64 = axis_vals.values().iter().sum(); 
            let avg: f64 = sum_vals / axis_vals.values().len() as f64;
            results.push(avg); 
        }

        Ok(results)
    }

    /// Calculate the mean of values along a specific axis
    fn stdev(&self, axis: usize) -> Result<Vec<f64>, String> {

        if axis >= self.shape().values().len() {
            let msg = "stdev: Axis too large for current array";
            return Err(msg.to_string());
        }

        let mut results: Vec<f64> = Vec::new(); 
        let mean_axis = self.mean(axis).unwrap();
        let shape_axis = self.shape().dim(axis);
        for shape in 0..shape_axis {
            let axis_vals = self.axis(axis, shape).unwrap();
            let mean_axis_val = mean_axis[shape];
            let subtract_mean = axis_vals.scalar_subtract(mean_axis_val).unwrap();
            let squared = subtract_mean.norm(2).unwrap();
            let sum: f64 = squared.values().iter().sum();
            let avg = sum / axis_vals.size() as f64;
            results.push(avg.sqrt()); 
        }

        Ok(results)
    }


    /// Calculate the mean of values along a specific axis
    fn stdev_sample(&self, axis: usize) -> Result<Vec<f64>, String> {

        if axis >= self.shape().values().len() {
            let msg = "stdev sample: Axis too large for current array";
            return Err(msg.to_string());
        }

        let mut results: Vec<f64> = Vec::new(); 
        let mean_axis = self.mean(axis).unwrap();
        let shape_axis = self.shape().dim(axis);
        for shape in 0..shape_axis {
            let axis_vals = self.axis(axis, shape).unwrap();
            let mean_axis_val = mean_axis[shape];
            let subtract_mean = axis_vals.scalar_subtract(mean_axis_val).unwrap();
            let squared = subtract_mean.norm(2).unwrap();
            let sum: f64 = squared.values().iter().sum();
            let avg = sum / (axis_vals.size() - 1) as f64;
            results.push(avg.sqrt()); 
        }

        Ok(results)
    }


}