The R Project SVN R-packages

Rev

Rev 2238 | Rev 3401 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

#include "dgCMatrix.h"

#include "chm_common.h"

/* FIXME -- we "forget" about dimnames almost everywhere : */

SEXP dgCMatrix_validate(SEXP x)
{
    SEXP pslot = GET_SLOT(x, Matrix_pSym),
    islot = GET_SLOT(x, Matrix_iSym),
    xslot = GET_SLOT(x, Matrix_xSym);
    int j,
    ncol = length(pslot) - 1,
    *dims = INTEGER(GET_SLOT(x, Matrix_DimSym)),
    nrow,
    *xp = INTEGER(pslot),
    *xi = INTEGER(islot);

    nrow = dims[0];
    if (length(islot) != length(xslot))
    return mkString(_("lengths of slots i and x must match"));
    if (length(pslot) <= 0)
    return mkString(_("slot p must have length > 0"));
    if (xp[0] != 0)
    return mkString(_("first element of slot p must be zero"));
    if (length(islot) != xp[ncol])
    return mkString(_("last element of slot p must match length of slots i and x"));
    for (j = 0; j < ncol; j++) {
    if (xp[j] > xp[j+1])
        return mkString(_("slot p must be non-decreasing"));
    }
    for (j = 0; j < length(islot); j++) {
    if (xi[j] < 0 || xi[j] >= nrow)
        return mkString(_("all row indices must be between 0 and nrow-1"));
    }
    if (csc_unsorted_columns(ncol, xp, xi))
    csc_sort_columns(ncol, xp, xi, REAL(xslot));

    return ScalarLogical(1);
}

SEXP csc_crossprod(SEXP x)
{
    SEXP pslot = GET_SLOT(x, Matrix_pSym),
    ans = PROTECT(NEW_OBJECT(MAKE_CLASS("dsCMatrix"))), tmp;
    int *xp = INTEGER(pslot),
    *xi = INTEGER(GET_SLOT(x, Matrix_iSym));
    double *xx = REAL(GET_SLOT(x, Matrix_xSym));

    int j, *iVal, ncol = length(pslot) - 1, maxnz, nnz = 0, *pVal;
    double *xVal;

    SET_SLOT(ans, Matrix_factorSym, allocVector(VECSXP, 0));
    SET_SLOT(ans, Matrix_DimSym, allocVector(INTSXP, 2));
    SET_SLOT(ans, Matrix_uploSym, mkString("L"));
    maxnz = (ncol * (ncol + 1))/2;
    iVal = Calloc(maxnz, int); xVal = Calloc(maxnz, double);
    SET_SLOT(ans, Matrix_pSym, allocVector(INTSXP, ncol + 1));
    tmp = GET_SLOT(ans, Matrix_pSym);
    pVal = INTEGER(tmp);
    for (j = 0; j < ncol; j++) {
    pVal[j] = nnz;
    if (xp[j] < xp[j+1]) {  /* column j contains some non-zeros */
        int ind, jj;
        double accum = 0.;
                /* diagonal elements */
        for (ind = xp[j]; ind < xp[j+1]; ind++)
        accum += xx[ind] * xx[ind];
        iVal[nnz] = j;
        xVal[nnz] = accum;
        nnz++;
                /* off-diagonals (lower triangle only) */
        for (jj = j+1; jj < ncol; jj++) {
        int ind2;

        ind = xp[j];
        ind2 = xp[jj];
        accum = 0.;
        while (ind < xp[j+1] && ind2 < xp[jj+1]) {
            if (xi[ind] < xi[ind2]) ind++;
            else {
            if (xi[ind] > xi[ind2]) ind2++;
            else {
                accum += xx[ind] * xx[ind2];
                ind++; ind2++;
            }
            }
        }
        if (accum != 0.) {
            iVal[nnz] = jj;
            xVal[nnz] = accum;
            nnz++;
        }
        }
    }
    }
    pVal[ncol] = nnz;

    SET_SLOT(ans, Matrix_iSym, allocVector(INTSXP, nnz));
    Memcpy(INTEGER(GET_SLOT(ans, Matrix_iSym)), iVal, nnz);
    SET_SLOT(ans, Matrix_xSym, allocVector(REALSXP, nnz));
    Memcpy(REAL(GET_SLOT(ans, Matrix_xSym)), xVal, nnz);
    Free(iVal); Free(xVal); UNPROTECT(1);
    return dgCMatrix_set_Dim(ans, ncol);
}

SEXP csc_tcrossprod(SEXP x)
{
    cholmod_sparse *chx = as_cholmod_sparse(x);
    cholmod_sparse *cha = cholmod_aat(chx, (int *) NULL, 0, 1, &c);
    cholmod_sparse *chas = cholmod_copy(cha, 1, 1, &c);

    Free(chx);
    cholmod_free_sparse(&cha, &c);
    return chm_sparse_to_SEXP(chas, 1);
}

SEXP csc_matrix_crossprod(SEXP x, SEXP y, SEXP classed)
{
    int cl = asLogical(classed);
    SEXP val = PROTECT(NEW_OBJECT(MAKE_CLASS("dgeMatrix")));
    int *xdims = INTEGER(GET_SLOT(x, Matrix_DimSym)),
    *ydims = INTEGER(cl ? GET_SLOT(y, Matrix_DimSym) :
             getAttrib(y, R_DimSymbol)),
    *vdims = INTEGER(ALLOC_SLOT(val, Matrix_DimSym, INTSXP, 2));
    int *xi = INTEGER(GET_SLOT(x, Matrix_iSym)),
    *xp = INTEGER(GET_SLOT(x, Matrix_pSym));
    int j, k = xdims[0], m = xdims[1], n = ydims[1];
    double *vx, *xx = REAL(GET_SLOT(x, Matrix_xSym)),
    *yx = REAL(cl ? GET_SLOT(y, Matrix_xSym) : y);

    if (!cl && !(isMatrix(y) && isReal(y)))
    error(_("y must be a numeric matrix"));
    if (ydims[0] != k)
    error(_("x and y must have the same number of rows"));
    if (m < 1 || n < 1 || k < 1)
    error(_("Matrices with zero extents cannot be multiplied"));
    vdims[0] = m; vdims[1] = n;
    vx = REAL(ALLOC_SLOT(val, Matrix_xSym, REALSXP, m * n));
    for (j = 0; j < n; j++) {
    int i; double *ypt = yx + j * k;
    for(i = 0; i < m; i++) {
        int ii; double accum = 0.;
        for (ii = xp[i]; ii < xp[i+1]; ii++) {
        accum += xx[ii] * ypt[xi[ii]];
        }
        vx[i + j * m] = accum;
    }
    }
    UNPROTECT(1);
    return val;
}

SEXP compressed_to_dgTMatrix(SEXP x, SEXP colP)
{
    int col = asLogical(colP); /* 1 if "C"olumn compressed;  0 if "R"ow */
    SEXP indSym = col ? Matrix_iSym : Matrix_jSym;
    SEXP ans = PROTECT(NEW_OBJECT(MAKE_CLASS("dgTMatrix"))),
    indP = GET_SLOT(x, indSym),
    pP = GET_SLOT(x, Matrix_pSym);
    int npt = length(pP) - 1;

    SET_SLOT(ans, Matrix_DimSym, duplicate(GET_SLOT(x, Matrix_DimSym)));
    SET_SLOT(ans, Matrix_xSym,  duplicate(GET_SLOT(x, Matrix_xSym)));
    SET_SLOT(ans, indSym, duplicate(indP));
    expand_cmprPt(npt, INTEGER(pP),
          INTEGER(ALLOC_SLOT(ans, col ? Matrix_jSym : Matrix_iSym,
                     INTSXP, length(indP))));
    UNPROTECT(1);
    return ans;
}

SEXP compressed_non_0_ij(SEXP x, SEXP colP)
{
    int col = asLogical(colP); /* 1 if "C"olumn compressed;  0 if "R"ow */
    SEXP ans, indSym = col ? Matrix_iSym : Matrix_jSym;
    SEXP indP = GET_SLOT(x, indSym),
    pP = GET_SLOT(x, Matrix_pSym);
    int n_el = length(indP), i, *ij;

    ij = INTEGER(ans = PROTECT(allocMatrix(INTSXP, n_el, 2)));
    /* expand the compressed margin to 'i' or 'j' : */
    expand_cmprPt(length(pP) - 1, INTEGER(pP), &ij[col ? n_el : 0]);
    /* and copy the other one: */
    if (col)
    for(i = 0; i < n_el; i++)
        ij[i] = INTEGER(indP)[i];
    else /* row compressed */
    for(i = 0; i < n_el; i++)
        ij[i + n_el] = INTEGER(indP)[i];

    UNPROTECT(1);
    return ans;
}

SEXP csc_to_matrix(SEXP x)
{
    SEXP ans, pslot = GET_SLOT(x, Matrix_pSym);
    int j, ncol = length(pslot) - 1,
    nrow = INTEGER(GET_SLOT(x, Matrix_DimSym))[0],
    *xp = INTEGER(pslot),
    *xi = INTEGER(GET_SLOT(x, Matrix_iSym));
    double *xx = REAL(GET_SLOT(x, Matrix_xSym)), *ax;

    ax = REAL(ans = PROTECT(allocMatrix(REALSXP, nrow, ncol)));
    for (j = 0; j < (nrow * ncol); j++) ax[j] = 0.;
    for (j = 0; j < ncol; j++) {
    int ind;
    for (ind = xp[j]; ind < xp[j+1]; ind++) {
        ax[j * nrow + xi[ind]] = xx[ind];
    }
    }
    UNPROTECT(1);
    return ans;
}

SEXP csc_to_dgeMatrix(SEXP x)
{
    SEXP ans = PROTECT(NEW_OBJECT(MAKE_CLASS("dgeMatrix"))),
    Dimslot = GET_SLOT(x, Matrix_DimSym);
    int *dims = INTEGER(Dimslot),
    *xp = INTEGER(GET_SLOT(x, Matrix_pSym)),
    *xi = INTEGER(GET_SLOT(x, Matrix_iSym));
    double *xx = REAL(GET_SLOT(x, Matrix_xSym)), *ax;
    int j, nrow = dims[0], ncol = dims[1];

    SET_SLOT(ans, Matrix_DimSym, duplicate(Dimslot));
    SET_SLOT(ans, Matrix_xSym, allocVector(REALSXP, nrow*ncol));
    SET_SLOT(ans, Matrix_factorSym, allocVector(VECSXP, 0));
    ax = REAL(GET_SLOT(ans, Matrix_xSym));
    for (j = 0; j < (nrow * ncol); j++) ax[j] = 0.;
    for (j = 0; j < ncol; j++) {
    int ind;
    for (ind = xp[j]; ind < xp[j+1]; ind++) {
        ax[j * nrow + xi[ind]] = xx[ind];
    }
    }
    UNPROTECT(1);
    return ans;
}

SEXP double_to_csc(double *a, int *dim_a)
{
    SEXP val = PROTECT(NEW_OBJECT(MAKE_CLASS("dgCMatrix")));
    int j, maxnz, nrow, ncol, nnz, *vp, *vi;
    double *vx;

    nrow = dim_a[0]; ncol = dim_a[1];
    SET_SLOT(val, Matrix_factorSym, allocVector(VECSXP, 0));
    SET_SLOT(val, Matrix_DimSym, allocVector(INTSXP, 2));
    SET_SLOT(val, Matrix_pSym, allocVector(INTSXP, ncol + 1));
    vp = INTEGER(GET_SLOT(val, Matrix_pSym));
    maxnz = nrow * ncol;
    vi = Calloc(maxnz, int); vx = Calloc(maxnz, double);
    nnz = 0;
    for (j = 0; j < ncol; j++) {
    int i;
    vp[j] = nnz;
    for (i = 0; i < nrow; i++) {
        double val = a[i + j * nrow];
        if (val != 0.) {
        vi[nnz] = i;
        vx[nnz] = val;
        nnz++;
        }
    }
    }
    vp[ncol] = nnz;
    SET_SLOT(val, Matrix_iSym, allocVector(INTSXP, nnz));
    Memcpy(INTEGER(GET_SLOT(val, Matrix_iSym)), vi, nnz);
    SET_SLOT(val, Matrix_xSym, allocVector(REALSXP, nnz));
    Memcpy(REAL(GET_SLOT(val, Matrix_xSym)), vx, nnz);
    Free(vi); Free(vx);
    UNPROTECT(1);
    return dgCMatrix_set_Dim(val, nrow);
}

SEXP matrix_to_csc(SEXP A)
{
    if (!(isMatrix(A) && isReal(A)))
    error(_("A must be a numeric matrix"));
    return double_to_csc(REAL(A),
             INTEGER(getAttrib(A, R_DimSymbol)));
}

SEXP dgeMatrix_to_csc(SEXP x)
{
    return double_to_csc(   REAL(GET_SLOT(x, Matrix_xSym)),
             INTEGER(GET_SLOT(x, Matrix_DimSym)));
}



SEXP dgTMatrix_to_csc(SEXP dgTMatrix)
{
    SEXP Tisl = GET_SLOT(dgTMatrix, Matrix_iSym);
    int *Ti = INTEGER(Tisl),
    *Tj = INTEGER(GET_SLOT(dgTMatrix, Matrix_jSym)),
    i, nrow, ncol,
    nz = length(Tisl);

    nrow = ncol = -1;
    for(i = 0; i < nz; i++) {
    if (Ti[i] > nrow) nrow = Ti[i];
    if (Tj[i] > ncol) ncol = Tj[i];
    }
    return triple_as_SEXP(nrow + 1, ncol + 1, nz, Ti, Tj,
              REAL(GET_SLOT(dgTMatrix, Matrix_xSym)),
              "dgCMatrix");
}

SEXP csc_getDiag(SEXP x)
{
    SEXP pslot = GET_SLOT(x, Matrix_pSym), ans;
    int *xp = INTEGER(pslot),
    *xi = INTEGER(GET_SLOT(x, Matrix_iSym)),
    j,
    ncol = length(pslot) - 1,
    nrow = INTEGER(GET_SLOT(x, Matrix_DimSym))[0],
    ndiag;
    double *xx = REAL(GET_SLOT(x, Matrix_xSym)), *diag;

    ndiag = (nrow < ncol) ? nrow : ncol;
    ans = PROTECT(allocVector(REALSXP, ndiag));
    diag = REAL(ans);
    for (j = 0; j < ndiag; j++) {
    int ind;
    diag[j] = 0.;
    for (ind = xp[j]; ind < xp[j+1]; ind++) {
        if (xi[ind] == j) diag[j] = xx[ind];
    }
    }
    UNPROTECT(1);
    return ans;
}

SEXP csc_transpose(SEXP x)
{
    cholmod_sparse *chx = as_cholmod_sparse(x);
    SEXP ans =
    chm_sparse_to_SEXP(cholmod_transpose(chx, 1, &c), 1);
    Free(chx);
    return ans;
}

SEXP csc_matrix_mm(SEXP a, SEXP b, SEXP classed, SEXP right)
{
    int cl = asLogical(classed), rt = asLogical(right);
    SEXP val = PROTECT(NEW_OBJECT(MAKE_CLASS("dgeMatrix")));
    int *adims = INTEGER(GET_SLOT(a, Matrix_DimSym)),
    *ai = INTEGER(GET_SLOT(a, Matrix_iSym)),
    *ap = INTEGER(GET_SLOT(a, Matrix_pSym)),
    *bdims = INTEGER(cl ? GET_SLOT(b, Matrix_DimSym) :
             getAttrib(b, R_DimSymbol)),
    *cdims = INTEGER(ALLOC_SLOT(val, Matrix_DimSym, INTSXP, 2)),
    chk, ione = 1, j, jj, k, m, n;
    double *ax = REAL(GET_SLOT(a, Matrix_xSym)),
    *bx = REAL(cl ? GET_SLOT(b, Matrix_xSym) : b), *cx;

    if (rt) {
    m = bdims[0]; n = adims[1]; k = bdims[1]; chk = adims[0];
    } else {
    m = adims[0]; n = bdims[1]; k = adims[1]; chk = bdims[0];
    }
    if (chk != k)
    error(_("Matrices are not conformable for multiplication"));
    if (m < 1 || n < 1 || k < 1)
    error(_("Matrices with zero extents cannot be multiplied"));
    cx = REAL(ALLOC_SLOT(val, Matrix_xSym, REALSXP, m * n));
    AZERO(cx, m * n); /* zero the accumulators */
    for (j = 0; j < n; j++) { /* across columns of c */
    if (rt) {
        int kk, k2 = ap[j + 1];
        for (kk = ap[j]; kk < k2; kk++) {
        F77_CALL(daxpy)(&m, &ax[kk], &bx[ai[kk]*m],
                &ione, &cx[j*m], &ione);
        }
    } else {
        double *ccol = cx + j * m,
        *bcol = bx + j * k;

        for (jj = 0; jj < k; jj++) { /* across columns of a */
        int kk, k2 = ap[jj + 1];
        for (kk = ap[jj]; kk < k2; kk++) {
            ccol[ai[kk]] += ax[kk] * bcol[jj];
        }
        }
    }
    }
    cdims[0] = m; cdims[1] = n;
    UNPROTECT(1);
    return val;
}

SEXP csc_col_permute(SEXP x, SEXP perm)
{
    SEXP val = PROTECT(NEW_OBJECT(MAKE_CLASS("dgCMatrix"))), tmp;
    int *iperm, *prm, *vi, *vp, *xi, *xp, j, k, ncol, pos;
    double *vx, *xx;

    SET_SLOT(val, Matrix_factorSym, allocVector(VECSXP, 0));
    tmp = GET_SLOT(x, Matrix_DimSym);
    SET_SLOT(val, Matrix_DimSym, duplicate(tmp));
    ncol = INTEGER(tmp)[1];
    if (!(isInteger(perm) && length(perm) == ncol))
    error(_("perm must be an integer vector of length %d"),
          ncol);
    prm = INTEGER(perm);
    if (!R_ldl_valid_perm(ncol, prm))
    error(_("perm is not a valid 0-based permutation"));
    iperm = Calloc(ncol, int);
    for (j = 0; j < ncol; j++) iperm[prm[j]] = j;
    tmp = GET_SLOT(x, Matrix_pSym);
    xp = INTEGER(tmp);
    SET_SLOT(val, Matrix_pSym, duplicate(tmp));
    vp = INTEGER(GET_SLOT(val, Matrix_pSym));
    tmp = GET_SLOT(x, Matrix_iSym);
    xi = INTEGER(tmp);
    SET_SLOT(val, Matrix_iSym, duplicate(tmp));
    vi = INTEGER(GET_SLOT(val, Matrix_iSym));
    tmp = GET_SLOT(x, Matrix_xSym);
    xx = REAL(tmp);
    SET_SLOT(val, Matrix_xSym, duplicate(tmp));
    vx = REAL(GET_SLOT(val, Matrix_xSym));

    pos = vp[0] = 0;
    for (j = 0; j < ncol; j++) {
    int jj = iperm[j];
    int j1 = xp[jj], j2 = xp[jj+1];
    vp[j + 1] = vp[j] + (j2 - j1);
    for (k = j1; k < j2; k++) {
        vi[pos] = xi[k];
        vx[pos] = xx[k];
        pos++;
    }
    }
    Free(iperm);
    UNPROTECT(1);
    return val;
}