|
Matrix $Rev: 2718 $ at $LastChangedDate: 2011-10-06 11:45:17 +0200 (Thu, 06 Oct 2011) $
|
00001 #include "chm_common.h" 00002 #include "Mutils.h" 00003 00004 Rboolean isValid_Csparse(SEXP x); /* -> Csparse.c */ 00005 00006 cholmod_common c; 00007 cholmod_common cl; 00008 00009 SEXP chm_common_env; 00010 static SEXP dboundSym, grow0Sym, grow1Sym, grow2Sym, maxrankSym, 00011 supernodal_switchSym, supernodalSym, final_asisSym, final_superSym, 00012 final_llSym, final_packSym, final_monotonicSym, final_resymbolSym, 00013 prefer_zomplexSym, prefer_upperSym, quick_return_if_not_posdefSym, 00014 nmethodsSym, m0_ordSym, postorderSym; 00015 00016 void CHM_store_common() { 00017 SEXP rho = chm_common_env; 00018 defineVar(dboundSym, ScalarReal(c.dbound), rho); 00019 defineVar(grow0Sym, ScalarReal(c.grow0), rho); 00020 defineVar(grow1Sym, ScalarReal(c.grow1), rho); 00021 defineVar(grow2Sym, ScalarInteger(c.grow2), rho); 00022 defineVar(maxrankSym, ScalarInteger(c.maxrank), rho); 00023 defineVar(supernodal_switchSym, 00024 ScalarReal(c.supernodal_switch), rho); 00025 defineVar(supernodalSym, ScalarInteger(c.supernodal), rho); 00026 defineVar(final_asisSym, ScalarLogical(c.final_asis), rho); 00027 defineVar(final_superSym, ScalarLogical(c.final_super), rho); 00028 defineVar(final_llSym, ScalarLogical(c.final_ll), rho); 00029 defineVar(final_packSym, ScalarLogical(c.final_pack), rho); 00030 defineVar(final_monotonicSym, ScalarLogical(c.final_monotonic), rho); 00031 defineVar(final_resymbolSym, ScalarLogical(c.final_resymbol), rho); 00032 defineVar(prefer_zomplexSym, ScalarLogical(c.prefer_zomplex), rho); 00033 defineVar(prefer_upperSym, ScalarLogical(c.prefer_upper), rho); 00034 defineVar(quick_return_if_not_posdefSym, 00035 ScalarLogical(c.quick_return_if_not_posdef), rho); 00036 defineVar(nmethodsSym, ScalarInteger(c.nmethods), rho); 00037 defineVar(m0_ordSym, ScalarInteger(c.method[0].ordering), rho); 00038 defineVar(postorderSym, ScalarLogical(c.postorder), rho); 00039 } 00040 00041 void CHM_restore_common() { 00042 SEXP rho = chm_common_env; 00043 c.dbound = asReal(findVarInFrame(rho, dboundSym)); 00044 c.grow0 = asReal(findVarInFrame(rho, grow0Sym)); 00045 c.grow1 = asReal(findVarInFrame(rho, grow1Sym)); 00046 c.grow2 = asInteger(findVarInFrame(rho, grow2Sym)); 00047 c.maxrank = asInteger(findVarInFrame(rho, maxrankSym)); 00048 c.supernodal_switch = asReal(findVarInFrame(rho, supernodal_switchSym)); 00049 c.supernodal = asLogical(findVarInFrame(rho, supernodalSym)); 00050 c.final_asis = asLogical(findVarInFrame(rho, final_asisSym)); 00051 c.final_super = asLogical(findVarInFrame(rho, final_superSym)); 00052 c.final_ll = asLogical(findVarInFrame(rho, final_llSym)); 00053 c.final_pack = asLogical(findVarInFrame(rho, final_packSym)); 00054 c.final_monotonic = asLogical(findVarInFrame(rho, final_monotonicSym)); 00055 c.final_resymbol = asLogical(findVarInFrame(rho, final_resymbolSym)); 00056 c.prefer_zomplex = asLogical(findVarInFrame(rho, prefer_zomplexSym)); 00057 c.prefer_upper = asLogical(findVarInFrame(rho, prefer_upperSym)); 00058 c.quick_return_if_not_posdef = 00059 asLogical(findVarInFrame(rho, quick_return_if_not_posdefSym)); 00060 c.nmethods = asInteger(findVarInFrame(rho, nmethodsSym)); 00061 c.method[0].ordering = asInteger(findVarInFrame(rho, m0_ordSym)); 00062 c.postorder = asLogical(findVarInFrame(rho, postorderSym)); 00063 } 00064 00065 SEXP CHM_set_common_env(SEXP rho) { 00066 if (!isEnvironment(rho)) 00067 error(_("Argument rho must be an environment")); 00068 chm_common_env = rho; 00069 dboundSym = install("dbound"); 00070 grow0Sym = install("grow0"); 00071 grow1Sym = install("grow1"); 00072 grow2Sym = install("grow2"); 00073 maxrankSym = install("maxrank"); 00074 supernodal_switchSym = install("supernodal_switch"); 00075 supernodalSym = install("supernodal"); 00076 final_asisSym = install("final_asis"); 00077 final_superSym = install("final_super"); 00078 final_llSym = install("final_ll"); 00079 final_packSym = install("final_pack"); 00080 final_monotonicSym = install("final_monotonic"); 00081 final_resymbolSym = install("final_resymbol"); 00082 prefer_zomplexSym = install("final_zomplex"); 00083 prefer_upperSym = install("final_upper"); 00084 quick_return_if_not_posdefSym = install("quick_return_if_not_posdef"); 00085 nmethodsSym = install("nmethods"); 00086 m0_ordSym = install("m0.ord"); 00087 postorderSym = install("postorder"); 00088 CHM_store_common(); 00089 return R_NilValue; 00090 } 00091 00092 static int stype(int ctype, SEXP x) 00093 { 00094 if ((ctype % 3) == 1) return (*uplo_P(x) == 'U') ? 1 : -1; 00095 return 0; 00096 } 00097 00098 static int xtype(int ctype) 00099 { 00100 switch(ctype / 3) { 00101 case 0: /* "d" */ 00102 case 1: /* "l" */ 00103 return CHOLMOD_REAL; 00104 case 2: /* "n" */ 00105 return CHOLMOD_PATTERN; 00106 case 3: /* "z" */ 00107 return CHOLMOD_COMPLEX; 00108 } 00109 return -1; 00110 } 00111 00112 /* coerce a vector to REAL and copy the result to freshly R_alloc'd memory */ 00113 static void *RallocedREAL(SEXP x) 00114 { 00115 SEXP rx = PROTECT(coerceVector(x, REALSXP)); 00116 int lx = LENGTH(rx); 00117 /* We over-allocate the memory chunk so that it is never NULL. */ 00118 /* The CHOLMOD code checks for a NULL pointer even in the length-0 case. */ 00119 double *ans = Memcpy((double*)R_alloc(lx + 1, sizeof(double)), 00120 REAL(rx), lx); 00121 UNPROTECT(1); 00122 return (void*)ans; 00123 } 00124 00125 00126 static void *xpt(int ctype, SEXP x) 00127 { 00128 switch(ctype / 3) { 00129 case 0: /* "d" */ 00130 return (void *) REAL(GET_SLOT(x, Matrix_xSym)); 00131 case 1: /* "l" */ 00132 return RallocedREAL(GET_SLOT(x, Matrix_xSym)); 00133 case 2: /* "n" */ 00134 return (void *) NULL; 00135 case 3: /* "z" */ 00136 return (void *) COMPLEX(GET_SLOT(x, Matrix_xSym)); 00137 } 00138 return (void *) NULL; /* -Wall */ 00139 } 00140 00141 Rboolean check_sorted_chm(CHM_SP A) 00142 { 00143 int *Ai = (int*)(A->i), *Ap = (int*)(A->p); 00144 int j, p; 00145 00146 for (j = 0; j < A->ncol; j++) { 00147 int p1 = Ap[j], p2 = Ap[j + 1] - 1; 00148 for (p = p1; p < p2; p++) 00149 if (Ai[p] >= Ai[p + 1]) 00150 return FALSE; 00151 } 00152 return TRUE; 00153 } 00154 00158 static void chm2Ralloc(CHM_SP dest, CHM_SP src) 00159 { 00160 int np1, nnz; 00161 00162 /* copy all the characteristics of src to dest */ 00163 memcpy(dest, src, sizeof(cholmod_sparse)); 00164 00165 /* R_alloc the vector storage for dest and copy the contents from src */ 00166 np1 = src->ncol + 1; 00167 nnz = (int) cholmod_nnz(src, &c); 00168 dest->p = (void*) Memcpy((int*)R_alloc(sizeof(int), np1), 00169 (int*)(src->p), np1); 00170 dest->i = (void*) Memcpy((int*)R_alloc(sizeof(int), nnz), 00171 (int*)(src->i), nnz); 00172 if(src->xtype) 00173 dest->x = (void*) Memcpy((double*)R_alloc(sizeof(double), nnz), 00174 (double*)(src->x), nnz); 00175 } 00176 00180 static void chTr2Ralloc(CHM_TR dest, CHM_TR src) 00181 { 00182 int nnz; 00183 00184 /* copy all the (non-pointer) characteristics of src to dest */ 00185 memcpy(dest, src, sizeof(cholmod_triplet)); 00186 00187 /* R_alloc the vector storage for dest and copy the contents from src */ 00188 nnz = src->nnz; 00189 dest->i = (void*) Memcpy((int*)R_alloc(sizeof(int), nnz), 00190 (int*)(src->i), nnz); 00191 dest->j = (void*) Memcpy((int*)R_alloc(sizeof(int), nnz), 00192 (int*)(src->j), nnz); 00193 if(src->xtype) 00194 dest->x = (void*) Memcpy((double*)R_alloc(sizeof(double), nnz), 00195 (double*)(src->x), nnz); 00196 } 00197 00217 CHM_SP as_cholmod_sparse(CHM_SP ans, SEXP x, 00218 Rboolean check_Udiag, Rboolean sort_in_place) 00219 { 00220 static const char *valid[] = { 00221 "dgCMatrix", "dsCMatrix", "dtCMatrix", 00222 "lgCMatrix", "lsCMatrix", "ltCMatrix", 00223 "ngCMatrix", "nsCMatrix", "ntCMatrix", 00224 "zgCMatrix", "zsCMatrix", "ztCMatrix", 00225 ""}; 00226 int *dims = INTEGER(GET_SLOT(x, Matrix_DimSym)), 00227 ctype = Matrix_check_class_etc(x, valid); 00228 SEXP islot = GET_SLOT(x, Matrix_iSym); 00229 00230 if (ctype < 0) error(_("invalid class of object to as_cholmod_sparse")); 00231 if (!isValid_Csparse(x)) 00232 error(_("invalid object passed to as_cholmod_sparse")); 00233 memset(ans, 0, sizeof(cholmod_sparse)); /* zero the struct */ 00234 00235 ans->itype = CHOLMOD_INT; /* characteristics of the system */ 00236 ans->dtype = CHOLMOD_DOUBLE; 00237 ans->packed = TRUE; 00238 /* slots always present */ 00239 ans->i = INTEGER(islot); 00240 ans->p = INTEGER(GET_SLOT(x, Matrix_pSym)); 00241 /* dimensions and nzmax */ 00242 ans->nrow = dims[0]; 00243 ans->ncol = dims[1]; 00244 /* Allow for over-allocation of the i and x slots. Needed for 00245 * sparse X form in lme4. Right now it looks too difficult to 00246 * check for the length of the x slot, because of the xpt 00247 * utility, but the lengths of x and i should agree. */ 00248 ans->nzmax = LENGTH(islot); 00249 /* values depending on ctype */ 00250 ans->x = xpt(ctype, x); 00251 ans->stype = stype(ctype, x); 00252 ans->xtype = xtype(ctype); 00253 00254 /* are the columns sorted (increasing row numbers) ?*/ 00255 ans->sorted = check_sorted_chm(ans); 00256 if (!(ans->sorted)) { /* sort columns */ 00257 if(sort_in_place) { 00258 if (!cholmod_sort(ans, &c)) 00259 error(_("in_place cholmod_sort returned an error code")); 00260 ans->sorted = 1; 00261 } 00262 else { 00263 CHM_SP tmp = cholmod_copy_sparse(ans, &c); 00264 if (!cholmod_sort(tmp, &c)) 00265 error(_("cholmod_sort returned an error code")); 00266 00267 #ifdef DEBUG_Matrix 00268 /* This "triggers" exactly for return values of dtCMatrix_sparse_solve():*/ 00269 /* Don't want to translate this: want it report */ 00270 Rprintf("Note: as_cholmod_sparse() needed cholmod_sort()ing\n"); 00271 #endif 00272 chm2Ralloc(ans, tmp); 00273 cholmod_free_sparse(&tmp, &c); 00274 } 00275 } 00276 00277 if (check_Udiag && ctype % 3 == 2 && (*diag_P(x) == 'U')) { /* diagU2N(.) "in place" : */ 00278 double one[] = {1, 0}; 00279 CHM_SP eye = cholmod_speye(ans->nrow, ans->ncol, ans->xtype, &c); 00280 CHM_SP tmp = cholmod_add(ans, eye, one, one, TRUE, TRUE, &c); 00281 00282 #ifdef DEBUG_Matrix_verbose /* quite often, e.g. in ../tests/indexing.R */ 00283 Rprintf("Note: as_cholmod_sparse(<ctype=%d>) - diagU2N\n", ctype); 00284 #endif 00285 chm2Ralloc(ans, tmp); 00286 cholmod_free_sparse(&tmp, &c); 00287 cholmod_free_sparse(&eye, &c); 00288 } /* else : 00289 * NOTE: if(*diag_P(x) == 'U'), the diagonal is lost (!); 00290 * ---- that may be ok, e.g. if we are just converting from/to Tsparse, 00291 * but is *not* at all ok, e.g. when used before matrix products */ 00292 00293 return ans; 00294 } 00295 00311 SEXP chm_sparse_to_SEXP(CHM_SP a, int dofree, int uploT, int Rkind, 00312 const char* diag, SEXP dn) 00313 { 00314 SEXP ans; 00315 char *cls = "";/* -Wall */ 00316 int *dims, nnz, *ansp, *ansi, *aii = (int*)(a->i), *api = (int*)(a->p), 00317 longi = (a->itype) == CHOLMOD_LONG; 00318 UF_long *ail = (UF_long*)(a->i), *apl = (UF_long*)(a->p); 00319 00320 PROTECT(dn); /* dn is usually UNPROTECTed before the call */ 00321 00322 /* ensure a is sorted and packed */ 00323 if (!a->sorted || !a->packed) 00324 longi ? cholmod_l_sort(a, &cl) : cholmod_sort(a, &c); 00325 /* determine the class of the result */ 00326 switch(a->xtype){ 00327 case CHOLMOD_PATTERN: 00328 cls = uploT ? "ntCMatrix": ((a->stype) ? "nsCMatrix" : "ngCMatrix"); 00329 break; 00330 case CHOLMOD_REAL: 00331 switch(Rkind) { 00332 case 0: 00333 cls = uploT ? "dtCMatrix": ((a->stype) ? "dsCMatrix" : "dgCMatrix"); 00334 break; 00335 case 1: 00336 cls = uploT ? "ltCMatrix": ((a->stype) ? "lsCMatrix" : "lgCMatrix"); 00337 break; 00338 default: 00339 error(_("chm_sparse_to_SEXP(<real>, *): invalid 'Rkind' (real kind code)")); 00340 } 00341 break; 00342 case CHOLMOD_COMPLEX: 00343 cls = uploT ? "ztCMatrix": ((a->stype) ? "zsCMatrix" : "zgCMatrix"); 00344 break; 00345 default: error(_("unknown xtype in cholmod_sparse object")); 00346 } 00347 ans = PROTECT(NEW_OBJECT(MAKE_CLASS(cls))); 00348 /* allocate and copy common slots */ 00349 nnz = longi ? cholmod_l_nnz(a, &cl) : cholmod_nnz(a, &c); 00350 dims = INTEGER(ALLOC_SLOT(ans, Matrix_DimSym, INTSXP, 2)); 00351 dims[0] = a->nrow; dims[1] = a->ncol; 00352 ansp = INTEGER(ALLOC_SLOT(ans, Matrix_pSym, INTSXP, a->ncol + 1)); 00353 ansi = INTEGER(ALLOC_SLOT(ans, Matrix_iSym, INTSXP, nnz)); 00354 for (int j = 0; j <= a->ncol; j++) ansp[j] = longi ? (int)(apl[j]) : api[j]; 00355 for (int p = 0; p < nnz; p++) ansi[p] = longi ? (int)(ail[p]) : aii[p]; 00356 /* copy data slot if present */ 00357 if (a->xtype == CHOLMOD_REAL) { 00358 int i, *m_x; 00359 double *a_x = (double *) a->x; 00360 switch(Rkind) { 00361 case 0: 00362 Memcpy(REAL(ALLOC_SLOT(ans, Matrix_xSym, REALSXP, nnz)), 00363 a_x, nnz); 00364 break; 00365 case 1: 00366 m_x = LOGICAL(ALLOC_SLOT(ans, Matrix_xSym, LGLSXP, nnz)); 00367 for (i=0; i < nnz; i++) 00368 m_x[i] = ISNAN(a_x[i]) ? NA_LOGICAL : (a_x[i] != 0); 00369 break; 00370 } 00371 } 00372 else if (a->xtype == CHOLMOD_COMPLEX) 00373 error(_("complex sparse matrix code not yet written")); 00374 /* Memcpy(COMPLEX(ALLOC_SLOT(ans, Matrix_xSym, CPLXSXP, nnz)), */ 00375 /* (complex *) a->x, nnz); */ 00376 if (uploT) { /* slots for triangularMatrix */ 00377 if (a->stype) error(_("Symmetric and triangular both set")); 00378 SET_SLOT(ans, Matrix_uploSym, mkString((uploT > 0) ? "U" : "L")); 00379 SET_SLOT(ans, Matrix_diagSym, mkString(diag)); 00380 } 00381 if (a->stype) /* slot for symmetricMatrix */ 00382 SET_SLOT(ans, Matrix_uploSym, 00383 mkString((a->stype > 0) ? "U" : "L")); 00384 if (dofree > 0) 00385 longi ? cholmod_l_free_sparse(&a, &cl) : cholmod_free_sparse(&a, &c); 00386 if (dofree < 0) Free(a); 00387 if (dn != R_NilValue) 00388 SET_SLOT(ans, Matrix_DimNamesSym, duplicate(dn)); 00389 00390 UNPROTECT(2); 00391 return ans; 00392 } 00393 00410 CHM_TR as_cholmod_triplet(CHM_TR ans, SEXP x, Rboolean check_Udiag) 00411 { 00412 static const char *valid[] = { MATRIX_VALID_Tsparse, ""}; 00413 int *dims = INTEGER(GET_SLOT(x, Matrix_DimSym)), 00414 ctype = Matrix_check_class_etc(x, valid); 00415 SEXP islot = GET_SLOT(x, Matrix_iSym); 00416 int m = LENGTH(islot); 00417 Rboolean do_Udiag = (check_Udiag && ctype % 3 == 2 && (*diag_P(x) == 'U')); 00418 if (ctype < 0) error(_("invalid class of object to as_cholmod_triplet")); 00419 00420 memset(ans, 0, sizeof(cholmod_triplet)); /* zero the struct */ 00421 00422 ans->itype = CHOLMOD_INT; /* characteristics of the system */ 00423 ans->dtype = CHOLMOD_DOUBLE; 00424 /* nzmax, dimensions, types and slots : */ 00425 ans->nnz = ans->nzmax = m; 00426 ans->nrow = dims[0]; 00427 ans->ncol = dims[1]; 00428 ans->stype = stype(ctype, x); 00429 ans->xtype = xtype(ctype); 00430 ans->i = (void *) INTEGER(islot); 00431 ans->j = (void *) INTEGER(GET_SLOT(x, Matrix_jSym)); 00432 ans->x = xpt(ctype, x); 00433 00434 if(do_Udiag) { 00435 /* diagU2N(.) "in place", similarly to Tsparse_diagU2N [./Tsparse.c] 00436 (but without new SEXP): */ 00437 int k = m + dims[0]; 00438 CHM_TR tmp = cholmod_l_copy_triplet(ans, &c); 00439 int *a_i, *a_j; 00440 00441 if(!cholmod_reallocate_triplet((size_t) k, tmp, &c)) 00442 error(_("as_cholmod_triplet(): could not reallocate for internal diagU2N()" 00443 )); 00444 00445 /* TODO? instead of copy_triplet() & reallocate_triplet() 00446 * ---- allocate to correct length + Memcpy() here, as in 00447 * Tsparse_diagU2N() & chTr2Ralloc() below */ 00448 a_i = tmp->i; 00449 a_j = tmp->j; 00450 /* add (@i, @j)[k+m] = k, @x[k+m] = 1. for k = 0,..,(n-1) */ 00451 for(k=0; k < dims[0]; k++) { 00452 a_i[k+m] = k; 00453 a_j[k+m] = k; 00454 00455 switch(ctype / 3) { 00456 case 0: { /* "d" */ 00457 double *a_x = tmp->x; 00458 a_x[k+m] = 1.; 00459 break; 00460 } 00461 case 1: { /* "l" */ 00462 int *a_x = tmp->x; 00463 a_x[k+m] = 1; 00464 break; 00465 } 00466 case 2: /* "n" */ 00467 break; 00468 case 3: { /* "z" */ 00469 double *a_x = tmp->x; 00470 a_x[2*(k+m) ] = 1.; 00471 a_x[2*(k+m)+1] = 0.; 00472 break; 00473 } 00474 } 00475 } /* for(k) */ 00476 00477 chTr2Ralloc(ans, tmp); 00478 cholmod_l_free_triplet(&tmp, &c); 00479 00480 } /* else : 00481 * NOTE: if(*diag_P(x) == 'U'), the diagonal is lost (!); 00482 * ---- that may be ok, e.g. if we are just converting from/to Tsparse, 00483 * but is *not* at all ok, e.g. when used before matrix products */ 00484 00485 return ans; 00486 } 00487 00503 SEXP chm_triplet_to_SEXP(CHM_TR a, int dofree, int uploT, int Rkind, 00504 const char* diag, SEXP dn) 00505 { 00506 SEXP ans; 00507 char *cl = ""; /* -Wall */ 00508 int *dims; 00509 00510 PROTECT(dn); /* dn is usually UNPROTECTed before the call */ 00511 /* determine the class of the result */ 00512 switch(a->xtype) { 00513 case CHOLMOD_PATTERN: 00514 cl = uploT ? "ntTMatrix" : 00515 ((a->stype) ? "nsTMatrix" : "ngTMatrix"); 00516 break; 00517 case CHOLMOD_REAL: 00518 switch(Rkind) { 00519 case 0: 00520 cl = uploT ? "dtTMatrix" : 00521 ((a->stype) ? "dsTMatrix" : "dgTMatrix"); 00522 break; 00523 case 1: 00524 cl = uploT ? "ltTMatrix" : 00525 ((a->stype) ? "lsTMatrix" : "lgTMatrix"); 00526 break; 00527 } 00528 break; 00529 case CHOLMOD_COMPLEX: 00530 cl = uploT ? "ztTMatrix" : 00531 ((a->stype) ? "zsTMatrix" : "zgTMatrix"); 00532 break; 00533 default: error(_("unknown xtype in cholmod_triplet object")); 00534 } 00535 ans = PROTECT(NEW_OBJECT(MAKE_CLASS(cl))); 00536 /* allocate and copy common slots */ 00537 dims = INTEGER(ALLOC_SLOT(ans, Matrix_DimSym, INTSXP, 2)); 00538 dims[0] = a->nrow; dims[1] = a->ncol; 00539 Memcpy(INTEGER(ALLOC_SLOT(ans, Matrix_iSym, INTSXP, a->nnz)), 00540 (int *) a->i, a->nnz); 00541 Memcpy(INTEGER(ALLOC_SLOT(ans, Matrix_jSym, INTSXP, a->nnz)), 00542 (int *) a->j, a->nnz); 00543 /* copy data slot if present */ 00544 if (a->xtype == CHOLMOD_REAL) { 00545 int i, *m_x; 00546 double *a_x = (double *) a->x; 00547 switch(Rkind) { 00548 case 0: 00549 Memcpy(REAL(ALLOC_SLOT(ans, Matrix_xSym, REALSXP, a->nnz)), 00550 a_x, a->nnz); 00551 break; 00552 case 1: 00553 m_x = LOGICAL(ALLOC_SLOT(ans, Matrix_xSym, LGLSXP, a->nnz)); 00554 for (i=0; i < a->nnz; i++) 00555 m_x[i] = ISNAN(a_x[i]) ? NA_LOGICAL : (a_x[i] != 0); 00556 break; 00557 } 00558 } 00559 else if (a->xtype == CHOLMOD_COMPLEX) 00560 error(_("complex sparse matrix code not yet written")); 00561 /* Memcpy(COMPLEX(ALLOC_SLOT(ans, Matrix_xSym, CPLXSXP, a->nnz)), */ 00562 /* (complex *) a->x, a->nz); */ 00563 if (uploT) { /* slots for triangularMatrix */ 00564 if (a->stype) error(_("Symmetric and triangular both set")); 00565 SET_SLOT(ans, Matrix_uploSym, mkString((uploT > 0) ? "U" : "L")); 00566 SET_SLOT(ans, Matrix_diagSym, mkString(diag)); 00567 } 00568 /* set symmetry attributes */ 00569 if (a->stype) 00570 SET_SLOT(ans, Matrix_uploSym, 00571 mkString((a->stype > 0) ? "U" : "L")); 00572 if (dofree > 0) cholmod_free_triplet(&a, &c); 00573 if (dofree < 0) Free(a); 00574 if (dn != R_NilValue) 00575 SET_SLOT(ans, Matrix_DimNamesSym, duplicate(dn)); 00576 UNPROTECT(2); 00577 return ans; 00578 } 00579 00593 CHM_DN as_cholmod_dense(CHM_DN ans, SEXP x) 00594 { 00595 #define _AS_cholmod_dense_1 \ 00596 static const char *valid[] = { MATRIX_VALID_dense, ""}; \ 00597 int dims[2], ctype = Matrix_check_class_etc(x, valid), nprot = 0; \ 00598 \ 00599 if (ctype < 0) { /* not a classed matrix */ \ 00600 if (isMatrix(x)) Memcpy(dims, INTEGER(getAttrib(x, R_DimSymbol)), 2); \ 00601 else {dims[0] = LENGTH(x); dims[1] = 1;} \ 00602 if (isInteger(x)) { \ 00603 x = PROTECT(coerceVector(x, REALSXP)); \ 00604 nprot++; \ 00605 } \ 00606 ctype = (isReal(x) ? 0 : \ 00607 (isLogical(x) ? 2 : /* logical -> default to "l", not "n" */ \ 00608 (isComplex(x) ? 6 : -1))); \ 00609 } else Memcpy(dims, INTEGER(GET_SLOT(x, Matrix_DimSym)), 2); \ 00610 if (ctype < 0) error(_("invalid class of object to as_cholmod_dense")); \ 00611 memset(ans, 0, sizeof(cholmod_dense)); /* zero the struct */ \ 00612 \ 00613 ans->dtype = CHOLMOD_DOUBLE; /* characteristics of the system */ \ 00614 ans->x = ans->z = (void *) NULL; \ 00615 /* dimensions and nzmax */ \ 00616 ans->d = ans->nrow = dims[0]; \ 00617 ans->ncol = dims[1]; \ 00618 ans->nzmax = dims[0] * dims[1]; \ 00619 /* set the xtype and any elements */ \ 00620 switch(ctype / 2) { \ 00621 case 0: /* "d" */ \ 00622 ans->xtype = CHOLMOD_REAL; \ 00623 ans->x = (void *) REAL((ctype % 2) ? GET_SLOT(x, Matrix_xSym) : x); \ 00624 break 00625 00626 _AS_cholmod_dense_1; 00627 00628 case 1: /* "l" */ 00629 ans->xtype = CHOLMOD_REAL; 00630 ans->x = RallocedREAL((ctype % 2) ? GET_SLOT(x, Matrix_xSym) : x); 00631 break; 00632 case 2: /* "n" */ 00633 ans->xtype = CHOLMOD_PATTERN; 00634 ans->x = (void *) LOGICAL((ctype % 2) ? GET_SLOT(x, Matrix_xSym) : x); 00635 break; 00636 00637 #define _AS_cholmod_dense_2 \ 00638 case 3: /* "z" */ \ 00639 ans->xtype = CHOLMOD_COMPLEX; \ 00640 ans->x = (void *) COMPLEX((ctype % 2) ? GET_SLOT(x, Matrix_xSym) : x); \ 00641 break; \ 00642 } \ 00643 UNPROTECT(nprot); \ 00644 return ans 00645 00646 _AS_cholmod_dense_2; 00647 } 00648 00649 /* version of as_cholmod_dense() that produces a cholmod_dense matrix 00650 * with REAL 'x' slot -- i.e. treats "nMatrix" as "lMatrix" -- as only difference; 00651 * Not just via a flag in as_cholmod_dense() since that has fixed API */ 00652 CHM_DN as_cholmod_x_dense(cholmod_dense *ans, SEXP x) 00653 { 00654 _AS_cholmod_dense_1; 00655 00656 case 1: /* "l" */ 00657 case 2: /* "n" (no NA in 'x', but *has* 'x' slot => treat as "l" */ 00658 ans->xtype = CHOLMOD_REAL; 00659 ans->x = RallocedREAL((ctype % 2) ? GET_SLOT(x, Matrix_xSym) : x); 00660 break; 00661 00662 _AS_cholmod_dense_2; 00663 } 00664 00665 #undef _AS_cholmod_dense_1 00666 #undef _AS_cholmod_dense_2 00667 00668 void R_cholmod_error(int status, const char *file, int line, const char *message) 00669 { 00670 CHM_restore_common(); /* restore any setting that may have been changed */ 00671 00672 /* NB: keep in sync with M_R_cholmod_error(), ../inst/include/Matrix_stubs.c */ 00673 00674 /* From CHOLMOD/Include/cholmod_core.h : ...status values. 00675 zero means success, negative means a fatal error, positive is a warning. 00676 */ 00677 #ifndef R_CHOLMOD_ALWAYS_ERROR 00678 if(status < 0) { 00679 #endif 00680 error(_("Cholmod error '%s' at file %s, line %d"), message, file, line); 00681 #ifndef R_CHOLMOD_ALWAYS_ERROR 00682 } 00683 else 00684 warning(_("Cholmod warning '%s' at file %s, line %d"), 00685 message, file, line); 00686 #endif 00687 } 00688 00689 /* just to get 'int' instead of 'void' as required by CHOLMOD's print_function */ 00690 static 00691 int R_cholmod_printf(const char* fmt, ...) 00692 { 00693 va_list(ap); 00694 00695 va_start(ap, fmt); 00696 Rprintf((char *)fmt, ap); 00697 va_end(ap); 00698 return 0; 00699 } 00700 00709 int R_cholmod_start(CHM_CM c) 00710 { 00711 int res; 00712 if (!(res = cholmod_start(c))) 00713 error(_("Unable to initialize cholmod: error code %d"), res); 00714 c->print_function = R_cholmod_printf; /* Rprintf gives warning */ 00715 /* Since we provide an error handler, it may not be a good idea to allow CHOLMOD printing, 00716 * because that's not easily suppressed on the R level : 00717 * Hence consider, at least temporarily * c->print_function = NULL; */ 00718 c->error_handler = R_cholmod_error; 00719 return TRUE; 00720 } 00721 00734 /* FIXME: should also have args (int uploST, char *diag) */ 00735 00736 SEXP chm_dense_to_SEXP(CHM_DN a, int dofree, int Rkind, SEXP dn) 00737 { 00738 SEXP ans; 00739 char *cl = ""; /* -Wall */ 00740 int *dims, ntot; 00741 00742 PROTECT(dn); /* << (why? -- just cut&paste from chm_dense_to_mat.. below*/ 00743 00744 switch(a->xtype) { /* determine the class of the result */ 00745 /* CHOLMOD_PATTERN never happens because cholmod_dense can't : 00746 * case CHOLMOD_PATTERN: 00747 * cl = "ngeMatrix"; break; 00748 */ 00749 case CHOLMOD_REAL: 00750 switch(Rkind) { /* -1: special for this function! */ 00751 case -1: cl = "ngeMatrix"; break; 00752 case 0: cl = "dgeMatrix"; break; 00753 case 1: cl = "lgeMatrix"; break; 00754 default: error(_("unknown 'Rkind'")); 00755 } 00756 break; 00757 case CHOLMOD_COMPLEX: 00758 cl = "zgeMatrix"; break; 00759 default: 00760 error(_("unknown xtype")); 00761 } 00762 00763 ans = PROTECT(NEW_OBJECT(MAKE_CLASS(cl))); 00764 /* allocate and copy common slots */ 00765 dims = INTEGER(ALLOC_SLOT(ans, Matrix_DimSym, INTSXP, 2)); 00766 dims[0] = a->nrow; dims[1] = a->ncol; 00767 ntot = dims[0] * dims[1]; 00768 if (a->d == a->nrow) { /* copy data slot -- always present in dense(!) */ 00769 if (a->xtype == CHOLMOD_REAL) { 00770 int i, *m_x; 00771 double *a_x = (double *) a->x; 00772 switch(Rkind) { 00773 case 0: 00774 Memcpy(REAL(ALLOC_SLOT(ans, Matrix_xSym, REALSXP, ntot)), 00775 a_x, ntot); 00776 break; 00777 case -1: /* nge*/ 00778 case 1: /* lge*/ 00779 m_x = LOGICAL(ALLOC_SLOT(ans, Matrix_xSym, LGLSXP, ntot)); 00780 for (i=0; i < ntot; i++) 00781 m_x[i] = ISNAN(a_x[i]) ? NA_LOGICAL : (a_x[i] != 0); 00782 break; 00783 } 00784 } 00785 else if (a->xtype == CHOLMOD_COMPLEX) 00786 error(_("complex sparse matrix code not yet written")); 00787 /* Memcpy(COMPLEX(ALLOC_SLOT(ans, Matrix_xSym, CPLXSXP, ntot)), */ 00788 /* (complex *) a->x, ntot); */ 00789 } else error(_("code for cholmod_dense with holes not yet written")); 00790 00791 if (dofree > 0) cholmod_free_dense(&a, &c); 00792 if (dofree < 0) Free(a); 00793 if (dn != R_NilValue) 00794 SET_SLOT(ans, Matrix_DimNamesSym, duplicate(dn)); 00795 UNPROTECT(2); 00796 return ans; 00797 } 00798 00809 SEXP chm_dense_to_matrix(CHM_DN a, int dofree, SEXP dn) 00810 { 00811 SEXP ans; 00812 SEXPTYPE typ; 00813 00814 PROTECT(dn); 00815 /* determine the class of the result */ 00816 typ = (a->xtype == CHOLMOD_PATTERN) ? LGLSXP : 00817 ((a->xtype == CHOLMOD_REAL) ? REALSXP : 00818 ((a->xtype == CHOLMOD_COMPLEX) ? CPLXSXP : NILSXP)); 00819 if (typ == NILSXP) error(_("unknown xtype")); 00820 00821 ans = PROTECT(allocMatrix(typ, a->nrow, a->ncol)); 00822 if (a->d == a->nrow) { /* copy data slot if present */ 00823 if (a->xtype == CHOLMOD_REAL) 00824 Memcpy(REAL(ans), (double *) a->x, a->nrow * a->ncol); 00825 else if (a->xtype == CHOLMOD_COMPLEX) 00826 error(_("complex sparse matrix code not yet written")); 00827 else if (a->xtype == CHOLMOD_PATTERN) 00828 error(_("don't know if a dense pattern matrix makes sense")); 00829 /* Memcpy(COMPLEX(ALLOC_SLOT(ans, Matrix_xSym, CPLXSXP, a->nnz)), */ 00830 /* (complex *) a->x, a->nz); */ 00831 } else error(_("code for cholmod_dense with holes not yet written")); 00832 00833 if (dofree > 0) cholmod_free_dense(&a, &c); 00834 if (dofree < 0) Free(a); 00835 if (dn != R_NilValue) 00836 setAttrib(ans, R_DimNamesSymbol, duplicate(dn)); 00837 UNPROTECT(2); 00838 return ans; 00839 } 00840 00841 CHM_DN numeric_as_chm_dense(CHM_DN ans, double *v, int nr, int nc) 00842 { 00843 ans->d = ans->nrow = nr; 00844 ans->ncol = nc; 00845 ans->nzmax = nr * nc; 00846 ans->x = (void *) v; 00847 ans->xtype = CHOLMOD_REAL; 00848 ans->dtype = CHOLMOD_DOUBLE; 00849 return ans; 00850 } 00851 00865 CHM_FR as_cholmod_factor(CHM_FR ans, SEXP x) 00866 { 00867 static const char *valid[] = { MATRIX_VALID_CHMfactor, ""}; 00868 int *type = INTEGER(GET_SLOT(x, install("type"))), 00869 ctype = Matrix_check_class_etc(x, valid); 00870 SEXP tmp; 00871 00872 if (ctype < 0) error(_("invalid class of object to as_cholmod_factor")); 00873 memset(ans, 0, sizeof(cholmod_factor)); /* zero the struct */ 00874 00875 ans->itype = CHOLMOD_INT; /* characteristics of the system */ 00876 ans->dtype = CHOLMOD_DOUBLE; 00877 ans->z = (void *) NULL; 00878 ans->xtype = (ctype < 2) ? CHOLMOD_REAL : CHOLMOD_PATTERN; 00879 00880 ans->ordering = type[0]; /* unravel the type */ 00881 ans->is_ll = (type[1] ? 1 : 0); 00882 ans->is_super = (type[2] ? 1 : 0); 00883 ans->is_monotonic = (type[3] ? 1 : 0); 00884 /* check for consistency */ 00885 if ((!(ans->is_ll)) && ans->is_super) 00886 error(_("Supernodal LDL' decomposition not available")); 00887 if ((!type[2]) ^ (ctype % 2)) 00888 error(_("Supernodal/simplicial class inconsistent with type flags")); 00889 /* slots always present */ 00890 tmp = GET_SLOT(x, Matrix_permSym); 00891 ans->minor = ans->n = LENGTH(tmp); ans->Perm = INTEGER(tmp); 00892 ans->ColCount = INTEGER(GET_SLOT(x, install("colcount"))); 00893 ans->z = ans->x = (void *) NULL; 00894 if (ctype < 2) { 00895 tmp = GET_SLOT(x, Matrix_xSym); 00896 ans->x = REAL(tmp); 00897 } 00898 if (ans->is_super) { /* supernodal factorization */ 00899 ans->xsize = LENGTH(tmp); 00900 ans->maxcsize = type[4]; ans->maxesize = type[5]; 00901 ans->i = (int*)NULL; 00902 tmp = GET_SLOT(x, install("super")); 00903 ans->nsuper = LENGTH(tmp) - 1; ans->super = INTEGER(tmp); 00904 /* Move these checks to the CHMfactor_validate function */ 00905 if (ans->nsuper < 1) 00906 error(_("Number of supernodes must be positive when is_super is TRUE")); 00907 tmp = GET_SLOT(x, install("pi")); 00908 if (LENGTH(tmp) != ans->nsuper + 1) 00909 error(_("Lengths of super and pi must be equal")); 00910 ans->pi = INTEGER(tmp); 00911 tmp = GET_SLOT(x, install("px")); 00912 if (LENGTH(tmp) != ans->nsuper + 1) 00913 error(_("Lengths of super and px must be equal")); 00914 ans->px = INTEGER(tmp); 00915 tmp = GET_SLOT(x, install("s")); 00916 ans->ssize = LENGTH(tmp); ans->s = INTEGER(tmp); 00917 } else { 00918 ans->nzmax = LENGTH(tmp); 00919 ans->p = INTEGER(GET_SLOT(x, Matrix_pSym)); 00920 ans->i = INTEGER(GET_SLOT(x, Matrix_iSym)); 00921 ans->nz = INTEGER(GET_SLOT(x, install("nz"))); 00922 ans->next = INTEGER(GET_SLOT(x, install("nxt"))); 00923 ans->prev = INTEGER(GET_SLOT(x, install("prv"))); 00924 } 00925 if (!cholmod_check_factor(ans, &c)) 00926 error(_("failure in as_cholmod_factor")); 00927 return ans; 00928 } 00929 00930 00940 SEXP chm_factor_to_SEXP(CHM_FR f, int dofree) 00941 { 00942 SEXP ans; 00943 int *dims, *type; 00944 char *class = (char*) NULL; /* -Wall */ 00945 00946 if(!chm_factor_ok(f)) 00947 error(_("previous CHOLMOD factorization was unsuccessful")); 00948 00949 switch(f->xtype) { 00950 case CHOLMOD_REAL: 00951 class = f->is_super ? "dCHMsuper" : "dCHMsimpl"; 00952 break; 00953 case CHOLMOD_PATTERN: 00954 class = f->is_super ? "nCHMsuper" : "nCHMsimpl"; 00955 break; 00956 default: 00957 error(_("f->xtype of %d not recognized"), f->xtype); 00958 } 00959 if(!chm_factor_ok(f)) 00960 error(_("CHOLMOD factorization was unsuccessful")); 00961 00962 ans = PROTECT(NEW_OBJECT(MAKE_CLASS(class))); 00963 dims = INTEGER(ALLOC_SLOT(ans, Matrix_DimSym, INTSXP, 2)); 00964 dims[0] = dims[1] = f->n; 00965 /* copy component of known length */ 00966 Memcpy(INTEGER(ALLOC_SLOT(ans, Matrix_permSym, INTSXP, f->n)), 00967 (int*)f->Perm, f->n); 00968 Memcpy(INTEGER(ALLOC_SLOT(ans, install("colcount"), INTSXP, f->n)), 00969 (int*)f->ColCount, f->n); 00970 type = INTEGER(ALLOC_SLOT(ans, install("type"), INTSXP, f->is_super ? 6 : 4)); 00971 type[0] = f->ordering; type[1] = f->is_ll; 00972 type[2] = f->is_super; type[3] = f->is_monotonic; 00973 if (f->is_super) { 00974 type[4] = f->maxcsize; type[5] = f->maxesize; 00975 Memcpy(INTEGER(ALLOC_SLOT(ans, install("super"), INTSXP, f->nsuper + 1)), 00976 (int*)f->super, f->nsuper+1); 00977 Memcpy(INTEGER(ALLOC_SLOT(ans, install("pi"), INTSXP, f->nsuper + 1)), 00978 (int*)f->pi, f->nsuper + 1); 00979 Memcpy(INTEGER(ALLOC_SLOT(ans, install("px"), INTSXP, f->nsuper + 1)), 00980 (int*)f->px, f->nsuper + 1); 00981 Memcpy(INTEGER(ALLOC_SLOT(ans, install("s"), INTSXP, f->ssize)), 00982 (int*)f->s, f->ssize); 00983 Memcpy(REAL(ALLOC_SLOT(ans, Matrix_xSym, REALSXP, f->xsize)), 00984 (double*)f->x, f->xsize); 00985 } else { 00986 Memcpy(INTEGER(ALLOC_SLOT(ans, Matrix_iSym, INTSXP, f->nzmax)), 00987 (int*)f->i, f->nzmax); 00988 Memcpy(INTEGER(ALLOC_SLOT(ans, Matrix_pSym, INTSXP, f->n + 1)), 00989 (int*)f->p, f->n + 1); 00990 Memcpy(REAL(ALLOC_SLOT(ans, Matrix_xSym, REALSXP, f->nzmax)), 00991 (double*)f->x, f->nzmax); 00992 Memcpy(INTEGER(ALLOC_SLOT(ans, install("nz"), INTSXP, f->n)), 00993 (int*)f->nz, f->n); 00994 Memcpy(INTEGER(ALLOC_SLOT(ans, install("nxt"), INTSXP, f->n + 2)), 00995 (int*)f->next, f->n + 2); 00996 Memcpy(INTEGER(ALLOC_SLOT(ans, install("prv"), INTSXP, f->n + 2)), 00997 (int*)f->prev, f->n + 2); 00998 00999 } 01000 if(dofree) { 01001 if (dofree > 0) cholmod_free_factor(&f, &c); 01002 else /* dofree < 0 */ Free(f); 01003 } 01004 UNPROTECT(1); 01005 return ans; 01006 } 01007 01019 void chm_diagN2U(CHM_SP chx, int uploT, Rboolean do_realloc) 01020 { 01021 int i, n = chx->nrow, nnz = (int)cholmod_nnz(chx, &c), 01022 n_nnz = nnz - n, /* the new nnz : we will have removed n entries */ 01023 i_to = 0, i_from = 0; 01024 01025 if(chx->ncol != n) 01026 error(_("chm_diagN2U(<non-square matrix>): nrow=%d, ncol=%d"), 01027 n, chx->ncol); 01028 01029 if (!chx->sorted || !chx->packed) cholmod_sort(chx, &c); 01030 /* dimensions and nzmax */ 01031 01032 #define _i(I) ( (int*) chx->i)[I] 01033 #define _x(I) ((double*) chx->x)[I] 01034 #define _p(I) ( (int*) chx->p)[I] 01035 01036 /* work by copying from i_from to i_to ==> MUST i_to <= i_from */ 01037 01038 if(uploT == 1) { /* "U" : upper triangular */ 01039 01040 for(i = 0; i < n; i++) { /* looking at i-th column */ 01041 int j, n_i = _p(i+1) - _p(i); /* = #{entries} in this column */ 01042 01043 /* 1) copy all but the last _above-diagonal_ column-entries: */ 01044 for(j = 1; j < n_i; j++, i_to++, i_from++) { 01045 _i(i_to) = _i(i_from); 01046 _x(i_to) = _x(i_from); 01047 } 01048 01049 /* 2) drop the last column-entry == diagonal entry */ 01050 i_from++; 01051 } 01052 } 01053 else if(uploT == -1) { /* "L" : lower triangular */ 01054 01055 for(i = 0; i < n; i++) { /* looking at i-th column */ 01056 int j, n_i = _p(i+1) - _p(i); /* = #{entries} in this column */ 01057 01058 /* 1) drop the first column-entry == diagonal entry */ 01059 i_from++; 01060 01061 /* 2) copy the other _below-diagonal_ column-entries: */ 01062 for(j = 1; j < n_i; j++, i_to++, i_from++) { 01063 _i(i_to) = _i(i_from); 01064 _x(i_to) = _x(i_from); 01065 } 01066 } 01067 } 01068 else { 01069 error(_("chm_diagN2U(x, uploT = %d): uploT should be +- 1"), uploT); 01070 } 01071 01072 /* the column pointers are modified the same in both cases :*/ 01073 for(i=1; i <= n; i++) 01074 _p(i) -= i; 01075 01076 #undef _i 01077 #undef _x 01078 #undef _p 01079 01080 if(do_realloc) /* shorten (i- and x-slots from nnz to n_nnz */ 01081 cholmod_reallocate_sparse(n_nnz, chx, &c); 01082 return; 01083 } 01084 01085 /* Placeholders; TODO: use checks above (search "CHMfactor_validate"): */ 01086 01087 SEXP CHMfactor_validate(SEXP obj) /* placeholder */ 01088 { 01089 return ScalarLogical(1); 01090 } 01091 01092 SEXP CHMsimpl_validate(SEXP obj) /* placeholder */ 01093 { 01094 return ScalarLogical(1); 01095 } 01096 01097 SEXP CHMsuper_validate(SEXP obj) /* placeholder */ 01098 { 01099 return ScalarLogical(1); 01100 } 01101