extern crate alloc;
use alloc::vec::Vec;
use super::adjoint::FiniteFunctor;
#[must_use]
pub fn kan_extension_left(k: &FiniteFunctor, f_image: &[u32], c: u32) -> u32 {
debug_assert_eq!(k.object_map.len(), f_image.len());
let mut acc: u32 = 0;
for (m, &kc) in k.object_map.iter().enumerate() {
if kc == c {
acc = acc.saturating_add(f_image[m]);
}
}
acc
}
#[must_use]
pub fn kan_extension_right(k: &FiniteFunctor, f_image: &[u32], c: u32) -> u32 {
debug_assert_eq!(k.object_map.len(), f_image.len());
let mut acc: u32 = 1;
for (m, &kc) in k.object_map.iter().enumerate() {
if kc == c {
acc = acc.saturating_mul(f_image[m]);
}
}
acc
}
#[must_use]
pub fn kan_extension_left_table(k: &FiniteFunctor, f_image: &[u32], c_n: u32) -> Vec<u32> {
(0..c_n)
.map(|c| kan_extension_left(k, f_image, c))
.collect()
}
#[must_use]
pub fn kan_extension_right_table(k: &FiniteFunctor, f_image: &[u32], c_n: u32) -> Vec<u32> {
(0..c_n)
.map(|c| kan_extension_right(k, f_image, c))
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn lan_at_unmapped_object_is_zero() {
let k = FiniteFunctor {
object_map: alloc::vec![0, 0],
};
let f = alloc::vec![3u32, 5];
assert_eq!(kan_extension_left(&k, &f, 1), 0);
}
#[test]
fn lan_sums_preimage() {
let k = FiniteFunctor {
object_map: alloc::vec![0, 0, 1],
};
let f = alloc::vec![3u32, 5, 7];
assert_eq!(kan_extension_left(&k, &f, 0), 8);
assert_eq!(kan_extension_left(&k, &f, 1), 7);
}
#[test]
fn ran_at_unmapped_object_is_one() {
let k = FiniteFunctor {
object_map: alloc::vec![0, 0],
};
let f = alloc::vec![3u32, 5];
assert_eq!(kan_extension_right(&k, &f, 1), 1);
}
#[test]
fn ran_multiplies_preimage() {
let k = FiniteFunctor {
object_map: alloc::vec![0, 0, 1],
};
let f = alloc::vec![3u32, 5, 7];
assert_eq!(kan_extension_right(&k, &f, 0), 15);
assert_eq!(kan_extension_right(&k, &f, 1), 7);
}
#[test]
fn table_matches_pointwise() {
let k = FiniteFunctor {
object_map: alloc::vec![0, 1, 0, 2, 1],
};
let f = alloc::vec![1u32, 2, 3, 4, 5];
let lan_table = kan_extension_left_table(&k, &f, 3);
let ran_table = kan_extension_right_table(&k, &f, 3);
for c in 0..3u32 {
assert_eq!(lan_table[c as usize], kan_extension_left(&k, &f, c));
assert_eq!(ran_table[c as usize], kan_extension_right(&k, &f, c));
}
}
#[test]
fn identity_kan_extension_is_f() {
let k = FiniteFunctor::identity(4);
let f = alloc::vec![2u32, 3, 5, 7];
for c in 0..4u32 {
assert_eq!(kan_extension_left(&k, &f, c), f[c as usize]);
assert_eq!(kan_extension_right(&k, &f, c), f[c as usize]);
}
}
#[test]
fn saturating_protects_overflow() {
let k = FiniteFunctor {
object_map: alloc::vec![0, 0, 0],
};
let f = alloc::vec![u32::MAX, u32::MAX, u32::MAX];
assert_eq!(kan_extension_left(&k, &f, 0), u32::MAX);
assert_eq!(kan_extension_right(&k, &f, 0), u32::MAX);
}
}