git-subtree-dir: vendor/ruvector git-subtree-split: b64c21726f2bb37286d9ee36a7869fef60cc6900
810 lines
24 KiB
Rust
810 lines
24 KiB
Rust
//! Category Theory Benchmarks for Prime-Radiant
|
|
//!
|
|
//! Benchmarks for category-theoretic operations including:
|
|
//! - Functor application
|
|
//! - Morphism composition chains
|
|
//! - Topos operations (pullback, pushforward, exponential)
|
|
//! - Natural transformation computation
|
|
//!
|
|
//! Target metrics:
|
|
//! - Functor application: < 100us per object
|
|
//! - Composition chain (100 morphisms): < 1ms
|
|
//! - Topos pullback: < 500us
|
|
|
|
use criterion::{
|
|
black_box, criterion_group, criterion_main, BenchmarkId, Criterion, Throughput,
|
|
};
|
|
use std::collections::HashMap;
|
|
|
|
// ============================================================================
|
|
// CATEGORY THEORY TYPES
|
|
// ============================================================================
|
|
|
|
/// Object identifier
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
|
struct ObjectId(u64);
|
|
|
|
/// Morphism identifier
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
|
struct MorphismId(u64);
|
|
|
|
/// A morphism in a category
|
|
#[derive(Clone, Debug)]
|
|
struct Morphism {
|
|
id: MorphismId,
|
|
source: ObjectId,
|
|
target: ObjectId,
|
|
/// Linear transformation matrix (for VectorCategory)
|
|
matrix: Option<Vec<Vec<f64>>>,
|
|
}
|
|
|
|
/// Category structure
|
|
struct Category {
|
|
objects: HashMap<ObjectId, Object>,
|
|
morphisms: HashMap<MorphismId, Morphism>,
|
|
/// Composition table: (f, g) -> f . g
|
|
compositions: HashMap<(MorphismId, MorphismId), MorphismId>,
|
|
/// Identity morphisms
|
|
identities: HashMap<ObjectId, MorphismId>,
|
|
next_id: u64,
|
|
}
|
|
|
|
/// Object with associated data
|
|
#[derive(Clone, Debug)]
|
|
struct Object {
|
|
id: ObjectId,
|
|
dimension: usize,
|
|
data: Vec<f64>,
|
|
}
|
|
|
|
impl Category {
|
|
fn new() -> Self {
|
|
Self {
|
|
objects: HashMap::new(),
|
|
morphisms: HashMap::new(),
|
|
compositions: HashMap::new(),
|
|
identities: HashMap::new(),
|
|
next_id: 0,
|
|
}
|
|
}
|
|
|
|
fn add_object(&mut self, dimension: usize) -> ObjectId {
|
|
let id = ObjectId(self.next_id);
|
|
self.next_id += 1;
|
|
|
|
let obj = Object {
|
|
id,
|
|
dimension,
|
|
data: vec![0.0; dimension],
|
|
};
|
|
self.objects.insert(id, obj);
|
|
|
|
// Add identity morphism
|
|
let mor_id = MorphismId(self.next_id);
|
|
self.next_id += 1;
|
|
|
|
let identity_matrix = (0..dimension)
|
|
.map(|i| {
|
|
let mut row = vec![0.0; dimension];
|
|
row[i] = 1.0;
|
|
row
|
|
})
|
|
.collect();
|
|
|
|
let identity = Morphism {
|
|
id: mor_id,
|
|
source: id,
|
|
target: id,
|
|
matrix: Some(identity_matrix),
|
|
};
|
|
|
|
self.morphisms.insert(mor_id, identity);
|
|
self.identities.insert(id, mor_id);
|
|
|
|
id
|
|
}
|
|
|
|
fn add_morphism(&mut self, source: ObjectId, target: ObjectId, matrix: Vec<Vec<f64>>) -> MorphismId {
|
|
let id = MorphismId(self.next_id);
|
|
self.next_id += 1;
|
|
|
|
let morphism = Morphism {
|
|
id,
|
|
source,
|
|
target,
|
|
matrix: Some(matrix),
|
|
};
|
|
|
|
self.morphisms.insert(id, morphism);
|
|
id
|
|
}
|
|
|
|
fn compose(&mut self, f: MorphismId, g: MorphismId) -> Option<MorphismId> {
|
|
// Check if already composed
|
|
if let Some(&result) = self.compositions.get(&(f, g)) {
|
|
return Some(result);
|
|
}
|
|
|
|
let mor_f = self.morphisms.get(&f)?;
|
|
let mor_g = self.morphisms.get(&g)?;
|
|
|
|
// Check composability: target(g) = source(f)
|
|
if mor_g.target != mor_f.source {
|
|
return None;
|
|
}
|
|
|
|
// Compose matrices
|
|
let mat_f = mor_f.matrix.as_ref()?;
|
|
let mat_g = mor_g.matrix.as_ref()?;
|
|
let composed_matrix = matrix_multiply(mat_f, mat_g);
|
|
|
|
let new_id = self.add_morphism(mor_g.source, mor_f.target, composed_matrix);
|
|
self.compositions.insert((f, g), new_id);
|
|
|
|
Some(new_id)
|
|
}
|
|
|
|
fn compose_chain(&mut self, morphisms: &[MorphismId]) -> Option<MorphismId> {
|
|
if morphisms.is_empty() {
|
|
return None;
|
|
}
|
|
|
|
let mut result = morphisms[0];
|
|
for &mor in morphisms.iter().skip(1) {
|
|
result = self.compose(result, mor)?;
|
|
}
|
|
|
|
Some(result)
|
|
}
|
|
}
|
|
|
|
/// Matrix multiplication
|
|
fn matrix_multiply(a: &[Vec<f64>], b: &[Vec<f64>]) -> Vec<Vec<f64>> {
|
|
let m = a.len();
|
|
let n = if b.is_empty() { 0 } else { b[0].len() };
|
|
let k = b.len();
|
|
|
|
let mut result = vec![vec![0.0; n]; m];
|
|
|
|
for i in 0..m {
|
|
for j in 0..n {
|
|
let mut sum = 0.0;
|
|
for l in 0..k {
|
|
sum += a[i][l] * b[l][j];
|
|
}
|
|
result[i][j] = sum;
|
|
}
|
|
}
|
|
|
|
result
|
|
}
|
|
|
|
// ============================================================================
|
|
// FUNCTOR IMPLEMENTATION
|
|
// ============================================================================
|
|
|
|
/// A functor between categories
|
|
struct Functor {
|
|
/// Object mapping (encoded as transformation)
|
|
object_map: Box<dyn Fn(&Object) -> Object + Send + Sync>,
|
|
/// Morphism mapping
|
|
morphism_map: Box<dyn Fn(&Morphism) -> Morphism + Send + Sync>,
|
|
}
|
|
|
|
impl Functor {
|
|
/// Embedding functor: embeds into higher dimension
|
|
fn embedding(target_dim: usize) -> Self {
|
|
Self {
|
|
object_map: Box::new(move |obj| {
|
|
let mut data = obj.data.clone();
|
|
data.resize(target_dim, 0.0);
|
|
Object {
|
|
id: obj.id,
|
|
dimension: target_dim,
|
|
data,
|
|
}
|
|
}),
|
|
morphism_map: Box::new(move |mor| {
|
|
let matrix = mor.matrix.as_ref().map(|m| {
|
|
let old_dim = m.len();
|
|
let mut new_matrix = vec![vec![0.0; target_dim]; target_dim];
|
|
|
|
// Copy old matrix into top-left corner
|
|
for i in 0..old_dim {
|
|
for j in 0..m[i].len().min(target_dim) {
|
|
new_matrix[i][j] = m[i][j];
|
|
}
|
|
}
|
|
|
|
// Extend with identity
|
|
for i in old_dim..target_dim {
|
|
new_matrix[i][i] = 1.0;
|
|
}
|
|
|
|
new_matrix
|
|
});
|
|
|
|
Morphism {
|
|
id: mor.id,
|
|
source: mor.source,
|
|
target: mor.target,
|
|
matrix,
|
|
}
|
|
}),
|
|
}
|
|
}
|
|
|
|
/// Projection functor: projects to lower dimension
|
|
fn projection(target_dim: usize) -> Self {
|
|
Self {
|
|
object_map: Box::new(move |obj| {
|
|
let data: Vec<f64> = obj.data.iter().take(target_dim).copied().collect();
|
|
Object {
|
|
id: obj.id,
|
|
dimension: target_dim,
|
|
data,
|
|
}
|
|
}),
|
|
morphism_map: Box::new(move |mor| {
|
|
let matrix = mor.matrix.as_ref().map(|m| {
|
|
m.iter()
|
|
.take(target_dim)
|
|
.map(|row| row.iter().take(target_dim).copied().collect())
|
|
.collect()
|
|
});
|
|
|
|
Morphism {
|
|
id: mor.id,
|
|
source: mor.source,
|
|
target: mor.target,
|
|
matrix,
|
|
}
|
|
}),
|
|
}
|
|
}
|
|
|
|
fn apply_object(&self, obj: &Object) -> Object {
|
|
(self.object_map)(obj)
|
|
}
|
|
|
|
fn apply_morphism(&self, mor: &Morphism) -> Morphism {
|
|
(self.morphism_map)(mor)
|
|
}
|
|
}
|
|
|
|
// ============================================================================
|
|
// TOPOS OPERATIONS
|
|
// ============================================================================
|
|
|
|
/// Topos structure with subobject classifier
|
|
struct Topos {
|
|
base_category: Category,
|
|
/// Subobject classifier: true/false
|
|
omega: ObjectId,
|
|
/// Terminal object
|
|
terminal: ObjectId,
|
|
}
|
|
|
|
impl Topos {
|
|
fn new() -> Self {
|
|
let mut cat = Category::new();
|
|
|
|
// Add terminal object (1-dimensional)
|
|
let terminal = cat.add_object(1);
|
|
|
|
// Add subobject classifier (2-dimensional for true/false)
|
|
let omega = cat.add_object(2);
|
|
|
|
Self {
|
|
base_category: cat,
|
|
omega,
|
|
terminal,
|
|
}
|
|
}
|
|
|
|
/// Compute pullback of f: A -> C and g: B -> C
|
|
fn pullback(&mut self, f: MorphismId, g: MorphismId) -> Option<(ObjectId, MorphismId, MorphismId)> {
|
|
let mor_f = self.base_category.morphisms.get(&f)?;
|
|
let mor_g = self.base_category.morphisms.get(&g)?;
|
|
|
|
// Check that codomain matches
|
|
if mor_f.target != mor_g.target {
|
|
return None;
|
|
}
|
|
|
|
let obj_a = self.base_category.objects.get(&mor_f.source)?;
|
|
let obj_b = self.base_category.objects.get(&mor_g.source)?;
|
|
|
|
// Pullback object dimension is sum of source dimensions
|
|
let pullback_dim = obj_a.dimension + obj_b.dimension;
|
|
let pullback_obj = self.base_category.add_object(pullback_dim);
|
|
|
|
// Create projection morphisms
|
|
// p1: A x_C B -> A (projection to first factor)
|
|
let p1_matrix: Vec<Vec<f64>> = (0..obj_a.dimension)
|
|
.map(|i| {
|
|
let mut row = vec![0.0; pullback_dim];
|
|
row[i] = 1.0;
|
|
row
|
|
})
|
|
.collect();
|
|
|
|
// p2: A x_C B -> B (projection to second factor)
|
|
let p2_matrix: Vec<Vec<f64>> = (0..obj_b.dimension)
|
|
.map(|i| {
|
|
let mut row = vec![0.0; pullback_dim];
|
|
row[obj_a.dimension + i] = 1.0;
|
|
row
|
|
})
|
|
.collect();
|
|
|
|
let p1 = self.base_category.add_morphism(pullback_obj, mor_f.source, p1_matrix);
|
|
let p2 = self.base_category.add_morphism(pullback_obj, mor_g.source, p2_matrix);
|
|
|
|
Some((pullback_obj, p1, p2))
|
|
}
|
|
|
|
/// Compute exponential object B^A
|
|
fn exponential(&mut self, a: ObjectId, b: ObjectId) -> Option<ObjectId> {
|
|
let obj_a = self.base_category.objects.get(&a)?;
|
|
let obj_b = self.base_category.objects.get(&b)?;
|
|
|
|
// Exponential dimension is dim(B)^dim(A) (approximated as product)
|
|
let exp_dim = obj_a.dimension * obj_b.dimension;
|
|
let exp_obj = self.base_category.add_object(exp_dim);
|
|
|
|
Some(exp_obj)
|
|
}
|
|
|
|
/// Compute pushout of f: C -> A and g: C -> B
|
|
fn pushout(&mut self, f: MorphismId, g: MorphismId) -> Option<(ObjectId, MorphismId, MorphismId)> {
|
|
let mor_f = self.base_category.morphisms.get(&f)?;
|
|
let mor_g = self.base_category.morphisms.get(&g)?;
|
|
|
|
// Check that domain matches
|
|
if mor_f.source != mor_g.source {
|
|
return None;
|
|
}
|
|
|
|
let obj_a = self.base_category.objects.get(&mor_f.target)?;
|
|
let obj_b = self.base_category.objects.get(&mor_g.target)?;
|
|
|
|
// Pushout dimension
|
|
let pushout_dim = obj_a.dimension + obj_b.dimension;
|
|
let pushout_obj = self.base_category.add_object(pushout_dim);
|
|
|
|
// Create injection morphisms
|
|
let i1_matrix: Vec<Vec<f64>> = (0..pushout_dim)
|
|
.map(|i| {
|
|
if i < obj_a.dimension {
|
|
let mut row = vec![0.0; obj_a.dimension];
|
|
row[i] = 1.0;
|
|
row
|
|
} else {
|
|
vec![0.0; obj_a.dimension]
|
|
}
|
|
})
|
|
.collect();
|
|
|
|
let i2_matrix: Vec<Vec<f64>> = (0..pushout_dim)
|
|
.map(|i| {
|
|
if i >= obj_a.dimension {
|
|
let mut row = vec![0.0; obj_b.dimension];
|
|
row[i - obj_a.dimension] = 1.0;
|
|
row
|
|
} else {
|
|
vec![0.0; obj_b.dimension]
|
|
}
|
|
})
|
|
.collect();
|
|
|
|
let i1 = self.base_category.add_morphism(mor_f.target, pushout_obj, i1_matrix);
|
|
let i2 = self.base_category.add_morphism(mor_g.target, pushout_obj, i2_matrix);
|
|
|
|
Some((pushout_obj, i1, i2))
|
|
}
|
|
}
|
|
|
|
// ============================================================================
|
|
// NATURAL TRANSFORMATION
|
|
// ============================================================================
|
|
|
|
/// Natural transformation between functors
|
|
struct NaturalTransformation {
|
|
/// Component morphisms for each object
|
|
components: HashMap<ObjectId, Vec<Vec<f64>>>,
|
|
}
|
|
|
|
impl NaturalTransformation {
|
|
fn new() -> Self {
|
|
Self {
|
|
components: HashMap::new(),
|
|
}
|
|
}
|
|
|
|
fn add_component(&mut self, obj: ObjectId, matrix: Vec<Vec<f64>>) {
|
|
self.components.insert(obj, matrix);
|
|
}
|
|
|
|
fn apply_at(&self, obj: ObjectId, data: &[f64]) -> Option<Vec<f64>> {
|
|
let matrix = self.components.get(&obj)?;
|
|
Some(matvec(matrix, data))
|
|
}
|
|
|
|
/// Check naturality square for a morphism f: A -> B
|
|
fn check_naturality(&self, f: &Morphism, f_prime: &Morphism) -> bool {
|
|
// Check: F(f) . eta_A = eta_B . G(f)
|
|
let eta_a = match self.components.get(&f.source) {
|
|
Some(m) => m,
|
|
None => return false,
|
|
};
|
|
let eta_b = match self.components.get(&f.target) {
|
|
Some(m) => m,
|
|
None => return false,
|
|
};
|
|
|
|
let mat_f = match &f.matrix {
|
|
Some(m) => m,
|
|
None => return false,
|
|
};
|
|
let mat_f_prime = match &f_prime.matrix {
|
|
Some(m) => m,
|
|
None => return false,
|
|
};
|
|
|
|
// Left side: F(f) . eta_A
|
|
let left = matrix_multiply(mat_f_prime, eta_a);
|
|
|
|
// Right side: eta_B . G(f)
|
|
let right = matrix_multiply(eta_b, mat_f);
|
|
|
|
// Check equality (within tolerance)
|
|
matrices_equal(&left, &right, 1e-10)
|
|
}
|
|
}
|
|
|
|
fn matvec(matrix: &[Vec<f64>], vec: &[f64]) -> Vec<f64> {
|
|
matrix
|
|
.iter()
|
|
.map(|row| row.iter().zip(vec.iter()).map(|(a, b)| a * b).sum())
|
|
.collect()
|
|
}
|
|
|
|
fn matrices_equal(a: &[Vec<f64>], b: &[Vec<f64>], tol: f64) -> bool {
|
|
if a.len() != b.len() {
|
|
return false;
|
|
}
|
|
|
|
for (row_a, row_b) in a.iter().zip(b.iter()) {
|
|
if row_a.len() != row_b.len() {
|
|
return false;
|
|
}
|
|
for (va, vb) in row_a.iter().zip(row_b.iter()) {
|
|
if (va - vb).abs() > tol {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
true
|
|
}
|
|
|
|
// ============================================================================
|
|
// BENCHMARK DATA GENERATORS
|
|
// ============================================================================
|
|
|
|
fn generate_random_matrix(rows: usize, cols: usize, seed: u64) -> Vec<Vec<f64>> {
|
|
let mut rng_state = seed;
|
|
|
|
(0..rows)
|
|
.map(|_| {
|
|
(0..cols)
|
|
.map(|_| {
|
|
rng_state = rng_state.wrapping_mul(6364136223846793005).wrapping_add(1);
|
|
((rng_state >> 33) as f64 / (u32::MAX as f64)) * 2.0 - 1.0
|
|
})
|
|
.collect()
|
|
})
|
|
.collect()
|
|
}
|
|
|
|
fn setup_category_with_chain(dimension: usize, chain_length: usize) -> (Category, Vec<MorphismId>) {
|
|
let mut cat = Category::new();
|
|
let mut objects = Vec::new();
|
|
let mut morphisms = Vec::new();
|
|
|
|
// Create chain of objects
|
|
for _ in 0..=chain_length {
|
|
objects.push(cat.add_object(dimension));
|
|
}
|
|
|
|
// Create chain of morphisms
|
|
for i in 0..chain_length {
|
|
let matrix = generate_random_matrix(dimension, dimension, (i as u64) * 42 + 1);
|
|
let mor = cat.add_morphism(objects[i], objects[i + 1], matrix);
|
|
morphisms.push(mor);
|
|
}
|
|
|
|
(cat, morphisms)
|
|
}
|
|
|
|
// ============================================================================
|
|
// BENCHMARKS
|
|
// ============================================================================
|
|
|
|
fn bench_functor_application(c: &mut Criterion) {
|
|
let mut group = c.benchmark_group("category/functor");
|
|
group.sample_size(100);
|
|
|
|
for &dim in &[16, 64, 128, 256] {
|
|
let target_dim = dim * 2;
|
|
let embedding = Functor::embedding(target_dim);
|
|
let projection = Functor::projection(dim / 2);
|
|
|
|
let obj = Object {
|
|
id: ObjectId(0),
|
|
dimension: dim,
|
|
data: (0..dim).map(|i| (i as f64).sin()).collect(),
|
|
};
|
|
|
|
let mor = Morphism {
|
|
id: MorphismId(0),
|
|
source: ObjectId(0),
|
|
target: ObjectId(1),
|
|
matrix: Some(generate_random_matrix(dim, dim, 42)),
|
|
};
|
|
|
|
group.throughput(Throughput::Elements(dim as u64));
|
|
|
|
group.bench_with_input(
|
|
BenchmarkId::new("embedding_object", dim),
|
|
&(&embedding, &obj),
|
|
|b, (functor, obj)| {
|
|
b.iter(|| black_box(functor.apply_object(black_box(obj))))
|
|
},
|
|
);
|
|
|
|
group.bench_with_input(
|
|
BenchmarkId::new("embedding_morphism", dim),
|
|
&(&embedding, &mor),
|
|
|b, (functor, mor)| {
|
|
b.iter(|| black_box(functor.apply_morphism(black_box(mor))))
|
|
},
|
|
);
|
|
|
|
group.bench_with_input(
|
|
BenchmarkId::new("projection_object", dim),
|
|
&(&projection, &obj),
|
|
|b, (functor, obj)| {
|
|
b.iter(|| black_box(functor.apply_object(black_box(obj))))
|
|
},
|
|
);
|
|
}
|
|
|
|
group.finish();
|
|
}
|
|
|
|
fn bench_composition_chains(c: &mut Criterion) {
|
|
let mut group = c.benchmark_group("category/composition");
|
|
group.sample_size(50);
|
|
|
|
for &chain_length in &[10, 50, 100, 200] {
|
|
let dim = 32;
|
|
let (mut cat, morphisms) = setup_category_with_chain(dim, chain_length);
|
|
|
|
group.throughput(Throughput::Elements(chain_length as u64));
|
|
|
|
group.bench_with_input(
|
|
BenchmarkId::new("sequential", chain_length),
|
|
&morphisms,
|
|
|b, morphisms| {
|
|
b.iter_batched(
|
|
|| {
|
|
let (cat, _) = setup_category_with_chain(dim, chain_length);
|
|
cat
|
|
},
|
|
|mut cat| {
|
|
let mut result = morphisms[0];
|
|
for &mor in morphisms.iter().skip(1) {
|
|
result = cat.compose(result, mor).unwrap();
|
|
}
|
|
black_box(result)
|
|
},
|
|
criterion::BatchSize::SmallInput,
|
|
)
|
|
},
|
|
);
|
|
|
|
group.bench_with_input(
|
|
BenchmarkId::new("chain_compose", chain_length),
|
|
&morphisms,
|
|
|b, morphisms| {
|
|
b.iter_batched(
|
|
|| {
|
|
let (cat, _) = setup_category_with_chain(dim, chain_length);
|
|
cat
|
|
},
|
|
|mut cat| black_box(cat.compose_chain(morphisms)),
|
|
criterion::BatchSize::SmallInput,
|
|
)
|
|
},
|
|
);
|
|
}
|
|
|
|
group.finish();
|
|
}
|
|
|
|
fn bench_topos_operations(c: &mut Criterion) {
|
|
let mut group = c.benchmark_group("category/topos");
|
|
group.sample_size(50);
|
|
|
|
for &dim in &[8, 16, 32, 64] {
|
|
group.throughput(Throughput::Elements(dim as u64));
|
|
|
|
// Setup for pullback
|
|
group.bench_with_input(
|
|
BenchmarkId::new("pullback", dim),
|
|
&dim,
|
|
|b, &dim| {
|
|
b.iter_batched(
|
|
|| {
|
|
let mut topos = Topos::new();
|
|
let a = topos.base_category.add_object(dim);
|
|
let b = topos.base_category.add_object(dim);
|
|
let c = topos.base_category.add_object(dim);
|
|
|
|
let mat_f = generate_random_matrix(dim, dim, 42);
|
|
let mat_g = generate_random_matrix(dim, dim, 43);
|
|
|
|
let f = topos.base_category.add_morphism(a, c, mat_f);
|
|
let g = topos.base_category.add_morphism(b, c, mat_g);
|
|
|
|
(topos, f, g)
|
|
},
|
|
|(mut topos, f, g)| black_box(topos.pullback(f, g)),
|
|
criterion::BatchSize::SmallInput,
|
|
)
|
|
},
|
|
);
|
|
|
|
// Pushout
|
|
group.bench_with_input(
|
|
BenchmarkId::new("pushout", dim),
|
|
&dim,
|
|
|b, &dim| {
|
|
b.iter_batched(
|
|
|| {
|
|
let mut topos = Topos::new();
|
|
let c = topos.base_category.add_object(dim);
|
|
let a = topos.base_category.add_object(dim);
|
|
let b = topos.base_category.add_object(dim);
|
|
|
|
let mat_f = generate_random_matrix(dim, dim, 44);
|
|
let mat_g = generate_random_matrix(dim, dim, 45);
|
|
|
|
let f = topos.base_category.add_morphism(c, a, mat_f);
|
|
let g = topos.base_category.add_morphism(c, b, mat_g);
|
|
|
|
(topos, f, g)
|
|
},
|
|
|(mut topos, f, g)| black_box(topos.pushout(f, g)),
|
|
criterion::BatchSize::SmallInput,
|
|
)
|
|
},
|
|
);
|
|
|
|
// Exponential
|
|
group.bench_with_input(
|
|
BenchmarkId::new("exponential", dim),
|
|
&dim,
|
|
|b, &dim| {
|
|
b.iter_batched(
|
|
|| {
|
|
let mut topos = Topos::new();
|
|
let a = topos.base_category.add_object(dim);
|
|
let b = topos.base_category.add_object(dim);
|
|
(topos, a, b)
|
|
},
|
|
|(mut topos, a, b)| black_box(topos.exponential(a, b)),
|
|
criterion::BatchSize::SmallInput,
|
|
)
|
|
},
|
|
);
|
|
}
|
|
|
|
group.finish();
|
|
}
|
|
|
|
fn bench_natural_transformation(c: &mut Criterion) {
|
|
let mut group = c.benchmark_group("category/natural_transformation");
|
|
group.sample_size(50);
|
|
|
|
for &dim in &[16, 32, 64, 128] {
|
|
let mut nat_trans = NaturalTransformation::new();
|
|
|
|
// Add components for multiple objects
|
|
for i in 0..10 {
|
|
let matrix = generate_random_matrix(dim, dim, i * 42);
|
|
nat_trans.add_component(ObjectId(i), matrix);
|
|
}
|
|
|
|
let data: Vec<f64> = (0..dim).map(|i| (i as f64).sin()).collect();
|
|
|
|
group.throughput(Throughput::Elements(dim as u64));
|
|
|
|
group.bench_with_input(
|
|
BenchmarkId::new("apply_component", dim),
|
|
&(&nat_trans, ObjectId(0), &data),
|
|
|b, (nat_trans, obj, data)| {
|
|
b.iter(|| black_box(nat_trans.apply_at(*obj, black_box(data))))
|
|
},
|
|
);
|
|
|
|
// Setup naturality check
|
|
let f = Morphism {
|
|
id: MorphismId(0),
|
|
source: ObjectId(0),
|
|
target: ObjectId(1),
|
|
matrix: Some(generate_random_matrix(dim, dim, 100)),
|
|
};
|
|
|
|
let f_prime = Morphism {
|
|
id: MorphismId(1),
|
|
source: ObjectId(0),
|
|
target: ObjectId(1),
|
|
matrix: Some(generate_random_matrix(dim, dim, 101)),
|
|
};
|
|
|
|
group.bench_with_input(
|
|
BenchmarkId::new("check_naturality", dim),
|
|
&(&nat_trans, &f, &f_prime),
|
|
|b, (nat_trans, f, f_prime)| {
|
|
b.iter(|| black_box(nat_trans.check_naturality(black_box(f), black_box(f_prime))))
|
|
},
|
|
);
|
|
}
|
|
|
|
group.finish();
|
|
}
|
|
|
|
fn bench_matrix_operations(c: &mut Criterion) {
|
|
let mut group = c.benchmark_group("category/matrix");
|
|
group.sample_size(50);
|
|
|
|
for &dim in &[32, 64, 128, 256] {
|
|
let a = generate_random_matrix(dim, dim, 42);
|
|
let b = generate_random_matrix(dim, dim, 43);
|
|
let v: Vec<f64> = (0..dim).map(|i| (i as f64).sin()).collect();
|
|
|
|
group.throughput(Throughput::Elements((dim * dim) as u64));
|
|
|
|
group.bench_with_input(
|
|
BenchmarkId::new("multiply", dim),
|
|
&(&a, &b),
|
|
|b, (a, b_mat)| {
|
|
b.iter(|| black_box(matrix_multiply(black_box(a), black_box(b_mat))))
|
|
},
|
|
);
|
|
|
|
group.bench_with_input(
|
|
BenchmarkId::new("matvec", dim),
|
|
&(&a, &v),
|
|
|b, (a, v)| {
|
|
b.iter(|| black_box(matvec(black_box(a), black_box(v))))
|
|
},
|
|
);
|
|
}
|
|
|
|
group.finish();
|
|
}
|
|
|
|
criterion_group!(
|
|
benches,
|
|
bench_functor_application,
|
|
bench_composition_chains,
|
|
bench_topos_operations,
|
|
bench_natural_transformation,
|
|
bench_matrix_operations,
|
|
);
|
|
criterion_main!(benches);
|