mxArray *spqr_mx_put_sparse ( cholmod_sparse **Ahandle, // CHOLMOD version of the matrix cholmod_common *cc ) { mxArray *Amatlab ; cholmod_sparse *A ; Long nz, is_complex ; A = *Ahandle ; is_complex = (A->xtype != CHOLMOD_REAL) ; Amatlab = mxCreateSparse (0, 0, 0, is_complex ? mxCOMPLEX: mxREAL) ; mxSetM (Amatlab, A->nrow) ; mxSetN (Amatlab, A->ncol) ; mxSetNzmax (Amatlab, A->nzmax) ; mxFree (mxGetJc (Amatlab)) ; mxFree (mxGetIr (Amatlab)) ; mxFree (mxGetPr (Amatlab)) ; mxSetJc (Amatlab, (mwIndex *) A->p) ; mxSetIr (Amatlab, (mwIndex *) A->i) ; nz = cholmod_l_nnz (A, cc) ; put_values (nz, Amatlab, (double *) A->x, is_complex, cc) ; A->p = NULL ; A->i = NULL ; A->x = NULL ; A->z = NULL ; cholmod_l_free_sparse (Ahandle, cc) ; return (Amatlab) ; }
void mexFunction ( int nargout, mxArray *pargout [ ], int nargin, const mxArray *pargin [ ] ) { void *G ; cholmod_dense *X = NULL ; cholmod_sparse *A = NULL, *Z = NULL ; cholmod_common Common, *cm ; Long *Ap = NULL, *Ai ; double *Ax, *Az = NULL ; char filename [MAXLEN] ; Long nz, k, is_complex = FALSE, nrow = 0, ncol = 0, allzero ; int mtype ; /* ---------------------------------------------------------------------- */ /* start CHOLMOD and set parameters */ /* ---------------------------------------------------------------------- */ cm = &Common ; cholmod_l_start (cm) ; sputil_config (SPUMONI, cm) ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ if (nargin < 1 || nargin > 2 || nargout > 2) { mexErrMsgTxt ("usage: [A Z] = mread (filename, prefer_binary)") ; } if (!mxIsChar (pargin [0])) { mexErrMsgTxt ("mread requires a filename") ; } mxGetString (pargin [0], filename, MAXLEN) ; sputil_file = fopen (filename, "r") ; if (sputil_file == NULL) { mexErrMsgTxt ("cannot open file") ; } if (nargin > 1) { cm->prefer_binary = (mxGetScalar (pargin [1]) != 0) ; } /* ---------------------------------------------------------------------- */ /* read the matrix, as either a dense or sparse matrix */ /* ---------------------------------------------------------------------- */ G = cholmod_l_read_matrix (sputil_file, 1, &mtype, cm) ; fclose (sputil_file) ; sputil_file = NULL ; if (G == NULL) { mexErrMsgTxt ("could not read file") ; } /* get the specific matrix (A or X), and change to ZOMPLEX if needed */ if (mtype == CHOLMOD_SPARSE) { A = (cholmod_sparse *) G ; nrow = A->nrow ; ncol = A->ncol ; is_complex = (A->xtype == CHOLMOD_COMPLEX) ; Ap = A->p ; Ai = A->i ; if (is_complex) { /* if complex, ensure A is ZOMPLEX */ cholmod_l_sparse_xtype (CHOLMOD_ZOMPLEX, A, cm) ; } Ax = A->x ; Az = A->z ; } else if (mtype == CHOLMOD_DENSE) { X = (cholmod_dense *) G ; nrow = X->nrow ; ncol = X->ncol ; is_complex = (X->xtype == CHOLMOD_COMPLEX) ; if (is_complex) { /* if complex, ensure X is ZOMPLEX */ cholmod_l_dense_xtype (CHOLMOD_ZOMPLEX, X, cm) ; } Ax = X->x ; Az = X->z ; } else { mexErrMsgTxt ("invalid file") ; } /* ---------------------------------------------------------------------- */ /* if requested, extract the zero entries and place them in Z */ /* ---------------------------------------------------------------------- */ if (nargout > 1) { if (mtype == CHOLMOD_SPARSE) { /* A is a sparse real/zomplex double matrix */ Z = sputil_extract_zeros (A, cm) ; } else { /* input is full; just return an empty Z matrix */ Z = cholmod_l_spzeros (nrow, ncol, 0, CHOLMOD_REAL, cm) ; } } /* ---------------------------------------------------------------------- */ /* prune the zero entries from A and set nzmax(A) to nnz(A) */ /* ---------------------------------------------------------------------- */ if (mtype == CHOLMOD_SPARSE) { sputil_drop_zeros (A) ; cholmod_l_reallocate_sparse (cholmod_l_nnz (A, cm), A, cm) ; } /* ---------------------------------------------------------------------- */ /* change a complex matrix to real if its imaginary part is all zero */ /* ---------------------------------------------------------------------- */ if (is_complex) { if (mtype == CHOLMOD_SPARSE) { nz = Ap [ncol] ; } else { nz = nrow * ncol ; } allzero = TRUE ; for (k = 0 ; k < nz ; k++) { if (Az [k] != 0) { allzero = FALSE ; break ; } } if (allzero) { /* discard the all-zero imaginary part */ if (mtype == CHOLMOD_SPARSE) { cholmod_l_sparse_xtype (CHOLMOD_REAL, A, cm) ; } else { cholmod_l_dense_xtype (CHOLMOD_REAL, X, cm) ; } } } /* ---------------------------------------------------------------------- */ /* return results to MATLAB */ /* ---------------------------------------------------------------------- */ if (mtype == CHOLMOD_SPARSE) { pargout [0] = sputil_put_sparse (&A, cm) ; } else { pargout [0] = sputil_put_dense (&X, cm) ; } if (nargout > 1) { pargout [1] = sputil_put_sparse (&Z, cm) ; } /* ---------------------------------------------------------------------- */ /* free workspace */ /* ---------------------------------------------------------------------- */ cholmod_l_finish (cm) ; cholmod_l_print_common (" ", cm) ; }
int main (int argc, char **argv) { cholmod_sparse *A, *R ; cholmod_dense *B, *C ; SuiteSparse_long *E ; int mtype ; long m, n, rnk ; size_t total_mem, available_mem ; double t ; // start CHOLMOD cholmod_common *cc, Common ; cc = &Common ; cholmod_l_start (cc) ; // warmup the GPU. This can take some time, but only needs // to be done once cc->useGPU = false ; t = SuiteSparse_time ( ) ; cholmod_l_gpu_memorysize (&total_mem, &available_mem, cc) ; cc->gpuMemorySize = available_mem ; t = SuiteSparse_time ( ) - t ; if (cc->gpuMemorySize <= 1) { printf ("no GPU available\n") ; } printf ("available GPU memory: %g MB, warmup time: %g\n", (double) (cc->gpuMemorySize) / (1024 * 1024), t) ; // A = mread (stdin) ; read in the sparse matrix A const char *filename = argv[1]; FILE *file = fopen(filename, "r"); A = (cholmod_sparse *) cholmod_l_read_matrix (file, 1, &mtype, cc) ; fclose(file); if (mtype != CHOLMOD_SPARSE) { printf ("input matrix must be sparse\n") ; exit (1) ; } // [m n] = size (A) ; m = A->nrow ; n = A->ncol ; long ordering = (argc < 3 ? SPQR_ORDERING_DEFAULT : atoi(argv[2])); printf ("Matrix %6ld-by-%-6ld nnz: %6ld\n", m, n, cholmod_l_nnz (A, cc)) ; // B = ones (m,1), a dense right-hand-side of the same type as A B = cholmod_l_ones (m, 1, A->xtype, cc) ; double tol = SPQR_NO_TOL ; long econ = 0 ; // [Q,R,E] = qr (A), but discard Q // SuiteSparseQR <double> (ordering, tol, econ, A, &R, &E, cc) ; // [C,R,E] = qr (A,b), but discard Q SuiteSparseQR <double> (ordering, tol, econ, A, B, &C, &R, &E, cc) ; // now R'*R-A(:,E)'*A(:,E) should be epsilon // and C = Q'*b. The solution to the least-squares problem // should be x=R\C. // write out R to a file FILE *f = fopen ("R.mtx", "w") ; cholmod_l_write_sparse (f, R, NULL, NULL, cc) ; fclose (f) ; // write out C to a file f = fopen ("C.mtx", "w") ; cholmod_l_write_dense (f, C, NULL, cc) ; fclose (f) ; // write out E to a file f = fopen ("E.txt", "w") ; for (long i = 0 ; i < n ; i++) { fprintf (f, "%ld\n", 1 + E [i]) ; } fclose (f) ; // free everything cholmod_l_free_sparse (&A, cc) ; cholmod_l_free_sparse (&R, cc) ; cholmod_l_free_dense (&C, cc) ; // cholmod_l_free (&E, cc) ; cholmod_l_finish (cc) ; return (0) ; }
/** * Copy the contents of a to an appropriate CsparseMatrix object and, * optionally, free a or free both a and its the pointers to its contents. * * @param a (cholmod_sparse) matrix to be converted * @param dofree 0 - don't free a; > 0 cholmod_free a; < 0 Free a * @param uploT 0 - not triangular; > 0 upper triangular; < 0 lower * @param Rkind - vector type to store for a->xtype == CHOLMOD_REAL, * 0 - REAL; 1 - LOGICAL [unused for other a->xtype] * @param diag character string suitable for the diag slot of a * triangular matrix (not accessed if uploT == 0). * @param dn either R_NilValue or an SEXP suitable for the Dimnames slot. * * @return SEXP containing a copy of a */ SEXP chm_sparse_to_SEXP(CHM_SP a, int dofree, int uploT, int Rkind, const char* diag, SEXP dn) { SEXP ans; char *cls = "";/* -Wall */ Rboolean longi = (a->itype) == CHOLMOD_LONG; int *dims, nnz, *ansp, *ansi; // if (longi) : SuiteSparse_long *ail = (SuiteSparse_long*)(a->i), *apl = (SuiteSparse_long*)(a->p); // else ((a->itype) == CHOLMOD_INT) : int *aii = (int*)(a->i), *api = (int*)(a->p); PROTECT(dn); /* dn is usually UNPROTECTed before the call */ /* ensure a is sorted and packed */ if (!a->sorted || !a->packed) longi ? cholmod_l_sort(a, &cl) : cholmod_sort(a, &c); /* determine the class of the result */ #define DOFREE_MAYBE \ if (dofree > 0) \ longi ? cholmod_l_free_sparse(&a, &cl) : cholmod_free_sparse(&a, &c); \ else if (dofree < 0) Free(a) switch(a->xtype) { case CHOLMOD_PATTERN: cls = uploT ? "ntCMatrix": ((a->stype) ? "nsCMatrix" : "ngCMatrix"); break; case CHOLMOD_REAL: switch(Rkind) { case 0: cls = uploT ? "dtCMatrix": ((a->stype) ? "dsCMatrix" : "dgCMatrix"); break; case 1: cls = uploT ? "ltCMatrix": ((a->stype) ? "lsCMatrix" : "lgCMatrix"); break; default: DOFREE_MAYBE; error(_("chm_sparse_to_SEXP(<real>, *): invalid 'Rkind' (real kind code)")); } break; case CHOLMOD_COMPLEX: cls = uploT ? "ztCMatrix": ((a->stype) ? "zsCMatrix" : "zgCMatrix"); break; default: DOFREE_MAYBE; error(_("unknown xtype in cholmod_sparse object")); } ans = PROTECT(NEW_OBJECT_OF_CLASS(cls)); /* allocate and copy common slots */ nnz = longi ? cholmod_l_nnz(a, &cl) : cholmod_nnz(a, &c); dims = INTEGER(ALLOC_SLOT(ans, Matrix_DimSym, INTSXP, 2)); dims[0] = a->nrow; dims[1] = a->ncol; ansp = INTEGER(ALLOC_SLOT(ans, Matrix_pSym, INTSXP, a->ncol + 1)); ansi = INTEGER(ALLOC_SLOT(ans, Matrix_iSym, INTSXP, nnz)); for (int j = 0; j <= a->ncol; j++) ansp[j] = longi ? (int)(apl[j]) : api[j]; for (int p = 0; p < nnz; p++) ansi[p] = longi ? (int)(ail[p]) : aii[p]; /* copy data slot if present */ if (a->xtype == CHOLMOD_REAL) { int i, *m_x; double *a_x = (double *) a->x; switch(Rkind) { case 0: Memcpy(REAL(ALLOC_SLOT(ans, Matrix_xSym, REALSXP, nnz)), a_x, nnz); break; case 1: m_x = LOGICAL(ALLOC_SLOT(ans, Matrix_xSym, LGLSXP, nnz)); for (i=0; i < nnz; i++) m_x[i] = ISNAN(a_x[i]) ? NA_LOGICAL : (a_x[i] != 0); break; } } else if (a->xtype == CHOLMOD_COMPLEX) { DOFREE_MAYBE; error(_("complex sparse matrix code not yet written")); /* Memcpy(COMPLEX(ALLOC_SLOT(ans, Matrix_xSym, CPLXSXP, nnz)), */ /* (complex *) a->x, nnz); */ } if (uploT) { /* slots for triangularMatrix */ if (a->stype) error(_("Symmetric and triangular both set")); SET_SLOT(ans, Matrix_uploSym, mkString((uploT > 0) ? "U" : "L")); SET_SLOT(ans, Matrix_diagSym, mkString(diag)); } if (a->stype) /* slot for symmetricMatrix */ SET_SLOT(ans, Matrix_uploSym, mkString((a->stype > 0) ? "U" : "L")); DOFREE_MAYBE; if (dn != R_NilValue) SET_SLOT(ans, Matrix_DimNamesSym, duplicate(dn)); UNPROTECT(2); return ans; }
int main (int argc, char **argv) { cholmod_common Common, *cc ; cholmod_sparse *A ; cholmod_dense *X, *B ; int mtype ; Long m, n ; // start CHOLMOD cc = &Common ; cholmod_l_start (cc) ; // A = mread (stdin) ; read in the sparse matrix A A = (cholmod_sparse *) cholmod_l_read_matrix (stdin, 1, &mtype, cc) ; if (mtype != CHOLMOD_SPARSE) { printf ("input matrix must be sparse\n") ; exit (1) ; } // [m n] = size (A) ; m = A->nrow ; n = A->ncol ; printf ("Matrix %6ld-by-%-6ld nnz: %6ld\n", m, n, cholmod_l_nnz (A, cc)) ; // B = ones (m,1), a dense right-hand-side of the same type as A B = cholmod_l_ones (m, 1, A->xtype, cc) ; // X = A\B ; with default ordering and default column 2-norm tolerance if (A->xtype == CHOLMOD_REAL) { // A, X, and B are all real X = SuiteSparseQR <double> (SPQR_ORDERING_DEFAULT, SPQR_DEFAULT_TOL, A, B, cc) ; } else { // A, X, and B are all complex X = SuiteSparseQR < std::complex<double> > (SPQR_ORDERING_DEFAULT, SPQR_DEFAULT_TOL, A, B, cc) ; } check_residual (A, X, B, cc) ; cholmod_l_free_dense (&X, cc) ; // ------------------------------------------------------------------------- // factorizing once then solving twice with different right-hand-sides // ------------------------------------------------------------------------- // Just the real case. Complex case is essentially identical if (A->xtype == CHOLMOD_REAL) { SuiteSparseQR_factorization <double> *QR ; cholmod_dense *Y ; Long i ; double *Bx ; // factorize once QR = SuiteSparseQR_factorize <double> (SPQR_ORDERING_DEFAULT, SPQR_DEFAULT_TOL, A, cc) ; // solve Ax=b, using the same B as before // Y = Q'*B Y = SuiteSparseQR_qmult (SPQR_QTX, QR, B, cc) ; // X = R\(E*Y) X = SuiteSparseQR_solve (SPQR_RETX_EQUALS_B, QR, Y, cc) ; // check the results check_residual (A, X, B, cc) ; // free X and Y cholmod_l_free_dense (&Y, cc) ; cholmod_l_free_dense (&X, cc) ; // repeat with a different B Bx = (double *) (B->x) ; for (i = 0 ; i < m ; i++) { Bx [i] = i ; } // Y = Q'*B Y = SuiteSparseQR_qmult (SPQR_QTX, QR, B, cc) ; // X = R\(E*Y) X = SuiteSparseQR_solve (SPQR_RETX_EQUALS_B, QR, Y, cc) ; // check the results check_residual (A, X, B, cc) ; // free X and Y cholmod_l_free_dense (&Y, cc) ; cholmod_l_free_dense (&X, cc) ; // free QR SuiteSparseQR_free (&QR, cc) ; } // ------------------------------------------------------------------------- // free everything that remains // ------------------------------------------------------------------------- cholmod_l_free_sparse (&A, cc) ; cholmod_l_free_dense (&B, cc) ; cholmod_l_finish (cc) ; return (0) ; }
int main (int argc, char **argv) { cholmod_sparse *A ; cholmod_dense *X, *B, *r, *atr ; double anorm, xnorm, rnorm, one [2] = {1,0}, minusone [2] = {-1,0}, t ; double zero [2] = {0,0}, atrnorm ; int mtype ; long m, n, rnk ; size_t total_mem, available_mem ; // start CHOLMOD cholmod_common *cc, Common ; cc = &Common ; cholmod_l_start (cc) ; // warmup the GPU. This can take some time, but only needs // to be done once cc->useGPU = true ; t = SuiteSparse_time ( ) ; cholmod_l_gpu_memorysize (&total_mem, &available_mem, cc) ; cc->gpuMemorySize = available_mem ; t = SuiteSparse_time ( ) - t ; if (cc->gpuMemorySize <= 1) { printf ("no GPU available\n") ; } printf ("available GPU memory: %g MB, warmup time: %g\n", (double) (cc->gpuMemorySize) / (1024 * 1024), t) ; // A = mread (stdin) ; read in the sparse matrix A const char *filename = (argc < 2 ? "Problems/2.mtx" : argv[1]); FILE *file = fopen(filename, "r"); A = (cholmod_sparse *) cholmod_l_read_matrix (file, 1, &mtype, cc) ; fclose(file); if (mtype != CHOLMOD_SPARSE) { printf ("input matrix must be sparse\n") ; exit (1) ; } // [m n] = size (A) ; m = A->nrow ; n = A->ncol ; long ordering = (argc < 3 ? SPQR_ORDERING_DEFAULT : atoi(argv[2])); #if 1 printf ("Matrix %6ld-by-%-6ld nnz: %6ld\n", m, n, cholmod_l_nnz (A, cc)) ; #endif // anorm = norm (A,1) ; anorm = cholmod_l_norm_sparse (A, 1, cc) ; // B = ones (m,1), a dense right-hand-side of the same type as A B = cholmod_l_ones (m, 1, A->xtype, cc) ; // X = A\B ; with default ordering and default column 2-norm tolerance if (A->xtype == CHOLMOD_REAL) { // A, X, and B are all real X = SuiteSparseQR <double>(ordering, SPQR_NO_TOL, A, B, cc) ; } else { #if SUPPORTS_COMPLEX // A, X, and B are all complex X = SuiteSparseQR < std::complex<double> > (SPQR_ORDERING_DEFAULT, SPQR_NO_TOL, A, B, cc) ; #else printf("Code doesn't support std::complex<?> types.\n"); #endif } // get the rank(A) estimate rnk = cc->SPQR_istat [4] ; // compute the residual r, and A'*r, and their norms r = cholmod_l_copy_dense (B, cc) ; // r = B cholmod_l_sdmult (A, 0, one, minusone, X, r, cc) ; // r = A*X-r = A*x-b rnorm = cholmod_l_norm_dense (r, 2, cc) ; // rnorm = norm (r) atr = cholmod_l_zeros (n, 1, CHOLMOD_REAL, cc) ; // atr = zeros (n,1) cholmod_l_sdmult (A, 1, one, zero, r, atr, cc) ; // atr = A'*r atrnorm = cholmod_l_norm_dense (atr, 2, cc) ; // atrnorm = norm (atr) // xnorm = norm (X) xnorm = cholmod_l_norm_dense (X, 2, cc) ; // write out X to a file FILE *f = fopen ("X.mtx", "w") ; cholmod_l_write_dense (f, X, NULL, cc) ; fclose (f) ; if (m <= n && anorm > 0 && xnorm > 0) { // find the relative residual, except for least-squares systems rnorm /= (anorm * xnorm) ; } printf ("\nnorm(Ax-b): %8.1e\n", rnorm) ; printf ("norm(A'(Ax-b)) %8.1e rank: %ld of %ld\n", atrnorm, rnk, (m < n) ? m:n) ; /* Write an info file. */ FILE *info = fopen("gpu_results.txt", "w"); fprintf(info, "%ld\n", cc->SPQR_istat[7]); // ordering method fprintf(info, "%ld\n", cc->memory_usage); // memory usage (bytes) fprintf(info, "%30.16e\n", cc->SPQR_flopcount); // flop count fprintf(info, "%lf\n", cc->SPQR_analyze_time); // analyze time fprintf(info, "%lf\n", cc->SPQR_factorize_time); // factorize time fprintf(info, "-1\n") ; // cpu memory (bytes) fprintf(info, "-1\n") ; // gpu memory (bytes) fprintf(info, "%32.16e\n", rnorm); // residual fprintf(info, "%ld\n", cholmod_l_nnz (A, cc)); // nnz(A) fprintf(info, "%ld\n", cc->SPQR_istat [0]); // nnz(R) fprintf(info, "%ld\n", cc->SPQR_istat [2]); // # of frontal matrices fprintf(info, "%ld\n", cc->SPQR_istat [3]); // ntasks, for now fprintf(info, "%lf\n", cc->gpuKernelTime); // kernel time (ms) fprintf(info, "%ld\n", cc->gpuFlops); // "actual" gpu flops fprintf(info, "%d\n", cc->gpuNumKernelLaunches); // # of kernel launches fprintf(info, "%32.16e\n", atrnorm) ; // norm (A'*(Ax-b)) fclose(info); // free everything cholmod_l_free_dense (&r, cc) ; cholmod_l_free_dense (&atr, cc) ; cholmod_l_free_sparse (&A, cc) ; cholmod_l_free_dense (&X, cc) ; cholmod_l_free_dense (&B, cc) ; cholmod_l_finish (cc) ; return (0) ; }