SparseQR.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 2005-2012 David Bateman
00004 
00005 This file is part of Octave.
00006 
00007 Octave is free software; you can redistribute it and/or modify it
00008 under the terms of the GNU General Public License as published by the
00009 Free Software Foundation; either version 3 of the License, or (at your
00010 option) any later version.
00011 
00012 Octave is distributed in the hope that it will be useful, but WITHOUT
00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00015 for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Octave; see the file COPYING.  If not, see
00019 <http://www.gnu.org/licenses/>.
00020 
00021 */
00022 
00023 #ifdef HAVE_CONFIG_H
00024 #include <config.h>
00025 #endif
00026 #include <vector>
00027 
00028 #include "lo-error.h"
00029 #include "SparseQR.h"
00030 #include "oct-locbuf.h"
00031 
00032 SparseQR::SparseQR_rep::SparseQR_rep (const SparseMatrix& a, int order)
00033   : count (1), nrows (0)
00034 #ifdef HAVE_CXSPARSE
00035     , S (0), N (0)
00036 #endif
00037 {
00038 #ifdef HAVE_CXSPARSE
00039   CXSPARSE_DNAME () A;
00040   A.nzmax = a.nnz ();
00041   A.m = a.rows ();
00042   A.n = a.cols ();
00043   nrows = A.m;
00044   // Cast away const on A, with full knowledge that CSparse won't touch it
00045   // Prevents the methods below making a copy of the data.
00046   A.p = const_cast<octave_idx_type *>(a.cidx ());
00047   A.i = const_cast<octave_idx_type *>(a.ridx ());
00048   A.x = const_cast<double *>(a.data ());
00049   A.nz = -1;
00050   BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00051 #if defined(CS_VER) && (CS_VER >= 2)
00052   S = CXSPARSE_DNAME (_sqr) (order, &A, 1);
00053 #else
00054   S = CXSPARSE_DNAME (_sqr) (&A, order - 1, 1);
00055 #endif
00056 
00057   N = CXSPARSE_DNAME (_qr) (&A, S);
00058   END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00059   if (!N)
00060     (*current_liboctave_error_handler)
00061       ("SparseQR: sparse matrix QR factorization filled");
00062   count = 1;
00063 #else
00064   (*current_liboctave_error_handler)
00065     ("SparseQR: sparse matrix QR factorization not implemented");
00066 #endif
00067 }
00068 
00069 SparseQR::SparseQR_rep::~SparseQR_rep (void)
00070 {
00071 #ifdef HAVE_CXSPARSE
00072   CXSPARSE_DNAME (_sfree) (S);
00073   CXSPARSE_DNAME (_nfree) (N);
00074 #endif
00075 }
00076 
00077 SparseMatrix
00078 SparseQR::SparseQR_rep::V (void) const
00079 {
00080 #ifdef HAVE_CXSPARSE
00081   // Drop zeros from V and sort
00082   // FIXME Is the double transpose to sort necessary?
00083   BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00084   CXSPARSE_DNAME (_dropzeros) (N->L);
00085   CXSPARSE_DNAME () *D = CXSPARSE_DNAME (_transpose) (N->L, 1);
00086   CXSPARSE_DNAME (_spfree) (N->L);
00087   N->L = CXSPARSE_DNAME (_transpose) (D, 1);
00088   CXSPARSE_DNAME (_spfree) (D);
00089   END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00090 
00091   octave_idx_type nc = N->L->n;
00092   octave_idx_type nz = N->L->nzmax;
00093   SparseMatrix ret (N->L->m, nc, nz);
00094   for (octave_idx_type j = 0; j < nc+1; j++)
00095     ret.xcidx (j) = N->L->p[j];
00096   for (octave_idx_type j = 0; j < nz; j++)
00097     {
00098       ret.xridx (j) = N->L->i[j];
00099       ret.xdata (j) = N->L->x[j];
00100     }
00101   return ret;
00102 #else
00103   return SparseMatrix ();
00104 #endif
00105 }
00106 
00107 ColumnVector
00108 SparseQR::SparseQR_rep::Pinv (void) const
00109 {
00110 #ifdef HAVE_CXSPARSE
00111   ColumnVector ret(N->L->m);
00112   for (octave_idx_type i = 0; i < N->L->m; i++)
00113 #if defined(CS_VER) && (CS_VER >= 2)
00114     ret.xelem(i) = S->pinv[i];
00115 #else
00116     ret.xelem(i) = S->Pinv[i];
00117 #endif
00118   return ret;
00119 #else
00120   return ColumnVector ();
00121 #endif
00122 }
00123 
00124 ColumnVector
00125 SparseQR::SparseQR_rep::P (void) const
00126 {
00127 #ifdef HAVE_CXSPARSE
00128   ColumnVector ret(N->L->m);
00129   for (octave_idx_type i = 0; i < N->L->m; i++)
00130 #if defined(CS_VER) && (CS_VER >= 2)
00131     ret.xelem(S->pinv[i]) = i;
00132 #else
00133     ret.xelem(S->Pinv[i]) = i;
00134 #endif
00135   return ret;
00136 #else
00137   return ColumnVector ();
00138 #endif
00139 }
00140 
00141 SparseMatrix
00142 SparseQR::SparseQR_rep::R (const bool econ) const
00143 {
00144 #ifdef HAVE_CXSPARSE
00145   // Drop zeros from R and sort
00146   // FIXME Is the double transpose to sort necessary?
00147   BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00148   CXSPARSE_DNAME (_dropzeros) (N->U);
00149   CXSPARSE_DNAME () *D = CXSPARSE_DNAME (_transpose) (N->U, 1);
00150   CXSPARSE_DNAME (_spfree) (N->U);
00151   N->U = CXSPARSE_DNAME (_transpose) (D, 1);
00152   CXSPARSE_DNAME (_spfree) (D);
00153   END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00154 
00155   octave_idx_type nc = N->U->n;
00156   octave_idx_type nz = N->U->nzmax;
00157 
00158   SparseMatrix ret ((econ ? (nc > nrows ? nrows : nc) : nrows), nc, nz);
00159 
00160   for (octave_idx_type j = 0; j < nc+1; j++)
00161     ret.xcidx (j) = N->U->p[j];
00162   for (octave_idx_type j = 0; j < nz; j++)
00163     {
00164       ret.xridx (j) = N->U->i[j];
00165       ret.xdata (j) = N->U->x[j];
00166     }
00167   return ret;
00168 #else
00169   return SparseMatrix ();
00170 #endif
00171 }
00172 
00173 Matrix
00174 SparseQR::SparseQR_rep::C (const Matrix &b) const
00175 {
00176 #ifdef HAVE_CXSPARSE
00177   octave_idx_type b_nr = b.rows();
00178   octave_idx_type b_nc = b.cols();
00179   octave_idx_type nc = N->L->n;
00180   octave_idx_type nr = nrows;
00181   const double *bvec = b.fortran_vec();
00182   Matrix ret (b_nr, b_nc);
00183   double *vec = ret.fortran_vec();
00184   if (nr < 0 || nc < 0 || nr != b_nr)
00185     (*current_liboctave_error_handler) ("matrix dimension mismatch");
00186   else if (nr == 0 || nc == 0 || b_nc == 0)
00187     ret = Matrix (nc, b_nc, 0.0);
00188   else
00189     {
00190       OCTAVE_LOCAL_BUFFER (double, buf, S->m2);
00191       for (volatile octave_idx_type j = 0, idx = 0; j < b_nc; j++, idx+=b_nr)
00192         {
00193           octave_quit ();
00194           for (octave_idx_type i = nr; i < S->m2; i++)
00195             buf[i] = 0.;
00196           volatile octave_idx_type nm = (nr < nc ? nr : nc);
00197           BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00198 #if defined(CS_VER) && (CS_VER >= 2)
00199           CXSPARSE_DNAME (_ipvec) (S->pinv, bvec + idx, buf, b_nr);
00200 #else
00201           CXSPARSE_DNAME (_ipvec) (b_nr, S->Pinv, bvec + idx, buf);
00202 #endif
00203           END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00204 
00205           for (volatile octave_idx_type i = 0; i < nm; i++)
00206             {
00207               octave_quit ();
00208               BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00209               CXSPARSE_DNAME (_happly) (N->L, i, N->B[i], buf);
00210               END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00211             }
00212           for (octave_idx_type i = 0; i < b_nr; i++)
00213             vec[i+idx] = buf[i];
00214         }
00215     }
00216   return ret;
00217 #else
00218   return Matrix ();
00219 #endif
00220 }
00221 
00222 Matrix
00223 SparseQR::SparseQR_rep::Q (void) const
00224 {
00225 #ifdef HAVE_CXSPARSE
00226   octave_idx_type nc = N->L->n;
00227   octave_idx_type nr = nrows;
00228   Matrix ret (nr, nr);
00229   double *vec = ret.fortran_vec();
00230   if (nr < 0 || nc < 0)
00231     (*current_liboctave_error_handler) ("matrix dimension mismatch");
00232   else if (nr == 0 || nc == 0)
00233     ret = Matrix (nc, nr, 0.0);
00234   else
00235     {
00236       OCTAVE_LOCAL_BUFFER (double, bvec, nr + 1);
00237       for (octave_idx_type i = 0; i < nr; i++)
00238         bvec[i] = 0.;
00239       OCTAVE_LOCAL_BUFFER (double, buf, S->m2);
00240       for (volatile octave_idx_type j = 0, idx = 0; j < nr; j++, idx+=nr)
00241         {
00242           octave_quit ();
00243           bvec[j] = 1.0;
00244           for (octave_idx_type i = nr; i < S->m2; i++)
00245             buf[i] = 0.;
00246           volatile octave_idx_type nm = (nr < nc ? nr : nc);
00247           BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00248 #if defined(CS_VER) && (CS_VER >= 2)
00249           CXSPARSE_DNAME (_ipvec) (S->pinv, bvec, buf, nr);
00250 #else
00251           CXSPARSE_DNAME (_ipvec) (nr, S->Pinv, bvec, buf);
00252 #endif
00253           END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00254 
00255           for (volatile octave_idx_type i = 0; i < nm; i++)
00256             {
00257               octave_quit ();
00258               BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00259               CXSPARSE_DNAME (_happly) (N->L, i, N->B[i], buf);
00260               END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00261             }
00262           for (octave_idx_type i = 0; i < nr; i++)
00263             vec[i+idx] = buf[i];
00264           bvec[j] = 0.0;
00265         }
00266     }
00267   return ret.transpose ();
00268 #else
00269   return Matrix ();
00270 #endif
00271 }
00272 
00273 Matrix
00274 qrsolve(const SparseMatrix&a, const Matrix &b, octave_idx_type& info)
00275 {
00276   info = -1;
00277 #ifdef HAVE_CXSPARSE
00278   octave_idx_type nr = a.rows();
00279   octave_idx_type nc = a.cols();
00280   octave_idx_type b_nc = b.cols();
00281   octave_idx_type b_nr = b.rows();
00282   const double *bvec = b.fortran_vec();
00283   Matrix x;
00284 
00285   if (nr < 0 || nc < 0 || nr != b_nr)
00286     (*current_liboctave_error_handler)
00287       ("matrix dimension mismatch in solution of minimum norm problem");
00288   else if (nr == 0 || nc == 0 || b_nc == 0)
00289     x = Matrix (nc, b_nc, 0.0);
00290   else if (nr >= nc)
00291     {
00292       SparseQR q (a, 3);
00293       if (! q.ok ())
00294         return Matrix();
00295       x.resize(nc, b_nc);
00296       double *vec = x.fortran_vec();
00297       OCTAVE_LOCAL_BUFFER (double, buf, q.S()->m2);
00298       for (volatile octave_idx_type i = 0, idx = 0, bidx = 0; i < b_nc;
00299            i++, idx+=nc, bidx+=b_nr)
00300         {
00301           octave_quit ();
00302           for (octave_idx_type j = nr; j < q.S()->m2; j++)
00303             buf[j] = 0.;
00304           BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00305 #if defined(CS_VER) && (CS_VER >= 2)
00306           CXSPARSE_DNAME (_ipvec) (q.S()->pinv, bvec + bidx, buf, nr);
00307 #else
00308           CXSPARSE_DNAME (_ipvec) (nr, q.S()->Pinv, bvec + bidx, buf);
00309 #endif
00310           END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00311           for (volatile octave_idx_type j = 0; j < nc; j++)
00312             {
00313               octave_quit ();
00314               BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00315               CXSPARSE_DNAME (_happly) (q.N()->L, j, q.N()->B[j], buf);
00316               END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00317             }
00318           BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00319           CXSPARSE_DNAME (_usolve) (q.N()->U, buf);
00320 #if defined(CS_VER) && (CS_VER >= 2)
00321           CXSPARSE_DNAME (_ipvec) (q.S()->q, buf, vec + idx, nc);
00322 #else
00323           CXSPARSE_DNAME (_ipvec) (nc, q.S()->Q, buf, vec + idx);
00324 #endif
00325           END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00326         }
00327       info = 0;
00328     }
00329   else
00330     {
00331       SparseMatrix at = a.hermitian();
00332       SparseQR q (at, 3);
00333       if (! q.ok ())
00334         return Matrix();
00335       x.resize(nc, b_nc);
00336       double *vec = x.fortran_vec();
00337       volatile octave_idx_type nbuf = (nc > q.S()->m2 ? nc : q.S()->m2);
00338       OCTAVE_LOCAL_BUFFER (double, buf, nbuf);
00339       for (volatile octave_idx_type i = 0, idx = 0, bidx = 0; i < b_nc;
00340            i++, idx+=nc, bidx+=b_nr)
00341         {
00342           octave_quit ();
00343           for (octave_idx_type j = nr; j < nbuf; j++)
00344             buf[j] = 0.;
00345           BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00346 #if defined(CS_VER) && (CS_VER >= 2)
00347           CXSPARSE_DNAME (_pvec) (q.S()->q, bvec + bidx, buf, nr);
00348 #else
00349           CXSPARSE_DNAME (_pvec) (nr, q.S()->Q, bvec + bidx, buf);
00350 #endif
00351           CXSPARSE_DNAME (_utsolve) (q.N()->U, buf);
00352           END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00353           for (volatile octave_idx_type j = nr-1; j >= 0; j--)
00354             {
00355               octave_quit ();
00356               BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00357               CXSPARSE_DNAME (_happly) (q.N()->L, j, q.N()->B[j], buf);
00358               END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00359             }
00360           BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00361 #if defined(CS_VER) && (CS_VER >= 2)
00362           CXSPARSE_DNAME (_pvec) (q.S()->pinv, buf, vec + idx, nc);
00363 #else
00364           CXSPARSE_DNAME (_pvec) (nc, q.S()->Pinv, buf, vec + idx);
00365 #endif
00366           END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00367         }
00368       info = 0;
00369     }
00370 
00371   return x;
00372 #else
00373   return Matrix ();
00374 #endif
00375 }
00376 
00377 SparseMatrix
00378 qrsolve(const SparseMatrix&a, const SparseMatrix &b, octave_idx_type &info)
00379 {
00380   info = -1;
00381 #ifdef HAVE_CXSPARSE
00382   octave_idx_type nr = a.rows();
00383   octave_idx_type nc = a.cols();
00384   octave_idx_type b_nr = b.rows();
00385   octave_idx_type b_nc = b.cols();
00386   SparseMatrix x;
00387   volatile octave_idx_type ii, x_nz;
00388 
00389   if (nr < 0 || nc < 0 || nr != b_nr)
00390     (*current_liboctave_error_handler)
00391       ("matrix dimension mismatch in solution of minimum norm problem");
00392   else if (nr == 0 || nc == 0 || b_nc == 0)
00393     x = SparseMatrix (nc, b_nc);
00394   else if (nr >= nc)
00395     {
00396       SparseQR q (a, 3);
00397       if (! q.ok ())
00398         return SparseMatrix();
00399       x = SparseMatrix (nc, b_nc, b.nnz());
00400       x.xcidx(0) = 0;
00401       x_nz = b.nnz();
00402       ii = 0;
00403       OCTAVE_LOCAL_BUFFER (double, Xx, (b_nr > nc ? b_nr : nc));
00404       OCTAVE_LOCAL_BUFFER (double, buf, q.S()->m2);
00405       for (volatile octave_idx_type i = 0, idx = 0; i < b_nc; i++, idx+=nc)
00406         {
00407           octave_quit ();
00408           for (octave_idx_type j = 0; j < b_nr; j++)
00409             Xx[j] = b.xelem(j,i);
00410           for (octave_idx_type j = nr; j < q.S()->m2; j++)
00411             buf[j] = 0.;
00412           BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00413 #if defined(CS_VER) && (CS_VER >= 2)
00414           CXSPARSE_DNAME (_ipvec) (q.S()->pinv, Xx, buf, nr);
00415 #else
00416           CXSPARSE_DNAME (_ipvec) (nr, q.S()->Pinv, Xx, buf);
00417 #endif
00418           END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00419           for (volatile octave_idx_type j = 0; j < nc; j++)
00420             {
00421               octave_quit ();
00422               BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00423               CXSPARSE_DNAME (_happly) (q.N()->L, j, q.N()->B[j], buf);
00424               END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00425             }
00426           BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00427           CXSPARSE_DNAME (_usolve) (q.N()->U, buf);
00428 #if defined(CS_VER) && (CS_VER >= 2)
00429           CXSPARSE_DNAME (_ipvec) (q.S()->q, buf, Xx, nc);
00430 #else
00431           CXSPARSE_DNAME (_ipvec) (nc, q.S()->Q, buf, Xx);
00432 #endif
00433           END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00434 
00435           for (octave_idx_type j = 0; j < nc; j++)
00436             {
00437               double tmp = Xx[j];
00438               if (tmp != 0.0)
00439                 {
00440                   if (ii == x_nz)
00441                     {
00442                       // Resize the sparse matrix
00443                       octave_idx_type sz = x_nz * (b_nc - i) / b_nc;
00444                       sz = (sz > 10 ? sz : 10) + x_nz;
00445                       x.change_capacity (sz);
00446                       x_nz = sz;
00447                     }
00448                   x.xdata(ii) = tmp;
00449                   x.xridx(ii++) = j;
00450                 }
00451             }
00452           x.xcidx(i+1) = ii;
00453         }
00454       info = 0;
00455     }
00456   else
00457     {
00458       SparseMatrix at = a.hermitian();
00459       SparseQR q (at, 3);
00460       if (! q.ok ())
00461         return SparseMatrix();
00462       x = SparseMatrix (nc, b_nc, b.nnz());
00463       x.xcidx(0) = 0;
00464       x_nz = b.nnz();
00465       ii = 0;
00466       volatile octave_idx_type nbuf = (nc > q.S()->m2 ? nc : q.S()->m2);
00467       OCTAVE_LOCAL_BUFFER (double, Xx, (b_nr > nc ? b_nr : nc));
00468       OCTAVE_LOCAL_BUFFER (double, buf, nbuf);
00469       for (volatile octave_idx_type i = 0, idx = 0; i < b_nc; i++, idx+=nc)
00470         {
00471           octave_quit ();
00472           for (octave_idx_type j = 0; j < b_nr; j++)
00473             Xx[j] = b.xelem(j,i);
00474           for (octave_idx_type j = nr; j < nbuf; j++)
00475             buf[j] = 0.;
00476           BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00477 #if defined(CS_VER) && (CS_VER >= 2)
00478           CXSPARSE_DNAME (_pvec) (q.S()->q, Xx, buf, nr);
00479 #else
00480           CXSPARSE_DNAME (_pvec) (nr, q.S()->Q, Xx, buf);
00481 #endif
00482           CXSPARSE_DNAME (_utsolve) (q.N()->U, buf);
00483           END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00484           for (volatile octave_idx_type j = nr-1; j >= 0; j--)
00485             {
00486               octave_quit ();
00487               BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00488               CXSPARSE_DNAME (_happly) (q.N()->L, j, q.N()->B[j], buf);
00489               END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00490             }
00491           BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00492 #if defined(CS_VER) && (CS_VER >= 2)
00493           CXSPARSE_DNAME (_pvec) (q.S()->pinv, buf, Xx, nc);
00494 #else
00495           CXSPARSE_DNAME (_pvec) (nc, q.S()->Pinv, buf, Xx);
00496 #endif
00497           END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00498 
00499           for (octave_idx_type j = 0; j < nc; j++)
00500             {
00501               double tmp = Xx[j];
00502               if (tmp != 0.0)
00503                 {
00504                   if (ii == x_nz)
00505                     {
00506                       // Resize the sparse matrix
00507                       octave_idx_type sz = x_nz * (b_nc - i) / b_nc;
00508                       sz = (sz > 10 ? sz : 10) + x_nz;
00509                       x.change_capacity (sz);
00510                       x_nz = sz;
00511                     }
00512                   x.xdata(ii) = tmp;
00513                   x.xridx(ii++) = j;
00514                 }
00515             }
00516           x.xcidx(i+1) = ii;
00517         }
00518       info = 0;
00519     }
00520 
00521   x.maybe_compress ();
00522   return x;
00523 #else
00524   return SparseMatrix ();
00525 #endif
00526 }
00527 
00528 ComplexMatrix
00529 qrsolve(const SparseMatrix&a, const ComplexMatrix &b, octave_idx_type &info)
00530 {
00531   info = -1;
00532 #ifdef HAVE_CXSPARSE
00533   octave_idx_type nr = a.rows();
00534   octave_idx_type nc = a.cols();
00535   octave_idx_type b_nc = b.cols();
00536   octave_idx_type b_nr = b.rows();
00537   ComplexMatrix x;
00538 
00539   if (nr < 0 || nc < 0 || nr != b_nr)
00540     (*current_liboctave_error_handler)
00541       ("matrix dimension mismatch in solution of minimum norm problem");
00542   else if (nr == 0 || nc == 0 || b_nc == 0)
00543     x = ComplexMatrix (nc, b_nc, Complex (0.0, 0.0));
00544   else if (nr >= nc)
00545     {
00546       SparseQR q (a, 3);
00547       if (! q.ok ())
00548         return ComplexMatrix();
00549       x.resize(nc, b_nc);
00550       Complex *vec = x.fortran_vec();
00551       OCTAVE_LOCAL_BUFFER (double, Xx, (b_nr > nc ? b_nr : nc));
00552       OCTAVE_LOCAL_BUFFER (double, Xz, (b_nr > nc ? b_nr : nc));
00553       OCTAVE_LOCAL_BUFFER (double, buf, q.S()->m2);
00554       for (volatile octave_idx_type i = 0, idx = 0; i < b_nc; i++, idx+=nc)
00555         {
00556           octave_quit ();
00557           for (octave_idx_type j = 0; j < b_nr; j++)
00558             {
00559               Complex c = b.xelem (j,i);
00560               Xx[j] = std::real (c);
00561               Xz[j] = std::imag (c);
00562             }
00563           for (octave_idx_type j = nr; j < q.S()->m2; j++)
00564             buf[j] = 0.;
00565           BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00566 #if defined(CS_VER) && (CS_VER >= 2)
00567           CXSPARSE_DNAME (_ipvec) (q.S()->pinv, Xx, buf, nr);
00568 #else
00569           CXSPARSE_DNAME (_ipvec) (nr, q.S()->Pinv, Xx, buf);
00570 #endif
00571           END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00572           for (volatile octave_idx_type j = 0; j < nc; j++)
00573             {
00574               octave_quit ();
00575               BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00576               CXSPARSE_DNAME (_happly) (q.N()->L, j, q.N()->B[j], buf);
00577               END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00578             }
00579           BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00580           CXSPARSE_DNAME (_usolve) (q.N()->U, buf);
00581 #if defined(CS_VER) && (CS_VER >= 2)
00582           CXSPARSE_DNAME (_ipvec) (q.S()->q, buf, Xx, nc);
00583 #else
00584           CXSPARSE_DNAME (_ipvec) (nc, q.S()->Q, buf, Xx);
00585 #endif
00586           for (octave_idx_type j = nr; j < q.S()->m2; j++)
00587             buf[j] = 0.;
00588 #if defined(CS_VER) && (CS_VER >= 2)
00589           CXSPARSE_DNAME (_ipvec) (q.S()->pinv, Xz, buf, nr);
00590 #else
00591           CXSPARSE_DNAME (_ipvec) (nr, q.S()->Pinv, Xz, buf);
00592 #endif
00593           END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00594           for (volatile octave_idx_type j = 0; j < nc; j++)
00595             {
00596               octave_quit ();
00597               BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00598               CXSPARSE_DNAME (_happly) (q.N()->L, j, q.N()->B[j], buf);
00599               END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00600             }
00601           BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00602           CXSPARSE_DNAME (_usolve) (q.N()->U, buf);
00603 #if defined(CS_VER) && (CS_VER >= 2)
00604           CXSPARSE_DNAME (_ipvec) (q.S()->q, buf, Xz, nc);
00605 #else
00606           CXSPARSE_DNAME (_ipvec) (nc, q.S()->Q, buf, Xz);
00607 #endif
00608           END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00609           for (octave_idx_type j = 0; j < nc; j++)
00610             vec[j+idx] = Complex (Xx[j], Xz[j]);
00611         }
00612       info = 0;
00613     }
00614   else
00615     {
00616       SparseMatrix at = a.hermitian();
00617       SparseQR q (at, 3);
00618       if (! q.ok ())
00619         return ComplexMatrix();
00620       x.resize(nc, b_nc);
00621       Complex *vec = x.fortran_vec();
00622       volatile octave_idx_type nbuf = (nc > q.S()->m2 ? nc : q.S()->m2);
00623       OCTAVE_LOCAL_BUFFER (double, Xx, (b_nr > nc ? b_nr : nc));
00624       OCTAVE_LOCAL_BUFFER (double, Xz, (b_nr > nc ? b_nr : nc));
00625       OCTAVE_LOCAL_BUFFER (double, buf, nbuf);
00626       for (volatile octave_idx_type i = 0, idx = 0; i < b_nc; i++, idx+=nc)
00627         {
00628           octave_quit ();
00629           for (octave_idx_type j = 0; j < b_nr; j++)
00630             {
00631               Complex c = b.xelem (j,i);
00632               Xx[j] = std::real (c);
00633               Xz[j] = std::imag (c);
00634             }
00635           for (octave_idx_type j = nr; j < nbuf; j++)
00636             buf[j] = 0.;
00637           BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00638 #if defined(CS_VER) && (CS_VER >= 2)
00639           CXSPARSE_DNAME (_pvec) (q.S()->q, Xx, buf, nr);
00640 #else
00641           CXSPARSE_DNAME (_pvec) (nr, q.S()->Q, Xx, buf);
00642 #endif
00643           CXSPARSE_DNAME (_utsolve) (q.N()->U, buf);
00644           END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00645           for (volatile octave_idx_type j = nr-1; j >= 0; j--)
00646             {
00647               octave_quit ();
00648               BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00649               CXSPARSE_DNAME (_happly) (q.N()->L, j, q.N()->B[j], buf);
00650               END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00651             }
00652           BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00653 #if defined(CS_VER) && (CS_VER >= 2)
00654           CXSPARSE_DNAME (_pvec) (q.S()->pinv, buf, Xx, nc);
00655 #else
00656           CXSPARSE_DNAME (_pvec) (nc, q.S()->Pinv, buf, Xx);
00657 #endif
00658           END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00659           for (octave_idx_type j = nr; j < nbuf; j++)
00660             buf[j] = 0.;
00661           BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00662 #if defined(CS_VER) && (CS_VER >= 2)
00663           CXSPARSE_DNAME (_pvec) (q.S()->q, Xz, buf, nr);
00664 #else
00665           CXSPARSE_DNAME (_pvec) (nr, q.S()->Q, Xz, buf);
00666 #endif
00667           CXSPARSE_DNAME (_utsolve) (q.N()->U, buf);
00668           END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00669           for (volatile octave_idx_type j = nr-1; j >= 0; j--)
00670             {
00671               octave_quit ();
00672               BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00673               CXSPARSE_DNAME (_happly) (q.N()->L, j, q.N()->B[j], buf);
00674               END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00675             }
00676           BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00677 #if defined(CS_VER) && (CS_VER >= 2)
00678           CXSPARSE_DNAME (_pvec) (q.S()->pinv, buf, Xz, nc);
00679 #else
00680           CXSPARSE_DNAME (_pvec) (nc, q.S()->Pinv, buf, Xz);
00681 #endif
00682           END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00683           for (octave_idx_type j = 0; j < nc; j++)
00684             vec[j+idx] = Complex (Xx[j], Xz[j]);
00685         }
00686       info = 0;
00687     }
00688 
00689   return x;
00690 #else
00691   return ComplexMatrix ();
00692 #endif
00693 }
00694 
00695 SparseComplexMatrix
00696 qrsolve(const SparseMatrix&a, const SparseComplexMatrix &b, octave_idx_type &info)
00697 {
00698   info = -1;
00699 #ifdef HAVE_CXSPARSE
00700   octave_idx_type nr = a.rows();
00701   octave_idx_type nc = a.cols();
00702   octave_idx_type b_nr = b.rows();
00703   octave_idx_type b_nc = b.cols();
00704   SparseComplexMatrix x;
00705   volatile octave_idx_type ii, x_nz;
00706 
00707   if (nr < 0 || nc < 0 || nr != b_nr)
00708     (*current_liboctave_error_handler)
00709       ("matrix dimension mismatch in solution of minimum norm problem");
00710   else if (nr == 0 || nc == 0 || b_nc == 0)
00711     x = SparseComplexMatrix (nc, b_nc);
00712   else if (nr >= nc)
00713     {
00714       SparseQR q (a, 3);
00715       if (! q.ok ())
00716         return SparseComplexMatrix();
00717       x = SparseComplexMatrix (nc, b_nc, b.nnz());
00718       x.xcidx(0) = 0;
00719       x_nz = b.nnz();
00720       ii = 0;
00721       OCTAVE_LOCAL_BUFFER (double, Xx, (b_nr > nc ? b_nr : nc));
00722       OCTAVE_LOCAL_BUFFER (double, Xz, (b_nr > nc ? b_nr : nc));
00723       OCTAVE_LOCAL_BUFFER (double, buf, q.S()->m2);
00724       for (volatile octave_idx_type i = 0, idx = 0; i < b_nc; i++, idx+=nc)
00725         {
00726           octave_quit ();
00727           for (octave_idx_type j = 0; j < b_nr; j++)
00728             {
00729               Complex c = b.xelem (j,i);
00730               Xx[j] = std::real (c);
00731               Xz[j] = std::imag (c);
00732             }
00733           for (octave_idx_type j = nr; j < q.S()->m2; j++)
00734             buf[j] = 0.;
00735           BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00736 #if defined(CS_VER) && (CS_VER >= 2)
00737           CXSPARSE_DNAME (_ipvec) (q.S()->pinv, Xx, buf, nr);
00738 #else
00739           CXSPARSE_DNAME (_ipvec) (nr, q.S()->Pinv, Xx, buf);
00740 #endif
00741           END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00742           for (volatile octave_idx_type j = 0; j < nc; j++)
00743             {
00744               octave_quit ();
00745               BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00746               CXSPARSE_DNAME (_happly) (q.N()->L, j, q.N()->B[j], buf);
00747               END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00748             }
00749           BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00750           CXSPARSE_DNAME (_usolve) (q.N()->U, buf);
00751 #if defined(CS_VER) && (CS_VER >= 2)
00752           CXSPARSE_DNAME (_ipvec) (q.S()->q, buf, Xx, nc);
00753 #else
00754           CXSPARSE_DNAME (_ipvec) (nc, q.S()->Q, buf, Xx);
00755 #endif
00756           END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00757           for (octave_idx_type j = nr; j < q.S()->m2; j++)
00758             buf[j] = 0.;
00759           BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00760 #if defined(CS_VER) && (CS_VER >= 2)
00761           CXSPARSE_DNAME (_ipvec) (q.S()->pinv, Xz, buf, nr);
00762 #else
00763           CXSPARSE_DNAME (_ipvec) (nr, q.S()->Pinv, Xz, buf);
00764 #endif
00765           END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00766           for (volatile octave_idx_type j = 0; j < nc; j++)
00767             {
00768               octave_quit ();
00769               BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00770               CXSPARSE_DNAME (_happly) (q.N()->L, j, q.N()->B[j], buf);
00771               END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00772             }
00773           BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00774           CXSPARSE_DNAME (_usolve) (q.N()->U, buf);
00775 #if defined(CS_VER) && (CS_VER >= 2)
00776           CXSPARSE_DNAME (_ipvec) (q.S()->q, buf, Xz, nc);
00777 #else
00778           CXSPARSE_DNAME (_ipvec) (nc, q.S()->Q, buf, Xz);
00779 #endif
00780           END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00781 
00782           for (octave_idx_type j = 0; j < nc; j++)
00783             {
00784               Complex tmp = Complex (Xx[j], Xz[j]);
00785               if (tmp != 0.0)
00786                 {
00787                   if (ii == x_nz)
00788                     {
00789                       // Resize the sparse matrix
00790                       octave_idx_type sz = x_nz * (b_nc - i) / b_nc;
00791                       sz = (sz > 10 ? sz : 10) + x_nz;
00792                       x.change_capacity (sz);
00793                       x_nz = sz;
00794                     }
00795                   x.xdata(ii) = tmp;
00796                   x.xridx(ii++) = j;
00797                 }
00798             }
00799           x.xcidx(i+1) = ii;
00800         }
00801       info = 0;
00802     }
00803   else
00804     {
00805       SparseMatrix at = a.hermitian();
00806       SparseQR q (at, 3);
00807       if (! q.ok ())
00808         return SparseComplexMatrix();
00809       x = SparseComplexMatrix (nc, b_nc, b.nnz());
00810       x.xcidx(0) = 0;
00811       x_nz = b.nnz();
00812       ii = 0;
00813       volatile octave_idx_type nbuf = (nc > q.S()->m2 ? nc : q.S()->m2);
00814       OCTAVE_LOCAL_BUFFER (double, Xx, (b_nr > nc ? b_nr : nc));
00815       OCTAVE_LOCAL_BUFFER (double, Xz, (b_nr > nc ? b_nr : nc));
00816       OCTAVE_LOCAL_BUFFER (double, buf, nbuf);
00817       for (volatile octave_idx_type i = 0, idx = 0; i < b_nc; i++, idx+=nc)
00818         {
00819           octave_quit ();
00820           for (octave_idx_type j = 0; j < b_nr; j++)
00821             {
00822               Complex c = b.xelem (j,i);
00823               Xx[j] = std::real (c);
00824               Xz[j] = std::imag (c);
00825             }
00826           for (octave_idx_type j = nr; j < nbuf; j++)
00827             buf[j] = 0.;
00828           BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00829 #if defined(CS_VER) && (CS_VER >= 2)
00830           CXSPARSE_DNAME (_pvec) (q.S()->q, Xx, buf, nr);
00831 #else
00832           CXSPARSE_DNAME (_pvec) (nr, q.S()->Q, Xx, buf);
00833 #endif
00834           CXSPARSE_DNAME (_utsolve) (q.N()->U, buf);
00835           END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00836           for (volatile octave_idx_type j = nr-1; j >= 0; j--)
00837             {
00838               octave_quit ();
00839               BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00840               CXSPARSE_DNAME (_happly) (q.N()->L, j, q.N()->B[j], buf);
00841               END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00842             }
00843           BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00844 #if defined(CS_VER) && (CS_VER >= 2)
00845           CXSPARSE_DNAME (_pvec) (q.S()->pinv, buf, Xx, nc);
00846 #else
00847           CXSPARSE_DNAME (_pvec) (nc, q.S()->Pinv, buf, Xx);
00848 #endif
00849           END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00850           for (octave_idx_type j = nr; j < nbuf; j++)
00851             buf[j] = 0.;
00852           BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00853 #if defined(CS_VER) && (CS_VER >= 2)
00854           CXSPARSE_DNAME (_pvec) (q.S()->q, Xz, buf, nr);
00855 #else
00856           CXSPARSE_DNAME (_pvec) (nr, q.S()->Q, Xz, buf);
00857 #endif
00858           CXSPARSE_DNAME (_utsolve) (q.N()->U, buf);
00859           END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00860           for (volatile octave_idx_type j = nr-1; j >= 0; j--)
00861             {
00862               octave_quit ();
00863               BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00864               CXSPARSE_DNAME (_happly) (q.N()->L, j, q.N()->B[j], buf);
00865               END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00866             }
00867           BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00868 #if defined(CS_VER) && (CS_VER >= 2)
00869           CXSPARSE_DNAME (_pvec) (q.S()->pinv, buf, Xz, nc);
00870 #else
00871           CXSPARSE_DNAME (_pvec) (nc, q.S()->Pinv, buf, Xz);
00872 #endif
00873           END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00874 
00875           for (octave_idx_type j = 0; j < nc; j++)
00876             {
00877               Complex tmp = Complex (Xx[j], Xz[j]);
00878               if (tmp != 0.0)
00879                 {
00880                   if (ii == x_nz)
00881                     {
00882                       // Resize the sparse matrix
00883                       octave_idx_type sz = x_nz * (b_nc - i) / b_nc;
00884                       sz = (sz > 10 ? sz : 10) + x_nz;
00885                       x.change_capacity (sz);
00886                       x_nz = sz;
00887                     }
00888                   x.xdata(ii) = tmp;
00889                   x.xridx(ii++) = j;
00890                 }
00891             }
00892           x.xcidx(i+1) = ii;
00893         }
00894       info = 0;
00895     }
00896 
00897   x.maybe_compress ();
00898   return x;
00899 #else
00900   return SparseComplexMatrix ();
00901 #endif
00902 }
00903 
00904 Matrix
00905 qrsolve(const SparseMatrix &a, const MArray<double> &b,
00906         octave_idx_type &info)
00907 {
00908   return qrsolve (a, Matrix (b), info);
00909 }
00910 
00911 ComplexMatrix
00912 qrsolve(const SparseMatrix &a, const MArray<Complex> &b,
00913         octave_idx_type &info)
00914 {
00915   return qrsolve (a, ComplexMatrix (b), info);
00916 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines