herta
Version:
Advanced mathematics framework for scientific, engineering, and financial applications
370 lines (322 loc) • 12.1 kB
JavaScript
/**
* 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;