xref: /petsc/src/mat/impls/aij/seq/spqr/aijspqr.c (revision e2b46ddf61ca707843fdebafd0bd150c6984485f)
1a2fc1e05SToby Isaac #include <petscsys.h>
2a2fc1e05SToby Isaac #include <../src/mat/impls/aij/seq/aij.h>
3a2fc1e05SToby Isaac #include <../src/mat/impls/sbaij/seq/cholmod/cholmodimpl.h>
4*e2b46ddfSPierre Jolivet #include <../src/mat/impls/shell/shell.h>
5a2fc1e05SToby Isaac 
6a2fc1e05SToby Isaac EXTERN_C_BEGIN
7a2fc1e05SToby Isaac #include <SuiteSparseQR_C.h>
8a2fc1e05SToby Isaac EXTERN_C_END
9a2fc1e05SToby Isaac 
10d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatWrapCholmod_SPQR_seqaij(Mat A, PetscBool values, cholmod_sparse *C, PetscBool *aijalloc, PetscBool *valloc)
11d71ae5a4SJacob Faibussowitsch {
12a2fc1e05SToby Isaac   Mat_SeqAIJ        *aij;
13*e2b46ddfSPierre Jolivet   Mat                AT, B  = NULL;
14*e2b46ddfSPierre Jolivet   const PetscScalar *aa, *L = NULL;
15a2fc1e05SToby Isaac   PetscScalar       *ca;
16a2fc1e05SToby Isaac   const PetscInt    *ai, *aj;
17a2fc1e05SToby Isaac   PetscInt           n = A->cmap->n, i, j, k, nz;
18a2fc1e05SToby Isaac   SuiteSparse_long  *ci, *cj; /* SuiteSparse_long is the only choice for SPQR */
1902ef7dfaSPierre Jolivet   PetscBool          vain = PETSC_FALSE, flg;
20a2fc1e05SToby Isaac 
21a2fc1e05SToby Isaac   PetscFunctionBegin;
229566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)A, MATNORMALHERMITIAN, &flg));
2365f45395SPierre Jolivet   if (flg) {
24*e2b46ddfSPierre Jolivet     PetscCall(MatNormalHermitianGetMat(A, &AT));
2565f45395SPierre Jolivet   } else if (!PetscDefined(USE_COMPLEX)) {
269566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)A, MATNORMAL, &flg));
27*e2b46ddfSPierre Jolivet     if (flg) PetscCall(MatNormalGetMat(A, &AT));
28*e2b46ddfSPierre Jolivet   }
29*e2b46ddfSPierre Jolivet   if (flg) {
30*e2b46ddfSPierre Jolivet     B = A;
31*e2b46ddfSPierre Jolivet     A = AT;
32*e2b46ddfSPierre Jolivet     PetscCheck(!((Mat_Shell *)B->data)->zrows && !((Mat_Shell *)B->data)->zcols, PetscObjectComm((PetscObject)B), PETSC_ERR_SUP, "Cannot call SuiteSparseQR if MatZeroRows() or MatZeroRowsColumns() has been called on the input Mat"); // TODO FIXME
33*e2b46ddfSPierre Jolivet     PetscCheck(!((Mat_Shell *)B->data)->axpy, PetscObjectComm((PetscObject)B), PETSC_ERR_SUP, "Cannot call SuiteSparseQR if MatAXPY() has been called on the input Mat");                                                                // TODO FIXME
34*e2b46ddfSPierre Jolivet     PetscCheck(((Mat_Shell *)B->data)->left == ((Mat_Shell *)B->data)->right, PetscObjectComm((PetscObject)B), PETSC_ERR_SUP, "Cannot call SuiteSparseQR if MatDiagonalScale() has been called on the input Mat with L != R");           // TODO FIXME
35*e2b46ddfSPierre Jolivet     if (values && ((Mat_Shell *)B->data)->left) {
36*e2b46ddfSPierre Jolivet       PetscCall(VecGetArrayRead(((Mat_Shell *)B->data)->left, &L));
37*e2b46ddfSPierre Jolivet #if PetscDefined(USE_COMPLEX)
38*e2b46ddfSPierre Jolivet       for (j = 0; j < n; j++)
39*e2b46ddfSPierre Jolivet         PetscCheck(PetscAbsReal(PetscImaginaryPart(L[j])) < PETSC_MACHINE_EPSILON, PetscObjectComm((PetscObject)B), PETSC_ERR_SUP, "Cannot call SuiteSparseQR if MatDiagonalScale() has been called on the input Mat with a complex Vec");
40*e2b46ddfSPierre Jolivet #endif
41*e2b46ddfSPierre Jolivet     }
42*e2b46ddfSPierre Jolivet     PetscCheck(!((Mat_Shell *)B->data)->dshift, PetscObjectComm((PetscObject)B), PETSC_ERR_SUP, "Cannot call SuiteSparseQR if MatDiagonalSet() has been called on the input Mat");                                  // TODO FIXME
43*e2b46ddfSPierre Jolivet     PetscCheck(PetscAbsScalar(((Mat_Shell *)B->data)->vshift) < PETSC_MACHINE_EPSILON, PetscObjectComm((PetscObject)B), PETSC_ERR_SUP, "Cannot call SuiteSparseQR if MatShift() has been called on the input Mat"); // TODO FIXME
4465f45395SPierre Jolivet   }
45a2fc1e05SToby Isaac   /* cholmod_sparse is compressed sparse column */
46b94d7dedSBarry Smith   PetscCall(MatIsSymmetric(A, 0.0, &flg));
4702ef7dfaSPierre Jolivet   if (flg) {
489566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)A));
49a2fc1e05SToby Isaac     AT = A;
50a2fc1e05SToby Isaac   } else {
519566063dSJacob Faibussowitsch     PetscCall(MatTranspose(A, MAT_INITIAL_MATRIX, &AT));
52a2fc1e05SToby Isaac   }
53a2fc1e05SToby Isaac   aij = (Mat_SeqAIJ *)AT->data;
54a2fc1e05SToby Isaac   ai  = aij->j;
55a2fc1e05SToby Isaac   aj  = aij->i;
56a2fc1e05SToby Isaac   for (j = 0, nz = 0; j < n; j++) nz += aj[j + 1] - aj[j];
579566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(n + 1, &cj, nz, &ci));
58a2fc1e05SToby Isaac   if (values) {
59a2fc1e05SToby Isaac     vain = PETSC_TRUE;
609566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nz, &ca));
619566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJGetArrayRead(AT, &aa));
62a2fc1e05SToby Isaac   }
63a2fc1e05SToby Isaac   for (j = 0, k = 0; j < n; j++) {
64a2fc1e05SToby Isaac     cj[j] = k;
65a2fc1e05SToby Isaac     for (i = aj[j]; i < aj[j + 1]; i++, k++) {
66a2fc1e05SToby Isaac       ci[k] = ai[i];
67*e2b46ddfSPierre Jolivet       if (values) {
68*e2b46ddfSPierre Jolivet         ca[k] = aa[i];
69*e2b46ddfSPierre Jolivet         if (L) ca[k] *= L[j];
70*e2b46ddfSPierre Jolivet       }
71a2fc1e05SToby Isaac     }
72a2fc1e05SToby Isaac   }
73a2fc1e05SToby Isaac   cj[j]     = k;
74a2fc1e05SToby Isaac   *aijalloc = PETSC_TRUE;
75a2fc1e05SToby Isaac   *valloc   = vain;
76*e2b46ddfSPierre Jolivet   if (values) {
77*e2b46ddfSPierre Jolivet     PetscCall(MatSeqAIJRestoreArrayRead(AT, &aa));
78*e2b46ddfSPierre Jolivet     if (L) PetscCall(VecRestoreArrayRead(((Mat_Shell *)B->data)->left, &L));
79*e2b46ddfSPierre Jolivet   }
80a2fc1e05SToby Isaac 
819566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(C, sizeof(*C)));
82a2fc1e05SToby Isaac 
8302ef7dfaSPierre Jolivet   C->nrow   = (size_t)AT->cmap->n;
8402ef7dfaSPierre Jolivet   C->ncol   = (size_t)AT->rmap->n;
85a2fc1e05SToby Isaac   C->nzmax  = (size_t)nz;
86a2fc1e05SToby Isaac   C->p      = cj;
87a2fc1e05SToby Isaac   C->i      = ci;
88a2fc1e05SToby Isaac   C->x      = values ? ca : 0;
89a2fc1e05SToby Isaac   C->stype  = 0;
90a2fc1e05SToby Isaac   C->itype  = CHOLMOD_LONG;
91a2fc1e05SToby Isaac   C->xtype  = values ? CHOLMOD_SCALAR_TYPE : CHOLMOD_PATTERN;
92a2fc1e05SToby Isaac   C->dtype  = CHOLMOD_DOUBLE;
93a2fc1e05SToby Isaac   C->sorted = 1;
94a2fc1e05SToby Isaac   C->packed = 1;
95a2fc1e05SToby Isaac 
969566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&AT));
973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
98a2fc1e05SToby Isaac }
99a2fc1e05SToby Isaac 
100d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatFactorGetSolverType_seqaij_SPQR(Mat A, MatSolverType *type)
101d71ae5a4SJacob Faibussowitsch {
102a2fc1e05SToby Isaac   PetscFunctionBegin;
103a2fc1e05SToby Isaac   *type = MATSOLVERSPQR;
1043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
105a2fc1e05SToby Isaac }
106a2fc1e05SToby Isaac 
107a2fc1e05SToby Isaac #define GET_ARRAY_READ  0
108a2fc1e05SToby Isaac #define GET_ARRAY_WRITE 1
109a2fc1e05SToby Isaac 
110d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSolve_SPQR_Internal(Mat F, cholmod_dense *cholB, cholmod_dense **_Y_handle)
111d71ae5a4SJacob Faibussowitsch {
112a2fc1e05SToby Isaac   Mat_CHOLMOD   *chol     = (Mat_CHOLMOD *)F->data;
11302ef7dfaSPierre Jolivet   cholmod_dense *Y_handle = NULL, *QTB_handle = NULL, *Z_handle = NULL;
114a2fc1e05SToby Isaac 
115a2fc1e05SToby Isaac   PetscFunctionBegin;
11602ef7dfaSPierre Jolivet   if (!chol->normal) {
117a2fc1e05SToby Isaac     QTB_handle = SuiteSparseQR_C_qmult(SPQR_QTX, chol->spqrfact, cholB, chol->common);
11828b400f6SJacob Faibussowitsch     PetscCheck(QTB_handle, PetscObjectComm((PetscObject)F), PETSC_ERR_LIB, "SuiteSparseQR_C_qmult failed");
119a2fc1e05SToby Isaac     Y_handle = SuiteSparseQR_C_solve(SPQR_RETX_EQUALS_B, chol->spqrfact, QTB_handle, chol->common);
12028b400f6SJacob Faibussowitsch     PetscCheck(Y_handle, PetscObjectComm((PetscObject)F), PETSC_ERR_LIB, "SuiteSparseQR_C_solve failed");
12102ef7dfaSPierre Jolivet   } else {
12202ef7dfaSPierre Jolivet     Z_handle = SuiteSparseQR_C_solve(SPQR_RTX_EQUALS_ETB, chol->spqrfact, cholB, chol->common);
12328b400f6SJacob Faibussowitsch     PetscCheck(Z_handle, PetscObjectComm((PetscObject)F), PETSC_ERR_LIB, "SuiteSparseQR_C_solve failed");
12402ef7dfaSPierre Jolivet     Y_handle = SuiteSparseQR_C_solve(SPQR_RETX_EQUALS_B, chol->spqrfact, Z_handle, chol->common);
12528b400f6SJacob Faibussowitsch     PetscCheck(Y_handle, PetscObjectComm((PetscObject)F), PETSC_ERR_LIB, "SuiteSparseQR_C_solve failed");
1263ba16761SJacob Faibussowitsch     PetscCallExternal(!cholmod_l_free_dense, &Z_handle, chol->common);
12702ef7dfaSPierre Jolivet   }
128a2fc1e05SToby Isaac   *_Y_handle = Y_handle;
1293ba16761SJacob Faibussowitsch   PetscCallExternal(!cholmod_l_free_dense, &QTB_handle, chol->common);
1303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
131a2fc1e05SToby Isaac }
132a2fc1e05SToby Isaac 
133d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSolve_SPQR(Mat F, Vec B, Vec X)
134d71ae5a4SJacob Faibussowitsch {
135a2fc1e05SToby Isaac   Mat_CHOLMOD  *chol = (Mat_CHOLMOD *)F->data;
136a2fc1e05SToby Isaac   cholmod_dense cholB, *Y_handle = NULL;
137a2fc1e05SToby Isaac   PetscInt      n;
138a2fc1e05SToby Isaac   PetscScalar  *v;
139a2fc1e05SToby Isaac 
140a2fc1e05SToby Isaac   PetscFunctionBegin;
1419566063dSJacob Faibussowitsch   PetscCall(VecWrapCholmod(B, GET_ARRAY_READ, &cholB));
1429566063dSJacob Faibussowitsch   PetscCall(MatSolve_SPQR_Internal(F, &cholB, &Y_handle));
1439566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(X, &n));
1449566063dSJacob Faibussowitsch   PetscCall(VecGetArrayWrite(X, &v));
1459566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(v, (PetscScalar *)(Y_handle->x), n));
1469566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayWrite(X, &v));
1473ba16761SJacob Faibussowitsch   PetscCallExternal(!cholmod_l_free_dense, &Y_handle, chol->common);
1489566063dSJacob Faibussowitsch   PetscCall(VecUnWrapCholmod(B, GET_ARRAY_READ, &cholB));
149*e2b46ddfSPierre Jolivet   PetscCall(VecScale(X, chol->scale));
1503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
151a2fc1e05SToby Isaac }
152a2fc1e05SToby Isaac 
153d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMatSolve_SPQR(Mat F, Mat B, Mat X)
154d71ae5a4SJacob Faibussowitsch {
155a2fc1e05SToby Isaac   Mat_CHOLMOD  *chol = (Mat_CHOLMOD *)F->data;
156a2fc1e05SToby Isaac   cholmod_dense cholB, *Y_handle = NULL;
157a2fc1e05SToby Isaac   PetscScalar  *v;
158a2fc1e05SToby Isaac   PetscInt      lda;
159a2fc1e05SToby Isaac 
160a2fc1e05SToby Isaac   PetscFunctionBegin;
1619566063dSJacob Faibussowitsch   PetscCall(MatDenseWrapCholmod(B, GET_ARRAY_READ, &cholB));
1629566063dSJacob Faibussowitsch   PetscCall(MatSolve_SPQR_Internal(F, &cholB, &Y_handle));
1639566063dSJacob Faibussowitsch   PetscCall(MatDenseGetArrayWrite(X, &v));
1649566063dSJacob Faibussowitsch   PetscCall(MatDenseGetLDA(X, &lda));
165a2fc1e05SToby Isaac   if ((size_t)lda == Y_handle->d) {
1669566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(v, (PetscScalar *)(Y_handle->x), lda * Y_handle->ncol));
167a2fc1e05SToby Isaac   } else {
16848a46eb9SPierre Jolivet     for (size_t j = 0; j < Y_handle->ncol; j++) PetscCall(PetscArraycpy(&v[j * lda], &(((PetscScalar *)Y_handle->x)[j * Y_handle->d]), Y_handle->nrow));
169a2fc1e05SToby Isaac   }
1709566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArrayWrite(X, &v));
1713ba16761SJacob Faibussowitsch   PetscCallExternal(!cholmod_l_free_dense, &Y_handle, chol->common);
1729566063dSJacob Faibussowitsch   PetscCall(MatDenseUnWrapCholmod(B, GET_ARRAY_READ, &cholB));
173*e2b46ddfSPierre Jolivet   PetscCall(MatScale(X, chol->scale));
1743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
175a2fc1e05SToby Isaac }
176a2fc1e05SToby Isaac 
177d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSolveTranspose_SPQR_Internal(Mat F, cholmod_dense *cholB, cholmod_dense **_Y_handle)
178d71ae5a4SJacob Faibussowitsch {
179a2fc1e05SToby Isaac   Mat_CHOLMOD   *chol     = (Mat_CHOLMOD *)F->data;
180a2fc1e05SToby Isaac   cholmod_dense *Y_handle = NULL, *RTB_handle = NULL;
181a2fc1e05SToby Isaac 
182a2fc1e05SToby Isaac   PetscFunctionBegin;
183a2fc1e05SToby Isaac   RTB_handle = SuiteSparseQR_C_solve(SPQR_RTX_EQUALS_ETB, chol->spqrfact, cholB, chol->common);
18428b400f6SJacob Faibussowitsch   PetscCheck(RTB_handle, PetscObjectComm((PetscObject)F), PETSC_ERR_LIB, "SuiteSparseQR_C_solve failed");
185a2fc1e05SToby Isaac   Y_handle = SuiteSparseQR_C_qmult(SPQR_QX, chol->spqrfact, RTB_handle, chol->common);
18628b400f6SJacob Faibussowitsch   PetscCheck(Y_handle, PetscObjectComm((PetscObject)F), PETSC_ERR_LIB, "SuiteSparseQR_C_qmult failed");
187a2fc1e05SToby Isaac   *_Y_handle = Y_handle;
1883ba16761SJacob Faibussowitsch   PetscCallExternal(!cholmod_l_free_dense, &RTB_handle, chol->common);
1893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
190a2fc1e05SToby Isaac }
191a2fc1e05SToby Isaac 
192d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSolveTranspose_SPQR(Mat F, Vec B, Vec X)
193d71ae5a4SJacob Faibussowitsch {
194a2fc1e05SToby Isaac   Mat_CHOLMOD  *chol = (Mat_CHOLMOD *)F->data;
195a2fc1e05SToby Isaac   cholmod_dense cholB, *Y_handle = NULL;
196a2fc1e05SToby Isaac   PetscInt      n;
197a2fc1e05SToby Isaac   PetscScalar  *v;
198a2fc1e05SToby Isaac 
199a2fc1e05SToby Isaac   PetscFunctionBegin;
2009566063dSJacob Faibussowitsch   PetscCall(VecWrapCholmod(B, GET_ARRAY_READ, &cholB));
2019566063dSJacob Faibussowitsch   PetscCall(MatSolveTranspose_SPQR_Internal(F, &cholB, &Y_handle));
2029566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(X, &n));
2039566063dSJacob Faibussowitsch   PetscCall(VecGetArrayWrite(X, &v));
2049566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(v, (PetscScalar *)Y_handle->x, n));
2059566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayWrite(X, &v));
2063ba16761SJacob Faibussowitsch   PetscCallExternal(!cholmod_l_free_dense, &Y_handle, chol->common);
2079566063dSJacob Faibussowitsch   PetscCall(VecUnWrapCholmod(B, GET_ARRAY_READ, &cholB));
2083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
209a2fc1e05SToby Isaac }
210a2fc1e05SToby Isaac 
211d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMatSolveTranspose_SPQR(Mat F, Mat B, Mat X)
212d71ae5a4SJacob Faibussowitsch {
213a2fc1e05SToby Isaac   Mat_CHOLMOD  *chol = (Mat_CHOLMOD *)F->data;
214a2fc1e05SToby Isaac   cholmod_dense cholB, *Y_handle = NULL;
215a2fc1e05SToby Isaac   PetscScalar  *v;
216a2fc1e05SToby Isaac   PetscInt      lda;
217a2fc1e05SToby Isaac 
218a2fc1e05SToby Isaac   PetscFunctionBegin;
2199566063dSJacob Faibussowitsch   PetscCall(MatDenseWrapCholmod(B, GET_ARRAY_READ, &cholB));
2209566063dSJacob Faibussowitsch   PetscCall(MatSolveTranspose_SPQR_Internal(F, &cholB, &Y_handle));
2219566063dSJacob Faibussowitsch   PetscCall(MatDenseGetArrayWrite(X, &v));
2229566063dSJacob Faibussowitsch   PetscCall(MatDenseGetLDA(X, &lda));
223a2fc1e05SToby Isaac   if ((size_t)lda == Y_handle->d) {
2249566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(v, (PetscScalar *)Y_handle->x, lda * Y_handle->ncol));
225a2fc1e05SToby Isaac   } else {
22648a46eb9SPierre Jolivet     for (size_t j = 0; j < Y_handle->ncol; j++) PetscCall(PetscArraycpy(&v[j * lda], &(((PetscScalar *)Y_handle->x)[j * Y_handle->d]), Y_handle->nrow));
227a2fc1e05SToby Isaac   }
2289566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArrayWrite(X, &v));
2293ba16761SJacob Faibussowitsch   PetscCallExternal(!cholmod_l_free_dense, &Y_handle, chol->common);
2309566063dSJacob Faibussowitsch   PetscCall(MatDenseUnWrapCholmod(B, GET_ARRAY_READ, &cholB));
2313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
232a2fc1e05SToby Isaac }
233a2fc1e05SToby Isaac 
234d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatQRFactorNumeric_SPQR(Mat F, Mat A, const MatFactorInfo *info)
235d71ae5a4SJacob Faibussowitsch {
236a2fc1e05SToby Isaac   Mat_CHOLMOD   *chol = (Mat_CHOLMOD *)F->data;
237a2fc1e05SToby Isaac   cholmod_sparse cholA;
23865f45395SPierre Jolivet   PetscBool      aijalloc, valloc;
239d0609cedSBarry Smith   int            err;
240a2fc1e05SToby Isaac 
241a2fc1e05SToby Isaac   PetscFunctionBegin;
2429566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)A, MATNORMALHERMITIAN, &chol->normal));
24348a46eb9SPierre Jolivet   if (!chol->normal && !PetscDefined(USE_COMPLEX)) PetscCall(PetscObjectTypeCompare((PetscObject)A, MATNORMAL, &chol->normal));
2449566063dSJacob Faibussowitsch   PetscCall((*chol->Wrap)(A, PETSC_TRUE, &cholA, &aijalloc, &valloc));
245d0609cedSBarry Smith   err = !SuiteSparseQR_C_numeric(PETSC_SMALL, &cholA, chol->spqrfact, chol->common);
246d0609cedSBarry Smith   PetscCheck(!err, PetscObjectComm((PetscObject)F), PETSC_ERR_LIB, "SPQR factorization failed with status %d", chol->common->status);
247a2fc1e05SToby Isaac 
2489566063dSJacob Faibussowitsch   if (aijalloc) PetscCall(PetscFree2(cholA.p, cholA.i));
2499566063dSJacob Faibussowitsch   if (valloc) PetscCall(PetscFree(cholA.x));
250a2fc1e05SToby Isaac 
251a2fc1e05SToby Isaac   F->ops->solve    = MatSolve_SPQR;
252a2fc1e05SToby Isaac   F->ops->matsolve = MatMatSolve_SPQR;
25302ef7dfaSPierre Jolivet   if (chol->normal) {
25402ef7dfaSPierre Jolivet     F->ops->solvetranspose    = MatSolve_SPQR;
25502ef7dfaSPierre Jolivet     F->ops->matsolvetranspose = MatMatSolve_SPQR;
256*e2b46ddfSPierre Jolivet     chol->scale               = 1.0 / ((Mat_Shell *)A->data)->vscale;
25702ef7dfaSPierre Jolivet   } else if (A->cmap->n == A->rmap->n) {
258a2fc1e05SToby Isaac     F->ops->solvetranspose    = MatSolveTranspose_SPQR;
259a2fc1e05SToby Isaac     F->ops->matsolvetranspose = MatMatSolveTranspose_SPQR;
260*e2b46ddfSPierre Jolivet     chol->scale               = 1.0;
261a2fc1e05SToby Isaac   }
2623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
263a2fc1e05SToby Isaac }
264a2fc1e05SToby Isaac 
265d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatQRFactorSymbolic_SPQR(Mat F, Mat A, IS perm, const MatFactorInfo *info)
266d71ae5a4SJacob Faibussowitsch {
267a2fc1e05SToby Isaac   Mat_CHOLMOD   *chol = (Mat_CHOLMOD *)F->data;
268a2fc1e05SToby Isaac   cholmod_sparse cholA;
26965f45395SPierre Jolivet   PetscBool      aijalloc, valloc;
270a2fc1e05SToby Isaac 
271a2fc1e05SToby Isaac   PetscFunctionBegin;
2729566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)A, MATNORMALHERMITIAN, &chol->normal));
27348a46eb9SPierre Jolivet   if (!chol->normal && !PetscDefined(USE_COMPLEX)) PetscCall(PetscObjectTypeCompare((PetscObject)A, MATNORMAL, &chol->normal));
2749566063dSJacob Faibussowitsch   PetscCall((*chol->Wrap)(A, PETSC_TRUE, &cholA, &aijalloc, &valloc));
2753ba16761SJacob Faibussowitsch   if (PetscDefined(USE_DEBUG)) PetscCallExternal(!cholmod_l_check_sparse, &cholA, chol->common);
2763ba16761SJacob Faibussowitsch   if (chol->spqrfact) PetscCallExternal(!SuiteSparseQR_C_free, &chol->spqrfact, chol->common);
277d0f82a0bSPierre Jolivet   chol->spqrfact = SuiteSparseQR_C_symbolic(SPQR_ORDERING_DEFAULT, 1, &cholA, chol->common);
27828b400f6SJacob Faibussowitsch   PetscCheck(chol->spqrfact, PetscObjectComm((PetscObject)F), PETSC_ERR_LIB, "CHOLMOD analysis failed using internal ordering with status %d", chol->common->status);
279a2fc1e05SToby Isaac 
2809566063dSJacob Faibussowitsch   if (aijalloc) PetscCall(PetscFree2(cholA.p, cholA.i));
2819566063dSJacob Faibussowitsch   if (valloc) PetscCall(PetscFree(cholA.x));
282a2fc1e05SToby Isaac 
2839566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)F, "MatQRFactorNumeric_C", MatQRFactorNumeric_SPQR));
2843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
285a2fc1e05SToby Isaac }
286a2fc1e05SToby Isaac 
287a2fc1e05SToby Isaac /*MC
288a2fc1e05SToby Isaac   MATSOLVERSPQR
289a2fc1e05SToby Isaac 
29011a5261eSBarry Smith   A matrix type providing direct solvers, QR factorizations, for sequential matrices
291a2fc1e05SToby Isaac   via the external package SPQR.
292a2fc1e05SToby Isaac 
2932ef1f0ffSBarry Smith   Use `./configure --download-suitesparse` to install PETSc to use SPQR
294a2fc1e05SToby Isaac 
29511a5261eSBarry Smith   Consult SPQR documentation for more information about the common parameters
296a2fc1e05SToby Isaac   which correspond to the options database keys below.
297a2fc1e05SToby Isaac 
298a2fc1e05SToby Isaac    Level: beginner
299a2fc1e05SToby Isaac 
30011a5261eSBarry Smith    Note:
3011d27aa22SBarry Smith    SPQR is part of SuiteSparse <http://faculty.cse.tamu.edu/davis/suitesparse.html>
302a2fc1e05SToby Isaac 
3031cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `PCQR`, `PCFactorSetMatSolverType()`, `MatSolverType`
304a2fc1e05SToby Isaac M*/
305a2fc1e05SToby Isaac 
306d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatGetFactor_seqaij_spqr(Mat A, MatFactorType ftype, Mat *F)
307d71ae5a4SJacob Faibussowitsch {
308a2fc1e05SToby Isaac   Mat          B;
309a2fc1e05SToby Isaac   Mat_CHOLMOD *chol;
310a2fc1e05SToby Isaac   PetscInt     m = A->rmap->n, n = A->cmap->n;
311a2fc1e05SToby Isaac   const char  *prefix;
312a2fc1e05SToby Isaac 
313a2fc1e05SToby Isaac   PetscFunctionBegin;
314a2fc1e05SToby Isaac   /* Create the factorization matrix F */
3159566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &B));
3169566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(B, PETSC_DECIDE, PETSC_DECIDE, m, n));
3179566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy("spqr", &((PetscObject)B)->type_name));
3189566063dSJacob Faibussowitsch   PetscCall(MatGetOptionsPrefix(A, &prefix));
3199566063dSJacob Faibussowitsch   PetscCall(MatSetOptionsPrefix(B, prefix));
3209566063dSJacob Faibussowitsch   PetscCall(MatSetUp(B));
3214dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&chol));
322a2fc1e05SToby Isaac 
323a2fc1e05SToby Isaac   chol->Wrap = MatWrapCholmod_SPQR_seqaij;
324a2fc1e05SToby Isaac   B->data    = chol;
325a2fc1e05SToby Isaac 
326a2fc1e05SToby Isaac   B->ops->getinfo = MatGetInfo_CHOLMOD;
327a2fc1e05SToby Isaac   B->ops->view    = MatView_CHOLMOD;
328a2fc1e05SToby Isaac   B->ops->destroy = MatDestroy_CHOLMOD;
329a2fc1e05SToby Isaac 
3309566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatFactorGetSolverType_C", MatFactorGetSolverType_seqaij_SPQR));
3319566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatQRFactorSymbolic_C", MatQRFactorSymbolic_SPQR));
332a2fc1e05SToby Isaac 
333a2fc1e05SToby Isaac   B->factortype   = MAT_FACTOR_QR;
334a2fc1e05SToby Isaac   B->assembled    = PETSC_TRUE;
335a2fc1e05SToby Isaac   B->preallocated = PETSC_TRUE;
336a2fc1e05SToby Isaac 
3379566063dSJacob Faibussowitsch   PetscCall(PetscFree(B->solvertype));
3389566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(MATSOLVERCHOLMOD, &B->solvertype));
339a2fc1e05SToby Isaac   B->canuseordering = PETSC_FALSE;
3409566063dSJacob Faibussowitsch   PetscCall(CholmodStart(B));
341a2fc1e05SToby Isaac   chol->common->itype = CHOLMOD_LONG;
342a2fc1e05SToby Isaac   *F                  = B;
3433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
344a2fc1e05SToby Isaac }
345