csa-rhdl 0.1.0

Carry-save adder compressor trees composed via comp-cat-rs, with hdl-cat backend
Documentation
//! Single-level arithmetic: `M` bundles → `floor(M/3)*2 + M%3` bundles.

use crate::category::graph::{LevelEdge, LevelKind};
use comp_cat_rs::collapse::free_category::Vertex;

/// Output bundle count after one CSA reduction stage.
#[must_use]
pub const fn next_bundles(m: usize) -> usize {
    (m / 3) * 2 + m % 3
}

/// Build a single [`LevelEdge`] for a CSA stage of `m` bundles at width `w`.
///
/// `source_idx` is the vertex index of the input shape; the edge
/// targets `source_idx + 1`.
#[must_use]
pub fn tree_level_edge(source_idx: usize, m: usize, w: usize) -> LevelEdge {
    LevelEdge {
        source: Vertex::new(source_idx),
        target: Vertex::new(source_idx + 1),
        kind: LevelKind::Csa { m, w },
    }
}

#[cfg(test)]
mod tests {
    use super::next_bundles;

    #[test]
    fn next_bundles_transitions() {
        let table: [(usize, usize); 8] = [
            (0, 0),
            (1, 1),
            (2, 2),
            (3, 2),
            (4, 3),
            (5, 4),
            (6, 4),
            (9, 6),
        ];
        table
            .iter()
            .for_each(|(m, want)| assert_eq!(next_bundles(*m), *want, "m={m}"));
    }

    #[test]
    fn nine_reduces_to_two_in_four_steps() {
        let steps = std::iter::successors(Some(9usize), |&b| match b {
            0..=2 => None,
            _ => Some(next_bundles(b)),
        })
        .collect::<Vec<_>>();
        assert_eq!(steps, vec![9, 6, 4, 3, 2]);
    }
}