1 2 #include <petscsys.h> 3 #include <../src/mat/impls/aij/seq/aij.h> 4 #include <../src/mat/impls/sbaij/seq/cholmod/cholmodimpl.h> 5 6 EXTERN_C_BEGIN 7 #include <SuiteSparseQR_C.h> 8 EXTERN_C_END 9 10 static PetscErrorCode MatWrapCholmod_SPQR_seqaij(Mat A,PetscBool values,cholmod_sparse *C,PetscBool *aijalloc,PetscBool *valloc) 11 { 12 Mat_SeqAIJ *aij; 13 Mat AT; 14 const PetscScalar *aa; 15 PetscScalar *ca; 16 const PetscInt *ai, *aj; 17 PetscInt n = A->cmap->n, i,j,k,nz; 18 SuiteSparse_long *ci, *cj; /* SuiteSparse_long is the only choice for SPQR */ 19 PetscBool vain = PETSC_FALSE,flg; 20 21 PetscFunctionBegin; 22 CHKERRQ(PetscObjectTypeCompare((PetscObject)A, MATNORMALHERMITIAN, &flg)); 23 if (flg) { 24 CHKERRQ(MatNormalHermitianGetMat(A, &A)); 25 } else if (!PetscDefined(USE_COMPLEX)) { 26 CHKERRQ(PetscObjectTypeCompare((PetscObject)A, MATNORMAL, &flg)); 27 if (flg) { 28 CHKERRQ(MatNormalGetMat(A, &A)); 29 } 30 } 31 /* cholmod_sparse is compressed sparse column */ 32 CHKERRQ(MatGetOption(A, MAT_SYMMETRIC, &flg)); 33 if (flg) { 34 CHKERRQ(PetscObjectReference((PetscObject)A)); 35 AT = A; 36 } else { 37 CHKERRQ(MatTranspose(A, MAT_INITIAL_MATRIX, &AT)); 38 } 39 aij = (Mat_SeqAIJ*)AT->data; 40 ai = aij->j; 41 aj = aij->i; 42 for (j=0,nz=0; j<n; j++) nz += aj[j+1] - aj[j]; 43 CHKERRQ(PetscMalloc2(n+1,&cj,nz,&ci)); 44 if (values) { 45 vain = PETSC_TRUE; 46 CHKERRQ(PetscMalloc1(nz,&ca)); 47 CHKERRQ(MatSeqAIJGetArrayRead(AT,&aa)); 48 } 49 for (j=0,k=0; j<n; j++) { 50 cj[j] = k; 51 for (i=aj[j]; i<aj[j+1]; i++,k++) { 52 ci[k] = ai[i]; 53 if (values) ca[k] = aa[i]; 54 } 55 } 56 cj[j] = k; 57 *aijalloc = PETSC_TRUE; 58 *valloc = vain; 59 if (values) { 60 CHKERRQ(MatSeqAIJRestoreArrayRead(AT,&aa)); 61 } 62 63 CHKERRQ(PetscMemzero(C,sizeof(*C))); 64 65 C->nrow = (size_t)AT->cmap->n; 66 C->ncol = (size_t)AT->rmap->n; 67 C->nzmax = (size_t)nz; 68 C->p = cj; 69 C->i = ci; 70 C->x = values ? ca : 0; 71 C->stype = 0; 72 C->itype = CHOLMOD_LONG; 73 C->xtype = values ? CHOLMOD_SCALAR_TYPE : CHOLMOD_PATTERN; 74 C->dtype = CHOLMOD_DOUBLE; 75 C->sorted = 1; 76 C->packed = 1; 77 78 CHKERRQ(MatDestroy(&AT)); 79 PetscFunctionReturn(0); 80 } 81 82 static PetscErrorCode MatFactorGetSolverType_seqaij_SPQR(Mat A,MatSolverType *type) 83 { 84 PetscFunctionBegin; 85 *type = MATSOLVERSPQR; 86 PetscFunctionReturn(0); 87 } 88 89 #define GET_ARRAY_READ 0 90 #define GET_ARRAY_WRITE 1 91 92 static PetscErrorCode MatSolve_SPQR_Internal(Mat F, cholmod_dense *cholB, cholmod_dense **_Y_handle) 93 { 94 Mat_CHOLMOD *chol = (Mat_CHOLMOD*)F->data; 95 cholmod_dense *Y_handle = NULL, *QTB_handle = NULL, *Z_handle = NULL; 96 97 PetscFunctionBegin; 98 if (!chol->normal) { 99 QTB_handle = SuiteSparseQR_C_qmult(SPQR_QTX, chol->spqrfact, cholB, chol->common); 100 PetscCheckFalse(!QTB_handle,PetscObjectComm((PetscObject)F), PETSC_ERR_LIB, "SuiteSparseQR_C_qmult failed"); 101 Y_handle = SuiteSparseQR_C_solve(SPQR_RETX_EQUALS_B, chol->spqrfact, QTB_handle, chol->common); 102 PetscCheckFalse(!Y_handle,PetscObjectComm((PetscObject)F), PETSC_ERR_LIB, "SuiteSparseQR_C_solve failed"); 103 } else { 104 Z_handle = SuiteSparseQR_C_solve(SPQR_RTX_EQUALS_ETB, chol->spqrfact, cholB, chol->common); 105 PetscCheckFalse(!Z_handle,PetscObjectComm((PetscObject)F), PETSC_ERR_LIB, "SuiteSparseQR_C_solve failed"); 106 Y_handle = SuiteSparseQR_C_solve(SPQR_RETX_EQUALS_B, chol->spqrfact, Z_handle, chol->common); 107 PetscCheckFalse(!Y_handle,PetscObjectComm((PetscObject)F), PETSC_ERR_LIB, "SuiteSparseQR_C_solve failed"); 108 CHKERRQ(!cholmod_l_free_dense(&Z_handle, chol->common)); 109 } 110 *_Y_handle = Y_handle; 111 CHKERRQ(!cholmod_l_free_dense(&QTB_handle, chol->common)); 112 PetscFunctionReturn(0); 113 } 114 115 static PetscErrorCode MatSolve_SPQR(Mat F,Vec B,Vec X) 116 { 117 Mat_CHOLMOD *chol = (Mat_CHOLMOD*)F->data; 118 cholmod_dense cholB,*Y_handle = NULL; 119 PetscInt n; 120 PetscScalar *v; 121 122 PetscFunctionBegin; 123 CHKERRQ(VecWrapCholmod(B,GET_ARRAY_READ,&cholB)); 124 CHKERRQ(MatSolve_SPQR_Internal(F, &cholB, &Y_handle)); 125 CHKERRQ(VecGetLocalSize(X, &n)); 126 CHKERRQ(VecGetArrayWrite(X, &v)); 127 CHKERRQ(PetscArraycpy(v, (PetscScalar *) (Y_handle->x), n)); 128 CHKERRQ(VecRestoreArrayWrite(X, &v)); 129 CHKERRQ(!cholmod_l_free_dense(&Y_handle, chol->common)); 130 CHKERRQ(VecUnWrapCholmod(B,GET_ARRAY_READ,&cholB)); 131 PetscFunctionReturn(0); 132 } 133 134 static PetscErrorCode MatMatSolve_SPQR(Mat F,Mat B,Mat X) 135 { 136 Mat_CHOLMOD *chol = (Mat_CHOLMOD*)F->data; 137 cholmod_dense cholB,*Y_handle = NULL; 138 PetscScalar *v; 139 PetscInt lda; 140 141 PetscFunctionBegin; 142 CHKERRQ(MatDenseWrapCholmod(B,GET_ARRAY_READ,&cholB)); 143 CHKERRQ(MatSolve_SPQR_Internal(F, &cholB, &Y_handle)); 144 CHKERRQ(MatDenseGetArrayWrite(X, &v)); 145 CHKERRQ(MatDenseGetLDA(X, &lda)); 146 if ((size_t) lda == Y_handle->d) { 147 CHKERRQ(PetscArraycpy(v, (PetscScalar *) (Y_handle->x), lda * Y_handle->ncol)); 148 } else { 149 for (size_t j = 0; j < Y_handle->ncol; j++) { 150 CHKERRQ(PetscArraycpy(&v[j*lda], &(((PetscScalar *) Y_handle->x)[j*Y_handle->d]), Y_handle->nrow)); 151 } 152 } 153 CHKERRQ(MatDenseRestoreArrayWrite(X, &v)); 154 CHKERRQ(!cholmod_l_free_dense(&Y_handle, chol->common)); 155 CHKERRQ(MatDenseUnWrapCholmod(B,GET_ARRAY_READ,&cholB)); 156 PetscFunctionReturn(0); 157 } 158 159 static PetscErrorCode MatSolveTranspose_SPQR_Internal(Mat F, cholmod_dense *cholB, cholmod_dense **_Y_handle) 160 { 161 Mat_CHOLMOD *chol = (Mat_CHOLMOD*)F->data; 162 cholmod_dense *Y_handle = NULL, *RTB_handle = NULL; 163 164 PetscFunctionBegin; 165 RTB_handle = SuiteSparseQR_C_solve(SPQR_RTX_EQUALS_ETB, chol->spqrfact, cholB, chol->common); 166 PetscCheckFalse(!RTB_handle,PetscObjectComm((PetscObject)F), PETSC_ERR_LIB, "SuiteSparseQR_C_solve failed"); 167 Y_handle = SuiteSparseQR_C_qmult(SPQR_QX, chol->spqrfact, RTB_handle, chol->common); 168 PetscCheckFalse(!Y_handle,PetscObjectComm((PetscObject)F), PETSC_ERR_LIB, "SuiteSparseQR_C_qmult failed"); 169 *_Y_handle = Y_handle; 170 CHKERRQ(!cholmod_l_free_dense(&RTB_handle, chol->common)); 171 PetscFunctionReturn(0); 172 } 173 174 static PetscErrorCode MatSolveTranspose_SPQR(Mat F,Vec B,Vec X) 175 { 176 Mat_CHOLMOD *chol = (Mat_CHOLMOD*)F->data; 177 cholmod_dense cholB,*Y_handle = NULL; 178 PetscInt n; 179 PetscScalar *v; 180 181 PetscFunctionBegin; 182 CHKERRQ(VecWrapCholmod(B,GET_ARRAY_READ,&cholB)); 183 CHKERRQ(MatSolveTranspose_SPQR_Internal(F, &cholB, &Y_handle)); 184 CHKERRQ(VecGetLocalSize(X, &n)); 185 CHKERRQ(VecGetArrayWrite(X, &v)); 186 CHKERRQ(PetscArraycpy(v, (PetscScalar *) Y_handle->x, n)); 187 CHKERRQ(VecRestoreArrayWrite(X, &v)); 188 CHKERRQ(!cholmod_l_free_dense(&Y_handle, chol->common)); 189 CHKERRQ(VecUnWrapCholmod(B,GET_ARRAY_READ,&cholB)); 190 PetscFunctionReturn(0); 191 } 192 193 static PetscErrorCode MatMatSolveTranspose_SPQR(Mat F,Mat B,Mat X) 194 { 195 Mat_CHOLMOD *chol = (Mat_CHOLMOD*)F->data; 196 cholmod_dense cholB,*Y_handle = NULL; 197 PetscScalar *v; 198 PetscInt lda; 199 200 PetscFunctionBegin; 201 CHKERRQ(MatDenseWrapCholmod(B,GET_ARRAY_READ,&cholB)); 202 CHKERRQ(MatSolveTranspose_SPQR_Internal(F, &cholB, &Y_handle)); 203 CHKERRQ(MatDenseGetArrayWrite(X, &v)); 204 CHKERRQ(MatDenseGetLDA(X, &lda)); 205 if ((size_t) lda == Y_handle->d) { 206 CHKERRQ(PetscArraycpy(v, (PetscScalar *) Y_handle->x, lda * Y_handle->ncol)); 207 } else { 208 for (size_t j = 0; j < Y_handle->ncol; j++) { 209 CHKERRQ(PetscArraycpy(&v[j*lda], &(((PetscScalar *) Y_handle->x)[j*Y_handle->d]), Y_handle->nrow)); 210 } 211 } 212 CHKERRQ(MatDenseRestoreArrayWrite(X, &v)); 213 CHKERRQ(!cholmod_l_free_dense(&Y_handle, chol->common)); 214 CHKERRQ(MatDenseUnWrapCholmod(B,GET_ARRAY_READ,&cholB)); 215 PetscFunctionReturn(0); 216 } 217 218 static PetscErrorCode MatQRFactorNumeric_SPQR(Mat F,Mat A,const MatFactorInfo *info) 219 { 220 Mat_CHOLMOD *chol = (Mat_CHOLMOD*)F->data; 221 cholmod_sparse cholA; 222 PetscBool aijalloc,valloc; 223 PetscErrorCode ierr; 224 225 PetscFunctionBegin; 226 CHKERRQ(PetscObjectTypeCompare((PetscObject)A, MATNORMALHERMITIAN, &chol->normal)); 227 if (!chol->normal && !PetscDefined(USE_COMPLEX)) { 228 CHKERRQ(PetscObjectTypeCompare((PetscObject)A, MATNORMAL, &chol->normal)); 229 } 230 CHKERRQ((*chol->Wrap)(A,PETSC_TRUE,&cholA,&aijalloc,&valloc)); 231 ierr = !SuiteSparseQR_C_numeric(PETSC_SMALL, &cholA, chol->spqrfact, chol->common); 232 PetscCheckFalse(ierr,PetscObjectComm((PetscObject)F),PETSC_ERR_LIB,"SPQR factorization failed with status %d",chol->common->status); 233 234 if (aijalloc) CHKERRQ(PetscFree2(cholA.p,cholA.i)); 235 if (valloc) CHKERRQ(PetscFree(cholA.x)); 236 237 F->ops->solve = MatSolve_SPQR; 238 F->ops->matsolve = MatMatSolve_SPQR; 239 if (chol->normal) { 240 F->ops->solvetranspose = MatSolve_SPQR; 241 F->ops->matsolvetranspose = MatMatSolve_SPQR; 242 } else if (A->cmap->n == A->rmap->n) { 243 F->ops->solvetranspose = MatSolveTranspose_SPQR; 244 F->ops->matsolvetranspose = MatMatSolveTranspose_SPQR; 245 } 246 PetscFunctionReturn(0); 247 } 248 249 PETSC_INTERN PetscErrorCode MatQRFactorSymbolic_SPQR(Mat F,Mat A,IS perm,const MatFactorInfo *info) 250 { 251 Mat_CHOLMOD *chol = (Mat_CHOLMOD*)F->data; 252 cholmod_sparse cholA; 253 PetscBool aijalloc,valloc; 254 255 PetscFunctionBegin; 256 CHKERRQ(PetscObjectTypeCompare((PetscObject)A, MATNORMALHERMITIAN, &chol->normal)); 257 if (!chol->normal && !PetscDefined(USE_COMPLEX)) { 258 CHKERRQ(PetscObjectTypeCompare((PetscObject)A, MATNORMAL, &chol->normal)); 259 } 260 CHKERRQ((*chol->Wrap)(A,PETSC_TRUE,&cholA,&aijalloc,&valloc)); 261 if (PetscDefined(USE_DEBUG)) { 262 CHKERRQ(!cholmod_l_check_sparse(&cholA, chol->common)); 263 } 264 if (chol->spqrfact) { 265 CHKERRQ(!SuiteSparseQR_C_free(&chol->spqrfact, chol->common)); 266 } 267 chol->spqrfact = SuiteSparseQR_C_symbolic(SPQR_ORDERING_DEFAULT, 1, &cholA, chol->common); 268 PetscCheckFalse(!chol->spqrfact,PetscObjectComm((PetscObject)F),PETSC_ERR_LIB,"CHOLMOD analysis failed using internal ordering with status %d",chol->common->status); 269 270 if (aijalloc) CHKERRQ(PetscFree2(cholA.p,cholA.i)); 271 if (valloc) CHKERRQ(PetscFree(cholA.x)); 272 273 CHKERRQ(PetscObjectComposeFunction((PetscObject)F,"MatQRFactorNumeric_C", MatQRFactorNumeric_SPQR)); 274 PetscFunctionReturn(0); 275 } 276 277 /*MC 278 MATSOLVERSPQR 279 280 A matrix type providing direct solvers (QR factorizations) for sequential matrices 281 via the external package SPQR. 282 283 Use ./configure --download-suitesparse to install PETSc to use CHOLMOD 284 285 Consult SPQR documentation for more information about the Common parameters 286 which correspond to the options database keys below. 287 288 Level: beginner 289 290 Note: SPQR is part of SuiteSparse http://faculty.cse.tamu.edu/davis/suitesparse.html 291 292 .seealso: PCQR, PCFactorSetMatSolverType(), MatSolverType 293 M*/ 294 295 PETSC_INTERN PetscErrorCode MatGetFactor_seqaij_spqr(Mat A,MatFactorType ftype,Mat *F) 296 { 297 Mat B; 298 Mat_CHOLMOD *chol; 299 PetscInt m=A->rmap->n,n=A->cmap->n; 300 const char *prefix; 301 302 PetscFunctionBegin; 303 /* Create the factorization matrix F */ 304 CHKERRQ(MatCreate(PetscObjectComm((PetscObject)A),&B)); 305 CHKERRQ(MatSetSizes(B,PETSC_DECIDE,PETSC_DECIDE,m,n)); 306 CHKERRQ(PetscStrallocpy("spqr",&((PetscObject)B)->type_name)); 307 CHKERRQ(MatGetOptionsPrefix(A,&prefix)); 308 CHKERRQ(MatSetOptionsPrefix(B,prefix)); 309 CHKERRQ(MatSetUp(B)); 310 CHKERRQ(PetscNewLog(B,&chol)); 311 312 chol->Wrap = MatWrapCholmod_SPQR_seqaij; 313 B->data = chol; 314 315 B->ops->getinfo = MatGetInfo_CHOLMOD; 316 B->ops->view = MatView_CHOLMOD; 317 B->ops->destroy = MatDestroy_CHOLMOD; 318 319 CHKERRQ(PetscObjectComposeFunction((PetscObject)B,"MatFactorGetSolverType_C",MatFactorGetSolverType_seqaij_SPQR)); 320 CHKERRQ(PetscObjectComposeFunction((PetscObject)B,"MatQRFactorSymbolic_C", MatQRFactorSymbolic_SPQR)); 321 322 B->factortype = MAT_FACTOR_QR; 323 B->assembled = PETSC_TRUE; 324 B->preallocated = PETSC_TRUE; 325 326 CHKERRQ(PetscFree(B->solvertype)); 327 CHKERRQ(PetscStrallocpy(MATSOLVERCHOLMOD,&B->solvertype)); 328 B->canuseordering = PETSC_FALSE; 329 CHKERRQ(CholmodStart(B)); 330 chol->common->itype = CHOLMOD_LONG; 331 *F = B; 332 PetscFunctionReturn(0); 333 } 334