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 / simplify.ml
6.9 kB 220 lines
1open Expr 2 3let max_iterations = 100 4 5let rec simplify_once = function 6 | Const _ as c -> c 7 | SymConst _ as s -> s 8 | Var _ as v -> v 9 | Add (e1, e2) -> simplify_add (simplify_once e1) (simplify_once e2) 10 | Sub (e1, e2) -> simplify_sub (simplify_once e1) (simplify_once e2) 11 | Mul (e1, e2) -> simplify_mul (simplify_once e1) (simplify_once e2) 12 | Div (e1, e2) -> simplify_div (simplify_once e1) (simplify_once e2) 13 | Pow (e1, e2) -> simplify_pow (simplify_once e1) (simplify_once e2) 14 | Neg e -> simplify_neg (simplify_once e) 15 | Sin e -> simplify_sin (simplify_once e) 16 | Cos e -> simplify_cos (simplify_once e) 17 | Tan e -> simplify_tan (simplify_once e) 18 | Sinh e -> simplify_sinh (simplify_once e) 19 | Cosh e -> simplify_cosh (simplify_once e) 20 | Tanh e -> simplify_tanh (simplify_once e) 21 | Asin e -> simplify_asin (simplify_once e) 22 | Acos e -> simplify_acos (simplify_once e) 23 | Atan e -> simplify_atan (simplify_once e) 24 | Atan2 (e1, e2) -> simplify_atan2 (simplify_once e1) (simplify_once e2) 25 | Exp e -> simplify_exp (simplify_once e) 26 | Ln e -> simplify_ln (simplify_once e) 27 | Log (e1, e2) -> simplify_log (simplify_once e1) (simplify_once e2) 28 | Sqrt e -> simplify_sqrt (simplify_once e) 29 | Abs e -> simplify_abs (simplify_once e) 30 31and simplify_add e1 e2 = 32 match (e1, e2) with 33 | Const 0.0, e | e, Const 0.0 -> e 34 | Const a, Const b -> Const (a +. b) 35 | Mul (Const a, e1), Mul (Const b, e2) when Canonical.equal e1 e2 -> 36 simplify_mul (Const (a +. b)) e1 37 | Mul (Const a, e1), e2 when Canonical.equal e1 e2 -> 38 simplify_mul (Const (a +. 1.0)) e1 39 | e1, Mul (Const b, e2) when Canonical.equal e1 e2 -> 40 simplify_mul (Const (1.0 +. b)) e1 41 | e1, e2 when Canonical.equal e1 e2 -> 42 simplify_mul (Const 2.0) e1 43 | Add (e1, Const a), Const b -> simplify_add e1 (Const (a +. b)) 44 | _ -> Add (e1, e2) 45 46and simplify_sub e1 e2 = 47 match (e1, e2) with 48 | e, Const 0.0 -> e 49 | Const a, Const b -> Const (a -. b) 50 | e1, e2 when Canonical.equal e1 e2 -> Const 0.0 51 | _ -> Sub (e1, e2) 52 53and simplify_mul e1 e2 = 54 match (e1, e2) with 55 | Const 0.0, _ | _, Const 0.0 -> Const 0.0 56 | Const 1.0, e | e, Const 1.0 -> e 57 | Const (-1.0), e -> simplify_neg e 58 | e, Const (-1.0) -> simplify_neg e 59 | Const a, Const b -> Const (a *. b) 60 | Const a, Mul (Const b, e) -> simplify_mul (Const (a *. b)) e 61 | Mul (Const a, e), Const b -> simplify_mul (Const (a *. b)) e 62 | Const a, Mul (e1, Mul (Const b, e2)) -> 63 simplify_mul (Const (a *. b)) (Mul (e1, e2)) 64 | Mul (Const a, e1), Mul (Const b, e2) -> 65 simplify_mul (Const (a *. b)) (Mul (e1, e2)) 66 | Pow (e1, a), Pow (e2, b) when Canonical.equal e1 e2 -> 67 simplify_pow e1 (simplify_add a b) 68 | e1, Pow (e2, b) when Canonical.equal e1 e2 -> 69 simplify_pow e1 (simplify_add (Const 1.0) b) 70 | Pow (e1, a), e2 when Canonical.equal e1 e2 -> 71 simplify_pow e1 (simplify_add a (Const 1.0)) 72 | e1, e2 when Canonical.equal e1 e2 -> 73 simplify_pow e1 (Const 2.0) 74 | Exp e1, Exp e2 -> Exp (simplify_add e1 e2) 75 | (Sin _ | Cos _ | Tan _ | Sinh _ | Cosh _ | Tanh _ | 76 Asin _ | Acos _ | Atan _ | Exp _ | Ln _ | Log _ | Sqrt _ | Abs _ | Pow _), Var _ -> 77 Mul (e2, e1) 78 | _ -> Mul (e1, e2) 79 80and simplify_div e1 e2 = 81 match (e1, e2) with 82 | Const 0.0, _ -> Const 0.0 83 | e, Const 1.0 -> e 84 | Const a, Const b -> Const (a /. b) 85 | e1, e2 when Canonical.equal e1 e2 -> Const 1.0 86 | Mul (e1, e2), e3 when Canonical.equal e2 e3 -> e1 87 | Mul (e1, e2), e3 when Canonical.equal e1 e3 -> e2 88 | _ -> Div (e1, e2) 89 90and simplify_pow e1 e2 = 91 match (e1, e2) with 92 | _, Const 0.0 -> Const 1.0 93 | e, Const 1.0 -> e 94 | Const 0.0, _ -> Const 0.0 95 | Const 1.0, _ -> Const 1.0 96 | Const a, Const b -> Const (a ** b) 97 | Pow (e, a), b -> simplify_pow e (simplify_mul a b) 98 | Sqrt e, Const 2.0 -> e 99 | e, Const 0.5 -> simplify_sqrt e 100 | SymConst E, Ln e -> e 101 | _ -> Pow (e1, e2) 102 103and simplify_neg = function 104 | Const c -> Const (-.c) 105 | Neg e -> e 106 | Mul (Const c, e) -> simplify_mul (Const (-.c)) e 107 | Mul (e, Const c) -> simplify_mul (Const (-.c)) e 108 | e -> Neg e 109 110and simplify_sin = function 111 | Const 0.0 -> Const 0.0 112 | Const c -> Const (sin c) 113 | Asin e -> e 114 | Neg e -> simplify_neg (Sin e) 115 | e -> Sin e 116 117and simplify_cos = function 118 | Const 0.0 -> Const 1.0 119 | Const c -> Const (cos c) 120 | Acos e -> e 121 | Neg e -> Cos e 122 | e -> Cos e 123 124and simplify_tan = function 125 | Const 0.0 -> Const 0.0 126 | Const c -> Const (tan c) 127 | Atan e -> e 128 | Neg e -> simplify_neg (Tan e) 129 | e -> Tan e 130 131and simplify_sinh = function 132 | Const 0.0 -> Const 0.0 133 | Const c -> Const (sinh c) 134 | Neg e -> simplify_neg (Sinh e) 135 | e -> Sinh e 136 137and simplify_cosh = function 138 | Const 0.0 -> Const 1.0 139 | Const c -> Const (cosh c) 140 | Neg e -> Cosh e 141 | e -> Cosh e 142 143and simplify_tanh = function 144 | Const 0.0 -> Const 0.0 145 | Const c -> Const (tanh c) 146 | Neg e -> simplify_neg (Tanh e) 147 | e -> Tanh e 148 149and simplify_asin = function 150 | Const c -> Const (asin c) 151 | Sin e -> e 152 | e -> Asin e 153 154and simplify_acos = function 155 | Const c -> Const (acos c) 156 | Cos e -> e 157 | e -> Acos e 158 159and simplify_atan = function 160 | Const c -> Const (atan c) 161 | Tan e -> e 162 | e -> Atan e 163 164and simplify_atan2 e1 e2 = 165 match (e1, e2) with 166 | Const a, Const b -> Const (atan2 a b) 167 | _ -> Atan2 (e1, e2) 168 169and simplify_exp = function 170 | Const 0.0 -> Const 1.0 171 | Const c -> Const (exp c) 172 | Ln e -> e 173 | Add (e1, e2) -> simplify_mul (Exp e1) (Exp e2) 174 | Mul (Const c, e) -> simplify_pow (Exp e) (Const c) 175 | e -> Exp e 176 177and simplify_ln = function 178 | Const 1.0 -> Const 0.0 179 | Const c when c > 0.0 -> Const (log c) 180 | Exp e -> e 181 | SymConst E -> Const 1.0 182 | Mul (e1, e2) -> simplify_add (Ln e1) (Ln e2) 183 | Div (e1, e2) -> simplify_sub (Ln e1) (Ln e2) 184 | Pow (e, Const c) -> simplify_mul (Const c) (Ln e) 185 | e -> Ln e 186 187and simplify_log base_e arg = 188 match (base_e, arg) with 189 | Const b, Const a when b > 0.0 && b <> 1.0 && a > 0.0 -> 190 Const (log a /. log b) 191 | b, a when Canonical.equal b a -> Const 1.0 192 | Const b, Pow (e, c) when Canonical.equal (Const b) e -> 193 c 194 | _ -> Log (base_e, arg) 195 196and simplify_sqrt = function 197 | Const 0.0 -> Const 0.0 198 | Const 1.0 -> Const 1.0 199 | Const c when c >= 0.0 -> Const (sqrt c) 200 | Pow (e, Const 2.0) -> simplify_abs e 201 | Mul (e1, e2) -> simplify_mul (Sqrt e1) (Sqrt e2) 202 | e -> Sqrt e 203 204and simplify_abs = function 205 | Const c -> Const (abs_float c) 206 | Abs e -> Abs e 207 | Neg e -> Abs e 208 | Mul (Const c, e) -> simplify_mul (Const (abs_float c)) (Abs e) 209 | e -> Abs e 210 211let simplify expr = 212 let rec fixed_point e count = 213 if count >= max_iterations then e 214 else 215 let canonical = Canonical.canonicalize e in 216 let simplified = simplify_once canonical in 217 if Canonical.equal simplified canonical then simplified 218 else fixed_point simplified (count + 1) 219 in 220 fixed_point expr 0