single-torrix-gsl.c

     
   1  //! @file single-torrix-gsl.c
   2  //! @author J. Marcel van der Veer
   3  
   4  //! @section Copyright
   5  //!
   6  //! This file is part of Algol68G - an Algol 68 compiler-interpreter.
   7  //! Copyright 2001-2025 J. Marcel van der Veer [algol68g@xs4all.nl].
   8  
   9  //! @section License
  10  //!
  11  //! This program is free software; you can redistribute it and/or modify it 
  12  //! under the terms of the GNU General Public License as published by the 
  13  //! Free Software Foundation; either version 3 of the License, or 
  14  //! (at your option) any later version.
  15  //!
  16  //! This program is distributed in the hope that it will be useful, but 
  17  //! WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
  18  //! or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 
  19  //! more details. You should have received a copy of the GNU General Public 
  20  //! License along with this program. If not, see [http://www.gnu.org/licenses/].
  21  
  22  //! @section Synopsis
  23  //!
  24  //! REAL GSL vector and matrix routines.
  25  
  26  #include "a68g.h"
  27  #include "a68g-torrix.h"
  28  
  29  #if defined (HAVE_GSL)
  30  
  31  //! @brief Set permutation vector element - function fails in gsl.
  32  
  33  void gsl_permutation_set (const gsl_permutation * p, const size_t i, const size_t j)
  34  {
  35    DATA (p)[i] = j;
  36  }
  37  
  38  //! @brief Map GSL error handler onto a68g error handler.
  39  
  40  void torrix_error_handler (const char *reason, const char *file, int line, int gsl_errno)
  41  {
  42    if (line != 0) {
  43      ASSERT (a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "%s in line %d of file %s", reason, line, file) >= 0);
  44    } else {
  45      ASSERT (a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "%s", reason) >= 0);
  46    }
  47    diagnostic (A68G_RUNTIME_ERROR, A68G (f_entry), ERROR_TORRIX, A68G (edit_line), gsl_strerror (gsl_errno));
  48    exit_genie (A68G (f_entry), A68G_RUNTIME_ERROR);
  49  }
  50  
  51  //! @brief Pop [] INT on the stack as gsl_permutation.
  52  
  53  gsl_permutation *pop_permutation (NODE_T * p, BOOL_T get)
  54  {
  55    A68G_REF desc; A68G_ARRAY *arr; A68G_TUPLE *tup;
  56    POP_REF (p, &desc);
  57    CHECK_REF (p, desc, M_ROW_INT);
  58    GET_DESCRIPTOR (arr, tup, &desc);
  59    size_t len = ROW_SIZE (tup);
  60    gsl_permutation *v = gsl_permutation_calloc ((size_t) len);
  61    if (get && len > 0) {
  62      BYTE_T *base = DEREF (BYTE_T, &ARRAY (arr));
  63      int idx = VECTOR_OFFSET (arr, tup);
  64      int inc = SPAN (tup) * ELEM_SIZE (arr);
  65      for (int k = 0; k < len; k++, idx += inc) {
  66        A68G_INT *x = (A68G_INT *) (base + idx);
  67        CHECK_INIT (p, INITIALISED (x), M_INT);
  68        gsl_permutation_set (v, (size_t) k, (size_t) VALUE (x));
  69      }
  70    }
  71    return v;
  72  }
  73  
  74  //! @brief Push gsl_permutation on the stack as [] INT.
  75  
  76  void push_permutation (NODE_T * p, gsl_permutation * v)
  77  {
  78    size_t len = SIZE (v);
  79    A68G_REF desc, row; A68G_ARRAY arr; A68G_TUPLE tup;
  80    NEW_ROW_1D (desc, row, arr, tup, M_ROW_INT, M_INT, len);
  81    BYTE_T *base = DEREF (BYTE_T, &ARRAY (&arr));
  82    int idx = VECTOR_OFFSET (&arr, &tup);
  83    int inc = SPAN (&tup) * ELEM_SIZE (&arr);
  84    for (size_t k = 0; k < len; k++, idx += inc) {
  85      A68G_INT *x = (A68G_INT *) (base + idx);
  86      STATUS (x) = INIT_MASK;
  87      VALUE (x) = (INT_T) gsl_permutation_get (v, k);
  88    }
  89    PUSH_REF (p, desc);
  90  }
  91  
  92  //! @brief Pop [] REAL on the stack as gsl_vector.
  93  
  94  gsl_vector *pop_vector (NODE_T * p, BOOL_T get)
  95  {
  96    A68G_REF desc; A68G_ARRAY *arr; A68G_TUPLE *tup;
  97    POP_REF (p, &desc);
  98    CHECK_REF (p, desc, M_ROW_REAL);
  99    GET_DESCRIPTOR (arr, tup, &desc);
 100    size_t len = ROW_SIZE (tup);
 101    gsl_vector *v = gsl_vector_calloc ((size_t) len);
 102    if (get && len > 0) {
 103      BYTE_T *base = DEREF (BYTE_T, &ARRAY (arr));
 104      int idx = VECTOR_OFFSET (arr, tup);
 105      int inc = SPAN (tup) * ELEM_SIZE (arr);
 106      for (int k = 0; k < len; k++, idx += inc) {
 107        A68G_REAL *x = (A68G_REAL *) (base + idx);
 108        CHECK_INIT (p, INITIALISED (x), M_REAL);
 109        gsl_vector_set (v, (size_t) k, VALUE (x));
 110      }
 111    }
 112    return v;
 113  }
 114  
 115  //! @brief Push gsl_vector on the stack as [] REAL.
 116  
 117  void push_vector (NODE_T * p, gsl_vector * v)
 118  {
 119    PUSH_REF (p, vector_to_row (p, v));
 120  }
 121  
 122  //! @brief Pop [, ] REAL on the stack as gsl_matrix.
 123  
 124  gsl_matrix *pop_matrix (NODE_T * p, BOOL_T get)
 125  {
 126    A68G_REF desc; A68G_ARRAY *arr; A68G_TUPLE *tup1, *tup2;
 127    POP_REF (p, &desc);
 128    CHECK_REF (p, desc, M_ROW_ROW_REAL);
 129    GET_DESCRIPTOR (arr, tup1, &desc);
 130    tup2 = &(tup1[1]);
 131    size_t len1 = ROW_SIZE (tup1), len2 = ROW_SIZE (tup2);
 132    gsl_matrix *a = gsl_matrix_calloc ((size_t) len1, (size_t) len2);
 133    if (get && (len1 * len2 > 0)) {
 134      BYTE_T *base = DEREF (BYTE_T, &ARRAY (arr));
 135      int idx1 = MATRIX_OFFSET (arr, tup1, tup2);
 136      int inc1 = SPAN (tup1) * ELEM_SIZE (arr), inc2 = SPAN (tup2) * ELEM_SIZE (arr);
 137      for (int k1 = 0; k1 < len1; k1++, idx1 += inc1) {
 138        for (int k2 = 0, idx2 = idx1; k2 < len2; k2++, idx2 += inc2) {
 139          A68G_REAL *x = (A68G_REAL *) (base + idx2);
 140          CHECK_INIT (p, INITIALISED (x), M_REAL);
 141          gsl_matrix_set (a, (size_t) k1, (size_t) k2, VALUE (x));
 142        }
 143      }
 144    }
 145    return a;
 146  }
 147  
 148  //! @brief Push gsl_matrix on the stack as [, ] REAL.
 149  
 150  void push_matrix (NODE_T * p, gsl_matrix * a)
 151  {
 152    PUSH_REF (p, matrix_to_row (p, a));
 153  }
 154  
 155  //! @brief Pop [] COMPLEX on the stack as gsl_vector_complex.
 156  
 157  gsl_vector_complex *pop_vector_complex (NODE_T * p, BOOL_T get)
 158  {
 159    A68G_REF desc; A68G_ARRAY *arr; A68G_TUPLE *tup;
 160    POP_REF (p, &desc);
 161    CHECK_REF (p, desc, M_ROW_COMPLEX);
 162    GET_DESCRIPTOR (arr, tup, &desc);
 163    size_t len = ROW_SIZE (tup);
 164    gsl_vector_complex *v = gsl_vector_complex_calloc ((size_t) len);
 165    if (get && len > 0) {
 166      BYTE_T *base = DEREF (BYTE_T, &ARRAY (arr));
 167      int idx = VECTOR_OFFSET (arr, tup);
 168      int inc = SPAN (tup) * ELEM_SIZE (arr);
 169      for (int k = 0; k < len; k++, idx += inc) {
 170        A68G_REAL *re = (A68G_REAL *) (base + idx);
 171        A68G_REAL *im = (A68G_REAL *) (base + idx + SIZE (M_REAL));
 172        gsl_complex z;
 173        CHECK_INIT (p, INITIALISED (re), M_COMPLEX);
 174        CHECK_INIT (p, INITIALISED (im), M_COMPLEX);
 175        GSL_SET_COMPLEX (&z, VALUE (re), VALUE (im));
 176        gsl_vector_complex_set (v, (size_t) k, z);
 177      }
 178    }
 179    return v;
 180  }
 181  
 182  //! @brief Push gsl_vector_complex on the stack as [] COMPLEX.
 183  
 184  void push_vector_complex (NODE_T * p, gsl_vector_complex * v)
 185  {
 186    size_t len = SIZE (v);
 187    A68G_REF desc, row; A68G_ARRAY arr; A68G_TUPLE tup;
 188    NEW_ROW_1D (desc, row, arr, tup, M_ROW_COMPLEX, M_COMPLEX, len);
 189    BYTE_T *base = DEREF (BYTE_T, &ARRAY (&arr));
 190    int idx = VECTOR_OFFSET (&arr, &tup);
 191    int inc = SPAN (&tup) * ELEM_SIZE (&arr);
 192    for (int k = 0; k < len; k++, idx += inc) {
 193      A68G_REAL *re = (A68G_REAL *) (base + idx);
 194      A68G_REAL *im = (A68G_REAL *) (base + idx + SIZE (M_REAL));
 195      gsl_complex z = gsl_vector_complex_get (v, (size_t) k);
 196      STATUS (re) = INIT_MASK;
 197      VALUE (re) = GSL_REAL (z);
 198      STATUS (im) = INIT_MASK;
 199      VALUE (im) = GSL_IMAG (z);
 200      CHECK_COMPLEX (p, VALUE (re), VALUE (im));
 201    }
 202    PUSH_REF (p, desc);
 203  }
 204  
 205  //! @brief Pop [, ] COMPLEX on the stack as gsl_matrix_complex.
 206  
 207  gsl_matrix_complex *pop_matrix_complex (NODE_T * p, BOOL_T get)
 208  {
 209    A68G_REF desc; A68G_ARRAY *arr; A68G_TUPLE *tup1, *tup2;
 210    POP_REF (p, &desc);
 211    CHECK_REF (p, desc, M_ROW_ROW_COMPLEX);
 212    GET_DESCRIPTOR (arr, tup1, &desc);
 213    tup2 = &(tup1[1]);
 214    size_t len1 = ROW_SIZE (tup1), len2 = ROW_SIZE (tup2);
 215    gsl_matrix_complex *a = gsl_matrix_complex_calloc ((size_t) len1, (size_t) len2);
 216    if (get && (len1 * len2 > 0)) {
 217      BYTE_T *base = DEREF (BYTE_T, &ARRAY (arr));
 218      int idx1 = MATRIX_OFFSET (arr, tup1, tup2);
 219      int inc1 = SPAN (tup1) * ELEM_SIZE (arr), inc2 = SPAN (tup2) * ELEM_SIZE (arr);
 220      for (int k1 = 0; k1 < len1; k1++, idx1 += inc1) {
 221        for (int k2 = 0, idx2 = idx1; k2 < len2; k2++, idx2 += inc2) {
 222          A68G_REAL *re = (A68G_REAL *) (base + idx2);
 223          A68G_REAL *im = (A68G_REAL *) (base + idx2 + SIZE (M_REAL));
 224          CHECK_INIT (p, INITIALISED (re), M_COMPLEX);
 225          CHECK_INIT (p, INITIALISED (im), M_COMPLEX);
 226          gsl_complex z;
 227          GSL_SET_COMPLEX (&z, VALUE (re), VALUE (im));
 228          gsl_matrix_complex_set (a, (size_t) k1, (size_t) k2, z);
 229        }
 230      }
 231    }
 232    return a;
 233  }
 234  
 235  //! @brief Push gsl_matrix_complex on the stack as [, ] COMPLEX.
 236  
 237  void push_matrix_complex (NODE_T * p, gsl_matrix_complex * a)
 238  {
 239    size_t len1 = SIZE1 (a), len2 = SIZE2 (a);
 240    A68G_REF desc, row; A68G_ARRAY arr; A68G_TUPLE tup1, tup2;
 241    desc = heap_generator (p, M_ROW_ROW_COMPLEX, DESCRIPTOR_SIZE (2));
 242    row = heap_generator_3 (p, M_ROW_ROW_COMPLEX, len1, len2, 2 * SIZE (M_REAL));
 243    DIM (&arr) = 2;
 244    MOID (&arr) = M_COMPLEX;
 245    ELEM_SIZE (&arr) = 2 * SIZE (M_REAL);
 246    SLICE_OFFSET (&arr) = FIELD_OFFSET (&arr) = 0;
 247    ARRAY (&arr) = row;
 248    LWB (&tup1) = 1; UPB (&tup1) = len1; SPAN (&tup1) = 1;
 249    SHIFT (&tup1) = LWB (&tup1); K (&tup1) = 0;
 250    LWB (&tup2) = 1; UPB (&tup2) = len2; SPAN (&tup2) = ROW_SIZE (&tup1);
 251    SHIFT (&tup2) = LWB (&tup2) * SPAN (&tup2); K (&tup2) = 0;
 252    PUT_DESCRIPTOR2 (arr, tup1, tup2, &desc);
 253    BYTE_T *base = DEREF (BYTE_T, &ARRAY (&arr));
 254    int idx1 = MATRIX_OFFSET (&arr, &tup1, &tup2);
 255    int inc1 = SPAN (&tup1) * ELEM_SIZE (&arr), inc2 = SPAN (&tup2) * ELEM_SIZE (&arr);
 256    for (int k1 = 0; k1 < len1; k1++, idx1 += inc1) {
 257      for (int k2 = 0, idx2 = idx1; k2 < len2; k2++, idx2 += inc2) {
 258        A68G_REAL *re = (A68G_REAL *) (base + idx2);
 259        A68G_REAL *im = (A68G_REAL *) (base + idx2 + SIZE (M_REAL));
 260        gsl_complex z = gsl_matrix_complex_get (a, (size_t) k1, (size_t) k2);
 261        STATUS (re) = INIT_MASK;
 262        VALUE (re) = GSL_REAL (z);
 263        STATUS (im) = INIT_MASK;
 264        VALUE (im) = GSL_IMAG (z);
 265        CHECK_COMPLEX (p, VALUE (re), VALUE (im));
 266      }
 267    }
 268    PUSH_REF (p, desc);
 269  }
 270  
 271  //! @brief Generically perform operation and assign result (+:=, -:=, ...) .
 272  
 273  void op_ab_torrix (NODE_T * p, MOID_T * m, MOID_T * n, GPROC * op)
 274  {
 275    ADDR_T parm_size = SIZE (m) + SIZE (n);
 276    A68G_REF dst, src, *save = (A68G_REF *) STACK_OFFSET (-parm_size);
 277    dst = *save;
 278    CHECK_REF (p, dst, m);
 279    *save = *DEREF (A68G_ROW, &dst);
 280    STATUS (&src) = (STATUS_MASK_T) (INIT_MASK | IN_STACK_MASK);
 281    OFFSET (&src) = A68G_SP - parm_size;
 282    (*op) (p);
 283    if (IS_REF (m)) {
 284      genie_store (p, SUB (m), &dst, &src);
 285    } else {
 286      ABEND (A68G_TRUE, ERROR_INTERNAL_CONSISTENCY, __func__);
 287    }
 288    *save = dst;
 289  }
 290  
 291  //! @brief PROC vector echo = ([] REAL) [] REAL
 292  
 293  void genie_vector_echo (NODE_T * p)
 294  {
 295    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
 296    gsl_vector *u = pop_vector (p, A68G_TRUE);
 297    push_vector (p, u);
 298    gsl_vector_free (u);
 299    (void) gsl_set_error_handler (save_handler);
 300  }
 301  
 302  //! @brief PROC matrix echo = ([, ] REAL) [, ] REAL
 303  
 304  void genie_matrix_echo (NODE_T * p)
 305  {
 306    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
 307    gsl_matrix *a = pop_matrix (p, A68G_TRUE);
 308    push_matrix (p, a);
 309    gsl_matrix_free (a);
 310    (void) gsl_set_error_handler (save_handler);
 311  }
 312  
 313  //! @brief PROC complex vector echo = ([] COMPLEX) [] COMPLEX
 314  
 315  void genie_vector_complex_echo (NODE_T * p)
 316  {
 317    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
 318    gsl_vector_complex *u = pop_vector_complex (p, A68G_TRUE);
 319    push_vector_complex (p, u);
 320    gsl_vector_complex_free (u);
 321    (void) gsl_set_error_handler (save_handler);
 322  }
 323  
 324  //! @brief PROC complex matrix echo = ([, ] COMPLEX) [, ] COMPLEX
 325  
 326  void genie_matrix_complex_echo (NODE_T * p)
 327  {
 328    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
 329    gsl_matrix_complex *a = pop_matrix_complex (p, A68G_TRUE);
 330    push_matrix_complex (p, a);
 331    gsl_matrix_complex_free (a);
 332    (void) gsl_set_error_handler (save_handler);
 333  }
 334  
 335  //! @brief OP ROW = ([] REAL) [, ] REAL
 336  
 337  void genie_vector_row (NODE_T * p)
 338  {
 339    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
 340    gsl_vector *u = pop_vector (p, A68G_TRUE);
 341    gsl_matrix *v = gsl_matrix_calloc (1, SIZE (u));
 342    ASSERT_GSL (gsl_matrix_set_row (v, 0, u));
 343    push_matrix (p, v);
 344    gsl_vector_free (u);
 345    gsl_matrix_free (v);
 346    (void) gsl_set_error_handler (save_handler);
 347  }
 348  
 349  //! @brief OP COL = ([] REAL) [, ] REAL
 350  
 351  void genie_vector_col (NODE_T * p)
 352  {
 353    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
 354    gsl_vector *u = pop_vector (p, A68G_TRUE);
 355    gsl_matrix *v = gsl_matrix_calloc (SIZE (u), 1);
 356    ASSERT_GSL (gsl_matrix_set_col (v, 0, u));
 357    push_matrix (p, v);
 358    gsl_vector_free (u);
 359    gsl_matrix_free (v);
 360    (void) gsl_set_error_handler (save_handler);
 361  }
 362  
 363  //! @brief OP - = ([] REAL) [] REAL
 364  
 365  void genie_vector_minus (NODE_T * p)
 366  {
 367    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
 368    gsl_vector *u = pop_vector (p, A68G_TRUE);
 369    ASSERT_GSL (gsl_vector_scale (u, -1));
 370    push_vector (p, u);
 371    gsl_vector_free (u);
 372    (void) gsl_set_error_handler (save_handler);
 373  }
 374  
 375  //! @brief OP - = ([, ] REAL) [, ] REAL
 376  
 377  void genie_matrix_minus (NODE_T * p)
 378  {
 379    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
 380    gsl_matrix * a = pop_matrix (p, A68G_TRUE);
 381    ASSERT_GSL (gsl_matrix_scale (a, -1));
 382    push_matrix (p, a);
 383    gsl_matrix_free (a);
 384    (void) gsl_set_error_handler (save_handler);
 385  }
 386  
 387  //! @brief OP T = ([, ] REAL) [, ] REAL
 388  
 389  void genie_matrix_transpose (NODE_T * p)
 390  {
 391    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
 392    gsl_matrix *a = pop_matrix (p, A68G_TRUE);
 393    gsl_matrix *t = gsl_matrix_calloc (SIZE2(a), SIZE1(a));
 394    ASSERT_GSL (gsl_matrix_transpose_memcpy (t, a));
 395    push_matrix (p, t);
 396    gsl_matrix_free (a);
 397    gsl_matrix_free (t);
 398    (void) gsl_set_error_handler (save_handler);
 399  }
 400  
 401  //! @brief OP T = ([, ] COMPLEX) [, ] COMPLEX
 402  
 403  void genie_matrix_complex_transpose (NODE_T * p)
 404  {
 405    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
 406    gsl_matrix_complex *a = pop_matrix_complex (p, A68G_TRUE);
 407    gsl_matrix_complex *t = gsl_matrix_complex_calloc (SIZE2(a), SIZE1(a));
 408    ASSERT_GSL ( gsl_matrix_complex_transpose_memcpy (t, a));
 409    push_matrix_complex (p, a);
 410    gsl_matrix_complex_free (a);
 411    gsl_matrix_complex_free (t);
 412    (void) gsl_set_error_handler (save_handler);
 413  }
 414  
 415  //! @brief OP INV = ([, ] REAL) [, ] REAL
 416  
 417  void genie_matrix_inv (NODE_T * p)
 418  {
 419  // Avoid direct use of the inverse whenever possible; linear solver functions
 420  // can obtain the same result more efficiently and reliably.
 421  // Consult any introductory textbook on numerical linear algebra for details.
 422    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
 423    gsl_matrix *u = pop_matrix (p, A68G_TRUE);
 424    unt M = SIZE1 (u), N =SIZE2 (u);
 425    MATH_RTE (p, M != N, M_ROW_ROW_REAL, "matrix is not square");
 426    gsl_matrix *inv = NO_REAL_MATRIX;
 427    compute_pseudo_inverse (p, &inv, u, 0); // Pseudo inverse equals inverse for a square matrix.
 428    push_matrix (p, inv);
 429    gsl_matrix_free (inv);
 430    gsl_matrix_free (u);
 431    (void) gsl_set_error_handler (save_handler);
 432  }
 433  
 434  //! @brief OP INV = ([, ] COMPLEX) [, ] COMPLEX
 435  
 436  void genie_matrix_complex_inv (NODE_T * p)
 437  {
 438  // Avoid direct use of the inverse whenever possible; linear solver functions
 439  // can obtain the same result more efficiently and reliably.
 440  // Consult any introductory textbook on numerical linear algebra for details.
 441    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
 442    gsl_matrix_complex *u = pop_matrix_complex (p, A68G_TRUE);
 443    unt M = SIZE1 (u), N =SIZE2 (u);
 444    MATH_RTE (p, M != N, M_ROW_ROW_COMPLEX, "matrix is not square");
 445    gsl_permutation *q = gsl_permutation_calloc (SIZE1 (u));
 446    int sign;
 447    ASSERT_GSL (gsl_linalg_complex_LU_decomp (u, q, &sign));
 448    gsl_matrix_complex *inv = gsl_matrix_complex_calloc (SIZE1 (u), SIZE2 (u));
 449    ASSERT_GSL (gsl_linalg_complex_LU_invert (u, q, inv));
 450    push_matrix_complex (p, inv);
 451    gsl_matrix_complex_free (inv);
 452    gsl_matrix_complex_free (u);
 453    gsl_permutation_free (q);
 454    (void) gsl_set_error_handler (save_handler);
 455  }
 456  
 457  //! @brief OP DET = ([, ] REAL) REAL
 458  
 459  void genie_matrix_det (NODE_T * p)
 460  {
 461    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
 462    gsl_matrix *u = pop_matrix (p, A68G_TRUE);
 463    gsl_permutation *q = gsl_permutation_calloc (SIZE1 (u));
 464    int sign;
 465    ASSERT_GSL (gsl_linalg_LU_decomp (u, q, &sign));
 466    REAL_T det = gsl_linalg_LU_det (u, sign);
 467    if (a68g_isnan_real (det)) { // Singularity.
 468      PUSH_VALUE (p, 0, A68G_REAL);
 469    } else {
 470      PUSH_VALUE (p, gsl_linalg_LU_det (u, sign), A68G_REAL);
 471    }
 472    gsl_matrix_free (u);
 473    gsl_permutation_free (q);
 474    (void) gsl_set_error_handler (save_handler);
 475  }
 476  
 477  //! @brief OP DET = ([, ] COMPLEX) COMPLEX
 478  
 479  void genie_matrix_complex_det (NODE_T * p)
 480  {
 481    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
 482    gsl_matrix_complex *u = pop_matrix_complex (p, A68G_TRUE);
 483    gsl_permutation *q = gsl_permutation_calloc (SIZE1 (u));
 484    int sign;
 485    ASSERT_GSL (gsl_linalg_complex_LU_decomp (u, q, &sign));
 486    gsl_complex det = gsl_linalg_complex_LU_det (u, sign);
 487    REAL_T re_det = GSL_REAL (det);
 488    if (a68g_isnan_real (re_det)) { // Singularity.
 489      PUSH_VALUE (p, 0, A68G_REAL);
 490    } else {
 491      PUSH_VALUE (p, re_det, A68G_REAL);
 492    }
 493    REAL_T im_det = GSL_IMAG (det);
 494    if (a68g_isnan_real (im_det)) { // Singularity.
 495      PUSH_VALUE (p, 0, A68G_REAL);
 496    } else {
 497      PUSH_VALUE (p, im_det, A68G_REAL);
 498    }
 499    gsl_matrix_complex_free (u);
 500    gsl_permutation_free (q);
 501    (void) gsl_set_error_handler (save_handler);
 502  }
 503  
 504  //! @brief OP TRACE = ([, ] REAL) REAL
 505  
 506  void genie_matrix_trace (NODE_T * p)
 507  {
 508    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
 509    gsl_matrix *a = pop_matrix (p, A68G_TRUE);
 510    size_t len1 = SIZE1 (a), len2 = SIZE2 (a);
 511    if (len1 != len2) {
 512      torrix_error_handler ("cannot calculate trace", __FILE__, __LINE__, GSL_ENOTSQR);
 513    }
 514    REAL_T sum = 0.0;
 515    for (int k = 0; k < len1; k++) {
 516      sum += gsl_matrix_get (a, (size_t) k, (size_t) k);
 517    }
 518    PUSH_VALUE (p, sum, A68G_REAL);
 519    gsl_matrix_free (a);
 520    (void) gsl_set_error_handler (save_handler);
 521  }
 522  
 523  //! @brief OP TRACE = ([, ] COMPLEX) COMPLEX
 524  
 525  void genie_matrix_complex_trace (NODE_T * p)
 526  {
 527    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
 528    gsl_matrix_complex *a = pop_matrix_complex (p, A68G_TRUE);
 529    size_t len1 = SIZE1 (a), len2 = SIZE2 (a);
 530    if (len1 != len2) {
 531      torrix_error_handler ("cannot calculate trace", __FILE__, __LINE__, GSL_ENOTSQR);
 532    }
 533    gsl_complex sum;
 534    GSL_SET_COMPLEX (&sum, 0.0, 0.0);
 535    for (int k = 0; k < len1; k++) {
 536      sum = gsl_complex_add (sum, gsl_matrix_complex_get (a, (size_t) k, (size_t) k));
 537    }
 538    PUSH_VALUE (p, GSL_REAL (sum), A68G_REAL);
 539    PUSH_VALUE (p, GSL_IMAG (sum), A68G_REAL);
 540    gsl_matrix_complex_free (a);
 541    (void) gsl_set_error_handler (save_handler);
 542  }
 543  
 544  //! @brief OP - = ([] COMPLEX) [] COMPLEX
 545  
 546  void genie_vector_complex_minus (NODE_T * p)
 547  {
 548    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
 549    gsl_vector_complex *u = pop_vector_complex (p, A68G_TRUE);
 550    gsl_blas_zdscal (-1, u);
 551    push_vector_complex (p, u);
 552    gsl_vector_complex_free (u);
 553    (void) gsl_set_error_handler (save_handler);
 554  }
 555  
 556  //! @brief OP - = ([, ] COMPLEX) [, ] COMPLEX
 557  
 558  void genie_matrix_complex_minus (NODE_T * p)
 559  {
 560    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
 561    gsl_complex one;
 562    GSL_SET_COMPLEX (&one, -1.0, 0.0);
 563    gsl_matrix_complex *a = pop_matrix_complex (p, A68G_TRUE);
 564    ASSERT_GSL (gsl_matrix_complex_scale (a, one));
 565    push_matrix_complex (p, a);
 566    gsl_matrix_complex_free (a);
 567    (void) gsl_set_error_handler (save_handler);
 568  }
 569  
 570  //! @brief OP + = ([] REAL, [] REAL) [] REAL
 571  
 572  void genie_vector_add (NODE_T * p)
 573  {
 574    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
 575    gsl_vector *v = pop_vector (p, A68G_TRUE);
 576    gsl_vector *u = pop_vector (p, A68G_TRUE);
 577    ASSERT_GSL (gsl_vector_add (u, v));
 578    push_vector (p, u);
 579    gsl_vector_free (u);
 580    gsl_vector_free (v);
 581    (void) gsl_set_error_handler (save_handler);
 582  }
 583  
 584  //! @brief OP - = ([] REAL, [] REAL) [] REAL
 585  
 586  void genie_vector_sub (NODE_T * p)
 587  {
 588    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
 589    gsl_vector *v = pop_vector (p, A68G_TRUE);
 590    gsl_vector *u = pop_vector (p, A68G_TRUE);
 591    ASSERT_GSL (gsl_vector_sub (u, v));
 592    push_vector (p, u);
 593    gsl_vector_free (u);
 594    gsl_vector_free (v);
 595    (void) gsl_set_error_handler (save_handler);
 596  }
 597  
 598  //! @brief OP = = ([] REAL, [] REAL) BOOL
 599  
 600  void genie_vector_eq (NODE_T * p)
 601  {
 602    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
 603    gsl_vector *v = pop_vector (p, A68G_TRUE);
 604    gsl_vector *u = pop_vector (p, A68G_TRUE);
 605    ASSERT_GSL (gsl_vector_sub (u, v));
 606    PUSH_VALUE (p, (BOOL_T) (gsl_vector_isnull (u) ? A68G_TRUE : A68G_FALSE), A68G_BOOL);
 607    gsl_vector_free (u);
 608    gsl_vector_free (v);
 609    (void) gsl_set_error_handler (save_handler);
 610  }
 611  
 612  //! @brief OP /= = ([] REAL, [] REAL) BOOL
 613  
 614  void genie_vector_ne (NODE_T * p)
 615  {
 616    genie_vector_eq (p);
 617    genie_not_bool (p);
 618  }
 619  
 620  //! @brief OP +:= = (REF [] REAL, [] REAL) REF [] REAL
 621  
 622  void genie_vector_plusab (NODE_T * p)
 623  {
 624    op_ab_torrix (p, M_REF_ROW_REAL, M_ROW_REAL, genie_vector_add);
 625  }
 626  
 627  //! @brief OP -:= = (REF [] REAL, [] REAL) REF [] REAL
 628  
 629  void genie_vector_minusab (NODE_T * p)
 630  {
 631    op_ab_torrix (p, M_REF_ROW_REAL, M_ROW_REAL, genie_vector_sub);
 632  }
 633  
 634  //! @brief OP + = ([, ] REAL, [, ] REAL) [, ] REAL
 635  
 636  void genie_matrix_add (NODE_T * p)
 637  {
 638    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
 639    gsl_matrix *v = pop_matrix (p, A68G_TRUE);
 640    gsl_matrix *u = pop_matrix (p, A68G_TRUE);
 641    ASSERT_GSL (gsl_matrix_add (u, v));
 642    push_matrix (p, u);
 643    gsl_matrix_free (u);
 644    gsl_matrix_free (v);
 645    (void) gsl_set_error_handler (save_handler);
 646  }
 647  
 648  //! @brief OP - = ([, ] REAL, [, ] REAL) [, ] REAL
 649  
 650  void genie_matrix_sub (NODE_T * p)
 651  {
 652    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
 653    gsl_matrix *v = pop_matrix (p, A68G_TRUE);
 654    gsl_matrix *u = pop_matrix (p, A68G_TRUE);
 655    ASSERT_GSL (gsl_matrix_sub (u, v));
 656    push_matrix (p, u);
 657    gsl_matrix_free (u);
 658    gsl_matrix_free (v);
 659    (void) gsl_set_error_handler (save_handler);
 660  }
 661  
 662  //! @brief OP = = ([, ] REAL, [, ] REAL) [, ] BOOL
 663  
 664  void genie_matrix_eq (NODE_T * p)
 665  {
 666    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
 667    gsl_matrix *v = pop_matrix (p, A68G_TRUE);
 668    gsl_matrix *u = pop_matrix (p, A68G_TRUE);
 669    ASSERT_GSL (gsl_matrix_sub (u, v));
 670    PUSH_VALUE (p, (BOOL_T) (gsl_matrix_isnull (u) ? A68G_TRUE : A68G_FALSE), A68G_BOOL);
 671    gsl_matrix_free (u);
 672    gsl_matrix_free (v);
 673    (void) gsl_set_error_handler (save_handler);
 674  }
 675  
 676  //! @brief OP /= = ([, ] REAL, [, ] REAL) [, ] BOOL
 677  
 678  void genie_matrix_ne (NODE_T * p)
 679  {
 680    genie_matrix_eq (p);
 681    genie_not_bool (p);
 682  }
 683  
 684  //! @brief OP +:= = (REF [, ] REAL, [, ] REAL) [, ] REAL
 685  
 686  void genie_matrix_plusab (NODE_T * p)
 687  {
 688    op_ab_torrix (p, M_REF_ROW_ROW_REAL, M_ROW_ROW_REAL, genie_matrix_add);
 689  }
 690  
 691  //! @brief OP -:= = (REF [, ] REAL, [, ] REAL) [, ] REAL
 692  
 693  void genie_matrix_minusab (NODE_T * p)
 694  {
 695    op_ab_torrix (p, M_REF_ROW_ROW_REAL, M_ROW_ROW_REAL, genie_matrix_sub);
 696  }
 697  
 698  //! @brief OP + = ([] COMPLEX, [] COMPLEX) [] COMPLEX
 699  
 700  void genie_vector_complex_add (NODE_T * p)
 701  {
 702    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
 703    gsl_complex one;
 704    GSL_SET_COMPLEX (&one, 1.0, 0.0);
 705    gsl_vector_complex *v = pop_vector_complex (p, A68G_TRUE);
 706    gsl_vector_complex *u = pop_vector_complex (p, A68G_TRUE);
 707    ASSERT_GSL (gsl_blas_zaxpy (one, u, v));
 708    push_vector_complex (p, v);
 709    gsl_vector_complex_free (u);
 710    gsl_vector_complex_free (v);
 711    (void) gsl_set_error_handler (save_handler);
 712  }
 713  
 714  //! @brief OP - = ([] COMPLEX, [] COMPLEX) [] COMPLEX
 715  
 716  void genie_vector_complex_sub (NODE_T * p)
 717  {
 718    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
 719    gsl_complex one;
 720    GSL_SET_COMPLEX (&one, -1.0, 0.0);
 721    gsl_vector_complex *v = pop_vector_complex (p, A68G_TRUE);
 722    gsl_vector_complex *u = pop_vector_complex (p, A68G_TRUE);
 723    ASSERT_GSL (gsl_blas_zaxpy (one, v, u));
 724    push_vector_complex (p, u);
 725    gsl_vector_complex_free (u);
 726    gsl_vector_complex_free (v);
 727    (void) gsl_set_error_handler (save_handler);
 728  }
 729  
 730  //! @brief OP = = ([] COMPLEX, [] COMPLEX) BOOL
 731  
 732  void genie_vector_complex_eq (NODE_T * p)
 733  {
 734    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
 735    gsl_complex one;
 736    GSL_SET_COMPLEX (&one, -1.0, 0.0);
 737    gsl_vector_complex *v = pop_vector_complex (p, A68G_TRUE);
 738    gsl_vector_complex *u = pop_vector_complex (p, A68G_TRUE);
 739    ASSERT_GSL (gsl_blas_zaxpy (one, v, u));
 740    PUSH_VALUE (p, (BOOL_T) (gsl_vector_complex_isnull (u) ? A68G_TRUE : A68G_FALSE), A68G_BOOL);
 741    gsl_vector_complex_free (u);
 742    gsl_vector_complex_free (v);
 743    (void) gsl_set_error_handler (save_handler);
 744  }
 745  
 746  //! @brief OP /= = ([] COMPLEX, [] COMPLEX) BOOL
 747  
 748  void genie_vector_complex_ne (NODE_T * p)
 749  {
 750    genie_vector_complex_eq (p);
 751    genie_not_bool (p);
 752  }
 753  
 754  //! @brief OP +:= = (REF [] COMPLEX, [] COMPLEX) [] COMPLEX
 755  
 756  void genie_vector_complex_plusab (NODE_T * p)
 757  {
 758    op_ab_torrix (p, M_REF_ROW_COMPLEX, M_ROW_COMPLEX, genie_vector_complex_add);
 759  }
 760  
 761  //! @brief OP -:= = (REF [] COMPLEX, [] COMPLEX) [] COMPLEX
 762  
 763  void genie_vector_complex_minusab (NODE_T * p)
 764  {
 765    op_ab_torrix (p, M_REF_ROW_COMPLEX, M_ROW_COMPLEX, genie_vector_complex_sub);
 766  }
 767  
 768  //! @brief OP + = ([, ] COMPLEX, [, ] COMPLEX) [, ] COMPLEX
 769  
 770  void genie_matrix_complex_add (NODE_T * p)
 771  {
 772    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
 773    gsl_matrix_complex *v = pop_matrix_complex (p, A68G_TRUE);
 774    gsl_matrix_complex *u = pop_matrix_complex (p, A68G_TRUE);
 775    ASSERT_GSL (gsl_matrix_complex_add (u, v));
 776    push_matrix_complex (p, u);
 777    gsl_matrix_complex_free (u);
 778    gsl_matrix_complex_free (v);
 779    (void) gsl_set_error_handler (save_handler);
 780  }
 781  
 782  //! @brief OP - = ([, ] COMPLEX, [, ] COMPLEX) [, ] COMPLEX
 783  
 784  void genie_matrix_complex_sub (NODE_T * p)
 785  {
 786    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
 787    gsl_matrix_complex *v = pop_matrix_complex (p, A68G_TRUE);
 788    gsl_matrix_complex *u = pop_matrix_complex (p, A68G_TRUE);
 789    ASSERT_GSL (gsl_matrix_complex_sub (u, v));
 790    push_matrix_complex (p, u);
 791    gsl_matrix_complex_free (u);
 792    gsl_matrix_complex_free (v);
 793    (void) gsl_set_error_handler (save_handler);
 794  }
 795  
 796  //! @brief OP = = ([, ] COMPLEX, [, ] COMPLEX) BOOL
 797  
 798  void genie_matrix_complex_eq (NODE_T * p)
 799  {
 800    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
 801    gsl_matrix_complex *v = pop_matrix_complex (p, A68G_TRUE);
 802    gsl_matrix_complex *u = pop_matrix_complex (p, A68G_TRUE);
 803    ASSERT_GSL (gsl_matrix_complex_sub (u, v));
 804    PUSH_VALUE (p, (BOOL_T) (gsl_matrix_complex_isnull (u) ? A68G_TRUE : A68G_FALSE), A68G_BOOL);
 805    gsl_matrix_complex_free (u);
 806    gsl_matrix_complex_free (v);
 807    (void) gsl_set_error_handler (save_handler);
 808  }
 809  
 810  //! @brief OP /= = ([, ] COMPLEX, [, ] COMPLEX) BOOL
 811  
 812  void genie_matrix_complex_ne (NODE_T * p)
 813  {
 814    genie_matrix_complex_eq (p);
 815    genie_not_bool (p);
 816  }
 817  
 818  //! @brief OP +:= = (REF [, ] COMPLEX, [, ] COMPLEX) [, ] COMPLEX
 819  
 820  void genie_matrix_complex_plusab (NODE_T * p)
 821  {
 822    op_ab_torrix (p, M_REF_ROW_ROW_COMPLEX, M_ROW_ROW_COMPLEX, genie_matrix_complex_add);
 823  }
 824  
 825  //! @brief OP -:= = (REF [, ] COMPLEX, [, ] COMPLEX) [, ] COMPLEX
 826  
 827  void genie_matrix_complex_minusab (NODE_T * p)
 828  {
 829    op_ab_torrix (p, M_REF_ROW_ROW_COMPLEX, M_ROW_ROW_COMPLEX, genie_matrix_complex_sub);
 830  }
 831  
 832  //! @brief OP * = ([] REAL, REAL) [] REAL
 833  
 834  void genie_vector_scale_real (NODE_T * p)
 835  {
 836    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
 837    A68G_REAL v;
 838    POP_OBJECT (p, &v, A68G_REAL);
 839    gsl_vector *u = pop_vector (p, A68G_TRUE);
 840    ASSERT_GSL (gsl_vector_scale (u, VALUE (&v)));
 841    push_vector (p, u);
 842    gsl_vector_free (u);
 843    (void) gsl_set_error_handler (save_handler);
 844  }
 845  
 846  //! @brief OP * = (REAL, [] REAL) [] REAL
 847  
 848  void genie_real_scale_vector (NODE_T * p)
 849  {
 850    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
 851    gsl_vector *u = pop_vector (p, A68G_TRUE);
 852    A68G_REAL v;
 853    POP_OBJECT (p, &v, A68G_REAL);
 854    ASSERT_GSL (gsl_vector_scale (u, VALUE (&v)));
 855    push_vector (p, u);
 856    gsl_vector_free (u);
 857    (void) gsl_set_error_handler (save_handler);
 858  }
 859  
 860  //! @brief OP * = ([, ] REAL, REAL) [, ] REAL
 861  
 862  void genie_matrix_scale_real (NODE_T * p)
 863  {
 864    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
 865    A68G_REAL v;
 866    POP_OBJECT (p, &v, A68G_REAL);
 867    gsl_matrix *u = pop_matrix (p, A68G_TRUE);
 868    ASSERT_GSL (gsl_matrix_scale (u, VALUE (&v)));
 869    push_matrix (p, u);
 870    gsl_matrix_free (u);
 871    (void) gsl_set_error_handler (save_handler);
 872  }
 873  
 874  //! @brief OP * = (REAL, [, ] REAL) [, ] REAL
 875  
 876  void genie_real_scale_matrix (NODE_T * p)
 877  {
 878    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
 879    gsl_matrix *u = pop_matrix (p, A68G_TRUE);
 880    A68G_REAL v;
 881    POP_OBJECT (p, &v, A68G_REAL);
 882    ASSERT_GSL (gsl_matrix_scale (u, VALUE (&v)));
 883    push_matrix (p, u);
 884    gsl_matrix_free (u);
 885    (void) gsl_set_error_handler (save_handler);
 886  }
 887  
 888  //! @brief OP * = ([] COMPLEX, COMPLEX) [] COMPLEX
 889  
 890  void genie_vector_complex_scale_complex (NODE_T * p)
 891  {
 892    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
 893    A68G_REAL re, im; gsl_complex v;
 894    POP_OBJECT (p, &im, A68G_REAL);
 895    POP_OBJECT (p, &re, A68G_REAL);
 896    GSL_SET_COMPLEX (&v, VALUE (&re), VALUE (&im));
 897    gsl_vector_complex *u = pop_vector_complex (p, A68G_TRUE);
 898    gsl_blas_zscal (v, u);
 899    push_vector_complex (p, u);
 900    gsl_vector_complex_free (u);
 901    (void) gsl_set_error_handler (save_handler);
 902  }
 903  
 904  //! @brief OP * = (COMPLEX, [] COMPLEX) [] COMPLEX
 905  
 906  void genie_complex_scale_vector_complex (NODE_T * p)
 907  {
 908    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
 909    gsl_vector_complex *u = pop_vector_complex (p, A68G_TRUE);
 910    A68G_REAL re, im; gsl_complex v;
 911    POP_OBJECT (p, &im, A68G_REAL);
 912    POP_OBJECT (p, &re, A68G_REAL);
 913    GSL_SET_COMPLEX (&v, VALUE (&re), VALUE (&im));
 914    gsl_blas_zscal (v, u);
 915    push_vector_complex (p, u);
 916    gsl_vector_complex_free (u);
 917    (void) gsl_set_error_handler (save_handler);
 918  }
 919  
 920  //! @brief OP * = ([, ] COMPLEX, COMPLEX) [, ] COMPLEX
 921  
 922  void genie_matrix_complex_scale_complex (NODE_T * p)
 923  {
 924    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
 925    A68G_REAL re, im; gsl_complex v;
 926    POP_OBJECT (p, &im, A68G_REAL);
 927    POP_OBJECT (p, &re, A68G_REAL);
 928    GSL_SET_COMPLEX (&v, VALUE (&re), VALUE (&im));
 929    gsl_matrix_complex *u = pop_matrix_complex (p, A68G_TRUE);
 930    ASSERT_GSL (gsl_matrix_complex_scale (u, v));
 931    push_matrix_complex (p, u);
 932    gsl_matrix_complex_free (u);
 933    (void) gsl_set_error_handler (save_handler);
 934  }
 935  
 936  //! @brief OP * = (COMPLEX, [, ] COMPLEX) [, ] COMPLEX
 937  
 938  void genie_complex_scale_matrix_complex (NODE_T * p)
 939  {
 940    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
 941    gsl_matrix_complex *u = pop_matrix_complex (p, A68G_TRUE);
 942    A68G_REAL re, im; gsl_complex v;
 943    POP_OBJECT (p, &im, A68G_REAL);
 944    POP_OBJECT (p, &re, A68G_REAL);
 945    GSL_SET_COMPLEX (&v, VALUE (&re), VALUE (&im));
 946    ASSERT_GSL (gsl_matrix_complex_scale (u, v));
 947    push_matrix_complex (p, u);
 948    gsl_matrix_complex_free (u);
 949    (void) gsl_set_error_handler (save_handler);
 950  }
 951  
 952  //! @brief OP *:= (REF [] REAL, REAL) REF [] REAL
 953  
 954  void genie_vector_scale_real_ab (NODE_T * p)
 955  {
 956    op_ab_torrix (p, M_REF_ROW_REAL, M_REAL, genie_vector_scale_real);
 957  }
 958  
 959  //! @brief OP *:= (REF [, ] REAL, REAL) REF [, ] REAL
 960  
 961  void genie_matrix_scale_real_ab (NODE_T * p)
 962  {
 963    op_ab_torrix (p, M_REF_ROW_ROW_REAL, M_REAL, genie_matrix_scale_real);
 964  }
 965  
 966  //! @brief OP *:= (REF [] COMPLEX, COMPLEX) REF [] COMPLEX
 967  
 968  void genie_vector_complex_scale_complex_ab (NODE_T * p)
 969  {
 970    op_ab_torrix (p, M_REF_ROW_COMPLEX, M_COMPLEX, genie_vector_complex_scale_complex);
 971  }
 972  
 973  //! @brief OP *:= (REF [, ] COMPLEX, COMPLEX) REF [, ] COMPLEX
 974  
 975  void genie_matrix_complex_scale_complex_ab (NODE_T * p)
 976  {
 977    op_ab_torrix (p, M_REF_ROW_ROW_COMPLEX, M_COMPLEX, genie_matrix_complex_scale_complex);
 978  }
 979  
 980  //! @brief OP / = ([] REAL, REAL) [] REAL
 981  
 982  void genie_vector_div_real (NODE_T * p)
 983  {
 984    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
 985    A68G_REAL v;
 986    POP_OBJECT (p, &v, A68G_REAL);
 987    if (VALUE (&v) == 0.0) {
 988      diagnostic (A68G_RUNTIME_ERROR, p, ERROR_DIVISION_BY_ZERO, M_ROW_REAL);
 989      exit_genie (p, A68G_RUNTIME_ERROR);
 990    }
 991    gsl_vector *u = pop_vector (p, A68G_TRUE);
 992    ASSERT_GSL (gsl_vector_scale (u, 1.0 / VALUE (&v)));
 993    push_vector (p, u);
 994    gsl_vector_free (u);
 995    (void) gsl_set_error_handler (save_handler);
 996  }
 997  
 998  //! @brief OP / = ([, ] REAL, REAL) [, ] REAL
 999  
1000  void genie_matrix_div_real (NODE_T * p)
1001  {
1002    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1003    A68G_REAL v;
1004    POP_OBJECT (p, &v, A68G_REAL);
1005    if (VALUE (&v) == 0.0) {
1006      diagnostic (A68G_RUNTIME_ERROR, p, ERROR_DIVISION_BY_ZERO, M_ROW_ROW_REAL);
1007      exit_genie (p, A68G_RUNTIME_ERROR);
1008    }
1009    gsl_matrix *u = pop_matrix (p, A68G_TRUE);
1010    ASSERT_GSL (gsl_matrix_scale (u, 1.0 / VALUE (&v)));
1011    push_matrix (p, u);
1012    gsl_matrix_free (u);
1013    (void) gsl_set_error_handler (save_handler);
1014  }
1015  
1016  //! @brief OP / = ([] COMPLEX, COMPLEX) [] COMPLEX
1017  
1018  void genie_vector_complex_div_complex (NODE_T * p)
1019  {
1020    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1021    A68G_REAL re, im; gsl_complex v;
1022    POP_OBJECT (p, &im, A68G_REAL);
1023    POP_OBJECT (p, &re, A68G_REAL);
1024    if (VALUE (&re) == 0.0 && VALUE (&im) == 0.0) {
1025      diagnostic (A68G_RUNTIME_ERROR, p, ERROR_DIVISION_BY_ZERO, M_ROW_COMPLEX);
1026      exit_genie (p, A68G_RUNTIME_ERROR);
1027    }
1028    GSL_SET_COMPLEX (&v, VALUE (&re), VALUE (&im));
1029    v = gsl_complex_inverse (v);
1030    gsl_vector_complex *u = pop_vector_complex (p, A68G_TRUE);
1031    gsl_blas_zscal (v, u);
1032    push_vector_complex (p, u);
1033    gsl_vector_complex_free (u);
1034    (void) gsl_set_error_handler (save_handler);
1035  }
1036  
1037  //! @brief OP / = ([, ] COMPLEX, COMPLEX) [, ] COMPLEX
1038  
1039  void genie_matrix_complex_div_complex (NODE_T * p)
1040  {
1041    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1042    A68G_REAL re, im; gsl_complex v;
1043    POP_OBJECT (p, &im, A68G_REAL);
1044    POP_OBJECT (p, &re, A68G_REAL);
1045    if (VALUE (&re) == 0.0 && VALUE (&im) == 0.0) {
1046      diagnostic (A68G_RUNTIME_ERROR, p, ERROR_DIVISION_BY_ZERO, M_ROW_ROW_COMPLEX);
1047      exit_genie (p, A68G_RUNTIME_ERROR);
1048    }
1049    GSL_SET_COMPLEX (&v, VALUE (&re), VALUE (&im));
1050    v = gsl_complex_inverse (v);
1051    gsl_matrix_complex *u = pop_matrix_complex (p, A68G_TRUE);
1052    ASSERT_GSL (gsl_matrix_complex_scale (u, v));
1053    push_matrix_complex (p, u);
1054    gsl_matrix_complex_free (u);
1055    (void) gsl_set_error_handler (save_handler);
1056  }
1057  
1058  //! @brief OP /:= (REF [] REAL, REAL) REF [] REAL
1059  
1060  void genie_vector_div_real_ab (NODE_T * p)
1061  {
1062    op_ab_torrix (p, M_REF_ROW_REAL, M_REAL, genie_vector_div_real);
1063  }
1064  
1065  //! @brief OP /:= (REF [, ] REAL, REAL) REF [, ] REAL
1066  
1067  void genie_matrix_div_real_ab (NODE_T * p)
1068  {
1069    op_ab_torrix (p, M_REF_ROW_ROW_REAL, M_REAL, genie_matrix_div_real);
1070  }
1071  
1072  //! @brief OP /:= (REF [] COMPLEX, COMPLEX) REF [] COMPLEX
1073  
1074  void genie_vector_complex_div_complex_ab (NODE_T * p)
1075  {
1076    op_ab_torrix (p, M_REF_ROW_COMPLEX, M_COMPLEX, genie_vector_complex_div_complex);
1077  }
1078  
1079  //! @brief OP /:= (REF [, ] COMPLEX, COMPLEX) REF [, ] COMPLEX
1080  
1081  void genie_matrix_complex_div_complex_ab (NODE_T * p)
1082  {
1083    op_ab_torrix (p, M_REF_ROW_ROW_COMPLEX, M_COMPLEX, genie_matrix_complex_div_complex);
1084  }
1085  
1086  //! @brief OP * = ([] REAL, [] REAL) REAL
1087  
1088  void genie_vector_dot (NODE_T * p)
1089  {
1090    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1091    gsl_vector *v = pop_vector (p, A68G_TRUE);
1092    gsl_vector *u = pop_vector (p, A68G_TRUE);
1093    REAL_T w;
1094    ASSERT_GSL (gsl_blas_ddot (u, v, &w));
1095    PUSH_VALUE (p, w, A68G_REAL);
1096    gsl_vector_free (u);
1097    gsl_vector_free (v);
1098    (void) gsl_set_error_handler (save_handler);
1099  }
1100  
1101  //! @brief OP * = ([] COMPLEX, [] COMPLEX) COMPLEX
1102  
1103  void genie_vector_complex_dot (NODE_T * p)
1104  {
1105    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1106    gsl_vector_complex *v = pop_vector_complex (p, A68G_TRUE);
1107    gsl_vector_complex *u = pop_vector_complex (p, A68G_TRUE);
1108    gsl_complex w;
1109    ASSERT_GSL (gsl_blas_zdotc (u, v, &w));
1110    PUSH_VALUE (p, GSL_REAL (w), A68G_REAL);
1111    PUSH_VALUE (p, GSL_IMAG (w), A68G_REAL);
1112    gsl_vector_complex_free (u);
1113    gsl_vector_complex_free (v);
1114    (void) gsl_set_error_handler (save_handler);
1115  }
1116  
1117  //! @brief OP NORM = ([] REAL) REAL
1118  
1119  void genie_vector_norm (NODE_T * p)
1120  {
1121    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1122    gsl_vector *u = pop_vector (p, A68G_TRUE);
1123    PUSH_VALUE (p, gsl_blas_dnrm2 (u), A68G_REAL);
1124    gsl_vector_free (u);
1125    (void) gsl_set_error_handler (save_handler);
1126  }
1127  
1128  //! @brief OP NORM = ([] COMPLEX) COMPLEX
1129  
1130  void genie_vector_complex_norm (NODE_T * p)
1131  {
1132    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1133    gsl_vector_complex *u = pop_vector_complex (p, A68G_TRUE);
1134    PUSH_VALUE (p, gsl_blas_dznrm2 (u), A68G_REAL);
1135    gsl_vector_complex_free (u);
1136    (void) gsl_set_error_handler (save_handler);
1137  }
1138  
1139  //! @brief OP DYAD = ([] REAL, [] REAL) [, ] REAL
1140  
1141  void genie_vector_dyad (NODE_T * p)
1142  {
1143    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1144    gsl_vector *v = pop_vector (p, A68G_TRUE);
1145    gsl_vector *u = pop_vector (p, A68G_TRUE);
1146    size_t len1 = SIZE (u), len2 = SIZE (v);
1147    gsl_matrix *w = gsl_matrix_calloc ((size_t) len1, (size_t) len2);
1148    for (int j = 0; j < len1; j++) {
1149      REAL_T uj = gsl_vector_get (u, (size_t) j);
1150      for (int k = 0; k < len2; k++) {
1151        REAL_T vk = gsl_vector_get (v, (size_t) k);
1152        gsl_matrix_set (w, (size_t) j, (size_t) k, uj * vk);
1153      }
1154    }
1155    push_matrix (p, w);
1156    gsl_vector_free (u);
1157    gsl_vector_free (v);
1158    gsl_matrix_free (w);
1159    (void) gsl_set_error_handler (save_handler);
1160  }
1161  
1162  //! @brief OP DYAD = ([] COMPLEX, [] COMPLEX) [, ] COMPLEX
1163  
1164  void genie_vector_complex_dyad (NODE_T * p)
1165  {
1166    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1167    gsl_vector_complex *v = pop_vector_complex (p, A68G_TRUE);
1168    gsl_vector_complex *u = pop_vector_complex (p, A68G_TRUE);
1169    size_t len1 = SIZE (u), len2 = SIZE (v);
1170    gsl_matrix_complex *w = gsl_matrix_complex_calloc ((size_t) len1, (size_t) len2);
1171    for (int j = 0; j < len1; j++) {
1172      gsl_complex uj = gsl_vector_complex_get (u, (size_t) j);
1173      for (int k = 0; k < len2; k++) {
1174        gsl_complex vk = gsl_vector_complex_get (u, (size_t) k);
1175        gsl_matrix_complex_set (w, (size_t) j, (size_t) k, gsl_complex_mul (uj, vk));
1176      }
1177    }
1178    push_matrix_complex (p, w);
1179    gsl_vector_complex_free (u);
1180    gsl_vector_complex_free (v);
1181    gsl_matrix_complex_free (w);
1182    (void) gsl_set_error_handler (save_handler);
1183  }
1184  
1185  //! @brief OP * = ([, ] REAL, [] REAL) [] REAL
1186  
1187  void genie_matrix_times_vector (NODE_T * p)
1188  {
1189    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1190    gsl_vector *u = pop_vector (p, A68G_TRUE);
1191    gsl_matrix *w = pop_matrix (p, A68G_TRUE);
1192    size_t len = SIZE (u);
1193    gsl_vector *v = gsl_vector_calloc ((size_t) len);
1194    gsl_vector_set_zero (v);
1195    ASSERT_GSL (gsl_blas_dgemv (CblasNoTrans, 1.0, w, u, 0.0, v));
1196    push_vector (p, v);
1197    gsl_vector_free (u);
1198    gsl_vector_free (v);
1199    gsl_matrix_free (w);
1200    (void) gsl_set_error_handler (save_handler);
1201  }
1202  
1203  //! @brief OP * = ([] REAL, [, ] REAL) [] REAL
1204  
1205  void genie_vector_times_matrix (NODE_T * p)
1206  {
1207    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1208    gsl_matrix *w = pop_matrix (p, A68G_TRUE);
1209    ASSERT_GSL (gsl_matrix_transpose (w));
1210    gsl_vector *u = pop_vector (p, A68G_TRUE);
1211    size_t len = SIZE (u);
1212    gsl_vector *v = gsl_vector_calloc ((size_t) len);
1213    gsl_vector_set_zero (v);
1214    ASSERT_GSL (gsl_blas_dgemv (CblasNoTrans, 1.0, w, u, 0.0, v));
1215    push_vector (p, v);
1216    gsl_vector_free (u);
1217    gsl_vector_free (v);
1218    gsl_matrix_free (w);
1219    (void) gsl_set_error_handler (save_handler);
1220  }
1221  
1222  //! @brief OP * = ([, ] REAL, [, ] REAL) [, ] REAL
1223  
1224  void genie_matrix_times_matrix (NODE_T * p)
1225  {
1226    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1227    gsl_matrix *v = pop_matrix (p, A68G_TRUE);
1228    gsl_matrix *u = pop_matrix (p, A68G_TRUE);
1229    size_t len2 = SIZE2 (v), len1 = SIZE1 (u);
1230    gsl_matrix *w = gsl_matrix_calloc ((size_t) len1, (size_t) len2);
1231    ASSERT_GSL (gsl_blas_dgemm (CblasNoTrans, CblasNoTrans, 1.0, u, v, 0.0, w));
1232    push_matrix (p, w);
1233    gsl_matrix_free (u);
1234    gsl_matrix_free (v);
1235    gsl_matrix_free (w);
1236    (void) gsl_set_error_handler (save_handler);
1237  }
1238  
1239  //! @brief OP * = ([, ] COMPLEX, [] COMPLEX) [] COMPLEX
1240  
1241  void genie_matrix_complex_times_vector (NODE_T * p)
1242  {
1243    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1244    gsl_complex zero, one;
1245    GSL_SET_COMPLEX (&zero, 0.0, 0.0);
1246    GSL_SET_COMPLEX (&one, 1.0, 0.0);
1247    gsl_vector_complex *u = pop_vector_complex (p, A68G_TRUE);
1248    gsl_matrix_complex *w = pop_matrix_complex (p, A68G_TRUE);
1249    size_t len = SIZE (u);
1250    gsl_vector_complex *v = gsl_vector_complex_calloc ((size_t) len);
1251    ASSERT_GSL (gsl_blas_zgemv (CblasNoTrans, one, w, u, zero, v));
1252    push_vector_complex (p, v);
1253    gsl_vector_complex_free (u);
1254    gsl_vector_complex_free (v);
1255    gsl_matrix_complex_free (w);
1256    (void) gsl_set_error_handler (save_handler);
1257  }
1258  
1259  //! @brief OP * = ([] COMPLEX, [, ] COMPLEX) [] COMPLEX
1260  
1261  void genie_vector_complex_times_matrix (NODE_T * p)
1262  {
1263    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1264    gsl_complex zero, one;
1265    GSL_SET_COMPLEX (&zero, 0.0, 0.0);
1266    GSL_SET_COMPLEX (&one, 1.0, 0.0);
1267    gsl_matrix_complex *w = pop_matrix_complex (p, A68G_TRUE);
1268    ASSERT_GSL (gsl_matrix_complex_transpose (w));
1269    gsl_vector_complex *u = pop_vector_complex (p, A68G_TRUE);
1270    size_t len = SIZE (u);
1271    gsl_vector_complex *v = gsl_vector_complex_calloc ((size_t) len);
1272    ASSERT_GSL (gsl_blas_zgemv (CblasNoTrans, one, w, u, zero, v));
1273    push_vector_complex (p, v);
1274    gsl_vector_complex_free (u);
1275    gsl_vector_complex_free (v);
1276    gsl_matrix_complex_free (w);
1277    (void) gsl_set_error_handler (save_handler);
1278  }
1279  
1280  //! @brief OP * = ([, ] COMPLEX, [, ] COMPLEX) [, ] COMPLEX
1281  
1282  void genie_matrix_complex_times_matrix (NODE_T * p)
1283  {
1284    gsl_error_handler_t *save_handler = gsl_set_error_handler (torrix_error_handler);
1285    gsl_complex zero, one;
1286    GSL_SET_COMPLEX (&zero, 0.0, 0.0);
1287    GSL_SET_COMPLEX (&one, 1.0, 0.0);
1288    gsl_matrix_complex *v = pop_matrix_complex (p, A68G_TRUE);
1289    gsl_matrix_complex *u = pop_matrix_complex (p, A68G_TRUE);
1290    size_t len1 = SIZE2 (v), len2 = SIZE1 (u);
1291    gsl_matrix_complex *w = gsl_matrix_complex_calloc ((size_t) len1, (size_t) len2);
1292    ASSERT_GSL (gsl_blas_zgemm (CblasNoTrans, CblasNoTrans, one, u, v, zero, w));
1293    gsl_matrix_complex_free (u);
1294    gsl_matrix_complex_free (v);
1295    push_matrix_complex (p, w);
1296    gsl_matrix_complex_free (w);
1297    (void) gsl_set_error_handler (save_handler);
1298  }
1299  
1300  #endif
     


© 2002-2025 J.M. van der Veer (jmvdveer@xs4all.nl)