meta-log-db
Version:
Native database package for Meta-Log (ProLog, DataLog, R5RS)
177 lines • 5.55 kB
JavaScript
"use strict";
/**
* Homology Validator
*
* Validates chain complexes using algebraic topology principles.
* Ensures ∂² = 0 property holds for all boundary operators.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.HomologyValidator = void 0;
/**
* Homology Validator
*
* Validates chain complexes and computes homology groups
*/
class HomologyValidator {
constructor(complex) {
this.complex = complex;
}
/**
* Validate that ∂_{n-1} ∘ ∂_n = 0 for all dimensions
*
* @param n - Dimension to validate (1, 2, 3, or 4)
* @returns true if ∂² = 0 holds, false otherwise
*/
validateComposition(n) {
const cells = this.getCells(n);
for (const cell of cells) {
// Compute boundary_n(cell)
const boundary_n = this.complex.boundary.get(cell.id) || [];
// For each boundary cell, compute boundary_{n-1}
for (const bId of boundary_n) {
const boundary_n_minus_1 = this.complex.boundary.get(bId) || [];
// Check if boundary forms a closed cycle (sums to zero)
if (!this.isCycle(boundary_n_minus_1)) {
return false;
}
}
}
return true;
}
/**
* Compute Betti number for dimension n
*
* Betti number β_n = dim(ker(∂_n)) - dim(im(∂_{n+1}))
*
* @param n - Dimension (0-4)
* @returns Betti number β_n
*/
computeBetti(n) {
if (n < 0 || n > 4) {
throw new Error(`Invalid dimension: ${n}. Must be 0-4`);
}
const cycles = this.computeKernel(n);
const boundaries = this.computeImage(n + 1);
// Betti number = dimension of cycles - dimension of boundaries
return cycles.length - boundaries.length;
}
/**
* Compute Euler characteristic
*
* χ = Σ(-1)ⁿ|Cₙ| = |C₀| - |C₁| + |C₂| - |C₃| + |C₄|
*
* @returns Euler characteristic
*/
computeEulerCharacteristic() {
return this.complex.C0.length
- this.complex.C1.length
+ this.complex.C2.length
- this.complex.C3.length
+ this.complex.C4.length;
}
/**
* Full validation of chain complex
*
* @returns HomologyResult with validation status, Betti numbers, and violations
*/
validate() {
const violations = [];
const betti = [];
// Validate all compositions
for (let n = 1; n <= 4; n++) {
if (!this.validateComposition(n)) {
const cells = this.getCells(n);
violations.push(...cells.map(c => c.id));
}
}
// Compute Betti numbers for all dimensions
for (let n = 0; n <= 4; n++) {
betti.push(this.computeBetti(n));
}
return {
valid: violations.length === 0,
betti,
eulerCharacteristic: this.computeEulerCharacteristic(),
violations: violations.length > 0 ? violations : undefined
};
}
/**
* Get cells for dimension n
*/
getCells(n) {
switch (n) {
case 0: return this.complex.C0;
case 1: return this.complex.C1;
case 2: return this.complex.C2;
case 3: return this.complex.C3;
case 4: return this.complex.C4;
default: return [];
}
}
/**
* Check if boundary forms a closed cycle
*
* For edges: each vertex should appear exactly twice (or zero times for isolated)
* For faces: each edge should appear exactly twice with opposite orientations
*
* @param boundary - Array of boundary cell IDs
* @returns true if boundary forms a closed cycle
*/
isCycle(boundary) {
if (boundary.length === 0)
return true;
// Count occurrences of each cell ID
const counts = new Map();
for (const id of boundary) {
counts.set(id, (counts.get(id) || 0) + 1);
}
// For a closed cycle, each cell should appear an even number of times
// (representing opposite orientations canceling out)
for (const [_, count] of counts) {
if (count % 2 !== 0) {
return false; // Not closed
}
}
return true;
}
/**
* Compute kernel of boundary operator ∂_n
*
* Kernel = {cells where ∂_n(cell) = 0}
*
* @param n - Dimension
* @returns Array of cell IDs in the kernel
*/
computeKernel(n) {
const cells = this.getCells(n);
return cells
.filter(c => {
const boundary = this.complex.boundary.get(c.id) || [];
return boundary.length === 0;
})
.map(c => c.id);
}
/**
* Compute image of boundary operator ∂_n
*
* Image = {cells that are boundaries of (n+1)-cells}
*
* @param n - Dimension
* @returns Array of cell IDs in the image
*/
computeImage(n) {
if (n > 4)
return [];
const cells = this.getCells(n);
const image = new Set();
for (const cell of cells) {
const boundary = this.complex.boundary.get(cell.id) || [];
for (const id of boundary) {
image.add(id);
}
}
return Array.from(image);
}
}
exports.HomologyValidator = HomologyValidator;
//# sourceMappingURL=validator.js.map