csa-rhdl 0.1.0

Carry-save adder compressor trees composed via comp-cat-rs, with hdl-cat backend
Documentation
//! Category / `MonoidalCategory` / `Braided` / `Symmetric` instances
//! for the circuit category.
//!
//! Since Rust's generic trait signatures cannot recover the shape
//! information carried by individual object types, the trait methods
//! here return structural `CircuitArrow` nodes (including the
//! shape-erased [`IdAbstract`](crate::category::arrow::CircuitArrow::IdAbstract)).
//! Downstream callers who need concrete shape-carrying morphisms use
//! the free constructors on [`CircuitArrow`] directly.
//!
//! The Category / Monoidal / Braided / Symmetric impls exist so the
//! categorical combinators of [`comp_cat_rs`] (free-category
//! `interpret`, `Iso`-based coherence, etc.) can mechanically apply.

use core::marker::PhantomData;

use comp_cat_rs::foundation::{Braided, Category, Iso, MonoidalCategory, Symmetric};

use crate::category::arrow::CircuitArrow;
use crate::shape::Shape;

/// Witness type for the circuit category.
#[derive(Debug, Clone, Copy)]
pub struct CircuitCat;

/// Phantom tensor product: `TensorObj<A, B>` represents `A ⊗ B`
/// at the type level.
#[derive(Debug, Clone, Copy)]
pub struct TensorObj<A, B> {
    _phantom: PhantomData<(A, B)>,
}

/// The unit object of the tensor product (the empty wire bundle).
#[derive(Debug, Clone, Copy)]
pub struct UnitShape;

impl From<Shape> for CircuitCat {
    fn from(_: Shape) -> Self {
        Self
    }
}

impl From<UnitShape> for CircuitCat {
    fn from(_: UnitShape) -> Self {
        Self
    }
}

impl<A, B> From<TensorObj<A, B>> for CircuitCat {
    fn from(_: TensorObj<A, B>) -> Self {
        Self
    }
}

impl Category for CircuitCat {
    type Hom<A: Into<Self>, B: Into<Self>> = CircuitArrow;

    fn id<A: Into<Self> + Clone>(_a: &A) -> Self::Hom<A, A> {
        CircuitArrow::IdAbstract
    }

    fn comp<A, B, C>(f: Self::Hom<A, B>, g: Self::Hom<B, C>) -> Self::Hom<A, C>
    where
        A: Into<Self>,
        B: Into<Self>,
        C: Into<Self>,
    {
        CircuitArrow::compose_unchecked(f, g)
    }
}

impl MonoidalCategory for CircuitCat {
    type Tensor<A: Into<Self>, B: Into<Self>> = TensorObj<A, B>;
    type Unit = UnitShape;

    fn tensor_map<A, B, C, D>(
        f: Self::Hom<A, B>,
        g: Self::Hom<C, D>,
    ) -> Self::Hom<Self::Tensor<A, C>, Self::Tensor<B, D>>
    where
        A: Into<Self>,
        B: Into<Self>,
        C: Into<Self>,
        D: Into<Self>,
    {
        CircuitArrow::tensor(f, g)
    }

    fn associator<A, B, C>() -> Iso<
        Self,
        Self::Tensor<Self::Tensor<A, B>, C>,
        Self::Tensor<A, Self::Tensor<B, C>>,
    >
    where
        A: Into<Self>,
        B: Into<Self>,
        C: Into<Self>,
    {
        Iso::new(CircuitArrow::IdAbstract, CircuitArrow::IdAbstract)
    }

    fn left_unitor<A>() -> Iso<Self, Self::Tensor<Self::Unit, A>, A>
    where
        A: Into<Self>,
    {
        Iso::new(CircuitArrow::IdAbstract, CircuitArrow::IdAbstract)
    }

    fn right_unitor<A>() -> Iso<Self, Self::Tensor<A, Self::Unit>, A>
    where
        A: Into<Self>,
    {
        Iso::new(CircuitArrow::IdAbstract, CircuitArrow::IdAbstract)
    }
}

impl Braided for CircuitCat {
    fn braid<A, B>() -> Iso<Self, Self::Tensor<A, B>, Self::Tensor<B, A>>
    where
        A: Into<Self>,
        B: Into<Self>,
    {
        Iso::new(CircuitArrow::IdAbstract, CircuitArrow::IdAbstract)
    }
}

impl Symmetric for CircuitCat {}

#[cfg(test)]
mod tests {
    use super::{CircuitCat, CircuitArrow, Shape};
    use comp_cat_rs::foundation::{Category, MonoidalCategory};

    #[test]
    fn category_comp_builds_nested_arrow() {
        let f: CircuitArrow = CircuitArrow::passthrough(Shape::new(2, 8));
        let g: CircuitArrow = CircuitArrow::passthrough(Shape::new(2, 8));
        let h = <CircuitCat as Category>::comp::<Shape, Shape, Shape>(f, g);
        match h {
            CircuitArrow::Compose { .. } => {}
            CircuitArrow::Id(_)
            | CircuitArrow::IdAbstract
            | CircuitArrow::FullAdder
            | CircuitArrow::Csa3to2 { .. }
            | CircuitArrow::Braid { .. }
            | CircuitArrow::Passthrough(_)
            | CircuitArrow::Tensor { .. } => panic!("expected Compose"),
        }
    }

    #[test]
    fn monoidal_tensor_map_builds_tensor() {
        let f = CircuitArrow::passthrough(Shape::new(1, 4));
        let g = CircuitArrow::passthrough(Shape::new(1, 4));
        let t = <CircuitCat as MonoidalCategory>::tensor_map::<Shape, Shape, Shape, Shape>(f, g);
        match t {
            CircuitArrow::Tensor { .. } => {}
            CircuitArrow::Id(_)
            | CircuitArrow::IdAbstract
            | CircuitArrow::FullAdder
            | CircuitArrow::Csa3to2 { .. }
            | CircuitArrow::Braid { .. }
            | CircuitArrow::Passthrough(_)
            | CircuitArrow::Compose { .. } => panic!("expected Tensor"),
        }
    }

    #[test]
    fn id_returns_abstract() {
        let s = Shape::new(3, 8);
        let a = <CircuitCat as Category>::id::<Shape>(&s);
        match a {
            CircuitArrow::IdAbstract => {}
            CircuitArrow::Id(_)
            | CircuitArrow::FullAdder
            | CircuitArrow::Csa3to2 { .. }
            | CircuitArrow::Braid { .. }
            | CircuitArrow::Passthrough(_)
            | CircuitArrow::Tensor { .. }
            | CircuitArrow::Compose { .. } => panic!("expected IdAbstract"),
        }
    }
}