sparse-base-chol.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 2005-2012 David Bateman
00004 Copyright (C) 1998-2005 Andy Adler
00005 
00006 This file is part of Octave.
00007 
00008 Octave is free software; you can redistribute it and/or modify it
00009 under the terms of the GNU General Public License as published by the
00010 Free Software Foundation; either version 3 of the License, or (at your
00011 option) any later version.
00012 
00013 Octave is distributed in the hope that it will be useful, but WITHOUT
00014 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00015 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00016 for more details.
00017 
00018 You should have received a copy of the GNU General Public License
00019 along with Octave; see the file COPYING.  If not, see
00020 <http://www.gnu.org/licenses/>.
00021 
00022 */
00023 
00024 #ifdef HAVE_CONFIG_H
00025 #include <config.h>
00026 #endif
00027 
00028 #include "sparse-base-chol.h"
00029 #include "sparse-util.h"
00030 #include "lo-error.h"
00031 #include "oct-sparse.h"
00032 #include "oct-spparms.h"
00033 #include "quit.h"
00034 #include "MatrixType.h"
00035 
00036 #ifdef HAVE_CHOLMOD
00037 // Can't use CHOLMOD_NAME(drop)(0.0, S, cm). It doesn't treat complex matrices
00038 template <class chol_type, class chol_elt, class p_type>
00039 void
00040 sparse_base_chol<chol_type, chol_elt, p_type>::sparse_base_chol_rep::drop_zeros
00041   (const cholmod_sparse* S)
00042 {
00043   chol_elt sik;
00044   octave_idx_type *Sp, *Si;
00045   chol_elt *Sx;
00046   octave_idx_type pdest, k, ncol, p, pend;
00047 
00048   if (! S)
00049     return;
00050 
00051   Sp = static_cast<octave_idx_type *>(S->p);
00052   Si = static_cast<octave_idx_type *>(S->i);
00053   Sx = static_cast<chol_elt *>(S->x);
00054   pdest = 0;
00055   ncol = S->ncol;
00056 
00057   for (k = 0; k < ncol; k++)
00058     {
00059       p = Sp [k];
00060       pend = Sp [k+1];
00061       Sp [k] = pdest;
00062       for (; p < pend; p++)
00063         {
00064           sik = Sx [p];
00065           if (CHOLMOD_IS_NONZERO (sik))
00066             {
00067               if (p != pdest)
00068                 {
00069                   Si [pdest] = Si [p];
00070                   Sx [pdest] = sik;
00071                 }
00072               pdest++;
00073             }
00074         }
00075     }
00076   Sp [ncol] = pdest;
00077 }
00078 #endif
00079 
00080 template <class chol_type, class chol_elt, class p_type>
00081 octave_idx_type
00082 sparse_base_chol<chol_type, chol_elt, p_type>::sparse_base_chol_rep::init
00083   (const chol_type& a, bool natural)
00084 {
00085   volatile octave_idx_type info = 0;
00086 #ifdef HAVE_CHOLMOD
00087   octave_idx_type a_nr = a.rows ();
00088   octave_idx_type a_nc = a.cols ();
00089 
00090   if (a_nr != a_nc)
00091     {
00092       (*current_liboctave_error_handler)
00093         ("SparseCHOL requires square matrix");
00094       return -1;
00095     }
00096 
00097   cholmod_common *cm = &Common;
00098 
00099   // Setup initial parameters
00100   CHOLMOD_NAME(start) (cm);
00101   cm->prefer_zomplex = false;
00102 
00103   double spu = octave_sparse_params::get_key ("spumoni");
00104   if (spu == 0.)
00105     {
00106       cm->print = -1;
00107       cm->print_function = 0;
00108     }
00109   else
00110     {
00111       cm->print = static_cast<int> (spu) + 2;
00112       cm->print_function =&SparseCholPrint;
00113     }
00114 
00115   cm->error_handler = &SparseCholError;
00116   cm->complex_divide = CHOLMOD_NAME(divcomplex);
00117   cm->hypotenuse = CHOLMOD_NAME(hypot);
00118 
00119   cm->final_asis = false;
00120   cm->final_super = false;
00121   cm->final_ll = true;
00122   cm->final_pack = true;
00123   cm->final_monotonic = true;
00124   cm->final_resymbol = false;
00125 
00126   cholmod_sparse A;
00127   cholmod_sparse *ac = &A;
00128   double dummy;
00129   ac->nrow = a_nr;
00130   ac->ncol = a_nc;
00131 
00132   ac->p = a.cidx();
00133   ac->i = a.ridx();
00134   ac->nzmax = a.nnz();
00135   ac->packed = true;
00136   ac->sorted = true;
00137   ac->nz = 0;
00138 #ifdef IDX_TYPE_LONG
00139   ac->itype = CHOLMOD_LONG;
00140 #else
00141   ac->itype = CHOLMOD_INT;
00142 #endif
00143   ac->dtype = CHOLMOD_DOUBLE;
00144   ac->stype = 1;
00145 #ifdef OCTAVE_CHOLMOD_TYPE
00146   ac->xtype = OCTAVE_CHOLMOD_TYPE;
00147 #else
00148   ac->xtype = CHOLMOD_REAL;
00149 #endif
00150 
00151   if (a_nr < 1)
00152     ac->x = &dummy;
00153   else
00154     ac->x = a.data();
00155 
00156   // use natural ordering if no q output parameter
00157   if (natural)
00158     {
00159       cm->nmethods = 1 ;
00160       cm->method [0].ordering = CHOLMOD_NATURAL ;
00161       cm->postorder = false ;
00162     }
00163 
00164   cholmod_factor *Lfactor;
00165   BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00166   Lfactor = CHOLMOD_NAME(analyze) (ac, cm);
00167   CHOLMOD_NAME(factorize) (ac, Lfactor, cm);
00168   END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00169 
00170   is_pd = cm->status == CHOLMOD_OK;
00171   info = (is_pd ? 0 : cm->status);
00172 
00173   if (is_pd)
00174     {
00175       BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00176       cond = CHOLMOD_NAME(rcond) (Lfactor, cm);
00177       END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00178 
00179       minor_p = Lfactor->minor;
00180 
00181       BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00182       Lsparse = CHOLMOD_NAME(factor_to_sparse) (Lfactor, cm);
00183       END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00184 
00185       if (minor_p > 0 && minor_p < a_nr)
00186         {
00187           size_t n1 = a_nr + 1;
00188           Lsparse->p = CHOLMOD_NAME(realloc) (minor_p+1,
00189                                               sizeof(octave_idx_type),
00190                                               Lsparse->p, &n1, cm);
00191           BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00192           CHOLMOD_NAME(reallocate_sparse)
00193             (static_cast<octave_idx_type *>(Lsparse->p)[minor_p], Lsparse, cm);
00194           END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00195           Lsparse->ncol = minor_p;
00196         }
00197 
00198       drop_zeros (Lsparse);
00199 
00200       if (! natural)
00201         {
00202           perms.resize (a_nr);
00203           for (octave_idx_type i = 0; i < a_nr; i++)
00204             perms(i) = static_cast<octave_idx_type *>(Lfactor->Perm)[i];
00205         }
00206 
00207       static char tmp[] = " ";
00208 
00209       BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00210       CHOLMOD_NAME(free_factor) (&Lfactor, cm);
00211       CHOLMOD_NAME(finish) (cm);
00212       CHOLMOD_NAME(print_common) (tmp, cm);
00213       END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00214     }
00215 #else
00216   (*current_liboctave_error_handler)
00217     ("Missing CHOLMOD. Sparse cholesky factorization disabled");
00218 #endif
00219   return info;
00220 }
00221 
00222 template <class chol_type, class chol_elt, class p_type>
00223 chol_type
00224 sparse_base_chol<chol_type, chol_elt, p_type>::L (void) const
00225 {
00226 #ifdef HAVE_CHOLMOD
00227   cholmod_sparse *m = rep->L();
00228   octave_idx_type nc = m->ncol;
00229   octave_idx_type nnz = m->nzmax;
00230   chol_type ret (m->nrow, nc, nnz);
00231   for (octave_idx_type j = 0; j < nc+1; j++)
00232     ret.xcidx(j) = static_cast<octave_idx_type *>(m->p)[j];
00233   for (octave_idx_type i = 0; i < nnz; i++)
00234     {
00235       ret.xridx(i) = static_cast<octave_idx_type *>(m->i)[i];
00236       ret.xdata(i) = static_cast<chol_elt *>(m->x)[i];
00237     }
00238   return ret;
00239 #else
00240   return chol_type();
00241 #endif
00242 }
00243 
00244 template <class chol_type, class chol_elt, class p_type>
00245 p_type
00246 sparse_base_chol<chol_type, chol_elt, p_type>::
00247 sparse_base_chol_rep::Q (void) const
00248 {
00249 #ifdef HAVE_CHOLMOD
00250   octave_idx_type n = Lsparse->nrow;
00251   p_type p (n, n, n);
00252 
00253   for (octave_idx_type i = 0; i < n; i++)
00254     {
00255       p.xcidx(i) = i;
00256       p.xridx(i) = static_cast<octave_idx_type>(perms(i));
00257       p.xdata(i) = 1;
00258     }
00259   p.xcidx(n) = n;
00260 
00261   return p;
00262 #else
00263   return p_type();
00264 #endif
00265 }
00266 
00267 template <class chol_type, class chol_elt, class p_type>
00268 chol_type
00269 sparse_base_chol<chol_type, chol_elt, p_type>::inverse (void) const
00270 {
00271   chol_type retval;
00272 #ifdef HAVE_CHOLMOD
00273   cholmod_sparse *m = rep->L();
00274   octave_idx_type n = m->ncol;
00275   ColumnVector perms = rep->perm();
00276   chol_type ret;
00277   double rcond2;
00278   octave_idx_type info;
00279   MatrixType mattype (MatrixType::Upper);
00280   chol_type linv = L().hermitian().inverse(mattype, info, rcond2, 1, 0);
00281 
00282   if (perms.length() == n)
00283     {
00284       p_type Qc = Q();
00285       retval = Qc * linv * linv.hermitian() * Qc.transpose();
00286     }
00287   else
00288     retval = linv * linv.hermitian ();
00289 #endif
00290   return retval;
00291 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines