1#include "include/calculus.h"
2#include "include/expression.h"
3#include "include/polynomial.h"
4#define _USE_MATH_DEFINES
12#define M_PI 3.14159265358979323846;
15std::shared_ptr<Expression> Calculus::differentiate(
16 std::shared_ptr<Expression> expr,
const std::string& var)
18 return partialDerivative(expr, var);
21std::shared_ptr<Expression> Calculus::partialDerivative(
22 std::shared_ptr<Expression> expr,
const std::string& var)
30 type = expr->getType();
33 case Expression::Type::CONSTANT: {
35 return std::make_shared<Constant>(0.0);
41 auto varExpr = std::dynamic_pointer_cast<Variable>(expr);
42 if (varExpr && varExpr->getName() == var) {
44 return std::make_shared<Constant>(1.0);
47 return std::make_shared<Constant>(0.0);
51 case Expression::Type::BINARY_OP: {
52 auto binExpr = std::dynamic_pointer_cast<BinaryOp>(expr);
57 auto left = binExpr->getLeft();
58 auto right = binExpr->getRight();
59 char op = binExpr->getOperator();
65 auto leftDeriv = partialDerivative(left, var);
66 auto rightDeriv = partialDerivative(right, var);
67 return std::make_shared<BinaryOp>(
68 leftDeriv, op, rightDeriv);
73 auto leftDeriv = partialDerivative(left, var);
74 auto rightDeriv = partialDerivative(right, var);
76 auto term1 = std::make_shared<BinaryOp>(leftDeriv,
'*', right);
77 auto term2 = std::make_shared<BinaryOp>(left,
'*', rightDeriv);
79 return std::make_shared<BinaryOp>(term1,
'+', term2);
84 auto leftDeriv = partialDerivative(left, var);
85 auto rightDeriv = partialDerivative(right, var);
87 auto numerator1 = std::make_shared<BinaryOp>(leftDeriv,
'*', right);
88 auto numerator2 = std::make_shared<BinaryOp>(left,
'*', rightDeriv);
90 std::make_shared<BinaryOp>(numerator1,
'-', numerator2);
92 auto denominator = std::make_shared<BinaryOp>(right,
'*', right);
94 return std::make_shared<BinaryOp>(
95 numerator,
'/', denominator);
104 if (right->getType() == Expression::Type::CONSTANT) {
106 std::dynamic_pointer_cast<Constant>(right);
108 double n = constExpr->getValue();
110 return std::make_shared<Constant>(0.0);
113 auto leftDeriv = partialDerivative(left, var);
114 auto nMinus1 = std::make_shared<Constant>(n - 1);
115 auto nConst = std::make_shared<Constant>(n);
118 auto power = std::make_shared<BinaryOp>(left,
'^', nMinus1);
119 auto temp = std::make_shared<BinaryOp>(nConst,
'*', power);
120 return std::make_shared<BinaryOp>(temp,
'*', leftDeriv);
126 throw std::runtime_error(
127 "Complex power rule differentiation not implemented");
133 case Expression::Type::
135 auto unaryExpr = std::dynamic_pointer_cast<UnaryOpExpression>(expr);
140 auto operand = unaryExpr->getOperand();
141 char op = unaryExpr->getOperator();
147 auto operandDeriv = partialDerivative(expr, var);
148 return std::make_shared<UnaryOpExpression>(
'-', operandDeriv);
152 return partialDerivative(expr, var);
158 case Expression::Type::
160 auto funcExpr = std::dynamic_pointer_cast<Function>(expr);
165 std::string funcName = funcExpr->getFunctionName();
166 auto arg = funcExpr->getArgument();
167 auto argDeriv = partialDerivative(arg, var);
170 if (funcName ==
"sin") {
171 auto cosFunc = std::make_shared<Function>(
"cos", arg);
172 return std::make_shared<BinaryOp>(cosFunc,
'*', argDeriv);
173 }
else if (funcName ==
"cos") {
174 auto sinFunc = std::make_shared<Function>(
"sin", arg);
175 auto negSin = std::make_shared<UnaryOpExpression>(
'-', sinFunc);
176 return std::make_shared<BinaryOp>(negSin,
'*', argDeriv);
177 }
else if (funcName ==
"tan") {
178 auto cosFunc = std::make_shared<Function>(
"cos", arg);
179 auto cos2 = std::make_shared<BinaryOp>(cosFunc,
'*', cosFunc);
180 auto one = std::make_shared<Constant>(1.0);
181 auto sec2 = std::make_shared<BinaryOp>(one,
'/', cos2);
182 return std::make_shared<BinaryOp>(sec2,
'*', argDeriv);
183 }
else if (funcName ==
"ln" || funcName ==
"log") {
184 auto reciprocal = std::make_shared<BinaryOp>(
185 std::make_shared<Constant>(1.0),
'/', arg);
186 return std::make_shared<BinaryOp>(reciprocal,
'*', argDeriv);
187 }
else if (funcName ==
"exp") {
188 auto expFunc = std::make_shared<Function>(
"exp", arg);
189 return std::make_shared<BinaryOp>(expFunc,
'*', argDeriv);
190 }
else if (funcName ==
"sqrt") {
192 auto two = std::make_shared<Constant>(2.0);
193 auto sqrtFunc = std::make_shared<Function>(
"sqrt", arg);
194 auto denominator = std::make_shared<BinaryOp>(two,
'*', sqrtFunc);
195 auto fraction = std::make_shared<BinaryOp>(
196 std::make_shared<Constant>(1.0),
'/', denominator);
197 return std::make_shared<BinaryOp>(fraction,
'*', argDeriv);
201 throw std::runtime_error(
"Differentiation of function '" + funcName
202 +
"' not implemented");
209 throw std::runtime_error(
210 "Unable to differentiate expression of unknown type");
214std::shared_ptr<Expression> Calculus::integrate(std::shared_ptr<Expression> expr,
const std::string& var) {
221 throw std::runtime_error(
"Symbolic integration not fully implemented - requires complete expression tree structure");
225double Calculus::trapezoidalRule(std::function<
double(
double)> f,
double a,
double b,
int n) {
226 if (n <= 0)
throw std::invalid_argument(
"Number of intervals must be positive");
228 double h = (b - a) / n;
229 double sum = 0.5 * (f(a) + f(b));
231 for (
int i = 1; i < n; i++) {
239double Calculus::simpsonsRule(std::function<
double(
double)> f,
double a,
double b,
int n) {
240 if (n <= 0 || n % 2 != 0)
throw std::invalid_argument(
"Number of intervals must be positive and even");
242 double h = (b - a) / n;
243 double sum = f(a) + f(b);
246 for (
int i = 1; i < n; i += 2) {
247 sum += 4 * f(a + i * h);
251 for (
int i = 2; i < n; i += 2) {
252 sum += 2 * f(a + i * h);
255 return sum * h / 3.0;
259double Calculus::gaussianQuadrature(std::function<
double(
double)> f,
double a,
double b,
int n) {
261 static const std::vector<std::vector<double>> points = {
264 {-0.5773502691896257, 0.5773502691896257},
265 {-0.7745966692414834, 0.0, 0.7745966692414834},
266 {-0.8611363115940526, -0.3399810435848563, 0.3399810435848563, 0.8611363115940526},
267 {-0.9061798459386640, -0.5384693101056831, 0.0, 0.5384693101056831, 0.9061798459386640}
270 static const std::vector<std::vector<double>> weights = {
274 {0.5555555555555556, 0.8888888888888888, 0.5555555555555556},
275 {0.3478548451374538, 0.6521451548625461, 0.6521451548625461, 0.3478548451374538},
276 {0.2369268850561891, 0.4786286704993665, 0.5688888888888889, 0.4786286704993665, 0.2369268850561891}
279 if (n < 1 || n > 5) {
280 throw std::invalid_argument(
"Gaussian quadrature only implemented for n=1 to 5");
284 double mid = (a + b) / 2.0;
285 double half_width = (b - a) / 2.0;
287 for (
int i = 0; i < n; i++) {
288 double x = mid + half_width * points[n][i];
289 sum += weights[n][i] * f(x);
292 return half_width * sum;
296double Calculus::monteCarloIntegration(std::function<
double(
double)> f,
double a,
double b,
int samples) {
297 if (samples <= 0)
throw std::invalid_argument(
"Number of samples must be positive");
299 std::random_device rd;
300 std::mt19937 gen(rd());
301 std::uniform_real_distribution<double> dis(a, b);
304 for (
int i = 0; i < samples; i++) {
309 return (b - a) * sum / samples;
313double Calculus::doubleIntegral(std::function<
double(
double,
double)> f,
314 double x1,
double x2,
double y1,
double y2,
int nx,
int ny) {
315 if (nx <= 0 || ny <= 0)
throw std::invalid_argument(
"Number of intervals must be positive");
317 double hx = (x2 - x1) / nx;
318 double hy = (y2 - y1) / ny;
322 for (
int i = 0; i <= nx; i++) {
323 double x = x1 + i * hx;
324 double weight_x = (i == 0 || i == nx) ? 0.5 : 1.0;
326 for (
int j = 0; j <= ny; j++) {
327 double y = y1 + j * hy;
328 double weight_y = (j == 0 || j == ny) ? 0.5 : 1.0;
330 sum += weight_x * weight_y * f(x, y);
334 return sum * hx * hy;
338Polynomial Calculus::taylorSeries(std::function<
double(
double)> f,
double center,
int degree) {
339 if (degree < 0)
throw std::invalid_argument(
"Degree must be non-negative");
341 std::vector<double> coefficients(degree + 1);
345 coefficients[0] = f(center);
347 for (
int n = 1; n <= degree; n++) {
349 double derivative = 0.0;
353 derivative = (f(center + h) - f(center - h)) / (2.0 * h);
357 std::function<double(
double)> fn = f;
358 for (
int i = 0; i < n; i++) {
360 fn = [prev_fn, h](
double x) {
361 return (prev_fn(x + h) - prev_fn(x - h)) / (2.0 * h);
364 derivative = fn(center);
368 double factorial = 1.0;
369 for (
int i = 1; i <= n; i++) {
373 coefficients[n] = derivative / factorial;
380Polynomial Calculus::chebyshevSeries(std::function<
double(
double)> f,
double a,
double b,
int degree) {
381 if (degree < 0)
throw std::invalid_argument(
"Degree must be non-negative");
383 std::vector<double> coefficients(degree + 1, 0.0);
386 auto transform = [a, b](
double t) {
return 0.5 * ((b - a) * t + a + b); };
389 for (
int k = 0; k <= degree; k++) {
391 int n_points = std::max(degree + 1, 50);
393 for (
int j = 0; j < n_points; j++) {
394 double t = std::cos(std::acos(-1.0) * (j + 0.5) / n_points);
395 double x = transform(t);
405 for (
int m = 2; m <= k; m++) {
406 double T_next = 2.0 * t * T_curr - T_prev;
416 coefficients[k] = (k == 0 ? 1.0 : 2.0) * sum / n_points;
425double Calculus::limit(std::function<
double(
double)> f,
double x,
double h) {
426 if (h <= 0)
throw std::invalid_argument(
"Step size must be positive");
429 double left_limit = f(x - h);
430 double right_limit = f(x + h);
433 double prev_avg = (left_limit + right_limit) / 2.0;
435 for (
int i = 0; i < 10; i++) {
437 left_limit = f(x - h);
438 right_limit = f(x + h);
439 double current_avg = (left_limit + right_limit) / 2.0;
442 if (std::abs(current_avg - prev_avg) < 1e-12) {
445 prev_avg = current_avg;