Matrix $Rev: 2718 $ at $LastChangedDate: 2011-10-06 11:45:17 +0200 (Thu, 06 Oct 2011) $
chm_common.c
Go to the documentation of this file.
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