Actual source code: htool.cxx

  1: #include <../src/mat/impls/htool/htool.hpp>
  2: #include <petscblaslapack.h>
  3: #include <set>

  5: #define ALEN(a) (sizeof(a)/sizeof((a)[0]))
  6: const char *const MatHtoolCompressorTypes[] = { "sympartialACA", "fullACA", "SVD" };
  7: const char *const MatHtoolClusteringTypes[] = { "PCARegular", "PCAGeometric", "BoundingBox1Regular", "BoundingBox1Geometric" };
  8: const char HtoolCitation[] = "@article{marchand2020two,\n"
  9: "  Author = {Marchand, Pierre and Claeys, Xavier and Jolivet, Pierre and Nataf, Fr\\'ed\\'eric and Tournier, Pierre-Henri},\n"
 10: "  Title = {Two-level preconditioning for $h$-version boundary element approximation of hypersingular operator with {GenEO}},\n"
 11: "  Year = {2020},\n"
 12: "  Publisher = {Elsevier},\n"
 13: "  Journal = {Numerische Mathematik},\n"
 14: "  Volume = {146},\n"
 15: "  Pages = {597--628},\n"
 16: "  Url = {https://github.com/htool-ddm/htool}\n"
 17: "}\n";
 18: static PetscBool HtoolCite = PETSC_FALSE;

 20: static PetscErrorCode MatGetDiagonal_Htool(Mat A,Vec v)
 21: {
 22:   Mat_Htool      *a = (Mat_Htool*)A->data;
 23:   PetscScalar    *x;
 24:   PetscBool      flg;

 26:   MatHasCongruentLayouts(A,&flg);
 28:   VecGetArrayWrite(v,&x);
 29:   a->hmatrix->copy_local_diagonal(x);
 30:   VecRestoreArrayWrite(v,&x);
 31:   VecScale(v,a->s);
 32:   return 0;
 33: }

 35: static PetscErrorCode MatGetDiagonalBlock_Htool(Mat A,Mat *b)
 36: {
 37:   Mat_Htool      *a = (Mat_Htool*)A->data;
 38:   Mat            B;
 39:   PetscScalar    *ptr;
 40:   PetscBool      flg;

 42:   MatHasCongruentLayouts(A,&flg);
 44:   PetscObjectQuery((PetscObject)A,"DiagonalBlock",(PetscObject*)&B); /* same logic as in MatGetDiagonalBlock_MPIDense() */
 45:   if (!B) {
 46:     MatCreateDense(PETSC_COMM_SELF,A->rmap->n,A->rmap->n,A->rmap->n,A->rmap->n,NULL,&B);
 47:     MatDenseGetArrayWrite(B,&ptr);
 48:     a->hmatrix->copy_local_diagonal_block(ptr);
 49:     MatDenseRestoreArrayWrite(B,&ptr);
 50:     MatPropagateSymmetryOptions(A,B);
 51:     MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);
 52:     MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);
 53:     MatScale(B,a->s);
 54:     PetscObjectCompose((PetscObject)A,"DiagonalBlock",(PetscObject)B);
 55:     *b   = B;
 56:     MatDestroy(&B);
 57:   } else *b = B;
 58:   return 0;
 59: }

 61: static PetscErrorCode MatMult_Htool(Mat A,Vec x,Vec y)
 62: {
 63:   Mat_Htool         *a = (Mat_Htool*)A->data;
 64:   const PetscScalar *in;
 65:   PetscScalar       *out;

 67:   VecGetArrayRead(x,&in);
 68:   VecGetArrayWrite(y,&out);
 69:   a->hmatrix->mvprod_local_to_local(in,out);
 70:   VecRestoreArrayRead(x,&in);
 71:   VecRestoreArrayWrite(y,&out);
 72:   VecScale(y,a->s);
 73:   return 0;
 74: }

 76: /* naive implementation of MatMultAdd() needed for FEM-BEM coupling via MATNEST */
 77: static PetscErrorCode MatMultAdd_Htool(Mat A,Vec v1,Vec v2,Vec v3)
 78: {
 79:   Mat_Htool         *a = (Mat_Htool*)A->data;
 80:   Vec               tmp;
 81:   const PetscScalar scale = a->s;

 83:   VecDuplicate(v2,&tmp);
 84:   VecCopy(v2,v3); /* no-op in MatMultAdd(bA->m[i][j],bx[j],by[i],by[i]) since VecCopy() checks for x == y */
 85:   a->s = 1.0; /* set s to 1.0 since VecAXPY() may be used to scale the MatMult() output Vec */
 86:   MatMult_Htool(A,v1,tmp);
 87:   VecAXPY(v3,scale,tmp);
 88:   VecDestroy(&tmp);
 89:   a->s = scale; /* set s back to its original value */
 90:   return 0;
 91: }

 93: static PetscErrorCode MatMultTranspose_Htool(Mat A,Vec x,Vec y)
 94: {
 95:   Mat_Htool         *a = (Mat_Htool*)A->data;
 96:   const PetscScalar *in;
 97:   PetscScalar       *out;

 99:   VecGetArrayRead(x,&in);
100:   VecGetArrayWrite(y,&out);
101:   a->hmatrix->mvprod_transp_local_to_local(in,out);
102:   VecRestoreArrayRead(x,&in);
103:   VecRestoreArrayWrite(y,&out);
104:   VecScale(y,a->s);
105:   return 0;
106: }

108: static PetscErrorCode MatIncreaseOverlap_Htool(Mat A,PetscInt is_max,IS is[],PetscInt ov)
109: {
110:   std::set<PetscInt> set;
111:   const PetscInt     *idx;
112:   PetscInt           *oidx,size,bs[2];
113:   PetscMPIInt        csize;

115:   MatGetBlockSizes(A,bs,bs+1);
116:   if (bs[0] != bs[1]) bs[0] = 1;
117:   for (PetscInt i=0; i<is_max; ++i) {
118:     /* basic implementation that adds indices by shifting an IS by -ov, -ov+1..., -1, 1..., ov-1, ov */
119:     /* needed to avoid subdomain matrices to replicate A since it is dense                           */
120:     MPI_Comm_size(PetscObjectComm((PetscObject)is[i]),&csize);
122:     ISGetSize(is[i],&size);
123:     ISGetIndices(is[i],&idx);
124:     for (PetscInt j=0; j<size; ++j) {
125:       set.insert(idx[j]);
126:       for (PetscInt k=1; k<=ov; ++k) {               /* for each layer of overlap      */
127:         if (idx[j] - k >= 0) set.insert(idx[j] - k); /* do not insert negative indices */
128:         if (idx[j] + k < A->rmap->N && idx[j] + k < A->cmap->N) set.insert(idx[j] + k); /* do not insert indices greater than the dimension of A */
129:       }
130:     }
131:     ISRestoreIndices(is[i],&idx);
132:     ISDestroy(is+i);
133:     if (bs[0] > 1) {
134:       for (std::set<PetscInt>::iterator it=set.cbegin(); it!=set.cend(); it++) {
135:         std::vector<PetscInt> block(bs[0]);
136:         std::iota(block.begin(),block.end(),(*it/bs[0])*bs[0]);
137:         set.insert(block.cbegin(),block.cend());
138:       }
139:     }
140:     size = set.size(); /* size with overlap */
141:     PetscMalloc1(size,&oidx);
142:     for (const PetscInt j : set) *oidx++ = j;
143:     oidx -= size;
144:     ISCreateGeneral(PETSC_COMM_SELF,size,oidx,PETSC_OWN_POINTER,is+i);
145:   }
146:   return 0;
147: }

149: static PetscErrorCode MatCreateSubMatrices_Htool(Mat A,PetscInt n,const IS irow[],const IS icol[],MatReuse scall,Mat *submat[])
150: {
151:   Mat_Htool         *a = (Mat_Htool*)A->data;
152:   Mat               D,B,BT;
153:   const PetscScalar *copy;
154:   PetscScalar       *ptr;
155:   const PetscInt    *idxr,*idxc,*it;
156:   PetscInt          nrow,m,i;
157:   PetscBool         flg;

159:   if (scall != MAT_REUSE_MATRIX) {
160:     PetscCalloc1(n,submat);
161:   }
162:   for (i=0; i<n; ++i) {
163:     ISGetLocalSize(irow[i],&nrow);
164:     ISGetLocalSize(icol[i],&m);
165:     ISGetIndices(irow[i],&idxr);
166:     ISGetIndices(icol[i],&idxc);
167:     if (scall != MAT_REUSE_MATRIX) {
168:       MatCreateDense(PETSC_COMM_SELF,nrow,m,nrow,m,NULL,(*submat)+i);
169:     }
170:     MatDenseGetArrayWrite((*submat)[i],&ptr);
171:     if (irow[i] == icol[i]) { /* same row and column IS? */
172:       MatHasCongruentLayouts(A,&flg);
173:       if (flg) {
174:         ISSorted(irow[i],&flg);
175:         if (flg) { /* sorted IS? */
176:           it = std::lower_bound(idxr,idxr+nrow,A->rmap->rstart);
177:           if (it != idxr+nrow && *it == A->rmap->rstart) { /* rmap->rstart in IS? */
178:             if (std::distance(idxr,it) + A->rmap->n <= nrow) { /* long enough IS to store the local diagonal block? */
179:               for (PetscInt j=0; j<A->rmap->n && flg; ++j) if (PetscUnlikely(it[j] != A->rmap->rstart+j)) flg = PETSC_FALSE;
180:               if (flg) { /* complete local diagonal block in IS? */
181:                 /* fast extraction when the local diagonal block is part of the submatrix, e.g., for PCASM or PCHPDDM
182:                  *      [   B   C   E   ]
183:                  *  A = [   B   D   E   ]
184:                  *      [   B   F   E   ]
185:                  */
186:                 m = std::distance(idxr,it); /* shift of the coefficient (0,0) of block D from above */
187:                 MatGetDiagonalBlock_Htool(A,&D);
188:                 MatDenseGetArrayRead(D,&copy);
189:                 for (PetscInt k=0; k<A->rmap->n; ++k) {
190:                   PetscArraycpy(ptr+(m+k)*nrow+m,copy+k*A->rmap->n,A->rmap->n); /* block D from above */
191:                 }
192:                 MatDenseRestoreArrayRead(D,&copy);
193:                 if (m) {
194:                   a->wrapper->copy_submatrix(nrow,m,idxr,idxc,ptr); /* vertical block B from above */
195:                   /* entry-wise assembly may be costly, so transpose already-computed entries when possible */
196:                   if (A->symmetric || A->hermitian) {
197:                     MatCreateDense(PETSC_COMM_SELF,A->rmap->n,m,A->rmap->n,m,ptr+m,&B);
198:                     MatDenseSetLDA(B,nrow);
199:                     MatCreateDense(PETSC_COMM_SELF,m,A->rmap->n,m,A->rmap->n,ptr+m*nrow,&BT);
200:                     MatDenseSetLDA(BT,nrow);
201:                     if (A->hermitian && PetscDefined(USE_COMPLEX)) {
202:                       MatHermitianTranspose(B,MAT_REUSE_MATRIX,&BT);
203:                     } else {
204:                       MatTranspose(B,MAT_REUSE_MATRIX,&BT);
205:                     }
206:                     MatDestroy(&B);
207:                     MatDestroy(&BT);
208:                   } else {
209:                     for (PetscInt k=0; k<A->rmap->n; ++k) { /* block C from above */
210:                       a->wrapper->copy_submatrix(m,1,idxr,idxc+m+k,ptr+(m+k)*nrow);
211:                     }
212:                   }
213:                 }
214:                 if (m+A->rmap->n != nrow) {
215:                   a->wrapper->copy_submatrix(nrow,std::distance(it+A->rmap->n,idxr+nrow),idxr,idxc+m+A->rmap->n,ptr+(m+A->rmap->n)*nrow); /* vertical block E from above */
216:                   /* entry-wise assembly may be costly, so transpose already-computed entries when possible */
217:                   if (A->symmetric || A->hermitian) {
218:                     MatCreateDense(PETSC_COMM_SELF,A->rmap->n,nrow-(m+A->rmap->n),A->rmap->n,nrow-(m+A->rmap->n),ptr+(m+A->rmap->n)*nrow+m,&B);
219:                     MatDenseSetLDA(B,nrow);
220:                     MatCreateDense(PETSC_COMM_SELF,nrow-(m+A->rmap->n),A->rmap->n,nrow-(m+A->rmap->n),A->rmap->n,ptr+m*nrow+m+A->rmap->n,&BT);
221:                     MatDenseSetLDA(BT,nrow);
222:                     if (A->hermitian && PetscDefined(USE_COMPLEX)) {
223:                       MatHermitianTranspose(B,MAT_REUSE_MATRIX,&BT);
224:                     } else {
225:                       MatTranspose(B,MAT_REUSE_MATRIX,&BT);
226:                     }
227:                     MatDestroy(&B);
228:                     MatDestroy(&BT);
229:                   } else {
230:                     for (PetscInt k=0; k<A->rmap->n; ++k) { /* block F from above */
231:                       a->wrapper->copy_submatrix(std::distance(it+A->rmap->n,idxr+nrow),1,it+A->rmap->n,idxc+m+k,ptr+(m+k)*nrow+m+A->rmap->n);
232:                     }
233:                   }
234:                 }
235:               } /* complete local diagonal block not in IS */
236:             } else flg = PETSC_FALSE; /* IS not long enough to store the local diagonal block */
237:           } else flg = PETSC_FALSE; /* rmap->rstart not in IS */
238:         } /* unsorted IS */
239:       }
240:     } else flg = PETSC_FALSE; /* different row and column IS */
241:     if (!flg) a->wrapper->copy_submatrix(nrow,m,idxr,idxc,ptr); /* reassemble everything */
242:     ISRestoreIndices(irow[i],&idxr);
243:     ISRestoreIndices(icol[i],&idxc);
244:     MatDenseRestoreArrayWrite((*submat)[i],&ptr);
245:     MatAssemblyBegin((*submat)[i],MAT_FINAL_ASSEMBLY);
246:     MatAssemblyEnd((*submat)[i],MAT_FINAL_ASSEMBLY);
247:     MatScale((*submat)[i],a->s);
248:   }
249:   return 0;
250: }

252: static PetscErrorCode MatDestroy_Htool(Mat A)
253: {
254:   Mat_Htool               *a = (Mat_Htool*)A->data;
255:   PetscContainer          container;
256:   MatHtoolKernelTranspose *kernelt;

258:   PetscObjectChangeTypeName((PetscObject)A,NULL);
259:   PetscObjectComposeFunction((PetscObject)A,"MatProductSetFromOptions_htool_seqdense_C",NULL);
260:   PetscObjectComposeFunction((PetscObject)A,"MatProductSetFromOptions_htool_mpidense_C",NULL);
261:   PetscObjectComposeFunction((PetscObject)A,"MatConvert_htool_seqdense_C",NULL);
262:   PetscObjectComposeFunction((PetscObject)A,"MatConvert_htool_mpidense_C",NULL);
263:   PetscObjectComposeFunction((PetscObject)A,"MatHtoolGetHierarchicalMat_C",NULL);
264:   PetscObjectComposeFunction((PetscObject)A,"MatHtoolSetKernel_C",NULL);
265:   PetscObjectComposeFunction((PetscObject)A,"MatHtoolGetPermutationSource_C",NULL);
266:   PetscObjectComposeFunction((PetscObject)A,"MatHtoolGetPermutationTarget_C",NULL);
267:   PetscObjectComposeFunction((PetscObject)A,"MatHtoolUsePermutation_C",NULL);
268:   PetscObjectQuery((PetscObject)A,"KernelTranspose",(PetscObject*)&container);
269:   if (container) { /* created in MatTranspose_Htool() */
270:     PetscContainerGetPointer(container,(void**)&kernelt);
271:     MatDestroy(&kernelt->A);
272:     PetscFree(kernelt);
273:     PetscContainerDestroy(&container);
274:     PetscObjectCompose((PetscObject)A,"KernelTranspose",NULL);
275:   }
276:   if (a->gcoords_source != a->gcoords_target) {
277:     PetscFree(a->gcoords_source);
278:   }
279:   PetscFree(a->gcoords_target);
280:   PetscFree2(a->work_source,a->work_target);
281:   delete a->wrapper;
282:   delete a->hmatrix;
283:   PetscFree(A->data);
284:   return 0;
285: }

287: static PetscErrorCode MatView_Htool(Mat A,PetscViewer pv)
288: {
289:   Mat_Htool      *a = (Mat_Htool*)A->data;
290:   PetscBool      flg;

292:   PetscObjectTypeCompare((PetscObject)pv,PETSCVIEWERASCII,&flg);
293:   if (flg) {
294:     PetscViewerASCIIPrintf(pv,"symmetry: %c\n",a->hmatrix->get_symmetry_type());
295:     if (PetscAbsScalar(a->s-1.0) > PETSC_MACHINE_EPSILON) {
296: #if defined(PETSC_USE_COMPLEX)
297:       PetscViewerASCIIPrintf(pv,"scaling: %g+%gi\n",(double)PetscRealPart(a->s),(double)PetscImaginaryPart(a->s));
298: #else
299:       PetscViewerASCIIPrintf(pv,"scaling: %g\n",(double)a->s);
300: #endif
301:     }
302:     PetscViewerASCIIPrintf(pv,"minimum cluster size: %" PetscInt_FMT "\n",a->bs[0]);
303:     PetscViewerASCIIPrintf(pv,"maximum block size: %" PetscInt_FMT "\n",a->bs[1]);
304:     PetscViewerASCIIPrintf(pv,"epsilon: %g\n",(double)a->epsilon);
305:     PetscViewerASCIIPrintf(pv,"eta: %g\n",(double)a->eta);
306:     PetscViewerASCIIPrintf(pv,"minimum target depth: %" PetscInt_FMT "\n",a->depth[0]);
307:     PetscViewerASCIIPrintf(pv,"minimum source depth: %" PetscInt_FMT "\n",a->depth[1]);
308:     PetscViewerASCIIPrintf(pv,"compressor: %s\n",MatHtoolCompressorTypes[a->compressor]);
309:     PetscViewerASCIIPrintf(pv,"clustering: %s\n",MatHtoolClusteringTypes[a->clustering]);
310:     PetscViewerASCIIPrintf(pv,"compression ratio: %s\n",a->hmatrix->get_infos("Compression_ratio").c_str());
311:     PetscViewerASCIIPrintf(pv,"space saving: %s\n",a->hmatrix->get_infos("Space_saving").c_str());
312:     PetscViewerASCIIPrintf(pv,"number of dense (resp. low rank) matrices: %s (resp. %s)\n",a->hmatrix->get_infos("Number_of_dmat").c_str(),a->hmatrix->get_infos("Number_of_lrmat").c_str());
313:     PetscViewerASCIIPrintf(pv,"(minimum, mean, maximum) dense block sizes: (%s, %s, %s)\n",a->hmatrix->get_infos("Dense_block_size_min").c_str(),a->hmatrix->get_infos("Dense_block_size_mean").c_str(),a->hmatrix->get_infos("Dense_block_size_max").c_str());
314:     PetscViewerASCIIPrintf(pv,"(minimum, mean, maximum) low rank block sizes: (%s, %s, %s)\n",a->hmatrix->get_infos("Low_rank_block_size_min").c_str(),a->hmatrix->get_infos("Low_rank_block_size_mean").c_str(),a->hmatrix->get_infos("Low_rank_block_size_max").c_str());
315:     PetscViewerASCIIPrintf(pv,"(minimum, mean, maximum) ranks: (%s, %s, %s)\n",a->hmatrix->get_infos("Rank_min").c_str(),a->hmatrix->get_infos("Rank_mean").c_str(),a->hmatrix->get_infos("Rank_max").c_str());
316:   }
317:   return 0;
318: }

320: static PetscErrorCode MatScale_Htool(Mat A,PetscScalar s)
321: {
322:   Mat_Htool *a = (Mat_Htool*)A->data;

324:   a->s *= s;
325:   return 0;
326: }

328: /* naive implementation of MatGetRow() needed for MatConvert_Nest_AIJ() */
329: static PetscErrorCode MatGetRow_Htool(Mat A,PetscInt row,PetscInt *nz,PetscInt **idx,PetscScalar **v)
330: {
331:   Mat_Htool      *a = (Mat_Htool*)A->data;
332:   PetscInt       *idxc;
333:   PetscBLASInt   one = 1,bn;

335:   if (nz) *nz = A->cmap->N;
336:   if (idx || v) { /* even if !idx, need to set idxc for htool::copy_submatrix() */
337:     PetscMalloc1(A->cmap->N,&idxc);
338:     for (PetscInt i=0; i<A->cmap->N; ++i) idxc[i] = i;
339:   }
340:   if (idx) *idx = idxc;
341:   if (v) {
342:     PetscMalloc1(A->cmap->N,v);
343:     if (a->wrapper) a->wrapper->copy_submatrix(1,A->cmap->N,&row,idxc,*v);
344:     else reinterpret_cast<htool::VirtualGenerator<PetscScalar>*>(a->kernelctx)->copy_submatrix(1,A->cmap->N,&row,idxc,*v);
345:     PetscBLASIntCast(A->cmap->N,&bn);
346:     PetscStackCallBLAS("BLASscal",BLASscal_(&bn,&a->s,*v,&one));
347:   }
348:   if (!idx) {
349:     PetscFree(idxc);
350:   }
351:   return 0;
352: }

354: static PetscErrorCode MatRestoreRow_Htool(Mat A,PetscInt row,PetscInt *nz,PetscInt **idx,PetscScalar **v)
355: {
356:   if (nz) *nz = 0;
357:   if (idx) {
358:     PetscFree(*idx);
359:   }
360:   if (v) {
361:     PetscFree(*v);
362:   }
363:   return 0;
364: }

366: static PetscErrorCode MatSetFromOptions_Htool(PetscOptionItems *PetscOptionsObject,Mat A)
367: {
368:   Mat_Htool      *a = (Mat_Htool*)A->data;
369:   PetscInt       n;
370:   PetscBool      flg;

372:   PetscOptionsHead(PetscOptionsObject,"Htool options");
373:   PetscOptionsInt("-mat_htool_min_cluster_size","Minimal leaf size in cluster tree",NULL,a->bs[0],a->bs,NULL);
374:   PetscOptionsInt("-mat_htool_max_block_size","Maximal number of coefficients in a dense block",NULL,a->bs[1],a->bs + 1,NULL);
375:   PetscOptionsReal("-mat_htool_epsilon","Relative error in Frobenius norm when approximating a block",NULL,a->epsilon,&a->epsilon,NULL);
376:   PetscOptionsReal("-mat_htool_eta","Admissibility condition tolerance",NULL,a->eta,&a->eta,NULL);
377:   PetscOptionsInt("-mat_htool_min_target_depth","Minimal cluster tree depth associated with the rows",NULL,a->depth[0],a->depth,NULL);
378:   PetscOptionsInt("-mat_htool_min_source_depth","Minimal cluster tree depth associated with the columns",NULL,a->depth[1],a->depth + 1,NULL);
379:   n = 0;
380:   PetscOptionsEList("-mat_htool_compressor","Type of compression","MatHtoolCompressorType",MatHtoolCompressorTypes,ALEN(MatHtoolCompressorTypes),MatHtoolCompressorTypes[MAT_HTOOL_COMPRESSOR_SYMPARTIAL_ACA],&n,&flg);
381:   if (flg) a->compressor = MatHtoolCompressorType(n);
382:   n = 0;
383:   PetscOptionsEList("-mat_htool_clustering","Type of clustering","MatHtoolClusteringType",MatHtoolClusteringTypes,ALEN(MatHtoolClusteringTypes),MatHtoolClusteringTypes[MAT_HTOOL_CLUSTERING_PCA_REGULAR],&n,&flg);
384:   if (flg) a->clustering = MatHtoolClusteringType(n);
385:   PetscOptionsTail();
386:   return 0;
387: }

389: static PetscErrorCode MatAssemblyEnd_Htool(Mat A,MatAssemblyType type)
390: {
391:   Mat_Htool                                                    *a = (Mat_Htool*)A->data;
392:   const PetscInt                                               *ranges;
393:   PetscInt                                                     *offset;
394:   PetscMPIInt                                                  size;
395:   char                                                         S = PetscDefined(USE_COMPLEX) && A->hermitian ? 'H' : (A->symmetric ? 'S' : 'N'),uplo = S == 'N' ? 'N' : 'U';
396:   htool::VirtualGenerator<PetscScalar>                         *generator = nullptr;
397:   std::shared_ptr<htool::VirtualCluster>                       t,s = nullptr;
398:   std::shared_ptr<htool::VirtualLowRankGenerator<PetscScalar>> compressor = nullptr;

400:   PetscCitationsRegister(HtoolCitation,&HtoolCite);
401:   delete a->wrapper;
402:   delete a->hmatrix;
403:   MPI_Comm_size(PetscObjectComm((PetscObject)A),&size);
404:   PetscMalloc1(2*size,&offset);
405:   MatGetOwnershipRanges(A,&ranges);
406:   for (PetscInt i=0; i<size; ++i) {
407:     offset[2*i] = ranges[i];
408:     offset[2*i+1] = ranges[i+1] - ranges[i];
409:   }
410:   switch (a->clustering) {
411:   case MAT_HTOOL_CLUSTERING_PCA_GEOMETRIC:
412:     t = std::make_shared<htool::Cluster<htool::PCA<htool::SplittingTypes::GeometricSplitting>>>(a->dim);
413:     break;
414:   case MAT_HTOOL_CLUSTERING_BOUNDING_BOX_1_GEOMETRIC:
415:     t = std::make_shared<htool::Cluster<htool::BoundingBox1<htool::SplittingTypes::GeometricSplitting>>>(a->dim);
416:     break;
417:   case MAT_HTOOL_CLUSTERING_BOUNDING_BOX_1_REGULAR:
418:     t = std::make_shared<htool::Cluster<htool::BoundingBox1<htool::SplittingTypes::RegularSplitting>>>(a->dim);
419:     break;
420:   default:
421:     t = std::make_shared<htool::Cluster<htool::PCA<htool::SplittingTypes::RegularSplitting>>>(a->dim);
422:   }
423:   t->set_minclustersize(a->bs[0]);
424:   t->build(A->rmap->N,a->gcoords_target,offset);
425:   if (a->kernel) a->wrapper = new WrapperHtool(A->rmap->N,A->cmap->N,a->dim,a->kernel,a->kernelctx);
426:   else {
427:     a->wrapper = NULL;
428:     generator = reinterpret_cast<htool::VirtualGenerator<PetscScalar>*>(a->kernelctx);
429:   }
430:   if (a->gcoords_target != a->gcoords_source) {
431:     MatGetOwnershipRangesColumn(A,&ranges);
432:     for (PetscInt i=0; i<size; ++i) {
433:       offset[2*i] = ranges[i];
434:       offset[2*i+1] = ranges[i+1] - ranges[i];
435:     }
436:     switch (a->clustering) {
437:     case MAT_HTOOL_CLUSTERING_PCA_GEOMETRIC:
438:       s = std::make_shared<htool::Cluster<htool::PCA<htool::SplittingTypes::GeometricSplitting>>>(a->dim);
439:       break;
440:     case MAT_HTOOL_CLUSTERING_BOUNDING_BOX_1_GEOMETRIC:
441:       s = std::make_shared<htool::Cluster<htool::BoundingBox1<htool::SplittingTypes::GeometricSplitting>>>(a->dim);
442:       break;
443:     case MAT_HTOOL_CLUSTERING_BOUNDING_BOX_1_REGULAR:
444:       s = std::make_shared<htool::Cluster<htool::BoundingBox1<htool::SplittingTypes::RegularSplitting>>>(a->dim);
445:       break;
446:     default:
447:       s = std::make_shared<htool::Cluster<htool::PCA<htool::SplittingTypes::RegularSplitting>>>(a->dim);
448:     }
449:     s->set_minclustersize(a->bs[0]);
450:     s->build(A->cmap->N,a->gcoords_source,offset);
451:     S = uplo = 'N';
452:   }
453:   PetscFree(offset);
454:   switch (a->compressor) {
455:   case MAT_HTOOL_COMPRESSOR_FULL_ACA:
456:     compressor = std::make_shared<htool::fullACA<PetscScalar>>();
457:     break;
458:   case MAT_HTOOL_COMPRESSOR_SVD:
459:     compressor = std::make_shared<htool::SVD<PetscScalar>>();
460:     break;
461:   default:
462:     compressor = std::make_shared<htool::sympartialACA<PetscScalar>>();
463:   }
464:   a->hmatrix = dynamic_cast<htool::VirtualHMatrix<PetscScalar>*>(new htool::HMatrix<PetscScalar>(t,s ? s : t,a->epsilon,a->eta,S,uplo));
465:   a->hmatrix->set_compression(compressor);
466:   a->hmatrix->set_maxblocksize(a->bs[1]);
467:   a->hmatrix->set_mintargetdepth(a->depth[0]);
468:   a->hmatrix->set_minsourcedepth(a->depth[1]);
469:   if (s) a->hmatrix->build(a->wrapper ? *a->wrapper : *generator,a->gcoords_target,a->gcoords_source);
470:   else   a->hmatrix->build(a->wrapper ? *a->wrapper : *generator,a->gcoords_target);
471:   return 0;
472: }

474: static PetscErrorCode MatProductNumeric_Htool(Mat C)
475: {
476:   Mat_Product       *product = C->product;
477:   Mat_Htool         *a = (Mat_Htool*)product->A->data;
478:   const PetscScalar *in;
479:   PetscScalar       *out;
480:   PetscInt          N,lda;

482:   MatCheckProduct(C,1);
483:   MatGetSize(C,NULL,&N);
484:   MatDenseGetLDA(C,&lda);
486:   MatDenseGetArrayRead(product->B,&in);
487:   MatDenseGetArrayWrite(C,&out);
488:   switch (product->type) {
489:   case MATPRODUCT_AB:
490:     a->hmatrix->mvprod_local_to_local(in,out,N);
491:     break;
492:   case MATPRODUCT_AtB:
493:     a->hmatrix->mvprod_transp_local_to_local(in,out,N);
494:     break;
495:   default:
496:     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"MatProductType %s is not supported",MatProductTypes[product->type]);
497:   }
498:   MatDenseRestoreArrayWrite(C,&out);
499:   MatDenseRestoreArrayRead(product->B,&in);
500:   MatScale(C,a->s);
501:   return 0;
502: }

504: static PetscErrorCode MatProductSymbolic_Htool(Mat C)
505: {
506:   Mat_Product    *product = C->product;
507:   Mat            A,B;
508:   PetscBool      flg;

510:   MatCheckProduct(C,1);
511:   A = product->A;
512:   B = product->B;
513:   PetscObjectTypeCompareAny((PetscObject)B,&flg,MATSEQDENSE,MATMPIDENSE,"");
515:   switch (product->type) {
516:   case MATPRODUCT_AB:
517:     if (C->rmap->n == PETSC_DECIDE || C->cmap->n == PETSC_DECIDE || C->rmap->N == PETSC_DECIDE || C->cmap->N == PETSC_DECIDE) {
518:       MatSetSizes(C,A->rmap->n,B->cmap->n,A->rmap->N,B->cmap->N);
519:     }
520:     break;
521:   case MATPRODUCT_AtB:
522:     if (C->rmap->n == PETSC_DECIDE || C->cmap->n == PETSC_DECIDE || C->rmap->N == PETSC_DECIDE || C->cmap->N == PETSC_DECIDE) {
523:       MatSetSizes(C,A->cmap->n,B->cmap->n,A->cmap->N,B->cmap->N);
524:     }
525:     break;
526:   default:
527:     SETERRQ(PetscObjectComm((PetscObject)B),PETSC_ERR_SUP,"ProductType %s is not supported",MatProductTypes[product->type]);
528:   }
529:   MatSetType(C,MATDENSE);
530:   MatSetUp(C);
531:   MatSetOption(C,MAT_NO_OFF_PROC_ENTRIES,PETSC_TRUE);
532:   MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY);
533:   MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY);
534:   C->ops->productsymbolic = NULL;
535:   C->ops->productnumeric = MatProductNumeric_Htool;
536:   return 0;
537: }

539: static PetscErrorCode MatProductSetFromOptions_Htool(Mat C)
540: {
541:   MatCheckProduct(C,1);
542:   if (C->product->type == MATPRODUCT_AB || C->product->type == MATPRODUCT_AtB) C->ops->productsymbolic = MatProductSymbolic_Htool;
543:   return 0;
544: }

546: static PetscErrorCode MatHtoolGetHierarchicalMat_Htool(Mat A,const htool::VirtualHMatrix<PetscScalar> **hmatrix)
547: {
548:   Mat_Htool *a = (Mat_Htool*)A->data;

550:   *hmatrix = a->hmatrix;
551:   return 0;
552: }

554: /*@C
555:      MatHtoolGetHierarchicalMat - Retrieves the opaque pointer to a Htool virtual matrix stored in a MATHTOOL.

557:    Input Parameter:
558: .     A - hierarchical matrix

560:    Output Parameter:
561: .     hmatrix - opaque pointer to a Htool virtual matrix

563:    Level: advanced

565: .seealso:  MATHTOOL
566: @*/
567: PETSC_EXTERN PetscErrorCode MatHtoolGetHierarchicalMat(Mat A,const htool::VirtualHMatrix<PetscScalar> **hmatrix)
568: {
571:   PetscTryMethod(A,"MatHtoolGetHierarchicalMat_C",(Mat,const htool::VirtualHMatrix<PetscScalar>**),(A,hmatrix));
572:   return 0;
573: }

575: static PetscErrorCode MatHtoolSetKernel_Htool(Mat A,MatHtoolKernel kernel,void *kernelctx)
576: {
577:   Mat_Htool *a = (Mat_Htool*)A->data;

579:   a->kernel    = kernel;
580:   a->kernelctx = kernelctx;
581:   delete a->wrapper;
582:   if (a->kernel) a->wrapper = new WrapperHtool(A->rmap->N,A->cmap->N,a->dim,a->kernel,a->kernelctx);
583:   return 0;
584: }

586: /*@C
587:      MatHtoolSetKernel - Sets the kernel and context used for the assembly of a MATHTOOL.

589:    Input Parameters:
590: +     A - hierarchical matrix
591: .     kernel - computational kernel (or NULL)
592: -     kernelctx - kernel context (if kernel is NULL, the pointer must be of type htool::VirtualGenerator<PetscScalar>*)

594:    Level: advanced

596: .seealso:  MATHTOOL, MatCreateHtoolFromKernel()
597: @*/
598: PETSC_EXTERN PetscErrorCode MatHtoolSetKernel(Mat A,MatHtoolKernel kernel,void *kernelctx)
599: {
603:   PetscTryMethod(A,"MatHtoolSetKernel_C",(Mat,MatHtoolKernel,void*),(A,kernel,kernelctx));
604:   return 0;
605: }

607: static PetscErrorCode MatHtoolGetPermutationSource_Htool(Mat A,IS* is)
608: {
609:   Mat_Htool             *a = (Mat_Htool*)A->data;
610:   std::vector<PetscInt> source;

612:   source = a->hmatrix->get_source_cluster()->get_local_perm();
613:   ISCreateGeneral(PetscObjectComm((PetscObject)A),source.size(),source.data(),PETSC_COPY_VALUES,is);
614:   ISSetPermutation(*is);
615:   return 0;
616: }

618: /*@C
619:      MatHtoolGetPermutationSource - Gets the permutation associated to the source cluster.

621:    Input Parameter:
622: .     A - hierarchical matrix

624:    Output Parameter:
625: .     is - permutation

627:    Level: advanced

629: .seealso:  MATHTOOL, MatHtoolGetPermutationTarget(), MatHtoolUsePermutation()
630: @*/
631: PETSC_EXTERN PetscErrorCode MatHtoolGetPermutationSource(Mat A,IS* is)
632: {
635:   PetscTryMethod(A,"MatHtoolGetPermutationSource_C",(Mat,IS*),(A,is));
636:   return 0;
637: }

639: static PetscErrorCode MatHtoolGetPermutationTarget_Htool(Mat A,IS* is)
640: {
641:   Mat_Htool             *a = (Mat_Htool*)A->data;
642:   std::vector<PetscInt> target;

644:   target = a->hmatrix->get_target_cluster()->get_local_perm();
645:   ISCreateGeneral(PetscObjectComm((PetscObject)A),target.size(),target.data(),PETSC_COPY_VALUES,is);
646:   ISSetPermutation(*is);
647:   return 0;
648: }

650: /*@C
651:      MatHtoolGetPermutationTarget - Gets the permutation associated to the target cluster.

653:    Input Parameter:
654: .     A - hierarchical matrix

656:    Output Parameter:
657: .     is - permutation

659:    Level: advanced

661: .seealso:  MATHTOOL, MatHtoolGetPermutationSource(), MatHtoolUsePermutation()
662: @*/
663: PETSC_EXTERN PetscErrorCode MatHtoolGetPermutationTarget(Mat A,IS* is)
664: {
667:   PetscTryMethod(A,"MatHtoolGetPermutationTarget_C",(Mat,IS*),(A,is));
668:   return 0;
669: }

671: static PetscErrorCode MatHtoolUsePermutation_Htool(Mat A,PetscBool use)
672: {
673:   Mat_Htool *a = (Mat_Htool*)A->data;

675:   a->hmatrix->set_use_permutation(use);
676:   return 0;
677: }

679: /*@C
680:      MatHtoolUsePermutation - Sets whether MATHTOOL should permute input (resp. output) vectors following its internal source (resp. target) permutation.

682:    Input Parameters:
683: +     A - hierarchical matrix
684: -     use - Boolean value

686:    Level: advanced

688: .seealso:  MATHTOOL, MatHtoolGetPermutationSource(), MatHtoolGetPermutationTarget()
689: @*/
690: PETSC_EXTERN PetscErrorCode MatHtoolUsePermutation(Mat A,PetscBool use)
691: {
694:   PetscTryMethod(A,"MatHtoolUsePermutation_C",(Mat,PetscBool),(A,use));
695:   return 0;
696: }

698: static PetscErrorCode MatConvert_Htool_Dense(Mat A,MatType newtype,MatReuse reuse,Mat *B)
699: {
700:   Mat            C;
701:   Mat_Htool      *a = (Mat_Htool*)A->data;
702:   PetscInt       lda;
703:   PetscScalar    *array;

705:   if (reuse == MAT_REUSE_MATRIX) {
706:     C = *B;
708:     MatDenseGetLDA(C,&lda);
710:   } else {
711:     MatCreate(PetscObjectComm((PetscObject)A),&C);
712:     MatSetSizes(C,A->rmap->n,A->cmap->n,A->rmap->N,A->cmap->N);
713:     MatSetType(C,MATDENSE);
714:     MatSetUp(C);
715:     MatSetOption(C,MAT_NO_OFF_PROC_ENTRIES,PETSC_TRUE);
716:   }
717:   MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY);
718:   MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY);
719:   MatDenseGetArrayWrite(C,&array);
720:   a->hmatrix->copy_local_dense_perm(array);
721:   MatDenseRestoreArrayWrite(C,&array);
722:   MatScale(C,a->s);
723:   if (reuse == MAT_INPLACE_MATRIX) {
724:     MatHeaderReplace(A,&C);
725:   } else *B = C;
726:   return 0;
727: }

729: static PetscErrorCode GenEntriesTranspose(PetscInt sdim,PetscInt M,PetscInt N,const PetscInt *rows,const PetscInt *cols,PetscScalar *ptr,void *ctx)
730: {
731:   MatHtoolKernelTranspose *generator = (MatHtoolKernelTranspose*)ctx;
732:   PetscScalar             *tmp;

734:   generator->kernel(sdim,N,M,cols,rows,ptr,generator->kernelctx);
735:   PetscMalloc1(M*N,&tmp);
736:   PetscArraycpy(tmp,ptr,M*N);
737:   for (PetscInt i=0; i<M; ++i) {
738:     for (PetscInt j=0; j<N; ++j) ptr[i+j*M] = tmp[j+i*N];
739:   }
740:   PetscFree(tmp);
741:   return 0;
742: }

744: /* naive implementation which keeps a reference to the original Mat */
745: static PetscErrorCode MatTranspose_Htool(Mat A,MatReuse reuse,Mat *B)
746: {
747:   Mat                     C;
748:   Mat_Htool               *a = (Mat_Htool*)A->data,*c;
749:   PetscInt                M = A->rmap->N,N = A->cmap->N,m = A->rmap->n,n = A->cmap->n;
750:   PetscContainer          container;
751:   MatHtoolKernelTranspose *kernelt;

754:   if (reuse == MAT_INITIAL_MATRIX) {
755:     MatCreate(PetscObjectComm((PetscObject)A),&C);
756:     MatSetSizes(C,n,m,N,M);
757:     MatSetType(C,((PetscObject)A)->type_name);
758:     MatSetUp(C);
759:     PetscContainerCreate(PetscObjectComm((PetscObject)C),&container);
760:     PetscNew(&kernelt);
761:     PetscContainerSetPointer(container,kernelt);
762:     PetscObjectCompose((PetscObject)C,"KernelTranspose",(PetscObject)container);
763:   } else {
764:     C = *B;
765:     PetscObjectQuery((PetscObject)C,"KernelTranspose",(PetscObject*)&container);
767:     PetscContainerGetPointer(container,(void**)&kernelt);
768:   }
769:   c                  = (Mat_Htool*)C->data;
770:   c->dim             = a->dim;
771:   c->s               = a->s;
772:   c->kernel          = GenEntriesTranspose;
773:   if (kernelt->A != A) {
774:     MatDestroy(&kernelt->A);
775:     kernelt->A       = A;
776:     PetscObjectReference((PetscObject)A);
777:   }
778:   kernelt->kernel    = a->kernel;
779:   kernelt->kernelctx = a->kernelctx;
780:   c->kernelctx       = kernelt;
781:   if (reuse == MAT_INITIAL_MATRIX) {
782:     PetscMalloc1(N*c->dim,&c->gcoords_target);
783:     PetscArraycpy(c->gcoords_target,a->gcoords_source,N*c->dim);
784:     if (a->gcoords_target != a->gcoords_source) {
785:       PetscMalloc1(M*c->dim,&c->gcoords_source);
786:       PetscArraycpy(c->gcoords_source,a->gcoords_target,M*c->dim);
787:     } else c->gcoords_source = c->gcoords_target;
788:     PetscCalloc2(M,&c->work_source,N,&c->work_target);
789:   }
790:   MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY);
791:   MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY);
792:   if (reuse == MAT_INITIAL_MATRIX) *B = C;
793:   return 0;
794: }

796: /*@C
797:      MatCreateHtoolFromKernel - Creates a MATHTOOL from a user-supplied kernel.

799:    Input Parameters:
800: +     comm - MPI communicator
801: .     m - number of local rows (or PETSC_DECIDE to have calculated if M is given)
802: .     n - number of local columns (or PETSC_DECIDE to have calculated if N is given)
803: .     M - number of global rows (or PETSC_DETERMINE to have calculated if m is given)
804: .     N - number of global columns (or PETSC_DETERMINE to have calculated if n is given)
805: .     spacedim - dimension of the space coordinates
806: .     coords_target - coordinates of the target
807: .     coords_source - coordinates of the source
808: .     kernel - computational kernel (or NULL)
809: -     kernelctx - kernel context (if kernel is NULL, the pointer must be of type htool::VirtualGenerator<PetscScalar>*)

811:    Output Parameter:
812: .     B - matrix

814:    Options Database Keys:
815: +     -mat_htool_min_cluster_size <PetscInt> - minimal leaf size in cluster tree
816: .     -mat_htool_max_block_size <PetscInt> - maximal number of coefficients in a dense block
817: .     -mat_htool_epsilon <PetscReal> - relative error in Frobenius norm when approximating a block
818: .     -mat_htool_eta <PetscReal> - admissibility condition tolerance
819: .     -mat_htool_min_target_depth <PetscInt> - minimal cluster tree depth associated with the rows
820: .     -mat_htool_min_source_depth <PetscInt> - minimal cluster tree depth associated with the columns
821: .     -mat_htool_compressor <sympartialACA, fullACA, SVD> - type of compression
822: -     -mat_htool_clustering <PCARegular, PCAGeometric, BounbingBox1Regular, BoundingBox1Geometric> - type of clustering

824:    Level: intermediate

826: .seealso:  MatCreate(), MATHTOOL, PCSetCoordinates(), MatHtoolSetKernel(), MatHtoolCompressorType, MATH2OPUS, MatCreateH2OpusFromKernel()
827: @*/
828: PetscErrorCode MatCreateHtoolFromKernel(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt M,PetscInt N,PetscInt spacedim,const PetscReal coords_target[],const PetscReal coords_source[],MatHtoolKernel kernel,void *kernelctx,Mat *B)
829: {
830:   Mat            A;
831:   Mat_Htool      *a;

833:   MatCreate(comm,&A);
839:   MatSetSizes(A,m,n,M,N);
840:   MatSetType(A,MATHTOOL);
841:   MatSetUp(A);
842:   a            = (Mat_Htool*)A->data;
843:   a->dim       = spacedim;
844:   a->s         = 1.0;
845:   a->kernel    = kernel;
846:   a->kernelctx = kernelctx;
847:   PetscCalloc1(A->rmap->N*spacedim,&a->gcoords_target);
848:   PetscArraycpy(a->gcoords_target+A->rmap->rstart*spacedim,coords_target,A->rmap->n*spacedim);
849:   MPIU_Allreduce(MPI_IN_PLACE,a->gcoords_target,A->rmap->N*spacedim,MPIU_REAL,MPI_SUM,PetscObjectComm((PetscObject)A)); /* global target coordinates */
850:   if (coords_target != coords_source) {
851:     PetscCalloc1(A->cmap->N*spacedim,&a->gcoords_source);
852:     PetscArraycpy(a->gcoords_source+A->cmap->rstart*spacedim,coords_source,A->cmap->n*spacedim);
853:     MPIU_Allreduce(MPI_IN_PLACE,a->gcoords_source,A->cmap->N*spacedim,MPIU_REAL,MPI_SUM,PetscObjectComm((PetscObject)A)); /* global source coordinates */
854:   } else a->gcoords_source = a->gcoords_target;
855:   PetscCalloc2(A->cmap->N,&a->work_source,A->rmap->N,&a->work_target);
856:   *B = A;
857:   return 0;
858: }

860: /*MC
861:      MATHTOOL = "htool" - A matrix type for hierarchical matrices using the Htool package.

863:   Use ./configure --download-htool to install PETSc to use Htool.

865:    Options Database Keys:
866: .     -mat_type htool - matrix type to "htool" during a call to MatSetFromOptions()

868:    Level: beginner

870: .seealso: MATH2OPUS, MATDENSE, MatCreateHtoolFromKernel(), MatHtoolSetKernel()
871: M*/
872: PETSC_EXTERN PetscErrorCode MatCreate_Htool(Mat A)
873: {
874:   Mat_Htool *a;

876:   PetscNewLog(A,&a);
877:   A->data = (void*)a;
878:   PetscObjectChangeTypeName((PetscObject)A,MATHTOOL);
879:   PetscMemzero(A->ops,sizeof(struct _MatOps));
880:   A->ops->getdiagonal       = MatGetDiagonal_Htool;
881:   A->ops->getdiagonalblock  = MatGetDiagonalBlock_Htool;
882:   A->ops->mult              = MatMult_Htool;
883:   A->ops->multadd           = MatMultAdd_Htool;
884:   A->ops->multtranspose     = MatMultTranspose_Htool;
885:   if (!PetscDefined(USE_COMPLEX)) A->ops->multhermitiantranspose = MatMultTranspose_Htool;
886:   A->ops->increaseoverlap   = MatIncreaseOverlap_Htool;
887:   A->ops->createsubmatrices = MatCreateSubMatrices_Htool;
888:   A->ops->transpose         = MatTranspose_Htool;
889:   A->ops->destroy           = MatDestroy_Htool;
890:   A->ops->view              = MatView_Htool;
891:   A->ops->setfromoptions    = MatSetFromOptions_Htool;
892:   A->ops->scale             = MatScale_Htool;
893:   A->ops->getrow            = MatGetRow_Htool;
894:   A->ops->restorerow        = MatRestoreRow_Htool;
895:   A->ops->assemblyend       = MatAssemblyEnd_Htool;
896:   a->dim                    = 0;
897:   a->gcoords_target         = NULL;
898:   a->gcoords_source         = NULL;
899:   a->s                      = 1.0;
900:   a->bs[0]                  = 10;
901:   a->bs[1]                  = 1000000;
902:   a->epsilon                = PetscSqrtReal(PETSC_SMALL);
903:   a->eta                    = 10.0;
904:   a->depth[0]               = 0;
905:   a->depth[1]               = 0;
906:   a->compressor             = MAT_HTOOL_COMPRESSOR_SYMPARTIAL_ACA;
907:   PetscObjectComposeFunction((PetscObject)A,"MatProductSetFromOptions_htool_seqdense_C",MatProductSetFromOptions_Htool);
908:   PetscObjectComposeFunction((PetscObject)A,"MatProductSetFromOptions_htool_mpidense_C",MatProductSetFromOptions_Htool);
909:   PetscObjectComposeFunction((PetscObject)A,"MatConvert_htool_seqdense_C",MatConvert_Htool_Dense);
910:   PetscObjectComposeFunction((PetscObject)A,"MatConvert_htool_mpidense_C",MatConvert_Htool_Dense);
911:   PetscObjectComposeFunction((PetscObject)A,"MatHtoolGetHierarchicalMat_C",MatHtoolGetHierarchicalMat_Htool);
912:   PetscObjectComposeFunction((PetscObject)A,"MatHtoolSetKernel_C",MatHtoolSetKernel_Htool);
913:   PetscObjectComposeFunction((PetscObject)A,"MatHtoolGetPermutationSource_C",MatHtoolGetPermutationSource_Htool);
914:   PetscObjectComposeFunction((PetscObject)A,"MatHtoolGetPermutationTarget_C",MatHtoolGetPermutationTarget_Htool);
915:   PetscObjectComposeFunction((PetscObject)A,"MatHtoolUsePermutation_C",MatHtoolUsePermutation_Htool);
916:   return 0;
917: }