sokobo
Loading...
Searching...
No Matches
laplace.cpp
1#include "include/laplace.h"
2#define _USE_MATH_DEFINES
3#include <cmath>
4#include <iostream>
5#include <stdexcept>
6#include <algorithm>
7#include <numeric>
8
9// Initialize static member
10std::map<std::string, std::function<ComplexNumber(ComplexNumber)>> LaplaceTransform::transformTable;
11
12void LaplaceTransform::initializeTransformTable() {
13 if (!transformTable.empty()) return; // Already initialized
14
15 // Basic transforms
16 transformTable["1"] = [](ComplexNumber s) -> ComplexNumber {
17 return ComplexNumber(1.0, 0.0) / s;
18 };
19
20 transformTable["t"] = [](ComplexNumber s) -> ComplexNumber {
21 return ComplexNumber(1.0, 0.0) / (s * s);
22 };
23
24 transformTable["t^2"] = [](ComplexNumber s) -> ComplexNumber {
25 return ComplexNumber(2.0, 0.0) / (s * s * s);
26 };
27
28 // Exponentials
29 transformTable["exp(at)"] = [](ComplexNumber s) -> ComplexNumber {
30 // This is a placeholder - actual 'a' value would need to be extracted from expression
31 double a = 1.0; // Default value
32 return ComplexNumber(1.0, 0.0) / (s - ComplexNumber(a, 0.0));
33 };
34
35 // Trigonometric functions
36 transformTable["sin(wt)"] = [](ComplexNumber s) -> ComplexNumber {
37 double w = 1.0; // Default value - would need to be extracted from expression
38 ComplexNumber w_complex(w, 0.0);
39 return w_complex / (s * s + w_complex * w_complex);
40 };
41
42 transformTable["cos(wt)"] = [](ComplexNumber s) -> ComplexNumber {
43 double w = 1.0; // Default value - would need to be extracted from expression
44 ComplexNumber w_complex(w, 0.0);
45 return s / (s * s + w_complex * w_complex);
46 };
47
48 // Hyperbolic functions
49 transformTable["sinh(at)"] = [](ComplexNumber s) -> ComplexNumber {
50 double a = 1.0; // Default value
51 ComplexNumber a_complex(a, 0.0);
52 return a_complex / (s * s - a_complex * a_complex);
53 };
54
55 transformTable["cosh(at)"] = [](ComplexNumber s) -> ComplexNumber {
56 double a = 1.0; // Default value
57 ComplexNumber a_complex(a, 0.0);
58 return s / (s * s - a_complex * a_complex);
59 };
60}
61
62// Symbolic Laplace transforms
63std::shared_ptr<Expression> LaplaceTransform::transform(std::shared_ptr<Expression> expr, const std::string& var) {
64 initializeTransformTable();
65
66 if (!expr) {
67 throw std::invalid_argument("Expression cannot be null");
68 }
69
70 // Get string representation of the expression
71 std::string exprStr = expr->toString();
72
73 // Simple pattern matching for basic transforms
74 // Note: This is a simplified implementation. A full implementation would need
75 // sophisticated expression parsing and pattern matching
76
77 if (exprStr == "1") {
78 // L{1} = 1/s
79 return std::make_shared<Variable>("1/s");
80 }
81 else if (exprStr == var) {
82 // L{t} = 1/s^2
83 return std::make_shared<Variable>("1/s^2");
84 }
85 else if (exprStr.find("exp") != std::string::npos) {
86 // Handle exponential functions
87 // This is simplified - would need proper parsing
88 return std::make_shared<Variable>("1/(s-a)");
89 }
90 else if (exprStr.find("sin") != std::string::npos) {
91 // Handle sine functions
92 return std::make_shared<Variable>("w/(s^2+w^2)");
93 }
94 else if (exprStr.find("cos") != std::string::npos) {
95 // Handle cosine functions
96 return std::make_shared<Variable>("s/(s^2+w^2)");
97 }
98
99 // Default case - return a placeholder
100 return std::make_shared<Variable>("L{" + exprStr + "}");
101}
102
103std::shared_ptr<Expression> LaplaceTransform::inverseTransform(std::shared_ptr<Expression> expr, const std::string& var) {
104 if (!expr) {
105 throw std::invalid_argument("Expression cannot be null");
106 }
107
108 std::string exprStr = expr->toString();
109
110 // Simple pattern matching for basic inverse transforms
111 if (exprStr == "1/s") {
112 return std::make_shared<Variable>("1");
113 }
114 else if (exprStr == "1/s^2") {
115 return std::make_shared<Variable>(var);
116 }
117 else if (exprStr.find("1/(s-") != std::string::npos) {
118 // Handle 1/(s-a) -> exp(at)
119 return std::make_shared<Variable>("exp(a*" + var + ")");
120 }
121 else if (exprStr.find("/(s^2+") != std::string::npos) {
122 if (exprStr.find("s/(s^2+") != std::string::npos) {
123 // s/(s^2+w^2) -> cos(wt)
124 return std::make_shared<Variable>("cos(w*" + var + ")");
125 } else {
126 // w/(s^2+w^2) -> sin(wt)
127 return std::make_shared<Variable>("sin(w*" + var + ")");
128 }
129 }
130
131 // Default case
132 return std::make_shared<Variable>("L^{-1}{" + exprStr + "}");
133}
134
135// Numerical Laplace transforms
136ComplexNumber LaplaceTransform::numericalTransform(std::function<double(double)> f, ComplexNumber s, double T) {
137 if (s.getValue().real() <= 0) {
138 throw std::invalid_argument("Real part of s must be positive for convergence");
139 }
140
141 const int samples = 1000;
142 double dt = T / samples;
143 ComplexNumber result(0, 0);
144
145 for (int n = 0; n < samples; ++n) {
146 double t = n * dt;
147 double ft = f(t);
148
149 // Calculate e^(-st)
150 ComplexNumber minus_st =
151 ComplexNumber(-s.getValue().real() * t, -s.getValue().imag() * t);
152 ComplexNumber exponential = minus_st.exp();
153
154 result = result + ComplexNumber(ft, 0) * exponential * dt;
155 }
156
157 return result;
158}
159
160// Helper function for factorial
161double factorial(int n)
162{
163 if (n <= 1) {
164 return 1.0;
165 }
166 double result = 1.0;
167 for (int i = 2; i <= n; ++i) {
168 result *= i;
169 }
170 return result;
171}
172
173std::function<double(double)> LaplaceTransform::numericalInverseTransform(
174 std::function<ComplexNumber(ComplexNumber)> F, double t_max) {
175
176 return [F, t_max](double t) -> double {
177 if (t < 0) return 0.0; // Laplace transform is causal
178
179 // Use Bromwich integral approximation
180 // This is a simplified implementation using the Gaver-Stehfest algorithm
181 const int N = 10; // Number of terms in the approximation
182
183 double result = 0.0;
184 double ln2_t = log(2.0) / t;
185
186 // Gaver-Stehfest coefficients
187 std::vector<double> V(N + 1);
188 for (int i = 1; i <= N; ++i) {
189 double sum = 0.0;
190 int k_min = (i + 1) / 2;
191 int k_max = std::min(i, N / 2);
192
193 for (int k = k_min; k <= k_max; ++k) {
194 double term = pow(k, N / 2) * factorial(2 * k);
195 term /= (factorial(N / 2 - k) * factorial(k) * factorial(k - 1) * factorial(i - k) * factorial(2 * k - i));
196 sum += term;
197 }
198
199 V[i] = pow(-1, i + N / 2) * sum;
200 }
201
202 // Compute the approximation
203 for (int i = 1; i <= N; ++i) {
204 ComplexNumber s(i * ln2_t, 0.0);
205 ComplexNumber F_s = F(s);
206 result += V[i] * F_s.getValue().real();
207 }
208
209 return ln2_t * result;
210 };
211}
212
213
214
215// Common transforms
216ComplexNumber LaplaceTransform::exponentialTransform(double a, ComplexNumber s) {
217 // L{e^(at)} = 1/(s-a)
218 ComplexNumber a_complex(a, 0.0);
219 return ComplexNumber(1.0, 0.0) / (s - a_complex);
220}
221
222ComplexNumber LaplaceTransform::sinusoidalTransform(double omega, ComplexNumber s) {
223 // L{sin(ωt)} = ω/(s²+ω²)
224 ComplexNumber omega_complex(omega, 0.0);
225 return omega_complex / (s * s + omega_complex * omega_complex);
226}
227
228ComplexNumber LaplaceTransform::polynomialTransform(const Polynomial& p, ComplexNumber s) {
229 // L{t^n} = n!/s^(n+1)
230 // For a polynomial, we sum the transforms of individual terms
231
232 ComplexNumber result(0, 0);
233
234 // Assuming Polynomial has getDegree() and getCoefficient(int) methods
235 for (int i = 0; i <= p.getDegree(); ++i) {
236 double coeff = p.getCoeff(i);
237 if (std::abs(coeff) < 1e-15) continue; // Skip zero coefficients
238
239 // Calculate i! / s^(i+1)
240 double factorial_i = factorial(i);
241 ComplexNumber s_power = s;
242 for (int j = 1; j < i + 1; ++j) {
243 s_power = s_power * s;
244 }
245
246 ComplexNumber term = ComplexNumber(coeff * factorial_i, 0.0) / s_power;
247 result = result + term;
248 }
249
250 return result;
251}
252
253// Properties
254std::shared_ptr<Expression> LaplaceTransform::convolution(std::shared_ptr<Expression> f1, std::shared_ptr<Expression> f2) {
255 if (!f1 || !f2) {
256 throw std::invalid_argument("Expressions cannot be null");
257 }
258
259 // L{f1 * f2} = F1(s) * F2(s) where * denotes convolution
260 auto F1 = transform(f1);
261 auto F2 = transform(f2);
262
263 // Create expression representing the product
264 std::string result_str = "(" + F1->toString() + ") * (" + F2->toString() + ")";
265 return std::make_shared<Variable>(result_str);
266}
267
268std::shared_ptr<Expression> LaplaceTransform::timeShift(std::shared_ptr<Expression> expr, double a) {
269 if (!expr) {
270 throw std::invalid_argument("Expression cannot be null");
271 }
272
273 if (a < 0) {
274 throw std::invalid_argument("Time shift must be non-negative");
275 }
276
277 // L{f(t-a)u(t-a)} = e^(-as) * F(s) where u is the unit step function
278 auto F = transform(expr);
279 std::string result_str = "exp(-" + std::to_string(a) + "*s) * (" + F->toString() + ")";
280 return std::make_shared<Variable>(result_str);
281}
282
283std::shared_ptr<Expression> LaplaceTransform::frequencyShift(std::shared_ptr<Expression> expr, double a) {
284 if (!expr) {
285 throw std::invalid_argument("Expression cannot be null");
286 }
287
288 // L{e^(at) * f(t)} = F(s-a)
289 auto F = transform(expr);
290 std::string original = F->toString();
291
292 // Replace 's' with '(s-a)' in the transformed expression
293 // This is a simplified implementation
294 std::string result_str = original;
295 size_t pos = 0;
296 while ((pos = result_str.find('s', pos)) != std::string::npos) {
297 result_str.replace(pos, 1, "(s-" + std::to_string(a) + ")");
298 pos += 4 + std::to_string(a).length();
299 }
300
301 return std::make_shared<Variable>(result_str);
302}