UNPKG

herta

Version:

Advanced mathematics framework for scientific, engineering, and financial applications

316 lines (271 loc) 9.89 kB
/** * Core calculus operations for herta.js * Provides differentiation, integration, and other calculus operations */ const Decimal = require('decimal.js'); const Complex = require('complex.js'); // Calculus module const calculus = {}; /** * Compute the derivative of an expression * @param {string|Function} expr - The expression to differentiate * @param {string} variable - The variable to differentiate with respect to * @param {Object} [options] - Additional options * @returns {string} - The derivative expression */ calculus.derivative = function (expr, variable, options = {}) { // Convert function to string if needed const expression = typeof expr === 'function' ? expr.toString() : expr; // Handle special cases and basic derivatives const result = computeBasicDerivative(expression, variable); if (result) return result; // Apply differentiation rules for more complex expressions return applyDifferentiationRules(expression, variable, options); }; /** * Compute basic derivatives for common functions * @private * @param {string} expr - The expression to differentiate * @param {string} variable - The differentiation variable * @returns {string|null} - The derivative or null if not a basic case */ function computeBasicDerivative(expr, variable) { // Constant rule: d/dx(c) = 0 if (!expr.includes(variable)) { return '0'; } // Power rule: d/dx(x^n) = n*x^(n-1) const powerRegex = new RegExp(`^${variable}\\^(\\d+)$`); const powerMatch = expr.match(powerRegex); if (powerMatch) { const power = parseInt(powerMatch[1]); if (power === 0) return '0'; if (power === 1) return '1'; return `${power}*${variable}^${power - 1}`; } // Linear rule: d/dx(x) = 1 if (expr === variable) { return '1'; } // Sine rule: d/dx(sin(x)) = cos(x) if (expr === `sin(${variable})`) { return `cos(${variable})`; } // Cosine rule: d/dx(cos(x)) = -sin(x) if (expr === `cos(${variable})`) { return `-sin(${variable})`; } // Exponential rule: d/dx(e^x) = e^x if (expr === `exp(${variable})` || expr === `e^${variable}`) { return expr; } // Natural logarithm rule: d/dx(ln(x)) = 1/x if (expr === `ln(${variable})`) { return `1/${variable}`; } // Not a basic case return null; } /** * Apply differentiation rules for complex expressions * @private * @param {string} expr - The expression to differentiate * @param {string} variable - The differentiation variable * @param {Object} options - Additional options * @returns {string} - The derivative expression */ function applyDifferentiationRules(expr, variable, options) { // This would implement the chain rule, product rule, quotient rule, etc. // For now, return a placeholder return `d/d${variable}(${expr})`; } /** * Compute a definite integral numerically * @param {string|Function} expr - The expression to integrate * @param {string} variable - The integration variable * @param {number} lowerBound - Lower bound of integration * @param {number} upperBound - Upper bound of integration * @param {Object} [options] - Additional options * @returns {number} - The numerical result of the integration */ calculus.integrate = function (expr, variable, lowerBound, upperBound, options = {}) { // Default options const defaultOptions = { method: 'simpson', // 'simpson', 'trapezoidal', 'midpoint' intervals: 1000, // Number of intervals for numerical integration tolerance: 1e-10 // Tolerance for adaptive methods }; const config = { ...defaultOptions, ...options }; // Convert function to string if needed for evaluation const expression = typeof expr === 'function' ? expr : (x) => { // Create a scope with the variable value const scope = {}; scope[variable] = x; // This would use the expression evaluation engine return evaluateExpression(expr, scope); }; // Perform numerical integration based on the selected method switch (config.method) { case 'simpson': return simpsonIntegration(expression, lowerBound, upperBound, config.intervals); case 'trapezoidal': return trapezoidalIntegration(expression, lowerBound, upperBound, config.intervals); case 'midpoint': return midpointIntegration(expression, lowerBound, upperBound, config.intervals); default: throw new Error(`Unsupported integration method: ${config.method}`); } }; /** * Placeholder for expression evaluation * @private * @param {string} expr - The expression to evaluate * @param {Object} scope - Variable values * @returns {number} - The evaluated result */ function evaluateExpression(expr, scope) { // This would be implemented with a proper expression parser return 0; } /** * Simpson's rule for numerical integration * @private * @param {Function} f - The function to integrate * @param {number} a - Lower bound * @param {number} b - Upper bound * @param {number} n - Number of intervals (must be even) * @returns {number} - The numerical result */ function simpsonIntegration(f, a, b, n) { // Ensure n is even if (n % 2 !== 0) n++; const h = (b - a) / n; let sum = f(a) + f(b); // Sum the odd-indexed terms for (let i = 1; i < n; i += 2) { sum += 4 * f(a + i * h); } // Sum the even-indexed terms for (let i = 2; i < n; i += 2) { sum += 2 * f(a + i * h); } return (h / 3) * sum; } /** * Trapezoidal rule for numerical integration * @private * @param {Function} f - The function to integrate * @param {number} a - Lower bound * @param {number} b - Upper bound * @param {number} n - Number of intervals * @returns {number} - The numerical result */ function trapezoidalIntegration(f, a, b, n) { const h = (b - a) / n; let sum = (f(a) + f(b)) / 2; for (let i = 1; i < n; i++) { sum += f(a + i * h); } return h * sum; } /** * Midpoint rule for numerical integration * @private * @param {Function} f - The function to integrate * @param {number} a - Lower bound * @param {number} b - Upper bound * @param {number} n - Number of intervals * @returns {number} - The numerical result */ function midpointIntegration(f, a, b, n) { const h = (b - a) / n; let sum = 0; for (let i = 0; i < n; i++) { sum += f(a + (i + 0.5) * h); } return h * sum; } /** * Compute a limit of an expression * @param {string|Function} expr - The expression * @param {string} variable - The variable * @param {number|string} point - The point to approach * @param {string} [direction] - The direction ('left', 'right', or 'both') * @returns {number|string} - The limit value or symbolic result */ calculus.limit = function (expr, variable, point, direction = 'both') { // Convert function to string if needed const expression = typeof expr === 'function' ? expr.toString() : expr; // Handle special cases like infinity if (point === 'Infinity' || point === '+Infinity') { return limitToInfinity(expression, variable, '+'); } if (point === '-Infinity') { return limitToInfinity(expression, variable, '-'); } // For numerical evaluation of limits const epsilon = 1e-10; // Evaluate the limit based on the direction if (direction === 'left' || direction === 'both') { // Approach from the left const leftLimit = evaluateExpression(expression, { [variable]: point - epsilon }); if (direction === 'left') { return leftLimit; } // If both directions, also approach from the right const rightLimit = evaluateExpression(expression, { [variable]: point + epsilon }); // Check if the limits from both sides are equal if (Math.abs(leftLimit - rightLimit) < epsilon) { return (leftLimit + rightLimit) / 2; } return 'Limit does not exist'; } if (direction === 'right') { // Approach from the right return evaluateExpression(expression, { [variable]: point + epsilon }); } throw new Error(`Invalid direction: ${direction}. Must be 'left', 'right', or 'both'.`); }; /** * Compute the limit as the variable approaches infinity * @private * @param {string} expr - The expression * @param {string} variable - The variable * @param {string} sign - The sign of infinity ('+' or '-') * @returns {number|string} - The limit value or symbolic result */ function limitToInfinity(expr, variable, sign) { // This would implement techniques for evaluating limits at infinity // For now, return a placeholder return `lim ${variable}->${sign}${expr}`; } /** * Find critical points of a function * @param {string|Function} expr - The function expression * @param {string} variable - The variable * @param {number} [lowerBound] - Lower bound of the search interval * @param {number} [upperBound] - Upper bound of the search interval * @returns {Array} - Array of critical points */ calculus.criticalPoints = function (expr, variable, lowerBound, upperBound) { // Find where the derivative equals zero const derivative = calculus.derivative(expr, variable); // This would implement numerical methods to find roots of the derivative // For now, return a placeholder return []; }; /** * Find inflection points of a function * @param {string|Function} expr - The function expression * @param {string} variable - The variable * @param {number} [lowerBound] - Lower bound of the search interval * @param {number} [upperBound] - Upper bound of the search interval * @returns {Array} - Array of inflection points */ calculus.inflectionPoints = function (expr, variable, lowerBound, upperBound) { // Find where the second derivative equals zero const firstDerivative = calculus.derivative(expr, variable); const secondDerivative = calculus.derivative(firstDerivative, variable); // This would implement numerical methods to find roots of the second derivative // For now, return a placeholder return []; }; module.exports = calculus;