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 / expr.ml
6.8 kB 207 lines
1type expr = 2 | Const of float 3 | Var of string 4 | Add of expr * expr 5 | Sub of expr * expr 6 | Mul of expr * expr 7 | Div of expr * expr 8 | Pow of expr * expr 9 | Neg of expr 10 | Sin of expr 11 | Cos of expr 12 | Tan of expr 13 | Exp of expr 14 | Ln of expr 15 16let rec to_string = function 17 | Const f -> 18 if Float.is_integer f then 19 string_of_int (int_of_float f) 20 else 21 string_of_float f 22 | Var s -> s 23 | Add (e1, e2) -> to_string_add e1 ^ " + " ^ to_string_add e2 24 | Sub (e1, e2) -> to_string e1 ^ " - " ^ to_string_paren e2 25 | Mul (e1, e2) -> to_string_mul e1 ^ "*" ^ to_string_mul e2 26 | Div (e1, e2) -> to_string_div e1 ^ "/" ^ to_string_paren e2 27 | Pow (e1, e2) -> to_string_atom e1 ^ "^" ^ to_string_pow_exp e2 28 | Neg e -> "-" ^ to_string_atom e 29 | Sin e -> "sin(" ^ to_string e ^ ")" 30 | Cos e -> "cos(" ^ to_string e ^ ")" 31 | Tan e -> "tan(" ^ to_string e ^ ")" 32 | Exp e -> "e^" ^ to_string_pow_exp e 33 | Ln e -> "ln(" ^ to_string e ^ ")" 34 35and to_string_atom = function 36 | (Const _ | Var _ | Sin _ | Cos _ | Tan _ | Exp _ | Ln _) as e -> to_string e 37 | e -> "(" ^ to_string e ^ ")" 38 39and to_string_mul = function 40 | (Const _ | Var _ | Pow _ | Sin _ | Cos _ | Tan _ | Exp _ | Ln _ | Mul _) as e -> to_string e 41 | e -> "(" ^ to_string e ^ ")" 42 43and to_string_div = function 44 | (Const _ | Var _ | Pow _ | Sin _ | Cos _ | Tan _ | Exp _ | Ln _ | Mul _) as e -> to_string e 45 | e -> "(" ^ to_string e ^ ")" 46 47and to_string_add = function 48 | (Add _ | Sub _) as e -> to_string e 49 | e -> to_string e 50 51and to_string_pow_exp = function 52 | (Const _ | Var _ | Pow _) as e -> to_string e 53 | e -> "(" ^ to_string e ^ ")" 54 55and to_string_paren = function 56 | (Add _ | Sub _) as e -> "(" ^ to_string e ^ ")" 57 | e -> to_string e 58 59let rec simplify = function 60 | Const _ as c -> c 61 | Var _ as v -> v 62 | Add (e1, e2) -> simplify_add (simplify e1) (simplify e2) 63 | Sub (e1, e2) -> simplify_sub (simplify e1) (simplify e2) 64 | Mul (e1, e2) -> simplify_mul (simplify e1) (simplify e2) 65 | Div (e1, e2) -> simplify_div (simplify e1) (simplify e2) 66 | Pow (e1, e2) -> simplify_pow (simplify e1) (simplify e2) 67 | Neg e -> simplify_neg (simplify e) 68 | Sin e -> Sin (simplify e) 69 | Cos e -> Cos (simplify e) 70 | Tan e -> Tan (simplify e) 71 | Exp e -> simplify_exp (simplify e) 72 | Ln e -> Ln (simplify e) 73 74and simplify_add e1 e2 = 75 match (e1, e2) with 76 | Const 0.0, e | e, Const 0.0 -> e 77 | Const a, Const b -> Const (a +. b) 78 | _ -> Add (e1, e2) 79 80and simplify_sub e1 e2 = 81 match (e1, e2) with 82 | e, Const 0.0 -> e 83 | Const a, Const b -> Const (a -. b) 84 | _ -> Sub (e1, e2) 85 86and simplify_mul e1 e2 = 87 match (e1, e2) with 88 | Const 0.0, _ | _, Const 0.0 -> Const 0.0 89 | Const 1.0, e | e, Const 1.0 -> e 90 | Const a, Const b -> Const (a *. b) 91 | Const a, Mul (Const b, e) -> simplify_mul (Const (a *. b)) e 92 | Mul (Const a, e), Const b -> simplify_mul (Const (a *. b)) e 93 | Const a, Mul (e1, Mul (Const b, e2)) -> 94 simplify_mul (Const (a *. b)) (Mul (e1, e2)) 95 | Mul (Const a, e1), Mul (Const b, e2) -> 96 simplify_mul (Const (a *. b)) (Mul (e1, e2)) 97 | (Sin _ | Cos _ | Tan _ | Exp _ | Ln _ | Pow _), Var _ -> 98 Mul (e2, e1) 99 | _ -> Mul (e1, e2) 100 101and simplify_div e1 e2 = 102 match (e1, e2) with 103 | Const 0.0, _ -> Const 0.0 104 | e, Const 1.0 -> e 105 | Const a, Const b -> Const (a /. b) 106 | e1, e2 when e1 = e2 -> Const 1.0 107 | _ -> Div (e1, e2) 108 109and simplify_pow e1 e2 = 110 match (e1, e2) with 111 | _, Const 0.0 -> Const 1.0 112 | e, Const 1.0 -> e 113 | Const 0.0, _ -> Const 0.0 114 | Const 1.0, _ -> Const 1.0 115 | Const a, Const b -> Const (a ** b) 116 | _ -> Pow (e1, e2) 117 118and simplify_neg = function 119 | Const c -> Const (-.c) 120 | Neg e -> e 121 | e -> Neg e 122 123and simplify_exp = function 124 | Const 0.0 -> Const 1.0 125 | Ln e -> e 126 | e -> Exp e 127 128let rec diff var = function 129 | Const _ -> Const 0.0 130 | Var v -> if v = var then Const 1.0 else Const 0.0 131 | Add (e1, e2) -> simplify (Add (diff var e1, diff var e2)) 132 | Sub (e1, e2) -> simplify (Sub (diff var e1, diff var e2)) 133 | Mul (e1, e2) -> 134 simplify (Add (Mul (diff var e1, e2), Mul (e1, diff var e2))) 135 | Div (e1, e2) -> 136 let num = Sub (Mul (diff var e1, e2), Mul (e1, diff var e2)) in 137 let den = Pow (e2, Const 2.0) in 138 simplify (Div (num, den)) 139 | Pow (e, Const n) -> 140 simplify (Mul (Mul (Const n, Pow (e, Const (n -. 1.0))), diff var e)) 141 | Pow (e1, e2) -> 142 let term1 = Mul (e2, Mul (Pow (e1, Sub (e2, Const 1.0)), diff var e1)) in 143 let term2 = Mul (Pow (e1, e2), Mul (Ln e1, diff var e2)) in 144 simplify (Add (term1, term2)) 145 | Neg e -> simplify (Neg (diff var e)) 146 | Sin e -> simplify (Mul (Cos e, diff var e)) 147 | Cos e -> simplify (Neg (Mul (Sin e, diff var e))) 148 | Tan e -> 149 let sec2 = Div (Const 1.0, Pow (Cos e, Const 2.0)) in 150 simplify (Mul (sec2, diff var e)) 151 | Exp e -> simplify (Mul (Exp e, diff var e)) 152 | Ln e -> simplify (Div (diff var e, e)) 153 154let rec diff_n var n expr = 155 if n <= 0 then expr 156 else diff_n var (n - 1) (diff var expr) 157 158let partial vars expr = 159 List.fold_left (fun e v -> diff v e) expr vars 160 161let rec to_latex = function 162 | Const f -> 163 if Float.is_integer f then 164 string_of_int (int_of_float f) 165 else 166 string_of_float f 167 | Var s -> s 168 | Add (e1, e2) -> to_latex e1 ^ " + " ^ to_latex e2 169 | Sub (e1, e2) -> to_latex e1 ^ " - " ^ to_latex_paren_latex e2 170 | Mul (e1, e2) -> to_latex_mul_latex e1 ^ to_latex_mul_latex e2 171 | Div (e1, e2) -> "\\frac{" ^ to_latex e1 ^ "}{" ^ to_latex e2 ^ "}" 172 | Pow (e1, e2) -> to_latex_atom_latex e1 ^ "^{" ^ to_latex e2 ^ "}" 173 | Neg e -> "-" ^ to_latex_atom_latex e 174 | Sin e -> "\\sin(" ^ to_latex e ^ ")" 175 | Cos e -> "\\cos(" ^ to_latex e ^ ")" 176 | Tan e -> "\\tan(" ^ to_latex e ^ ")" 177 | Exp e -> "e^{" ^ to_latex e ^ "}" 178 | Ln e -> "\\ln(" ^ to_latex e ^ ")" 179 180and to_latex_atom_latex = function 181 | (Const _ | Var _) as e -> to_latex e 182 | e -> "(" ^ to_latex e ^ ")" 183 184and to_latex_mul_latex = function 185 | (Const _ | Var _ | Pow _ | Sin _ | Cos _ | Tan _ | Exp _ | Ln _) as e -> to_latex e 186 | e -> "(" ^ to_latex e ^ ")" 187 188and to_latex_paren_latex = function 189 | (Add _ | Sub _) as e -> "(" ^ to_latex e ^ ")" 190 | e -> to_latex e 191 192let rec eval env = function 193 | Const f -> f 194 | Var v -> 195 (try List.assoc v env 196 with Not_found -> failwith ("unbound variable: " ^ v)) 197 | Add (e1, e2) -> eval env e1 +. eval env e2 198 | Sub (e1, e2) -> eval env e1 -. eval env e2 199 | Mul (e1, e2) -> eval env e1 *. eval env e2 200 | Div (e1, e2) -> eval env e1 /. eval env e2 201 | Pow (e1, e2) -> eval env e1 ** eval env e2 202 | Neg e -> -.(eval env e) 203 | Sin e -> sin (eval env e) 204 | Cos e -> cos (eval env e) 205 | Tan e -> tan (eval env e) 206 | Exp e -> exp (eval env e) 207 | Ln e -> log (eval env e)