dSparse.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 2004-2012 David Bateman
00004 Copyright (C) 1998-2004 Andy Adler
00005 Copyright (C) 2010 VZLU Prague
00006 
00007 This file is part of Octave.
00008 
00009 Octave is free software; you can redistribute it and/or modify it
00010 under the terms of the GNU General Public License as published by the
00011 Free Software Foundation; either version 3 of the License, or (at your
00012 option) any later version.
00013 
00014 Octave is distributed in the hope that it will be useful, but WITHOUT
00015 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00016 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00017 for more details.
00018 
00019 You should have received a copy of the GNU General Public License
00020 along with Octave; see the file COPYING.  If not, see
00021 <http://www.gnu.org/licenses/>.
00022 
00023 */
00024 
00025 #ifdef HAVE_CONFIG_H
00026 #include <config.h>
00027 #endif
00028 
00029 #include <cfloat>
00030 
00031 #include <iostream>
00032 #include <vector>
00033 #include <functional>
00034 
00035 #include "quit.h"
00036 #include "lo-ieee.h"
00037 #include "lo-mappers.h"
00038 #include "f77-fcn.h"
00039 #include "dRowVector.h"
00040 #include "oct-locbuf.h"
00041 
00042 #include "dDiagMatrix.h"
00043 #include "CSparse.h"
00044 #include "boolSparse.h"
00045 #include "dSparse.h"
00046 #include "functor.h"
00047 #include "oct-spparms.h"
00048 #include "SparsedbleLU.h"
00049 #include "MatrixType.h"
00050 #include "oct-sparse.h"
00051 #include "sparse-util.h"
00052 #include "SparsedbleCHOL.h"
00053 #include "SparseQR.h"
00054 
00055 #include "Sparse-diag-op-defs.h"
00056 
00057 #include "Sparse-perm-op-defs.h"
00058 
00059 // Define whether to use a basic QR solver or one that uses a Dulmange
00060 // Mendelsohn factorization to seperate the problem into under-determined,
00061 // well-determined and over-determined parts and solves them seperately
00062 #ifndef USE_QRSOLVE
00063 #include "sparse-dmsolve.cc"
00064 #endif
00065 
00066 // Fortran functions we call.
00067 extern "C"
00068 {
00069   F77_RET_T
00070   F77_FUNC (dgbtrf, DGBTRF) (const octave_idx_type&, const octave_idx_type&,
00071                              const octave_idx_type&, const octave_idx_type&,
00072                              double*, const octave_idx_type&,
00073                              octave_idx_type*, octave_idx_type&);
00074 
00075   F77_RET_T
00076   F77_FUNC (dgbtrs, DGBTRS) (F77_CONST_CHAR_ARG_DECL,
00077                              const octave_idx_type&, const octave_idx_type&,
00078                              const octave_idx_type&, const octave_idx_type&,
00079                              const double*, const octave_idx_type&,
00080                              const octave_idx_type*, double*,
00081                              const octave_idx_type&, octave_idx_type&
00082                              F77_CHAR_ARG_LEN_DECL);
00083 
00084   F77_RET_T
00085   F77_FUNC (dgbcon, DGBCON) (F77_CONST_CHAR_ARG_DECL,
00086                              const octave_idx_type&, const octave_idx_type&,
00087                              const octave_idx_type&, double*,
00088                              const octave_idx_type&, const octave_idx_type*,
00089                              const double&, double&, double*,
00090                              octave_idx_type*, octave_idx_type&
00091                              F77_CHAR_ARG_LEN_DECL);
00092 
00093   F77_RET_T
00094   F77_FUNC (dpbtrf, DPBTRF) (F77_CONST_CHAR_ARG_DECL,
00095                              const octave_idx_type&, const octave_idx_type&,
00096                              double*, const octave_idx_type&, octave_idx_type&
00097                              F77_CHAR_ARG_LEN_DECL);
00098 
00099   F77_RET_T
00100   F77_FUNC (dpbtrs, DPBTRS) (F77_CONST_CHAR_ARG_DECL,
00101                              const octave_idx_type&, const octave_idx_type&,
00102                              const octave_idx_type&, double*,
00103                              const octave_idx_type&, double*,
00104                              const octave_idx_type&, octave_idx_type&
00105                              F77_CHAR_ARG_LEN_DECL);
00106 
00107   F77_RET_T
00108   F77_FUNC (dpbcon, DPBCON) (F77_CONST_CHAR_ARG_DECL,
00109                              const octave_idx_type&, const octave_idx_type&,
00110                              double*, const octave_idx_type&,
00111                              const double&, double&, double*,
00112                              octave_idx_type*, octave_idx_type&
00113                              F77_CHAR_ARG_LEN_DECL);
00114   F77_RET_T
00115   F77_FUNC (dptsv, DPTSV) (const octave_idx_type&, const octave_idx_type&,
00116                            double*, double*, double*, const octave_idx_type&,
00117                            octave_idx_type&);
00118 
00119   F77_RET_T
00120   F77_FUNC (dgtsv, DGTSV) (const octave_idx_type&, const octave_idx_type&,
00121                            double*, double*, double*, double*,
00122                            const octave_idx_type&, octave_idx_type&);
00123 
00124   F77_RET_T
00125   F77_FUNC (dgttrf, DGTTRF) (const octave_idx_type&, double*, double*,
00126                              double*, double*, octave_idx_type*,
00127                              octave_idx_type&);
00128 
00129   F77_RET_T
00130   F77_FUNC (dgttrs, DGTTRS) (F77_CONST_CHAR_ARG_DECL,
00131                              const octave_idx_type&, const octave_idx_type&,
00132                              const double*, const double*, const double*,
00133                              const double*, const octave_idx_type*,
00134                              double *, const octave_idx_type&, octave_idx_type&
00135                              F77_CHAR_ARG_LEN_DECL);
00136 
00137   F77_RET_T
00138   F77_FUNC (zptsv, ZPTSV) (const octave_idx_type&, const octave_idx_type&,
00139                            double*, Complex*, Complex*, const octave_idx_type&,
00140                            octave_idx_type&);
00141 
00142   F77_RET_T
00143   F77_FUNC (zgtsv, ZGTSV) (const octave_idx_type&, const octave_idx_type&,
00144                            Complex*, Complex*, Complex*, Complex*,
00145                            const octave_idx_type&, octave_idx_type&);
00146 
00147 }
00148 
00149 SparseMatrix::SparseMatrix (const SparseBoolMatrix &a)
00150   : MSparse<double> (a.rows (), a.cols (), a.nnz ())
00151 {
00152   octave_idx_type nc = cols ();
00153   octave_idx_type nz = a.nnz ();
00154 
00155   for (octave_idx_type i = 0; i < nc + 1; i++)
00156     cidx (i) = a.cidx (i);
00157 
00158   for (octave_idx_type i = 0; i < nz; i++)
00159     {
00160       data (i) = a.data (i);
00161       ridx (i) = a.ridx (i);
00162     }
00163 }
00164 
00165 SparseMatrix::SparseMatrix (const DiagMatrix& a)
00166   : MSparse<double> (a.rows (), a.cols (), a.length ())
00167 {
00168   octave_idx_type j = 0, l = a.length ();
00169   for (octave_idx_type i = 0; i < l; i++)
00170     {
00171       cidx (i) = j;
00172       if (a(i, i) != 0.0)
00173         {
00174           data (j) = a(i, i);
00175           ridx (j) = i;
00176           j++;
00177         }
00178     }
00179   for (octave_idx_type i = l; i <= a.cols (); i++)
00180     cidx(i) = j;
00181 }
00182 
00183 bool
00184 SparseMatrix::operator == (const SparseMatrix& a) const
00185 {
00186   octave_idx_type nr = rows ();
00187   octave_idx_type nc = cols ();
00188   octave_idx_type nz = nnz ();
00189   octave_idx_type nr_a = a.rows ();
00190   octave_idx_type nc_a = a.cols ();
00191   octave_idx_type nz_a = a.nnz ();
00192 
00193   if (nr != nr_a || nc != nc_a || nz != nz_a)
00194     return false;
00195 
00196   for (octave_idx_type i = 0; i < nc + 1; i++)
00197     if (cidx(i) != a.cidx(i))
00198         return false;
00199 
00200   for (octave_idx_type i = 0; i < nz; i++)
00201     if (data(i) != a.data(i) || ridx(i) != a.ridx(i))
00202       return false;
00203 
00204   return true;
00205 }
00206 
00207 bool
00208 SparseMatrix::operator != (const SparseMatrix& a) const
00209 {
00210   return !(*this == a);
00211 }
00212 
00213 bool
00214 SparseMatrix::is_symmetric (void) const
00215 {
00216   octave_idx_type nr = rows ();
00217   octave_idx_type nc = cols ();
00218 
00219   if (nr == nc && nr > 0)
00220     {
00221       for (octave_idx_type j = 0; j < nc; j++)
00222         {
00223           for (octave_idx_type i = cidx(j); i < cidx(j+1); i++)
00224             {
00225               octave_idx_type ri = ridx(i);
00226 
00227               if (ri != j)
00228                 {
00229                   bool found = false;
00230 
00231                   for (octave_idx_type k = cidx(ri); k < cidx(ri+1); k++)
00232                     {
00233                       if (ridx(k) == j)
00234                         {
00235                           if (data(i) == data(k))
00236                             found = true;
00237                           break;
00238                         }
00239                     }
00240 
00241                   if (! found)
00242                     return false;
00243                 }
00244             }
00245         }
00246 
00247       return true;
00248     }
00249 
00250   return false;
00251 }
00252 
00253 SparseMatrix&
00254 SparseMatrix::insert (const SparseMatrix& a, octave_idx_type r, octave_idx_type c)
00255 {
00256   MSparse<double>::insert (a, r, c);
00257   return *this;
00258 }
00259 
00260 SparseMatrix&
00261 SparseMatrix::insert (const SparseMatrix& a, const Array<octave_idx_type>& indx)
00262 {
00263   MSparse<double>::insert (a, indx);
00264   return *this;
00265 }
00266 
00267 SparseMatrix
00268 SparseMatrix::max (int dim) const
00269 {
00270   Array<octave_idx_type> dummy_idx;
00271   return max (dummy_idx, dim);
00272 }
00273 
00274 SparseMatrix
00275 SparseMatrix::max (Array<octave_idx_type>& idx_arg, int dim) const
00276 {
00277   SparseMatrix result;
00278   dim_vector dv = dims ();
00279 
00280   if (dv.numel () == 0 || dim >= dv.length ())
00281     return result;
00282 
00283   if (dim < 0)
00284     dim = dv.first_non_singleton ();
00285 
00286   octave_idx_type nr = dv(0);
00287   octave_idx_type nc = dv(1);
00288 
00289   if (dim == 0)
00290     {
00291       idx_arg.clear (1, nc);
00292       octave_idx_type nel = 0;
00293       for (octave_idx_type j = 0; j < nc; j++)
00294         {
00295           double tmp_max = octave_NaN;
00296           octave_idx_type idx_j = 0;
00297           for (octave_idx_type i = cidx(j); i < cidx(j+1); i++)
00298             {
00299               if (ridx(i) != idx_j)
00300                 break;
00301               else
00302                 idx_j++;
00303             }
00304 
00305           if (idx_j != nr)
00306             tmp_max = 0.;
00307 
00308           for (octave_idx_type i = cidx(j); i < cidx(j+1); i++)
00309             {
00310               double tmp = data (i);
00311 
00312               if (xisnan (tmp))
00313                 continue;
00314               else if (xisnan (tmp_max) || tmp > tmp_max)
00315                 {
00316                   idx_j = ridx (i);
00317                   tmp_max = tmp;
00318                 }
00319 
00320             }
00321 
00322           idx_arg.elem (j) = xisnan (tmp_max) ? 0 : idx_j;
00323           if (tmp_max != 0.)
00324             nel++;
00325         }
00326 
00327       result = SparseMatrix (1, nc, nel);
00328 
00329       octave_idx_type ii = 0;
00330       result.xcidx (0) = 0;
00331       for (octave_idx_type j = 0; j < nc; j++)
00332         {
00333           double tmp = elem (idx_arg(j), j);
00334           if (tmp != 0.)
00335             {
00336               result.xdata (ii) = tmp;
00337               result.xridx (ii++) = 0;
00338             }
00339           result.xcidx (j+1) = ii;
00340 
00341         }
00342     }
00343   else
00344     {
00345       idx_arg.resize (dim_vector  (nr, 1), 0);
00346 
00347       for (octave_idx_type i = cidx(0); i < cidx(1); i++)
00348         idx_arg.elem(ridx(i)) = -1;
00349 
00350       for (octave_idx_type j = 0; j < nc; j++)
00351         for (octave_idx_type i = 0; i < nr; i++)
00352           {
00353             if (idx_arg.elem(i) != -1)
00354               continue;
00355             bool found = false;
00356             for (octave_idx_type k = cidx(j); k < cidx(j+1); k++)
00357               if (ridx(k) == i)
00358                 {
00359                   found = true;
00360                   break;
00361                 }
00362 
00363             if (!found)
00364               idx_arg.elem(i) = j;
00365 
00366           }
00367 
00368       for (octave_idx_type j = 0; j < nc; j++)
00369         {
00370           for (octave_idx_type i = cidx(j); i < cidx(j+1); i++)
00371             {
00372               octave_idx_type ir = ridx (i);
00373               octave_idx_type ix = idx_arg.elem (ir);
00374               double tmp = data (i);
00375 
00376               if (xisnan (tmp))
00377                 continue;
00378               else if (ix == -1 || tmp > elem (ir, ix))
00379                 idx_arg.elem (ir) = j;
00380             }
00381         }
00382 
00383       octave_idx_type nel = 0;
00384       for (octave_idx_type j = 0; j < nr; j++)
00385         if (idx_arg.elem(j) == -1 || elem (j, idx_arg.elem (j)) != 0.)
00386           nel++;
00387 
00388       result = SparseMatrix (nr, 1, nel);
00389 
00390       octave_idx_type ii = 0;
00391       result.xcidx (0) = 0;
00392       result.xcidx (1) = nel;
00393       for (octave_idx_type j = 0; j < nr; j++)
00394         {
00395           if (idx_arg(j) == -1)
00396             {
00397               idx_arg(j) = 0;
00398               result.xdata (ii) = octave_NaN;
00399               result.xridx (ii++) = j;
00400             }
00401           else
00402             {
00403               double tmp = elem (j, idx_arg(j));
00404               if (tmp != 0.)
00405                 {
00406                   result.xdata (ii) = tmp;
00407                   result.xridx (ii++) = j;
00408                 }
00409             }
00410         }
00411     }
00412 
00413   return result;
00414 }
00415 
00416 SparseMatrix
00417 SparseMatrix::min (int dim) const
00418 {
00419   Array<octave_idx_type> dummy_idx;
00420   return min (dummy_idx, dim);
00421 }
00422 
00423 SparseMatrix
00424 SparseMatrix::min (Array<octave_idx_type>& idx_arg, int dim) const
00425 {
00426   SparseMatrix result;
00427   dim_vector dv = dims ();
00428 
00429   if (dv.numel () == 0 || dim >= dv.length ())
00430     return result;
00431 
00432   if (dim < 0)
00433     dim = dv.first_non_singleton ();
00434 
00435   octave_idx_type nr = dv(0);
00436   octave_idx_type nc = dv(1);
00437 
00438   if (dim == 0)
00439     {
00440       idx_arg.clear (1, nc);
00441       octave_idx_type nel = 0;
00442       for (octave_idx_type j = 0; j < nc; j++)
00443         {
00444           double tmp_min = octave_NaN;
00445           octave_idx_type idx_j = 0;
00446           for (octave_idx_type i = cidx(j); i < cidx(j+1); i++)
00447             {
00448               if (ridx(i) != idx_j)
00449                 break;
00450               else
00451                 idx_j++;
00452             }
00453 
00454           if (idx_j != nr)
00455             tmp_min = 0.;
00456 
00457           for (octave_idx_type i = cidx(j); i < cidx(j+1); i++)
00458             {
00459               double tmp = data (i);
00460 
00461               if (xisnan (tmp))
00462                 continue;
00463               else if (xisnan (tmp_min) || tmp < tmp_min)
00464                 {
00465                   idx_j = ridx (i);
00466                   tmp_min = tmp;
00467                 }
00468 
00469             }
00470 
00471           idx_arg.elem (j) = xisnan (tmp_min) ? 0 : idx_j;
00472           if (tmp_min != 0.)
00473             nel++;
00474         }
00475 
00476       result = SparseMatrix (1, nc, nel);
00477 
00478       octave_idx_type ii = 0;
00479       result.xcidx (0) = 0;
00480       for (octave_idx_type j = 0; j < nc; j++)
00481         {
00482           double tmp = elem (idx_arg(j), j);
00483           if (tmp != 0.)
00484             {
00485               result.xdata (ii) = tmp;
00486               result.xridx (ii++) = 0;
00487             }
00488           result.xcidx (j+1) = ii;
00489 
00490         }
00491     }
00492   else
00493     {
00494       idx_arg.resize (dim_vector (nr, 1), 0);
00495 
00496       for (octave_idx_type i = cidx(0); i < cidx(1); i++)
00497         idx_arg.elem(ridx(i)) = -1;
00498 
00499       for (octave_idx_type j = 0; j < nc; j++)
00500         for (octave_idx_type i = 0; i < nr; i++)
00501           {
00502             if (idx_arg.elem(i) != -1)
00503               continue;
00504             bool found = false;
00505             for (octave_idx_type k = cidx(j); k < cidx(j+1); k++)
00506               if (ridx(k) == i)
00507                 {
00508                   found = true;
00509                   break;
00510                 }
00511 
00512             if (!found)
00513               idx_arg.elem(i) = j;
00514 
00515           }
00516 
00517       for (octave_idx_type j = 0; j < nc; j++)
00518         {
00519           for (octave_idx_type i = cidx(j); i < cidx(j+1); i++)
00520             {
00521               octave_idx_type ir = ridx (i);
00522               octave_idx_type ix = idx_arg.elem (ir);
00523               double tmp = data (i);
00524 
00525               if (xisnan (tmp))
00526                 continue;
00527               else if (ix == -1 || tmp < elem (ir, ix))
00528                 idx_arg.elem (ir) = j;
00529             }
00530         }
00531 
00532       octave_idx_type nel = 0;
00533       for (octave_idx_type j = 0; j < nr; j++)
00534         if (idx_arg.elem(j) == -1 || elem (j, idx_arg.elem (j)) != 0.)
00535           nel++;
00536 
00537       result = SparseMatrix (nr, 1, nel);
00538 
00539       octave_idx_type ii = 0;
00540       result.xcidx (0) = 0;
00541       result.xcidx (1) = nel;
00542       for (octave_idx_type j = 0; j < nr; j++)
00543         {
00544           if (idx_arg(j) == -1)
00545             {
00546               idx_arg(j) = 0;
00547               result.xdata (ii) = octave_NaN;
00548               result.xridx (ii++) = j;
00549             }
00550           else
00551             {
00552               double tmp = elem (j, idx_arg(j));
00553               if (tmp != 0.)
00554                 {
00555                   result.xdata (ii) = tmp;
00556                   result.xridx (ii++) = j;
00557                 }
00558             }
00559         }
00560     }
00561 
00562   return result;
00563 }
00564 
00565 RowVector
00566 SparseMatrix::row (octave_idx_type i) const
00567 {
00568   octave_idx_type nc = columns ();
00569   RowVector retval (nc, 0);
00570 
00571   for (octave_idx_type j = 0; j < nc; j++)
00572     for (octave_idx_type k = cidx (j); k < cidx (j+1); k++)
00573       {
00574         if (ridx (k) == i)
00575           {
00576             retval(j) = data (k);
00577             break;
00578           }
00579       }
00580 
00581   return retval;
00582 }
00583 
00584 ColumnVector
00585 SparseMatrix::column (octave_idx_type i) const
00586 {
00587   octave_idx_type nr = rows ();
00588   ColumnVector retval (nr, 0);
00589 
00590   for (octave_idx_type k = cidx (i); k < cidx (i+1); k++)
00591     retval(ridx (k)) = data (k);
00592 
00593   return retval;
00594 }
00595 
00596 SparseMatrix
00597 SparseMatrix::concat (const SparseMatrix& rb, const Array<octave_idx_type>& ra_idx)
00598 {
00599   // Don't use numel to avoid all possiblity of an overflow
00600   if (rb.rows () > 0 && rb.cols () > 0)
00601     insert (rb, ra_idx(0), ra_idx(1));
00602   return *this;
00603 }
00604 
00605 SparseComplexMatrix
00606 SparseMatrix::concat (const SparseComplexMatrix& rb, const Array<octave_idx_type>& ra_idx)
00607 {
00608   SparseComplexMatrix retval (*this);
00609   if (rb.rows () > 0 && rb.cols () > 0)
00610     retval.insert (rb, ra_idx(0), ra_idx(1));
00611   return retval;
00612 }
00613 
00614 SparseMatrix
00615 real (const SparseComplexMatrix& a)
00616 {
00617   octave_idx_type nr = a.rows ();
00618   octave_idx_type nc = a.cols ();
00619   octave_idx_type nz = a.nnz ();
00620   SparseMatrix r (nr, nc, nz);
00621 
00622   for (octave_idx_type i = 0; i < nc +1; i++)
00623     r.cidx(i) = a.cidx(i);
00624 
00625   for (octave_idx_type i = 0; i < nz; i++)
00626     {
00627       r.data(i) = std::real (a.data(i));
00628       r.ridx(i) = a.ridx(i);
00629     }
00630 
00631   return r;
00632 }
00633 
00634 SparseMatrix
00635 imag (const SparseComplexMatrix& a)
00636 {
00637   octave_idx_type nr = a.rows ();
00638   octave_idx_type nc = a.cols ();
00639   octave_idx_type nz = a.nnz ();
00640   SparseMatrix r (nr, nc, nz);
00641 
00642   for (octave_idx_type i = 0; i < nc +1; i++)
00643     r.cidx(i) = a.cidx(i);
00644 
00645   for (octave_idx_type i = 0; i < nz; i++)
00646     {
00647       r.data(i) = std::imag (a.data(i));
00648       r.ridx(i) = a.ridx(i);
00649     }
00650 
00651   return r;
00652 }
00653 
00654 SparseMatrix
00655 atan2 (const double& x, const SparseMatrix& y)
00656 {
00657   octave_idx_type nr = y.rows ();
00658   octave_idx_type nc = y.cols ();
00659 
00660   if (x == 0.)
00661     return SparseMatrix (nr, nc);
00662   else
00663     {
00664       // Its going to be basically full, so this is probably the
00665       // best way to handle it.
00666       Matrix tmp (nr, nc, atan2 (x, 0.));
00667 
00668       for (octave_idx_type j = 0; j < nc; j++)
00669         for (octave_idx_type i = y.cidx (j); i < y.cidx (j+1); i++)
00670           tmp.elem (y.ridx(i), j) = atan2 (x, y.data(i));
00671 
00672       return SparseMatrix (tmp);
00673     }
00674 }
00675 
00676 SparseMatrix
00677 atan2 (const SparseMatrix& x, const double& y)
00678 {
00679   octave_idx_type nr = x.rows ();
00680   octave_idx_type nc = x.cols ();
00681   octave_idx_type nz = x.nnz ();
00682 
00683   SparseMatrix retval (nr, nc, nz);
00684 
00685   octave_idx_type ii = 0;
00686   retval.xcidx(0) = 0;
00687   for (octave_idx_type i = 0; i < nc; i++)
00688     {
00689       for (octave_idx_type j = x.cidx(i); j < x.cidx(i+1); j++)
00690         {
00691           double tmp = atan2 (x.data(j), y);
00692           if (tmp != 0.)
00693             {
00694               retval.xdata (ii) = tmp;
00695               retval.xridx (ii++) = x.ridx (j);
00696             }
00697         }
00698       retval.xcidx (i+1) = ii;
00699     }
00700 
00701   if (ii != nz)
00702     {
00703       SparseMatrix retval2 (nr, nc, ii);
00704       for (octave_idx_type i = 0; i < nc+1; i++)
00705         retval2.xcidx (i) = retval.cidx (i);
00706       for (octave_idx_type i = 0; i < ii; i++)
00707         {
00708           retval2.xdata (i) = retval.data (i);
00709           retval2.xridx (i) = retval.ridx (i);
00710         }
00711       return retval2;
00712     }
00713   else
00714     return retval;
00715 }
00716 
00717 SparseMatrix
00718 atan2 (const SparseMatrix& x, const SparseMatrix& y)
00719 {
00720   SparseMatrix r;
00721 
00722   if ((x.rows() == y.rows()) && (x.cols() == y.cols()))
00723     {
00724       octave_idx_type x_nr = x.rows ();
00725       octave_idx_type x_nc = x.cols ();
00726 
00727       octave_idx_type y_nr = y.rows ();
00728       octave_idx_type y_nc = y.cols ();
00729 
00730       if (x_nr != y_nr || x_nc != y_nc)
00731         gripe_nonconformant ("atan2", x_nr, x_nc, y_nr, y_nc);
00732       else
00733         {
00734           r = SparseMatrix (x_nr, x_nc, (x.nnz () + y.nnz ()));
00735 
00736           octave_idx_type jx = 0;
00737           r.cidx (0) = 0;
00738           for (octave_idx_type i = 0 ; i < x_nc ; i++)
00739             {
00740               octave_idx_type  ja = x.cidx(i);
00741               octave_idx_type  ja_max = x.cidx(i+1);
00742               bool ja_lt_max= ja < ja_max;
00743 
00744               octave_idx_type  jb = y.cidx(i);
00745               octave_idx_type  jb_max = y.cidx(i+1);
00746               bool jb_lt_max = jb < jb_max;
00747 
00748               while (ja_lt_max || jb_lt_max )
00749                 {
00750                   octave_quit ();
00751                   if ((! jb_lt_max) ||
00752                       (ja_lt_max && (x.ridx(ja) < y.ridx(jb))))
00753                     {
00754                       r.ridx(jx) = x.ridx(ja);
00755                       r.data(jx) = atan2 (x.data(ja), 0.);
00756                       jx++;
00757                       ja++;
00758                       ja_lt_max= ja < ja_max;
00759                     }
00760                   else if (( !ja_lt_max ) ||
00761                            (jb_lt_max && (y.ridx(jb) < x.ridx(ja)) ) )
00762                     {
00763                       jb++;
00764                       jb_lt_max= jb < jb_max;
00765                     }
00766                   else
00767                     {
00768                       double tmp = atan2 (x.data(ja), y.data(jb));
00769                       if (tmp != 0.)
00770                         {
00771                           r.data(jx) = tmp;
00772                           r.ridx(jx) = x.ridx(ja);
00773                           jx++;
00774                         }
00775                       ja++;
00776                       ja_lt_max= ja < ja_max;
00777                       jb++;
00778                       jb_lt_max= jb < jb_max;
00779                     }
00780                 }
00781               r.cidx(i+1) = jx;
00782             }
00783 
00784           r.maybe_compress ();
00785         }
00786     }
00787   else
00788     (*current_liboctave_error_handler) ("matrix size mismatch");
00789 
00790   return r;
00791 }
00792 
00793 SparseMatrix
00794 SparseMatrix::inverse (void) const
00795 {
00796   octave_idx_type info;
00797   double rcond;
00798   MatrixType mattype (*this);
00799   return inverse (mattype, info, rcond, 0, 0);
00800 }
00801 
00802 SparseMatrix
00803 SparseMatrix::inverse (MatrixType& mattype) const
00804 {
00805   octave_idx_type info;
00806   double rcond;
00807   return inverse (mattype, info, rcond, 0, 0);
00808 }
00809 
00810 SparseMatrix
00811 SparseMatrix::inverse (MatrixType& mattype, octave_idx_type& info) const
00812 {
00813   double rcond;
00814   return inverse (mattype, info, rcond, 0, 0);
00815 }
00816 
00817 SparseMatrix
00818 SparseMatrix::dinverse (MatrixType &mattyp, octave_idx_type& info,
00819                         double& rcond, const bool,
00820                         const bool calccond) const
00821 {
00822   SparseMatrix retval;
00823 
00824   octave_idx_type nr = rows ();
00825   octave_idx_type nc = cols ();
00826   info = 0;
00827 
00828   if (nr == 0 || nc == 0 || nr != nc)
00829     (*current_liboctave_error_handler) ("inverse requires square matrix");
00830   else
00831     {
00832       // Print spparms("spumoni") info if requested
00833       int typ = mattyp.type ();
00834       mattyp.info ();
00835 
00836       if (typ == MatrixType::Diagonal ||
00837           typ == MatrixType::Permuted_Diagonal)
00838         {
00839           if (typ == MatrixType::Permuted_Diagonal)
00840             retval = transpose();
00841           else
00842             retval = *this;
00843 
00844           // Force make_unique to be called
00845           double *v = retval.data();
00846 
00847           if (calccond)
00848             {
00849               double dmax = 0., dmin = octave_Inf;
00850               for (octave_idx_type i = 0; i < nr; i++)
00851                 {
00852                   double tmp = fabs(v[i]);
00853                   if (tmp > dmax)
00854                     dmax = tmp;
00855                   if (tmp < dmin)
00856                     dmin = tmp;
00857                 }
00858               rcond = dmin / dmax;
00859             }
00860 
00861           for (octave_idx_type i = 0; i < nr; i++)
00862             v[i] = 1.0 / v[i];
00863         }
00864       else
00865         (*current_liboctave_error_handler) ("incorrect matrix type");
00866     }
00867 
00868   return retval;
00869 }
00870 
00871 SparseMatrix
00872 SparseMatrix::tinverse (MatrixType &mattyp, octave_idx_type& info,
00873                         double& rcond, const bool,
00874                         const bool calccond) const
00875 {
00876   SparseMatrix retval;
00877 
00878   octave_idx_type nr = rows ();
00879   octave_idx_type nc = cols ();
00880   info = 0;
00881 
00882   if (nr == 0 || nc == 0 || nr != nc)
00883     (*current_liboctave_error_handler) ("inverse requires square matrix");
00884   else
00885     {
00886       // Print spparms("spumoni") info if requested
00887       int typ = mattyp.type ();
00888       mattyp.info ();
00889 
00890       if (typ == MatrixType::Upper || typ == MatrixType::Permuted_Upper ||
00891           typ == MatrixType::Lower || typ == MatrixType::Permuted_Lower)
00892         {
00893           double anorm = 0.;
00894           double ainvnorm = 0.;
00895 
00896           if (calccond)
00897             {
00898               // Calculate the 1-norm of matrix for rcond calculation
00899               for (octave_idx_type j = 0; j < nr; j++)
00900                 {
00901                   double atmp = 0.;
00902                   for (octave_idx_type i = cidx(j); i < cidx(j+1); i++)
00903                     atmp += fabs(data(i));
00904                   if (atmp > anorm)
00905                     anorm = atmp;
00906                 }
00907             }
00908 
00909           if (typ == MatrixType::Upper || typ == MatrixType::Lower)
00910             {
00911               octave_idx_type nz = nnz ();
00912               octave_idx_type cx = 0;
00913               octave_idx_type nz2 = nz;
00914               retval = SparseMatrix (nr, nc, nz2);
00915 
00916               for (octave_idx_type i = 0; i < nr; i++)
00917                 {
00918                   octave_quit ();
00919                   // place the 1 in the identity position
00920                   octave_idx_type cx_colstart = cx;
00921 
00922                   if (cx == nz2)
00923                     {
00924                       nz2 *= 2;
00925                       retval.change_capacity (nz2);
00926                     }
00927 
00928                   retval.xcidx(i) = cx;
00929                   retval.xridx(cx) = i;
00930                   retval.xdata(cx) = 1.0;
00931                   cx++;
00932 
00933                   // iterate accross columns of input matrix
00934                   for (octave_idx_type j = i+1; j < nr; j++)
00935                     {
00936                       double v = 0.;
00937                       // iterate to calculate sum
00938                       octave_idx_type colXp = retval.xcidx(i);
00939                       octave_idx_type colUp = cidx(j);
00940                       octave_idx_type rpX, rpU;
00941 
00942                       if (cidx(j) == cidx(j+1))
00943                         {
00944                           (*current_liboctave_error_handler)
00945                             ("division by zero");
00946                           goto inverse_singular;
00947                         }
00948 
00949                       do
00950                         {
00951                           octave_quit ();
00952                           rpX = retval.xridx(colXp);
00953                           rpU = ridx(colUp);
00954 
00955                           if (rpX < rpU)
00956                             colXp++;
00957                           else if (rpX > rpU)
00958                             colUp++;
00959                           else
00960                             {
00961                               v -= retval.xdata(colXp) * data(colUp);
00962                               colXp++;
00963                               colUp++;
00964                             }
00965                         } while ((rpX<j) && (rpU<j) &&
00966                                  (colXp<cx) && (colUp<nz));
00967 
00968                       // get A(m,m)
00969                       if (typ == MatrixType::Upper)
00970                         colUp = cidx(j+1) - 1;
00971                       else
00972                         colUp = cidx(j);
00973                       double pivot = data(colUp);
00974                       if (pivot == 0. || ridx(colUp) != j)
00975                         {
00976                           (*current_liboctave_error_handler)
00977                             ("division by zero");
00978                           goto inverse_singular;
00979                         }
00980 
00981                       if (v != 0.)
00982                         {
00983                           if (cx == nz2)
00984                             {
00985                               nz2 *= 2;
00986                               retval.change_capacity (nz2);
00987                             }
00988 
00989                           retval.xridx(cx) = j;
00990                           retval.xdata(cx) = v / pivot;
00991                           cx++;
00992                         }
00993                     }
00994 
00995                   // get A(m,m)
00996                   octave_idx_type colUp;
00997                   if (typ == MatrixType::Upper)
00998                     colUp = cidx(i+1) - 1;
00999                   else
01000                     colUp = cidx(i);
01001                   double pivot = data(colUp);
01002                   if (pivot == 0. || ridx(colUp) != i)
01003                     {
01004                       (*current_liboctave_error_handler) ("division by zero");
01005                       goto inverse_singular;
01006                     }
01007 
01008                   if (pivot != 1.0)
01009                     for (octave_idx_type j = cx_colstart; j < cx; j++)
01010                       retval.xdata(j) /= pivot;
01011                 }
01012               retval.xcidx(nr) = cx;
01013               retval.maybe_compress ();
01014             }
01015           else
01016             {
01017               octave_idx_type nz = nnz ();
01018               octave_idx_type cx = 0;
01019               octave_idx_type nz2 = nz;
01020               retval = SparseMatrix (nr, nc, nz2);
01021 
01022               OCTAVE_LOCAL_BUFFER (double, work, nr);
01023               OCTAVE_LOCAL_BUFFER (octave_idx_type, rperm, nr);
01024 
01025               octave_idx_type *perm = mattyp.triangular_perm();
01026               if (typ == MatrixType::Permuted_Upper)
01027                 {
01028                   for (octave_idx_type i = 0; i < nr; i++)
01029                     rperm[perm[i]] = i;
01030                 }
01031               else
01032                 {
01033                   for (octave_idx_type i = 0; i < nr; i++)
01034                     rperm[i] = perm[i];
01035                   for (octave_idx_type i = 0; i < nr; i++)
01036                     perm[rperm[i]] = i;
01037                 }
01038 
01039               for (octave_idx_type i = 0; i < nr; i++)
01040                 {
01041                   octave_quit ();
01042                   octave_idx_type iidx = rperm[i];
01043 
01044                   for (octave_idx_type j = 0; j < nr; j++)
01045                     work[j] = 0.;
01046 
01047                   // place the 1 in the identity position
01048                   work[iidx] = 1.0;
01049 
01050                   // iterate accross columns of input matrix
01051                   for (octave_idx_type j = iidx+1; j < nr; j++)
01052                     {
01053                       double v = 0.;
01054                       octave_idx_type jidx = perm[j];
01055                       // iterate to calculate sum
01056                       for (octave_idx_type k = cidx(jidx);
01057                            k < cidx(jidx+1); k++)
01058                         {
01059                           octave_quit ();
01060                           v -= work[ridx(k)] * data(k);
01061                         }
01062 
01063                       // get A(m,m)
01064                       double pivot;
01065                       if (typ == MatrixType::Permuted_Upper)
01066                         pivot = data(cidx(jidx+1) - 1);
01067                       else
01068                         pivot = data(cidx(jidx));
01069                       if (pivot == 0.)
01070                         {
01071                           (*current_liboctave_error_handler)
01072                             ("division by zero");
01073                           goto inverse_singular;
01074                         }
01075 
01076                       work[j] = v / pivot;
01077                     }
01078 
01079                   // get A(m,m)
01080                   octave_idx_type colUp;
01081                   if (typ == MatrixType::Permuted_Upper)
01082                     colUp = cidx(perm[iidx]+1) - 1;
01083                   else
01084                     colUp = cidx(perm[iidx]);
01085 
01086                   double pivot = data(colUp);
01087                   if (pivot == 0.)
01088                     {
01089                       (*current_liboctave_error_handler)
01090                         ("division by zero");
01091                       goto inverse_singular;
01092                     }
01093 
01094                   octave_idx_type new_cx = cx;
01095                   for (octave_idx_type j = iidx; j < nr; j++)
01096                     if (work[j] != 0.0)
01097                       {
01098                         new_cx++;
01099                         if (pivot != 1.0)
01100                           work[j] /= pivot;
01101                       }
01102 
01103                   if (cx < new_cx)
01104                     {
01105                       nz2 = (2*nz2 < new_cx ? new_cx : 2*nz2);
01106                       retval.change_capacity (nz2);
01107                     }
01108 
01109                   retval.xcidx(i) = cx;
01110                   for (octave_idx_type j = iidx; j < nr; j++)
01111                     if (work[j] != 0.)
01112                       {
01113                         retval.xridx(cx) = j;
01114                         retval.xdata(cx++) = work[j];
01115                       }
01116                 }
01117 
01118               retval.xcidx(nr) = cx;
01119               retval.maybe_compress ();
01120             }
01121 
01122           if (calccond)
01123             {
01124               // Calculate the 1-norm of inverse matrix for rcond calculation
01125               for (octave_idx_type j = 0; j < nr; j++)
01126                 {
01127                   double atmp = 0.;
01128                   for (octave_idx_type i = retval.cidx(j);
01129                        i < retval.cidx(j+1); i++)
01130                     atmp += fabs(retval.data(i));
01131                   if (atmp > ainvnorm)
01132                     ainvnorm = atmp;
01133                 }
01134 
01135               rcond = 1. / ainvnorm / anorm;
01136             }
01137         }
01138       else
01139         (*current_liboctave_error_handler) ("incorrect matrix type");
01140     }
01141 
01142   return retval;
01143 
01144  inverse_singular:
01145   return SparseMatrix();
01146 }
01147 
01148 SparseMatrix
01149 SparseMatrix::inverse (MatrixType &mattype, octave_idx_type& info,
01150                        double& rcond, int, int calc_cond) const
01151 {
01152   int typ = mattype.type (false);
01153   SparseMatrix ret;
01154 
01155   if (typ == MatrixType::Unknown)
01156     typ = mattype.type (*this);
01157 
01158   if (typ == MatrixType::Diagonal || typ == MatrixType::Permuted_Diagonal)
01159     ret = dinverse (mattype, info, rcond, true, calc_cond);
01160   else if (typ == MatrixType::Upper || typ == MatrixType::Permuted_Upper)
01161     ret = tinverse (mattype, info, rcond, true, calc_cond).transpose();
01162   else if (typ == MatrixType::Lower || typ == MatrixType::Permuted_Lower)
01163     {
01164       MatrixType newtype = mattype.transpose();
01165       ret = transpose().tinverse (newtype, info, rcond, true, calc_cond);
01166     }
01167   else
01168     {
01169       if (mattype.is_hermitian())
01170         {
01171           MatrixType tmp_typ (MatrixType::Upper);
01172           SparseCHOL fact (*this, info, false);
01173           rcond = fact.rcond();
01174           if (info == 0)
01175             {
01176               double rcond2;
01177               SparseMatrix Q = fact.Q();
01178               SparseMatrix InvL = fact.L().transpose().tinverse(tmp_typ,
01179                                            info, rcond2, true, false);
01180               ret = Q * InvL.transpose() * InvL * Q.transpose();
01181             }
01182           else
01183             {
01184               // Matrix is either singular or not positive definite
01185               mattype.mark_as_unsymmetric ();
01186               typ = MatrixType::Full;
01187             }
01188         }
01189 
01190       if (!mattype.is_hermitian())
01191         {
01192           octave_idx_type n = rows();
01193           ColumnVector Qinit(n);
01194           for (octave_idx_type i = 0; i < n; i++)
01195             Qinit(i) = i;
01196 
01197           MatrixType tmp_typ (MatrixType::Upper);
01198           SparseLU fact (*this, Qinit, Matrix(), false, false);
01199           rcond = fact.rcond();
01200           double rcond2;
01201           SparseMatrix InvL = fact.L().transpose().tinverse(tmp_typ,
01202                                            info, rcond2, true, false);
01203           SparseMatrix InvU = fact.U().tinverse(tmp_typ, info, rcond2,
01204                                            true, false).transpose();
01205           ret = fact.Pc().transpose() * InvU * InvL * fact.Pr();
01206         }
01207     }
01208 
01209   return ret;
01210 }
01211 
01212 DET
01213 SparseMatrix::determinant (void) const
01214 {
01215   octave_idx_type info;
01216   double rcond;
01217   return determinant (info, rcond, 0);
01218 }
01219 
01220 DET
01221 SparseMatrix::determinant (octave_idx_type& info) const
01222 {
01223   double rcond;
01224   return determinant (info, rcond, 0);
01225 }
01226 
01227 DET
01228 SparseMatrix::determinant (octave_idx_type& err, double& rcond, int) const
01229 {
01230   DET retval;
01231 
01232 #ifdef HAVE_UMFPACK
01233   octave_idx_type nr = rows ();
01234   octave_idx_type nc = cols ();
01235 
01236   if (nr == 0 || nc == 0 || nr != nc)
01237     {
01238       retval = DET (1.0);
01239     }
01240   else
01241     {
01242       err = 0;
01243 
01244       // Setup the control parameters
01245       Matrix Control (UMFPACK_CONTROL, 1);
01246       double *control = Control.fortran_vec ();
01247       UMFPACK_DNAME (defaults) (control);
01248 
01249       double tmp = octave_sparse_params::get_key ("spumoni");
01250       if (!xisnan (tmp))
01251         Control (UMFPACK_PRL) = tmp;
01252 
01253       tmp = octave_sparse_params::get_key ("piv_tol");
01254       if (!xisnan (tmp))
01255         {
01256           Control (UMFPACK_SYM_PIVOT_TOLERANCE) = tmp;
01257           Control (UMFPACK_PIVOT_TOLERANCE) = tmp;
01258         }
01259 
01260       // Set whether we are allowed to modify Q or not
01261       tmp = octave_sparse_params::get_key ("autoamd");
01262       if (!xisnan (tmp))
01263         Control (UMFPACK_FIXQ) = tmp;
01264 
01265       // Turn-off UMFPACK scaling for LU
01266       Control (UMFPACK_SCALE) = UMFPACK_SCALE_NONE;
01267 
01268       UMFPACK_DNAME (report_control) (control);
01269 
01270       const octave_idx_type *Ap = cidx ();
01271       const octave_idx_type *Ai = ridx ();
01272       const double *Ax = data ();
01273 
01274       UMFPACK_DNAME (report_matrix) (nr, nc, Ap, Ai, Ax, 1, control);
01275 
01276       void *Symbolic;
01277       Matrix Info (1, UMFPACK_INFO);
01278       double *info = Info.fortran_vec ();
01279       int status = UMFPACK_DNAME (qsymbolic) (nr, nc, Ap, Ai,
01280                                          Ax, 0, &Symbolic, control, info);
01281 
01282       if (status < 0)
01283         {
01284           (*current_liboctave_error_handler)
01285             ("SparseMatrix::determinant symbolic factorization failed");
01286 
01287           UMFPACK_DNAME (report_status) (control, status);
01288           UMFPACK_DNAME (report_info) (control, info);
01289 
01290           UMFPACK_DNAME (free_symbolic) (&Symbolic) ;
01291         }
01292       else
01293         {
01294           UMFPACK_DNAME (report_symbolic) (Symbolic, control);
01295 
01296           void *Numeric;
01297           status = UMFPACK_DNAME (numeric) (Ap, Ai, Ax, Symbolic,
01298                                        &Numeric, control, info) ;
01299           UMFPACK_DNAME (free_symbolic) (&Symbolic) ;
01300 
01301           rcond = Info (UMFPACK_RCOND);
01302 
01303           if (status < 0)
01304             {
01305               (*current_liboctave_error_handler)
01306                 ("SparseMatrix::determinant numeric factorization failed");
01307 
01308               UMFPACK_DNAME (report_status) (control, status);
01309               UMFPACK_DNAME (report_info) (control, info);
01310 
01311               UMFPACK_DNAME (free_numeric) (&Numeric);
01312             }
01313           else
01314             {
01315               UMFPACK_DNAME (report_numeric) (Numeric, control);
01316 
01317               double c10, e10;
01318 
01319               status = UMFPACK_DNAME (get_determinant) (&c10, &e10, Numeric, info);
01320 
01321               if (status < 0)
01322                 {
01323                   (*current_liboctave_error_handler)
01324                     ("SparseMatrix::determinant error calculating determinant");
01325 
01326                   UMFPACK_DNAME (report_status) (control, status);
01327                   UMFPACK_DNAME (report_info) (control, info);
01328                 }
01329               else
01330                 retval = DET (c10, e10, 10);
01331 
01332               UMFPACK_DNAME (free_numeric) (&Numeric);
01333             }
01334         }
01335     }
01336 #else
01337   (*current_liboctave_error_handler) ("UMFPACK not installed");
01338 #endif
01339 
01340   return retval;
01341 }
01342 
01343 Matrix
01344 SparseMatrix::dsolve (MatrixType &mattype, const Matrix& b, octave_idx_type& err,
01345                       double& rcond, solve_singularity_handler,
01346                       bool calc_cond) const
01347 {
01348   Matrix retval;
01349 
01350   octave_idx_type nr = rows ();
01351   octave_idx_type nc = cols ();
01352   octave_idx_type nm = (nc < nr ? nc : nr);
01353   err = 0;
01354 
01355   if (nr != b.rows ())
01356     (*current_liboctave_error_handler)
01357       ("matrix dimension mismatch solution of linear equations");
01358   else if (nr == 0 || nc == 0 || b.cols () == 0)
01359     retval = Matrix (nc, b.cols (), 0.0);
01360   else
01361     {
01362       // Print spparms("spumoni") info if requested
01363       int typ = mattype.type ();
01364       mattype.info ();
01365 
01366       if (typ == MatrixType::Diagonal ||
01367           typ == MatrixType::Permuted_Diagonal)
01368         {
01369           retval.resize (nc, b.cols(), 0.);
01370           if (typ == MatrixType::Diagonal)
01371             for (octave_idx_type j = 0; j < b.cols(); j++)
01372               for (octave_idx_type i = 0; i < nm; i++)
01373                 retval(i,j) = b(i,j) / data (i);
01374           else
01375             for (octave_idx_type j = 0; j < b.cols(); j++)
01376               for (octave_idx_type k = 0; k < nc; k++)
01377                 for (octave_idx_type i = cidx(k); i < cidx(k+1); i++)
01378                   retval(k,j) = b(ridx(i),j) / data (i);
01379 
01380           if (calc_cond)
01381             {
01382               double dmax = 0., dmin = octave_Inf;
01383               for (octave_idx_type i = 0; i < nm; i++)
01384                 {
01385                   double tmp = fabs(data(i));
01386                   if (tmp > dmax)
01387                     dmax = tmp;
01388                   if (tmp < dmin)
01389                     dmin = tmp;
01390                 }
01391               rcond = dmin / dmax;
01392             }
01393           else
01394             rcond = 1.;
01395         }
01396       else
01397         (*current_liboctave_error_handler) ("incorrect matrix type");
01398     }
01399 
01400   return retval;
01401 }
01402 
01403 SparseMatrix
01404 SparseMatrix::dsolve (MatrixType &mattype, const SparseMatrix& b,
01405                       octave_idx_type& err, double& rcond,
01406                       solve_singularity_handler, bool calc_cond) const
01407 {
01408   SparseMatrix retval;
01409 
01410   octave_idx_type nr = rows ();
01411   octave_idx_type nc = cols ();
01412   octave_idx_type nm = (nc < nr ? nc : nr);
01413   err = 0;
01414 
01415   if (nr != b.rows ())
01416     (*current_liboctave_error_handler)
01417       ("matrix dimension mismatch solution of linear equations");
01418   else if (nr == 0 || nc == 0 || b.cols () == 0)
01419     retval = SparseMatrix (nc, b.cols ());
01420   else
01421     {
01422       // Print spparms("spumoni") info if requested
01423       int typ = mattype.type ();
01424       mattype.info ();
01425 
01426       if (typ == MatrixType::Diagonal ||
01427           typ == MatrixType::Permuted_Diagonal)
01428         {
01429           octave_idx_type b_nc = b.cols ();
01430           octave_idx_type b_nz = b.nnz ();
01431           retval = SparseMatrix (nc, b_nc, b_nz);
01432 
01433           retval.xcidx(0) = 0;
01434           octave_idx_type ii = 0;
01435           if (typ == MatrixType::Diagonal)
01436             for (octave_idx_type j = 0; j < b_nc; j++)
01437               {
01438                 for (octave_idx_type i = b.cidx(j); i < b.cidx(j+1); i++)
01439                   {
01440                     if (b.ridx(i) >= nm)
01441                       break;
01442                     retval.xridx (ii) = b.ridx(i);
01443                     retval.xdata (ii++) = b.data(i) / data (b.ridx (i));
01444                   }
01445                 retval.xcidx(j+1) = ii;
01446               }
01447           else
01448             for (octave_idx_type j = 0; j < b_nc; j++)
01449               {
01450                 for (octave_idx_type l = 0; l < nc; l++)
01451                   for (octave_idx_type i = cidx(l); i < cidx(l+1); i++)
01452                     {
01453                       bool found = false;
01454                       octave_idx_type k;
01455                       for (k = b.cidx(j); k < b.cidx(j+1); k++)
01456                         if (ridx(i) == b.ridx(k))
01457                           {
01458                             found = true;
01459                             break;
01460                           }
01461                       if (found)
01462                         {
01463                           retval.xridx (ii) = l;
01464                           retval.xdata (ii++) = b.data(k) / data (i);
01465                         }
01466                     }
01467                 retval.xcidx(j+1) = ii;
01468               }
01469 
01470           if (calc_cond)
01471             {
01472               double dmax = 0., dmin = octave_Inf;
01473               for (octave_idx_type i = 0; i < nm; i++)
01474                 {
01475                   double tmp = fabs(data(i));
01476                   if (tmp > dmax)
01477                     dmax = tmp;
01478                   if (tmp < dmin)
01479                     dmin = tmp;
01480                 }
01481               rcond = dmin / dmax;
01482             }
01483           else
01484             rcond = 1.;
01485         }
01486       else
01487         (*current_liboctave_error_handler) ("incorrect matrix type");
01488     }
01489 
01490   return retval;
01491 }
01492 
01493 ComplexMatrix
01494 SparseMatrix::dsolve (MatrixType &mattype, const ComplexMatrix& b,
01495                       octave_idx_type& err, double& rcond,
01496                       solve_singularity_handler, bool calc_cond) const
01497 {
01498   ComplexMatrix retval;
01499 
01500   octave_idx_type nr = rows ();
01501   octave_idx_type nc = cols ();
01502   octave_idx_type nm = (nc < nr ? nc : nr);
01503   err = 0;
01504 
01505   if (nr != b.rows ())
01506     (*current_liboctave_error_handler)
01507       ("matrix dimension mismatch solution of linear equations");
01508   else if (nr == 0 || nc == 0 || b.cols () == 0)
01509     retval = ComplexMatrix (nc, b.cols (), Complex (0.0, 0.0));
01510   else
01511     {
01512       // Print spparms("spumoni") info if requested
01513       int typ = mattype.type ();
01514       mattype.info ();
01515 
01516       if (typ == MatrixType::Diagonal ||
01517           typ == MatrixType::Permuted_Diagonal)
01518         {
01519           retval.resize (nc, b.cols(), 0);
01520           if (typ == MatrixType::Diagonal)
01521             for (octave_idx_type j = 0; j < b.cols(); j++)
01522                 for (octave_idx_type i = 0; i < nm; i++)
01523                   retval(i,j) = b(i,j) / data (i);
01524           else
01525             for (octave_idx_type j = 0; j < b.cols(); j++)
01526               for (octave_idx_type k = 0; k < nc; k++)
01527                 for (octave_idx_type i = cidx(k); i < cidx(k+1); i++)
01528                   retval(k,j) = b(ridx(i),j) / data (i);
01529 
01530           if (calc_cond)
01531             {
01532               double dmax = 0., dmin = octave_Inf;
01533               for (octave_idx_type i = 0; i < nm; i++)
01534                 {
01535                   double tmp = fabs(data(i));
01536                   if (tmp > dmax)
01537                     dmax = tmp;
01538                   if (tmp < dmin)
01539                     dmin = tmp;
01540                 }
01541               rcond = dmin / dmax;
01542             }
01543           else
01544             rcond = 1.;
01545         }
01546       else
01547         (*current_liboctave_error_handler) ("incorrect matrix type");
01548     }
01549 
01550   return retval;
01551 }
01552 
01553 SparseComplexMatrix
01554 SparseMatrix::dsolve (MatrixType &mattype, const SparseComplexMatrix& b,
01555                      octave_idx_type& err, double& rcond,
01556                      solve_singularity_handler, bool calc_cond) const
01557 {
01558   SparseComplexMatrix retval;
01559 
01560   octave_idx_type nr = rows ();
01561   octave_idx_type nc = cols ();
01562   octave_idx_type nm = (nc < nr ? nc : nr);
01563   err = 0;
01564 
01565   if (nr != b.rows ())
01566     (*current_liboctave_error_handler)
01567       ("matrix dimension mismatch solution of linear equations");
01568   else if (nr == 0 || nc == 0 || b.cols () == 0)
01569     retval = SparseComplexMatrix (nc, b.cols ());
01570   else
01571     {
01572       // Print spparms("spumoni") info if requested
01573       int typ = mattype.type ();
01574       mattype.info ();
01575 
01576       if (typ == MatrixType::Diagonal ||
01577           typ == MatrixType::Permuted_Diagonal)
01578         {
01579           octave_idx_type b_nc = b.cols ();
01580           octave_idx_type b_nz = b.nnz ();
01581           retval = SparseComplexMatrix (nc, b_nc, b_nz);
01582 
01583           retval.xcidx(0) = 0;
01584           octave_idx_type ii = 0;
01585           if (typ == MatrixType::Diagonal)
01586             for (octave_idx_type j = 0; j < b.cols(); j++)
01587               {
01588                 for (octave_idx_type i = b.cidx(j); i < b.cidx(j+1); i++)
01589                   {
01590                     if (b.ridx(i) >= nm)
01591                       break;
01592                     retval.xridx (ii) = b.ridx(i);
01593                     retval.xdata (ii++) = b.data(i) / data (b.ridx (i));
01594                   }
01595                 retval.xcidx(j+1) = ii;
01596               }
01597           else
01598             for (octave_idx_type j = 0; j < b.cols(); j++)
01599               {
01600                 for (octave_idx_type l = 0; l < nc; l++)
01601                   for (octave_idx_type i = cidx(l); i < cidx(l+1); i++)
01602                     {
01603                       bool found = false;
01604                       octave_idx_type k;
01605                       for (k = b.cidx(j); k < b.cidx(j+1); k++)
01606                         if (ridx(i) == b.ridx(k))
01607                           {
01608                             found = true;
01609                             break;
01610                           }
01611                       if (found)
01612                         {
01613                           retval.xridx (ii) = l;
01614                           retval.xdata (ii++) = b.data(k) / data (i);
01615                         }
01616                     }
01617                 retval.xcidx(j+1) = ii;
01618               }
01619 
01620           if (calc_cond)
01621             {
01622               double dmax = 0., dmin = octave_Inf;
01623               for (octave_idx_type i = 0; i < nm; i++)
01624                 {
01625                   double tmp = fabs(data(i));
01626                   if (tmp > dmax)
01627                     dmax = tmp;
01628                   if (tmp < dmin)
01629                     dmin = tmp;
01630                 }
01631               rcond = dmin / dmax;
01632             }
01633           else
01634             rcond = 1.;
01635         }
01636       else
01637         (*current_liboctave_error_handler) ("incorrect matrix type");
01638     }
01639 
01640   return retval;
01641 }
01642 
01643 Matrix
01644 SparseMatrix::utsolve (MatrixType &mattype, const Matrix& b,
01645                        octave_idx_type& err, double& rcond,
01646                        solve_singularity_handler sing_handler,
01647                        bool calc_cond) const
01648 {
01649   Matrix retval;
01650 
01651   octave_idx_type nr = rows ();
01652   octave_idx_type nc = cols ();
01653   octave_idx_type nm = (nc > nr ? nc : nr);
01654   err = 0;
01655 
01656   if (nr != b.rows ())
01657     (*current_liboctave_error_handler)
01658       ("matrix dimension mismatch solution of linear equations");
01659   else if (nr == 0 || nc == 0 || b.cols () == 0)
01660     retval = Matrix (nc, b.cols (), 0.0);
01661   else
01662     {
01663       // Print spparms("spumoni") info if requested
01664       int typ = mattype.type ();
01665       mattype.info ();
01666 
01667       if (typ == MatrixType::Permuted_Upper ||
01668           typ == MatrixType::Upper)
01669         {
01670           double anorm = 0.;
01671           double ainvnorm = 0.;
01672           octave_idx_type b_nc = b.cols ();
01673           rcond = 1.;
01674 
01675           if (calc_cond)
01676             {
01677               // Calculate the 1-norm of matrix for rcond calculation
01678               for (octave_idx_type j = 0; j < nc; j++)
01679                 {
01680                   double atmp = 0.;
01681                   for (octave_idx_type i = cidx(j); i < cidx(j+1); i++)
01682                     atmp += fabs(data(i));
01683                   if (atmp > anorm)
01684                     anorm = atmp;
01685                 }
01686             }
01687 
01688           if (typ == MatrixType::Permuted_Upper)
01689             {
01690               retval.resize (nc, b_nc);
01691               octave_idx_type *perm = mattype.triangular_perm ();
01692               OCTAVE_LOCAL_BUFFER (double, work, nm);
01693 
01694               for (octave_idx_type j = 0; j < b_nc; j++)
01695                 {
01696                   for (octave_idx_type i = 0; i < nr; i++)
01697                     work[i] = b(i,j);
01698                   for (octave_idx_type i = nr; i < nc; i++)
01699                     work[i] = 0.;
01700 
01701                   for (octave_idx_type k = nc-1; k >= 0; k--)
01702                     {
01703                       octave_idx_type kidx = perm[k];
01704 
01705                       if (work[k] != 0.)
01706                         {
01707                           if (ridx(cidx(kidx+1)-1) != k ||
01708                               data(cidx(kidx+1)-1) == 0.)
01709                             {
01710                               err = -2;
01711                               goto triangular_error;
01712                             }
01713 
01714                           double tmp = work[k] / data(cidx(kidx+1)-1);
01715                           work[k] = tmp;
01716                           for (octave_idx_type i = cidx(kidx);
01717                                i < cidx(kidx+1)-1; i++)
01718                             {
01719                               octave_idx_type iidx = ridx(i);
01720                               work[iidx] = work[iidx] - tmp * data(i);
01721                             }
01722                         }
01723                     }
01724 
01725                   for (octave_idx_type i = 0; i < nc; i++)
01726                     retval.xelem (perm[i], j) = work[i];
01727                 }
01728 
01729               if (calc_cond)
01730                 {
01731                   // Calculation of 1-norm of inv(*this)
01732                   for (octave_idx_type i = 0; i < nm; i++)
01733                     work[i] = 0.;
01734 
01735                   for (octave_idx_type j = 0; j < nr; j++)
01736                     {
01737                       work[j] = 1.;
01738 
01739                       for (octave_idx_type k = j; k >= 0; k--)
01740                         {
01741                           octave_idx_type iidx = perm[k];
01742 
01743                           if (work[k] != 0.)
01744                             {
01745                               double tmp = work[k] / data(cidx(iidx+1)-1);
01746                               work[k] = tmp;
01747                               for (octave_idx_type i = cidx(iidx);
01748                                    i < cidx(iidx+1)-1; i++)
01749                                 {
01750                                   octave_idx_type idx2 = ridx(i);
01751                                   work[idx2] = work[idx2] - tmp * data(i);
01752                                 }
01753                             }
01754                         }
01755                       double atmp = 0;
01756                       for (octave_idx_type i = 0; i < j+1; i++)
01757                         {
01758                           atmp += fabs(work[i]);
01759                           work[i] = 0.;
01760                         }
01761                       if (atmp > ainvnorm)
01762                         ainvnorm = atmp;
01763                     }
01764                   rcond = 1. / ainvnorm / anorm;
01765                 }
01766             }
01767           else
01768             {
01769               OCTAVE_LOCAL_BUFFER (double, work, nm);
01770               retval.resize (nc, b_nc);
01771 
01772               for (octave_idx_type j = 0; j < b_nc; j++)
01773                 {
01774                   for (octave_idx_type i = 0; i < nr; i++)
01775                     work[i] = b(i,j);
01776                   for (octave_idx_type i = nr; i < nc; i++)
01777                     work[i] = 0.;
01778 
01779                   for (octave_idx_type k = nc-1; k >= 0; k--)
01780                     {
01781                       if (work[k] != 0.)
01782                         {
01783                           if (ridx(cidx(k+1)-1) != k ||
01784                               data(cidx(k+1)-1) == 0.)
01785                             {
01786                               err = -2;
01787                               goto triangular_error;
01788                             }
01789 
01790                           double tmp = work[k] / data(cidx(k+1)-1);
01791                           work[k] = tmp;
01792                           for (octave_idx_type i = cidx(k); i < cidx(k+1)-1; i++)
01793                             {
01794                               octave_idx_type iidx = ridx(i);
01795                               work[iidx] = work[iidx] - tmp * data(i);
01796                             }
01797                         }
01798                     }
01799 
01800                   for (octave_idx_type i = 0; i < nc; i++)
01801                     retval.xelem (i, j) = work[i];
01802                 }
01803 
01804               if (calc_cond)
01805                 {
01806                   // Calculation of 1-norm of inv(*this)
01807                   for (octave_idx_type i = 0; i < nm; i++)
01808                     work[i] = 0.;
01809 
01810                   for (octave_idx_type j = 0; j < nr; j++)
01811                     {
01812                       work[j] = 1.;
01813 
01814                       for (octave_idx_type k = j; k >= 0; k--)
01815                         {
01816                           if (work[k] != 0.)
01817                             {
01818                               double tmp = work[k] / data(cidx(k+1)-1);
01819                               work[k] = tmp;
01820                               for (octave_idx_type i = cidx(k); i < cidx(k+1)-1; i++)
01821                                 {
01822                                   octave_idx_type iidx = ridx(i);
01823                                   work[iidx] = work[iidx] - tmp * data(i);
01824                                 }
01825                             }
01826                         }
01827                       double atmp = 0;
01828                       for (octave_idx_type i = 0; i < j+1; i++)
01829                         {
01830                           atmp += fabs(work[i]);
01831                           work[i] = 0.;
01832                         }
01833                       if (atmp > ainvnorm)
01834                         ainvnorm = atmp;
01835                     }
01836                   rcond = 1. / ainvnorm / anorm;
01837                 }
01838             }
01839 
01840         triangular_error:
01841           if (err != 0)
01842             {
01843               if (sing_handler)
01844                 {
01845                   sing_handler (rcond);
01846                   mattype.mark_as_rectangular ();
01847                 }
01848               else
01849                 (*current_liboctave_error_handler)
01850                   ("SparseMatrix::solve matrix singular to machine precision, rcond = %g",
01851                    rcond);
01852             }
01853 
01854           volatile double rcond_plus_one = rcond + 1.0;
01855 
01856           if (rcond_plus_one == 1.0 || xisnan (rcond))
01857             {
01858               err = -2;
01859 
01860               if (sing_handler)
01861                 {
01862                   sing_handler (rcond);
01863                   mattype.mark_as_rectangular ();
01864                 }
01865               else
01866                 (*current_liboctave_error_handler)
01867                   ("matrix singular to machine precision, rcond = %g",
01868                    rcond);
01869             }
01870         }
01871       else
01872         (*current_liboctave_error_handler) ("incorrect matrix type");
01873     }
01874 
01875   return retval;
01876 }
01877 
01878 SparseMatrix
01879 SparseMatrix::utsolve (MatrixType &mattype, const SparseMatrix& b,
01880                        octave_idx_type& err, double& rcond,
01881                        solve_singularity_handler sing_handler,
01882                        bool calc_cond) const
01883 {
01884   SparseMatrix retval;
01885 
01886   octave_idx_type nr = rows ();
01887   octave_idx_type nc = cols ();
01888   octave_idx_type nm = (nc > nr ? nc : nr);
01889   err = 0;
01890 
01891   if (nr != b.rows ())
01892     (*current_liboctave_error_handler)
01893       ("matrix dimension mismatch solution of linear equations");
01894   else if (nr == 0 || nc == 0 || b.cols () == 0)
01895     retval = SparseMatrix (nc, b.cols ());
01896   else
01897     {
01898       // Print spparms("spumoni") info if requested
01899       int typ = mattype.type ();
01900       mattype.info ();
01901 
01902       if (typ == MatrixType::Permuted_Upper ||
01903           typ == MatrixType::Upper)
01904         {
01905           double anorm = 0.;
01906           double ainvnorm = 0.;
01907           rcond = 1.;
01908 
01909           if (calc_cond)
01910             {
01911               // Calculate the 1-norm of matrix for rcond calculation
01912               for (octave_idx_type j = 0; j < nc; j++)
01913                 {
01914                   double atmp = 0.;
01915                   for (octave_idx_type i = cidx(j); i < cidx(j+1); i++)
01916                     atmp += fabs(data(i));
01917                   if (atmp > anorm)
01918                     anorm = atmp;
01919                 }
01920             }
01921 
01922           octave_idx_type b_nc = b.cols ();
01923           octave_idx_type b_nz = b.nnz ();
01924           retval = SparseMatrix (nc, b_nc, b_nz);
01925           retval.xcidx(0) = 0;
01926           octave_idx_type ii = 0;
01927           octave_idx_type x_nz = b_nz;
01928 
01929           if (typ == MatrixType::Permuted_Upper)
01930             {
01931               octave_idx_type *perm = mattype.triangular_perm ();
01932               OCTAVE_LOCAL_BUFFER (double, work, nm);
01933 
01934               OCTAVE_LOCAL_BUFFER (octave_idx_type, rperm, nc);
01935               for (octave_idx_type i = 0; i < nc; i++)
01936                 rperm[perm[i]] = i;
01937 
01938               for (octave_idx_type j = 0; j < b_nc; j++)
01939                 {
01940                   for (octave_idx_type i = 0; i < nm; i++)
01941                     work[i] = 0.;
01942                   for (octave_idx_type i = b.cidx(j); i < b.cidx(j+1); i++)
01943                     work[b.ridx(i)] = b.data(i);
01944 
01945                   for (octave_idx_type k = nc-1; k >= 0; k--)
01946                     {
01947                       octave_idx_type kidx = perm[k];
01948 
01949                       if (work[k] != 0.)
01950                         {
01951                           if (ridx(cidx(kidx+1)-1) != k ||
01952                               data(cidx(kidx+1)-1) == 0.)
01953                             {
01954                               err = -2;
01955                               goto triangular_error;
01956                             }
01957 
01958                           double tmp = work[k] / data(cidx(kidx+1)-1);
01959                           work[k] = tmp;
01960                           for (octave_idx_type i = cidx(kidx);
01961                                i < cidx(kidx+1)-1; i++)
01962                             {
01963                               octave_idx_type iidx = ridx(i);
01964                               work[iidx] = work[iidx] - tmp * data(i);
01965                             }
01966                         }
01967                     }
01968 
01969                   // Count non-zeros in work vector and adjust space in
01970                   // retval if needed
01971                   octave_idx_type new_nnz = 0;
01972                   for (octave_idx_type i = 0; i < nc; i++)
01973                     if (work[i] != 0.)
01974                       new_nnz++;
01975 
01976                   if (ii + new_nnz > x_nz)
01977                     {
01978                       // Resize the sparse matrix
01979                       octave_idx_type sz = new_nnz * (b_nc - j) + x_nz;
01980                       retval.change_capacity (sz);
01981                       x_nz = sz;
01982                     }
01983 
01984                   for (octave_idx_type i = 0; i < nc; i++)
01985                     if (work[rperm[i]] != 0.)
01986                       {
01987                         retval.xridx(ii) = i;
01988                         retval.xdata(ii++) = work[rperm[i]];
01989                       }
01990                   retval.xcidx(j+1) = ii;
01991                 }
01992 
01993               retval.maybe_compress ();
01994 
01995               if (calc_cond)
01996                 {
01997                   // Calculation of 1-norm of inv(*this)
01998                   for (octave_idx_type i = 0; i < nm; i++)
01999                     work[i] = 0.;
02000 
02001                   for (octave_idx_type j = 0; j < nr; j++)
02002                     {
02003                       work[j] = 1.;
02004 
02005                       for (octave_idx_type k = j; k >= 0; k--)
02006                         {
02007                           octave_idx_type iidx = perm[k];
02008 
02009                           if (work[k] != 0.)
02010                             {
02011                               double tmp = work[k] / data(cidx(iidx+1)-1);
02012                               work[k] = tmp;
02013                               for (octave_idx_type i = cidx(iidx);
02014                                    i < cidx(iidx+1)-1; i++)
02015                                 {
02016                                   octave_idx_type idx2 = ridx(i);
02017                                   work[idx2] = work[idx2] - tmp * data(i);
02018                                 }
02019                             }
02020                         }
02021                       double atmp = 0;
02022                       for (octave_idx_type i = 0; i < j+1; i++)
02023                         {
02024                           atmp += fabs(work[i]);
02025                           work[i] = 0.;
02026                         }
02027                       if (atmp > ainvnorm)
02028                         ainvnorm = atmp;
02029                     }
02030                   rcond = 1. / ainvnorm / anorm;
02031                 }
02032             }
02033           else
02034             {
02035               OCTAVE_LOCAL_BUFFER (double, work, nm);
02036 
02037               for (octave_idx_type j = 0; j < b_nc; j++)
02038                 {
02039                   for (octave_idx_type i = 0; i < nm; i++)
02040                     work[i] = 0.;
02041                   for (octave_idx_type i = b.cidx(j); i < b.cidx(j+1); i++)
02042                     work[b.ridx(i)] = b.data(i);
02043 
02044                   for (octave_idx_type k = nc-1; k >= 0; k--)
02045                     {
02046                       if (work[k] != 0.)
02047                         {
02048                           if (ridx(cidx(k+1)-1) != k ||
02049                               data(cidx(k+1)-1) == 0.)
02050                             {
02051                               err = -2;
02052                               goto triangular_error;
02053                             }
02054 
02055                           double tmp = work[k] / data(cidx(k+1)-1);
02056                           work[k] = tmp;
02057                           for (octave_idx_type i = cidx(k); i < cidx(k+1)-1; i++)
02058                             {
02059                               octave_idx_type iidx = ridx(i);
02060                               work[iidx] = work[iidx] - tmp * data(i);
02061                             }
02062                         }
02063                     }
02064 
02065                   // Count non-zeros in work vector and adjust space in
02066                   // retval if needed
02067                   octave_idx_type new_nnz = 0;
02068                   for (octave_idx_type i = 0; i < nc; i++)
02069                     if (work[i] != 0.)
02070                       new_nnz++;
02071 
02072                   if (ii + new_nnz > x_nz)
02073                     {
02074                       // Resize the sparse matrix
02075                       octave_idx_type sz = new_nnz * (b_nc - j) + x_nz;
02076                       retval.change_capacity (sz);
02077                       x_nz = sz;
02078                     }
02079 
02080                   for (octave_idx_type i = 0; i < nc; i++)
02081                     if (work[i] != 0.)
02082                       {
02083                         retval.xridx(ii) = i;
02084                         retval.xdata(ii++) = work[i];
02085                       }
02086                   retval.xcidx(j+1) = ii;
02087                 }
02088 
02089               retval.maybe_compress ();
02090 
02091               if (calc_cond)
02092                 {
02093                   // Calculation of 1-norm of inv(*this)
02094                   for (octave_idx_type i = 0; i < nm; i++)
02095                     work[i] = 0.;
02096 
02097                   for (octave_idx_type j = 0; j < nr; j++)
02098                     {
02099                       work[j] = 1.;
02100 
02101                       for (octave_idx_type k = j; k >= 0; k--)
02102                         {
02103                           if (work[k] != 0.)
02104                             {
02105                               double tmp = work[k] / data(cidx(k+1)-1);
02106                               work[k] = tmp;
02107                               for (octave_idx_type i = cidx(k);
02108                                    i < cidx(k+1)-1; i++)
02109                                 {
02110                                   octave_idx_type iidx = ridx(i);
02111                                   work[iidx] = work[iidx] - tmp * data(i);
02112                                 }
02113                             }
02114                         }
02115                       double atmp = 0;
02116                       for (octave_idx_type i = 0; i < j+1; i++)
02117                         {
02118                           atmp += fabs(work[i]);
02119                           work[i] = 0.;
02120                         }
02121                       if (atmp > ainvnorm)
02122                         ainvnorm = atmp;
02123                     }
02124                   rcond = 1. / ainvnorm / anorm;
02125                 }
02126             }
02127 
02128         triangular_error:
02129           if (err != 0)
02130             {
02131               if (sing_handler)
02132                 {
02133                   sing_handler (rcond);
02134                   mattype.mark_as_rectangular ();
02135                 }
02136               else
02137                 (*current_liboctave_error_handler)
02138                   ("SparseMatrix::solve matrix singular to machine precision, rcond = %g",
02139                    rcond);
02140             }
02141 
02142           volatile double rcond_plus_one = rcond + 1.0;
02143 
02144           if (rcond_plus_one == 1.0 || xisnan (rcond))
02145             {
02146               err = -2;
02147 
02148               if (sing_handler)
02149                 {
02150                   sing_handler (rcond);
02151                   mattype.mark_as_rectangular ();
02152                 }
02153               else
02154                 (*current_liboctave_error_handler)
02155                   ("matrix singular to machine precision, rcond = %g",
02156                    rcond);
02157             }
02158         }
02159       else
02160         (*current_liboctave_error_handler) ("incorrect matrix type");
02161     }
02162   return retval;
02163 }
02164 
02165 ComplexMatrix
02166 SparseMatrix::utsolve (MatrixType &mattype, const ComplexMatrix& b,
02167                        octave_idx_type& err, double& rcond,
02168                        solve_singularity_handler sing_handler,
02169                        bool calc_cond) const
02170 {
02171   ComplexMatrix retval;
02172 
02173   octave_idx_type nr = rows ();
02174   octave_idx_type nc = cols ();
02175   octave_idx_type nm = (nc > nr ? nc : nr);
02176   err = 0;
02177 
02178   if (nr != b.rows ())
02179     (*current_liboctave_error_handler)
02180       ("matrix dimension mismatch solution of linear equations");
02181   else if (nr == 0 || nc == 0 || b.cols () == 0)
02182     retval = ComplexMatrix (nc, b.cols (), Complex (0.0, 0.0));
02183   else
02184     {
02185       // Print spparms("spumoni") info if requested
02186       int typ = mattype.type ();
02187       mattype.info ();
02188 
02189       if (typ == MatrixType::Permuted_Upper ||
02190           typ == MatrixType::Upper)
02191         {
02192           double anorm = 0.;
02193           double ainvnorm = 0.;
02194           octave_idx_type b_nc = b.cols ();
02195           rcond = 1.;
02196 
02197           if (calc_cond)
02198             {
02199               // Calculate the 1-norm of matrix for rcond calculation
02200               for (octave_idx_type j = 0; j < nc; j++)
02201                 {
02202                   double atmp = 0.;
02203                   for (octave_idx_type i = cidx(j); i < cidx(j+1); i++)
02204                     atmp += fabs(data(i));
02205                   if (atmp > anorm)
02206                     anorm = atmp;
02207                 }
02208             }
02209 
02210           if (typ == MatrixType::Permuted_Upper)
02211             {
02212               retval.resize (nc, b_nc);
02213               octave_idx_type *perm = mattype.triangular_perm ();
02214               OCTAVE_LOCAL_BUFFER (Complex, cwork, nm);
02215 
02216               for (octave_idx_type j = 0; j < b_nc; j++)
02217                 {
02218                   for (octave_idx_type i = 0; i < nr; i++)
02219                     cwork[i] = b(i,j);
02220                   for (octave_idx_type i = nr; i < nc; i++)
02221                     cwork[i] = 0.;
02222 
02223                   for (octave_idx_type k = nc-1; k >= 0; k--)
02224                     {
02225                       octave_idx_type kidx = perm[k];
02226 
02227                       if (cwork[k] != 0.)
02228                         {
02229                           if (ridx(cidx(kidx+1)-1) != k ||
02230                               data(cidx(kidx+1)-1) == 0.)
02231                             {
02232                               err = -2;
02233                               goto triangular_error;
02234                             }
02235 
02236                           Complex tmp = cwork[k] / data(cidx(kidx+1)-1);
02237                           cwork[k] = tmp;
02238                           for (octave_idx_type i = cidx(kidx);
02239                                i < cidx(kidx+1)-1; i++)
02240                             {
02241                               octave_idx_type iidx = ridx(i);
02242                               cwork[iidx] = cwork[iidx] - tmp * data(i);
02243                             }
02244                         }
02245                     }
02246 
02247                   for (octave_idx_type i = 0; i < nc; i++)
02248                     retval.xelem (perm[i], j) = cwork[i];
02249                 }
02250 
02251               if (calc_cond)
02252                 {
02253                   // Calculation of 1-norm of inv(*this)
02254                   OCTAVE_LOCAL_BUFFER (double, work, nm);
02255                   for (octave_idx_type i = 0; i < nm; i++)
02256                     work[i] = 0.;
02257 
02258                   for (octave_idx_type j = 0; j < nr; j++)
02259                     {
02260                       work[j] = 1.;
02261 
02262                       for (octave_idx_type k = j; k >= 0; k--)
02263                         {
02264                           octave_idx_type iidx = perm[k];
02265 
02266                           if (work[k] != 0.)
02267                             {
02268                               double tmp = work[k] / data(cidx(iidx+1)-1);
02269                               work[k] = tmp;
02270                               for (octave_idx_type i = cidx(iidx);
02271                                    i < cidx(iidx+1)-1; i++)
02272                                 {
02273                                   octave_idx_type idx2 = ridx(i);
02274                                   work[idx2] = work[idx2] - tmp * data(i);
02275                                 }
02276                             }
02277                         }
02278                       double atmp = 0;
02279                       for (octave_idx_type i = 0; i < j+1; i++)
02280                         {
02281                           atmp += fabs(work[i]);
02282                           work[i] = 0.;
02283                         }
02284                       if (atmp > ainvnorm)
02285                         ainvnorm = atmp;
02286                     }
02287                   rcond = 1. / ainvnorm / anorm;
02288                 }
02289             }
02290           else
02291             {
02292               OCTAVE_LOCAL_BUFFER (Complex, cwork, nm);
02293               retval.resize (nc, b_nc);
02294 
02295               for (octave_idx_type j = 0; j < b_nc; j++)
02296                 {
02297                   for (octave_idx_type i = 0; i < nr; i++)
02298                     cwork[i] = b(i,j);
02299                   for (octave_idx_type i = nr; i < nc; i++)
02300                     cwork[i] = 0.;
02301 
02302                   for (octave_idx_type k = nc-1; k >= 0; k--)
02303                     {
02304                       if (cwork[k] != 0.)
02305                         {
02306                           if (ridx(cidx(k+1)-1) != k ||
02307                               data(cidx(k+1)-1) == 0.)
02308                             {
02309                               err = -2;
02310                               goto triangular_error;
02311                             }
02312 
02313                           Complex tmp = cwork[k] / data(cidx(k+1)-1);
02314                           cwork[k] = tmp;
02315                           for (octave_idx_type i = cidx(k); i < cidx(k+1)-1; i++)
02316                             {
02317                               octave_idx_type iidx = ridx(i);
02318                               cwork[iidx] = cwork[iidx] - tmp  * data(i);
02319                             }
02320                         }
02321                     }
02322 
02323                   for (octave_idx_type i = 0; i < nc; i++)
02324                     retval.xelem (i, j) = cwork[i];
02325                 }
02326 
02327               if (calc_cond)
02328                 {
02329                   // Calculation of 1-norm of inv(*this)
02330                   OCTAVE_LOCAL_BUFFER (double, work, nm);
02331                   for (octave_idx_type i = 0; i < nm; i++)
02332                     work[i] = 0.;
02333 
02334                   for (octave_idx_type j = 0; j < nr; j++)
02335                     {
02336                       work[j] = 1.;
02337 
02338                       for (octave_idx_type k = j; k >= 0; k--)
02339                         {
02340                           if (work[k] != 0.)
02341                             {
02342                               double tmp = work[k] / data(cidx(k+1)-1);
02343                               work[k] = tmp;
02344                               for (octave_idx_type i = cidx(k);
02345                                    i < cidx(k+1)-1; i++)
02346                                 {
02347                                   octave_idx_type iidx = ridx(i);
02348                                   work[iidx] = work[iidx] - tmp * data(i);
02349                                 }
02350                             }
02351                         }
02352                       double atmp = 0;
02353                       for (octave_idx_type i = 0; i < j+1; i++)
02354                         {
02355                           atmp += fabs(work[i]);
02356                           work[i] = 0.;
02357                         }
02358                       if (atmp > ainvnorm)
02359                         ainvnorm = atmp;
02360                     }
02361                   rcond = 1. / ainvnorm / anorm;
02362                 }
02363             }
02364 
02365         triangular_error:
02366           if (err != 0)
02367             {
02368               if (sing_handler)
02369                 {
02370                   sing_handler (rcond);
02371                   mattype.mark_as_rectangular ();
02372                 }
02373               else
02374                 (*current_liboctave_error_handler)
02375                   ("SparseMatrix::solve matrix singular to machine precision, rcond = %g",
02376                    rcond);
02377             }
02378 
02379           volatile double rcond_plus_one = rcond + 1.0;
02380 
02381           if (rcond_plus_one == 1.0 || xisnan (rcond))
02382             {
02383               err = -2;
02384 
02385               if (sing_handler)
02386                 {
02387                   sing_handler (rcond);
02388                   mattype.mark_as_rectangular ();
02389                 }
02390               else
02391                 (*current_liboctave_error_handler)
02392                   ("matrix singular to machine precision, rcond = %g",
02393                    rcond);
02394             }
02395         }
02396       else
02397         (*current_liboctave_error_handler) ("incorrect matrix type");
02398     }
02399 
02400   return retval;
02401 }
02402 
02403 SparseComplexMatrix
02404 SparseMatrix::utsolve (MatrixType &mattype, const SparseComplexMatrix& b,
02405                        octave_idx_type& err, double& rcond,
02406                        solve_singularity_handler sing_handler,
02407                        bool calc_cond) const
02408 {
02409   SparseComplexMatrix retval;
02410 
02411   octave_idx_type nr = rows ();
02412   octave_idx_type nc = cols ();
02413   octave_idx_type nm = (nc > nr ? nc : nr);
02414   err = 0;
02415 
02416   if (nr != b.rows ())
02417     (*current_liboctave_error_handler)
02418       ("matrix dimension mismatch solution of linear equations");
02419   else if (nr == 0 || nc == 0 || b.cols () == 0)
02420     retval = SparseComplexMatrix (nc, b.cols ());
02421   else
02422     {
02423       // Print spparms("spumoni") info if requested
02424       int typ = mattype.type ();
02425       mattype.info ();
02426 
02427       if (typ == MatrixType::Permuted_Upper ||
02428           typ == MatrixType::Upper)
02429         {
02430           double anorm = 0.;
02431           double ainvnorm = 0.;
02432           rcond = 1.;
02433 
02434           if (calc_cond)
02435             {
02436               // Calculate the 1-norm of matrix for rcond calculation
02437               for (octave_idx_type j = 0; j < nc; j++)
02438                 {
02439                   double atmp = 0.;
02440                   for (octave_idx_type i = cidx(j); i < cidx(j+1); i++)
02441                     atmp += fabs(data(i));
02442                   if (atmp > anorm)
02443                     anorm = atmp;
02444                 }
02445             }
02446 
02447           octave_idx_type b_nc = b.cols ();
02448           octave_idx_type b_nz = b.nnz ();
02449           retval = SparseComplexMatrix (nc, b_nc, b_nz);
02450           retval.xcidx(0) = 0;
02451           octave_idx_type ii = 0;
02452           octave_idx_type x_nz = b_nz;
02453 
02454           if (typ == MatrixType::Permuted_Upper)
02455             {
02456               octave_idx_type *perm = mattype.triangular_perm ();
02457               OCTAVE_LOCAL_BUFFER (Complex, cwork, nm);
02458 
02459               OCTAVE_LOCAL_BUFFER (octave_idx_type, rperm, nc);
02460               for (octave_idx_type i = 0; i < nc; i++)
02461                 rperm[perm[i]] = i;
02462 
02463               for (octave_idx_type j = 0; j < b_nc; j++)
02464                 {
02465                   for (octave_idx_type i = 0; i < nm; i++)
02466                     cwork[i] = 0.;
02467                   for (octave_idx_type i = b.cidx(j); i < b.cidx(j+1); i++)
02468                     cwork[b.ridx(i)] = b.data(i);
02469 
02470                   for (octave_idx_type k = nc-1; k >= 0; k--)
02471                     {
02472                       octave_idx_type kidx = perm[k];
02473 
02474                       if (cwork[k] != 0.)
02475                         {
02476                           if (ridx(cidx(kidx+1)-1) != k ||
02477                               data(cidx(kidx+1)-1) == 0.)
02478                             {
02479                               err = -2;
02480                               goto triangular_error;
02481                             }
02482 
02483                           Complex tmp = cwork[k] / data(cidx(kidx+1)-1);
02484                           cwork[k] = tmp;
02485                           for (octave_idx_type i = cidx(kidx);
02486                                i < cidx(kidx+1)-1; i++)
02487                             {
02488                               octave_idx_type iidx = ridx(i);
02489                               cwork[iidx] = cwork[iidx] - tmp * data(i);
02490                             }
02491                         }
02492                     }
02493 
02494                   // Count non-zeros in work vector and adjust space in
02495                   // retval if needed
02496                   octave_idx_type new_nnz = 0;
02497                   for (octave_idx_type i = 0; i < nc; i++)
02498                     if (cwork[i] != 0.)
02499                       new_nnz++;
02500 
02501                   if (ii + new_nnz > x_nz)
02502                     {
02503                       // Resize the sparse matrix
02504                       octave_idx_type sz = new_nnz * (b_nc - j) + x_nz;
02505                       retval.change_capacity (sz);
02506                       x_nz = sz;
02507                     }
02508 
02509                   for (octave_idx_type i = 0; i < nc; i++)
02510                     if (cwork[rperm[i]] != 0.)
02511                       {
02512                         retval.xridx(ii) = i;
02513                         retval.xdata(ii++) = cwork[rperm[i]];
02514                       }
02515                   retval.xcidx(j+1) = ii;
02516                 }
02517 
02518               retval.maybe_compress ();
02519 
02520               if (calc_cond)
02521                 {
02522                   // Calculation of 1-norm of inv(*this)
02523                   OCTAVE_LOCAL_BUFFER (double, work, nm);
02524                   for (octave_idx_type i = 0; i < nm; i++)
02525                     work[i] = 0.;
02526 
02527                   for (octave_idx_type j = 0; j < nr; j++)
02528                     {
02529                       work[j] = 1.;
02530 
02531                       for (octave_idx_type k = j; k >= 0; k--)
02532                         {
02533                           octave_idx_type iidx = perm[k];
02534 
02535                           if (work[k] != 0.)
02536                             {
02537                               double tmp = work[k] / data(cidx(iidx+1)-1);
02538                               work[k] = tmp;
02539                               for (octave_idx_type i = cidx(iidx);
02540                                    i < cidx(iidx+1)-1; i++)
02541                                 {
02542                                   octave_idx_type idx2 = ridx(i);
02543                                   work[idx2] = work[idx2] - tmp * data(i);
02544                                 }
02545                             }
02546                         }
02547                       double atmp = 0;
02548                       for (octave_idx_type i = 0; i < j+1; i++)
02549                         {
02550                           atmp += fabs(work[i]);
02551                           work[i] = 0.;
02552                         }
02553                       if (atmp > ainvnorm)
02554                         ainvnorm = atmp;
02555                     }
02556                   rcond = 1. / ainvnorm / anorm;
02557                 }
02558             }
02559           else
02560             {
02561               OCTAVE_LOCAL_BUFFER (Complex, cwork, nm);
02562 
02563               for (octave_idx_type j = 0; j < b_nc; j++)
02564                 {
02565                   for (octave_idx_type i = 0; i < nm; i++)
02566                     cwork[i] = 0.;
02567                   for (octave_idx_type i = b.cidx(j); i < b.cidx(j+1); i++)
02568                     cwork[b.ridx(i)] = b.data(i);
02569 
02570                   for (octave_idx_type k = nc-1; k >= 0; k--)
02571                     {
02572                       if (cwork[k] != 0.)
02573                         {
02574                           if (ridx(cidx(k+1)-1) != k ||
02575                               data(cidx(k+1)-1) == 0.)
02576                             {
02577                               err = -2;
02578                               goto triangular_error;
02579                             }
02580 
02581                           Complex tmp = cwork[k] / data(cidx(k+1)-1);
02582                           cwork[k] = tmp;
02583                           for (octave_idx_type i = cidx(k); i < cidx(k+1)-1; i++)
02584                             {
02585                               octave_idx_type iidx = ridx(i);
02586                               cwork[iidx] = cwork[iidx] - tmp * data(i);
02587                             }
02588                         }
02589                     }
02590 
02591                   // Count non-zeros in work vector and adjust space in
02592                   // retval if needed
02593                   octave_idx_type new_nnz = 0;
02594                   for (octave_idx_type i = 0; i < nc; i++)
02595                     if (cwork[i] != 0.)
02596                       new_nnz++;
02597 
02598                   if (ii + new_nnz > x_nz)
02599                     {
02600                       // Resize the sparse matrix
02601                       octave_idx_type sz = new_nnz * (b_nc - j) + x_nz;
02602                       retval.change_capacity (sz);
02603                       x_nz = sz;
02604                     }
02605 
02606                   for (octave_idx_type i = 0; i < nc; i++)
02607                     if (cwork[i] != 0.)
02608                       {
02609                         retval.xridx(ii) = i;
02610                         retval.xdata(ii++) = cwork[i];
02611                       }
02612                   retval.xcidx(j+1) = ii;
02613                 }
02614 
02615               retval.maybe_compress ();
02616 
02617               if (calc_cond)
02618                 {
02619                   // Calculation of 1-norm of inv(*this)
02620                   OCTAVE_LOCAL_BUFFER (double, work, nm);
02621                   for (octave_idx_type i = 0; i < nm; i++)
02622                     work[i] = 0.;
02623 
02624                   for (octave_idx_type j = 0; j < nr; j++)
02625                     {
02626                       work[j] = 1.;
02627 
02628                       for (octave_idx_type k = j; k >= 0; k--)
02629                         {
02630                           if (work[k] != 0.)
02631                             {
02632                               double tmp = work[k] / data(cidx(k+1)-1);
02633                               work[k] = tmp;
02634                               for (octave_idx_type i = cidx(k);
02635                                    i < cidx(k+1)-1; i++)
02636                                 {
02637                                   octave_idx_type iidx = ridx(i);
02638                                   work[iidx] = work[iidx] - tmp * data(i);
02639                                 }
02640                             }
02641                         }
02642                       double atmp = 0;
02643                       for (octave_idx_type i = 0; i < j+1; i++)
02644                         {
02645                           atmp += fabs(work[i]);
02646                           work[i] = 0.;
02647                         }
02648                       if (atmp > ainvnorm)
02649                         ainvnorm = atmp;
02650                     }
02651                   rcond = 1. / ainvnorm / anorm;
02652                 }
02653             }
02654 
02655         triangular_error:
02656           if (err != 0)
02657             {
02658               if (sing_handler)
02659                 {
02660                   sing_handler (rcond);
02661                   mattype.mark_as_rectangular ();
02662                 }
02663               else
02664                 (*current_liboctave_error_handler)
02665                   ("SparseMatrix::solve matrix singular to machine precision, rcond = %g",
02666                    rcond);
02667             }
02668 
02669           volatile double rcond_plus_one = rcond + 1.0;
02670 
02671           if (rcond_plus_one == 1.0 || xisnan (rcond))
02672             {
02673               err = -2;
02674 
02675               if (sing_handler)
02676                 {
02677                   sing_handler (rcond);
02678                   mattype.mark_as_rectangular ();
02679                 }
02680               else
02681                 (*current_liboctave_error_handler)
02682                   ("matrix singular to machine precision, rcond = %g",
02683                    rcond);
02684             }
02685         }
02686       else
02687         (*current_liboctave_error_handler) ("incorrect matrix type");
02688     }
02689 
02690   return retval;
02691 }
02692 
02693 Matrix
02694 SparseMatrix::ltsolve (MatrixType &mattype, const Matrix& b,
02695                        octave_idx_type& err, double& rcond,
02696                        solve_singularity_handler sing_handler,
02697                        bool calc_cond) const
02698 {
02699   Matrix retval;
02700 
02701   octave_idx_type nr = rows ();
02702   octave_idx_type nc = cols ();
02703   octave_idx_type nm = (nc > nr ? nc : nr);
02704   err = 0;
02705 
02706   if (nr != b.rows ())
02707     (*current_liboctave_error_handler)
02708       ("matrix dimension mismatch solution of linear equations");
02709   else if (nr == 0 || nc == 0 || b.cols () == 0)
02710     retval = Matrix (nc, b.cols (), 0.0);
02711   else
02712     {
02713       // Print spparms("spumoni") info if requested
02714       int typ = mattype.type ();
02715       mattype.info ();
02716 
02717       if (typ == MatrixType::Permuted_Lower ||
02718           typ == MatrixType::Lower)
02719         {
02720           double anorm = 0.;
02721           double ainvnorm = 0.;
02722           octave_idx_type b_nc = b.cols ();
02723           rcond = 1.;
02724 
02725           if (calc_cond)
02726             {
02727               // Calculate the 1-norm of matrix for rcond calculation
02728               for (octave_idx_type j = 0; j < nc; j++)
02729                 {
02730                   double atmp = 0.;
02731                   for (octave_idx_type i = cidx(j); i < cidx(j+1); i++)
02732                     atmp += fabs(data(i));
02733                   if (atmp > anorm)
02734                     anorm = atmp;
02735                 }
02736             }
02737 
02738           if (typ == MatrixType::Permuted_Lower)
02739             {
02740               retval.resize (nc, b_nc);
02741               OCTAVE_LOCAL_BUFFER (double, work, nm);
02742               octave_idx_type *perm = mattype.triangular_perm ();
02743 
02744               for (octave_idx_type j = 0; j < b_nc; j++)
02745                 {
02746                   if (nc > nr)
02747                     for (octave_idx_type i = 0; i < nm; i++)
02748                       work[i] = 0.;
02749                   for (octave_idx_type i = 0; i < nr; i++)
02750                     work[perm[i]] = b(i,j);
02751 
02752                   for (octave_idx_type k = 0; k < nc; k++)
02753                     {
02754                       if (work[k] != 0.)
02755                         {
02756                           octave_idx_type minr = nr;
02757                           octave_idx_type mini = 0;
02758 
02759                           for (octave_idx_type i = cidx(k); i < cidx(k+1); i++)
02760                             if (perm[ridx(i)] < minr)
02761                               {
02762                                 minr = perm[ridx(i)];
02763                                 mini = i;
02764                               }
02765 
02766                           if (minr != k || data(mini) == 0)
02767                             {
02768                               err = -2;
02769                               goto triangular_error;
02770                             }
02771 
02772                           double tmp = work[k] / data(mini);
02773                           work[k] = tmp;
02774                           for (octave_idx_type i = cidx(k); i < cidx(k+1); i++)
02775                             {
02776                               if (i == mini)
02777                                 continue;
02778 
02779                               octave_idx_type iidx = perm[ridx(i)];
02780                               work[iidx] = work[iidx] - tmp * data(i);
02781                             }
02782                         }
02783                     }
02784 
02785                   for (octave_idx_type i = 0; i < nc; i++)
02786                     retval (i, j) = work[i];
02787                 }
02788 
02789               if (calc_cond)
02790                 {
02791                   // Calculation of 1-norm of inv(*this)
02792                   for (octave_idx_type i = 0; i < nm; i++)
02793                     work[i] = 0.;
02794 
02795                   for (octave_idx_type j = 0; j < nr; j++)
02796                     {
02797                       work[j] = 1.;
02798 
02799                       for (octave_idx_type k = 0; k < nc; k++)
02800                         {
02801                           if (work[k] != 0.)
02802                             {
02803                               octave_idx_type minr = nr;
02804                               octave_idx_type mini = 0;
02805 
02806                               for (octave_idx_type i = cidx(k);
02807                                    i < cidx(k+1); i++)
02808                                 if (perm[ridx(i)] < minr)
02809                                   {
02810                                     minr = perm[ridx(i)];
02811                                     mini = i;
02812                                   }
02813 
02814                               double tmp = work[k] / data(mini);
02815                               work[k] = tmp;
02816                               for (octave_idx_type i = cidx(k);
02817                                    i < cidx(k+1); i++)
02818                                 {
02819                                   if (i == mini)
02820                                     continue;
02821 
02822                                   octave_idx_type iidx = perm[ridx(i)];
02823                                   work[iidx] = work[iidx] - tmp * data(i);
02824                                 }
02825                             }
02826                         }
02827 
02828                       double atmp = 0;
02829                       for (octave_idx_type i = j; i < nc; i++)
02830                         {
02831                           atmp += fabs(work[i]);
02832                           work[i] = 0.;
02833                         }
02834                       if (atmp > ainvnorm)
02835                         ainvnorm = atmp;
02836                     }
02837                   rcond = 1. / ainvnorm / anorm;
02838                 }
02839             }
02840           else
02841             {
02842               OCTAVE_LOCAL_BUFFER (double, work, nm);
02843               retval.resize (nc, b_nc, 0.);
02844 
02845               for (octave_idx_type j = 0; j < b_nc; j++)
02846                 {
02847                   for (octave_idx_type i = 0; i < nr; i++)
02848                     work[i] = b(i,j);
02849                   for (octave_idx_type i = nr; i < nc; i++)
02850                     work[i] = 0.;
02851                   for (octave_idx_type k = 0; k < nc; k++)
02852                     {
02853                       if (work[k] != 0.)
02854                         {
02855                           if (ridx(cidx(k)) != k ||
02856                               data(cidx(k)) == 0.)
02857                             {
02858                               err = -2;
02859                               goto triangular_error;
02860                             }
02861 
02862                           double tmp = work[k] / data(cidx(k));
02863                           work[k] = tmp;
02864                           for (octave_idx_type i = cidx(k)+1;
02865                                i < cidx(k+1); i++)
02866                             {
02867                               octave_idx_type iidx = ridx(i);
02868                               work[iidx] = work[iidx] - tmp * data(i);
02869                             }
02870                         }
02871                     }
02872 
02873                   for (octave_idx_type i = 0; i < nc; i++)
02874                     retval.xelem (i, j) = work[i];
02875                 }
02876 
02877               if (calc_cond)
02878                 {
02879                   // Calculation of 1-norm of inv(*this)
02880                   for (octave_idx_type i = 0; i < nm; i++)
02881                     work[i] = 0.;
02882 
02883                   for (octave_idx_type j = 0; j < nr; j++)
02884                     {
02885                       work[j] = 1.;
02886 
02887                       for (octave_idx_type k = j; k < nc; k++)
02888                         {
02889 
02890                           if (work[k] != 0.)
02891                             {
02892                               double tmp = work[k] / data(cidx(k));
02893                               work[k] = tmp;
02894                               for (octave_idx_type i = cidx(k)+1;
02895                                    i < cidx(k+1); i++)
02896                                 {
02897                                   octave_idx_type iidx = ridx(i);
02898                                   work[iidx] = work[iidx] - tmp * data(i);
02899                                 }
02900                             }
02901                         }
02902                       double atmp = 0;
02903                       for (octave_idx_type i = j; i < nc; i++)
02904                         {
02905                           atmp += fabs(work[i]);
02906                           work[i] = 0.;
02907                         }
02908                       if (atmp > ainvnorm)
02909                         ainvnorm = atmp;
02910                     }
02911                   rcond = 1. / ainvnorm / anorm;
02912                 }
02913             }
02914 
02915         triangular_error:
02916           if (err != 0)
02917             {
02918               if (sing_handler)
02919                 {
02920                   sing_handler (rcond);
02921                   mattype.mark_as_rectangular ();
02922                 }
02923               else
02924                 (*current_liboctave_error_handler)
02925                   ("SparseMatrix::solve matrix singular to machine precision, rcond = %g",
02926                    rcond);
02927             }
02928 
02929           volatile double rcond_plus_one = rcond + 1.0;
02930 
02931           if (rcond_plus_one == 1.0 || xisnan (rcond))
02932             {
02933               err = -2;
02934 
02935               if (sing_handler)
02936                 {
02937                   sing_handler (rcond);
02938                   mattype.mark_as_rectangular ();
02939                 }
02940               else
02941                 (*current_liboctave_error_handler)
02942                   ("matrix singular to machine precision, rcond = %g",
02943                    rcond);
02944             }
02945         }
02946       else
02947         (*current_liboctave_error_handler) ("incorrect matrix type");
02948     }
02949 
02950   return retval;
02951 }
02952 
02953 SparseMatrix
02954 SparseMatrix::ltsolve (MatrixType &mattype, const SparseMatrix& b,
02955                        octave_idx_type& err, double& rcond,
02956                        solve_singularity_handler sing_handler,
02957                        bool calc_cond) const
02958 {
02959   SparseMatrix retval;
02960 
02961   octave_idx_type nr = rows ();
02962   octave_idx_type nc = cols ();
02963   octave_idx_type nm = (nc > nr ? nc : nr);
02964   err = 0;
02965 
02966   if (nr != b.rows ())
02967     (*current_liboctave_error_handler)
02968       ("matrix dimension mismatch solution of linear equations");
02969   else if (nr == 0 || nc == 0 || b.cols () == 0)
02970     retval = SparseMatrix (nc, b.cols ());
02971   else
02972     {
02973       // Print spparms("spumoni") info if requested
02974       int typ = mattype.type ();
02975       mattype.info ();
02976 
02977       if (typ == MatrixType::Permuted_Lower ||
02978           typ == MatrixType::Lower)
02979         {
02980           double anorm = 0.;
02981           double ainvnorm = 0.;
02982           rcond = 1.;
02983 
02984           if (calc_cond)
02985             {
02986               // Calculate the 1-norm of matrix for rcond calculation
02987               for (octave_idx_type j = 0; j < nc; j++)
02988                 {
02989                   double atmp = 0.;
02990                   for (octave_idx_type i = cidx(j); i < cidx(j+1); i++)
02991                     atmp += fabs(data(i));
02992                   if (atmp > anorm)
02993                     anorm = atmp;
02994                 }
02995             }
02996 
02997           octave_idx_type b_nc = b.cols ();
02998           octave_idx_type b_nz = b.nnz ();
02999           retval = SparseMatrix (nc, b_nc, b_nz);
03000           retval.xcidx(0) = 0;
03001           octave_idx_type ii = 0;
03002           octave_idx_type x_nz = b_nz;
03003 
03004           if (typ == MatrixType::Permuted_Lower)
03005             {
03006               OCTAVE_LOCAL_BUFFER (double, work, nm);
03007               octave_idx_type *perm = mattype.triangular_perm ();
03008 
03009               for (octave_idx_type j = 0; j < b_nc; j++)
03010                 {
03011                   for (octave_idx_type i = 0; i < nm; i++)
03012                     work[i] = 0.;
03013                   for (octave_idx_type i = b.cidx(j); i < b.cidx(j+1); i++)
03014                     work[perm[b.ridx(i)]] = b.data(i);
03015 
03016                   for (octave_idx_type k = 0; k < nc; k++)
03017                     {
03018                       if (work[k] != 0.)
03019                         {
03020                           octave_idx_type minr = nr;
03021                           octave_idx_type mini = 0;
03022 
03023                           for (octave_idx_type i = cidx(k); i < cidx(k+1); i++)
03024                             if (perm[ridx(i)] < minr)
03025                               {
03026                                 minr = perm[ridx(i)];
03027                                 mini = i;
03028                               }
03029 
03030                           if (minr != k || data(mini) == 0)
03031                             {
03032                               err = -2;
03033                               goto triangular_error;
03034                             }
03035 
03036                           double tmp = work[k] / data(mini);
03037                           work[k] = tmp;
03038                           for (octave_idx_type i = cidx(k); i < cidx(k+1); i++)
03039                             {
03040                               if (i == mini)
03041                                 continue;
03042 
03043                               octave_idx_type iidx = perm[ridx(i)];
03044                               work[iidx] = work[iidx] - tmp * data(i);
03045                             }
03046                         }
03047                     }
03048 
03049                   // Count non-zeros in work vector and adjust space in
03050                   // retval if needed
03051                   octave_idx_type new_nnz = 0;
03052                   for (octave_idx_type i = 0; i < nc; i++)
03053                     if (work[i] != 0.)
03054                       new_nnz++;
03055 
03056                   if (ii + new_nnz > x_nz)
03057                     {
03058                       // Resize the sparse matrix
03059                       octave_idx_type sz = new_nnz * (b_nc - j) + x_nz;
03060                       retval.change_capacity (sz);
03061                       x_nz = sz;
03062                     }
03063 
03064                   for (octave_idx_type i = 0; i < nc; i++)
03065                     if (work[i] != 0.)
03066                       {
03067                         retval.xridx(ii) = i;
03068                         retval.xdata(ii++) = work[i];
03069                       }
03070                   retval.xcidx(j+1) = ii;
03071                 }
03072 
03073               retval.maybe_compress ();
03074 
03075               if (calc_cond)
03076                 {
03077                   // Calculation of 1-norm of inv(*this)
03078                   for (octave_idx_type i = 0; i < nm; i++)
03079                     work[i] = 0.;
03080 
03081                   for (octave_idx_type j = 0; j < nr; j++)
03082                     {
03083                       work[j] = 1.;
03084 
03085                       for (octave_idx_type k = 0; k < nc; k++)
03086                         {
03087                           if (work[k] != 0.)
03088                             {
03089                               octave_idx_type minr = nr;
03090                               octave_idx_type mini = 0;
03091 
03092                               for (octave_idx_type i = cidx(k);
03093                                    i < cidx(k+1); i++)
03094                                 if (perm[ridx(i)] < minr)
03095                                   {
03096                                     minr = perm[ridx(i)];
03097                                     mini = i;
03098                                   }
03099 
03100                               double tmp = work[k] / data(mini);
03101                               work[k] = tmp;
03102                               for (octave_idx_type i = cidx(k);
03103                                    i < cidx(k+1); i++)
03104                                 {
03105                                   if (i == mini)
03106                                     continue;
03107 
03108                                   octave_idx_type iidx = perm[ridx(i)];
03109                                   work[iidx] = work[iidx] - tmp * data(i);
03110                                 }
03111                             }
03112                         }
03113 
03114                       double atmp = 0;
03115                       for (octave_idx_type i = j; i < nr; i++)
03116                         {
03117                           atmp += fabs(work[i]);
03118                           work[i] = 0.;
03119                         }
03120                       if (atmp > ainvnorm)
03121                         ainvnorm = atmp;
03122                     }
03123                   rcond = 1. / ainvnorm / anorm;
03124                 }
03125             }
03126           else
03127             {
03128               OCTAVE_LOCAL_BUFFER (double, work, nm);
03129 
03130               for (octave_idx_type j = 0; j < b_nc; j++)
03131                 {
03132                   for (octave_idx_type i = 0; i < nm; i++)
03133                     work[i] = 0.;
03134                   for (octave_idx_type i = b.cidx(j); i < b.cidx(j+1); i++)
03135                     work[b.ridx(i)] = b.data(i);
03136 
03137                   for (octave_idx_type k = 0; k < nc; k++)
03138                     {
03139                       if (work[k] != 0.)
03140                         {
03141                           if (ridx(cidx(k)) != k ||
03142                               data(cidx(k)) == 0.)
03143                             {
03144                               err = -2;
03145                               goto triangular_error;
03146                             }
03147 
03148                           double tmp = work[k] / data(cidx(k));
03149                           work[k] = tmp;
03150                           for (octave_idx_type i = cidx(k)+1; i < cidx(k+1); i++)
03151                             {
03152                               octave_idx_type iidx = ridx(i);
03153                               work[iidx] = work[iidx] - tmp * data(i);
03154                             }
03155                         }
03156                     }
03157 
03158                   // Count non-zeros in work vector and adjust space in
03159                   // retval if needed
03160                   octave_idx_type new_nnz = 0;
03161                   for (octave_idx_type i = 0; i < nc; i++)
03162                     if (work[i] != 0.)
03163                       new_nnz++;
03164 
03165                   if (ii + new_nnz > x_nz)
03166                     {
03167                       // Resize the sparse matrix
03168                       octave_idx_type sz = new_nnz * (b_nc - j) + x_nz;
03169                       retval.change_capacity (sz);
03170                       x_nz = sz;
03171                     }
03172 
03173                   for (octave_idx_type i = 0; i < nc; i++)
03174                     if (work[i] != 0.)
03175                       {
03176                         retval.xridx(ii) = i;
03177                         retval.xdata(ii++) = work[i];
03178                       }
03179                   retval.xcidx(j+1) = ii;
03180                 }
03181 
03182               retval.maybe_compress ();
03183 
03184               if (calc_cond)
03185                 {
03186                   // Calculation of 1-norm of inv(*this)
03187                   for (octave_idx_type i = 0; i < nm; i++)
03188                     work[i] = 0.;
03189 
03190                   for (octave_idx_type j = 0; j < nr; j++)
03191                     {
03192                       work[j] = 1.;
03193 
03194                       for (octave_idx_type k = j; k < nc; k++)
03195                         {
03196 
03197                           if (work[k] != 0.)
03198                             {
03199                               double tmp = work[k] / data(cidx(k));
03200                               work[k] = tmp;
03201                               for (octave_idx_type i = cidx(k)+1;
03202                                    i < cidx(k+1); i++)
03203                                 {
03204                                   octave_idx_type iidx = ridx(i);
03205                                   work[iidx] = work[iidx] - tmp * data(i);
03206                                 }
03207                             }
03208                         }
03209                       double atmp = 0;
03210                       for (octave_idx_type i = j; i < nc; i++)
03211                         {
03212                           atmp += fabs(work[i]);
03213                           work[i] = 0.;
03214                         }
03215                       if (atmp > ainvnorm)
03216                         ainvnorm = atmp;
03217                     }
03218                   rcond = 1. / ainvnorm / anorm;
03219                 }
03220             }
03221 
03222         triangular_error:
03223           if (err != 0)
03224             {
03225               if (sing_handler)
03226                 {
03227                   sing_handler (rcond);
03228                   mattype.mark_as_rectangular ();
03229                 }
03230               else
03231                 (*current_liboctave_error_handler)
03232                   ("SparseMatrix::solve matrix singular to machine precision, rcond = %g",
03233                    rcond);
03234             }
03235 
03236           volatile double rcond_plus_one = rcond + 1.0;
03237 
03238           if (rcond_plus_one == 1.0 || xisnan (rcond))
03239             {
03240               err = -2;
03241 
03242               if (sing_handler)
03243                 {
03244                   sing_handler (rcond);
03245                   mattype.mark_as_rectangular ();
03246                 }
03247               else
03248                 (*current_liboctave_error_handler)
03249                   ("matrix singular to machine precision, rcond = %g",
03250                    rcond);
03251             }
03252         }
03253       else
03254         (*current_liboctave_error_handler) ("incorrect matrix type");
03255     }
03256 
03257   return retval;
03258 }
03259 
03260 ComplexMatrix
03261 SparseMatrix::ltsolve (MatrixType &mattype, const ComplexMatrix& b,
03262                        octave_idx_type& err, double& rcond,
03263                        solve_singularity_handler sing_handler,
03264                        bool calc_cond) const
03265 {
03266   ComplexMatrix retval;
03267 
03268   octave_idx_type nr = rows ();
03269   octave_idx_type nc = cols ();
03270   octave_idx_type nm = (nc > nr ? nc : nr);
03271   err = 0;
03272 
03273   if (nr != b.rows ())
03274     (*current_liboctave_error_handler)
03275       ("matrix dimension mismatch solution of linear equations");
03276   else if (nr == 0 || nc == 0 || b.cols () == 0)
03277     retval = ComplexMatrix (nc, b.cols (), Complex (0.0, 0.0));
03278   else
03279     {
03280       // Print spparms("spumoni") info if requested
03281       int typ = mattype.type ();
03282       mattype.info ();
03283 
03284       if (typ == MatrixType::Permuted_Lower ||
03285           typ == MatrixType::Lower)
03286         {
03287           double anorm = 0.;
03288           double ainvnorm = 0.;
03289           octave_idx_type b_nc = b.cols ();
03290           rcond = 1.;
03291 
03292           if (calc_cond)
03293             {
03294               // Calculate the 1-norm of matrix for rcond calculation
03295               for (octave_idx_type j = 0; j < nc; j++)
03296                 {
03297                   double atmp = 0.;
03298                   for (octave_idx_type i = cidx(j); i < cidx(j+1); i++)
03299                     atmp += fabs(data(i));
03300                   if (atmp > anorm)
03301                     anorm = atmp;
03302                 }
03303             }
03304 
03305           if (typ == MatrixType::Permuted_Lower)
03306             {
03307               retval.resize (nc, b_nc);
03308               OCTAVE_LOCAL_BUFFER (Complex, cwork, nm);
03309               octave_idx_type *perm = mattype.triangular_perm ();
03310 
03311               for (octave_idx_type j = 0; j < b_nc; j++)
03312                 {
03313                   for (octave_idx_type i = 0; i < nm; i++)
03314                     cwork[i] = 0.;
03315                   for (octave_idx_type i = 0; i < nr; i++)
03316                     cwork[perm[i]] = b(i,j);
03317 
03318                   for (octave_idx_type k = 0; k < nc; k++)
03319                     {
03320                       if (cwork[k] != 0.)
03321                         {
03322                           octave_idx_type minr = nr;
03323                           octave_idx_type mini = 0;
03324 
03325                           for (octave_idx_type i = cidx(k); i < cidx(k+1); i++)
03326                             if (perm[ridx(i)] < minr)
03327                               {
03328                                 minr = perm[ridx(i)];
03329                                 mini = i;
03330                               }
03331 
03332                           if (minr != k || data(mini) == 0)
03333                             {
03334                               err = -2;
03335                               goto triangular_error;
03336                             }
03337 
03338                           Complex tmp = cwork[k] / data(mini);
03339                           cwork[k] = tmp;
03340                           for (octave_idx_type i = cidx(k); i < cidx(k+1); i++)
03341                             {
03342                               if (i == mini)
03343                                 continue;
03344 
03345                               octave_idx_type iidx = perm[ridx(i)];
03346                               cwork[iidx] = cwork[iidx] - tmp * data(i);
03347                             }
03348                         }
03349                     }
03350 
03351                   for (octave_idx_type i = 0; i < nc; i++)
03352                     retval (i, j) = cwork[i];
03353                 }
03354 
03355               if (calc_cond)
03356                 {
03357                   // Calculation of 1-norm of inv(*this)
03358                   OCTAVE_LOCAL_BUFFER (double, work, nm);
03359                   for (octave_idx_type i = 0; i < nm; i++)
03360                     work[i] = 0.;
03361 
03362                   for (octave_idx_type j = 0; j < nr; j++)
03363                     {
03364                       work[j] = 1.;
03365 
03366                       for (octave_idx_type k = 0; k < nc; k++)
03367                         {
03368                           if (work[k] != 0.)
03369                             {
03370                               octave_idx_type minr = nr;
03371                               octave_idx_type mini = 0;
03372 
03373                               for (octave_idx_type i = cidx(k);
03374                                    i < cidx(k+1); i++)
03375                                 if (perm[ridx(i)] < minr)
03376                                   {
03377                                     minr = perm[ridx(i)];
03378                                     mini = i;
03379                                   }
03380 
03381                               double tmp = work[k] / data(mini);
03382                               work[k] = tmp;
03383                               for (octave_idx_type i = cidx(k);
03384                                    i < cidx(k+1); i++)
03385                                 {
03386                                   if (i == mini)
03387                                     continue;
03388 
03389                                   octave_idx_type iidx = perm[ridx(i)];
03390                                   work[iidx] = work[iidx] - tmp * data(i);
03391                                 }
03392                             }
03393                         }
03394 
03395                       double atmp = 0;
03396                       for (octave_idx_type i = j; i < nc; i++)
03397                         {
03398                           atmp += fabs(work[i]);
03399                           work[i] = 0.;
03400                         }
03401                       if (atmp > ainvnorm)
03402                         ainvnorm = atmp;
03403                     }
03404                   rcond = 1. / ainvnorm / anorm;
03405                 }
03406             }
03407           else
03408             {
03409               OCTAVE_LOCAL_BUFFER (Complex, cwork, nm);
03410               retval.resize (nc, b_nc, 0.);
03411 
03412               for (octave_idx_type j = 0; j < b_nc; j++)
03413                 {
03414                   for (octave_idx_type i = 0; i < nr; i++)
03415                     cwork[i] = b(i,j);
03416                   for (octave_idx_type i = nr; i < nc; i++)
03417                     cwork[i] = 0.;
03418 
03419                   for (octave_idx_type k = 0; k < nc; k++)
03420                     {
03421                       if (cwork[k] != 0.)
03422                         {
03423                           if (ridx(cidx(k)) != k ||
03424                               data(cidx(k)) == 0.)
03425                             {
03426                               err = -2;
03427                               goto triangular_error;
03428                             }
03429 
03430                           Complex tmp = cwork[k] / data(cidx(k));
03431                           cwork[k] = tmp;
03432                           for (octave_idx_type i = cidx(k)+1; i < cidx(k+1); i++)
03433                             {
03434                               octave_idx_type iidx = ridx(i);
03435                               cwork[iidx] = cwork[iidx] - tmp * data(i);
03436                             }
03437                         }
03438                     }
03439 
03440                   for (octave_idx_type i = 0; i < nc; i++)
03441                     retval.xelem (i, j) = cwork[i];
03442                 }
03443 
03444               if (calc_cond)
03445                 {
03446                   // Calculation of 1-norm of inv(*this)
03447                   OCTAVE_LOCAL_BUFFER (double, work, nm);
03448                   for (octave_idx_type i = 0; i < nm; i++)
03449                     work[i] = 0.;
03450 
03451                   for (octave_idx_type j = 0; j < nr; j++)
03452                     {
03453                       work[j] = 1.;
03454 
03455                       for (octave_idx_type k = j; k < nc; k++)
03456                         {
03457 
03458                           if (work[k] != 0.)
03459                             {
03460                               double tmp = work[k] / data(cidx(k));
03461                               work[k] = tmp;
03462                               for (octave_idx_type i = cidx(k)+1;
03463                                    i < cidx(k+1); i++)
03464                                 {
03465                                   octave_idx_type iidx = ridx(i);
03466                                   work[iidx] = work[iidx] - tmp * data(i);
03467                                 }
03468                             }
03469                         }
03470                       double atmp = 0;
03471                       for (octave_idx_type i = j; i < nc; i++)
03472                         {
03473                           atmp += fabs(work[i]);
03474                           work[i] = 0.;
03475                         }
03476                       if (atmp > ainvnorm)
03477                         ainvnorm = atmp;
03478                     }
03479                   rcond = 1. / ainvnorm / anorm;
03480                 }
03481             }
03482 
03483         triangular_error:
03484           if (err != 0)
03485             {
03486               if (sing_handler)
03487                 {
03488                   sing_handler (rcond);
03489                   mattype.mark_as_rectangular ();
03490                 }
03491               else
03492                 (*current_liboctave_error_handler)
03493                   ("SparseMatrix::solve matrix singular to machine precision, rcond = %g",
03494                    rcond);
03495             }
03496 
03497           volatile double rcond_plus_one = rcond + 1.0;
03498 
03499           if (rcond_plus_one == 1.0 || xisnan (rcond))
03500             {
03501               err = -2;
03502 
03503               if (sing_handler)
03504                 {
03505                   sing_handler (rcond);
03506                   mattype.mark_as_rectangular ();
03507                 }
03508               else
03509                 (*current_liboctave_error_handler)
03510                   ("matrix singular to machine precision, rcond = %g",
03511                    rcond);
03512             }
03513         }
03514       else
03515         (*current_liboctave_error_handler) ("incorrect matrix type");
03516     }
03517 
03518   return retval;
03519 }
03520 
03521 SparseComplexMatrix
03522 SparseMatrix::ltsolve (MatrixType &mattype, const SparseComplexMatrix& b,
03523                        octave_idx_type& err, double& rcond,
03524                        solve_singularity_handler sing_handler,
03525                        bool calc_cond) const
03526 {
03527   SparseComplexMatrix retval;
03528 
03529   octave_idx_type nr = rows ();
03530   octave_idx_type nc = cols ();
03531   octave_idx_type nm = (nc > nr ? nc : nr);
03532   err = 0;
03533 
03534   if (nr != b.rows ())
03535     (*current_liboctave_error_handler)
03536       ("matrix dimension mismatch solution of linear equations");
03537   else if (nr == 0 || nc == 0 || b.cols () == 0)
03538     retval = SparseComplexMatrix (nc, b.cols ());
03539   else
03540     {
03541       // Print spparms("spumoni") info if requested
03542       int typ = mattype.type ();
03543       mattype.info ();
03544 
03545       if (typ == MatrixType::Permuted_Lower ||
03546           typ == MatrixType::Lower)
03547         {
03548           double anorm = 0.;
03549           double ainvnorm = 0.;
03550           rcond = 1.;
03551 
03552           if (calc_cond)
03553             {
03554               // Calculate the 1-norm of matrix for rcond calculation
03555               for (octave_idx_type j = 0; j < nc; j++)
03556                 {
03557                   double atmp = 0.;
03558                   for (octave_idx_type i = cidx(j); i < cidx(j+1); i++)
03559                     atmp += fabs(data(i));
03560                   if (atmp > anorm)
03561                     anorm = atmp;
03562                 }
03563             }
03564 
03565           octave_idx_type b_nc = b.cols ();
03566           octave_idx_type b_nz = b.nnz ();
03567           retval = SparseComplexMatrix (nc, b_nc, b_nz);
03568           retval.xcidx(0) = 0;
03569           octave_idx_type ii = 0;
03570           octave_idx_type x_nz = b_nz;
03571 
03572           if (typ == MatrixType::Permuted_Lower)
03573             {
03574               OCTAVE_LOCAL_BUFFER (Complex, cwork, nm);
03575               octave_idx_type *perm = mattype.triangular_perm ();
03576 
03577               for (octave_idx_type j = 0; j < b_nc; j++)
03578                 {
03579                   for (octave_idx_type i = 0; i < nm; i++)
03580                     cwork[i] = 0.;
03581                   for (octave_idx_type i = b.cidx(j); i < b.cidx(j+1); i++)
03582                     cwork[perm[b.ridx(i)]] = b.data(i);
03583 
03584                   for (octave_idx_type k = 0; k < nc; k++)
03585                     {
03586                       if (cwork[k] != 0.)
03587                         {
03588                           octave_idx_type minr = nr;
03589                           octave_idx_type mini = 0;
03590 
03591                           for (octave_idx_type i = cidx(k); i < cidx(k+1); i++)
03592                             if (perm[ridx(i)] < minr)
03593                               {
03594                                 minr = perm[ridx(i)];
03595                                 mini = i;
03596                               }
03597 
03598                           if (minr != k || data(mini) == 0)
03599                             {
03600                               err = -2;
03601                               goto triangular_error;
03602                             }
03603 
03604                           Complex tmp = cwork[k] / data(mini);
03605                           cwork[k] = tmp;
03606                           for (octave_idx_type i = cidx(k); i < cidx(k+1); i++)
03607                             {
03608                               if (i == mini)
03609                                 continue;
03610 
03611                               octave_idx_type iidx = perm[ridx(i)];
03612                               cwork[iidx] = cwork[iidx] - tmp * data(i);
03613                             }
03614                         }
03615                     }
03616 
03617                   // Count non-zeros in work vector and adjust space in
03618                   // retval if needed
03619                   octave_idx_type new_nnz = 0;
03620                   for (octave_idx_type i = 0; i < nc; i++)
03621                     if (cwork[i] != 0.)
03622                       new_nnz++;
03623 
03624                   if (ii + new_nnz > x_nz)
03625                     {
03626                       // Resize the sparse matrix
03627                       octave_idx_type sz = new_nnz * (b_nc - j) + x_nz;
03628                       retval.change_capacity (sz);
03629                       x_nz = sz;
03630                     }
03631 
03632                   for (octave_idx_type i = 0; i < nc; i++)
03633                     if (cwork[i] != 0.)
03634                       {
03635                         retval.xridx(ii) = i;
03636                         retval.xdata(ii++) = cwork[i];
03637                       }
03638                   retval.xcidx(j+1) = ii;
03639                 }
03640 
03641               retval.maybe_compress ();
03642 
03643               if (calc_cond)
03644                 {
03645                   // Calculation of 1-norm of inv(*this)
03646                   OCTAVE_LOCAL_BUFFER (double, work, nm);
03647                   for (octave_idx_type i = 0; i < nm; i++)
03648                     work[i] = 0.;
03649 
03650                   for (octave_idx_type j = 0; j < nr; j++)
03651                     {
03652                       work[j] = 1.;
03653 
03654                       for (octave_idx_type k = 0; k < nc; k++)
03655                         {
03656                           if (work[k] != 0.)
03657                             {
03658                               octave_idx_type minr = nr;
03659                               octave_idx_type mini = 0;
03660 
03661                               for (octave_idx_type i = cidx(k);
03662                                    i < cidx(k+1); i++)
03663                                 if (perm[ridx(i)] < minr)
03664                                   {
03665                                     minr = perm[ridx(i)];
03666                                     mini = i;
03667                                   }
03668 
03669                               double tmp = work[k] / data(mini);
03670                               work[k] = tmp;
03671                               for (octave_idx_type i = cidx(k);
03672                                    i < cidx(k+1); i++)
03673                                 {
03674                                   if (i == mini)
03675                                     continue;
03676 
03677                                   octave_idx_type iidx = perm[ridx(i)];
03678                                   work[iidx] = work[iidx] - tmp * data(i);
03679                                 }
03680                             }
03681                         }
03682 
03683                       double atmp = 0;
03684                       for (octave_idx_type i = j; i < nc; i++)
03685                         {
03686                           atmp += fabs(work[i]);
03687                           work[i] = 0.;
03688                         }
03689                       if (atmp > ainvnorm)
03690                         ainvnorm = atmp;
03691                     }
03692                   rcond = 1. / ainvnorm / anorm;
03693                 }
03694             }
03695           else
03696             {
03697               OCTAVE_LOCAL_BUFFER (Complex, cwork, nm);
03698 
03699               for (octave_idx_type j = 0; j < b_nc; j++)
03700                 {
03701                   for (octave_idx_type i = 0; i < nm; i++)
03702                     cwork[i] = 0.;
03703                   for (octave_idx_type i = b.cidx(j); i < b.cidx(j+1); i++)
03704                     cwork[b.ridx(i)] = b.data(i);
03705 
03706                   for (octave_idx_type k = 0; k < nc; k++)
03707                     {
03708                       if (cwork[k] != 0.)
03709                         {
03710                           if (ridx(cidx(k)) != k ||
03711                               data(cidx(k)) == 0.)
03712                             {
03713                               err = -2;
03714                               goto triangular_error;
03715                             }
03716 
03717                           Complex tmp = cwork[k] / data(cidx(k));
03718                           cwork[k] = tmp;
03719                           for (octave_idx_type i = cidx(k)+1; i < cidx(k+1); i++)
03720                             {
03721                               octave_idx_type iidx = ridx(i);
03722                               cwork[iidx] = cwork[iidx] - tmp * data(i);
03723                             }
03724                         }
03725                     }
03726 
03727                   // Count non-zeros in work vector and adjust space in
03728                   // retval if needed
03729                   octave_idx_type new_nnz = 0;
03730                   for (octave_idx_type i = 0; i < nc; i++)
03731                     if (cwork[i] != 0.)
03732                       new_nnz++;
03733 
03734                   if (ii + new_nnz > x_nz)
03735                     {
03736                       // Resize the sparse matrix
03737                       octave_idx_type sz = new_nnz * (b_nc - j) + x_nz;
03738                       retval.change_capacity (sz);
03739                       x_nz = sz;
03740                     }
03741 
03742                   for (octave_idx_type i = 0; i < nc; i++)
03743                     if (cwork[i] != 0.)
03744                       {
03745                         retval.xridx(ii) = i;
03746                         retval.xdata(ii++) = cwork[i];
03747                       }
03748                   retval.xcidx(j+1) = ii;
03749                 }
03750 
03751               retval.maybe_compress ();
03752 
03753               if (calc_cond)
03754                 {
03755                   // Calculation of 1-norm of inv(*this)
03756                   OCTAVE_LOCAL_BUFFER (double, work, nm);
03757                   for (octave_idx_type i = 0; i < nm; i++)
03758                     work[i] = 0.;
03759 
03760                   for (octave_idx_type j = 0; j < nr; j++)
03761                     {
03762                       work[j] = 1.;
03763 
03764                       for (octave_idx_type k = j; k < nc; k++)
03765                         {
03766 
03767                           if (work[k] != 0.)
03768                             {
03769                               double tmp = work[k] / data(cidx(k));
03770                               work[k] = tmp;
03771                               for (octave_idx_type i = cidx(k)+1;
03772                                    i < cidx(k+1); i++)
03773                                 {
03774                                   octave_idx_type iidx = ridx(i);
03775                                   work[iidx] = work[iidx] - tmp * data(i);
03776                                 }
03777                             }
03778                         }
03779                       double atmp = 0;
03780                       for (octave_idx_type i = j; i < nc; i++)
03781                         {
03782                           atmp += fabs(work[i]);
03783                           work[i] = 0.;
03784                         }
03785                       if (atmp > ainvnorm)
03786                         ainvnorm = atmp;
03787                     }
03788                   rcond = 1. / ainvnorm / anorm;
03789                 }
03790             }
03791 
03792         triangular_error:
03793           if (err != 0)
03794             {
03795               if (sing_handler)
03796                 {
03797                   sing_handler (rcond);
03798                   mattype.mark_as_rectangular ();
03799                 }
03800               else
03801                 (*current_liboctave_error_handler)
03802                   ("SparseMatrix::solve matrix singular to machine precision, rcond = %g",
03803                    rcond);
03804             }
03805 
03806           volatile double rcond_plus_one = rcond + 1.0;
03807 
03808           if (rcond_plus_one == 1.0 || xisnan (rcond))
03809             {
03810               err = -2;
03811 
03812               if (sing_handler)
03813                 {
03814                   sing_handler (rcond);
03815                   mattype.mark_as_rectangular ();
03816                 }
03817               else
03818                 (*current_liboctave_error_handler)
03819                   ("matrix singular to machine precision, rcond = %g",
03820                    rcond);
03821             }
03822         }
03823       else
03824         (*current_liboctave_error_handler) ("incorrect matrix type");
03825     }
03826 
03827   return retval;
03828 }
03829 
03830 Matrix
03831 SparseMatrix::trisolve (MatrixType &mattype, const Matrix& b,
03832                         octave_idx_type& err, double& rcond,
03833                         solve_singularity_handler sing_handler,
03834                         bool calc_cond) const
03835 {
03836   Matrix retval;
03837 
03838   octave_idx_type nr = rows ();
03839   octave_idx_type nc = cols ();
03840   err = 0;
03841 
03842   if (nr != nc || nr != b.rows ())
03843     (*current_liboctave_error_handler)
03844       ("matrix dimension mismatch solution of linear equations");
03845   else if (nr == 0 || b.cols () == 0)
03846     retval = Matrix (nc, b.cols (), 0.0);
03847   else if (calc_cond)
03848     (*current_liboctave_error_handler)
03849       ("calculation of condition number not implemented");
03850   else
03851     {
03852       // Print spparms("spumoni") info if requested
03853       volatile int typ = mattype.type ();
03854       mattype.info ();
03855 
03856       if (typ == MatrixType::Tridiagonal_Hermitian)
03857         {
03858           OCTAVE_LOCAL_BUFFER (double, D, nr);
03859           OCTAVE_LOCAL_BUFFER (double, DL, nr - 1);
03860 
03861           if (mattype.is_dense ())
03862             {
03863               octave_idx_type ii = 0;
03864 
03865               for (octave_idx_type j = 0; j < nc-1; j++)
03866                 {
03867                   D[j] = data(ii++);
03868                   DL[j] = data(ii);
03869                   ii += 2;
03870                 }
03871               D[nc-1] = data(ii);
03872             }
03873           else
03874             {
03875               D[0] = 0.;
03876               for (octave_idx_type i = 0; i < nr - 1; i++)
03877                 {
03878                   D[i+1] = 0.;
03879                   DL[i] = 0.;
03880                 }
03881 
03882               for (octave_idx_type j = 0; j < nc; j++)
03883                 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++)
03884                   {
03885                     if (ridx(i) == j)
03886                       D[j] = data(i);
03887                     else if (ridx(i) == j + 1)
03888                       DL[j] = data(i);
03889                   }
03890             }
03891 
03892           octave_idx_type b_nc = b.cols();
03893           retval = b;
03894           double *result = retval.fortran_vec ();
03895 
03896           F77_XFCN (dptsv, DPTSV, (nr, b_nc, D, DL, result,
03897                                    b.rows(), err));
03898 
03899           if (err != 0)
03900             {
03901               err = 0;
03902               mattype.mark_as_unsymmetric ();
03903               typ = MatrixType::Tridiagonal;
03904             }
03905           else
03906             rcond = 1.;
03907         }
03908 
03909       if (typ == MatrixType::Tridiagonal)
03910         {
03911           OCTAVE_LOCAL_BUFFER (double, DU, nr - 1);
03912           OCTAVE_LOCAL_BUFFER (double, D, nr);
03913           OCTAVE_LOCAL_BUFFER (double, DL, nr - 1);
03914 
03915           if (mattype.is_dense ())
03916             {
03917               octave_idx_type ii = 0;
03918 
03919               for (octave_idx_type j = 0; j < nc-1; j++)
03920                 {
03921                   D[j] = data(ii++);
03922                   DL[j] = data(ii++);
03923                   DU[j] = data(ii++);
03924                 }
03925               D[nc-1] = data(ii);
03926             }
03927           else
03928             {
03929               D[0] = 0.;
03930               for (octave_idx_type i = 0; i < nr - 1; i++)
03931                 {
03932                   D[i+1] = 0.;
03933                   DL[i] = 0.;
03934                   DU[i] = 0.;
03935                 }
03936 
03937               for (octave_idx_type j = 0; j < nc; j++)
03938                 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++)
03939                   {
03940                     if (ridx(i) == j)
03941                       D[j] = data(i);
03942                     else if (ridx(i) == j + 1)
03943                       DL[j] = data(i);
03944                     else if (ridx(i) == j - 1)
03945                       DU[j-1] = data(i);
03946                   }
03947             }
03948 
03949           octave_idx_type b_nc = b.cols();
03950           retval = b;
03951           double *result = retval.fortran_vec ();
03952 
03953           F77_XFCN (dgtsv, DGTSV, (nr, b_nc, DL, D, DU, result,
03954                                    b.rows(), err));
03955 
03956           if (err != 0)
03957             {
03958               rcond = 0.;
03959               err = -2;
03960 
03961               if (sing_handler)
03962                 {
03963                   sing_handler (rcond);
03964                   mattype.mark_as_rectangular ();
03965                 }
03966               else
03967                 (*current_liboctave_error_handler)
03968                   ("matrix singular to machine precision");
03969 
03970             }
03971           else
03972             rcond = 1.;
03973         }
03974       else if (typ != MatrixType::Tridiagonal_Hermitian)
03975                (*current_liboctave_error_handler) ("incorrect matrix type");
03976     }
03977 
03978   return retval;
03979 }
03980 
03981 SparseMatrix
03982 SparseMatrix::trisolve (MatrixType &mattype, const SparseMatrix& b,
03983                         octave_idx_type& err, double& rcond,
03984                         solve_singularity_handler sing_handler,
03985                         bool calc_cond) const
03986 {
03987   SparseMatrix retval;
03988 
03989   octave_idx_type nr = rows ();
03990   octave_idx_type nc = cols ();
03991   err = 0;
03992 
03993   if (nr != nc || nr != b.rows ())
03994     (*current_liboctave_error_handler)
03995       ("matrix dimension mismatch solution of linear equations");
03996   else if (nr == 0 || b.cols () == 0)
03997     retval = SparseMatrix (nc, b.cols ());
03998   else if (calc_cond)
03999     (*current_liboctave_error_handler)
04000       ("calculation of condition number not implemented");
04001   else
04002     {
04003       // Print spparms("spumoni") info if requested
04004       int typ = mattype.type ();
04005       mattype.info ();
04006 
04007       // Note can't treat symmetric case as there is no dpttrf function
04008       if (typ == MatrixType::Tridiagonal ||
04009           typ == MatrixType::Tridiagonal_Hermitian)
04010         {
04011           OCTAVE_LOCAL_BUFFER (double, DU2, nr - 2);
04012           OCTAVE_LOCAL_BUFFER (double, DU, nr - 1);
04013           OCTAVE_LOCAL_BUFFER (double, D, nr);
04014           OCTAVE_LOCAL_BUFFER (double, DL, nr - 1);
04015           Array<octave_idx_type> ipvt (dim_vector (nr, 1));
04016           octave_idx_type *pipvt = ipvt.fortran_vec ();
04017 
04018           if (mattype.is_dense ())
04019             {
04020               octave_idx_type ii = 0;
04021 
04022               for (octave_idx_type j = 0; j < nc-1; j++)
04023                 {
04024                   D[j] = data(ii++);
04025                   DL[j] = data(ii++);
04026                   DU[j] = data(ii++);
04027                 }
04028               D[nc-1] = data(ii);
04029             }
04030           else
04031             {
04032               D[0] = 0.;
04033               for (octave_idx_type i = 0; i < nr - 1; i++)
04034                 {
04035                   D[i+1] = 0.;
04036                   DL[i] = 0.;
04037                   DU[i] = 0.;
04038                 }
04039 
04040               for (octave_idx_type j = 0; j < nc; j++)
04041                 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++)
04042                   {
04043                     if (ridx(i) == j)
04044                       D[j] = data(i);
04045                     else if (ridx(i) == j + 1)
04046                       DL[j] = data(i);
04047                     else if (ridx(i) == j - 1)
04048                       DU[j-1] = data(i);
04049                   }
04050             }
04051 
04052           F77_XFCN (dgttrf, DGTTRF, (nr, DL, D, DU, DU2, pipvt, err));
04053 
04054           if (err != 0)
04055             {
04056               rcond = 0.0;
04057               err = -2;
04058 
04059               if (sing_handler)
04060                 {
04061                   sing_handler (rcond);
04062                   mattype.mark_as_rectangular ();
04063                 }
04064               else
04065                 (*current_liboctave_error_handler)
04066                   ("matrix singular to machine precision");
04067 
04068             }
04069           else
04070             {
04071               rcond = 1.0;
04072               char job = 'N';
04073               volatile octave_idx_type x_nz = b.nnz ();
04074               octave_idx_type b_nc = b.cols ();
04075               retval = SparseMatrix (nr, b_nc, x_nz);
04076               retval.xcidx(0) = 0;
04077               volatile octave_idx_type ii = 0;
04078 
04079               OCTAVE_LOCAL_BUFFER (double, work, nr);
04080 
04081               for (volatile octave_idx_type j = 0; j < b_nc; j++)
04082                 {
04083                   for (octave_idx_type i = 0; i < nr; i++)
04084                     work[i] = 0.;
04085                   for (octave_idx_type i = b.cidx(j); i < b.cidx(j+1); i++)
04086                     work[b.ridx(i)] = b.data(i);
04087 
04088                   F77_XFCN (dgttrs, DGTTRS,
04089                             (F77_CONST_CHAR_ARG2 (&job, 1),
04090                              nr, 1, DL, D, DU, DU2, pipvt,
04091                              work, b.rows (), err
04092                              F77_CHAR_ARG_LEN (1)));
04093 
04094                   // Count non-zeros in work vector and adjust
04095                   // space in retval if needed
04096                   octave_idx_type new_nnz = 0;
04097                   for (octave_idx_type i = 0; i < nr; i++)
04098                     if (work[i] != 0.)
04099                       new_nnz++;
04100 
04101                   if (ii + new_nnz > x_nz)
04102                     {
04103                       // Resize the sparse matrix
04104                       octave_idx_type sz = new_nnz * (b_nc - j) + x_nz;
04105                       retval.change_capacity (sz);
04106                       x_nz = sz;
04107                     }
04108 
04109                   for (octave_idx_type i = 0; i < nr; i++)
04110                     if (work[i] != 0.)
04111                       {
04112                         retval.xridx(ii) = i;
04113                         retval.xdata(ii++) = work[i];
04114                       }
04115                   retval.xcidx(j+1) = ii;
04116                 }
04117 
04118               retval.maybe_compress ();
04119             }
04120         }
04121       else if (typ != MatrixType::Tridiagonal_Hermitian)
04122         (*current_liboctave_error_handler) ("incorrect matrix type");
04123     }
04124 
04125   return retval;
04126 }
04127 
04128 ComplexMatrix
04129 SparseMatrix::trisolve (MatrixType &mattype, const ComplexMatrix& b,
04130                         octave_idx_type& err, double& rcond,
04131                         solve_singularity_handler sing_handler,
04132                         bool calc_cond) const
04133 {
04134   ComplexMatrix retval;
04135 
04136   octave_idx_type nr = rows ();
04137   octave_idx_type nc = cols ();
04138   err = 0;
04139 
04140   if (nr != nc || nr != b.rows ())
04141     (*current_liboctave_error_handler)
04142       ("matrix dimension mismatch solution of linear equations");
04143   else if (nr == 0 || b.cols () == 0)
04144     retval = ComplexMatrix (nc, b.cols (), Complex (0.0, 0.0));
04145   else if (calc_cond)
04146     (*current_liboctave_error_handler)
04147       ("calculation of condition number not implemented");
04148   else
04149     {
04150       // Print spparms("spumoni") info if requested
04151       volatile int typ = mattype.type ();
04152       mattype.info ();
04153 
04154       if (typ == MatrixType::Tridiagonal_Hermitian)
04155         {
04156           OCTAVE_LOCAL_BUFFER (double, D, nr);
04157           OCTAVE_LOCAL_BUFFER (Complex, DL, nr - 1);
04158 
04159           if (mattype.is_dense ())
04160             {
04161               octave_idx_type ii = 0;
04162 
04163               for (octave_idx_type j = 0; j < nc-1; j++)
04164                 {
04165                   D[j] = data(ii++);
04166                   DL[j] = data(ii);
04167                   ii += 2;
04168                 }
04169               D[nc-1] = data(ii);
04170             }
04171           else
04172             {
04173               D[0] = 0.;
04174               for (octave_idx_type i = 0; i < nr - 1; i++)
04175                 {
04176                   D[i+1] = 0.;
04177                   DL[i] = 0.;
04178                 }
04179 
04180               for (octave_idx_type j = 0; j < nc; j++)
04181                 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++)
04182                   {
04183                     if (ridx(i) == j)
04184                       D[j] = data(i);
04185                     else if (ridx(i) == j + 1)
04186                       DL[j] = data(i);
04187                   }
04188             }
04189 
04190           octave_idx_type b_nr = b.rows ();
04191           octave_idx_type b_nc = b.cols();
04192           rcond = 1.;
04193 
04194           retval = b;
04195           Complex *result = retval.fortran_vec ();
04196 
04197           F77_XFCN (zptsv, ZPTSV, (nr, b_nc, D, DL, result,
04198                                    b_nr, err));
04199 
04200           if (err != 0)
04201             {
04202               err = 0;
04203               mattype.mark_as_unsymmetric ();
04204               typ = MatrixType::Tridiagonal;
04205             }
04206         }
04207 
04208       if (typ == MatrixType::Tridiagonal)
04209         {
04210           OCTAVE_LOCAL_BUFFER (Complex, DU, nr - 1);
04211           OCTAVE_LOCAL_BUFFER (Complex, D, nr);
04212           OCTAVE_LOCAL_BUFFER (Complex, DL, nr - 1);
04213 
04214           if (mattype.is_dense ())
04215             {
04216               octave_idx_type ii = 0;
04217 
04218               for (octave_idx_type j = 0; j < nc-1; j++)
04219                 {
04220                   D[j] = data(ii++);
04221                   DL[j] = data(ii++);
04222                   DU[j] = data(ii++);
04223                 }
04224               D[nc-1] = data(ii);
04225             }
04226           else
04227             {
04228               D[0] = 0.;
04229               for (octave_idx_type i = 0; i < nr - 1; i++)
04230                 {
04231                   D[i+1] = 0.;
04232                   DL[i] = 0.;
04233                   DU[i] = 0.;
04234                 }
04235 
04236               for (octave_idx_type j = 0; j < nc; j++)
04237                 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++)
04238                   {
04239                     if (ridx(i) == j)
04240                       D[j] = data(i);
04241                     else if (ridx(i) == j + 1)
04242                       DL[j] = data(i);
04243                     else if (ridx(i) == j - 1)
04244                       DU[j-1] = data(i);
04245                   }
04246             }
04247 
04248           octave_idx_type b_nr = b.rows();
04249           octave_idx_type b_nc = b.cols();
04250           rcond = 1.;
04251 
04252           retval = b;
04253           Complex *result = retval.fortran_vec ();
04254 
04255           F77_XFCN (zgtsv, ZGTSV, (nr, b_nc, DL, D, DU, result,
04256                                    b_nr, err));
04257 
04258           if (err != 0)
04259             {
04260               rcond = 0.;
04261               err = -2;
04262 
04263               if (sing_handler)
04264                 {
04265                   sing_handler (rcond);
04266                   mattype.mark_as_rectangular ();
04267                 }
04268               else
04269                 (*current_liboctave_error_handler)
04270                   ("matrix singular to machine precision");
04271             }
04272         }
04273       else if (typ != MatrixType::Tridiagonal_Hermitian)
04274         (*current_liboctave_error_handler) ("incorrect matrix type");
04275     }
04276 
04277   return retval;
04278 }
04279 
04280 SparseComplexMatrix
04281 SparseMatrix::trisolve (MatrixType &mattype, const SparseComplexMatrix& b,
04282                         octave_idx_type& err, double& rcond,
04283                         solve_singularity_handler sing_handler,
04284                         bool calc_cond) const
04285 {
04286   SparseComplexMatrix retval;
04287 
04288   octave_idx_type nr = rows ();
04289   octave_idx_type nc = cols ();
04290   err = 0;
04291 
04292   if (nr != nc || nr != b.rows ())
04293     (*current_liboctave_error_handler)
04294       ("matrix dimension mismatch solution of linear equations");
04295   else if (nr == 0 || b.cols () == 0)
04296     retval = SparseComplexMatrix (nc, b.cols ());
04297   else if (calc_cond)
04298     (*current_liboctave_error_handler)
04299       ("calculation of condition number not implemented");
04300   else
04301     {
04302       // Print spparms("spumoni") info if requested
04303       int typ = mattype.type ();
04304       mattype.info ();
04305 
04306       // Note can't treat symmetric case as there is no dpttrf function
04307       if (typ == MatrixType::Tridiagonal ||
04308           typ == MatrixType::Tridiagonal_Hermitian)
04309         {
04310           OCTAVE_LOCAL_BUFFER (double, DU2, nr - 2);
04311           OCTAVE_LOCAL_BUFFER (double, DU, nr - 1);
04312           OCTAVE_LOCAL_BUFFER (double, D, nr);
04313           OCTAVE_LOCAL_BUFFER (double, DL, nr - 1);
04314           Array<octave_idx_type> ipvt (dim_vector (nr, 1));
04315           octave_idx_type *pipvt = ipvt.fortran_vec ();
04316 
04317           if (mattype.is_dense ())
04318             {
04319               octave_idx_type ii = 0;
04320 
04321               for (octave_idx_type j = 0; j < nc-1; j++)
04322                 {
04323                   D[j] = data(ii++);
04324                   DL[j] = data(ii++);
04325                   DU[j] = data(ii++);
04326                 }
04327               D[nc-1] = data(ii);
04328             }
04329           else
04330             {
04331               D[0] = 0.;
04332               for (octave_idx_type i = 0; i < nr - 1; i++)
04333                 {
04334                   D[i+1] = 0.;
04335                   DL[i] = 0.;
04336                   DU[i] = 0.;
04337                 }
04338 
04339               for (octave_idx_type j = 0; j < nc; j++)
04340                 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++)
04341                   {
04342                     if (ridx(i) == j)
04343                       D[j] = data(i);
04344                     else if (ridx(i) == j + 1)
04345                       DL[j] = data(i);
04346                     else if (ridx(i) == j - 1)
04347                       DU[j-1] = data(i);
04348                   }
04349             }
04350 
04351           F77_XFCN (dgttrf, DGTTRF, (nr, DL, D, DU, DU2, pipvt, err));
04352 
04353           if (err != 0)
04354             {
04355               rcond = 0.0;
04356               err = -2;
04357 
04358               if (sing_handler)
04359                 {
04360                   sing_handler (rcond);
04361                   mattype.mark_as_rectangular ();
04362                 }
04363               else
04364                 (*current_liboctave_error_handler)
04365                   ("matrix singular to machine precision");
04366             }
04367           else
04368             {
04369               rcond = 1.;
04370               char job = 'N';
04371               octave_idx_type b_nr = b.rows ();
04372               octave_idx_type b_nc = b.cols ();
04373               OCTAVE_LOCAL_BUFFER (double, Bx, b_nr);
04374               OCTAVE_LOCAL_BUFFER (double, Bz, b_nr);
04375 
04376               // Take a first guess that the number of non-zero terms
04377               // will be as many as in b
04378               volatile octave_idx_type x_nz = b.nnz ();
04379               volatile octave_idx_type ii = 0;
04380               retval = SparseComplexMatrix (b_nr, b_nc, x_nz);
04381 
04382               retval.xcidx(0) = 0;
04383               for (volatile octave_idx_type j = 0; j < b_nc; j++)
04384                 {
04385 
04386                   for (octave_idx_type i = 0; i < b_nr; i++)
04387                     {
04388                       Complex c = b (i,j);
04389                       Bx[i] = std::real (c);
04390                       Bz[i] = std::imag (c);
04391                     }
04392 
04393                   F77_XFCN (dgttrs, DGTTRS,
04394                             (F77_CONST_CHAR_ARG2 (&job, 1),
04395                              nr, 1, DL, D, DU, DU2, pipvt,
04396                              Bx, b_nr, err
04397                              F77_CHAR_ARG_LEN (1)));
04398 
04399                   if (err != 0)
04400                     {
04401                       (*current_liboctave_error_handler)
04402                         ("SparseMatrix::solve solve failed");
04403 
04404                       err = -1;
04405                       break;
04406                     }
04407 
04408                   F77_XFCN (dgttrs, DGTTRS,
04409                             (F77_CONST_CHAR_ARG2 (&job, 1),
04410                              nr, 1, DL, D, DU, DU2, pipvt,
04411                              Bz, b_nr, err
04412                              F77_CHAR_ARG_LEN (1)));
04413 
04414                   if (err != 0)
04415                     {
04416                       (*current_liboctave_error_handler)
04417                         ("SparseMatrix::solve solve failed");
04418 
04419                       err = -1;
04420                       break;
04421                     }
04422 
04423                   // Count non-zeros in work vector and adjust
04424                   // space in retval if needed
04425                   octave_idx_type new_nnz = 0;
04426                   for (octave_idx_type i = 0; i < nr; i++)
04427                     if (Bx[i] != 0. || Bz[i] != 0.)
04428                       new_nnz++;
04429 
04430                   if (ii + new_nnz > x_nz)
04431                     {
04432                       // Resize the sparse matrix
04433                       octave_idx_type sz = new_nnz * (b_nc - j) + x_nz;
04434                       retval.change_capacity (sz);
04435                       x_nz = sz;
04436                     }
04437 
04438                   for (octave_idx_type i = 0; i < nr; i++)
04439                     if (Bx[i] != 0. || Bz[i] != 0.)
04440                       {
04441                         retval.xridx(ii) = i;
04442                         retval.xdata(ii++) =
04443                           Complex (Bx[i], Bz[i]);
04444                       }
04445 
04446                   retval.xcidx(j+1) = ii;
04447                 }
04448 
04449               retval.maybe_compress ();
04450             }
04451         }
04452       else if (typ != MatrixType::Tridiagonal_Hermitian)
04453         (*current_liboctave_error_handler) ("incorrect matrix type");
04454     }
04455 
04456   return retval;
04457 }
04458 
04459 Matrix
04460 SparseMatrix::bsolve (MatrixType &mattype, const Matrix& b,
04461                       octave_idx_type& err, double& rcond,
04462                       solve_singularity_handler sing_handler,
04463                       bool calc_cond) const
04464 {
04465   Matrix retval;
04466 
04467   octave_idx_type nr = rows ();
04468   octave_idx_type nc = cols ();
04469   err = 0;
04470 
04471   if (nr != nc || nr != b.rows ())
04472     (*current_liboctave_error_handler)
04473       ("matrix dimension mismatch solution of linear equations");
04474   else if (nr == 0 || b.cols () == 0)
04475     retval = Matrix (nc, b.cols (), 0.0);
04476   else
04477     {
04478       // Print spparms("spumoni") info if requested
04479       volatile int typ = mattype.type ();
04480       mattype.info ();
04481 
04482       if (typ == MatrixType::Banded_Hermitian)
04483         {
04484           octave_idx_type n_lower = mattype.nlower ();
04485           octave_idx_type ldm = n_lower + 1;
04486           Matrix m_band (ldm, nc);
04487           double *tmp_data = m_band.fortran_vec ();
04488 
04489           if (! mattype.is_dense ())
04490             {
04491               octave_idx_type ii = 0;
04492 
04493               for (octave_idx_type j = 0; j < ldm; j++)
04494                 for (octave_idx_type i = 0; i < nc; i++)
04495                   tmp_data[ii++] = 0.;
04496             }
04497 
04498           for (octave_idx_type j = 0; j < nc; j++)
04499             for (octave_idx_type i = cidx(j); i < cidx(j+1); i++)
04500               {
04501                 octave_idx_type ri = ridx (i);
04502                 if (ri >= j)
04503                   m_band(ri - j, j) = data(i);
04504               }
04505 
04506           // Calculate the norm of the matrix, for later use.
04507           double anorm;
04508           if (calc_cond)
04509             anorm = m_band.abs().sum().row(0).max();
04510 
04511           char job = 'L';
04512           F77_XFCN (dpbtrf, DPBTRF, (F77_CONST_CHAR_ARG2 (&job, 1),
04513                                      nr, n_lower, tmp_data, ldm, err
04514                                      F77_CHAR_ARG_LEN (1)));
04515 
04516           if (err != 0)
04517             {
04518               // Matrix is not positive definite!! Fall through to
04519               // unsymmetric banded solver.
04520               mattype.mark_as_unsymmetric ();
04521               typ = MatrixType::Banded;
04522               rcond = 0.0;
04523               err = 0;
04524             }
04525           else
04526             {
04527               if (calc_cond)
04528                 {
04529                   Array<double> z (dim_vector (3 * nr, 1));
04530                   double *pz = z.fortran_vec ();
04531                   Array<octave_idx_type> iz (dim_vector (nr, 1));
04532                   octave_idx_type *piz = iz.fortran_vec ();
04533 
04534                   F77_XFCN (dpbcon, DPBCON,
04535                     (F77_CONST_CHAR_ARG2 (&job, 1),
04536                      nr, n_lower, tmp_data, ldm,
04537                      anorm, rcond, pz, piz, err
04538                      F77_CHAR_ARG_LEN (1)));
04539 
04540                   if (err != 0)
04541                     err = -2;
04542 
04543                   volatile double rcond_plus_one = rcond + 1.0;
04544 
04545                   if (rcond_plus_one == 1.0 || xisnan (rcond))
04546                     {
04547                       err = -2;
04548 
04549                       if (sing_handler)
04550                         {
04551                           sing_handler (rcond);
04552                           mattype.mark_as_rectangular ();
04553                         }
04554                       else
04555                         (*current_liboctave_error_handler)
04556                           ("matrix singular to machine precision, rcond = %g",
04557                            rcond);
04558                     }
04559                 }
04560               else
04561                 rcond = 1.;
04562 
04563               if (err == 0)
04564                 {
04565                   retval = b;
04566                   double *result = retval.fortran_vec ();
04567 
04568                   octave_idx_type b_nc = b.cols ();
04569 
04570                   F77_XFCN (dpbtrs, DPBTRS,
04571                             (F77_CONST_CHAR_ARG2 (&job, 1),
04572                              nr, n_lower, b_nc, tmp_data,
04573                              ldm, result, b.rows(), err
04574                              F77_CHAR_ARG_LEN (1)));
04575 
04576                   if (err != 0)
04577                     {
04578                       (*current_liboctave_error_handler)
04579                         ("SparseMatrix::solve solve failed");
04580                       err = -1;
04581                     }
04582                 }
04583             }
04584         }
04585 
04586       if (typ == MatrixType::Banded)
04587         {
04588           // Create the storage for the banded form of the sparse matrix
04589           octave_idx_type n_upper = mattype.nupper ();
04590           octave_idx_type n_lower = mattype.nlower ();
04591           octave_idx_type ldm = n_upper + 2 * n_lower + 1;
04592 
04593           Matrix m_band (ldm, nc);
04594           double *tmp_data = m_band.fortran_vec ();
04595 
04596           if (! mattype.is_dense ())
04597             {
04598               octave_idx_type ii = 0;
04599 
04600               for (octave_idx_type j = 0; j < ldm; j++)
04601                 for (octave_idx_type i = 0; i < nc; i++)
04602                   tmp_data[ii++] = 0.;
04603             }
04604 
04605           for (octave_idx_type j = 0; j < nc; j++)
04606             for (octave_idx_type i = cidx(j); i < cidx(j+1); i++)
04607               m_band(ridx(i) - j + n_lower + n_upper, j) = data(i);
04608 
04609           // Calculate the norm of the matrix, for later use.
04610           double anorm;
04611           if (calc_cond)
04612             {
04613               for (octave_idx_type j = 0; j < nr; j++)
04614                 {
04615                   double atmp = 0.;
04616                   for (octave_idx_type i = cidx(j); i < cidx(j+1); i++)
04617                     atmp += fabs(data(i));
04618                   if (atmp > anorm)
04619                     anorm = atmp;
04620                 }
04621             }
04622 
04623           Array<octave_idx_type> ipvt (dim_vector (nr, 1));
04624           octave_idx_type *pipvt = ipvt.fortran_vec ();
04625 
04626           F77_XFCN (dgbtrf, DGBTRF, (nr, nr, n_lower, n_upper, tmp_data,
04627                                      ldm, pipvt, err));
04628 
04629           // Throw-away extra info LAPACK gives so as to not
04630           // change output.
04631           if (err != 0)
04632             {
04633               err = -2;
04634               rcond = 0.0;
04635 
04636               if (sing_handler)
04637                 {
04638                   sing_handler (rcond);
04639                   mattype.mark_as_rectangular ();
04640                 }
04641               else
04642                 (*current_liboctave_error_handler)
04643                   ("matrix singular to machine precision");
04644 
04645             }
04646           else
04647             {
04648               if (calc_cond)
04649                 {
04650                   char job = '1';
04651                   Array<double> z (dim_vector (3 * nr, 1));
04652                   double *pz = z.fortran_vec ();
04653                   Array<octave_idx_type> iz (dim_vector (nr, 1));
04654                   octave_idx_type *piz = iz.fortran_vec ();
04655 
04656                   F77_XFCN (dgbcon, DGBCON,
04657                     (F77_CONST_CHAR_ARG2 (&job, 1),
04658                      nc, n_lower, n_upper, tmp_data, ldm, pipvt,
04659                      anorm, rcond, pz, piz, err
04660                      F77_CHAR_ARG_LEN (1)));
04661 
04662                    if (err != 0)
04663                     err = -2;
04664 
04665                   volatile double rcond_plus_one = rcond + 1.0;
04666 
04667                   if (rcond_plus_one == 1.0 || xisnan (rcond))
04668                     {
04669                       err = -2;
04670 
04671                       if (sing_handler)
04672                         {
04673                           sing_handler (rcond);
04674                           mattype.mark_as_rectangular ();
04675                         }
04676                       else
04677                         (*current_liboctave_error_handler)
04678                           ("matrix singular to machine precision, rcond = %g",
04679                            rcond);
04680                     }
04681                 }
04682               else
04683                 rcond = 1.;
04684 
04685               if (err == 0)
04686                 {
04687                   retval = b;
04688                   double *result = retval.fortran_vec ();
04689 
04690                   octave_idx_type b_nc = b.cols ();
04691 
04692                   char job = 'N';
04693                   F77_XFCN (dgbtrs, DGBTRS,
04694                             (F77_CONST_CHAR_ARG2 (&job, 1),
04695                              nr, n_lower, n_upper, b_nc, tmp_data,
04696                              ldm, pipvt, result, b.rows(), err
04697                              F77_CHAR_ARG_LEN (1)));
04698                 }
04699             }
04700         }
04701       else if (typ != MatrixType::Banded_Hermitian)
04702         (*current_liboctave_error_handler) ("incorrect matrix type");
04703     }
04704 
04705   return retval;
04706 }
04707 
04708 SparseMatrix
04709 SparseMatrix::bsolve (MatrixType &mattype, const SparseMatrix& b,
04710                       octave_idx_type& err, double& rcond,
04711                       solve_singularity_handler sing_handler,
04712                       bool calc_cond) const
04713 {
04714   SparseMatrix retval;
04715 
04716   octave_idx_type nr = rows ();
04717   octave_idx_type nc = cols ();
04718   err = 0;
04719 
04720   if (nr != nc || nr != b.rows ())
04721     (*current_liboctave_error_handler)
04722       ("matrix dimension mismatch solution of linear equations");
04723   else if (nr == 0 || b.cols () == 0)
04724     retval = SparseMatrix (nc, b.cols ());
04725   else
04726     {
04727       // Print spparms("spumoni") info if requested
04728       volatile int typ = mattype.type ();
04729       mattype.info ();
04730 
04731       if (typ == MatrixType::Banded_Hermitian)
04732         {
04733           octave_idx_type n_lower = mattype.nlower ();
04734           octave_idx_type ldm = n_lower + 1;
04735 
04736           Matrix m_band (ldm, nc);
04737           double *tmp_data = m_band.fortran_vec ();
04738 
04739           if (! mattype.is_dense ())
04740             {
04741               octave_idx_type ii = 0;
04742 
04743               for (octave_idx_type j = 0; j < ldm; j++)
04744                 for (octave_idx_type i = 0; i < nc; i++)
04745                   tmp_data[ii++] = 0.;
04746             }
04747 
04748           for (octave_idx_type j = 0; j < nc; j++)
04749             for (octave_idx_type i = cidx(j); i < cidx(j+1); i++)
04750               {
04751                 octave_idx_type ri = ridx (i);
04752                 if (ri >= j)
04753                   m_band(ri - j, j) = data(i);
04754               }
04755 
04756           // Calculate the norm of the matrix, for later use.
04757           double anorm;
04758           if (calc_cond)
04759             anorm = m_band.abs().sum().row(0).max();
04760 
04761           char job = 'L';
04762           F77_XFCN (dpbtrf, DPBTRF, (F77_CONST_CHAR_ARG2 (&job, 1),
04763                                      nr, n_lower, tmp_data, ldm, err
04764                                      F77_CHAR_ARG_LEN (1)));
04765 
04766           if (err != 0)
04767             {
04768               mattype.mark_as_unsymmetric ();
04769               typ = MatrixType::Banded;
04770               rcond = 0.0;
04771               err = 0;
04772             }
04773           else
04774             {
04775               if (calc_cond)
04776                 {
04777                   Array<double> z (dim_vector (3 * nr, 1));
04778                   double *pz = z.fortran_vec ();
04779                   Array<octave_idx_type> iz (dim_vector (nr, 1));
04780                   octave_idx_type *piz = iz.fortran_vec ();
04781 
04782                   F77_XFCN (dpbcon, DPBCON,
04783                     (F77_CONST_CHAR_ARG2 (&job, 1),
04784                      nr, n_lower, tmp_data, ldm,
04785                      anorm, rcond, pz, piz, err
04786                      F77_CHAR_ARG_LEN (1)));
04787 
04788                   if (err != 0)
04789                     err = -2;
04790 
04791                   volatile double rcond_plus_one = rcond + 1.0;
04792 
04793                   if (rcond_plus_one == 1.0 || xisnan (rcond))
04794                     {
04795                       err = -2;
04796 
04797                       if (sing_handler)
04798                         {
04799                           sing_handler (rcond);
04800                           mattype.mark_as_rectangular ();
04801                         }
04802                       else
04803                         (*current_liboctave_error_handler)
04804                           ("matrix singular to machine precision, rcond = %g",
04805                            rcond);
04806                     }
04807                 }
04808               else
04809                 rcond = 1.;
04810 
04811               if (err == 0)
04812                 {
04813                   octave_idx_type b_nr = b.rows ();
04814                   octave_idx_type b_nc = b.cols ();
04815                   OCTAVE_LOCAL_BUFFER (double, Bx, b_nr);
04816 
04817                   // Take a first guess that the number of non-zero terms
04818                   // will be as many as in b
04819                   volatile octave_idx_type x_nz = b.nnz ();
04820                   volatile octave_idx_type ii = 0;
04821                   retval = SparseMatrix (b_nr, b_nc, x_nz);
04822 
04823                   retval.xcidx(0) = 0;
04824                   for (volatile octave_idx_type j = 0; j < b_nc; j++)
04825                     {
04826                       for (octave_idx_type i = 0; i < b_nr; i++)
04827                         Bx[i] = b.elem (i, j);
04828 
04829                       F77_XFCN (dpbtrs, DPBTRS,
04830                                 (F77_CONST_CHAR_ARG2 (&job, 1),
04831                                  nr, n_lower, 1, tmp_data,
04832                                  ldm, Bx, b_nr, err
04833                                  F77_CHAR_ARG_LEN (1)));
04834 
04835                       if (err != 0)
04836                         {
04837                           (*current_liboctave_error_handler)
04838                             ("SparseMatrix::solve solve failed");
04839                           err = -1;
04840                           break;
04841                         }
04842 
04843                       for (octave_idx_type i = 0; i < b_nr; i++)
04844                         {
04845                           double tmp = Bx[i];
04846                           if (tmp != 0.0)
04847                             {
04848                               if (ii == x_nz)
04849                                 {
04850                                   // Resize the sparse matrix
04851                                   octave_idx_type sz = x_nz *
04852                                     (b_nc - j) / b_nc;
04853                                   sz = (sz > 10 ? sz : 10) + x_nz;
04854                                   retval.change_capacity (sz);
04855                                   x_nz = sz;
04856                                 }
04857                               retval.xdata(ii) = tmp;
04858                               retval.xridx(ii++) = i;
04859                             }
04860                         }
04861                       retval.xcidx(j+1) = ii;
04862                     }
04863 
04864                   retval.maybe_compress ();
04865                 }
04866             }
04867         }
04868 
04869       if (typ == MatrixType::Banded)
04870         {
04871           // Create the storage for the banded form of the sparse matrix
04872           octave_idx_type n_upper = mattype.nupper ();
04873           octave_idx_type n_lower = mattype.nlower ();
04874           octave_idx_type ldm = n_upper + 2 * n_lower + 1;
04875 
04876           Matrix m_band (ldm, nc);
04877           double *tmp_data = m_band.fortran_vec ();
04878 
04879           if (! mattype.is_dense ())
04880             {
04881               octave_idx_type ii = 0;
04882 
04883               for (octave_idx_type j = 0; j < ldm; j++)
04884                 for (octave_idx_type i = 0; i < nc; i++)
04885                   tmp_data[ii++] = 0.;
04886             }
04887 
04888           for (octave_idx_type j = 0; j < nc; j++)
04889             for (octave_idx_type i = cidx(j); i < cidx(j+1); i++)
04890               m_band(ridx(i) - j + n_lower + n_upper, j) = data(i);
04891 
04892           // Calculate the norm of the matrix, for later use.
04893           double anorm;
04894           if (calc_cond)
04895             {
04896               for (octave_idx_type j = 0; j < nr; j++)
04897                 {
04898                   double atmp = 0.;
04899                   for (octave_idx_type i = cidx(j); i < cidx(j+1); i++)
04900                     atmp += fabs(data(i));
04901                   if (atmp > anorm)
04902                     anorm = atmp;
04903                 }
04904             }
04905 
04906           Array<octave_idx_type> ipvt (dim_vector (nr, 1));
04907           octave_idx_type *pipvt = ipvt.fortran_vec ();
04908 
04909           F77_XFCN (dgbtrf, DGBTRF, (nr, nr, n_lower, n_upper, tmp_data,
04910                                      ldm, pipvt, err));
04911 
04912           if (err != 0)
04913             {
04914               err = -2;
04915               rcond = 0.0;
04916 
04917               if (sing_handler)
04918                 {
04919                   sing_handler (rcond);
04920                   mattype.mark_as_rectangular ();
04921                 }
04922               else
04923                 (*current_liboctave_error_handler)
04924                   ("matrix singular to machine precision");
04925 
04926             }
04927           else
04928             {
04929               if (calc_cond)
04930                 {
04931                   char job = '1';
04932                   Array<double> z (dim_vector (3 * nr, 1));
04933                   double *pz = z.fortran_vec ();
04934                   Array<octave_idx_type> iz (dim_vector (nr, 1));
04935                   octave_idx_type *piz = iz.fortran_vec ();
04936 
04937                   F77_XFCN (dgbcon, DGBCON,
04938                     (F77_CONST_CHAR_ARG2 (&job, 1),
04939                      nc, n_lower, n_upper, tmp_data, ldm, pipvt,
04940                      anorm, rcond, pz, piz, err
04941                      F77_CHAR_ARG_LEN (1)));
04942 
04943                    if (err != 0)
04944                     err = -2;
04945 
04946                   volatile double rcond_plus_one = rcond + 1.0;
04947 
04948                   if (rcond_plus_one == 1.0 || xisnan (rcond))
04949                     {
04950                       err = -2;
04951 
04952                       if (sing_handler)
04953                         {
04954                           sing_handler (rcond);
04955                           mattype.mark_as_rectangular ();
04956                         }
04957                       else
04958                         (*current_liboctave_error_handler)
04959                           ("matrix singular to machine precision, rcond = %g",
04960                            rcond);
04961                     }
04962                 }
04963               else
04964                 rcond = 1.;
04965 
04966               if (err == 0)
04967                 {
04968                   char job = 'N';
04969                   volatile octave_idx_type x_nz = b.nnz ();
04970                   octave_idx_type b_nc = b.cols ();
04971                   retval = SparseMatrix (nr, b_nc, x_nz);
04972                   retval.xcidx(0) = 0;
04973                   volatile octave_idx_type ii = 0;
04974 
04975                   OCTAVE_LOCAL_BUFFER (double, work, nr);
04976 
04977                   for (volatile octave_idx_type j = 0; j < b_nc; j++)
04978                     {
04979                       for (octave_idx_type i = 0; i < nr; i++)
04980                         work[i] = 0.;
04981                       for (octave_idx_type i = b.cidx(j);
04982                            i < b.cidx(j+1); i++)
04983                         work[b.ridx(i)] = b.data(i);
04984 
04985                       F77_XFCN (dgbtrs, DGBTRS,
04986                                 (F77_CONST_CHAR_ARG2 (&job, 1),
04987                                  nr, n_lower, n_upper, 1, tmp_data,
04988                                  ldm, pipvt, work, b.rows (), err
04989                                  F77_CHAR_ARG_LEN (1)));
04990 
04991                       // Count non-zeros in work vector and adjust
04992                       // space in retval if needed
04993                       octave_idx_type new_nnz = 0;
04994                       for (octave_idx_type i = 0; i < nr; i++)
04995                         if (work[i] != 0.)
04996                           new_nnz++;
04997 
04998                       if (ii + new_nnz > x_nz)
04999                         {
05000                           // Resize the sparse matrix
05001                           octave_idx_type sz = new_nnz * (b_nc - j) + x_nz;
05002                           retval.change_capacity (sz);
05003                           x_nz = sz;
05004                         }
05005 
05006                       for (octave_idx_type i = 0; i < nr; i++)
05007                         if (work[i] != 0.)
05008                           {
05009                             retval.xridx(ii) = i;
05010                             retval.xdata(ii++) = work[i];
05011                           }
05012                       retval.xcidx(j+1) = ii;
05013                     }
05014 
05015                   retval.maybe_compress ();
05016                 }
05017             }
05018         }
05019       else if (typ != MatrixType::Banded_Hermitian)
05020         (*current_liboctave_error_handler) ("incorrect matrix type");
05021     }
05022 
05023   return retval;
05024 }
05025 
05026 ComplexMatrix
05027 SparseMatrix::bsolve (MatrixType &mattype, const ComplexMatrix& b,
05028                       octave_idx_type& err, double& rcond,
05029                       solve_singularity_handler sing_handler,
05030                       bool calc_cond) const
05031 {
05032   ComplexMatrix retval;
05033 
05034   octave_idx_type nr = rows ();
05035   octave_idx_type nc = cols ();
05036   err = 0;
05037 
05038   if (nr != nc || nr != b.rows ())
05039     (*current_liboctave_error_handler)
05040       ("matrix dimension mismatch solution of linear equations");
05041   else if (nr == 0 || b.cols () == 0)
05042     retval = ComplexMatrix (nc, b.cols (), Complex (0.0, 0.0));
05043   else
05044     {
05045       // Print spparms("spumoni") info if requested
05046       volatile int typ = mattype.type ();
05047       mattype.info ();
05048 
05049       if (typ == MatrixType::Banded_Hermitian)
05050         {
05051           octave_idx_type n_lower = mattype.nlower ();
05052           octave_idx_type ldm = n_lower + 1;
05053 
05054           Matrix m_band (ldm, nc);
05055           double *tmp_data = m_band.fortran_vec ();
05056 
05057           if (! mattype.is_dense ())
05058             {
05059               octave_idx_type ii = 0;
05060 
05061               for (octave_idx_type j = 0; j < ldm; j++)
05062                 for (octave_idx_type i = 0; i < nc; i++)
05063                   tmp_data[ii++] = 0.;
05064             }
05065 
05066           for (octave_idx_type j = 0; j < nc; j++)
05067             for (octave_idx_type i = cidx(j); i < cidx(j+1); i++)
05068               {
05069                 octave_idx_type ri = ridx (i);
05070                 if (ri >= j)
05071                   m_band(ri - j, j) = data(i);
05072               }
05073 
05074           // Calculate the norm of the matrix, for later use.
05075           double anorm;
05076           if (calc_cond)
05077             anorm = m_band.abs().sum().row(0).max();
05078 
05079           char job = 'L';
05080           F77_XFCN (dpbtrf, DPBTRF, (F77_CONST_CHAR_ARG2 (&job, 1),
05081                                      nr, n_lower, tmp_data, ldm, err
05082                                      F77_CHAR_ARG_LEN (1)));
05083 
05084           if (err != 0)
05085             {
05086               // Matrix is not positive definite!! Fall through to
05087               // unsymmetric banded solver.
05088               mattype.mark_as_unsymmetric ();
05089               typ = MatrixType::Banded;
05090               rcond = 0.0;
05091               err = 0;
05092             }
05093           else
05094             {
05095               if (calc_cond)
05096                 {
05097                   Array<double> z (dim_vector (3 * nr, 1));
05098                   double *pz = z.fortran_vec ();
05099                   Array<octave_idx_type> iz (dim_vector (nr, 1));
05100                   octave_idx_type *piz = iz.fortran_vec ();
05101 
05102                   F77_XFCN (dpbcon, DPBCON,
05103                     (F77_CONST_CHAR_ARG2 (&job, 1),
05104                      nr, n_lower, tmp_data, ldm,
05105                      anorm, rcond, pz, piz, err
05106                      F77_CHAR_ARG_LEN (1)));
05107 
05108                   if (err != 0)
05109                     err = -2;
05110 
05111                   volatile double rcond_plus_one = rcond + 1.0;
05112 
05113                   if (rcond_plus_one == 1.0 || xisnan (rcond))
05114                     {
05115                       err = -2;
05116 
05117                       if (sing_handler)
05118                         {
05119                           sing_handler (rcond);
05120                           mattype.mark_as_rectangular ();
05121                         }
05122                       else
05123                         (*current_liboctave_error_handler)
05124                           ("matrix singular to machine precision, rcond = %g",
05125                            rcond);
05126                     }
05127                 }
05128               else
05129                 rcond = 1.;
05130 
05131               if (err == 0)
05132                 {
05133                   octave_idx_type b_nr = b.rows ();
05134                   octave_idx_type b_nc = b.cols ();
05135 
05136                   OCTAVE_LOCAL_BUFFER (double, Bx, b_nr);
05137                   OCTAVE_LOCAL_BUFFER (double, Bz, b_nr);
05138 
05139                   retval.resize (b_nr, b_nc);
05140 
05141                   for (volatile octave_idx_type j = 0; j < b_nc; j++)
05142                     {
05143                       for (octave_idx_type i = 0; i < b_nr; i++)
05144                         {
05145                           Complex c = b (i,j);
05146                           Bx[i] = std::real (c);
05147                           Bz[i] = std::imag (c);
05148                         }
05149 
05150                       F77_XFCN (dpbtrs, DPBTRS,
05151                                 (F77_CONST_CHAR_ARG2 (&job, 1),
05152                                  nr, n_lower, 1, tmp_data,
05153                                  ldm, Bx, b_nr, err
05154                                  F77_CHAR_ARG_LEN (1)));
05155 
05156                       if (err != 0)
05157                         {
05158                           (*current_liboctave_error_handler)
05159                             ("SparseMatrix::solve solve failed");
05160                           err = -1;
05161                           break;
05162                         }
05163 
05164                       F77_XFCN (dpbtrs, DPBTRS,
05165                                 (F77_CONST_CHAR_ARG2 (&job, 1),
05166                                  nr, n_lower, 1, tmp_data,
05167                                  ldm, Bz, b.rows(), err
05168                                  F77_CHAR_ARG_LEN (1)));
05169 
05170                       if (err != 0)
05171                         {
05172                           (*current_liboctave_error_handler)
05173                             ("SparseMatrix::solve solve failed");
05174                           err = -1;
05175                           break;
05176                         }
05177 
05178                       for (octave_idx_type i = 0; i < b_nr; i++)
05179                         retval (i, j) = Complex (Bx[i], Bz[i]);
05180                     }
05181                 }
05182             }
05183         }
05184 
05185       if (typ == MatrixType::Banded)
05186         {
05187           // Create the storage for the banded form of the sparse matrix
05188           octave_idx_type n_upper = mattype.nupper ();
05189           octave_idx_type n_lower = mattype.nlower ();
05190           octave_idx_type ldm = n_upper + 2 * n_lower + 1;
05191 
05192           Matrix m_band (ldm, nc);
05193           double *tmp_data = m_band.fortran_vec ();
05194 
05195           if (! mattype.is_dense ())
05196             {
05197               octave_idx_type ii = 0;
05198 
05199               for (octave_idx_type j = 0; j < ldm; j++)
05200                 for (octave_idx_type i = 0; i < nc; i++)
05201                   tmp_data[ii++] = 0.;
05202             }
05203 
05204           for (octave_idx_type j = 0; j < nc; j++)
05205             for (octave_idx_type i = cidx(j); i < cidx(j+1); i++)
05206               m_band(ridx(i) - j + n_lower + n_upper, j) = data(i);
05207 
05208           // Calculate the norm of the matrix, for later use.
05209           double anorm;
05210           if (calc_cond)
05211             {
05212               for (octave_idx_type j = 0; j < nr; j++)
05213                 {
05214                   double atmp = 0.;
05215                   for (octave_idx_type i = cidx(j); i < cidx(j+1); i++)
05216                     atmp += fabs(data(i));
05217                   if (atmp > anorm)
05218                     anorm = atmp;
05219                 }
05220             }
05221 
05222           Array<octave_idx_type> ipvt (dim_vector (nr, 1));
05223           octave_idx_type *pipvt = ipvt.fortran_vec ();
05224 
05225           F77_XFCN (dgbtrf, DGBTRF, (nr, nr, n_lower, n_upper, tmp_data,
05226                                      ldm, pipvt, err));
05227 
05228           if (err != 0)
05229             {
05230               err = -2;
05231               rcond = 0.0;
05232 
05233               if (sing_handler)
05234                 {
05235                 sing_handler (rcond);
05236                 mattype.mark_as_rectangular ();
05237                 }
05238               else
05239                 (*current_liboctave_error_handler)
05240                   ("matrix singular to machine precision");
05241 
05242             }
05243           else
05244             {
05245               if (calc_cond)
05246                 {
05247                   char job = '1';
05248                   Array<double> z (dim_vector (3 * nr, 1));
05249                   double *pz = z.fortran_vec ();
05250                   Array<octave_idx_type> iz (dim_vector (nr, 1));
05251                   octave_idx_type *piz = iz.fortran_vec ();
05252 
05253                   F77_XFCN (dpbcon, DPBCON,
05254                     (F77_CONST_CHAR_ARG2 (&job, 1),
05255                      nr, n_lower, tmp_data, ldm,
05256                      anorm, rcond, pz, piz, err
05257                      F77_CHAR_ARG_LEN (1)));
05258 
05259                   if (err != 0)
05260                     err = -2;
05261 
05262                   volatile double rcond_plus_one = rcond + 1.0;
05263 
05264                   if (rcond_plus_one == 1.0 || xisnan (rcond))
05265                     {
05266                       err = -2;
05267 
05268                       if (sing_handler)
05269                         {
05270                         sing_handler (rcond);
05271                         mattype.mark_as_rectangular ();
05272                         }
05273                       else
05274                         (*current_liboctave_error_handler)
05275                           ("matrix singular to machine precision, rcond = %g",
05276                            rcond);
05277                     }
05278                 }
05279               else
05280                 rcond = 1.;
05281 
05282               if (err == 0)
05283                 {
05284                   char job = 'N';
05285                   octave_idx_type b_nc = b.cols ();
05286                   retval.resize (nr,b_nc);
05287 
05288                   OCTAVE_LOCAL_BUFFER (double, Bz, nr);
05289                   OCTAVE_LOCAL_BUFFER (double, Bx, nr);
05290 
05291                   for (volatile octave_idx_type j = 0; j < b_nc; j++)
05292                     {
05293                       for (octave_idx_type i = 0; i < nr; i++)
05294                         {
05295                           Complex c = b (i, j);
05296                           Bx[i] = std::real (c);
05297                           Bz[i] = std::imag  (c);
05298                         }
05299 
05300                       F77_XFCN (dgbtrs, DGBTRS,
05301                                 (F77_CONST_CHAR_ARG2 (&job, 1),
05302                                  nr, n_lower, n_upper, 1, tmp_data,
05303                                  ldm, pipvt, Bx, b.rows (), err
05304                                  F77_CHAR_ARG_LEN (1)));
05305 
05306                       F77_XFCN (dgbtrs, DGBTRS,
05307                                 (F77_CONST_CHAR_ARG2 (&job, 1),
05308                                  nr, n_lower, n_upper, 1, tmp_data,
05309                                  ldm, pipvt, Bz, b.rows (), err
05310                                  F77_CHAR_ARG_LEN (1)));
05311 
05312                       for (octave_idx_type i = 0; i < nr; i++)
05313                         retval (i, j) = Complex (Bx[i], Bz[i]);
05314                     }
05315                 }
05316             }
05317         }
05318       else if (typ != MatrixType::Banded_Hermitian)
05319         (*current_liboctave_error_handler) ("incorrect matrix type");
05320     }
05321 
05322   return retval;
05323 }
05324 
05325 SparseComplexMatrix
05326 SparseMatrix::bsolve (MatrixType &mattype, const SparseComplexMatrix& b,
05327                       octave_idx_type& err, double& rcond,
05328                       solve_singularity_handler sing_handler,
05329                       bool calc_cond) const
05330 {
05331   SparseComplexMatrix retval;
05332 
05333   octave_idx_type nr = rows ();
05334   octave_idx_type nc = cols ();
05335   err = 0;
05336 
05337   if (nr != nc || nr != b.rows ())
05338     (*current_liboctave_error_handler)
05339       ("matrix dimension mismatch solution of linear equations");
05340   else if (nr == 0 || b.cols () == 0)
05341     retval = SparseComplexMatrix (nc, b.cols ());
05342   else
05343     {
05344       // Print spparms("spumoni") info if requested
05345       volatile int typ = mattype.type ();
05346       mattype.info ();
05347 
05348       if (typ == MatrixType::Banded_Hermitian)
05349         {
05350           octave_idx_type n_lower = mattype.nlower ();
05351           octave_idx_type ldm = n_lower + 1;
05352 
05353           Matrix m_band (ldm, nc);
05354           double *tmp_data = m_band.fortran_vec ();
05355 
05356           if (! mattype.is_dense ())
05357             {
05358               octave_idx_type ii = 0;
05359 
05360               for (octave_idx_type j = 0; j < ldm; j++)
05361                 for (octave_idx_type i = 0; i < nc; i++)
05362                   tmp_data[ii++] = 0.;
05363             }
05364 
05365           for (octave_idx_type j = 0; j < nc; j++)
05366             for (octave_idx_type i = cidx(j); i < cidx(j+1); i++)
05367               {
05368                 octave_idx_type ri = ridx (i);
05369                 if (ri >= j)
05370                   m_band(ri - j, j) = data(i);
05371               }
05372 
05373           // Calculate the norm of the matrix, for later use.
05374           double anorm;
05375           if (calc_cond)
05376             anorm = m_band.abs().sum().row(0).max();
05377 
05378           char job = 'L';
05379           F77_XFCN (dpbtrf, DPBTRF, (F77_CONST_CHAR_ARG2 (&job, 1),
05380                                      nr, n_lower, tmp_data, ldm, err
05381                                      F77_CHAR_ARG_LEN (1)));
05382 
05383           if (err != 0)
05384             {
05385               // Matrix is not positive definite!! Fall through to
05386               // unsymmetric banded solver.
05387               mattype.mark_as_unsymmetric ();
05388               typ = MatrixType::Banded;
05389 
05390               rcond = 0.0;
05391               err = 0;
05392             }
05393           else
05394             {
05395               if (calc_cond)
05396                 {
05397                   Array<double> z (dim_vector (3 * nr, 1));
05398                   double *pz = z.fortran_vec ();
05399                   Array<octave_idx_type> iz (dim_vector (nr, 1));
05400                   octave_idx_type *piz = iz.fortran_vec ();
05401 
05402                   F77_XFCN (dpbcon, DPBCON,
05403                     (F77_CONST_CHAR_ARG2 (&job, 1),
05404                      nr, n_lower, tmp_data, ldm,
05405                      anorm, rcond, pz, piz, err
05406                      F77_CHAR_ARG_LEN (1)));
05407 
05408                   if (err != 0)
05409                     err = -2;
05410 
05411                   volatile double rcond_plus_one = rcond + 1.0;
05412 
05413                   if (rcond_plus_one == 1.0 || xisnan (rcond))
05414                     {
05415                       err = -2;
05416 
05417                       if (sing_handler)
05418                         {
05419                           sing_handler (rcond);
05420                           mattype.mark_as_rectangular ();
05421                         }
05422                       else
05423                         (*current_liboctave_error_handler)
05424                           ("matrix singular to machine precision, rcond = %g",
05425                            rcond);
05426                     }
05427                 }
05428               else
05429                 rcond = 1.;
05430 
05431               if (err == 0)
05432                 {
05433                   octave_idx_type b_nr = b.rows ();
05434                   octave_idx_type b_nc = b.cols ();
05435                   OCTAVE_LOCAL_BUFFER (double, Bx, b_nr);
05436                   OCTAVE_LOCAL_BUFFER (double, Bz, b_nr);
05437 
05438                   // Take a first guess that the number of non-zero terms
05439                   // will be as many as in b
05440                   volatile octave_idx_type x_nz = b.nnz ();
05441                   volatile octave_idx_type ii = 0;
05442                   retval = SparseComplexMatrix (b_nr, b_nc, x_nz);
05443 
05444                   retval.xcidx(0) = 0;
05445                   for (volatile octave_idx_type j = 0; j < b_nc; j++)
05446                     {
05447 
05448                       for (octave_idx_type i = 0; i < b_nr; i++)
05449                         {
05450                           Complex c = b (i,j);
05451                           Bx[i] = std::real (c);
05452                           Bz[i] = std::imag (c);
05453                         }
05454 
05455                       F77_XFCN (dpbtrs, DPBTRS,
05456                                 (F77_CONST_CHAR_ARG2 (&job, 1),
05457                                  nr, n_lower, 1, tmp_data,
05458                                  ldm, Bx, b_nr, err
05459                                  F77_CHAR_ARG_LEN (1)));
05460 
05461                       if (err != 0)
05462                         {
05463                           (*current_liboctave_error_handler)
05464                             ("SparseMatrix::solve solve failed");
05465                           err = -1;
05466                           break;
05467                         }
05468 
05469                       F77_XFCN (dpbtrs, DPBTRS,
05470                                 (F77_CONST_CHAR_ARG2 (&job, 1),
05471                                  nr, n_lower, 1, tmp_data,
05472                                  ldm, Bz, b_nr, err
05473                                  F77_CHAR_ARG_LEN (1)));
05474 
05475                       if (err != 0)
05476                         {
05477                           (*current_liboctave_error_handler)
05478                             ("SparseMatrix::solve solve failed");
05479 
05480                           err = -1;
05481                           break;
05482                         }
05483 
05484                       // Count non-zeros in work vector and adjust
05485                       // space in retval if needed
05486                       octave_idx_type new_nnz = 0;
05487                       for (octave_idx_type i = 0; i < nr; i++)
05488                         if (Bx[i] != 0. || Bz[i] != 0.)
05489                           new_nnz++;
05490 
05491                       if (ii + new_nnz > x_nz)
05492                         {
05493                           // Resize the sparse matrix
05494                           octave_idx_type sz = new_nnz * (b_nc - j) + x_nz;
05495                           retval.change_capacity (sz);
05496                           x_nz = sz;
05497                         }
05498 
05499                       for (octave_idx_type i = 0; i < nr; i++)
05500                         if (Bx[i] != 0. || Bz[i] != 0.)
05501                           {
05502                             retval.xridx(ii) = i;
05503                             retval.xdata(ii++) =
05504                               Complex (Bx[i], Bz[i]);
05505                           }
05506 
05507                       retval.xcidx(j+1) = ii;
05508                     }
05509 
05510                   retval.maybe_compress ();
05511                 }
05512             }
05513         }
05514 
05515       if (typ == MatrixType::Banded)
05516         {
05517           // Create the storage for the banded form of the sparse matrix
05518           octave_idx_type n_upper = mattype.nupper ();
05519           octave_idx_type n_lower = mattype.nlower ();
05520           octave_idx_type ldm = n_upper + 2 * n_lower + 1;
05521 
05522           Matrix m_band (ldm, nc);
05523           double *tmp_data = m_band.fortran_vec ();
05524 
05525           if (! mattype.is_dense ())
05526             {
05527               octave_idx_type ii = 0;
05528 
05529               for (octave_idx_type j = 0; j < ldm; j++)
05530                 for (octave_idx_type i = 0; i < nc; i++)
05531                   tmp_data[ii++] = 0.;
05532             }
05533 
05534           for (octave_idx_type j = 0; j < nc; j++)
05535             for (octave_idx_type i = cidx(j); i < cidx(j+1); i++)
05536               m_band(ridx(i) - j + n_lower + n_upper, j) = data(i);
05537 
05538           // Calculate the norm of the matrix, for later use.
05539           double anorm;
05540           if (calc_cond)
05541             {
05542               for (octave_idx_type j = 0; j < nr; j++)
05543                 {
05544                   double atmp = 0.;
05545                   for (octave_idx_type i = cidx(j); i < cidx(j+1); i++)
05546                     atmp += fabs(data(i));
05547                   if (atmp > anorm)
05548                     anorm = atmp;
05549                 }
05550             }
05551 
05552           Array<octave_idx_type> ipvt (dim_vector (nr, 1));
05553           octave_idx_type *pipvt = ipvt.fortran_vec ();
05554 
05555           F77_XFCN (dgbtrf, DGBTRF, (nr, nr, n_lower, n_upper, tmp_data,
05556                                      ldm, pipvt, err));
05557 
05558           if (err != 0)
05559             {
05560               err = -2;
05561               rcond = 0.0;
05562 
05563               if (sing_handler)
05564                 {
05565                   sing_handler (rcond);
05566                   mattype.mark_as_rectangular ();
05567                 }
05568               else
05569                 (*current_liboctave_error_handler)
05570                   ("matrix singular to machine precision");
05571 
05572             }
05573           else
05574             {
05575               if (calc_cond)
05576                 {
05577                   char job = '1';
05578                   Array<double> z (dim_vector (3 * nr, 1));
05579                   double *pz = z.fortran_vec ();
05580                   Array<octave_idx_type> iz (dim_vector (nr, 1));
05581                   octave_idx_type *piz = iz.fortran_vec ();
05582 
05583                   F77_XFCN (dgbcon, DGBCON,
05584                     (F77_CONST_CHAR_ARG2 (&job, 1),
05585                      nc, n_lower, n_upper, tmp_data, ldm, pipvt,
05586                      anorm, rcond, pz, piz, err
05587                      F77_CHAR_ARG_LEN (1)));
05588 
05589                    if (err != 0)
05590                     err = -2;
05591 
05592                   volatile double rcond_plus_one = rcond + 1.0;
05593 
05594                   if (rcond_plus_one == 1.0 || xisnan (rcond))
05595                     {
05596                       err = -2;
05597 
05598                       if (sing_handler)
05599                         {
05600                           sing_handler (rcond);
05601                           mattype.mark_as_rectangular ();
05602                         }
05603                       else
05604                         (*current_liboctave_error_handler)
05605                           ("matrix singular to machine precision, rcond = %g",
05606                            rcond);
05607                     }
05608                 }
05609               else
05610                 rcond = 1.;
05611 
05612               if (err == 0)
05613                 {
05614                   char job = 'N';
05615                   volatile octave_idx_type x_nz = b.nnz ();
05616                   octave_idx_type b_nc = b.cols ();
05617                   retval = SparseComplexMatrix (nr, b_nc, x_nz);
05618                   retval.xcidx(0) = 0;
05619                   volatile octave_idx_type ii = 0;
05620 
05621                   OCTAVE_LOCAL_BUFFER (double, Bx, nr);
05622                   OCTAVE_LOCAL_BUFFER (double, Bz, nr);
05623 
05624                   for (volatile octave_idx_type j = 0; j < b_nc; j++)
05625                     {
05626                       for (octave_idx_type i = 0; i < nr; i++)
05627                         {
05628                           Bx[i] = 0.;
05629                           Bz[i] = 0.;
05630                         }
05631                       for (octave_idx_type i = b.cidx(j);
05632                            i < b.cidx(j+1); i++)
05633                         {
05634                           Complex c = b.data(i);
05635                           Bx[b.ridx(i)] = std::real (c);
05636                           Bz[b.ridx(i)] = std::imag (c);
05637                         }
05638 
05639                       F77_XFCN (dgbtrs, DGBTRS,
05640                                 (F77_CONST_CHAR_ARG2 (&job, 1),
05641                                  nr, n_lower, n_upper, 1, tmp_data,
05642                                  ldm, pipvt, Bx, b.rows (), err
05643                                  F77_CHAR_ARG_LEN (1)));
05644 
05645                       F77_XFCN (dgbtrs, DGBTRS,
05646                                 (F77_CONST_CHAR_ARG2 (&job, 1),
05647                                  nr, n_lower, n_upper, 1, tmp_data,
05648                                  ldm, pipvt, Bz, b.rows (), err
05649                                  F77_CHAR_ARG_LEN (1)));
05650 
05651                       // Count non-zeros in work vector and adjust
05652                       // space in retval if needed
05653                       octave_idx_type new_nnz = 0;
05654                       for (octave_idx_type i = 0; i < nr; i++)
05655                         if (Bx[i] != 0. || Bz[i] != 0.)
05656                           new_nnz++;
05657 
05658                       if (ii + new_nnz > x_nz)
05659                         {
05660                           // Resize the sparse matrix
05661                           octave_idx_type sz = new_nnz * (b_nc - j) + x_nz;
05662                           retval.change_capacity (sz);
05663                           x_nz = sz;
05664                         }
05665 
05666                       for (octave_idx_type i = 0; i < nr; i++)
05667                         if (Bx[i] != 0. || Bz[i] != 0.)
05668                           {
05669                             retval.xridx(ii) = i;
05670                             retval.xdata(ii++) =
05671                               Complex (Bx[i], Bz[i]);
05672                           }
05673                       retval.xcidx(j+1) = ii;
05674                     }
05675 
05676                   retval.maybe_compress ();
05677                 }
05678             }
05679         }
05680       else if (typ != MatrixType::Banded_Hermitian)
05681         (*current_liboctave_error_handler) ("incorrect matrix type");
05682     }
05683 
05684   return retval;
05685 }
05686 
05687 void *
05688 SparseMatrix::factorize (octave_idx_type& err, double &rcond, Matrix &Control,
05689                          Matrix &Info, solve_singularity_handler sing_handler,
05690                          bool calc_cond) const
05691 {
05692   // The return values
05693   void *Numeric = 0;
05694   err = 0;
05695 
05696 #ifdef HAVE_UMFPACK
05697   // Setup the control parameters
05698   Control = Matrix (UMFPACK_CONTROL, 1);
05699   double *control = Control.fortran_vec ();
05700   UMFPACK_DNAME (defaults) (control);
05701 
05702   double tmp = octave_sparse_params::get_key ("spumoni");
05703   if (!xisnan (tmp))
05704     Control (UMFPACK_PRL) = tmp;
05705   tmp = octave_sparse_params::get_key ("piv_tol");
05706   if (!xisnan (tmp))
05707     {
05708       Control (UMFPACK_SYM_PIVOT_TOLERANCE) = tmp;
05709       Control (UMFPACK_PIVOT_TOLERANCE) = tmp;
05710     }
05711 
05712   // Set whether we are allowed to modify Q or not
05713   tmp = octave_sparse_params::get_key ("autoamd");
05714   if (!xisnan (tmp))
05715     Control (UMFPACK_FIXQ) = tmp;
05716 
05717   UMFPACK_DNAME (report_control) (control);
05718 
05719   const octave_idx_type *Ap = cidx ();
05720   const octave_idx_type *Ai = ridx ();
05721   const double *Ax = data ();
05722   octave_idx_type nr = rows ();
05723   octave_idx_type nc = cols ();
05724 
05725   UMFPACK_DNAME (report_matrix) (nr, nc, Ap, Ai, Ax, 1, control);
05726 
05727   void *Symbolic;
05728   Info = Matrix (1, UMFPACK_INFO);
05729   double *info = Info.fortran_vec ();
05730   int status = UMFPACK_DNAME (qsymbolic) (nr, nc, Ap, Ai, Ax, 0,
05731                                      &Symbolic, control, info);
05732 
05733   if (status < 0)
05734     {
05735       (*current_liboctave_error_handler)
05736         ("SparseMatrix::solve symbolic factorization failed");
05737       err = -1;
05738 
05739       UMFPACK_DNAME (report_status) (control, status);
05740       UMFPACK_DNAME (report_info) (control, info);
05741 
05742       UMFPACK_DNAME (free_symbolic) (&Symbolic) ;
05743     }
05744   else
05745     {
05746       UMFPACK_DNAME (report_symbolic) (Symbolic, control);
05747 
05748       status = UMFPACK_DNAME (numeric) (Ap, Ai, Ax, Symbolic,
05749                                    &Numeric, control, info) ;
05750       UMFPACK_DNAME (free_symbolic) (&Symbolic) ;
05751 
05752       if (calc_cond)
05753         rcond = Info (UMFPACK_RCOND);
05754       else
05755         rcond = 1.;
05756       volatile double rcond_plus_one = rcond + 1.0;
05757 
05758       if (status == UMFPACK_WARNING_singular_matrix ||
05759           rcond_plus_one == 1.0 || xisnan (rcond))
05760         {
05761           UMFPACK_DNAME (report_numeric) (Numeric, control);
05762 
05763           err = -2;
05764 
05765           if (sing_handler)
05766             sing_handler (rcond);
05767           else
05768             (*current_liboctave_error_handler)
05769               ("SparseMatrix::solve matrix singular to machine precision, rcond = %g",
05770                rcond);
05771 
05772         }
05773       else if (status < 0)
05774           {
05775             (*current_liboctave_error_handler)
05776               ("SparseMatrix::solve numeric factorization failed");
05777 
05778             UMFPACK_DNAME (report_status) (control, status);
05779             UMFPACK_DNAME (report_info) (control, info);
05780 
05781             err = -1;
05782           }
05783         else
05784           {
05785             UMFPACK_DNAME (report_numeric) (Numeric, control);
05786           }
05787     }
05788 
05789   if (err != 0)
05790     UMFPACK_DNAME (free_numeric) (&Numeric);
05791 
05792 #else
05793   (*current_liboctave_error_handler) ("UMFPACK not installed");
05794 #endif
05795 
05796   return Numeric;
05797 }
05798 
05799 Matrix
05800 SparseMatrix::fsolve (MatrixType &mattype, const Matrix& b,
05801                       octave_idx_type& err, double& rcond,
05802                       solve_singularity_handler sing_handler,
05803                       bool calc_cond) const
05804 {
05805   Matrix retval;
05806 
05807   octave_idx_type nr = rows ();
05808   octave_idx_type nc = cols ();
05809   err = 0;
05810 
05811   if (nr != nc || nr != b.rows ())
05812     (*current_liboctave_error_handler)
05813       ("matrix dimension mismatch solution of linear equations");
05814   else if (nr == 0 || b.cols () == 0)
05815     retval = Matrix (nc, b.cols (), 0.0);
05816   else
05817     {
05818       // Print spparms("spumoni") info if requested
05819       volatile int typ = mattype.type ();
05820       mattype.info ();
05821 
05822       if (typ == MatrixType::Hermitian)
05823         {
05824 #ifdef HAVE_CHOLMOD
05825           cholmod_common Common;
05826           cholmod_common *cm = &Common;
05827 
05828           // Setup initial parameters
05829           CHOLMOD_NAME(start) (cm);
05830           cm->prefer_zomplex = false;
05831 
05832           double spu = octave_sparse_params::get_key ("spumoni");
05833           if (spu == 0.)
05834             {
05835               cm->print = -1;
05836               cm->print_function = 0;
05837             }
05838           else
05839             {
05840               cm->print = static_cast<int> (spu) + 2;
05841               cm->print_function =&SparseCholPrint;
05842             }
05843 
05844           cm->error_handler = &SparseCholError;
05845           cm->complex_divide = CHOLMOD_NAME(divcomplex);
05846           cm->hypotenuse = CHOLMOD_NAME(hypot);
05847 
05848           cm->final_ll = true;
05849 
05850           cholmod_sparse Astore;
05851           cholmod_sparse *A = &Astore;
05852           double dummy;
05853           A->nrow = nr;
05854           A->ncol = nc;
05855 
05856           A->p = cidx();
05857           A->i = ridx();
05858           A->nzmax = nnz();
05859           A->packed = true;
05860           A->sorted = true;
05861           A->nz = 0;
05862 #ifdef IDX_TYPE_LONG
05863           A->itype = CHOLMOD_LONG;
05864 #else
05865           A->itype = CHOLMOD_INT;
05866 #endif
05867           A->dtype = CHOLMOD_DOUBLE;
05868           A->stype = 1;
05869           A->xtype = CHOLMOD_REAL;
05870 
05871           if (nr < 1)
05872             A->x = &dummy;
05873           else
05874             A->x = data();
05875 
05876           cholmod_dense Bstore;
05877           cholmod_dense *B = &Bstore;
05878           B->nrow = b.rows();
05879           B->ncol = b.cols();
05880           B->d = B->nrow;
05881           B->nzmax = B->nrow * B->ncol;
05882           B->dtype = CHOLMOD_DOUBLE;
05883           B->xtype = CHOLMOD_REAL;
05884           if (nc < 1 || b.cols() < 1)
05885             B->x = &dummy;
05886           else
05887             // We won't alter it, honest :-)
05888             B->x = const_cast<double *>(b.fortran_vec());
05889 
05890           cholmod_factor *L;
05891           BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
05892           L = CHOLMOD_NAME(analyze) (A, cm);
05893           CHOLMOD_NAME(factorize) (A, L, cm);
05894           if (calc_cond)
05895             rcond = CHOLMOD_NAME(rcond)(L, cm);
05896           else
05897             rcond = 1.0;
05898 
05899           END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
05900 
05901           if (rcond == 0.0)
05902             {
05903               // Either its indefinite or singular. Try UMFPACK
05904               mattype.mark_as_unsymmetric ();
05905               typ = MatrixType::Full;
05906             }
05907           else
05908             {
05909               volatile double rcond_plus_one = rcond + 1.0;
05910 
05911               if (rcond_plus_one == 1.0 || xisnan (rcond))
05912                 {
05913                   err = -2;
05914 
05915                   if (sing_handler)
05916                     {
05917                       sing_handler (rcond);
05918                       mattype.mark_as_rectangular ();
05919                     }
05920                   else
05921                     (*current_liboctave_error_handler)
05922                       ("SparseMatrix::solve matrix singular to machine precision, rcond = %g",
05923                        rcond);
05924 
05925                   return retval;
05926                 }
05927 
05928               cholmod_dense *X;
05929               BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
05930               X = CHOLMOD_NAME(solve) (CHOLMOD_A, L, B, cm);
05931               END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
05932 
05933               retval.resize (b.rows (), b.cols());
05934               for (octave_idx_type j = 0; j < b.cols(); j++)
05935                 {
05936                   octave_idx_type jr = j * b.rows();
05937                   for (octave_idx_type i = 0; i < b.rows(); i++)
05938                     retval.xelem(i,j) = static_cast<double *>(X->x)[jr + i];
05939                 }
05940 
05941               BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
05942               CHOLMOD_NAME(free_dense) (&X, cm);
05943               CHOLMOD_NAME(free_factor) (&L, cm);
05944               CHOLMOD_NAME(finish) (cm);
05945               static char tmp[] = " ";
05946               CHOLMOD_NAME(print_common) (tmp, cm);
05947               END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
05948             }
05949 #else
05950           (*current_liboctave_warning_handler)
05951             ("CHOLMOD not installed");
05952 
05953           mattype.mark_as_unsymmetric ();
05954           typ = MatrixType::Full;
05955 #endif
05956         }
05957 
05958       if (typ == MatrixType::Full)
05959         {
05960 #ifdef HAVE_UMFPACK
05961           Matrix Control, Info;
05962           void *Numeric =
05963             factorize (err, rcond, Control, Info, sing_handler, calc_cond);
05964 
05965           if (err == 0)
05966             {
05967               const double *Bx = b.fortran_vec ();
05968               retval.resize (b.rows (), b.cols());
05969               double *result = retval.fortran_vec ();
05970               octave_idx_type b_nr = b.rows ();
05971               octave_idx_type b_nc = b.cols ();
05972               int status = 0;
05973               double *control = Control.fortran_vec ();
05974               double *info = Info.fortran_vec ();
05975               const octave_idx_type *Ap = cidx ();
05976               const octave_idx_type *Ai = ridx ();
05977               const double *Ax = data ();
05978 
05979               for (octave_idx_type j = 0, iidx = 0; j < b_nc; j++, iidx += b_nr)
05980                 {
05981                   status = UMFPACK_DNAME (solve) (UMFPACK_A, Ap,
05982                                              Ai, Ax, &result[iidx], &Bx[iidx],
05983                                              Numeric, control, info);
05984                   if (status < 0)
05985                     {
05986                       (*current_liboctave_error_handler)
05987                         ("SparseMatrix::solve solve failed");
05988 
05989                       UMFPACK_DNAME (report_status) (control, status);
05990 
05991                       err = -1;
05992 
05993                       break;
05994                     }
05995                 }
05996 
05997               UMFPACK_DNAME (report_info) (control, info);
05998 
05999               UMFPACK_DNAME (free_numeric) (&Numeric);
06000             }
06001           else
06002             mattype.mark_as_rectangular ();
06003 
06004 #else
06005           (*current_liboctave_error_handler) ("UMFPACK not installed");
06006 #endif
06007         }
06008       else if (typ != MatrixType::Hermitian)
06009         (*current_liboctave_error_handler) ("incorrect matrix type");
06010     }
06011 
06012   return retval;
06013 }
06014 
06015 SparseMatrix
06016 SparseMatrix::fsolve (MatrixType &mattype, const SparseMatrix& b,
06017                       octave_idx_type& err, double& rcond,
06018                       solve_singularity_handler sing_handler,
06019                       bool calc_cond) const
06020 {
06021   SparseMatrix retval;
06022 
06023   octave_idx_type nr = rows ();
06024   octave_idx_type nc = cols ();
06025   err = 0;
06026 
06027   if (nr != nc || nr != b.rows ())
06028     (*current_liboctave_error_handler)
06029       ("matrix dimension mismatch solution of linear equations");
06030   else if (nr == 0 || b.cols () == 0)
06031     retval = SparseMatrix (nc, b.cols ());
06032   else
06033     {
06034       // Print spparms("spumoni") info if requested
06035       volatile int typ = mattype.type ();
06036       mattype.info ();
06037 
06038       if (typ == MatrixType::Hermitian)
06039         {
06040 #ifdef HAVE_CHOLMOD
06041           cholmod_common Common;
06042           cholmod_common *cm = &Common;
06043 
06044           // Setup initial parameters
06045           CHOLMOD_NAME(start) (cm);
06046           cm->prefer_zomplex = false;
06047 
06048           double spu = octave_sparse_params::get_key ("spumoni");
06049           if (spu == 0.)
06050             {
06051               cm->print = -1;
06052               cm->print_function = 0;
06053             }
06054           else
06055             {
06056               cm->print = static_cast<int> (spu) + 2;
06057               cm->print_function =&SparseCholPrint;
06058             }
06059 
06060           cm->error_handler = &SparseCholError;
06061           cm->complex_divide = CHOLMOD_NAME(divcomplex);
06062           cm->hypotenuse = CHOLMOD_NAME(hypot);
06063 
06064           cm->final_ll = true;
06065 
06066           cholmod_sparse Astore;
06067           cholmod_sparse *A = &Astore;
06068           double dummy;
06069           A->nrow = nr;
06070           A->ncol = nc;
06071 
06072           A->p = cidx();
06073           A->i = ridx();
06074           A->nzmax = nnz();
06075           A->packed = true;
06076           A->sorted = true;
06077           A->nz = 0;
06078 #ifdef IDX_TYPE_LONG
06079           A->itype = CHOLMOD_LONG;
06080 #else
06081           A->itype = CHOLMOD_INT;
06082 #endif
06083           A->dtype = CHOLMOD_DOUBLE;
06084           A->stype = 1;
06085           A->xtype = CHOLMOD_REAL;
06086 
06087           if (nr < 1)
06088             A->x = &dummy;
06089           else
06090             A->x = data();
06091 
06092           cholmod_sparse Bstore;
06093           cholmod_sparse *B = &Bstore;
06094           B->nrow = b.rows();
06095           B->ncol = b.cols();
06096           B->p = b.cidx();
06097           B->i = b.ridx();
06098           B->nzmax = b.nnz();
06099           B->packed = true;
06100           B->sorted = true;
06101           B->nz = 0;
06102 #ifdef IDX_TYPE_LONG
06103           B->itype = CHOLMOD_LONG;
06104 #else
06105           B->itype = CHOLMOD_INT;
06106 #endif
06107           B->dtype = CHOLMOD_DOUBLE;
06108           B->stype = 0;
06109           B->xtype = CHOLMOD_REAL;
06110 
06111           if (b.rows() < 1 || b.cols() < 1)
06112             B->x = &dummy;
06113           else
06114             B->x = b.data();
06115 
06116           cholmod_factor *L;
06117           BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
06118           L = CHOLMOD_NAME(analyze) (A, cm);
06119           CHOLMOD_NAME(factorize) (A, L, cm);
06120           if (calc_cond)
06121             rcond = CHOLMOD_NAME(rcond)(L, cm);
06122           else
06123             rcond = 1.;
06124           END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
06125 
06126           if (rcond == 0.0)
06127             {
06128               // Either its indefinite or singular. Try UMFPACK
06129               mattype.mark_as_unsymmetric ();
06130               typ = MatrixType::Full;
06131             }
06132           else
06133             {
06134               volatile double rcond_plus_one = rcond + 1.0;
06135 
06136               if (rcond_plus_one == 1.0 || xisnan (rcond))
06137                 {
06138                   err = -2;
06139 
06140                   if (sing_handler)
06141                     {
06142                       sing_handler (rcond);
06143                       mattype.mark_as_rectangular ();
06144                     }
06145                   else
06146                     (*current_liboctave_error_handler)
06147                       ("SparseMatrix::solve matrix singular to machine precision, rcond = %g",
06148                        rcond);
06149 
06150                   return retval;
06151                 }
06152 
06153               cholmod_sparse *X;
06154               BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
06155               X = CHOLMOD_NAME(spsolve) (CHOLMOD_A, L, B, cm);
06156               END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
06157 
06158               retval = SparseMatrix (static_cast<octave_idx_type>(X->nrow),
06159                                      static_cast<octave_idx_type>(X->ncol),
06160                                      static_cast<octave_idx_type>(X->nzmax));
06161               for (octave_idx_type j = 0;
06162                    j <= static_cast<octave_idx_type>(X->ncol); j++)
06163                 retval.xcidx(j) = static_cast<octave_idx_type *>(X->p)[j];
06164               for (octave_idx_type j = 0;
06165                    j < static_cast<octave_idx_type>(X->nzmax); j++)
06166                 {
06167                   retval.xridx(j) = static_cast<octave_idx_type *>(X->i)[j];
06168                   retval.xdata(j) = static_cast<double *>(X->x)[j];
06169                 }
06170 
06171               BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
06172               CHOLMOD_NAME(free_sparse) (&X, cm);
06173               CHOLMOD_NAME(free_factor) (&L, cm);
06174               CHOLMOD_NAME(finish) (cm);
06175               static char tmp[] = " ";
06176               CHOLMOD_NAME(print_common) (tmp, cm);
06177               END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
06178             }
06179 #else
06180           (*current_liboctave_warning_handler)
06181             ("CHOLMOD not installed");
06182 
06183           mattype.mark_as_unsymmetric ();
06184           typ = MatrixType::Full;
06185 #endif
06186         }
06187 
06188       if (typ == MatrixType::Full)
06189         {
06190 #ifdef HAVE_UMFPACK
06191           Matrix Control, Info;
06192           void *Numeric = factorize (err, rcond, Control, Info,
06193                                      sing_handler, calc_cond);
06194 
06195           if (err == 0)
06196             {
06197               octave_idx_type b_nr = b.rows ();
06198               octave_idx_type b_nc = b.cols ();
06199               int status = 0;
06200               double *control = Control.fortran_vec ();
06201               double *info = Info.fortran_vec ();
06202               const octave_idx_type *Ap = cidx ();
06203               const octave_idx_type *Ai = ridx ();
06204               const double *Ax = data ();
06205 
06206               OCTAVE_LOCAL_BUFFER (double, Bx, b_nr);
06207               OCTAVE_LOCAL_BUFFER (double, Xx, b_nr);
06208 
06209               // Take a first guess that the number of non-zero terms
06210               // will be as many as in b
06211               octave_idx_type x_nz = b.nnz ();
06212               octave_idx_type ii = 0;
06213               retval = SparseMatrix (b_nr, b_nc, x_nz);
06214 
06215               retval.xcidx(0) = 0;
06216               for (octave_idx_type j = 0; j < b_nc; j++)
06217                 {
06218 
06219                   for (octave_idx_type i = 0; i < b_nr; i++)
06220                     Bx[i] = b.elem (i, j);
06221 
06222                   status = UMFPACK_DNAME (solve) (UMFPACK_A, Ap,
06223                                              Ai, Ax, Xx, Bx, Numeric, control,
06224                                              info);
06225                   if (status < 0)
06226                     {
06227                       (*current_liboctave_error_handler)
06228                         ("SparseMatrix::solve solve failed");
06229 
06230                       UMFPACK_DNAME (report_status) (control, status);
06231 
06232                       err = -1;
06233 
06234                       break;
06235                     }
06236 
06237                   for (octave_idx_type i = 0; i < b_nr; i++)
06238                     {
06239                       double tmp = Xx[i];
06240                       if (tmp != 0.0)
06241                         {
06242                           if (ii == x_nz)
06243                             {
06244                               // Resize the sparse matrix
06245                               octave_idx_type sz = x_nz * (b_nc - j) / b_nc;
06246                               sz = (sz > 10 ? sz : 10) + x_nz;
06247                               retval.change_capacity (sz);
06248                               x_nz = sz;
06249                             }
06250                           retval.xdata(ii) = tmp;
06251                           retval.xridx(ii++) = i;
06252                         }
06253                     }
06254                   retval.xcidx(j+1) = ii;
06255                 }
06256 
06257               retval.maybe_compress ();
06258 
06259               UMFPACK_DNAME (report_info) (control, info);
06260 
06261               UMFPACK_DNAME (free_numeric) (&Numeric);
06262             }
06263           else
06264             mattype.mark_as_rectangular ();
06265 
06266 #else
06267           (*current_liboctave_error_handler) ("UMFPACK not installed");
06268 #endif
06269         }
06270       else if (typ != MatrixType::Hermitian)
06271         (*current_liboctave_error_handler) ("incorrect matrix type");
06272     }
06273 
06274   return retval;
06275 }
06276 
06277 ComplexMatrix
06278 SparseMatrix::fsolve (MatrixType &mattype, const ComplexMatrix& b,
06279                       octave_idx_type& err, double& rcond,
06280                       solve_singularity_handler sing_handler,
06281                       bool calc_cond) const
06282 {
06283   ComplexMatrix retval;
06284 
06285   octave_idx_type nr = rows ();
06286   octave_idx_type nc = cols ();
06287   err = 0;
06288 
06289   if (nr != nc || nr != b.rows ())
06290     (*current_liboctave_error_handler)
06291       ("matrix dimension mismatch solution of linear equations");
06292   else if (nr == 0 || b.cols () == 0)
06293     retval = ComplexMatrix (nc, b.cols (), Complex (0.0, 0.0));
06294   else
06295     {
06296       // Print spparms("spumoni") info if requested
06297       volatile int typ = mattype.type ();
06298       mattype.info ();
06299 
06300       if (typ == MatrixType::Hermitian)
06301         {
06302 #ifdef HAVE_CHOLMOD
06303           cholmod_common Common;
06304           cholmod_common *cm = &Common;
06305 
06306           // Setup initial parameters
06307           CHOLMOD_NAME(start) (cm);
06308           cm->prefer_zomplex = false;
06309 
06310           double spu = octave_sparse_params::get_key ("spumoni");
06311           if (spu == 0.)
06312             {
06313               cm->print = -1;
06314               cm->print_function = 0;
06315             }
06316           else
06317             {
06318               cm->print = static_cast<int> (spu) + 2;
06319               cm->print_function =&SparseCholPrint;
06320             }
06321 
06322           cm->error_handler = &SparseCholError;
06323           cm->complex_divide = CHOLMOD_NAME(divcomplex);
06324           cm->hypotenuse = CHOLMOD_NAME(hypot);
06325 
06326           cm->final_ll = true;
06327 
06328           cholmod_sparse Astore;
06329           cholmod_sparse *A = &Astore;
06330           double dummy;
06331           A->nrow = nr;
06332           A->ncol = nc;
06333 
06334           A->p = cidx();
06335           A->i = ridx();
06336           A->nzmax = nnz();
06337           A->packed = true;
06338           A->sorted = true;
06339           A->nz = 0;
06340 #ifdef IDX_TYPE_LONG
06341           A->itype = CHOLMOD_LONG;
06342 #else
06343           A->itype = CHOLMOD_INT;
06344 #endif
06345           A->dtype = CHOLMOD_DOUBLE;
06346           A->stype = 1;
06347           A->xtype = CHOLMOD_REAL;
06348 
06349           if (nr < 1)
06350             A->x = &dummy;
06351           else
06352             A->x = data();
06353 
06354           cholmod_dense Bstore;
06355           cholmod_dense *B = &Bstore;
06356           B->nrow = b.rows();
06357           B->ncol = b.cols();
06358           B->d = B->nrow;
06359           B->nzmax = B->nrow * B->ncol;
06360           B->dtype = CHOLMOD_DOUBLE;
06361           B->xtype = CHOLMOD_COMPLEX;
06362           if (nc < 1 || b.cols() < 1)
06363             B->x = &dummy;
06364           else
06365             // We won't alter it, honest :-)
06366             B->x = const_cast<Complex *>(b.fortran_vec());
06367 
06368           cholmod_factor *L;
06369           BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
06370           L = CHOLMOD_NAME(analyze) (A, cm);
06371           CHOLMOD_NAME(factorize) (A, L, cm);
06372           if (calc_cond)
06373             rcond = CHOLMOD_NAME(rcond)(L, cm);
06374           else
06375             rcond = 1.0;
06376           END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
06377 
06378           if (rcond == 0.0)
06379             {
06380               // Either its indefinite or singular. Try UMFPACK
06381               mattype.mark_as_unsymmetric ();
06382               typ = MatrixType::Full;
06383             }
06384           else
06385             {
06386               volatile double rcond_plus_one = rcond + 1.0;
06387 
06388               if (rcond_plus_one == 1.0 || xisnan (rcond))
06389                 {
06390                   err = -2;
06391 
06392                   if (sing_handler)
06393                     {
06394                       sing_handler (rcond);
06395                       mattype.mark_as_rectangular ();
06396                     }
06397                   else
06398                     (*current_liboctave_error_handler)
06399                       ("SparseMatrix::solve matrix singular to machine precision, rcond = %g",
06400                        rcond);
06401 
06402                   return retval;
06403                 }
06404 
06405               cholmod_dense *X;
06406               BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
06407               X = CHOLMOD_NAME(solve) (CHOLMOD_A, L, B, cm);
06408               END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
06409 
06410               retval.resize (b.rows (), b.cols());
06411               for (octave_idx_type j = 0; j < b.cols(); j++)
06412                 {
06413                   octave_idx_type jr = j * b.rows();
06414                   for (octave_idx_type i = 0; i < b.rows(); i++)
06415                     retval.xelem(i,j) = static_cast<Complex *>(X->x)[jr + i];
06416                 }
06417 
06418               BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
06419               CHOLMOD_NAME(free_dense) (&X, cm);
06420               CHOLMOD_NAME(free_factor) (&L, cm);
06421               CHOLMOD_NAME(finish) (cm);
06422               static char tmp[] = " ";
06423               CHOLMOD_NAME(print_common) (tmp, cm);
06424               END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
06425             }
06426 #else
06427           (*current_liboctave_warning_handler)
06428             ("CHOLMOD not installed");
06429 
06430           mattype.mark_as_unsymmetric ();
06431           typ = MatrixType::Full;
06432 #endif
06433         }
06434 
06435       if (typ == MatrixType::Full)
06436         {
06437 #ifdef HAVE_UMFPACK
06438           Matrix Control, Info;
06439           void *Numeric = factorize (err, rcond, Control, Info,
06440                                      sing_handler, calc_cond);
06441 
06442           if (err == 0)
06443             {
06444               octave_idx_type b_nr = b.rows ();
06445               octave_idx_type b_nc = b.cols ();
06446               int status = 0;
06447               double *control = Control.fortran_vec ();
06448               double *info = Info.fortran_vec ();
06449               const octave_idx_type *Ap = cidx ();
06450               const octave_idx_type *Ai = ridx ();
06451               const double *Ax = data ();
06452 
06453               OCTAVE_LOCAL_BUFFER (double, Bx, b_nr);
06454               OCTAVE_LOCAL_BUFFER (double, Bz, b_nr);
06455 
06456               retval.resize (b_nr, b_nc);
06457 
06458               OCTAVE_LOCAL_BUFFER (double, Xx, b_nr);
06459               OCTAVE_LOCAL_BUFFER (double, Xz, b_nr);
06460 
06461               for (octave_idx_type j = 0; j < b_nc; j++)
06462                 {
06463                   for (octave_idx_type i = 0; i < b_nr; i++)
06464                     {
06465                       Complex c = b (i,j);
06466                       Bx[i] = std::real (c);
06467                       Bz[i] = std::imag (c);
06468                     }
06469 
06470                   status = UMFPACK_DNAME (solve) (UMFPACK_A, Ap,
06471                                              Ai, Ax, Xx, Bx, Numeric, control,
06472                                              info);
06473                   int status2 = UMFPACK_DNAME (solve) (UMFPACK_A,
06474                                                   Ap, Ai, Ax, Xz, Bz, Numeric,
06475                                                   control, info) ;
06476 
06477                   if (status < 0 || status2 < 0)
06478                     {
06479                       (*current_liboctave_error_handler)
06480                         ("SparseMatrix::solve solve failed");
06481 
06482                       UMFPACK_DNAME (report_status) (control, status);
06483 
06484                       err = -1;
06485 
06486                       break;
06487                     }
06488 
06489                   for (octave_idx_type i = 0; i < b_nr; i++)
06490                     retval (i, j) = Complex (Xx[i], Xz[i]);
06491                 }
06492 
06493               UMFPACK_DNAME (report_info) (control, info);
06494 
06495               UMFPACK_DNAME (free_numeric) (&Numeric);
06496             }
06497           else
06498             mattype.mark_as_rectangular ();
06499 
06500 #else
06501           (*current_liboctave_error_handler) ("UMFPACK not installed");
06502 #endif
06503         }
06504       else if (typ != MatrixType::Hermitian)
06505         (*current_liboctave_error_handler) ("incorrect matrix type");
06506     }
06507 
06508   return retval;
06509 }
06510 
06511 SparseComplexMatrix
06512 SparseMatrix::fsolve (MatrixType &mattype, const SparseComplexMatrix& b,
06513                       octave_idx_type& err, double& rcond,
06514                       solve_singularity_handler sing_handler,
06515                       bool calc_cond) const
06516 {
06517   SparseComplexMatrix retval;
06518 
06519   octave_idx_type nr = rows ();
06520   octave_idx_type nc = cols ();
06521   err = 0;
06522 
06523   if (nr != nc || nr != b.rows ())
06524     (*current_liboctave_error_handler)
06525       ("matrix dimension mismatch solution of linear equations");
06526   else if (nr == 0 || b.cols () == 0)
06527     retval = SparseComplexMatrix (nc, b.cols ());
06528   else
06529     {
06530       // Print spparms("spumoni") info if requested
06531       volatile int typ = mattype.type ();
06532       mattype.info ();
06533 
06534       if (typ == MatrixType::Hermitian)
06535         {
06536 #ifdef HAVE_CHOLMOD
06537           cholmod_common Common;
06538           cholmod_common *cm = &Common;
06539 
06540           // Setup initial parameters
06541           CHOLMOD_NAME(start) (cm);
06542           cm->prefer_zomplex = false;
06543 
06544           double spu = octave_sparse_params::get_key ("spumoni");
06545           if (spu == 0.)
06546             {
06547               cm->print = -1;
06548               cm->print_function = 0;
06549             }
06550           else
06551             {
06552               cm->print = static_cast<int> (spu) + 2;
06553               cm->print_function =&SparseCholPrint;
06554             }
06555 
06556           cm->error_handler = &SparseCholError;
06557           cm->complex_divide = CHOLMOD_NAME(divcomplex);
06558           cm->hypotenuse = CHOLMOD_NAME(hypot);
06559 
06560           cm->final_ll = true;
06561 
06562           cholmod_sparse Astore;
06563           cholmod_sparse *A = &Astore;
06564           double dummy;
06565           A->nrow = nr;
06566           A->ncol = nc;
06567 
06568           A->p = cidx();
06569           A->i = ridx();
06570           A->nzmax = nnz();
06571           A->packed = true;
06572           A->sorted = true;
06573           A->nz = 0;
06574 #ifdef IDX_TYPE_LONG
06575           A->itype = CHOLMOD_LONG;
06576 #else
06577           A->itype = CHOLMOD_INT;
06578 #endif
06579           A->dtype = CHOLMOD_DOUBLE;
06580           A->stype = 1;
06581           A->xtype = CHOLMOD_REAL;
06582 
06583           if (nr < 1)
06584             A->x = &dummy;
06585           else
06586             A->x = data();
06587 
06588           cholmod_sparse Bstore;
06589           cholmod_sparse *B = &Bstore;
06590           B->nrow = b.rows();
06591           B->ncol = b.cols();
06592           B->p = b.cidx();
06593           B->i = b.ridx();
06594           B->nzmax = b.nnz();
06595           B->packed = true;
06596           B->sorted = true;
06597           B->nz = 0;
06598 #ifdef IDX_TYPE_LONG
06599           B->itype = CHOLMOD_LONG;
06600 #else
06601           B->itype = CHOLMOD_INT;
06602 #endif
06603           B->dtype = CHOLMOD_DOUBLE;
06604           B->stype = 0;
06605           B->xtype = CHOLMOD_COMPLEX;
06606 
06607           if (b.rows() < 1 || b.cols() < 1)
06608             B->x = &dummy;
06609           else
06610             B->x = b.data();
06611 
06612           cholmod_factor *L;
06613           BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
06614           L = CHOLMOD_NAME(analyze) (A, cm);
06615           CHOLMOD_NAME(factorize) (A, L, cm);
06616           if (calc_cond)
06617             rcond = CHOLMOD_NAME(rcond)(L, cm);
06618           else
06619             rcond = 1.0;
06620           END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
06621 
06622           if (rcond == 0.0)
06623             {
06624               // Either its indefinite or singular. Try UMFPACK
06625               mattype.mark_as_unsymmetric ();
06626               typ = MatrixType::Full;
06627             }
06628           else
06629             {
06630               volatile double rcond_plus_one = rcond + 1.0;
06631 
06632               if (rcond_plus_one == 1.0 || xisnan (rcond))
06633                 {
06634                   err = -2;
06635 
06636                   if (sing_handler)
06637                     {
06638                       sing_handler (rcond);
06639                       mattype.mark_as_rectangular ();
06640                     }
06641                   else
06642                     (*current_liboctave_error_handler)
06643                       ("SparseMatrix::solve matrix singular to machine precision, rcond = %g",
06644                        rcond);
06645 
06646                   return retval;
06647                 }
06648 
06649               cholmod_sparse *X;
06650               BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
06651               X = CHOLMOD_NAME(spsolve) (CHOLMOD_A, L, B, cm);
06652               END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
06653 
06654               retval = SparseComplexMatrix
06655                 (static_cast<octave_idx_type>(X->nrow),
06656                  static_cast<octave_idx_type>(X->ncol),
06657                  static_cast<octave_idx_type>(X->nzmax));
06658               for (octave_idx_type j = 0;
06659                    j <= static_cast<octave_idx_type>(X->ncol); j++)
06660                 retval.xcidx(j) = static_cast<octave_idx_type *>(X->p)[j];
06661               for (octave_idx_type j = 0;
06662                    j < static_cast<octave_idx_type>(X->nzmax); j++)
06663                 {
06664                   retval.xridx(j) = static_cast<octave_idx_type *>(X->i)[j];
06665                   retval.xdata(j) = static_cast<Complex *>(X->x)[j];
06666                 }
06667 
06668               BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
06669               CHOLMOD_NAME(free_sparse) (&X, cm);
06670               CHOLMOD_NAME(free_factor) (&L, cm);
06671               CHOLMOD_NAME(finish) (cm);
06672               static char tmp[] = " ";
06673               CHOLMOD_NAME(print_common) (tmp, cm);
06674               END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
06675             }
06676 #else
06677           (*current_liboctave_warning_handler)
06678             ("CHOLMOD not installed");
06679 
06680           mattype.mark_as_unsymmetric ();
06681           typ = MatrixType::Full;
06682 #endif
06683         }
06684 
06685       if (typ == MatrixType::Full)
06686         {
06687 #ifdef HAVE_UMFPACK
06688           Matrix Control, Info;
06689           void *Numeric = factorize (err, rcond, Control, Info,
06690                                      sing_handler, calc_cond);
06691 
06692           if (err == 0)
06693             {
06694               octave_idx_type b_nr = b.rows ();
06695               octave_idx_type b_nc = b.cols ();
06696               int status = 0;
06697               double *control = Control.fortran_vec ();
06698               double *info = Info.fortran_vec ();
06699               const octave_idx_type *Ap = cidx ();
06700               const octave_idx_type *Ai = ridx ();
06701               const double *Ax = data ();
06702 
06703               OCTAVE_LOCAL_BUFFER (double, Bx, b_nr);
06704               OCTAVE_LOCAL_BUFFER (double, Bz, b_nr);
06705 
06706               // Take a first guess that the number of non-zero terms
06707               // will be as many as in b
06708               octave_idx_type x_nz = b.nnz ();
06709               octave_idx_type ii = 0;
06710               retval = SparseComplexMatrix (b_nr, b_nc, x_nz);
06711 
06712               OCTAVE_LOCAL_BUFFER (double, Xx, b_nr);
06713               OCTAVE_LOCAL_BUFFER (double, Xz, b_nr);
06714 
06715               retval.xcidx(0) = 0;
06716               for (octave_idx_type j = 0; j < b_nc; j++)
06717                 {
06718                   for (octave_idx_type i = 0; i < b_nr; i++)
06719                     {
06720                       Complex c = b (i,j);
06721                       Bx[i] = std::real (c);
06722                       Bz[i] = std::imag (c);
06723                     }
06724 
06725                   status = UMFPACK_DNAME (solve) (UMFPACK_A, Ap,
06726                                              Ai, Ax, Xx, Bx, Numeric, control,
06727                                              info);
06728                   int status2 = UMFPACK_DNAME (solve) (UMFPACK_A,
06729                                                   Ap, Ai, Ax, Xz, Bz, Numeric,
06730                                                   control, info) ;
06731 
06732                   if (status < 0 || status2 < 0)
06733                     {
06734                       (*current_liboctave_error_handler)
06735                         ("SparseMatrix::solve solve failed");
06736 
06737                       UMFPACK_DNAME (report_status) (control, status);
06738 
06739                       err = -1;
06740 
06741                       break;
06742                     }
06743 
06744                   for (octave_idx_type i = 0; i < b_nr; i++)
06745                     {
06746                       Complex tmp = Complex (Xx[i], Xz[i]);
06747                       if (tmp != 0.0)
06748                         {
06749                           if (ii == x_nz)
06750                             {
06751                               // Resize the sparse matrix
06752                               octave_idx_type sz = x_nz * (b_nc - j) / b_nc;
06753                               sz = (sz > 10 ? sz : 10) + x_nz;
06754                               retval.change_capacity (sz);
06755                               x_nz = sz;
06756                             }
06757                           retval.xdata(ii) = tmp;
06758                           retval.xridx(ii++) = i;
06759                         }
06760                     }
06761                   retval.xcidx(j+1) = ii;
06762                 }
06763 
06764               retval.maybe_compress ();
06765 
06766               UMFPACK_DNAME (report_info) (control, info);
06767 
06768               UMFPACK_DNAME (free_numeric) (&Numeric);
06769             }
06770           else
06771             mattype.mark_as_rectangular ();
06772 #else
06773           (*current_liboctave_error_handler) ("UMFPACK not installed");
06774 #endif
06775         }
06776       else if (typ != MatrixType::Hermitian)
06777         (*current_liboctave_error_handler) ("incorrect matrix type");
06778     }
06779 
06780   return retval;
06781 }
06782 
06783 Matrix
06784 SparseMatrix::solve (MatrixType &mattype, const Matrix& b) const
06785 {
06786   octave_idx_type info;
06787   double rcond;
06788   return solve (mattype, b, info, rcond, 0);
06789 }
06790 
06791 Matrix
06792 SparseMatrix::solve (MatrixType &mattype, const Matrix& b,
06793                      octave_idx_type& info) const
06794 {
06795   double rcond;
06796   return solve (mattype, b, info, rcond, 0);
06797 }
06798 
06799 Matrix
06800 SparseMatrix::solve (MatrixType &mattype, const Matrix& b, octave_idx_type& info,
06801                      double& rcond) const
06802 {
06803   return solve (mattype, b, info, rcond, 0);
06804 }
06805 
06806 Matrix
06807 SparseMatrix::solve (MatrixType &mattype, const Matrix& b, octave_idx_type& err,
06808                      double& rcond, solve_singularity_handler sing_handler,
06809                      bool singular_fallback) const
06810 {
06811   Matrix retval;
06812   int typ = mattype.type (false);
06813 
06814   if (typ == MatrixType::Unknown)
06815     typ = mattype.type (*this);
06816 
06817   // Only calculate the condition number for CHOLMOD/UMFPACK
06818   if (typ == MatrixType::Diagonal || typ == MatrixType::Permuted_Diagonal)
06819     retval = dsolve (mattype, b, err, rcond, sing_handler, false);
06820   else if (typ == MatrixType::Upper || typ == MatrixType::Permuted_Upper)
06821     retval = utsolve (mattype, b, err, rcond, sing_handler, false);
06822   else if (typ == MatrixType::Lower || typ == MatrixType::Permuted_Lower)
06823     retval = ltsolve (mattype, b, err, rcond, sing_handler, false);
06824   else if (typ == MatrixType::Banded || typ == MatrixType::Banded_Hermitian)
06825     retval = bsolve (mattype, b, err, rcond, sing_handler, false);
06826   else if (typ == MatrixType::Tridiagonal ||
06827            typ == MatrixType::Tridiagonal_Hermitian)
06828     retval = trisolve (mattype, b, err, rcond, sing_handler, false);
06829   else if (typ == MatrixType::Full || typ == MatrixType::Hermitian)
06830     retval = fsolve (mattype, b, err, rcond, sing_handler, true);
06831   else if (typ != MatrixType::Rectangular)
06832     {
06833       (*current_liboctave_error_handler) ("unknown matrix type");
06834       return Matrix ();
06835     }
06836 
06837   // Rectangular or one of the above solvers flags a singular matrix
06838   if (singular_fallback && mattype.type (false) == MatrixType::Rectangular)
06839     {
06840       rcond = 1.;
06841 #ifdef USE_QRSOLVE
06842       retval = qrsolve (*this, b, err);
06843 #else
06844       retval = dmsolve<Matrix, SparseMatrix, Matrix> (*this, b, err);
06845 #endif
06846     }
06847 
06848   return retval;
06849 }
06850 
06851 SparseMatrix
06852 SparseMatrix::solve (MatrixType &mattype, const SparseMatrix& b) const
06853 {
06854   octave_idx_type info;
06855   double rcond;
06856   return solve (mattype, b, info, rcond, 0);
06857 }
06858 
06859 SparseMatrix
06860 SparseMatrix::solve (MatrixType &mattype, const SparseMatrix& b,
06861                      octave_idx_type& info) const
06862 {
06863   double rcond;
06864   return solve (mattype, b, info, rcond, 0);
06865 }
06866 
06867 SparseMatrix
06868 SparseMatrix::solve (MatrixType &mattype, const SparseMatrix& b,
06869                      octave_idx_type& info, double& rcond) const
06870 {
06871   return solve (mattype, b, info, rcond, 0);
06872 }
06873 
06874 SparseMatrix
06875 SparseMatrix::solve (MatrixType &mattype, const SparseMatrix& b,
06876                      octave_idx_type& err, double& rcond,
06877                      solve_singularity_handler sing_handler,
06878                      bool singular_fallback) const
06879 {
06880   SparseMatrix retval;
06881   int typ = mattype.type (false);
06882 
06883   if (typ == MatrixType::Unknown)
06884     typ = mattype.type (*this);
06885 
06886   if (typ == MatrixType::Diagonal || typ == MatrixType::Permuted_Diagonal)
06887     retval = dsolve (mattype, b, err, rcond, sing_handler, false);
06888   else if (typ == MatrixType::Upper || typ == MatrixType::Permuted_Upper)
06889     retval = utsolve (mattype, b, err, rcond, sing_handler, false);
06890   else if (typ == MatrixType::Lower || typ == MatrixType::Permuted_Lower)
06891     retval = ltsolve (mattype, b, err, rcond, sing_handler, false);
06892   else if (typ == MatrixType::Banded || typ == MatrixType::Banded_Hermitian)
06893     retval = bsolve (mattype, b, err, rcond, sing_handler, false);
06894   else if (typ == MatrixType::Tridiagonal ||
06895            typ == MatrixType::Tridiagonal_Hermitian)
06896     retval = trisolve (mattype, b, err, rcond, sing_handler, false);
06897   else if (typ == MatrixType::Full || typ == MatrixType::Hermitian)
06898     retval = fsolve (mattype, b, err, rcond, sing_handler, true);
06899   else if (typ != MatrixType::Rectangular)
06900     {
06901       (*current_liboctave_error_handler) ("unknown matrix type");
06902       return SparseMatrix ();
06903     }
06904 
06905   if (singular_fallback && mattype.type (false) == MatrixType::Rectangular)
06906     {
06907       rcond = 1.;
06908 #ifdef USE_QRSOLVE
06909       retval = qrsolve (*this, b, err);
06910 #else
06911       retval = dmsolve<SparseMatrix, SparseMatrix,
06912         SparseMatrix> (*this, b, err);
06913 #endif
06914     }
06915 
06916   return retval;
06917 }
06918 
06919 ComplexMatrix
06920 SparseMatrix::solve (MatrixType &mattype, const ComplexMatrix& b) const
06921 {
06922   octave_idx_type info;
06923   double rcond;
06924   return solve (mattype, b, info, rcond, 0);
06925 }
06926 
06927 ComplexMatrix
06928 SparseMatrix::solve (MatrixType &mattype, const ComplexMatrix& b,
06929                             octave_idx_type& info) const
06930 {
06931   double rcond;
06932   return solve (mattype, b, info, rcond, 0);
06933 }
06934 
06935 ComplexMatrix
06936 SparseMatrix::solve (MatrixType &mattype, const ComplexMatrix& b,
06937                      octave_idx_type& info, double& rcond) const
06938 {
06939   return solve (mattype, b, info, rcond, 0);
06940 }
06941 
06942 ComplexMatrix
06943 SparseMatrix::solve (MatrixType &mattype, const ComplexMatrix& b,
06944                      octave_idx_type& err, double& rcond,
06945                      solve_singularity_handler sing_handler,
06946                      bool singular_fallback) const
06947 {
06948   ComplexMatrix retval;
06949   int typ = mattype.type (false);
06950 
06951   if (typ == MatrixType::Unknown)
06952     typ = mattype.type (*this);
06953 
06954   if (typ == MatrixType::Diagonal || typ == MatrixType::Permuted_Diagonal)
06955     retval = dsolve (mattype, b, err, rcond, sing_handler, false);
06956   else if (typ == MatrixType::Upper || typ == MatrixType::Permuted_Upper)
06957     retval = utsolve (mattype, b, err, rcond, sing_handler, false);
06958   else if (typ == MatrixType::Lower || typ == MatrixType::Permuted_Lower)
06959     retval = ltsolve (mattype, b, err, rcond, sing_handler, false);
06960   else if (typ == MatrixType::Banded || typ == MatrixType::Banded_Hermitian)
06961     retval = bsolve (mattype, b, err, rcond, sing_handler, false);
06962   else if (typ == MatrixType::Tridiagonal ||
06963            typ == MatrixType::Tridiagonal_Hermitian)
06964     retval = trisolve (mattype, b, err, rcond, sing_handler, false);
06965   else if (typ == MatrixType::Full || typ == MatrixType::Hermitian)
06966     retval = fsolve (mattype, b, err, rcond, sing_handler, true);
06967   else if (typ != MatrixType::Rectangular)
06968     {
06969       (*current_liboctave_error_handler) ("unknown matrix type");
06970       return ComplexMatrix ();
06971     }
06972 
06973   if (singular_fallback && mattype.type(false) == MatrixType::Rectangular)
06974     {
06975       rcond = 1.;
06976 #ifdef USE_QRSOLVE
06977       retval = qrsolve (*this, b, err);
06978 #else
06979       retval = dmsolve<ComplexMatrix, SparseMatrix,
06980         ComplexMatrix> (*this, b, err);
06981 #endif
06982     }
06983 
06984   return retval;
06985 }
06986 
06987 SparseComplexMatrix
06988 SparseMatrix::solve (MatrixType &mattype, const SparseComplexMatrix& b) const
06989 {
06990   octave_idx_type info;
06991   double rcond;
06992   return solve (mattype, b, info, rcond, 0);
06993 }
06994 
06995 SparseComplexMatrix
06996 SparseMatrix::solve (MatrixType &mattype, const SparseComplexMatrix& b,
06997                      octave_idx_type& info) const
06998 {
06999   double rcond;
07000   return solve (mattype, b, info, rcond, 0);
07001 }
07002 
07003 SparseComplexMatrix
07004 SparseMatrix::solve (MatrixType &mattype, const SparseComplexMatrix& b,
07005                      octave_idx_type& info, double& rcond) const
07006 {
07007   return solve (mattype, b, info, rcond, 0);
07008 }
07009 
07010 SparseComplexMatrix
07011 SparseMatrix::solve (MatrixType &mattype, const SparseComplexMatrix& b,
07012                      octave_idx_type& err, double& rcond,
07013                      solve_singularity_handler sing_handler,
07014                      bool singular_fallback) const
07015 {
07016   SparseComplexMatrix retval;
07017   int typ = mattype.type (false);
07018 
07019   if (typ == MatrixType::Unknown)
07020     typ = mattype.type (*this);
07021 
07022   if (typ == MatrixType::Diagonal || typ == MatrixType::Permuted_Diagonal)
07023     retval = dsolve (mattype, b, err, rcond, sing_handler, false);
07024   else if (typ == MatrixType::Upper || typ == MatrixType::Permuted_Upper)
07025     retval = utsolve (mattype, b, err, rcond, sing_handler, false);
07026   else if (typ == MatrixType::Lower || typ == MatrixType::Permuted_Lower)
07027     retval = ltsolve (mattype, b, err, rcond, sing_handler, false);
07028   else if (typ == MatrixType::Banded || typ == MatrixType::Banded_Hermitian)
07029     retval = bsolve (mattype, b, err, rcond, sing_handler, false);
07030   else if (typ == MatrixType::Tridiagonal ||
07031            typ == MatrixType::Tridiagonal_Hermitian)
07032     retval = trisolve (mattype, b, err, rcond, sing_handler, false);
07033   else if (typ == MatrixType::Full || typ == MatrixType::Hermitian)
07034     retval = fsolve (mattype, b, err, rcond, sing_handler, true);
07035   else if (typ != MatrixType::Rectangular)
07036     {
07037       (*current_liboctave_error_handler) ("unknown matrix type");
07038       return SparseComplexMatrix ();
07039     }
07040 
07041   if (singular_fallback && mattype.type(false) == MatrixType::Rectangular)
07042     {
07043       rcond = 1.;
07044 #ifdef USE_QRSOLVE
07045       retval = qrsolve (*this, b, err);
07046 #else
07047       retval = dmsolve<SparseComplexMatrix, SparseMatrix,
07048         SparseComplexMatrix> (*this, b, err);
07049 #endif
07050     }
07051 
07052   return retval;
07053 }
07054 
07055 ColumnVector
07056 SparseMatrix::solve (MatrixType &mattype, const ColumnVector& b) const
07057 {
07058   octave_idx_type info; double rcond;
07059   return solve (mattype, b, info, rcond);
07060 }
07061 
07062 ColumnVector
07063 SparseMatrix::solve (MatrixType &mattype, const ColumnVector& b, octave_idx_type& info) const
07064 {
07065   double rcond;
07066   return solve (mattype, b, info, rcond);
07067 }
07068 
07069 ColumnVector
07070 SparseMatrix::solve (MatrixType &mattype, const ColumnVector& b, octave_idx_type& info, double& rcond) const
07071 {
07072   return solve (mattype, b, info, rcond, 0);
07073 }
07074 
07075 ColumnVector
07076 SparseMatrix::solve (MatrixType &mattype, const ColumnVector& b, octave_idx_type& info, double& rcond,
07077                solve_singularity_handler sing_handler) const
07078 {
07079   Matrix tmp (b);
07080   return solve (mattype, tmp, info, rcond, sing_handler).column (static_cast<octave_idx_type> (0));
07081 }
07082 
07083 ComplexColumnVector
07084 SparseMatrix::solve (MatrixType &mattype, const ComplexColumnVector& b) const
07085 {
07086   octave_idx_type info;
07087   double rcond;
07088   return solve (mattype, b, info, rcond, 0);
07089 }
07090 
07091 ComplexColumnVector
07092 SparseMatrix::solve (MatrixType &mattype, const ComplexColumnVector& b, octave_idx_type& info) const
07093 {
07094   double rcond;
07095   return solve (mattype, b, info, rcond, 0);
07096 }
07097 
07098 ComplexColumnVector
07099 SparseMatrix::solve (MatrixType &mattype, const ComplexColumnVector& b, octave_idx_type& info,
07100                      double& rcond) const
07101 {
07102   return solve (mattype, b, info, rcond, 0);
07103 }
07104 
07105 ComplexColumnVector
07106 SparseMatrix::solve (MatrixType &mattype, const ComplexColumnVector& b, octave_idx_type& info, double& rcond,
07107                solve_singularity_handler sing_handler) const
07108 {
07109   ComplexMatrix tmp (b);
07110   return solve (mattype, tmp, info, rcond, sing_handler).column (static_cast<octave_idx_type> (0));
07111 }
07112 
07113 Matrix
07114 SparseMatrix::solve (const Matrix& b) const
07115 {
07116   octave_idx_type info;
07117   double rcond;
07118   return solve (b, info, rcond, 0);
07119 }
07120 
07121 Matrix
07122 SparseMatrix::solve (const Matrix& b, octave_idx_type& info) const
07123 {
07124   double rcond;
07125   return solve (b, info, rcond, 0);
07126 }
07127 
07128 Matrix
07129 SparseMatrix::solve (const Matrix& b, octave_idx_type& info,
07130                      double& rcond) const
07131 {
07132   return solve (b, info, rcond, 0);
07133 }
07134 
07135 Matrix
07136 SparseMatrix::solve (const Matrix& b, octave_idx_type& err,
07137                      double& rcond,
07138                      solve_singularity_handler sing_handler) const
07139 {
07140   MatrixType mattype (*this);
07141   return solve (mattype, b, err, rcond, sing_handler);
07142 }
07143 
07144 SparseMatrix
07145 SparseMatrix::solve (const SparseMatrix& b) const
07146 {
07147   octave_idx_type info;
07148   double rcond;
07149   return solve (b, info, rcond, 0);
07150 }
07151 
07152 SparseMatrix
07153 SparseMatrix::solve (const SparseMatrix& b,
07154                      octave_idx_type& info) const
07155 {
07156   double rcond;
07157   return solve (b, info, rcond, 0);
07158 }
07159 
07160 SparseMatrix
07161 SparseMatrix::solve (const SparseMatrix& b,
07162                      octave_idx_type& info, double& rcond) const
07163 {
07164   return solve (b, info, rcond, 0);
07165 }
07166 
07167 SparseMatrix
07168 SparseMatrix::solve (const SparseMatrix& b,
07169                      octave_idx_type& err, double& rcond,
07170                      solve_singularity_handler sing_handler) const
07171 {
07172   MatrixType mattype (*this);
07173   return solve (mattype, b, err, rcond, sing_handler);
07174 }
07175 
07176 ComplexMatrix
07177 SparseMatrix::solve (const ComplexMatrix& b,
07178                             octave_idx_type& info) const
07179 {
07180   double rcond;
07181   return solve (b, info, rcond, 0);
07182 }
07183 
07184 ComplexMatrix
07185 SparseMatrix::solve (const ComplexMatrix& b,
07186                      octave_idx_type& info, double& rcond) const
07187 {
07188   return solve (b, info, rcond, 0);
07189 }
07190 
07191 ComplexMatrix
07192 SparseMatrix::solve (const ComplexMatrix& b,
07193                      octave_idx_type& err, double& rcond,
07194                      solve_singularity_handler sing_handler) const
07195 {
07196   MatrixType mattype (*this);
07197   return solve (mattype, b, err, rcond, sing_handler);
07198 }
07199 
07200 SparseComplexMatrix
07201 SparseMatrix::solve (const SparseComplexMatrix& b) const
07202 {
07203   octave_idx_type info;
07204   double rcond;
07205   return solve (b, info, rcond, 0);
07206 }
07207 
07208 SparseComplexMatrix
07209 SparseMatrix::solve (const SparseComplexMatrix& b,
07210                      octave_idx_type& info) const
07211 {
07212   double rcond;
07213   return solve (b, info, rcond, 0);
07214 }
07215 
07216 SparseComplexMatrix
07217 SparseMatrix::solve (const SparseComplexMatrix& b,
07218                      octave_idx_type& info, double& rcond) const
07219 {
07220   return solve (b, info, rcond, 0);
07221 }
07222 
07223 SparseComplexMatrix
07224 SparseMatrix::solve (const SparseComplexMatrix& b,
07225                      octave_idx_type& err, double& rcond,
07226                      solve_singularity_handler sing_handler) const
07227 {
07228   MatrixType mattype (*this);
07229   return solve (mattype, b, err, rcond, sing_handler);
07230 }
07231 
07232 ColumnVector
07233 SparseMatrix::solve (const ColumnVector& b) const
07234 {
07235   octave_idx_type info; double rcond;
07236   return solve (b, info, rcond);
07237 }
07238 
07239 ColumnVector
07240 SparseMatrix::solve (const ColumnVector& b, octave_idx_type& info) const
07241 {
07242   double rcond;
07243   return solve (b, info, rcond);
07244 }
07245 
07246 ColumnVector
07247 SparseMatrix::solve (const ColumnVector& b, octave_idx_type& info, double& rcond) const
07248 {
07249   return solve (b, info, rcond, 0);
07250 }
07251 
07252 ColumnVector
07253 SparseMatrix::solve (const ColumnVector& b, octave_idx_type& info, double& rcond,
07254                solve_singularity_handler sing_handler) const
07255 {
07256   Matrix tmp (b);
07257   return solve (tmp, info, rcond, sing_handler).column (static_cast<octave_idx_type> (0));
07258 }
07259 
07260 ComplexColumnVector
07261 SparseMatrix::solve (const ComplexColumnVector& b) const
07262 {
07263   octave_idx_type info;
07264   double rcond;
07265   return solve (b, info, rcond, 0);
07266 }
07267 
07268 ComplexColumnVector
07269 SparseMatrix::solve (const ComplexColumnVector& b, octave_idx_type& info) const
07270 {
07271   double rcond;
07272   return solve (b, info, rcond, 0);
07273 }
07274 
07275 ComplexColumnVector
07276 SparseMatrix::solve (const ComplexColumnVector& b, octave_idx_type& info,
07277                      double& rcond) const
07278 {
07279   return solve (b, info, rcond, 0);
07280 }
07281 
07282 ComplexColumnVector
07283 SparseMatrix::solve (const ComplexColumnVector& b, octave_idx_type& info, double& rcond,
07284                solve_singularity_handler sing_handler) const
07285 {
07286   ComplexMatrix tmp (b);
07287   return solve (tmp, info, rcond, sing_handler).column (static_cast<octave_idx_type> (0));
07288 }
07289 
07290 // other operations.
07291 
07292 bool
07293 SparseMatrix::any_element_is_negative (bool neg_zero) const
07294 {
07295   octave_idx_type nel = nnz ();
07296 
07297   if (neg_zero)
07298     {
07299       for (octave_idx_type i = 0; i < nel; i++)
07300         if (lo_ieee_signbit (data (i)))
07301           return true;
07302     }
07303   else
07304     {
07305       for (octave_idx_type i = 0; i < nel; i++)
07306         if (data (i) < 0)
07307           return true;
07308     }
07309 
07310   return false;
07311 }
07312 
07313 bool
07314 SparseMatrix::any_element_is_nan (void) const
07315 {
07316   octave_idx_type nel = nnz ();
07317 
07318   for (octave_idx_type i = 0; i < nel; i++)
07319     {
07320       double val = data (i);
07321       if (xisnan (val))
07322         return true;
07323     }
07324 
07325   return false;
07326 }
07327 
07328 bool
07329 SparseMatrix::any_element_is_inf_or_nan (void) const
07330 {
07331   octave_idx_type nel = nnz ();
07332 
07333   for (octave_idx_type i = 0; i < nel; i++)
07334     {
07335       double val = data (i);
07336       if (xisinf (val) || xisnan (val))
07337         return true;
07338     }
07339 
07340   return false;
07341 }
07342 
07343 bool
07344 SparseMatrix::any_element_not_one_or_zero (void) const
07345 {
07346   octave_idx_type nel = nnz ();
07347 
07348   for (octave_idx_type i = 0; i < nel; i++)
07349     {
07350       double val = data (i);
07351       if (val != 0.0 && val != 1.0)
07352         return true;
07353     }
07354 
07355   return false;
07356 }
07357 
07358 bool
07359 SparseMatrix::all_elements_are_zero (void) const
07360 {
07361   octave_idx_type nel = nnz ();
07362 
07363   for (octave_idx_type i = 0; i < nel; i++)
07364     if (data (i) != 0)
07365       return false;
07366 
07367   return true;
07368 }
07369 
07370 bool
07371 SparseMatrix::all_elements_are_int_or_inf_or_nan (void) const
07372 {
07373   octave_idx_type nel = nnz ();
07374 
07375   for (octave_idx_type i = 0; i < nel; i++)
07376     {
07377       double val = data (i);
07378       if (xisnan (val) || D_NINT (val) == val)
07379         continue;
07380       else
07381         return false;
07382     }
07383 
07384   return true;
07385 }
07386 
07387 // Return nonzero if any element of M is not an integer.  Also extract
07388 // the largest and smallest values and return them in MAX_VAL and MIN_VAL.
07389 
07390 bool
07391 SparseMatrix::all_integers (double& max_val, double& min_val) const
07392 {
07393   octave_idx_type nel = nnz ();
07394 
07395   if (nel == 0)
07396     return false;
07397 
07398   max_val = data (0);
07399   min_val = data (0);
07400 
07401   for (octave_idx_type i = 0; i < nel; i++)
07402     {
07403       double val = data (i);
07404 
07405       if (val > max_val)
07406         max_val = val;
07407 
07408       if (val < min_val)
07409         min_val = val;
07410 
07411       if (D_NINT (val) != val)
07412         return false;
07413     }
07414 
07415   return true;
07416 }
07417 
07418 bool
07419 SparseMatrix::too_large_for_float (void) const
07420 {
07421   octave_idx_type nel = nnz ();
07422 
07423   for (octave_idx_type i = 0; i < nel; i++)
07424     {
07425       double val = data (i);
07426 
07427       if (val > FLT_MAX || val < FLT_MIN)
07428         return true;
07429     }
07430 
07431   return false;
07432 }
07433 
07434 SparseBoolMatrix
07435 SparseMatrix::operator ! (void) const
07436 {
07437   if (any_element_is_nan ())
07438     gripe_nan_to_logical_conversion ();
07439 
07440   octave_idx_type nr = rows ();
07441   octave_idx_type nc = cols ();
07442   octave_idx_type nz1 = nnz ();
07443   octave_idx_type nz2 = nr*nc - nz1;
07444 
07445   SparseBoolMatrix r (nr, nc, nz2);
07446 
07447   octave_idx_type ii = 0;
07448   octave_idx_type jj = 0;
07449   r.cidx (0) = 0;
07450   for (octave_idx_type i = 0; i < nc; i++)
07451     {
07452       for (octave_idx_type j = 0; j < nr; j++)
07453         {
07454           if (jj < cidx(i+1) && ridx(jj) == j)
07455             jj++;
07456           else
07457             {
07458               r.data(ii) = true;
07459               r.ridx(ii++) = j;
07460             }
07461         }
07462       r.cidx (i+1) = ii;
07463     }
07464 
07465   return r;
07466 }
07467 
07468 // FIXME Do these really belong here?  Maybe they should be
07469 // in a base class?
07470 
07471 SparseBoolMatrix
07472 SparseMatrix::all (int dim) const
07473 {
07474   SPARSE_ALL_OP (dim);
07475 }
07476 
07477 SparseBoolMatrix
07478 SparseMatrix::any (int dim) const
07479 {
07480   SPARSE_ANY_OP (dim);
07481 }
07482 
07483 SparseMatrix
07484 SparseMatrix::cumprod (int dim) const
07485 {
07486   SPARSE_CUMPROD (SparseMatrix, double, cumprod);
07487 }
07488 
07489 SparseMatrix
07490 SparseMatrix::cumsum (int dim) const
07491 {
07492   SPARSE_CUMSUM (SparseMatrix, double, cumsum);
07493 }
07494 
07495 SparseMatrix
07496 SparseMatrix::prod (int dim) const
07497 {
07498   if ((rows() == 1 && dim == -1) || dim == 1)
07499     return transpose (). prod (0). transpose();
07500   else
07501     {
07502       SPARSE_REDUCTION_OP (SparseMatrix, double, *=,
07503                            (cidx(j+1) - cidx(j) < nr ? 0.0 : 1.0), 1.0);
07504     }
07505 }
07506 
07507 SparseMatrix
07508 SparseMatrix::sum (int dim) const
07509 {
07510   SPARSE_REDUCTION_OP (SparseMatrix, double, +=, 0.0, 0.0);
07511 }
07512 
07513 SparseMatrix
07514 SparseMatrix::sumsq (int dim) const
07515 {
07516 #define ROW_EXPR \
07517   double d = data (i); \
07518   tmp[ridx(i)] += d * d
07519 
07520 #define COL_EXPR \
07521   double d = data (i); \
07522   tmp[j] += d * d
07523 
07524   SPARSE_BASE_REDUCTION_OP (SparseMatrix, double, ROW_EXPR, COL_EXPR,
07525                             0.0, 0.0);
07526 
07527 #undef ROW_EXPR
07528 #undef COL_EXPR
07529 }
07530 
07531 SparseMatrix
07532 SparseMatrix::abs (void) const
07533 {
07534   octave_idx_type nz = nnz ();
07535 
07536   SparseMatrix retval (*this);
07537 
07538   for (octave_idx_type i = 0; i < nz; i++)
07539     retval.data(i) = fabs(retval.data(i));
07540 
07541   return retval;
07542 }
07543 
07544 SparseMatrix
07545 SparseMatrix::diag (octave_idx_type k) const
07546 {
07547   return MSparse<double>::diag (k);
07548 }
07549 
07550 Matrix
07551 SparseMatrix::matrix_value (void) const
07552 {
07553   return Sparse<double>::array_value ();
07554 }
07555 
07556 std::ostream&
07557 operator << (std::ostream& os, const SparseMatrix& a)
07558 {
07559   octave_idx_type nc = a.cols ();
07560 
07561    // add one to the printed indices to go from
07562    //  zero-based to one-based arrays
07563    for (octave_idx_type j = 0; j < nc; j++)
07564      {
07565        octave_quit ();
07566        for (octave_idx_type i = a.cidx(j); i < a.cidx(j+1); i++)
07567          {
07568            os << a.ridx(i) + 1 << " "  << j + 1 << " ";
07569            octave_write_double (os, a.data(i));
07570            os << "\n";
07571          }
07572      }
07573 
07574   return os;
07575 }
07576 
07577 std::istream&
07578 operator >> (std::istream& is, SparseMatrix& a)
07579 {
07580   typedef SparseMatrix::element_type elt_type;
07581 
07582   return read_sparse_matrix<elt_type> (is, a, octave_read_value<double>);
07583 }
07584 
07585 SparseMatrix
07586 SparseMatrix::squeeze (void) const
07587 {
07588   return MSparse<double>::squeeze ();
07589 }
07590 
07591 SparseMatrix
07592 SparseMatrix::reshape (const dim_vector& new_dims) const
07593 {
07594   return MSparse<double>::reshape (new_dims);
07595 }
07596 
07597 SparseMatrix
07598 SparseMatrix::permute (const Array<octave_idx_type>& vec, bool inv) const
07599 {
07600   return MSparse<double>::permute (vec, inv);
07601 }
07602 
07603 SparseMatrix
07604 SparseMatrix::ipermute (const Array<octave_idx_type>& vec) const
07605 {
07606   return MSparse<double>::ipermute (vec);
07607 }
07608 
07609 // matrix by matrix -> matrix operations
07610 
07611 SparseMatrix
07612 operator * (const SparseMatrix& m, const SparseMatrix& a)
07613 {
07614   SPARSE_SPARSE_MUL (SparseMatrix, double, double);
07615 }
07616 
07617 Matrix
07618 operator * (const Matrix& m, const SparseMatrix& a)
07619 {
07620   FULL_SPARSE_MUL (Matrix, double, 0.);
07621 }
07622 
07623 Matrix
07624 mul_trans (const Matrix& m, const SparseMatrix& a)
07625 {
07626   FULL_SPARSE_MUL_TRANS (Matrix, double, 0., );
07627 }
07628 
07629 Matrix
07630 operator * (const SparseMatrix& m, const Matrix& a)
07631 {
07632   SPARSE_FULL_MUL (Matrix, double, 0.);
07633 }
07634 
07635 Matrix
07636 trans_mul (const SparseMatrix& m, const Matrix& a)
07637 {
07638   SPARSE_FULL_TRANS_MUL (Matrix, double, 0., );
07639 }
07640 
07641 // diag * sparse and sparse * diag
07642 
07643 SparseMatrix
07644 operator * (const DiagMatrix& d, const SparseMatrix& a)
07645 {
07646   return do_mul_dm_sm<SparseMatrix> (d, a);
07647 }
07648 
07649 SparseMatrix
07650 operator * (const SparseMatrix& a, const DiagMatrix& d)
07651 {
07652   return do_mul_sm_dm<SparseMatrix> (a, d);
07653 }
07654 
07655 SparseMatrix
07656 operator + (const DiagMatrix& d, const SparseMatrix& a)
07657 {
07658   return do_add_dm_sm<SparseMatrix> (d, a);
07659 }
07660 
07661 SparseMatrix
07662 operator - (const DiagMatrix& d, const SparseMatrix& a)
07663 {
07664   return do_sub_dm_sm<SparseMatrix> (d, a);
07665 }
07666 
07667 SparseMatrix
07668 operator + (const SparseMatrix& a, const DiagMatrix& d)
07669 {
07670   return do_add_sm_dm<SparseMatrix> (a, d);
07671 }
07672 
07673 SparseMatrix
07674 operator - (const SparseMatrix& a, const DiagMatrix& d)
07675 {
07676   return do_sub_sm_dm<SparseMatrix> (a, d);
07677 }
07678 
07679 // perm * sparse and sparse * perm
07680 
07681 SparseMatrix
07682 operator * (const PermMatrix& p, const SparseMatrix& a)
07683 {
07684   return octinternal_do_mul_pm_sm (p, a);
07685 }
07686 
07687 SparseMatrix
07688 operator * (const SparseMatrix& a, const PermMatrix& p)
07689 {
07690   return octinternal_do_mul_sm_pm (a, p);
07691 }
07692 
07693 // FIXME -- it would be nice to share code among the min/max
07694 // functions below.
07695 
07696 #define EMPTY_RETURN_CHECK(T) \
07697   if (nr == 0 || nc == 0) \
07698     return T (nr, nc);
07699 
07700 SparseMatrix
07701 min (double d, const SparseMatrix& m)
07702 {
07703   SparseMatrix result;
07704 
07705   octave_idx_type nr = m.rows ();
07706   octave_idx_type nc = m.columns ();
07707 
07708   EMPTY_RETURN_CHECK (SparseMatrix);
07709 
07710   // Count the number of non-zero elements
07711   if (d < 0.)
07712     {
07713       result = SparseMatrix (nr, nc, d);
07714       for (octave_idx_type j = 0; j < nc; j++)
07715         for (octave_idx_type i = m.cidx(j); i < m.cidx(j+1); i++)
07716           {
07717             double tmp = xmin (d, m.data (i));
07718             if (tmp != 0.)
07719               {
07720                 octave_idx_type idx = m.ridx(i) + j * nr;
07721                 result.xdata(idx) = tmp;
07722                 result.xridx(idx) = m.ridx(i);
07723               }
07724           }
07725     }
07726   else
07727     {
07728       octave_idx_type nel = 0;
07729       for (octave_idx_type j = 0; j < nc; j++)
07730         for (octave_idx_type i = m.cidx(j); i < m.cidx(j+1); i++)
07731           if (xmin (d, m.data (i)) != 0.)
07732             nel++;
07733 
07734       result = SparseMatrix (nr, nc, nel);
07735 
07736       octave_idx_type ii = 0;
07737       result.xcidx(0) = 0;
07738       for (octave_idx_type j = 0; j < nc; j++)
07739         {
07740           for (octave_idx_type i = m.cidx(j); i < m.cidx(j+1); i++)
07741             {
07742               double tmp = xmin (d, m.data (i));
07743 
07744               if (tmp != 0.)
07745                 {
07746                   result.xdata(ii) = tmp;
07747                   result.xridx(ii++) = m.ridx(i);
07748                 }
07749             }
07750           result.xcidx(j+1) = ii;
07751         }
07752     }
07753 
07754   return result;
07755 }
07756 
07757 SparseMatrix
07758 min (const SparseMatrix& m, double d)
07759 {
07760   return min (d, m);
07761 }
07762 
07763 SparseMatrix
07764 min (const SparseMatrix& a, const SparseMatrix& b)
07765 {
07766   SparseMatrix r;
07767 
07768   if ((a.rows() == b.rows()) && (a.cols() == b.cols()))
07769     {
07770       octave_idx_type a_nr = a.rows ();
07771       octave_idx_type a_nc = a.cols ();
07772 
07773       octave_idx_type b_nr = b.rows ();
07774       octave_idx_type b_nc = b.cols ();
07775 
07776       if (a_nr != b_nr || a_nc != b_nc)
07777         gripe_nonconformant ("min", a_nr, a_nc, b_nr, b_nc);
07778       else
07779         {
07780           r = SparseMatrix (a_nr, a_nc, (a.nnz () + b.nnz ()));
07781 
07782           octave_idx_type jx = 0;
07783           r.cidx (0) = 0;
07784           for (octave_idx_type i = 0 ; i < a_nc ; i++)
07785             {
07786               octave_idx_type  ja = a.cidx(i);
07787               octave_idx_type  ja_max = a.cidx(i+1);
07788               bool ja_lt_max= ja < ja_max;
07789 
07790               octave_idx_type  jb = b.cidx(i);
07791               octave_idx_type  jb_max = b.cidx(i+1);
07792               bool jb_lt_max = jb < jb_max;
07793 
07794               while (ja_lt_max || jb_lt_max )
07795                 {
07796                   octave_quit ();
07797                   if ((! jb_lt_max) ||
07798                       (ja_lt_max && (a.ridx(ja) < b.ridx(jb))))
07799                     {
07800                       double tmp = xmin (a.data(ja), 0.);
07801                       if (tmp != 0.)
07802                         {
07803                           r.ridx(jx) = a.ridx(ja);
07804                           r.data(jx) = tmp;
07805                           jx++;
07806                         }
07807                       ja++;
07808                       ja_lt_max= ja < ja_max;
07809                     }
07810                   else if (( !ja_lt_max ) ||
07811                            (jb_lt_max && (b.ridx(jb) < a.ridx(ja)) ) )
07812                     {
07813                       double tmp = xmin (0., b.data(jb));
07814                       if (tmp != 0.)
07815                         {
07816                           r.ridx(jx) = b.ridx(jb);
07817                           r.data(jx) = tmp;
07818                           jx++;
07819                         }
07820                       jb++;
07821                       jb_lt_max= jb < jb_max;
07822                     }
07823                   else
07824                     {
07825                       double tmp = xmin (a.data(ja), b.data(jb));
07826                       if (tmp != 0.)
07827                         {
07828                           r.data(jx) = tmp;
07829                           r.ridx(jx) = a.ridx(ja);
07830                           jx++;
07831                         }
07832                       ja++;
07833                       ja_lt_max= ja < ja_max;
07834                       jb++;
07835                       jb_lt_max= jb < jb_max;
07836                     }
07837                 }
07838               r.cidx(i+1) = jx;
07839             }
07840 
07841           r.maybe_compress ();
07842         }
07843     }
07844   else
07845     (*current_liboctave_error_handler) ("matrix size mismatch");
07846 
07847   return r;
07848 }
07849 
07850 SparseMatrix
07851 max (double d, const SparseMatrix& m)
07852 {
07853   SparseMatrix result;
07854 
07855   octave_idx_type nr = m.rows ();
07856   octave_idx_type nc = m.columns ();
07857 
07858   EMPTY_RETURN_CHECK (SparseMatrix);
07859 
07860   // Count the number of non-zero elements
07861   if (d > 0.)
07862     {
07863       result = SparseMatrix (nr, nc, d);
07864       for (octave_idx_type j = 0; j < nc; j++)
07865         for (octave_idx_type i = m.cidx(j); i < m.cidx(j+1); i++)
07866           {
07867             double tmp = xmax (d, m.data (i));
07868 
07869             if (tmp != 0.)
07870               {
07871                 octave_idx_type idx = m.ridx(i) + j * nr;
07872                 result.xdata(idx) = tmp;
07873                 result.xridx(idx) = m.ridx(i);
07874               }
07875           }
07876     }
07877   else
07878     {
07879       octave_idx_type nel = 0;
07880       for (octave_idx_type j = 0; j < nc; j++)
07881         for (octave_idx_type i = m.cidx(j); i < m.cidx(j+1); i++)
07882           if (xmax (d, m.data (i)) != 0.)
07883             nel++;
07884 
07885       result = SparseMatrix (nr, nc, nel);
07886 
07887       octave_idx_type ii = 0;
07888       result.xcidx(0) = 0;
07889       for (octave_idx_type j = 0; j < nc; j++)
07890         {
07891           for (octave_idx_type i = m.cidx(j); i < m.cidx(j+1); i++)
07892             {
07893               double tmp = xmax (d, m.data (i));
07894               if (tmp != 0.)
07895                 {
07896                   result.xdata(ii) = tmp;
07897                   result.xridx(ii++) = m.ridx(i);
07898                 }
07899             }
07900           result.xcidx(j+1) = ii;
07901         }
07902     }
07903 
07904   return result;
07905 }
07906 
07907 SparseMatrix
07908 max (const SparseMatrix& m, double d)
07909 {
07910   return max (d, m);
07911 }
07912 
07913 SparseMatrix
07914 max (const SparseMatrix& a, const SparseMatrix& b)
07915 {
07916   SparseMatrix r;
07917 
07918   if ((a.rows() == b.rows()) && (a.cols() == b.cols()))
07919     {
07920       octave_idx_type a_nr = a.rows ();
07921       octave_idx_type a_nc = a.cols ();
07922 
07923       octave_idx_type b_nr = b.rows ();
07924       octave_idx_type b_nc = b.cols ();
07925 
07926       if (a_nr != b_nr || a_nc != b_nc)
07927         gripe_nonconformant ("min", a_nr, a_nc, b_nr, b_nc);
07928       else
07929         {
07930           r = SparseMatrix (a_nr, a_nc, (a.nnz () + b.nnz ()));
07931 
07932           octave_idx_type jx = 0;
07933           r.cidx (0) = 0;
07934           for (octave_idx_type i = 0 ; i < a_nc ; i++)
07935             {
07936               octave_idx_type  ja = a.cidx(i);
07937               octave_idx_type  ja_max = a.cidx(i+1);
07938               bool ja_lt_max= ja < ja_max;
07939 
07940               octave_idx_type  jb = b.cidx(i);
07941               octave_idx_type  jb_max = b.cidx(i+1);
07942               bool jb_lt_max = jb < jb_max;
07943 
07944               while (ja_lt_max || jb_lt_max )
07945                 {
07946                   octave_quit ();
07947                   if ((! jb_lt_max) ||
07948                       (ja_lt_max && (a.ridx(ja) < b.ridx(jb))))
07949                     {
07950                       double tmp = xmax (a.data(ja), 0.);
07951                       if (tmp != 0.)
07952                         {
07953                           r.ridx(jx) = a.ridx(ja);
07954                           r.data(jx) = tmp;
07955                           jx++;
07956                         }
07957                       ja++;
07958                       ja_lt_max= ja < ja_max;
07959                     }
07960                   else if (( !ja_lt_max ) ||
07961                            (jb_lt_max && (b.ridx(jb) < a.ridx(ja)) ) )
07962                     {
07963                       double tmp = xmax (0., b.data(jb));
07964                       if (tmp != 0.)
07965                         {
07966                           r.ridx(jx) = b.ridx(jb);
07967                           r.data(jx) = tmp;
07968                           jx++;
07969                         }
07970                       jb++;
07971                       jb_lt_max= jb < jb_max;
07972                     }
07973                   else
07974                     {
07975                       double tmp = xmax (a.data(ja), b.data(jb));
07976                       if (tmp != 0.)
07977                         {
07978                           r.data(jx) = tmp;
07979                           r.ridx(jx) = a.ridx(ja);
07980                           jx++;
07981                         }
07982                       ja++;
07983                       ja_lt_max= ja < ja_max;
07984                       jb++;
07985                       jb_lt_max= jb < jb_max;
07986                     }
07987                 }
07988               r.cidx(i+1) = jx;
07989             }
07990 
07991           r.maybe_compress ();
07992         }
07993     }
07994   else
07995     (*current_liboctave_error_handler) ("matrix size mismatch");
07996 
07997   return r;
07998 }
07999 
08000 SPARSE_SMS_CMP_OPS (SparseMatrix, 0.0, , double, 0.0, )
08001 SPARSE_SMS_BOOL_OPS (SparseMatrix, double, 0.0)
08002 
08003 SPARSE_SSM_CMP_OPS (double, 0.0, , SparseMatrix, 0.0, )
08004 SPARSE_SSM_BOOL_OPS (double, SparseMatrix, 0.0)
08005 
08006 SPARSE_SMSM_CMP_OPS (SparseMatrix, 0.0, , SparseMatrix, 0.0, )
08007 SPARSE_SMSM_BOOL_OPS (SparseMatrix, SparseMatrix, 0.0)
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines