|
1 | 1 | > module Calculus.SyntaxTree where |
2 | 2 |
|
3 | | -> import Calculus.Calculus |
| 3 | +> import Calculus.Calculus as C |
4 | 4 | > import Data.Tree as T |
5 | 5 | > import Data.Tree.Pretty as P |
6 | 6 |
|
7 | | -> -- | Pretty prints expressions as trees |
| 7 | +Pretty prints expressions as trees |
| 8 | + |
8 | 9 | > printExpr :: FunExpr -> IO () |
9 | 10 | > printExpr = putStrLn . drawVerticalTree . makeTree |
10 | 11 |
|
11 | | -> -- | Pretty prints the steps taken when canonifying an expression |
| 12 | +Pretty prints the steps taken when canonifying an expression |
| 13 | + |
12 | 14 | > prettyCan :: FunExpr -> IO () |
13 | 15 | > prettyCan e = |
14 | 16 | > let t = makeTree e |
|
19 | 21 | > putStrLn $ drawVerticalTree t |
20 | 22 | > prettyCan e' |
21 | 23 |
|
22 | | -> -- Possible generalization, make it work on lists of Expr |
23 | | -> -- | Pretty prints syntactic checking of equality |
| 24 | +Pretty prints syntactic checking of equality |
| 25 | + |
24 | 26 | > prettyEqual :: FunExpr -> FunExpr -> IO Bool |
25 | 27 | > prettyEqual e1 e2 = if e1 == e2 then |
26 | 28 | > do |
|
32 | 34 | > putStrLn $ drawVerticalForest [makeTree e1, makeTree e2] |
33 | 35 | > let c1 = canonify e1 |
34 | 36 | > c2 = canonify e2 |
35 | | -> in if c1 == e1 && c2 == e2 then putStrLn "Can't simplify no more" >> return False |
36 | | -> else prettyEqual c1 c2 |
37 | | - |
38 | | -> -- Parse an expression as a Tree of Strings |
39 | | -> makeTree :: FunExpr -> T.Tree String |
40 | | -> makeTree (e1 :+ e2) = T.Node "+" [makeTree e1, makeTree e2] |
41 | | -> makeTree (e1 :- e2) = T.Node "-" [makeTree e1, makeTree e2] |
42 | | -> makeTree (e1 :* e2) = T.Node "*" [makeTree e1, makeTree e2] |
43 | | -> makeTree (e1 :/ e2) = T.Node "Div" [makeTree e1, makeTree e2] |
44 | | -> makeTree (Exp :. e) = T.Node "Exp" [makeTree e] |
45 | | -> makeTree (e1 :. e2) = T.Node "o" [makeTree e1, makeTree e2] |
46 | | -> makeTree Id = T.Node "Id" [] |
47 | | -> --makeTree (Lambda s e) = T.Node ("Lambda " ++ s) [makeTree e] |
48 | | -> --makeTree (Func s) = T.Node s [] |
49 | | -> --makeTree (Delta e) = T.Node "Delta" [makeTree e] |
50 | | -> makeTree (D e) = T.Node "D" [makeTree e] |
51 | | -> --makeTree (e1 :$ e2) = T.Node "$" [makeTree e1, makeTree e2] |
52 | | -> makeTree (Const num) = T.Node (show (floor num)) [] -- | Note the use of floor |
53 | | -> makeTree Exp = T.Node "Exp" [] |
54 | | -> makeTree e = error $ show e |
55 | | - |
56 | | -> -- Staged for removal |
57 | | -> equals :: FunExpr -> FunExpr -> Bool |
58 | | -> -- Addition is commutative |
59 | | -> equals (e1 :+ e2) (e3 :+ e4) = (canonify (e1 :+ e2) == canonify (e3 :+ e4)) || |
60 | | -> (canonify (e1 :+ e2) == canonify (e4 :+ e3)) |
61 | | -> -- | Addition is associative |
62 | | -> -- equals (e1 :+ (e2 :+ e3)) = undefined |
63 | | -> -- Multiplication is commutative |
64 | | -> equals (e1 :* e2) (e3 :* e4) = (canonify (e1 :* e2) == canonify (e3 :* e4)) || |
65 | | -> (canonify (e1 :* e2) == canonify (e4 :* e3)) |
66 | | -> equals e1 e2 = canonify e1 == canonify e2 |
| 37 | +> in if c1 == e1 && c2 == e2 then putStrLn "Can't simplify no more" |
| 38 | +> >> return False |
| 39 | +> else prettyEqual c1 c2 |
| 40 | + |
| 41 | +Syntactic checking of equality |
| 42 | + |
| 43 | +> equal :: FunExpr -> FunExpr -> Bool |
| 44 | +> equal e1 e2 = case e1 == e2 of |
| 45 | +> True -> True |
| 46 | +> False -> let c1 = canonify e1 |
| 47 | +> c2 = canonify e2 |
| 48 | +> in case e1 == c1 && c2 == e2 of |
| 49 | +> True -> False |
| 50 | +> False -> equal c1 c2 |
| 51 | + |
| 52 | +Parse an expression as a Tree of Strings |
| 53 | + |
| 54 | +> makeTree :: FunExpr -> Tree String |
| 55 | +> makeTree (e1 :+ e2) = Node "+" [makeTree e1, makeTree e2] |
| 56 | +> makeTree (e1 :- e2) = Node "-" [makeTree e1, makeTree e2] |
| 57 | +> makeTree (e1 :* e2) = Node "*" [makeTree e1, makeTree e2] |
| 58 | +> makeTree (e1 :/ e2) = Node "Div" [makeTree e1, makeTree e2] |
| 59 | +> makeTree (e1 :^ e2) = Node "**" [makeTree e1, makeTree e2] |
| 60 | +> makeTree (e1 :. e2) = Node "o" [makeTree e1, makeTree e2] |
| 61 | +> makeTree (D e) = Node "d/dx" [makeTree e] |
| 62 | +> makeTree (Delta r e) = Node "Δ" [makeTree (Const r), makeTree e] |
| 63 | +> makeTree (I r e) = Node "I" [makeTree (Const r), makeTree e] |
| 64 | +> makeTree Id = Node "Id" [] |
| 65 | +> makeTree Exp = Node "Exp" [] |
| 66 | +> makeTree Log = Node "Log" [] |
| 67 | +> makeTree Sin = Node "Sin" [] |
| 68 | +> makeTree Cos = Node "Cos" [] |
| 69 | +> makeTree Asin = Node "Asin" [] |
| 70 | +> makeTree Acos = Node "Acos" [] |
| 71 | +> makeTree (Const num) = Node (show (floor num)) [] -- | Note the use of floor |
| 72 | + |
| 73 | +Of course this is all bit too verbose, but I'm keeping it that way until every |
| 74 | +case is covered, Calculus is a bit of a black box for me right now |
67 | 75 |
|
68 | 76 | > canonify :: FunExpr -> FunExpr |
69 | | -> -- | Addition |
70 | | -> -- | e + 0 = e |
| 77 | + |
| 78 | +Addition |
| 79 | + |
71 | 80 | > canonify (e :+ Const 0) = canonify e |
72 | 81 | > canonify (Const 0 :+ e) = canonify e |
73 | | -> -- | Lifting |
74 | 82 | > canonify (Const x :+ Const y) = Const (x + y) |
75 | 83 | > canonify (e1 :+ e2) = canonify e1 :+ canonify e2 |
76 | 84 |
|
77 | | -> -- | Subtraction |
78 | | -> -- | e - 0 = e |
| 85 | +Subtraction |
| 86 | + |
79 | 87 | > canonify (e :- Const 0) = canonify e |
80 | | -> -- | 0 - b = -b |
81 | | -> --canonify (Const 0 :- b) = negate (canonify b) |
82 | | -> -- | Lifting |
83 | 88 | > canonify (Const a :- Const b) = Const (a - b) |
84 | 89 | > canonify (e1 :- e2) = canonify e1 :- canonify e2 |
85 | | -> |
86 | | -> -- | Multiplication |
87 | | -> -- | e * 0 = 0 (Kills the tree immediately) |
| 90 | + |
| 91 | +Multiplication |
| 92 | + |
88 | 93 | > canonify (_ :* Const 0) = Const 0 |
89 | 94 | > canonify (Const 0 :* _) = Const 0 |
90 | | -> -- | e * 1 = e |
91 | 95 | > canonify (e :* Const 1) = canonify e |
92 | 96 | > canonify (Const 1 :* e) = canonify e |
93 | | -> -- | Lifting |
94 | 97 | > canonify (Const a :* Const b) = Const (a * b) |
95 | | -> -- | Propagate |
96 | 98 | > canonify (e1 :* e2) = canonify e1 :* canonify e2 |
97 | | -> |
98 | | -> -- | Division |
| 99 | + |
| 100 | +Division |
| 101 | + |
99 | 102 | > canonify (Const a :/ Const b) = Const (a / b) |
100 | 103 | > canonify (e1 :/ e2) = canonify e1 :/ canonify e2 |
101 | | -> |
102 | | -> -- | Lambda |
103 | | -> --canonify (Lambda p b) = Lambda p (canonify b) |
104 | | -> |
105 | | -> -- | Function |
106 | | -> --canonify (Func string) = Func string |
107 | | -> |
108 | | -> -- | Application |
109 | | -> --canonify (e1 :$ e2) = canonify e1 :$ canonify e2 |
110 | | -> |
111 | | -> -- | Delta |
112 | | -> --canonify (Delta e) = Delta $ canonify e |
113 | | -> |
114 | | -> -- | Derivative |
| 104 | + |
| 105 | +Delta |
| 106 | + |
| 107 | +> canonify (Delta r e) = Delta r $ canonify e |
| 108 | + |
| 109 | +Derivatives |
| 110 | + |
115 | 111 | > canonify (D e) = derive e |
116 | | -> |
117 | | -> -- | Catch all |
118 | | -> canonify (Const x) = Const x |
119 | | -> canonify Id = Id |
| 112 | + |
| 113 | +Composition |
| 114 | + |
120 | 115 | > canonify (e1 :. e2) = canonify e1 :. canonify e2 |
121 | | -> canonify e = error $ show e |
122 | 116 |
|
| 117 | +Catch all |
| 118 | + |
| 119 | +> canonify e = e |
| 120 | + |
| 121 | +"Proofs" |
| 122 | +-------------- |
123 | 123 |
|
124 | | -> -- | "Proofs" |
125 | 124 | > syntacticProofOfComForMultiplication :: FunExpr -> FunExpr -> IO Bool |
126 | 125 | > syntacticProofOfComForMultiplication e1 e2 = prettyEqual (e1 :* e2) (e2 :* e1) |
127 | | -> |
| 126 | + |
128 | 127 | > syntacticProofOfAssocForMultiplication :: FunExpr -> FunExpr -> FunExpr -> IO Bool |
129 | 128 | > syntacticProofOfAssocForMultiplication e1 e2 e3 = prettyEqual (e1 :* (e2 :* e3)) |
130 | 129 | > ((e1 :* e2) :* e3) |
131 | | -> |
| 130 | + |
132 | 131 | > syntacticProofOfDistForMultiplication :: FunExpr -> FunExpr -> FunExpr -> IO Bool |
133 | 132 | > syntacticProofOfDistForMultiplication e1 e2 e3 = prettyEqual (e1 :* (e2 :+ e3)) |
134 | 133 | > ((e1 :* e2) :+ (e1 :* e3)) |
135 | | -> |
| 134 | + |
136 | 135 | > {- syntacticProofOfIdentityForMultiplication :: FunExpr -> IO Bool -} |
137 | 136 | > {- syntacticProofOfIdentityForMultiplication e = -} |
138 | 137 | > {- putStrLn "[*] Checking right identity" >> -} |
139 | 138 | > {- prettyEqual e (1 :* e) >> -} |
140 | 139 | > {- putStrLn "[*] Checking left identity" >> -} |
141 | 140 | > {- prettyEqual e (e :* 1) -} |
142 | | -> |
| 141 | + |
143 | 142 | > {- syntacticProofOfPropertyOf0ForMultiplication :: FunExpr -> IO Bool -} |
144 | 143 | > {- syntacticProofOfPropertyOf0ForMultiplication e = -} |
145 | 144 | > {- prettyEqual (e :* 0) 0 -} |
146 | | -> |
| 145 | + |
147 | 146 | > -- | Fails since default implementation of negate x for Num is 0 - x |
148 | 147 | > {- syntacticProofOfPropertyOfNegationForMultiplication :: FunExpr -> IO Bool -} |
149 | 148 | > {- syntacticProofOfPropertyOfNegationForMultiplication e = -} |
150 | 149 | > {- prettyEqual (Const (-1) :* e) (negate e) -} |
151 | | -> |
| 150 | + |
152 | 151 | > syntacticProofOfComForAddition :: FunExpr -> FunExpr -> IO Bool |
153 | 152 | > syntacticProofOfComForAddition e1 e2 = prettyEqual (e1 :+ e2) (e2 :+ e1) |
154 | | -> |
| 153 | + |
155 | 154 | > syntacticProofOfAssocForAddition :: FunExpr -> FunExpr -> FunExpr -> IO Bool |
156 | 155 | > syntacticProofOfAssocForAddition e1 e2 e3 = prettyEqual (e1 :+ (e2 :+ e3)) |
157 | 156 | > ((e1 :+ e2) :+ e3) |
158 | | -> |
| 157 | + |
159 | 158 | > test :: FunExpr -> FunExpr -> IO Bool |
160 | 159 | > test b c = prettyEqual b (a :* c) |
161 | 160 | > where |
162 | 161 | > a = b :/ c |
163 | | -> |
164 | | -> |
| 162 | + |
| 163 | + |
165 | 164 | > syntacticProofOfIdentityForAddition :: FunExpr -> IO Bool |
166 | 165 | > syntacticProofOfIdentityForAddition e = putStrLn "[*] Checking right identity" >> |
167 | 166 | > prettyEqual e (0 :+ e) >> |
168 | 167 | > putStrLn "[*] Checking left identity" >> |
169 | 168 | > prettyEqual e (e :+ 0) |
170 | | -> |
171 | | -> -- | Dummy expressions |
172 | | -> --eT = D (Func "sin") :+ Func "cos" :$ (Const 2 :+ Const 3) :* (Const 3 :+ Const 2 :* Delta (Const 1 :+ Const 2)) :/ (Const 5 :- (Const 4 :+ Const 8)) :+ Lambda "x" (Const 2) |
| 169 | + |
| 170 | +Dummy expressions |
| 171 | + |
173 | 172 | > e1 = Const 1 |
174 | 173 | > e2 = Const 2 |
175 | 174 | > e3 = Const 3 |
176 | 175 | > e4 = (Const 1 :+ Const 2) :* (Const 3 :+ Const 4) |
177 | 176 | > e5 = (Const 1 :+ Const 2) :* (Const 4 :+ Const 3) |
178 | 177 | > e6 = Const 2 :+ Const 3 :* Const 8 :* Const 19 |
| 178 | +> e7 = (Delta 3 ((Delta (0 - 5) (I 7 Acos)) :. (Acos :* Exp))) |
| 179 | + |
0 commit comments