Rev 5006 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
/* CHOLMOD factors */#include "CHMfactor.h"SEXP CHMfactor_to_sparse(SEXP x){CHM_FR L = AS_CHM_FR(x), Lcp;CHM_SP Lm;R_CheckStack();/* cholmod_factor_to_sparse changes its first argument. Make a copy */Lcp = cholmod_copy_factor(L, &c);if (!(Lcp->is_ll))if (!cholmod_change_factor(Lcp->xtype, 1, 0, 1, 1, Lcp, &c))error(_("cholmod_change_factor failed with status %d"), c.status);Lm = cholmod_factor_to_sparse(Lcp, &c); cholmod_free_factor(&Lcp, &c);return chm_sparse_to_SEXP(Lm, 1/*do_free*/, -1/*uploT*/, 0/*Rkind*/,"N"/*non_unit*/, R_NilValue/*dimNames*/);}SEXP CHMfactor_solve(SEXP a, SEXP b, SEXP system){CHM_FR L = AS_CHM_FR(a);SEXP bb = PROTECT(dup_mMatrix_as_dgeMatrix(b));CHM_DN B = AS_CHM_DN(bb), X;int sys = asInteger(system);R_CheckStack();if (!(sys--)) /* -- align with CHOLMOD defs */error(_("system argument is not valid"));X = cholmod_solve(sys, L, B, &c);UNPROTECT(1);return chm_dense_to_SEXP(X, 1/*do_free*/, 0/*Rkind*/,GET_SLOT(bb, Matrix_DimNamesSym));}SEXP CHMfactor_spsolve(SEXP a, SEXP b, SEXP system){CHM_FR L = AS_CHM_FR(a);CHM_SP B = AS_CHM_SP(b);int sys = asInteger(system);R_CheckStack();if (!(sys--)) /* -- align with CHOLMOD defs */error(_("system argument is not valid"));return chm_sparse_to_SEXP(cholmod_spsolve(sys, L, B, &c),1/*do_free*/, 0/*uploT*/, 0/*Rkind*/,"", GET_SLOT(b, Matrix_DimNamesSym));}/*** Evaluate the logarithm of the square of the determinant of L** @param f pointer to a CHMfactor object** @return log(det(L)^2)**/double chm_factor_ldetL2(CHM_FR f){int i, j, p;double ans = 0;if (f->is_super) {int *lpi = (int*)(f->pi), *lsup = (int*)(f->super);for (i = 0; i < f->nsuper; i++) { /* supernodal block i */int nrp1 = 1 + lpi[i + 1] - lpi[i],nc = lsup[i + 1] - lsup[i];double *x = (double*)(f->x) + ((int*)(f->px))[i];for (j = 0; j < nc; j++) {ans += 2 * log(fabs(x[j * nrp1]));}}} else {int *li = (int*)(f->i), *lp = (int*)(f->p);double *lx = (double *)(f->x);for (j = 0; j < f->n; j++) {for (p = lp[j]; li[p] != j && p < lp[j + 1]; p++) {};if (li[p] != j) {error(_("%d diagonal element of Cholesky factor is missing"), j);break; /* -Wall */}ans += log(lx[p] * ((f->is_ll) ? lx[p] : 1.));}}return ans;}SEXP CHMfactor_ldetL2(SEXP x){CHM_FR L = AS_CHM_FR(x); R_CheckStack();return ScalarReal(chm_factor_ldetL2(L));}/*** Update the numerical values in the factor f as A + mult * I, if A is* symmetric, otherwise AA' + mult * I** @param f pointer to a CHM_FR object. f is updated upon return.* @param A pointer to a CHM_SP object, possibly symmetric* @param mult multiple of the identity to be added to A or AA' before* decomposing.** \note: A and f must be compatible. There is no check on this* here. Incompatibility of A and f will cause the CHOLMOD functions* to take an error exit.**/CHM_FR chm_factor_update(CHM_FR f, CHM_SP A, double mult){double mm[2] = {0, 0};mm[0] = mult;if (!cholmod_factorize_p(A, mm, (int*)NULL, 0 /*fsize*/, f, &c))error(_("cholmod_factorize_p failed: status %d, minor %d of ncol %d"),c.status, f->minor, f->n);return f;}SEXP CHMfactor_update(SEXP object, SEXP parent, SEXP mult){CHM_FR L = AS_CHM_FR(object), Lcp;CHM_SP A = AS_CHM_SP(parent);R_CheckStack();Lcp = cholmod_copy_factor(L, &c);return chm_factor_to_SEXP(chm_factor_update(Lcp, A, asReal(mult)), 1);}SEXP CHMfactor_ldetL2up(SEXP x, SEXP parent, SEXP mult){SEXP ans = PROTECT(duplicate(mult));int i, nmult = LENGTH(mult);double *aa = REAL(ans), *mm = REAL(mult);CHM_FR L = AS_CHM_FR(x), Lcp;CHM_SP A = AS_CHM_SP(parent);R_CheckStack();Lcp = cholmod_copy_factor(L, &c);for (i = 0; i < nmult; i++)aa[i] = chm_factor_ldetL2(chm_factor_update(Lcp, A, mm[i]));cholmod_free_factor(&Lcp, &c);UNPROTECT(1);return ans;}