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