symbolic mathematics engine in OCaml with differentiation, integration, simplification, and numerical methods
1open OUnit2
2open Leibniz
3
4let test_lexer_basic _ =
5 let tokens = Lexer.tokenize "2 + 3" in
6 assert_equal 4 (List.length tokens)
7
8let test_lexer_implicit_mult _ =
9 let tokens = Lexer.tokenize "2x" in
10 let token_list = List.map (fun t -> t.Lexer.token) tokens in
11 assert_equal 4 (List.length token_list);
12 match token_list with
13 | [Lexer.Num 2.0; Lexer.Star; Lexer.Var "x"; Lexer.EOF] -> ()
14 | _ -> assert_failure "implicit multiplication not working"
15
16let test_parser_basic _ =
17 let expr = Parser.parse "x + 1" in
18 assert_equal (Expr.Add (Expr.Var "x", Expr.Const 1.0)) expr
19
20let test_parser_implicit_mult _ =
21 let expr = Parser.parse "2x" in
22 assert_equal (Expr.Mul (Expr.Const 2.0, Expr.Var "x")) expr
23
24let test_parser_symbolic_constants _ =
25 let expr = Parser.parse "pi" in
26 assert_equal (Expr.SymConst Expr.Pi) expr
27
28let test_simplify_basic _ =
29 let expr = Expr.Add (Expr.Const 0.0, Expr.Var "x") in
30 let result = Simplify.simplify expr in
31 assert_equal (Expr.Var "x") result
32
33let test_simplify_fixed_point _ =
34 let expr = Expr.Add (Expr.Mul (Expr.Const 0.0, Expr.Var "x"), Expr.Var "y") in
35 let result = Simplify.simplify expr in
36 assert_equal (Expr.Var "y") result
37
38let test_simplify_collect_like_terms _ =
39 let expr = Expr.Add (Expr.Var "x", Expr.Var "x") in
40 let result = Simplify.simplify expr in
41 assert_equal (Expr.Mul (Expr.Const 2.0, Expr.Var "x")) result
42
43let test_diff_basic _ =
44 let expr = Expr.Pow (Expr.Var "x", Expr.Const 2.0) in
45 let result = Diff.diff "x" expr in
46 let expected = Simplify.simplify (Expr.Mul (Expr.Const 2.0, Expr.Var "x")) in
47 assert_equal expected result
48
49let test_diff_sin _ =
50 let expr = Expr.Sin (Expr.Var "x") in
51 let result = Diff.diff "x" expr in
52 assert_equal (Expr.Cos (Expr.Var "x")) result
53
54let test_diff_product_rule _ =
55 let expr = Expr.Mul (Expr.Var "x", Expr.Sin (Expr.Var "x")) in
56 let _result = Diff.diff "x" expr in
57 ()
58
59let test_eval_basic _ =
60 let expr = Expr.Add (Expr.Var "x", Expr.Const 1.0) in
61 let result = Eval.eval [("x", 2.0)] expr in
62 assert_equal 3.0 result
63
64let test_eval_symbolic_constants _ =
65 let expr = Expr.SymConst Expr.Pi in
66 let result = Eval.eval [] expr in
67 assert_bool "pi evaluation" (abs_float (result -. 3.14159265) < 0.0001)
68
69let test_canonical_equality _ =
70 let e1 = Expr.Add (Expr.Var "x", Expr.Var "y") in
71 let e2 = Expr.Add (Expr.Var "y", Expr.Var "x") in
72 assert_bool "commutativity" (Canonical.equal e1 e2)
73
74let test_substitute_basic _ =
75 let expr = Expr.Add (Expr.Var "x", Expr.Const 1.0) in
76 let result = Substitute.substitute "x" (Expr.Const 2.0) expr in
77 assert_equal (Expr.Add (Expr.Const 2.0, Expr.Const 1.0)) result
78
79let test_integrate_basic _ =
80 let expr = Expr.Var "x" in
81 match Integrate.integrate "x" expr with
82 | Some result ->
83 let expected = Expr.Div (Expr.Pow (Expr.Var "x", Expr.Const 2.0), Expr.Const 2.0) in
84 assert_bool "integration result not equal" (Canonical.equal expected result)
85 | None -> assert_failure "integration failed"
86
87let test_integrate_sin _ =
88 let expr = Expr.Sin (Expr.Var "x") in
89 match Integrate.integrate "x" expr with
90 | Some result ->
91 assert_equal (Expr.Neg (Expr.Cos (Expr.Var "x"))) result
92 | None -> assert_failure "integration of sin failed"
93
94let test_taylor_sin _ =
95 let expr = Expr.Sin (Expr.Var "x") in
96 let _result = Series.maclaurin "x" expr 5 in
97 ()
98
99let test_gradient_basic _ =
100 let expr = Expr.Add (Expr.Pow (Expr.Var "x", Expr.Const 2.0),
101 Expr.Pow (Expr.Var "y", Expr.Const 2.0)) in
102 let grad = Multivariate.gradient ["x"; "y"] expr in
103 assert_equal 2 (List.length grad)
104
105let test_numerical_bisection _ =
106 let expr = Expr.Sub (Expr.Pow (Expr.Var "x", Expr.Const 2.0), Expr.Const 4.0) in
107 match Numerical.bisection expr "x" 0.0 3.0 0.001 100 with
108 | Some root -> assert_bool "root near 2" (abs_float (root -. 2.0) < 0.01)
109 | None -> assert_failure "bisection failed"
110
111let suite =
112 "leibniz tests" >::: [
113 "lexer basic" >:: test_lexer_basic;
114 "lexer implicit mult" >:: test_lexer_implicit_mult;
115 "parser basic" >:: test_parser_basic;
116 "parser implicit mult" >:: test_parser_implicit_mult;
117 "parser symbolic constants" >:: test_parser_symbolic_constants;
118 "simplify basic" >:: test_simplify_basic;
119 "simplify fixed point" >:: test_simplify_fixed_point;
120 "simplify collect like terms" >:: test_simplify_collect_like_terms;
121 "diff basic" >:: test_diff_basic;
122 "diff sin" >:: test_diff_sin;
123 "diff product rule" >:: test_diff_product_rule;
124 "eval basic" >:: test_eval_basic;
125 "eval symbolic constants" >:: test_eval_symbolic_constants;
126 "canonical equality" >:: test_canonical_equality;
127 "substitute basic" >:: test_substitute_basic;
128 "integrate basic" >:: test_integrate_basic;
129 "integrate sin" >:: test_integrate_sin;
130 "taylor sin" >:: test_taylor_sin;
131 "gradient basic" >:: test_gradient_basic;
132 "numerical bisection" >:: test_numerical_bisection;
133 ]
134
135let () = run_test_tt_main suite