symbolic mathematics engine in OCaml with differentiation, integration, simplification, and numerical methods
17

Configure Feed

Select the types of activity you want to include in your feed.

leibniz / lib / cse.ml
3.5 kB 110 lines
1open Expr 2open Canonical 3 4type cse_result = { 5 final_expr: expr; 6 subexpressions: (string * expr) list; 7} 8 9let common_subexpression_elimination expr = 10 let counter = ref 0 in 11 let subexpr_map = Hashtbl.create 100 in 12 let name_map = Hashtbl.create 100 in 13 14 let get_or_create_name e = 15 let h = hash e in 16 match Hashtbl.find_opt name_map h with 17 | Some name -> Var name 18 | None -> 19 incr counter; 20 let name = Printf.sprintf "cse_%d" !counter in 21 Hashtbl.add name_map h name; 22 Hashtbl.add subexpr_map name e; 23 Var name 24 in 25 26 let should_extract = function 27 | Const _ | SymConst _ | Var _ -> false 28 | _ -> true 29 in 30 31 let rec count_occurrences e counts = 32 let h = hash e in 33 Hashtbl.replace counts h (1 + (Hashtbl.find_opt counts h |> Option.value ~default:0)); 34 match e with 35 | Add (e1, e2) | Sub (e1, e2) | Mul (e1, e2) | Div (e1, e2) | Pow (e1, e2) -> 36 count_occurrences e1 counts; 37 count_occurrences e2 counts 38 | Neg e | Sin e | Cos e | Tan e | Sinh e | Cosh e | Tanh e 39 | Asin e | Acos e | Atan e | Exp e | Ln e | Sqrt e | Abs e -> 40 count_occurrences e counts 41 | Atan2 (e1, e2) | Log (e1, e2) -> 42 count_occurrences e1 counts; 43 count_occurrences e2 counts 44 | _ -> () 45 in 46 47 let counts = Hashtbl.create 100 in 48 count_occurrences expr counts; 49 50 let rec extract e = 51 if should_extract e && Hashtbl.find counts (hash e) >= 2 then 52 get_or_create_name e 53 else 54 match e with 55 | Add (e1, e2) -> Add (extract e1, extract e2) 56 | Sub (e1, e2) -> Sub (extract e1, extract e2) 57 | Mul (e1, e2) -> Mul (extract e1, extract e2) 58 | Div (e1, e2) -> Div (extract e1, extract e2) 59 | Pow (e1, e2) -> Pow (extract e1, extract e2) 60 | Neg e -> Neg (extract e) 61 | Sin e -> Sin (extract e) 62 | Cos e -> Cos (extract e) 63 | Tan e -> Tan (extract e) 64 | Sinh e -> Sinh (extract e) 65 | Cosh e -> Cosh (extract e) 66 | Tanh e -> Tanh (extract e) 67 | Asin e -> Asin (extract e) 68 | Acos e -> Acos (extract e) 69 | Atan e -> Atan (extract e) 70 | Atan2 (e1, e2) -> Atan2 (extract e1, extract e2) 71 | Exp e -> Exp (extract e) 72 | Ln e -> Ln (extract e) 73 | Log (e1, e2) -> Log (extract e1, extract e2) 74 | Sqrt e -> Sqrt (extract e) 75 | Abs e -> Abs (extract e) 76 | e -> e 77 in 78 79 let final = extract expr in 80 let subexprs = Hashtbl.fold (fun name e acc -> (name, e) :: acc) subexpr_map [] in 81 {final_expr = final; subexpressions = List.sort (fun (n1, _) (n2, _) -> String.compare n1 n2) subexprs} 82 83let horner_form expr var = 84 let rec collect_poly e = 85 match e with 86 | Const c -> [(0, Const c)] 87 | Var v when v = var -> [(1, Const 1.0)] 88 | Pow (Var v, Const n) when v = var && Float.is_integer n -> 89 [(int_of_float n, Const 1.0)] 90 | Mul (Const c, Pow (Var v, Const n)) when v = var && Float.is_integer n -> 91 [(int_of_float n, Const c)] 92 | Add (e1, e2) -> collect_poly e1 @ collect_poly e2 93 | _ -> [(0, e)] 94 in 95 96 let terms = collect_poly expr in 97 let max_degree = List.fold_left (fun acc (deg, _) -> max acc deg) 0 terms in 98 99 let coeffs = Array.make (max_degree + 1) (Const 0.0) in 100 List.iter (fun (deg, coeff) -> 101 coeffs.(deg) <- Simplify.simplify (Add (coeffs.(deg), coeff)) 102 ) terms; 103 104 let rec build_horner deg = 105 if deg < 0 then Const 0.0 106 else if deg = 0 then coeffs.(0) 107 else Add (coeffs.(deg), Mul (Var var, build_horner (deg - 1))) 108 in 109 110 Simplify.simplify (build_horner max_degree)