1 /*
2 * gretl -- Gnu Regression, Econometrics and Time-series Library
3 * Copyright (C) 2001 Allin Cottrell and Riccardo "Jack" Lucchetti
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 */
19
20 #include "libgretl.h"
21 #include "gretl_f2c.h"
22 #include "clapack_complex.h"
23 #include "gretl_cmatrix.h"
24
25 /* Note: since we include gretl_cmatrix.h (which in turn includes
26 C99's complex.h) before fftw3.h, FFTW's fftw_complex will be
27 typedef'd to C99's "double complex" and can be manipulated as
28 such.
29 */
30
31 #include <fftw3.h>
32 #include <errno.h>
33
34 #define cscalar(m) (m->rows == 1 && m->cols == 1)
35
36 /* helper function for fftw-based real FFT functions */
37
fft_allocate(double ** ffx,double complex ** ffz,gretl_matrix ** ret,int r,int c,int inverse,int newstyle)38 static int fft_allocate (double **ffx, double complex **ffz,
39 gretl_matrix **ret, int r, int c,
40 int inverse, int newstyle)
41 {
42 /* real workspace, per series */
43 *ffx = fftw_malloc(r * sizeof **ffx);
44 if (*ffx == NULL) {
45 return E_ALLOC;
46 }
47
48 /* complex workspace, per series */
49 *ffz = fftw_malloc((r/2 + 1 + r % 2) * sizeof **ffz);
50 if (*ffz == NULL) {
51 free(*ffx);
52 return E_ALLOC;
53 }
54
55 /* matrix to hold output */
56 if (newstyle && !inverse) {
57 *ret = gretl_cmatrix_new(r, c);
58 } else {
59 *ret = gretl_matrix_alloc(r, c);
60 }
61 if (*ret == NULL) {
62 free(*ffx);
63 free(*ffz);
64 return E_ALLOC;
65 }
66
67 return 0;
68 }
69
70 /* FFT for real input -> complex output and
71 FFTI for Hermetian input -> real output.
72 Both old and new-style complex formats
73 are supported.
74 */
75
76 static gretl_matrix *
real_matrix_fft(const gretl_matrix * y,int inverse,int newstyle,int * err)77 real_matrix_fft (const gretl_matrix *y, int inverse,
78 int newstyle, int *err)
79 {
80 gretl_matrix *ret = NULL;
81 fftw_plan p = NULL;
82 double *ffx = NULL;
83 double complex *ffz = NULL;
84 double xr, xi;
85 int r, c, m, odd, cr, ci;
86 int incols, outcols;
87 int i, j;
88
89 if (y->rows < 2) {
90 *err = E_DATA;
91 return NULL;
92 }
93
94 r = y->rows;
95 m = r / 2;
96 odd = r % 2;
97
98 incols = y->cols;
99 if (newstyle) {
100 /* the number of columns is invariant wrt real vs complex */
101 outcols = incols;
102 } else {
103 /* the number of columns is double for complex what it is
104 for real */
105 outcols = inverse ? incols / 2 : incols * 2;
106 }
107
108 *err = fft_allocate(&ffx, &ffz, &ret, r, outcols,
109 inverse, newstyle);
110 if (*err) {
111 return NULL;
112 }
113
114 c = MIN(incols, outcols);
115 cr = 0;
116 ci = 1;
117
118 for (j=0; j<c; j++) {
119 /* load the data */
120 if (newstyle && inverse) {
121 for (i=0; i<=m+odd; i++) {
122 ffz[i] = gretl_cmatrix_get(y, i, j);
123 }
124 } else if (inverse) {
125 for (i=0; i<=m+odd; i++) {
126 xr = gretl_matrix_get(y, i, cr);
127 xi = gretl_matrix_get(y, i, ci);
128 ffz[i] = xr + xi * I;
129 }
130 } else {
131 /* going in the real -> complex direction */
132 for (i=0; i<r; i++) {
133 ffx[i] = gretl_matrix_get(y, i, j);
134 }
135 }
136
137 if (j == 0) {
138 /* make the plan just once */
139 if (inverse) {
140 p = fftw_plan_dft_c2r_1d(r, ffz, ffx, FFTW_ESTIMATE);
141 } else {
142 p = fftw_plan_dft_r2c_1d(r, ffx, ffz, FFTW_ESTIMATE);
143 }
144 }
145
146 /* run the transform */
147 fftw_execute(p);
148
149 /* transcribe the result */
150 if (inverse) {
151 for (i=0; i<r; i++) {
152 gretl_matrix_set(ret, i, j, ffx[i] / r);
153 }
154 } else if (newstyle) {
155 for (i=0; i<=m+odd; i++) {
156 gretl_cmatrix_set(ret, i, j, ffz[i]);
157 }
158 for (i=m; i>0; i--) {
159 gretl_cmatrix_set(ret, r-i, j, conj(ffz[i]));
160 }
161 } else {
162 for (i=0; i<=m+odd; i++) {
163 gretl_matrix_set(ret, i, cr, creal(ffz[i]));
164 gretl_matrix_set(ret, i, ci, cimag(ffz[i]));
165 }
166 for (i=m; i>0; i--) {
167 gretl_matrix_set(ret, r-i, cr, creal(ffz[i]));
168 gretl_matrix_set(ret, r-i, ci, -cimag(ffz[i]));
169 }
170 }
171 cr += 2;
172 ci += 2;
173 }
174
175 fftw_destroy_plan(p);
176 fftw_free(ffz);
177 fftw_free(ffx);
178
179 return ret;
180 }
181
row_is_real(const gretl_matrix * y,int i)182 static int row_is_real (const gretl_matrix *y, int i)
183 {
184 double complex z;
185 int j;
186
187 for (j=0; j<y->cols; j++) {
188 z = gretl_cmatrix_get(y, i, j);
189 if (cimag(z) != 0) {
190 return 0;
191 }
192 }
193
194 return 1;
195 }
196
rows_are_conjugate(const gretl_matrix * y,int i,int k)197 static int rows_are_conjugate (const gretl_matrix *y, int i, int k)
198 {
199 double complex z1, z2;
200 int j;
201
202 for (j=0; j<y->cols; j++) {
203 z1 = gretl_cmatrix_get(y, i, j);
204 z2 = gretl_cmatrix_get(y, k, j);
205 if (z1 != conj(z2)) {
206 return 0;
207 }
208 }
209
210 return 1;
211 }
212
fft_is_hermitian(const gretl_matrix * y)213 static int fft_is_hermitian (const gretl_matrix *y)
214 {
215 if (!row_is_real(y, 0)) {
216 return 0;
217 } else {
218 int i, k, n2 = y->rows / 2;
219
220 if (y->rows % 2 == 0 && !row_is_real(y, n2)) {
221 /* In the Hermitian case the middle row of the
222 odd-numbered remainder, on excluding the first
223 row, must be real.
224 */
225 return 0;
226 }
227 for (i=1; i<n2; i++) {
228 k = y->rows - i;
229 if (!rows_are_conjugate(y, i, k)) {
230 return 0;
231 }
232 }
233 }
234
235 return 1;
236 }
237
gretl_matrix_fft(const gretl_matrix * y,int cmat,int * err)238 gretl_matrix *gretl_matrix_fft (const gretl_matrix *y, int cmat, int *err)
239 {
240 return real_matrix_fft(y, 0, cmat, err);
241 }
242
gretl_matrix_ffti(const gretl_matrix * y,int * err)243 gretl_matrix *gretl_matrix_ffti (const gretl_matrix *y, int *err)
244 {
245 if (y->is_complex) {
246 /* new-style */
247 if (fft_is_hermitian(y)) {
248 /* its inverse should be real */
249 return real_matrix_fft(y, 1, 1, err);
250 } else {
251 return gretl_cmatrix_fft(y, 1, err);
252 }
253 } else {
254 /* old-style */
255 return real_matrix_fft(y, 1, 0, err);
256 }
257 }
258
cmatrix_validate(const gretl_matrix * m,int square)259 static int cmatrix_validate (const gretl_matrix *m, int square)
260 {
261 int ret = 1;
262
263 if (gretl_is_null_matrix(m)) {
264 ret = 0;
265 } else if (!m->is_complex || m->z == NULL) {
266 ret = 0;
267 } else if (square && m->rows != m->cols) {
268 ret = 0;
269 }
270
271 if (!ret) {
272 fprintf(stderr, "cmatrix_validate: failed\n");
273 }
274
275 return ret;
276 }
277
278 /* Construct a complex matrix, with all-zero imaginary part,
279 from real matrix @A.
280 */
281
complex_from_real(const gretl_matrix * A,int * err)282 static gretl_matrix *complex_from_real (const gretl_matrix *A,
283 int *err)
284 {
285 gretl_matrix *C = NULL;
286
287 if (gretl_is_null_matrix(A)) {
288 *err = E_DATA;
289 return NULL;
290 }
291
292 C = gretl_cmatrix_new0(A->rows, A->cols);
293
294 if (C == NULL) {
295 *err = E_ALLOC;
296 } else {
297 int i, n = A->rows * A->cols;
298
299 for (i=0; i<n; i++) {
300 C->z[i] = A->val[i];
301 }
302 }
303
304 return C;
305 }
306
307 #if 0 /* currently unused but could be useful! */
308
309 /* Multiplication of complex matrices via BLAS zgemm(),
310 allowing for conjugate transposition of @A or @B.
311 */
312
313 static int gretl_zgemm_full (cmplx alpha,
314 const gretl_matrix *A,
315 char transa,
316 const gretl_matrix *B,
317 char transb,
318 cmplx beta,
319 gretl_matrix *C)
320 {
321 integer lda, ldb, ldc;
322 integer m, n, k, kb;
323
324 if (transa == 'C') {
325 m = A->cols; /* rows of op(A) */
326 k = A->rows; /* cols of op(A) */
327 } else {
328 m = A->rows; /* complex rows of A */
329 k = A->cols; /* cols of A */
330 }
331
332 if (transb == 'C') {
333 n = B->rows; /* columns of op(B) */
334 kb = B->cols; /* rows of op(B) */
335 } else {
336 n = B->cols;
337 kb = B->rows;
338 }
339
340 if (k != kb || C->rows != m || C->cols != n) {
341 return E_NONCONF;
342 }
343
344 lda = A->rows;
345 ldb = B->rows;
346 ldc = C->rows;
347
348 zgemm_(&transa, &transb, &m, &n, &k, &alpha,
349 (cmplx *) A->val, &lda, (cmplx *) B->val, &ldb,
350 &beta, (cmplx *) C->val, &ldc);
351
352 return 0;
353 }
354
355 #endif /* currently unused */
356
357 /* Variant of zgemm: simplified version of gretl_zgemm_full
358 which allocates the product matrix, C.
359 */
360
gretl_zgemm(const gretl_matrix * A,char transa,const gretl_matrix * B,char transb,int * err)361 static gretl_matrix *gretl_zgemm (const gretl_matrix *A,
362 char transa,
363 const gretl_matrix *B,
364 char transb,
365 int *err)
366 {
367 gretl_matrix *C;
368 cmplx alpha = {1, 0};
369 cmplx beta = {0, 0};
370 integer lda, ldb, ldc;
371 integer m, n, k, kb;
372
373 if (!cmatrix_validate(A, 0) || !cmatrix_validate(B, 0)) {
374 *err = E_INVARG;
375 return NULL;
376 }
377
378 if (transa == 'C') {
379 m = A->cols; /* rows of op(A) */
380 k = A->rows; /* cols of op(A) */
381 } else {
382 m = A->rows; /* complex rows of A */
383 k = A->cols; /* cols of A */
384 }
385
386 if (transb == 'C') {
387 n = B->rows; /* columns of op(B) */
388 kb = B->cols; /* rows of op(B) */
389 } else {
390 n = B->cols;
391 kb = B->rows;
392 }
393
394 if (k != kb) {
395 *err = E_NONCONF;
396 return NULL;
397 }
398
399 C = gretl_cmatrix_new(m, n);
400 if (C == NULL) {
401 *err = E_ALLOC;
402 return NULL;
403 }
404
405 lda = A->rows;
406 ldb = B->rows;
407 ldc = C->rows;
408
409 zgemm_(&transa, &transb, &m, &n, &k, &alpha,
410 (cmplx *) A->val, &lda, (cmplx *) B->val, &ldb,
411 &beta, (cmplx *) C->val, &ldc);
412
413 return C;
414 }
415
real_cmatrix_multiply(const gretl_matrix * A,const gretl_matrix * B,char transa,int * err)416 static gretl_matrix *real_cmatrix_multiply (const gretl_matrix *A,
417 const gretl_matrix *B,
418 char transa, int *err)
419 {
420 gretl_matrix *C = NULL;
421 gretl_matrix *T = NULL;
422
423 if (A->is_complex && B->is_complex) {
424 if (transa == 'N' && (cscalar(A) || cscalar(B))) {
425 return gretl_cmatrix_dot_op(A, B, '*', err);
426 } else {
427 C = gretl_zgemm(A, transa, B, 'N', err);
428 }
429 } else if (A->is_complex) {
430 /* case of real B */
431 T = complex_from_real(B, err);
432 if (T != NULL) {
433 C = gretl_zgemm(A, transa, T, 'N', err);
434 }
435 } else if (B->is_complex) {
436 /* case of real A */
437 T = complex_from_real(A, err);
438 if (T != NULL) {
439 C = gretl_zgemm(T, transa, B, 'N', err);
440 }
441 } else {
442 *err = E_TYPES;
443 }
444
445 gretl_matrix_free(T);
446
447 return C;
448 }
449
450 /* Multiplication of @A times @B, where we know that at
451 least one of them is complex; the other, if it's not
452 complex, must be converted to a complex matrix with
453 a zero imaginary part first.
454 */
455
gretl_cmatrix_multiply(const gretl_matrix * A,const gretl_matrix * B,int * err)456 gretl_matrix *gretl_cmatrix_multiply (const gretl_matrix *A,
457 const gretl_matrix *B,
458 int *err)
459 {
460 return real_cmatrix_multiply(A, B, 'N', err);
461 }
462
463 /* Returns (conjugate transpose of A, or A^H) times B,
464 allowing for the possibility that either A or B (but
465 not both!) may be a real matrix on input.
466 */
467
gretl_cmatrix_AHB(const gretl_matrix * A,const gretl_matrix * B,int * err)468 gretl_matrix *gretl_cmatrix_AHB (const gretl_matrix *A,
469 const gretl_matrix *B,
470 int *err)
471 {
472 return real_cmatrix_multiply(A, B, 'C', err);
473 }
474
475 /* Eigen decomposition of complex (Hermitian) matrix using
476 LAPACK's zheev() */
477
gretl_zheev(gretl_matrix * A,int eigenvecs,int * err)478 gretl_matrix *gretl_zheev (gretl_matrix *A, int eigenvecs,
479 int *err)
480 {
481 gretl_matrix *evals = NULL;
482 integer n, info, lwork;
483 double *w = NULL;
484 double *rwork = NULL;
485 cmplx *a = NULL;
486 cmplx *work = NULL;
487 cmplx wsz;
488 char jobz = eigenvecs ? 'V' : 'N';
489 char uplo = 'U';
490
491 if (!cmatrix_validate(A, 1)) {
492 *err = E_INVARG;
493 return NULL;
494 }
495
496 n = A->rows;
497 evals = gretl_matrix_alloc(n, 1);
498 if (evals == NULL) {
499 *err = E_ALLOC;
500 goto bailout;
501 }
502
503 w = evals->val;
504 a = (cmplx *) A->val;
505
506 /* get optimal workspace size */
507 lwork = -1;
508 zheev_(&jobz, &uplo, &n, a, &n, w, &wsz, &lwork, rwork, &info);
509
510 lwork = (integer) wsz.r;
511 work = malloc(lwork * sizeof *work);
512 rwork = malloc((3 * n - 2) * sizeof *rwork);
513 if (work == NULL || rwork == NULL) {
514 *err = E_ALLOC;
515 goto bailout;
516 }
517
518 /* do the actual decomposition */
519 zheev_(&jobz, &uplo, &n, a, &n, w, work, &lwork, rwork, &info);
520 if (info != 0) {
521 fprintf(stderr, "zheev: info = %d\n", info);
522 *err = E_DATA;
523 }
524
525 bailout:
526
527 free(rwork);
528 free(work);
529
530 if (*err) {
531 gretl_matrix_free(evals);
532 evals = NULL;
533 }
534
535 return evals;
536 }
537
ensure_aux_cmatrix(gretl_matrix * m,gretl_matrix ** paux,cmplx ** ppz,int r,int c)538 static int ensure_aux_cmatrix (gretl_matrix *m,
539 gretl_matrix **paux,
540 cmplx **ppz,
541 int r, int c)
542 {
543 gretl_matrix *aux = NULL;
544 int mrc, dim = r * c;
545
546 mrc = (m == NULL)? 0 : m->rows * m->cols;
547
548 /* We need an r x c complex matrix for output:
549 can we just use @m?
550 */
551 if (mrc == dim && m->is_complex) {
552 /* OK, reusable complex matrix */
553 m->rows = r;
554 m->cols = c;
555 if (ppz != NULL) {
556 *ppz = (cmplx *) m->val;
557 }
558 } else if (mrc == 2*dim && !m->is_complex) {
559 /* OK, reusable real matrix */
560 m->rows = 2*r;
561 m->cols = c;
562 gretl_matrix_set_complex_full(m, 1);
563 if (ppz != NULL) {
564 *ppz = (cmplx *) m->val;
565 }
566 } else {
567 /* nope, have to allocate anew */
568 aux = gretl_cmatrix_new0(r, c);
569 if (aux == NULL) {
570 return E_ALLOC;
571 } else {
572 *paux = aux;
573 if (ppz != NULL) {
574 *ppz = (cmplx *) aux->val;
575 }
576 }
577 }
578
579 return 0;
580 }
581
582 /* Eigen decomposition of complex (non-Hermitian) matrix using
583 LAPACK's zgeev() */
584
gretl_zgeev(const gretl_matrix * A,gretl_matrix * VR,gretl_matrix * VL,int * err)585 gretl_matrix *gretl_zgeev (const gretl_matrix *A,
586 gretl_matrix *VR,
587 gretl_matrix *VL,
588 int *err)
589 {
590 gretl_matrix *ret = NULL;
591 gretl_matrix *Acpy = NULL;
592 gretl_matrix *Ltmp = NULL;
593 gretl_matrix *Rtmp = NULL;
594 integer n, info, lwork;
595 integer ldvl, ldvr;
596 double *w = NULL;
597 double *rwork = NULL;
598 cmplx *a = NULL;
599 cmplx *work = NULL;
600 cmplx *vl = NULL, *vr = NULL;
601 cmplx wsz;
602 char jobvl = VL != NULL ? 'V' : 'N';
603 char jobvr = VR != NULL ? 'V' : 'N';
604
605 if (!cmatrix_validate(A, 1)) {
606 *err = E_INVARG;
607 return NULL;
608 }
609
610 n = A->rows;
611 ldvl = VL != NULL ? n : 1;
612 ldvr = VR != NULL ? n : 1;
613
614 /* we need a copy of @A, which gets overwritten */
615 Acpy = gretl_matrix_copy(A);
616 if (Acpy == NULL) {
617 *err = E_ALLOC;
618 goto bailout;
619 }
620
621 a = (cmplx *) Acpy->val;
622
623 if (VL != NULL) {
624 /* left eigenvectors wanted */
625 *err = ensure_aux_cmatrix(VL, &Ltmp, &vl, n, n);
626 if (*err) {
627 goto bailout;
628 }
629 }
630
631 if (VR != NULL) {
632 /* right eigenvectors wanted */
633 *err = ensure_aux_cmatrix(VR, &Rtmp, &vr, n, n);
634 if (*err) {
635 goto bailout;
636 }
637 }
638
639 rwork = malloc(2 * n * sizeof *rwork);
640 ret = gretl_cmatrix_new(n, 1);
641 if (rwork == NULL || ret == NULL) {
642 *err = E_ALLOC;
643 goto bailout;
644 }
645
646 w = ret->val;
647
648 /* get optimal workspace size */
649 lwork = -1;
650 zgeev_(&jobvl, &jobvr, &n, a, &n, w, vl, &ldvl, vr, &ldvr,
651 &wsz, &lwork, rwork, &info);
652 lwork = (integer) wsz.r;
653 work = malloc(lwork * sizeof *work);
654 if (work == NULL) {
655 *err = E_ALLOC;
656 goto bailout;
657 }
658
659 /* do the actual decomposition */
660 zgeev_(&jobvl, &jobvr, &n, a, &n, w, vl, &ldvl, vr, &ldvr,
661 work, &lwork, rwork, &info);
662 if (info != 0) {
663 fprintf(stderr, "zgeev: info = %d\n", info);
664 *err = E_DATA;
665 } else {
666 if (Ltmp != NULL) {
667 gretl_matrix_replace_content(VL, Ltmp);
668 }
669 if (Rtmp != NULL) {
670 gretl_matrix_replace_content(VR, Rtmp);
671 }
672 }
673
674 bailout:
675
676 free(rwork);
677 free(work);
678 gretl_matrix_free(Acpy);
679 gretl_matrix_free(Ltmp);
680 gretl_matrix_free(Rtmp);
681
682 if (*err) {
683 gretl_matrix_free(ret);
684 ret = NULL;
685 }
686
687 return ret;
688 }
689
690 /* Schur factorization of @A, with optional assignment of the
691 matrix of Schur vectors to @Z and/or the eigenvalues of @A
692 to @W, via LAPACK zgees().
693 */
694
gretl_zgees(const gretl_matrix * A,gretl_matrix * Z,gretl_matrix * W,int * err)695 gretl_matrix *gretl_zgees (const gretl_matrix *A,
696 gretl_matrix *Z,
697 gretl_matrix *W,
698 int *err)
699 {
700 gretl_matrix *ret = NULL;
701 gretl_matrix *Ztmp = NULL;
702 gretl_matrix *Wtmp = NULL;
703 integer n, info, lwork;
704 integer ldvs;
705 double *rwork = NULL;
706 cmplx *a = NULL;
707 cmplx *work = NULL;
708 cmplx *vs = NULL;
709 cmplx *w = NULL;
710 char jobvs = Z != NULL ? 'V' : 'N';
711 char srt = 'N';
712 integer sdim = 0;
713
714 if (!cmatrix_validate(A, 1)) {
715 *err = E_INVARG;
716 return NULL;
717 }
718
719 n = A->rows;
720 ldvs = Z != NULL ? n : 1;
721
722 /* we need a copy of @A, which gets overwritten */
723 ret = gretl_matrix_copy(A);
724 if (ret == NULL) {
725 *err = E_ALLOC;
726 goto bailout;
727 }
728
729 a = (cmplx *) ret->z;
730
731 if (Z != NULL) {
732 /* Schur vectors wanted */
733 *err = ensure_aux_cmatrix(Z, &Ztmp, &vs, n, n);
734 if (*err) {
735 goto bailout;
736 }
737 }
738
739 /* Eigenvalues vector: seems like we need this,
740 regardless of whether @W is passed?
741 */
742 *err = ensure_aux_cmatrix(W, &Wtmp, &w, n, 1);
743 if (*err) {
744 goto bailout;
745 }
746
747 work = malloc(sizeof *work);
748 rwork = malloc(n * sizeof *rwork);
749 if (work == NULL || rwork == NULL) {
750 *err = E_ALLOC;
751 goto bailout;
752 }
753
754 /* get optimal workspace size */
755 lwork = -1;
756 zgees_(&jobvs, &srt, NULL, &n, a, &n, &sdim, w, vs, &ldvs,
757 work, &lwork, rwork, NULL, &info);
758 lwork = (integer) work[0].r;
759 work = realloc(work, lwork * sizeof *work);
760 if (work == NULL) {
761 *err = E_ALLOC;
762 goto bailout;
763 }
764
765 /* do the actual factorization */
766 zgees_(&jobvs, &srt, NULL, &n, a, &n, &sdim, w, vs, &ldvs,
767 work, &lwork, rwork, NULL, &info);
768 if (info != 0) {
769 *err = E_DATA;
770 } else {
771 if (Ztmp != NULL) {
772 gretl_matrix_replace_content(Z, Ztmp);
773 }
774 if (W != NULL && Wtmp != NULL) {
775 gretl_matrix_replace_content(W, Wtmp);
776 }
777 }
778
779 bailout:
780
781 free(rwork);
782 free(work);
783 gretl_matrix_free(Ztmp);
784 gretl_matrix_free(Wtmp);
785
786 if (*err) {
787 gretl_matrix_free(ret);
788 ret = NULL;
789 }
790
791 return ret;
792 }
793
794 /* SVD of a complex matrix via the LAPACK function zgesvd() */
795
gretl_cmatrix_SVD(const gretl_matrix * x,gretl_matrix ** pu,gretl_vector ** ps,gretl_matrix ** pvt,int full)796 int gretl_cmatrix_SVD (const gretl_matrix *x, gretl_matrix **pu,
797 gretl_vector **ps, gretl_matrix **pvt,
798 int full)
799 {
800 integer m, n, lda;
801 integer ldu = 1, ldvt = 1;
802 integer lwork = -1L;
803 double *rwork = NULL;
804 integer info;
805 gretl_matrix *s = NULL;
806 gretl_matrix *u = NULL;
807 gretl_matrix *vt = NULL;
808 cmplx *az;
809 char jobu = 'N', jobvt = 'N';
810 cmplx zu, zvt;
811 cmplx *uval = &zu;
812 cmplx *vtval = &zvt;
813 cmplx *work = NULL;
814 int xsize, k, err = 0;
815
816 if (pu == NULL && ps == NULL && pvt == NULL) {
817 /* no-op */
818 return 0;
819 }
820
821 if (!cmatrix_validate(x, 0)) {
822 return E_INVARG;
823 }
824
825 lda = m = x->rows;
826 n = x->cols;
827 xsize = lda * n;
828
829 az = malloc(xsize * sizeof *az);
830 if (az == NULL) {
831 return E_ALLOC;
832 }
833 memcpy(az, x->val, xsize * sizeof *az);
834
835 k = MIN(m, n);
836
837 s = gretl_vector_alloc(k);
838 if (s == NULL) {
839 err = E_ALLOC;
840 goto bailout;
841 }
842
843 if (pu != NULL) {
844 ldu = m;
845 if (full) {
846 u = gretl_cmatrix_new(ldu, m);
847 } else {
848 u = gretl_cmatrix_new(ldu, k);
849 }
850 if (u == NULL) {
851 err = E_ALLOC;
852 goto bailout;
853 } else {
854 uval = (cmplx *) u->val;
855 jobu = full ? 'A' : 'S';
856 }
857 }
858
859 if (pvt != NULL) {
860 ldvt = full ? n : k;
861 vt = gretl_cmatrix_new(ldvt, n);
862 if (vt == NULL) {
863 err = E_ALLOC;
864 goto bailout;
865 } else {
866 vtval = (cmplx *) vt->val;
867 jobvt = full ? 'A' : 'S';
868 }
869 }
870
871 work = malloc(sizeof *work);
872 rwork = malloc(5 * k * sizeof *rwork);
873 if (work == NULL || rwork == NULL) {
874 err = E_ALLOC;
875 goto bailout;
876 }
877
878 /* workspace query */
879 lwork = -1;
880 zgesvd_(&jobu, &jobvt, &m, &n, az, &lda, s->val, uval, &ldu,
881 vtval, &ldvt, work, &lwork, rwork, &info);
882
883 if (info != 0 || work[0].r <= 0.0) {
884 fprintf(stderr, "zgesvd: workspace query failed\n");
885 err = E_DATA;
886 goto bailout;
887 }
888
889 lwork = (integer) work[0].r;
890 work = realloc(work, lwork * sizeof *work);
891 if (work == NULL) {
892 err = E_ALLOC;
893 goto bailout;
894 }
895
896 /* actual computation */
897 zgesvd_(&jobu, &jobvt, &m, &n, az, &lda, s->val, uval, &ldu,
898 vtval, &ldvt, work, &lwork, rwork, &info);
899
900 if (info != 0) {
901 fprintf(stderr, "gretl_cmatrix_SVD: info = %d\n", (int) info);
902 err = E_DATA;
903 goto bailout;
904 }
905
906 if (ps != NULL) {
907 *ps = s;
908 s = NULL;
909 }
910 if (pu != NULL) {
911 *pu = u;
912 u = NULL;
913 }
914 if (pvt != NULL) {
915 *pvt = vt;
916 vt = NULL;
917 }
918
919 bailout:
920
921 free(az);
922 free(work);
923 free(rwork);
924 gretl_matrix_free(s);
925 gretl_matrix_free(u);
926 gretl_matrix_free(vt);
927
928 return err;
929 }
930
csvd_smin(const gretl_matrix * a,double smax)931 static double csvd_smin (const gretl_matrix *a, double smax)
932 {
933 const double macheps = 2.20e-16;
934 int dmax = (a->rows > a->cols)? a->rows : a->cols;
935
936 /* as per numpy, Matlab (2015-09-28) */
937 return dmax * macheps * smax;
938 }
939
gretl_cmatrix_rank(const gretl_matrix * A,int * err)940 int gretl_cmatrix_rank (const gretl_matrix *A, int *err)
941 {
942 gretl_matrix *S = NULL;
943 int i, k, rank = 0;
944
945 if (!cmatrix_validate(A, 0)) {
946 *err = E_INVARG;
947 return 0;
948 }
949
950 k = MIN(A->rows, A->cols);
951
952 if (A->rows > 4 * k || A->cols > 4 * k) {
953 char trans1 = A->rows > k ? 'C' : 'N';
954 char trans2 = A->cols > k ? 'C' : 'N';
955 gretl_matrix *B;
956
957 B = gretl_zgemm(A, trans1, A, trans2, err);
958 if (!*err) {
959 *err = gretl_cmatrix_SVD(B, NULL, &S, NULL, 1);
960 }
961 gretl_matrix_free(B);
962 } else {
963 *err = gretl_cmatrix_SVD(A, NULL, &S, NULL, 1);
964 }
965
966 if (!*err) {
967 double smin = csvd_smin(A, S->val[0]);
968
969 for (i=0; i<k; i++) {
970 if (S->val[i] > smin) {
971 rank++;
972 }
973 }
974 }
975
976 gretl_matrix_free(S);
977
978 return rank;
979 }
980
981 /* Inverse of a complex matrix via its SVD. If the @generalized
982 flag is non-zero the generalized inverse is produced in case
983 of rank deficiency, othewise an error is flagged if @A is not
984 of full rank.
985 */
986
cmatrix_SVD_inverse(const gretl_matrix * A,int generalized,int * err)987 static gretl_matrix *cmatrix_SVD_inverse (const gretl_matrix *A,
988 int generalized,
989 int *err)
990 {
991 gretl_matrix *U = NULL;
992 gretl_matrix *V = NULL;
993 gretl_matrix *s = NULL;
994 gretl_matrix *Vt = NULL;
995 gretl_matrix *ret = NULL;
996
997 *err = gretl_cmatrix_SVD(A, &U, &s, &V, 1);
998
999 if (!*err) {
1000 double smin = csvd_smin(A, s->val[0]);
1001 double complex vij;
1002 int i, j, h = 0;
1003
1004 for (i=0; i<s->cols; i++) {
1005 h += s->val[i] > smin;
1006 }
1007 if (!generalized && h < s->cols) {
1008 gretl_errmsg_set(_("Matrix is singular"));
1009 *err = E_SINGULAR;
1010 goto bailout;
1011 }
1012 Vt = gretl_ctrans(V, 1, err);
1013 if (!*err) {
1014 for (j=0; j<h; j++) {
1015 for (i=0; i<Vt->rows; i++) {
1016 vij = gretl_cmatrix_get(Vt, i, j);
1017 gretl_cmatrix_set(Vt, i, j, vij / s->val[j]);
1018 }
1019 }
1020 }
1021 if (!*err) {
1022 Vt->cols = U->cols = h;
1023 ret = gretl_zgemm(Vt, 'N', U, 'C', err);
1024 }
1025 }
1026
1027 bailout:
1028
1029 gretl_matrix_free(U);
1030 gretl_matrix_free(V);
1031 gretl_matrix_free(s);
1032 gretl_matrix_free(Vt);
1033
1034 return ret;
1035 }
1036
gretl_cmatrix_ginv(const gretl_matrix * A,int * err)1037 gretl_matrix *gretl_cmatrix_ginv (const gretl_matrix *A, int *err)
1038 {
1039 return cmatrix_SVD_inverse(A, 1, err);
1040 }
1041
gretl_cmatrix_inverse(const gretl_matrix * A,int * err)1042 gretl_matrix *gretl_cmatrix_inverse (const gretl_matrix *A, int *err)
1043 {
1044 return cmatrix_SVD_inverse(A, 0, err);
1045 }
1046
1047 /* Horizontal direct product of complex @A and @B, or of
1048 @A with itself if B is NULL.
1049 */
1050
real_cmatrix_hdp(const gretl_matrix * A,const gretl_matrix * B,int * err)1051 static gretl_matrix *real_cmatrix_hdp (const gretl_matrix *A,
1052 const gretl_matrix *B,
1053 int *err)
1054 {
1055 gretl_matrix *C = NULL;
1056 double complex aij, bik;
1057 int do_symmetric = 0;
1058 int i, j, k, ndx;
1059 int r, p, q, ccols;
1060
1061 if (!cmatrix_validate(A,0)) {
1062 *err = E_INVARG;
1063 } else if (B != NULL) {
1064 if (!cmatrix_validate(B,0)) {
1065 *err = E_INVARG;
1066 } else if (B->rows != A->rows) {
1067 *err = E_NONCONF;
1068 }
1069 } else {
1070 do_symmetric = 1;
1071 }
1072
1073 if (*err) {
1074 return NULL;
1075 }
1076
1077 r = A->rows;
1078 p = A->cols;
1079
1080 if (do_symmetric) {
1081 q = p;
1082 ccols = p * (p+1) / 2;
1083 } else {
1084 q = B->cols;
1085 ccols = p * q;
1086 }
1087
1088 C = gretl_cmatrix_new0(r, ccols);
1089
1090 if (C == NULL) {
1091 *err = E_ALLOC;
1092 return NULL;
1093 }
1094
1095 for (i=0; i<r; i++) {
1096 ndx = 0;
1097 for (j=0; j<p; j++) {
1098 aij = gretl_cmatrix_get(A, i, j);
1099 if (do_symmetric) {
1100 for (k=j; k<q; k++) {
1101 bik = gretl_cmatrix_get(A, i, k);
1102 gretl_cmatrix_set(C, i, ndx++, aij*conj(bik));
1103 }
1104 } else if (aij != 0.0) {
1105 ndx = j * q;
1106 for (k=0; k<q; k++) {
1107 bik = gretl_cmatrix_get(B, i, k);
1108 gretl_cmatrix_set(C, i, ndx + k, aij*bik);
1109 }
1110 }
1111 }
1112 }
1113
1114 return C;
1115 }
1116
1117 /* Kronecker product of complex @A and @B */
1118
real_cmatrix_kron(const gretl_matrix * A,const gretl_matrix * B,int * err)1119 static gretl_matrix *real_cmatrix_kron (const gretl_matrix *A,
1120 const gretl_matrix *B,
1121 int *err)
1122 {
1123 gretl_matrix *K = NULL;
1124 int p, q, r, s;
1125
1126 if (!cmatrix_validate(A,0) || !cmatrix_validate(B,0)) {
1127 *err = E_INVARG;
1128 return NULL;
1129 }
1130
1131 p = A->rows;
1132 q = A->cols;
1133 r = B->rows;
1134 s = B->cols;
1135
1136 K = gretl_cmatrix_new0(p*r, q*s);
1137
1138 if (K == NULL) {
1139 *err = E_ALLOC;
1140 } else {
1141 double complex x, aij, bkl;
1142 int i, j, k, l;
1143 int ioff, joff;
1144 int Ki, Kj;
1145
1146 for (i=0; i<p; i++) {
1147 ioff = i * r;
1148 for (j=0; j<q; j++) {
1149 /* block ij is an r * s matrix, a_{ij} * B */
1150 aij = gretl_cmatrix_get(A, i, j);
1151 joff = j * s;
1152 for (k=0; k<r; k++) {
1153 Ki = ioff + k;
1154 for (l=0; l<s; l++) {
1155 bkl = gretl_cmatrix_get(B, k, l);
1156 Kj = joff + l;
1157 x = aij * bkl;
1158 gretl_cmatrix_set(K, Ki, Kj, x);
1159 }
1160 }
1161 }
1162 }
1163 }
1164
1165 return K;
1166 }
1167
gretl_cmatrix_kronlike(const gretl_matrix * A,const gretl_matrix * B,int hdp,int * err)1168 gretl_matrix *gretl_cmatrix_kronlike (const gretl_matrix *A,
1169 const gretl_matrix *B,
1170 int hdp, int *err)
1171 {
1172 gretl_matrix *L = (gretl_matrix *) A;
1173 gretl_matrix *R = (gretl_matrix *) B;
1174 gretl_matrix *C = NULL;
1175
1176 if (A->is_complex && hdp && B == NULL) {
1177 ; /* OK */
1178 } else if (A->is_complex && B->is_complex) {
1179 ; /* OK */
1180 } else if (A->is_complex) {
1181 R = complex_from_real(B, err);
1182 } else if (B->is_complex) {
1183 L = complex_from_real(A, err);
1184 } else {
1185 *err = E_TYPES;
1186 }
1187
1188 if (!*err) {
1189 if (hdp) {
1190 C = real_cmatrix_hdp(L, R, err);
1191 } else {
1192 C = real_cmatrix_kron(L, R, err);
1193 }
1194 }
1195
1196 if (L != A) gretl_matrix_free(L);
1197 if (R != B) gretl_matrix_free(R);
1198
1199 return C;
1200 }
1201
gretl_cmatrix_hdprod(const gretl_matrix * A,const gretl_matrix * B,int * err)1202 gretl_matrix *gretl_cmatrix_hdprod (const gretl_matrix *A,
1203 const gretl_matrix *B,
1204 int *err)
1205 {
1206 return gretl_cmatrix_kronlike(A, B, 1, err);
1207 }
1208
gretl_cmatrix_kronecker(const gretl_matrix * A,const gretl_matrix * B,int * err)1209 gretl_matrix *gretl_cmatrix_kronecker (const gretl_matrix *A,
1210 const gretl_matrix *B,
1211 int *err)
1212 {
1213 return gretl_cmatrix_kronlike(A, B, 0, err);
1214 }
1215
1216 /* Complex FFT (or inverse) via fftw */
1217
gretl_cmatrix_fft(const gretl_matrix * A,int inverse,int * err)1218 gretl_matrix *gretl_cmatrix_fft (const gretl_matrix *A,
1219 int inverse, int *err)
1220 {
1221 gretl_matrix *B = NULL;
1222 double complex *tmp, *ptr;
1223 fftw_plan p;
1224 int sign;
1225 int r, c, j;
1226
1227 if (!cmatrix_validate(A, 0)) {
1228 *err = E_INVARG;
1229 return NULL;
1230 }
1231
1232 B = gretl_matrix_copy(A);
1233 if (B == NULL) {
1234 *err = E_ALLOC;
1235 return NULL;
1236 }
1237
1238 r = A->rows;
1239 c = A->cols;
1240
1241 tmp = (double complex *) B->val;
1242 sign = inverse ? FFTW_BACKWARD : FFTW_FORWARD;
1243
1244 ptr = tmp;
1245 for (j=0; j<c; j++) {
1246 p = fftw_plan_dft_1d(r, ptr, ptr, sign, FFTW_ESTIMATE);
1247 fftw_execute(p);
1248 fftw_destroy_plan(p);
1249 /* advance pointer to next column */
1250 ptr += r;
1251 }
1252
1253 if (inverse) {
1254 /* "FFTW computes an unnormalized transform: computing a
1255 forward followed by a backward transform (or vice versa)
1256 will result in the original data multiplied by the size of
1257 the transform (the product of the dimensions)."
1258 So should we do the following?
1259 */
1260 for (j=0; j<r*c; j++) {
1261 tmp[j] /= r;
1262 }
1263 }
1264
1265 return B;
1266 }
1267
1268 #define CDEC5 1 /* five decimal places in default format */
1269
gretl_cmatrix_print_range(const gretl_matrix * A,const char * name,int rmin,int rmax,PRN * prn)1270 int gretl_cmatrix_print_range (const gretl_matrix *A,
1271 const char *name,
1272 int rmin, int rmax,
1273 PRN *prn)
1274 {
1275 double complex aij;
1276 double re, im, ai, xmax;
1277 int alt_default = 0;
1278 int all_ints = 1;
1279 int intmax = 1000;
1280 #if CDEC5
1281 int altmin = 1000;
1282 #else
1283 int altmin = 100;
1284 #endif
1285 int zwidth = 0;
1286 int rdecs, idecs;
1287 char pm;
1288 int r, c, i, j;
1289
1290 if (!cmatrix_validate(A, 0)) {
1291 return E_INVARG;
1292 }
1293
1294 r = A->rows;
1295 c = A->cols;
1296
1297 if (rmin < 0) rmin = 0;
1298 if (rmax < 0) rmax = r;
1299
1300 xmax = 0;
1301
1302 for (j=0; j<c; j++) {
1303 for (i=rmin; i<rmax; i++) {
1304 aij = gretl_cmatrix_get(A, i, j);
1305 re = creal(aij);
1306 im = cimag(aij);
1307 if (all_ints && (floor(re) != re || floor(im) != im)) {
1308 all_ints = 0;
1309 }
1310 re = MAX(fabs(re), fabs(im));
1311 if (re > xmax) {
1312 xmax = re;
1313 }
1314 if (all_ints && xmax >= intmax) {
1315 all_ints = 0;
1316 }
1317 if (!all_ints && xmax >= altmin) {
1318 break;
1319 }
1320 }
1321 if (!all_ints && xmax >= altmin) {
1322 break;
1323 }
1324 }
1325
1326 if (all_ints) {
1327 /* apply a more compact format */
1328 zwidth = 2 + (xmax >= 10) + (xmax >= 100);
1329 } else if (xmax >= altmin) {
1330 /* we'll want a different default format */
1331 alt_default = 1;
1332 }
1333
1334 if (name != NULL && *name != '\0') {
1335 pprintf(prn, "%s (%d x %d)", name, r, c);
1336 pputs(prn, "\n\n");
1337 }
1338
1339 for (i=rmin; i<rmax; i++) {
1340 for (j=0; j<c; j++) {
1341 aij = gretl_cmatrix_get(A, i, j);
1342 re = creal(aij);
1343 im = cimag(aij);
1344 pm = (im >= -0) ? '+' : '-';
1345 ai = fabs(im);
1346 if (zwidth > 0) {
1347 pprintf(prn, "%*g %c %*gi", zwidth, re, pm, zwidth-1, ai);
1348 } else if (alt_default) {
1349 pprintf(prn, "%# 9.4e %c %#8.4ei", re, pm, ai);
1350 } else {
1351 #if CDEC5
1352 rdecs = re <= -10 ? 4 : 5;
1353 idecs = ai >= 10 ? 4 : 5;
1354 pprintf(prn, "%8.*f %c %7.*fi", rdecs, re, pm, idecs, ai);
1355 #else
1356 rdecs = re <= -10 ? 3 : 4;
1357 idecs = ai >= 10 ? 3 : 4;
1358 pprintf(prn, "%7.*f %c %6.*fi", rdecs, re, pm, idecs, ai);
1359 #endif
1360 }
1361 if (j < c - 1) {
1362 pputs(prn, " ");
1363 }
1364 }
1365 pputc(prn, '\n');
1366 }
1367 pputc(prn, '\n');
1368
1369 return 0;
1370 }
1371
gretl_cmatrix_print(const gretl_matrix * A,const char * name,PRN * prn)1372 int gretl_cmatrix_print (const gretl_matrix *A,
1373 const char *name,
1374 PRN *prn)
1375 {
1376 return gretl_cmatrix_print_range(A, name, -1, -1, prn);
1377 }
1378
gretl_cmatrix_printf(const gretl_matrix * A,const char * fmt,PRN * prn)1379 int gretl_cmatrix_printf (const gretl_matrix *A,
1380 const char *fmt,
1381 PRN *prn)
1382 {
1383 double complex aij;
1384 double re, im;
1385 gchar *fmtstr = NULL;
1386 char s[3] = " ";
1387 int r, c, i, j;
1388
1389 if (!cmatrix_validate(A, 0)) {
1390 return E_INVARG;
1391 }
1392
1393 if (fmt == NULL) {
1394 fmt = "%7.4f";
1395 } else {
1396 /* we only accept floating-point formats */
1397 char c = fmt[strlen(fmt) - 1];
1398
1399 if (c != 'f' && c != 'g') {
1400 return E_INVARG;
1401 }
1402 }
1403
1404 fmtstr = g_strdup_printf("%s%%s%si", fmt, fmt);
1405
1406 r = A->rows;
1407 c = A->cols;
1408
1409 for (i=0; i<r; i++) {
1410 for (j=0; j<c; j++) {
1411 aij = gretl_cmatrix_get(A, i, j);
1412 re = creal(aij);
1413 im = cimag(aij);
1414 s[1] = (im >= 0) ? '+' : '-';
1415 pprintf(prn, fmtstr, re, s, fabs(im));
1416 if (j < c - 1) {
1417 pputs(prn, " ");
1418 }
1419 }
1420 pputc(prn, '\n');
1421 }
1422 pputc(prn, '\n');
1423
1424 g_free(fmtstr);
1425
1426 return 0;
1427 }
1428
1429 /* Compose a complex matrix from its real and imaginary
1430 components. If @Re is NULL the result will have a
1431 constant real part given by @x; and if @Im is NULL it
1432 will have a constant imaginary part given by @y. If
1433 both matrix arguments are non-NULL they must be of
1434 the same dimensions.
1435 */
1436
gretl_cmatrix_build(const gretl_matrix * Re,const gretl_matrix * Im,double x,double y,int * err)1437 gretl_matrix *gretl_cmatrix_build (const gretl_matrix *Re,
1438 const gretl_matrix *Im,
1439 double x, double y,
1440 int *err)
1441 {
1442 gretl_matrix *C = NULL;
1443 int r = 1, c = 1;
1444 int i, n;
1445
1446 if (Re != NULL) {
1447 if (Re->is_complex) {
1448 *err = E_INVARG;
1449 } else {
1450 r = Re->rows;
1451 c = Re->cols;
1452 }
1453 }
1454 if (!*err && Im != NULL) {
1455 if (Im->is_complex) {
1456 *err = E_INVARG;
1457 } else if (Re != NULL) {
1458 if (Im->rows != r || Im->cols != c) {
1459 *err = E_NONCONF;
1460 }
1461 } else {
1462 r = Im->rows;
1463 c = Im->cols;
1464 }
1465 }
1466
1467 if (!*err) {
1468 n = r * c;
1469 C = gretl_cmatrix_new(r, c);
1470 if (C == NULL) {
1471 *err = E_ALLOC;
1472 }
1473 }
1474
1475 if (!*err) {
1476 for (i=0; i<n; i++) {
1477 if (Re != NULL) {
1478 x = Re->val[i];
1479 }
1480 if (Im != NULL) {
1481 y = Im->val[i];
1482 }
1483 C->z[i] = x + y * I;
1484 }
1485 }
1486
1487 return C;
1488 }
1489
1490 /* Extract the real part of @A if @im = 0 or the imaginary part
1491 if @im is non-zero.
1492 */
1493
gretl_cmatrix_extract(const gretl_matrix * A,int im,int * err)1494 gretl_matrix *gretl_cmatrix_extract (const gretl_matrix *A,
1495 int im, int *err)
1496 {
1497 gretl_matrix *B = NULL;
1498 int i, n;
1499
1500 if (!cmatrix_validate(A, 0)) {
1501 *err = E_INVARG;
1502 return NULL;
1503 }
1504
1505 B = gretl_matrix_alloc(A->rows, A->cols);
1506
1507 if (B == NULL) {
1508 *err = E_ALLOC;
1509 } else {
1510 n = A->rows * A->cols;
1511 for (i=0; i<n; i++) {
1512 B->val[i] = im ? cimag(A->z[i]) : creal(A->z[i]);
1513 }
1514 }
1515
1516 return B;
1517 }
1518
1519 /* Return [conjugate] transpose of complex matrix @A */
1520
gretl_ctrans(const gretl_matrix * A,int conjugate,int * err)1521 gretl_matrix *gretl_ctrans (const gretl_matrix *A,
1522 int conjugate, int *err)
1523 {
1524 gretl_matrix *C = NULL;
1525 double complex aij;
1526 int i, j;
1527
1528 if (!cmatrix_validate(A, 0)) {
1529 *err = E_INVARG;
1530 return NULL;
1531 }
1532
1533 C = gretl_cmatrix_new(A->cols, A->rows);
1534 if (C == NULL) {
1535 *err = E_ALLOC;
1536 return NULL;
1537 }
1538
1539 for (j=0; j<A->cols; j++) {
1540 for (i=0; i<A->rows; i++) {
1541 aij = gretl_cmatrix_get(A, i, j);
1542 if (conjugate) {
1543 aij = conj(aij);
1544 }
1545 gretl_cmatrix_set(C, j, i, aij);
1546 }
1547 }
1548
1549 return C;
1550 }
1551
1552 /* Convert complex matrix @A to its conjugate transpose */
1553
gretl_ctrans_in_place(gretl_matrix * A)1554 int gretl_ctrans_in_place (gretl_matrix *A)
1555 {
1556 gretl_matrix *C = NULL;
1557 double complex aij;
1558 int i, j, n;
1559 int err = 0;
1560
1561 if (!cmatrix_validate(A, 0)) {
1562 return E_INVARG;
1563 }
1564
1565 /* temporary matrix */
1566 C = gretl_cmatrix_new(A->cols, A->rows);
1567 if (C == NULL) {
1568 return E_ALLOC;
1569 }
1570
1571 for (j=0; j<A->cols; j++) {
1572 for (i=0; i<A->rows; i++) {
1573 aij = gretl_cmatrix_get(A, i, j);
1574 gretl_cmatrix_set(C, j, i, conj(aij));
1575 }
1576 }
1577
1578 /* now rejig @A */
1579 A->rows = C->rows;
1580 A->cols = C->cols;
1581 n = C->rows * C->cols;
1582 memcpy(A->z, C->z, n * sizeof *A->z);
1583 gretl_matrix_destroy_info(A);
1584
1585 gretl_matrix_free(C);
1586
1587 return err;
1588 }
1589
1590 /* Addition or subtraction of matrices: handle the case
1591 where one operand is complex and the other is real.
1592 In addition handle the case where one of them is a
1593 scalar matrix, real or complex.
1594 */
1595
gretl_cmatrix_add_sub(const gretl_matrix * A,const gretl_matrix * B,int sgn,int * err)1596 gretl_matrix *gretl_cmatrix_add_sub (const gretl_matrix *A,
1597 const gretl_matrix *B,
1598 int sgn, int *err)
1599 {
1600 gretl_matrix *C = NULL;
1601 double complex aval = 0;
1602 double complex bval = 0;
1603 int cr = A->rows;
1604 int cc = A->cols;
1605 int a_scalar = 0;
1606 int b_scalar = 0;
1607
1608 if (A->is_complex && B->rows == 1 && B->cols == 1) {
1609 b_scalar = 1;
1610 bval = B->is_complex ? B->z[0] : B->val[0];
1611 goto allocate;
1612 } else if (B->is_complex && A->rows == 1 && A->cols == 1) {
1613 cr = B->rows;
1614 cc = B->cols;
1615 a_scalar = 1;
1616 aval = A->is_complex ? A->z[0] : A->val[0];
1617 goto allocate;
1618 }
1619
1620 if (B->cols != A->cols) {
1621 *err = E_NONCONF;
1622 return NULL;
1623 }
1624
1625 if (A->is_complex && B->is_complex) {
1626 /* both complex */
1627 if (B->rows != cr) {
1628 *err = E_NONCONF;
1629 }
1630 } else if (A->is_complex) {
1631 /* A complex, B real */
1632 if (B->rows != cr) {
1633 *err = E_NONCONF;
1634 }
1635 } else {
1636 /* A real, B complex */
1637 cr = B->rows;
1638 if (A->rows != cr) {
1639 *err = E_NONCONF;
1640 }
1641 }
1642
1643 allocate:
1644
1645 if (!*err) {
1646 C = gretl_cmatrix_new(cr, cc);
1647 if (C == NULL) {
1648 *err = E_ALLOC;
1649 }
1650 }
1651
1652 if (!*err) {
1653 int i, n = cc * cr;
1654
1655 if (b_scalar) {
1656 for (i=0; i<n; i++) {
1657 C->z[i] = sgn < 0 ? A->z[i] - bval : A->z[i] + bval;
1658 }
1659 } else if (a_scalar) {
1660 for (i=0; i<n; i++) {
1661 C->z[i] = sgn < 0 ? aval - B->z[i] : aval + B->z[i];
1662 }
1663 } else if (A->is_complex && B->is_complex) {
1664 for (i=0; i<n; i++) {
1665 C->z[i] = sgn < 0 ? A->z[i] - B->z[i] : A->z[i] + B->z[i];
1666 }
1667 } else if (A->is_complex) {
1668 for (i=0; i<n; i++) {
1669 C->z[i] = sgn < 0 ? A->z[i] - B->val[i] : A->z[i] + B->val[i];
1670 }
1671 } else {
1672 for (i=0; i<n; i++) {
1673 C->z[i] = sgn < 0 ? A->val[i] - B->z[i] : A->val[i] + B->z[i];
1674 }
1675 }
1676 }
1677
1678 return C;
1679 }
1680
1681 /* Apply a function which maps from complex to real:
1682 creal, cimag, carg, cmod.
1683 */
1684
apply_cmatrix_dfunc(gretl_matrix * targ,const gretl_matrix * src,double (* dfunc)(double complex))1685 int apply_cmatrix_dfunc (gretl_matrix *targ,
1686 const gretl_matrix *src,
1687 double (*dfunc) (double complex))
1688 {
1689 int n = src->cols * src->rows;
1690 int i, err = 0;
1691
1692 if (!cmatrix_validate(src, 0) || targ->is_complex) {
1693 return E_INVARG;
1694 }
1695
1696 errno = 0;
1697
1698 for (i=0; i<n; i++) {
1699 targ->val[i] = dfunc(src->z[i]);
1700 }
1701
1702 if (errno) {
1703 gretl_errmsg_set_from_errno(NULL, errno);
1704 err = E_DATA;
1705 }
1706
1707 return err;
1708 }
1709
1710 /* Apply a function which maps from complex to complex;
1711 includes trigonometric functions, log, exp.
1712 */
1713
apply_cmatrix_cfunc(gretl_matrix * targ,const gretl_matrix * src,double complex (* cfunc)(double complex))1714 int apply_cmatrix_cfunc (gretl_matrix *targ,
1715 const gretl_matrix *src,
1716 double complex (*cfunc) (double complex))
1717 {
1718 int n = src->cols * src->rows;
1719 int i, err = 0;
1720
1721 if (!cmatrix_validate(src, 0) || !cmatrix_validate(targ, 0)) {
1722 return E_INVARG;
1723 }
1724
1725 errno = 0;
1726
1727 for (i=0; i<n; i++) {
1728 targ->z[i] = cfunc(src->z[i]);
1729 }
1730
1731 if (errno) {
1732 gretl_errmsg_set_from_errno(NULL, errno);
1733 err = E_DATA;
1734 }
1735
1736 return err;
1737 }
1738
apply_cmatrix_unary_op(gretl_matrix * targ,const gretl_matrix * src,int op)1739 int apply_cmatrix_unary_op (gretl_matrix *targ,
1740 const gretl_matrix *src,
1741 int op)
1742 {
1743 int i, n = src->cols * src->rows;
1744 int err = 0;
1745
1746 if (!cmatrix_validate(src, 0) || !cmatrix_validate(targ, 0)) {
1747 return E_INVARG;
1748 }
1749
1750 for (i=0; i<n && !err; i++) {
1751 if (op == 1) {
1752 /* U_NEG */
1753 targ->z[i] = -src->z[i];
1754 } else if (op == 2) {
1755 /* U_POS */
1756 targ->z[i] = src->z[i];
1757 } else if (op == 3) {
1758 /* U_NOT */
1759 targ->z[i] = (src->z[i] == 0);
1760 } else {
1761 err = E_INVARG;
1762 }
1763 }
1764
1765 return err;
1766 }
1767
gretl_cmatrix_from_scalar(double complex z,int * err)1768 gretl_matrix *gretl_cmatrix_from_scalar (double complex z, int *err)
1769 {
1770 gretl_matrix *ret = gretl_cmatrix_new(1, 1);
1771
1772 if (ret == NULL) {
1773 *err = E_ALLOC;
1774 } else {
1775 ret->z[0] = z;
1776 }
1777
1778 return ret;
1779 }
1780
1781 /* Determinant via eigenvalues */
1782
gretl_cmatrix_determinant(const gretl_matrix * X,int log,int * err)1783 gretl_matrix *gretl_cmatrix_determinant (const gretl_matrix *X,
1784 int log, int *err)
1785 {
1786 gretl_matrix *E = NULL;
1787 gretl_matrix *ret = NULL;
1788
1789 if (!cmatrix_validate(X, 1)) {
1790 *err = E_INVARG;
1791 return ret;
1792 }
1793
1794 E = gretl_zgeev(X, NULL, NULL, err);
1795
1796 if (E != NULL) {
1797 double complex cret = 1;
1798 int i;
1799
1800 for (i=0; i<E->rows; i++) {
1801 cret *= E->z[i];
1802 }
1803 gretl_matrix_free(E);
1804 if (log) {
1805 cret = clog(cret);
1806 }
1807 ret = gretl_cmatrix_from_scalar(cret, err);
1808 }
1809
1810 return ret;
1811 }
1812
gretl_cmatrix_trace(const gretl_matrix * X,int * err)1813 gretl_matrix *gretl_cmatrix_trace (const gretl_matrix *X,
1814 int *err)
1815 {
1816 gretl_matrix *ret = NULL;
1817
1818 if (!cmatrix_validate(X, 1)) {
1819 *err = E_INVARG;
1820 } else {
1821 double complex tr = 0;
1822 int i;
1823
1824 for (i=0; i<X->rows; i++) {
1825 tr += gretl_cmatrix_get(X, i, i);
1826 }
1827 ret = gretl_cmatrix_from_scalar(tr, err);
1828 }
1829
1830 return ret;
1831 }
1832
1833 /* Set the diagonal of complex matrix @targ using either
1834 @src (if not NULL) or @x. In the first case @src can
1835 be either a complex vector of the right length, or a
1836 real vector, or a complex scalar.
1837 */
1838
gretl_cmatrix_set_diagonal(gretl_matrix * targ,const gretl_matrix * src,double x)1839 int gretl_cmatrix_set_diagonal (gretl_matrix *targ,
1840 const gretl_matrix *src,
1841 double x)
1842 {
1843 double complex zi = 0;
1844 int d, i;
1845 int match = 0;
1846 int err = 0;
1847
1848 if (!cmatrix_validate(targ, 0)) {
1849 return E_INVARG;
1850 }
1851
1852 d = MIN(targ->rows, targ->cols);
1853
1854 if (src != NULL) {
1855 if (src->is_complex) {
1856 if (gretl_vector_get_length(src) == d) {
1857 /* conformable complex vector */
1858 match = 1;
1859 } else if (cscalar(src)) {
1860 /* complex scalar */
1861 zi = src->z[0];
1862 match = 2;
1863 }
1864 } else if (gretl_vector_get_length(src) == d) {
1865 /* conformable real vector */
1866 match = 3;
1867 }
1868 } else {
1869 /* use real scalar, @x */
1870 zi = x;
1871 match = 4;
1872 }
1873
1874 if (match == 0) {
1875 return E_NONCONF;
1876 }
1877
1878 for (i=0; i<d; i++) {
1879 if (match == 1) {
1880 gretl_cmatrix_set(targ, i, i, src->z[i]);
1881 } else if (match == 3) {
1882 gretl_cmatrix_set(targ, i, i, src->val[i]);
1883 } else {
1884 gretl_cmatrix_set(targ, i, i, zi);
1885 }
1886 }
1887
1888 return err;
1889 }
1890
1891 /* Set the lower or upper part of square complex matrix
1892 @targ using either @src (if not NULL) or @x. In the first
1893 case @src can be either a complex vector of the right length,
1894 or a real vector, or a complex scalar.
1895 */
1896
gretl_cmatrix_set_triangle(gretl_matrix * targ,const gretl_matrix * src,double x,int upper)1897 int gretl_cmatrix_set_triangle (gretl_matrix *targ,
1898 const gretl_matrix *src,
1899 double x, int upper)
1900 {
1901 double complex zi = 0;
1902 int r, c, p, i, j, n;
1903 int lower = !upper;
1904 int match = 0;
1905 int err = 0;
1906
1907 if (!cmatrix_validate(targ, 0)) {
1908 return E_INVARG;
1909 }
1910
1911 r = targ->rows;
1912 c = targ->cols;
1913
1914 if ((c == 1 && upper) || (r == 1 && !upper)) {
1915 /* no such part */
1916 return E_INVARG;
1917 }
1918
1919 p = MIN(r, c);
1920 n = (p * (p-1)) / 2;
1921
1922 if (r > c && lower) {
1923 n += (r - c) * c;
1924 } else if (c > r && upper) {
1925 n += (c - r) * r;
1926 }
1927
1928 if (src != NULL) {
1929 if (src->is_complex) {
1930 if (gretl_vector_get_length(src) == n) {
1931 /* conformable complex vector */
1932 match = 1;
1933 } else if (cscalar(src)) {
1934 /* complex scalar */
1935 zi = src->z[0];
1936 match = 2;
1937 }
1938 } else if (gretl_vector_get_length(src) == n) {
1939 /* conformable real vector */
1940 match = 3;
1941 }
1942 } else {
1943 /* use real scalar, @x */
1944 zi = x;
1945 match = 2;
1946 }
1947
1948 if (match == 0) {
1949 return E_NONCONF;
1950 } else {
1951 int jmin = upper ? 1 : 0;
1952 int jmax = upper ? c : r;
1953 int imin = upper ? 0 : 1;
1954 int imax = upper ? 1 : r;
1955 int k = 0;
1956
1957 for (j=jmin; j<jmax; j++) {
1958 for (i=imin; i<imax; i++) {
1959 if (match == 1) {
1960 gretl_cmatrix_set(targ, i, j, src->z[k++]);
1961 } else if (match == 3) {
1962 gretl_cmatrix_set(targ, i, j, src->val[k++]);
1963 } else {
1964 gretl_cmatrix_set(targ, i, j, zi);
1965 }
1966 }
1967 if (lower) {
1968 imin++;
1969 } else if (imax < r) {
1970 imax++;
1971 }
1972 }
1973 }
1974
1975 return err;
1976 }
1977
1978 /* switch between "legacy" and new representations of a
1979 complex matrix */
1980
gretl_cmatrix_switch(const gretl_matrix * m,int to_new,int * err)1981 gretl_matrix *gretl_cmatrix_switch (const gretl_matrix *m,
1982 int to_new, int *err)
1983 {
1984 gretl_matrix *ret = NULL;
1985 int r, c, i, j, k;
1986
1987 if (gretl_is_null_matrix(m)) {
1988 return gretl_null_matrix_new();
1989 }
1990
1991 if ((to_new && m->is_complex) ||
1992 (!to_new && !cmatrix_validate(m, 0))) {
1993 *err = E_INVARG;
1994 return NULL;
1995 }
1996
1997 r = m->rows;
1998 c = to_new ? m->cols / 2 : m->cols * 2;
1999
2000 if (to_new) {
2001 ret = gretl_cmatrix_new(r, c);
2002 } else {
2003 ret = gretl_matrix_alloc(r, c);
2004 }
2005 if (ret == NULL) {
2006 *err = E_ALLOC;
2007 return NULL;
2008 }
2009
2010 k = 0;
2011
2012 if (to_new) {
2013 /* make re and im components contiguous */
2014 double xr, xi;
2015
2016 for (j=0; j<ret->cols; j++) {
2017 for (i=0; i<m->rows; i++) {
2018 xr = gretl_matrix_get(m, i, k);
2019 xi = gretl_matrix_get(m, i, k+1);
2020 gretl_cmatrix_set(ret, i, j, xr + xi * I);
2021 }
2022 k += 2;
2023 }
2024 } else {
2025 /* put re and im components in adjacent columns */
2026 double complex mij;
2027
2028 for (j=0; j<m->cols; j++) {
2029 for (i=0; i<ret->rows; i++) {
2030 mij = gretl_cmatrix_get(m, i, j);
2031 gretl_matrix_set(ret, i, k, creal(mij));
2032 gretl_matrix_set(ret, i, k+1, cimag(mij));
2033 }
2034 k += 2;
2035 }
2036 }
2037
2038 return ret;
2039 }
2040
2041 /* Compute column or row sums, means or products */
2042
gretl_cmatrix_vector_stat(const gretl_matrix * m,GretlVecStat vs,int rowwise,int * err)2043 gretl_matrix *gretl_cmatrix_vector_stat (const gretl_matrix *m,
2044 GretlVecStat vs, int rowwise,
2045 int *err)
2046 {
2047 double complex z;
2048 gretl_matrix *ret;
2049 int r, c, i, j;
2050
2051 if (!cmatrix_validate(m, 0)) {
2052 *err = E_INVARG;
2053 return NULL;
2054 }
2055
2056 r = rowwise ? m->rows : 1;
2057 c = rowwise ? 1 : m->cols;
2058
2059 ret = gretl_cmatrix_new(r, c);
2060 if (ret == NULL) {
2061 *err = E_ALLOC;
2062 return NULL;
2063 }
2064
2065 if (rowwise) {
2066 /* by rows */
2067 int jmin = vs == V_PROD ? 1 : 0;
2068
2069 for (i=0; i<m->rows; i++) {
2070 z = vs == V_PROD ? m->z[i] : 0;
2071 for (j=jmin; j<m->cols; j++) {
2072 if (vs == V_PROD) {
2073 z *= gretl_cmatrix_get(m, i, j);
2074 } else {
2075 z += gretl_cmatrix_get(m, i, j);
2076 }
2077 }
2078 if (vs == V_MEAN) {
2079 z /= m->cols;
2080 }
2081 gretl_cmatrix_set(ret, i, 0, z);
2082 }
2083 } else {
2084 /* by columns */
2085 int imin = vs == V_PROD ? 1 : 0;
2086
2087 for (j=0; j<m->cols; j++) {
2088 z = vs == V_PROD ? gretl_cmatrix_get(m, 0, j) : 0;
2089 for (i=imin; i<m->rows; i++) {
2090 if (vs == V_PROD) {
2091 z *= gretl_cmatrix_get(m, i, j);
2092 } else {
2093 z += gretl_cmatrix_get(m, i, j);
2094 }
2095 }
2096 if (vs == V_MEAN) {
2097 z /= m->rows;
2098 }
2099 gretl_cmatrix_set(ret, 0, j, z);
2100 }
2101 }
2102
2103 return ret;
2104 }
2105
gretl_cmatrix_fill(gretl_matrix * m,double complex z)2106 int gretl_cmatrix_fill (gretl_matrix *m, double complex z)
2107 {
2108 if (!cmatrix_validate(m, 0)) {
2109 return E_TYPES;
2110 } else {
2111 int i, n = m->cols * m->rows;
2112
2113 for (i=0; i<n; i++) {
2114 m->z[i] = z;
2115 }
2116 return 0;
2117 }
2118 }
2119
vec_x_op_vec_y(double complex * z,const double complex * x,const double complex * y,int n,int op)2120 static void vec_x_op_vec_y (double complex *z,
2121 const double complex *x,
2122 const double complex *y,
2123 int n, int op)
2124 {
2125 int i;
2126
2127 switch (op) {
2128 case '*':
2129 for (i=0; i<n; i++) {
2130 z[i] = x[i] * y[i];
2131 }
2132 break;
2133 case '/':
2134 for (i=0; i<n; i++) {
2135 z[i] = x[i] / y[i];
2136 }
2137 break;
2138 case '+':
2139 for (i=0; i<n; i++) {
2140 z[i] = x[i] + y[i];
2141 }
2142 break;
2143 case '-':
2144 for (i=0; i<n; i++) {
2145 z[i] = x[i] - y[i];
2146 }
2147 break;
2148 case '^':
2149 for (i=0; i<n; i++) {
2150 z[i] = cpow(x[i], y[i]);
2151 }
2152 break;
2153 case '=':
2154 for (i=0; i<n; i++) {
2155 z[i] = x[i] == y[i];
2156 }
2157 break;
2158 case '!':
2159 for (i=0; i<n; i++) {
2160 z[i] = x[i] != y[i];
2161 }
2162 break;
2163 default:
2164 break;
2165 }
2166 }
2167
vec_x_op_y(double complex * z,const double complex * x,double complex y,int n,int op)2168 static void vec_x_op_y (double complex *z,
2169 const double complex *x,
2170 double complex y,
2171 int n, int op)
2172 {
2173 int i;
2174
2175 switch (op) {
2176 case '*':
2177 for (i=0; i<n; i++) {
2178 z[i] = x[i] * y;
2179 }
2180 break;
2181 case '/':
2182 for (i=0; i<n; i++) {
2183 z[i] = x[i] / y;
2184 }
2185 break;
2186 case '+':
2187 for (i=0; i<n; i++) {
2188 z[i] = x[i] + y;
2189 }
2190 break;
2191 case '-':
2192 for (i=0; i<n; i++) {
2193 z[i] = x[i] - y;
2194 }
2195 break;
2196 case '^':
2197 for (i=0; i<n; i++) {
2198 z[i] = cpow(x[i], y);
2199 }
2200 break;
2201 case '=':
2202 for (i=0; i<n; i++) {
2203 z[i] = x[i] == y;
2204 }
2205 break;
2206 case '!':
2207 for (i=0; i<n; i++) {
2208 z[i] = x[i] != y;
2209 }
2210 break;
2211 default:
2212 break;
2213 }
2214 }
2215
x_op_vec_y(double complex * z,double complex x,const double complex * y,int n,int op)2216 static void x_op_vec_y (double complex *z,
2217 double complex x,
2218 const double complex *y,
2219 int n, int op)
2220 {
2221 int i;
2222
2223 switch (op) {
2224 case '*':
2225 for (i=0; i<n; i++) {
2226 z[i] = x * y[i];
2227 }
2228 break;
2229 case '/':
2230 for (i=0; i<n; i++) {
2231 z[i] = x / y[i];
2232 }
2233 break;
2234 case '+':
2235 for (i=0; i<n; i++) {
2236 z[i] = x + y[i];
2237 }
2238 break;
2239 case '-':
2240 for (i=0; i<n; i++) {
2241 z[i] = x - y[i];
2242 }
2243 break;
2244 case '^':
2245 for (i=0; i<n; i++) {
2246 z[i] = cpow(x, y[i]);
2247 }
2248 break;
2249 case '=':
2250 for (i=0; i<n; i++) {
2251 z[i] = x == y[i];
2252 }
2253 break;
2254 case '!':
2255 for (i=0; i<n; i++) {
2256 z[i] = x != y[i];
2257 }
2258 break;
2259 default:
2260 break;
2261 }
2262 }
2263
x_op_y(double complex x,double complex y,int op)2264 static double complex x_op_y (double complex x,
2265 double complex y,
2266 int op)
2267 {
2268 switch (op) {
2269 case '*':
2270 return x * y;
2271 case '/':
2272 return x / y;
2273 case '+':
2274 return x + y;
2275 case '-':
2276 return x - y;
2277 case '^':
2278 return cpow(x, y);
2279 case '=':
2280 return x == y;
2281 case '!':
2282 return x != y;
2283 default:
2284 return 0;
2285 }
2286 }
2287
cmatrix_dot_op(const gretl_matrix * A,const gretl_matrix * B,int op,int * err)2288 static gretl_matrix *cmatrix_dot_op (const gretl_matrix *A,
2289 const gretl_matrix *B,
2290 int op, int *err)
2291 {
2292 gretl_matrix *C = NULL;
2293 double complex x, y;
2294 int nr, nc;
2295 int conftype;
2296 int i, j, off;
2297
2298 if (gretl_is_null_matrix(A) || gretl_is_null_matrix(B)) {
2299 *err = E_DATA;
2300 return NULL;
2301 }
2302
2303 conftype = dot_operator_conf(A, B, &nr, &nc);
2304
2305 if (conftype == CONF_NONE) {
2306 fputs("gretl_cmatrix_dot_op: matrices not conformable\n", stderr);
2307 fprintf(stderr, " op = '%c', A is %d x %d, B is %d x %d\n",
2308 (char) op, A->rows/2, A->cols, B->rows/2, B->cols);
2309 *err = E_NONCONF;
2310 return NULL;
2311 }
2312
2313 C = gretl_cmatrix_new(nr, nc);
2314 if (C == NULL) {
2315 *err = E_ALLOC;
2316 return NULL;
2317 }
2318
2319 #if 0 /* maybe expose this in gretl_matrix.h? */
2320 math_err_init();
2321 #endif
2322
2323 switch (conftype) {
2324 case CONF_ELEMENTS:
2325 vec_x_op_vec_y(C->z, A->z, B->z, nr*nc, op);
2326 break;
2327 case CONF_A_COLVEC:
2328 for (i=0; i<nr; i++) {
2329 x = A->z[i];
2330 for (j=0; j<nc; j++) {
2331 y = gretl_cmatrix_get(B, i, j);
2332 y = x_op_y(x, y, op);
2333 gretl_cmatrix_set(C, i, j, y);
2334 }
2335 }
2336 break;
2337 case CONF_B_COLVEC:
2338 for (i=0; i<nr; i++) {
2339 y = B->z[i];
2340 for (j=0; j<nc; j++) {
2341 x = gretl_cmatrix_get(A, i, j);
2342 x = x_op_y(x, y, op);
2343 gretl_cmatrix_set(C, i, j, x);
2344 }
2345 }
2346 break;
2347 case CONF_A_ROWVEC:
2348 off = 0;
2349 for (j=0; j<nc; j++) {
2350 x = A->z[j];
2351 x_op_vec_y(C->z + off, x, B->z + off, nr, op);
2352 off += nr;
2353 }
2354 break;
2355 case CONF_B_ROWVEC:
2356 off = 0;
2357 for (j=0; j<nc; j++) {
2358 y = B->z[j];
2359 vec_x_op_y(C->z + off, A->z + off, y, nr, op);
2360 off += nr;
2361 }
2362 break;
2363 case CONF_A_SCALAR:
2364 x_op_vec_y(C->z, A->z[0], B->z, nr*nc, op);
2365 break;
2366 case CONF_B_SCALAR:
2367 vec_x_op_y(C->z, A->z, B->z[0], nr*nc, op);
2368 break;
2369 case CONF_AC_BR:
2370 for (i=0; i<nr; i++) {
2371 x = A->z[i];
2372 for (j=0; j<nc; j++) {
2373 y = B->z[j];
2374 y = x_op_y(x, y, op);
2375 gretl_cmatrix_set(C, i, j, y);
2376 }
2377 }
2378 break;
2379 case CONF_AR_BC:
2380 for (j=0; j<nc; j++) {
2381 x = A->z[j];
2382 for (i=0; i<nr; i++) {
2383 y = B->z[i];
2384 y = x_op_y(x, y, op);
2385 gretl_cmatrix_set(C, i, j, y);
2386 }
2387 }
2388 break;
2389 default: /* hush a warning */
2390 break;
2391 }
2392
2393 if (errno) {
2394 #if 0 /* not yet */
2395 *err = math_err_check("gretl_matrix_dot_op", errno);
2396 #endif
2397 if (*err) {
2398 gretl_matrix_free(C);
2399 C = NULL;
2400 }
2401 }
2402
2403 return C;
2404 }
2405
gretl_cmatrix_dot_op(const gretl_matrix * A,const gretl_matrix * B,int op,int * err)2406 gretl_matrix *gretl_cmatrix_dot_op (const gretl_matrix *A,
2407 const gretl_matrix *B,
2408 int op, int *err)
2409 {
2410 gretl_matrix *T = NULL;
2411 gretl_matrix *C = NULL;
2412
2413 if (A->is_complex && B->is_complex) {
2414 C = cmatrix_dot_op(A, B, op, err);
2415 } else if (A->is_complex) {
2416 /* case of real B */
2417 T = complex_from_real(B, err);
2418 if (T != NULL) {
2419 C = cmatrix_dot_op(A, T, op, err);
2420 }
2421 } else if (B->is_complex) {
2422 /* case of real A */
2423 T = complex_from_real(A, err);
2424 if (T != NULL) {
2425 C = cmatrix_dot_op(T, B, op, err);
2426 }
2427 } else {
2428 *err = E_TYPES;
2429 }
2430
2431 gretl_matrix_free(T);
2432
2433 return C;
2434 }
2435
gretl_cmatrix_divide(const gretl_matrix * A,const gretl_matrix * B,GretlMatrixMod mod,int * err)2436 gretl_matrix *gretl_cmatrix_divide (const gretl_matrix *A,
2437 const gretl_matrix *B,
2438 GretlMatrixMod mod,
2439 int *err)
2440 {
2441 gretl_matrix *T = NULL;
2442 gretl_matrix *C = NULL;
2443
2444 if (A->is_complex && B->is_complex) {
2445 C = gretl_matrix_divide(A, B, mod, err);
2446 } else if (A->is_complex) {
2447 /* case of real B */
2448 T = complex_from_real(B, err);
2449 if (T != NULL) {
2450 C = gretl_matrix_divide(A, T, mod, err);
2451 }
2452 } else if (B->is_complex) {
2453 /* case of real A */
2454 T = complex_from_real(A, err);
2455 if (T != NULL) {
2456 C = gretl_matrix_divide(T, B, mod, err);
2457 }
2458 } else {
2459 *err = E_TYPES;
2460 }
2461
2462 gretl_matrix_free(T);
2463
2464 return C;
2465 }
2466
cmatrix_get_element(const gretl_matrix * M,int i,int * err)2467 gretl_matrix *cmatrix_get_element (const gretl_matrix *M,
2468 int i, int *err)
2469 {
2470 gretl_matrix *ret = NULL;
2471
2472 if (M == NULL) {
2473 *err = E_DATA;
2474 } else if (i < 0 || i >= M->rows * M->cols) {
2475 gretl_errmsg_sprintf(_("Index value %d is out of bounds"), i+1);
2476 *err = E_INVARG;
2477 } else {
2478 ret = gretl_cmatrix_from_scalar(M->z[i], err);
2479 }
2480
2481 return ret;
2482 }
2483
2484 /* Set either the real or the imaginary part of @targ,
2485 using @src if non-NULL or @x otherwise.
2486 */
2487
gretl_cmatrix_set_part(gretl_matrix * targ,const gretl_matrix * src,double x,int im)2488 int gretl_cmatrix_set_part (gretl_matrix *targ,
2489 const gretl_matrix *src,
2490 double x, int im)
2491 {
2492 double complex z;
2493 int i, j;
2494
2495 if (!cmatrix_validate(targ, 0)) {
2496 return E_TYPES;
2497 } else if (src != NULL) {
2498 if (gretl_is_null_matrix(src) ||
2499 src->rows != targ->rows ||
2500 src->cols != targ->cols ||
2501 src->is_complex) {
2502 return E_INVARG;
2503 }
2504 }
2505
2506 for (j=0; j<targ->cols; j++) {
2507 for (i=0; i<targ->rows; i++) {
2508 if (src != NULL) {
2509 x = gretl_matrix_get(src, i, j);
2510 }
2511 z = gretl_cmatrix_get(targ, i, j);
2512 if (im) {
2513 z = creal(z) + x * I;
2514 } else {
2515 z = x + cimag(z) * I;
2516 }
2517 gretl_cmatrix_set(targ, i, j, z);
2518 }
2519 }
2520
2521 return 0;
2522 }
2523
imag_part_zero(const gretl_matrix * A)2524 static int imag_part_zero (const gretl_matrix *A)
2525 {
2526 int i, n = A->rows * A->cols;
2527 double tol = 1.0e-15; /* ?? */
2528
2529 for (i=0; i<n; i++) {
2530 if (fabs(cimag(A->z[i])) > tol) {
2531 fprintf(stderr, "imag_part_zero? no, got %g\n",
2532 cimag(A->z[i]));
2533 return 0;
2534 }
2535 }
2536 return 1;
2537 }
2538
2539 /* Matrix logarithm, for a diagonalizable matrix */
2540
gretl_matrix_log(const gretl_matrix * A,int * err)2541 gretl_matrix *gretl_matrix_log (const gretl_matrix *A, int *err)
2542 {
2543 gretl_matrix *C = NULL;
2544 gretl_matrix *V = NULL;
2545 gretl_matrix *Vi = NULL;
2546 gretl_matrix *w = NULL;
2547 gretl_matrix *R = NULL;
2548 int i;
2549
2550 if (gretl_is_null_matrix(A) || A->rows != A->cols) {
2551 /* we require a square matrix, real or complex */
2552 *err = E_INVARG;
2553 return NULL;
2554 }
2555
2556 if (A->is_complex) {
2557 C = gretl_matrix_copy(A);
2558 if (C == NULL) {
2559 *err = E_ALLOC;
2560 }
2561 } else {
2562 C = gretl_cmatrix_build(A, NULL, 0, 0, err);
2563 }
2564
2565 if (!*err) {
2566 V = gretl_cmatrix_new(A->rows, A->rows);
2567 if (V == NULL) {
2568 *err = E_ALLOC;
2569 } else {
2570 w = gretl_zgeev(C, V, NULL, err);
2571 }
2572 }
2573
2574 if (!*err) {
2575 /* The following step will fail if
2576 @A is not diagonalizable
2577 */
2578 Vi = gretl_cmatrix_inverse(V, err);
2579 }
2580
2581 if (!*err) {
2582 for (i=0; i<A->rows; i++) {
2583 w->z[i] = clog(w->z[i]);
2584 }
2585 R = cmatrix_dot_op(w, Vi, '*', err);
2586 if (!*err) {
2587 gretl_matrix_free(Vi);
2588 Vi = gretl_cmatrix_multiply(V, R, err);
2589 }
2590 }
2591
2592 gretl_matrix_free(C);
2593
2594 if (!*err) {
2595 if (imag_part_zero(Vi)) {
2596 /* should we do this? */
2597 C = gretl_cmatrix_extract(Vi, 0, err);
2598 } else {
2599 C = Vi;
2600 Vi = NULL;
2601 }
2602 } else {
2603 C = NULL;
2604 }
2605
2606 gretl_matrix_free(V);
2607 gretl_matrix_free(Vi);
2608 gretl_matrix_free(w);
2609 gretl_matrix_free(R);
2610
2611 return C;
2612 }
2613
2614 /* Matrix exponential for a diagonalizable complex matrix */
2615
gretl_cmatrix_exp(const gretl_matrix * A,int * err)2616 gretl_matrix *gretl_cmatrix_exp (const gretl_matrix *A, int *err)
2617 {
2618 gretl_matrix *C = NULL;
2619 gretl_matrix *V = NULL;
2620 gretl_matrix *Vi = NULL;
2621 gretl_matrix *w = NULL;
2622 gretl_matrix *R = NULL;
2623 int i;
2624
2625 if (!cmatrix_validate(A, 1)) {
2626 *err = E_INVARG;
2627 return NULL;
2628 }
2629
2630 C = gretl_matrix_copy(A);
2631 if (C == NULL) {
2632 *err = E_ALLOC;
2633 }
2634
2635 if (!*err) {
2636 V = gretl_cmatrix_new(A->rows, A->rows);
2637 if (V == NULL) {
2638 *err = E_ALLOC;
2639 } else {
2640 w = gretl_zgeev(C, V, NULL, err);
2641 }
2642 }
2643
2644 if (!*err) {
2645 /* The following step will fail if
2646 @A is not diagonalizable
2647 */
2648 Vi = gretl_cmatrix_inverse(V, err);
2649 }
2650
2651 gretl_matrix_free(C);
2652 C = NULL;
2653
2654 if (!*err) {
2655 for (i=0; i<A->rows; i++) {
2656 w->z[i] = cexp(w->z[i]);
2657 }
2658 R = cmatrix_dot_op(w, Vi, '*', err);
2659 if (!*err) {
2660 C = gretl_cmatrix_multiply(V, R, err);
2661 }
2662 }
2663
2664 gretl_matrix_free(V);
2665 gretl_matrix_free(Vi);
2666 gretl_matrix_free(w);
2667 gretl_matrix_free(R);
2668
2669 return C;
2670 }
2671
matrix_is_hermitian(const gretl_matrix * z)2672 static int matrix_is_hermitian (const gretl_matrix *z)
2673 {
2674 double complex zij, zji;
2675 int i, j, n = z->rows;
2676
2677 for (j=0; j<n; j++) {
2678 for (i=0; i<n; i++) {
2679 zij = gretl_cmatrix_get(z, i, j);
2680 zji = gretl_cmatrix_get(z, j, i);
2681 if (zji != conj(zij)) {
2682 return 0;
2683 }
2684 }
2685 }
2686 return 1;
2687 }
2688
2689 /* Cholesky decomposition of Hermitian matrix using LAPACK
2690 function zpotrf()
2691 */
2692
gretl_cmatrix_cholesky(const gretl_matrix * A,int * err)2693 gretl_matrix *gretl_cmatrix_cholesky (const gretl_matrix *A,
2694 int *err)
2695 {
2696 gretl_matrix *C = NULL;
2697 char uplo = 'L';
2698 integer n, info;
2699
2700 if (!cmatrix_validate(A, 1)) {
2701 *err = E_INVARG;
2702 } else if (!matrix_is_hermitian(A)) {
2703 gretl_errmsg_set(_("Matrix is not Hermitian"));
2704 *err = E_INVARG;
2705 } else {
2706 C = gretl_matrix_copy(A);
2707 if (C == NULL) {
2708 *err = E_ALLOC;
2709 }
2710 }
2711
2712 if (*err) {
2713 return NULL;
2714 }
2715
2716 n = A->rows;
2717 zpotrf_(&uplo, &n, (cmplx *) C->val, &n, &info);
2718 if (info != 0) {
2719 fprintf(stderr, "gretl_cmatrix_cholesky: "
2720 "zpotrf failed with info = %d (n = %d)\n", (int) info, (int) n);
2721 *err = (info > 0)? E_NOTPD : E_DATA;
2722 }
2723
2724 if (*err) {
2725 gretl_matrix_free(C);
2726 C = NULL;
2727 } else {
2728 gretl_matrix_zero_upper(C);
2729 }
2730
2731 return C;
2732 }
2733
2734 /* QR decomposition of complex matrix using LAPACK functions
2735 zgeqrf() and zungqr().
2736 */
2737
gretl_cmatrix_QR_decomp(const gretl_matrix * A,gretl_matrix * R,int * err)2738 gretl_matrix *gretl_cmatrix_QR_decomp (const gretl_matrix *A,
2739 gretl_matrix *R,
2740 int *err)
2741 {
2742 gretl_matrix *Q = NULL;
2743 gretl_matrix *Rtmp = NULL;
2744 integer m, n, lda;
2745 integer info = 0;
2746 integer lwork = -1;
2747 cmplx *tau = NULL;
2748 cmplx *work = NULL;
2749 int i, j;
2750
2751 if (!cmatrix_validate(A, 0)) {
2752 *err = E_INVARG;
2753 return NULL;
2754 }
2755
2756 lda = m = A->rows;
2757 n = A->cols;
2758 if (n > m) {
2759 *err = E_NONCONF;
2760 return NULL;
2761 }
2762
2763 Q = gretl_matrix_copy(A);
2764 if (Q == NULL) {
2765 *err = E_ALLOC;
2766 return NULL;
2767 }
2768
2769 if (R != NULL) {
2770 *err = ensure_aux_cmatrix(R, &Rtmp, NULL, n, n);
2771 if (*err) {
2772 goto bailout;
2773 } else if (Rtmp != NULL) {
2774 gretl_matrix_replace_content(R, Rtmp);
2775 }
2776 }
2777
2778 /* dim of tau is min (m, n) */
2779 tau = malloc(n * sizeof *tau);
2780 work = malloc(sizeof *work);
2781 if (tau == NULL || work == NULL) {
2782 *err = E_ALLOC;
2783 goto bailout;
2784 }
2785
2786 /* workspace size query */
2787 zgeqrf_(&m, &n, (cmplx *) Q->val, &lda, tau, work, &lwork, &info);
2788 if (info != 0) {
2789 fprintf(stderr, "zgeqrf: info = %d\n", (int) info);
2790 *err = E_DATA;
2791 } else {
2792 /* optimally sized work array */
2793 lwork = (integer) work[0].r;
2794 work = realloc(work, (size_t) lwork * sizeof *work);
2795 if (work == NULL) {
2796 *err = E_ALLOC;
2797 }
2798 }
2799
2800 if (*err) {
2801 goto bailout;
2802 }
2803
2804 /* run actual QR factorization */
2805 zgeqrf_(&m, &n, (cmplx *) Q->val, &lda, tau, work, &lwork, &info);
2806 if (info != 0) {
2807 fprintf(stderr, "zgeqrf: info = %d\n", (int) info);
2808 *err = E_DATA;
2809 goto bailout;
2810 }
2811
2812 if (R != NULL) {
2813 /* copy the upper triangular R out of Q */
2814 double complex z;
2815
2816 for (i=0; i<n; i++) {
2817 for (j=0; j<n; j++) {
2818 if (i <= j) {
2819 z = gretl_cmatrix_get(Q, i, j);
2820 gretl_cmatrix_set(R, i, j, z);
2821 } else {
2822 gretl_cmatrix_set(R, i, j, 0.0);
2823 }
2824 }
2825 }
2826 }
2827
2828 /* turn Q into "the real" Q, with the help of tau */
2829 zungqr_(&m, &n, &n, (cmplx *) Q->val, &lda, tau, work, &lwork, &info);
2830 if (info != 0) {
2831 fprintf(stderr, "zungqr: info = %d\n", (int) info);
2832 *err = E_DATA;
2833 }
2834
2835 bailout:
2836
2837 free(tau);
2838 free(work);
2839 gretl_matrix_free(Rtmp);
2840
2841 if (*err) {
2842 gretl_matrix_free(Q);
2843 Q = NULL;
2844 }
2845
2846 return Q;
2847 }
2848
2849 /* Copy data from real matrix @src to complex matrix *targ,
2850 starting at offset (@r0, @c0) into @targ. @src is treated
2851 as a complex matrix with zero imaginary part.
2852 */
2853
real_to_complex_fill(gretl_matrix * targ,const gretl_matrix * src,int r0,int c0)2854 void real_to_complex_fill (gretl_matrix *targ,
2855 const gretl_matrix *src,
2856 int r0, int c0)
2857 {
2858 double complex z;
2859 int i, j, r, c;
2860
2861 for (j=0, c=c0; j<src->cols && c<targ->cols; j++, c++) {
2862 for (i=0, r=r0; i<src->rows && r<targ->rows; i++, r++) {
2863 z = gretl_matrix_get(src, i, j);
2864 gretl_cmatrix_set(targ, r, c, z);
2865 }
2866 }
2867 }
2868