UNPKG

4.55 kBtext/coffeescriptView Raw
1# Evaluate a user defined function
2
3
4#define F p3 # F is the function body
5#define A p4 # A is the formal argument list
6#define B p5 # B is the calling argument list
7#define S p6 # S is the argument substitution list
8
9# we got here because there was a function invocation and
10# it's not been parsed (and consequently tagged) as any
11# system function.
12# So we are dealing with another function.
13# The function could be actually defined, or not yet,
14# so we'll deal with both cases.
15
16### d =====================================================================
17
18Tags
19----
20scripting, JS, internal, treenode, general concept
21
22Parameters
23----------
24f,x
25
26General description
27-------------------
28Returns the partial derivative of f with respect to x. x can be a vector e.g. [x,y].
29
30###
31
32Eval_user_function = ->
33
34 # Use "derivative" instead of "d" if there is no user function "d"
35
36 if DEBUG then console.log "Eval_user_function evaluating: " + car(p1)
37 if (car(p1) == symbol(SYMBOL_D) && get_binding(symbol(SYMBOL_D)) == symbol(SYMBOL_D))
38 Eval_derivative()
39 return
40
41 # normally car(p1) is a symbol with the function name
42 # but it could be something that has to be
43 # evaluated to get to the function definition instead
44 # (e.g. the function is an element of an array)
45 # so we do an eval to sort it all out.
46 push(car(p1))
47 Eval()
48
49 # we expect to find either the body and
50 # formula arguments, OR, if the function
51 # has not been defined yet, then the
52 # function will just contain its own name, as
53 # all undefined variables do.
54 bodyAndFormalArguments = pop()
55
56 p3 = car(cdr(bodyAndFormalArguments)) # p3 is function body F
57 # p4 is the formal argument list
58 # that is also contained here in the FUNCTION node
59 p4 = car(cdr(cdr(bodyAndFormalArguments)))
60
61 p5 = cdr(p1); # p5 is B
62
63 # example:
64 # f(x) = x+2
65 # then:
66 # p3.toString() = "x + 2"
67 # p4 = x
68 # p5 = 2
69
70 # Undefined function?
71 if (bodyAndFormalArguments == car(p1)) # p3 is F
72 h = tos
73 push(bodyAndFormalArguments); # p3 is F
74 p1 = p5; # p5 is B
75 while (iscons(p1))
76 push(car(p1))
77 Eval()
78 p1 = cdr(p1)
79 list(tos - h)
80 return
81
82 # Create the argument substitution list p6(S)
83
84 p1 = p4; # p4 is A
85 p2 = p5; # p5 is B
86 h = tos
87 while (iscons(p1) && iscons(p2))
88 push(car(p1))
89 push(car(p2))
90 # why explicitly Eval the parameters when
91 # the body of the function is
92 # evalled anyways? Commenting it out. All tests pass...
93 #Eval()
94 p1 = cdr(p1)
95 p2 = cdr(p2)
96
97 list(tos - h)
98 p6 = pop(); # p6 is S
99
100 # Evaluate the function body
101
102 push(p3); # p3 is F
103 if (iscons(p6)) # p6 is S
104 push(p6); # p6 is S
105 rewrite_args()
106 #console.log "rewritten body: " + stack[tos-1]
107 Eval()
108
109# Rewrite by expanding symbols that contain args
110
111rewrite_args = ->
112 n = 0
113 save()
114
115 # subst. list which is a list
116 # where each consecutive pair
117 # is what needs to be substituted and with what
118 p2 = pop();
119 #console.log "subst. list " + p2
120
121 # expr to substitute in i.e. the
122 # function body
123 p1 = pop();
124 #console.log "expr: " + p1
125
126 if (istensor(p1))
127 n = rewrite_args_tensor()
128 restore()
129 return n
130
131 if (iscons(p1))
132 h = tos
133 if (car(p1) == car(p2))
134 # rewrite a function in
135 # the body with the one
136 # passed from the paramaters
137 push_symbol(EVAL)
138 push(car(cdr(p2)));
139 list(2)
140 else
141 # if there is no match
142 # then no substitution necessary
143 push(car(p1));
144
145 # continue recursively to
146 # rewrite the rest of the body
147 p1 = cdr(p1)
148 while (iscons(p1))
149 push(car(p1))
150 push(p2)
151 n += rewrite_args()
152 p1 = cdr(p1)
153 list(tos - h)
154 restore()
155 return n
156
157 # ground cases here
158 # (apart from function name which has
159 # already been substituted as it's in the head
160 # of the cons)
161 # -----------------
162
163 # If not a symbol then no
164 # substitution to be done
165 if (!issymbol(p1))
166 push(p1)
167 restore()
168 return 0
169
170 # Here we are in a symbol case
171 # so we need to substitute
172
173 # Check if there is a direct match
174 # of symbols right away
175 p3 = p2
176 while (iscons(p3))
177 if (p1 == car(p3))
178 push(cadr(p3))
179 restore()
180 return 1
181 p3 = cddr(p3)
182
183 # Get the symbol's content, if _that_
184 # matches then do the substitution
185 p3 = get_binding(p1)
186 push(p3)
187 if (p1 != p3)
188 push(p2); # subst. list
189 n = rewrite_args()
190 if (n == 0)
191 pop()
192 push(p1); # restore if not rewritten with arg
193
194 restore()
195 return n
196
197rewrite_args_tensor = ->
198 n = 0
199 i = 0
200 push(p1)
201 copy_tensor()
202 p1 = pop()
203 for i in [0...p1.tensor.nelem]
204 push(p1.tensor.elem[i])
205 push(p2)
206 n += rewrite_args()
207 p1.tensor.elem[i] = pop()
208
209 check_tensor_dimensions p1
210
211 push(p1)
212 return n