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
//! Reductions over the logical region.
//!
//! Reductions are where padding bites: a naive sum over the padded buffer would
//! fold in garbage. Every reduction here walks only logical elements, which is the
//! whole reason the lattice keeps a [`crate::mask::Mask`] around.
use crate::lattice::PaddedTileLattice;
impl PaddedTileLattice<f32> {
/// Sum of every logical element.
pub fn sum(&self) -> f32 {
self.iter_logical().map(|(_, _, v)| v).sum()
}
/// Largest logical element, or `None` if the lattice is empty.
pub fn max(&self) -> Option<f32> {
self.iter_logical()
.map(|(_, _, v)| v)
.fold(None, |acc, v| match acc {
None => Some(v),
Some(m) => Some(if v > m { v } else { m }),
})
}
/// Smallest logical element, or `None` if the lattice is empty.
pub fn min(&self) -> Option<f32> {
self.iter_logical()
.map(|(_, _, v)| v)
.fold(None, |acc, v| match acc {
None => Some(v),
Some(m) => Some(if v < m { v } else { m }),
})
}
/// Arithmetic mean of every logical element, or `None` if empty.
pub fn mean(&self) -> Option<f32> {
if self.is_empty() {
return None;
}
Some(self.sum() / self.len() as f32)
}
/// Per-row sums, length `rows`.
pub fn row_sums(&self) -> Vec<f32> {
let mut out = vec![0.0f32; self.rows()];
for (row, _, v) in self.iter_logical() {
out[row] += v;
}
out
}
/// Per-column sums, length `cols`.
pub fn col_sums(&self) -> Vec<f32> {
let mut out = vec![0.0f32; self.cols()];
for (_, col, v) in self.iter_logical() {
out[col] += v;
}
out
}
}