UNPKG

4.02 kBtext/coffeescriptView Raw
1### det =====================================================================
2
3Tags
4----
5scripting, JS, internal, treenode, general concept
6
7Parameters
8----------
9m
10
11General description
12-------------------
13Returns the determinant of matrix m.
14Uses Gaussian elimination for numerical matrices.
15
16Example:
17
18 det(((1,2),(3,4)))
19 > -2
20
21###
22
23
24DET_check_arg = ->
25 if (!istensor(p1))
26 return 0
27 else if (p1.tensor.ndim != 2)
28 return 0
29 else if (p1.tensor.dim[0] != p1.tensor.dim[1])
30 return 0
31 else
32 return 1
33
34det = ->
35 i = 0
36 n = 0
37 #U **a
38
39 save()
40
41 p1 = pop()
42
43 if (DET_check_arg() == 0)
44 push_symbol(DET)
45 push(p1)
46 list(2)
47 restore()
48 return
49
50 n = p1.tensor.nelem
51
52 a = p1.tensor.elem
53
54 for i in [0...n]
55 if (!isnum(a[i]))
56 break
57
58 if (i == n)
59 yydetg()
60 else
61 for i in [0...p1.tensor.nelem]
62 push(p1.tensor.elem[i])
63 determinant(p1.tensor.dim[0])
64
65 restore()
66
67# determinant of n * n matrix elements on the stack
68
69determinant = (n) ->
70 h = 0
71 i = 0
72 j = 0
73 k = 0
74 q = 0
75 s = 0
76 sign_ = 0
77 t = 0
78
79 a = []
80 #int *a, *c, *d
81
82 h = tos - n * n
83
84 #a = (int *) malloc(3 * n * sizeof (int))
85
86 #if (a == NULL)
87 # out_of_memory()
88
89 for i in [0...n]
90 a[i] = i
91 a[i+n] = 0
92 a[i+n+n] = 1
93
94 sign_ = 1
95
96 push(zero)
97
98 while 1
99
100 if (sign_ == 1)
101 push_integer(1)
102 else
103 push_integer(-1)
104
105 for i in [0...n]
106 k = n * a[i] + i
107 push(stack[h + k])
108 multiply(); # FIXME -- problem here
109
110 add()
111
112 # next permutation (Knuth's algorithm P)
113
114 j = n - 1
115 s = 0
116
117 breakFromOutherWhile = false
118 while 1
119 q = a[n+j] + a[n+n+j]
120 if (q < 0)
121 a[n+n+j] = -a[n+n+j]
122 j--
123 continue
124 if (q == j + 1)
125 if (j == 0)
126 breakFromOutherWhile = true
127 break
128 s++
129 a[n+n+j] = -a[n+n+j]
130 j--
131 continue
132 break
133
134 if breakFromOutherWhile
135 break
136
137 t = a[j - a[n+j] + s]
138 a[j - a[n+j] + s] = a[j - q + s]
139 a[j - q + s] = t
140 a[n+j] = q
141
142 sign_ = -sign_
143
144
145 stack[h] = stack[tos - 1]
146
147 moveTos h + 1
148
149#-----------------------------------------------------------------------------
150#
151# Input: Matrix on stack
152#
153# Output: Determinant on stack
154#
155# Note:
156#
157# Uses Gaussian elimination which is faster for numerical matrices.
158#
159# Gaussian Elimination works by walking down the diagonal and clearing
160# out the columns below it.
161#
162#-----------------------------------------------------------------------------
163
164detg = ->
165 save()
166
167 p1 = pop()
168
169 if (DET_check_arg() == 0)
170 push_symbol(DET)
171 push(p1)
172 list(2)
173 restore()
174 return
175
176 yydetg()
177
178 restore()
179
180yydetg = ->
181 i = 0
182 n = 0
183
184 n = p1.tensor.dim[0]
185
186 for i in [0...(n * n)]
187 push(p1.tensor.elem[i])
188
189 lu_decomp(n)
190
191 moveTos tos - n * n
192
193 push(p1)
194
195#-----------------------------------------------------------------------------
196#
197# Input: n * n matrix elements on stack
198#
199# Output: p1 determinant
200#
201# p2 mangled
202#
203# upper diagonal matrix on stack
204#
205#-----------------------------------------------------------------------------
206
207M = (h,n,i, j) ->
208 stack[h + n * (i) + (j)]
209
210setM = (h,n,i,j,value) ->
211 stack[h + n * (i) + (j)] = value
212
213lu_decomp = (n) ->
214 d = 0
215 h = 0
216 i = 0
217 j = 0
218
219 h = tos - n * n
220
221 p1 = one
222
223 for d in [0...(n - 1)]
224
225 # diagonal element zero?
226
227 if (equal(M(h,n,d, d), zero))
228
229 # find a new row
230
231 for i in [(d + 1)...n]
232 if (!equal(M(h,n,i, d), zero))
233 break
234
235 if (i == n)
236 p1 = zero
237 break
238
239 # exchange rows
240
241 for j in [d...n]
242 p2 = M(h,n,d, j)
243 setM(h,n,d, j, M(h,n,i, j))
244 setM(h,n,i, j, p2)
245
246 # negate det
247
248 push(p1)
249 negate()
250 p1 = pop()
251
252 # update det
253
254 push(p1)
255 push(M(h,n,d, d))
256 multiply()
257 p1 = pop()
258
259 # update lower diagonal matrix
260
261 for i in [(d + 1)...n]
262
263 # multiplier
264
265 push(M(h,n,i, d))
266 push(M(h,n,d, d))
267 divide()
268 negate()
269
270 p2 = pop()
271
272 # update one row
273
274 setM(h,n,i, d, zero); # clear column below pivot d
275
276 for j in [(d + 1)...n]
277 push(M(h,n,d, j))
278 push(p2)
279 multiply()
280 push(M(h,n,i, j))
281 add()
282 setM(h,n,i, j, pop())
283
284 # last diagonal element
285
286 push(p1)
287 push(M(h,n,n - 1, n - 1))
288 multiply()
289 p1 = pop()