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

134 lines
4.8 KiB
OCaml

open Expr
open Simplify
open Diff
open Substitute
let rec integrate var = function
| Const c -> Some (Mul (Const c, Var var))
| SymConst _ as s -> Some (Mul (s, Var var))
| Var v when v = var -> Some (Div (Pow (Var var, Const 2.0), Const 2.0))
| Var v -> Some (Mul (Var v, Var var))
| Add (e1, e2) ->
(match (integrate var e1, integrate var e2) with
| Some i1, Some i2 -> Some (simplify (Add (i1, i2)))
| _ -> None)
| Sub (e1, e2) ->
(match (integrate var e1, integrate var e2) with
| Some i1, Some i2 -> Some (simplify (Sub (i1, i2)))
| _ -> None)
| Mul (Const c, e) | Mul (e, Const c) ->
(match integrate var e with
| Some i -> Some (simplify (Mul (Const c, i)))
| None -> None)
| Mul (SymConst s, e) | Mul (e, SymConst s) ->
(match integrate var e with
| Some i -> Some (simplify (Mul (SymConst s, i)))
| None -> None)
| Pow (Var v, Const n) when v = var && n <> -1.0 ->
let exp = n +. 1.0 in
Some (simplify (Div (Pow (Var var, Const exp), Const exp)))
| Div (Const 1.0, Var v) when v = var ->
Some (Ln (Abs (Var var)))
| Div (e, Var v) when v = var ->
(match e with
| Const c -> Some (simplify (Mul (Const c, Ln (Abs (Var var)))))
| _ -> None)
| Sin (Var v) when v = var ->
Some (Neg (Cos (Var var)))
| Cos (Var v) when v = var ->
Some (Sin (Var var))
| Tan (Var v) when v = var ->
Some (Neg (Ln (Abs (Cos (Var var)))))
| Div (Const 1.0, Pow (Cos (Var v), Const 2.0)) when v = var ->
Some (Tan (Var var))
| Sinh (Var v) when v = var ->
Some (Cosh (Var var))
| Cosh (Var v) when v = var ->
Some (Sinh (Var var))
| Tanh (Var v) when v = var ->
Some (Ln (Cosh (Var var)))
| Div (Const 1.0, Sqrt (Sub (Const 1.0, Pow (Var v, Const 2.0)))) when v = var ->
Some (Asin (Var var))
| Neg (Div (Const 1.0, Sqrt (Sub (Const 1.0, Pow (Var v, Const 2.0))))) when v = var ->
Some (Acos (Var var))
| Div (Const 1.0, Add (Const 1.0, Pow (Var v, Const 2.0))) when v = var ->
Some (Atan (Var var))
| Exp (Var v) when v = var ->
Some (Exp (Var var))
| Pow (Const a, Var v) when v = var ->
Some (simplify (Div (Pow (Const a, Var var), Ln (Const a))))
| Pow (SymConst E, Var v) when v = var ->
Some (Exp (Var var))
| e ->
match try_u_substitution var e with
| Some result -> Some result
| None -> try_by_parts var e
and try_u_substitution var expr =
let rec find_inner = function
| Sin u | Cos u | Tan u | Sinh u | Cosh u | Tanh u
| Asin u | Acos u | Atan u | Exp u | Ln u | Sqrt u | Abs u -> Some u
| Pow (u, _) -> Some u
| Add (e1, e2) | Sub (e1, e2) | Mul (e1, e2) | Div (e1, e2) ->
(match find_inner e1 with
| Some _ as r -> r
| None -> find_inner e2)
| _ -> None
in
match find_inner expr with
| Some u when u <> Var var ->
let u_prime = diff var u in
let expr_simplified = simplify expr in
let test_expr = simplify (Div (expr_simplified, u_prime)) in
let substituted = substitute var (Var "u_temp") test_expr in
(match substituted with
| e when not (contains_var var e) ->
(match integrate "u_temp" e with
| Some integrated ->
let result = substitute "u_temp" u integrated in
Some (simplify result)
| None -> None)
| _ -> None)
| _ -> None
and try_by_parts var = function
| Mul (e1, e2) ->
let priority = function
| Ln _ -> 5
| Asin _ | Acos _ | Atan _ -> 4
| Var _ | Pow (Var _, _) -> 3
| Sin _ | Cos _ | Tan _ | Sinh _ | Cosh _ | Tanh _ -> 2
| Exp _ -> 1
| _ -> 0
in
let (u, dv) =
if priority e1 >= priority e2 then (e1, e2) else (e2, e1)
in
(match integrate var dv with
| Some v ->
let du = diff var u in
(match integrate var (simplify (Mul (v, du))) with
| Some second_integral ->
Some (simplify (Sub (Mul (u, v), second_integral)))
| None -> None)
| None -> None)
| _ -> None
and contains_var var = function
| Const _ | SymConst _ -> false
| Var v -> v = var
| Add (e1, e2) | Sub (e1, e2) | Mul (e1, e2) | Div (e1, e2) | Pow (e1, e2) ->
contains_var var e1 || contains_var var e2
| Neg e | Sin e | Cos e | Tan e | Sinh e | Cosh e | Tanh e
| Asin e | Acos e | Atan e | Exp e | Ln e | Sqrt e | Abs e ->
contains_var var e
| Atan2 (e1, e2) | Log (e1, e2) ->
contains_var var e1 || contains_var var e2
let integrate_definite var lower upper expr =
match integrate var expr with
| None -> None
| Some antideriv ->
let upper_val = Eval.eval [(var, upper)] antideriv in
let lower_val = Eval.eval [(var, lower)] antideriv in
Some (upper_val -. lower_val)