1pub mod educational;
9pub mod methods;
10
11use crate::core::polynomial::PolynomialProperties;
12use crate::core::{Expression, Number, Symbol};
13use methods::LimitMethods;
14
15#[derive(Debug, Clone, Copy, PartialEq)]
17pub enum LimitDirection {
18 Both,
20 Left,
22 Right,
24}
25
26pub trait Limits {
28 fn limit(&self, variable: &Symbol, point: &Expression) -> Expression;
45
46 fn limit_directed(
60 &self,
61 variable: &Symbol,
62 point: &Expression,
63 direction: LimitDirection,
64 ) -> Expression;
65
66 fn limit_at_infinity(&self, variable: &Symbol) -> Expression;
79
80 fn limit_at_negative_infinity(&self, variable: &Symbol) -> Expression;
93}
94
95impl Limits for Expression {
96 fn limit(&self, variable: &Symbol, point: &Expression) -> Expression {
97 match self {
100 Expression::Mul(factors) if factors.len() == 2 => {
101 if let Expression::Pow(denom, exp) = &factors[1] {
104 if let Expression::Number(Number::Integer(n)) = exp.as_ref() {
105 if *n < 0 {
106 let positive_exp = Expression::integer(-n);
108 let denominator_positive =
109 Expression::pow(denom.as_ref().clone(), positive_exp);
110 return LimitMethods::rational_limit(
111 &factors[0],
112 &denominator_positive,
113 variable,
114 point,
115 );
116 }
117 }
118 }
119 if let Expression::Pow(denom, exp) = &factors[0] {
120 if let Expression::Number(Number::Integer(n)) = exp.as_ref() {
121 if *n < 0 {
122 let positive_exp = Expression::integer(-n);
124 let denominator_positive =
125 Expression::pow(denom.as_ref().clone(), positive_exp);
126 return LimitMethods::rational_limit(
127 &factors[1],
128 &denominator_positive,
129 variable,
130 point,
131 );
132 }
133 }
134 }
135 }
136 _ => {}
137 }
138
139 let substituted = LimitMethods::substitute_and_evaluate(self, variable, point);
141
142 if !LimitMethods::is_indeterminate_form(&substituted, variable, point) {
143 return substituted;
144 }
145
146 match self {
147 Expression::Mul(_factors) => LimitMethods::trigonometric_limit(self, variable, point),
148 Expression::Function { name: _, args: _ } => {
149 LimitMethods::trigonometric_limit(self, variable, point)
150 }
151 _ => Expression::function(
152 "limit",
153 vec![
154 self.clone(),
155 Expression::symbol(variable.clone()),
156 point.clone(),
157 ],
158 ),
159 }
160 }
161
162 fn limit_directed(
163 &self,
164 variable: &Symbol,
165 point: &Expression,
166 direction: LimitDirection,
167 ) -> Expression {
168 let direction_expr = match direction {
169 LimitDirection::Both => Expression::symbol("both"),
170 LimitDirection::Left => Expression::symbol("left"),
171 LimitDirection::Right => Expression::symbol("right"),
172 };
173
174 Expression::function(
175 "limit_directed",
176 vec![
177 self.clone(),
178 Expression::symbol(variable.clone()),
179 point.clone(),
180 direction_expr,
181 ],
182 )
183 }
184
185 fn limit_at_infinity(&self, variable: &Symbol) -> Expression {
186 match self {
187 Expression::Number(_) | Expression::Constant(_) => self.clone(),
188
189 Expression::Symbol(s) if s == variable => Expression::infinity(),
190
191 Expression::Function { name, args } => {
192 if (name == "ln" || name == "log") && args.len() == 1 {
194 if let Expression::Symbol(s) = &args[0] {
195 if s == variable {
196 return Expression::infinity();
197 }
198 }
199 }
200
201 Expression::function(
202 "limit",
203 vec![
204 self.clone(),
205 Expression::symbol(variable.clone()),
206 Expression::infinity(),
207 ],
208 )
209 }
210
211 Expression::Pow(base, exp) => {
212 if let Expression::Symbol(exp_sym) = exp.as_ref() {
214 if exp_sym == variable {
215 let base_limit = base.limit_at_infinity(variable);
216 if base_limit == Expression::integer(1) {
217 return Expression::e();
218 }
219 }
220 }
221
222 if let Expression::Symbol(s) = base.as_ref() {
223 if s == variable {
224 match exp.as_ref() {
225 Expression::Number(Number::Integer(n)) if *n > 0 => {
226 return Expression::infinity();
227 }
228 Expression::Number(Number::Integer(n)) if *n < 0 => {
229 return Expression::integer(0);
230 }
231 _ => {}
232 }
233 }
234 }
235
236 Expression::function(
237 "limit",
238 vec![
239 self.clone(),
240 Expression::symbol(variable.clone()),
241 Expression::infinity(),
242 ],
243 )
244 }
245
246 Expression::Add(_terms) => {
247 if let Some(degree) = self.degree(variable) {
248 let lc = self.leading_coefficient(variable);
249 if degree > 0 {
250 return Expression::infinity();
251 } else if degree == 0 {
252 return lc;
253 }
254 }
255
256 Expression::function(
257 "limit",
258 vec![
259 self.clone(),
260 Expression::symbol(variable.clone()),
261 Expression::infinity(),
262 ],
263 )
264 }
265
266 Expression::Mul(factors) => {
267 let mut numer_factors = Vec::new();
268 let mut denom_factors = Vec::new();
269
270 for factor in factors.as_ref() {
271 match factor {
272 Expression::Pow(base, exp) if *exp.as_ref() == Expression::integer(-1) => {
273 denom_factors.push(base.as_ref().clone());
274 }
275 _ => {
276 numer_factors.push(factor.clone());
277 }
278 }
279 }
280
281 if !denom_factors.is_empty() {
282 let numerator = if numer_factors.is_empty() {
283 Expression::integer(1)
284 } else if numer_factors.len() == 1 {
285 numer_factors[0].clone()
286 } else {
287 Expression::mul(numer_factors)
288 };
289
290 let denominator = if denom_factors.len() == 1 {
291 denom_factors[0].clone()
292 } else {
293 Expression::mul(denom_factors)
294 };
295
296 let num_degree = numerator.degree(variable);
297 let den_degree = denominator.degree(variable);
298
299 match (num_degree, den_degree) {
300 (Some(nd), Some(dd)) if nd == dd => {
301 let num_lc = numerator.leading_coefficient(variable);
302 let den_lc = denominator.leading_coefficient(variable);
303 return Expression::mul(vec![
304 num_lc,
305 Expression::pow(den_lc, Expression::integer(-1)),
306 ]);
307 }
308 (Some(nd), Some(dd)) if nd > dd => {
309 return Expression::infinity();
310 }
311 (Some(nd), Some(dd)) if nd < dd => {
312 return Expression::integer(0);
313 }
314 (None, Some(_)) | (Some(_), None) => {
315 return LimitMethods::rational_limit_at_infinity(
316 &numerator,
317 &denominator,
318 variable,
319 );
320 }
321 _ => {}
322 }
323 }
324
325 if let Some(degree) = self.degree(variable) {
326 if degree > 0 {
327 return Expression::infinity();
328 } else if degree == 0 {
329 return self.clone();
330 }
331 }
332
333 Expression::function(
334 "limit",
335 vec![
336 self.clone(),
337 Expression::symbol(variable.clone()),
338 Expression::infinity(),
339 ],
340 )
341 }
342
343 _ => Expression::function(
344 "limit",
345 vec![
346 self.clone(),
347 Expression::symbol(variable.clone()),
348 Expression::infinity(),
349 ],
350 ),
351 }
352 }
353
354 fn limit_at_negative_infinity(&self, variable: &Symbol) -> Expression {
355 Expression::function(
356 "limit",
357 vec![
358 self.clone(),
359 Expression::symbol(variable.clone()),
360 Expression::mul(vec![Expression::integer(-1), Expression::infinity()]),
361 ],
362 )
363 }
364}
365
366#[cfg(test)]
367mod tests {
368 use super::*;
369 use crate::symbol;
370
371 #[test]
372 fn test_polynomial_limit() {
373 let x = symbol!(x);
374 let expr = Expression::pow(Expression::symbol(x.clone()), Expression::integer(2));
375 let point = Expression::integer(3);
376 let result = expr.limit(&x, &point);
377
378 assert_eq!(result, Expression::integer(9));
379 }
380
381 #[test]
382 fn test_rational_limit_continuous() {
383 let x = symbol!(x);
384 let numerator =
385 Expression::add(vec![Expression::symbol(x.clone()), Expression::integer(1)]);
386 let denominator =
387 Expression::add(vec![Expression::symbol(x.clone()), Expression::integer(2)]);
388 let expr = Expression::mul(vec![
389 numerator,
390 Expression::pow(denominator, Expression::integer(-1)),
391 ]);
392 let point = Expression::integer(1);
393 let result = expr.limit(&x, &point);
394
395 assert_eq!(result, Expression::rational(2, 3));
396 }
397
398 #[test]
399 fn test_trigonometric_limit() {
400 let x = symbol!(x);
401 let sin_x = Expression::function("sin", vec![Expression::symbol(x.clone())]);
402 let expr = Expression::mul(vec![
403 sin_x,
404 Expression::pow(Expression::symbol(x.clone()), Expression::integer(-1)),
405 ]);
406 let point = Expression::integer(0);
407 let result = expr.limit(&x, &point);
408
409 assert_eq!(result, Expression::integer(1));
410 }
411
412 #[test]
413 fn test_limit_at_infinity_constant() {
414 let x = symbol!(x);
415 let expr = Expression::integer(5);
416 let result = expr.limit_at_infinity(&x);
417
418 assert_eq!(result, Expression::integer(5));
419 }
420
421 #[test]
422 fn test_limit_at_infinity_variable() {
423 let x = symbol!(x);
424 let expr = Expression::symbol(x.clone());
425 let result = expr.limit_at_infinity(&x);
426
427 assert_eq!(result, Expression::infinity());
428 }
429
430 #[test]
431 fn test_limit_at_infinity_inverse() {
432 let x = symbol!(x);
433 let expr = Expression::pow(Expression::symbol(x.clone()), Expression::integer(-1));
434 let result = expr.limit_at_infinity(&x);
435
436 assert_eq!(result, Expression::integer(0));
437 }
438
439 #[test]
440 fn test_limit_at_infinity_polynomial() {
441 let x = symbol!(x);
442 let expr = Expression::pow(Expression::symbol(x.clone()), Expression::integer(3));
443 let result = expr.limit_at_infinity(&x);
444
445 assert_eq!(result, Expression::infinity());
446 }
447
448 #[test]
449 fn test_limit_at_infinity_rational_same_degree() {
450 let x = symbol!(x);
451 let numerator = Expression::mul(vec![
452 Expression::integer(3),
453 Expression::pow(Expression::symbol(x.clone()), Expression::integer(2)),
454 ]);
455 let denominator = Expression::mul(vec![
456 Expression::integer(2),
457 Expression::pow(Expression::symbol(x.clone()), Expression::integer(2)),
458 ]);
459 let expr = Expression::mul(vec![
460 numerator,
461 Expression::pow(denominator, Expression::integer(-1)),
462 ]);
463 let result = expr.limit_at_infinity(&x);
464
465 assert_eq!(result, Expression::rational(3, 2));
466 }
467
468 #[test]
469 fn test_limit_at_infinity_rational_num_greater() {
470 let x = symbol!(x);
471 let numerator = Expression::pow(Expression::symbol(x.clone()), Expression::integer(3));
472 let denominator = Expression::pow(Expression::symbol(x.clone()), Expression::integer(2));
473 let expr = Expression::mul(vec![
474 numerator,
475 Expression::pow(denominator, Expression::integer(-1)),
476 ]);
477 let result = expr.limit_at_infinity(&x);
478
479 assert_eq!(result, Expression::infinity());
480 }
481
482 #[test]
483 fn test_limit_at_infinity_rational_den_greater() {
484 let x = symbol!(x);
485 let numerator = Expression::pow(Expression::symbol(x.clone()), Expression::integer(1));
486 let denominator = Expression::pow(Expression::symbol(x.clone()), Expression::integer(3));
487 let expr = Expression::mul(vec![
488 numerator,
489 Expression::pow(denominator, Expression::integer(-1)),
490 ]);
491 let result = expr.limit_at_infinity(&x);
492
493 assert_eq!(result, Expression::integer(0));
494 }
495}