extern crate alloc;
use alloc::vec::Vec;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FiniteCategory {
pub n: u32,
pub hom_size: Vec<u32>,
}
impl FiniteCategory {
#[must_use]
pub fn discrete(n: u32) -> Self {
let n_us = n as usize;
let mut hom_size = alloc::vec![0u32; n_us * n_us];
for i in 0..n_us {
hom_size[i * n_us + i] = 1;
}
Self { n, hom_size }
}
#[must_use]
pub fn hom(&self, source: u32, target: u32) -> u32 {
if source >= self.n || target >= self.n {
return 0;
}
self.hom_size
.get((source * self.n + target) as usize)
.copied()
.unwrap_or(0)
}
}
#[must_use]
pub fn yoneda_embedding(category: &FiniteCategory, x: u32) -> Vec<u32> {
(0..category.n).map(|c| category.hom(c, x)).collect()
}
#[must_use]
pub fn yoneda_natural_iso(_category: &FiniteCategory, _x: u32, f_at_x: u32) -> u32 {
f_at_x
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn discrete_category_self_hom_is_one() {
let cat = FiniteCategory::discrete(4);
for i in 0..4 {
assert_eq!(cat.hom(i, i), 1);
}
}
#[test]
fn discrete_category_cross_hom_is_zero() {
let cat = FiniteCategory::discrete(4);
for i in 0..4 {
for j in 0..4 {
if i != j {
assert_eq!(cat.hom(i, j), 0);
}
}
}
}
#[test]
fn yoneda_embedding_on_discrete_is_unit_vector() {
let cat = FiniteCategory::discrete(3);
assert_eq!(yoneda_embedding(&cat, 0), alloc::vec![1, 0, 0]);
assert_eq!(yoneda_embedding(&cat, 1), alloc::vec![0, 1, 0]);
assert_eq!(yoneda_embedding(&cat, 2), alloc::vec![0, 0, 1]);
}
#[test]
fn yoneda_iso_equals_f_image_cardinality() {
let cat = FiniteCategory::discrete(3);
for &f_at_x in &[0u32, 1, 2, 5, 100, u32::MAX] {
assert_eq!(yoneda_natural_iso(&cat, 0, f_at_x), f_at_x);
}
}
#[test]
fn yoneda_invariant_under_richer_homsets() {
let mut cat = FiniteCategory::discrete(3);
cat.hom_size[0 * 3 + 1] = 2;
let f_at_x = 7;
assert_eq!(yoneda_natural_iso(&cat, 1, f_at_x), 7);
}
#[test]
fn empty_f_image_means_no_natural_transformations() {
let cat = FiniteCategory::discrete(2);
assert_eq!(yoneda_natural_iso(&cat, 0, 0), 0);
}
}