Rev 1574 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
#include "dsCMatrix.h"SEXP dsCMatrix_validate(SEXP obj){SEXP val = check_scalar_string(GET_SLOT(obj, Matrix_uploSym),"LU", "uplo");int *Dim = INTEGER(GET_SLOT(obj, Matrix_DimSym));if (isString(val)) return val;if (Dim[0] != Dim[1])return mkString(_("Symmetric matrix must be square"));csc_check_column_sorting(obj);return ScalarLogical(1);}SEXP dsCMatrix_chol(SEXP x, SEXP pivot){SEXP pSlot = GET_SLOT(x, Matrix_pSym), xorig = x;int *Ai = INTEGER(GET_SLOT(x, Matrix_iSym)),*Ap = INTEGER(pSlot),*Lp, *Parent, info,lo = CHAR(asChar(GET_SLOT(x, Matrix_uploSym)))[0] == 'L',n = length(pSlot)-1,nnz, piv = asLogical(pivot);SEXP val = PROTECT(NEW_OBJECT(MAKE_CLASS("dCholCMatrix")));int *P, *Pinv = (int *) NULL;double *Ax;/* FIXME: Check if there is a Cholesky factorization. If yes,check if the permutation status matches that of the call. Ifso, return it. */if (lo) {x = PROTECT(ssc_transpose(x));Ai = INTEGER(GET_SLOT(x, Matrix_iSym));Ap = INTEGER(GET_SLOT(x, Matrix_pSym));}SET_SLOT(val, Matrix_uploSym, mkString("L"));SET_SLOT(val, Matrix_diagSym, mkString("U"));SET_SLOT(val, Matrix_DimSym, duplicate(GET_SLOT(x, Matrix_DimSym)));Parent = INTEGER(ALLOC_SLOT(val, Matrix_ParentSym, INTSXP, n));Lp = INTEGER(ALLOC_SLOT(val, Matrix_pSym, INTSXP, n + 1));P = INTEGER(ALLOC_SLOT(val, Matrix_permSym, INTSXP, n));if (piv) {SEXP trip = PROTECT(dsCMatrix_to_dgTMatrix(x));SEXP Ti = GET_SLOT(trip, Matrix_iSym);/* determine the permutation with Metis */Pinv = Calloc(n, int);ssc_metis_order(n, Ap, Ai, P, Pinv);/* create a symmetrized form of x */nnz = length(Ti);Ai = Calloc(nnz, int);Ax = Calloc(nnz, double);Ap = Calloc(n + 1, int);triplet_to_col(n, n, nnz, INTEGER(Ti),INTEGER(GET_SLOT(trip, Matrix_jSym)),REAL(GET_SLOT(trip, Matrix_xSym)),Ap, Ai, Ax);UNPROTECT(1);} else {int i;for (i = 0; i < n; i++) P[i] = i;Ax = REAL(GET_SLOT(x, Matrix_xSym));}R_ldl_symbolic(n, Ap, Ai, Lp, Parent, (piv) ? P : (int *)NULL,(piv) ? Pinv : (int *)NULL);nnz = Lp[n];SET_SLOT(val, Matrix_iSym, allocVector(INTSXP, nnz));SET_SLOT(val, Matrix_xSym, allocVector(REALSXP, nnz));SET_SLOT(val, Matrix_DSym, allocVector(REALSXP, n));info = R_ldl_numeric(n, Ap, Ai, Ax, Lp, Parent,INTEGER(GET_SLOT(val, Matrix_iSym)),REAL(GET_SLOT(val, Matrix_xSym)),REAL(GET_SLOT(val, Matrix_DSym)),(piv) ? P : (int *)NULL,(piv) ? Pinv : (int *)NULL);if (info != n)error(_("Leading minor of size %d (possibly after permutation) is indefinite"),info + 1);if (piv) {Free(Pinv); Free(Ax); Free(Ai); Free(Ap);}UNPROTECT(lo ? 2 : 1);return set_factors(xorig, val, "Cholesky");}SEXP dsCMatrix_matrix_solve(SEXP a, SEXP b, SEXP classed){int cl = asLogical(classed);SEXP Chol = get_factors(a, "Cholesky"), perm,bdP = cl ? GET_SLOT(b, Matrix_DimSym) : getAttrib(b, R_DimSymbol),val = PROTECT(NEW_OBJECT(MAKE_CLASS("dgeMatrix")));int *adims = INTEGER(GET_SLOT(a, Matrix_DimSym)),*bdims = INTEGER(bdP),*Li, *Lp, j, piv;int n = adims[1], ncol = bdims[1];double *Lx, *D, *in = REAL(cl ? GET_SLOT(b, Matrix_xSym) : b),*out = REAL(ALLOC_SLOT(val, Matrix_xSym, REALSXP, n * ncol)),*tmp = (double *) NULL;if (!cl && !(isReal(b) && isMatrix(b)))error(_("Argument b must be a numeric matrix"));if (*adims != *bdims || ncol < 1 || *adims < 1)error(_("Dimensions of system to be solved are inconsistent"));if (Chol == R_NilValue) Chol = dsCMatrix_chol(a, ScalarLogical(1));SET_SLOT(val, Matrix_DimSym, duplicate(bdP));perm = GET_SLOT(Chol, Matrix_permSym);piv = length(perm);if (piv) tmp = Calloc(n, double);Li = INTEGER(GET_SLOT(Chol, Matrix_iSym));Lp = INTEGER(GET_SLOT(Chol, Matrix_pSym));Lx = REAL(GET_SLOT(Chol, Matrix_xSym));D = REAL(GET_SLOT(Chol, Matrix_DSym));for (j = 0; j < ncol; j++, in += n, out += n) {if (piv) R_ldl_perm(n, out, in, INTEGER(perm));else Memcpy(out, in, n);R_ldl_lsolve(n, out, Lp, Li, Lx);R_ldl_dsolve(n, out, D);R_ldl_ltsolve(n, out, Lp, Li, Lx);if (piv) R_ldl_permt(n, out, Memcpy(tmp, out, n), INTEGER(perm));}if (piv) Free(tmp);UNPROTECT(1);return val;}SEXP dsCMatrix_inverse_factor(SEXP A){return R_NilValue; /* FIXME: Write this function. */}SEXP ssc_transpose(SEXP x){SEXP ans = PROTECT(NEW_OBJECT(MAKE_CLASS("dsCMatrix"))),islot = GET_SLOT(x, Matrix_iSym);int nnz = length(islot), *adims,*xdims = INTEGER(GET_SLOT(x, Matrix_DimSym));adims = INTEGER(ALLOC_SLOT(ans, Matrix_DimSym, INTSXP, 2));adims[0] = xdims[1]; adims[1] = xdims[0];if (CHAR(asChar(GET_SLOT(x, Matrix_uploSym)))[0] == 'U')SET_SLOT(ans, Matrix_uploSym, mkString("L"));elseSET_SLOT(ans, Matrix_uploSym, mkString("U"));csc_compTr(xdims[0], xdims[1], nnz,INTEGER(GET_SLOT(x, Matrix_pSym)), INTEGER(islot),REAL(GET_SLOT(x, Matrix_xSym)),INTEGER(ALLOC_SLOT(ans, Matrix_pSym, INTSXP, xdims[0] + 1)),INTEGER(ALLOC_SLOT(ans, Matrix_iSym, INTSXP, nnz)),REAL(ALLOC_SLOT(ans, Matrix_xSym, REALSXP, nnz)));UNPROTECT(1);return ans;}SEXP dsCMatrix_to_dgTMatrix(SEXP x){SEXPans = PROTECT(NEW_OBJECT(MAKE_CLASS("dgTMatrix"))),islot = GET_SLOT(x, Matrix_iSym),pslot = GET_SLOT(x, Matrix_pSym);int *ai, *aj, *iv = INTEGER(islot),j, jj, nnz = length(islot), nout,n = length(pslot) - 1,*p = INTEGER(pslot), pos;double *ax, *xv = REAL(GET_SLOT(x, Matrix_xSym));/* increment output count by number of off-diagonals */nout = nnz;for (j = 0; j < n; j++) {int p2 = p[j+1];for (jj = p[j]; jj < p2; jj++) {if (iv[jj] != j) nout++;}}SET_SLOT(ans, Matrix_DimSym, duplicate(GET_SLOT(x, Matrix_DimSym)));SET_SLOT(ans, Matrix_iSym, allocVector(INTSXP, nout));ai = INTEGER(GET_SLOT(ans, Matrix_iSym));SET_SLOT(ans, Matrix_jSym, allocVector(INTSXP, nout));aj = INTEGER(GET_SLOT(ans, Matrix_jSym));SET_SLOT(ans, Matrix_xSym, allocVector(REALSXP, nout));ax = REAL(GET_SLOT(ans, Matrix_xSym));pos = 0;for (j = 0; j < n; j++) {int p2 = p[j+1];for (jj = p[j]; jj < p2; jj++) {int ii = iv[jj];double xx = xv[jj];ai[pos] = ii; aj[pos] = j; ax[pos] = xx; pos++;if (ii != j) {aj[pos] = ii; ai[pos] = j; ax[pos] = xx; pos++;}}}UNPROTECT(1);return ans;}SEXP dsCMatrix_ldl_symbolic(SEXP x, SEXP doPerm){SEXP Ax, Dims = GET_SLOT(x, Matrix_DimSym),ans = PROTECT(allocVector(VECSXP, 3)), tsc;int i, n = INTEGER(Dims)[0], nz, nza,*Ap, *Ai, *Lp, *Li, *Parent,doperm = asLogical(doPerm),*P = (int *) NULL, *Pinv = (int *) NULL;if (CHAR(asChar(GET_SLOT(x, Matrix_uploSym)))[0] == 'L') {x = PROTECT(ssc_transpose(x));} else {x = PROTECT(duplicate(x));}Ax = GET_SLOT(x, Matrix_xSym);nza = length(Ax);Ap = INTEGER(GET_SLOT(x, Matrix_pSym));Ai = INTEGER(GET_SLOT(x, Matrix_iSym));if (doperm) {int *perm, *iperm = Calloc(n, int);SET_VECTOR_ELT(ans, 2, allocVector(INTSXP, n));perm = INTEGER(VECTOR_ELT(ans, 2));ssc_metis_order(n, Ap, Ai, perm, iperm);ssc_symbolic_permute(n, 1, iperm, Ap, Ai);Free(iperm);}SET_VECTOR_ELT(ans, 0, allocVector(INTSXP, n));Parent = INTEGER(VECTOR_ELT(ans, 0));SET_VECTOR_ELT(ans, 1, NEW_OBJECT(MAKE_CLASS("dtCMatrix")));tsc = VECTOR_ELT(ans, 1);SET_SLOT(tsc, Matrix_uploSym, mkString("L"));SET_SLOT(tsc, Matrix_diagSym, mkString("U"));SET_SLOT(tsc, Matrix_DimSym, Dims);SET_SLOT(tsc, Matrix_pSym, allocVector(INTSXP, n + 1));Lp = INTEGER(GET_SLOT(tsc, Matrix_pSym));R_ldl_symbolic(n, Ap, Ai, Lp, Parent, P, Pinv);nz = Lp[n];SET_SLOT(tsc, Matrix_iSym, allocVector(INTSXP, nz));Li = INTEGER(GET_SLOT(tsc, Matrix_iSym));SET_SLOT(tsc, Matrix_xSym, allocVector(REALSXP, nz));for (i = 0; i < nza; i++) REAL(Ax)[i] = 0.00001;for (i = 0; i < n; i++) REAL(Ax)[Ap[i+1]-1] = 10000.;i = R_ldl_numeric(n, Ap, Ai, REAL(Ax), Lp, Parent, Li,REAL(GET_SLOT(tsc, Matrix_xSym)),(double *) R_alloc(n, sizeof(double)), /* D */P, Pinv);UNPROTECT(2);return ans;}SEXP dsCMatrix_metis_perm(SEXP x){SEXP pSlot = GET_SLOT(x, Matrix_pSym),ans = PROTECT(allocVector(VECSXP, 2));int n = length(pSlot) - 1;SET_VECTOR_ELT(ans, 0, allocVector(INTSXP, n));SET_VECTOR_ELT(ans, 1, allocVector(INTSXP, n));ssc_metis_order(n,INTEGER(pSlot),INTEGER(GET_SLOT(x, Matrix_iSym)),INTEGER(VECTOR_ELT(ans, 0)),INTEGER(VECTOR_ELT(ans, 1)));UNPROTECT(1);return ans;}