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