Matrix $Rev: 2718 $ at $LastChangedDate: 2011-10-06 11:45:17 +0200 (Thu, 06 Oct 2011) $
Mutils.c
Go to the documentation of this file.
00001 #include <limits.h>
00002 
00003 #include "Mutils.h"
00004 #include <R_ext/Lapack.h>
00005 
00006 #if 0 /* defined(R_VERSION) && R_VERSION >= R_Version(2, 7, 0) *
00007        * La_norm_type() & La_rcond_type() are now in R_ext/Lapack.h
00008        * but because of the 'module-mess' that's not sufficient */
00009 #else
00010 char La_norm_type(const char *typstr)
00011 {
00012     char typup;
00013 
00014     if (strlen(typstr) != 1)
00015         error(
00016             _("argument type[1]='%s' must be a one-letter character string"),
00017             typstr);
00018     typup = toupper(*typstr);
00019     if (typup == '1')
00020         typup = 'O'; /* alias */
00021     else if (typup == 'E')
00022         typup = 'F';
00023     else if (typup != 'M' && typup != 'O' && typup != 'I' && typup != 'F')
00024         error(_("argument type[1]='%s' must be one of 'M','1','O','I','F' or 'E'"),
00025               typstr);
00026     return typup;
00027 }
00028 
00029 char La_rcond_type(const char *typstr)
00030 {
00031     char typup;
00032 
00033     if (strlen(typstr) != 1)
00034         error(
00035             _("argument type[1]='%s' must be a one-letter character string"),
00036             typstr);
00037     typup = toupper(*typstr);
00038     if (typup == '1')
00039         typup = 'O'; /* alias */
00040     else if (typup != 'O' && typup != 'I')
00041         error(_("argument type[1]='%s' must be one of '1','O', or 'I'"),
00042               typstr);
00043     return typup;
00044 }
00045 #endif
00046 
00047 double get_double_by_name(SEXP obj, char *nm)
00048 {
00049     SEXP nms = getAttrib(obj, R_NamesSymbol);
00050     int i, len = length(obj);
00051 
00052     if ((!isReal(obj)) || (length(obj) > 0 && nms == R_NilValue))
00053         error(_("object must be a named, numeric vector"));
00054     for (i = 0; i < len; i++) {
00055         if (!strcmp(nm, CHAR(STRING_ELT(nms, i)))) {
00056             return REAL(obj)[i];
00057         }
00058     }
00059     return R_NaReal;
00060 }
00061 
00062 SEXP
00063 set_double_by_name(SEXP obj, double val, char *nm)
00064 {
00065     SEXP nms = getAttrib(obj, R_NamesSymbol);
00066     int i, len = length(obj);
00067 
00068     if ((!isReal(obj)) || (length(obj) > 0 && nms == R_NilValue))
00069         error(_("object must be a named, numeric vector"));
00070     for (i = 0; i < len; i++) {
00071         if (!strcmp(nm, CHAR(STRING_ELT(nms, i)))) {
00072             REAL(obj)[i] = val;
00073             return obj;
00074         }
00075     }
00076     {
00077         SEXP nx = PROTECT(allocVector(REALSXP, len + 1)),
00078             nnms = allocVector(STRSXP, len + 1);
00079 
00080         setAttrib(nx, R_NamesSymbol, nnms);
00081         for (i = 0; i < len; i++) {
00082             REAL(nx)[i] = REAL(obj)[i];
00083             SET_STRING_ELT(nnms, i, duplicate(STRING_ELT(nms, i)));
00084         }
00085         REAL(nx)[len] = val;
00086         SET_STRING_ELT(nnms, len, mkChar(nm));
00087         UNPROTECT(1);
00088         return nx;
00089     }
00090 }
00091 
00092 SEXP as_det_obj(double val, int log, int sign)
00093 {
00094     SEXP det = PROTECT(allocVector(VECSXP, 2)),
00095         nms = PROTECT(allocVector(STRSXP, 2)),
00096         vv = PROTECT(ScalarReal(val));
00097 
00098     setAttrib(det, R_NamesSymbol, nms);
00099     SET_STRING_ELT(nms, 0, mkChar("modulus"));
00100     SET_STRING_ELT(nms, 1, mkChar("sign"));
00101     setAttrib(vv, install("logarithm"), ScalarLogical(log));
00102     SET_VECTOR_ELT(det, 0, vv);
00103     SET_VECTOR_ELT(det, 1, ScalarInteger(sign));
00104     setAttrib(det, R_ClassSymbol, mkString("det"));
00105     UNPROTECT(3);
00106     return det;
00107 }
00108 
00109 SEXP get_factors(SEXP obj, char *nm)
00110 {
00111     SEXP fac = GET_SLOT(obj, Matrix_factorSym),
00112         nms = getAttrib(fac, R_NamesSymbol);
00113     int i, len = length(fac);
00114 
00115     if ((!isNewList(fac)) || (length(fac) > 0 && nms == R_NilValue))
00116         error(_("'factors' slot must be a named list"));
00117     for (i = 0; i < len; i++) {
00118         if (!strcmp(nm, CHAR(STRING_ELT(nms, i)))) {
00119             return VECTOR_ELT(fac, i);
00120         }
00121     }
00122     return R_NilValue;
00123 }
00124 
00125 /* In the past this function installed a duplicate of val in the
00126  * factors slot for obj then returned the (typically unprotected)
00127  * val.  This is now changed to return the duplicate, which will be
00128  * protected if obj is protected. */
00129 SEXP set_factors(SEXP obj, SEXP val, char *nm)
00130 {
00131     SEXP fac = GET_SLOT(obj, Matrix_factorSym),
00132         nms = getAttrib(fac, R_NamesSymbol), nfac, nnms;
00133     int i, len = length(fac);
00134 
00135     if ((!isNewList(fac)) || (length(fac) > 0 && nms == R_NilValue))
00136         error(_("'factors' slot must be a named list"));
00137     PROTECT(val); /* set_factors(..) may be called as "finalizer" after UNPROTECT()*/
00138     for (i = 0; i < len; i++) {
00139         if (!strcmp(nm, CHAR(STRING_ELT(nms, i)))) {
00140             SET_VECTOR_ELT(fac, i, duplicate(val));
00141             return val;
00142         }
00143     }
00144     nfac = PROTECT(allocVector(VECSXP, len + 1));
00145     nnms = PROTECT(allocVector(STRSXP, len + 1));
00146     setAttrib(nfac, R_NamesSymbol, nnms);
00147     for (i = 0; i < len; i++) {
00148         SET_VECTOR_ELT(nfac, i, VECTOR_ELT(fac, i));
00149         SET_STRING_ELT(nnms, i, duplicate(STRING_ELT(nms, i)));
00150     }
00151     SET_VECTOR_ELT(nfac, len, duplicate(val));
00152     SET_STRING_ELT(nnms, len, mkChar(nm));
00153     SET_SLOT(obj, Matrix_factorSym, nfac);
00154     UNPROTECT(3);
00155     return VECTOR_ELT(nfac, len);
00156 }
00157 
00158 #if 0                           /* unused */
00159 /* useful for all the ..CMatrix classes (and ..R by [0] <-> [1]); but unused */
00160 SEXP CMatrix_set_Dim(SEXP x, int nrow)
00161 {
00162     int *dims = INTEGER(GET_SLOT(x, Matrix_DimSym));
00163 
00164     dims[0] = nrow;
00165     dims[1] = length(GET_SLOT(x, Matrix_pSym)) - 1;
00166     return x;
00167 }
00168 #endif  /* unused */
00169 
00170 /* Fill in the "trivial remainder" in  n*m  array ;
00171  *  typically the 'x' slot of a "dtrMatrix" :
00172  * But should be usable for double/logical/int/complex : */
00173 
00174 #define MAKE_TRIANGULAR_BODY(_TO_, _FROM_, _ZERO_, _ONE_)       \
00175 {                                                               \
00176     int i, j, *dims = INTEGER(GET_SLOT(_FROM_, Matrix_DimSym)); \
00177     int n = dims[0], m = dims[1];                               \
00178                                                                 \
00179     if (*uplo_P(_FROM_) == 'U') {                               \
00180         for (j = 0; j < n; j++)                                 \
00181             for (i = j+1; i < m; i++)                           \
00182                 _TO_[i + j*m] = _ZERO_;                         \
00183     } else {                                                    \
00184         for (j = 1; j < n; j++)                                 \
00185             for (i = 0; i < j && i < m; i++)                    \
00186                 _TO_[i + j*m] = _ZERO_;                         \
00187     }                                                           \
00188     if (*diag_P(_FROM_) == 'U') {                               \
00189         j = (n < m) ? n : m;                                    \
00190         for (i = 0; i < j; i++)                                 \
00191             _TO_[i * (m + 1)] = _ONE_;                          \
00192     }                                                           \
00193 }
00194 
00195 void make_d_matrix_triangular(double *to, SEXP from)
00196     MAKE_TRIANGULAR_BODY(to, from, 0., 1.)
00197 void make_i_matrix_triangular(int *to, SEXP from)
00198     MAKE_TRIANGULAR_BODY(to, from, 0, 1)
00199 
00200 
00201 /* Should work for double/logical/int/complex : */
00202 #define MAKE_SYMMETRIC_BODY(_TO_, _FROM_)                       \
00203 {                                                               \
00204     int i, j, n = INTEGER(GET_SLOT(_FROM_, Matrix_DimSym))[0];  \
00205                                                                 \
00206     if (*uplo_P(_FROM_) == 'U') {                               \
00207         for (j = 0; j < n; j++)                                 \
00208             for (i = j+1; i < n; i++)                           \
00209                 _TO_[i + j*n] = _TO_[j + i*n];                  \
00210     } else {                                                    \
00211         for (j = 1; j < n; j++)                                 \
00212             for (i = 0; i < j && i < n; i++)                    \
00213                 _TO_[i + j*n] = _TO_[j + i*n];                  \
00214     }                                                           \
00215 }
00216 
00217 void make_d_matrix_symmetric(double *to, SEXP from)
00218     MAKE_SYMMETRIC_BODY(to, from)
00219 
00220 void make_i_matrix_symmetric(int *to, SEXP from)
00221     MAKE_SYMMETRIC_BODY(to, from)
00222 
00223 
00224 #define Matrix_Error_Bufsiz    4096
00225 
00236 SEXP check_scalar_string(SEXP sP, char *vals, char *nm)
00237 {
00238     SEXP val = ScalarLogical(1);
00239     char *buf;
00240     /* only allocate when needed: in good case, none is needed */
00241 #define SPRINTF buf = Alloca(Matrix_Error_Bufsiz, char); R_CheckStack(); sprintf
00242 
00243     if (length(sP) != 1) {
00244         SPRINTF(buf, _("'%s' slot must have length 1"), nm);
00245     } else {
00246         const char *str = CHAR(STRING_ELT(sP, 0));
00247         if (strlen(str) != 1) {
00248             SPRINTF(buf, _("'%s' must have string length 1"), nm);
00249         } else {
00250             int i, len;
00251             for (i = 0, len = strlen(vals); i < len; i++) {
00252                 if (str[0] == vals[i])
00253                     return R_NilValue;
00254             }
00255             SPRINTF(buf, _("'%s' must be in '%s'"), nm, vals);
00256         }
00257     }
00258     /* 'error' returns : */
00259     val = mkString(buf);
00260     return val;
00261 #undef SPRINTF
00262 }
00263 
00264 /* FIXME? Something like this should be part of the R API ?
00265  *        But then, R has the more general  compute_identical()
00266  * in src/main/identical.c: Rboolean compute_identical(SEXP x, SEXP y);
00267 */
00268 Rboolean equal_string_vectors(SEXP s1, SEXP s2)
00269 {
00270     Rboolean n1 = isNull(s1), n2 = isNull(s2);
00271     if (n1 || n2)
00272         return (n1 == n2) ? TRUE : FALSE;
00273     else if (TYPEOF(s1) != STRSXP || TYPEOF(s2) != STRSXP) {
00274         error(_("'s1' and 's2' must be \"character\" vectors"));
00275         return FALSE; /* -Wall */
00276     } else {
00277         int n = LENGTH(s1), i;
00278         if (n != LENGTH(s2))
00279             return FALSE;
00280         for(i = 0; i < n; i++) {
00281             /* note that compute_identical() code for STRSXP
00282                is careful about NA's which we don't need */
00283             if(strcmp(CHAR(STRING_ELT(s1, i)),
00284                       CHAR(STRING_ELT(s2, i))))
00285                 return FALSE;
00286         }
00287         return TRUE; /* they *are* equal */
00288     }
00289 }
00290 
00291 
00292 SEXP dense_nonpacked_validate(SEXP obj)
00293 {
00294     int *dims = INTEGER(GET_SLOT(obj, Matrix_DimSym));
00295     if ((dims[0] * dims[1]) != length(GET_SLOT(obj, Matrix_xSym)))
00296         return mkString(_("length of x slot != prod(Dim)"));
00297     return ScalarLogical(1);
00298 }
00299 
00300 
00301 #define PACKED_TO_FULL(TYPE)                                            \
00302 TYPE *packed_to_full_ ## TYPE(TYPE *dest, const TYPE *src,              \
00303                         int n, enum CBLAS_UPLO uplo)                    \
00304 {                                                                       \
00305     int i, j, pos = 0;                                                  \
00306                                                                         \
00307     AZERO(dest, n*n);                                                   \
00308     for (j = 0; j < n; j++) {                                           \
00309         switch(uplo) {                                                  \
00310         case UPP:                                                       \
00311             for (i = 0; i <= j; i++) dest[i + j * n] = src[pos++];      \
00312             break;                                                      \
00313         case LOW:                                                       \
00314             for (i = j; i < n; i++) dest[i + j * n] = src[pos++];       \
00315             break;                                                      \
00316         default:                                                        \
00317             error(_("'uplo' must be UPP or LOW"));                      \
00318         }                                                               \
00319     }                                                                   \
00320     return dest;                                                        \
00321 }
00322 
00323 PACKED_TO_FULL(double)
00324 PACKED_TO_FULL(int)
00325 
00326 #define FULL_TO_PACKED(TYPE)                                            \
00327 TYPE *full_to_packed_ ## TYPE(TYPE *dest, const TYPE *src, int n,       \
00328                       enum CBLAS_UPLO uplo, enum CBLAS_DIAG diag)       \
00329 {                                                                       \
00330     int i, j, pos = 0;                                                  \
00331                                                                         \
00332     for (j = 0; j < n; j++) {                                           \
00333         switch(uplo) {                                                  \
00334         case UPP:                                                       \
00335             for (i = 0; i <= j; i++)                                    \
00336                 dest[pos++] = (i == j && diag== UNT) ? 1 : src[i + j*n]; \
00337             break;                                                      \
00338         case LOW:                                                       \
00339             for (i = j; i < n; i++)                                     \
00340                 dest[pos++] = (i == j && diag== UNT) ? 1 : src[i + j*n]; \
00341             break;                                                      \
00342         default:                                                        \
00343             error(_("'uplo' must be UPP or LOW"));                      \
00344         }                                                               \
00345     }                                                                   \
00346     return dest;                                                        \
00347 }
00348 
00349 FULL_TO_PACKED(double)
00350 FULL_TO_PACKED(int)
00351 
00352 
00353 
00363 void d_packed_getDiag(double *dest, SEXP x, int n)
00364 {
00365     double *xx = REAL(GET_SLOT(x, Matrix_xSym));
00366 
00367 #define END_packed_getDiag                                              \
00368     int j, pos = 0;                                                     \
00369                                                                         \
00370     if (*uplo_P(x) == 'U') {                                            \
00371         for(pos= 0, j=0; j < n; pos += 1+(++j))  dest[j] = xx[pos];     \
00372     } else {                                                            \
00373         for(pos= 0, j=0; j < n; pos += (n - j), j++) dest[j] = xx[pos]; \
00374     }                                                                   \
00375     return
00376 
00377     END_packed_getDiag;
00378 }
00379 
00380 void l_packed_getDiag(int *dest, SEXP x, int n)
00381 {
00382     int *xx = LOGICAL(GET_SLOT(x, Matrix_xSym));
00383 
00384     END_packed_getDiag;
00385 }
00386 
00387 #undef END_packed_getDiag
00388 
00389 void tr_d_packed_getDiag(double *dest, SEXP x)
00390 {
00391     int n = INTEGER(GET_SLOT(x, Matrix_DimSym))[0];
00392     SEXP val = PROTECT(allocVector(REALSXP, n));
00393     double *v = REAL(val);
00394 
00395     if (*diag_P(x) == 'U') {
00396         int j;
00397         for (j = 0; j < n; j++) v[j] = 1.;
00398     } else {
00399         d_packed_getDiag(v, x, n);
00400     }
00401     UNPROTECT(1);
00402     return;
00403 }
00404 
00405 void tr_l_packed_getDiag(   int *dest, SEXP x)
00406 {
00407     int n = INTEGER(GET_SLOT(x, Matrix_DimSym))[0];
00408     SEXP val = PROTECT(allocVector(LGLSXP, n));
00409     int *v = LOGICAL(val);
00410 
00411     if (*diag_P(x) == 'U') {
00412         int j;
00413         for (j = 0; j < n; j++) v[j] = 1;
00414     } else {
00415         l_packed_getDiag(v, x, n);
00416     }
00417     UNPROTECT(1);
00418     return;
00419 }
00420 
00421 SEXP Matrix_expand_pointers(SEXP pP)
00422 {
00423     int n = length(pP) - 1;
00424     int *p = INTEGER(pP);
00425     SEXP ans = PROTECT(allocVector(INTSXP, p[n]));
00426 
00427     expand_cmprPt(n, p, INTEGER(ans));
00428     UNPROTECT(1);
00429     return ans;
00430 }
00431 
00432 
00441 SEXP
00442 Matrix_getElement(SEXP list, char *nm) {
00443     SEXP names = getAttrib(list, R_NamesSymbol);
00444     int i;
00445 
00446     for (i = 0; i < LENGTH(names); i++)
00447         if (!strcmp(CHAR(STRING_ELT(names, i)), nm))
00448             return(VECTOR_ELT(list, i));
00449     return R_NilValue;
00450 }
00451 
00460 static double *
00461 install_diagonal(double *dest, SEXP A)
00462 {
00463     int nc = INTEGER(GET_SLOT(A, Matrix_DimSym))[0];
00464     int i, ncp1 = nc + 1, unit = *diag_P(A) == 'U';
00465     double *ax = REAL(GET_SLOT(A, Matrix_xSym));
00466 
00467     AZERO(dest, nc * nc);
00468     for (i = 0; i < nc; i++)
00469         dest[i * ncp1] = (unit) ? 1. : ax[i];
00470     return dest;
00471 }
00472 
00473 static int *
00474 install_diagonal_int(int *dest, SEXP A)
00475 {
00476     int nc = INTEGER(GET_SLOT(A, Matrix_DimSym))[0];
00477     int i, ncp1 = nc + 1, unit = *diag_P(A) == 'U';
00478     int *ax = INTEGER(GET_SLOT(A, Matrix_xSym));
00479 
00480     AZERO(dest, nc * nc);
00481     for (i = 0; i < nc; i++)
00482         dest[i * ncp1] = (unit) ? 1 : ax[i];
00483     return dest;
00484 }
00485 
00486 
00494 /* NOTA BENE: If you enlarge this list, do change '14' and '6' below !
00495  * ---------  ddiMatrix & ldiMatrix  are no longer ddense or ldense on the R level,
00496  *            ---         ---        but are still dealt with here.
00497  */
00498 
00499 #define ddense_CLASSES                                                  \
00500                     "dgeMatrix", "dtrMatrix",                           \
00501                     "dsyMatrix", "dpoMatrix", "ddiMatrix",              \
00502                     "dtpMatrix", "dspMatrix", "dppMatrix",              \
00503                     /* sub classes of those above:*/                    \
00504                     /* dtr */ "Cholesky", "LDL", "BunchKaufman",        \
00505                     /* dtp */ "pCholesky", "pBunchKaufman",             \
00506                     /* dpo */ "corMatrix"
00507 
00508 #define ldense_CLASSES                                  \
00509                     "lgeMatrix", "ltrMatrix",           \
00510                     "lsyMatrix", "ldiMatrix",           \
00511                     "ltpMatrix", "lspMatrix"
00512 
00513 #define ndense_CLASSES                                  \
00514                     "ngeMatrix", "ntrMatrix",           \
00515                     "nsyMatrix",                        \
00516                     "ntpMatrix", "nspMatrix"
00517 
00518 /* Generalized -- "geMatrix" -- dispatch where needed : */
00519 SEXP dup_mMatrix_as_geMatrix(SEXP A)
00520 {
00521     SEXP ans, ad = R_NilValue, an = R_NilValue; /* -Wall */
00522     static const char *valid[] = {
00523         "_NOT_A_CLASS_",/* *_CLASSES defined in ./Mutils.h */
00524         ddense_CLASSES, /* 14 */
00525         ldense_CLASSES, /* 6  */
00526         ndense_CLASSES, /* 5  */
00527         ""};
00528     int sz, ctype = Matrix_check_class_etc(A, valid),
00529         nprot = 1;
00530     enum dense_enum { ddense, ldense, ndense } M_type = ddense /* -Wall */;
00531 
00532     if (ctype > 0) { /* a [nld]denseMatrix object */
00533         ad = GET_SLOT(A, Matrix_DimSym);
00534         an = GET_SLOT(A, Matrix_DimNamesSym);
00535         M_type = (ctype <= 14) ? ddense :
00536             ((ctype <= 14+6) ? ldense : ndense);
00537     }
00538     else if (ctype < 0) {       /* not a (recognized) classed matrix */
00539 
00540         if (isReal(A))
00541             M_type = ddense;
00542         else if (isInteger(A)) {
00543             A = PROTECT(coerceVector(A, REALSXP));
00544             nprot++;
00545             M_type = ddense;
00546         }
00547         else if (isLogical(A))
00548             M_type = ldense;
00549         else
00550             error(_("invalid class '%s' to dup_mMatrix_as_geMatrix"),
00551                   class_P(A));
00552 
00553 #define DUP_MMATRIX_NON_CLASS                                           \
00554         if (isMatrix(A)) {      /* "matrix" */                          \
00555             ad = getAttrib(A, R_DimSymbol);                             \
00556             an = getAttrib(A, R_DimNamesSymbol);                        \
00557         } else {/* maybe "numeric" (incl integer,logical) --> (n x 1) */\
00558             int* dd = INTEGER(ad = PROTECT(allocVector(INTSXP, 2)));    \
00559             nprot++;                                                    \
00560             dd[0] = LENGTH(A);                                          \
00561             dd[1] = 1;                                                  \
00562             an = R_NilValue;                                            \
00563         }                                                               \
00564         ctype = 0
00565 
00566         DUP_MMATRIX_NON_CLASS;
00567     }
00568 
00569     ans = PROTECT(NEW_OBJECT(MAKE_CLASS(M_type == ddense ? "dgeMatrix" :
00570                                         (M_type == ldense ? "lgeMatrix" :
00571                                          "ngeMatrix"))));
00572 #define DUP_MMATRIX_SET_1                                       \
00573     SET_SLOT(ans, Matrix_DimSym, duplicate(ad));                \
00574     SET_SLOT(ans, Matrix_DimNamesSym, (LENGTH(an) == 2) ?       \
00575              duplicate(an): allocVector(VECSXP, 2));            \
00576     sz = INTEGER(ad)[0] * INTEGER(ad)[1]
00577 
00578     DUP_MMATRIX_SET_1;
00579 
00580     if(M_type == ddense) { /* ddense -> dge */
00581 
00582         double *ansx;
00583 
00584 #define DUP_MMATRIX_ddense_CASES                                                \
00585         ansx = REAL(ALLOC_SLOT(ans, Matrix_xSym, REALSXP, sz));                 \
00586         switch(ctype) {                                                         \
00587         case 0:                 /* unclassed real matrix */                     \
00588             Memcpy(ansx, REAL(A), sz);                                          \
00589             break;                                                              \
00590         case 1:                 /* dgeMatrix */                                 \
00591             Memcpy(ansx, REAL(GET_SLOT(A, Matrix_xSym)), sz);                   \
00592             break;                                                              \
00593         case 2:                 /* dtrMatrix   and subclasses */                \
00594         case 9: case 10: case 11:   /* ---      Cholesky, LDL, BunchKaufman */  \
00595             Memcpy(ansx, REAL(GET_SLOT(A, Matrix_xSym)), sz);                   \
00596             make_d_matrix_triangular(ansx, A);                                  \
00597             break;                                                              \
00598         case 3:                 /* dsyMatrix */                                 \
00599         case 4:                 /* dpoMatrix  + subclass */                     \
00600         case 14:                        /* ---  corMatrix */                    \
00601             Memcpy(ansx, REAL(GET_SLOT(A, Matrix_xSym)), sz);                   \
00602             make_d_matrix_symmetric(ansx, A);                                   \
00603             break;                                                              \
00604         case 5:                 /* ddiMatrix */                                 \
00605             install_diagonal(ansx, A);                                          \
00606             break;                                                              \
00607         case 6:                 /* dtpMatrix  + subclasses */                   \
00608         case 12: case 13:               /* ---  pCholesky, pBunchKaufman */     \
00609             packed_to_full_double(ansx, REAL(GET_SLOT(A, Matrix_xSym)),         \
00610                                   INTEGER(ad)[0],                               \
00611                                   *uplo_P(A) == 'U' ? UPP : LOW);               \
00612             make_d_matrix_triangular(ansx, A);                                  \
00613             break;                                                              \
00614         case 7:                 /* dspMatrix */                                 \
00615         case 8:                 /* dppMatrix */                                 \
00616             packed_to_full_double(ansx, REAL(GET_SLOT(A, Matrix_xSym)),         \
00617                                   INTEGER(ad)[0],                               \
00618                                   *uplo_P(A) == 'U' ? UPP : LOW);               \
00619             make_d_matrix_symmetric(ansx, A);                                   \
00620             break;                                                              \
00621         }  /* switch(ctype) */
00622 
00623         DUP_MMATRIX_ddense_CASES
00624 
00625     }
00626     else { /* M_type == ldense || M_type = ndense  */
00627         /* ldense -> lge */
00628         /* ndense -> nge */
00629         int *ansx = LOGICAL(ALLOC_SLOT(ans, Matrix_xSym, LGLSXP, sz));
00630 
00631         switch(ctype) {
00632         case 0:                 /* unclassed logical matrix */
00633             Memcpy(ansx, LOGICAL(A), sz);
00634             break;
00635 
00636         case 1+14:                      /* lgeMatrix */
00637         case 1+14+6:                    /* ngeMatrix */
00638             Memcpy(ansx, LOGICAL(GET_SLOT(A, Matrix_xSym)), sz);
00639             break;
00640         case 2+14:                      /* ltrMatrix */
00641         case 2+14+6:                    /* ntrMatrix */
00642             Memcpy(ansx, LOGICAL(GET_SLOT(A, Matrix_xSym)), sz);
00643             make_i_matrix_triangular(ansx, A);
00644             break;
00645         case 3+14:                      /* lsyMatrix */
00646         case 3+14+6:                    /* nsyMatrix */
00647             Memcpy(ansx, LOGICAL(GET_SLOT(A, Matrix_xSym)), sz);
00648             make_i_matrix_symmetric(ansx, A);
00649             break;
00650         case 4+14:                      /* ldiMatrix */
00651         case 4+14+6:                    /* ndiMatrix */
00652             install_diagonal_int(ansx, A);
00653             break;
00654         case 5+14:                      /* ltpMatrix */
00655         case 5+14+6:                    /* ntpMatrix */
00656             packed_to_full_int(ansx, LOGICAL(GET_SLOT(A, Matrix_xSym)),
00657                                INTEGER(ad)[0],
00658                                *uplo_P(A) == 'U' ? UPP : LOW);
00659             make_i_matrix_triangular(ansx, A);
00660             break;
00661         case 6+14:                      /* lspMatrix */
00662         case 6+14+6:                    /* nspMatrix */
00663             packed_to_full_int(ansx, LOGICAL(GET_SLOT(A, Matrix_xSym)),
00664                                INTEGER(ad)[0],
00665                                *uplo_P(A) == 'U' ? UPP : LOW);
00666             make_i_matrix_symmetric(ansx, A);
00667             break;
00668 
00669         default:
00670             error(_("unexpected ctype = %d in dup_mMatrix_as_geMatrix"), ctype);
00671         }  /* switch(ctype) */
00672 
00673     }  /* if(M_type == .) */
00674 
00675     UNPROTECT(nprot);
00676     return ans;
00677 }
00678 
00679 SEXP dup_mMatrix_as_dgeMatrix(SEXP A)
00680 {
00681     SEXP ans = PROTECT(NEW_OBJECT(MAKE_CLASS("dgeMatrix"))),
00682         ad = R_NilValue , an = R_NilValue;      /* -Wall */
00683     static const char *valid[] = {"_NOT_A_CLASS_", ddense_CLASSES, ""};
00684     int ctype = Matrix_check_class_etc(A, valid),
00685         nprot = 1, sz;
00686     double *ansx;
00687 
00688     if (ctype > 0) {            /* a ddenseMatrix object */
00689         ad = GET_SLOT(A, Matrix_DimSym);
00690         an = GET_SLOT(A, Matrix_DimNamesSym);
00691     }
00692     else if (ctype < 0) {       /* not a (recognized) classed matrix */
00693 
00694         DUP_MMATRIX_NON_CLASS;
00695 
00696         if (isInteger(A) || isLogical(A)) {
00697             A = PROTECT(coerceVector(A, REALSXP));
00698             nprot++;
00699         }
00700         if (!isReal(A))
00701             error(_("invalid class '%s' to dup_mMatrix_as_dgeMatrix"),
00702                   class_P(A));
00703     }
00704 
00705     DUP_MMATRIX_SET_1;
00706 
00707     DUP_MMATRIX_ddense_CASES
00708 
00709     UNPROTECT(nprot);
00710     return ans;
00711 }
00712 
00713 
00714 SEXP new_dgeMatrix(int nrow, int ncol)
00715 {
00716     SEXP ans = PROTECT(NEW_OBJECT(MAKE_CLASS("dgeMatrix"))),
00717          ad = PROTECT(allocVector(INTSXP, 2));
00718 
00719     INTEGER(ad)[0] = nrow;
00720     INTEGER(ad)[1] = ncol;
00721     SET_SLOT(ans, Matrix_DimSym, ad);
00722     SET_SLOT(ans, Matrix_DimNamesSym, allocVector(VECSXP, 2));
00723     ALLOC_SLOT(ans, Matrix_xSym, REALSXP, nrow * ncol);
00724 
00725     UNPROTECT(2);
00726     return ans;
00727 }
00728 
00738 SEXP m_encodeInd(SEXP ij, SEXP di, SEXP chk_bnds)
00739 {
00740     SEXP ans;
00741     int *ij_di = NULL, n, *Di = INTEGER(di), *IJ, *j_;
00742     Rboolean check_bounds = asLogical(chk_bnds);
00743 
00744     ij = PROTECT(coerceVector(ij, INTSXP));
00745     if(!isMatrix(ij) ||
00746        (ij_di = INTEGER(getAttrib(ij, R_DimSymbol)))[1] != 2)
00747         error(_("Argument ij must be 2-column integer matrix"));
00748     n = ij_di[0];
00749     IJ = INTEGER(ij);
00750     j_ = IJ+n;/* pointer offset! */
00751 
00752     if((Di[0] * (double) Di[1]) >= 1 + (double)INT_MAX) { /* need double */
00753         ans = PROTECT(allocVector(REALSXP, n));
00754         double *ii = REAL(ans), nr = (double) Di[0];
00755 #define do_ii_FILL(_i_, _j_)                                    \
00756         int i;                                                          \
00757         if(check_bounds) {                                              \
00758             for(i=0; i < n; i++) {                                      \
00759                 if(_i_[i] == NA_INTEGER || _j_[i] == NA_INTEGER)        \
00760                     ii[i] = NA_INTEGER;                                 \
00761                 else {                                                  \
00762                     if(_i_[i] < 0 || _i_[i] >= Di[0])                   \
00763                         error(_("subscript 'i' out of bounds in M[ij]")); \
00764                     if(_j_[i] < 0 || _j_[i] >= Di[1])                   \
00765                         error(_("subscript 'j' out of bounds in M[ij]")); \
00766                     ii[i] = _i_[i] + _j_[i] * nr;                       \
00767                 }                                                       \
00768             }                                                           \
00769         } else {                                                        \
00770             for(i=0; i < n; i++)                                        \
00771                 ii[i] = (_i_[i] == NA_INTEGER || _j_[i] == NA_INTEGER)  \
00772                     ? NA_INTEGER : _i_[i] + _j_[i] * nr;                \
00773         }
00774 
00775         do_ii_FILL(IJ, j_);
00776     } else {
00777         ans = PROTECT(allocVector(INTSXP, n));
00778         int *ii = INTEGER(ans), nr = Di[0];
00779 
00780         do_ii_FILL(IJ, j_);
00781     }
00782     UNPROTECT(2);
00783     return ans;
00784 }
00785 
00796 SEXP m_encodeInd2(SEXP i, SEXP j, SEXP di, SEXP chk_bnds)
00797 {
00798     SEXP ans;
00799     int n = LENGTH(i);
00800     int *Di = INTEGER(di), *i_, *j_;
00801     Rboolean check_bounds = asLogical(chk_bnds);
00802 
00803     if(LENGTH(j) != n || !isInteger(i) || !isInteger(j))
00804         error(_("i and j must be integer vectors of the same length"));
00805     i_ = INTEGER(i);
00806     j_ = INTEGER(j);
00807 
00808     if((Di[0] * (double) Di[1]) >= 1 + (double)INT_MAX) { /* need double */
00809         ans = PROTECT(allocVector(REALSXP, n));
00810         double *ii = REAL(ans), nr = (double) Di[0];
00811 
00812         do_ii_FILL(i_, j_);
00813     } else {
00814         ans = PROTECT(allocVector(INTSXP, n));
00815         int *ii = INTEGER(ans), nr = Di[0];
00816 
00817         do_ii_FILL(i_, j_);
00818     }
00819     UNPROTECT(1);
00820     return ans;
00821 }
00822 #undef do_ii_FILL
00823 
00824 
00825 #if R_VERSION < R_Version(2, 13, 0)
00826 
00836 int Matrix_check_class_and_super(SEXP x, const char **valid, SEXP rho)
00837 {
00838     int ans;
00839     SEXP cl = getAttrib(x, R_ClassSymbol);
00840     const char *class = CHAR(asChar(cl));
00841     for (ans = 0; ; ans++) {
00842         if (!strlen(valid[ans])) // empty string
00843             break;
00844         if (!strcmp(class, valid[ans])) return ans;
00845     }
00846     /* if not found directly, now search the non-virtual super classes :*/
00847     if(IS_S4_OBJECT(x)) {
00848         /* now try the superclasses, i.e.,  try   is(x, "....");  superCl :=
00849            .selectSuperClasses(getClass("...")@contains, dropVirtual=TRUE)  */
00850         SEXP classExts, superCl, _call;
00851         int i;
00852         PROTECT(_call = lang2(install("getClassDef"), cl));
00853         classExts = GET_SLOT(eval(_call, rho),
00854                              install("contains"));
00855         UNPROTECT(1);
00856         PROTECT(classExts);
00857         PROTECT(_call = lang3(install(".selectSuperClasses"), classExts,
00858                               /* dropVirtual = */ ScalarLogical(1)));
00859         superCl = eval(_call, rho);
00860         UNPROTECT(2);
00861         PROTECT(superCl);
00862         for(i=0; i < length(superCl); i++) {
00863             const char *s_class = CHAR(STRING_ELT(superCl, i));
00864             for (ans = 0; ; ans++) {
00865                 if (!strlen(valid[ans]))
00866                     break;
00867                 if (!strcmp(s_class, valid[ans])) {
00868                     UNPROTECT(1);
00869                     return ans;
00870                 }
00871             }
00872         }
00873         UNPROTECT(1);
00874     }
00875     return -1;
00876 }
00877 #endif
00878 
00889 int Matrix_check_class_etc(SEXP x, const char **valid)
00890 {
00891     static SEXP s_M_classEnv = NULL;
00892     SEXP cl = getAttrib(x, R_ClassSymbol), rho = R_GlobalEnv, pkg;
00893 /*     PROTECT(cl); */
00894     if(!s_M_classEnv)
00895         s_M_classEnv = install(".M.classEnv");
00896 
00897     pkg = getAttrib(cl, R_PackageSymbol); /* ==R== packageSlot(class(x)) */
00898     if(!isNull(pkg)) { /* find  rho := correct class Environment */
00899         SEXP clEnvCall;
00900         /* need to make sure we find ".M.classEnv" even if Matrix is not
00901            attached, but just namespace-loaded: */
00902 
00903         /* Matrix::: does not work here either ... :
00904          *          rho = eval(lang2(install("Matrix:::.M.classEnv"), cl), */
00905 
00906         /* Now make this work via .onLoad() hack in ../R/zzz.R  : */
00907         PROTECT(clEnvCall = lang2(s_M_classEnv, cl));
00908         rho = eval(clEnvCall, R_GlobalEnv);
00909         UNPROTECT(1);
00910 
00911         if(!isEnvironment(rho))
00912             error(_("could not find correct environment; please report!"));
00913     }
00914 /*     UNPROTECT(1); */
00915     return Matrix_check_class_and_super(x, valid, rho);
00916 }