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

154 lines
5.1 KiB
OCaml

open Diff
open Eval
open Multivariate
let newton_raphson expr var initial tolerance max_iter =
let f_prime = diff var expr in
let rec iterate x n =
if n >= max_iter then None
else
let fx = eval [(var, x)] expr in
if abs_float fx < tolerance then Some x
else
let fpx = eval [(var, x)] f_prime in
if abs_float fpx < 1e-10 then None
else
let x_next = x -. fx /. fpx in
if abs_float (x_next -. x) < tolerance then Some x_next
else iterate x_next (n + 1)
in
iterate initial 0
let bisection expr var left right tolerance max_iter =
let rec iterate a b n =
if n >= max_iter then None
else
let fa = eval [(var, a)] expr in
let fb = eval [(var, b)] expr in
if fa *. fb > 0.0 then None
else
let mid = (a +. b) /. 2.0 in
let fmid = eval [(var, mid)] expr in
if abs_float fmid < tolerance || abs_float (b -. a) < tolerance then
Some mid
else if fa *. fmid < 0.0 then
iterate a mid (n + 1)
else
iterate mid b (n + 1)
in
iterate left right 0
let trapezoidal expr var lower upper n =
let h = (upper -. lower) /. float_of_int n in
let rec sum_interior i acc =
if i >= n then acc
else
let x = lower +. float_of_int i *. h in
let fx = eval [(var, x)] expr in
sum_interior (i + 1) (acc +. fx)
in
let f_lower = eval [(var, lower)] expr in
let f_upper = eval [(var, upper)] expr in
let interior = sum_interior 1 0.0 in
h *. (f_lower /. 2.0 +. interior +. f_upper /. 2.0)
let simpsons expr var lower upper n =
let n = if n mod 2 = 1 then n + 1 else n in
let h = (upper -. lower) /. float_of_int n in
let rec sum_terms i acc_odd acc_even =
if i >= n then (acc_odd, acc_even)
else
let x = lower +. float_of_int i *. h in
let fx = eval [(var, x)] expr in
if i mod 2 = 1 then
sum_terms (i + 1) (acc_odd +. fx) acc_even
else if i > 0 then
sum_terms (i + 1) acc_odd (acc_even +. fx)
else
sum_terms (i + 1) acc_odd acc_even
in
let f_lower = eval [(var, lower)] expr in
let f_upper = eval [(var, upper)] expr in
let (odd, even) = sum_terms 1 0.0 0.0 in
h /. 3.0 *. (f_lower +. 4.0 *. odd +. 2.0 *. even +. f_upper)
let rec adaptive_quadrature expr var lower upper tolerance =
let mid = (lower +. upper) /. 2.0 in
let whole = simpsons expr var lower upper 10 in
let left_half = simpsons expr var lower mid 10 in
let right_half = simpsons expr var mid upper 10 in
let error = abs_float (whole -. (left_half +. right_half)) in
if error < tolerance then
left_half +. right_half
else
let left = adaptive_quadrature expr var lower mid (tolerance /. 2.0) in
let right = adaptive_quadrature expr var mid upper (tolerance /. 2.0) in
left +. right
let gradient_descent expr vars initial learning_rate max_iter =
let grad_exprs = gradient vars expr in
let rec iterate point n =
if n >= max_iter then Some point
else
let env = List.combine vars point in
let grad_vals = List.map (eval env) grad_exprs in
let new_point = List.map2 (fun p g -> p -. learning_rate *. g) point grad_vals in
let diff = List.map2 (fun a b -> abs_float (a -. b)) new_point point in
let max_diff = List.fold_left max 0.0 diff in
if max_diff < 1e-6 then Some new_point
else iterate new_point (n + 1)
in
iterate initial 0
let invert_matrix matrix =
let n = List.length matrix in
let augmented = List.mapi (fun i row ->
row @ List.init n (fun j -> if i = j then 1.0 else 0.0)
) matrix in
let rec gaussian_elimination mat row =
if row >= n then mat
else
let pivot_row = List.nth mat row in
let pivot = List.nth pivot_row row in
if abs_float pivot < 1e-10 then mat
else
let normalized = List.map (fun x -> x /. pivot) pivot_row in
let updated = List.mapi (fun i r ->
if i = row then normalized
else
let factor = List.nth r row in
List.map2 (fun a b -> a -. factor *. b) r normalized
) mat in
gaussian_elimination updated (row + 1)
in
let reduced = gaussian_elimination augmented 0 in
List.map (fun row -> List.filteri (fun i _ -> i >= n) row) reduced
let newtons_method_opt expr vars initial tolerance max_iter =
let grad_exprs = gradient vars expr in
let hess_matrix = hessian vars expr in
let rec iterate point n =
if n >= max_iter then None
else
let env = List.combine vars point in
let grad_vals = List.map (eval env) grad_exprs in
let hess_vals = List.map (fun row ->
List.map (eval env) row
) hess_matrix in
let hess_inv = invert_matrix hess_vals in
let delta = List.map (fun row ->
List.fold_left2 (fun acc h g -> acc +. h *. g) 0.0 row grad_vals
) hess_inv in
let new_point = List.map2 (fun p d -> p -. d) point delta in
let diff = List.map2 (fun a b -> abs_float (a -. b)) new_point point in
let max_diff = List.fold_left max 0.0 diff in
if max_diff < tolerance then Some new_point
else iterate new_point (n + 1)
in
iterate initial 0