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