UNPKG

herta

Version:

Advanced mathematics framework for scientific, engineering, and financial applications

370 lines (322 loc) 12.1 kB
/** * Advanced symbolic integration module for herta.js * Provides capabilities beyond what math.js can offer */ const Complex = require('complex.js'); // Integration module const integration = {}; /** * Symbolic integration of mathematical expressions * @param {string|Function} expr - The expression to integrate * @param {string} variable - The integration variable * @param {number} [lowerBound] - Lower bound for definite integration * @param {number} [upperBound] - Upper bound for definite integration * @returns {string|number} - The symbolic result or numerical approximation */ integration.integrate = function (expr, variable, lowerBound, upperBound) { // Check if it's a definite integral const isDefinite = lowerBound !== undefined && upperBound !== undefined; // Convert string expression to a standardized form const expression = typeof expr === 'string' ? expr : expr.toString(); // Special case handling for common integrals const result = handleSpecialCases(expression, variable); if (result) { // If definite integral is requested, evaluate the antiderivative at bounds if (isDefinite) { return evaluateDefiniteIntegral(result, variable, lowerBound, upperBound); } return result; } // For expressions not handled by special cases, use numerical methods for definite integrals if (isDefinite) { return numericalIntegration(expression, variable, lowerBound, upperBound); } // For symbolic integration of complex expressions, use series expansions and approximations return symbolicIntegration(expression, variable); }; /** * Handle special cases of integrals that have known analytical solutions * @param {string} expr - The expression to integrate * @param {string} variable - The integration variable * @returns {string|null} - The symbolic result or null if not a special case */ function handleSpecialCases(expr, variable) { // Basic power rule: ∫x^n dx = x^(n+1)/(n+1) for n ≠ -1 const powerRegex = new RegExp(`(${variable})\s*\^\s*([\d.]+)`); const powerMatch = expr.match(powerRegex); if (powerMatch) { const power = parseFloat(powerMatch[2]); if (power !== -1) { return `(${variable}^${power + 1})/${power + 1}`; } return `ln(abs(${variable}))`; } // Trigonometric functions if (expr === `sin(${variable})`) { return `-cos(${variable})`; } if (expr === `cos(${variable})`) { return `sin(${variable})`; } if (expr === `tan(${variable})`) { return `-ln(abs(cos(${variable})))`; } // Exponential functions if (expr === `exp(${variable})` || expr === `e^${variable}`) { return `exp(${variable})`; } if (expr.match(new RegExp(`a\^${variable}`))) { const base = expr.split('^')[0]; return `(${base}^${variable})/ln(${base})`; } // Logarithmic function if (expr === `ln(${variable})`) { return `${variable}*ln(${variable}) - ${variable}`; } // Special case: sin(x^2) if (expr === `sin(${variable}^2)`) { return `C(${variable}) * sqrt(π/2) + S(${variable}) * sqrt(π/2)`; } // Special case: 1/(1+x^2) if (expr === `1/(1+${variable}^2)`) { return `atan(${variable})`; } return null; } /** * Evaluate a definite integral using the fundamental theorem of calculus * @param {string} antiderivative - The symbolic antiderivative * @param {string} variable - The integration variable * @param {number} lowerBound - Lower bound * @param {number} upperBound - Upper bound * @returns {number} - The numerical result */ function evaluateDefiniteIntegral(antiderivative, variable, lowerBound, upperBound) { // This is a simplified implementation // In a full implementation, we would parse and evaluate the antiderivative expression // For demonstration, we'll use numerical integration return numericalIntegration(antiderivative, variable, lowerBound, upperBound); } /** * Perform numerical integration using adaptive Simpson's rule * @param {string} expr - The expression to integrate * @param {string} variable - The integration variable * @param {number} lowerBound - Lower bound * @param {number} upperBound - Upper bound * @param {number} [tolerance=1e-10] - Error tolerance * @returns {number} - The numerical approximation */ function numericalIntegration(expr, variable, lowerBound, upperBound, tolerance = 1e-10) { // Implementation of adaptive Simpson's rule for numerical integration function evaluateExpr(x) { // Simple expression evaluator (would be replaced with a proper parser in production) // This is just a placeholder for demonstration return Function(variable, `return ${expr.replace(/\^/g, '**')}`)(x); } function simpson(a, b) { const c = (a + b) / 2; const fa = evaluateExpr(a); const fb = evaluateExpr(b); const fc = evaluateExpr(c); return (b - a) * (fa + 4 * fc + fb) / 6; } function adaptiveSimpson(a, b, fa, fb, fc, eps) { const c = (a + b) / 2; const d = (a + c) / 2; const e = (c + b) / 2; const fd = evaluateExpr(d); const fe = evaluateExpr(e); const left = (c - a) * (fa + 4 * fd + fc) / 6; const right = (b - c) * (fc + 4 * fe + fb) / 6; const whole = (b - a) * (fa + 4 * fc + fb) / 6; if (Math.abs(left + right - whole) <= 15 * eps) { return left + right + (left + right - whole) / 15; } return adaptiveSimpson(a, c, fa, fc, fd, eps / 2) + adaptiveSimpson(c, b, fc, fb, fe, eps / 2); } // Handle potential errors in evaluation try { const fa = evaluateExpr(lowerBound); const fb = evaluateExpr(upperBound); const fc = evaluateExpr((lowerBound + upperBound) / 2); return adaptiveSimpson( lowerBound, upperBound, fa, fb, fc, tolerance ); } catch (error) { throw new Error(`Error in numerical integration: ${error.message}`); } } /** * Perform symbolic integration for complex expressions * @param {string} expr - The expression to integrate * @param {string} variable - The integration variable * @returns {string} - The symbolic result */ function symbolicIntegration(expr, variable) { // This would be a complex implementation using techniques like: // - Pattern matching // - Integration by parts // - Substitution methods // - Series expansions // For demonstration, we'll return a placeholder result // In a full implementation, this would use advanced symbolic computation techniques // Check for common patterns that can be transformed // For expressions not handled by special cases or transformations, // return a formal integral notation return `∫(${expr})d${variable}`; } /** * Compute Fresnel integrals (used in certain physics applications) * @param {number} x - The upper limit of integration * @param {string} type - 'S' for sine integral, 'C' for cosine integral * @returns {number} - The value of the Fresnel integral */ integration.fresnelIntegral = function (x, type) { // Fresnel integrals are defined as: // S(x) = ∫(0 to x) sin(πt²/2) dt // C(x) = ∫(0 to x) cos(πt²/2) dt // Implementation using series expansion for small x // and asymptotic expansion for large x if (Math.abs(x) < 1.5) { // Series expansion let result = 0; const sign = type === 'S' ? -1 : 1; const func = type === 'S' ? Math.sin : Math.cos; for (let k = 0; k < 20; k++) { const term = x ** (4 * k + 3) / (factorial(2 * k + 1) * (4 * k + 3)); result += sign * term * func(Math.PI * (2 * k + 1) / 2); } return result; } // Asymptotic expansion for large x const sign = x >= 0 ? 1 : -1; const absX = Math.abs(x); if (type === 'S') { return sign * (0.5 - Math.cos(Math.PI * absX * absX / 2) / (Math.PI * absX)); } // type === 'C' return sign * (0.5 + Math.sin(Math.PI * absX * absX / 2) / (Math.PI * absX)); }; /** * Helper function to compute factorial * @param {number} n - Non-negative integer * @returns {number} - The factorial of n */ function factorial(n) { if (n === 0 || n === 1) return 1; let result = 1; for (let i = 2; i <= n; i++) { result *= i; } return result; } /** * Compute the Laplace transform of a function * @param {string|Function} expr - The expression to transform * @param {string} timeVar - The time variable (usually 't') * @param {string} freqVar - The frequency variable (usually 's') * @returns {string} - The symbolic Laplace transform */ integration.laplaceTransform = function (expr, timeVar = 't', freqVar = 's') { // Convert string expression to a standardized form const expression = typeof expr === 'string' ? expr : expr.toString(); // Handle common Laplace transforms if (expression === '1') { return `1/${freqVar}`; } if (expression === timeVar) { return `1/${freqVar}^2`; } if (expression === `${timeVar}^2`) { return `2/${freqVar}^3`; } if (expression === `exp(${timeVar})` || expression === `e^${timeVar}`) { return `1/(${freqVar}-1)`; } if (expression === `sin(${timeVar})`) { return `1/(${freqVar}^2+1)`; } if (expression === `cos(${timeVar})`) { return `${freqVar}/(${freqVar}^2+1)`; } // For more complex expressions, return formal notation return `L{${expression}}(${freqVar})`; }; /** * Compute the inverse Laplace transform * @param {string|Function} expr - The expression to inverse transform * @param {string} freqVar - The frequency variable (usually 's') * @param {string} timeVar - The time variable (usually 't') * @returns {string} - The symbolic inverse Laplace transform */ integration.inverseLaplaceTransform = function (expr, freqVar = 's', timeVar = 't') { // Convert string expression to a standardized form const expression = typeof expr === 'string' ? expr : expr.toString(); // Handle common inverse Laplace transforms if (expression === `1/${freqVar}`) { return '1'; } if (expression === `1/${freqVar}^2`) { return timeVar; } if (expression === `1/(${freqVar}-1)` || expression === `1/${freqVar}-1`) { return `exp(${timeVar})`; } if (expression === `1/(${freqVar}^2+1)`) { return `sin(${timeVar})`; } if (expression === `${freqVar}/(${freqVar}^2+1)`) { return `cos(${timeVar})`; } // For more complex expressions, return formal notation return `L^{-1}{${expression}}(${timeVar})`; }; /** * Compute the Fourier transform of a function * @param {string|Function} expr - The expression to transform * @param {string} timeVar - The time variable (usually 't') * @param {string} freqVar - The frequency variable (usually 'ω') * @returns {string} - The symbolic Fourier transform */ integration.fourierTransform = function (expr, timeVar = 't', freqVar = 'ω') { // Convert string expression to a standardized form const expression = typeof expr === 'string' ? expr : expr.toString(); // Handle common Fourier transforms if (expression === '1') { return `2π·δ(${freqVar})`; } if (expression === `exp(-${timeVar}^2/2)`) { return `sqrt(2π)·exp(-${freqVar}^2/2)`; } if (expression === `exp(-a·abs(${timeVar}))`) { return `2a/(a^2+${freqVar}^2)`; } // For more complex expressions, return formal notation return `F{${expression}}(${freqVar})`; }; /** * Compute the inverse Fourier transform * @param {string|Function} expr - The expression to inverse transform * @param {string} freqVar - The frequency variable (usually 'ω') * @param {string} timeVar - The time variable (usually 't') * @returns {string} - The symbolic inverse Fourier transform */ integration.inverseFourierTransform = function (expr, freqVar = 'ω', timeVar = 't') { // Convert string expression to a standardized form const expression = typeof expr === 'string' ? expr : expr.toString(); // Handle common inverse Fourier transforms if (expression === `δ(${freqVar})`) { return '1/(2π)'; } if (expression === `exp(-${freqVar}^2/2)`) { return `1/sqrt(2π)·exp(-${timeVar}^2/2)`; } // For more complex expressions, return formal notation return `F^{-1}{${expression}}(${timeVar})`; }; module.exports = integration;