GNU Octave  9.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
CMatrix.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 1994-2024 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING. If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if defined (HAVE_CONFIG_H)
27 # include "config.h"
28 #endif
29 
30 #include <algorithm>
31 #include <complex>
32 #include <istream>
33 #include <limits>
34 #include <ostream>
35 
36 #include "Array-util.h"
37 #include "CDiagMatrix.h"
38 #include "CMatrix.h"
39 #include "CNDArray.h"
40 #include "CRowVector.h"
41 #include "DET.h"
42 #include "boolMatrix.h"
43 #include "chMatrix.h"
44 #include "chol.h"
45 #include "dDiagMatrix.h"
46 #include "dMatrix.h"
47 #include "dRowVector.h"
48 #include "lo-blas-proto.h"
49 #include "lo-error.h"
50 #include "lo-ieee.h"
51 #include "lo-lapack-proto.h"
52 #include "lo-mappers.h"
53 #include "lo-utils.h"
54 #include "mx-cm-dm.h"
55 #include "mx-cm-s.h"
56 #include "mx-dm-cm.h"
57 #include "mx-inlines.cc"
58 #include "mx-op-defs.h"
59 #include "oct-cmplx.h"
60 #include "oct-fftw.h"
61 #include "oct-locbuf.h"
62 #include "oct-norm.h"
63 #include "schur.h"
64 #include "svd.h"
65 
66 static const Complex Complex_NaN_result (octave::numeric_limits<double>::NaN (),
68 
69 // Complex Matrix class
70 
72  : ComplexNDArray (a)
73 { }
74 
76  : ComplexNDArray (rv)
77 { }
78 
80  : ComplexNDArray (cv)
81 { }
82 
84  : ComplexNDArray (a.dims (), 0.0)
85 {
86  for (octave_idx_type i = 0; i < a.length (); i++)
87  elem (i, i) = a.elem (i, i);
88 }
89 
91  : ComplexNDArray (a.dims (), 0.0)
92 {
93  for (octave_idx_type i = 0; i < a.length (); i++)
94  elem (i, i) = a.elem (i, i);
95 }
96 
98  : ComplexNDArray (a.dims (), 0.0)
99 {
100  for (octave_idx_type i = 0; i < a.length (); i++)
101  elem (i, i) = a.elem (i, i);
102 }
103 
105  : ComplexNDArray (rv)
106 { }
107 
109  : ComplexNDArray (cv)
110 { }
111 
113  : ComplexNDArray (a.dims (), 0.0)
114 {
115  for (octave_idx_type i = 0; i < a.length (); i++)
116  elem (i, i) = a.elem (i, i);
117 }
118 
120  : ComplexNDArray (a.dims (), 0.0)
121 {
122  for (octave_idx_type i = 0; i < a.length (); i++)
123  elem (i, i) = a.elem (i, i);
124 }
125 
127  : ComplexNDArray (a.dims (), 0.0)
128 {
129  for (octave_idx_type i = 0; i < a.length (); i++)
130  elem (i, i) = a.elem (i, i);
131 }
132 
133 // FIXME: could we use a templated mixed-type copy function here?
134 
136  : ComplexNDArray (a)
137 { }
138 
140  : ComplexNDArray (a.dims (), 0.0)
141 {
142  for (octave_idx_type i = 0; i < a.rows (); i++)
143  for (octave_idx_type j = 0; j < a.cols (); j++)
144  elem (i, j) = static_cast<unsigned char> (a.elem (i, j));
145 }
146 
148  : ComplexNDArray (re.dims ())
149 {
150  if (im.rows () != rows () || im.cols () != cols ())
151  (*current_liboctave_error_handler) ("complex: internal error");
152 
153  octave_idx_type nel = numel ();
154  for (octave_idx_type i = 0; i < nel; i++)
155  xelem (i) = Complex (re(i), im(i));
156 }
157 
158 bool
160 {
161  if (rows () != a.rows () || cols () != a.cols ())
162  return false;
163 
164  return mx_inline_equal (numel (), data (), a.data ());
165 }
166 
167 bool
169 {
170  return !(*this == a);
171 }
172 
173 bool
175 {
176  octave_idx_type nr = rows ();
177  octave_idx_type nc = cols ();
178 
179  if (issquare () && nr > 0)
180  {
181  for (octave_idx_type i = 0; i < nr; i++)
182  for (octave_idx_type j = i; j < nc; j++)
183  if (elem (i, j) != conj (elem (j, i)))
184  return false;
185 
186  return true;
187  }
188 
189  return false;
190 }
191 
192 // destructive insert/delete/reorder operations
193 
196 {
197  octave_idx_type a_nr = a.rows ();
198  octave_idx_type a_nc = a.cols ();
199 
200  if (r < 0 || r + a_nr > rows () || c < 0 || c + a_nc > cols ())
201  (*current_liboctave_error_handler) ("range error for insert");
202 
203  if (a_nr >0 && a_nc > 0)
204  {
205  make_unique ();
206 
207  for (octave_idx_type j = 0; j < a_nc; j++)
208  for (octave_idx_type i = 0; i < a_nr; i++)
209  xelem (r+i, c+j) = a.elem (i, j);
210  }
211 
212  return *this;
213 }
214 
217 {
218  octave_idx_type a_len = a.numel ();
219 
220  if (r < 0 || r >= rows () || c < 0 || c + a_len > cols ())
221  (*current_liboctave_error_handler) ("range error for insert");
222 
223  if (a_len > 0)
224  {
225  make_unique ();
226 
227  for (octave_idx_type i = 0; i < a_len; i++)
228  xelem (r, c+i) = a.elem (i);
229  }
230 
231  return *this;
232 }
233 
237 {
238  octave_idx_type a_len = a.numel ();
239 
240  if (r < 0 || r + a_len > rows () || c < 0 || c >= cols ())
241  (*current_liboctave_error_handler) ("range error for insert");
242 
243  if (a_len > 0)
244  {
245  make_unique ();
246 
247  for (octave_idx_type i = 0; i < a_len; i++)
248  xelem (r+i, c) = a.elem (i);
249  }
250 
251  return *this;
252 }
253 
257 {
258  octave_idx_type a_nr = a.rows ();
259  octave_idx_type a_nc = a.cols ();
260 
261  if (r < 0 || r + a_nr > rows () || c < 0 || c + a_nc > cols ())
262  (*current_liboctave_error_handler) ("range error for insert");
263 
264  fill (0.0, r, c, r + a_nr - 1, c + a_nc - 1);
265 
266  octave_idx_type a_len = a.length ();
267 
268  if (a_len > 0)
269  {
270  make_unique ();
271 
272  for (octave_idx_type i = 0; i < a_len; i++)
273  xelem (r+i, c+i) = a.elem (i, i);
274  }
275 
276  return *this;
277 }
278 
282 {
283  ComplexNDArray::insert (a, r, c);
284  return *this;
285 }
286 
290 {
291  octave_idx_type a_len = a.numel ();
292  if (r < 0 || r >= rows () || c < 0 || c + a_len > cols ())
293  (*current_liboctave_error_handler) ("range error for insert");
294 
295  for (octave_idx_type i = 0; i < a_len; i++)
296  elem (r, c+i) = a.elem (i);
297 
298  return *this;
299 }
300 
304 {
305  octave_idx_type a_len = a.numel ();
306 
307  if (r < 0 || r + a_len > rows () || c < 0 || c >= cols ())
308  (*current_liboctave_error_handler) ("range error for insert");
309 
310  if (a_len > 0)
311  {
312  make_unique ();
313 
314  for (octave_idx_type i = 0; i < a_len; i++)
315  xelem (r+i, c) = a.elem (i);
316  }
317 
318  return *this;
319 }
320 
324 {
325  octave_idx_type a_nr = a.rows ();
326  octave_idx_type a_nc = a.cols ();
327 
328  if (r < 0 || r + a_nr > rows () || c < 0 || c + a_nc > cols ())
329  (*current_liboctave_error_handler) ("range error for insert");
330 
331  fill (0.0, r, c, r + a_nr - 1, c + a_nc - 1);
332 
333  octave_idx_type a_len = a.length ();
334 
335  if (a_len > 0)
336  {
337  make_unique ();
338 
339  for (octave_idx_type i = 0; i < a_len; i++)
340  xelem (r+i, c+i) = a.elem (i, i);
341  }
342 
343  return *this;
344 }
345 
348 {
349  octave_idx_type nr = rows ();
350  octave_idx_type nc = cols ();
351 
352  if (nr > 0 && nc > 0)
353  {
354  make_unique ();
355 
356  for (octave_idx_type j = 0; j < nc; j++)
357  for (octave_idx_type i = 0; i < nr; i++)
358  xelem (i, j) = val;
359  }
360 
361  return *this;
362 }
363 
366 {
367  octave_idx_type nr = rows ();
368  octave_idx_type nc = cols ();
369 
370  if (nr > 0 && nc > 0)
371  {
372  make_unique ();
373 
374  for (octave_idx_type j = 0; j < nc; j++)
375  for (octave_idx_type i = 0; i < nr; i++)
376  xelem (i, j) = val;
377  }
378 
379  return *this;
380 }
381 
385 {
386  octave_idx_type nr = rows ();
387  octave_idx_type nc = cols ();
388 
389  if (r1 < 0 || r2 < 0 || c1 < 0 || c2 < 0
390  || r1 >= nr || r2 >= nr || c1 >= nc || c2 >= nc)
391  (*current_liboctave_error_handler) ("range error for fill");
392 
393  if (r1 > r2) { std::swap (r1, r2); }
394  if (c1 > c2) { std::swap (c1, c2); }
395 
396  if (r2 >= r1 && c2 >= c1)
397  {
398  make_unique ();
399 
400  for (octave_idx_type j = c1; j <= c2; j++)
401  for (octave_idx_type i = r1; i <= r2; i++)
402  xelem (i, j) = val;
403  }
404 
405  return *this;
406 }
407 
411 {
412  octave_idx_type nr = rows ();
413  octave_idx_type nc = cols ();
414 
415  if (r1 < 0 || r2 < 0 || c1 < 0 || c2 < 0
416  || r1 >= nr || r2 >= nr || c1 >= nc || c2 >= nc)
417  (*current_liboctave_error_handler) ("range error for fill");
418 
419  if (r1 > r2) { std::swap (r1, r2); }
420  if (c1 > c2) { std::swap (c1, c2); }
421 
422  if (r2 >= r1 && c2 >=c1)
423  {
424  make_unique ();
425 
426  for (octave_idx_type j = c1; j <= c2; j++)
427  for (octave_idx_type i = r1; i <= r2; i++)
428  xelem (i, j) = val;
429  }
430 
431  return *this;
432 }
433 
436 {
437  octave_idx_type nr = rows ();
438  octave_idx_type nc = cols ();
439  if (nr != a.rows ())
440  (*current_liboctave_error_handler) ("row dimension mismatch for append");
441 
442  octave_idx_type nc_insert = nc;
443  ComplexMatrix retval (nr, nc + a.cols ());
444  retval.insert (*this, 0, 0);
445  retval.insert (a, 0, nc_insert);
446  return retval;
447 }
448 
451 {
452  octave_idx_type nr = rows ();
453  octave_idx_type nc = cols ();
454  if (nr != 1)
455  (*current_liboctave_error_handler) ("row dimension mismatch for append");
456 
457  octave_idx_type nc_insert = nc;
458  ComplexMatrix retval (nr, nc + a.numel ());
459  retval.insert (*this, 0, 0);
460  retval.insert (a, 0, nc_insert);
461  return retval;
462 }
463 
466 {
467  octave_idx_type nr = rows ();
468  octave_idx_type nc = cols ();
469  if (nr != a.numel ())
470  (*current_liboctave_error_handler) ("row dimension mismatch for append");
471 
472  octave_idx_type nc_insert = nc;
473  ComplexMatrix retval (nr, nc + 1);
474  retval.insert (*this, 0, 0);
475  retval.insert (a, 0, nc_insert);
476  return retval;
477 }
478 
481 {
482  octave_idx_type nr = rows ();
483  octave_idx_type nc = cols ();
484  if (nr != a.rows ())
485  (*current_liboctave_error_handler) ("row dimension mismatch for append");
486 
487  octave_idx_type nc_insert = nc;
488  ComplexMatrix retval (nr, nc + a.cols ());
489  retval.insert (*this, 0, 0);
490  retval.insert (a, 0, nc_insert);
491  return retval;
492 }
493 
496 {
497  octave_idx_type nr = rows ();
498  octave_idx_type nc = cols ();
499  if (nr != a.rows ())
500  (*current_liboctave_error_handler) ("row dimension mismatch for append");
501 
502  octave_idx_type nc_insert = nc;
503  ComplexMatrix retval (nr, nc + a.cols ());
504  retval.insert (*this, 0, 0);
505  retval.insert (a, 0, nc_insert);
506  return retval;
507 }
508 
511 {
512  octave_idx_type nr = rows ();
513  octave_idx_type nc = cols ();
514  if (nr != 1)
515  (*current_liboctave_error_handler) ("row dimension mismatch for append");
516 
517  octave_idx_type nc_insert = nc;
518  ComplexMatrix retval (nr, nc + a.numel ());
519  retval.insert (*this, 0, 0);
520  retval.insert (a, 0, nc_insert);
521  return retval;
522 }
523 
526 {
527  octave_idx_type nr = rows ();
528  octave_idx_type nc = cols ();
529  if (nr != a.numel ())
530  (*current_liboctave_error_handler) ("row dimension mismatch for append");
531 
532  octave_idx_type nc_insert = nc;
533  ComplexMatrix retval (nr, nc + 1);
534  retval.insert (*this, 0, 0);
535  retval.insert (a, 0, nc_insert);
536  return retval;
537 }
538 
541 {
542  octave_idx_type nr = rows ();
543  octave_idx_type nc = cols ();
544  if (nr != a.rows ())
545  (*current_liboctave_error_handler) ("row dimension mismatch for append");
546 
547  octave_idx_type nc_insert = nc;
548  ComplexMatrix retval (nr, nc + a.cols ());
549  retval.insert (*this, 0, 0);
550  retval.insert (a, 0, nc_insert);
551  return retval;
552 }
553 
555 ComplexMatrix::stack (const Matrix& a) const
556 {
557  octave_idx_type nr = rows ();
558  octave_idx_type nc = cols ();
559  if (nc != a.cols ())
560  (*current_liboctave_error_handler) ("column dimension mismatch for stack");
561 
562  octave_idx_type nr_insert = nr;
563  ComplexMatrix retval (nr + a.rows (), nc);
564  retval.insert (*this, 0, 0);
565  retval.insert (a, nr_insert, 0);
566  return retval;
567 }
568 
571 {
572  octave_idx_type nr = rows ();
573  octave_idx_type nc = cols ();
574  if (nc != a.numel ())
575  (*current_liboctave_error_handler) ("column dimension mismatch for stack");
576 
577  octave_idx_type nr_insert = nr;
578  ComplexMatrix retval (nr + 1, nc);
579  retval.insert (*this, 0, 0);
580  retval.insert (a, nr_insert, 0);
581  return retval;
582 }
583 
586 {
587  octave_idx_type nr = rows ();
588  octave_idx_type nc = cols ();
589  if (nc != 1)
590  (*current_liboctave_error_handler) ("column dimension mismatch for stack");
591 
592  octave_idx_type nr_insert = nr;
593  ComplexMatrix retval (nr + a.numel (), nc);
594  retval.insert (*this, 0, 0);
595  retval.insert (a, nr_insert, 0);
596  return retval;
597 }
598 
601 {
602  octave_idx_type nr = rows ();
603  octave_idx_type nc = cols ();
604  if (nc != a.cols ())
605  (*current_liboctave_error_handler) ("column dimension mismatch for stack");
606 
607  octave_idx_type nr_insert = nr;
608  ComplexMatrix retval (nr + a.rows (), nc);
609  retval.insert (*this, 0, 0);
610  retval.insert (a, nr_insert, 0);
611  return retval;
612 }
613 
616 {
617  octave_idx_type nr = rows ();
618  octave_idx_type nc = cols ();
619  if (nc != a.cols ())
620  (*current_liboctave_error_handler) ("column dimension mismatch for stack");
621 
622  octave_idx_type nr_insert = nr;
623  ComplexMatrix retval (nr + a.rows (), nc);
624  retval.insert (*this, 0, 0);
625  retval.insert (a, nr_insert, 0);
626  return retval;
627 }
628 
631 {
632  octave_idx_type nr = rows ();
633  octave_idx_type nc = cols ();
634  if (nc != a.numel ())
635  (*current_liboctave_error_handler) ("column dimension mismatch for stack");
636 
637  octave_idx_type nr_insert = nr;
638  ComplexMatrix retval (nr + 1, nc);
639  retval.insert (*this, 0, 0);
640  retval.insert (a, nr_insert, 0);
641  return retval;
642 }
643 
646 {
647  octave_idx_type nr = rows ();
648  octave_idx_type nc = cols ();
649  if (nc != 1)
650  (*current_liboctave_error_handler) ("column dimension mismatch for stack");
651 
652  octave_idx_type nr_insert = nr;
653  ComplexMatrix retval (nr + a.numel (), nc);
654  retval.insert (*this, 0, 0);
655  retval.insert (a, nr_insert, 0);
656  return retval;
657 }
658 
661 {
662  octave_idx_type nr = rows ();
663  octave_idx_type nc = cols ();
664  if (nc != a.cols ())
665  (*current_liboctave_error_handler) ("column dimension mismatch for stack");
666 
667  octave_idx_type nr_insert = nr;
668  ComplexMatrix retval (nr + a.rows (), nc);
669  retval.insert (*this, 0, 0);
670  retval.insert (a, nr_insert, 0);
671  return retval;
672 }
673 
675 conj (const ComplexMatrix& a)
676 {
677  return do_mx_unary_map<Complex, Complex, std::conj<double>> (a);
678 }
679 
680 // resize is the destructive equivalent for this one
681 
684  octave_idx_type r2, octave_idx_type c2) const
685 {
686  if (r1 > r2) { std::swap (r1, r2); }
687  if (c1 > c2) { std::swap (c1, c2); }
688 
689  return index (octave::idx_vector (r1, r2+1), octave::idx_vector (c1, c2+1));
690 }
691 
694  octave_idx_type nr, octave_idx_type nc) const
695 {
696  return index (octave::idx_vector (r1, r1 + nr), octave::idx_vector (c1, c1 + nc));
697 }
698 
699 // extract row or column i.
700 
703 {
704  return index (octave::idx_vector (i), octave::idx_vector::colon);
705 }
706 
709 {
710  return index (octave::idx_vector::colon, octave::idx_vector (i));
711 }
712 
713 // Local function to calculate the 1-norm.
714 static
715 double
716 norm1 (const ComplexMatrix& a)
717 {
718  double anorm = 0.0;
719  RowVector colsum = a.abs ().sum ().row (0);
720 
721  for (octave_idx_type i = 0; i < colsum.numel (); i++)
722  {
723  double sum = colsum.xelem (i);
724  if (octave::math::isinf (sum) || octave::math::isnan (sum))
725  {
726  anorm = sum; // Pass Inf or NaN to output
727  break;
728  }
729  else
730  anorm = std::max (anorm, sum);
731  }
732 
733  return anorm;
734 }
735 
738 {
739  octave_idx_type info;
740  double rcon;
741  MatrixType mattype (*this);
742  return inverse (mattype, info, rcon, 0, 0);
743 }
744 
747 {
748  double rcon;
749  MatrixType mattype (*this);
750  return inverse (mattype, info, rcon, 0, 0);
751 }
752 
754 ComplexMatrix::inverse (octave_idx_type& info, double& rcon, bool force,
755  bool calc_cond) const
756 {
757  MatrixType mattype (*this);
758  return inverse (mattype, info, rcon, force, calc_cond);
759 }
760 
763 {
764  octave_idx_type info;
765  double rcon;
766  return inverse (mattype, info, rcon, 0, 0);
767 }
768 
771 {
772  double rcon;
773  return inverse (mattype, info, rcon, 0, 0);
774 }
775 
777 ComplexMatrix::tinverse (MatrixType& mattype, octave_idx_type& info,
778  double& rcon, bool force, bool calc_cond) const
779 {
780  ComplexMatrix retval;
781 
782  F77_INT nr = octave::to_f77_int (rows ());
783  F77_INT nc = octave::to_f77_int (cols ());
784 
785  if (nr != nc || nr == 0 || nc == 0)
786  (*current_liboctave_error_handler) ("inverse requires square matrix");
787 
788  int typ = mattype.type ();
789  char uplo = (typ == MatrixType::Lower ? 'L' : 'U');
790  char udiag = 'N';
791  retval = *this;
792  Complex *tmp_data = retval.fortran_vec ();
793 
794  F77_INT tmp_info = 0;
795 
796  F77_XFCN (ztrtri, ZTRTRI, (F77_CONST_CHAR_ARG2 (&uplo, 1),
797  F77_CONST_CHAR_ARG2 (&udiag, 1),
798  nr, F77_DBLE_CMPLX_ARG (tmp_data), nr, tmp_info
799  F77_CHAR_ARG_LEN (1)
800  F77_CHAR_ARG_LEN (1)));
801 
802  info = tmp_info;
803 
804  // Throw away extra info LAPACK gives so as to not change output.
805  rcon = 0.0;
806  if (info != 0)
807  info = -1;
808  else if (calc_cond)
809  {
810  F77_INT ztrcon_info = 0;
811  char job = '1';
812 
813  OCTAVE_LOCAL_BUFFER (Complex, cwork, 2*nr);
814  OCTAVE_LOCAL_BUFFER (double, rwork, nr);
815 
816  F77_XFCN (ztrcon, ZTRCON, (F77_CONST_CHAR_ARG2 (&job, 1),
817  F77_CONST_CHAR_ARG2 (&uplo, 1),
818  F77_CONST_CHAR_ARG2 (&udiag, 1),
819  nr, F77_DBLE_CMPLX_ARG (tmp_data), nr, rcon,
820  F77_DBLE_CMPLX_ARG (cwork), rwork, ztrcon_info
821  F77_CHAR_ARG_LEN (1)
822  F77_CHAR_ARG_LEN (1)
823  F77_CHAR_ARG_LEN (1)));
824 
825  if (ztrcon_info != 0)
826  info = -1;
827  }
828 
829  if (info == -1 && ! force)
830  retval = *this; // Restore matrix contents.
831 
832  return retval;
833 }
834 
836 ComplexMatrix::finverse (MatrixType& mattype, octave_idx_type& info,
837  double& rcon, bool force, bool calc_cond) const
838 {
839  ComplexMatrix retval;
840 
841  F77_INT nr = octave::to_f77_int (rows ());
842  F77_INT nc = octave::to_f77_int (cols ());
843 
844  if (nr != nc)
845  (*current_liboctave_error_handler) ("inverse requires square matrix");
846 
847  Array<F77_INT> ipvt (dim_vector (nr, 1));
848  F77_INT *pipvt = ipvt.fortran_vec ();
849 
850  retval = *this;
851  Complex *tmp_data = retval.fortran_vec ();
852 
853  Array<Complex> z (dim_vector (1, 1));
854  F77_INT lwork = -1;
855 
856  // Query the optimum work array size.
857 
858  F77_INT tmp_info = 0;
859 
860  F77_XFCN (zgetri, ZGETRI, (nc, F77_DBLE_CMPLX_ARG (tmp_data), nr, pipvt,
861  F77_DBLE_CMPLX_ARG (z.fortran_vec ()), lwork,
862  tmp_info));
863 
864  lwork = static_cast<F77_INT> (std::real (z(0)));
865  lwork = (lwork < 2 * nc ? 2 * nc : lwork);
866  z.resize (dim_vector (lwork, 1));
867  Complex *pz = z.fortran_vec ();
868 
869  info = 0;
870  tmp_info = 0;
871 
872  // Calculate norm of the matrix (always, see bug #45577) for later use.
873  double anorm = norm1 (retval);
874 
875  // Work around bug #45577, LAPACK crashes Octave if norm is NaN
876  // and bug #46330, segfault with matrices containing Inf & NaN
877  if (octave::math::isnan (anorm) || octave::math::isinf (anorm))
878  info = -1;
879  else
880  {
881  F77_XFCN (zgetrf, ZGETRF, (nc, nc, F77_DBLE_CMPLX_ARG (tmp_data), nr,
882  pipvt, tmp_info));
883 
884  info = tmp_info;
885  }
886 
887  // Throw away extra info LAPACK gives so as to not change output.
888  rcon = 0.0;
889  if (info != 0)
890  info = -1;
891  else if (calc_cond)
892  {
893  if (octave::math::isnan (anorm))
895  else
896  {
897  F77_INT zgecon_info = 0;
898 
899  // Now calculate the condition number for non-singular matrix.
900  char job = '1';
901  Array<double> rz (dim_vector (2 * nc, 1));
902  double *prz = rz.fortran_vec ();
903  F77_XFCN (zgecon, ZGECON, (F77_CONST_CHAR_ARG2 (&job, 1),
904  nc, F77_DBLE_CMPLX_ARG (tmp_data), nr,
905  anorm, rcon, F77_DBLE_CMPLX_ARG (pz), prz,
906  zgecon_info F77_CHAR_ARG_LEN (1)));
907 
908  if (zgecon_info != 0)
909  info = -1;
910  }
911  }
912 
913  if ((info == -1 && ! force)
914  || octave::math::isnan (anorm) || octave::math::isinf (anorm))
915  retval = *this; // Restore contents.
916  else
917  {
918  F77_INT zgetri_info = 0;
919 
920  F77_XFCN (zgetri, ZGETRI, (nc, F77_DBLE_CMPLX_ARG (tmp_data), nr, pipvt,
921  F77_DBLE_CMPLX_ARG (pz), lwork, zgetri_info));
922 
923  if (zgetri_info != 0)
924  info = -1;
925  }
926 
927  if (info != 0)
928  mattype.mark_as_rectangular ();
929 
930  return retval;
931 }
932 
935  double& rcon, bool force, bool calc_cond) const
936 {
937  int typ = mattype.type (false);
938  ComplexMatrix ret;
939 
940  if (typ == MatrixType::Unknown)
941  typ = mattype.type (*this);
942 
943  if (typ == MatrixType::Diagonal) // a scalar is classified as Diagonal.
944  {
945  Complex scalar = this->elem (0);
946  double real = std::real (scalar);
947  double imag = std::imag (scalar);
948 
949  if (real == 0 && imag == 0)
950  ret = ComplexMatrix (1, 1,
952  else
953  ret = Complex (1, 0) / (*this);
954 
955  if (calc_cond)
956  {
958  && (real != 0 || imag != 0))
959  rcon = 1.0;
961  || (real == 0 && imag == 0))
962  rcon = 0.0;
963  else
965  }
966  }
967  else if (typ == MatrixType::Upper || typ == MatrixType::Lower)
968  ret = tinverse (mattype, info, rcon, force, calc_cond);
969  else
970  {
971  if (mattype.ishermitian ())
972  {
973  octave::math::chol<ComplexMatrix> chol (*this, info, true, calc_cond);
974  if (info == 0)
975  {
976  if (calc_cond)
977  rcon = chol.rcond ();
978  else
979  rcon = 1.0;
980  ret = chol.inverse ();
981  }
982  else
983  mattype.mark_as_unsymmetric ();
984  }
985 
986  if (! mattype.ishermitian ())
987  ret = finverse (mattype, info, rcon, force, calc_cond);
988 
989  if ((calc_cond || mattype.ishermitian ()) && rcon == 0.0)
990  {
991  ret = ComplexMatrix (rows (), columns (),
993  }
994  }
995 
996  return ret;
997 }
998 
1001 {
1002  ComplexMatrix retval;
1003 
1004  octave::math::svd<ComplexMatrix> result (*this,
1005  octave::math::svd<ComplexMatrix>::Type::economy);
1006 
1007  DiagMatrix S = result.singular_values ();
1008  ComplexMatrix U = result.left_singular_matrix ();
1009  ComplexMatrix V = result.right_singular_matrix ();
1010 
1011  ColumnVector sigma = S.extract_diag ();
1012 
1013  octave_idx_type r = sigma.numel () - 1;
1014  octave_idx_type nr = rows ();
1015  octave_idx_type nc = cols ();
1016 
1017  if (tol <= 0.0)
1018  {
1019  tol = std::max (nr, nc) * sigma.elem (0)
1020  * std::numeric_limits<double>::epsilon ();
1021 
1022  if (tol == 0)
1024  }
1025 
1026  while (r >= 0 && sigma.elem (r) < tol)
1027  r--;
1028 
1029  if (r < 0)
1030  retval = ComplexMatrix (nc, nr, 0.0);
1031  else
1032  {
1033  ComplexMatrix Ur = U.extract (0, 0, nr-1, r);
1034  DiagMatrix D = DiagMatrix (sigma.extract (0, r)).inverse ();
1035  ComplexMatrix Vr = V.extract (0, 0, nc-1, r);
1036  retval = Vr * D * Ur.hermitian ();
1037  }
1038 
1039  return retval;
1040 }
1041 
1042 #if defined (HAVE_FFTW)
1043 
1046 {
1047  std::size_t nr = rows ();
1048  std::size_t nc = cols ();
1049 
1050  ComplexMatrix retval (nr, nc);
1051 
1052  std::size_t npts, nsamples;
1053 
1054  if (nr == 1 || nc == 1)
1055  {
1056  npts = (nr > nc ? nr : nc);
1057  nsamples = 1;
1058  }
1059  else
1060  {
1061  npts = nr;
1062  nsamples = nc;
1063  }
1064 
1065  const Complex *in (data ());
1066  Complex *out (retval.fortran_vec ());
1067 
1068  octave::fftw::fft (in, out, npts, nsamples);
1069 
1070  return retval;
1071 }
1072 
1075 {
1076  std::size_t nr = rows ();
1077  std::size_t nc = cols ();
1078 
1079  ComplexMatrix retval (nr, nc);
1080 
1081  std::size_t npts, nsamples;
1082 
1083  if (nr == 1 || nc == 1)
1084  {
1085  npts = (nr > nc ? nr : nc);
1086  nsamples = 1;
1087  }
1088  else
1089  {
1090  npts = nr;
1091  nsamples = nc;
1092  }
1093 
1094  const Complex *in (data ());
1095  Complex *out (retval.fortran_vec ());
1096 
1097  octave::fftw::ifft (in, out, npts, nsamples);
1098 
1099  return retval;
1100 }
1101 
1104 {
1105  dim_vector dv (rows (), cols ());
1106 
1107  ComplexMatrix retval (rows (), cols ());
1108  const Complex *in (data ());
1109  Complex *out (retval.fortran_vec ());
1110 
1111  octave::fftw::fftNd (in, out, 2, dv);
1112 
1113  return retval;
1114 }
1115 
1118 {
1119  dim_vector dv (rows (), cols ());
1120 
1121  ComplexMatrix retval (rows (), cols ());
1122  const Complex *in (data ());
1123  Complex *out (retval.fortran_vec ());
1124 
1125  octave::fftw::ifftNd (in, out, 2, dv);
1126 
1127  return retval;
1128 }
1129 
1130 #else
1131 
1133 ComplexMatrix::fourier () const
1134 {
1135  (*current_liboctave_error_handler)
1136  ("support for FFTW was unavailable or disabled when liboctave was built");
1137 
1138  return ComplexMatrix ();
1139 }
1140 
1142 ComplexMatrix::ifourier () const
1143 {
1144  (*current_liboctave_error_handler)
1145  ("support for FFTW was unavailable or disabled when liboctave was built");
1146 
1147  return ComplexMatrix ();
1148 }
1149 
1151 ComplexMatrix::fourier2d () const
1152 {
1153  (*current_liboctave_error_handler)
1154  ("support for FFTW was unavailable or disabled when liboctave was built");
1155 
1156  return ComplexMatrix ();
1157 }
1158 
1161 {
1162  (*current_liboctave_error_handler)
1163  ("support for FFTW was unavailable or disabled when liboctave was built");
1164 
1165  return ComplexMatrix ();
1166 }
1167 
1168 #endif
1169 
1170 ComplexDET
1172 {
1173  octave_idx_type info;
1174  double rcon;
1175  return determinant (info, rcon, 0);
1176 }
1177 
1178 ComplexDET
1180 {
1181  double rcon;
1182  return determinant (info, rcon, 0);
1183 }
1184 
1185 ComplexDET
1187  bool calc_cond) const
1188 {
1189  MatrixType mattype (*this);
1190  return determinant (mattype, info, rcon, calc_cond);
1191 }
1192 
1193 ComplexDET
1195  octave_idx_type& info, double& rcon,
1196  bool calc_cond) const
1197 {
1198  ComplexDET retval (1.0);
1199 
1200  info = 0;
1201  rcon = 0.0;
1202 
1203  F77_INT nr = octave::to_f77_int (rows ());
1204  F77_INT nc = octave::to_f77_int (cols ());
1205 
1206  if (nr != nc)
1207  (*current_liboctave_error_handler) ("matrix must be square");
1208 
1209  volatile int typ = mattype.type ();
1210 
1211  // Even though the matrix is marked as singular (Rectangular), we may
1212  // still get a useful number from the LU factorization, because it always
1213  // completes.
1214 
1215  if (typ == MatrixType::Unknown)
1216  typ = mattype.type (*this);
1217  else if (typ == MatrixType::Rectangular)
1218  typ = MatrixType::Full;
1219 
1220  if (typ == MatrixType::Lower || typ == MatrixType::Upper)
1221  {
1222  for (F77_INT i = 0; i < nc; i++)
1223  retval *= elem (i, i);
1224  }
1225  else if (typ == MatrixType::Hermitian)
1226  {
1227  ComplexMatrix atmp = *this;
1228  Complex *tmp_data = atmp.fortran_vec ();
1229 
1230  double anorm;
1231  if (calc_cond)
1232  anorm = norm1 (*this);
1233 
1234  F77_INT tmp_info = 0;
1235 
1236  char job = 'L';
1237  F77_XFCN (zpotrf, ZPOTRF, (F77_CONST_CHAR_ARG2 (&job, 1), nr,
1238  F77_DBLE_CMPLX_ARG (tmp_data), nr, tmp_info
1239  F77_CHAR_ARG_LEN (1)));
1240 
1241  info = tmp_info;
1242 
1243  if (info != 0)
1244  {
1245  rcon = 0.0;
1246  mattype.mark_as_unsymmetric ();
1247  typ = MatrixType::Full;
1248  }
1249  else
1250  {
1251  if (calc_cond)
1252  {
1253  Array<Complex> z (dim_vector (2 * nc, 1));
1254  Complex *pz = z.fortran_vec ();
1255  Array<double> rz (dim_vector (nc, 1));
1256  double *prz = rz.fortran_vec ();
1257 
1258  F77_XFCN (zpocon, ZPOCON, (F77_CONST_CHAR_ARG2 (&job, 1),
1259  nr, F77_DBLE_CMPLX_ARG (tmp_data), nr, anorm,
1260  rcon, F77_DBLE_CMPLX_ARG (pz), prz, tmp_info
1261  F77_CHAR_ARG_LEN (1)));
1262 
1263  info = tmp_info;
1264 
1265  if (info != 0)
1266  rcon = 0.0;
1267  }
1268 
1269  for (F77_INT i = 0; i < nc; i++)
1270  retval *= atmp(i, i);
1271 
1272  retval = retval.square ();
1273  }
1274  }
1275  else if (typ != MatrixType::Full)
1276  (*current_liboctave_error_handler) ("det: invalid dense matrix type");
1277 
1278  if (typ == MatrixType::Full)
1279  {
1280  Array<F77_INT> ipvt (dim_vector (nr, 1));
1281  F77_INT *pipvt = ipvt.fortran_vec ();
1282 
1283  ComplexMatrix atmp = *this;
1284  Complex *tmp_data = atmp.fortran_vec ();
1285 
1286  info = 0;
1287 
1288  // Calculate norm of the matrix (always, see bug #45577) for later use.
1289  double anorm = norm1 (*this);
1290 
1291  F77_INT tmp_info = 0;
1292 
1293  // Work around bug #45577, LAPACK crashes Octave if norm is NaN
1294  if (octave::math::isnan (anorm))
1295  info = -1;
1296  else
1297  {
1298  F77_XFCN (zgetrf, ZGETRF, (nr, nr, F77_DBLE_CMPLX_ARG (tmp_data), nr, pipvt,
1299  tmp_info));
1300 
1301  info = tmp_info;
1302  }
1303 
1304  // Throw away extra info LAPACK gives so as to not change output.
1305  rcon = 0.0;
1306  if (info != 0)
1307  {
1308  info = -1;
1309  retval = ComplexDET ();
1310  }
1311  else
1312  {
1313  if (calc_cond)
1314  {
1315  // Now calc the condition number for non-singular matrix.
1316  char job = '1';
1317  Array<Complex> z (dim_vector (2 * nc, 1));
1318  Complex *pz = z.fortran_vec ();
1319  Array<double> rz (dim_vector (2 * nc, 1));
1320  double *prz = rz.fortran_vec ();
1321 
1322  F77_XFCN (zgecon, ZGECON, (F77_CONST_CHAR_ARG2 (&job, 1),
1323  nc, F77_DBLE_CMPLX_ARG (tmp_data), nr, anorm,
1324  rcon, F77_DBLE_CMPLX_ARG (pz), prz, tmp_info
1325  F77_CHAR_ARG_LEN (1)));
1326 
1327  info = tmp_info;
1328  }
1329 
1330  if (info != 0)
1331  {
1332  info = -1;
1333  retval = ComplexDET ();
1334  }
1335  else
1336  {
1337  for (F77_INT i = 0; i < nc; i++)
1338  {
1339  Complex c = atmp(i, i);
1340  retval *= (ipvt(i) != (i+1)) ? -c : c;
1341  }
1342  }
1343  }
1344  }
1345 
1346  return retval;
1347 }
1348 
1349 double
1351 {
1352  MatrixType mattype (*this);
1353  return rcond (mattype);
1354 }
1355 
1356 double
1358 {
1359  double rcon = octave::numeric_limits<double>::NaN ();
1360  F77_INT nr = octave::to_f77_int (rows ());
1361  F77_INT nc = octave::to_f77_int (cols ());
1362 
1363  if (nr != nc)
1364  (*current_liboctave_error_handler) ("matrix must be square");
1365 
1366  if (nr == 0 || nc == 0)
1368  else
1369  {
1370  volatile int typ = mattype.type ();
1371 
1372  if (typ == MatrixType::Unknown)
1373  typ = mattype.type (*this);
1374 
1375  // Only calculate the condition number for LU/Cholesky
1376  if (typ == MatrixType::Upper)
1377  {
1378  const Complex *tmp_data = data ();
1379  F77_INT info = 0;
1380  char norm = '1';
1381  char uplo = 'U';
1382  char dia = 'N';
1383 
1384  Array<Complex> z (dim_vector (2 * nc, 1));
1385  Complex *pz = z.fortran_vec ();
1386  Array<double> rz (dim_vector (nc, 1));
1387  double *prz = rz.fortran_vec ();
1388 
1389  F77_XFCN (ztrcon, ZTRCON, (F77_CONST_CHAR_ARG2 (&norm, 1),
1390  F77_CONST_CHAR_ARG2 (&uplo, 1),
1391  F77_CONST_CHAR_ARG2 (&dia, 1),
1392  nr, F77_CONST_DBLE_CMPLX_ARG (tmp_data), nr, rcon,
1393  F77_DBLE_CMPLX_ARG (pz), prz, info
1394  F77_CHAR_ARG_LEN (1)
1395  F77_CHAR_ARG_LEN (1)
1396  F77_CHAR_ARG_LEN (1)));
1397 
1398  if (info != 0)
1399  rcon = 0;
1400  }
1401  else if (typ == MatrixType::Permuted_Upper)
1402  (*current_liboctave_error_handler)
1403  ("permuted triangular matrix not implemented");
1404  else if (typ == MatrixType::Lower)
1405  {
1406  const Complex *tmp_data = data ();
1407  F77_INT info = 0;
1408  char norm = '1';
1409  char uplo = 'L';
1410  char dia = 'N';
1411 
1412  Array<Complex> z (dim_vector (2 * nc, 1));
1413  Complex *pz = z.fortran_vec ();
1414  Array<double> rz (dim_vector (nc, 1));
1415  double *prz = rz.fortran_vec ();
1416 
1417  F77_XFCN (ztrcon, ZTRCON, (F77_CONST_CHAR_ARG2 (&norm, 1),
1418  F77_CONST_CHAR_ARG2 (&uplo, 1),
1419  F77_CONST_CHAR_ARG2 (&dia, 1),
1420  nr, F77_CONST_DBLE_CMPLX_ARG (tmp_data), nr, rcon,
1421  F77_DBLE_CMPLX_ARG (pz), prz, info
1422  F77_CHAR_ARG_LEN (1)
1423  F77_CHAR_ARG_LEN (1)
1424  F77_CHAR_ARG_LEN (1)));
1425 
1426  if (info != 0)
1427  rcon = 0.0;
1428  }
1429  else if (typ == MatrixType::Permuted_Lower)
1430  (*current_liboctave_error_handler)
1431  ("permuted triangular matrix not implemented");
1432  else if (typ == MatrixType::Full || typ == MatrixType::Hermitian)
1433  {
1434  double anorm = -1.0;
1435 
1436  if (typ == MatrixType::Hermitian)
1437  {
1438  F77_INT info = 0;
1439  char job = 'L';
1440 
1441  ComplexMatrix atmp = *this;
1442  Complex *tmp_data = atmp.fortran_vec ();
1443 
1444  anorm = norm1 (atmp);
1445 
1446  F77_XFCN (zpotrf, ZPOTRF, (F77_CONST_CHAR_ARG2 (&job, 1), nr,
1447  F77_DBLE_CMPLX_ARG (tmp_data), nr, info
1448  F77_CHAR_ARG_LEN (1)));
1449 
1450  if (info != 0)
1451  {
1452  rcon = 0.0;
1453 
1454  mattype.mark_as_unsymmetric ();
1455  typ = MatrixType::Full;
1456  }
1457  else
1458  {
1459  Array<Complex> z (dim_vector (2 * nc, 1));
1460  Complex *pz = z.fortran_vec ();
1461  Array<double> rz (dim_vector (nc, 1));
1462  double *prz = rz.fortran_vec ();
1463 
1464  F77_XFCN (zpocon, ZPOCON, (F77_CONST_CHAR_ARG2 (&job, 1),
1465  nr, F77_DBLE_CMPLX_ARG (tmp_data), nr, anorm,
1466  rcon, F77_DBLE_CMPLX_ARG (pz), prz, info
1467  F77_CHAR_ARG_LEN (1)));
1468 
1469  if (info != 0)
1470  rcon = 0.0;
1471  }
1472  }
1473 
1474  if (typ == MatrixType::Full)
1475  {
1476  F77_INT info = 0;
1477 
1478  ComplexMatrix atmp = *this;
1479  Complex *tmp_data = atmp.fortran_vec ();
1480 
1481  Array<F77_INT> ipvt (dim_vector (nr, 1));
1482  F77_INT *pipvt = ipvt.fortran_vec ();
1483 
1484  if (anorm < 0.0)
1485  anorm = norm1 (atmp);
1486 
1487  Array<Complex> z (dim_vector (2 * nc, 1));
1488  Complex *pz = z.fortran_vec ();
1489  Array<double> rz (dim_vector (2 * nc, 1));
1490  double *prz = rz.fortran_vec ();
1491 
1492  // Work around bug #45577, LAPACK crashes Octave if norm is NaN
1493  if (octave::math::isnan (anorm))
1494  info = -1;
1495  else
1496  F77_XFCN (zgetrf, ZGETRF, (nr, nr,
1497  F77_DBLE_CMPLX_ARG (tmp_data),
1498  nr, pipvt, info));
1499 
1500  if (info != 0)
1501  {
1502  rcon = 0.0;
1503  mattype.mark_as_rectangular ();
1504  }
1505  else
1506  {
1507  char job = '1';
1508  F77_XFCN (zgecon, ZGECON, (F77_CONST_CHAR_ARG2 (&job, 1),
1509  nc, F77_DBLE_CMPLX_ARG (tmp_data), nr, anorm,
1510  rcon, F77_DBLE_CMPLX_ARG (pz), prz, info
1511  F77_CHAR_ARG_LEN (1)));
1512 
1513  if (info != 0)
1514  rcon = 0.0;
1515  }
1516  }
1517  }
1518  else
1519  rcon = 0.0;
1520  }
1521 
1522  return rcon;
1523 }
1524 
1526 ComplexMatrix::utsolve (MatrixType& mattype, const ComplexMatrix& b,
1527  octave_idx_type& info, double& rcon,
1528  solve_singularity_handler sing_handler,
1529  bool calc_cond, blas_trans_type transt) const
1530 {
1531  ComplexMatrix retval;
1532 
1533  F77_INT nr = octave::to_f77_int (rows ());
1534  F77_INT nc = octave::to_f77_int (cols ());
1535 
1536  F77_INT b_nr = octave::to_f77_int (b.rows ());
1537  F77_INT b_nc = octave::to_f77_int (b.cols ());
1538 
1539  if (nr != b_nr)
1540  (*current_liboctave_error_handler)
1541  ("matrix dimension mismatch solution of linear equations");
1542 
1543  if (nr == 0 || nc == 0 || b_nc == 0)
1544  retval = ComplexMatrix (nc, b_nc, Complex (0.0, 0.0));
1545  else
1546  {
1547  volatile int typ = mattype.type ();
1548 
1549  if (typ != MatrixType::Permuted_Upper && typ != MatrixType::Upper)
1550  (*current_liboctave_error_handler) ("incorrect matrix type");
1551 
1552  rcon = 1.0;
1553  info = 0;
1554 
1555  if (typ == MatrixType::Permuted_Upper)
1556  (*current_liboctave_error_handler)
1557  ("permuted triangular matrix not implemented");
1558 
1559  const Complex *tmp_data = data ();
1560 
1561  retval = b;
1562  Complex *result = retval.fortran_vec ();
1563 
1564  char uplo = 'U';
1565  char trans = get_blas_char (transt);
1566  char dia = 'N';
1567 
1568  F77_INT tmp_info = 0;
1569 
1570  F77_XFCN (ztrtrs, ZTRTRS, (F77_CONST_CHAR_ARG2 (&uplo, 1),
1571  F77_CONST_CHAR_ARG2 (&trans, 1),
1572  F77_CONST_CHAR_ARG2 (&dia, 1),
1573  nr, b_nc, F77_CONST_DBLE_CMPLX_ARG (tmp_data), nr,
1574  F77_DBLE_CMPLX_ARG (result), nr, tmp_info
1575  F77_CHAR_ARG_LEN (1)
1576  F77_CHAR_ARG_LEN (1)
1577  F77_CHAR_ARG_LEN (1)));
1578 
1579  info = tmp_info;
1580 
1581  if (calc_cond)
1582  {
1583  char norm = '1';
1584  uplo = 'U';
1585  dia = 'N';
1586 
1587  Array<Complex> z (dim_vector (2 * nc, 1));
1588  Complex *pz = z.fortran_vec ();
1589  Array<double> rz (dim_vector (nc, 1));
1590  double *prz = rz.fortran_vec ();
1591 
1592  F77_XFCN (ztrcon, ZTRCON, (F77_CONST_CHAR_ARG2 (&norm, 1),
1593  F77_CONST_CHAR_ARG2 (&uplo, 1),
1594  F77_CONST_CHAR_ARG2 (&dia, 1),
1595  nr, F77_CONST_DBLE_CMPLX_ARG (tmp_data), nr, rcon,
1596  F77_DBLE_CMPLX_ARG (pz), prz, tmp_info
1597  F77_CHAR_ARG_LEN (1)
1598  F77_CHAR_ARG_LEN (1)
1599  F77_CHAR_ARG_LEN (1)));
1600 
1601  info = tmp_info;
1602 
1603  if (info != 0)
1604  info = -2;
1605 
1606  volatile double rcond_plus_one = rcon + 1.0;
1607 
1608  if (rcond_plus_one == 1.0 || octave::math::isnan (rcon))
1609  {
1610  info = -2;
1611 
1612  if (sing_handler)
1613  sing_handler (rcon);
1614  else
1616  }
1617  }
1618  }
1619 
1620  return retval;
1621 }
1622 
1624 ComplexMatrix::ltsolve (MatrixType& mattype, const ComplexMatrix& b,
1625  octave_idx_type& info, double& rcon,
1626  solve_singularity_handler sing_handler,
1627  bool calc_cond, blas_trans_type transt) const
1628 {
1629  ComplexMatrix retval;
1630 
1631  F77_INT nr = octave::to_f77_int (rows ());
1632  F77_INT nc = octave::to_f77_int (cols ());
1633 
1634  F77_INT b_nr = octave::to_f77_int (b.rows ());
1635  F77_INT b_nc = octave::to_f77_int (b.cols ());
1636 
1637  if (nr != b_nr)
1638  (*current_liboctave_error_handler)
1639  ("matrix dimension mismatch solution of linear equations");
1640 
1641  if (nr == 0 || nc == 0 || b_nc == 0)
1642  retval = ComplexMatrix (nc, b_nc, Complex (0.0, 0.0));
1643  else
1644  {
1645  volatile int typ = mattype.type ();
1646 
1647  if (typ != MatrixType::Permuted_Lower && typ != MatrixType::Lower)
1648  (*current_liboctave_error_handler) ("incorrect matrix type");
1649 
1650  rcon = 1.0;
1651  info = 0;
1652 
1653  if (typ == MatrixType::Permuted_Lower)
1654  (*current_liboctave_error_handler)
1655  ("permuted triangular matrix not implemented");
1656 
1657  const Complex *tmp_data = data ();
1658 
1659  retval = b;
1660  Complex *result = retval.fortran_vec ();
1661 
1662  char uplo = 'L';
1663  char trans = get_blas_char (transt);
1664  char dia = 'N';
1665 
1666  F77_INT tmp_info = 0;
1667 
1668  F77_XFCN (ztrtrs, ZTRTRS, (F77_CONST_CHAR_ARG2 (&uplo, 1),
1669  F77_CONST_CHAR_ARG2 (&trans, 1),
1670  F77_CONST_CHAR_ARG2 (&dia, 1),
1671  nr, b_nc, F77_CONST_DBLE_CMPLX_ARG (tmp_data), nr,
1672  F77_DBLE_CMPLX_ARG (result), nr, tmp_info
1673  F77_CHAR_ARG_LEN (1)
1674  F77_CHAR_ARG_LEN (1)
1675  F77_CHAR_ARG_LEN (1)));
1676 
1677  info = tmp_info;
1678 
1679  if (calc_cond)
1680  {
1681  char norm = '1';
1682  uplo = 'L';
1683  dia = 'N';
1684 
1685  Array<Complex> z (dim_vector (2 * nc, 1));
1686  Complex *pz = z.fortran_vec ();
1687  Array<double> rz (dim_vector (nc, 1));
1688  double *prz = rz.fortran_vec ();
1689 
1690  F77_XFCN (ztrcon, ZTRCON, (F77_CONST_CHAR_ARG2 (&norm, 1),
1691  F77_CONST_CHAR_ARG2 (&uplo, 1),
1692  F77_CONST_CHAR_ARG2 (&dia, 1),
1693  nr, F77_CONST_DBLE_CMPLX_ARG (tmp_data), nr, rcon,
1694  F77_DBLE_CMPLX_ARG (pz), prz, tmp_info
1695  F77_CHAR_ARG_LEN (1)
1696  F77_CHAR_ARG_LEN (1)
1697  F77_CHAR_ARG_LEN (1)));
1698 
1699  info = tmp_info;
1700 
1701  if (info != 0)
1702  info = -2;
1703 
1704  volatile double rcond_plus_one = rcon + 1.0;
1705 
1706  if (rcond_plus_one == 1.0 || octave::math::isnan (rcon))
1707  {
1708  info = -2;
1709 
1710  if (sing_handler)
1711  sing_handler (rcon);
1712  else
1714  }
1715  }
1716  }
1717 
1718  return retval;
1719 }
1720 
1722 ComplexMatrix::fsolve (MatrixType& mattype, const ComplexMatrix& b,
1723  octave_idx_type& info, double& rcon,
1724  solve_singularity_handler sing_handler,
1725  bool calc_cond) const
1726 {
1727  ComplexMatrix retval;
1728 
1729  F77_INT nr = octave::to_f77_int (rows ());
1730  F77_INT nc = octave::to_f77_int (cols ());
1731 
1732  F77_INT b_nr = octave::to_f77_int (b.rows ());
1733  F77_INT b_nc = octave::to_f77_int (b.cols ());
1734 
1735  if (nr != nc || nr != b_nr)
1736  (*current_liboctave_error_handler)
1737  ("matrix dimension mismatch solution of linear equations");
1738 
1739  if (nr == 0 || b_nc == 0)
1740  retval = ComplexMatrix (nc, b_nc, Complex (0.0, 0.0));
1741  else
1742  {
1743  volatile int typ = mattype.type ();
1744 
1745  // Calculate the norm of the matrix for later use when determining rcon.
1746  double anorm = -1.0;
1747 
1748  if (typ == MatrixType::Hermitian)
1749  {
1750  info = 0;
1751  char job = 'L';
1752 
1753  ComplexMatrix atmp = *this;
1754  Complex *tmp_data = atmp.fortran_vec ();
1755 
1756  // The norm of the matrix for later use when determining rcon.
1757  if (calc_cond)
1758  anorm = norm1 (atmp);
1759 
1760  F77_INT tmp_info = 0;
1761 
1762  F77_XFCN (zpotrf, ZPOTRF, (F77_CONST_CHAR_ARG2 (&job, 1), nr,
1763  F77_DBLE_CMPLX_ARG (tmp_data), nr, tmp_info
1764  F77_CHAR_ARG_LEN (1)));
1765 
1766  info = tmp_info;
1767 
1768  // Throw away extra info LAPACK gives so as to not change output.
1769  rcon = 0.0;
1770  if (info != 0)
1771  {
1772  info = -2;
1773 
1774  mattype.mark_as_unsymmetric ();
1775  typ = MatrixType::Full;
1776  }
1777  else
1778  {
1779  if (calc_cond)
1780  {
1781  Array<Complex> z (dim_vector (2 * nc, 1));
1782  Complex *pz = z.fortran_vec ();
1783  Array<double> rz (dim_vector (nc, 1));
1784  double *prz = rz.fortran_vec ();
1785 
1786  F77_XFCN (zpocon, ZPOCON, (F77_CONST_CHAR_ARG2 (&job, 1),
1787  nr, F77_DBLE_CMPLX_ARG (tmp_data), nr, anorm,
1788  rcon, F77_DBLE_CMPLX_ARG (pz), prz, tmp_info
1789  F77_CHAR_ARG_LEN (1)));
1790 
1791  info = tmp_info;
1792 
1793  if (info != 0)
1794  info = -2;
1795 
1796  volatile double rcond_plus_one = rcon + 1.0;
1797 
1798  if (rcond_plus_one == 1.0 || octave::math::isnan (rcon))
1799  {
1800  info = -2;
1801 
1802  if (sing_handler)
1803  sing_handler (rcon);
1804  else
1806  }
1807  }
1808 
1809  if (info == 0)
1810  {
1811  retval = b;
1812  Complex *result = retval.fortran_vec ();
1813 
1814  F77_XFCN (zpotrs, ZPOTRS, (F77_CONST_CHAR_ARG2 (&job, 1),
1815  nr, b_nc, F77_DBLE_CMPLX_ARG (tmp_data), nr,
1816  F77_DBLE_CMPLX_ARG (result), b_nr, tmp_info
1817  F77_CHAR_ARG_LEN (1)));
1818 
1819  info = tmp_info;
1820  }
1821  else
1822  {
1823  mattype.mark_as_unsymmetric ();
1824  typ = MatrixType::Full;
1825  }
1826  }
1827  }
1828 
1829  if (typ == MatrixType::Full)
1830  {
1831  info = 0;
1832 
1833  Array<F77_INT> ipvt (dim_vector (nr, 1));
1834  F77_INT *pipvt = ipvt.fortran_vec ();
1835 
1836  ComplexMatrix atmp = *this;
1837  Complex *tmp_data = atmp.fortran_vec ();
1838 
1839  Array<Complex> z (dim_vector (2 * nc, 1));
1840  Complex *pz = z.fortran_vec ();
1841  Array<double> rz (dim_vector (2 * nc, 1));
1842  double *prz = rz.fortran_vec ();
1843 
1844  // Calculate the norm of the matrix, for later use.
1845  if (calc_cond && anorm < 0.0)
1846  anorm = norm1 (atmp);
1847 
1848  F77_INT tmp_info = 0;
1849 
1850  // Work around bug #45577, LAPACK crashes Octave if norm is NaN
1851  // and bug #46330, segfault with matrices containing Inf & NaN
1852  if (octave::math::isnan (anorm) || octave::math::isinf (anorm))
1853  info = -2;
1854  else
1855  {
1856  F77_XFCN (zgetrf, ZGETRF, (nr, nr, F77_DBLE_CMPLX_ARG (tmp_data),
1857  nr, pipvt, tmp_info));
1858 
1859  info = tmp_info;
1860  }
1861 
1862  // Throw away extra info LAPACK gives so as to not change output.
1863  rcon = 0.0;
1864  if (info != 0)
1865  {
1866  info = -2;
1867 
1868  if (sing_handler)
1869  sing_handler (rcon);
1870  else
1872 
1873  mattype.mark_as_rectangular ();
1874  }
1875  else
1876  {
1877  if (calc_cond)
1878  {
1879  // Calculate the condition number for non-singular matrix.
1880  char job = '1';
1881  F77_XFCN (zgecon, ZGECON, (F77_CONST_CHAR_ARG2 (&job, 1),
1882  nc, F77_DBLE_CMPLX_ARG (tmp_data), nr, anorm,
1883  rcon, F77_DBLE_CMPLX_ARG (pz), prz, tmp_info
1884  F77_CHAR_ARG_LEN (1)));
1885 
1886  info = tmp_info;
1887 
1888  if (info != 0)
1889  info = -2;
1890 
1891  volatile double rcond_plus_one = rcon + 1.0;
1892 
1893  if (rcond_plus_one == 1.0 || octave::math::isnan (rcon))
1894  {
1895  if (sing_handler)
1896  sing_handler (rcon);
1897  else
1899  }
1900  }
1901 
1902  if (info == 0)
1903  {
1904  retval = b;
1905  Complex *result = retval.fortran_vec ();
1906 
1907  char job = 'N';
1908  F77_XFCN (zgetrs, ZGETRS, (F77_CONST_CHAR_ARG2 (&job, 1),
1909  nr, b_nc, F77_DBLE_CMPLX_ARG (tmp_data), nr,
1910  pipvt, F77_DBLE_CMPLX_ARG (result), b_nr, tmp_info
1911  F77_CHAR_ARG_LEN (1)));
1912 
1913  info = tmp_info;
1914  }
1915  else
1916  mattype.mark_as_rectangular ();
1917  }
1918  }
1919 
1920  if (octave::math::isinf (anorm))
1921  {
1922  retval = ComplexMatrix (b_nr, b_nc, Complex (0, 0));
1923  mattype.mark_as_full ();
1924  }
1925  }
1926 
1927  return retval;
1928 }
1929 
1931 ComplexMatrix::solve (MatrixType& mattype, const Matrix& b) const
1932 {
1933  octave_idx_type info;
1934  double rcon;
1935  return solve (mattype, b, info, rcon, nullptr);
1936 }
1937 
1940  octave_idx_type& info) const
1941 {
1942  double rcon;
1943  return solve (mattype, b, info, rcon, nullptr);
1944 }
1945 
1948  octave_idx_type& info, double& rcon) const
1949 {
1950  return solve (mattype, b, info, rcon, nullptr);
1951 }
1952 
1955  octave_idx_type& info, double& rcon,
1956  solve_singularity_handler sing_handler,
1957  bool singular_fallback, blas_trans_type transt) const
1958 {
1959  ComplexMatrix tmp (b);
1960  return solve (mattype, tmp, info, rcon, sing_handler, singular_fallback,
1961  transt);
1962 }
1963 
1966 {
1967  octave_idx_type info;
1968  double rcon;
1969  return solve (mattype, b, info, rcon, nullptr);
1970 }
1971 
1974  octave_idx_type& info) const
1975 {
1976  double rcon;
1977  return solve (mattype, b, info, rcon, nullptr);
1978 }
1979 
1982  octave_idx_type& info, double& rcon) const
1983 {
1984  return solve (mattype, b, info, rcon, nullptr);
1985 }
1986 
1989  octave_idx_type& info, double& rcon,
1990  solve_singularity_handler sing_handler,
1991  bool singular_fallback, blas_trans_type transt) const
1992 {
1993  ComplexMatrix retval;
1994  int typ = mattype.type ();
1995 
1996  if (typ == MatrixType::Unknown)
1997  typ = mattype.type (*this);
1998 
1999  // Only calculate the condition number for LU/Cholesky
2000  if (typ == MatrixType::Upper || typ == MatrixType::Permuted_Upper)
2001  retval = utsolve (mattype, b, info, rcon, sing_handler, true, transt);
2002  else if (typ == MatrixType::Lower || typ == MatrixType::Permuted_Lower)
2003  retval = ltsolve (mattype, b, info, rcon, sing_handler, true, transt);
2004  else if (transt == blas_trans)
2005  return transpose ().solve (mattype, b, info, rcon, sing_handler,
2006  singular_fallback);
2007  else if (transt == blas_conj_trans)
2008  retval = hermitian ().solve (mattype, b, info, rcon, sing_handler,
2009  singular_fallback);
2010  else if (typ == MatrixType::Full || typ == MatrixType::Hermitian)
2011  retval = fsolve (mattype, b, info, rcon, sing_handler, true);
2012  else if (typ != MatrixType::Rectangular)
2013  (*current_liboctave_error_handler) ("unknown matrix type");
2014 
2015  // Rectangular or one of the above solvers flags a singular matrix
2016  if (singular_fallback && mattype.type () == MatrixType::Rectangular)
2017  {
2018  octave_idx_type rank;
2019  retval = lssolve (b, info, rank, rcon);
2020  }
2021 
2022  return retval;
2023 }
2024 
2027 {
2028  octave_idx_type info;
2029  double rcon;
2030  return solve (mattype, ComplexColumnVector (b), info, rcon, nullptr);
2031 }
2032 
2035  octave_idx_type& info) const
2036 {
2037  double rcon;
2038  return solve (mattype, ComplexColumnVector (b), info, rcon, nullptr);
2039 }
2040 
2043  octave_idx_type& info, double& rcon) const
2044 {
2045  return solve (mattype, ComplexColumnVector (b), info, rcon, nullptr);
2046 }
2047 
2050  octave_idx_type& info, double& rcon,
2051  solve_singularity_handler sing_handler,
2052  blas_trans_type transt) const
2053 {
2054  return solve (mattype, ComplexColumnVector (b), info, rcon, sing_handler,
2055  transt);
2056 }
2057 
2060 {
2061  octave_idx_type info;
2062  double rcon;
2063  return solve (mattype, b, info, rcon, nullptr);
2064 }
2065 
2068  octave_idx_type& info) const
2069 {
2070  double rcon;
2071  return solve (mattype, b, info, rcon, nullptr);
2072 }
2073 
2076  octave_idx_type& info, double& rcon) const
2077 {
2078  return solve (mattype, b, info, rcon, nullptr);
2079 }
2080 
2083  octave_idx_type& info, double& rcon,
2084  solve_singularity_handler sing_handler,
2085  blas_trans_type transt) const
2086 {
2087 
2088  ComplexMatrix tmp (b);
2089  tmp = solve (mattype, tmp, info, rcon, sing_handler, true, transt);
2090  return tmp.column (static_cast<octave_idx_type> (0));
2091 }
2092 
2095 {
2096  octave_idx_type info;
2097  double rcon;
2098  return solve (b, info, rcon, nullptr);
2099 }
2100 
2103 {
2104  double rcon;
2105  return solve (b, info, rcon, nullptr);
2106 }
2107 
2110  double& rcon) const
2111 {
2112  return solve (b, info, rcon, nullptr);
2113 }
2114 
2116 ComplexMatrix::solve (const Matrix& b, octave_idx_type& info, double& rcon,
2117  solve_singularity_handler sing_handler,
2118  blas_trans_type transt) const
2119 {
2120  ComplexMatrix tmp (b);
2121  return solve (tmp, info, rcon, sing_handler, transt);
2122 }
2123 
2126 {
2127  octave_idx_type info;
2128  double rcon;
2129  return solve (b, info, rcon, nullptr);
2130 }
2131 
2134 {
2135  double rcon;
2136  return solve (b, info, rcon, nullptr);
2137 }
2138 
2141  double& rcon) const
2142 {
2143  return solve (b, info, rcon, nullptr);
2144 }
2145 
2148  double& rcon,
2149  solve_singularity_handler sing_handler,
2150  blas_trans_type transt) const
2151 {
2152  MatrixType mattype (*this);
2153  return solve (mattype, b, info, rcon, sing_handler, true, transt);
2154 }
2155 
2158 {
2159  octave_idx_type info;
2160  double rcon;
2161  return solve (ComplexColumnVector (b), info, rcon, nullptr);
2162 }
2163 
2166 {
2167  double rcon;
2168  return solve (ComplexColumnVector (b), info, rcon, nullptr);
2169 }
2170 
2173  double& rcon) const
2174 {
2175  return solve (ComplexColumnVector (b), info, rcon, nullptr);
2176 }
2177 
2180  double& rcon,
2181  solve_singularity_handler sing_handler,
2182  blas_trans_type transt) const
2183 {
2184  return solve (ComplexColumnVector (b), info, rcon, sing_handler, transt);
2185 }
2186 
2189 {
2190  octave_idx_type info;
2191  double rcon;
2192  return solve (b, info, rcon, nullptr);
2193 }
2194 
2197 {
2198  double rcon;
2199  return solve (b, info, rcon, nullptr);
2200 }
2201 
2204  double& rcon) const
2205 {
2206  return solve (b, info, rcon, nullptr);
2207 }
2208 
2211  double& rcon,
2212  solve_singularity_handler sing_handler,
2213  blas_trans_type transt) const
2214 {
2215  MatrixType mattype (*this);
2216  return solve (mattype, b, info, rcon, sing_handler, transt);
2217 }
2218 
2221 {
2222  octave_idx_type info;
2223  octave_idx_type rank;
2224  double rcon;
2225  return lssolve (ComplexMatrix (b), info, rank, rcon);
2226 }
2227 
2230 {
2231  octave_idx_type rank;
2232  double rcon;
2233  return lssolve (ComplexMatrix (b), info, rank, rcon);
2234 }
2235 
2238  octave_idx_type& rank) const
2239 {
2240  double rcon;
2241  return lssolve (ComplexMatrix (b), info, rank, rcon);
2242 }
2243 
2246  octave_idx_type& rank, double& rcon) const
2247 {
2248  return lssolve (ComplexMatrix (b), info, rank, rcon);
2249 }
2250 
2253 {
2254  octave_idx_type info;
2255  octave_idx_type rank;
2256  double rcon;
2257  return lssolve (b, info, rank, rcon);
2258 }
2259 
2262 {
2263  octave_idx_type rank;
2264  double rcon;
2265  return lssolve (b, info, rank, rcon);
2266 }
2267 
2270  octave_idx_type& rank) const
2271 {
2272  double rcon;
2273  return lssolve (b, info, rank, rcon);
2274 }
2275 
2278  octave_idx_type& rank, double& rcon) const
2279 {
2280  ComplexMatrix retval;
2281 
2282  F77_INT m = octave::to_f77_int (rows ());
2283  F77_INT n = octave::to_f77_int (cols ());
2284 
2285  F77_INT b_nr = octave::to_f77_int (b.rows ());
2286  F77_INT b_nc = octave::to_f77_int (b.cols ());
2287  F77_INT nrhs = b_nc; // alias for code readability
2288 
2289  if (m != b_nr)
2290  (*current_liboctave_error_handler)
2291  ("matrix dimension mismatch solution of linear equations");
2292 
2293  if (m == 0 || n == 0 || b_nc == 0)
2294  retval = ComplexMatrix (n, b_nc, Complex (0.0, 0.0));
2295  else
2296  {
2297  volatile F77_INT minmn = (m < n ? m : n);
2298  F77_INT maxmn = (m > n ? m : n);
2299  rcon = -1.0;
2300 
2301  if (m != n)
2302  {
2303  retval = ComplexMatrix (maxmn, nrhs);
2304 
2305  for (F77_INT j = 0; j < nrhs; j++)
2306  for (F77_INT i = 0; i < m; i++)
2307  retval.elem (i, j) = b.elem (i, j);
2308  }
2309  else
2310  retval = b;
2311 
2312  ComplexMatrix atmp = *this;
2313  Complex *tmp_data = atmp.fortran_vec ();
2314 
2315  Complex *pretval = retval.fortran_vec ();
2316  Array<double> s (dim_vector (minmn, 1));
2317  double *ps = s.fortran_vec ();
2318 
2319  // Ask ZGELSD what the dimension of WORK should be.
2320  F77_INT lwork = -1;
2321 
2322  Array<Complex> work (dim_vector (1, 1));
2323 
2324  F77_INT smlsiz;
2325  F77_FUNC (xilaenv, XILAENV) (9, F77_CONST_CHAR_ARG2 ("ZGELSD", 6),
2326  F77_CONST_CHAR_ARG2 (" ", 1),
2327  0, 0, 0, 0, smlsiz
2328  F77_CHAR_ARG_LEN (6)
2329  F77_CHAR_ARG_LEN (1));
2330 
2331  F77_INT mnthr;
2332  F77_FUNC (xilaenv, XILAENV) (6, F77_CONST_CHAR_ARG2 ("ZGELSD", 6),
2333  F77_CONST_CHAR_ARG2 (" ", 1),
2334  m, n, nrhs, -1, mnthr
2335  F77_CHAR_ARG_LEN (6)
2336  F77_CHAR_ARG_LEN (1));
2337 
2338  // We compute the size of rwork and iwork because ZGELSD in
2339  // older versions of LAPACK does not return them on a query
2340  // call.
2341  double dminmn = static_cast<double> (minmn);
2342  double dsmlsizp1 = static_cast<double> (smlsiz+1);
2343  double tmp = octave::math::log2 (dminmn / dsmlsizp1);
2344 
2345  F77_INT nlvl = static_cast<F77_INT> (tmp) + 1;
2346  if (nlvl < 0)
2347  nlvl = 0;
2348 
2349  F77_INT lrwork = minmn*(10 + 2*smlsiz + 8*nlvl)
2350  + 3*smlsiz*nrhs
2351  + std::max ((smlsiz+1)*(smlsiz+1),
2352  n*(1+nrhs) + 2*nrhs);
2353  if (lrwork < 1)
2354  lrwork = 1;
2355  Array<double> rwork (dim_vector (lrwork, 1));
2356  double *prwork = rwork.fortran_vec ();
2357 
2358  F77_INT liwork = 3 * minmn * nlvl + 11 * minmn;
2359  if (liwork < 1)
2360  liwork = 1;
2361  Array<F77_INT> iwork (dim_vector (liwork, 1));
2362  F77_INT *piwork = iwork.fortran_vec ();
2363 
2364  F77_INT tmp_info = 0;
2365  F77_INT tmp_rank = 0;
2366 
2367  F77_XFCN (zgelsd, ZGELSD, (m, n, nrhs, F77_DBLE_CMPLX_ARG (tmp_data), m,
2368  F77_DBLE_CMPLX_ARG (pretval), maxmn,
2369  ps, rcon, tmp_rank, F77_DBLE_CMPLX_ARG (work.fortran_vec ()),
2370  lwork, prwork, piwork, tmp_info));
2371 
2372  info = tmp_info;
2373  rank = tmp_rank;
2374 
2375  // The workspace query is broken in at least LAPACK 3.0.0
2376  // through 3.1.1 when n >= mnthr. The obtuse formula below
2377  // should provide sufficient workspace for ZGELSD to operate
2378  // efficiently.
2379  if (n > m && n >= mnthr)
2380  {
2381  F77_INT addend = m;
2382 
2383  if (2*m-4 > addend)
2384  addend = 2*m-4;
2385 
2386  if (nrhs > addend)
2387  addend = nrhs;
2388 
2389  if (n-3*m > addend)
2390  addend = n-3*m;
2391 
2392  const F77_INT lworkaround = 4*m + m*m + addend;
2393 
2394  if (std::real (work(0)) < lworkaround)
2395  work(0) = lworkaround;
2396  }
2397  else if (m >= n)
2398  {
2399  F77_INT lworkaround = 2*m + m*nrhs;
2400 
2401  if (std::real (work(0)) < lworkaround)
2402  work(0) = lworkaround;
2403  }
2404 
2405  lwork = static_cast<F77_INT> (std::real (work(0)));
2406  work.resize (dim_vector (lwork, 1));
2407 
2408  double anorm = norm1 (*this);
2409 
2410  if (octave::math::isinf (anorm))
2411  {
2412  rcon = 0.0;
2413  retval = ComplexMatrix (n, b_nc, 0.0);
2414  }
2415  else if (octave::math::isnan (anorm))
2416  {
2418  retval = ComplexMatrix (n, b_nc,
2420  }
2421  else
2422  {
2423  F77_XFCN (zgelsd, ZGELSD, (m, n, nrhs, F77_DBLE_CMPLX_ARG (tmp_data),
2424  m, F77_DBLE_CMPLX_ARG (pretval),
2425  maxmn, ps, rcon, tmp_rank,
2426  F77_DBLE_CMPLX_ARG (work.fortran_vec ()),
2427  lwork, prwork, piwork, tmp_info));
2428 
2429  info = tmp_info;
2430  rank = tmp_rank;
2431 
2432  if (s.elem (0) == 0.0)
2433  rcon = 0.0;
2434  else
2435  rcon = s.elem (minmn - 1) / s.elem (0);
2436 
2437  retval.resize (n, nrhs);
2438  }
2439  }
2440 
2441  return retval;
2442 }
2443 
2446 {
2447  octave_idx_type info;
2448  octave_idx_type rank;
2449  double rcon;
2450  return lssolve (ComplexColumnVector (b), info, rank, rcon);
2451 }
2452 
2455 {
2456  octave_idx_type rank;
2457  double rcon;
2458  return lssolve (ComplexColumnVector (b), info, rank, rcon);
2459 }
2460 
2463  octave_idx_type& rank) const
2464 {
2465  double rcon;
2466  return lssolve (ComplexColumnVector (b), info, rank, rcon);
2467 }
2468 
2471  octave_idx_type& rank, double& rcon) const
2472 {
2473  return lssolve (ComplexColumnVector (b), info, rank, rcon);
2474 }
2475 
2478 {
2479  octave_idx_type info;
2480  octave_idx_type rank;
2481  double rcon;
2482  return lssolve (b, info, rank, rcon);
2483 }
2484 
2487  octave_idx_type& info) const
2488 {
2489  octave_idx_type rank;
2490  double rcon;
2491  return lssolve (b, info, rank, rcon);
2492 }
2493 
2496  octave_idx_type& rank) const
2497 {
2498  double rcon;
2499  return lssolve (b, info, rank, rcon);
2500 
2501 }
2502 
2505  octave_idx_type& rank, double& rcon) const
2506 {
2507  ComplexColumnVector retval;
2508 
2509  F77_INT nrhs = 1;
2510 
2511  F77_INT m = octave::to_f77_int (rows ());
2512  F77_INT n = octave::to_f77_int (cols ());
2513 
2514  F77_INT b_nel = octave::to_f77_int (b.numel ());
2515 
2516  if (m != b_nel)
2517  (*current_liboctave_error_handler)
2518  ("matrix dimension mismatch solution of linear equations");
2519 
2520  if (m == 0 || n == 0)
2521  retval = ComplexColumnVector (n, Complex (0.0, 0.0));
2522  else
2523  {
2524  volatile F77_INT minmn = (m < n ? m : n);
2525  F77_INT maxmn = (m > n ? m : n);
2526  rcon = -1.0;
2527 
2528  if (m != n)
2529  {
2530  retval = ComplexColumnVector (maxmn);
2531 
2532  for (F77_INT i = 0; i < m; i++)
2533  retval.elem (i) = b.elem (i);
2534  }
2535  else
2536  retval = b;
2537 
2538  ComplexMatrix atmp = *this;
2539  Complex *tmp_data = atmp.fortran_vec ();
2540 
2541  Complex *pretval = retval.fortran_vec ();
2542  Array<double> s (dim_vector (minmn, 1));
2543  double *ps = s.fortran_vec ();
2544 
2545  // Ask ZGELSD what the dimension of WORK should be.
2546  F77_INT lwork = -1;
2547 
2548  Array<Complex> work (dim_vector (1, 1));
2549 
2550  F77_INT smlsiz;
2551  F77_FUNC (xilaenv, XILAENV) (9, F77_CONST_CHAR_ARG2 ("ZGELSD", 6),
2552  F77_CONST_CHAR_ARG2 (" ", 1),
2553  0, 0, 0, 0, smlsiz
2554  F77_CHAR_ARG_LEN (6)
2555  F77_CHAR_ARG_LEN (1));
2556 
2557  // We compute the size of rwork and iwork because ZGELSD in
2558  // older versions of LAPACK does not return them on a query
2559  // call.
2560  double dminmn = static_cast<double> (minmn);
2561  double dsmlsizp1 = static_cast<double> (smlsiz+1);
2562  double tmp = octave::math::log2 (dminmn / dsmlsizp1);
2563 
2564  F77_INT nlvl = static_cast<F77_INT> (tmp) + 1;
2565  if (nlvl < 0)
2566  nlvl = 0;
2567 
2568  F77_INT lrwork = minmn*(10 + 2*smlsiz + 8*nlvl)
2569  + 3*smlsiz*nrhs + (smlsiz+1)*(smlsiz+1);
2570  if (lrwork < 1)
2571  lrwork = 1;
2572  Array<double> rwork (dim_vector (lrwork, 1));
2573  double *prwork = rwork.fortran_vec ();
2574 
2575  F77_INT liwork = 3 * minmn * nlvl + 11 * minmn;
2576  if (liwork < 1)
2577  liwork = 1;
2578  Array<F77_INT> iwork (dim_vector (liwork, 1));
2579  F77_INT *piwork = iwork.fortran_vec ();
2580 
2581  F77_INT tmp_info = 0;
2582  F77_INT tmp_rank = 0;
2583 
2584  F77_XFCN (zgelsd, ZGELSD, (m, n, nrhs, F77_DBLE_CMPLX_ARG (tmp_data), m,
2585  F77_DBLE_CMPLX_ARG (pretval), maxmn,
2586  ps, rcon, tmp_rank, F77_DBLE_CMPLX_ARG (work.fortran_vec ()),
2587  lwork, prwork, piwork, tmp_info));
2588 
2589  info = tmp_info;
2590  rank = tmp_rank;
2591 
2592  lwork = static_cast<F77_INT> (std::real (work(0)));
2593  work.resize (dim_vector (lwork, 1));
2594  rwork.resize (dim_vector (static_cast<F77_INT> (rwork(0)), 1));
2595  iwork.resize (dim_vector (iwork(0), 1));
2596 
2597  F77_XFCN (zgelsd, ZGELSD, (m, n, nrhs, F77_DBLE_CMPLX_ARG (tmp_data), m,
2598  F77_DBLE_CMPLX_ARG (pretval),
2599  maxmn, ps, rcon, tmp_rank,
2600  F77_DBLE_CMPLX_ARG (work.fortran_vec ()), lwork,
2601  prwork, piwork, tmp_info));
2602 
2603  info = tmp_info;
2604  rank = tmp_rank;
2605 
2606  if (rank < minmn)
2607  {
2608  if (s.elem (0) == 0.0)
2609  rcon = 0.0;
2610  else
2611  rcon = s.elem (minmn - 1) / s.elem (0);
2612 
2613  retval.resize (n);
2614  }
2615  }
2616 
2617  return retval;
2618 }
2619 
2620 // column vector by row vector -> matrix operations
2621 
2624 {
2625  ComplexColumnVector tmp (v);
2626  return tmp * a;
2627 }
2628 
2631 {
2632  ComplexRowVector tmp (b);
2633  return a * tmp;
2634 }
2635 
2638 {
2639  ComplexMatrix retval;
2640 
2641  F77_INT len = octave::to_f77_int (v.numel ());
2642 
2643  if (len != 0)
2644  {
2645  F77_INT a_len = octave::to_f77_int (a.numel ());
2646 
2647  retval = ComplexMatrix (len, a_len);
2648  Complex *c = retval.fortran_vec ();
2649 
2650  F77_XFCN (zgemm, ZGEMM, (F77_CONST_CHAR_ARG2 ("N", 1),
2651  F77_CONST_CHAR_ARG2 ("N", 1),
2652  len, a_len, 1, 1.0, F77_CONST_DBLE_CMPLX_ARG (v.data ()), len,
2654  F77_CHAR_ARG_LEN (1)
2655  F77_CHAR_ARG_LEN (1)));
2656  }
2657 
2658  return retval;
2659 }
2660 
2661 // matrix by diagonal matrix -> matrix operations
2662 
2665 {
2666  octave_idx_type nr = rows ();
2667  octave_idx_type nc = cols ();
2668 
2669  octave_idx_type a_nr = a.rows ();
2670  octave_idx_type a_nc = a.cols ();
2671 
2672  if (nr != a_nr || nc != a_nc)
2673  octave::err_nonconformant ("operator +=", nr, nc, a_nr, a_nc);
2674 
2675  for (octave_idx_type i = 0; i < a.length (); i++)
2676  elem (i, i) += a.elem (i, i);
2677 
2678  return *this;
2679 }
2680 
2683 {
2684  octave_idx_type nr = rows ();
2685  octave_idx_type nc = cols ();
2686 
2687  octave_idx_type a_nr = a.rows ();
2688  octave_idx_type a_nc = a.cols ();
2689 
2690  if (nr != a_nr || nc != a_nc)
2691  octave::err_nonconformant ("operator -=", nr, nc, a_nr, a_nc);
2692 
2693  for (octave_idx_type i = 0; i < a.length (); i++)
2694  elem (i, i) -= a.elem (i, i);
2695 
2696  return *this;
2697 }
2698 
2701 {
2702  octave_idx_type nr = rows ();
2703  octave_idx_type nc = cols ();
2704 
2705  octave_idx_type a_nr = a.rows ();
2706  octave_idx_type a_nc = a.cols ();
2707 
2708  if (nr != a_nr || nc != a_nc)
2709  octave::err_nonconformant ("operator +=", nr, nc, a_nr, a_nc);
2710 
2711  for (octave_idx_type i = 0; i < a.length (); i++)
2712  elem (i, i) += a.elem (i, i);
2713 
2714  return *this;
2715 }
2716 
2719 {
2720  octave_idx_type nr = rows ();
2721  octave_idx_type nc = cols ();
2722 
2723  octave_idx_type a_nr = a.rows ();
2724  octave_idx_type a_nc = a.cols ();
2725 
2726  if (nr != a_nr || nc != a_nc)
2727  octave::err_nonconformant ("operator -=", nr, nc, a_nr, a_nc);
2728 
2729  for (octave_idx_type i = 0; i < a.length (); i++)
2730  elem (i, i) -= a.elem (i, i);
2731 
2732  return *this;
2733 }
2734 
2735 // matrix by matrix -> matrix operations
2736 
2739 {
2740  octave_idx_type nr = rows ();
2741  octave_idx_type nc = cols ();
2742 
2743  octave_idx_type a_nr = a.rows ();
2744  octave_idx_type a_nc = a.cols ();
2745 
2746  if (nr != a_nr || nc != a_nc)
2747  octave::err_nonconformant ("operator +=", nr, nc, a_nr, a_nc);
2748 
2749  if (nr == 0 || nc == 0)
2750  return *this;
2751 
2752  Complex *d = fortran_vec (); // Ensures only one reference to my privates!
2753 
2754  mx_inline_add2 (numel (), d, a.data ());
2755  return *this;
2756 }
2757 
2760 {
2761  octave_idx_type nr = rows ();
2762  octave_idx_type nc = cols ();
2763 
2764  octave_idx_type a_nr = a.rows ();
2765  octave_idx_type a_nc = a.cols ();
2766 
2767  if (nr != a_nr || nc != a_nc)
2768  octave::err_nonconformant ("operator -=", nr, nc, a_nr, a_nc);
2769 
2770  if (nr == 0 || nc == 0)
2771  return *this;
2772 
2773  Complex *d = fortran_vec (); // Ensures only one reference to my privates!
2774 
2775  mx_inline_sub2 (numel (), d, a.data ());
2776  return *this;
2777 }
2778 
2779 // other operations
2780 
2781 boolMatrix
2782 ComplexMatrix::all (int dim) const
2783 {
2784  return ComplexNDArray::all (dim);
2785 }
2786 
2787 boolMatrix
2788 ComplexMatrix::any (int dim) const
2789 {
2790  return ComplexNDArray::any (dim);
2791 }
2792 
2794 ComplexMatrix::cumprod (int dim) const
2795 {
2796  return ComplexNDArray::cumprod (dim);
2797 }
2798 
2800 ComplexMatrix::cumsum (int dim) const
2801 {
2802  return ComplexNDArray::cumsum (dim);
2803 }
2804 
2806 ComplexMatrix::prod (int dim) const
2807 {
2808  return ComplexNDArray::prod (dim);
2809 }
2810 
2812 ComplexMatrix::sum (int dim) const
2813 {
2814  return ComplexNDArray::sum (dim);
2815 }
2816 
2818 ComplexMatrix::sumsq (int dim) const
2819 {
2820  return ComplexNDArray::sumsq (dim);
2821 }
2822 
2823 Matrix
2825 {
2826  return ComplexNDArray::abs ();
2827 }
2828 
2831 {
2832  return ComplexNDArray::diag (k);
2833 }
2834 
2837 {
2838  octave_idx_type nr = rows ();
2839  octave_idx_type nc = cols ();
2840 
2841  if (nr != 1 && nc != 1)
2842  (*current_liboctave_error_handler) ("diag: expecting vector argument");
2843 
2844  return ComplexDiagMatrix (*this, m, n);
2845 }
2846 
2847 bool
2849 {
2850  bool retval = true;
2851 
2852  octave_idx_type nc = columns ();
2853 
2854  for (octave_idx_type j = 0; j < nc; j++)
2855  {
2856  if (std::imag (elem (i, j)) != 0.0)
2857  {
2858  retval = false;
2859  break;
2860  }
2861  }
2862 
2863  return retval;
2864 }
2865 
2866 bool
2868 {
2869  bool retval = true;
2870 
2871  octave_idx_type nr = rows ();
2872 
2873  for (octave_idx_type i = 0; i < nr; i++)
2874  {
2875  if (std::imag (elem (i, j)) != 0.0)
2876  {
2877  retval = false;
2878  break;
2879  }
2880  }
2881 
2882  return retval;
2883 }
2884 
2887 {
2888  Array<octave_idx_type> dummy_idx;
2889  return row_min (dummy_idx);
2890 }
2891 
2894 {
2895  ComplexColumnVector result;
2896 
2897  octave_idx_type nr = rows ();
2898  octave_idx_type nc = cols ();
2899 
2900  if (nr > 0 && nc > 0)
2901  {
2902  result.resize (nr);
2903  idx_arg.resize (dim_vector (nr, 1));
2904 
2905  for (octave_idx_type i = 0; i < nr; i++)
2906  {
2907  bool real_only = row_is_real_only (i);
2908 
2909  octave_idx_type idx_j;
2910 
2911  Complex tmp_min;
2912 
2913  double abs_min = octave::numeric_limits<double>::NaN ();
2914 
2915  for (idx_j = 0; idx_j < nc; idx_j++)
2916  {
2917  tmp_min = elem (i, idx_j);
2918 
2919  if (! octave::math::isnan (tmp_min))
2920  {
2921  abs_min = (real_only ? tmp_min.real ()
2922  : std::abs (tmp_min));
2923  break;
2924  }
2925  }
2926 
2927  for (octave_idx_type j = idx_j+1; j < nc; j++)
2928  {
2929  Complex tmp = elem (i, j);
2930 
2931  if (octave::math::isnan (tmp))
2932  continue;
2933 
2934  double abs_tmp = (real_only ? tmp.real () : std::abs (tmp));
2935 
2936  if (abs_tmp < abs_min)
2937  {
2938  idx_j = j;
2939  tmp_min = tmp;
2940  abs_min = abs_tmp;
2941  }
2942  }
2943 
2944  if (octave::math::isnan (tmp_min))
2945  {
2946  result.elem (i) = Complex_NaN_result;
2947  idx_arg.elem (i) = 0;
2948  }
2949  else
2950  {
2951  result.elem (i) = tmp_min;
2952  idx_arg.elem (i) = idx_j;
2953  }
2954  }
2955  }
2956 
2957  return result;
2958 }
2959 
2962 {
2963  Array<octave_idx_type> dummy_idx;
2964  return row_max (dummy_idx);
2965 }
2966 
2969 {
2970  ComplexColumnVector result;
2971 
2972  octave_idx_type nr = rows ();
2973  octave_idx_type nc = cols ();
2974 
2975  if (nr > 0 && nc > 0)
2976  {
2977  result.resize (nr);
2978  idx_arg.resize (dim_vector (nr, 1));
2979 
2980  for (octave_idx_type i = 0; i < nr; i++)
2981  {
2982  bool real_only = row_is_real_only (i);
2983 
2984  octave_idx_type idx_j;
2985 
2986  Complex tmp_max;
2987 
2988  double abs_max = octave::numeric_limits<double>::NaN ();
2989 
2990  for (idx_j = 0; idx_j < nc; idx_j++)
2991  {
2992  tmp_max = elem (i, idx_j);
2993 
2994  if (! octave::math::isnan (tmp_max))
2995  {
2996  abs_max = (real_only ? tmp_max.real ()
2997  : std::abs (tmp_max));
2998  break;
2999  }
3000  }
3001 
3002  for (octave_idx_type j = idx_j+1; j < nc; j++)
3003  {
3004  Complex tmp = elem (i, j);
3005 
3006  if (octave::math::isnan (tmp))
3007  continue;
3008 
3009  double abs_tmp = (real_only ? tmp.real () : std::abs (tmp));
3010 
3011  if (abs_tmp > abs_max)
3012  {
3013  idx_j = j;
3014  tmp_max = tmp;
3015  abs_max = abs_tmp;
3016  }
3017  }
3018 
3019  if (octave::math::isnan (tmp_max))
3020  {
3021  result.elem (i) = Complex_NaN_result;
3022  idx_arg.elem (i) = 0;
3023  }
3024  else
3025  {
3026  result.elem (i) = tmp_max;
3027  idx_arg.elem (i) = idx_j;
3028  }
3029  }
3030  }
3031 
3032  return result;
3033 }
3034 
3037 {
3038  Array<octave_idx_type> dummy_idx;
3039  return column_min (dummy_idx);
3040 }
3041 
3044 {
3045  ComplexRowVector result;
3046 
3047  octave_idx_type nr = rows ();
3048  octave_idx_type nc = cols ();
3049 
3050  if (nr > 0 && nc > 0)
3051  {
3052  result.resize (nc);
3053  idx_arg.resize (dim_vector (1, nc));
3054 
3055  for (octave_idx_type j = 0; j < nc; j++)
3056  {
3057  bool real_only = column_is_real_only (j);
3058 
3059  octave_idx_type idx_i;
3060 
3061  Complex tmp_min;
3062 
3063  double abs_min = octave::numeric_limits<double>::NaN ();
3064 
3065  for (idx_i = 0; idx_i < nr; idx_i++)
3066  {
3067  tmp_min = elem (idx_i, j);
3068 
3069  if (! octave::math::isnan (tmp_min))
3070  {
3071  abs_min = (real_only ? tmp_min.real ()
3072  : std::abs (tmp_min));
3073  break;
3074  }
3075  }
3076 
3077  for (octave_idx_type i = idx_i+1; i < nr; i++)
3078  {
3079  Complex tmp = elem (i, j);
3080 
3081  if (octave::math::isnan (tmp))
3082  continue;
3083 
3084  double abs_tmp = (real_only ? tmp.real () : std::abs (tmp));
3085 
3086  if (abs_tmp < abs_min)
3087  {
3088  idx_i = i;
3089  tmp_min = tmp;
3090  abs_min = abs_tmp;
3091  }
3092  }
3093 
3094  if (octave::math::isnan (tmp_min))
3095  {
3096  result.elem (j) = Complex_NaN_result;
3097  idx_arg.elem (j) = 0;
3098  }
3099  else
3100  {
3101  result.elem (j) = tmp_min;
3102  idx_arg.elem (j) = idx_i;
3103  }
3104  }
3105  }
3106 
3107  return result;
3108 }
3109 
3112 {
3113  Array<octave_idx_type> dummy_idx;
3114  return column_max (dummy_idx);
3115 }
3116 
3119 {
3120  ComplexRowVector result;
3121 
3122  octave_idx_type nr = rows ();
3123  octave_idx_type nc = cols ();
3124 
3125  if (nr > 0 && nc > 0)
3126  {
3127  result.resize (nc);
3128  idx_arg.resize (dim_vector (1, nc));
3129 
3130  for (octave_idx_type j = 0; j < nc; j++)
3131  {
3132  bool real_only = column_is_real_only (j);
3133 
3134  octave_idx_type idx_i;
3135 
3136  Complex tmp_max;
3137 
3138  double abs_max = octave::numeric_limits<double>::NaN ();
3139 
3140  for (idx_i = 0; idx_i < nr; idx_i++)
3141  {
3142  tmp_max = elem (idx_i, j);
3143 
3144  if (! octave::math::isnan (tmp_max))
3145  {
3146  abs_max = (real_only ? tmp_max.real ()
3147  : std::abs (tmp_max));
3148  break;
3149  }
3150  }
3151 
3152  for (octave_idx_type i = idx_i+1; i < nr; i++)
3153  {
3154  Complex tmp = elem (i, j);
3155 
3156  if (octave::math::isnan (tmp))
3157  continue;
3158 
3159  double abs_tmp = (real_only ? tmp.real () : std::abs (tmp));
3160 
3161  if (abs_tmp > abs_max)
3162  {
3163  idx_i = i;
3164  tmp_max = tmp;
3165  abs_max = abs_tmp;
3166  }
3167  }
3168 
3169  if (octave::math::isnan (tmp_max))
3170  {
3171  result.elem (j) = Complex_NaN_result;
3172  idx_arg.elem (j) = 0;
3173  }
3174  else
3175  {
3176  result.elem (j) = tmp_max;
3177  idx_arg.elem (j) = idx_i;
3178  }
3179  }
3180  }
3181 
3182  return result;
3183 }
3184 
3185 // i/o
3186 
3187 std::ostream&
3188 operator << (std::ostream& os, const ComplexMatrix& a)
3189 {
3190  for (octave_idx_type i = 0; i < a.rows (); i++)
3191  {
3192  for (octave_idx_type j = 0; j < a.cols (); j++)
3193  {
3194  os << ' ';
3195  octave::write_value<Complex> (os, a.elem (i, j));
3196  }
3197  os << "\n";
3198  }
3199  return os;
3200 }
3201 
3202 std::istream&
3203 operator >> (std::istream& is, ComplexMatrix& a)
3204 {
3205  octave_idx_type nr = a.rows ();
3206  octave_idx_type nc = a.cols ();
3207 
3208  if (nr > 0 && nc > 0)
3209  {
3210  Complex tmp;
3211  for (octave_idx_type i = 0; i < nr; i++)
3212  for (octave_idx_type j = 0; j < nc; j++)
3213  {
3214  tmp = octave::read_value<Complex> (is);
3215  if (is)
3216  a.elem (i, j) = tmp;
3217  else
3218  return is;
3219  }
3220  }
3221 
3222  return is;
3223 }
3224 
3226 Givens (const Complex& x, const Complex& y)
3227 {
3228  double cc;
3229  Complex cs, temp_r;
3230 
3231  F77_FUNC (zlartg, ZLARTG) (F77_CONST_DBLE_CMPLX_ARG (&x),
3233  cc,
3234  F77_DBLE_CMPLX_ARG (&cs),
3235  F77_DBLE_CMPLX_ARG (&temp_r));
3236 
3237  ComplexMatrix g (2, 2);
3238 
3239  g.elem (0, 0) = cc;
3240  g.elem (1, 1) = cc;
3241  g.elem (0, 1) = cs;
3242  g.elem (1, 0) = -conj (cs);
3243 
3244  return g;
3245 }
3246 
3249  const ComplexMatrix& c)
3250 {
3251  ComplexMatrix retval;
3252 
3253  // FIXME: need to check that a, b, and c are all the same size.
3254 
3255  // Compute Schur decompositions
3256 
3257  octave::math::schur<ComplexMatrix> as (a, "U");
3258  octave::math::schur<ComplexMatrix> bs (b, "U");
3259 
3260  // Transform c to new coordinates.
3261 
3262  ComplexMatrix ua = as.unitary_schur_matrix ();
3263  ComplexMatrix sch_a = as.schur_matrix ();
3264 
3265  ComplexMatrix ub = bs.unitary_schur_matrix ();
3266  ComplexMatrix sch_b = bs.schur_matrix ();
3267 
3268  ComplexMatrix cx = ua.hermitian () * c * ub;
3269 
3270  // Solve the sylvester equation, back-transform, and return the solution.
3271 
3272  F77_INT a_nr = octave::to_f77_int (a.rows ());
3273  F77_INT b_nr = octave::to_f77_int (b.rows ());
3274 
3275  double scale;
3276  F77_INT info;
3277 
3278  Complex *pa = sch_a.fortran_vec ();
3279  Complex *pb = sch_b.fortran_vec ();
3280  Complex *px = cx.fortran_vec ();
3281 
3282  F77_XFCN (ztrsyl, ZTRSYL, (F77_CONST_CHAR_ARG2 ("N", 1),
3283  F77_CONST_CHAR_ARG2 ("N", 1),
3284  1, a_nr, b_nr, F77_DBLE_CMPLX_ARG (pa), a_nr, F77_DBLE_CMPLX_ARG (pb),
3285  b_nr, F77_DBLE_CMPLX_ARG (px), a_nr, scale, info
3286  F77_CHAR_ARG_LEN (1)
3287  F77_CHAR_ARG_LEN (1)));
3288 
3289  // FIXME: check info?
3290 
3291  retval = ua * cx * ub.hermitian ();
3292 
3293  return retval;
3294 }
3295 
3298 {
3299  if (m.columns () > std::min (m.rows (), a.columns ()) / 10)
3300  return ComplexMatrix (real (m) * a, imag (m) * a);
3301  else
3302  return m * ComplexMatrix (a);
3303 }
3304 
3307 {
3308  if (a.rows () > std::min (m.rows (), a.columns ()) / 10)
3309  return ComplexMatrix (m * real (a), m * imag (a));
3310  else
3311  return ComplexMatrix (m) * a;
3312 }
3313 
3314 /*
3315 
3316 ## Simple Dot Product, Matrix-Vector, and Matrix-Matrix Unit tests
3317 %!assert ([1+i 2+i 3+i] * [ 4+i ; 5+i ; 6+i], 29+21i, 1e-14)
3318 %!assert ([1+i 2+i ; 3+i 4+i ] * [5+i ; 6+i], [15 + 14i ; 37 + 18i], 1e-14)
3319 %!assert ([1+i 2+i ; 3+i 4+i ] * [5+i 6+i ; 7+i 8+i], [17 + 15i 20 + 17i; 41 + 19i 48 + 21i], 1e-14)
3320 %!assert ([1 i]*[i 0]', -i)
3321 
3322 ## Test some simple identities
3323 %!shared M, cv, rv
3324 %! M = randn (10,10) + i*rand (10,10);
3325 %! cv = randn (10,1) + i*rand (10,1);
3326 %! rv = randn (1,10) + i*rand (1,10);
3327 %!assert ([M*cv,M*cv], M*[cv,cv], 1e-14)
3328 %!assert ([M.'*cv,M.'*cv], M.'*[cv,cv], 1e-14)
3329 %!assert ([M'*cv,M'*cv], M'*[cv,cv], 1e-14)
3330 %!assert ([rv*M;rv*M], [rv;rv]*M, 1e-14)
3331 %!assert ([rv*M.';rv*M.'], [rv;rv]*M.', 1e-14)
3332 %!assert ([rv*M';rv*M'], [rv;rv]*M', 1e-14)
3333 %!assert (2*rv*cv, [rv,rv]*[cv;cv], 2e-14)
3334 
3335 */
3336 
3337 static inline char
3338 get_blas_trans_arg (bool trans, bool conj)
3339 {
3340  return trans ? (conj ? 'C' : 'T') : 'N';
3341 }
3342 
3343 // the general GEMM operation
3344 
3346 xgemm (const ComplexMatrix& a, const ComplexMatrix& b,
3347  blas_trans_type transa, blas_trans_type transb)
3348 {
3349  ComplexMatrix retval;
3350 
3351  bool tra = transa != blas_no_trans;
3352  bool trb = transb != blas_no_trans;
3353  bool cja = transa == blas_conj_trans;
3354  bool cjb = transb == blas_conj_trans;
3355 
3356  F77_INT a_nr = octave::to_f77_int (tra ? a.cols () : a.rows ());
3357  F77_INT a_nc = octave::to_f77_int (tra ? a.rows () : a.cols ());
3358 
3359  F77_INT b_nr = octave::to_f77_int (trb ? b.cols () : b.rows ());
3360  F77_INT b_nc = octave::to_f77_int (trb ? b.rows () : b.cols ());
3361 
3362  if (a_nc != b_nr)
3363  octave::err_nonconformant ("operator *", a_nr, a_nc, b_nr, b_nc);
3364 
3365  if (a_nr == 0 || a_nc == 0 || b_nc == 0)
3366  retval = ComplexMatrix (a_nr, b_nc, 0.0);
3367  else if (a.data () == b.data () && a_nr == b_nc && tra != trb)
3368  {
3369  F77_INT lda = octave::to_f77_int (a.rows ());
3370 
3371  // FIXME: looking at the reference BLAS, it appears that it
3372  // should not be necessary to initialize the output matrix if
3373  // BETA is 0 in the call to ZHERK, but ATLAS appears to
3374  // use the result matrix before zeroing the elements.
3375 
3376  retval = ComplexMatrix (a_nr, b_nc, 0.0);
3377  Complex *c = retval.fortran_vec ();
3378 
3379  const char ctra = get_blas_trans_arg (tra, cja);
3380  if (cja || cjb)
3381  {
3382  F77_XFCN (zherk, ZHERK, (F77_CONST_CHAR_ARG2 ("U", 1),
3383  F77_CONST_CHAR_ARG2 (&ctra, 1),
3384  a_nr, a_nc, 1.0,
3385  F77_CONST_DBLE_CMPLX_ARG (a.data ()), lda, 0.0, F77_DBLE_CMPLX_ARG (c), a_nr
3386  F77_CHAR_ARG_LEN (1)
3387  F77_CHAR_ARG_LEN (1)));
3388  for (F77_INT j = 0; j < a_nr; j++)
3389  for (F77_INT i = 0; i < j; i++)
3390  retval.xelem (j, i) = octave::math::conj (retval.xelem (i, j));
3391  }
3392  else
3393  {
3394  F77_XFCN (zsyrk, ZSYRK, (F77_CONST_CHAR_ARG2 ("U", 1),
3395  F77_CONST_CHAR_ARG2 (&ctra, 1),
3396  a_nr, a_nc, 1.0,
3397  F77_CONST_DBLE_CMPLX_ARG (a.data ()), lda, 0.0, F77_DBLE_CMPLX_ARG (c), a_nr
3398  F77_CHAR_ARG_LEN (1)
3399  F77_CHAR_ARG_LEN (1)));
3400  for (F77_INT j = 0; j < a_nr; j++)
3401  for (F77_INT i = 0; i < j; i++)
3402  retval.xelem (j, i) = retval.xelem (i, j);
3403 
3404  }
3405 
3406  }
3407  else
3408  {
3409  F77_INT lda = octave::to_f77_int (a.rows ());
3410  F77_INT tda = octave::to_f77_int (a.cols ());
3411  F77_INT ldb = octave::to_f77_int (b.rows ());
3412  F77_INT tdb = octave::to_f77_int (b.cols ());
3413 
3414  retval = ComplexMatrix (a_nr, b_nc, 0.0);
3415  Complex *c = retval.fortran_vec ();
3416 
3417  if (b_nc == 1 && a_nr == 1)
3418  {
3419  if (cja == cjb)
3420  {
3421  F77_FUNC (xzdotu, XZDOTU) (a_nc, F77_CONST_DBLE_CMPLX_ARG (a.data ()), 1,
3422  F77_CONST_DBLE_CMPLX_ARG (b.data ()), 1,
3423  F77_DBLE_CMPLX_ARG (c));
3424  if (cja) *c = octave::math::conj (*c);
3425  }
3426  else if (cja)
3427  F77_FUNC (xzdotc, XZDOTC) (a_nc, F77_CONST_DBLE_CMPLX_ARG (a.data ()), 1,
3428  F77_CONST_DBLE_CMPLX_ARG (b.data ()), 1,
3429  F77_DBLE_CMPLX_ARG (c));
3430  else
3431  F77_FUNC (xzdotc, XZDOTC) (a_nc, F77_CONST_DBLE_CMPLX_ARG (b.data ()), 1,
3432  F77_CONST_DBLE_CMPLX_ARG (a.data ()), 1,
3433  F77_DBLE_CMPLX_ARG (c));
3434  }
3435  else if (b_nc == 1 && ! cjb)
3436  {
3437  const char ctra = get_blas_trans_arg (tra, cja);
3438  F77_XFCN (zgemv, ZGEMV, (F77_CONST_CHAR_ARG2 (&ctra, 1),
3439  lda, tda, 1.0, F77_CONST_DBLE_CMPLX_ARG (a.data ()), lda,
3440  F77_CONST_DBLE_CMPLX_ARG (b.data ()), 1, 0.0, F77_DBLE_CMPLX_ARG (c), 1
3441  F77_CHAR_ARG_LEN (1)));
3442  }
3443  else if (a_nr == 1 && ! cja && ! cjb)
3444  {
3445  const char crevtrb = get_blas_trans_arg (! trb, cjb);
3446  F77_XFCN (zgemv, ZGEMV, (F77_CONST_CHAR_ARG2 (&crevtrb, 1),
3447  ldb, tdb, 1.0, F77_CONST_DBLE_CMPLX_ARG (b.data ()), ldb,
3448  F77_CONST_DBLE_CMPLX_ARG (a.data ()), 1, 0.0, F77_DBLE_CMPLX_ARG (c), 1
3449  F77_CHAR_ARG_LEN (1)));
3450  }
3451  else
3452  {
3453  const char ctra = get_blas_trans_arg (tra, cja);
3454  const char ctrb = get_blas_trans_arg (trb, cjb);
3455  F77_XFCN (zgemm, ZGEMM, (F77_CONST_CHAR_ARG2 (&ctra, 1),
3456  F77_CONST_CHAR_ARG2 (&ctrb, 1),
3457  a_nr, b_nc, a_nc, 1.0, F77_CONST_DBLE_CMPLX_ARG (a.data ()),
3458  lda, F77_CONST_DBLE_CMPLX_ARG (b.data ()), ldb, 0.0, F77_DBLE_CMPLX_ARG (c),
3459  a_nr
3460  F77_CHAR_ARG_LEN (1)
3461  F77_CHAR_ARG_LEN (1)));
3462  }
3463  }
3464 
3465  return retval;
3466 }
3467 
3470 {
3471  return xgemm (a, b);
3472 }
3473 
3474 // FIXME: it would be nice to share code among the min/max functions below.
3475 
3476 #define EMPTY_RETURN_CHECK(T) \
3477  if (nr == 0 || nc == 0) \
3478  return T (nr, nc);
3479 
3481 min (const Complex& c, const ComplexMatrix& m)
3482 {
3483  octave_idx_type nr = m.rows ();
3484  octave_idx_type nc = m.columns ();
3485 
3487 
3488  ComplexMatrix result (nr, nc);
3489 
3490  for (octave_idx_type j = 0; j < nc; j++)
3491  for (octave_idx_type i = 0; i < nr; i++)
3492  {
3493  octave_quit ();
3494  result(i, j) = octave::math::min (c, m(i, j));
3495  }
3496 
3497  return result;
3498 }
3499 
3501 min (const ComplexMatrix& m, const Complex& c)
3502 {
3503  return min (c, m);
3504 }
3505 
3507 min (const ComplexMatrix& a, const ComplexMatrix& b)
3508 {
3509  octave_idx_type nr = a.rows ();
3510  octave_idx_type nc = a.columns ();
3511 
3512  if (nr != b.rows () || nc != b.columns ())
3513  (*current_liboctave_error_handler)
3514  ("two-arg min requires same size arguments");
3515 
3517 
3518  ComplexMatrix result (nr, nc);
3519 
3520  for (octave_idx_type j = 0; j < nc; j++)
3521  {
3522  bool columns_are_real_only = true;
3523  for (octave_idx_type i = 0; i < nr; i++)
3524  {
3525  octave_quit ();
3526  if (std::imag (a(i, j)) != 0.0 || std::imag (b(i, j)) != 0.0)
3527  {
3528  columns_are_real_only = false;
3529  break;
3530  }
3531  }
3532 
3533  if (columns_are_real_only)
3534  {
3535  for (octave_idx_type i = 0; i < nr; i++)
3536  result(i, j) = octave::math::min (std::real (a(i, j)),
3537  std::real (b(i, j)));
3538  }
3539  else
3540  {
3541  for (octave_idx_type i = 0; i < nr; i++)
3542  {
3543  octave_quit ();
3544  result(i, j) = octave::math::min (a(i, j), b(i, j));
3545  }
3546  }
3547  }
3548 
3549  return result;
3550 }
3551 
3553 max (const Complex& c, const ComplexMatrix& m)
3554 {
3555  octave_idx_type nr = m.rows ();
3556  octave_idx_type nc = m.columns ();
3557 
3559 
3560  ComplexMatrix result (nr, nc);
3561 
3562  for (octave_idx_type j = 0; j < nc; j++)
3563  for (octave_idx_type i = 0; i < nr; i++)
3564  {
3565  octave_quit ();
3566  result(i, j) = octave::math::max (c, m(i, j));
3567  }
3568 
3569  return result;
3570 }
3571 
3573 max (const ComplexMatrix& m, const Complex& c)
3574 {
3575  return max (c, m);
3576 }
3577 
3579 max (const ComplexMatrix& a, const ComplexMatrix& b)
3580 {
3581  octave_idx_type nr = a.rows ();
3582  octave_idx_type nc = a.columns ();
3583 
3584  if (nr != b.rows () || nc != b.columns ())
3585  (*current_liboctave_error_handler)
3586  ("two-arg max requires same size arguments");
3587 
3589 
3590  ComplexMatrix result (nr, nc);
3591 
3592  for (octave_idx_type j = 0; j < nc; j++)
3593  {
3594  bool columns_are_real_only = true;
3595  for (octave_idx_type i = 0; i < nr; i++)
3596  {
3597  octave_quit ();
3598  if (std::imag (a(i, j)) != 0.0 || std::imag (b(i, j)) != 0.0)
3599  {
3600  columns_are_real_only = false;
3601  break;
3602  }
3603  }
3604 
3605  // FIXME: is it so much faster?
3606  if (columns_are_real_only)
3607  {
3608  for (octave_idx_type i = 0; i < nr; i++)
3609  {
3610  octave_quit ();
3611  result(i, j) = octave::math::max (std::real (a(i, j)),
3612  std::real (b(i, j)));
3613  }
3614  }
3615  else
3616  {
3617  for (octave_idx_type i = 0; i < nr; i++)
3618  {
3619  octave_quit ();
3620  result(i, j) = octave::math::max (a(i, j), b(i, j));
3621  }
3622  }
3623  }
3624 
3625  return result;
3626 }
3627 
3630  const ComplexColumnVector& x2,
3632 {
3633  octave_idx_type m = x1.numel ();
3634 
3635  if (x2.numel () != m)
3636  (*current_liboctave_error_handler)
3637  ("linspace: vectors must be of equal length");
3638 
3639  ComplexMatrix retval;
3640 
3641  if (n < 1)
3642  {
3643  retval.clear (m, 0);
3644  return retval;
3645  }
3646 
3647  retval.clear (m, n);
3648  for (octave_idx_type i = 0; i < m; i++)
3649  retval.insert (linspace (x1(i), x2(i), n), i, 0);
3650 
3651  return retval;
3652 }
3653 
3656 
3659 
std::ostream & operator<<(std::ostream &os, const ComplexMatrix &a)
Definition: CMatrix.cc:3188
ComplexMatrix max(const Complex &c, const ComplexMatrix &m)
Definition: CMatrix.cc:3553
ComplexMatrix Givens(const Complex &x, const Complex &y)
Definition: CMatrix.cc:3226
ComplexMatrix conj(const ComplexMatrix &a)
Definition: CMatrix.cc:675
ComplexMatrix linspace(const ComplexColumnVector &x1, const ComplexColumnVector &x2, octave_idx_type n)
Definition: CMatrix.cc:3629
ComplexMatrix Sylvester(const ComplexMatrix &a, const ComplexMatrix &b, const ComplexMatrix &c)
Definition: CMatrix.cc:3248
ComplexMatrix min(const Complex &c, const ComplexMatrix &m)
Definition: CMatrix.cc:3481
#define EMPTY_RETURN_CHECK(T)
Definition: CMatrix.cc:3476
std::istream & operator>>(std::istream &is, ComplexMatrix &a)
Definition: CMatrix.cc:3203
ComplexMatrix operator*(const ColumnVector &v, const ComplexRowVector &a)
Definition: CMatrix.cc:2623
ComplexMatrix xgemm(const ComplexMatrix &a, const ComplexMatrix &b, blas_trans_type transa, blas_trans_type transb)
Definition: CMatrix.cc:3346
base_det< Complex > ComplexDET
Definition: DET.h:88
#define Inf
Definition: Faddeeva.cc:260
#define NaN
Definition: Faddeeva.cc:261
N Dimensional Array with copy-on-write semantics.
Definition: Array.h:130
T & elem(octave_idx_type n)
Size of the specified dimension.
Definition: Array.h:562
T * fortran_vec()
Size of the specified dimension.
Definition: Array-base.cc:1764
Array< T, Alloc > index(const octave::idx_vector &i) const
Indexing without resizing.
Definition: Array-base.cc:710
bool issquare() const
Size of the specified dimension.
Definition: Array.h:648
void clear()
Definition: Array-base.cc:109
octave_idx_type rows() const
Definition: Array.h:459
void resize(const dim_vector &dv, const T &rfv)
Size of the specified dimension.
Definition: Array-base.cc:1023
const T * data() const
Size of the specified dimension.
Definition: Array.h:663
octave_idx_type columns() const
Definition: Array.h:471
octave_idx_type cols() const
Definition: Array.h:469
void make_unique()
Definition: Array.h:216
T & xelem(octave_idx_type n)
Size of the specified dimension.
Definition: Array.h:524
octave_idx_type numel() const
Number of elements in the array.
Definition: Array.h:414
ColumnVector extract(octave_idx_type r1, octave_idx_type r2) const
Definition: dColVector.cc:151
void resize(octave_idx_type n, const Complex &rfv=Complex(0))
Definition: CColVector.h:148
ComplexRowVector column_max() const
Definition: CMatrix.cc:3111
ComplexMatrix & operator+=(const DiagMatrix &a)
Definition: CMatrix.cc:2664
ComplexMatrix & operator-=(const DiagMatrix &a)
Definition: CMatrix.cc:2682
ComplexMatrix lssolve(const Matrix &b) const
Definition: CMatrix.cc:2220
ComplexMatrix ifourier2d() const
Definition: CMatrix.cc:1117
ComplexColumnVector row_max() const
Definition: CMatrix.cc:2961
ComplexMatrix extract(octave_idx_type r1, octave_idx_type c1, octave_idx_type r2, octave_idx_type c2) const
Definition: CMatrix.cc:683
ComplexColumnVector row_min() const
Definition: CMatrix.cc:2886
ComplexMatrix fourier() const
Definition: CMatrix.cc:1045
friend ComplexMatrix conj(const ComplexMatrix &a)
Definition: CMatrix.cc:675
boolMatrix all(int dim=-1) const
Definition: CMatrix.cc:2782
ComplexMatrix & fill(double val)
Definition: CMatrix.cc:347
ComplexMatrix append(const Matrix &a) const
Definition: CMatrix.cc:435
ComplexMatrix diag(octave_idx_type k=0) const
Definition: CMatrix.cc:2830
ComplexMatrix pseudo_inverse(double tol=0.0) const
Definition: CMatrix.cc:1000
bool operator==(const ComplexMatrix &a) const
Definition: CMatrix.cc:159
ComplexMatrix fourier2d() const
Definition: CMatrix.cc:1103
ComplexRowVector row(octave_idx_type i) const
Definition: CMatrix.cc:702
ComplexMatrix & insert(const Matrix &a, octave_idx_type r, octave_idx_type c)
Definition: CMatrix.cc:195
double rcond() const
Definition: CMatrix.cc:1350
ComplexMatrix solve(MatrixType &mattype, const Matrix &b) const
Definition: CMatrix.cc:1931
ComplexMatrix inverse() const
Definition: CMatrix.cc:737
bool row_is_real_only(octave_idx_type) const
Definition: CMatrix.cc:2848
ComplexMatrix sumsq(int dim=-1) const
Definition: CMatrix.cc:2818
void resize(octave_idx_type nr, octave_idx_type nc, const Complex &rfv=Complex(0))
Definition: CMatrix.h:193
Matrix abs() const
Definition: CMatrix.cc:2824
ComplexMatrix extract_n(octave_idx_type r1, octave_idx_type c1, octave_idx_type nr, octave_idx_type nc) const
Definition: CMatrix.cc:693
ComplexMatrix stack(const Matrix &a) const
Definition: CMatrix.cc:555
ComplexMatrix cumprod(int dim=-1) const
Definition: CMatrix.cc:2794
ComplexMatrix transpose() const
Definition: CMatrix.h:172
ComplexMatrix prod(int dim=-1) const
Definition: CMatrix.cc:2806
ComplexDET determinant() const
Definition: CMatrix.cc:1171
ComplexMatrix cumsum(int dim=-1) const
Definition: CMatrix.cc:2800
ComplexMatrix ifourier() const
Definition: CMatrix.cc:1074
boolMatrix any(int dim=-1) const
Definition: CMatrix.cc:2788
ComplexRowVector column_min() const
Definition: CMatrix.cc:3036
bool operator!=(const ComplexMatrix &a) const
Definition: CMatrix.cc:168
ComplexMatrix hermitian() const
Definition: CMatrix.h:170
bool column_is_real_only(octave_idx_type) const
Definition: CMatrix.cc:2867
ComplexMatrix sum(int dim=-1) const
Definition: CMatrix.cc:2812
ComplexMatrix()=default
ComplexColumnVector column(octave_idx_type i) const
Definition: CMatrix.cc:708
bool ishermitian() const
Definition: CMatrix.cc:174
boolNDArray any(int dim=-1) const
Definition: CNDArray.cc:352
ComplexNDArray prod(int dim=-1) const
Definition: CNDArray.cc:370
NDArray abs() const
Definition: CNDArray.cc:478
ComplexNDArray sumsq(int dim=-1) const
Definition: CNDArray.cc:388
ComplexNDArray diag(octave_idx_type k=0) const
Definition: CNDArray.cc:585
ComplexNDArray cumsum(int dim=-1) const
Definition: CNDArray.cc:364
ComplexNDArray & insert(const NDArray &a, octave_idx_type r, octave_idx_type c)
Definition: CNDArray.cc:508
ComplexNDArray cumprod(int dim=-1) const
Definition: CNDArray.cc:358
boolNDArray all(int dim=-1) const
Definition: CNDArray.cc:346
ComplexNDArray sum(int dim=-1) const
Definition: CNDArray.cc:376
void resize(octave_idx_type n, const Complex &rfv=Complex(0))
Definition: CRowVector.h:129
octave_idx_type rows() const
Definition: DiagArray2.h:89
octave_idx_type length() const
Definition: DiagArray2.h:95
T elem(octave_idx_type r, octave_idx_type c) const
Definition: DiagArray2.h:117
octave_idx_type cols() const
Definition: DiagArray2.h:90
DiagMatrix inverse() const
Definition: dDiagMatrix.cc:227
ColumnVector extract_diag(octave_idx_type k=0) const
Definition: dDiagMatrix.h:107
bool ishermitian() const
Definition: MatrixType.h:122
void mark_as_unsymmetric()
Definition: MatrixType.cc:920
@ Permuted_Lower
Definition: MatrixType.h:48
@ Permuted_Upper
Definition: MatrixType.h:47
void mark_as_full()
Definition: MatrixType.h:153
int type(bool quiet=true)
Definition: MatrixType.cc:656
void mark_as_rectangular()
Definition: MatrixType.h:155
Definition: dMatrix.h:42
Matrix sum(int dim=-1) const
Definition: dMatrix.cc:2389
RowVector row(octave_idx_type i) const
Definition: dMatrix.cc:416
Definition: DET.h:39
base_det square() const
Definition: DET.h:68
Definition: chol.h:38
COND_T rcond() const
Definition: chol.h:63
T inverse() const
Definition: chol.cc:250
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:94
ColumnVector real(const ComplexColumnVector &a)
Definition: dColVector.cc:137
ColumnVector imag(const ComplexColumnVector &a)
Definition: dColVector.cc:143
#define F77_DBLE_CMPLX_ARG(x)
Definition: f77-fcn.h:316
#define F77_XFCN(f, F, args)
Definition: f77-fcn.h:45
octave_f77_int_type F77_INT
Definition: f77-fcn.h:306
#define F77_CONST_DBLE_CMPLX_ARG(x)
Definition: f77-fcn.h:319
double norm(const ColumnVector &v)
Definition: graphics.cc:5547
void scale(Matrix &m, double x, double y, double z)
Definition: graphics.cc:5500
octave::idx_vector idx_vector
Definition: idx-vector.h:1022
void err_nonconformant(const char *op, octave_idx_type op1_len, octave_idx_type op2_len)
void warn_singular_matrix(double rcond)
F77_RET_T const F77_INT const F77_INT const F77_INT const F77_DBLE const F77_DBLE F77_INT F77_DBLE * V
Complex log2(const Complex &x)
Definition: lo-mappers.cc:141
bool isfinite(double x)
Definition: lo-mappers.h:192
bool isinf(double x)
Definition: lo-mappers.h:203
bool isnan(bool)
Definition: lo-mappers.h:178
F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE * d
F77_RET_T const F77_DBLE * x
blas_trans_type
Definition: mx-defs.h:80
@ blas_no_trans
Definition: mx-defs.h:81
@ blas_conj_trans
Definition: mx-defs.h:83
@ blas_trans
Definition: mx-defs.h:82
char get_blas_char(blas_trans_type transt)
Definition: mx-defs.h:87
void mx_inline_sub2(std::size_t n, R *r, const X *x)
Definition: mx-inlines.cc:128
void mx_inline_add2(std::size_t n, R *r, const X *x)
Definition: mx-inlines.cc:127
bool mx_inline_equal(std::size_t n, const T1 *x, const T2 *y)
Definition: mx-inlines.cc:577
T octave_idx_type m
Definition: mx-inlines.cc:781
octave_idx_type n
Definition: mx-inlines.cc:761
T * r
Definition: mx-inlines.cc:781
#define MM_BOOL_OPS(M1, M2)
Definition: mx-op-defs.h:213
#define MM_CMP_OPS(M1, M2)
Definition: mx-op-defs.h:196
#define MS_CMP_OPS(M, S)
Definition: mx-op-defs.h:110
#define SM_CMP_OPS(S, M)
Definition: mx-op-defs.h:153
#define SM_BOOL_OPS(S, M)
Definition: mx-op-defs.h:170
#define MS_BOOL_OPS(M, S)
Definition: mx-op-defs.h:127
std::complex< double > Complex
Definition: oct-cmplx.h:33
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition: oct-locbuf.h:44
F77_RET_T F77_FUNC(xerbla, XERBLA)(F77_CONST_CHAR_ARG_DEF(s_arg
F77_RET_T len
Definition: xerbla.cc:61
subroutine xilaenv(ispec, name, opts, n1, n2, n3, n4, retval)
Definition: xilaenv.f:2
subroutine xzdotc(n, zx, incx, zy, incy, retval)
Definition: xzdotc.f:2
subroutine xzdotu(n, zx, incx, zy, incy, retval)
Definition: xzdotu.f:2