xref: /petsc/src/mat/impls/aij/seq/spqr/aijspqr.c (revision b9c875b8ccb0466cfbdbcc08c79b487b3a7d395f)
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>
4a2fc1e05SToby Isaac 
5a2fc1e05SToby Isaac EXTERN_C_BEGIN
6a2fc1e05SToby Isaac #include <SuiteSparseQR_C.h>
7a2fc1e05SToby Isaac EXTERN_C_END
8a2fc1e05SToby Isaac 
9d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatWrapCholmod_SPQR_seqaij(Mat A, PetscBool values, cholmod_sparse *C, PetscBool *aijalloc, PetscBool *valloc)
10d71ae5a4SJacob Faibussowitsch {
11a2fc1e05SToby Isaac   Mat_SeqAIJ        *aij;
12e2b46ddfSPierre Jolivet   Mat                AT, B = NULL;
13*b9c875b8SPierre Jolivet   Vec                left, right;
14e2b46ddfSPierre Jolivet   const PetscScalar *aa, *L = NULL;
15*b9c875b8SPierre Jolivet   PetscScalar       *ca, scale;
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) {
24e2b46ddfSPierre Jolivet     PetscCall(MatNormalHermitianGetMat(A, &AT));
2565f45395SPierre Jolivet   } else if (!PetscDefined(USE_COMPLEX)) {
269566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)A, MATNORMAL, &flg));
27e2b46ddfSPierre Jolivet     if (flg) PetscCall(MatNormalGetMat(A, &AT));
28e2b46ddfSPierre Jolivet   }
29e2b46ddfSPierre Jolivet   if (flg) {
30e2b46ddfSPierre Jolivet     B = A;
31e2b46ddfSPierre Jolivet     A = AT;
32*b9c875b8SPierre Jolivet     PetscCall(MatShellGetScalingShifts(B, (PetscScalar *)MAT_SHELL_NOT_ALLOWED, &scale, (Vec *)MAT_SHELL_NOT_ALLOWED, &left, &right, (Mat *)MAT_SHELL_NOT_ALLOWED, (IS *)MAT_SHELL_NOT_ALLOWED, (IS *)MAT_SHELL_NOT_ALLOWED));
33*b9c875b8SPierre Jolivet     PetscCheck(left == right, PetscObjectComm((PetscObject)B), PETSC_ERR_SUP, "Cannot call SuiteSparseQR if MatDiagonalScale() has been called on the input Mat with L != R");
34*b9c875b8SPierre Jolivet     if (values && left) {
35*b9c875b8SPierre Jolivet       PetscCall(VecGetArrayRead(left, &L));
36e2b46ddfSPierre Jolivet #if PetscDefined(USE_COMPLEX)
37e2b46ddfSPierre Jolivet       for (j = 0; j < n; j++)
38e2b46ddfSPierre 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");
39e2b46ddfSPierre Jolivet #endif
40e2b46ddfSPierre Jolivet     }
4165f45395SPierre Jolivet   }
42a2fc1e05SToby Isaac   /* cholmod_sparse is compressed sparse column */
43b94d7dedSBarry Smith   PetscCall(MatIsSymmetric(A, 0.0, &flg));
4402ef7dfaSPierre Jolivet   if (flg) {
459566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)A));
46a2fc1e05SToby Isaac     AT = A;
47a2fc1e05SToby Isaac   } else {
489566063dSJacob Faibussowitsch     PetscCall(MatTranspose(A, MAT_INITIAL_MATRIX, &AT));
49a2fc1e05SToby Isaac   }
50a2fc1e05SToby Isaac   aij = (Mat_SeqAIJ *)AT->data;
51a2fc1e05SToby Isaac   ai  = aij->j;
52a2fc1e05SToby Isaac   aj  = aij->i;
53a2fc1e05SToby Isaac   for (j = 0, nz = 0; j < n; j++) nz += aj[j + 1] - aj[j];
549566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(n + 1, &cj, nz, &ci));
55a2fc1e05SToby Isaac   if (values) {
56a2fc1e05SToby Isaac     vain = PETSC_TRUE;
579566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nz, &ca));
589566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJGetArrayRead(AT, &aa));
59a2fc1e05SToby Isaac   }
60a2fc1e05SToby Isaac   for (j = 0, k = 0; j < n; j++) {
61a2fc1e05SToby Isaac     cj[j] = k;
62a2fc1e05SToby Isaac     for (i = aj[j]; i < aj[j + 1]; i++, k++) {
63a2fc1e05SToby Isaac       ci[k] = ai[i];
64e2b46ddfSPierre Jolivet       if (values) {
65e2b46ddfSPierre Jolivet         ca[k] = aa[i];
66e2b46ddfSPierre Jolivet         if (L) ca[k] *= L[j];
67e2b46ddfSPierre Jolivet       }
68a2fc1e05SToby Isaac     }
69a2fc1e05SToby Isaac   }
70a2fc1e05SToby Isaac   cj[j]     = k;
71a2fc1e05SToby Isaac   *aijalloc = PETSC_TRUE;
72a2fc1e05SToby Isaac   *valloc   = vain;
73e2b46ddfSPierre Jolivet   if (values) {
74e2b46ddfSPierre Jolivet     PetscCall(MatSeqAIJRestoreArrayRead(AT, &aa));
75*b9c875b8SPierre Jolivet     if (L) PetscCall(VecRestoreArrayRead(left, &L));
76e2b46ddfSPierre Jolivet   }
77a2fc1e05SToby Isaac 
789566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(C, sizeof(*C)));
79a2fc1e05SToby Isaac 
8002ef7dfaSPierre Jolivet   C->nrow   = (size_t)AT->cmap->n;
8102ef7dfaSPierre Jolivet   C->ncol   = (size_t)AT->rmap->n;
82a2fc1e05SToby Isaac   C->nzmax  = (size_t)nz;
83a2fc1e05SToby Isaac   C->p      = cj;
84a2fc1e05SToby Isaac   C->i      = ci;
85a2fc1e05SToby Isaac   C->x      = values ? ca : 0;
86a2fc1e05SToby Isaac   C->stype  = 0;
87a2fc1e05SToby Isaac   C->itype  = CHOLMOD_LONG;
88a2fc1e05SToby Isaac   C->xtype  = values ? CHOLMOD_SCALAR_TYPE : CHOLMOD_PATTERN;
89a2fc1e05SToby Isaac   C->dtype  = CHOLMOD_DOUBLE;
90a2fc1e05SToby Isaac   C->sorted = 1;
91a2fc1e05SToby Isaac   C->packed = 1;
92a2fc1e05SToby Isaac 
939566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&AT));
943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
95a2fc1e05SToby Isaac }
96a2fc1e05SToby Isaac 
97d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatFactorGetSolverType_seqaij_SPQR(Mat A, MatSolverType *type)
98d71ae5a4SJacob Faibussowitsch {
99a2fc1e05SToby Isaac   PetscFunctionBegin;
100a2fc1e05SToby Isaac   *type = MATSOLVERSPQR;
1013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
102a2fc1e05SToby Isaac }
103a2fc1e05SToby Isaac 
104a2fc1e05SToby Isaac #define GET_ARRAY_READ  0
105a2fc1e05SToby Isaac #define GET_ARRAY_WRITE 1
106a2fc1e05SToby Isaac 
107d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSolve_SPQR_Internal(Mat F, cholmod_dense *cholB, cholmod_dense **_Y_handle)
108d71ae5a4SJacob Faibussowitsch {
109a2fc1e05SToby Isaac   Mat_CHOLMOD   *chol     = (Mat_CHOLMOD *)F->data;
11002ef7dfaSPierre Jolivet   cholmod_dense *Y_handle = NULL, *QTB_handle = NULL, *Z_handle = NULL;
111a2fc1e05SToby Isaac 
112a2fc1e05SToby Isaac   PetscFunctionBegin;
11302ef7dfaSPierre Jolivet   if (!chol->normal) {
114a2fc1e05SToby Isaac     QTB_handle = SuiteSparseQR_C_qmult(SPQR_QTX, chol->spqrfact, cholB, chol->common);
11528b400f6SJacob Faibussowitsch     PetscCheck(QTB_handle, PetscObjectComm((PetscObject)F), PETSC_ERR_LIB, "SuiteSparseQR_C_qmult failed");
116a2fc1e05SToby Isaac     Y_handle = SuiteSparseQR_C_solve(SPQR_RETX_EQUALS_B, chol->spqrfact, QTB_handle, chol->common);
11728b400f6SJacob Faibussowitsch     PetscCheck(Y_handle, PetscObjectComm((PetscObject)F), PETSC_ERR_LIB, "SuiteSparseQR_C_solve failed");
11802ef7dfaSPierre Jolivet   } else {
11902ef7dfaSPierre Jolivet     Z_handle = SuiteSparseQR_C_solve(SPQR_RTX_EQUALS_ETB, chol->spqrfact, cholB, chol->common);
12028b400f6SJacob Faibussowitsch     PetscCheck(Z_handle, PetscObjectComm((PetscObject)F), PETSC_ERR_LIB, "SuiteSparseQR_C_solve failed");
12102ef7dfaSPierre Jolivet     Y_handle = SuiteSparseQR_C_solve(SPQR_RETX_EQUALS_B, chol->spqrfact, Z_handle, chol->common);
12228b400f6SJacob Faibussowitsch     PetscCheck(Y_handle, PetscObjectComm((PetscObject)F), PETSC_ERR_LIB, "SuiteSparseQR_C_solve failed");
1233ba16761SJacob Faibussowitsch     PetscCallExternal(!cholmod_l_free_dense, &Z_handle, chol->common);
12402ef7dfaSPierre Jolivet   }
125a2fc1e05SToby Isaac   *_Y_handle = Y_handle;
1263ba16761SJacob Faibussowitsch   PetscCallExternal(!cholmod_l_free_dense, &QTB_handle, chol->common);
1273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
128a2fc1e05SToby Isaac }
129a2fc1e05SToby Isaac 
130d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSolve_SPQR(Mat F, Vec B, Vec X)
131d71ae5a4SJacob Faibussowitsch {
132a2fc1e05SToby Isaac   Mat_CHOLMOD  *chol = (Mat_CHOLMOD *)F->data;
133a2fc1e05SToby Isaac   cholmod_dense cholB, *Y_handle = NULL;
134a2fc1e05SToby Isaac   PetscInt      n;
135a2fc1e05SToby Isaac   PetscScalar  *v;
136a2fc1e05SToby Isaac 
137a2fc1e05SToby Isaac   PetscFunctionBegin;
1389566063dSJacob Faibussowitsch   PetscCall(VecWrapCholmod(B, GET_ARRAY_READ, &cholB));
1399566063dSJacob Faibussowitsch   PetscCall(MatSolve_SPQR_Internal(F, &cholB, &Y_handle));
1409566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(X, &n));
1419566063dSJacob Faibussowitsch   PetscCall(VecGetArrayWrite(X, &v));
142f4f49eeaSPierre Jolivet   PetscCall(PetscArraycpy(v, (PetscScalar *)Y_handle->x, n));
1439566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayWrite(X, &v));
1443ba16761SJacob Faibussowitsch   PetscCallExternal(!cholmod_l_free_dense, &Y_handle, chol->common);
1459566063dSJacob Faibussowitsch   PetscCall(VecUnWrapCholmod(B, GET_ARRAY_READ, &cholB));
146e2b46ddfSPierre Jolivet   PetscCall(VecScale(X, chol->scale));
1473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
148a2fc1e05SToby Isaac }
149a2fc1e05SToby Isaac 
150d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMatSolve_SPQR(Mat F, Mat B, Mat X)
151d71ae5a4SJacob Faibussowitsch {
152a2fc1e05SToby Isaac   Mat_CHOLMOD  *chol = (Mat_CHOLMOD *)F->data;
153a2fc1e05SToby Isaac   cholmod_dense cholB, *Y_handle = NULL;
154a2fc1e05SToby Isaac   PetscScalar  *v;
155a2fc1e05SToby Isaac   PetscInt      lda;
156a2fc1e05SToby Isaac 
157a2fc1e05SToby Isaac   PetscFunctionBegin;
1589566063dSJacob Faibussowitsch   PetscCall(MatDenseWrapCholmod(B, GET_ARRAY_READ, &cholB));
1599566063dSJacob Faibussowitsch   PetscCall(MatSolve_SPQR_Internal(F, &cholB, &Y_handle));
1609566063dSJacob Faibussowitsch   PetscCall(MatDenseGetArrayWrite(X, &v));
1619566063dSJacob Faibussowitsch   PetscCall(MatDenseGetLDA(X, &lda));
162a2fc1e05SToby Isaac   if ((size_t)lda == Y_handle->d) {
163f4f49eeaSPierre Jolivet     PetscCall(PetscArraycpy(v, (PetscScalar *)Y_handle->x, lda * Y_handle->ncol));
164a2fc1e05SToby Isaac   } else {
16548a46eb9SPierre 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));
166a2fc1e05SToby Isaac   }
1679566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArrayWrite(X, &v));
1683ba16761SJacob Faibussowitsch   PetscCallExternal(!cholmod_l_free_dense, &Y_handle, chol->common);
1699566063dSJacob Faibussowitsch   PetscCall(MatDenseUnWrapCholmod(B, GET_ARRAY_READ, &cholB));
170e2b46ddfSPierre Jolivet   PetscCall(MatScale(X, chol->scale));
1713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
172a2fc1e05SToby Isaac }
173a2fc1e05SToby Isaac 
174d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSolveTranspose_SPQR_Internal(Mat F, cholmod_dense *cholB, cholmod_dense **_Y_handle)
175d71ae5a4SJacob Faibussowitsch {
176a2fc1e05SToby Isaac   Mat_CHOLMOD   *chol     = (Mat_CHOLMOD *)F->data;
177a2fc1e05SToby Isaac   cholmod_dense *Y_handle = NULL, *RTB_handle = NULL;
178a2fc1e05SToby Isaac 
179a2fc1e05SToby Isaac   PetscFunctionBegin;
180a2fc1e05SToby Isaac   RTB_handle = SuiteSparseQR_C_solve(SPQR_RTX_EQUALS_ETB, chol->spqrfact, cholB, chol->common);
18128b400f6SJacob Faibussowitsch   PetscCheck(RTB_handle, PetscObjectComm((PetscObject)F), PETSC_ERR_LIB, "SuiteSparseQR_C_solve failed");
182a2fc1e05SToby Isaac   Y_handle = SuiteSparseQR_C_qmult(SPQR_QX, chol->spqrfact, RTB_handle, chol->common);
18328b400f6SJacob Faibussowitsch   PetscCheck(Y_handle, PetscObjectComm((PetscObject)F), PETSC_ERR_LIB, "SuiteSparseQR_C_qmult failed");
184a2fc1e05SToby Isaac   *_Y_handle = Y_handle;
1853ba16761SJacob Faibussowitsch   PetscCallExternal(!cholmod_l_free_dense, &RTB_handle, chol->common);
1863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
187a2fc1e05SToby Isaac }
188a2fc1e05SToby Isaac 
189d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSolveTranspose_SPQR(Mat F, Vec B, Vec X)
190d71ae5a4SJacob Faibussowitsch {
191a2fc1e05SToby Isaac   Mat_CHOLMOD  *chol = (Mat_CHOLMOD *)F->data;
192a2fc1e05SToby Isaac   cholmod_dense cholB, *Y_handle = NULL;
193a2fc1e05SToby Isaac   PetscInt      n;
194a2fc1e05SToby Isaac   PetscScalar  *v;
195a2fc1e05SToby Isaac 
196a2fc1e05SToby Isaac   PetscFunctionBegin;
1979566063dSJacob Faibussowitsch   PetscCall(VecWrapCholmod(B, GET_ARRAY_READ, &cholB));
1989566063dSJacob Faibussowitsch   PetscCall(MatSolveTranspose_SPQR_Internal(F, &cholB, &Y_handle));
1999566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(X, &n));
2009566063dSJacob Faibussowitsch   PetscCall(VecGetArrayWrite(X, &v));
2019566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(v, (PetscScalar *)Y_handle->x, n));
2029566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayWrite(X, &v));
2033ba16761SJacob Faibussowitsch   PetscCallExternal(!cholmod_l_free_dense, &Y_handle, chol->common);
2049566063dSJacob Faibussowitsch   PetscCall(VecUnWrapCholmod(B, GET_ARRAY_READ, &cholB));
2053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
206a2fc1e05SToby Isaac }
207a2fc1e05SToby Isaac 
208d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMatSolveTranspose_SPQR(Mat F, Mat B, Mat X)
209d71ae5a4SJacob Faibussowitsch {
210a2fc1e05SToby Isaac   Mat_CHOLMOD  *chol = (Mat_CHOLMOD *)F->data;
211a2fc1e05SToby Isaac   cholmod_dense cholB, *Y_handle = NULL;
212a2fc1e05SToby Isaac   PetscScalar  *v;
213a2fc1e05SToby Isaac   PetscInt      lda;
214a2fc1e05SToby Isaac 
215a2fc1e05SToby Isaac   PetscFunctionBegin;
2169566063dSJacob Faibussowitsch   PetscCall(MatDenseWrapCholmod(B, GET_ARRAY_READ, &cholB));
2179566063dSJacob Faibussowitsch   PetscCall(MatSolveTranspose_SPQR_Internal(F, &cholB, &Y_handle));
2189566063dSJacob Faibussowitsch   PetscCall(MatDenseGetArrayWrite(X, &v));
2199566063dSJacob Faibussowitsch   PetscCall(MatDenseGetLDA(X, &lda));
220a2fc1e05SToby Isaac   if ((size_t)lda == Y_handle->d) {
2219566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(v, (PetscScalar *)Y_handle->x, lda * Y_handle->ncol));
222a2fc1e05SToby Isaac   } else {
22348a46eb9SPierre 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));
224a2fc1e05SToby Isaac   }
2259566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArrayWrite(X, &v));
2263ba16761SJacob Faibussowitsch   PetscCallExternal(!cholmod_l_free_dense, &Y_handle, chol->common);
2279566063dSJacob Faibussowitsch   PetscCall(MatDenseUnWrapCholmod(B, GET_ARRAY_READ, &cholB));
2283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
229a2fc1e05SToby Isaac }
230a2fc1e05SToby Isaac 
231d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatQRFactorNumeric_SPQR(Mat F, Mat A, const MatFactorInfo *info)
232d71ae5a4SJacob Faibussowitsch {
233a2fc1e05SToby Isaac   Mat_CHOLMOD   *chol = (Mat_CHOLMOD *)F->data;
234a2fc1e05SToby Isaac   cholmod_sparse cholA;
23565f45395SPierre Jolivet   PetscBool      aijalloc, valloc;
236d0609cedSBarry Smith   int            err;
237a2fc1e05SToby Isaac 
238a2fc1e05SToby Isaac   PetscFunctionBegin;
2399566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)A, MATNORMALHERMITIAN, &chol->normal));
24048a46eb9SPierre Jolivet   if (!chol->normal && !PetscDefined(USE_COMPLEX)) PetscCall(PetscObjectTypeCompare((PetscObject)A, MATNORMAL, &chol->normal));
2419566063dSJacob Faibussowitsch   PetscCall((*chol->Wrap)(A, PETSC_TRUE, &cholA, &aijalloc, &valloc));
242d0609cedSBarry Smith   err = !SuiteSparseQR_C_numeric(PETSC_SMALL, &cholA, chol->spqrfact, chol->common);
243d0609cedSBarry Smith   PetscCheck(!err, PetscObjectComm((PetscObject)F), PETSC_ERR_LIB, "SPQR factorization failed with status %d", chol->common->status);
244a2fc1e05SToby Isaac 
2459566063dSJacob Faibussowitsch   if (aijalloc) PetscCall(PetscFree2(cholA.p, cholA.i));
2469566063dSJacob Faibussowitsch   if (valloc) PetscCall(PetscFree(cholA.x));
247a2fc1e05SToby Isaac 
248a2fc1e05SToby Isaac   F->ops->solve    = MatSolve_SPQR;
249a2fc1e05SToby Isaac   F->ops->matsolve = MatMatSolve_SPQR;
25002ef7dfaSPierre Jolivet   if (chol->normal) {
251*b9c875b8SPierre Jolivet     PetscScalar scale;
252*b9c875b8SPierre Jolivet 
253*b9c875b8SPierre Jolivet     PetscCall(MatShellGetScalingShifts(A, (PetscScalar *)MAT_SHELL_NOT_ALLOWED, &scale, (Vec *)MAT_SHELL_NOT_ALLOWED, NULL, NULL, (Mat *)MAT_SHELL_NOT_ALLOWED, (IS *)MAT_SHELL_NOT_ALLOWED, (IS *)MAT_SHELL_NOT_ALLOWED));
25402ef7dfaSPierre Jolivet     F->ops->solvetranspose    = MatSolve_SPQR;
25502ef7dfaSPierre Jolivet     F->ops->matsolvetranspose = MatMatSolve_SPQR;
256*b9c875b8SPierre Jolivet     chol->scale               = 1.0 / scale;
25702ef7dfaSPierre Jolivet   } else if (A->cmap->n == A->rmap->n) {
258a2fc1e05SToby Isaac     F->ops->solvetranspose    = MatSolveTranspose_SPQR;
259a2fc1e05SToby Isaac     F->ops->matsolvetranspose = MatMatSolveTranspose_SPQR;
260e2b46ddfSPierre 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