UNPKG

ts-quantum

Version:

TypeScript library for quantum mechanics calculations and utilities

254 lines 9.8 kB
"use strict"; /** * Wigner symbols implementation * Includes 3j, 6j, and 9j symbols for angular momentum coupling */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.wigner9j = exports.wigner6j = exports.wigner3jSymmetry = exports.wigner3j = exports.isValidTriangle = void 0; const composition_1 = require("./composition"); const math_1 = require("../utils/math"); const math = __importStar(require("mathjs")); /** * Validates triangle inequality for three angular momenta * * @param j1 First angular momentum * @param j2 Second angular momentum * @param j3 Third angular momentum * @returns true if triangle inequality is satisfied */ function isValidTriangle(j1, j2, j3) { return (Math.abs(j1 - j2) <= j3 && j3 <= j1 + j2 && Math.abs(j2 - j3) <= j1 && j1 <= j2 + j3 && Math.abs(j3 - j1) <= j2 && j2 <= j3 + j1); } exports.isValidTriangle = isValidTriangle; /** * Validates all four triangle conditions for Wigner 6j symbols * * @param j1 Angular momentum j1 * @param j2 Angular momentum j2 * @param j3 Angular momentum j3 * @param l1 Angular momentum l1 * @param l2 Angular momentum l2 * @param l3 Angular momentum l3 * @returns true if all triangle conditions are satisfied */ function validate6jTriangles(j1, j2, j3, l1, l2, l3) { return (isValidTriangle(j1, j2, j3) && isValidTriangle(j1, l2, l3) && isValidTriangle(l1, j2, l3) && isValidTriangle(l1, l2, j3)); } /** * Calculates phase factor (-1)^n * * @param n Power for phase factor * @returns 1 or -1 */ function phaseFactor(n) { return Math.pow(-1, Math.round(n)); } /** * Validates Wigner 3j symbol quantum numbers * * @param j1 First angular momentum * @param j2 Second angular momentum * @param j3 Third angular momentum * @param m1 First magnetic quantum number * @param m2 Second magnetic quantum number * @param m3 Third magnetic quantum number * @returns true if all quantum numbers are valid */ function validateWigner3j(j1, j2, j3, m1, m2, m3) { // Check that j values are non-negative if (j1 < 0 || j2 < 0 || j3 < 0) { return false; } // Check that m values are within bounds if (Math.abs(m1) > j1 || Math.abs(m2) > j2 || Math.abs(m3) > j3) { return false; } // Check triangle inequality if (!isValidTriangle(j1, j2, j3)) { return false; } // Check magnetic quantum number conservation if (Math.abs(m1 + m2 + m3) > 1e-10) { return false; } return true; } /** * Calculates Wigner 3j symbol using Clebsch-Gordan coefficients * * The Wigner 3j symbol is related to Clebsch-Gordan coefficients by: * (j1 j2 j3) = (-1)^(j1-j2-m3) / sqrt(2*j3+1) * ⟨j1,m1;j2,m2|j3,-m3⟩ * (m1 m2 m3) * * Based on verified formula from Sage/SymPy documentation: * ⟨j₁ m₁ j₂ m₂ | j₃ m₃⟩ = (-1)^(j₁-j₂+m₃) * √(2j₃+1) * Wigner3j(j₁, j₂, j₃, m₁, m₂, -m₃) * * @param j1 First angular momentum * @param j2 Second angular momentum * @param j3 Third angular momentum * @param m1 First magnetic quantum number * @param m2 Second magnetic quantum number * @param m3 Third magnetic quantum number * @returns Wigner 3j symbol value */ function wigner3j(j1, j2, j3, m1, m2, m3) { // Validate quantum numbers if (!validateWigner3j(j1, j2, j3, m1, m2, m3)) { return math.complex(0, 0); } // Get Clebsch-Gordan coefficient ⟨j1,m1;j2,m2|j3,-m3⟩ // NOTE: Critical fix - using -m3 as the last argument const cgCoeff = (0, composition_1.clebschGordan)(j1, m1, j2, m2, j3, -m3); // Phase factor: (-1)^(j1-j2+m3) const phase = phaseFactor(j1 - j2 + m3); // Normalization factor: 1/sqrt(2*j3+1) const normalization = 1 / Math.sqrt(2 * j3 + 1); // Combine all factors: phase * normalization * CG coefficient const result = math.multiply(phase * normalization, cgCoeff); return result; } exports.wigner3j = wigner3j; /** * Applies symmetry operation to Wigner 3j symbol * There are 12 symmetry operations for 3j symbols * * @param j1 First angular momentum * @param j2 Second angular momentum * @param j3 Third angular momentum * @param m1 First magnetic quantum number * @param m2 Second magnetic quantum number * @param m3 Third magnetic quantum number * @param operation Symmetry operation index (0-11) * @returns Transformed 3j symbol with phase factor */ function wigner3jSymmetry(j1, j2, j3, m1, m2, m3, operation) { const base = wigner3j(j1, j2, j3, m1, m2, m3); switch (operation) { case 0: // Identity return { value: base, phase: 1 }; case 1: // Cyclic permutation (j1,j2,j3) → (j2,j3,j1) return { value: wigner3j(j2, j3, j1, m2, m3, m1), phase: phaseFactor(j1 + j2 + j3) }; case 2: // Cyclic permutation (j1,j2,j3) → (j3,j1,j2) return { value: wigner3j(j3, j1, j2, m3, m1, m2), phase: phaseFactor(j1 + j2 + j3) }; case 3: // Exchange first two: (j1,j2,j3) → (j2,j1,j3) return { value: wigner3j(j2, j1, j3, m2, m1, m3), phase: phaseFactor(j1 + j2 + j3) }; case 4: // Sign reversal: (m1,m2,m3) → (-m1,-m2,-m3) return { value: wigner3j(j1, j2, j3, -m1, -m2, -m3), phase: phaseFactor(j1 + j2 + j3) }; default: return { value: base, phase: 1 }; } } exports.wigner3jSymmetry = wigner3jSymmetry; /** * Calculates Wigner 6j symbol using Racah's formula * * Uses the explicit sum formula: * {j1 j2 j3} = Delta(j1,j2,j3)Delta(j1,l2,l3)Delta(l1,j2,l3)Delta(l1,l2,j3) × * {l1 l2 l3} Σ_z (-1)^z [(z-j1-j2-j3)!(z-j1-l2-l3)!(z-l1-j2-l3)!(z-l1-l2-j3)! × * (j1+j2+l1+l2-z)!(j2+j3+l2+l3-z)!(j3+j1+l3+l1-z)!]^(-1) * * where Delta(a,b,c) is the triangle coefficient. * * @param j1 Angular momentum j1 * @param j2 Angular momentum j2 * @param j3 Angular momentum j3 * @param l1 Angular momentum l1 * @param l2 Angular momentum l2 * @param l3 Angular momentum l3 * @returns Wigner 6j symbol value */ function wigner6j(j1, j2, j3, l1, l2, l3) { // Validate all triangle conditions if (!validate6jTriangles(j1, j2, j3, l1, l2, l3)) { return math.complex(0, 0); } // Check for negative angular momenta if (j1 < 0 || j2 < 0 || j3 < 0 || l1 < 0 || l2 < 0 || l3 < 0) { return math.complex(0, 0); } // Calculate triangle coefficients const delta1 = (0, math_1.triangleCoefficient)(j1, j2, j3); const delta2 = (0, math_1.triangleCoefficient)(j1, l2, l3); const delta3 = (0, math_1.triangleCoefficient)(l1, j2, l3); const delta4 = (0, math_1.triangleCoefficient)(l1, l2, j3); // If any triangle coefficient is zero, the 6j symbol is zero if (delta1 === 0 || delta2 === 0 || delta3 === 0 || delta4 === 0) { return math.complex(0, 0); } // Calculate sum limits const zMin = Math.max(j1 + j2 + j3, j1 + l2 + l3, l1 + j2 + l3, l1 + l2 + j3); const zMax = Math.min(j1 + j2 + l1 + l2, j2 + j3 + l2 + l3, j3 + j1 + l3 + l1); // Calculate sum using log factorials for numerical stability let sumLog = -Infinity; for (let z = Math.round(zMin); z <= Math.round(zMax); z++) { // Calculate log of denominator terms const logDenom = ((0, math_1.logFactorial)(z - Math.round(j1 + j2 + j3)) + (0, math_1.logFactorial)(z - Math.round(j1 + l2 + l3)) + (0, math_1.logFactorial)(z - Math.round(l1 + j2 + l3)) + (0, math_1.logFactorial)(z - Math.round(l1 + l2 + j3)) + (0, math_1.logFactorial)(Math.round(j1 + j2 + l1 + l2 - z)) + (0, math_1.logFactorial)(Math.round(j2 + j3 + l2 + l3 - z)) + (0, math_1.logFactorial)(Math.round(j3 + j1 + l3 + l1 - z))); // Add term to sum (in log space) const logTerm = -logDenom; if (sumLog === -Infinity) { sumLog = logTerm; } else { // Use log sum exp trick for numerical stability const maxLog = Math.max(sumLog, logTerm); sumLog = maxLog + Math.log(Math.exp(sumLog - maxLog) + Math.exp(logTerm - maxLog)); } } // Calculate final result const phaseFactor = Math.pow(-1, Math.round(j1 + j2 + j3 + l1 + l2 + l3)); const result = phaseFactor * delta1 * delta2 * delta3 * delta4 * Math.exp(sumLog); return math.complex(result, 0); } exports.wigner6j = wigner6j; function wigner9j(j1, j2, j3, l1, l2, l3, k1, k2, k3) { // TODO: Implement in Phase 3 return math.complex(0, 0); } exports.wigner9j = wigner9j; //# sourceMappingURL=wignerSymbols.js.map