1use crate::calculus::derivatives::Derivative;
12use crate::core::{Expression, Symbol};
13use crate::simplify::Simplify;
14
15#[derive(Debug, Clone, Copy, PartialEq)]
17pub enum SeriesType {
18 Taylor,
20 Laurent,
22 Maclaurin,
24 Fourier,
26 Power,
28}
29
30pub trait SeriesExpansion {
32 fn taylor_series(&self, variable: &Symbol, point: &Expression, order: u32) -> Expression;
46
47 fn laurent_series(&self, variable: &Symbol, point: &Expression, order: u32) -> Expression;
64
65 fn maclaurin_series(&self, variable: &Symbol, order: u32) -> Expression;
78
79 fn power_series_coefficients(
93 &self,
94 variable: &Symbol,
95 point: &Expression,
96 order: u32,
97 ) -> Vec<Expression>;
98}
99
100pub struct SeriesMethods;
102
103impl SeriesMethods {
104 pub fn factorial(n: u32) -> Expression {
106 if n == 0 || n == 1 {
107 Expression::integer(1)
108 } else {
109 let mut result = 1i64;
110 for i in 2..=n {
111 result *= i as i64;
112 }
113 Expression::integer(result)
114 }
115 }
116
117 pub fn binomial_coefficient(n: u32, k: u32) -> Expression {
119 if k > n {
120 Expression::integer(0)
121 } else if k == 0 || k == n {
122 Expression::integer(1)
123 } else {
124 let numerator = Self::factorial(n);
125 let denominator = Expression::mul(vec![Self::factorial(k), Self::factorial(n - k)]);
126 Expression::mul(vec![
127 numerator,
128 Expression::pow(denominator, Expression::integer(-1)),
129 ])
130 .simplify()
131 }
132 }
133
134 pub fn known_series(
136 function_name: &str,
137 variable: &Symbol,
138 point: &Expression,
139 order: u32,
140 ) -> Option<Expression> {
141 match function_name {
142 "exp" if point.is_zero() => {
143 let mut terms = vec![Expression::integer(1)];
145 for n in 1..=order {
146 let term = Expression::mul(vec![
147 Expression::pow(
148 Expression::symbol(variable.clone()),
149 Expression::integer(n as i64),
150 ),
151 Expression::pow(Self::factorial(n), Expression::integer(-1)),
152 ])
153 .simplify();
154 terms.push(term);
155 }
156 Some(Expression::add(terms))
157 }
158 "sin" if point.is_zero() => {
159 let mut terms = Vec::new();
161 for n in 0..=order {
162 let power = 2 * n + 1;
163 if power > order {
164 break;
165 }
166
167 let sign = if n % 2 == 0 { 1 } else { -1 };
168 let term = Expression::mul(vec![
169 Expression::integer(sign),
170 Expression::pow(
171 Expression::symbol(variable.clone()),
172 Expression::integer(power as i64),
173 ),
174 Expression::pow(Self::factorial(power), Expression::integer(-1)),
175 ])
176 .simplify();
177 terms.push(term);
178 }
179 Some(Expression::add(terms))
180 }
181 "cos" if point.is_zero() => {
182 let mut terms = Vec::new();
184 for n in 0..=order {
185 let power = 2 * n;
186 if power > order {
187 break;
188 }
189
190 let sign = if n % 2 == 0 { 1 } else { -1 };
191 let term = if power == 0 {
192 Expression::integer(sign)
193 } else {
194 Expression::mul(vec![
195 Expression::integer(sign),
196 Expression::pow(
197 Expression::symbol(variable.clone()),
198 Expression::integer(power as i64),
199 ),
200 Expression::pow(Self::factorial(power), Expression::integer(-1)),
201 ])
202 .simplify()
203 };
204 terms.push(term);
205 }
206 Some(Expression::add(terms))
207 }
208 "ln" if *point == Expression::integer(1) => {
209 let mut terms = Vec::new();
211 for n in 1..=order {
212 let sign = if n % 2 == 1 { 1 } else { -1 };
213 let term = Expression::mul(vec![
214 Expression::integer(sign),
215 Expression::pow(
216 Expression::symbol(variable.clone()),
217 Expression::integer(n as i64),
218 ),
219 Expression::pow(Expression::integer(n as i64), Expression::integer(-1)),
220 ]);
221 terms.push(term);
222 }
223 Some(Expression::add(terms))
224 }
225 _ => None,
226 }
227 }
228
229 pub fn general_taylor_series(
238 expr: &Expression,
239 variable: &Symbol,
240 point: &Expression,
241 order: u32,
242 ) -> Expression {
243 let mut terms = Vec::new();
244
245 for n in 0..=order {
246 let nth_derivative = expr.nth_derivative(variable.clone(), n);
247 let derivative_at_point = Self::evaluate_at_point(&nth_derivative, variable, point);
248
249 let x_minus_a = if point.is_zero() {
250 Expression::symbol(variable.clone())
251 } else {
252 Expression::add(vec![
253 Expression::symbol(variable.clone()),
254 Expression::mul(vec![Expression::integer(-1), point.clone()]),
255 ])
256 };
257
258 let term = if n == 0 {
259 derivative_at_point
260 } else {
261 Expression::mul(vec![
264 derivative_at_point,
265 Expression::pow(x_minus_a, Expression::integer(n as i64)),
266 Expression::pow(Self::factorial(n), Expression::integer(-1)),
267 ])
268 };
269
270 terms.push(term);
271 }
272
273 Expression::add(terms).simplify()
274 }
275
276 pub fn evaluate_at_point(
278 expr: &Expression,
279 variable: &Symbol,
280 point: &Expression,
281 ) -> Expression {
282 match expr {
283 Expression::Symbol(sym) => {
284 if sym == variable {
285 point.clone()
286 } else {
287 expr.clone()
288 }
289 }
290 Expression::Add(terms) => {
291 let evaluated: Vec<Expression> = terms
292 .iter()
293 .map(|term| Self::evaluate_at_point(term, variable, point))
294 .collect();
295 Expression::add(evaluated).simplify()
296 }
297 Expression::Mul(factors) => {
298 let evaluated: Vec<Expression> = factors
299 .iter()
300 .map(|factor| Self::evaluate_at_point(factor, variable, point))
301 .collect();
302 Expression::mul(evaluated).simplify()
303 }
304 Expression::Pow(base, exp) => {
305 let eval_base = Self::evaluate_at_point(base, variable, point);
306 let eval_exp = Self::evaluate_at_point(exp, variable, point);
307 Expression::pow(eval_base, eval_exp).simplify()
308 }
309 Expression::Function { name, args } => {
310 let evaluated_args: Vec<Expression> = args
311 .iter()
312 .map(|arg| Self::evaluate_at_point(arg, variable, point))
313 .collect();
314 Expression::function(name.clone(), evaluated_args)
315 }
316 _ => expr.clone(),
317 }
318 }
319}
320
321impl SeriesExpansion for Expression {
322 fn taylor_series(&self, variable: &Symbol, point: &Expression, order: u32) -> Expression {
323 if let Expression::Function { name, args } = self {
325 if args.len() == 1 {
326 if let Expression::Symbol(sym) = &args[0] {
327 if sym == variable {
328 if let Some(known) =
329 SeriesMethods::known_series(name, variable, point, order)
330 {
331 return known;
332 }
333 }
334 }
335 }
336 }
337
338 SeriesMethods::general_taylor_series(self, variable, point, order)
340 }
341
342 fn laurent_series(&self, variable: &Symbol, point: &Expression, order: u32) -> Expression {
343 Expression::function(
346 "laurent_series",
347 vec![
348 self.clone(),
349 Expression::symbol(variable.clone()),
350 point.clone(),
351 Expression::integer(order as i64),
352 ],
353 )
354 }
355
356 fn maclaurin_series(&self, variable: &Symbol, order: u32) -> Expression {
357 self.taylor_series(variable, &Expression::integer(0), order)
358 }
359
360 fn power_series_coefficients(
361 &self,
362 variable: &Symbol,
363 point: &Expression,
364 order: u32,
365 ) -> Vec<Expression> {
366 let mut coefficients = Vec::new();
367
368 for n in 0..=order {
369 let nth_derivative = self.nth_derivative(variable.clone(), n);
370 let derivative_at_point =
371 SeriesMethods::evaluate_at_point(&nth_derivative, variable, point);
372 let coefficient = Expression::mul(vec![
373 derivative_at_point,
374 Expression::pow(SeriesMethods::factorial(n), Expression::integer(-1)),
375 ])
376 .simplify();
377 coefficients.push(coefficient);
378 }
379
380 coefficients
381 }
382}
383
384#[cfg(test)]
385mod tests {
386 use super::*;
387 use crate::symbol;
388
389 #[test]
390 fn test_exponential_maclaurin() {
391 let x = symbol!(x);
392 let expr = Expression::function("exp", vec![Expression::symbol(x.clone())]);
393 let result = expr.maclaurin_series(&x, 3);
394
395 let expected = Expression::add(vec![
397 Expression::integer(1),
398 Expression::symbol(x.clone()),
399 Expression::mul(vec![
400 Expression::rational(1, 2),
401 Expression::pow(Expression::symbol(x.clone()), Expression::integer(2)),
402 ]),
403 Expression::mul(vec![
404 Expression::rational(1, 6),
405 Expression::pow(Expression::symbol(x.clone()), Expression::integer(3)),
406 ]),
407 ]);
408
409 assert_eq!(result.simplify(), expected.simplify());
410 }
411
412 #[test]
413 fn test_sine_maclaurin() {
414 let x = symbol!(x);
415 let expr = Expression::function("sin", vec![Expression::symbol(x.clone())]);
416 let result = expr.maclaurin_series(&x, 3);
417
418 let expected = Expression::add(vec![
420 Expression::symbol(x.clone()),
421 Expression::mul(vec![
422 Expression::rational(-1, 6),
423 Expression::pow(Expression::symbol(x.clone()), Expression::integer(3)),
424 ]),
425 ]);
426
427 assert_eq!(result.simplify(), expected.simplify());
428 }
429
430 #[test]
431 fn test_cosine_maclaurin() {
432 let x = symbol!(x);
433 let expr = Expression::function("cos", vec![Expression::symbol(x.clone())]);
434 let result = expr.maclaurin_series(&x, 2);
435
436 let expected = Expression::add(vec![
438 Expression::integer(1),
439 Expression::mul(vec![
440 Expression::rational(-1, 2),
441 Expression::pow(Expression::symbol(x.clone()), Expression::integer(2)),
442 ]),
443 ]);
444
445 assert_eq!(result.simplify(), expected.simplify());
446 }
447
448 #[test]
449 fn test_factorial() {
450 assert_eq!(SeriesMethods::factorial(0), Expression::integer(1));
451 assert_eq!(SeriesMethods::factorial(1), Expression::integer(1));
452 assert_eq!(SeriesMethods::factorial(4), Expression::integer(24));
453 assert_eq!(SeriesMethods::factorial(5), Expression::integer(120));
454 }
455}