Merge commit 'd803bfe2b1fe7f5e219e50ac20d6801a0a58ac75' as 'vendor/ruvector'

This commit is contained in:
ruv
2026-02-28 14:39:40 -05:00
7854 changed files with 3522914 additions and 0 deletions

View File

@@ -0,0 +1,454 @@
//! # Topos Theory
//!
//! A topos is a category with additional structure that makes it behave
//! like a generalized universe of sets. It provides an internal logic
//! for reasoning about mathematical structures.
//!
//! ## Key Features
//!
//! - **Subobject classifier**: An object Ω with a universal property
//! for classifying subobjects (generalizes {true, false} in Set)
//! - **Internal logic**: Intuitionistic logic derived from the topos structure
//! - **Exponentials**: All function spaces exist
//! - **Limits and colimits**: All finite limits and colimits exist
use crate::category::{
Category, CategoryWithMono, CategoryWithProducts, CartesianClosedCategory,
Object, ObjectData, Morphism, MorphismData,
};
use crate::{CategoryError, MorphismId, ObjectId, Result};
use dashmap::DashMap;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::sync::Arc;
/// The subobject classifier Ω
///
/// In a topos, the subobject classifier has a characteristic morphism
/// true: 1 -> Ω such that for any monomorphism m: A >-> B, there exists
/// a unique χ_m: B -> Ω making the pullback square commute.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SubobjectClassifier<T: Clone + std::fmt::Debug> {
/// The classifier object Ω
pub omega: Object<T>,
/// The terminal object 1
pub terminal: Object<T>,
/// The truth morphism: true: 1 -> Ω
pub truth: MorphismId,
/// Cached characteristic morphisms
pub characteristics: HashMap<MorphismId, MorphismId>,
}
impl<T: Clone + std::fmt::Debug + PartialEq> SubobjectClassifier<T> {
/// Creates a new subobject classifier
pub fn new(omega: Object<T>, terminal: Object<T>, truth: MorphismId) -> Self {
Self {
omega,
terminal,
truth,
characteristics: HashMap::new(),
}
}
/// Registers a characteristic morphism for a monomorphism
pub fn register_characteristic(&mut self, mono: MorphismId, chi: MorphismId) {
self.characteristics.insert(mono, chi);
}
/// Gets the characteristic morphism for a monomorphism
pub fn characteristic_of(&self, mono: &MorphismId) -> Option<MorphismId> {
self.characteristics.get(mono).copied()
}
}
/// A topos is a category with special structure
///
/// Key properties:
/// 1. Has all finite limits
/// 2. Has all finite colimits
/// 3. Is cartesian closed (has exponentials)
/// 4. Has a subobject classifier
#[derive(Debug)]
pub struct Topos<C: Category> {
/// The underlying category
pub category: C,
/// The subobject classifier
subobject_classifier: Option<SubobjectClassifier<ObjectData>>,
/// Truth values in the internal logic
truth_values: Vec<MorphismId>,
/// Cached exponential objects
exponentials: Arc<DashMap<(ObjectId, ObjectId), ObjectId>>,
/// Cached pullbacks
pullbacks: Arc<DashMap<(MorphismId, MorphismId), PullbackData>>,
}
/// Data for a pullback square
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PullbackData {
/// The pullback object P
pub pullback: ObjectId,
/// First projection P -> A
pub proj1: MorphismId,
/// Second projection P -> B
pub proj2: MorphismId,
}
impl<C: Category> Topos<C> {
/// Creates a new topos from a category
///
/// Note: This does not verify that the category actually forms a topos.
/// Use `verify_topos_axioms` to check.
pub fn new(category: C) -> Self {
Self {
category,
subobject_classifier: None,
truth_values: Vec::new(),
exponentials: Arc::new(DashMap::new()),
pullbacks: Arc::new(DashMap::new()),
}
}
/// Sets the subobject classifier
pub fn with_subobject_classifier(
mut self,
classifier: SubobjectClassifier<ObjectData>,
) -> Self {
self.subobject_classifier = Some(classifier);
self
}
/// Gets the subobject classifier if it exists
pub fn subobject_classifier(&self) -> Option<&SubobjectClassifier<ObjectData>> {
self.subobject_classifier.as_ref()
}
/// Adds a truth value
pub fn add_truth_value(&mut self, morphism: MorphismId) {
self.truth_values.push(morphism);
}
/// Gets all truth values
pub fn truth_values(&self) -> &[MorphismId] {
&self.truth_values
}
/// Gets the underlying category
pub fn category(&self) -> &C {
&self.category
}
}
impl<C: Category + CategoryWithProducts> Topos<C> {
/// Computes a pullback of f: A -> C and g: B -> C
///
/// Returns the pullback object P with projections
/// such that the square commutes.
pub fn pullback(
&self,
f: &C::Morphism,
g: &C::Morphism,
) -> Option<(C::Object, C::Morphism, C::Morphism)> {
// Check that f and g have the same codomain
if self.category.codomain(f) != self.category.codomain(g) {
return None;
}
// For a concrete implementation, we would compute the actual pullback
// This is a simplified version using products as an approximation
let a = self.category.domain(f);
let b = self.category.domain(g);
// P is a subobject of A x B
let product = self.category.product(&a, &b)?;
let p1 = self.category.proj1(&product)?;
let p2 = self.category.proj2(&product)?;
Some((product, p1, p2))
}
/// Computes the equalizer of f, g: A -> B
///
/// The equalizer E is the largest subobject of A where f = g
pub fn equalizer(
&self,
f: &C::Morphism,
g: &C::Morphism,
) -> Option<(C::Object, C::Morphism)> {
// f and g must have the same domain and codomain
if self.category.domain(f) != self.category.domain(g) {
return None;
}
if self.category.codomain(f) != self.category.codomain(g) {
return None;
}
// Simplified: return domain with identity if f = g
// A real implementation would compute the actual equalizer
let a = self.category.domain(f);
let id = self.category.identity(&a)?;
Some((a, id))
}
}
impl<C: Category + CategoryWithProducts + CategoryWithMono> Topos<C> {
/// Verifies that this is a valid topos
///
/// Checks:
/// 1. Finite limits exist (simplified: products and equalizers)
/// 2. Has subobject classifier
/// 3. Is cartesian closed (simplified check)
pub fn verify_topos_axioms(&self) -> ToposVerification {
let mut verification = ToposVerification::new();
// Check subobject classifier
if self.subobject_classifier.is_some() {
verification.has_subobject_classifier = true;
}
// Check products (simplified)
let objects = self.category.objects();
if objects.len() >= 2 {
let a = &objects[0];
let b = &objects[1];
verification.has_finite_products = self.category.product(a, b).is_some();
}
// Check for terminal object (simplified)
verification.has_terminal = !objects.is_empty();
verification
}
}
/// Result of topos axiom verification
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToposVerification {
pub has_subobject_classifier: bool,
pub has_finite_products: bool,
pub has_finite_coproducts: bool,
pub has_equalizers: bool,
pub has_coequalizers: bool,
pub has_terminal: bool,
pub has_initial: bool,
pub is_cartesian_closed: bool,
}
impl ToposVerification {
pub fn new() -> Self {
Self {
has_subobject_classifier: false,
has_finite_products: false,
has_finite_coproducts: false,
has_equalizers: false,
has_coequalizers: false,
has_terminal: false,
has_initial: false,
is_cartesian_closed: false,
}
}
pub fn is_topos(&self) -> bool {
self.has_subobject_classifier
&& self.has_finite_products
&& self.has_terminal
&& self.is_cartesian_closed
}
}
impl Default for ToposVerification {
fn default() -> Self {
Self::new()
}
}
/// Internal logic operations in a topos
///
/// The subobject classifier Ω supports logical operations
/// that form an internal Heyting algebra.
#[derive(Debug)]
pub struct InternalLogic {
/// Conjunction: ∧: Ω x Ω -> Ω
pub conjunction: Option<MorphismId>,
/// Disjunction: : Ω x Ω -> Ω
pub disjunction: Option<MorphismId>,
/// Implication: →: Ω x Ω -> Ω
pub implication: Option<MorphismId>,
/// Negation: ¬: Ω -> Ω
pub negation: Option<MorphismId>,
/// Universal quantifier for each object
pub universal: HashMap<ObjectId, MorphismId>,
/// Existential quantifier for each object
pub existential: HashMap<ObjectId, MorphismId>,
}
impl InternalLogic {
pub fn new() -> Self {
Self {
conjunction: None,
disjunction: None,
implication: None,
negation: None,
universal: HashMap::new(),
existential: HashMap::new(),
}
}
/// Checks if the logic is complete (all operations defined)
pub fn is_complete(&self) -> bool {
self.conjunction.is_some()
&& self.disjunction.is_some()
&& self.implication.is_some()
&& self.negation.is_some()
}
/// Checks if the logic is classical (excluded middle holds)
/// In general, topos logic is intuitionistic
pub fn is_classical(&self) -> bool {
// Would need to verify ¬¬p = p for all p
// By default, topos logic is intuitionistic
false
}
}
impl Default for InternalLogic {
fn default() -> Self {
Self::new()
}
}
/// A subobject in a topos
///
/// Subobjects are equivalence classes of monomorphisms into an object
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Subobject {
/// The source object of the monomorphism
pub source: ObjectId,
/// The target object (what we're a subobject of)
pub target: ObjectId,
/// The monomorphism
pub mono: MorphismId,
/// The characteristic morphism χ: target -> Ω
pub characteristic: Option<MorphismId>,
}
impl Subobject {
pub fn new(source: ObjectId, target: ObjectId, mono: MorphismId) -> Self {
Self {
source,
target,
mono,
characteristic: None,
}
}
pub fn with_characteristic(mut self, chi: MorphismId) -> Self {
self.characteristic = Some(chi);
self
}
}
/// Lattice of subobjects for an object in a topos
///
/// In a topos, the subobjects of any object form a Heyting algebra
#[derive(Debug)]
pub struct SubobjectLattice {
/// The object whose subobjects we're tracking
pub object: ObjectId,
/// All subobjects (ordered by inclusion)
pub subobjects: Vec<Subobject>,
/// Meet (intersection) results
meets: HashMap<(usize, usize), usize>,
/// Join (union) results
joins: HashMap<(usize, usize), usize>,
}
impl SubobjectLattice {
pub fn new(object: ObjectId) -> Self {
Self {
object,
subobjects: Vec::new(),
meets: HashMap::new(),
joins: HashMap::new(),
}
}
/// Adds a subobject to the lattice
pub fn add(&mut self, subobject: Subobject) -> usize {
let index = self.subobjects.len();
self.subobjects.push(subobject);
index
}
/// Computes the meet (intersection) of two subobjects
pub fn meet(&self, a: usize, b: usize) -> Option<usize> {
self.meets.get(&(a.min(b), a.max(b))).copied()
}
/// Computes the join (union) of two subobjects
pub fn join(&self, a: usize, b: usize) -> Option<usize> {
self.joins.get(&(a.min(b), a.max(b))).copied()
}
/// Records a meet computation
pub fn record_meet(&mut self, a: usize, b: usize, result: usize) {
self.meets.insert((a.min(b), a.max(b)), result);
}
/// Records a join computation
pub fn record_join(&mut self, a: usize, b: usize, result: usize) {
self.joins.insert((a.min(b), a.max(b)), result);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::category::SetCategory;
#[test]
fn test_topos_creation() {
let cat = SetCategory::new();
let topos = Topos::new(cat);
assert!(topos.subobject_classifier().is_none());
}
#[test]
fn test_subobject_classifier() {
let omega = Object::new(ObjectData::FiniteSet(2)); // {false, true}
let terminal = Object::new(ObjectData::Terminal);
let truth = MorphismId::new();
let classifier = SubobjectClassifier::new(omega, terminal, truth);
assert_eq!(classifier.omega.data, ObjectData::FiniteSet(2));
}
#[test]
fn test_internal_logic() {
let logic = InternalLogic::new();
assert!(!logic.is_complete());
assert!(!logic.is_classical());
}
#[test]
fn test_subobject() {
let source = ObjectId::new();
let target = ObjectId::new();
let mono = MorphismId::new();
let sub = Subobject::new(source, target, mono);
assert_eq!(sub.source, source);
assert!(sub.characteristic.is_none());
}
#[test]
fn test_topos_verification() {
let verification = ToposVerification::new();
assert!(!verification.is_topos());
}
}