ts-quantum
Version:
TypeScript library for quantum mechanics calculations and utilities
185 lines • 5.94 kB
JavaScript
/**
* Math utilities for quantum operations
*/
import * as math from 'mathjs';
// Cache for factorial computations
const factorialCache = new Map();
const logFactorialCache = new Map();
const doubleFactorialCache = new Map();
/**
* Computes log(n!) avoiding overflow using summation of logs
* Uses caching for efficiency
*
* @param n Input number (must be non-negative integer)
* @returns log(n!)
*/
export function logFactorial(n) {
if (n < 0)
return -Infinity;
if (Math.abs(Math.round(n) - n) > 1e-10) {
throw new Error('Factorial only defined for integers');
}
n = Math.round(n); // Ensure integer
// Check cache
const cached = logFactorialCache.get(n);
if (cached !== undefined)
return cached;
// Compute using summation of logs
let result = 0;
for (let i = 2; i <= n; i++) {
result += Math.log(i);
}
// Cache result
logFactorialCache.set(n, result);
return result;
}
/**
* Computes n! using cached log factorial
*
* @param n Input number (must be non-negative integer)
* @returns n!
*/
export function factorial(n) {
if (n < 0)
throw new Error('Factorial not defined for negative numbers');
if (n > 170)
throw new Error('Factorial too large for direct computation');
// Check cache
const cached = factorialCache.get(n);
if (cached !== undefined)
return cached;
const result = Math.exp(logFactorial(n));
factorialCache.set(n, result);
return result;
}
/**
* Computes double factorial n!! = n * (n-2) * (n-4) * ...
* Uses caching for efficiency
*
* @param n Input number (must be non-negative integer)
* @returns n!!
*/
export function doubleFactorial(n) {
if (n < 0)
throw new Error('Double factorial not defined for negative numbers');
if (n > 300)
throw new Error('Double factorial too large for direct computation');
// Check cache
const cached = doubleFactorialCache.get(n);
if (cached !== undefined)
return cached;
// Base cases
if (n <= 1)
return 1;
const result = n * doubleFactorial(n - 2);
doubleFactorialCache.set(n, result);
return result;
}
/**
* Computes Legendre polynomial P_n(x) using recursion
*
* @param n Degree of polynomial (must be non-negative integer)
* @param x Argument (-1 <= x <= 1)
* @returns P_n(x)
*/
/**
* Calculates triangle coefficient for three angular momenta
* Delta(a,b,c) = sqrt((a+b-c)!(a-b+c)!(-a+b+c)!/(a+b+c+1)!)
*
* @param a First angular momentum
* @param b Second angular momentum
* @param c Third angular momentum
* @returns Triangle coefficient
*/
export function triangleCoefficient(a, b, c) {
// Check triangle inequality
if (c > a + b || c < Math.abs(a - b)) {
return 0;
}
// Calculate using log factorials to avoid overflow
const sum = logFactorial(Math.round(a + b - c)) +
logFactorial(Math.round(a - b + c)) +
logFactorial(Math.round(-a + b + c)) -
logFactorial(Math.round(a + b + c + 1));
return Math.exp(sum / 2); // sqrt of exp(sum)
}
/**
* Computes Legendre polynomial P_n(x) using recursion
*
* @param n Degree of polynomial (must be non-negative integer)
* @param x Argument (-1 <= x <= 1)
* @returns P_n(x)
*/
export function legendrePolynomial(n, x) {
if (n < 0 || Math.abs(Math.round(n) - n) > 1e-10) {
throw new Error('Degree must be non-negative integer');
}
if (Math.abs(x) > 1) {
throw new Error('Argument must be in [-1,1]');
}
// Base cases
if (n === 0)
return 1;
if (n === 1)
return x;
// Bonnet's recursion formula
let p0 = 1; // P_0(x)
let p1 = x; // P_1(x)
let pn = 0; // P_n(x)
for (let k = 2; k <= n; k++) {
pn = ((2 * k - 1) * x * p1 - (k - 1) * p0) / k;
p0 = p1;
p1 = pn;
}
return pn;
}
/**
* Computes matrix exponential using Taylor series
*/
export function matrixExponential(matrix, terms = 10) {
const dim = matrix.length;
// Initialize result to identity matrix
const result = Array(dim).fill(null).map((_, i) => Array(dim).fill(null).map((_, j) => i === j ? math.complex(1, 0) : math.complex(0, 0)));
// Initialize term to identity
let term = Array(dim).fill(null).map((_, i) => Array(dim).fill(null).map((_, j) => i === j ? math.complex(1, 0) : math.complex(0, 0)));
// Compute sum of terms
for (let n = 1; n <= terms; n++) {
// Multiply term by matrix and divide by n
term = multiplyMatrices(term, matrix).map(row => row.map(element => math.complex(element.re / n, element.im / n)));
// Add to result
result.forEach((row, i) => row.forEach((_, j) => {
result[i][j] = math.add(result[i][j], term[i][j]);
}));
}
return result;
}
/**
* Multiplies two complex matrices
*/
export function multiplyMatrices(a, b) {
const dim = a.length;
const result = Array(dim).fill(null).map(() => Array(dim).fill(null).map(() => math.complex(0, 0)));
for (let i = 0; i < dim; i++) {
for (let j = 0; j < dim; j++) {
for (let k = 0; k < dim; k++) {
const prod = math.multiply(a[i][k], b[k][j]);
result[i][j] = math.add(result[i][j], prod);
}
}
}
return result;
}
/**
* Computes the singular value decomposition of a matrix
* Note: This is a placeholder for a proper SVD implementation
*/
export function singularValueDecomposition(matrix) {
const dim = matrix.length;
// Placeholder implementation
return {
U: Array(dim).fill(null).map((_, i) => Array(dim).fill(null).map((_, j) => i === j ? math.complex(1, 0) : math.complex(0, 0))),
S: Array(dim).fill(1),
V: Array(dim).fill(null).map((_, i) => Array(dim).fill(null).map((_, j) => i === j ? math.complex(1, 0) : math.complex(0, 0)))
};
}
//# sourceMappingURL=math.js.map