UNPKG

7.91 kBtext/coffeescriptView Raw
1###
2Transform an expression using a pattern. The
3pattern can come from the integrals table or
4the user-defined patterns.
5
6The expression and free variable are on the stack.
7
8The argument s is a null terminated list of transform rules.
9
10For example, see the itab (integrals table)
11
12Internally, the following symbols are used:
13
14 F input expression
15
16 X free variable, i.e. F of X
17
18 A template expression
19
20 B result expression
21
22 C list of conditional expressions
23
24Puts the final expression on top of stack
25(whether it's transformed or not) and returns
26true is successful, false if not.
27
28
29###
30
31
32
33# p1 and p2 are tmps
34
35#define F p3
36#define X p4
37#define A p5
38#define B p6
39#define C p7
40
41transform = (s, generalTransform) ->
42 transform_h = 0
43
44 save()
45
46 p1 = null
47
48 p4 = pop() # X i.e. free variable
49 p3 = pop() # F i.e. input expression
50
51 if DEBUG
52 console.log " !!!!!!!!! transform on: " + p3
53
54
55 saveMetaBindings()
56
57 set_binding(symbol(METAX), p4)
58
59 # put constants in F(X) on the stack
60
61 transform_h = tos
62 push_integer(1)
63 push(p3)
64 push(p4)
65 polyform(); # collect coefficients of x, x^2, etc.
66 push(p4)
67
68 bookmarkTosToPrintDecomps = tos - 2
69 decomp(generalTransform)
70 numberOfDecomps = tos - bookmarkTosToPrintDecomps
71
72 if DEBUG
73 console.log " " + numberOfDecomps + " decomposed elements ====== "
74 for i in [0...numberOfDecomps]
75 console.log " decomposition element " + i + ": " + stack[tos-1-i]
76
77 transformationSuccessful = false
78
79 if generalTransform
80 # "general tranform" mode is supposed to be more generic than
81 # "integrals" mode.
82 # In general transform mode we get only one transformation
83 # in s
84
85 # simple numbers can end up matching complicated templates,
86 # which we don't want.
87 # for example "1" ends up matching "inner(transpose(a_),a_)"
88 # since "1" is decomposed to "1" and replacing "a_" with "1"
89 # there is a match.
90 # Although this match is OK at some fundamental level, we want to
91 # avoid it because that's not what the spirit of this match
92 # is: "1" does not have any structural resemblance with
93 # "inner(transpose(a_),a_)". There are probably better ways
94 # to so this, for example we might notice that "inner" is an
95 # anchor since it "sits above" any meta variables, so we
96 # might want to mandate it to be matched at the top
97 # of the tree. For the time
98 # being let's just skip matching on simple numbers.
99 if !isnum(p3)
100
101 theTransform = s
102 if DEBUG then console.log "applying transform: " + theTransform
103 if DEBUG then console.log "scanning table entry " + theTransform
104
105 push theTransform
106
107 # replacements of meta variables. Note that we don't
108 # use scan_meta because the pattern is not a string
109 # that we have to parse, it's a tree already.
110 # replace a_ with METAA in the passed transformation
111 push symbol(SYMBOL_A_UNDERSCORE)
112 push symbol(METAA)
113 subst()
114
115 # replace b_ with METAB in the passed transformation
116 push symbol(SYMBOL_B_UNDERSCORE)
117 push symbol(METAB)
118 subst()
119
120 # replace x_ with METAX in the passed transformation
121 push symbol(SYMBOL_X_UNDERSCORE)
122 push symbol(METAX)
123 subst()
124
125 p1 = pop()
126
127 p5 = car(p1)
128 if DEBUG then console.log "template expression: " + p5
129 p6 = cadr(p1)
130 p7 = cddr(p1)
131
132 ###
133 p5 = p1.tensor.elem[0]
134 p6 = p1.tensor.elem[1]
135 for i in [2..(p1.tensor.elem.length-1)]
136 push p1.tensor.elem[i]
137 list(p1.tensor.elem.length - 2)
138 p7 = pop()
139 ###
140
141
142
143 if (f_equals_a(transform_h, generalTransform))
144 # successful transformation,
145 # transformed result is in p6
146 transformationSuccessful = true
147 else
148 # the match failed but perhaps we can match
149 # something lower down in the tree, so
150 # let's recurse the tree
151
152 if DEBUG then console.log "p3 at this point: " + p3
153
154 transformedTerms = []
155
156 if DEBUG then console.log "car(p3): " + car(p3)
157 restTerm = p3
158
159 if iscons(restTerm)
160 transformedTerms.push car(p3)
161 restTerm = cdr(p3)
162
163 while (iscons(restTerm))
164 secondTerm = car(restTerm)
165 restTerm = cdr(restTerm)
166
167 if DEBUG then console.log "tos before recursive transform: " + tos
168
169 push(secondTerm)
170 push_symbol(NIL)
171 if DEBUG then console.log "testing: " + secondTerm
172 #if (secondTerm+"") == "eig(A x,transpose(A x))()"
173 # debugger
174 if DEBUG then console.log "about to try to simplify other term: " + secondTerm
175 success = transform(s, generalTransform)
176 transformationSuccessful = transformationSuccessful or success
177
178 transformedTerms.push pop()
179
180 if DEBUG then console.log "tried to simplify other term: " + secondTerm + " ...successful?: " + success + " ...transformed: " + transformedTerms[transformedTerms.length-1]
181
182
183 # recreate the tree we were passed,
184 # but with all the terms being transformed
185 if transformedTerms.length != 0
186 for i in transformedTerms
187 push i
188 list(transformedTerms.length)
189 p6 = pop()
190
191
192
193 else # "integrals" mode
194 for eachTransformEntry in s
195 if DEBUG
196 console.log "scanning table entry " + eachTransformEntry
197 if (eachTransformEntry + "").indexOf("f(sqrt(a+b*x),2/3*1/b*sqrt((a+b*x)^3))") != -1
198 debugger
199 if eachTransformEntry
200 scan_meta(eachTransformEntry)
201 p1 = pop()
202
203 p5 = cadr(p1)
204 p6 = caddr(p1)
205 p7 = cdddr(p1)
206
207 ###
208 p5 = p1.tensor.elem[0]
209 p6 = p1.tensor.elem[1]
210 for i in [2..(p1.tensor.elem.length-1)]
211 push p1.tensor.elem[i]
212 list(p1.tensor.elem.length - 2)
213 p7 = pop()
214 ###
215
216
217 if (f_equals_a(transform_h, generalTransform))
218 # there is a successful transformation,
219 # transformed result is in p6
220 transformationSuccessful = true
221 break
222
223
224
225
226 moveTos transform_h
227
228
229 if transformationSuccessful
230 #console.log "transformation successful"
231 # a transformation was successful
232 push(p6)
233 Eval()
234 p1 = pop()
235 #console.log "...into: " + p1
236 transformationSuccessful = true
237 else
238 # transformations failed
239 if generalTransform
240 # result = original expression
241 p1 = p3
242 else
243 p1 = symbol(NIL)
244
245 restoreMetaBindings()
246
247 push(p1)
248
249 restore()
250 return transformationSuccessful
251
252saveMetaBindings = ->
253 push(get_binding(symbol(METAA)))
254 push(get_binding(symbol(METAB)))
255 push(get_binding(symbol(METAX)))
256
257
258restoreMetaBindings = ->
259 set_binding(symbol(METAX), pop())
260 set_binding(symbol(METAB), pop())
261 set_binding(symbol(METAA), pop())
262
263# search for a METAA and METAB such that F = A
264
265f_equals_a = (h, generalTransform) ->
266 fea_i = 0
267 fea_j = 0
268 for fea_i in [h...tos]
269
270 set_binding(symbol(METAA), stack[fea_i])
271 if DEBUG
272 console.log " binding METAA to " + get_binding(symbol(METAA))
273 for fea_j in [h...tos]
274
275 set_binding(symbol(METAB), stack[fea_j])
276 if DEBUG
277 console.log " binding METAB to " + get_binding(symbol(METAB))
278
279 # now test all the conditions (it's an and between them)
280 p1 = p7
281 while (iscons(p1))
282 push(car(p1))
283 Eval()
284 p2 = pop()
285 if (iszero(p2))
286 break
287 p1 = cdr(p1)
288
289 if (iscons(p1))
290 # conditions are not met,
291 # skip to the next binding of metas
292 continue
293 push(p3); # F = A?
294 if DEBUG
295 console.log "about to evaluate template expression: " + p5 +
296 " binding METAA to " + get_binding(symbol(METAA)) +
297 " and binding METAB to " + get_binding(symbol(METAB)) +
298 " and binding METAX to " + get_binding(symbol(METAX))
299 push(p5)
300 if generalTransform
301 originalexpanding = expanding
302 expanding = false
303 Eval()
304 if generalTransform
305 expanding = originalexpanding
306 if DEBUG
307 console.log " comparing " + stack[tos-1] + " to: " + stack[tos-2]
308 subtract()
309 p1 = pop()
310 if (iszero(p1))
311 if DEBUG
312 console.log "binding METAA to " + get_binding(symbol(METAA))
313 console.log "binding METAB to " + get_binding(symbol(METAB))
314 console.log "binding METAX to " + get_binding(symbol(METAX))
315 console.log "comparing " + p3 + " to: " + p5
316 return 1; # yes
317 return 0; # no