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