extern crate alloc;
use alloc::vec::Vec;
use super::yoneda::FiniteCategory;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FiniteFunctor {
pub object_map: Vec<u32>,
}
impl FiniteFunctor {
#[must_use]
pub fn identity(n: u32) -> Self {
Self {
object_map: (0..n).collect(),
}
}
#[must_use]
pub fn apply(&self, c: u32) -> u32 {
self.object_map.get(c as usize).copied().unwrap_or(u32::MAX)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AdjointPair {
pub is_adjoint: bool,
pub witness: Option<(u32, u32)>,
}
#[must_use]
pub fn is_adjoint_pair(
c_cat: &FiniteCategory,
d_cat: &FiniteCategory,
f: &FiniteFunctor,
g: &FiniteFunctor,
) -> AdjointPair {
if f.object_map.len() as u32 != c_cat.n || g.object_map.len() as u32 != d_cat.n {
return AdjointPair {
is_adjoint: false,
witness: Some((0, 0)),
};
}
for c in 0..c_cat.n {
for d in 0..d_cat.n {
let lhs = d_cat.hom(f.apply(c), d);
let rhs = c_cat.hom(c, g.apply(d));
if lhs != rhs {
return AdjointPair {
is_adjoint: false,
witness: Some((c, d)),
};
}
}
}
AdjointPair {
is_adjoint: true,
witness: None,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn identity_is_self_adjoint_on_discrete() {
let cat = FiniteCategory::discrete(3);
let id = FiniteFunctor::identity(3);
let result = is_adjoint_pair(&cat, &cat, &id, &id);
assert!(result.is_adjoint);
assert!(result.witness.is_none());
}
#[test]
fn non_adjoint_pinpoints_failure() {
let cat = FiniteCategory::discrete(2);
let f = FiniteFunctor {
object_map: alloc::vec![0, 0],
};
let g = FiniteFunctor::identity(2);
let result = is_adjoint_pair(&cat, &cat, &f, &g);
assert!(!result.is_adjoint);
assert!(result.witness.is_some());
}
#[test]
fn partial_adjunction_rejected() {
let cat = FiniteCategory::discrete(2);
let f = FiniteFunctor::identity(2);
let g = FiniteFunctor {
object_map: alloc::vec![1, 0],
};
let result = is_adjoint_pair(&cat, &cat, &f, &g);
assert!(!result.is_adjoint);
}
#[test]
fn identity_adjoint_pair_for_any_size() {
for n in [1u32, 2, 4, 8] {
let cat = FiniteCategory::discrete(n);
let id = FiniteFunctor::identity(n);
assert!(is_adjoint_pair(&cat, &cat, &id, &id).is_adjoint);
}
}
}