leibniz/lib/limits.ml
2026-01-19 03:37:26 +00:00

70 lines
2.1 KiB
OCaml

open Expr
open Simplify
open Diff
open Substitute
type direction = FromLeft | FromRight | Bidirectional
let rec limit expr var point direction =
let try_direct_sub () =
try
let substituted = substitute var point expr in
let simplified = simplify substituted in
match simplified with
| Const c when not (Float.is_nan c || Float.is_infinite c) -> Some simplified
| _ -> None
with _ -> None
in
let try_lhopital () =
let numerator, denominator = match expr with
| Div (n, d) -> (n, d)
| _ -> (expr, Const 1.0)
in
let num_at_point = substitute var point numerator |> simplify in
let den_at_point = substitute var point denominator |> simplify in
match (num_at_point, den_at_point) with
| (Const 0.0, Const 0.0) ->
let num_deriv = diff var numerator in
let den_deriv = diff var denominator in
let new_expr = Div (num_deriv, den_deriv) in
limit new_expr var point direction
| _ -> None
in
let try_series_expansion () =
None
in
match try_direct_sub () with
| Some result -> Some result
| None ->
match try_lhopital () with
| Some result -> Some result
| None -> try_series_expansion ()
let limit_at_infinity expr var =
let rec find_highest_power = function
| Pow (Var v, Const n) when v = var -> Some (int_of_float n)
| Div (num, den) ->
let num_pow = find_highest_power num |> Option.value ~default:0 in
let den_pow = find_highest_power den |> Option.value ~default:0 in
Some (num_pow - den_pow)
| Add (e1, e2) | Sub (e1, e2) ->
let p1 = find_highest_power e1 |> Option.value ~default:0 in
let p2 = find_highest_power e2 |> Option.value ~default:0 in
Some (max p1 p2)
| Mul (e1, e2) ->
let p1 = find_highest_power e1 |> Option.value ~default:0 in
let p2 = find_highest_power e2 |> Option.value ~default:0 in
Some (p1 + p2)
| _ -> None
in
match find_highest_power expr with
| Some p when p > 0 -> Some (SymConst E)
| Some p when p < 0 -> Some (Const 0.0)
| Some _ -> Some (Const 1.0)
| None -> None