00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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
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
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
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 }