GNU Octave  9.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
dMatrix.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 <istream>
32 #include <limits>
33 #include <ostream>
34 
35 #include "Array-util.h"
36 #include "CColVector.h"
37 #include "CMatrix.h"
38 #include "DET.h"
39 #include "PermMatrix.h"
40 #include "boolMatrix.h"
41 #include "byte-swap.h"
42 #include "chMatrix.h"
43 #include "chol.h"
44 #include "dColVector.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-dm-m.h"
55 #include "mx-inlines.cc"
56 #include "mx-m-dm.h"
57 #include "mx-op-defs.h"
58 #include "oct-cmplx.h"
59 #include "oct-fftw.h"
60 #include "oct-locbuf.h"
61 #include "oct-norm.h"
62 #include "quit.h"
63 #include "schur.h"
64 #include "svd.h"
65 
66 // Matrix class.
67 
69  : NDArray (rv)
70 { }
71 
73  : NDArray (cv)
74 { }
75 
77  : NDArray (a.dims (), 0.0)
78 {
79  for (octave_idx_type i = 0; i < a.length (); i++)
80  elem (i, i) = a.elem (i, i);
81 }
82 
84  : NDArray (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  : NDArray (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  : NDArray (a.dims (), 0.0)
99 {
100  const Array<octave_idx_type> ia (a.col_perm_vec ());
101  octave_idx_type len = a.rows ();
102  for (octave_idx_type i = 0; i < len; i++)
103  elem (ia(i), i) = 1.0;
104 }
105 
106 // FIXME: could we use a templated mixed-type copy function here?
107 
109  : NDArray (a)
110 { }
111 
113  : NDArray (a.dims ())
114 {
115  for (octave_idx_type i = 0; i < a.rows (); i++)
116  for (octave_idx_type j = 0; j < a.cols (); j++)
117  elem (i, j) = static_cast<unsigned char> (a.elem (i, j));
118 }
119 
120 bool
122 {
123  if (rows () != a.rows () || cols () != a.cols ())
124  return false;
125 
126  return mx_inline_equal (numel (), data (), a.data ());
127 }
128 
129 bool
131 {
132  return !(*this == a);
133 }
134 
135 bool
137 {
138  if (issquare () && rows () > 0)
139  {
140  for (octave_idx_type i = 0; i < rows (); i++)
141  for (octave_idx_type j = i+1; j < cols (); j++)
142  if (elem (i, j) != elem (j, i))
143  return false;
144 
145  return true;
146  }
147 
148  return false;
149 }
150 
151 Matrix&
153 {
154  Array<double>::insert (a, r, c);
155  return *this;
156 }
157 
158 Matrix&
160 {
161  octave_idx_type a_len = a.numel ();
162 
163  if (r < 0 || r >= rows () || c < 0 || c + a_len > cols ())
164  (*current_liboctave_error_handler) ("range error for insert");
165 
166  if (a_len > 0)
167  {
168  make_unique ();
169 
170  for (octave_idx_type i = 0; i < a_len; i++)
171  xelem (r, c+i) = a.elem (i);
172  }
173 
174  return *this;
175 }
176 
177 Matrix&
179 {
180  octave_idx_type a_len = a.numel ();
181 
182  if (r < 0 || r + a_len > rows () || c < 0 || c >= cols ())
183  (*current_liboctave_error_handler) ("range error for insert");
184 
185  if (a_len > 0)
186  {
187  make_unique ();
188 
189  for (octave_idx_type i = 0; i < a_len; i++)
190  xelem (r+i, c) = a.elem (i);
191  }
192 
193  return *this;
194 }
195 
196 Matrix&
198 {
199  octave_idx_type a_nr = a.rows ();
200  octave_idx_type a_nc = a.cols ();
201 
202  if (r < 0 || r + a_nr > rows () || c < 0 || c + a_nc > cols ())
203  (*current_liboctave_error_handler) ("range error for insert");
204 
205  fill (0.0, r, c, r + a_nr - 1, c + a_nc - 1);
206 
207  octave_idx_type a_len = a.length ();
208 
209  if (a_len > 0)
210  {
211  make_unique ();
212 
213  for (octave_idx_type i = 0; i < a_len; i++)
214  xelem (r+i, c+i) = a.elem (i, i);
215  }
216 
217  return *this;
218 }
219 
220 Matrix&
221 Matrix::fill (double val)
222 {
223  octave_idx_type nr = rows ();
224  octave_idx_type nc = cols ();
225 
226  if (nr > 0 && nc > 0)
227  {
228  make_unique ();
229 
230  for (octave_idx_type j = 0; j < nc; j++)
231  for (octave_idx_type i = 0; i < nr; i++)
232  xelem (i, j) = val;
233  }
234 
235  return *this;
236 }
237 
238 Matrix&
241 {
242  octave_idx_type nr = rows ();
243  octave_idx_type nc = cols ();
244 
245  if (r1 < 0 || r2 < 0 || c1 < 0 || c2 < 0
246  || r1 >= nr || r2 >= nr || c1 >= nc || c2 >= nc)
247  (*current_liboctave_error_handler) ("range error for fill");
248 
249  if (r1 > r2) { std::swap (r1, r2); }
250  if (c1 > c2) { std::swap (c1, c2); }
251 
252  if (r2 >= r1 && c2 >= c1)
253  {
254  make_unique ();
255 
256  for (octave_idx_type j = c1; j <= c2; j++)
257  for (octave_idx_type i = r1; i <= r2; i++)
258  xelem (i, j) = val;
259  }
260 
261  return *this;
262 }
263 
264 Matrix
265 Matrix::append (const Matrix& a) const
266 {
267  octave_idx_type nr = rows ();
268  octave_idx_type nc = cols ();
269  if (nr != a.rows ())
270  (*current_liboctave_error_handler) ("row dimension mismatch for append");
271 
272  octave_idx_type nc_insert = nc;
273  Matrix retval (nr, nc + a.cols ());
274  retval.insert (*this, 0, 0);
275  retval.insert (a, 0, nc_insert);
276  return retval;
277 }
278 
279 Matrix
280 Matrix::append (const RowVector& a) const
281 {
282  octave_idx_type nr = rows ();
283  octave_idx_type nc = cols ();
284  if (nr != 1)
285  (*current_liboctave_error_handler) ("row dimension mismatch for append");
286 
287  octave_idx_type nc_insert = nc;
288  Matrix retval (nr, nc + a.numel ());
289  retval.insert (*this, 0, 0);
290  retval.insert (a, 0, nc_insert);
291  return retval;
292 }
293 
294 Matrix
295 Matrix::append (const ColumnVector& a) const
296 {
297  octave_idx_type nr = rows ();
298  octave_idx_type nc = cols ();
299  if (nr != a.numel ())
300  (*current_liboctave_error_handler) ("row dimension mismatch for append");
301 
302  octave_idx_type nc_insert = nc;
303  Matrix retval (nr, nc + 1);
304  retval.insert (*this, 0, 0);
305  retval.insert (a, 0, nc_insert);
306  return retval;
307 }
308 
309 Matrix
310 Matrix::append (const DiagMatrix& a) const
311 {
312  octave_idx_type nr = rows ();
313  octave_idx_type nc = cols ();
314  if (nr != a.rows ())
315  (*current_liboctave_error_handler) ("row dimension mismatch for append");
316 
317  octave_idx_type nc_insert = nc;
318  Matrix retval (nr, nc + a.cols ());
319  retval.insert (*this, 0, 0);
320  retval.insert (a, 0, nc_insert);
321  return retval;
322 }
323 
324 Matrix
325 Matrix::stack (const Matrix& a) const
326 {
327  octave_idx_type nr = rows ();
328  octave_idx_type nc = cols ();
329  if (nc != a.cols ())
330  (*current_liboctave_error_handler) ("column dimension mismatch for stack");
331 
332  octave_idx_type nr_insert = nr;
333  Matrix retval (nr + a.rows (), nc);
334  retval.insert (*this, 0, 0);
335  retval.insert (a, nr_insert, 0);
336  return retval;
337 }
338 
339 Matrix
340 Matrix::stack (const RowVector& a) const
341 {
342  octave_idx_type nr = rows ();
343  octave_idx_type nc = cols ();
344  if (nc != a.numel ())
345  (*current_liboctave_error_handler) ("column dimension mismatch for stack");
346 
347  octave_idx_type nr_insert = nr;
348  Matrix retval (nr + 1, nc);
349  retval.insert (*this, 0, 0);
350  retval.insert (a, nr_insert, 0);
351  return retval;
352 }
353 
354 Matrix
355 Matrix::stack (const ColumnVector& a) const
356 {
357  octave_idx_type nr = rows ();
358  octave_idx_type nc = cols ();
359  if (nc != 1)
360  (*current_liboctave_error_handler) ("column dimension mismatch for stack");
361 
362  octave_idx_type nr_insert = nr;
363  Matrix retval (nr + a.numel (), nc);
364  retval.insert (*this, 0, 0);
365  retval.insert (a, nr_insert, 0);
366  return retval;
367 }
368 
369 Matrix
370 Matrix::stack (const DiagMatrix& a) const
371 {
372  octave_idx_type nr = rows ();
373  octave_idx_type nc = cols ();
374  if (nc != a.cols ())
375  (*current_liboctave_error_handler) ("column dimension mismatch for stack");
376 
377  octave_idx_type nr_insert = nr;
378  Matrix retval (nr + a.rows (), nc);
379  retval.insert (*this, 0, 0);
380  retval.insert (a, nr_insert, 0);
381  return retval;
382 }
383 
384 Matrix
385 real (const ComplexMatrix& a)
386 {
387  return do_mx_unary_op<double, Complex> (a, mx_inline_real);
388 }
389 
390 Matrix
391 imag (const ComplexMatrix& a)
392 {
393  return do_mx_unary_op<double, Complex> (a, mx_inline_imag);
394 }
395 
396 Matrix
398  octave_idx_type r2, octave_idx_type c2) const
399 {
400  if (r1 > r2) { std::swap (r1, r2); }
401  if (c1 > c2) { std::swap (c1, c2); }
402 
403  return index (octave::idx_vector (r1, r2+1), octave::idx_vector (c1, c2+1));
404 }
405 
406 Matrix
408  octave_idx_type nc) const
409 {
410  return index (octave::idx_vector (r1, r1 + nr), octave::idx_vector (c1, c1 + nc));
411 }
412 
413 // extract row or column i.
414 
415 RowVector
417 {
418  return index (octave::idx_vector (i), octave::idx_vector::colon);
419 }
420 
423 {
424  return index (octave::idx_vector::colon, octave::idx_vector (i));
425 }
426 
427 // Local function to calculate the 1-norm.
428 static
429 double
430 norm1 (const Matrix& a)
431 {
432  double anorm = 0.0;
433  RowVector colsum = a.abs ().sum ().row (0);
434 
435  for (octave_idx_type i = 0; i < colsum.numel (); i++)
436  {
437  double sum = colsum.xelem (i);
438  if (octave::math::isinf (sum) || octave::math::isnan (sum))
439  {
440  anorm = sum; // Pass Inf or NaN to output
441  break;
442  }
443  else
444  anorm = std::max (anorm, sum);
445  }
446 
447  return anorm;
448 }
449 
450 Matrix
452 {
453  octave_idx_type info;
454  double rcon;
455  MatrixType mattype (*this);
456  return inverse (mattype, info, rcon, 0, 0);
457 }
458 
459 Matrix
461 {
462  double rcon;
463  MatrixType mattype (*this);
464  return inverse (mattype, info, rcon, 0, 0);
465 }
466 
467 Matrix
468 Matrix::inverse (octave_idx_type& info, double& rcon, bool force,
469  bool calc_cond) const
470 {
471  MatrixType mattype (*this);
472  return inverse (mattype, info, rcon, force, calc_cond);
473 }
474 
475 Matrix
476 Matrix::inverse (MatrixType& mattype) const
477 {
478  octave_idx_type info;
479  double rcon;
480  return inverse (mattype, info, rcon, 0, 0);
481 }
482 
483 Matrix
485 {
486  double rcon;
487  return inverse (mattype, info, rcon, 0, 0);
488 }
489 
490 Matrix
491 Matrix::tinverse (MatrixType& mattype, octave_idx_type& info, double& rcon,
492  bool force, bool calc_cond) const
493 {
494  Matrix retval;
495 
496  F77_INT nr = octave::to_f77_int (rows ());
497  F77_INT nc = octave::to_f77_int (cols ());
498 
499  if (nr != nc || nr == 0 || nc == 0)
500  (*current_liboctave_error_handler) ("inverse requires square matrix");
501 
502  int typ = mattype.type ();
503  char uplo = (typ == MatrixType::Lower ? 'L' : 'U');
504  char udiag = 'N';
505  retval = *this;
506  double *tmp_data = retval.fortran_vec ();
507 
508  F77_INT tmp_info = 0;
509 
510  F77_XFCN (dtrtri, DTRTRI, (F77_CONST_CHAR_ARG2 (&uplo, 1),
511  F77_CONST_CHAR_ARG2 (&udiag, 1),
512  nr, tmp_data, nr, tmp_info
513  F77_CHAR_ARG_LEN (1)
514  F77_CHAR_ARG_LEN (1)));
515 
516  info = tmp_info;
517 
518  // Throw away extra info LAPACK gives so as to not change output.
519  rcon = 0.0;
520  if (info != 0)
521  info = -1;
522  else if (calc_cond)
523  {
524  F77_INT dtrcon_info = 0;
525  char job = '1';
526 
527  OCTAVE_LOCAL_BUFFER (double, work, 3 * nr);
528  OCTAVE_LOCAL_BUFFER (F77_INT, iwork, nr);
529 
530  F77_XFCN (dtrcon, DTRCON, (F77_CONST_CHAR_ARG2 (&job, 1),
531  F77_CONST_CHAR_ARG2 (&uplo, 1),
532  F77_CONST_CHAR_ARG2 (&udiag, 1),
533  nr, tmp_data, nr, rcon,
534  work, iwork, dtrcon_info
535  F77_CHAR_ARG_LEN (1)
536  F77_CHAR_ARG_LEN (1)
537  F77_CHAR_ARG_LEN (1)));
538 
539  if (dtrcon_info != 0)
540  info = -1;
541  }
542 
543  if (info == -1 && ! force)
544  retval = *this; // Restore matrix contents.
545 
546  return retval;
547 }
548 
549 Matrix
550 Matrix::finverse (MatrixType& mattype, octave_idx_type& info, double& rcon,
551  bool force, bool calc_cond) const
552 {
553  Matrix retval;
554 
555  F77_INT nr = octave::to_f77_int (rows ());
556  F77_INT nc = octave::to_f77_int (cols ());
557 
558  if (nr != nc || nr == 0 || nc == 0)
559  (*current_liboctave_error_handler) ("inverse requires square matrix");
560 
561  Array<F77_INT> ipvt (dim_vector (nr, 1));
562  F77_INT *pipvt = ipvt.fortran_vec ();
563 
564  retval = *this;
565  double *tmp_data = retval.fortran_vec ();
566 
567  Array<double> z (dim_vector (1, 1));
568  F77_INT lwork = -1;
569 
570  F77_INT tmp_info = 0;
571 
572  // Query the optimum work array size.
573  F77_XFCN (dgetri, DGETRI, (nc, tmp_data, nr, pipvt,
574  z.fortran_vec (), lwork, tmp_info));
575 
576  lwork = static_cast<F77_INT> (z(0));
577  lwork = (lwork < 4 * nc ? 4 * nc : lwork);
578  z.resize (dim_vector (lwork, 1));
579  double *pz = z.fortran_vec ();
580 
581  info = 0;
582  tmp_info = 0;
583 
584  // Calculate the norm of the matrix for later use when determining rcon.
585  double anorm;
586  if (calc_cond)
587  anorm = norm1 (retval);
588 
589  F77_XFCN (dgetrf, DGETRF, (nc, nc, tmp_data, nr, pipvt, tmp_info));
590 
591  info = tmp_info;
592 
593  // Throw away extra info LAPACK gives so as to not change output.
594  rcon = 0.0;
595  if (info != 0)
596  info = -1;
597  else if (calc_cond)
598  {
599  if (octave::math::isnan (anorm))
601  else
602  {
603  F77_INT dgecon_info = 0;
604 
605  // Now calculate the condition number for non-singular matrix.
606  char job = '1';
607  Array<F77_INT> iz (dim_vector (nc, 1));
608  F77_INT *piz = iz.fortran_vec ();
609  F77_XFCN (dgecon, DGECON, (F77_CONST_CHAR_ARG2 (&job, 1),
610  nc, tmp_data, nr, anorm,
611  rcon, pz, piz, dgecon_info
612  F77_CHAR_ARG_LEN (1)));
613 
614  if (dgecon_info != 0)
615  info = -1;
616  }
617  }
618 
619  if (info == -1 && ! force)
620  retval = *this; // Restore matrix contents.
621  else
622  {
623  F77_INT dgetri_info = 0;
624 
625  F77_XFCN (dgetri, DGETRI, (nc, tmp_data, nr, pipvt,
626  pz, lwork, dgetri_info));
627 
628  if (dgetri_info != 0)
629  info = -1;
630  }
631 
632  if (info != 0)
633  mattype.mark_as_rectangular ();
634 
635  return retval;
636 }
637 
638 Matrix
639 Matrix::inverse (MatrixType& mattype, octave_idx_type& info, double& rcon,
640  bool force, bool calc_cond) const
641 {
642  int typ = mattype.type (false);
643  Matrix ret;
644 
645  if (typ == MatrixType::Unknown)
646  typ = mattype.type (*this);
647 
648  if (typ == MatrixType::Diagonal) // a scalar is classified as Diagonal.
649  {
650  ret = 1 / (*this);
651  if (calc_cond)
652  {
653  double scalar = this->elem (0);
654  if (octave::math::isfinite (scalar) && scalar != 0)
655  rcon = 1.0;
656  else if (octave::math::isinf (scalar) || scalar == 0)
657  rcon = 0.0;
658  else
660  }
661  }
662  else if (typ == MatrixType::Upper || typ == MatrixType::Lower)
663  ret = tinverse (mattype, info, rcon, force, calc_cond);
664  else
665  {
666  if (mattype.ishermitian ())
667  {
668  octave::math::chol<Matrix> chol (*this, info, true, calc_cond);
669  if (info == 0)
670  {
671  if (calc_cond)
672  rcon = chol.rcond ();
673  else
674  rcon = 1.0;
675  ret = chol.inverse ();
676  }
677  else
678  mattype.mark_as_unsymmetric ();
679  }
680 
681  if (! mattype.ishermitian ())
682  ret = finverse (mattype, info, rcon, force, calc_cond);
683 
684  if ((calc_cond || mattype.ishermitian ()) && rcon == 0.0)
685  ret = Matrix (rows (), columns (),
687  }
688 
689  return ret;
690 }
691 
692 Matrix
693 Matrix::pseudo_inverse (double tol) const
694 {
695  octave::math::svd<Matrix> result (*this,
696  octave::math::svd<Matrix>::Type::economy);
697 
698  DiagMatrix S = result.singular_values ();
699  Matrix U = result.left_singular_matrix ();
700  Matrix V = result.right_singular_matrix ();
701 
702  ColumnVector sigma = S.extract_diag ();
703 
704  octave_idx_type r = sigma.numel () - 1;
705  octave_idx_type nr = rows ();
706  octave_idx_type nc = cols ();
707 
708  if (tol <= 0.0)
709  {
710  tol = std::max (nr, nc) * sigma.elem (0)
711  * std::numeric_limits<double>::epsilon ();
712 
713  if (tol == 0)
715  }
716 
717  while (r >= 0 && sigma.elem (r) < tol)
718  r--;
719 
720  if (r < 0)
721  return Matrix (nc, nr, 0.0);
722  else
723  {
724  Matrix Ur = U.extract (0, 0, nr-1, r);
725  DiagMatrix D = DiagMatrix (sigma.extract (0, r)).inverse ();
726  Matrix Vr = V.extract (0, 0, nc-1, r);
727  return Vr * D * Ur.transpose ();
728  }
729 }
730 
731 #if defined (HAVE_FFTW)
732 
735 {
736  std::size_t nr = rows ();
737  std::size_t nc = cols ();
738 
739  ComplexMatrix retval (nr, nc);
740 
741  std::size_t npts, nsamples;
742 
743  if (nr == 1 || nc == 1)
744  {
745  npts = (nr > nc ? nr : nc);
746  nsamples = 1;
747  }
748  else
749  {
750  npts = nr;
751  nsamples = nc;
752  }
753 
754  const double *in (data ());
755  Complex *out (retval.fortran_vec ());
756 
757  octave::fftw::fft (in, out, npts, nsamples);
758 
759  return retval;
760 }
761 
764 {
765  std::size_t nr = rows ();
766  std::size_t nc = cols ();
767 
768  ComplexMatrix retval (nr, nc);
769 
770  std::size_t npts, nsamples;
771 
772  if (nr == 1 || nc == 1)
773  {
774  npts = (nr > nc ? nr : nc);
775  nsamples = 1;
776  }
777  else
778  {
779  npts = nr;
780  nsamples = nc;
781  }
782 
783  ComplexMatrix tmp (*this);
784  const Complex *in (tmp.data ());
785  Complex *out (retval.fortran_vec ());
786 
787  octave::fftw::ifft (in, out, npts, nsamples);
788 
789  return retval;
790 }
791 
794 {
795  dim_vector dv (rows (), cols ());
796 
797  const double *in = data ();
798  ComplexMatrix retval (rows (), cols ());
799  octave::fftw::fftNd (in, retval.fortran_vec (), 2, dv);
800 
801  return retval;
802 }
803 
806 {
807  dim_vector dv (rows (), cols ());
808 
809  ComplexMatrix retval (*this);
810  Complex *out (retval.fortran_vec ());
811 
812  octave::fftw::ifftNd (out, out, 2, dv);
813 
814  return retval;
815 }
816 
817 #else
818 
820 Matrix::fourier () const
821 {
822  (*current_liboctave_error_handler)
823  ("support for FFTW was unavailable or disabled when liboctave was built");
824 
825  return ComplexMatrix ();
826 }
827 
829 Matrix::ifourier () const
830 {
831  (*current_liboctave_error_handler)
832  ("support for FFTW was unavailable or disabled when liboctave was built");
833 
834  return ComplexMatrix ();
835 }
836 
838 Matrix::fourier2d () const
839 {
840  (*current_liboctave_error_handler)
841  ("support for FFTW was unavailable or disabled when liboctave was built");
842 
843  return ComplexMatrix ();
844 }
845 
847 Matrix::ifourier2d () const
848 {
849  (*current_liboctave_error_handler)
850  ("support for FFTW was unavailable or disabled when liboctave was built");
851 
852  return ComplexMatrix ();
853 }
854 
855 #endif
856 
857 DET
859 {
860  octave_idx_type info;
861  double rcon;
862  return determinant (info, rcon, 0);
863 }
864 
865 DET
867 {
868  double rcon;
869  return determinant (info, rcon, 0);
870 }
871 
872 DET
873 Matrix::determinant (octave_idx_type& info, double& rcon, bool calc_cond) const
874 {
875  MatrixType mattype (*this);
876  return determinant (mattype, info, rcon, calc_cond);
877 }
878 
879 DET
881  octave_idx_type& info, double& rcon, bool calc_cond) const
882 {
883  DET retval (1.0);
884 
885  info = 0;
886  rcon = 0.0;
887 
888  F77_INT nr = octave::to_f77_int (rows ());
889  F77_INT nc = octave::to_f77_int (cols ());
890 
891  if (nr != nc)
892  (*current_liboctave_error_handler) ("matrix must be square");
893 
894  volatile int typ = mattype.type ();
895 
896  // Even though the matrix is marked as singular (Rectangular), we may still
897  // get a useful number from the LU factorization, because it always completes.
898 
899  if (typ == MatrixType::Unknown)
900  typ = mattype.type (*this);
901  else if (typ == MatrixType::Rectangular)
902  typ = MatrixType::Full;
903 
904  if (typ == MatrixType::Lower || typ == MatrixType::Upper)
905  {
906  for (F77_INT i = 0; i < nc; i++)
907  retval *= elem (i, i);
908  }
909  else if (typ == MatrixType::Hermitian)
910  {
911  Matrix atmp = *this;
912  double *tmp_data = atmp.fortran_vec ();
913 
914  // Calculate the norm of the matrix for later use when determining rcon.
915  double anorm;
916  if (calc_cond)
917  anorm = norm1 (*this);
918 
919  F77_INT tmp_info = 0;
920 
921  char job = 'L';
922  F77_XFCN (dpotrf, DPOTRF, (F77_CONST_CHAR_ARG2 (&job, 1), nr,
923  tmp_data, nr, tmp_info
924  F77_CHAR_ARG_LEN (1)));
925 
926  info = tmp_info;
927 
928  if (info != 0)
929  {
930  rcon = 0.0;
931  mattype.mark_as_unsymmetric ();
932  typ = MatrixType::Full;
933  }
934  else
935  {
936  if (calc_cond)
937  {
938  Array<double> z (dim_vector (3 * nc, 1));
939  double *pz = z.fortran_vec ();
940  Array<F77_INT> iz (dim_vector (nc, 1));
941  F77_INT *piz = iz.fortran_vec ();
942 
943  F77_XFCN (dpocon, DPOCON, (F77_CONST_CHAR_ARG2 (&job, 1),
944  nr, tmp_data, nr, anorm,
945  rcon, pz, piz, tmp_info
946  F77_CHAR_ARG_LEN (1)));
947 
948  info = tmp_info;
949 
950  if (info != 0)
951  rcon = 0.0;
952  }
953 
954  for (F77_INT i = 0; i < nc; i++)
955  retval *= atmp(i, i);
956 
957  retval = retval.square ();
958  }
959  }
960  else if (typ != MatrixType::Full)
961  (*current_liboctave_error_handler) ("det: invalid dense matrix type");
962 
963  if (typ == MatrixType::Full)
964  {
965  Array<F77_INT> ipvt (dim_vector (nr, 1));
966  F77_INT *pipvt = ipvt.fortran_vec ();
967 
968  Matrix atmp = *this;
969  double *tmp_data = atmp.fortran_vec ();
970 
971  info = 0;
972  F77_INT tmp_info = 0;
973 
974  // Calculate the norm of the matrix for later use when determining rcon.
975  double anorm;
976  if (calc_cond)
977  anorm = norm1 (*this);
978 
979  F77_XFCN (dgetrf, DGETRF, (nr, nr, tmp_data, nr, pipvt, tmp_info));
980 
981  info = tmp_info;
982 
983  // Throw away extra info LAPACK gives so as to not change output.
984  rcon = 0.0;
985  if (info != 0)
986  {
987  info = -1;
988  retval = DET ();
989  }
990  else
991  {
992  if (calc_cond)
993  {
994  // Now calc the condition number for non-singular matrix.
995  char job = '1';
996  Array<double> z (dim_vector (4 * nc, 1));
997  double *pz = z.fortran_vec ();
998  Array<F77_INT> iz (dim_vector (nc, 1));
999  F77_INT *piz = iz.fortran_vec ();
1000 
1001  F77_XFCN (dgecon, DGECON, (F77_CONST_CHAR_ARG2 (&job, 1),
1002  nc, tmp_data, nr, anorm,
1003  rcon, pz, piz, tmp_info
1004  F77_CHAR_ARG_LEN (1)));
1005 
1006  info = tmp_info;
1007  }
1008 
1009  if (info != 0)
1010  {
1011  info = -1;
1012  retval = DET ();
1013  }
1014  else
1015  {
1016  for (F77_INT i = 0; i < nc; i++)
1017  {
1018  double c = atmp(i, i);
1019  retval *= (ipvt(i) != (i+1)) ? -c : c;
1020  }
1021  }
1022  }
1023  }
1024 
1025  return retval;
1026 }
1027 
1028 double
1030 {
1031  MatrixType mattype (*this);
1032  return rcond (mattype);
1033 }
1034 
1035 double
1036 Matrix::rcond (MatrixType& mattype) const
1037 {
1038  double rcon = octave::numeric_limits<double>::NaN ();
1039  F77_INT nr = octave::to_f77_int (rows ());
1040  F77_INT nc = octave::to_f77_int (cols ());
1041 
1042  if (nr != nc)
1043  (*current_liboctave_error_handler) ("matrix must be square");
1044 
1045  if (nr == 0 || nc == 0)
1047  else
1048  {
1049  volatile int typ = mattype.type ();
1050 
1051  if (typ == MatrixType::Unknown)
1052  typ = mattype.type (*this);
1053 
1054  // Only calculate the condition number for LU/Cholesky
1055  if (typ == MatrixType::Upper)
1056  {
1057  const double *tmp_data = data ();
1058  F77_INT info = 0;
1059  char norm = '1';
1060  char uplo = 'U';
1061  char dia = 'N';
1062 
1063  Array<double> z (dim_vector (3 * nc, 1));
1064  double *pz = z.fortran_vec ();
1065  Array<F77_INT> iz (dim_vector (nc, 1));
1066  F77_INT *piz = iz.fortran_vec ();
1067 
1068  F77_XFCN (dtrcon, DTRCON, (F77_CONST_CHAR_ARG2 (&norm, 1),
1069  F77_CONST_CHAR_ARG2 (&uplo, 1),
1070  F77_CONST_CHAR_ARG2 (&dia, 1),
1071  nr, tmp_data, nr, rcon,
1072  pz, piz, info
1073  F77_CHAR_ARG_LEN (1)
1074  F77_CHAR_ARG_LEN (1)
1075  F77_CHAR_ARG_LEN (1)));
1076 
1077  if (info != 0)
1078  rcon = 0.0;
1079  }
1080  else if (typ == MatrixType::Permuted_Upper)
1081  (*current_liboctave_error_handler)
1082  ("permuted triangular matrix not implemented");
1083  else if (typ == MatrixType::Lower)
1084  {
1085  const double *tmp_data = data ();
1086  F77_INT info = 0;
1087  char norm = '1';
1088  char uplo = 'L';
1089  char dia = 'N';
1090 
1091  Array<double> z (dim_vector (3 * nc, 1));
1092  double *pz = z.fortran_vec ();
1093  Array<F77_INT> iz (dim_vector (nc, 1));
1094  F77_INT *piz = iz.fortran_vec ();
1095 
1096  F77_XFCN (dtrcon, DTRCON, (F77_CONST_CHAR_ARG2 (&norm, 1),
1097  F77_CONST_CHAR_ARG2 (&uplo, 1),
1098  F77_CONST_CHAR_ARG2 (&dia, 1),
1099  nr, tmp_data, nr, rcon,
1100  pz, piz, info
1101  F77_CHAR_ARG_LEN (1)
1102  F77_CHAR_ARG_LEN (1)
1103  F77_CHAR_ARG_LEN (1)));
1104 
1105  if (info != 0)
1106  rcon = 0.0;
1107  }
1108  else if (typ == MatrixType::Permuted_Lower)
1109  (*current_liboctave_error_handler)
1110  ("permuted triangular matrix not implemented");
1111  else if (typ == MatrixType::Full || typ == MatrixType::Hermitian)
1112  {
1113  double anorm = -1.0;
1114 
1115  if (typ == MatrixType::Hermitian)
1116  {
1117  F77_INT info = 0;
1118  char job = 'L';
1119 
1120  Matrix atmp = *this;
1121  double *tmp_data = atmp.fortran_vec ();
1122 
1123  anorm = norm1 (atmp);
1124 
1125  F77_XFCN (dpotrf, DPOTRF, (F77_CONST_CHAR_ARG2 (&job, 1), nr,
1126  tmp_data, nr, info
1127  F77_CHAR_ARG_LEN (1)));
1128 
1129  if (info != 0)
1130  {
1131  rcon = 0.0;
1132  mattype.mark_as_unsymmetric ();
1133  typ = MatrixType::Full;
1134  }
1135  else
1136  {
1137  Array<double> z (dim_vector (3 * nc, 1));
1138  double *pz = z.fortran_vec ();
1139  Array<F77_INT> iz (dim_vector (nc, 1));
1140  F77_INT *piz = iz.fortran_vec ();
1141 
1142  F77_XFCN (dpocon, DPOCON, (F77_CONST_CHAR_ARG2 (&job, 1),
1143  nr, tmp_data, nr, anorm,
1144  rcon, pz, piz, info
1145  F77_CHAR_ARG_LEN (1)));
1146 
1147  if (info != 0)
1148  rcon = 0.0;
1149  }
1150  }
1151 
1152  if (typ == MatrixType::Full)
1153  {
1154  F77_INT info = 0;
1155 
1156  Matrix atmp = *this;
1157  double *tmp_data = atmp.fortran_vec ();
1158 
1159  Array<F77_INT> ipvt (dim_vector (nr, 1));
1160  F77_INT *pipvt = ipvt.fortran_vec ();
1161 
1162  if (anorm < 0.0)
1163  anorm = norm1 (atmp);
1164 
1165  Array<double> z (dim_vector (4 * nc, 1));
1166  double *pz = z.fortran_vec ();
1167  Array<F77_INT> iz (dim_vector (nc, 1));
1168  F77_INT *piz = iz.fortran_vec ();
1169 
1170  F77_XFCN (dgetrf, DGETRF, (nr, nr, tmp_data, nr, pipvt, info));
1171 
1172  if (info != 0)
1173  {
1174  rcon = 0.0;
1175  mattype.mark_as_rectangular ();
1176  }
1177  else
1178  {
1179  char job = '1';
1180  F77_XFCN (dgecon, DGECON, (F77_CONST_CHAR_ARG2 (&job, 1),
1181  nc, tmp_data, nr, anorm,
1182  rcon, pz, piz, info
1183  F77_CHAR_ARG_LEN (1)));
1184 
1185  if (info != 0)
1186  rcon = 0.0;
1187  }
1188  }
1189  }
1190  else
1191  rcon = 0.0;
1192  }
1193 
1194  return rcon;
1195 }
1196 
1197 Matrix
1198 Matrix::utsolve (MatrixType& mattype, const Matrix& b, octave_idx_type& info,
1199  double& rcon, solve_singularity_handler sing_handler,
1200  bool calc_cond, blas_trans_type transt) const
1201 {
1202  Matrix retval;
1203 
1204  F77_INT nr = octave::to_f77_int (rows ());
1205  F77_INT nc = octave::to_f77_int (cols ());
1206 
1207  F77_INT b_nr = octave::to_f77_int (b.rows ());
1208  F77_INT b_nc = octave::to_f77_int (b.cols ());
1209 
1210  if (nr != b_nr)
1211  (*current_liboctave_error_handler)
1212  ("matrix dimension mismatch solution of linear equations");
1213 
1214  if (nr == 0 || nc == 0 || b_nc == 0)
1215  retval = Matrix (nc, b_nc, 0.0);
1216  else
1217  {
1218  volatile int typ = mattype.type ();
1219 
1220  if (typ != MatrixType::Permuted_Upper && typ != MatrixType::Upper)
1221  (*current_liboctave_error_handler) ("incorrect matrix type");
1222 
1223  rcon = 1.0;
1224  info = 0;
1225 
1226  if (typ == MatrixType::Permuted_Upper)
1227  (*current_liboctave_error_handler)
1228  ("permuted triangular matrix not implemented");
1229 
1230  const double *tmp_data = data ();
1231 
1232  retval = b;
1233  double *result = retval.fortran_vec ();
1234 
1235  char uplo = 'U';
1236  char trans = get_blas_char (transt);
1237  char dia = 'N';
1238 
1239  F77_INT tmp_info = 0;
1240 
1241  F77_XFCN (dtrtrs, DTRTRS, (F77_CONST_CHAR_ARG2 (&uplo, 1),
1242  F77_CONST_CHAR_ARG2 (&trans, 1),
1243  F77_CONST_CHAR_ARG2 (&dia, 1),
1244  nr, b_nc, tmp_data, nr,
1245  result, nr, tmp_info
1246  F77_CHAR_ARG_LEN (1)
1247  F77_CHAR_ARG_LEN (1)
1248  F77_CHAR_ARG_LEN (1)));
1249 
1250  info = tmp_info;
1251 
1252  if (calc_cond)
1253  {
1254  char norm = '1';
1255  uplo = 'U';
1256  dia = 'N';
1257 
1258  Array<double> z (dim_vector (3 * nc, 1));
1259  double *pz = z.fortran_vec ();
1260  Array<F77_INT> iz (dim_vector (nc, 1));
1261  F77_INT *piz = iz.fortran_vec ();
1262 
1263  F77_XFCN (dtrcon, DTRCON, (F77_CONST_CHAR_ARG2 (&norm, 1),
1264  F77_CONST_CHAR_ARG2 (&uplo, 1),
1265  F77_CONST_CHAR_ARG2 (&dia, 1),
1266  nr, tmp_data, nr, rcon,
1267  pz, piz, tmp_info
1268  F77_CHAR_ARG_LEN (1)
1269  F77_CHAR_ARG_LEN (1)
1270  F77_CHAR_ARG_LEN (1)));
1271 
1272  info = tmp_info;
1273 
1274  if (info != 0)
1275  info = -2;
1276 
1277  // FIXME: Why calculate this, rather than just compare to 0.0?
1278  volatile double rcond_plus_one = rcon + 1.0;
1279 
1280  if (rcond_plus_one == 1.0 || octave::math::isnan (rcon))
1281  {
1282  info = -2;
1283 
1284  if (sing_handler)
1285  sing_handler (rcon);
1286  else
1288  }
1289  }
1290  }
1291 
1292  return retval;
1293 }
1294 
1295 Matrix
1296 Matrix::ltsolve (MatrixType& mattype, const Matrix& b, octave_idx_type& info,
1297  double& rcon, solve_singularity_handler sing_handler,
1298  bool calc_cond, blas_trans_type transt) const
1299 {
1300  Matrix retval;
1301 
1302  F77_INT nr = octave::to_f77_int (rows ());
1303  F77_INT nc = octave::to_f77_int (cols ());
1304 
1305  F77_INT b_nr = octave::to_f77_int (b.rows ());
1306  F77_INT b_nc = octave::to_f77_int (b.cols ());
1307 
1308  if (nr != b_nr)
1309  (*current_liboctave_error_handler)
1310  ("matrix dimension mismatch solution of linear equations");
1311 
1312  if (nr == 0 || nc == 0 || b_nc == 0)
1313  retval = Matrix (nc, b_nc, 0.0);
1314  else
1315  {
1316  volatile int typ = mattype.type ();
1317 
1318  if (typ != MatrixType::Permuted_Lower && typ != MatrixType::Lower)
1319  (*current_liboctave_error_handler) ("incorrect matrix type");
1320 
1321  rcon = 1.0;
1322  info = 0;
1323 
1324  if (typ == MatrixType::Permuted_Lower)
1325  (*current_liboctave_error_handler)
1326  ("permuted triangular matrix not implemented");
1327 
1328  const double *tmp_data = data ();
1329 
1330  retval = b;
1331  double *result = retval.fortran_vec ();
1332 
1333  char uplo = 'L';
1334  char trans = get_blas_char (transt);
1335  char dia = 'N';
1336 
1337  F77_INT tmp_info = 0;
1338 
1339  F77_XFCN (dtrtrs, DTRTRS, (F77_CONST_CHAR_ARG2 (&uplo, 1),
1340  F77_CONST_CHAR_ARG2 (&trans, 1),
1341  F77_CONST_CHAR_ARG2 (&dia, 1),
1342  nr, b_nc, tmp_data, nr,
1343  result, nr, tmp_info
1344  F77_CHAR_ARG_LEN (1)
1345  F77_CHAR_ARG_LEN (1)
1346  F77_CHAR_ARG_LEN (1)));
1347 
1348  info = tmp_info;
1349 
1350  if (calc_cond)
1351  {
1352  char norm = '1';
1353  uplo = 'L';
1354  dia = 'N';
1355 
1356  Array<double> z (dim_vector (3 * nc, 1));
1357  double *pz = z.fortran_vec ();
1358  Array<F77_INT> iz (dim_vector (nc, 1));
1359  F77_INT *piz = iz.fortran_vec ();
1360 
1361  F77_XFCN (dtrcon, DTRCON, (F77_CONST_CHAR_ARG2 (&norm, 1),
1362  F77_CONST_CHAR_ARG2 (&uplo, 1),
1363  F77_CONST_CHAR_ARG2 (&dia, 1),
1364  nr, tmp_data, nr, rcon,
1365  pz, piz, tmp_info
1366  F77_CHAR_ARG_LEN (1)
1367  F77_CHAR_ARG_LEN (1)
1368  F77_CHAR_ARG_LEN (1)));
1369 
1370  info = tmp_info;
1371 
1372  if (info != 0)
1373  info = -2;
1374 
1375  volatile double rcond_plus_one = rcon + 1.0;
1376 
1377  if (rcond_plus_one == 1.0 || octave::math::isnan (rcon))
1378  {
1379  info = -2;
1380 
1381  if (sing_handler)
1382  sing_handler (rcon);
1383  else
1385  }
1386  }
1387  }
1388 
1389  return retval;
1390 }
1391 
1392 Matrix
1393 Matrix::fsolve (MatrixType& mattype, const Matrix& b, octave_idx_type& info,
1394  double& rcon, solve_singularity_handler sing_handler,
1395  bool calc_cond) const
1396 {
1397  Matrix retval;
1398 
1399  F77_INT nr = octave::to_f77_int (rows ());
1400  F77_INT nc = octave::to_f77_int (cols ());
1401 
1402  if (nr != nc || nr != b.rows ())
1403  (*current_liboctave_error_handler)
1404  ("matrix dimension mismatch solution of linear equations");
1405 
1406  if (nr == 0 || b.cols () == 0)
1407  retval = Matrix (nc, b.cols (), 0.0);
1408  else
1409  {
1410  volatile int typ = mattype.type ();
1411 
1412  // Calculate the norm of the matrix for later use when determining rcon.
1413  double anorm = -1.0;
1414 
1415  if (typ == MatrixType::Hermitian)
1416  {
1417  info = 0;
1418  char job = 'L';
1419 
1420  Matrix atmp = *this;
1421  double *tmp_data = atmp.fortran_vec ();
1422 
1423  // The norm of the matrix for later use when determining rcon.
1424  if (calc_cond)
1425  anorm = norm1 (atmp);
1426 
1427  F77_INT tmp_info = 0;
1428 
1429  F77_XFCN (dpotrf, DPOTRF, (F77_CONST_CHAR_ARG2 (&job, 1), nr,
1430  tmp_data, nr, tmp_info
1431  F77_CHAR_ARG_LEN (1)));
1432 
1433  info = tmp_info;
1434 
1435  // Throw away extra info LAPACK gives so as to not change output.
1436  rcon = 0.0;
1437  if (info != 0)
1438  {
1439  info = -2;
1440 
1441  mattype.mark_as_unsymmetric ();
1442  typ = MatrixType::Full;
1443  }
1444  else
1445  {
1446  if (calc_cond)
1447  {
1448  Array<double> z (dim_vector (3 * nc, 1));
1449  double *pz = z.fortran_vec ();
1450  Array<F77_INT> iz (dim_vector (nc, 1));
1451  F77_INT *piz = iz.fortran_vec ();
1452 
1453  F77_XFCN (dpocon, DPOCON, (F77_CONST_CHAR_ARG2 (&job, 1),
1454  nr, tmp_data, nr, anorm,
1455  rcon, pz, piz, tmp_info
1456  F77_CHAR_ARG_LEN (1)));
1457 
1458  info = tmp_info;
1459 
1460  if (info != 0)
1461  info = -2;
1462 
1463  volatile double rcond_plus_one = rcon + 1.0;
1464 
1465  if (rcond_plus_one == 1.0 || octave::math::isnan (rcon))
1466  {
1467  info = -2;
1468 
1469  if (sing_handler)
1470  sing_handler (rcon);
1471  else
1473  }
1474  }
1475 
1476  if (info == 0)
1477  {
1478  retval = b;
1479  double *result = retval.fortran_vec ();
1480 
1481  F77_INT b_nr = octave::to_f77_int (b.rows ());
1482  F77_INT b_nc = octave::to_f77_int (b.cols ());
1483 
1484  F77_XFCN (dpotrs, DPOTRS, (F77_CONST_CHAR_ARG2 (&job, 1),
1485  nr, b_nc, tmp_data, nr,
1486  result, b_nr, tmp_info
1487  F77_CHAR_ARG_LEN (1)));
1488 
1489  info = tmp_info;
1490  }
1491  else
1492  {
1493  mattype.mark_as_unsymmetric ();
1494  typ = MatrixType::Full;
1495  }
1496  }
1497  }
1498 
1499  if (typ == MatrixType::Full)
1500  {
1501  info = 0;
1502 
1503  Array<F77_INT> ipvt (dim_vector (nr, 1));
1504  F77_INT *pipvt = ipvt.fortran_vec ();
1505 
1506  Matrix atmp = *this;
1507  double *tmp_data = atmp.fortran_vec ();
1508 
1509  if (calc_cond && anorm < 0.0)
1510  anorm = norm1 (atmp);
1511 
1512  Array<double> z (dim_vector (4 * nc, 1));
1513  double *pz = z.fortran_vec ();
1514  Array<F77_INT> iz (dim_vector (nc, 1));
1515  F77_INT *piz = iz.fortran_vec ();
1516 
1517  F77_INT tmp_info = 0;
1518 
1519  F77_XFCN (dgetrf, DGETRF, (nr, nr, tmp_data, nr, pipvt, tmp_info));
1520 
1521  info = tmp_info;
1522 
1523  // Throw away extra info LAPACK gives so as to not change output.
1524  rcon = 0.0;
1525  if (info != 0)
1526  {
1527  info = -2;
1528 
1529  if (sing_handler)
1530  sing_handler (rcon);
1531  else
1533 
1534  mattype.mark_as_rectangular ();
1535  }
1536  else
1537  {
1538  if (calc_cond)
1539  {
1540  // Calculate the condition number for non-singular matrix.
1541  char job = '1';
1542  F77_XFCN (dgecon, DGECON, (F77_CONST_CHAR_ARG2 (&job, 1),
1543  nc, tmp_data, nr, anorm,
1544  rcon, pz, piz, tmp_info
1545  F77_CHAR_ARG_LEN (1)));
1546 
1547  info = tmp_info;
1548 
1549  if (info != 0)
1550  info = -2;
1551 
1552  volatile double rcond_plus_one = rcon + 1.0;
1553 
1554  if (rcond_plus_one == 1.0 || octave::math::isnan (rcon))
1555  {
1556  if (sing_handler)
1557  sing_handler (rcon);
1558  else
1560  }
1561  }
1562 
1563  if (info == 0)
1564  {
1565  retval = b;
1566  double *result = retval.fortran_vec ();
1567 
1568  F77_INT b_nr = octave::to_f77_int (b.rows ());
1569  F77_INT b_nc = octave::to_f77_int (b.cols ());
1570 
1571  char job = 'N';
1572  F77_XFCN (dgetrs, DGETRS, (F77_CONST_CHAR_ARG2 (&job, 1),
1573  nr, b_nc, tmp_data, nr,
1574  pipvt, result, b_nr, tmp_info
1575  F77_CHAR_ARG_LEN (1)));
1576 
1577  info = tmp_info;
1578  }
1579  else
1580  mattype.mark_as_rectangular ();
1581  }
1582  }
1583  else if (typ != MatrixType::Hermitian)
1584  (*current_liboctave_error_handler) ("incorrect matrix type");
1585  }
1586 
1587  return retval;
1588 }
1589 
1590 Matrix
1591 Matrix::solve (MatrixType& mattype, const Matrix& b) const
1592 {
1593  octave_idx_type info;
1594  double rcon;
1595  return solve (mattype, b, info, rcon, nullptr);
1596 }
1597 
1598 Matrix
1599 Matrix::solve (MatrixType& mattype, const Matrix& b,
1600  octave_idx_type& info) const
1601 {
1602  double rcon;
1603  return solve (mattype, b, info, rcon, nullptr);
1604 }
1605 
1606 Matrix
1607 Matrix::solve (MatrixType& mattype, const Matrix& b, octave_idx_type& info,
1608  double& rcon) const
1609 {
1610  return solve (mattype, b, info, rcon, nullptr);
1611 }
1612 
1613 Matrix
1614 Matrix::solve (MatrixType& mattype, const Matrix& b, octave_idx_type& info,
1615  double& rcon, solve_singularity_handler sing_handler,
1616  bool singular_fallback, blas_trans_type transt) const
1617 {
1618  Matrix retval;
1619  int typ = mattype.type ();
1620 
1621  if (typ == MatrixType::Unknown)
1622  typ = mattype.type (*this);
1623 
1624  // Only calculate the condition number for LU/Cholesky
1625  if (typ == MatrixType::Upper || typ == MatrixType::Permuted_Upper)
1626  retval = utsolve (mattype, b, info, rcon, sing_handler, true, transt);
1627  else if (typ == MatrixType::Lower || typ == MatrixType::Permuted_Lower)
1628  retval = ltsolve (mattype, b, info, rcon, sing_handler, true, transt);
1629  else if (transt == blas_trans || transt == blas_conj_trans)
1630  return transpose ().solve (mattype, b, info, rcon, sing_handler,
1631  singular_fallback);
1632  else if (typ == MatrixType::Full || typ == MatrixType::Hermitian)
1633  retval = fsolve (mattype, b, info, rcon, sing_handler, true);
1634  else if (typ != MatrixType::Rectangular)
1635  (*current_liboctave_error_handler) ("unknown matrix type");
1636 
1637  // Rectangular or one of the above solvers flags a singular matrix
1638  if (singular_fallback && mattype.type () == MatrixType::Rectangular)
1639  {
1640  octave_idx_type rank;
1641  retval = lssolve (b, info, rank, rcon);
1642  }
1643 
1644  return retval;
1645 }
1646 
1648 Matrix::solve (MatrixType& mattype, const ComplexMatrix& b) const
1649 {
1650  octave_idx_type info;
1651  double rcon;
1652  return solve (mattype, b, info, rcon, nullptr);
1653 }
1654 
1657  octave_idx_type& info) const
1658 {
1659  double rcon;
1660  return solve (mattype, b, info, rcon, nullptr);
1661 }
1662 
1665  octave_idx_type& info, double& rcon) const
1666 {
1667  return solve (mattype, b, info, rcon, nullptr);
1668 }
1669 
1670 static Matrix
1671 stack_complex_matrix (const ComplexMatrix& cm)
1672 {
1673  octave_idx_type m = cm.rows ();
1674  octave_idx_type n = cm.cols ();
1675  octave_idx_type nel = m*n;
1676  Matrix retval (m, 2*n);
1677  const Complex *cmd = cm.data ();
1678  double *rd = retval.fortran_vec ();
1679  for (octave_idx_type i = 0; i < nel; i++)
1680  {
1681  rd[i] = std::real (cmd[i]);
1682  rd[nel+i] = std::imag (cmd[i]);
1683  }
1684  return retval;
1685 }
1686 
1687 static ComplexMatrix
1688 unstack_complex_matrix (const Matrix& sm)
1689 {
1690  octave_idx_type m = sm.rows ();
1691  octave_idx_type n = sm.cols () / 2;
1692  octave_idx_type nel = m*n;
1693  ComplexMatrix retval (m, n);
1694  const double *smd = sm.data ();
1695  Complex *rd = retval.fortran_vec ();
1696  for (octave_idx_type i = 0; i < nel; i++)
1697  rd[i] = Complex (smd[i], smd[nel+i]);
1698  return retval;
1699 }
1700 
1703  octave_idx_type& info, double& rcon,
1704  solve_singularity_handler sing_handler,
1705  bool singular_fallback, blas_trans_type transt) const
1706 {
1707  Matrix tmp = stack_complex_matrix (b);
1708  tmp = solve (mattype, tmp, info, rcon, sing_handler, singular_fallback,
1709  transt);
1710  return unstack_complex_matrix (tmp);
1711 }
1712 
1714 Matrix::solve (MatrixType& mattype, const ColumnVector& b) const
1715 {
1716  octave_idx_type info; double rcon;
1717  return solve (mattype, b, info, rcon);
1718 }
1719 
1722  octave_idx_type& info) const
1723 {
1724  double rcon;
1725  return solve (mattype, b, info, rcon);
1726 }
1727 
1730  octave_idx_type& info, double& rcon) const
1731 {
1732  return solve (mattype, b, info, rcon, nullptr);
1733 }
1734 
1737  octave_idx_type& info, double& rcon,
1738  solve_singularity_handler sing_handler,
1739  blas_trans_type transt) const
1740 {
1741  Matrix tmp (b);
1742  tmp = solve (mattype, tmp, info, rcon, sing_handler, true, transt);
1743  return tmp.column (static_cast<octave_idx_type> (0));
1744 }
1745 
1748 {
1749  ComplexMatrix tmp (*this);
1750  return tmp.solve (mattype, b);
1751 }
1752 
1755  octave_idx_type& info) const
1756 {
1757  ComplexMatrix tmp (*this);
1758  return tmp.solve (mattype, b, info);
1759 }
1760 
1763  octave_idx_type& info, double& rcon) const
1764 {
1765  ComplexMatrix tmp (*this);
1766  return tmp.solve (mattype, b, info, rcon);
1767 }
1768 
1771  octave_idx_type& info, double& rcon,
1772  solve_singularity_handler sing_handler,
1773  blas_trans_type transt) const
1774 {
1775  ComplexMatrix tmp (*this);
1776  return tmp.solve (mattype, b, info, rcon, sing_handler, transt);
1777 }
1778 
1779 Matrix
1780 Matrix::solve (const Matrix& b) const
1781 {
1782  octave_idx_type info;
1783  double rcon;
1784  return solve (b, info, rcon, nullptr);
1785 }
1786 
1787 Matrix
1788 Matrix::solve (const Matrix& b, octave_idx_type& info) const
1789 {
1790  double rcon;
1791  return solve (b, info, rcon, nullptr);
1792 }
1793 
1794 Matrix
1795 Matrix::solve (const Matrix& b, octave_idx_type& info, double& rcon) const
1796 {
1797  return solve (b, info, rcon, nullptr);
1798 }
1799 
1800 Matrix
1802  double& rcon, solve_singularity_handler sing_handler,
1803  blas_trans_type transt) const
1804 {
1805  MatrixType mattype (*this);
1806  return solve (mattype, b, info, rcon, sing_handler, true, transt);
1807 }
1808 
1811 {
1812  ComplexMatrix tmp (*this);
1813  return tmp.solve (b);
1814 }
1815 
1818 {
1819  ComplexMatrix tmp (*this);
1820  return tmp.solve (b, info);
1821 }
1822 
1825  double& rcon) const
1826 {
1827  ComplexMatrix tmp (*this);
1828  return tmp.solve (b, info, rcon);
1829 }
1830 
1832 Matrix::solve (const ComplexMatrix& b, octave_idx_type& info, double& rcon,
1833  solve_singularity_handler sing_handler,
1834  blas_trans_type transt) const
1835 {
1836  ComplexMatrix tmp (*this);
1837  return tmp.solve (b, info, rcon, sing_handler, transt);
1838 }
1839 
1841 Matrix::solve (const ColumnVector& b) const
1842 {
1843  octave_idx_type info; double rcon;
1844  return solve (b, info, rcon);
1845 }
1846 
1849 {
1850  double rcon;
1851  return solve (b, info, rcon);
1852 }
1853 
1855 Matrix::solve (const ColumnVector& b, octave_idx_type& info, double& rcon) const
1856 {
1857  return solve (b, info, rcon, nullptr);
1858 }
1859 
1861 Matrix::solve (const ColumnVector& b, octave_idx_type& info, double& rcon,
1862  solve_singularity_handler sing_handler,
1863  blas_trans_type transt) const
1864 {
1865  MatrixType mattype (*this);
1866  return solve (mattype, b, info, rcon, sing_handler, transt);
1867 }
1868 
1871 {
1872  ComplexMatrix tmp (*this);
1873  return tmp.solve (b);
1874 }
1875 
1878 {
1879  ComplexMatrix tmp (*this);
1880  return tmp.solve (b, info);
1881 }
1882 
1885  double& rcon) const
1886 {
1887  ComplexMatrix tmp (*this);
1888  return tmp.solve (b, info, rcon);
1889 }
1890 
1893  double& rcon,
1894  solve_singularity_handler sing_handler,
1895  blas_trans_type transt) const
1896 {
1897  ComplexMatrix tmp (*this);
1898  return tmp.solve (b, info, rcon, sing_handler, transt);
1899 }
1900 
1901 Matrix
1902 Matrix::lssolve (const Matrix& b) const
1903 {
1904  octave_idx_type info;
1905  octave_idx_type rank;
1906  double rcon;
1907  return lssolve (b, info, rank, rcon);
1908 }
1909 
1910 Matrix
1911 Matrix::lssolve (const Matrix& b, octave_idx_type& info) const
1912 {
1913  octave_idx_type rank;
1914  double rcon;
1915  return lssolve (b, info, rank, rcon);
1916 }
1917 
1918 Matrix
1920  octave_idx_type& rank) const
1921 {
1922  double rcon;
1923  return lssolve (b, info, rank, rcon);
1924 }
1925 
1926 Matrix
1928  octave_idx_type& rank, double& rcon) const
1929 {
1930  Matrix retval;
1931 
1932  F77_INT m = octave::to_f77_int (rows ());
1933  F77_INT n = octave::to_f77_int (cols ());
1934 
1935  F77_INT b_nr = octave::to_f77_int (b.rows ());
1936  F77_INT b_nc = octave::to_f77_int (b.cols ());
1937  F77_INT nrhs = b_nc; // alias for code readability
1938 
1939  if (m != b_nr)
1940  (*current_liboctave_error_handler)
1941  ("matrix dimension mismatch solution of linear equations");
1942 
1943  if (m == 0 || n == 0 || b_nc == 0)
1944  retval = Matrix (n, b_nc, 0.0);
1945  else
1946  {
1947  volatile F77_INT minmn = (m < n ? m : n);
1948  F77_INT maxmn = (m > n ? m : n);
1949  rcon = -1.0;
1950  if (m != n)
1951  {
1952  retval = Matrix (maxmn, nrhs, 0.0);
1953 
1954  for (F77_INT j = 0; j < nrhs; j++)
1955  for (F77_INT i = 0; i < m; i++)
1956  retval.elem (i, j) = b.elem (i, j);
1957  }
1958  else
1959  retval = b;
1960 
1961  Matrix atmp = *this;
1962  double *tmp_data = atmp.fortran_vec ();
1963 
1964  double *pretval = retval.fortran_vec ();
1965  Array<double> s (dim_vector (minmn, 1));
1966  double *ps = s.fortran_vec ();
1967 
1968  // Ask DGELSD what the dimension of WORK should be.
1969  F77_INT lwork = -1;
1970 
1971  Array<double> work (dim_vector (1, 1));
1972 
1973  F77_INT smlsiz;
1974  F77_FUNC (xilaenv, XILAENV) (9, F77_CONST_CHAR_ARG2 ("DGELSD", 6),
1975  F77_CONST_CHAR_ARG2 (" ", 1),
1976  0, 0, 0, 0, smlsiz
1977  F77_CHAR_ARG_LEN (6)
1978  F77_CHAR_ARG_LEN (1));
1979 
1980  F77_INT mnthr;
1981  F77_FUNC (xilaenv, XILAENV) (6, F77_CONST_CHAR_ARG2 ("DGELSD", 6),
1982  F77_CONST_CHAR_ARG2 (" ", 1),
1983  m, n, nrhs, -1, mnthr
1984  F77_CHAR_ARG_LEN (6)
1985  F77_CHAR_ARG_LEN (1));
1986 
1987  // We compute the size of iwork because DGELSD in older versions
1988  // of LAPACK does not return it on a query call.
1989  double dminmn = static_cast<double> (minmn);
1990  double dsmlsizp1 = static_cast<double> (smlsiz+1);
1991  double tmp = octave::math::log2 (dminmn / dsmlsizp1);
1992 
1993  F77_INT nlvl = static_cast<F77_INT> (tmp) + 1;
1994  if (nlvl < 0)
1995  nlvl = 0;
1996 
1997  F77_INT liwork = 3 * minmn * nlvl + 11 * minmn;
1998  if (liwork < 1)
1999  liwork = 1;
2000  Array<F77_INT> iwork (dim_vector (liwork, 1));
2001  F77_INT *piwork = iwork.fortran_vec ();
2002 
2003  F77_INT tmp_info = 0;
2004  F77_INT tmp_rank = 0;
2005 
2006  F77_XFCN (dgelsd, DGELSD, (m, n, nrhs, tmp_data, m, pretval, maxmn,
2007  ps, rcon, tmp_rank, work.fortran_vec (),
2008  lwork, piwork, tmp_info));
2009 
2010  info = tmp_info;
2011  rank = tmp_rank;
2012 
2013  // The workspace query is broken in at least LAPACK 3.0.0
2014  // through 3.1.1 when n >= mnthr. The obtuse formula below
2015  // should provide sufficient workspace for DGELSD to operate
2016  // efficiently.
2017  if (n > m && n >= mnthr)
2018  {
2019  const F77_INT wlalsd
2020  = 9*m + 2*m*smlsiz + 8*m*nlvl + m*nrhs + (smlsiz+1)*(smlsiz+1);
2021 
2022  F77_INT addend = m;
2023 
2024  if (2*m-4 > addend)
2025  addend = 2*m-4;
2026 
2027  if (nrhs > addend)
2028  addend = nrhs;
2029 
2030  if (n-3*m > addend)
2031  addend = n-3*m;
2032 
2033  if (wlalsd > addend)
2034  addend = wlalsd;
2035 
2036  const F77_INT lworkaround = 4*m + m*m + addend;
2037 
2038  if (work(0) < lworkaround)
2039  work(0) = lworkaround;
2040  }
2041  else if (m >= n)
2042  {
2043  F77_INT lworkaround
2044  = 12*n + 2*n*smlsiz + 8*n*nlvl + n*nrhs + (smlsiz+1)*(smlsiz+1);
2045 
2046  if (work(0) < lworkaround)
2047  work(0) = lworkaround;
2048  }
2049 
2050  lwork = static_cast<F77_INT> (work(0));
2051  work.resize (dim_vector (lwork, 1));
2052 
2053  double anorm = norm1 (*this);
2054 
2055  if (octave::math::isinf (anorm))
2056  {
2057  rcon = 0.0;
2058  retval = Matrix (n, b_nc, 0.0);
2059  }
2060  else if (octave::math::isnan (anorm))
2061  {
2063  retval = Matrix (n, b_nc, octave::numeric_limits<double>::NaN ());
2064  }
2065  else
2066  {
2067  F77_XFCN (dgelsd, DGELSD, (m, n, nrhs, tmp_data, m, pretval,
2068  maxmn, ps, rcon, tmp_rank,
2069  work.fortran_vec (), lwork,
2070  piwork, tmp_info));
2071 
2072  info = tmp_info;
2073  rank = tmp_rank;
2074 
2075  if (s.elem (0) == 0.0)
2076  rcon = 0.0;
2077  else
2078  rcon = s.elem (minmn - 1) / s.elem (0);
2079 
2080  retval.resize (n, nrhs);
2081  }
2082  }
2083 
2084  return retval;
2085 }
2086 
2089 {
2090  ComplexMatrix tmp (*this);
2091  octave_idx_type info;
2092  octave_idx_type rank;
2093  double rcon;
2094  return tmp.lssolve (b, info, rank, rcon);
2095 }
2096 
2099 {
2100  ComplexMatrix tmp (*this);
2101  octave_idx_type rank;
2102  double rcon;
2103  return tmp.lssolve (b, info, rank, rcon);
2104 }
2105 
2108  octave_idx_type& rank) const
2109 {
2110  ComplexMatrix tmp (*this);
2111  double rcon;
2112  return tmp.lssolve (b, info, rank, rcon);
2113 }
2114 
2117  octave_idx_type& rank, double& rcon) const
2118 {
2119  ComplexMatrix tmp (*this);
2120  return tmp.lssolve (b, info, rank, rcon);
2121 }
2122 
2125 {
2126  octave_idx_type info;
2127  octave_idx_type rank;
2128  double rcon;
2129  return lssolve (b, info, rank, rcon);
2130 }
2131 
2134 {
2135  octave_idx_type rank;
2136  double rcon;
2137  return lssolve (b, info, rank, rcon);
2138 }
2139 
2142  octave_idx_type& rank) const
2143 {
2144  double rcon;
2145  return lssolve (b, info, rank, rcon);
2146 }
2147 
2150  octave_idx_type& rank, double& rcon) const
2151 {
2152  ColumnVector retval;
2153 
2154  F77_INT nrhs = 1;
2155 
2156  F77_INT m = octave::to_f77_int (rows ());
2157  F77_INT n = octave::to_f77_int (cols ());
2158 
2159  F77_INT b_nel = octave::to_f77_int (b.numel ());
2160 
2161  if (m != b_nel)
2162  (*current_liboctave_error_handler)
2163  ("matrix dimension mismatch solution of linear equations");
2164 
2165  if (m == 0 || n == 0)
2166  retval = ColumnVector (n, 0.0);
2167  else
2168  {
2169  volatile F77_INT minmn = (m < n ? m : n);
2170  F77_INT maxmn = (m > n ? m : n);
2171  rcon = -1.0;
2172 
2173  if (m != n)
2174  {
2175  retval = ColumnVector (maxmn, 0.0);
2176 
2177  for (F77_INT i = 0; i < m; i++)
2178  retval.elem (i) = b.elem (i);
2179  }
2180  else
2181  retval = b;
2182 
2183  Matrix atmp = *this;
2184  double *tmp_data = atmp.fortran_vec ();
2185 
2186  double *pretval = retval.fortran_vec ();
2187  Array<double> s (dim_vector (minmn, 1));
2188  double *ps = s.fortran_vec ();
2189 
2190  // Ask DGELSD what the dimension of WORK should be.
2191  F77_INT lwork = -1;
2192 
2193  Array<double> work (dim_vector (1, 1));
2194 
2195  F77_INT smlsiz;
2196  F77_FUNC (xilaenv, XILAENV) (9, F77_CONST_CHAR_ARG2 ("DGELSD", 6),
2197  F77_CONST_CHAR_ARG2 (" ", 1),
2198  0, 0, 0, 0, smlsiz
2199  F77_CHAR_ARG_LEN (6)
2200  F77_CHAR_ARG_LEN (1));
2201 
2202  // We compute the size of iwork because DGELSD in older versions
2203  // of LAPACK does not return it on a query call.
2204  double dminmn = static_cast<double> (minmn);
2205  double dsmlsizp1 = static_cast<double> (smlsiz+1);
2206  double tmp = octave::math::log2 (dminmn / dsmlsizp1);
2207 
2208  F77_INT nlvl = static_cast<F77_INT> (tmp) + 1;
2209  if (nlvl < 0)
2210  nlvl = 0;
2211 
2212  F77_INT liwork = 3 * minmn * nlvl + 11 * minmn;
2213  if (liwork < 1)
2214  liwork = 1;
2215  Array<F77_INT> iwork (dim_vector (liwork, 1));
2216  F77_INT *piwork = iwork.fortran_vec ();
2217 
2218  F77_INT tmp_info = 0;
2219  F77_INT tmp_rank = 0;
2220 
2221  F77_XFCN (dgelsd, DGELSD, (m, n, nrhs, tmp_data, m, pretval, maxmn,
2222  ps, rcon, tmp_rank, work.fortran_vec (),
2223  lwork, piwork, tmp_info));
2224 
2225  info = tmp_info;
2226  rank = tmp_rank;
2227 
2228  lwork = static_cast<F77_INT> (work(0));
2229  work.resize (dim_vector (lwork, 1));
2230 
2231  F77_XFCN (dgelsd, DGELSD, (m, n, nrhs, tmp_data, m, pretval,
2232  maxmn, ps, rcon, tmp_rank,
2233  work.fortran_vec (), lwork,
2234  piwork, tmp_info));
2235 
2236  info = tmp_info;
2237  rank = tmp_rank;
2238 
2239  if (rank < minmn)
2240  {
2241  if (s.elem (0) == 0.0)
2242  rcon = 0.0;
2243  else
2244  rcon = s.elem (minmn - 1) / s.elem (0);
2245  }
2246 
2247  retval.resize (n);
2248  }
2249 
2250  return retval;
2251 }
2252 
2255 {
2256  ComplexMatrix tmp (*this);
2257  octave_idx_type info;
2258  octave_idx_type rank;
2259  double rcon;
2260  return tmp.lssolve (b, info, rank, rcon);
2261 }
2262 
2265 {
2266  ComplexMatrix tmp (*this);
2267  octave_idx_type rank;
2268  double rcon;
2269  return tmp.lssolve (b, info, rank, rcon);
2270 }
2271 
2274  octave_idx_type& rank) const
2275 {
2276  ComplexMatrix tmp (*this);
2277  double rcon;
2278  return tmp.lssolve (b, info, rank, rcon);
2279 }
2280 
2283  octave_idx_type& rank, double& rcon) const
2284 {
2285  ComplexMatrix tmp (*this);
2286  return tmp.lssolve (b, info, rank, rcon);
2287 }
2288 
2289 Matrix&
2291 {
2292  octave_idx_type nr = rows ();
2293  octave_idx_type nc = cols ();
2294 
2295  octave_idx_type a_nr = a.rows ();
2296  octave_idx_type a_nc = a.cols ();
2297 
2298  if (nr != a_nr || nc != a_nc)
2299  octave::err_nonconformant ("operator +=", nr, nc, a_nr, a_nc);
2300 
2301  for (octave_idx_type i = 0; i < a.length (); i++)
2302  elem (i, i) += a.elem (i, i);
2303 
2304  return *this;
2305 }
2306 
2307 Matrix&
2309 {
2310  octave_idx_type nr = rows ();
2311  octave_idx_type nc = cols ();
2312 
2313  octave_idx_type a_nr = a.rows ();
2314  octave_idx_type a_nc = a.cols ();
2315 
2316  if (nr != a_nr || nc != a_nc)
2317  octave::err_nonconformant ("operator -=", nr, nc, a_nr, a_nc);
2318 
2319  for (octave_idx_type i = 0; i < a.length (); i++)
2320  elem (i, i) -= a.elem (i, i);
2321 
2322  return *this;
2323 }
2324 
2325 // unary operations
2326 
2327 // column vector by row vector -> matrix operations
2328 
2329 Matrix
2331 {
2332  Matrix retval;
2333 
2334  F77_INT len = octave::to_f77_int (v.numel ());
2335 
2336  if (len != 0)
2337  {
2338  F77_INT a_len = octave::to_f77_int (a.numel ());
2339 
2340  retval = Matrix (len, a_len);
2341  double *c = retval.fortran_vec ();
2342 
2343  F77_XFCN (dgemm, DGEMM, (F77_CONST_CHAR_ARG2 ("N", 1),
2344  F77_CONST_CHAR_ARG2 ("N", 1),
2345  len, a_len, 1, 1.0, v.data (), len,
2346  a.data (), 1, 0.0, c, len
2347  F77_CHAR_ARG_LEN (1)
2348  F77_CHAR_ARG_LEN (1)));
2349  }
2350 
2351  return retval;
2352 }
2353 
2354 // other operations.
2355 
2356 // FIXME: Do these really belong here? Maybe they should be in a base class?
2357 
2358 boolMatrix
2359 Matrix::all (int dim) const
2360 {
2361  return NDArray::all (dim);
2362 }
2363 
2364 boolMatrix
2365 Matrix::any (int dim) const
2366 {
2367  return NDArray::any (dim);
2368 }
2369 
2370 Matrix
2371 Matrix::cumprod (int dim) const
2372 {
2373  return NDArray::cumprod (dim);
2374 }
2375 
2376 Matrix
2377 Matrix::cumsum (int dim) const
2378 {
2379  return NDArray::cumsum (dim);
2380 }
2381 
2382 Matrix
2383 Matrix::prod (int dim) const
2384 {
2385  return NDArray::prod (dim);
2386 }
2387 
2388 Matrix
2389 Matrix::sum (int dim) const
2390 {
2391  return NDArray::sum (dim);
2392 }
2393 
2394 Matrix
2395 Matrix::sumsq (int dim) const
2396 {
2397  return NDArray::sumsq (dim);
2398 }
2399 
2400 Matrix
2401 Matrix::abs () const
2402 {
2403  return NDArray::abs ();
2404 }
2405 
2406 Matrix
2408 {
2409  return NDArray::diag (k);
2410 }
2411 
2412 DiagMatrix
2414 {
2415  DiagMatrix retval;
2416 
2417  octave_idx_type nr = rows ();
2418  octave_idx_type nc = cols ();
2419 
2420  if (nr == 1 || nc == 1)
2421  retval = DiagMatrix (*this, m, n);
2422  else
2423  (*current_liboctave_error_handler) ("diag: expecting vector argument");
2424 
2425  return retval;
2426 }
2427 
2430 {
2431  Array<octave_idx_type> dummy_idx;
2432  return row_min (dummy_idx);
2433 }
2434 
2437 {
2438  ColumnVector result;
2439 
2440  octave_idx_type nr = rows ();
2441  octave_idx_type nc = cols ();
2442 
2443  if (nr > 0 && nc > 0)
2444  {
2445  result.resize (nr);
2446  idx_arg.resize (dim_vector (nr, 1));
2447 
2448  for (octave_idx_type i = 0; i < nr; i++)
2449  {
2450  octave_idx_type idx_j;
2451 
2452  double tmp_min = octave::numeric_limits<double>::NaN ();
2453 
2454  for (idx_j = 0; idx_j < nc; idx_j++)
2455  {
2456  tmp_min = elem (i, idx_j);
2457 
2458  if (! octave::math::isnan (tmp_min))
2459  break;
2460  }
2461 
2462  for (octave_idx_type j = idx_j+1; j < nc; j++)
2463  {
2464  double tmp = elem (i, j);
2465 
2466  if (octave::math::isnan (tmp))
2467  continue;
2468  else if (tmp < tmp_min)
2469  {
2470  idx_j = j;
2471  tmp_min = tmp;
2472  }
2473  }
2474 
2475  result.elem (i) = tmp_min;
2476  idx_arg.elem (i) = (octave::math::isnan (tmp_min) ? 0 : idx_j);
2477  }
2478  }
2479 
2480  return result;
2481 }
2482 
2485 {
2486  Array<octave_idx_type> dummy_idx;
2487  return row_max (dummy_idx);
2488 }
2489 
2492 {
2493  ColumnVector result;
2494 
2495  octave_idx_type nr = rows ();
2496  octave_idx_type nc = cols ();
2497 
2498  if (nr > 0 && nc > 0)
2499  {
2500  result.resize (nr);
2501  idx_arg.resize (dim_vector (nr, 1));
2502 
2503  for (octave_idx_type i = 0; i < nr; i++)
2504  {
2505  octave_idx_type idx_j;
2506 
2507  double tmp_max = octave::numeric_limits<double>::NaN ();
2508 
2509  for (idx_j = 0; idx_j < nc; idx_j++)
2510  {
2511  tmp_max = elem (i, idx_j);
2512 
2513  if (! octave::math::isnan (tmp_max))
2514  break;
2515  }
2516 
2517  for (octave_idx_type j = idx_j+1; j < nc; j++)
2518  {
2519  double tmp = elem (i, j);
2520 
2521  if (octave::math::isnan (tmp))
2522  continue;
2523  else if (tmp > tmp_max)
2524  {
2525  idx_j = j;
2526  tmp_max = tmp;
2527  }
2528  }
2529 
2530  result.elem (i) = tmp_max;
2531  idx_arg.elem (i) = (octave::math::isnan (tmp_max) ? 0 : idx_j);
2532  }
2533  }
2534 
2535  return result;
2536 }
2537 
2538 RowVector
2540 {
2541  Array<octave_idx_type> dummy_idx;
2542  return column_min (dummy_idx);
2543 }
2544 
2545 RowVector
2547 {
2548  RowVector result;
2549 
2550  octave_idx_type nr = rows ();
2551  octave_idx_type nc = cols ();
2552 
2553  if (nr > 0 && nc > 0)
2554  {
2555  result.resize (nc);
2556  idx_arg.resize (dim_vector (1, nc));
2557 
2558  for (octave_idx_type j = 0; j < nc; j++)
2559  {
2560  octave_idx_type idx_i;
2561 
2562  double tmp_min = octave::numeric_limits<double>::NaN ();
2563 
2564  for (idx_i = 0; idx_i < nr; idx_i++)
2565  {
2566  tmp_min = elem (idx_i, j);
2567 
2568  if (! octave::math::isnan (tmp_min))
2569  break;
2570  }
2571 
2572  for (octave_idx_type i = idx_i+1; i < nr; i++)
2573  {
2574  double tmp = elem (i, j);
2575 
2576  if (octave::math::isnan (tmp))
2577  continue;
2578  else if (tmp < tmp_min)
2579  {
2580  idx_i = i;
2581  tmp_min = tmp;
2582  }
2583  }
2584 
2585  result.elem (j) = tmp_min;
2586  idx_arg.elem (j) = (octave::math::isnan (tmp_min) ? 0 : idx_i);
2587  }
2588  }
2589 
2590  return result;
2591 }
2592 
2593 RowVector
2595 {
2596  Array<octave_idx_type> dummy_idx;
2597  return column_max (dummy_idx);
2598 }
2599 
2600 RowVector
2602 {
2603  RowVector result;
2604 
2605  octave_idx_type nr = rows ();
2606  octave_idx_type nc = cols ();
2607 
2608  if (nr > 0 && nc > 0)
2609  {
2610  result.resize (nc);
2611  idx_arg.resize (dim_vector (1, nc));
2612 
2613  for (octave_idx_type j = 0; j < nc; j++)
2614  {
2615  octave_idx_type idx_i;
2616 
2617  double tmp_max = octave::numeric_limits<double>::NaN ();
2618 
2619  for (idx_i = 0; idx_i < nr; idx_i++)
2620  {
2621  tmp_max = elem (idx_i, j);
2622 
2623  if (! octave::math::isnan (tmp_max))
2624  break;
2625  }
2626 
2627  for (octave_idx_type i = idx_i+1; i < nr; i++)
2628  {
2629  double tmp = elem (i, j);
2630 
2631  if (octave::math::isnan (tmp))
2632  continue;
2633  else if (tmp > tmp_max)
2634  {
2635  idx_i = i;
2636  tmp_max = tmp;
2637  }
2638  }
2639 
2640  result.elem (j) = tmp_max;
2641  idx_arg.elem (j) = (octave::math::isnan (tmp_max) ? 0 : idx_i);
2642  }
2643  }
2644 
2645  return result;
2646 }
2647 
2648 std::ostream&
2649 operator << (std::ostream& os, const Matrix& a)
2650 {
2651  for (octave_idx_type i = 0; i < a.rows (); i++)
2652  {
2653  for (octave_idx_type j = 0; j < a.cols (); j++)
2654  {
2655  os << ' ';
2656  octave::write_value<double> (os, a.elem (i, j));
2657  }
2658  os << "\n";
2659  }
2660  return os;
2661 }
2662 
2663 std::istream&
2664 operator >> (std::istream& is, Matrix& a)
2665 {
2666  octave_idx_type nr = a.rows ();
2667  octave_idx_type nc = a.cols ();
2668 
2669  if (nr > 0 && nc > 0)
2670  {
2671  double tmp;
2672  for (octave_idx_type i = 0; i < nr; i++)
2673  for (octave_idx_type j = 0; j < nc; j++)
2674  {
2675  tmp = octave::read_value<double> (is);
2676  if (is)
2677  a.elem (i, j) = tmp;
2678  else
2679  return is;
2680  }
2681  }
2682 
2683  return is;
2684 }
2685 
2686 Matrix
2687 Givens (double x, double y)
2688 {
2689  double cc, s, temp_r;
2690 
2691  F77_FUNC (dlartg, DLARTG) (x, y, cc, s, temp_r);
2692 
2693  Matrix g (2, 2);
2694 
2695  g.elem (0, 0) = cc;
2696  g.elem (1, 1) = cc;
2697  g.elem (0, 1) = s;
2698  g.elem (1, 0) = -s;
2699 
2700  return g;
2701 }
2702 
2703 Matrix
2704 Sylvester (const Matrix& a, const Matrix& b, const Matrix& c)
2705 {
2706  Matrix retval;
2707 
2708  // FIXME: need to check that a, b, and c are all the same size.
2709 
2710  // Compute Schur decompositions.
2711 
2712  octave::math::schur<Matrix> as (a, "U");
2713  octave::math::schur<Matrix> bs (b, "U");
2714 
2715  // Transform c to new coordinates.
2716 
2717  Matrix ua = as.unitary_schur_matrix ();
2718  Matrix sch_a = as.schur_matrix ();
2719 
2720  Matrix ub = bs.unitary_schur_matrix ();
2721  Matrix sch_b = bs.schur_matrix ();
2722 
2723  Matrix cx = ua.transpose () * c * ub;
2724 
2725  // Solve the sylvester equation, back-transform, and return the solution.
2726 
2727  F77_INT a_nr = octave::to_f77_int (a.rows ());
2728  F77_INT b_nr = octave::to_f77_int (b.rows ());
2729 
2730  double scale;
2731  F77_INT info;
2732 
2733  double *pa = sch_a.fortran_vec ();
2734  double *pb = sch_b.fortran_vec ();
2735  double *px = cx.fortran_vec ();
2736 
2737  F77_XFCN (dtrsyl, DTRSYL, (F77_CONST_CHAR_ARG2 ("N", 1),
2738  F77_CONST_CHAR_ARG2 ("N", 1),
2739  1, a_nr, b_nr, pa, a_nr, pb,
2740  b_nr, px, a_nr, scale, info
2741  F77_CHAR_ARG_LEN (1)
2742  F77_CHAR_ARG_LEN (1)));
2743 
2744  // FIXME: check info?
2745 
2746  retval = ua*cx*ub.transpose ();
2747 
2748  return retval;
2749 }
2750 
2751 // matrix by matrix -> matrix operations
2752 
2753 /*
2754 
2755 ## Simple Dot Product, Matrix-Vector and Matrix-Matrix Unit tests
2756 %!assert ([1 2 3] * [ 4 ; 5 ; 6], 32, 1e-14)
2757 %!assert ([1 2 ; 3 4 ] * [5 ; 6], [17 ; 39 ], 1e-14)
2758 %!assert ([1 2 ; 3 4 ] * [5 6 ; 7 8], [19 22; 43 50], 1e-14)
2759 
2760 ## Test some simple identities
2761 %!shared M, cv, rv, Mt, rvt
2762 %! M = randn (10,10) + 100*eye (10,10);
2763 %! Mt = M';
2764 %! cv = randn (10,1);
2765 %! rv = randn (1,10);
2766 %! rvt = rv';
2767 %!assert ([M*cv,M*cv], M*[cv,cv], 2e-13)
2768 %!assert ([M'*cv,M'*cv], M'*[cv,cv], 2e-13)
2769 %!assert ([rv*M;rv*M], [rv;rv]*M, 2e-13)
2770 %!assert ([rv*M';rv*M'], [rv;rv]*M', 2e-13)
2771 %!assert (2*rv*cv, [rv,rv]*[cv;cv], 2e-13)
2772 %!assert (M'\cv, Mt\cv, 1e-14)
2773 %!assert (M'\rv', Mt\rvt, 1e-14)
2774 
2775 */
2776 
2777 static inline char
2778 get_blas_trans_arg (bool trans)
2779 {
2780  return trans ? 'T' : 'N';
2781 }
2782 
2783 // the general GEMM operation
2784 
2785 Matrix
2786 xgemm (const Matrix& a, const Matrix& b,
2787  blas_trans_type transa, blas_trans_type transb)
2788 {
2789  Matrix retval;
2790 
2791  bool tra = transa != blas_no_trans;
2792  bool trb = transb != blas_no_trans;
2793 
2794  F77_INT a_nr = octave::to_f77_int (tra ? a.cols () : a.rows ());
2795  F77_INT a_nc = octave::to_f77_int (tra ? a.rows () : a.cols ());
2796 
2797  F77_INT b_nr = octave::to_f77_int (trb ? b.cols () : b.rows ());
2798  F77_INT b_nc = octave::to_f77_int (trb ? b.rows () : b.cols ());
2799 
2800  if (a_nc != b_nr)
2801  octave::err_nonconformant ("operator *", a_nr, a_nc, b_nr, b_nc);
2802 
2803  if (a_nr == 0 || a_nc == 0 || b_nc == 0)
2804  retval = Matrix (a_nr, b_nc, 0.0);
2805  else if (a.data () == b.data () && a_nr == b_nc && tra != trb)
2806  {
2807  F77_INT lda = octave::to_f77_int (a.rows ());
2808 
2809  retval = Matrix (a_nr, b_nc);
2810  double *c = retval.fortran_vec ();
2811 
2812  const char ctra = get_blas_trans_arg (tra);
2813  F77_XFCN (dsyrk, DSYRK, (F77_CONST_CHAR_ARG2 ("U", 1),
2814  F77_CONST_CHAR_ARG2 (&ctra, 1),
2815  a_nr, a_nc, 1.0,
2816  a.data (), lda, 0.0, c, a_nr
2817  F77_CHAR_ARG_LEN (1)
2818  F77_CHAR_ARG_LEN (1)));
2819  for (int j = 0; j < a_nr; j++)
2820  for (int i = 0; i < j; i++)
2821  retval.xelem (j, i) = retval.xelem (i, j);
2822 
2823  }
2824  else
2825  {
2826  F77_INT lda = octave::to_f77_int (a.rows ());
2827  F77_INT tda = octave::to_f77_int (a.cols ());
2828  F77_INT ldb = octave::to_f77_int (b.rows ());
2829  F77_INT tdb = octave::to_f77_int (b.cols ());
2830 
2831  retval = Matrix (a_nr, b_nc);
2832  double *c = retval.fortran_vec ();
2833 
2834  if (b_nc == 1)
2835  {
2836  if (a_nr == 1)
2837  F77_FUNC (xddot, XDDOT) (a_nc, a.data (), 1, b.data (), 1, *c);
2838  else
2839  {
2840  const char ctra = get_blas_trans_arg (tra);
2841  F77_XFCN (dgemv, DGEMV, (F77_CONST_CHAR_ARG2 (&ctra, 1),
2842  lda, tda, 1.0, a.data (), lda,
2843  b.data (), 1, 0.0, c, 1
2844  F77_CHAR_ARG_LEN (1)));
2845  }
2846  }
2847  else if (a_nr == 1)
2848  {
2849  const char crevtrb = get_blas_trans_arg (! trb);
2850  F77_XFCN (dgemv, DGEMV, (F77_CONST_CHAR_ARG2 (&crevtrb, 1),
2851  ldb, tdb, 1.0, b.data (), ldb,
2852  a.data (), 1, 0.0, c, 1
2853  F77_CHAR_ARG_LEN (1)));
2854  }
2855  else
2856  {
2857  const char ctra = get_blas_trans_arg (tra);
2858  const char ctrb = get_blas_trans_arg (trb);
2859  F77_XFCN (dgemm, DGEMM, (F77_CONST_CHAR_ARG2 (&ctra, 1),
2860  F77_CONST_CHAR_ARG2 (&ctrb, 1),
2861  a_nr, b_nc, a_nc, 1.0, a.data (),
2862  lda, b.data (), ldb, 0.0, c, a_nr
2863  F77_CHAR_ARG_LEN (1)
2864  F77_CHAR_ARG_LEN (1)));
2865  }
2866  }
2867 
2868  return retval;
2869 }
2870 
2871 Matrix
2872 operator * (const Matrix& a, const Matrix& b)
2873 {
2874  return xgemm (a, b);
2875 }
2876 
2877 // FIXME: it would be nice to share code among the min/max functions below.
2878 
2879 #define EMPTY_RETURN_CHECK(T) \
2880  if (nr == 0 || nc == 0) \
2881  return T (nr, nc);
2882 
2883 Matrix
2884 min (double d, const Matrix& m)
2885 {
2886  octave_idx_type nr = m.rows ();
2887  octave_idx_type nc = m.columns ();
2888 
2890 
2891  Matrix result (nr, nc);
2892 
2893  for (octave_idx_type j = 0; j < nc; j++)
2894  for (octave_idx_type i = 0; i < nr; i++)
2895  {
2896  octave_quit ();
2897  result(i, j) = octave::math::min (d, m(i, j));
2898  }
2899 
2900  return result;
2901 }
2902 
2903 Matrix
2904 min (const Matrix& m, double d)
2905 {
2906  octave_idx_type nr = m.rows ();
2907  octave_idx_type nc = m.columns ();
2908 
2910 
2911  Matrix result (nr, nc);
2912 
2913  for (octave_idx_type j = 0; j < nc; j++)
2914  for (octave_idx_type i = 0; i < nr; i++)
2915  {
2916  octave_quit ();
2917  result(i, j) = octave::math::min (m(i, j), d);
2918  }
2919 
2920  return result;
2921 }
2922 
2923 Matrix
2924 min (const Matrix& a, const Matrix& b)
2925 {
2926  octave_idx_type nr = a.rows ();
2927  octave_idx_type nc = a.columns ();
2928 
2929  if (nr != b.rows () || nc != b.columns ())
2930  (*current_liboctave_error_handler)
2931  ("two-arg min requires same size arguments");
2932 
2934 
2935  Matrix result (nr, nc);
2936 
2937  for (octave_idx_type j = 0; j < nc; j++)
2938  for (octave_idx_type i = 0; i < nr; i++)
2939  {
2940  octave_quit ();
2941  result(i, j) = octave::math::min (a(i, j), b(i, j));
2942  }
2943 
2944  return result;
2945 }
2946 
2947 Matrix
2948 max (double d, const Matrix& m)
2949 {
2950  octave_idx_type nr = m.rows ();
2951  octave_idx_type nc = m.columns ();
2952 
2954 
2955  Matrix result (nr, nc);
2956 
2957  for (octave_idx_type j = 0; j < nc; j++)
2958  for (octave_idx_type i = 0; i < nr; i++)
2959  {
2960  octave_quit ();
2961  result(i, j) = octave::math::max (d, m(i, j));
2962  }
2963 
2964  return result;
2965 }
2966 
2967 Matrix
2968 max (const Matrix& m, double d)
2969 {
2970  octave_idx_type nr = m.rows ();
2971  octave_idx_type nc = m.columns ();
2972 
2974 
2975  Matrix result (nr, nc);
2976 
2977  for (octave_idx_type j = 0; j < nc; j++)
2978  for (octave_idx_type i = 0; i < nr; i++)
2979  {
2980  octave_quit ();
2981  result(i, j) = octave::math::max (m(i, j), d);
2982  }
2983 
2984  return result;
2985 }
2986 
2987 Matrix
2988 max (const Matrix& a, const Matrix& b)
2989 {
2990  octave_idx_type nr = a.rows ();
2991  octave_idx_type nc = a.columns ();
2992 
2993  if (nr != b.rows () || nc != b.columns ())
2994  (*current_liboctave_error_handler)
2995  ("two-arg max requires same size arguments");
2996 
2998 
2999  Matrix result (nr, nc);
3000 
3001  for (octave_idx_type j = 0; j < nc; j++)
3002  for (octave_idx_type i = 0; i < nr; i++)
3003  {
3004  octave_quit ();
3005  result(i, j) = octave::math::max (a(i, j), b(i, j));
3006  }
3007 
3008  return result;
3009 }
3010 
3011 Matrix
3013  const ColumnVector& x2,
3015 
3016 {
3017  octave_idx_type m = x1.numel ();
3018 
3019  if (x2.numel () != m)
3020  (*current_liboctave_error_handler)
3021  ("linspace: vectors must be of equal length");
3022 
3023  Matrix retval;
3024 
3025  if (n < 1)
3026  {
3027  retval.clear (m, 0);
3028  return retval;
3029  }
3030 
3031  retval.clear (m, n);
3032  for (octave_idx_type i = 0; i < m; i++)
3033  retval.insert (linspace (x1(i), x2(i), n), i, 0);
3034 
3035  return retval;
3036 }
3037 
3040 
3043 
base_det< double > DET
Definition: DET.h:86
#define Inf
Definition: Faddeeva.cc:260
#define NaN
Definition: Faddeeva.cc:261
double & elem(octave_idx_type n)
Definition: Array.h:562
T * fortran_vec()
Size of the specified dimension.
Definition: Array-base.cc:1764
Array< double, Alloc > index(const octave::idx_vector &i) const
Indexing without resizing.
Definition: Array-base.cc:710
bool issquare() const
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
Array< T, Alloc > & insert(const Array< T, Alloc > &a, const Array< octave_idx_type > &idx)
Insert an array into another at a specified position.
Definition: Array-base.cc:1608
const double * data() const
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
double & xelem(octave_idx_type n)
Definition: Array.h:524
octave_idx_type numel() const
Number of elements in the array.
Definition: Array.h:414
void resize(octave_idx_type n, const double &rfv=0)
Definition: dColVector.h:114
ColumnVector extract(octave_idx_type r1, octave_idx_type r2) const
Definition: dColVector.cc:151
ComplexMatrix lssolve(const Matrix &b) const
Definition: CMatrix.cc:2220
ComplexMatrix solve(MatrixType &mattype, const Matrix &b) const
Definition: CMatrix.cc:1931
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
int type(bool quiet=true)
Definition: MatrixType.cc:656
void mark_as_rectangular()
Definition: MatrixType.h:155
Definition: dMatrix.h:42
Matrix pseudo_inverse(double tol=0.0) const
Definition: dMatrix.cc:693
Matrix & fill(double val)
Definition: dMatrix.cc:221
Matrix()=default
ComplexMatrix fourier() const
Definition: dMatrix.cc:734
Matrix diag(octave_idx_type k=0) const
Definition: dMatrix.cc:2407
Matrix abs() const
Definition: dMatrix.cc:2401
boolMatrix all(int dim=-1) const
Definition: dMatrix.cc:2359
ComplexMatrix fourier2d() const
Definition: dMatrix.cc:793
Matrix sum(int dim=-1) const
Definition: dMatrix.cc:2389
ComplexMatrix ifourier2d() const
Definition: dMatrix.cc:805
Matrix sumsq(int dim=-1) const
Definition: dMatrix.cc:2395
Matrix & insert(const Matrix &a, octave_idx_type r, octave_idx_type c)
Definition: dMatrix.cc:152
Matrix prod(int dim=-1) const
Definition: dMatrix.cc:2383
RowVector row(octave_idx_type i) const
Definition: dMatrix.cc:416
Matrix stack(const Matrix &a) const
Definition: dMatrix.cc:325
Matrix append(const Matrix &a) const
Definition: dMatrix.cc:265
Matrix extract(octave_idx_type r1, octave_idx_type c1, octave_idx_type r2, octave_idx_type c2) const
Definition: dMatrix.cc:397
DET determinant() const
Definition: dMatrix.cc:858
ComplexMatrix ifourier() const
Definition: dMatrix.cc:763
Matrix transpose() const
Definition: dMatrix.h:140
RowVector column_min() const
Definition: dMatrix.cc:2539
Matrix cumprod(int dim=-1) const
Definition: dMatrix.cc:2371
bool issymmetric() const
Definition: dMatrix.cc:136
RowVector column_max() const
Definition: dMatrix.cc:2594
Matrix extract_n(octave_idx_type r1, octave_idx_type c1, octave_idx_type nr, octave_idx_type nc) const
Definition: dMatrix.cc:407
Matrix & operator+=(const DiagMatrix &a)
Definition: dMatrix.cc:2290
double rcond() const
Definition: dMatrix.cc:1029
boolMatrix any(int dim=-1) const
Definition: dMatrix.cc:2365
Matrix & operator-=(const DiagMatrix &a)
Definition: dMatrix.cc:2308
friend class ComplexMatrix
Definition: dMatrix.h:137
Matrix inverse() const
Definition: dMatrix.cc:451
bool operator==(const Matrix &a) const
Definition: dMatrix.cc:121
Matrix solve(MatrixType &mattype, const Matrix &b) const
Definition: dMatrix.cc:1591
ColumnVector row_min() const
Definition: dMatrix.cc:2429
Matrix cumsum(int dim=-1) const
Definition: dMatrix.cc:2377
bool operator!=(const Matrix &a) const
Definition: dMatrix.cc:130
Matrix lssolve(const Matrix &b) const
Definition: dMatrix.cc:1902
void resize(octave_idx_type nr, octave_idx_type nc, double rfv=0)
Definition: dMatrix.h:158
ColumnVector row_max() const
Definition: dMatrix.cc:2484
ColumnVector column(octave_idx_type i) const
Definition: dMatrix.cc:422
NDArray abs() const
Definition: dNDArray.cc:570
NDArray diag(octave_idx_type k=0) const
Definition: dNDArray.cc:609
NDArray cumsum(int dim=-1) const
Definition: dNDArray.cc:413
NDArray sumsq(int dim=-1) const
Definition: dNDArray.cc:437
NDArray prod(int dim=-1) const
Definition: dNDArray.cc:419
NDArray cumprod(int dim=-1) const
Definition: dNDArray.cc:407
boolNDArray all(int dim=-1) const
Definition: dNDArray.cc:395
boolNDArray any(int dim=-1) const
Definition: dNDArray.cc:401
NDArray sum(int dim=-1) const
Definition: dNDArray.cc:425
octave_idx_type rows() const
Definition: PermMatrix.h:62
const Array< octave_idx_type > & col_perm_vec() const
Definition: PermMatrix.h:83
void resize(octave_idx_type n, const double &rfv=0)
Definition: dRowVector.h:102
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
Matrix imag(const ComplexMatrix &a)
Definition: dMatrix.cc:391
std::ostream & operator<<(std::ostream &os, const Matrix &a)
Definition: dMatrix.cc:2649
Matrix xgemm(const Matrix &a, const Matrix &b, blas_trans_type transa, blas_trans_type transb)
Definition: dMatrix.cc:2786
std::istream & operator>>(std::istream &is, Matrix &a)
Definition: dMatrix.cc:2664
Matrix Givens(double x, double y)
Definition: dMatrix.cc:2687
Matrix max(double d, const Matrix &m)
Definition: dMatrix.cc:2948
Matrix Sylvester(const Matrix &a, const Matrix &b, const Matrix &c)
Definition: dMatrix.cc:2704
Matrix operator*(const ColumnVector &v, const RowVector &a)
Definition: dMatrix.cc:2330
#define EMPTY_RETURN_CHECK(T)
Definition: dMatrix.cc:2879
Matrix linspace(const ColumnVector &x1, const ColumnVector &x2, octave_idx_type n)
Definition: dMatrix.cc:3012
Matrix min(double d, const Matrix &m)
Definition: dMatrix.cc:2884
Matrix real(const ComplexMatrix &a)
Definition: dMatrix.cc:385
#define F77_XFCN(f, F, args)
Definition: f77-fcn.h:45
octave_f77_int_type F77_INT
Definition: f77-fcn.h:306
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)
OCTAVE_NORETURN liboctave_error_handler current_liboctave_error_handler
Definition: lo-error.c:41
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
bool mx_inline_equal(std::size_t n, const T1 *x, const T2 *y)
Definition: mx-inlines.cc:577
void mx_inline_real(std::size_t n, T *r, const std::complex< T > *x)
Definition: mx-inlines.cc:325
void mx_inline_imag(std::size_t n, T *r, const std::complex< T > *x)
Definition: mx-inlines.cc:333
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
subroutine xddot(n, dx, incx, dy, incy, retval)
Definition: xddot.f:2
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