154 lines
5.1 KiB
OCaml
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
|