1 /**
2 @file gsl.c
3 @author J. Marcel van der Veer.
4 @brief Vector, matrix and FFT support through GSL.
5 
6 @section Copyright
7 
8 This file is part of Algol68G - an Algol 68 interpreter.
9 Copyright 2001-2016 J. Marcel van der Veer <algol68g@xs4all.nl>.
10 
11 @section Description
12 
13 This program is free software; you can redistribute it and/or modify it under
14 the terms of the GNU General Public License as published by the Free Software
15 Foundation; either version 3 of the License, or (at your option) any later
16 version.
17 
18 This program is distributed in the hope that it will be useful, but WITHOUT ANY
19 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
20 PARTICULAR PURPOSE. See the GNU General Public License for more details.
21 
22 You should have received a copy of the GNU General Public License along with
23 this program. If not, see <http://www.gnu.org/licenses/>.
24 **/
25 
26 #include "a68g.h"
27 
28 #if defined HAVE_GNU_GSL
29 
30 static NODE_T *error_node = NO_NODE;
31 
32 #define VECTOR_OFFSET(a, t)\
33   ((LWB (t) * SPAN (t) - SHIFT (t) + SLICE_OFFSET (a)) * ELEM_SIZE (a) + FIELD_OFFSET (a))
34 
35 #define MATRIX_OFFSET(a, t1, t2)\
36   ((LWB (t1) * SPAN (t1) - SHIFT (t1) + LWB (t2) * SPAN (t2) - SHIFT (t2) + SLICE_OFFSET (a)) * ELEM_SIZE (a) + FIELD_OFFSET (a))
37 
38 /**
39 @brief Set permutation vector element - function fails in gsl.
40 @param p Permutation vector.
41 @param i Element iindex.
42 @param j Element value.
43 **/
44 
45 void
gsl_permutation_set(const gsl_permutation * p,const size_t i,const size_t j)46 gsl_permutation_set (const gsl_permutation * p, const size_t i, const size_t j)
47 {
48   DATA (p)[i] = j;
49 }
50 
51 /**
52 @brief Map GSL error handler onto a68g error handler.
53 @param reason Error text.
54 @param file Gsl file where error occured.
55 @param line Line in above file.
56 @param gsl_errno Gsl error number.
57 **/
58 
59 void
torrix_error_handler(const char * reason,const char * file,int line,int gsl_errno)60 torrix_error_handler (const char *reason, const char *file, int line, int gsl_errno)
61 {
62   if (line != 0) {
63     ASSERT (snprintf (edit_line, SNPRINTF_SIZE, "%s in line %d of file %s", reason, line, file) >= 0);
64   } else {
65     ASSERT (snprintf (edit_line, SNPRINTF_SIZE, "%s", reason) >= 0);
66   }
67   diagnostic_node (A68_RUNTIME_ERROR, error_node, ERROR_TORRIX, edit_line, gsl_strerror (gsl_errno));
68   exit_genie (error_node, A68_RUNTIME_ERROR);
69 }
70 
71 /**
72 @brief Detect math errors, mainly in BLAS functions.
73 @param rc Return code from function.
74 **/
75 
76 static void
torrix_test_error(int rc)77 torrix_test_error (int rc)
78 {
79   if (rc != 0) {
80     torrix_error_handler ("math error", "", 0, rc);
81   }
82 }
83 
84 /**
85 @brief Pop [] INT on the stack as gsl_permutation.
86 @param p Node in syntax tree.
87 @param get Whether to get elements from row in the stack.
88 @return Gsl_permutation_complex.
89 **/
90 
91 static gsl_permutation *
pop_permutation(NODE_T * p,BOOL_T get)92 pop_permutation (NODE_T * p, BOOL_T get)
93 {
94   A68_REF desc;
95   A68_ARRAY *arr;
96   A68_TUPLE *tup;
97   int len, inc, iindex, k;
98   BYTE_T *base;
99   gsl_permutation *v;
100 /* Pop arguments */
101   POP_REF (p, &desc);
102   CHECK_REF (p, desc, MODE (ROW_INT));
103   GET_DESCRIPTOR (arr, tup, &desc);
104   len = ROW_SIZE (tup);
105   v = gsl_permutation_alloc ((size_t) len);
106   if (get && len > 0) {
107     base = DEREF (BYTE_T, &ARRAY (arr));
108     iindex = VECTOR_OFFSET (arr, tup);
109     inc = SPAN (tup) * ELEM_SIZE (arr);
110     for (k = 0; k < len; k++, iindex += inc) {
111       A68_INT *x = (A68_INT *) (base + iindex);
112       CHECK_INIT (p, INITIALISED (x), MODE (INT));
113       gsl_permutation_set (v, (size_t) k, (size_t) VALUE (x));
114     }
115   }
116   return (v);
117 }
118 
119 /**
120 @brief Push gsl_permutation on the stack as [] INT.
121 @param p Node in syntax tree.
122 @param v Permutation.
123 **/
124 
125 static void
push_permutation(NODE_T * p,gsl_permutation * v)126 push_permutation (NODE_T * p, gsl_permutation * v)
127 {
128   A68_REF desc, row;
129   A68_ARRAY arr;
130   A68_TUPLE tup;
131   int len, inc, iindex, k;
132   BYTE_T *base;
133   len = (int) (SIZE (v));
134   desc = heap_generator (p, MODE (ROW_INT), SIZE_AL (A68_ARRAY) + SIZE_AL (A68_TUPLE));
135   row = heap_generator (p, MODE (ROW_INT), len * SIZE (MODE (INT)));
136   DIM (&arr) = 1;
137   MOID (&arr) = MODE (INT);
138   ELEM_SIZE (&arr) = SIZE (MODE (INT));
139   SLICE_OFFSET (&arr) = FIELD_OFFSET (&arr) = 0;
140   ARRAY (&arr) = row;
141   LWB (&tup) = 1;
142   UPB (&tup) = len;
143   SPAN (&tup) = 1;
144   SHIFT (&tup) = LWB (&tup);
145   K (&tup) = 0;
146   PUT_DESCRIPTOR (arr, tup, &desc);
147   base = DEREF (BYTE_T, &ARRAY (&arr));
148   iindex = VECTOR_OFFSET (&arr, &tup);
149   inc = SPAN (&tup) * ELEM_SIZE (&arr);
150   for (k = 0; k < len; k++, iindex += inc) {
151     A68_INT *x = (A68_INT *) (base + iindex);
152     STATUS (x) = INIT_MASK;
153     VALUE (x) = (int) gsl_permutation_get (v, (size_t) k);
154   }
155   PUSH_REF (p, desc);
156 }
157 
158 /**
159 @brief Pop [] REAL on the stack as gsl_vector.
160 @param p Node in syntax tree.
161 @param get Whether to get elements from row in the stack.
162 @return Gsl_vector_complex.
163 **/
164 
165 static gsl_vector *
pop_vector(NODE_T * p,BOOL_T get)166 pop_vector (NODE_T * p, BOOL_T get)
167 {
168   A68_REF desc;
169   A68_ARRAY *arr;
170   A68_TUPLE *tup;
171   int len, inc, iindex, k;
172   BYTE_T *base;
173   gsl_vector *v;
174 /* Pop arguments */
175   POP_REF (p, &desc);
176   CHECK_REF (p, desc, MODE (ROW_REAL));
177   GET_DESCRIPTOR (arr, tup, &desc);
178   len = ROW_SIZE (tup);
179   v = gsl_vector_alloc ((size_t) len);
180   if (get && len > 0) {
181     base = DEREF (BYTE_T, &ARRAY (arr));
182     iindex = VECTOR_OFFSET (arr, tup);
183     inc = SPAN (tup) * ELEM_SIZE (arr);
184     for (k = 0; k < len; k++, iindex += inc) {
185       A68_REAL *x = (A68_REAL *) (base + iindex);
186       CHECK_INIT (p, INITIALISED (x), MODE (REAL));
187       gsl_vector_set (v, (size_t) k, VALUE (x));
188     }
189   }
190   return (v);
191 }
192 
193 /**
194 @brief Push gsl_vector on the stack as [] REAL.
195 @param p Node in syntax tree.
196 @param v Vector.
197 **/
198 
199 static void
push_vector(NODE_T * p,gsl_vector * v)200 push_vector (NODE_T * p, gsl_vector * v)
201 {
202   A68_REF desc, row;
203   A68_ARRAY arr;
204   A68_TUPLE tup;
205   int len, inc, iindex, k;
206   BYTE_T *base;
207   len = (int) (SIZE (v));
208   desc = heap_generator (p, MODE (ROW_REAL), SIZE_AL (A68_ARRAY) + SIZE_AL (A68_TUPLE));
209   row = heap_generator (p, MODE (ROW_REAL), len * SIZE (MODE (REAL)));
210   DIM (&arr) = 1;
211   MOID (&arr) = MODE (REAL);
212   ELEM_SIZE (&arr) = SIZE (MODE (REAL));
213   SLICE_OFFSET (&arr) = FIELD_OFFSET (&arr) = 0;
214   ARRAY (&arr) = row;
215   LWB (&tup) = 1;
216   UPB (&tup) = len;
217   SPAN (&tup) = 1;
218   SHIFT (&tup) = LWB (&tup);
219   K (&tup) = 0;
220   PUT_DESCRIPTOR (arr, tup, &desc);
221   base = DEREF (BYTE_T, &ARRAY (&arr));
222   iindex = VECTOR_OFFSET (&arr, &tup);
223   inc = SPAN (&tup) * ELEM_SIZE (&arr);
224   for (k = 0; k < len; k++, iindex += inc) {
225     A68_REAL *x = (A68_REAL *) (base + iindex);
226     STATUS (x) = INIT_MASK;
227     VALUE (x) = gsl_vector_get (v, (size_t) k);
228     CHECK_REAL_REPRESENTATION (p, VALUE (x));
229   }
230   PUSH_REF (p, desc);
231 }
232 
233 /**
234 @brief Pop [,] REAL on the stack as gsl_matrix.
235 @param p Node in syntax tree.
236 @param get Whether to get elements from row in the stack.
237 @return Gsl_matrix.
238 **/
239 
240 static gsl_matrix *
pop_matrix(NODE_T * p,BOOL_T get)241 pop_matrix (NODE_T * p, BOOL_T get)
242 {
243   A68_REF desc;
244   A68_ARRAY *arr;
245   A68_TUPLE *tup1, *tup2;
246   int len1, len2, inc1, inc2, iindex1, iindex2, k1, k2;
247   BYTE_T *base;
248   gsl_matrix *a;
249 /* Pop arguments */
250   POP_REF (p, &desc);
251   CHECK_REF (p, desc, MODE (ROWROW_REAL));
252   GET_DESCRIPTOR (arr, tup1, &desc);
253   tup2 = &(tup1[1]);
254   len1 = ROW_SIZE (tup1);
255   len2 = ROW_SIZE (tup2);
256   a = gsl_matrix_alloc ((size_t) len1, (size_t) len2);
257   if (get && (len1 * len2 > 0)) {
258     base = DEREF (BYTE_T, &ARRAY (arr));
259     iindex1 = MATRIX_OFFSET (arr, tup1, tup2);
260     inc1 = SPAN (tup1) * ELEM_SIZE (arr);
261     inc2 = SPAN (tup2) * ELEM_SIZE (arr);
262     for (k1 = 0; k1 < len1; k1++, iindex1 += inc1) {
263       for (k2 = 0, iindex2 = iindex1; k2 < len2; k2++, iindex2 += inc2) {
264         A68_REAL *x = (A68_REAL *) (base + iindex2);
265         CHECK_INIT (p, INITIALISED (x), MODE (REAL));
266         gsl_matrix_set (a, (size_t) k1, (size_t) k2, VALUE (x));
267       }
268     }
269   }
270   return (a);
271 }
272 
273 /**
274 @brief Push gsl_matrix on the stack as [,] REAL.
275 @param p Node in syntax tree.
276 @param a Matrix.
277 **/
278 
279 static void
push_matrix(NODE_T * p,gsl_matrix * a)280 push_matrix (NODE_T * p, gsl_matrix * a)
281 {
282   A68_REF desc, row;
283   A68_ARRAY arr;
284   A68_TUPLE tup1, tup2;
285   int len1, len2, inc1, inc2, iindex1, iindex2, k1, k2;
286   BYTE_T *base;
287   len1 = (int) (SIZE1 (a));
288   len2 = (int) (SIZE2 (a));
289   desc = heap_generator (p, MODE (ROWROW_REAL), SIZE_AL (A68_ARRAY) + 2 * SIZE_AL (A68_TUPLE));
290   row = heap_generator (p, MODE (ROWROW_REAL), len1 * len2 * SIZE (MODE (REAL)));
291   DIM (&arr) = 2;
292   MOID (&arr) = MODE (REAL);
293   ELEM_SIZE (&arr) = SIZE (MODE (REAL));
294   SLICE_OFFSET (&arr) = FIELD_OFFSET (&arr) = 0;
295   ARRAY (&arr) = row;
296   LWB (&tup1) = 1;
297   UPB (&tup1) = len1;
298   SPAN (&tup1) = 1;
299   SHIFT (&tup1) = LWB (&tup1);
300   K (&tup1) = 0;
301   LWB (&tup2) = 1;
302   UPB (&tup2) = len2;
303   SPAN (&tup2) = ROW_SIZE (&tup1);
304   SHIFT (&tup2) = LWB (&tup2) * SPAN (&tup2);
305   K (&tup2) = 0;
306   PUT_DESCRIPTOR2 (arr, tup1, tup2, &desc);
307   base = DEREF (BYTE_T, &ARRAY (&arr));
308   iindex1 = MATRIX_OFFSET (&arr, &tup1, &tup2);
309   inc1 = SPAN (&tup1) * ELEM_SIZE (&arr);
310   inc2 = SPAN (&tup2) * ELEM_SIZE (&arr);
311   for (k1 = 0; k1 < len1; k1++, iindex1 += inc1) {
312     for (k2 = 0, iindex2 = iindex1; k2 < len2; k2++, iindex2 += inc2) {
313       A68_REAL *x = (A68_REAL *) (base + iindex2);
314       STATUS (x) = INIT_MASK;
315       VALUE (x) = gsl_matrix_get (a, (size_t) k1, (size_t) k2);
316       CHECK_REAL_REPRESENTATION (p, VALUE (x));
317     }
318   }
319   PUSH_REF (p, desc);
320 }
321 
322 /**
323 @brief Pop [] COMPLEX on the stack as gsl_vector_complex.
324 @param p Node in syntax tree.
325 @param get Whether to get elements from row in the stack.
326 @return Gsl_vector_complex.
327 **/
328 
329 static gsl_vector_complex *
pop_vector_complex(NODE_T * p,BOOL_T get)330 pop_vector_complex (NODE_T * p, BOOL_T get)
331 {
332   A68_REF desc;
333   A68_ARRAY *arr;
334   A68_TUPLE *tup;
335   int len, inc, iindex, k;
336   BYTE_T *base;
337   gsl_vector_complex *v;
338 /* Pop arguments */
339   POP_REF (p, &desc);
340   CHECK_REF (p, desc, MODE (ROW_COMPLEX));
341   GET_DESCRIPTOR (arr, tup, &desc);
342   len = ROW_SIZE (tup);
343   v = gsl_vector_complex_alloc ((size_t) len);
344   if (get && len > 0) {
345     base = DEREF (BYTE_T, &ARRAY (arr));
346     iindex = VECTOR_OFFSET (arr, tup);
347     inc = SPAN (tup) * ELEM_SIZE (arr);
348     for (k = 0; k < len; k++, iindex += inc) {
349       A68_REAL *re = (A68_REAL *) (base + iindex);
350       A68_REAL *im = (A68_REAL *) (base + iindex + SIZE (MODE (REAL)));
351       gsl_complex z;
352       CHECK_INIT (p, INITIALISED (re), MODE (COMPLEX));
353       CHECK_INIT (p, INITIALISED (im), MODE (COMPLEX));
354       GSL_SET_COMPLEX (&z, VALUE (re), VALUE (im));
355       gsl_vector_complex_set (v, (size_t) k, z);
356     }
357   }
358   return (v);
359 }
360 
361 /**
362 @brief Push gsl_vector_complex on the stack as [] COMPLEX.
363 @param p Node in syntax tree.
364 @param v Vector.
365 **/
366 
367 static void
push_vector_complex(NODE_T * p,gsl_vector_complex * v)368 push_vector_complex (NODE_T * p, gsl_vector_complex * v)
369 {
370   A68_REF desc, row;
371   A68_ARRAY arr;
372   A68_TUPLE tup;
373   int len, inc, iindex, k;
374   BYTE_T *base;
375   len = (int) (SIZE (v));
376   desc = heap_generator (p, MODE (ROW_COMPLEX), SIZE_AL (A68_ARRAY) + SIZE_AL (A68_TUPLE));
377   row = heap_generator (p, MODE (ROW_COMPLEX), len * 2 * SIZE (MODE (REAL)));
378   DIM (&arr) = 1;
379   MOID (&arr) = MODE (COMPLEX);
380   ELEM_SIZE (&arr) = 2 * SIZE (MODE (REAL));
381   SLICE_OFFSET (&arr) = FIELD_OFFSET (&arr) = 0;
382   ARRAY (&arr) = row;
383   LWB (&tup) = 1;
384   UPB (&tup) = len;
385   SPAN (&tup) = 1;
386   SHIFT (&tup) = LWB (&tup);
387   K (&tup) = 0;
388   PUT_DESCRIPTOR (arr, tup, &desc);
389   base = DEREF (BYTE_T, &ARRAY (&arr));
390   iindex = VECTOR_OFFSET (&arr, &tup);
391   inc = SPAN (&tup) * ELEM_SIZE (&arr);
392   for (k = 0; k < len; k++, iindex += inc) {
393     A68_REAL *re = (A68_REAL *) (base + iindex);
394     A68_REAL *im = (A68_REAL *) (base + iindex + SIZE (MODE (REAL)));
395     gsl_complex z = gsl_vector_complex_get (v, (size_t) k);
396     STATUS (re) = INIT_MASK;
397     VALUE (re) = GSL_REAL (z);
398     STATUS (im) = INIT_MASK;
399     VALUE (im) = GSL_IMAG (z);
400     CHECK_COMPLEX_REPRESENTATION (p, VALUE (re), VALUE (im));
401   }
402   PUSH_REF (p, desc);
403 }
404 
405 /**
406 @brief Pop [,] COMPLEX on the stack as gsl_matrix_complex.
407 @param p Node in syntax tree.
408 @param get Whether to get elements from row in the stack.
409 @return Gsl_matrix_complex.
410 **/
411 
412 static gsl_matrix_complex *
pop_matrix_complex(NODE_T * p,BOOL_T get)413 pop_matrix_complex (NODE_T * p, BOOL_T get)
414 {
415   A68_REF desc;
416   A68_ARRAY *arr;
417   A68_TUPLE *tup1, *tup2;
418   int len1, len2;
419   gsl_matrix_complex *a;
420 /* Pop arguments */
421   POP_REF (p, &desc);
422   CHECK_REF (p, desc, MODE (ROWROW_COMPLEX));
423   GET_DESCRIPTOR (arr, tup1, &desc);
424   tup2 = &(tup1[1]);
425   len1 = ROW_SIZE (tup1);
426   len2 = ROW_SIZE (tup2);
427   a = gsl_matrix_complex_alloc ((size_t) len1, (size_t) len2);
428   if (get && (len1 * len2 > 0)) {
429     BYTE_T *base = DEREF (BYTE_T, &ARRAY (arr));
430     int iindex1 = MATRIX_OFFSET (arr, tup1, tup2);
431     int inc1 = SPAN (tup1) * ELEM_SIZE (arr), inc2 = SPAN (tup2) * ELEM_SIZE (arr), k1;
432     for (k1 = 0; k1 < len1; k1++, iindex1 += inc1) {
433       int iindex2, k2;
434       for (k2 = 0, iindex2 = iindex1; k2 < len2; k2++, iindex2 += inc2) {
435         A68_REAL *re = (A68_REAL *) (base + iindex2);
436         A68_REAL *im = (A68_REAL *) (base + iindex2 + SIZE (MODE (REAL)));
437         gsl_complex z;
438         CHECK_INIT (p, INITIALISED (re), MODE (COMPLEX));
439         CHECK_INIT (p, INITIALISED (im), MODE (COMPLEX));
440         GSL_SET_COMPLEX (&z, VALUE (re), VALUE (im));
441         gsl_matrix_complex_set (a, (size_t) k1, (size_t) k2, z);
442       }
443     }
444   }
445   return (a);
446 }
447 
448 /**
449 @brief Push gsl_matrix_complex on the stack as [,] COMPLEX.
450 @param p Node in syntax tree.
451 @param a Matrix.
452 **/
453 
454 static void
push_matrix_complex(NODE_T * p,gsl_matrix_complex * a)455 push_matrix_complex (NODE_T * p, gsl_matrix_complex * a)
456 {
457   A68_REF desc, row;
458   A68_ARRAY arr;
459   A68_TUPLE tup1, tup2;
460   int len1, len2, inc1, inc2, iindex1, iindex2, k1, k2;
461   BYTE_T *base;
462   len1 = (int) (SIZE1 (a));
463   len2 = (int) (SIZE2 (a));
464   desc = heap_generator (p, MODE (ROWROW_COMPLEX), SIZE_AL (A68_ARRAY) + 2 * SIZE_AL (A68_TUPLE));
465   row = heap_generator (p, MODE (ROWROW_COMPLEX), len1 * len2 * 2 * SIZE (MODE (REAL)));
466   DIM (&arr) = 2;
467   MOID (&arr) = MODE (COMPLEX);
468   ELEM_SIZE (&arr) = 2 * SIZE (MODE (REAL));
469   SLICE_OFFSET (&arr) = FIELD_OFFSET (&arr) = 0;
470   ARRAY (&arr) = row;
471   LWB (&tup1) = 1;
472   UPB (&tup1) = len1;
473   SPAN (&tup1) = 1;
474   SHIFT (&tup1) = LWB (&tup1);
475   K (&tup1) = 0;
476   LWB (&tup2) = 1;
477   UPB (&tup2) = len2;
478   SPAN (&tup2) = ROW_SIZE (&tup1);
479   SHIFT (&tup2) = LWB (&tup2) * SPAN (&tup2);
480   K (&tup2) = 0;
481   PUT_DESCRIPTOR2 (arr, tup1, tup2, &desc);
482   base = DEREF (BYTE_T, &ARRAY (&arr));
483   iindex1 = MATRIX_OFFSET (&arr, &tup1, &tup2);
484   inc1 = SPAN (&tup1) * ELEM_SIZE (&arr);
485   inc2 = SPAN (&tup2) * ELEM_SIZE (&arr);
486   for (k1 = 0; k1 < len1; k1++, iindex1 += inc1) {
487     for (k2 = 0, iindex2 = iindex1; k2 < len2; k2++, iindex2 += inc2) {
488       A68_REAL *re = (A68_REAL *) (base + iindex2);
489       A68_REAL *im = (A68_REAL *) (base + iindex2 + SIZE (MODE (REAL)));
490       gsl_complex z = gsl_matrix_complex_get (a, (size_t) k1, (size_t) k2);
491       STATUS (re) = INIT_MASK;
492       VALUE (re) = GSL_REAL (z);
493       STATUS (im) = INIT_MASK;
494       VALUE (im) = GSL_IMAG (z);
495       CHECK_COMPLEX_REPRESENTATION (p, VALUE (re), VALUE (im));
496     }
497   }
498   PUSH_REF (p, desc);
499 }
500 
501 /**
502 @brief Generically perform operation and assign result (+:=, -:=, ...) .
503 @param p Node in syntax tree.
504 @param m Mode of REF [...] M.
505 @param n Mode of right operand M.
506 @param op Operation to be performed.
507 **/
508 
509 static void
op_ab(NODE_T * p,MOID_T * m,MOID_T * n,GPROC * op)510 op_ab (NODE_T * p, MOID_T * m, MOID_T * n, GPROC * op)
511 {
512   ADDR_T parm_size = SIZE (m) + SIZE (n);
513   A68_REF dst, src, *save = (A68_REF *) STACK_OFFSET (-parm_size);
514   error_node = p;
515   dst = *save;
516   CHECK_REF (p, dst, m);
517   *save = *DEREF (A68_ROW, &dst);
518   STATUS (&src) = (STATUS_MASK) (INIT_MASK | IN_STACK_MASK);
519   OFFSET (&src) = stack_pointer - parm_size;
520   (*op) (p);
521   genie_store (p, n, &dst, &src);
522   *save = dst;
523 }
524 
525 /**
526 @brief PROC vector echo = ([] REAL) [] REAL
527 @param p Node in syntax tree.
528 **/
529 
530 void
genie_vector_echo(NODE_T * p)531 genie_vector_echo (NODE_T * p)
532 {
533   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
534   gsl_vector *u;
535   error_node = p;
536   u = pop_vector (p, A68_TRUE);
537   push_vector (p, u);
538   gsl_vector_free (u);
539   (void) gsl_set_error_handler (save_handler);
540 }
541 
542 /**
543 @brief PROC matrix echo = ([,] REAL) [,] REAL
544 @param p Node in syntax tree.
545 **/
546 
547 void
genie_matrix_echo(NODE_T * p)548 genie_matrix_echo (NODE_T * p)
549 {
550   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
551   gsl_matrix *a;
552   error_node = p;
553   a = pop_matrix (p, A68_TRUE);
554   push_matrix (p, a);
555   gsl_matrix_free (a);
556   (void) gsl_set_error_handler (save_handler);
557 }
558 
559 /**
560 @brief PROC complex vector echo = ([] COMPLEX) [] COMPLEX
561 @param p Node in syntax tree.
562 **/
563 
564 void
genie_vector_complex_echo(NODE_T * p)565 genie_vector_complex_echo (NODE_T * p)
566 {
567   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
568   gsl_vector_complex *u;
569   error_node = p;
570   u = pop_vector_complex (p, A68_TRUE);
571   push_vector_complex (p, u);
572   gsl_vector_complex_free (u);
573   (void) gsl_set_error_handler (save_handler);
574 }
575 
576 /**
577 @brief PROC complex matrix echo = ([,] COMPLEX) [,] COMPLEX
578 @param p Node in syntax tree.
579 **/
580 
581 void
genie_matrix_complex_echo(NODE_T * p)582 genie_matrix_complex_echo (NODE_T * p)
583 {
584   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
585   gsl_matrix_complex *a;
586   error_node = p;
587   a = pop_matrix_complex (p, A68_TRUE);
588   push_matrix_complex (p, a);
589   gsl_matrix_complex_free (a);
590   (void) gsl_set_error_handler (save_handler);
591 }
592 
593 /**
594 @brief OP - = ([] REAL) [] REAL
595 @param p Node in syntax tree.
596 **/
597 
598 void
genie_vector_minus(NODE_T * p)599 genie_vector_minus (NODE_T * p)
600 {
601   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
602   gsl_vector *u;
603   int rc;
604   error_node = p;
605   u = pop_vector (p, A68_TRUE);
606   rc = gsl_vector_scale (u, -1);
607   torrix_test_error (rc);
608   push_vector (p, u);
609   gsl_vector_free (u);
610   (void) gsl_set_error_handler (save_handler);
611 }
612 
613 /**
614 @brief OP - = ([,] REAL) [,] REAL
615 @param p Node in syntax tree.
616 **/
617 
618 void
genie_matrix_minus(NODE_T * p)619 genie_matrix_minus (NODE_T * p)
620 {
621   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
622   gsl_matrix *a;
623   int rc;
624   error_node = p;
625   a = pop_matrix (p, A68_TRUE);
626   rc = gsl_matrix_scale (a, -1);
627   torrix_test_error (rc);
628   push_matrix (p, a);
629   gsl_matrix_free (a);
630   (void) gsl_set_error_handler (save_handler);
631 }
632 
633 /**
634 @brief OP T = ([,] REAL) [,] REAL
635 @param p Node in syntax tree.
636 **/
637 
638 void
genie_matrix_transpose(NODE_T * p)639 genie_matrix_transpose (NODE_T * p)
640 {
641   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
642   gsl_matrix *a;
643   int rc;
644   error_node = p;
645   a = pop_matrix (p, A68_TRUE);
646   rc = gsl_matrix_transpose (a);
647   torrix_test_error (rc);
648   push_matrix (p, a);
649   gsl_matrix_free (a);
650   (void) gsl_set_error_handler (save_handler);
651 }
652 
653 /**
654 @brief OP T = ([,] COMPLEX) [,] COMPLEX
655 @param p Node in syntax tree.
656 **/
657 
658 void
genie_matrix_complex_transpose(NODE_T * p)659 genie_matrix_complex_transpose (NODE_T * p)
660 {
661   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
662   gsl_matrix_complex *a;
663   int rc;
664   error_node = p;
665   a = pop_matrix_complex (p, A68_TRUE);
666   rc = gsl_matrix_complex_transpose (a);
667   torrix_test_error (rc);
668   push_matrix_complex (p, a);
669   gsl_matrix_complex_free (a);
670   (void) gsl_set_error_handler (save_handler);
671 }
672 
673 /**
674 @brief OP INV = ([,] REAL) [,] REAL
675 @param p Node in syntax tree.
676 **/
677 
678 void
genie_matrix_inv(NODE_T * p)679 genie_matrix_inv (NODE_T * p)
680 {
681   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
682   gsl_permutation *q;
683   gsl_matrix *u, *inv;
684   int rc, signum;
685   error_node = p;
686   u = pop_matrix (p, A68_TRUE);
687   q = gsl_permutation_alloc (SIZE1 (u));
688   rc = gsl_linalg_LU_decomp (u, q, &signum);
689   torrix_test_error (rc);
690   inv = gsl_matrix_alloc (SIZE1 (u), SIZE2 (u));
691   rc = gsl_linalg_LU_invert (u, q, inv);
692   torrix_test_error (rc);
693   push_matrix (p, inv);
694   gsl_matrix_free (inv);
695   gsl_matrix_free (u);
696   gsl_permutation_free (q);
697   (void) gsl_set_error_handler (save_handler);
698 }
699 
700 /**
701 @brief OP INV = ([,] COMPLEX) [,] COMPLEX
702 @param p Node in syntax tree.
703 **/
704 
705 void
genie_matrix_complex_inv(NODE_T * p)706 genie_matrix_complex_inv (NODE_T * p)
707 {
708   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
709   gsl_permutation *q;
710   gsl_matrix_complex *u, *inv;
711   int rc, signum;
712   error_node = p;
713   u = pop_matrix_complex (p, A68_TRUE);
714   q = gsl_permutation_alloc (SIZE1 (u));
715   rc = gsl_linalg_complex_LU_decomp (u, q, &signum);
716   torrix_test_error (rc);
717   inv = gsl_matrix_complex_alloc (SIZE1 (u), SIZE2 (u));
718   rc = gsl_linalg_complex_LU_invert (u, q, inv);
719   torrix_test_error (rc);
720   push_matrix_complex (p, inv);
721   gsl_matrix_complex_free (inv);
722   gsl_matrix_complex_free (u);
723   gsl_permutation_free (q);
724   (void) gsl_set_error_handler (save_handler);
725 }
726 
727 /**
728 @brief OP DET = ([,] REAL) REAL
729 @param p Node in syntax tree.
730 **/
731 
732 void
genie_matrix_det(NODE_T * p)733 genie_matrix_det (NODE_T * p)
734 {
735   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
736   gsl_permutation *q;
737   gsl_matrix *u;
738   int rc, signum;
739   error_node = p;
740   u = pop_matrix (p, A68_TRUE);
741   q = gsl_permutation_alloc (SIZE1 (u));
742   rc = gsl_linalg_LU_decomp (u, q, &signum);
743   torrix_test_error (rc);
744   PUSH_PRIMITIVE (p, gsl_linalg_LU_det (u, signum), A68_REAL);
745   gsl_matrix_free (u);
746   gsl_permutation_free (q);
747   (void) gsl_set_error_handler (save_handler);
748 }
749 
750 /**
751 @brief OP DET = ([,] COMPLEX) COMPLEX
752 @param p Node in syntax tree.
753 **/
754 
755 void
genie_matrix_complex_det(NODE_T * p)756 genie_matrix_complex_det (NODE_T * p)
757 {
758   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
759   gsl_permutation *q;
760   gsl_matrix_complex *u;
761   int rc, signum;
762   gsl_complex det;
763   error_node = p;
764   u = pop_matrix_complex (p, A68_TRUE);
765   q = gsl_permutation_alloc (SIZE1 (u));
766   rc = gsl_linalg_complex_LU_decomp (u, q, &signum);
767   torrix_test_error (rc);
768   det = gsl_linalg_complex_LU_det (u, signum);
769   PUSH_PRIMITIVE (p, GSL_REAL (det), A68_REAL);
770   PUSH_PRIMITIVE (p, GSL_IMAG (det), A68_REAL);
771   gsl_matrix_complex_free (u);
772   gsl_permutation_free (q);
773   (void) gsl_set_error_handler (save_handler);
774 }
775 
776 /**
777 @brief OP TRACE = ([,] REAL) REAL
778 @param p Node in syntax tree.
779 **/
780 
781 void
genie_matrix_trace(NODE_T * p)782 genie_matrix_trace (NODE_T * p)
783 {
784   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
785   gsl_matrix *a;
786   double sum;
787   int len1, len2, k;
788   error_node = p;
789   a = pop_matrix (p, A68_TRUE);
790   len1 = (int) (SIZE1 (a));
791   len2 = (int) (SIZE2 (a));
792   if (len1 != len2) {
793     torrix_error_handler ("cannot calculate trace", __FILE__, __LINE__, GSL_ENOTSQR);
794   }
795   sum = 0.0;
796   for (k = 0; k < len1; k++) {
797     sum += gsl_matrix_get (a, (size_t) k, (size_t) k);
798   }
799   PUSH_PRIMITIVE (p, sum, A68_REAL);
800   gsl_matrix_free (a);
801   (void) gsl_set_error_handler (save_handler);
802 }
803 
804 /**
805 @brief OP TRACE = ([,] COMPLEX) COMPLEX
806 @param p Node in syntax tree.
807 **/
808 
809 void
genie_matrix_complex_trace(NODE_T * p)810 genie_matrix_complex_trace (NODE_T * p)
811 {
812   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
813   gsl_matrix_complex *a;
814   gsl_complex sum;
815   int len1, len2, k;
816   error_node = p;
817   a = pop_matrix_complex (p, A68_TRUE);
818   len1 = (int) (SIZE1 (a));
819   len2 = (int) (SIZE2 (a));
820   if (len1 != len2) {
821     torrix_error_handler ("cannot calculate trace", __FILE__, __LINE__, GSL_ENOTSQR);
822   }
823   GSL_SET_COMPLEX (&sum, 0.0, 0.0);
824   for (k = 0; k < len1; k++) {
825     sum = gsl_complex_add (sum, gsl_matrix_complex_get (a, (size_t) k, (size_t) k));
826   }
827   PUSH_PRIMITIVE (p, GSL_REAL (sum), A68_REAL);
828   PUSH_PRIMITIVE (p, GSL_IMAG (sum), A68_REAL);
829   gsl_matrix_complex_free (a);
830   (void) gsl_set_error_handler (save_handler);
831 }
832 
833 /**
834 @brief OP - = ([] COMPLEX) [] COMPLEX
835 @param p Node in syntax tree.
836 **/
837 
838 void
genie_vector_complex_minus(NODE_T * p)839 genie_vector_complex_minus (NODE_T * p)
840 {
841   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
842   gsl_vector_complex *u;
843   error_node = p;
844   u = pop_vector_complex (p, A68_TRUE);
845   gsl_blas_zdscal (-1, u);
846   push_vector_complex (p, u);
847   gsl_vector_complex_free (u);
848   (void) gsl_set_error_handler (save_handler);
849 }
850 
851 /**
852 @brief OP - = ([,] COMPLEX) [,] COMPLEX
853 @param p Node in syntax tree.
854 **/
855 
856 void
genie_matrix_complex_minus(NODE_T * p)857 genie_matrix_complex_minus (NODE_T * p)
858 {
859   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
860   gsl_matrix_complex *a;
861   gsl_complex one;
862   int rc;
863   error_node = p;
864   GSL_SET_COMPLEX (&one, -1.0, 0.0);
865   a = pop_matrix_complex (p, A68_TRUE);
866   rc = gsl_matrix_complex_scale (a, one);
867   torrix_test_error (rc);
868   push_matrix_complex (p, a);
869   gsl_matrix_complex_free (a);
870   (void) gsl_set_error_handler (save_handler);
871 }
872 
873 /**
874 @brief OP + = ([] REAL, [] REAL) [] REAL
875 @param p Node in syntax tree.
876 **/
877 
878 void
genie_vector_add(NODE_T * p)879 genie_vector_add (NODE_T * p)
880 {
881   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
882   gsl_vector *u, *v;
883   int rc;
884   error_node = p;
885   v = pop_vector (p, A68_TRUE);
886   u = pop_vector (p, A68_TRUE);
887   rc = gsl_vector_add (u, v);
888   torrix_test_error (rc);
889   push_vector (p, u);
890   gsl_vector_free (u);
891   gsl_vector_free (v);
892   (void) gsl_set_error_handler (save_handler);
893 }
894 
895 /**
896 @brief OP - = ([] REAL, [] REAL) [] REAL
897 @param p Node in syntax tree.
898 **/
899 
900 void
genie_vector_sub(NODE_T * p)901 genie_vector_sub (NODE_T * p)
902 {
903   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
904   gsl_vector *u, *v;
905   int rc;
906   error_node = p;
907   v = pop_vector (p, A68_TRUE);
908   u = pop_vector (p, A68_TRUE);
909   rc = gsl_vector_sub (u, v);
910   torrix_test_error (rc);
911   push_vector (p, u);
912   gsl_vector_free (u);
913   gsl_vector_free (v);
914   (void) gsl_set_error_handler (save_handler);
915 }
916 
917 /**
918 @brief OP = = ([] REAL, [] REAL) BOOL
919 @param p Node in syntax tree.
920 **/
921 
922 void
genie_vector_eq(NODE_T * p)923 genie_vector_eq (NODE_T * p)
924 {
925   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
926   gsl_vector *u, *v;
927   int rc;
928   error_node = p;
929   v = pop_vector (p, A68_TRUE);
930   u = pop_vector (p, A68_TRUE);
931   rc = gsl_vector_sub (u, v);
932   torrix_test_error (rc);
933   PUSH_PRIMITIVE (p, (BOOL_T) (gsl_vector_isnull (u) ? A68_TRUE : A68_FALSE), A68_BOOL);
934   gsl_vector_free (u);
935   gsl_vector_free (v);
936   (void) gsl_set_error_handler (save_handler);
937 }
938 
939 /**
940 @brief OP /= = ([] REAL, [] REAL) BOOL
941 @param p Node in syntax tree.
942 **/
943 
944 void
genie_vector_ne(NODE_T * p)945 genie_vector_ne (NODE_T * p)
946 {
947   genie_vector_eq (p);
948   genie_not_bool (p);
949 }
950 
951 /**
952 @brief OP +:= = (REF [] REAL, [] REAL) REF [] REAL
953 @param p Node in syntax tree.
954 **/
955 
956 void
genie_vector_plusab(NODE_T * p)957 genie_vector_plusab (NODE_T * p)
958 {
959   op_ab (p, MODE (REF_ROW_REAL), MODE (ROW_REAL), genie_vector_add);
960 }
961 
962 /**
963 @brief OP -:= = (REF [] REAL, [] REAL) REF [] REAL
964 @param p Node in syntax tree.
965 **/
966 
967 void
genie_vector_minusab(NODE_T * p)968 genie_vector_minusab (NODE_T * p)
969 {
970   op_ab (p, MODE (REF_ROW_REAL), MODE (ROW_REAL), genie_vector_sub);
971 }
972 
973 /**
974 @brief OP + = ([, ] REAL, [, ] REAL) [, ] REAL
975 @param p Node in syntax tree.
976 **/
977 
978 void
genie_matrix_add(NODE_T * p)979 genie_matrix_add (NODE_T * p)
980 {
981   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
982   gsl_matrix *u, *v;
983   int rc;
984   error_node = p;
985   v = pop_matrix (p, A68_TRUE);
986   u = pop_matrix (p, A68_TRUE);
987   rc = gsl_matrix_add (u, v);
988   torrix_test_error (rc);
989   push_matrix (p, u);
990   gsl_matrix_free (u);
991   gsl_matrix_free (v);
992   (void) gsl_set_error_handler (save_handler);
993 }
994 
995 /**
996 @brief OP - = ([, ] REAL, [, ] REAL) [, ] REAL
997 @param p Node in syntax tree.
998 **/
999 
1000 void
genie_matrix_sub(NODE_T * p)1001 genie_matrix_sub (NODE_T * p)
1002 {
1003   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1004   gsl_matrix *u, *v;
1005   int rc;
1006   error_node = p;
1007   v = pop_matrix (p, A68_TRUE);
1008   u = pop_matrix (p, A68_TRUE);
1009   rc = gsl_matrix_sub (u, v);
1010   torrix_test_error (rc);
1011   push_matrix (p, u);
1012   gsl_matrix_free (u);
1013   gsl_matrix_free (v);
1014   (void) gsl_set_error_handler (save_handler);
1015 }
1016 
1017 /**
1018 @brief OP = = ([, ] REAL, [, ] REAL) [, ] BOOL
1019 @param p Node in syntax tree.
1020 **/
1021 
1022 void
genie_matrix_eq(NODE_T * p)1023 genie_matrix_eq (NODE_T * p)
1024 {
1025   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1026   gsl_matrix *u, *v;
1027   int rc;
1028   error_node = p;
1029   v = pop_matrix (p, A68_TRUE);
1030   u = pop_matrix (p, A68_TRUE);
1031   rc = gsl_matrix_sub (u, v);
1032   torrix_test_error (rc);
1033   PUSH_PRIMITIVE (p, (BOOL_T) (gsl_matrix_isnull (u) ? A68_TRUE : A68_FALSE), A68_BOOL);
1034   gsl_matrix_free (u);
1035   gsl_matrix_free (v);
1036   (void) gsl_set_error_handler (save_handler);
1037 }
1038 
1039 /**
1040 @brief OP /= = ([, ] REAL, [, ] REAL) [, ] BOOL
1041 @param p Node in syntax tree.
1042 **/
1043 
1044 void
genie_matrix_ne(NODE_T * p)1045 genie_matrix_ne (NODE_T * p)
1046 {
1047   genie_matrix_eq (p);
1048   genie_not_bool (p);
1049 }
1050 
1051 /**
1052 @brief OP +:= = (REF [, ] REAL, [, ] REAL) [, ] REAL
1053 @param p Node in syntax tree.
1054 **/
1055 
1056 void
genie_matrix_plusab(NODE_T * p)1057 genie_matrix_plusab (NODE_T * p)
1058 {
1059   op_ab (p, MODE (REF_ROWROW_REAL), MODE (ROWROW_REAL), genie_matrix_add);
1060 }
1061 
1062 /**
1063 @brief OP -:= = (REF [, ] REAL, [, ] REAL) [, ] REAL
1064 @param p Node in syntax tree.
1065 **/
1066 
1067 void
genie_matrix_minusab(NODE_T * p)1068 genie_matrix_minusab (NODE_T * p)
1069 {
1070   op_ab (p, MODE (REF_ROWROW_REAL), MODE (ROWROW_REAL), genie_matrix_sub);
1071 }
1072 
1073 /**
1074 @brief OP + = ([] COMPLEX, [] COMPLEX) [] COMPLEX
1075 @param p Node in syntax tree.
1076 **/
1077 
1078 void
genie_vector_complex_add(NODE_T * p)1079 genie_vector_complex_add (NODE_T * p)
1080 {
1081   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1082   gsl_vector_complex *u, *v;
1083   gsl_complex one;
1084   int rc;
1085   error_node = p;
1086   GSL_SET_COMPLEX (&one, 1.0, 0.0);
1087   v = pop_vector_complex (p, A68_TRUE);
1088   u = pop_vector_complex (p, A68_TRUE);
1089   rc = gsl_blas_zaxpy (one, u, v);
1090   torrix_test_error (rc);
1091   push_vector_complex (p, v);
1092   gsl_vector_complex_free (u);
1093   gsl_vector_complex_free (v);
1094   (void) gsl_set_error_handler (save_handler);
1095 }
1096 
1097 /**
1098 @brief OP - = ([] COMPLEX, [] COMPLEX) [] COMPLEX
1099 @param p Node in syntax tree.
1100 **/
1101 
1102 void
genie_vector_complex_sub(NODE_T * p)1103 genie_vector_complex_sub (NODE_T * p)
1104 {
1105   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1106   gsl_vector_complex *u, *v;
1107   gsl_complex one;
1108   int rc;
1109   error_node = p;
1110   GSL_SET_COMPLEX (&one, -1.0, 0.0);
1111   v = pop_vector_complex (p, A68_TRUE);
1112   u = pop_vector_complex (p, A68_TRUE);
1113   rc = gsl_blas_zaxpy (one, v, u);
1114   torrix_test_error (rc);
1115   push_vector_complex (p, u);
1116   gsl_vector_complex_free (u);
1117   gsl_vector_complex_free (v);
1118   (void) gsl_set_error_handler (save_handler);
1119 }
1120 
1121 /**
1122 @brief OP = = ([] COMPLEX, [] COMPLEX) BOOL
1123 @param p Node in syntax tree.
1124 **/
1125 
1126 void
genie_vector_complex_eq(NODE_T * p)1127 genie_vector_complex_eq (NODE_T * p)
1128 {
1129   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1130   gsl_vector_complex *u, *v;
1131   gsl_complex one;
1132   int rc;
1133   error_node = p;
1134   GSL_SET_COMPLEX (&one, -1.0, 0.0);
1135   v = pop_vector_complex (p, A68_TRUE);
1136   u = pop_vector_complex (p, A68_TRUE);
1137   rc = gsl_blas_zaxpy (one, v, u);
1138   torrix_test_error (rc);
1139   PUSH_PRIMITIVE (p, (BOOL_T) (gsl_vector_complex_isnull (u) ? A68_TRUE : A68_FALSE), A68_BOOL);
1140   gsl_vector_complex_free (u);
1141   gsl_vector_complex_free (v);
1142   (void) gsl_set_error_handler (save_handler);
1143 }
1144 
1145 /**
1146 @brief OP /= = ([] COMPLEX, [] COMPLEX) BOOL
1147 @param p Node in syntax tree.
1148 **/
1149 
1150 void
genie_vector_complex_ne(NODE_T * p)1151 genie_vector_complex_ne (NODE_T * p)
1152 {
1153   genie_vector_complex_eq (p);
1154   genie_not_bool (p);
1155 }
1156 
1157 /**
1158 @brief OP +:= = (REF [] COMPLEX, [] COMPLEX) [] COMPLEX
1159 @param p Node in syntax tree.
1160 **/
1161 
1162 void
genie_vector_complex_plusab(NODE_T * p)1163 genie_vector_complex_plusab (NODE_T * p)
1164 {
1165   op_ab (p, MODE (REF_ROW_COMPLEX), MODE (ROW_COMPLEX), genie_vector_complex_add);
1166 }
1167 
1168 /**
1169 @brief OP -:= = (REF [] COMPLEX, [] COMPLEX) [] COMPLEX
1170 @param p Node in syntax tree.
1171 **/
1172 
1173 void
genie_vector_complex_minusab(NODE_T * p)1174 genie_vector_complex_minusab (NODE_T * p)
1175 {
1176   op_ab (p, MODE (REF_ROW_COMPLEX), MODE (ROW_COMPLEX), genie_vector_complex_sub);
1177 }
1178 
1179 /**
1180 @brief OP + = ([, ] COMPLEX, [, ] COMPLEX) [, ] COMPLEX
1181 @param p Node in syntax tree.
1182 **/
1183 
1184 void
genie_matrix_complex_add(NODE_T * p)1185 genie_matrix_complex_add (NODE_T * p)
1186 {
1187   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1188   gsl_matrix_complex *u, *v;
1189   int rc;
1190   error_node = p;
1191   v = pop_matrix_complex (p, A68_TRUE);
1192   u = pop_matrix_complex (p, A68_TRUE);
1193   rc = gsl_matrix_complex_add (u, v);
1194   torrix_test_error (rc);
1195   push_matrix_complex (p, u);
1196   gsl_matrix_complex_free (u);
1197   gsl_matrix_complex_free (v);
1198   (void) gsl_set_error_handler (save_handler);
1199 }
1200 
1201 /**
1202 @brief OP - = ([, ] COMPLEX, [, ] COMPLEX) [, ] COMPLEX
1203 @param p Node in syntax tree.
1204 **/
1205 
1206 void
genie_matrix_complex_sub(NODE_T * p)1207 genie_matrix_complex_sub (NODE_T * p)
1208 {
1209   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1210   gsl_matrix_complex *u, *v;
1211   int rc;
1212   error_node = p;
1213   v = pop_matrix_complex (p, A68_TRUE);
1214   u = pop_matrix_complex (p, A68_TRUE);
1215   rc = gsl_matrix_complex_sub (u, v);
1216   torrix_test_error (rc);
1217   push_matrix_complex (p, u);
1218   gsl_matrix_complex_free (u);
1219   gsl_matrix_complex_free (v);
1220   (void) gsl_set_error_handler (save_handler);
1221 }
1222 
1223 /**
1224 @brief OP = = ([, ] COMPLEX, [, ] COMPLEX) BOOL
1225 @param p Node in syntax tree.
1226 **/
1227 
1228 void
genie_matrix_complex_eq(NODE_T * p)1229 genie_matrix_complex_eq (NODE_T * p)
1230 {
1231   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1232   gsl_matrix_complex *u, *v;
1233   int rc;
1234   error_node = p;
1235   v = pop_matrix_complex (p, A68_TRUE);
1236   u = pop_matrix_complex (p, A68_TRUE);
1237   rc = gsl_matrix_complex_sub (u, v);
1238   torrix_test_error (rc);
1239   PUSH_PRIMITIVE (p, (BOOL_T) (gsl_matrix_complex_isnull (u) ? A68_TRUE : A68_FALSE), A68_BOOL);
1240   gsl_matrix_complex_free (u);
1241   gsl_matrix_complex_free (v);
1242   (void) gsl_set_error_handler (save_handler);
1243 }
1244 
1245 /**
1246 @brief OP /= = ([, ] COMPLEX, [, ] COMPLEX) BOOL
1247 @param p Node in syntax tree.
1248 **/
1249 
1250 void
genie_matrix_complex_ne(NODE_T * p)1251 genie_matrix_complex_ne (NODE_T * p)
1252 {
1253   genie_matrix_complex_eq (p);
1254   genie_not_bool (p);
1255 }
1256 
1257 /**
1258 @brief OP +:= = (REF [, ] COMPLEX, [, ] COMPLEX) [, ] COMPLEX
1259 @param p Node in syntax tree.
1260 **/
1261 
1262 void
genie_matrix_complex_plusab(NODE_T * p)1263 genie_matrix_complex_plusab (NODE_T * p)
1264 {
1265   op_ab (p, MODE (REF_ROWROW_COMPLEX), MODE (ROWROW_COMPLEX), genie_matrix_complex_add);
1266 }
1267 
1268 /**
1269 @brief OP -:= = (REF [, ] COMPLEX, [, ] COMPLEX) [, ] COMPLEX
1270 @param p Node in syntax tree.
1271 **/
1272 
1273 void
genie_matrix_complex_minusab(NODE_T * p)1274 genie_matrix_complex_minusab (NODE_T * p)
1275 {
1276   op_ab (p, MODE (REF_ROWROW_COMPLEX), MODE (ROWROW_COMPLEX), genie_matrix_complex_sub);
1277 }
1278 
1279 /**
1280 @brief OP * = ([] REAL, REAL) [] REAL
1281 @param p Node in syntax tree.
1282 **/
1283 
1284 void
genie_vector_scale_real(NODE_T * p)1285 genie_vector_scale_real (NODE_T * p)
1286 {
1287   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1288   gsl_vector *u;
1289   A68_REAL v;
1290   int rc;
1291   error_node = p;
1292   POP_OBJECT (p, &v, A68_REAL);
1293   u = pop_vector (p, A68_TRUE);
1294   rc = gsl_vector_scale (u, VALUE (&v));
1295   torrix_test_error (rc);
1296   push_vector (p, u);
1297   gsl_vector_free (u);
1298   (void) gsl_set_error_handler (save_handler);
1299 }
1300 
1301 /**
1302 @brief OP * = (REAL, [] REAL) [] REAL
1303 @param p Node in syntax tree.
1304 **/
1305 
1306 void
genie_real_scale_vector(NODE_T * p)1307 genie_real_scale_vector (NODE_T * p)
1308 {
1309   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1310   gsl_vector *u;
1311   A68_REAL v;
1312   int rc;
1313   error_node = p;
1314   u = pop_vector (p, A68_TRUE);
1315   POP_OBJECT (p, &v, A68_REAL);
1316   rc = gsl_vector_scale (u, VALUE (&v));
1317   torrix_test_error (rc);
1318   push_vector (p, u);
1319   gsl_vector_free (u);
1320   (void) gsl_set_error_handler (save_handler);
1321 }
1322 
1323 /**
1324 @brief OP * = ([, ] REAL, REAL) [, ] REAL
1325 @param p Node in syntax tree.
1326 **/
1327 
1328 void
genie_matrix_scale_real(NODE_T * p)1329 genie_matrix_scale_real (NODE_T * p)
1330 {
1331   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1332   gsl_matrix *u;
1333   A68_REAL v;
1334   int rc;
1335   error_node = p;
1336   POP_OBJECT (p, &v, A68_REAL);
1337   u = pop_matrix (p, A68_TRUE);
1338   rc = gsl_matrix_scale (u, VALUE (&v));
1339   torrix_test_error (rc);
1340   push_matrix (p, u);
1341   gsl_matrix_free (u);
1342   (void) gsl_set_error_handler (save_handler);
1343 }
1344 
1345 /**
1346 @brief OP * = (REAL, [, ] REAL) [, ] REAL
1347 @param p Node in syntax tree.
1348 **/
1349 
1350 void
genie_real_scale_matrix(NODE_T * p)1351 genie_real_scale_matrix (NODE_T * p)
1352 {
1353   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1354   gsl_matrix *u;
1355   A68_REAL v;
1356   int rc;
1357   error_node = p;
1358   u = pop_matrix (p, A68_TRUE);
1359   POP_OBJECT (p, &v, A68_REAL);
1360   rc = gsl_matrix_scale (u, VALUE (&v));
1361   torrix_test_error (rc);
1362   push_matrix (p, u);
1363   gsl_matrix_free (u);
1364   (void) gsl_set_error_handler (save_handler);
1365 }
1366 
1367 /**
1368 @brief OP * = ([] COMPLEX, COMPLEX) [] COMPLEX
1369 @param p Node in syntax tree.
1370 **/
1371 
1372 void
genie_vector_complex_scale_complex(NODE_T * p)1373 genie_vector_complex_scale_complex (NODE_T * p)
1374 {
1375   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1376   gsl_vector_complex *u;
1377   A68_REAL re, im;
1378   gsl_complex v;
1379   error_node = p;
1380   POP_OBJECT (p, &im, A68_REAL);
1381   POP_OBJECT (p, &re, A68_REAL);
1382   GSL_SET_COMPLEX (&v, VALUE (&re), VALUE (&im));
1383   u = pop_vector_complex (p, A68_TRUE);
1384   gsl_blas_zscal (v, u);
1385   push_vector_complex (p, u);
1386   gsl_vector_complex_free (u);
1387   (void) gsl_set_error_handler (save_handler);
1388 }
1389 
1390 /**
1391 @brief OP * = (COMPLEX, [] COMPLEX) [] COMPLEX
1392 @param p Node in syntax tree.
1393 **/
1394 
1395 void
genie_complex_scale_vector_complex(NODE_T * p)1396 genie_complex_scale_vector_complex (NODE_T * p)
1397 {
1398   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1399   gsl_vector_complex *u;
1400   A68_REAL re, im;
1401   gsl_complex v;
1402   error_node = p;
1403   u = pop_vector_complex (p, A68_TRUE);
1404   POP_OBJECT (p, &im, A68_REAL);
1405   POP_OBJECT (p, &re, A68_REAL);
1406   GSL_SET_COMPLEX (&v, VALUE (&re), VALUE (&im));
1407   gsl_blas_zscal (v, u);
1408   push_vector_complex (p, u);
1409   gsl_vector_complex_free (u);
1410   (void) gsl_set_error_handler (save_handler);
1411 }
1412 
1413 /**
1414 @brief OP * = ([, ] COMPLEX, COMPLEX) [, ] COMPLEX
1415 @param p Node in syntax tree.
1416 **/
1417 
1418 void
genie_matrix_complex_scale_complex(NODE_T * p)1419 genie_matrix_complex_scale_complex (NODE_T * p)
1420 {
1421   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1422   gsl_matrix_complex *u;
1423   A68_REAL re, im;
1424   gsl_complex v;
1425   int rc;
1426   error_node = p;
1427   POP_OBJECT (p, &im, A68_REAL);
1428   POP_OBJECT (p, &re, A68_REAL);
1429   GSL_SET_COMPLEX (&v, VALUE (&re), VALUE (&im));
1430   u = pop_matrix_complex (p, A68_TRUE);
1431   rc = gsl_matrix_complex_scale (u, v);
1432   torrix_test_error (rc);
1433   push_matrix_complex (p, u);
1434   gsl_matrix_complex_free (u);
1435   (void) gsl_set_error_handler (save_handler);
1436 }
1437 
1438 /**
1439 @brief OP * = (COMPLEX, [, ] COMPLEX) [, ] COMPLEX
1440 @param p Node in syntax tree.
1441 **/
1442 
1443 void
genie_complex_scale_matrix_complex(NODE_T * p)1444 genie_complex_scale_matrix_complex (NODE_T * p)
1445 {
1446   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1447   gsl_matrix_complex *u;
1448   A68_REAL re, im;
1449   gsl_complex v;
1450   int rc;
1451   error_node = p;
1452   u = pop_matrix_complex (p, A68_TRUE);
1453   POP_OBJECT (p, &im, A68_REAL);
1454   POP_OBJECT (p, &re, A68_REAL);
1455   GSL_SET_COMPLEX (&v, VALUE (&re), VALUE (&im));
1456   rc = gsl_matrix_complex_scale (u, v);
1457   torrix_test_error (rc);
1458   push_matrix_complex (p, u);
1459   gsl_matrix_complex_free (u);
1460   (void) gsl_set_error_handler (save_handler);
1461 }
1462 
1463 /**
1464 @brief OP *:= (REF [] REAL, REAL) REF [] REAL
1465 @param p Node in syntax tree.
1466 **/
1467 
1468 void
genie_vector_scale_real_ab(NODE_T * p)1469 genie_vector_scale_real_ab (NODE_T * p)
1470 {
1471   op_ab (p, MODE (REF_ROW_REAL), MODE (REAL), genie_vector_scale_real);
1472 }
1473 
1474 /**
1475 @brief OP *:= (REF [, ] REAL, REAL) REF [, ] REAL
1476 @param p Node in syntax tree.
1477 **/
1478 
1479 void
genie_matrix_scale_real_ab(NODE_T * p)1480 genie_matrix_scale_real_ab (NODE_T * p)
1481 {
1482   op_ab (p, MODE (REF_ROWROW_REAL), MODE (REAL), genie_matrix_scale_real);
1483 }
1484 
1485 /**
1486 @brief OP *:= (REF [] COMPLEX, COMPLEX) REF [] COMPLEX
1487 @param p Node in syntax tree.
1488 **/
1489 
1490 void
genie_vector_complex_scale_complex_ab(NODE_T * p)1491 genie_vector_complex_scale_complex_ab (NODE_T * p)
1492 {
1493   op_ab (p, MODE (REF_ROW_COMPLEX), MODE (COMPLEX), genie_vector_complex_scale_complex);
1494 }
1495 
1496 /**
1497 @brief OP *:= (REF [, ] COMPLEX, COMPLEX) REF [, ] COMPLEX
1498 @param p Node in syntax tree.
1499 **/
1500 
1501 void
genie_matrix_complex_scale_complex_ab(NODE_T * p)1502 genie_matrix_complex_scale_complex_ab (NODE_T * p)
1503 {
1504   op_ab (p, MODE (REF_ROWROW_COMPLEX), MODE (COMPLEX), genie_matrix_complex_scale_complex);
1505 }
1506 
1507 /**
1508 @brief OP / = ([] REAL, REAL) [] REAL
1509 @param p Node in syntax tree.
1510 **/
1511 
1512 void
genie_vector_div_real(NODE_T * p)1513 genie_vector_div_real (NODE_T * p)
1514 {
1515   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1516   gsl_vector *u;
1517   A68_REAL v;
1518   int rc;
1519   error_node = p;
1520   POP_OBJECT (p, &v, A68_REAL);
1521   if (VALUE (&v) == 0.0) {
1522     diagnostic_node (A68_RUNTIME_ERROR, p, ERROR_DIVISION_BY_ZERO, MODE (ROW_REAL));
1523     exit_genie (p, A68_RUNTIME_ERROR);
1524   }
1525   u = pop_vector (p, A68_TRUE);
1526   rc = gsl_vector_scale (u, 1.0 / VALUE (&v));
1527   torrix_test_error (rc);
1528   push_vector (p, u);
1529   gsl_vector_free (u);
1530   (void) gsl_set_error_handler (save_handler);
1531 }
1532 
1533 /**
1534 @brief OP / = ([, ] REAL, REAL) [, ] REAL
1535 @param p Node in syntax tree.
1536 **/
1537 
1538 void
genie_matrix_div_real(NODE_T * p)1539 genie_matrix_div_real (NODE_T * p)
1540 {
1541   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1542   gsl_matrix *u;
1543   A68_REAL v;
1544   int rc;
1545   error_node = p;
1546   POP_OBJECT (p, &v, A68_REAL);
1547   if (VALUE (&v) == 0.0) {
1548     diagnostic_node (A68_RUNTIME_ERROR, p, ERROR_DIVISION_BY_ZERO, MODE (ROWROW_REAL));
1549     exit_genie (p, A68_RUNTIME_ERROR);
1550   }
1551   u = pop_matrix (p, A68_TRUE);
1552   rc = gsl_matrix_scale (u, 1.0 / VALUE (&v));
1553   torrix_test_error (rc);
1554   push_matrix (p, u);
1555   gsl_matrix_free (u);
1556   (void) gsl_set_error_handler (save_handler);
1557 }
1558 
1559 /**
1560 @brief OP / = ([] COMPLEX, COMPLEX) [] COMPLEX
1561 @param p Node in syntax tree.
1562 **/
1563 
1564 void
genie_vector_complex_div_complex(NODE_T * p)1565 genie_vector_complex_div_complex (NODE_T * p)
1566 {
1567   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1568   gsl_vector_complex *u;
1569   A68_REAL re, im;
1570   gsl_complex v;
1571   error_node = p;
1572   POP_OBJECT (p, &im, A68_REAL);
1573   POP_OBJECT (p, &re, A68_REAL);
1574   if (VALUE (&re) == 0.0 && VALUE (&im) == 0.0) {
1575     diagnostic_node (A68_RUNTIME_ERROR, p, ERROR_DIVISION_BY_ZERO, MODE (ROW_COMPLEX));
1576     exit_genie (p, A68_RUNTIME_ERROR);
1577   }
1578   GSL_SET_COMPLEX (&v, VALUE (&re), VALUE (&im));
1579   u = pop_vector_complex (p, A68_TRUE);
1580   v = gsl_complex_inverse (v);
1581   gsl_blas_zscal (v, u);
1582   push_vector_complex (p, u);
1583   gsl_vector_complex_free (u);
1584   (void) gsl_set_error_handler (save_handler);
1585 }
1586 
1587 /**
1588 @brief OP / = ([, ] COMPLEX, COMPLEX) [, ] COMPLEX
1589 @param p Node in syntax tree.
1590 **/
1591 
1592 void
genie_matrix_complex_div_complex(NODE_T * p)1593 genie_matrix_complex_div_complex (NODE_T * p)
1594 {
1595   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1596   gsl_matrix_complex *u;
1597   A68_REAL re, im;
1598   gsl_complex v;
1599   int rc;
1600   error_node = p;
1601   POP_OBJECT (p, &im, A68_REAL);
1602   POP_OBJECT (p, &re, A68_REAL);
1603   if (VALUE (&re) == 0.0 && VALUE (&im) == 0.0) {
1604     diagnostic_node (A68_RUNTIME_ERROR, p, ERROR_DIVISION_BY_ZERO, MODE (ROWROW_COMPLEX));
1605     exit_genie (p, A68_RUNTIME_ERROR);
1606   }
1607   GSL_SET_COMPLEX (&v, VALUE (&re), VALUE (&im));
1608   v = gsl_complex_inverse (v);
1609   u = pop_matrix_complex (p, A68_TRUE);
1610   rc = gsl_matrix_complex_scale (u, v);
1611   torrix_test_error (rc);
1612   push_matrix_complex (p, u);
1613   gsl_matrix_complex_free (u);
1614   (void) gsl_set_error_handler (save_handler);
1615 }
1616 
1617 /**
1618 @brief OP /:= (REF [] REAL, REAL) REF [] REAL
1619 @param p Node in syntax tree.
1620 **/
1621 
1622 void
genie_vector_div_real_ab(NODE_T * p)1623 genie_vector_div_real_ab (NODE_T * p)
1624 {
1625   op_ab (p, MODE (REF_ROW_REAL), MODE (REAL), genie_vector_div_real);
1626 }
1627 
1628 /**
1629 @brief OP /:= (REF [, ] REAL, REAL) REF [, ] REAL
1630 @param p Node in syntax tree.
1631 **/
1632 
1633 void
genie_matrix_div_real_ab(NODE_T * p)1634 genie_matrix_div_real_ab (NODE_T * p)
1635 {
1636   op_ab (p, MODE (REF_ROWROW_REAL), MODE (REAL), genie_matrix_div_real);
1637 }
1638 
1639 /**
1640 @brief OP /:= (REF [] COMPLEX, COMPLEX) REF [] COMPLEX
1641 @param p Node in syntax tree.
1642 **/
1643 
1644 void
genie_vector_complex_div_complex_ab(NODE_T * p)1645 genie_vector_complex_div_complex_ab (NODE_T * p)
1646 {
1647   op_ab (p, MODE (REF_ROW_COMPLEX), MODE (COMPLEX), genie_vector_complex_div_complex);
1648 }
1649 
1650 /**
1651 @brief OP /:= (REF [, ] COMPLEX, COMPLEX) REF [, ] COMPLEX
1652 @param p Node in syntax tree.
1653 **/
1654 
1655 void
genie_matrix_complex_div_complex_ab(NODE_T * p)1656 genie_matrix_complex_div_complex_ab (NODE_T * p)
1657 {
1658   op_ab (p, MODE (REF_ROWROW_COMPLEX), MODE (COMPLEX), genie_matrix_complex_div_complex);
1659 }
1660 
1661 /**
1662 @brief OP * = ([] REAL, [] REAL) REAL
1663 @param p Node in syntax tree.
1664 **/
1665 
1666 void
genie_vector_dot(NODE_T * p)1667 genie_vector_dot (NODE_T * p)
1668 {
1669   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1670   gsl_vector *u, *v;
1671   double w;
1672   int rc;
1673   error_node = p;
1674   v = pop_vector (p, A68_TRUE);
1675   u = pop_vector (p, A68_TRUE);
1676   rc = gsl_blas_ddot (u, v, &w);
1677   torrix_test_error (rc);
1678   PUSH_PRIMITIVE (p, w, A68_REAL);
1679   gsl_vector_free (u);
1680   gsl_vector_free (v);
1681   (void) gsl_set_error_handler (save_handler);
1682 }
1683 
1684 /**
1685 @brief OP * = ([] COMPLEX, [] COMPLEX) COMPLEX
1686 @param p Node in syntax tree.
1687 **/
1688 
1689 void
genie_vector_complex_dot(NODE_T * p)1690 genie_vector_complex_dot (NODE_T * p)
1691 {
1692   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1693   gsl_vector_complex *u, *v;
1694   gsl_complex w;
1695   int rc;
1696   error_node = p;
1697   v = pop_vector_complex (p, A68_TRUE);
1698   u = pop_vector_complex (p, A68_TRUE);
1699   rc = gsl_blas_zdotc (u, v, &w);
1700   torrix_test_error (rc);
1701   PUSH_PRIMITIVE (p, GSL_REAL (w), A68_REAL);
1702   PUSH_PRIMITIVE (p, GSL_IMAG (w), A68_REAL);
1703   gsl_vector_complex_free (u);
1704   gsl_vector_complex_free (v);
1705   (void) gsl_set_error_handler (save_handler);
1706 }
1707 
1708 /**
1709 @brief OP NORM = ([] REAL) REAL
1710 @param p Node in syntax tree.
1711 **/
1712 
1713 void
genie_vector_norm(NODE_T * p)1714 genie_vector_norm (NODE_T * p)
1715 {
1716   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1717   gsl_vector *u;
1718   error_node = p;
1719   u = pop_vector (p, A68_TRUE);
1720   PUSH_PRIMITIVE (p, gsl_blas_dnrm2 (u), A68_REAL);
1721   gsl_vector_free (u);
1722   (void) gsl_set_error_handler (save_handler);
1723 }
1724 
1725 /**
1726 @brief OP NORM = ([] COMPLEX) COMPLEX
1727 @param p Node in syntax tree.
1728 **/
1729 
1730 void
genie_vector_complex_norm(NODE_T * p)1731 genie_vector_complex_norm (NODE_T * p)
1732 {
1733   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1734   gsl_vector_complex *u;
1735   error_node = p;
1736   u = pop_vector_complex (p, A68_TRUE);
1737   PUSH_PRIMITIVE (p, gsl_blas_dznrm2 (u), A68_REAL);
1738   gsl_vector_complex_free (u);
1739   (void) gsl_set_error_handler (save_handler);
1740 }
1741 
1742 /**
1743 @brief OP DYAD = ([] REAL, [] REAL) [, ] REAL
1744 @param p Node in syntax tree.
1745 **/
1746 
1747 void
genie_vector_dyad(NODE_T * p)1748 genie_vector_dyad (NODE_T * p)
1749 {
1750   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1751   gsl_vector *u, *v;
1752   gsl_matrix *w;
1753   int len1, len2, j, k;
1754   error_node = p;
1755   v = pop_vector (p, A68_TRUE);
1756   u = pop_vector (p, A68_TRUE);
1757   len1 = (int) (SIZE (u));
1758   len2 = (int) (SIZE (v));
1759   w = gsl_matrix_alloc ((size_t) len1, (size_t) len2);
1760   for (j = 0; j < len1; j++) {
1761     double uj = gsl_vector_get (u, (size_t) j);
1762     for (k = 0; k < len2; k++) {
1763       double vk = gsl_vector_get (v, (size_t) k);
1764       gsl_matrix_set (w, (size_t) j, (size_t) k, uj * vk);
1765     }
1766   }
1767   push_matrix (p, w);
1768   gsl_vector_free (u);
1769   gsl_vector_free (v);
1770   gsl_matrix_free (w);
1771   (void) gsl_set_error_handler (save_handler);
1772 }
1773 
1774 /**
1775 @brief OP DYAD = ([] COMPLEX, [] COMPLEX) [, ] COMPLEX
1776 @param p Node in syntax tree.
1777 **/
1778 
1779 void
genie_vector_complex_dyad(NODE_T * p)1780 genie_vector_complex_dyad (NODE_T * p)
1781 {
1782   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1783   gsl_vector_complex *u, *v;
1784   gsl_matrix_complex *w;
1785   int len1, len2, j, k;
1786   error_node = p;
1787   v = pop_vector_complex (p, A68_TRUE);
1788   u = pop_vector_complex (p, A68_TRUE);
1789   len1 = (int) (SIZE (u));
1790   len2 = (int) (SIZE (v));
1791   w = gsl_matrix_complex_alloc ((size_t) len1, (size_t) len2);
1792   for (j = 0; j < len1; j++) {
1793     gsl_complex uj = gsl_vector_complex_get (u, (size_t) j);
1794     for (k = 0; k < len2; k++) {
1795       gsl_complex vk = gsl_vector_complex_get (u, (size_t) k);
1796       gsl_matrix_complex_set (w, (size_t) j, (size_t) k, gsl_complex_mul (uj, vk));
1797     }
1798   }
1799   push_matrix_complex (p, w);
1800   gsl_vector_complex_free (u);
1801   gsl_vector_complex_free (v);
1802   gsl_matrix_complex_free (w);
1803   (void) gsl_set_error_handler (save_handler);
1804 }
1805 
1806 /**
1807 @brief OP * = ([, ] REAL, [] REAL) [] REAL
1808 @param p Node in syntax tree.
1809 **/
1810 
1811 void
genie_matrix_times_vector(NODE_T * p)1812 genie_matrix_times_vector (NODE_T * p)
1813 {
1814   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1815   int len;
1816   int rc;
1817   gsl_vector *u, *v;
1818   gsl_matrix *w;
1819   error_node = p;
1820   u = pop_vector (p, A68_TRUE);
1821   w = pop_matrix (p, A68_TRUE);
1822   len = (int) (SIZE (u));
1823   v = gsl_vector_alloc ((size_t) len);
1824   gsl_vector_set_zero (v);
1825   rc = gsl_blas_dgemv (CblasNoTrans, 1.0, w, u, 0.0, v);
1826   torrix_test_error (rc);
1827   push_vector (p, v);
1828   gsl_vector_free (u);
1829   gsl_vector_free (v);
1830   gsl_matrix_free (w);
1831   (void) gsl_set_error_handler (save_handler);
1832 }
1833 
1834 /**
1835 @brief OP * = ([] REAL, [, ] REAL) [] REAL
1836 @param p Node in syntax tree.
1837 **/
1838 
1839 void
genie_vector_times_matrix(NODE_T * p)1840 genie_vector_times_matrix (NODE_T * p)
1841 {
1842   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1843   int len;
1844   int rc;
1845   gsl_vector *u, *v;
1846   gsl_matrix *w;
1847   error_node = p;
1848   w = pop_matrix (p, A68_TRUE);
1849   rc = gsl_matrix_transpose (w);
1850   torrix_test_error (rc);
1851   u = pop_vector (p, A68_TRUE);
1852   len = (int) (SIZE (u));
1853   v = gsl_vector_alloc ((size_t) len);
1854   gsl_vector_set_zero (v);
1855   rc = gsl_blas_dgemv (CblasNoTrans, 1.0, w, u, 0.0, v);
1856   torrix_test_error (rc);
1857   push_vector (p, v);
1858   gsl_vector_free (u);
1859   gsl_vector_free (v);
1860   gsl_matrix_free (w);
1861   (void) gsl_set_error_handler (save_handler);
1862 }
1863 
1864 /**
1865 @brief OP * = ([, ] REAL, [, ] REAL) [, ] REAL
1866 @param p Node in syntax tree.
1867 **/
1868 
1869 void
genie_matrix_times_matrix(NODE_T * p)1870 genie_matrix_times_matrix (NODE_T * p)
1871 {
1872   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1873   int len1, len2;
1874   int rc;
1875   gsl_matrix *u, *v, *w;
1876   error_node = p;
1877   v = pop_matrix (p, A68_TRUE);
1878   u = pop_matrix (p, A68_TRUE);
1879   len2 = (int) (SIZE2 (v));
1880   len1 = (int) (SIZE1 (u));
1881   w = gsl_matrix_alloc ((size_t) len1, (size_t) len2);
1882   gsl_matrix_set_zero (w);
1883   rc = gsl_blas_dgemm (CblasNoTrans, CblasNoTrans, 1.0, u, v, 0.0, w);
1884   torrix_test_error (rc);
1885   push_matrix (p, w);
1886   gsl_matrix_free (u);
1887   gsl_matrix_free (v);
1888   gsl_matrix_free (w);
1889   (void) gsl_set_error_handler (save_handler);
1890 }
1891 
1892 /**
1893 @brief OP * = ([, ] COMPLEX, [] COMPLEX) [] COMPLEX
1894 @param p Node in syntax tree.
1895 **/
1896 
1897 void
genie_matrix_complex_times_vector(NODE_T * p)1898 genie_matrix_complex_times_vector (NODE_T * p)
1899 {
1900   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1901   int len, rc;
1902   gsl_vector_complex *u, *v;
1903   gsl_matrix_complex *w;
1904   gsl_complex zero, one;
1905   error_node = p;
1906   GSL_SET_COMPLEX (&zero, 0.0, 0.0);
1907   GSL_SET_COMPLEX (&one, 1.0, 0.0);
1908   u = pop_vector_complex (p, A68_TRUE);
1909   w = pop_matrix_complex (p, A68_TRUE);
1910   len = (int) (SIZE (u));
1911   v = gsl_vector_complex_alloc ((size_t) len);
1912   gsl_vector_complex_set_zero (v);
1913   rc = gsl_blas_zgemv (CblasNoTrans, one, w, u, zero, v);
1914   torrix_test_error (rc);
1915   push_vector_complex (p, v);
1916   gsl_vector_complex_free (u);
1917   gsl_vector_complex_free (v);
1918   gsl_matrix_complex_free (w);
1919   (void) gsl_set_error_handler (save_handler);
1920 }
1921 
1922 /**
1923 @brief OP * = ([] COMPLEX, [, ] COMPLEX) [] COMPLEX
1924 @param p Node in syntax tree.
1925 **/
1926 
1927 void
genie_vector_complex_times_matrix(NODE_T * p)1928 genie_vector_complex_times_matrix (NODE_T * p)
1929 {
1930   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1931   int len, rc;
1932   gsl_vector_complex *u, *v;
1933   gsl_matrix_complex *w;
1934   gsl_complex zero, one;
1935   error_node = p;
1936   GSL_SET_COMPLEX (&zero, 0.0, 0.0);
1937   GSL_SET_COMPLEX (&one, 1.0, 0.0);
1938   w = pop_matrix_complex (p, A68_TRUE);
1939   rc = gsl_matrix_complex_transpose (w);
1940   torrix_test_error (rc);
1941   u = pop_vector_complex (p, A68_TRUE);
1942   len = (int) (SIZE (u));
1943   v = gsl_vector_complex_alloc ((size_t) len);
1944   gsl_vector_complex_set_zero (v);
1945   rc = gsl_blas_zgemv (CblasNoTrans, one, w, u, zero, v);
1946   torrix_test_error (rc);
1947   push_vector_complex (p, v);
1948   gsl_vector_complex_free (u);
1949   gsl_vector_complex_free (v);
1950   gsl_matrix_complex_free (w);
1951   (void) gsl_set_error_handler (save_handler);
1952 }
1953 
1954 /**
1955 @brief OP * = ([, ] COMPLEX, [, ] COMPLEX) [, ] COMPLEX
1956 @param p Node in syntax tree.
1957 **/
1958 
1959 void
genie_matrix_complex_times_matrix(NODE_T * p)1960 genie_matrix_complex_times_matrix (NODE_T * p)
1961 {
1962   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1963   int len1, len2, rc;
1964   gsl_matrix_complex *u, *v, *w;
1965   gsl_complex zero, one;
1966   error_node = p;
1967   GSL_SET_COMPLEX (&zero, 0.0, 0.0);
1968   GSL_SET_COMPLEX (&one, 1.0, 0.0);
1969   v = pop_matrix_complex (p, A68_TRUE);
1970   u = pop_matrix_complex (p, A68_TRUE);
1971   len1 = (int) (SIZE2 (v));
1972   len2 = (int) (SIZE1 (u));
1973   w = gsl_matrix_complex_alloc ((size_t) len1, (size_t) len2);
1974   gsl_matrix_complex_set_zero (w);
1975   rc = gsl_blas_zgemm (CblasNoTrans, CblasNoTrans, one, u, v, zero, w);
1976   torrix_test_error (rc);
1977   push_matrix_complex (p, w);
1978   gsl_matrix_complex_free (u);
1979   gsl_matrix_complex_free (v);
1980   gsl_matrix_complex_free (w);
1981   (void) gsl_set_error_handler (save_handler);
1982 }
1983 
1984 /**
1985 @brief PROC lu decomp = ([, ] REAL, REF [] INT, REF INT) [, ] REAL
1986 @param p Node in syntax tree.
1987 **/
1988 
1989 void
genie_matrix_lu(NODE_T * p)1990 genie_matrix_lu (NODE_T * p)
1991 {
1992   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1993   A68_REF ref_signum, ref_q;
1994   gsl_permutation *q;
1995   gsl_matrix *u;
1996   int rc;
1997   A68_INT signum;
1998   error_node = p;
1999   POP_REF (p, &ref_signum);
2000   CHECK_REF (p, ref_signum, MODE (REF_INT));
2001   POP_REF (p, &ref_q);
2002   CHECK_REF (p, ref_q, MODE (REF_ROW_INT));
2003   PUSH_REF (p, *DEREF (A68_ROW, &ref_q));
2004   q = pop_permutation (p, A68_FALSE);
2005   u = pop_matrix (p, A68_TRUE);
2006   rc = gsl_linalg_LU_decomp (u, q, &(VALUE (&signum)));
2007   torrix_test_error (rc);
2008   STATUS (&signum) = INIT_MASK;
2009   *DEREF (A68_INT, &ref_signum) = signum;
2010   push_permutation (p, q);
2011   POP_REF (p, DEREF (A68_ROW, &ref_q));
2012   push_matrix (p, u);
2013   gsl_matrix_free (u);
2014   gsl_permutation_free (q);
2015   (void) gsl_set_error_handler (save_handler);
2016 }
2017 
2018 /**
2019 @brief PROC lu det = ([, ] REAL, INT) REAL
2020 @param p Node in syntax tree.
2021 **/
2022 
2023 void
genie_matrix_lu_det(NODE_T * p)2024 genie_matrix_lu_det (NODE_T * p)
2025 {
2026   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
2027   gsl_matrix *lu;
2028   A68_INT signum;
2029   error_node = p;
2030   POP_OBJECT (p, &signum, A68_INT);
2031   lu = pop_matrix (p, A68_TRUE);
2032   PUSH_PRIMITIVE (p, gsl_linalg_LU_det (lu, VALUE (&signum)), A68_REAL);
2033   gsl_matrix_free (lu);
2034   (void) gsl_set_error_handler (save_handler);
2035 }
2036 
2037 /**
2038 @brief PROC lu inv = ([, ] REAL, [] INT) [, ] REAL
2039 @param p Node in syntax tree.
2040 **/
2041 
2042 void
genie_matrix_lu_inv(NODE_T * p)2043 genie_matrix_lu_inv (NODE_T * p)
2044 {
2045   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
2046   gsl_permutation *q;
2047   gsl_matrix *lu, *inv;
2048   int rc;
2049   error_node = p;
2050   q = pop_permutation (p, A68_TRUE);
2051   lu = pop_matrix (p, A68_TRUE);
2052   inv = gsl_matrix_alloc (SIZE1 (lu), SIZE2 (lu));
2053   rc = gsl_linalg_LU_invert (lu, q, inv);
2054   torrix_test_error (rc);
2055   push_matrix (p, inv);
2056   gsl_matrix_free (lu);
2057   gsl_matrix_free (inv);
2058   gsl_permutation_free (q);
2059   (void) gsl_set_error_handler (save_handler);
2060 }
2061 
2062 /**
2063 @brief PROC lu solve ([, ] REAL, [, ] REAL, [] INT, [] REAL) [] REAL
2064 @param p Node in syntax tree.
2065 **/
2066 
2067 void
genie_matrix_lu_solve(NODE_T * p)2068 genie_matrix_lu_solve (NODE_T * p)
2069 {
2070   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
2071   gsl_permutation *q;
2072   gsl_matrix *a, *lu;
2073   gsl_vector *b, *x, *r;
2074   int rc;
2075   error_node = p;
2076   b = pop_vector (p, A68_TRUE);
2077   q = pop_permutation (p, A68_TRUE);
2078   lu = pop_matrix (p, A68_TRUE);
2079   a = pop_matrix (p, A68_TRUE);
2080   x = gsl_vector_alloc (SIZE (b));
2081   r = gsl_vector_alloc (SIZE (b));
2082   rc = gsl_linalg_LU_solve (lu, q, b, x);
2083   torrix_test_error (rc);
2084   rc = gsl_linalg_LU_refine (a, lu, q, b, x, r);
2085   torrix_test_error (rc);
2086   push_vector (p, x);
2087   gsl_matrix_free (a);
2088   gsl_matrix_free (lu);
2089   gsl_vector_free (b);
2090   gsl_vector_free (r);
2091   gsl_vector_free (x);
2092   gsl_permutation_free (q);
2093   (void) gsl_set_error_handler (save_handler);
2094 }
2095 
2096 /**
2097 @brief PROC complex lu decomp = ([, ] COMPLEX, REF [] INT, REF INT) [, ] COMPLEX
2098 @param p Node in syntax tree.
2099 **/
2100 
2101 void
genie_matrix_complex_lu(NODE_T * p)2102 genie_matrix_complex_lu (NODE_T * p)
2103 {
2104   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
2105   A68_REF ref_signum, ref_q;
2106   gsl_permutation *q;
2107   gsl_matrix_complex *u;
2108   int rc;
2109   A68_INT signum;
2110   error_node = p;
2111   POP_REF (p, &ref_signum);
2112   CHECK_REF (p, ref_signum, MODE (REF_INT));
2113   POP_REF (p, &ref_q);
2114   CHECK_REF (p, ref_q, MODE (REF_ROW_INT));
2115   PUSH_REF (p, *DEREF (A68_ROW, &ref_q));
2116   q = pop_permutation (p, A68_FALSE);
2117   u = pop_matrix_complex (p, A68_TRUE);
2118   rc = gsl_linalg_complex_LU_decomp (u, q, &(VALUE (&signum)));
2119   torrix_test_error (rc);
2120   STATUS (&signum) = INIT_MASK;
2121   *DEREF (A68_INT, &ref_signum) = signum;
2122   push_permutation (p, q);
2123   POP_REF (p, DEREF (A68_ROW, &ref_q));
2124   push_matrix_complex (p, u);
2125   gsl_matrix_complex_free (u);
2126   gsl_permutation_free (q);
2127   (void) gsl_set_error_handler (save_handler);
2128 }
2129 
2130 /**
2131 @brief PROC complex lu det = ([, ] COMPLEX, INT) COMPLEX
2132 @param p Node in syntax tree.
2133 **/
2134 
2135 void
genie_matrix_complex_lu_det(NODE_T * p)2136 genie_matrix_complex_lu_det (NODE_T * p)
2137 {
2138   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
2139   gsl_matrix_complex *lu;
2140   A68_INT signum;
2141   gsl_complex det;
2142   error_node = p;
2143   POP_OBJECT (p, &signum, A68_INT);
2144   lu = pop_matrix_complex (p, A68_TRUE);
2145   det = gsl_linalg_complex_LU_det (lu, VALUE (&signum));
2146   PUSH_PRIMITIVE (p, GSL_REAL (det), A68_REAL);
2147   PUSH_PRIMITIVE (p, GSL_IMAG (det), A68_REAL);
2148   gsl_matrix_complex_free (lu);
2149   (void) gsl_set_error_handler (save_handler);
2150 }
2151 
2152 /**
2153 @brief PROC complex lu inv = ([, ] COMPLEX, [] INT) [, ] COMPLEX
2154 @param p Node in syntax tree.
2155 **/
2156 
2157 void
genie_matrix_complex_lu_inv(NODE_T * p)2158 genie_matrix_complex_lu_inv (NODE_T * p)
2159 {
2160   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
2161   gsl_permutation *q;
2162   gsl_matrix_complex *lu, *inv;
2163   int rc;
2164   error_node = p;
2165   q = pop_permutation (p, A68_TRUE);
2166   lu = pop_matrix_complex (p, A68_TRUE);
2167   inv = gsl_matrix_complex_alloc (SIZE1 (lu), SIZE2 (lu));
2168   rc = gsl_linalg_complex_LU_invert (lu, q, inv);
2169   torrix_test_error (rc);
2170   push_matrix_complex (p, inv);
2171   gsl_matrix_complex_free (lu);
2172   gsl_matrix_complex_free (inv);
2173   gsl_permutation_free (q);
2174   (void) gsl_set_error_handler (save_handler);
2175 }
2176 
2177 /**
2178 @brief PROC complex lu solve ([, ] COMPLEX, [, ] COMPLEX, [] INT, [] COMPLEX) [] COMPLEX
2179 @param p Node in syntax tree.
2180 **/
2181 
2182 void
genie_matrix_complex_lu_solve(NODE_T * p)2183 genie_matrix_complex_lu_solve (NODE_T * p)
2184 {
2185   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
2186   gsl_permutation *q;
2187   gsl_matrix_complex *a, *lu;
2188   gsl_vector_complex *b, *x, *r;
2189   int rc;
2190   error_node = p;
2191   b = pop_vector_complex (p, A68_TRUE);
2192   q = pop_permutation (p, A68_TRUE);
2193   lu = pop_matrix_complex (p, A68_TRUE);
2194   a = pop_matrix_complex (p, A68_TRUE);
2195   x = gsl_vector_complex_alloc (SIZE (b));
2196   r = gsl_vector_complex_alloc (SIZE (b));
2197   rc = gsl_linalg_complex_LU_solve (lu, q, b, x);
2198   torrix_test_error (rc);
2199   rc = gsl_linalg_complex_LU_refine (a, lu, q, b, x, r);
2200   torrix_test_error (rc);
2201   push_vector_complex (p, x);
2202   gsl_matrix_complex_free (a);
2203   gsl_matrix_complex_free (lu);
2204   gsl_vector_complex_free (b);
2205   gsl_vector_complex_free (r);
2206   gsl_vector_complex_free (x);
2207   gsl_permutation_free (q);
2208   (void) gsl_set_error_handler (save_handler);
2209 }
2210 
2211 /**
2212 @brief PROC svd decomp = ([, ] REAL, REF [, ] REAL, REF [] REAL) [, ] REAL
2213 @param p Node in syntax tree.
2214 **/
2215 
2216 void
genie_matrix_svd(NODE_T * p)2217 genie_matrix_svd (NODE_T * p)
2218 {
2219   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
2220   gsl_matrix *a, *v;
2221   gsl_vector *s, *w;
2222   A68_REF ref_s, ref_v;
2223   int rc;
2224   error_node = p;
2225   POP_REF (p, &ref_s);
2226   CHECK_REF (p, ref_s, MODE (REF_ROW_REAL));
2227   PUSH_REF (p, *DEREF (A68_ROW, &ref_s));
2228   s = pop_vector (p, A68_FALSE);
2229   POP_REF (p, &ref_v);
2230   CHECK_REF (p, ref_v, MODE (REF_ROWROW_REAL));
2231   PUSH_REF (p, *DEREF (A68_ROW, &ref_v));
2232   v = pop_matrix (p, A68_FALSE);
2233   a = pop_matrix (p, A68_TRUE);
2234   w = gsl_vector_alloc (SIZE2 (v));
2235   rc = gsl_linalg_SV_decomp (a, v, s, w);
2236   torrix_test_error (rc);
2237   push_vector (p, s);
2238   POP_REF (p, DEREF (A68_ROW, &ref_s));
2239   push_matrix (p, v);
2240   POP_REF (p, DEREF (A68_ROW, &ref_v));
2241   push_matrix (p, a);
2242   gsl_matrix_free (a);
2243   gsl_matrix_free (v);
2244   gsl_vector_free (s);
2245   gsl_vector_free (w);
2246   (void) gsl_set_error_handler (save_handler);
2247 }
2248 
2249 /**
2250 @brief PROC svd solve = ([, ] REAL, [, ] REAL, [] REAL, [] REAL) [] REAL
2251 @param p Node in syntax tree.
2252 **/
2253 
2254 void
genie_matrix_svd_solve(NODE_T * p)2255 genie_matrix_svd_solve (NODE_T * p)
2256 {
2257   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
2258   gsl_matrix *u, *v;
2259   gsl_vector *s, *b, *x;
2260   int rc;
2261   error_node = p;
2262   b = pop_vector (p, A68_TRUE);
2263   s = pop_vector (p, A68_TRUE);
2264   v = pop_matrix (p, A68_TRUE);
2265   u = pop_matrix (p, A68_TRUE);
2266   x = gsl_vector_alloc (SIZE (b));
2267   rc = gsl_linalg_SV_solve (u, v, s, b, x);
2268   push_vector (p, x);
2269   gsl_vector_free (x);
2270   gsl_vector_free (b);
2271   gsl_vector_free (s);
2272   gsl_matrix_free (v);
2273   gsl_matrix_free (u);
2274   (void) rc;
2275   (void) gsl_set_error_handler (save_handler);
2276 }
2277 
2278 /**
2279 @brief PROC qr decomp = ([, ] REAL, [] REAL) [, ] REAL
2280 @param p Node in syntax tree.
2281 **/
2282 
2283 void
genie_matrix_qr(NODE_T * p)2284 genie_matrix_qr (NODE_T * p)
2285 {
2286   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
2287   gsl_matrix *a;
2288   gsl_vector *t;
2289   A68_REF ref_t;
2290   int rc;
2291   error_node = p;
2292   POP_REF (p, &ref_t);
2293   CHECK_REF (p, ref_t, MODE (REF_ROW_REAL));
2294   PUSH_REF (p, *DEREF (A68_ROW, &ref_t));
2295   t = pop_vector (p, A68_FALSE);
2296   a = pop_matrix (p, A68_TRUE);
2297   rc = gsl_linalg_QR_decomp (a, t);
2298   torrix_test_error (rc);
2299   push_vector (p, t);
2300   POP_REF (p, DEREF (A68_ROW, &ref_t));
2301   push_matrix (p, a);
2302   gsl_matrix_free (a);
2303   gsl_vector_free (t);
2304   (void) gsl_set_error_handler (save_handler);
2305 }
2306 
2307 /**
2308 @brief PROC qr solve = ([, ] REAL, [] REAL, [] REAL) [] REAL
2309 @param p Node in syntax tree.
2310 **/
2311 
2312 void
genie_matrix_qr_solve(NODE_T * p)2313 genie_matrix_qr_solve (NODE_T * p)
2314 {
2315   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
2316   gsl_matrix *q;
2317   gsl_vector *t, *b, *x;
2318   int rc;
2319   error_node = p;
2320   b = pop_vector (p, A68_TRUE);
2321   t = pop_vector (p, A68_TRUE);
2322   q = pop_matrix (p, A68_TRUE);
2323   x = gsl_vector_alloc (SIZE (b));
2324   rc = gsl_linalg_QR_solve (q, t, b, x);
2325   push_vector (p, x);
2326   gsl_vector_free (x);
2327   gsl_vector_free (b);
2328   gsl_vector_free (t);
2329   gsl_matrix_free (q);
2330   (void) rc;
2331   (void) gsl_set_error_handler (save_handler);
2332 }
2333 
2334 /**
2335 @brief PROC qr ls solve = ([, ] REAL, [] REAL, [] REAL) [] REAL
2336 @param p Node in syntax tree.
2337 **/
2338 
2339 void
genie_matrix_qr_ls_solve(NODE_T * p)2340 genie_matrix_qr_ls_solve (NODE_T * p)
2341 {
2342   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
2343   gsl_matrix *q;
2344   gsl_vector *t, *b, *x, *r;
2345   int rc;
2346   error_node = p;
2347   b = pop_vector (p, A68_TRUE);
2348   t = pop_vector (p, A68_TRUE);
2349   q = pop_matrix (p, A68_TRUE);
2350   r = gsl_vector_alloc (SIZE (b));
2351   x = gsl_vector_alloc (SIZE (b));
2352   rc = gsl_linalg_QR_lssolve (q, t, b, x, r);
2353   push_vector (p, x);
2354   gsl_vector_free (x);
2355   gsl_vector_free (r);
2356   gsl_vector_free (b);
2357   gsl_vector_free (t);
2358   gsl_matrix_free (q);
2359   (void) rc;
2360   (void) gsl_set_error_handler (save_handler);
2361 }
2362 
2363 /**
2364 @brief PROC cholesky decomp = ([, ] REAL) [, ] REAL
2365 @param p Node in syntax tree.
2366 **/
2367 
2368 void
genie_matrix_ch(NODE_T * p)2369 genie_matrix_ch (NODE_T * p)
2370 {
2371   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
2372   gsl_matrix *a;
2373   int rc;
2374   error_node = p;
2375   a = pop_matrix (p, A68_TRUE);
2376   rc = gsl_linalg_cholesky_decomp (a);
2377   torrix_test_error (rc);
2378   push_matrix (p, a);
2379   gsl_matrix_free (a);
2380   (void) gsl_set_error_handler (save_handler);
2381 }
2382 
2383 /**
2384 @brief PROC cholesky solve = ([, ] REAL, [] REAL) [] REAL
2385 @param p Node in syntax tree.
2386 **/
2387 
2388 void
genie_matrix_ch_solve(NODE_T * p)2389 genie_matrix_ch_solve (NODE_T * p)
2390 {
2391   gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
2392   gsl_matrix *c;
2393   gsl_vector *b, *x;
2394   int rc;
2395   error_node = p;
2396   b = pop_vector (p, A68_TRUE);
2397   c = pop_matrix (p, A68_TRUE);
2398   x = gsl_vector_alloc (SIZE (b));
2399   rc = gsl_linalg_cholesky_solve (c, b, x);
2400   push_vector (p, x);
2401   gsl_vector_free (x);
2402   gsl_vector_free (b);
2403   gsl_matrix_free (c);
2404   (void) rc;
2405   (void) gsl_set_error_handler (save_handler);
2406 }
2407 
2408 /**
2409 @brief Map GSL error handler onto a68g error handler.
2410 @param reason Error text.
2411 @param file Gsl file where error occured.
2412 @param line Line in above file.
2413 @param gsl_errno Gsl error number.
2414 **/
2415 
2416 void
fft_error_handler(const char * reason,const char * file,int line,int gsl_errno)2417 fft_error_handler (const char *reason, const char *file, int line, int gsl_errno)
2418 {
2419   if (line != 0) {
2420     ASSERT (snprintf (edit_line, SNPRINTF_SIZE, "%s in line %d of file %s", reason, line, file) >= 0);
2421   } else {
2422     ASSERT (snprintf (edit_line, SNPRINTF_SIZE, "%s", reason) >= 0);
2423   }
2424   diagnostic_node (A68_RUNTIME_ERROR, error_node, ERROR_FFT, edit_line, gsl_strerror (gsl_errno));
2425   exit_genie (error_node, A68_RUNTIME_ERROR);
2426 }
2427 
2428 /**
2429 @brief Detect math errors.
2430 @param rc Return code from function.
2431 **/
2432 
2433 static void
fft_test_error(int rc)2434 fft_test_error (int rc)
2435 {
2436   if (rc != 0) {
2437     fft_error_handler ("math error", "", 0, rc);
2438   }
2439 }
2440 
2441 /**
2442 @brief Pop [] REAL on the stack as complex double [].
2443 @param p Node in syntax tree.
2444 @param len Length of array.
2445 @return Double [].
2446 **/
2447 
2448 static double *
pop_array_real(NODE_T * p,int * len)2449 pop_array_real (NODE_T * p, int *len)
2450 {
2451   A68_REF desc;
2452   A68_ARRAY *arr;
2453   A68_TUPLE *tup;
2454   int inc, iindex, k;
2455   BYTE_T *base;
2456   double *v;
2457   error_node = p;
2458 /* Pop arguments */
2459   POP_REF (p, &desc);
2460   CHECK_REF (p, desc, MODE (ROW_REAL));
2461   GET_DESCRIPTOR (arr, tup, &desc);
2462   *len = ROW_SIZE (tup);
2463   if ((*len) <= 0) {
2464     return (NO_REAL);
2465   }
2466   v = malloc (2 * (size_t) (*len) * sizeof (double));
2467   fft_test_error (v == NO_REAL ? GSL_ENOMEM : GSL_SUCCESS);
2468   base = DEREF (BYTE_T, &ARRAY (arr));
2469   iindex = VECTOR_OFFSET (arr, tup);
2470   inc = SPAN (tup) * ELEM_SIZE (arr);
2471   for (k = 0; k < (*len); k++, iindex += inc) {
2472     A68_REAL *x = (A68_REAL *) (base + iindex);
2473     CHECK_INIT (p, INITIALISED (x), MODE (REAL));
2474     v[2 * k] = VALUE (x);
2475     v[2 * k + 1] = 0.0;
2476   }
2477   return (v);
2478 }
2479 
2480 /**
2481 @brief Push double [] on the stack as [] REAL.
2482 @param p Node in syntax tree.
2483 @param v First element.
2484 @param len Length of array.
2485 **/
2486 
2487 static void
push_array_real(NODE_T * p,double * v,int len)2488 push_array_real (NODE_T * p, double *v, int len)
2489 {
2490   A68_REF desc, row;
2491   A68_ARRAY arr;
2492   A68_TUPLE tup;
2493   int inc, iindex, k;
2494   BYTE_T *base;
2495   error_node = p;
2496   desc = heap_generator (p, MODE (ROW_REAL), SIZE_AL (A68_ARRAY) + SIZE_AL (A68_TUPLE));
2497   row = heap_generator (p, MODE (ROW_REAL), len * SIZE (MODE (REAL)));
2498   DIM (&arr) = 1;
2499   MOID (&arr) = MODE (REAL);
2500   ELEM_SIZE (&arr) = SIZE (MODE (REAL));
2501   SLICE_OFFSET (&arr) = FIELD_OFFSET (&arr) = 0;
2502   ARRAY (&arr) = row;
2503   LWB (&tup) = 1;
2504   UPB (&tup) = len;
2505   SHIFT (&tup) = LWB (&tup);
2506   SPAN (&tup) = 1;
2507   K (&tup) = 0;
2508   PUT_DESCRIPTOR (arr, tup, &desc);
2509   base = DEREF (BYTE_T, &ARRAY (&arr));
2510   iindex = VECTOR_OFFSET (&arr, &tup);
2511   inc = SPAN (&tup) * ELEM_SIZE (&arr);
2512   for (k = 0; k < len; k++, iindex += inc) {
2513     A68_REAL *x = (A68_REAL *) (base + iindex);
2514     STATUS (x) = INIT_MASK;
2515     VALUE (x) = v[2 * k];
2516     CHECK_REAL_REPRESENTATION (p, VALUE (x));
2517   }
2518   PUSH_REF (p, desc);
2519 }
2520 
2521 /**
2522 @brief Pop [] COMPLEX on the stack as double [].
2523 @param p Node in syntax tree.
2524 @param len Length or array.
2525 @return Double [].
2526 **/
2527 
2528 static double *
pop_array_complex(NODE_T * p,int * len)2529 pop_array_complex (NODE_T * p, int *len)
2530 {
2531   A68_REF desc;
2532   A68_ARRAY *arr;
2533   A68_TUPLE *tup;
2534   int inc, iindex, k;
2535   BYTE_T *base;
2536   double *v;
2537   error_node = p;
2538 /* Pop arguments */
2539   POP_REF (p, &desc);
2540   CHECK_REF (p, desc, MODE (ROW_COMPLEX));
2541   GET_DESCRIPTOR (arr, tup, &desc);
2542   *len = ROW_SIZE (tup);
2543   if ((*len) <= 0) {
2544     return (NO_REAL);
2545   }
2546   v = malloc (2 * (size_t) (*len) * sizeof (double));
2547   fft_test_error (v == NO_REAL ? GSL_ENOMEM : GSL_SUCCESS);
2548   base = DEREF (BYTE_T, &ARRAY (arr));
2549   iindex = VECTOR_OFFSET (arr, tup);
2550   inc = SPAN (tup) * ELEM_SIZE (arr);
2551   for (k = 0; k < (*len); k++, iindex += inc) {
2552     A68_REAL *re = (A68_REAL *) (base + iindex);
2553     A68_REAL *im = (A68_REAL *) (base + iindex + SIZE (MODE (REAL)));
2554     CHECK_INIT (p, INITIALISED (re), MODE (COMPLEX));
2555     CHECK_INIT (p, INITIALISED (im), MODE (COMPLEX));
2556     v[2 * k] = VALUE (re);
2557     v[2 * k + 1] = VALUE (im);
2558   }
2559   return (v);
2560 }
2561 
2562 /**
2563 @brief Push double [] on the stack as [] COMPLEX.
2564 @param p Node in syntax tree.
2565 @param v First element.
2566 @param len Length of array.
2567 **/
2568 
2569 static void
push_array_complex(NODE_T * p,double * v,int len)2570 push_array_complex (NODE_T * p, double *v, int len)
2571 {
2572   A68_REF desc, row;
2573   A68_ARRAY arr;
2574   A68_TUPLE tup;
2575   int inc, iindex, k;
2576   BYTE_T *base;
2577   error_node = p;
2578   desc = heap_generator (p, MODE (ROW_COMPLEX), SIZE_AL (A68_ARRAY) + SIZE_AL (A68_TUPLE));
2579   row = heap_generator (p, MODE (ROW_COMPLEX), len * 2 * SIZE (MODE (REAL)));
2580   DIM (&arr) = 1;
2581   MOID (&arr) = MODE (COMPLEX);
2582   ELEM_SIZE (&arr) = 2 * SIZE (MODE (REAL));
2583   SLICE_OFFSET (&arr) = FIELD_OFFSET (&arr) = 0;
2584   ARRAY (&arr) = row;
2585   LWB (&tup) = 1;
2586   UPB (&tup) = len;
2587   SHIFT (&tup) = LWB (&tup);
2588   SPAN (&tup) = 1;
2589   K (&tup) = 0;
2590   PUT_DESCRIPTOR (arr, tup, &desc);
2591   base = DEREF (BYTE_T, &ARRAY (&arr));
2592   iindex = VECTOR_OFFSET (&arr, &tup);
2593   inc = SPAN (&tup) * ELEM_SIZE (&arr);
2594   for (k = 0; k < len; k++, iindex += inc) {
2595     A68_REAL *re = (A68_REAL *) (base + iindex);
2596     A68_REAL *im = (A68_REAL *) (base + iindex + SIZE (MODE (REAL)));
2597     STATUS (re) = INIT_MASK;
2598     VALUE (re) = v[2 * k];
2599     STATUS (im) = INIT_MASK;
2600     VALUE (im) = v[2 * k + 1];
2601     CHECK_COMPLEX_REPRESENTATION (p, VALUE (re), VALUE (im));
2602   }
2603   PUSH_REF (p, desc);
2604 }
2605 
2606 /**
2607 @brief Push prime factorisation on the stack as [] INT.
2608 @param p Node in syntax tree.
2609 **/
2610 
2611 void
genie_prime_factors(NODE_T * p)2612 genie_prime_factors (NODE_T * p)
2613 {
2614   gsl_error_handler_t *save_handler = gsl_set_error_handler (fft_error_handler);
2615   A68_INT n;
2616   A68_REF desc, row;
2617   A68_ARRAY arr;
2618   A68_TUPLE tup;
2619   int len, inc, iindex, k;
2620   BYTE_T *base;
2621   gsl_fft_complex_wavetable *wt;
2622   error_node = p;
2623   POP_OBJECT (p, &n, A68_INT);
2624   CHECK_INIT (p, INITIALISED (&n), MODE (INT));
2625   wt = gsl_fft_complex_wavetable_alloc ((size_t) (VALUE (&n)));
2626   len = (int) (NF (wt));
2627   desc = heap_generator (p, MODE (ROW_INT), SIZE_AL (A68_ARRAY) + SIZE_AL (A68_TUPLE));
2628   row = heap_generator (p, MODE (ROW_INT), len * SIZE (MODE (INT)));
2629   DIM (&arr) = 1;
2630   MOID (&arr) = MODE (INT);
2631   ELEM_SIZE (&arr) = SIZE (MODE (INT));
2632   SLICE_OFFSET (&arr) = FIELD_OFFSET (&arr) = 0;
2633   ARRAY (&arr) = row;
2634   LWB (&tup) = 1;
2635   UPB (&tup) = len;
2636   SHIFT (&tup) = LWB (&tup);
2637   SPAN (&tup) = 1;
2638   K (&tup) = 0;
2639   PUT_DESCRIPTOR (arr, tup, &desc);
2640   base = DEREF (BYTE_T, &ARRAY (&arr));
2641   iindex = VECTOR_OFFSET (&arr, &tup);
2642   inc = SPAN (&tup) * ELEM_SIZE (&arr);
2643   for (k = 0; k < len; k++, iindex += inc) {
2644     A68_INT *x = (A68_INT *) (base + iindex);
2645     STATUS (x) = INIT_MASK;
2646     VALUE (x) = (int) ((FACTOR (wt))[k]);
2647   }
2648   gsl_fft_complex_wavetable_free (wt);
2649   PUSH_REF (p, desc);
2650   (void) gsl_set_error_handler (save_handler);
2651 }
2652 
2653 /**
2654 @brief PROC ([] COMPLEX) [] COMPLEX fft complex forward
2655 @param p Node in syntax tree.
2656 **/
2657 
2658 void
genie_fft_complex_forward(NODE_T * p)2659 genie_fft_complex_forward (NODE_T * p)
2660 {
2661   gsl_error_handler_t *save_handler = gsl_set_error_handler (fft_error_handler);
2662   int len, rc;
2663   double *data;
2664   gsl_fft_complex_wavetable *wt;
2665   gsl_fft_complex_workspace *ws;
2666   error_node = p;
2667   data = pop_array_complex (p, &len);
2668   fft_test_error (len == 0 ? GSL_EDOM : GSL_SUCCESS);
2669   wt = gsl_fft_complex_wavetable_alloc ((size_t) len);
2670   ws = gsl_fft_complex_workspace_alloc ((size_t) len);
2671   rc = gsl_fft_complex_forward (data, 1, (size_t) len, wt, ws);
2672   fft_test_error (rc);
2673   push_array_complex (p, data, len);
2674   gsl_fft_complex_wavetable_free (wt);
2675   gsl_fft_complex_workspace_free (ws);
2676   if (data != NO_REAL) {
2677     free (data);
2678   }
2679   (void) gsl_set_error_handler (save_handler);
2680 }
2681 
2682 /**
2683 @brief PROC ([] COMPLEX) [] COMPLEX fft complex backward
2684 @param p Node in syntax tree.
2685 **/
2686 
2687 void
genie_fft_complex_backward(NODE_T * p)2688 genie_fft_complex_backward (NODE_T * p)
2689 {
2690   gsl_error_handler_t *save_handler = gsl_set_error_handler (fft_error_handler);
2691   int len, rc;
2692   double *data;
2693   gsl_fft_complex_wavetable *wt;
2694   gsl_fft_complex_workspace *ws;
2695   error_node = p;
2696   data = pop_array_complex (p, &len);
2697   fft_test_error (len == 0 ? GSL_EDOM : GSL_SUCCESS);
2698   wt = gsl_fft_complex_wavetable_alloc ((size_t) len);
2699   ws = gsl_fft_complex_workspace_alloc ((size_t) len);
2700   rc = gsl_fft_complex_backward (data, 1, (size_t) len, wt, ws);
2701   fft_test_error (rc);
2702   push_array_complex (p, data, len);
2703   gsl_fft_complex_wavetable_free (wt);
2704   gsl_fft_complex_workspace_free (ws);
2705   if (data != NO_REAL) {
2706     free (data);
2707   }
2708   (void) gsl_set_error_handler (save_handler);
2709 }
2710 
2711 /**
2712 @brief PROC ([] COMPLEX) [] COMPLEX fft complex inverse
2713 @param p Node in syntax tree.
2714 **/
2715 
2716 void
genie_fft_complex_inverse(NODE_T * p)2717 genie_fft_complex_inverse (NODE_T * p)
2718 {
2719   gsl_error_handler_t *save_handler = gsl_set_error_handler (fft_error_handler);
2720   int len, rc;
2721   double *data;
2722   gsl_fft_complex_wavetable *wt;
2723   gsl_fft_complex_workspace *ws;
2724   error_node = p;
2725   data = pop_array_complex (p, &len);
2726   fft_test_error (len == 0 ? GSL_EDOM : GSL_SUCCESS);
2727   wt = gsl_fft_complex_wavetable_alloc ((size_t) len);
2728   ws = gsl_fft_complex_workspace_alloc ((size_t) len);
2729   rc = gsl_fft_complex_inverse (data, 1, (size_t) len, wt, ws);
2730   fft_test_error (rc);
2731   push_array_complex (p, data, len);
2732   gsl_fft_complex_wavetable_free (wt);
2733   gsl_fft_complex_workspace_free (ws);
2734   if (data != NO_REAL) {
2735     free (data);
2736   }
2737   (void) gsl_set_error_handler (save_handler);
2738 }
2739 
2740 /**
2741 @brief PROC ([] REAL) [] COMPLEX fft forward
2742 @param p Node in syntax tree.
2743 **/
2744 
2745 void
genie_fft_forward(NODE_T * p)2746 genie_fft_forward (NODE_T * p)
2747 {
2748   gsl_error_handler_t *save_handler = gsl_set_error_handler (fft_error_handler);
2749   int len, rc;
2750   double *data;
2751   gsl_fft_complex_wavetable *wt;
2752   gsl_fft_complex_workspace *ws;
2753   error_node = p;
2754   data = pop_array_real (p, &len);
2755   fft_test_error (len == 0 ? GSL_EDOM : GSL_SUCCESS);
2756   wt = gsl_fft_complex_wavetable_alloc ((size_t) len);
2757   ws = gsl_fft_complex_workspace_alloc ((size_t) len);
2758   rc = gsl_fft_complex_forward (data, 1, (size_t) len, wt, ws);
2759   fft_test_error (rc);
2760   push_array_complex (p, data, len);
2761   gsl_fft_complex_wavetable_free (wt);
2762   gsl_fft_complex_workspace_free (ws);
2763   if (data != NO_REAL) {
2764     free (data);
2765   }
2766   (void) gsl_set_error_handler (save_handler);
2767 }
2768 
2769 /**
2770 @brief PROC ([] COMPLEX) [] REAL fft backward
2771 @param p Node in syntax tree.
2772 **/
2773 
2774 void
genie_fft_backward(NODE_T * p)2775 genie_fft_backward (NODE_T * p)
2776 {
2777   gsl_error_handler_t *save_handler = gsl_set_error_handler (fft_error_handler);
2778   int len, rc;
2779   double *data;
2780   gsl_fft_complex_wavetable *wt;
2781   gsl_fft_complex_workspace *ws;
2782   error_node = p;
2783   data = pop_array_complex (p, &len);
2784   fft_test_error (len == 0 ? GSL_EDOM : GSL_SUCCESS);
2785   wt = gsl_fft_complex_wavetable_alloc ((size_t) len);
2786   ws = gsl_fft_complex_workspace_alloc ((size_t) len);
2787   rc = gsl_fft_complex_backward (data, 1, (size_t) len, wt, ws);
2788   fft_test_error (rc);
2789   push_array_real (p, data, len);
2790   gsl_fft_complex_wavetable_free (wt);
2791   gsl_fft_complex_workspace_free (ws);
2792   if (data != NO_REAL) {
2793     free (data);
2794   }
2795   (void) gsl_set_error_handler (save_handler);
2796 }
2797 
2798 /**
2799 @brief PROC ([] COMPLEX) [] REAL fft inverse
2800 @param p Node in syntax tree.
2801 **/
2802 
2803 void
genie_fft_inverse(NODE_T * p)2804 genie_fft_inverse (NODE_T * p)
2805 {
2806   gsl_error_handler_t *save_handler = gsl_set_error_handler (fft_error_handler);
2807   int len, rc;
2808   double *data;
2809   gsl_fft_complex_wavetable *wt;
2810   gsl_fft_complex_workspace *ws;
2811   error_node = p;
2812   data = pop_array_complex (p, &len);
2813   fft_test_error (len == 0 ? GSL_EDOM : GSL_SUCCESS);
2814   wt = gsl_fft_complex_wavetable_alloc ((size_t) len);
2815   ws = gsl_fft_complex_workspace_alloc ((size_t) len);
2816   rc = gsl_fft_complex_inverse (data, 1, (size_t) len, wt, ws);
2817   fft_test_error (rc);
2818   push_array_real (p, data, len);
2819   gsl_fft_complex_wavetable_free (wt);
2820   gsl_fft_complex_workspace_free (ws);
2821   if (data != NO_REAL) {
2822     free (data);
2823   }
2824   (void) gsl_set_error_handler (save_handler);
2825 }
2826 
2827 /**
2828 @brief Map GSL error handler onto a68g error handler.
2829 @param reason Error text.
2830 @param file Gsl file where error occured.
2831 @param line Line in above file.
2832 @param gsl_errno Gsl error number.
2833 **/
2834 
2835 void
laplace_error_handler(const char * reason,const char * file,int line,int gsl_errno)2836 laplace_error_handler (const char *reason, const char *file, int line, int gsl_errno)
2837 {
2838   if (line != 0) {
2839     ASSERT (snprintf (edit_line, SNPRINTF_SIZE, "%s in line %d of file %s", reason, line, file) >= 0);
2840   } else {
2841     ASSERT (snprintf (edit_line, SNPRINTF_SIZE, "%s", reason) >= 0);
2842   }
2843   diagnostic_node (A68_RUNTIME_ERROR, error_node, ERROR_LAPLACE, edit_line, gsl_strerror (gsl_errno));
2844   exit_genie (error_node, A68_RUNTIME_ERROR);
2845 }
2846 
2847 /**
2848 @brief Detect math errors.
2849 @param rc Return code from function.
2850 **/
2851 
2852 static void
laplace_test_error(int rc)2853 laplace_test_error (int rc)
2854 {
2855   if (rc != 0) {
2856     laplace_error_handler ("math error", "", 0, rc);
2857   }
2858 }
2859 
2860 /**
2861 @brief PROC (PROC (REAL) REAL, REAL, REF REAL) REAL laplace
2862 @param p Node in syntax tree.
2863 **/
2864 
2865 #define LAPLACE_DIVISIONS 1024
2866 
2867 typedef struct A68_LAPLACE A68_LAPLACE;
2868 
2869 struct A68_LAPLACE
2870 {
2871   NODE_T *p;
2872   A68_PROCEDURE f;
2873   double s;
2874 };
2875 
2876 /**
2877 @brief Evaluate function for Laplace transform.
2878 @param t Argument.
2879 @param z LAPLACE value.
2880 **/
2881 
2882 double
laplace_f(double t,void * z)2883 laplace_f (double t, void *z)
2884 {
2885   A68_LAPLACE *l = (A68_LAPLACE *) z;
2886   ADDR_T pop_sp = stack_pointer, pop_fp = frame_pointer;
2887   MOID_T *u = MODE (PROC_REAL_REAL);
2888   A68_REAL *ft = (A68_REAL *) STACK_TOP;
2889   PUSH_PRIMITIVE (P (l), t, A68_REAL);
2890   genie_call_procedure (P (l), MOID (&(F (l))), u, u, &(F (l)), pop_sp, pop_fp);
2891   stack_pointer = pop_sp;
2892   return (VALUE (ft) * a68g_exp (-(S (l)) * t));
2893 }
2894 
2895 /**
2896 @brief Calculate Laplace transform.
2897 @param p Node in syntax tree.
2898 **/
2899 
2900 void
genie_laplace(NODE_T * p)2901 genie_laplace (NODE_T * p)
2902 {
2903   A68_REF ref_error;
2904   A68_REAL s, *error;
2905   A68_PROCEDURE f;
2906   A68_LAPLACE l;
2907   gsl_function g;
2908   gsl_integration_workspace *w;
2909   double result, estimated_error;
2910   int rc;
2911   gsl_error_handler_t *save_handler = gsl_set_error_handler (laplace_error_handler);
2912   POP_REF (p, &ref_error);
2913   CHECK_REF (p, ref_error, MODE (REF_REAL));
2914   error = (A68_REAL *) ADDRESS (&ref_error);
2915   POP_OBJECT (p, &s, A68_REAL);
2916   POP_PROCEDURE (p, &f);
2917   P (&l) = p;
2918   F (&l) = f;
2919   S (&l) = VALUE (&s);
2920   FUNCTION (&g) = &laplace_f;
2921   GSL_PARAMS (&g) = &l;
2922   w = gsl_integration_workspace_alloc (LAPLACE_DIVISIONS);
2923   if (VALUE (error) >= 0.0) {
2924     rc = gsl_integration_qagiu (&g, 0.0, VALUE (error), 0.0, LAPLACE_DIVISIONS, w, &result, &estimated_error);
2925   } else {
2926     rc = gsl_integration_qagiu (&g, 0.0, 0.0, -VALUE (error), LAPLACE_DIVISIONS, w, &result, &estimated_error);
2927   }
2928   laplace_test_error (rc);
2929   VALUE (error) = estimated_error;
2930   PUSH_PRIMITIVE (p, result, A68_REAL);
2931   gsl_integration_workspace_free (w);
2932   (void) gsl_set_error_handler (save_handler);
2933 }
2934 
2935 #endif /* defined HAVE_GNU_GSL */
2936