UNPKG

meta-log-db

Version:

Native database package for Meta-Log (ProLog, DataLog, R5RS)

177 lines 5.55 kB
"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