systile 0.10.0

A TPU-native tiled tensor data structure: the Systolic Tile Lattice. Padding-aware, sublane/lane laid out, bf16/int8 first, with a CPU reference simulator of systolic dataflow.
Documentation
//! 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
    }
}