1#include "include/differential_equations.h"
2#include "include/expression.h"
3#define _USE_MATH_DEFINES
11std::vector<double> DifferentialEquations::eulerMethod(std::function<
double(
double,
double)> f,
12 double x0,
double y0,
double h,
int steps) {
13 if (steps <= 0)
throw std::invalid_argument(
"Number of steps must be positive");
15 std::vector<double> solution;
16 solution.reserve(steps + 1);
17 solution.push_back(y0);
22 for (
int i = 0; i < steps; i++) {
25 solution.push_back(y);
32std::vector<double> DifferentialEquations::rungeKutta4(std::function<
double(
double,
double)> f,
33 double x0,
double y0,
double h,
int steps) {
34 if (steps <= 0)
throw std::invalid_argument(
"Number of steps must be positive");
36 std::vector<double> solution;
37 solution.reserve(steps + 1);
38 solution.push_back(y0);
43 for (
int i = 0; i < steps; i++) {
44 double k1 = h * f(x, y);
45 double k2 = h * f(x + h/2, y + k1/2);
46 double k3 = h * f(x + h/2, y + k2/2);
47 double k4 = h * f(x + h, y + k3);
49 y = y + (k1 + 2*k2 + 2*k3 + k4) / 6.0;
51 solution.push_back(y);
58std::vector<double> DifferentialEquations::adamsBashforth(std::function<
double(
double,
double)> f,
59 double x0,
double y0,
double h,
int steps) {
60 if (steps <= 0)
throw std::invalid_argument(
"Number of steps must be positive");
62 std::vector<double> solution;
63 solution.reserve(steps + 1);
64 solution.push_back(y0);
67 std::vector<double> f_values;
71 f_values.push_back(f(x, y));
74 for (
int i = 0; i < std::min(3, steps); i++) {
75 double k1 = h * f(x, y);
76 double k2 = h * f(x + h/2, y + k1/2);
77 double k3 = h * f(x + h/2, y + k2/2);
78 double k4 = h * f(x + h, y + k3);
80 y = y + (k1 + 2*k2 + 2*k3 + k4) / 6.0;
82 solution.push_back(y);
83 f_values.push_back(f(x, y));
87 for (
int i = 3; i < steps; i++) {
89 double y_new = y + h * (55.0*f_values[i] - 59.0*f_values[i-1] +
90 37.0*f_values[i-2] - 9.0*f_values[i-3]) / 24.0;
94 solution.push_back(y);
95 f_values.push_back(f(x, y));
102std::vector<std::vector<double>> DifferentialEquations::systemRungeKutta4(
103 std::vector<std::function<
double(
double,
const std::vector<double>&)>> f,
104 double x0,
const std::vector<double>& y0,
double h,
int steps) {
106 if (steps <= 0)
throw std::invalid_argument(
"Number of steps must be positive");
107 if (f.size() != y0.size())
throw std::invalid_argument(
"Number of functions must match initial conditions");
110 std::vector<std::vector<double>> solution(n);
112 for (
int i = 0; i < n; i++) {
113 solution[i].reserve(steps + 1);
114 solution[i].push_back(y0[i]);
118 std::vector<double> y = y0;
120 for (
int step = 0; step < steps; step++) {
121 std::vector<double> k1(n), k2(n), k3(n), k4(n);
122 std::vector<double> temp(n);
125 for (
int i = 0; i < n; i++) {
126 k1[i] = h * f[i](x, y);
130 for (
int i = 0; i < n; i++) {
131 temp[i] = y[i] + k1[i]/2;
133 for (
int i = 0; i < n; i++) {
134 k2[i] = h * f[i](x + h/2, temp);
138 for (
int i = 0; i < n; i++) {
139 temp[i] = y[i] + k2[i]/2;
141 for (
int i = 0; i < n; i++) {
142 k3[i] = h * f[i](x + h/2, temp);
146 for (
int i = 0; i < n; i++) {
147 temp[i] = y[i] + k3[i];
149 for (
int i = 0; i < n; i++) {
150 k4[i] = h * f[i](x + h, temp);
154 for (
int i = 0; i < n; i++) {
155 y[i] = y[i] + (k1[i] + 2*k2[i] + 2*k3[i] + k4[i]) / 6.0;
156 solution[i].push_back(y[i]);
159 x = x0 + (step + 1) * h;
166std::vector<double> DifferentialEquations::shootingMethod(
167 std::function<
double(
double,
double,
double)> f,
168 double a,
double b,
double alpha,
double beta,
int n) {
170 if (n <= 0)
throw std::invalid_argument(
"Number of points must be positive");
172 double h = (b - a) / n;
175 auto system = [f](
double x,
const std::vector<double>& y) -> std::vector<double> {
176 return {y[1], f(x, y[0], y[1])};
183 auto shoot = [&](
double slope) ->
double {
184 std::vector<double> initial = {alpha, slope};
185 std::vector<std::function<double(
double,
const std::vector<double>&)>> funcs = {
186 [](
double x,
const std::vector<double>& y) {
return y[1]; },
187 [f](
double x,
const std::vector<double>& y) {
return f(x, y[0], y[1]); }
190 auto result = systemRungeKutta4(funcs, a, initial, h, n);
191 return result[0].back() - beta;
194 double f1 = shoot(s1);
195 double f2 = shoot(s2);
198 for (
int iter = 0; iter < 50; iter++) {
199 if (std::abs(f2) < 1e-10)
break;
201 double s_new = s2 - f2 * (s2 - s1) / (f2 - f1);
209 std::vector<double> initial = {alpha, s2};
210 std::vector<std::function<double(
double,
const std::vector<double>&)>> funcs = {
211 [](
double x,
const std::vector<double>& y) {
return y[1]; },
212 [f](
double x,
const std::vector<double>& y) {
return f(x, y[0], y[1]); }
215 auto result = systemRungeKutta4(funcs, a, initial, h, n);
220std::vector<std::vector<double>> DifferentialEquations::heatEquation1D(
221 double alpha,
double L,
double T,
int nx,
int nt,
222 std::function<
double(
double)> initialCondition,
223 std::function<
double(
double)> boundaryLeft,
224 std::function<
double(
double)> boundaryRight) {
226 if (nx <= 0 || nt <= 0)
throw std::invalid_argument(
"Grid dimensions must be positive");
228 double dx = L / (nx - 1);
229 double dt = T / (nt - 1);
230 double r = alpha * dt / (dx * dx);
234 throw std::runtime_error(
"Unstable parameters: r = α*dt/dx² must be ≤ 0.5");
237 std::vector<std::vector<double>> u(nt, std::vector<double>(nx));
240 for (
int i = 0; i < nx; i++) {
242 u[0][i] = initialCondition(x);
246 for (
int t = 1; t < nt; t++) {
247 double time = t * dt;
250 u[t][0] = boundaryLeft(time);
251 u[t][nx-1] = boundaryRight(time);
254 for (
int i = 1; i < nx - 1; i++) {
255 u[t][i] = u[t-1][i] + r * (u[t-1][i+1] - 2*u[t-1][i] + u[t-1][i-1]);
263std::vector<std::vector<double>> DifferentialEquations::waveEquation1D(
264 double c,
double L,
double T,
int nx,
int nt,
265 std::function<
double(
double)> initialPosition,
266 std::function<
double(
double)> initialVelocity) {
268 if (nx <= 0 || nt <= 0)
throw std::invalid_argument(
"Grid dimensions must be positive");
270 double dx = L / (nx - 1);
271 double dt = T / (nt - 1);
272 double r = c * dt / dx;
276 throw std::runtime_error(
"Unstable parameters: c*dt/dx must be ≤ 1");
279 std::vector<std::vector<double>> u(nt, std::vector<double>(nx));
282 for (
int i = 0; i < nx; i++) {
284 u[0][i] = initialPosition(x);
288 for (
int i = 1; i < nx - 1; i++) {
290 u[1][i] = u[0][i] + dt * initialVelocity(x) +
291 0.5 * r * r * (u[0][i+1] - 2*u[0][i] + u[0][i-1]);
295 for (
int t = 0; t < nt; t++) {
301 for (
int t = 2; t < nt; t++) {
302 for (
int i = 1; i < nx - 1; i++) {
303 u[t][i] = 2*u[t-1][i] - u[t-2][i] +
304 r*r * (u[t-1][i+1] - 2*u[t-1][i] + u[t-1][i-1]);
312std::vector<std::vector<double>> DifferentialEquations::laplaceEquation2D(
313 int nx,
int ny,
double tolerance,
314 std::function<
double(
double,
double)> boundaryCondition) {
316 if (nx <= 0 || ny <= 0)
throw std::invalid_argument(
"Grid dimensions must be positive");
318 std::vector<std::vector<double>> u(ny, std::vector<double>(nx, 0.0));
319 std::vector<std::vector<double>> u_old(ny, std::vector<double>(nx, 0.0));
322 if (boundaryCondition) {
323 for (
int i = 0; i < nx; i++) {
324 double x =
static_cast<double>(i) / (nx - 1);
325 u[0][i] = boundaryCondition(x, 0.0);
326 u[ny-1][i] = boundaryCondition(x, 1.0);
328 for (
int j = 0; j < ny; j++) {
329 double y =
static_cast<double>(j) / (ny - 1);
330 u[j][0] = boundaryCondition(0.0, y);
331 u[j][nx-1] = boundaryCondition(1.0, y);
336 int max_iterations = 10000;
337 for (
int iter = 0; iter < max_iterations; iter++) {
341 for (
int j = 1; j < ny - 1; j++) {
342 for (
int i = 1; i < nx - 1; i++) {
343 u[j][i] = 0.25 * (u[j][i+1] + u[j][i-1] + u[j+1][i] + u[j-1][i]);
348 double max_error = 0.0;
349 for (
int j = 1; j < ny - 1; j++) {
350 for (
int i = 1; i < nx - 1; i++) {
351 max_error = std::max(max_error, std::abs(u[j][i] - u_old[j][i]));
355 if (max_error < tolerance) {
364std::shared_ptr<Expression> DifferentialEquations::solveLinearODE(
const std::vector<double>& coeffs,
365 std::shared_ptr<Expression> rhs) {
368 throw std::runtime_error(
"Symbolic ODE solution not implemented - requires complete expression tree system");
372std::shared_ptr<Expression> DifferentialEquations::solveSeparableODE(std::shared_ptr<Expression> expr) {
375 throw std::runtime_error(
"Symbolic separable ODE solution not implemented - requires complete expression tree system");