dMatrix.cc

Go to the documentation of this file.
00001 // Matrix manipulations.
00002 /*
00003 
00004 Copyright (C) 1994-2012 John W. Eaton
00005 Copyright (C) 2008 Jaroslav Hajek
00006 Copyright (C) 2009 VZLU Prague, a.s.
00007 
00008 This file is part of Octave.
00009 
00010 Octave is free software; you can redistribute it and/or modify it
00011 under the terms of the GNU General Public License as published by the
00012 Free Software Foundation; either version 3 of the License, or (at your
00013 option) any later version.
00014 
00015 Octave is distributed in the hope that it will be useful, but WITHOUT
00016 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00017 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00018 for more details.
00019 
00020 You should have received a copy of the GNU General Public License
00021 along with Octave; see the file COPYING.  If not, see
00022 <http://www.gnu.org/licenses/>.
00023 
00024 */
00025 
00026 #ifdef HAVE_CONFIG_H
00027 #include <config.h>
00028 #endif
00029 
00030 #include <cfloat>
00031 
00032 #include <iostream>
00033 #include <vector>
00034 
00035 #include "Array-util.h"
00036 #include "byte-swap.h"
00037 #include "dMatrix.h"
00038 #include "dbleAEPBAL.h"
00039 #include "DET.h"
00040 #include "dbleSCHUR.h"
00041 #include "dbleSVD.h"
00042 #include "dbleCHOL.h"
00043 #include "f77-fcn.h"
00044 #include "functor.h"
00045 #include "lo-error.h"
00046 #include "oct-locbuf.h"
00047 #include "lo-ieee.h"
00048 #include "lo-mappers.h"
00049 #include "lo-utils.h"
00050 #include "mx-base.h"
00051 #include "mx-m-dm.h"
00052 #include "mx-dm-m.h"
00053 #include "mx-inlines.cc"
00054 #include "mx-op-defs.h"
00055 #include "oct-cmplx.h"
00056 #include "oct-fftw.h"
00057 #include "oct-norm.h"
00058 #include "quit.h"
00059 
00060 // Fortran functions we call.
00061 
00062 extern "C"
00063 {
00064   F77_RET_T
00065   F77_FUNC (xilaenv, XILAENV) (const octave_idx_type&,
00066                                F77_CONST_CHAR_ARG_DECL,
00067                                F77_CONST_CHAR_ARG_DECL,
00068                                const octave_idx_type&, const octave_idx_type&,
00069                                const octave_idx_type&, const octave_idx_type&,
00070                                octave_idx_type&
00071                                F77_CHAR_ARG_LEN_DECL
00072                                F77_CHAR_ARG_LEN_DECL);
00073 
00074   F77_RET_T
00075   F77_FUNC (dgebal, DGEBAL) (F77_CONST_CHAR_ARG_DECL,
00076                              const octave_idx_type&, double*,
00077                              const octave_idx_type&, octave_idx_type&,
00078                              octave_idx_type&, double*, octave_idx_type&
00079                              F77_CHAR_ARG_LEN_DECL);
00080 
00081   F77_RET_T
00082   F77_FUNC (dgebak, DGEBAK) (F77_CONST_CHAR_ARG_DECL,
00083                              F77_CONST_CHAR_ARG_DECL,
00084                              const octave_idx_type&, const octave_idx_type&,
00085                              const octave_idx_type&, double*,
00086                              const octave_idx_type&, double*,
00087                              const octave_idx_type&, octave_idx_type&
00088                              F77_CHAR_ARG_LEN_DECL
00089                              F77_CHAR_ARG_LEN_DECL);
00090 
00091 
00092   F77_RET_T
00093   F77_FUNC (dgemm, DGEMM) (F77_CONST_CHAR_ARG_DECL,
00094                            F77_CONST_CHAR_ARG_DECL,
00095                            const octave_idx_type&, const octave_idx_type&,
00096                            const octave_idx_type&, const double&,
00097                            const double*, const octave_idx_type&,
00098                            const double*, const octave_idx_type&,
00099                            const double&, double*, const octave_idx_type&
00100                            F77_CHAR_ARG_LEN_DECL
00101                            F77_CHAR_ARG_LEN_DECL);
00102 
00103   F77_RET_T
00104   F77_FUNC (dgemv, DGEMV) (F77_CONST_CHAR_ARG_DECL,
00105                            const octave_idx_type&, const octave_idx_type&,
00106                            const double&, const double*,
00107                            const octave_idx_type&, const double*,
00108                            const octave_idx_type&, const double&, double*,
00109                            const octave_idx_type&
00110                            F77_CHAR_ARG_LEN_DECL);
00111 
00112   F77_RET_T
00113   F77_FUNC (xddot, XDDOT) (const octave_idx_type&, const double*,
00114                            const octave_idx_type&, const double*,
00115                            const octave_idx_type&, double&);
00116 
00117   F77_RET_T
00118   F77_FUNC (dsyrk, DSYRK) (F77_CONST_CHAR_ARG_DECL,
00119                            F77_CONST_CHAR_ARG_DECL,
00120                            const octave_idx_type&, const octave_idx_type&,
00121                            const double&, const double*, const octave_idx_type&,
00122                            const double&, double*, const octave_idx_type&
00123                            F77_CHAR_ARG_LEN_DECL
00124                            F77_CHAR_ARG_LEN_DECL);
00125 
00126   F77_RET_T
00127   F77_FUNC (dgetrf, DGETRF) (const octave_idx_type&, const octave_idx_type&,
00128                              double*, const octave_idx_type&,
00129                              octave_idx_type*, octave_idx_type&);
00130 
00131   F77_RET_T
00132   F77_FUNC (dgetrs, DGETRS) (F77_CONST_CHAR_ARG_DECL,
00133                              const octave_idx_type&, const octave_idx_type&,
00134                              const double*, const octave_idx_type&,
00135                              const octave_idx_type*, double*,
00136                              const octave_idx_type&, octave_idx_type&
00137                              F77_CHAR_ARG_LEN_DECL);
00138 
00139   F77_RET_T
00140   F77_FUNC (dgetri, DGETRI) (const octave_idx_type&, double*,
00141                              const octave_idx_type&, const octave_idx_type*,
00142                              double*, const octave_idx_type&,
00143                              octave_idx_type&);
00144 
00145   F77_RET_T
00146   F77_FUNC (dgecon, DGECON) (F77_CONST_CHAR_ARG_DECL,
00147                              const octave_idx_type&, double*,
00148                              const octave_idx_type&, const double&, double&,
00149                              double*, octave_idx_type*, octave_idx_type&
00150                              F77_CHAR_ARG_LEN_DECL);
00151 
00152   F77_RET_T
00153   F77_FUNC (dgelsy, DGELSY) (const octave_idx_type&, const octave_idx_type&,
00154                              const octave_idx_type&, double*,
00155                              const octave_idx_type&, double*,
00156                              const octave_idx_type&, octave_idx_type*,
00157                              double&, octave_idx_type&, double*,
00158                              const octave_idx_type&, octave_idx_type&);
00159 
00160   F77_RET_T
00161   F77_FUNC (dgelsd, DGELSD) (const octave_idx_type&, const octave_idx_type&,
00162                              const octave_idx_type&, double*,
00163                              const octave_idx_type&, double*,
00164                              const octave_idx_type&, double*, double&,
00165                              octave_idx_type&, double*,
00166                              const octave_idx_type&, octave_idx_type*,
00167                              octave_idx_type&);
00168 
00169   F77_RET_T
00170   F77_FUNC (dpotrf, DPOTRF) (F77_CONST_CHAR_ARG_DECL,
00171                              const octave_idx_type&, double *,
00172                              const octave_idx_type&, octave_idx_type&
00173                              F77_CHAR_ARG_LEN_DECL);
00174 
00175   F77_RET_T
00176   F77_FUNC (dpocon, DPOCON) (F77_CONST_CHAR_ARG_DECL,
00177                              const octave_idx_type&, double*,
00178                              const octave_idx_type&, const double&,
00179                              double&, double*, octave_idx_type*,
00180                              octave_idx_type&
00181                              F77_CHAR_ARG_LEN_DECL);
00182   F77_RET_T
00183   F77_FUNC (dpotrs, DPOTRS) (F77_CONST_CHAR_ARG_DECL,
00184                              const octave_idx_type&, const octave_idx_type&,
00185                              const double*, const octave_idx_type&, double*,
00186                              const octave_idx_type&, octave_idx_type&
00187                              F77_CHAR_ARG_LEN_DECL);
00188 
00189   F77_RET_T
00190   F77_FUNC (dtrtri, DTRTRI) (F77_CONST_CHAR_ARG_DECL,
00191                              F77_CONST_CHAR_ARG_DECL,
00192                              const octave_idx_type&, const double*,
00193                              const octave_idx_type&, octave_idx_type&
00194                              F77_CHAR_ARG_LEN_DECL
00195                              F77_CHAR_ARG_LEN_DECL);
00196   F77_RET_T
00197   F77_FUNC (dtrcon, DTRCON) (F77_CONST_CHAR_ARG_DECL,
00198                              F77_CONST_CHAR_ARG_DECL,
00199                              F77_CONST_CHAR_ARG_DECL,
00200                              const octave_idx_type&, const double*,
00201                              const octave_idx_type&, double&,
00202                              double*, octave_idx_type*, octave_idx_type&
00203                              F77_CHAR_ARG_LEN_DECL
00204                              F77_CHAR_ARG_LEN_DECL
00205                              F77_CHAR_ARG_LEN_DECL);
00206   F77_RET_T
00207   F77_FUNC (dtrtrs, DTRTRS) (F77_CONST_CHAR_ARG_DECL,
00208                              F77_CONST_CHAR_ARG_DECL,
00209                              F77_CONST_CHAR_ARG_DECL,
00210                              const octave_idx_type&, const octave_idx_type&,
00211                              const double*, const octave_idx_type&, double*,
00212                              const octave_idx_type&, octave_idx_type&
00213                              F77_CHAR_ARG_LEN_DECL
00214                              F77_CHAR_ARG_LEN_DECL
00215                              F77_CHAR_ARG_LEN_DECL);
00216 
00217   F77_RET_T
00218   F77_FUNC (dlartg, DLARTG) (const double&, const double&, double&,
00219                              double&, double&);
00220 
00221   F77_RET_T
00222   F77_FUNC (dtrsyl, DTRSYL) (F77_CONST_CHAR_ARG_DECL,
00223                              F77_CONST_CHAR_ARG_DECL,
00224                              const octave_idx_type&, const octave_idx_type&,
00225                              const octave_idx_type&, const double*,
00226                              const octave_idx_type&, const double*,
00227                              const octave_idx_type&, const double*,
00228                              const octave_idx_type&, double&, octave_idx_type&
00229                              F77_CHAR_ARG_LEN_DECL
00230                              F77_CHAR_ARG_LEN_DECL);
00231 
00232   F77_RET_T
00233   F77_FUNC (xdlange, XDLANGE) (F77_CONST_CHAR_ARG_DECL,
00234                                const octave_idx_type&, const octave_idx_type&,
00235                                const double*, const octave_idx_type&,
00236                                double*, double&
00237                                F77_CHAR_ARG_LEN_DECL);
00238 }
00239 
00240 // Matrix class.
00241 
00242 Matrix::Matrix (const RowVector& rv)
00243   : MArray<double> (rv)
00244 {
00245 }
00246 
00247 Matrix::Matrix (const ColumnVector& cv)
00248   : MArray<double> (cv)
00249 {
00250 }
00251 
00252 Matrix::Matrix (const DiagMatrix& a)
00253   : MArray<double> (a.dims (), 0.0)
00254 {
00255   for (octave_idx_type i = 0; i < a.length (); i++)
00256     elem (i, i) = a.elem (i, i);
00257 }
00258 
00259 Matrix::Matrix (const PermMatrix& a)
00260   : MArray<double> (a.dims (), 0.0)
00261 {
00262   const Array<octave_idx_type> ia (a.pvec ());
00263   octave_idx_type len = a.rows ();
00264   if (a.is_col_perm ())
00265     for (octave_idx_type i = 0; i < len; i++)
00266       elem (ia(i), i) = 1.0;
00267   else
00268     for (octave_idx_type i = 0; i < len; i++)
00269       elem (i, ia(i)) = 1.0;
00270 }
00271 
00272 // FIXME -- could we use a templated mixed-type copy function
00273 // here?
00274 
00275 Matrix::Matrix (const boolMatrix& a)
00276   : MArray<double> (a)
00277 {
00278 }
00279 
00280 Matrix::Matrix (const charMatrix& a)
00281   : MArray<double> (a.dims ())
00282 {
00283   for (octave_idx_type i = 0; i < a.rows (); i++)
00284     for (octave_idx_type j = 0; j < a.cols (); j++)
00285       elem (i, j) = static_cast<unsigned char> (a.elem (i, j));
00286 }
00287 
00288 bool
00289 Matrix::operator == (const Matrix& a) const
00290 {
00291   if (rows () != a.rows () || cols () != a.cols ())
00292     return false;
00293 
00294   return mx_inline_equal (length (), data (), a.data ());
00295 }
00296 
00297 bool
00298 Matrix::operator != (const Matrix& a) const
00299 {
00300   return !(*this == a);
00301 }
00302 
00303 bool
00304 Matrix::is_symmetric (void) const
00305 {
00306   if (is_square () && rows () > 0)
00307     {
00308       for (octave_idx_type i = 0; i < rows (); i++)
00309         for (octave_idx_type j = i+1; j < cols (); j++)
00310           if (elem (i, j) != elem (j, i))
00311             return false;
00312 
00313       return true;
00314     }
00315 
00316   return false;
00317 }
00318 
00319 Matrix&
00320 Matrix::insert (const Matrix& a, octave_idx_type r, octave_idx_type c)
00321 {
00322   Array<double>::insert (a, r, c);
00323   return *this;
00324 }
00325 
00326 Matrix&
00327 Matrix::insert (const RowVector& a, octave_idx_type r, octave_idx_type c)
00328 {
00329   octave_idx_type a_len = a.length ();
00330 
00331   if (r < 0 || r >= rows () || c < 0 || c + a_len > cols ())
00332     {
00333       (*current_liboctave_error_handler) ("range error for insert");
00334       return *this;
00335     }
00336 
00337   if (a_len > 0)
00338     {
00339       make_unique ();
00340 
00341       for (octave_idx_type i = 0; i < a_len; i++)
00342         xelem (r, c+i) = a.elem (i);
00343     }
00344 
00345   return *this;
00346 }
00347 
00348 Matrix&
00349 Matrix::insert (const ColumnVector& a, octave_idx_type r, octave_idx_type c)
00350 {
00351   octave_idx_type a_len = a.length ();
00352 
00353   if (r < 0 || r + a_len > rows () || c < 0 || c >= cols ())
00354     {
00355       (*current_liboctave_error_handler) ("range error for insert");
00356       return *this;
00357     }
00358 
00359   if (a_len > 0)
00360     {
00361       make_unique ();
00362 
00363       for (octave_idx_type i = 0; i < a_len; i++)
00364         xelem (r+i, c) = a.elem (i);
00365     }
00366 
00367   return *this;
00368 }
00369 
00370 Matrix&
00371 Matrix::insert (const DiagMatrix& a, octave_idx_type r, octave_idx_type c)
00372 {
00373   octave_idx_type a_nr = a.rows ();
00374   octave_idx_type a_nc = a.cols ();
00375 
00376   if (r < 0 || r + a_nr > rows () || c < 0 || c + a_nc > cols ())
00377     {
00378       (*current_liboctave_error_handler) ("range error for insert");
00379       return *this;
00380     }
00381 
00382   fill (0.0, r, c, r + a_nr - 1, c + a_nc - 1);
00383 
00384   octave_idx_type a_len = a.length ();
00385 
00386   if (a_len > 0)
00387     {
00388       make_unique ();
00389 
00390       for (octave_idx_type i = 0; i < a_len; i++)
00391         xelem (r+i, c+i) = a.elem (i, i);
00392     }
00393 
00394   return *this;
00395 }
00396 
00397 Matrix&
00398 Matrix::fill (double val)
00399 {
00400   octave_idx_type nr = rows ();
00401   octave_idx_type nc = cols ();
00402 
00403   if (nr > 0 && nc > 0)
00404     {
00405       make_unique ();
00406 
00407       for (octave_idx_type j = 0; j < nc; j++)
00408         for (octave_idx_type i = 0; i < nr; i++)
00409           xelem (i, j) = val;
00410     }
00411 
00412   return *this;
00413 }
00414 
00415 Matrix&
00416 Matrix::fill (double val, octave_idx_type r1, octave_idx_type c1, octave_idx_type r2, octave_idx_type c2)
00417 {
00418   octave_idx_type nr = rows ();
00419   octave_idx_type nc = cols ();
00420 
00421   if (r1 < 0 || r2 < 0 || c1 < 0 || c2 < 0
00422       || r1 >= nr || r2 >= nr || c1 >= nc || c2 >= nc)
00423     {
00424       (*current_liboctave_error_handler) ("range error for fill");
00425       return *this;
00426     }
00427 
00428   if (r1 > r2) { octave_idx_type tmp = r1; r1 = r2; r2 = tmp; }
00429   if (c1 > c2) { octave_idx_type tmp = c1; c1 = c2; c2 = tmp; }
00430 
00431   if (r2 >= r1 && c2 >= c1)
00432     {
00433       make_unique ();
00434 
00435       for (octave_idx_type j = c1; j <= c2; j++)
00436         for (octave_idx_type i = r1; i <= r2; i++)
00437           xelem (i, j) = val;
00438     }
00439 
00440   return *this;
00441 }
00442 
00443 Matrix
00444 Matrix::append (const Matrix& a) const
00445 {
00446   octave_idx_type nr = rows ();
00447   octave_idx_type nc = cols ();
00448   if (nr != a.rows ())
00449     {
00450       (*current_liboctave_error_handler) ("row dimension mismatch for append");
00451       return Matrix ();
00452     }
00453 
00454   octave_idx_type nc_insert = nc;
00455   Matrix retval (nr, nc + a.cols ());
00456   retval.insert (*this, 0, 0);
00457   retval.insert (a, 0, nc_insert);
00458   return retval;
00459 }
00460 
00461 Matrix
00462 Matrix::append (const RowVector& a) const
00463 {
00464   octave_idx_type nr = rows ();
00465   octave_idx_type nc = cols ();
00466   if (nr != 1)
00467     {
00468       (*current_liboctave_error_handler) ("row dimension mismatch for append");
00469       return Matrix ();
00470     }
00471 
00472   octave_idx_type nc_insert = nc;
00473   Matrix retval (nr, nc + a.length ());
00474   retval.insert (*this, 0, 0);
00475   retval.insert (a, 0, nc_insert);
00476   return retval;
00477 }
00478 
00479 Matrix
00480 Matrix::append (const ColumnVector& a) const
00481 {
00482   octave_idx_type nr = rows ();
00483   octave_idx_type nc = cols ();
00484   if (nr != a.length ())
00485     {
00486       (*current_liboctave_error_handler) ("row dimension mismatch for append");
00487       return Matrix ();
00488     }
00489 
00490   octave_idx_type nc_insert = nc;
00491   Matrix retval (nr, nc + 1);
00492   retval.insert (*this, 0, 0);
00493   retval.insert (a, 0, nc_insert);
00494   return retval;
00495 }
00496 
00497 Matrix
00498 Matrix::append (const DiagMatrix& a) const
00499 {
00500   octave_idx_type nr = rows ();
00501   octave_idx_type nc = cols ();
00502   if (nr != a.rows ())
00503     {
00504       (*current_liboctave_error_handler) ("row dimension mismatch for append");
00505       return *this;
00506     }
00507 
00508   octave_idx_type nc_insert = nc;
00509   Matrix retval (nr, nc + a.cols ());
00510   retval.insert (*this, 0, 0);
00511   retval.insert (a, 0, nc_insert);
00512   return retval;
00513 }
00514 
00515 Matrix
00516 Matrix::stack (const Matrix& a) const
00517 {
00518   octave_idx_type nr = rows ();
00519   octave_idx_type nc = cols ();
00520   if (nc != a.cols ())
00521     {
00522       (*current_liboctave_error_handler)
00523         ("column dimension mismatch for stack");
00524       return Matrix ();
00525     }
00526 
00527   octave_idx_type nr_insert = nr;
00528   Matrix retval (nr + a.rows (), nc);
00529   retval.insert (*this, 0, 0);
00530   retval.insert (a, nr_insert, 0);
00531   return retval;
00532 }
00533 
00534 Matrix
00535 Matrix::stack (const RowVector& a) const
00536 {
00537   octave_idx_type nr = rows ();
00538   octave_idx_type nc = cols ();
00539   if (nc != a.length ())
00540     {
00541       (*current_liboctave_error_handler)
00542         ("column dimension mismatch for stack");
00543       return Matrix ();
00544     }
00545 
00546   octave_idx_type nr_insert = nr;
00547   Matrix retval (nr + 1, nc);
00548   retval.insert (*this, 0, 0);
00549   retval.insert (a, nr_insert, 0);
00550   return retval;
00551 }
00552 
00553 Matrix
00554 Matrix::stack (const ColumnVector& a) const
00555 {
00556   octave_idx_type nr = rows ();
00557   octave_idx_type nc = cols ();
00558   if (nc != 1)
00559     {
00560       (*current_liboctave_error_handler)
00561         ("column dimension mismatch for stack");
00562       return Matrix ();
00563     }
00564 
00565   octave_idx_type nr_insert = nr;
00566   Matrix retval (nr + a.length (), nc);
00567   retval.insert (*this, 0, 0);
00568   retval.insert (a, nr_insert, 0);
00569   return retval;
00570 }
00571 
00572 Matrix
00573 Matrix::stack (const DiagMatrix& a) const
00574 {
00575   octave_idx_type nr = rows ();
00576   octave_idx_type nc = cols ();
00577   if (nc != a.cols ())
00578     {
00579       (*current_liboctave_error_handler)
00580         ("column dimension mismatch for stack");
00581       return Matrix ();
00582     }
00583 
00584   octave_idx_type nr_insert = nr;
00585   Matrix retval (nr + a.rows (), nc);
00586   retval.insert (*this, 0, 0);
00587   retval.insert (a, nr_insert, 0);
00588   return retval;
00589 }
00590 
00591 Matrix
00592 real (const ComplexMatrix& a)
00593 {
00594   return do_mx_unary_op<double, Complex> (a, mx_inline_real);
00595 }
00596 
00597 Matrix
00598 imag (const ComplexMatrix& a)
00599 {
00600   return do_mx_unary_op<double, Complex> (a, mx_inline_imag);
00601 }
00602 
00603 Matrix
00604 Matrix::extract (octave_idx_type r1, octave_idx_type c1, octave_idx_type r2, octave_idx_type c2) const
00605 {
00606   if (r1 > r2) { octave_idx_type tmp = r1; r1 = r2; r2 = tmp; }
00607   if (c1 > c2) { octave_idx_type tmp = c1; c1 = c2; c2 = tmp; }
00608 
00609   return index (idx_vector (r1, r2+1), idx_vector (c1, c2+1));
00610 }
00611 
00612 Matrix
00613 Matrix::extract_n (octave_idx_type r1, octave_idx_type c1, octave_idx_type nr, octave_idx_type nc) const
00614 {
00615   return index (idx_vector (r1, r1 + nr), idx_vector (c1, c1 + nc));
00616 }
00617 
00618 // extract row or column i.
00619 
00620 RowVector
00621 Matrix::row (octave_idx_type i) const
00622 {
00623   return index (idx_vector (i), idx_vector::colon);
00624 }
00625 
00626 ColumnVector
00627 Matrix::column (octave_idx_type i) const
00628 {
00629   return index (idx_vector::colon, idx_vector (i));
00630 }
00631 
00632 Matrix
00633 Matrix::inverse (void) const
00634 {
00635   octave_idx_type info;
00636   double rcon;
00637   MatrixType mattype (*this);
00638   return inverse (mattype, info, rcon, 0, 0);
00639 }
00640 
00641 Matrix
00642 Matrix::inverse (octave_idx_type& info) const
00643 {
00644   double rcon;
00645   MatrixType mattype (*this);
00646   return inverse (mattype, info, rcon, 0, 0);
00647 }
00648 
00649 Matrix
00650 Matrix::inverse (octave_idx_type& info, double& rcon, int force,
00651                  int calc_cond) const
00652 {
00653   MatrixType mattype (*this);
00654   return inverse (mattype, info, rcon, force, calc_cond);
00655 }
00656 
00657 Matrix
00658 Matrix::inverse (MatrixType& mattype) const
00659 {
00660   octave_idx_type info;
00661   double rcon;
00662   return inverse (mattype, info, rcon, 0, 0);
00663 }
00664 
00665 Matrix
00666 Matrix::inverse (MatrixType &mattype, octave_idx_type& info) const
00667 {
00668   double rcon;
00669   return inverse (mattype, info, rcon, 0, 0);
00670 }
00671 
00672 Matrix
00673 Matrix::tinverse (MatrixType &mattype, octave_idx_type& info, double& rcon,
00674                   int force, int calc_cond) const
00675 {
00676   Matrix retval;
00677 
00678   octave_idx_type nr = rows ();
00679   octave_idx_type nc = cols ();
00680 
00681   if (nr != nc || nr == 0 || nc == 0)
00682     (*current_liboctave_error_handler) ("inverse requires square matrix");
00683   else
00684     {
00685       int typ = mattype.type ();
00686       char uplo = (typ == MatrixType::Lower ? 'L' : 'U');
00687       char udiag = 'N';
00688       retval = *this;
00689       double *tmp_data = retval.fortran_vec ();
00690 
00691       F77_XFCN (dtrtri, DTRTRI, (F77_CONST_CHAR_ARG2 (&uplo, 1),
00692                                  F77_CONST_CHAR_ARG2 (&udiag, 1),
00693                                  nr, tmp_data, nr, info
00694                                  F77_CHAR_ARG_LEN (1)
00695                                  F77_CHAR_ARG_LEN (1)));
00696 
00697       // Throw-away extra info LAPACK gives so as to not change output.
00698       rcon = 0.0;
00699       if (info != 0)
00700         info = -1;
00701       else if (calc_cond)
00702         {
00703           octave_idx_type dtrcon_info = 0;
00704           char job = '1';
00705 
00706           OCTAVE_LOCAL_BUFFER (double, work, 3 * nr);
00707           OCTAVE_LOCAL_BUFFER (octave_idx_type, iwork, nr);
00708 
00709           F77_XFCN (dtrcon, DTRCON, (F77_CONST_CHAR_ARG2 (&job, 1),
00710                                      F77_CONST_CHAR_ARG2 (&uplo, 1),
00711                                      F77_CONST_CHAR_ARG2 (&udiag, 1),
00712                                      nr, tmp_data, nr, rcon,
00713                                      work, iwork, dtrcon_info
00714                                      F77_CHAR_ARG_LEN (1)
00715                                      F77_CHAR_ARG_LEN (1)
00716                                      F77_CHAR_ARG_LEN (1)));
00717 
00718           if (dtrcon_info != 0)
00719             info = -1;
00720         }
00721 
00722       if (info == -1 && ! force)
00723         retval = *this; // Restore matrix contents.
00724     }
00725 
00726   return retval;
00727 }
00728 
00729 
00730 Matrix
00731 Matrix::finverse (MatrixType &mattype, octave_idx_type& info, double& rcon,
00732                   int force, int calc_cond) const
00733 {
00734   Matrix retval;
00735 
00736   octave_idx_type nr = rows ();
00737   octave_idx_type nc = cols ();
00738 
00739   if (nr != nc || nr == 0 || nc == 0)
00740     (*current_liboctave_error_handler) ("inverse requires square matrix");
00741   else
00742     {
00743       Array<octave_idx_type> ipvt (dim_vector (nr, 1));
00744       octave_idx_type *pipvt = ipvt.fortran_vec ();
00745 
00746       retval = *this;
00747       double *tmp_data = retval.fortran_vec ();
00748 
00749       Array<double> z (dim_vector (1, 1));
00750       octave_idx_type lwork = -1;
00751 
00752       // Query the optimum work array size.
00753       F77_XFCN (dgetri, DGETRI, (nc, tmp_data, nr, pipvt,
00754                                  z.fortran_vec (), lwork, info));
00755 
00756       lwork = static_cast<octave_idx_type> (z(0));
00757       lwork = (lwork < 2 *nc ? 2*nc : lwork);
00758       z.resize (dim_vector (lwork, 1));
00759       double *pz = z.fortran_vec ();
00760 
00761       info = 0;
00762 
00763       // Calculate the norm of the matrix, for later use.
00764       double anorm = 0;
00765       if (calc_cond)
00766         anorm = retval.abs().sum().row(static_cast<octave_idx_type>(0)).max();
00767 
00768       F77_XFCN (dgetrf, DGETRF, (nc, nc, tmp_data, nr, pipvt, info));
00769 
00770       // Throw-away extra info LAPACK gives so as to not change output.
00771       rcon = 0.0;
00772       if (info != 0)
00773         info = -1;
00774       else if (calc_cond)
00775         {
00776           octave_idx_type dgecon_info = 0;
00777 
00778           // Now calculate the condition number for non-singular matrix.
00779           char job = '1';
00780           Array<octave_idx_type> iz (dim_vector (nc, 1));
00781           octave_idx_type *piz = iz.fortran_vec ();
00782           F77_XFCN (dgecon, DGECON, (F77_CONST_CHAR_ARG2 (&job, 1),
00783                                      nc, tmp_data, nr, anorm,
00784                                      rcon, pz, piz, dgecon_info
00785                                      F77_CHAR_ARG_LEN (1)));
00786 
00787           if (dgecon_info != 0)
00788             info = -1;
00789         }
00790 
00791       if (info == -1 && ! force)
00792         retval = *this; // Restore matrix contents.
00793       else
00794         {
00795           octave_idx_type dgetri_info = 0;
00796 
00797           F77_XFCN (dgetri, DGETRI, (nc, tmp_data, nr, pipvt,
00798                                      pz, lwork, dgetri_info));
00799 
00800           if (dgetri_info != 0)
00801             info = -1;
00802         }
00803 
00804       if (info != 0)
00805         mattype.mark_as_rectangular();
00806     }
00807 
00808   return retval;
00809 }
00810 
00811 Matrix
00812 Matrix::inverse (MatrixType &mattype, octave_idx_type& info, double& rcon,
00813                  int force, int calc_cond) const
00814 {
00815   int typ = mattype.type (false);
00816   Matrix ret;
00817 
00818   if (typ == MatrixType::Unknown)
00819     typ = mattype.type (*this);
00820 
00821   if (typ == MatrixType::Upper || typ == MatrixType::Lower)
00822     ret = tinverse (mattype, info, rcon, force, calc_cond);
00823   else
00824     {
00825       if (mattype.is_hermitian ())
00826         {
00827           CHOL chol (*this, info, calc_cond);
00828           if (info == 0)
00829             {
00830               if (calc_cond)
00831                 rcon = chol.rcond ();
00832               else
00833                 rcon = 1.0;
00834               ret = chol.inverse ();
00835             }
00836           else
00837             mattype.mark_as_unsymmetric ();
00838         }
00839 
00840       if (!mattype.is_hermitian ())
00841         ret = finverse(mattype, info, rcon, force, calc_cond);
00842 
00843       if ((mattype.is_hermitian () || calc_cond) && rcon == 0.)
00844         ret = Matrix (rows (), columns (), octave_Inf);
00845     }
00846 
00847   return ret;
00848 }
00849 
00850 Matrix
00851 Matrix::pseudo_inverse (double tol) const
00852 {
00853   SVD result (*this, SVD::economy);
00854 
00855   DiagMatrix S = result.singular_values ();
00856   Matrix U = result.left_singular_matrix ();
00857   Matrix V = result.right_singular_matrix ();
00858 
00859   ColumnVector sigma = S.diag ();
00860 
00861   octave_idx_type r = sigma.length () - 1;
00862   octave_idx_type nr = rows ();
00863   octave_idx_type nc = cols ();
00864 
00865   if (tol <= 0.0)
00866     {
00867       if (nr > nc)
00868         tol = nr * sigma.elem (0) * DBL_EPSILON;
00869       else
00870         tol = nc * sigma.elem (0) * DBL_EPSILON;
00871     }
00872 
00873   while (r >= 0 && sigma.elem (r) < tol)
00874     r--;
00875 
00876   if (r < 0)
00877     return Matrix (nc, nr, 0.0);
00878   else
00879     {
00880       Matrix Ur = U.extract (0, 0, nr-1, r);
00881       DiagMatrix D = DiagMatrix (sigma.extract (0, r)) . inverse ();
00882       Matrix Vr = V.extract (0, 0, nc-1, r);
00883       return Vr * D * Ur.transpose ();
00884     }
00885 }
00886 
00887 #if defined (HAVE_FFTW)
00888 
00889 ComplexMatrix
00890 Matrix::fourier (void) const
00891 {
00892   size_t nr = rows ();
00893   size_t nc = cols ();
00894 
00895   ComplexMatrix retval (nr, nc);
00896 
00897   size_t npts, nsamples;
00898 
00899   if (nr == 1 || nc == 1)
00900     {
00901       npts = nr > nc ? nr : nc;
00902       nsamples = 1;
00903     }
00904   else
00905     {
00906       npts = nr;
00907       nsamples = nc;
00908     }
00909 
00910   const double *in (fortran_vec ());
00911   Complex *out (retval.fortran_vec ());
00912 
00913   octave_fftw::fft (in, out, npts, nsamples);
00914 
00915   return retval;
00916 }
00917 
00918 ComplexMatrix
00919 Matrix::ifourier (void) const
00920 {
00921   size_t nr = rows ();
00922   size_t nc = cols ();
00923 
00924   ComplexMatrix retval (nr, nc);
00925 
00926   size_t npts, nsamples;
00927 
00928   if (nr == 1 || nc == 1)
00929     {
00930       npts = nr > nc ? nr : nc;
00931       nsamples = 1;
00932     }
00933   else
00934     {
00935       npts = nr;
00936       nsamples = nc;
00937     }
00938 
00939   ComplexMatrix tmp (*this);
00940   Complex *in (tmp.fortran_vec ());
00941   Complex *out (retval.fortran_vec ());
00942 
00943   octave_fftw::ifft (in, out, npts, nsamples);
00944 
00945   return retval;
00946 }
00947 
00948 ComplexMatrix
00949 Matrix::fourier2d (void) const
00950 {
00951   dim_vector dv(rows (), cols ());
00952 
00953   const double *in = fortran_vec ();
00954   ComplexMatrix retval (rows (), cols ());
00955   octave_fftw::fftNd (in, retval.fortran_vec (), 2, dv);
00956 
00957   return retval;
00958 }
00959 
00960 ComplexMatrix
00961 Matrix::ifourier2d (void) const
00962 {
00963   dim_vector dv(rows (), cols ());
00964 
00965   ComplexMatrix retval (*this);
00966   Complex *out (retval.fortran_vec ());
00967 
00968   octave_fftw::ifftNd (out, out, 2, dv);
00969 
00970   return retval;
00971 }
00972 
00973 #else
00974 
00975 extern "C"
00976 {
00977   // Note that the original complex fft routines were not written for
00978   // double complex arguments.  They have been modified by adding an
00979   // implicit double precision (a-h,o-z) statement at the beginning of
00980   // each subroutine.
00981 
00982   F77_RET_T
00983   F77_FUNC (zffti, ZFFTI) (const octave_idx_type&, Complex*);
00984 
00985   F77_RET_T
00986   F77_FUNC (zfftf, ZFFTF) (const octave_idx_type&, Complex*, Complex*);
00987 
00988   F77_RET_T
00989   F77_FUNC (zfftb, ZFFTB) (const octave_idx_type&, Complex*, Complex*);
00990 }
00991 
00992 ComplexMatrix
00993 Matrix::fourier (void) const
00994 {
00995   ComplexMatrix retval;
00996 
00997   octave_idx_type nr = rows ();
00998   octave_idx_type nc = cols ();
00999 
01000   octave_idx_type npts, nsamples;
01001 
01002   if (nr == 1 || nc == 1)
01003     {
01004       npts = nr > nc ? nr : nc;
01005       nsamples = 1;
01006     }
01007   else
01008     {
01009       npts = nr;
01010       nsamples = nc;
01011     }
01012 
01013   octave_idx_type nn = 4*npts+15;
01014 
01015   Array<Complex> wsave (dim_vector (nn, 1));
01016   Complex *pwsave = wsave.fortran_vec ();
01017 
01018   retval = ComplexMatrix (*this);
01019   Complex *tmp_data = retval.fortran_vec ();
01020 
01021   F77_FUNC (zffti, ZFFTI) (npts, pwsave);
01022 
01023   for (octave_idx_type j = 0; j < nsamples; j++)
01024     {
01025       octave_quit ();
01026 
01027       F77_FUNC (zfftf, ZFFTF) (npts, &tmp_data[npts*j], pwsave);
01028     }
01029 
01030   return retval;
01031 }
01032 
01033 ComplexMatrix
01034 Matrix::ifourier (void) const
01035 {
01036   ComplexMatrix retval;
01037 
01038   octave_idx_type nr = rows ();
01039   octave_idx_type nc = cols ();
01040 
01041   octave_idx_type npts, nsamples;
01042 
01043   if (nr == 1 || nc == 1)
01044     {
01045       npts = nr > nc ? nr : nc;
01046       nsamples = 1;
01047     }
01048   else
01049     {
01050       npts = nr;
01051       nsamples = nc;
01052     }
01053 
01054   octave_idx_type nn = 4*npts+15;
01055 
01056   Array<Complex> wsave (dim_vector (nn, 1));
01057   Complex *pwsave = wsave.fortran_vec ();
01058 
01059   retval = ComplexMatrix (*this);
01060   Complex *tmp_data = retval.fortran_vec ();
01061 
01062   F77_FUNC (zffti, ZFFTI) (npts, pwsave);
01063 
01064   for (octave_idx_type j = 0; j < nsamples; j++)
01065     {
01066       octave_quit ();
01067 
01068       F77_FUNC (zfftb, ZFFTB) (npts, &tmp_data[npts*j], pwsave);
01069     }
01070 
01071   for (octave_idx_type j = 0; j < npts*nsamples; j++)
01072     tmp_data[j] = tmp_data[j] / static_cast<double> (npts);
01073 
01074   return retval;
01075 }
01076 
01077 ComplexMatrix
01078 Matrix::fourier2d (void) const
01079 {
01080   ComplexMatrix retval;
01081 
01082   octave_idx_type nr = rows ();
01083   octave_idx_type nc = cols ();
01084 
01085   octave_idx_type npts, nsamples;
01086 
01087   if (nr == 1 || nc == 1)
01088     {
01089       npts = nr > nc ? nr : nc;
01090       nsamples = 1;
01091     }
01092   else
01093     {
01094       npts = nr;
01095       nsamples = nc;
01096     }
01097 
01098   octave_idx_type nn = 4*npts+15;
01099 
01100   Array<Complex> wsave (dim_vector (nn, 1));
01101   Complex *pwsave = wsave.fortran_vec ();
01102 
01103   retval = ComplexMatrix (*this);
01104   Complex *tmp_data = retval.fortran_vec ();
01105 
01106   F77_FUNC (zffti, ZFFTI) (npts, pwsave);
01107 
01108   for (octave_idx_type j = 0; j < nsamples; j++)
01109     {
01110       octave_quit ();
01111 
01112       F77_FUNC (zfftf, ZFFTF) (npts, &tmp_data[npts*j], pwsave);
01113     }
01114 
01115   npts = nc;
01116   nsamples = nr;
01117   nn = 4*npts+15;
01118 
01119   wsave.resize (dim_vector (nn, 1));
01120   pwsave = wsave.fortran_vec ();
01121 
01122   Array<Complex> tmp (dim_vector (npts, 1));
01123   Complex *prow = tmp.fortran_vec ();
01124 
01125   F77_FUNC (zffti, ZFFTI) (npts, pwsave);
01126 
01127   for (octave_idx_type j = 0; j < nsamples; j++)
01128     {
01129       octave_quit ();
01130 
01131       for (octave_idx_type i = 0; i < npts; i++)
01132         prow[i] = tmp_data[i*nr + j];
01133 
01134       F77_FUNC (zfftf, ZFFTF) (npts, prow, pwsave);
01135 
01136       for (octave_idx_type i = 0; i < npts; i++)
01137         tmp_data[i*nr + j] = prow[i];
01138     }
01139 
01140   return retval;
01141 }
01142 
01143 ComplexMatrix
01144 Matrix::ifourier2d (void) const
01145 {
01146   ComplexMatrix retval;
01147 
01148   octave_idx_type nr = rows ();
01149   octave_idx_type nc = cols ();
01150 
01151   octave_idx_type npts, nsamples;
01152 
01153   if (nr == 1 || nc == 1)
01154     {
01155       npts = nr > nc ? nr : nc;
01156       nsamples = 1;
01157     }
01158   else
01159     {
01160       npts = nr;
01161       nsamples = nc;
01162     }
01163 
01164   octave_idx_type nn = 4*npts+15;
01165 
01166   Array<Complex> wsave (dim_vector (nn, 1));
01167   Complex *pwsave = wsave.fortran_vec ();
01168 
01169   retval = ComplexMatrix (*this);
01170   Complex *tmp_data = retval.fortran_vec ();
01171 
01172   F77_FUNC (zffti, ZFFTI) (npts, pwsave);
01173 
01174   for (octave_idx_type j = 0; j < nsamples; j++)
01175     {
01176       octave_quit ();
01177 
01178       F77_FUNC (zfftb, ZFFTB) (npts, &tmp_data[npts*j], pwsave);
01179     }
01180 
01181   for (octave_idx_type j = 0; j < npts*nsamples; j++)
01182     tmp_data[j] = tmp_data[j] / static_cast<double> (npts);
01183 
01184   npts = nc;
01185   nsamples = nr;
01186   nn = 4*npts+15;
01187 
01188   wsave.resize (dim_vector (nn, 1));
01189   pwsave = wsave.fortran_vec ();
01190 
01191   Array<Complex> tmp (dim_vector (npts, 1));
01192   Complex *prow = tmp.fortran_vec ();
01193 
01194   F77_FUNC (zffti, ZFFTI) (npts, pwsave);
01195 
01196   for (octave_idx_type j = 0; j < nsamples; j++)
01197     {
01198       octave_quit ();
01199 
01200       for (octave_idx_type i = 0; i < npts; i++)
01201         prow[i] = tmp_data[i*nr + j];
01202 
01203       F77_FUNC (zfftb, ZFFTB) (npts, prow, pwsave);
01204 
01205       for (octave_idx_type i = 0; i < npts; i++)
01206         tmp_data[i*nr + j] = prow[i] / static_cast<double> (npts);
01207     }
01208 
01209   return retval;
01210 }
01211 
01212 #endif
01213 
01214 DET
01215 Matrix::determinant (void) const
01216 {
01217   octave_idx_type info;
01218   double rcon;
01219   return determinant (info, rcon, 0);
01220 }
01221 
01222 DET
01223 Matrix::determinant (octave_idx_type& info) const
01224 {
01225   double rcon;
01226   return determinant (info, rcon, 0);
01227 }
01228 
01229 DET
01230 Matrix::determinant (octave_idx_type& info, double& rcon, int calc_cond) const
01231 {
01232   MatrixType mattype (*this);
01233   return determinant (mattype, info, rcon, calc_cond);
01234 }
01235 
01236 DET
01237 Matrix::determinant (MatrixType& mattype,
01238                      octave_idx_type& info, double& rcon, int calc_cond) const
01239 {
01240   DET retval (1.0);
01241 
01242   info = 0;
01243   rcon = 0.0;
01244 
01245   octave_idx_type nr = rows ();
01246   octave_idx_type nc = cols ();
01247 
01248   if (nr != nc)
01249     (*current_liboctave_error_handler) ("matrix must be square");
01250   else
01251     {
01252       volatile int typ = mattype.type ();
01253 
01254       // Even though the matrix is marked as singular (Rectangular), we may
01255       // still get a useful number from the LU factorization, because it always
01256       // completes.
01257 
01258       if (typ == MatrixType::Unknown)
01259         typ = mattype.type (*this);
01260       else if (typ == MatrixType::Rectangular)
01261         typ = MatrixType::Full;
01262 
01263       if (typ == MatrixType::Lower || typ == MatrixType::Upper)
01264         {
01265           for (octave_idx_type i = 0; i < nc; i++)
01266             retval *= elem (i,i);
01267         }
01268       else if (typ == MatrixType::Hermitian)
01269         {
01270           Matrix atmp = *this;
01271           double *tmp_data = atmp.fortran_vec ();
01272 
01273           double anorm = 0;
01274           if (calc_cond) anorm = xnorm (*this, 1);
01275 
01276 
01277           char job = 'L';
01278           F77_XFCN (dpotrf, DPOTRF, (F77_CONST_CHAR_ARG2 (&job, 1), nr,
01279                                      tmp_data, nr, info
01280                                      F77_CHAR_ARG_LEN (1)));
01281 
01282           if (info != 0)
01283             {
01284               rcon = 0.0;
01285               mattype.mark_as_unsymmetric ();
01286               typ = MatrixType::Full;
01287             }
01288           else
01289             {
01290               Array<double> z (dim_vector (3 * nc, 1));
01291               double *pz = z.fortran_vec ();
01292               Array<octave_idx_type> iz (dim_vector (nc, 1));
01293               octave_idx_type *piz = iz.fortran_vec ();
01294 
01295               F77_XFCN (dpocon, DPOCON, (F77_CONST_CHAR_ARG2 (&job, 1),
01296                                          nr, tmp_data, nr, anorm,
01297                                          rcon, pz, piz, info
01298                                          F77_CHAR_ARG_LEN (1)));
01299 
01300               if (info != 0)
01301                 rcon = 0.0;
01302 
01303               for (octave_idx_type i = 0; i < nc; i++)
01304                 retval *= atmp (i,i);
01305 
01306               retval = retval.square ();
01307             }
01308         }
01309       else if (typ != MatrixType::Full)
01310         (*current_liboctave_error_handler) ("det: invalid dense matrix type");
01311 
01312       if (typ == MatrixType::Full)
01313         {
01314           Array<octave_idx_type> ipvt (dim_vector (nr, 1));
01315           octave_idx_type *pipvt = ipvt.fortran_vec ();
01316 
01317           Matrix atmp = *this;
01318           double *tmp_data = atmp.fortran_vec ();
01319 
01320           info = 0;
01321 
01322           // Calculate the norm of the matrix, for later use.
01323           double anorm = 0;
01324           if (calc_cond) anorm = xnorm (*this, 1);
01325 
01326           F77_XFCN (dgetrf, DGETRF, (nr, nr, tmp_data, nr, pipvt, info));
01327 
01328           // Throw-away extra info LAPACK gives so as to not change output.
01329           rcon = 0.0;
01330           if (info != 0)
01331             {
01332               info = -1;
01333               retval = DET ();
01334             }
01335           else
01336             {
01337               if (calc_cond)
01338                 {
01339                   // Now calc the condition number for non-singular matrix.
01340                   char job = '1';
01341                   Array<double> z (dim_vector (4 * nc, 1));
01342                   double *pz = z.fortran_vec ();
01343                   Array<octave_idx_type> iz (dim_vector (nc, 1));
01344                   octave_idx_type *piz = iz.fortran_vec ();
01345 
01346                   F77_XFCN (dgecon, DGECON, (F77_CONST_CHAR_ARG2 (&job, 1),
01347                                              nc, tmp_data, nr, anorm,
01348                                              rcon, pz, piz, info
01349                                              F77_CHAR_ARG_LEN (1)));
01350                 }
01351 
01352               if (info != 0)
01353                 {
01354                   info = -1;
01355                   retval = DET ();
01356                 }
01357               else
01358                 {
01359                   for (octave_idx_type i = 0; i < nc; i++)
01360                     {
01361                       double c = atmp(i,i);
01362                       retval *= (ipvt(i) != (i+1)) ? -c : c;
01363                     }
01364                 }
01365             }
01366         }
01367     }
01368 
01369   return retval;
01370 }
01371 
01372 double
01373 Matrix::rcond (void) const
01374 {
01375   MatrixType mattype (*this);
01376   return rcond (mattype);
01377 }
01378 
01379 double
01380 Matrix::rcond (MatrixType &mattype) const
01381 {
01382   double rcon;
01383   octave_idx_type nr = rows ();
01384   octave_idx_type nc = cols ();
01385 
01386   if (nr != nc)
01387     (*current_liboctave_error_handler) ("matrix must be square");
01388   else if (nr == 0 || nc == 0)
01389     rcon = octave_Inf;
01390   else
01391     {
01392       int typ = mattype.type ();
01393 
01394       if (typ == MatrixType::Unknown)
01395         typ = mattype.type (*this);
01396 
01397       // Only calculate the condition number for LU/Cholesky
01398       if (typ == MatrixType::Upper)
01399         {
01400           const double *tmp_data = fortran_vec ();
01401           octave_idx_type info = 0;
01402           char norm = '1';
01403           char uplo = 'U';
01404           char dia = 'N';
01405 
01406           Array<double> z (dim_vector (3 * nc, 1));
01407           double *pz = z.fortran_vec ();
01408           Array<octave_idx_type> iz (dim_vector (nc, 1));
01409           octave_idx_type *piz = iz.fortran_vec ();
01410 
01411           F77_XFCN (dtrcon, DTRCON, (F77_CONST_CHAR_ARG2 (&norm, 1),
01412                                      F77_CONST_CHAR_ARG2 (&uplo, 1),
01413                                      F77_CONST_CHAR_ARG2 (&dia, 1),
01414                                      nr, tmp_data, nr, rcon,
01415                                      pz, piz, info
01416                                      F77_CHAR_ARG_LEN (1)
01417                                      F77_CHAR_ARG_LEN (1)
01418                                      F77_CHAR_ARG_LEN (1)));
01419 
01420           if (info != 0)
01421             rcon = 0.0;
01422         }
01423       else if  (typ == MatrixType::Permuted_Upper)
01424         (*current_liboctave_error_handler)
01425           ("permuted triangular matrix not implemented");
01426       else if (typ == MatrixType::Lower)
01427         {
01428           const double *tmp_data = fortran_vec ();
01429           octave_idx_type info = 0;
01430           char norm = '1';
01431           char uplo = 'L';
01432           char dia = 'N';
01433 
01434           Array<double> z (dim_vector (3 * nc, 1));
01435           double *pz = z.fortran_vec ();
01436           Array<octave_idx_type> iz (dim_vector (nc, 1));
01437           octave_idx_type *piz = iz.fortran_vec ();
01438 
01439           F77_XFCN (dtrcon, DTRCON, (F77_CONST_CHAR_ARG2 (&norm, 1),
01440                                      F77_CONST_CHAR_ARG2 (&uplo, 1),
01441                                      F77_CONST_CHAR_ARG2 (&dia, 1),
01442                                      nr, tmp_data, nr, rcon,
01443                                      pz, piz, info
01444                                      F77_CHAR_ARG_LEN (1)
01445                                      F77_CHAR_ARG_LEN (1)
01446                                      F77_CHAR_ARG_LEN (1)));
01447 
01448           if (info != 0)
01449             rcon = 0.0;
01450         }
01451       else if (typ == MatrixType::Permuted_Lower)
01452         (*current_liboctave_error_handler)
01453           ("permuted triangular matrix not implemented");
01454       else if (typ == MatrixType::Full || typ == MatrixType::Hermitian)
01455         {
01456           double anorm = -1.0;
01457 
01458           if (typ == MatrixType::Hermitian)
01459             {
01460               octave_idx_type info = 0;
01461               char job = 'L';
01462 
01463               Matrix atmp = *this;
01464               double *tmp_data = atmp.fortran_vec ();
01465 
01466               anorm = atmp.abs().sum().
01467                 row(static_cast<octave_idx_type>(0)).max();
01468 
01469               F77_XFCN (dpotrf, DPOTRF, (F77_CONST_CHAR_ARG2 (&job, 1), nr,
01470                                          tmp_data, nr, info
01471                                          F77_CHAR_ARG_LEN (1)));
01472 
01473               if (info != 0)
01474                 {
01475                   rcon = 0.0;
01476                   mattype.mark_as_unsymmetric ();
01477                   typ = MatrixType::Full;
01478                 }
01479               else
01480                 {
01481                   Array<double> z (dim_vector (3 * nc, 1));
01482                   double *pz = z.fortran_vec ();
01483                   Array<octave_idx_type> iz (dim_vector (nc, 1));
01484                   octave_idx_type *piz = iz.fortran_vec ();
01485 
01486                   F77_XFCN (dpocon, DPOCON, (F77_CONST_CHAR_ARG2 (&job, 1),
01487                                              nr, tmp_data, nr, anorm,
01488                                              rcon, pz, piz, info
01489                                              F77_CHAR_ARG_LEN (1)));
01490 
01491                   if (info != 0)
01492                     rcon = 0.0;
01493                 }
01494             }
01495 
01496           if (typ == MatrixType::Full)
01497             {
01498               octave_idx_type info = 0;
01499 
01500               Matrix atmp = *this;
01501               double *tmp_data = atmp.fortran_vec ();
01502 
01503               Array<octave_idx_type> ipvt (dim_vector (nr, 1));
01504               octave_idx_type *pipvt = ipvt.fortran_vec ();
01505 
01506               if(anorm < 0.)
01507                 anorm = atmp.abs().sum().
01508                   row(static_cast<octave_idx_type>(0)).max();
01509 
01510               Array<double> z (dim_vector (4 * nc, 1));
01511               double *pz = z.fortran_vec ();
01512               Array<octave_idx_type> iz (dim_vector (nc, 1));
01513               octave_idx_type *piz = iz.fortran_vec ();
01514 
01515               F77_XFCN (dgetrf, DGETRF, (nr, nr, tmp_data, nr, pipvt, info));
01516 
01517               if (info != 0)
01518                 {
01519                   rcon = 0.0;
01520                   mattype.mark_as_rectangular ();
01521                 }
01522               else
01523                 {
01524                   char job = '1';
01525                   F77_XFCN (dgecon, DGECON, (F77_CONST_CHAR_ARG2 (&job, 1),
01526                                              nc, tmp_data, nr, anorm,
01527                                              rcon, pz, piz, info
01528                                              F77_CHAR_ARG_LEN (1)));
01529 
01530                   if (info != 0)
01531                     rcon = 0.0;
01532                 }
01533             }
01534         }
01535       else
01536         rcon = 0.0;
01537     }
01538 
01539   return rcon;
01540 }
01541 
01542 Matrix
01543 Matrix::utsolve (MatrixType &mattype, const Matrix& b, octave_idx_type& info,
01544                 double& rcon, solve_singularity_handler sing_handler,
01545                 bool calc_cond, blas_trans_type transt) const
01546 {
01547   Matrix retval;
01548 
01549   octave_idx_type nr = rows ();
01550   octave_idx_type nc = cols ();
01551 
01552   if (nr != b.rows ())
01553     (*current_liboctave_error_handler)
01554       ("matrix dimension mismatch solution of linear equations");
01555   else if (nr == 0 || nc == 0 || b.cols () == 0)
01556     retval = Matrix (nc, b.cols (), 0.0);
01557   else
01558     {
01559       volatile int typ = mattype.type ();
01560 
01561       if (typ == MatrixType::Permuted_Upper ||
01562           typ == MatrixType::Upper)
01563         {
01564           octave_idx_type b_nc = b.cols ();
01565           rcon = 1.;
01566           info = 0;
01567 
01568           if (typ == MatrixType::Permuted_Upper)
01569             {
01570               (*current_liboctave_error_handler)
01571                 ("permuted triangular matrix not implemented");
01572             }
01573           else
01574             {
01575               const double *tmp_data = fortran_vec ();
01576 
01577               if (calc_cond)
01578                 {
01579                   char norm = '1';
01580                   char uplo = 'U';
01581                   char dia = 'N';
01582 
01583                   Array<double> z (dim_vector (3 * nc, 1));
01584                   double *pz = z.fortran_vec ();
01585                   Array<octave_idx_type> iz (dim_vector (nc, 1));
01586                   octave_idx_type *piz = iz.fortran_vec ();
01587 
01588                   F77_XFCN (dtrcon, DTRCON, (F77_CONST_CHAR_ARG2 (&norm, 1),
01589                                              F77_CONST_CHAR_ARG2 (&uplo, 1),
01590                                              F77_CONST_CHAR_ARG2 (&dia, 1),
01591                                              nr, tmp_data, nr, rcon,
01592                                              pz, piz, info
01593                                              F77_CHAR_ARG_LEN (1)
01594                                              F77_CHAR_ARG_LEN (1)
01595                                              F77_CHAR_ARG_LEN (1)));
01596 
01597                   if (info != 0)
01598                     info = -2;
01599 
01600                   volatile double rcond_plus_one = rcon + 1.0;
01601 
01602                   if (rcond_plus_one == 1.0 || xisnan (rcon))
01603                     {
01604                       info = -2;
01605 
01606                       if (sing_handler)
01607                         sing_handler (rcon);
01608                       else
01609                         (*current_liboctave_error_handler)
01610                           ("matrix singular to machine precision, rcond = %g",
01611                            rcon);
01612                     }
01613                 }
01614 
01615               if (info == 0)
01616                 {
01617                   retval = b;
01618                   double *result = retval.fortran_vec ();
01619 
01620                   char uplo = 'U';
01621                   char trans = get_blas_char (transt);
01622                   char dia = 'N';
01623 
01624                   F77_XFCN (dtrtrs, DTRTRS, (F77_CONST_CHAR_ARG2 (&uplo, 1),
01625                                              F77_CONST_CHAR_ARG2 (&trans, 1),
01626                                              F77_CONST_CHAR_ARG2 (&dia, 1),
01627                                              nr, b_nc, tmp_data, nr,
01628                                              result, nr, info
01629                                              F77_CHAR_ARG_LEN (1)
01630                                              F77_CHAR_ARG_LEN (1)
01631                                              F77_CHAR_ARG_LEN (1)));
01632                 }
01633             }
01634         }
01635       else
01636         (*current_liboctave_error_handler) ("incorrect matrix type");
01637     }
01638 
01639   return retval;
01640 }
01641 
01642 Matrix
01643 Matrix::ltsolve (MatrixType &mattype, const Matrix& b, octave_idx_type& info,
01644                 double& rcon, solve_singularity_handler sing_handler,
01645                 bool calc_cond, blas_trans_type transt) const
01646 {
01647   Matrix retval;
01648 
01649   octave_idx_type nr = rows ();
01650   octave_idx_type nc = cols ();
01651 
01652   if (nr != b.rows ())
01653     (*current_liboctave_error_handler)
01654       ("matrix dimension mismatch solution of linear equations");
01655   else if (nr == 0 || nc == 0 || b.cols () == 0)
01656     retval = Matrix (nc, b.cols (), 0.0);
01657   else
01658     {
01659       volatile int typ = mattype.type ();
01660 
01661       if (typ == MatrixType::Permuted_Lower ||
01662           typ == MatrixType::Lower)
01663         {
01664           octave_idx_type b_nc = b.cols ();
01665           rcon = 1.;
01666           info = 0;
01667 
01668           if (typ == MatrixType::Permuted_Lower)
01669             {
01670               (*current_liboctave_error_handler)
01671                 ("permuted triangular matrix not implemented");
01672             }
01673           else
01674             {
01675               const double *tmp_data = fortran_vec ();
01676 
01677               if (calc_cond)
01678                 {
01679                   char norm = '1';
01680                   char uplo = 'L';
01681                   char dia = 'N';
01682 
01683                   Array<double> z (dim_vector (3 * nc, 1));
01684                   double *pz = z.fortran_vec ();
01685                   Array<octave_idx_type> iz (dim_vector (nc, 1));
01686                   octave_idx_type *piz = iz.fortran_vec ();
01687 
01688                   F77_XFCN (dtrcon, DTRCON, (F77_CONST_CHAR_ARG2 (&norm, 1),
01689                                              F77_CONST_CHAR_ARG2 (&uplo, 1),
01690                                              F77_CONST_CHAR_ARG2 (&dia, 1),
01691                                              nr, tmp_data, nr, rcon,
01692                                              pz, piz, info
01693                                              F77_CHAR_ARG_LEN (1)
01694                                              F77_CHAR_ARG_LEN (1)
01695                                              F77_CHAR_ARG_LEN (1)));
01696 
01697                   if (info != 0)
01698                     info = -2;
01699 
01700                   volatile double rcond_plus_one = rcon + 1.0;
01701 
01702                   if (rcond_plus_one == 1.0 || xisnan (rcon))
01703                     {
01704                       info = -2;
01705 
01706                       if (sing_handler)
01707                         sing_handler (rcon);
01708                       else
01709                         (*current_liboctave_error_handler)
01710                           ("matrix singular to machine precision, rcond = %g",
01711                            rcon);
01712                     }
01713                 }
01714 
01715               if (info == 0)
01716                 {
01717                   retval = b;
01718                   double *result = retval.fortran_vec ();
01719 
01720                   char uplo = 'L';
01721                   char trans = get_blas_char (transt);
01722                   char dia = 'N';
01723 
01724                   F77_XFCN (dtrtrs, DTRTRS, (F77_CONST_CHAR_ARG2 (&uplo, 1),
01725                                              F77_CONST_CHAR_ARG2 (&trans, 1),
01726                                              F77_CONST_CHAR_ARG2 (&dia, 1),
01727                                              nr, b_nc, tmp_data, nr,
01728                                              result, nr, info
01729                                              F77_CHAR_ARG_LEN (1)
01730                                              F77_CHAR_ARG_LEN (1)
01731                                              F77_CHAR_ARG_LEN (1)));
01732                 }
01733             }
01734         }
01735       else
01736         (*current_liboctave_error_handler) ("incorrect matrix type");
01737     }
01738 
01739   return retval;
01740 }
01741 
01742 Matrix
01743 Matrix::fsolve (MatrixType &mattype, const Matrix& b, octave_idx_type& info,
01744                 double& rcon, solve_singularity_handler sing_handler,
01745                 bool calc_cond) const
01746 {
01747   Matrix retval;
01748 
01749   octave_idx_type nr = rows ();
01750   octave_idx_type nc = cols ();
01751 
01752   if (nr != nc || nr != b.rows ())
01753     (*current_liboctave_error_handler)
01754       ("matrix dimension mismatch solution of linear equations");
01755   else if (nr == 0 || b.cols () == 0)
01756     retval = Matrix (nc, b.cols (), 0.0);
01757   else
01758     {
01759       volatile int typ = mattype.type ();
01760 
01761      // Calculate the norm of the matrix, for later use.
01762       double anorm = -1.;
01763 
01764       if (typ == MatrixType::Hermitian)
01765         {
01766           info = 0;
01767           char job = 'L';
01768 
01769           Matrix atmp = *this;
01770           double *tmp_data = atmp.fortran_vec ();
01771 
01772           anorm = atmp.abs().sum().row(static_cast<octave_idx_type>(0)).max();
01773 
01774           F77_XFCN (dpotrf, DPOTRF, (F77_CONST_CHAR_ARG2 (&job, 1), nr,
01775                                      tmp_data, nr, info
01776                                      F77_CHAR_ARG_LEN (1)));
01777 
01778           // Throw-away extra info LAPACK gives so as to not change output.
01779           rcon = 0.0;
01780           if (info != 0)
01781             {
01782               info = -2;
01783 
01784               mattype.mark_as_unsymmetric ();
01785               typ = MatrixType::Full;
01786             }
01787           else
01788             {
01789               if (calc_cond)
01790                 {
01791                   Array<double> z (dim_vector (3 * nc, 1));
01792                   double *pz = z.fortran_vec ();
01793                   Array<octave_idx_type> iz (dim_vector (nc, 1));
01794                   octave_idx_type *piz = iz.fortran_vec ();
01795 
01796                   F77_XFCN (dpocon, DPOCON, (F77_CONST_CHAR_ARG2 (&job, 1),
01797                                              nr, tmp_data, nr, anorm,
01798                                              rcon, pz, piz, info
01799                                              F77_CHAR_ARG_LEN (1)));
01800 
01801                   if (info != 0)
01802                     info = -2;
01803 
01804                   volatile double rcond_plus_one = rcon + 1.0;
01805 
01806                   if (rcond_plus_one == 1.0 || xisnan (rcon))
01807                     {
01808                       info = -2;
01809 
01810                       if (sing_handler)
01811                         sing_handler (rcon);
01812                       else
01813                         (*current_liboctave_error_handler)
01814                           ("matrix singular to machine precision, rcond = %g",
01815                            rcon);
01816                     }
01817                 }
01818 
01819               if (info == 0)
01820                 {
01821                   retval = b;
01822                   double *result = retval.fortran_vec ();
01823 
01824                   octave_idx_type b_nc = b.cols ();
01825 
01826                   F77_XFCN (dpotrs, DPOTRS, (F77_CONST_CHAR_ARG2 (&job, 1),
01827                                              nr, b_nc, tmp_data, nr,
01828                                              result, b.rows(), info
01829                                              F77_CHAR_ARG_LEN (1)));
01830                 }
01831               else
01832                 {
01833                   mattype.mark_as_unsymmetric ();
01834                   typ = MatrixType::Full;
01835                 }
01836             }
01837         }
01838 
01839       if (typ == MatrixType::Full)
01840         {
01841           info = 0;
01842 
01843           Array<octave_idx_type> ipvt (dim_vector (nr, 1));
01844           octave_idx_type *pipvt = ipvt.fortran_vec ();
01845 
01846           Matrix atmp = *this;
01847           double *tmp_data = atmp.fortran_vec ();
01848 
01849           if(anorm < 0.)
01850             anorm = atmp.abs().sum().row(static_cast<octave_idx_type>(0)).max();
01851 
01852           Array<double> z (dim_vector (4 * nc, 1));
01853           double *pz = z.fortran_vec ();
01854           Array<octave_idx_type> iz (dim_vector (nc, 1));
01855           octave_idx_type *piz = iz.fortran_vec ();
01856 
01857           F77_XFCN (dgetrf, DGETRF, (nr, nr, tmp_data, nr, pipvt, info));
01858 
01859           // Throw-away extra info LAPACK gives so as to not change output.
01860           rcon = 0.0;
01861           if (info != 0)
01862             {
01863               info = -2;
01864 
01865               if (sing_handler)
01866                 sing_handler (rcon);
01867               else
01868                 (*current_liboctave_error_handler)
01869                   ("matrix singular to machine precision");
01870 
01871               mattype.mark_as_rectangular ();
01872             }
01873           else
01874             {
01875               if (calc_cond)
01876                 {
01877                   // Now calculate the condition number for
01878                   // non-singular matrix.
01879                   char job = '1';
01880                   F77_XFCN (dgecon, DGECON, (F77_CONST_CHAR_ARG2 (&job, 1),
01881                                              nc, tmp_data, nr, anorm,
01882                                              rcon, pz, piz, info
01883                                              F77_CHAR_ARG_LEN (1)));
01884 
01885                   if (info != 0)
01886                     info = -2;
01887 
01888                   volatile double rcond_plus_one = rcon + 1.0;
01889 
01890                   if (rcond_plus_one == 1.0 || xisnan (rcon))
01891                     {
01892                       info = -2;
01893 
01894                       if (sing_handler)
01895                         sing_handler (rcon);
01896                       else
01897                         (*current_liboctave_error_handler)
01898                           ("matrix singular to machine precision, rcond = %g",
01899                            rcon);
01900                     }
01901                 }
01902 
01903               if (info == 0)
01904                 {
01905                   retval = b;
01906                   double *result = retval.fortran_vec ();
01907 
01908                   octave_idx_type b_nc = b.cols ();
01909 
01910                   char job = 'N';
01911                   F77_XFCN (dgetrs, DGETRS, (F77_CONST_CHAR_ARG2 (&job, 1),
01912                                              nr, b_nc, tmp_data, nr,
01913                                              pipvt, result, b.rows(), info
01914                                              F77_CHAR_ARG_LEN (1)));
01915                 }
01916               else
01917                 mattype.mark_as_rectangular ();
01918             }
01919         }
01920       else if (typ != MatrixType::Hermitian)
01921         (*current_liboctave_error_handler) ("incorrect matrix type");
01922     }
01923 
01924   return retval;
01925 }
01926 
01927 Matrix
01928 Matrix::solve (MatrixType &typ, const Matrix& b) const
01929 {
01930   octave_idx_type info;
01931   double rcon;
01932   return solve (typ, b, info, rcon, 0);
01933 }
01934 
01935 Matrix
01936 Matrix::solve (MatrixType &typ, const Matrix& b, octave_idx_type& info) const
01937 {
01938   double rcon;
01939   return solve (typ, b, info, rcon, 0);
01940 }
01941 
01942 Matrix
01943 Matrix::solve (MatrixType &typ, const Matrix& b, octave_idx_type& info,
01944                double& rcon) const
01945 {
01946   return solve (typ, b, info, rcon, 0);
01947 }
01948 
01949 Matrix
01950 Matrix::solve (MatrixType &mattype, const Matrix& b, octave_idx_type& info,
01951                double& rcon, solve_singularity_handler sing_handler,
01952                bool singular_fallback, blas_trans_type transt) const
01953 {
01954   Matrix retval;
01955   int typ = mattype.type ();
01956 
01957   if (typ == MatrixType::Unknown)
01958     typ = mattype.type (*this);
01959 
01960   // Only calculate the condition number for LU/Cholesky
01961   if (typ == MatrixType::Upper || typ == MatrixType::Permuted_Upper)
01962     retval = utsolve (mattype, b, info, rcon, sing_handler, false, transt);
01963   else if (typ == MatrixType::Lower || typ == MatrixType::Permuted_Lower)
01964     retval = ltsolve (mattype, b, info, rcon, sing_handler, false, transt);
01965   else if (transt == blas_trans || transt == blas_conj_trans)
01966     return transpose ().solve (mattype, b, info, rcon, sing_handler, singular_fallback);
01967   else if (typ == MatrixType::Full || typ == MatrixType::Hermitian)
01968     retval = fsolve (mattype, b, info, rcon, sing_handler, true);
01969   else if (typ != MatrixType::Rectangular)
01970     {
01971       (*current_liboctave_error_handler) ("unknown matrix type");
01972       return Matrix ();
01973     }
01974 
01975   // Rectangular or one of the above solvers flags a singular matrix
01976   if (singular_fallback && mattype.type () == MatrixType::Rectangular)
01977     {
01978       octave_idx_type rank;
01979       retval = lssolve (b, info, rank, rcon);
01980     }
01981 
01982   return retval;
01983 }
01984 
01985 ComplexMatrix
01986 Matrix::solve (MatrixType &typ, const ComplexMatrix& b) const
01987 {
01988   octave_idx_type info;
01989   double rcon;
01990   return solve (typ, b, info, rcon, 0);
01991 }
01992 
01993 ComplexMatrix
01994 Matrix::solve (MatrixType &typ, const ComplexMatrix& b,
01995   octave_idx_type& info) const
01996 {
01997   double rcon;
01998   return solve (typ, b, info, rcon, 0);
01999 }
02000 
02001 ComplexMatrix
02002 Matrix::solve (MatrixType &typ, const ComplexMatrix& b, octave_idx_type& info,
02003                double& rcon) const
02004 {
02005   return solve (typ, b, info, rcon, 0);
02006 }
02007 
02008 static Matrix
02009 stack_complex_matrix (const ComplexMatrix& cm)
02010 {
02011   octave_idx_type m = cm.rows (), n = cm.cols (), nel = m*n;
02012   Matrix retval (m, 2*n);
02013   const Complex *cmd = cm.data ();
02014   double *rd = retval.fortran_vec ();
02015   for (octave_idx_type i = 0; i < nel; i++)
02016     {
02017       rd[i] = std::real (cmd[i]);
02018       rd[nel+i] = std::imag (cmd[i]);
02019     }
02020   return retval;
02021 }
02022 
02023 static ComplexMatrix
02024 unstack_complex_matrix (const Matrix& sm)
02025 {
02026   octave_idx_type m = sm.rows (), n = sm.cols () / 2, nel = m*n;
02027   ComplexMatrix retval (m, n);
02028   const double *smd = sm.data ();
02029   Complex *rd = retval.fortran_vec ();
02030   for (octave_idx_type i = 0; i < nel; i++)
02031     rd[i] = Complex (smd[i], smd[nel+i]);
02032   return retval;
02033 }
02034 
02035 ComplexMatrix
02036 Matrix::solve (MatrixType &typ, const ComplexMatrix& b, octave_idx_type& info,
02037                double& rcon, solve_singularity_handler sing_handler,
02038                bool singular_fallback, blas_trans_type transt) const
02039 {
02040   Matrix tmp = stack_complex_matrix (b);
02041   tmp = solve (typ, tmp, info, rcon, sing_handler, singular_fallback, transt);
02042   return unstack_complex_matrix (tmp);
02043 }
02044 
02045 ColumnVector
02046 Matrix::solve (MatrixType &typ, const ColumnVector& b) const
02047 {
02048   octave_idx_type info; double rcon;
02049   return solve (typ, b, info, rcon);
02050 }
02051 
02052 ColumnVector
02053 Matrix::solve (MatrixType &typ, const ColumnVector& b,
02054                octave_idx_type& info) const
02055 {
02056   double rcon;
02057   return solve (typ, b, info, rcon);
02058 }
02059 
02060 ColumnVector
02061 Matrix::solve (MatrixType &typ, const ColumnVector& b, octave_idx_type& info,
02062                double& rcon) const
02063 {
02064   return solve (typ, b, info, rcon, 0);
02065 }
02066 
02067 ColumnVector
02068 Matrix::solve (MatrixType &typ, const ColumnVector& b, octave_idx_type& info,
02069                double& rcon, solve_singularity_handler sing_handler, blas_trans_type transt) const
02070 {
02071   Matrix tmp (b);
02072   tmp = solve (typ, tmp, info, rcon, sing_handler, true, transt);
02073   return tmp.column(static_cast<octave_idx_type> (0));
02074 }
02075 
02076 ComplexColumnVector
02077 Matrix::solve (MatrixType &typ, const ComplexColumnVector& b) const
02078 {
02079   ComplexMatrix tmp (*this);
02080   return tmp.solve (typ, b);
02081 }
02082 
02083 ComplexColumnVector
02084 Matrix::solve (MatrixType &typ, const ComplexColumnVector& b,
02085                octave_idx_type& info) const
02086 {
02087   ComplexMatrix tmp (*this);
02088   return tmp.solve (typ, b, info);
02089 }
02090 
02091 ComplexColumnVector
02092 Matrix::solve (MatrixType &typ, const ComplexColumnVector& b,
02093                octave_idx_type& info, double& rcon) const
02094 {
02095   ComplexMatrix tmp (*this);
02096   return tmp.solve (typ, b, info, rcon);
02097 }
02098 
02099 ComplexColumnVector
02100 Matrix::solve (MatrixType &typ, const ComplexColumnVector& b,
02101                octave_idx_type& info, double& rcon,
02102                solve_singularity_handler sing_handler, blas_trans_type transt) const
02103 {
02104   ComplexMatrix tmp (*this);
02105   return tmp.solve(typ, b, info, rcon, sing_handler, transt);
02106 }
02107 
02108 Matrix
02109 Matrix::solve (const Matrix& b) const
02110 {
02111   octave_idx_type info;
02112   double rcon;
02113   return solve (b, info, rcon, 0);
02114 }
02115 
02116 Matrix
02117 Matrix::solve (const Matrix& b, octave_idx_type& info) const
02118 {
02119   double rcon;
02120   return solve (b, info, rcon, 0);
02121 }
02122 
02123 Matrix
02124 Matrix::solve (const Matrix& b, octave_idx_type& info, double& rcon) const
02125 {
02126   return solve (b, info, rcon, 0);
02127 }
02128 
02129 Matrix
02130 Matrix::solve (const Matrix& b, octave_idx_type& info,
02131                double& rcon, solve_singularity_handler sing_handler, blas_trans_type transt) const
02132 {
02133   MatrixType mattype (*this);
02134   return solve (mattype, b, info, rcon, sing_handler, true, transt);
02135 }
02136 
02137 ComplexMatrix
02138 Matrix::solve (const ComplexMatrix& b) const
02139 {
02140   ComplexMatrix tmp (*this);
02141   return tmp.solve (b);
02142 }
02143 
02144 ComplexMatrix
02145 Matrix::solve (const ComplexMatrix& b, octave_idx_type& info) const
02146 {
02147   ComplexMatrix tmp (*this);
02148   return tmp.solve (b, info);
02149 }
02150 
02151 ComplexMatrix
02152 Matrix::solve (const ComplexMatrix& b, octave_idx_type& info, double& rcon) const
02153 {
02154   ComplexMatrix tmp (*this);
02155   return tmp.solve (b, info, rcon);
02156 }
02157 
02158 ComplexMatrix
02159 Matrix::solve (const ComplexMatrix& b, octave_idx_type& info, double& rcon,
02160                solve_singularity_handler sing_handler, blas_trans_type transt) const
02161 {
02162   ComplexMatrix tmp (*this);
02163   return tmp.solve (b, info, rcon, sing_handler, transt);
02164 }
02165 
02166 ColumnVector
02167 Matrix::solve (const ColumnVector& b) const
02168 {
02169   octave_idx_type info; double rcon;
02170   return solve (b, info, rcon);
02171 }
02172 
02173 ColumnVector
02174 Matrix::solve (const ColumnVector& b, octave_idx_type& info) const
02175 {
02176   double rcon;
02177   return solve (b, info, rcon);
02178 }
02179 
02180 ColumnVector
02181 Matrix::solve (const ColumnVector& b, octave_idx_type& info, double& rcon) const
02182 {
02183   return solve (b, info, rcon, 0);
02184 }
02185 
02186 ColumnVector
02187 Matrix::solve (const ColumnVector& b, octave_idx_type& info, double& rcon,
02188                solve_singularity_handler sing_handler, blas_trans_type transt) const
02189 {
02190   MatrixType mattype (*this);
02191   return solve (mattype, b, info, rcon, sing_handler, transt);
02192 }
02193 
02194 ComplexColumnVector
02195 Matrix::solve (const ComplexColumnVector& b) const
02196 {
02197   ComplexMatrix tmp (*this);
02198   return tmp.solve (b);
02199 }
02200 
02201 ComplexColumnVector
02202 Matrix::solve (const ComplexColumnVector& b, octave_idx_type& info) const
02203 {
02204   ComplexMatrix tmp (*this);
02205   return tmp.solve (b, info);
02206 }
02207 
02208 ComplexColumnVector
02209 Matrix::solve (const ComplexColumnVector& b, octave_idx_type& info, double& rcon) const
02210 {
02211   ComplexMatrix tmp (*this);
02212   return tmp.solve (b, info, rcon);
02213 }
02214 
02215 ComplexColumnVector
02216 Matrix::solve (const ComplexColumnVector& b, octave_idx_type& info, double& rcon,
02217                solve_singularity_handler sing_handler, blas_trans_type transt) const
02218 {
02219   ComplexMatrix tmp (*this);
02220   return tmp.solve (b, info, rcon, sing_handler, transt);
02221 }
02222 
02223 Matrix
02224 Matrix::lssolve (const Matrix& b) const
02225 {
02226   octave_idx_type info;
02227   octave_idx_type rank;
02228   double rcon;
02229   return lssolve (b, info, rank, rcon);
02230 }
02231 
02232 Matrix
02233 Matrix::lssolve (const Matrix& b, octave_idx_type& info) const
02234 {
02235   octave_idx_type rank;
02236   double rcon;
02237   return lssolve (b, info, rank, rcon);
02238 }
02239 
02240 Matrix
02241 Matrix::lssolve (const Matrix& b, octave_idx_type& info,
02242                  octave_idx_type& rank) const
02243 {
02244   double rcon;
02245   return lssolve (b, info, rank, rcon);
02246 }
02247 
02248 Matrix
02249 Matrix::lssolve (const Matrix& b, octave_idx_type& info,
02250                  octave_idx_type& rank, double &rcon) const
02251 {
02252   Matrix retval;
02253 
02254   octave_idx_type nrhs = b.cols ();
02255 
02256   octave_idx_type m = rows ();
02257   octave_idx_type n = cols ();
02258 
02259   if (m != b.rows ())
02260     (*current_liboctave_error_handler)
02261       ("matrix dimension mismatch solution of linear equations");
02262   else if (m == 0 || n == 0 || b.cols () == 0)
02263     retval = Matrix (n, b.cols (), 0.0);
02264   else
02265     {
02266       volatile octave_idx_type minmn = (m < n ? m : n);
02267       octave_idx_type maxmn = m > n ? m : n;
02268       rcon = -1.0;
02269       if (m != n)
02270         {
02271           retval = Matrix (maxmn, nrhs, 0.0);
02272 
02273           for (octave_idx_type j = 0; j < nrhs; j++)
02274             for (octave_idx_type i = 0; i < m; i++)
02275               retval.elem (i, j) = b.elem (i, j);
02276         }
02277       else
02278         retval = b;
02279 
02280       Matrix atmp = *this;
02281       double *tmp_data = atmp.fortran_vec ();
02282 
02283       double *pretval = retval.fortran_vec ();
02284       Array<double> s (dim_vector (minmn, 1));
02285       double *ps = s.fortran_vec ();
02286 
02287       // Ask DGELSD what the dimension of WORK should be.
02288       octave_idx_type lwork = -1;
02289 
02290       Array<double> work (dim_vector (1, 1));
02291 
02292       octave_idx_type smlsiz;
02293       F77_FUNC (xilaenv, XILAENV) (9, F77_CONST_CHAR_ARG2 ("DGELSD", 6),
02294                                    F77_CONST_CHAR_ARG2 (" ", 1),
02295                                    0, 0, 0, 0, smlsiz
02296                                    F77_CHAR_ARG_LEN (6)
02297                                    F77_CHAR_ARG_LEN (1));
02298 
02299       octave_idx_type mnthr;
02300       F77_FUNC (xilaenv, XILAENV) (6, F77_CONST_CHAR_ARG2 ("DGELSD", 6),
02301                                    F77_CONST_CHAR_ARG2 (" ", 1),
02302                                    m, n, nrhs, -1, mnthr
02303                                    F77_CHAR_ARG_LEN (6)
02304                                    F77_CHAR_ARG_LEN (1));
02305 
02306       // We compute the size of iwork because DGELSD in older versions
02307       // of LAPACK does not return it on a query call.
02308       double dminmn = static_cast<double> (minmn);
02309       double dsmlsizp1 = static_cast<double> (smlsiz+1);
02310 #if defined (HAVE_LOG2)
02311       double tmp = log2 (dminmn / dsmlsizp1);
02312 #else
02313       double tmp = log (dminmn / dsmlsizp1) / log (2.0);
02314 #endif
02315       octave_idx_type nlvl = static_cast<octave_idx_type> (tmp) + 1;
02316       if (nlvl < 0)
02317         nlvl = 0;
02318 
02319       octave_idx_type liwork = 3 * minmn * nlvl + 11 * minmn;
02320       if (liwork < 1)
02321         liwork = 1;
02322       Array<octave_idx_type> iwork (dim_vector (liwork, 1));
02323       octave_idx_type* piwork = iwork.fortran_vec ();
02324 
02325       F77_XFCN (dgelsd, DGELSD, (m, n, nrhs, tmp_data, m, pretval, maxmn,
02326                                  ps, rcon, rank, work.fortran_vec (),
02327                                  lwork, piwork, info));
02328 
02329       // The workspace query is broken in at least LAPACK 3.0.0
02330       // through 3.1.1 when n >= mnthr.  The obtuse formula below
02331       // should provide sufficient workspace for DGELSD to operate
02332       // efficiently.
02333       if (n > m && n >= mnthr)
02334         {
02335           const octave_idx_type wlalsd
02336             = 9*m + 2*m*smlsiz + 8*m*nlvl + m*nrhs + (smlsiz+1)*(smlsiz+1);
02337 
02338           octave_idx_type addend = m;
02339 
02340           if (2*m-4 > addend)
02341             addend = 2*m-4;
02342 
02343           if (nrhs > addend)
02344             addend = nrhs;
02345 
02346           if (n-3*m > addend)
02347             addend = n-3*m;
02348 
02349           if (wlalsd > addend)
02350             addend = wlalsd;
02351 
02352           const octave_idx_type lworkaround = 4*m + m*m + addend;
02353 
02354           if (work(0) < lworkaround)
02355             work(0) = lworkaround;
02356         }
02357       else if (m >= n)
02358         {
02359           octave_idx_type lworkaround
02360             = 12*n + 2*n*smlsiz + 8*n*nlvl + n*nrhs + (smlsiz+1)*(smlsiz+1);
02361 
02362           if (work(0) < lworkaround)
02363             work(0) = lworkaround;
02364         }
02365 
02366       lwork = static_cast<octave_idx_type> (work(0));
02367       work.resize (dim_vector (lwork, 1));
02368 
02369       F77_XFCN (dgelsd, DGELSD, (m, n, nrhs, tmp_data, m, pretval,
02370                                  maxmn, ps, rcon, rank,
02371                                  work.fortran_vec (), lwork,
02372                                  piwork, info));
02373 
02374       if (s.elem (0) == 0.0)
02375         rcon = 0.0;
02376       else
02377         rcon = s.elem (minmn - 1) / s.elem (0);
02378 
02379       retval.resize (n, nrhs);
02380     }
02381 
02382   return retval;
02383 }
02384 
02385 ComplexMatrix
02386 Matrix::lssolve (const ComplexMatrix& b) const
02387 {
02388   ComplexMatrix tmp (*this);
02389   octave_idx_type info;
02390   octave_idx_type rank;
02391   double rcon;
02392   return tmp.lssolve (b, info, rank, rcon);
02393 }
02394 
02395 ComplexMatrix
02396 Matrix::lssolve (const ComplexMatrix& b, octave_idx_type& info) const
02397 {
02398   ComplexMatrix tmp (*this);
02399   octave_idx_type rank;
02400   double rcon;
02401   return tmp.lssolve (b, info, rank, rcon);
02402 }
02403 
02404 ComplexMatrix
02405 Matrix::lssolve (const ComplexMatrix& b, octave_idx_type& info,
02406                  octave_idx_type& rank) const
02407 {
02408   ComplexMatrix tmp (*this);
02409   double rcon;
02410   return tmp.lssolve (b, info, rank, rcon);
02411 }
02412 
02413 ComplexMatrix
02414 Matrix::lssolve (const ComplexMatrix& b, octave_idx_type& info,
02415                  octave_idx_type& rank, double& rcon) const
02416 {
02417   ComplexMatrix tmp (*this);
02418   return tmp.lssolve (b, info, rank, rcon);
02419 }
02420 
02421 ColumnVector
02422 Matrix::lssolve (const ColumnVector& b) const
02423 {
02424   octave_idx_type info;
02425   octave_idx_type rank;
02426   double rcon;
02427   return lssolve (b, info, rank, rcon);
02428 }
02429 
02430 ColumnVector
02431 Matrix::lssolve (const ColumnVector& b, octave_idx_type& info) const
02432 {
02433   octave_idx_type rank;
02434   double rcon;
02435   return lssolve (b, info, rank, rcon);
02436 }
02437 
02438 ColumnVector
02439 Matrix::lssolve (const ColumnVector& b, octave_idx_type& info,
02440                  octave_idx_type& rank) const
02441 {
02442   double rcon;
02443   return lssolve (b, info, rank, rcon);
02444 }
02445 
02446 ColumnVector
02447 Matrix::lssolve (const ColumnVector& b, octave_idx_type& info,
02448                  octave_idx_type& rank, double &rcon) const
02449 {
02450   ColumnVector retval;
02451 
02452   octave_idx_type nrhs = 1;
02453 
02454   octave_idx_type m = rows ();
02455   octave_idx_type n = cols ();
02456 
02457   if (m != b.length ())
02458     (*current_liboctave_error_handler)
02459       ("matrix dimension mismatch solution of linear equations");
02460   else if (m == 0 || n == 0)
02461     retval = ColumnVector (n, 0.0);
02462   else
02463     {
02464       volatile octave_idx_type minmn = (m < n ? m : n);
02465       octave_idx_type maxmn = m > n ? m : n;
02466       rcon = -1.0;
02467 
02468       if (m != n)
02469         {
02470           retval = ColumnVector (maxmn, 0.0);
02471 
02472           for (octave_idx_type i = 0; i < m; i++)
02473             retval.elem (i) = b.elem (i);
02474         }
02475       else
02476         retval = b;
02477 
02478       Matrix atmp = *this;
02479       double *tmp_data = atmp.fortran_vec ();
02480 
02481       double *pretval = retval.fortran_vec ();
02482       Array<double> s (dim_vector (minmn, 1));
02483       double *ps = s.fortran_vec ();
02484 
02485       // Ask DGELSD what the dimension of WORK should be.
02486       octave_idx_type lwork = -1;
02487 
02488       Array<double> work (dim_vector (1, 1));
02489 
02490       octave_idx_type smlsiz;
02491       F77_FUNC (xilaenv, XILAENV) (9, F77_CONST_CHAR_ARG2 ("DGELSD", 6),
02492                                    F77_CONST_CHAR_ARG2 (" ", 1),
02493                                    0, 0, 0, 0, smlsiz
02494                                    F77_CHAR_ARG_LEN (6)
02495                                    F77_CHAR_ARG_LEN (1));
02496 
02497       // We compute the size of iwork because DGELSD in older versions
02498       // of LAPACK does not return it on a query call.
02499       double dminmn = static_cast<double> (minmn);
02500       double dsmlsizp1 = static_cast<double> (smlsiz+1);
02501 #if defined (HAVE_LOG2)
02502       double tmp = log2 (dminmn / dsmlsizp1);
02503 #else
02504       double tmp = log (dminmn / dsmlsizp1) / log (2.0);
02505 #endif
02506       octave_idx_type nlvl = static_cast<octave_idx_type> (tmp) + 1;
02507       if (nlvl < 0)
02508         nlvl = 0;
02509 
02510       octave_idx_type liwork = 3 * minmn * nlvl + 11 * minmn;
02511       if (liwork < 1)
02512         liwork = 1;
02513       Array<octave_idx_type> iwork (dim_vector (liwork, 1));
02514       octave_idx_type* piwork = iwork.fortran_vec ();
02515 
02516       F77_XFCN (dgelsd, DGELSD, (m, n, nrhs, tmp_data, m, pretval, maxmn,
02517                                  ps, rcon, rank, work.fortran_vec (),
02518                                  lwork, piwork, info));
02519 
02520       lwork = static_cast<octave_idx_type> (work(0));
02521       work.resize (dim_vector (lwork, 1));
02522 
02523       F77_XFCN (dgelsd, DGELSD, (m, n, nrhs, tmp_data, m, pretval,
02524                                  maxmn, ps, rcon, rank,
02525                                  work.fortran_vec (), lwork,
02526                                  piwork, info));
02527 
02528       if (rank < minmn)
02529         {
02530           if (s.elem (0) == 0.0)
02531             rcon = 0.0;
02532           else
02533             rcon = s.elem (minmn - 1) / s.elem (0);
02534         }
02535 
02536       retval.resize (n, nrhs);
02537     }
02538 
02539   return retval;
02540 }
02541 
02542 ComplexColumnVector
02543 Matrix::lssolve (const ComplexColumnVector& b) const
02544 {
02545   ComplexMatrix tmp (*this);
02546   octave_idx_type info;
02547   octave_idx_type rank;
02548   double rcon;
02549   return tmp.lssolve (b, info, rank, rcon);
02550 }
02551 
02552 ComplexColumnVector
02553 Matrix::lssolve (const ComplexColumnVector& b, octave_idx_type& info) const
02554 {
02555   ComplexMatrix tmp (*this);
02556   octave_idx_type rank;
02557   double rcon;
02558   return tmp.lssolve (b, info, rank, rcon);
02559 }
02560 
02561 ComplexColumnVector
02562 Matrix::lssolve (const ComplexColumnVector& b, octave_idx_type& info,
02563                  octave_idx_type& rank) const
02564 {
02565   ComplexMatrix tmp (*this);
02566   double rcon;
02567   return tmp.lssolve (b, info, rank, rcon);
02568 }
02569 
02570 ComplexColumnVector
02571 Matrix::lssolve (const ComplexColumnVector& b, octave_idx_type& info,
02572                  octave_idx_type& rank, double &rcon) const
02573 {
02574   ComplexMatrix tmp (*this);
02575   return tmp.lssolve (b, info, rank, rcon);
02576 }
02577 
02578 Matrix&
02579 Matrix::operator += (const DiagMatrix& a)
02580 {
02581   octave_idx_type nr = rows ();
02582   octave_idx_type nc = cols ();
02583 
02584   octave_idx_type a_nr = a.rows ();
02585   octave_idx_type a_nc = a.cols ();
02586 
02587   if (nr != a_nr || nc != a_nc)
02588     {
02589       gripe_nonconformant ("operator +=", nr, nc, a_nr, a_nc);
02590       return *this;
02591     }
02592 
02593   for (octave_idx_type i = 0; i < a.length (); i++)
02594     elem (i, i) += a.elem (i, i);
02595 
02596   return *this;
02597 }
02598 
02599 Matrix&
02600 Matrix::operator -= (const DiagMatrix& a)
02601 {
02602   octave_idx_type nr = rows ();
02603   octave_idx_type nc = cols ();
02604 
02605   octave_idx_type a_nr = a.rows ();
02606   octave_idx_type a_nc = a.cols ();
02607 
02608   if (nr != a_nr || nc != a_nc)
02609     {
02610       gripe_nonconformant ("operator -=", nr, nc, a_nr, a_nc);
02611       return *this;
02612     }
02613 
02614   for (octave_idx_type i = 0; i < a.length (); i++)
02615     elem (i, i) -= a.elem (i, i);
02616 
02617   return *this;
02618 }
02619 
02620 // unary operations
02621 
02622 boolMatrix
02623 Matrix::operator ! (void) const
02624 {
02625   if (any_element_is_nan ())
02626     gripe_nan_to_logical_conversion ();
02627 
02628   return do_mx_unary_op<bool, double> (*this, mx_inline_not);
02629 }
02630 
02631 // column vector by row vector -> matrix operations
02632 
02633 Matrix
02634 operator * (const ColumnVector& v, const RowVector& a)
02635 {
02636   Matrix retval;
02637 
02638   octave_idx_type len = v.length ();
02639 
02640   if (len != 0)
02641     {
02642       octave_idx_type a_len = a.length ();
02643 
02644       retval = Matrix (len, a_len);
02645       double *c = retval.fortran_vec ();
02646 
02647       F77_XFCN (dgemm, DGEMM, (F77_CONST_CHAR_ARG2 ("N", 1),
02648                                F77_CONST_CHAR_ARG2 ("N", 1),
02649                                len, a_len, 1, 1.0, v.data (), len,
02650                                a.data (), 1, 0.0, c, len
02651                                F77_CHAR_ARG_LEN (1)
02652                                F77_CHAR_ARG_LEN (1)));
02653     }
02654 
02655   return retval;
02656 }
02657 
02658 // other operations.
02659 
02660 bool
02661 Matrix::any_element_is_negative (bool neg_zero) const
02662 {
02663   return (neg_zero ? test_all (xnegative_sign)
02664           : do_mx_check<double> (*this, mx_inline_any_negative));
02665 }
02666 
02667 bool
02668 Matrix::any_element_is_positive (bool neg_zero) const
02669 {
02670   return (neg_zero ? test_all (xpositive_sign)
02671           : do_mx_check<double> (*this, mx_inline_any_positive));
02672 }
02673 
02674 bool
02675 Matrix::any_element_is_nan (void) const
02676 {
02677   return do_mx_check<double> (*this, mx_inline_any_nan);
02678 }
02679 
02680 bool
02681 Matrix::any_element_is_inf_or_nan (void) const
02682 {
02683   return ! do_mx_check<double> (*this, mx_inline_all_finite);
02684 }
02685 
02686 bool
02687 Matrix::any_element_not_one_or_zero (void) const
02688 {
02689   return ! test_all (xis_one_or_zero);
02690 }
02691 
02692 bool
02693 Matrix::all_elements_are_int_or_inf_or_nan (void) const
02694 {
02695   return test_all (xis_int_or_inf_or_nan);
02696 }
02697 
02698 // Return nonzero if any element of M is not an integer.  Also extract
02699 // the largest and smallest values and return them in MAX_VAL and MIN_VAL.
02700 
02701 bool
02702 Matrix::all_integers (double& max_val, double& min_val) const
02703 {
02704   octave_idx_type nel = nelem ();
02705 
02706   if (nel > 0)
02707     {
02708       max_val = elem (0);
02709       min_val = elem (0);
02710     }
02711   else
02712     return false;
02713 
02714   for (octave_idx_type i = 0; i < nel; i++)
02715     {
02716       double val = elem (i);
02717 
02718       if (val > max_val)
02719         max_val = val;
02720 
02721       if (val < min_val)
02722         min_val = val;
02723 
02724       if (! xisinteger (val))
02725         return false;
02726     }
02727 
02728   return true;
02729 }
02730 
02731 bool
02732 Matrix::too_large_for_float (void) const
02733 {
02734   return test_all (xtoo_large_for_float);
02735 }
02736 
02737 // FIXME Do these really belong here?  Maybe they should be
02738 // in a base class?
02739 
02740 boolMatrix
02741 Matrix::all (int dim) const
02742 {
02743   return do_mx_red_op<bool, double> (*this, dim, mx_inline_all);
02744 }
02745 
02746 boolMatrix
02747 Matrix::any (int dim) const
02748 {
02749   return do_mx_red_op<bool, double> (*this, dim, mx_inline_any);
02750 }
02751 
02752 Matrix
02753 Matrix::cumprod (int dim) const
02754 {
02755   return do_mx_cum_op<double, double> (*this, dim, mx_inline_cumprod);
02756 }
02757 
02758 Matrix
02759 Matrix::cumsum (int dim) const
02760 {
02761   return do_mx_cum_op<double, double> (*this, dim, mx_inline_cumsum);
02762 }
02763 
02764 Matrix
02765 Matrix::prod (int dim) const
02766 {
02767   return do_mx_red_op<double, double> (*this, dim, mx_inline_prod);
02768 }
02769 
02770 Matrix
02771 Matrix::sum (int dim) const
02772 {
02773   return do_mx_red_op<double, double> (*this, dim, mx_inline_sum);
02774 }
02775 
02776 Matrix
02777 Matrix::sumsq (int dim) const
02778 {
02779   return do_mx_red_op<double, double> (*this, dim, mx_inline_sumsq);
02780 }
02781 
02782 Matrix
02783 Matrix::abs (void) const
02784 {
02785   return do_mx_unary_map<double, double, std::abs> (*this);
02786 }
02787 
02788 Matrix
02789 Matrix::diag (octave_idx_type k) const
02790 {
02791   return MArray<double>::diag (k);
02792 }
02793 
02794 ColumnVector
02795 Matrix::row_min (void) const
02796 {
02797   Array<octave_idx_type> dummy_idx;
02798   return row_min (dummy_idx);
02799 }
02800 
02801 ColumnVector
02802 Matrix::row_min (Array<octave_idx_type>& idx_arg) const
02803 {
02804   ColumnVector result;
02805 
02806   octave_idx_type nr = rows ();
02807   octave_idx_type nc = cols ();
02808 
02809   if (nr > 0 && nc > 0)
02810     {
02811       result.resize (nr);
02812       idx_arg.resize (dim_vector (nr, 1));
02813 
02814       for (octave_idx_type i = 0; i < nr; i++)
02815         {
02816           octave_idx_type idx_j;
02817 
02818           double tmp_min = octave_NaN;
02819 
02820           for (idx_j = 0; idx_j < nc; idx_j++)
02821             {
02822               tmp_min = elem (i, idx_j);
02823 
02824               if (! xisnan (tmp_min))
02825                 break;
02826             }
02827 
02828           for (octave_idx_type j = idx_j+1; j < nc; j++)
02829             {
02830               double tmp = elem (i, j);
02831 
02832               if (xisnan (tmp))
02833                 continue;
02834               else if (tmp < tmp_min)
02835                 {
02836                   idx_j = j;
02837                   tmp_min = tmp;
02838                 }
02839             }
02840 
02841           result.elem (i) = tmp_min;
02842           idx_arg.elem (i) = xisnan (tmp_min) ? 0 : idx_j;
02843         }
02844     }
02845 
02846   return result;
02847 }
02848 
02849 ColumnVector
02850 Matrix::row_max (void) const
02851 {
02852   Array<octave_idx_type> dummy_idx;
02853   return row_max (dummy_idx);
02854 }
02855 
02856 ColumnVector
02857 Matrix::row_max (Array<octave_idx_type>& idx_arg) const
02858 {
02859   ColumnVector result;
02860 
02861   octave_idx_type nr = rows ();
02862   octave_idx_type nc = cols ();
02863 
02864   if (nr > 0 && nc > 0)
02865     {
02866       result.resize (nr);
02867       idx_arg.resize (dim_vector (nr, 1));
02868 
02869       for (octave_idx_type i = 0; i < nr; i++)
02870         {
02871           octave_idx_type idx_j;
02872 
02873           double tmp_max = octave_NaN;
02874 
02875           for (idx_j = 0; idx_j < nc; idx_j++)
02876             {
02877               tmp_max = elem (i, idx_j);
02878 
02879               if (! xisnan (tmp_max))
02880                 break;
02881             }
02882 
02883           for (octave_idx_type j = idx_j+1; j < nc; j++)
02884             {
02885               double tmp = elem (i, j);
02886 
02887               if (xisnan (tmp))
02888                 continue;
02889               else if (tmp > tmp_max)
02890                 {
02891                   idx_j = j;
02892                   tmp_max = tmp;
02893                 }
02894             }
02895 
02896           result.elem (i) = tmp_max;
02897           idx_arg.elem (i) = xisnan (tmp_max) ? 0 : idx_j;
02898         }
02899     }
02900 
02901   return result;
02902 }
02903 
02904 RowVector
02905 Matrix::column_min (void) const
02906 {
02907   Array<octave_idx_type> dummy_idx;
02908   return column_min (dummy_idx);
02909 }
02910 
02911 RowVector
02912 Matrix::column_min (Array<octave_idx_type>& idx_arg) const
02913 {
02914   RowVector result;
02915 
02916   octave_idx_type nr = rows ();
02917   octave_idx_type nc = cols ();
02918 
02919   if (nr > 0 && nc > 0)
02920     {
02921       result.resize (nc);
02922       idx_arg.resize (dim_vector (1, nc));
02923 
02924       for (octave_idx_type j = 0; j < nc; j++)
02925         {
02926           octave_idx_type idx_i;
02927 
02928           double tmp_min = octave_NaN;
02929 
02930           for (idx_i = 0; idx_i < nr; idx_i++)
02931             {
02932               tmp_min = elem (idx_i, j);
02933 
02934               if (! xisnan (tmp_min))
02935                 break;
02936             }
02937 
02938           for (octave_idx_type i = idx_i+1; i < nr; i++)
02939             {
02940               double tmp = elem (i, j);
02941 
02942               if (xisnan (tmp))
02943                 continue;
02944               else if (tmp < tmp_min)
02945                 {
02946                   idx_i = i;
02947                   tmp_min = tmp;
02948                 }
02949             }
02950 
02951           result.elem (j) = tmp_min;
02952           idx_arg.elem (j) = xisnan (tmp_min) ? 0 : idx_i;
02953         }
02954     }
02955 
02956   return result;
02957 }
02958 
02959 RowVector
02960 Matrix::column_max (void) const
02961 {
02962   Array<octave_idx_type> dummy_idx;
02963   return column_max (dummy_idx);
02964 }
02965 
02966 RowVector
02967 Matrix::column_max (Array<octave_idx_type>& idx_arg) const
02968 {
02969   RowVector result;
02970 
02971   octave_idx_type nr = rows ();
02972   octave_idx_type nc = cols ();
02973 
02974   if (nr > 0 && nc > 0)
02975     {
02976       result.resize (nc);
02977       idx_arg.resize (dim_vector (1, nc));
02978 
02979       for (octave_idx_type j = 0; j < nc; j++)
02980         {
02981           octave_idx_type idx_i;
02982 
02983           double tmp_max = octave_NaN;
02984 
02985           for (idx_i = 0; idx_i < nr; idx_i++)
02986             {
02987               tmp_max = elem (idx_i, j);
02988 
02989               if (! xisnan (tmp_max))
02990                 break;
02991             }
02992 
02993           for (octave_idx_type i = idx_i+1; i < nr; i++)
02994             {
02995               double tmp = elem (i, j);
02996 
02997               if (xisnan (tmp))
02998                 continue;
02999               else if (tmp > tmp_max)
03000                 {
03001                   idx_i = i;
03002                   tmp_max = tmp;
03003                 }
03004             }
03005 
03006           result.elem (j) = tmp_max;
03007           idx_arg.elem (j) = xisnan (tmp_max) ? 0 : idx_i;
03008         }
03009     }
03010 
03011   return result;
03012 }
03013 
03014 std::ostream&
03015 operator << (std::ostream& os, const Matrix& a)
03016 {
03017   for (octave_idx_type i = 0; i < a.rows (); i++)
03018     {
03019       for (octave_idx_type j = 0; j < a.cols (); j++)
03020         {
03021           os << " ";
03022           octave_write_double (os, a.elem (i, j));
03023         }
03024       os << "\n";
03025     }
03026   return os;
03027 }
03028 
03029 std::istream&
03030 operator >> (std::istream& is, Matrix& a)
03031 {
03032   octave_idx_type nr = a.rows ();
03033   octave_idx_type nc = a.cols ();
03034 
03035   if (nr > 0 && nc > 0)
03036     {
03037       double tmp;
03038       for (octave_idx_type i = 0; i < nr; i++)
03039         for (octave_idx_type j = 0; j < nc; j++)
03040           {
03041             tmp = octave_read_value<double> (is);
03042             if (is)
03043               a.elem (i, j) = tmp;
03044             else
03045               goto done;
03046           }
03047     }
03048 
03049  done:
03050 
03051   return is;
03052 }
03053 
03054 Matrix
03055 Givens (double x, double y)
03056 {
03057   double cc, s, temp_r;
03058 
03059   F77_FUNC (dlartg, DLARTG) (x, y, cc, s, temp_r);
03060 
03061   Matrix g (2, 2);
03062 
03063   g.elem (0, 0) = cc;
03064   g.elem (1, 1) = cc;
03065   g.elem (0, 1) = s;
03066   g.elem (1, 0) = -s;
03067 
03068   return g;
03069 }
03070 
03071 Matrix
03072 Sylvester (const Matrix& a, const Matrix& b, const Matrix& c)
03073 {
03074   Matrix retval;
03075 
03076   // FIXME -- need to check that a, b, and c are all the same
03077   // size.
03078 
03079   // Compute Schur decompositions.
03080 
03081   SCHUR as (a, "U");
03082   SCHUR bs (b, "U");
03083 
03084   // Transform c to new coordinates.
03085 
03086   Matrix ua = as.unitary_matrix ();
03087   Matrix sch_a = as.schur_matrix ();
03088 
03089   Matrix ub = bs.unitary_matrix ();
03090   Matrix sch_b = bs.schur_matrix ();
03091 
03092   Matrix cx = ua.transpose () * c * ub;
03093 
03094   // Solve the sylvester equation, back-transform, and return the
03095   // solution.
03096 
03097   octave_idx_type a_nr = a.rows ();
03098   octave_idx_type b_nr = b.rows ();
03099 
03100   double scale;
03101   octave_idx_type info;
03102 
03103   double *pa = sch_a.fortran_vec ();
03104   double *pb = sch_b.fortran_vec ();
03105   double *px = cx.fortran_vec ();
03106 
03107   F77_XFCN (dtrsyl, DTRSYL, (F77_CONST_CHAR_ARG2 ("N", 1),
03108                              F77_CONST_CHAR_ARG2 ("N", 1),
03109                              1, a_nr, b_nr, pa, a_nr, pb,
03110                              b_nr, px, a_nr, scale, info
03111                              F77_CHAR_ARG_LEN (1)
03112                              F77_CHAR_ARG_LEN (1)));
03113 
03114 
03115   // FIXME -- check info?
03116 
03117   retval = -ua*cx*ub.transpose ();
03118 
03119   return retval;
03120 }
03121 
03122 // matrix by matrix -> matrix operations
03123 
03124 /* Simple Dot Product, Matrix-Vector and Matrix-Matrix Unit tests
03125 %!assert([1 2 3] * [ 4 ; 5 ; 6], 32, 1e-14)
03126 %!assert([1 2 ; 3 4 ] * [5 ; 6], [17 ; 39 ], 1e-14)
03127 %!assert([1 2 ; 3 4 ] * [5 6 ; 7 8], [19 22; 43 50], 1e-14)
03128 */
03129 
03130 /* Test some simple identities
03131 %!shared M, cv, rv, Mt, rvt
03132 %! M = randn(10,10)+100*eye(10,10);
03133 %! Mt = M';
03134 %! cv = randn(10,1);
03135 %! rv = randn(1,10);
03136 %! rvt = rv';
03137 %!assert([M*cv,M*cv],M*[cv,cv],1e-13)
03138 %!assert([M'*cv,M'*cv],M'*[cv,cv],1e-13)
03139 %!assert([rv*M;rv*M],[rv;rv]*M,1e-13)
03140 %!assert([rv*M';rv*M'],[rv;rv]*M',1e-13)
03141 %!assert(2*rv*cv,[rv,rv]*[cv;cv],1e-13)
03142 %!assert(M'\cv,Mt\cv,1e-14)
03143 %!assert(M'\rv',Mt\rvt,1e-14)
03144 */
03145 
03146 static inline char
03147 get_blas_trans_arg (bool trans)
03148 {
03149   return trans ? 'T' : 'N';
03150 }
03151 
03152 // the general GEMM operation
03153 
03154 Matrix
03155 xgemm (const Matrix& a, const Matrix& b,
03156        blas_trans_type transa, blas_trans_type transb)
03157 {
03158   Matrix retval;
03159 
03160   bool tra = transa != blas_no_trans, trb = transb != blas_no_trans;
03161 
03162   octave_idx_type a_nr = tra ? a.cols () : a.rows ();
03163   octave_idx_type a_nc = tra ? a.rows () : a.cols ();
03164 
03165   octave_idx_type b_nr = trb ? b.cols () : b.rows ();
03166   octave_idx_type b_nc = trb ? b.rows () : b.cols ();
03167 
03168   if (a_nc != b_nr)
03169     gripe_nonconformant ("operator *", a_nr, a_nc, b_nr, b_nc);
03170   else
03171     {
03172       if (a_nr == 0 || a_nc == 0 || b_nc == 0)
03173         retval = Matrix (a_nr, b_nc, 0.0);
03174       else if (a.data () == b.data () && a_nr == b_nc && tra != trb)
03175         {
03176           octave_idx_type lda = a.rows ();
03177 
03178           retval = Matrix (a_nr, b_nc);
03179           double *c = retval.fortran_vec ();
03180 
03181           const char ctra = get_blas_trans_arg (tra);
03182           F77_XFCN (dsyrk, DSYRK, (F77_CONST_CHAR_ARG2 ("U", 1),
03183                                    F77_CONST_CHAR_ARG2 (&ctra, 1),
03184                                    a_nr, a_nc, 1.0,
03185                                    a.data (), lda, 0.0, c, a_nr
03186                                    F77_CHAR_ARG_LEN (1)
03187                                    F77_CHAR_ARG_LEN (1)));
03188           for (int j = 0; j < a_nr; j++)
03189             for (int i = 0; i < j; i++)
03190               retval.xelem (j,i) = retval.xelem (i,j);
03191 
03192         }
03193       else
03194         {
03195           octave_idx_type lda = a.rows (), tda = a.cols ();
03196           octave_idx_type ldb = b.rows (), tdb = b.cols ();
03197 
03198           retval = Matrix (a_nr, b_nc);
03199           double *c = retval.fortran_vec ();
03200 
03201           if (b_nc == 1)
03202             {
03203               if (a_nr == 1)
03204                 F77_FUNC (xddot, XDDOT) (a_nc, a.data (), 1, b.data (), 1, *c);
03205               else
03206                 {
03207                   const char ctra = get_blas_trans_arg (tra);
03208                   F77_XFCN (dgemv, DGEMV, (F77_CONST_CHAR_ARG2 (&ctra, 1),
03209                                            lda, tda, 1.0,  a.data (), lda,
03210                                            b.data (), 1, 0.0, c, 1
03211                                            F77_CHAR_ARG_LEN (1)));
03212                 }
03213             }
03214           else if (a_nr == 1)
03215             {
03216               const char crevtrb = get_blas_trans_arg (! trb);
03217               F77_XFCN (dgemv, DGEMV, (F77_CONST_CHAR_ARG2 (&crevtrb, 1),
03218                                        ldb, tdb, 1.0,  b.data (), ldb,
03219                                        a.data (), 1, 0.0, c, 1
03220                                        F77_CHAR_ARG_LEN (1)));
03221             }
03222           else
03223             {
03224               const char ctra = get_blas_trans_arg (tra);
03225               const char ctrb = get_blas_trans_arg (trb);
03226               F77_XFCN (dgemm, DGEMM, (F77_CONST_CHAR_ARG2 (&ctra, 1),
03227                                        F77_CONST_CHAR_ARG2 (&ctrb, 1),
03228                                        a_nr, b_nc, a_nc, 1.0, a.data (),
03229                                        lda, b.data (), ldb, 0.0, c, a_nr
03230                                        F77_CHAR_ARG_LEN (1)
03231                                        F77_CHAR_ARG_LEN (1)));
03232             }
03233         }
03234     }
03235 
03236   return retval;
03237 }
03238 
03239 Matrix
03240 operator * (const Matrix& a, const Matrix& b)
03241 {
03242   return xgemm (a, b);
03243 }
03244 
03245 // FIXME -- it would be nice to share code among the min/max
03246 // functions below.
03247 
03248 #define EMPTY_RETURN_CHECK(T) \
03249   if (nr == 0 || nc == 0) \
03250     return T (nr, nc);
03251 
03252 Matrix
03253 min (double d, const Matrix& m)
03254 {
03255   octave_idx_type nr = m.rows ();
03256   octave_idx_type nc = m.columns ();
03257 
03258   EMPTY_RETURN_CHECK (Matrix);
03259 
03260   Matrix result (nr, nc);
03261 
03262   for (octave_idx_type j = 0; j < nc; j++)
03263     for (octave_idx_type i = 0; i < nr; i++)
03264       {
03265         octave_quit ();
03266         result (i, j) = xmin (d, m (i, j));
03267       }
03268 
03269   return result;
03270 }
03271 
03272 Matrix
03273 min (const Matrix& m, double d)
03274 {
03275   octave_idx_type nr = m.rows ();
03276   octave_idx_type nc = m.columns ();
03277 
03278   EMPTY_RETURN_CHECK (Matrix);
03279 
03280   Matrix result (nr, nc);
03281 
03282   for (octave_idx_type j = 0; j < nc; j++)
03283     for (octave_idx_type i = 0; i < nr; i++)
03284       {
03285         octave_quit ();
03286         result (i, j) = xmin (m (i, j), d);
03287       }
03288 
03289   return result;
03290 }
03291 
03292 Matrix
03293 min (const Matrix& a, const Matrix& b)
03294 {
03295   octave_idx_type nr = a.rows ();
03296   octave_idx_type nc = a.columns ();
03297 
03298   if (nr != b.rows () || nc != b.columns ())
03299     {
03300       (*current_liboctave_error_handler)
03301         ("two-arg min expecting args of same size");
03302       return Matrix ();
03303     }
03304 
03305   EMPTY_RETURN_CHECK (Matrix);
03306 
03307   Matrix result (nr, nc);
03308 
03309   for (octave_idx_type j = 0; j < nc; j++)
03310     for (octave_idx_type i = 0; i < nr; i++)
03311       {
03312         octave_quit ();
03313         result (i, j) = xmin (a (i, j), b (i, j));
03314       }
03315 
03316   return result;
03317 }
03318 
03319 Matrix
03320 max (double d, const Matrix& m)
03321 {
03322   octave_idx_type nr = m.rows ();
03323   octave_idx_type nc = m.columns ();
03324 
03325   EMPTY_RETURN_CHECK (Matrix);
03326 
03327   Matrix result (nr, nc);
03328 
03329   for (octave_idx_type j = 0; j < nc; j++)
03330     for (octave_idx_type i = 0; i < nr; i++)
03331       {
03332         octave_quit ();
03333         result (i, j) = xmax (d, m (i, j));
03334       }
03335 
03336   return result;
03337 }
03338 
03339 Matrix
03340 max (const Matrix& m, double d)
03341 {
03342   octave_idx_type nr = m.rows ();
03343   octave_idx_type nc = m.columns ();
03344 
03345   EMPTY_RETURN_CHECK (Matrix);
03346 
03347   Matrix result (nr, nc);
03348 
03349   for (octave_idx_type j = 0; j < nc; j++)
03350     for (octave_idx_type i = 0; i < nr; i++)
03351       {
03352         octave_quit ();
03353         result (i, j) = xmax (m (i, j), d);
03354       }
03355 
03356   return result;
03357 }
03358 
03359 Matrix
03360 max (const Matrix& a, const Matrix& b)
03361 {
03362   octave_idx_type nr = a.rows ();
03363   octave_idx_type nc = a.columns ();
03364 
03365   if (nr != b.rows () || nc != b.columns ())
03366     {
03367       (*current_liboctave_error_handler)
03368         ("two-arg max expecting args of same size");
03369       return Matrix ();
03370     }
03371 
03372   EMPTY_RETURN_CHECK (Matrix);
03373 
03374   Matrix result (nr, nc);
03375 
03376   for (octave_idx_type j = 0; j < nc; j++)
03377     for (octave_idx_type i = 0; i < nr; i++)
03378       {
03379         octave_quit ();
03380         result (i, j) = xmax (a (i, j), b (i, j));
03381       }
03382 
03383   return result;
03384 }
03385 
03386 Matrix linspace (const ColumnVector& x1,
03387                  const ColumnVector& x2,
03388                  octave_idx_type n)
03389 
03390 {
03391   if (n < 1) n = 1;
03392 
03393   octave_idx_type m = x1.length ();
03394 
03395   if (x2.length () != m)
03396     (*current_liboctave_error_handler) ("linspace: vectors must be of equal length");
03397 
03398   NoAlias<Matrix> retval;
03399 
03400   retval.clear (m, n);
03401   for (octave_idx_type i = 0; i < m; i++)
03402     retval(i, 0) = x1(i);
03403 
03404   // The last column is not needed while using delta.
03405   double *delta = &retval(0, n-1);
03406   for (octave_idx_type i = 0; i < m; i++)
03407     delta[i] = (x2(i) - x1(i)) / (n - 1);
03408 
03409   for (octave_idx_type j = 1; j < n-1; j++)
03410     for (octave_idx_type i = 0; i < m; i++)
03411       retval(i, j) = x1(i) + j*delta[i];
03412 
03413   for (octave_idx_type i = 0; i < m; i++)
03414     retval(i, n-1) = x2(i);
03415 
03416   return retval;
03417 }
03418 
03419 MS_CMP_OPS (Matrix, double)
03420 MS_BOOL_OPS (Matrix, double)
03421 
03422 SM_CMP_OPS (double, Matrix)
03423 SM_BOOL_OPS (double, Matrix)
03424 
03425 MM_CMP_OPS (Matrix, Matrix)
03426 MM_BOOL_OPS (Matrix, Matrix)
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines