1 #include <../src/mat/impls/shell/shell.h> /*I "petscmat.h" I*/
2
3 typedef struct {
4 Mat A;
5 Mat D; /* local submatrix for diagonal part */
6 Vec w;
7 } Mat_Normal;
8
MatIncreaseOverlap_Normal(Mat A,PetscInt is_max,IS is[],PetscInt ov)9 static PetscErrorCode MatIncreaseOverlap_Normal(Mat A, PetscInt is_max, IS is[], PetscInt ov)
10 {
11 Mat_Normal *a;
12 Mat pattern;
13
14 PetscFunctionBegin;
15 PetscCheck(ov >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Negative overlap specified");
16 PetscCall(MatShellGetContext(A, &a));
17 PetscCall(MatProductCreate(a->A, a->A, NULL, &pattern));
18 PetscCall(MatProductSetType(pattern, MATPRODUCT_AtB));
19 PetscCall(MatProductSetFromOptions(pattern));
20 PetscCall(MatProductSymbolic(pattern));
21 PetscCall(MatIncreaseOverlap(pattern, is_max, is, ov));
22 PetscCall(MatDestroy(&pattern));
23 PetscFunctionReturn(PETSC_SUCCESS);
24 }
25
MatCreateSubMatrices_Normal(Mat mat,PetscInt n,const IS irow[],const IS icol[],MatReuse scall,Mat * submat[])26 static PetscErrorCode MatCreateSubMatrices_Normal(Mat mat, PetscInt n, const IS irow[], const IS icol[], MatReuse scall, Mat *submat[])
27 {
28 Mat_Normal *a;
29 Mat B, *suba;
30 IS *row;
31 PetscScalar shift, scale;
32 PetscInt M;
33
34 PetscFunctionBegin;
35 PetscCheck(irow == icol, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Not implemented");
36 PetscCall(MatShellGetScalingShifts(mat, &shift, &scale, (Vec *)MAT_SHELL_NOT_ALLOWED, (Vec *)MAT_SHELL_NOT_ALLOWED, (Vec *)MAT_SHELL_NOT_ALLOWED, (Mat *)MAT_SHELL_NOT_ALLOWED, (IS *)MAT_SHELL_NOT_ALLOWED, (IS *)MAT_SHELL_NOT_ALLOWED));
37 PetscCall(MatShellGetContext(mat, &a));
38 B = a->A;
39 if (scall != MAT_REUSE_MATRIX) PetscCall(PetscCalloc1(n, submat));
40 PetscCall(MatGetSize(B, &M, NULL));
41 PetscCall(PetscMalloc1(n, &row));
42 PetscCall(ISCreateStride(PETSC_COMM_SELF, M, 0, 1, &row[0]));
43 PetscCall(ISSetIdentity(row[0]));
44 for (M = 1; M < n; ++M) row[M] = row[0];
45 PetscCall(MatCreateSubMatrices(B, n, row, icol, MAT_INITIAL_MATRIX, &suba));
46 for (M = 0; M < n; ++M) {
47 PetscCall(MatCreateNormal(suba[M], *submat + M));
48 PetscCall(MatShift((*submat)[M], shift));
49 PetscCall(MatScale((*submat)[M], scale));
50 }
51 PetscCall(ISDestroy(&row[0]));
52 PetscCall(PetscFree(row));
53 PetscCall(MatDestroySubMatrices(n, &suba));
54 PetscFunctionReturn(PETSC_SUCCESS);
55 }
56
MatPermute_Normal(Mat A,IS rowp,IS colp,Mat * B)57 static PetscErrorCode MatPermute_Normal(Mat A, IS rowp, IS colp, Mat *B)
58 {
59 Mat_Normal *a;
60 Mat C, Aa;
61 IS row;
62 PetscScalar shift, scale;
63
64 PetscFunctionBegin;
65 PetscCheck(rowp == colp, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_INCOMP, "Row permutation and column permutation must be the same");
66 PetscCall(MatShellGetScalingShifts(A, &shift, &scale, (Vec *)MAT_SHELL_NOT_ALLOWED, (Vec *)MAT_SHELL_NOT_ALLOWED, (Vec *)MAT_SHELL_NOT_ALLOWED, (Mat *)MAT_SHELL_NOT_ALLOWED, (IS *)MAT_SHELL_NOT_ALLOWED, (IS *)MAT_SHELL_NOT_ALLOWED));
67 PetscCall(MatShellGetContext(A, &a));
68 Aa = a->A;
69 PetscCall(ISCreateStride(PetscObjectComm((PetscObject)Aa), Aa->rmap->n, Aa->rmap->rstart, 1, &row));
70 PetscCall(ISSetIdentity(row));
71 PetscCall(MatPermute(Aa, row, colp, &C));
72 PetscCall(ISDestroy(&row));
73 PetscCall(MatCreateNormal(C, B));
74 PetscCall(MatDestroy(&C));
75 PetscCall(MatShift(*B, shift));
76 PetscCall(MatScale(*B, scale));
77 PetscFunctionReturn(PETSC_SUCCESS);
78 }
79
MatDuplicate_Normal(Mat A,MatDuplicateOption op,Mat * B)80 static PetscErrorCode MatDuplicate_Normal(Mat A, MatDuplicateOption op, Mat *B)
81 {
82 Mat_Normal *a;
83 Mat C;
84
85 PetscFunctionBegin;
86 PetscCall(MatShellGetContext(A, &a));
87 PetscCall(MatDuplicate(a->A, op, &C));
88 PetscCall(MatCreateNormal(C, B));
89 PetscCall(MatDestroy(&C));
90 if (op == MAT_COPY_VALUES) PetscCall(MatCopy(A, *B, SAME_NONZERO_PATTERN));
91 PetscFunctionReturn(PETSC_SUCCESS);
92 }
93
MatCopy_Normal(Mat A,Mat B,MatStructure str)94 static PetscErrorCode MatCopy_Normal(Mat A, Mat B, MatStructure str)
95 {
96 Mat_Normal *a, *b;
97
98 PetscFunctionBegin;
99 PetscCall(MatShellGetContext(A, &a));
100 PetscCall(MatShellGetContext(B, &b));
101 PetscCall(MatCopy(a->A, b->A, str));
102 PetscFunctionReturn(PETSC_SUCCESS);
103 }
104
MatMult_Normal(Mat N,Vec x,Vec y)105 static PetscErrorCode MatMult_Normal(Mat N, Vec x, Vec y)
106 {
107 Mat_Normal *Na;
108
109 PetscFunctionBegin;
110 PetscCall(MatShellGetContext(N, &Na));
111 PetscCall(MatMult(Na->A, x, Na->w));
112 PetscCall(MatMultTranspose(Na->A, Na->w, y));
113 PetscFunctionReturn(PETSC_SUCCESS);
114 }
115
MatDestroy_Normal(Mat N)116 static PetscErrorCode MatDestroy_Normal(Mat N)
117 {
118 Mat_Normal *Na;
119
120 PetscFunctionBegin;
121 PetscCall(MatShellGetContext(N, &Na));
122 PetscCall(MatDestroy(&Na->A));
123 PetscCall(MatDestroy(&Na->D));
124 PetscCall(VecDestroy(&Na->w));
125 PetscCall(PetscFree(Na));
126 PetscCall(PetscObjectComposeFunction((PetscObject)N, "MatNormalGetMat_C", NULL));
127 PetscCall(PetscObjectComposeFunction((PetscObject)N, "MatConvert_normal_seqaij_C", NULL));
128 PetscCall(PetscObjectComposeFunction((PetscObject)N, "MatConvert_normal_mpiaij_C", NULL));
129 #if defined(PETSC_HAVE_HYPRE)
130 PetscCall(PetscObjectComposeFunction((PetscObject)N, "MatConvert_normal_hypre_C", NULL));
131 #endif
132 PetscCall(PetscObjectComposeFunction((PetscObject)N, "MatProductSetFromOptions_normal_seqdense_C", NULL));
133 PetscCall(PetscObjectComposeFunction((PetscObject)N, "MatProductSetFromOptions_normal_mpidense_C", NULL));
134 PetscCall(PetscObjectComposeFunction((PetscObject)N, "MatShellSetContext_C", NULL));
135 PetscFunctionReturn(PETSC_SUCCESS);
136 }
137
138 /*
139 Slow, nonscalable version
140 */
MatGetDiagonal_Normal(Mat N,Vec v)141 static PetscErrorCode MatGetDiagonal_Normal(Mat N, Vec v)
142 {
143 Mat_Normal *Na;
144 Mat A;
145 PetscInt i, j, rstart, rend, nnz;
146 const PetscInt *cols;
147 PetscScalar *work, *values;
148 const PetscScalar *mvalues;
149
150 PetscFunctionBegin;
151 PetscCall(MatShellGetContext(N, &Na));
152 A = Na->A;
153 PetscCall(PetscMalloc1(A->cmap->N, &work));
154 PetscCall(PetscArrayzero(work, A->cmap->N));
155 PetscCall(MatGetOwnershipRange(A, &rstart, &rend));
156 for (i = rstart; i < rend; i++) {
157 PetscCall(MatGetRow(A, i, &nnz, &cols, &mvalues));
158 for (j = 0; j < nnz; j++) work[cols[j]] += mvalues[j] * mvalues[j];
159 PetscCall(MatRestoreRow(A, i, &nnz, &cols, &mvalues));
160 }
161 PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, work, A->cmap->N, MPIU_SCALAR, MPIU_SUM, PetscObjectComm((PetscObject)N)));
162 rstart = N->cmap->rstart;
163 rend = N->cmap->rend;
164 PetscCall(VecGetArray(v, &values));
165 PetscCall(PetscArraycpy(values, work + rstart, rend - rstart));
166 PetscCall(VecRestoreArray(v, &values));
167 PetscCall(PetscFree(work));
168 PetscFunctionReturn(PETSC_SUCCESS);
169 }
170
MatGetDiagonalBlock_Normal(Mat N,Mat * D)171 static PetscErrorCode MatGetDiagonalBlock_Normal(Mat N, Mat *D)
172 {
173 Mat_Normal *Na;
174 Mat M, A;
175
176 PetscFunctionBegin;
177 PetscCall(MatShellGetContext(N, &Na));
178 A = Na->A;
179 PetscCall(MatGetDiagonalBlock(A, &M));
180 PetscCall(MatCreateNormal(M, &Na->D));
181 *D = Na->D;
182 PetscFunctionReturn(PETSC_SUCCESS);
183 }
184
MatNormalGetMat_Normal(Mat A,Mat * M)185 static PetscErrorCode MatNormalGetMat_Normal(Mat A, Mat *M)
186 {
187 Mat_Normal *Aa;
188
189 PetscFunctionBegin;
190 PetscCall(MatShellGetContext(A, &Aa));
191 *M = Aa->A;
192 PetscFunctionReturn(PETSC_SUCCESS);
193 }
194
195 /*@
196 MatNormalGetMat - Gets the `Mat` object stored inside a `MATNORMAL`
197
198 Logically Collective
199
200 Input Parameter:
201 . A - the `MATNORMAL` matrix
202
203 Output Parameter:
204 . M - the matrix object stored inside `A`
205
206 Level: intermediate
207
208 .seealso: [](ch_matrices), `Mat`, `MATNORMAL`, `MATNORMALHERMITIAN`, `MatCreateNormal()`
209 @*/
MatNormalGetMat(Mat A,Mat * M)210 PetscErrorCode MatNormalGetMat(Mat A, Mat *M)
211 {
212 PetscFunctionBegin;
213 PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
214 PetscValidType(A, 1);
215 PetscAssertPointer(M, 2);
216 PetscUseMethod(A, "MatNormalGetMat_C", (Mat, Mat *), (A, M));
217 PetscFunctionReturn(PETSC_SUCCESS);
218 }
219
MatConvert_Normal_AIJ(Mat A,MatType newtype,MatReuse reuse,Mat * newmat)220 static PetscErrorCode MatConvert_Normal_AIJ(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
221 {
222 Mat_Normal *Aa;
223 Mat B;
224 Vec left, right, dshift;
225 PetscScalar scale, shift;
226 PetscInt m, n, M, N;
227
228 PetscFunctionBegin;
229 PetscCall(MatShellGetContext(A, &Aa));
230 PetscCall(MatShellGetScalingShifts(A, &shift, &scale, &dshift, &left, &right, (Mat *)MAT_SHELL_NOT_ALLOWED, (IS *)MAT_SHELL_NOT_ALLOWED, (IS *)MAT_SHELL_NOT_ALLOWED));
231 PetscCall(MatGetSize(A, &M, &N));
232 PetscCall(MatGetLocalSize(A, &m, &n));
233 if (reuse == MAT_REUSE_MATRIX) {
234 B = *newmat;
235 PetscCall(MatProductReplaceMats(Aa->A, Aa->A, NULL, B));
236 } else {
237 PetscCall(MatProductCreate(Aa->A, Aa->A, NULL, &B));
238 PetscCall(MatProductSetType(B, MATPRODUCT_AtB));
239 PetscCall(MatProductSetFromOptions(B));
240 PetscCall(MatProductSymbolic(B));
241 PetscCall(MatSetOption(B, MAT_SYMMETRIC, PETSC_TRUE));
242 }
243 PetscCall(MatProductNumeric(B));
244 if (reuse == MAT_INPLACE_MATRIX) PetscCall(MatHeaderReplace(A, &B));
245 else if (reuse == MAT_INITIAL_MATRIX) *newmat = B;
246 PetscCall(MatConvert(*newmat, MATAIJ, MAT_INPLACE_MATRIX, newmat));
247 PetscCall(MatDiagonalScale(*newmat, left, right));
248 PetscCall(MatScale(*newmat, scale));
249 PetscCall(MatShift(*newmat, shift));
250 if (dshift) PetscCall(MatDiagonalSet(*newmat, dshift, ADD_VALUES));
251 PetscFunctionReturn(PETSC_SUCCESS);
252 }
253
254 #if defined(PETSC_HAVE_HYPRE)
MatConvert_Normal_HYPRE(Mat A,MatType type,MatReuse reuse,Mat * B)255 static PetscErrorCode MatConvert_Normal_HYPRE(Mat A, MatType type, MatReuse reuse, Mat *B)
256 {
257 PetscFunctionBegin;
258 if (reuse == MAT_INITIAL_MATRIX) {
259 PetscCall(MatConvert(A, MATAIJ, reuse, B));
260 PetscCall(MatConvert(*B, type, MAT_INPLACE_MATRIX, B));
261 } else PetscCall(MatConvert_Basic(A, type, reuse, B)); /* fall back to basic convert */
262 PetscFunctionReturn(PETSC_SUCCESS);
263 }
264 #endif
265
266 typedef struct {
267 Mat work[2];
268 } Normal_Dense;
269
MatProductNumeric_Normal_Dense(Mat C)270 static PetscErrorCode MatProductNumeric_Normal_Dense(Mat C)
271 {
272 Mat A, B;
273 Normal_Dense *contents;
274 Mat_Normal *a;
275 Vec right;
276 PetscScalar *array, scale;
277
278 PetscFunctionBegin;
279 MatCheckProduct(C, 1);
280 A = C->product->A;
281 B = C->product->B;
282 PetscCall(MatShellGetContext(A, &a));
283 contents = (Normal_Dense *)C->product->data;
284 PetscCheck(contents, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Product data empty");
285 PetscCall(MatShellGetScalingShifts(A, (PetscScalar *)MAT_SHELL_NOT_ALLOWED, &scale, (Vec *)MAT_SHELL_NOT_ALLOWED, (Vec *)MAT_SHELL_NOT_ALLOWED, &right, (Mat *)MAT_SHELL_NOT_ALLOWED, (IS *)MAT_SHELL_NOT_ALLOWED, (IS *)MAT_SHELL_NOT_ALLOWED));
286 if (right) {
287 PetscCall(MatCopy(B, C, SAME_NONZERO_PATTERN));
288 PetscCall(MatDiagonalScale(C, right, NULL));
289 }
290 PetscCall(MatProductNumeric(contents->work[0]));
291 PetscCall(MatDenseGetArrayWrite(C, &array));
292 PetscCall(MatDensePlaceArray(contents->work[1], array));
293 PetscCall(MatProductNumeric(contents->work[1]));
294 PetscCall(MatDenseRestoreArrayWrite(C, &array));
295 PetscCall(MatDenseResetArray(contents->work[1]));
296 PetscCall(MatSetOption(C, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE));
297 PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY));
298 PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY));
299 PetscCall(MatScale(C, scale));
300 PetscFunctionReturn(PETSC_SUCCESS);
301 }
302
MatNormal_DenseDestroy(PetscCtxRt ctx)303 static PetscErrorCode MatNormal_DenseDestroy(PetscCtxRt ctx)
304 {
305 Normal_Dense *contents = *(Normal_Dense **)ctx;
306
307 PetscFunctionBegin;
308 PetscCall(MatDestroy(contents->work));
309 PetscCall(MatDestroy(contents->work + 1));
310 PetscCall(PetscFree(contents));
311 PetscFunctionReturn(PETSC_SUCCESS);
312 }
313
MatProductSymbolic_Normal_Dense(Mat C)314 static PetscErrorCode MatProductSymbolic_Normal_Dense(Mat C)
315 {
316 Mat A, B;
317 Normal_Dense *contents = NULL;
318 Mat_Normal *a;
319 Vec right;
320 PetscScalar *array, scale;
321 PetscInt n, N, m, M;
322
323 PetscFunctionBegin;
324 MatCheckProduct(C, 1);
325 PetscCheck(!C->product->data, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Product data not empty");
326 A = C->product->A;
327 B = C->product->B;
328 PetscCall(MatShellGetScalingShifts(A, (PetscScalar *)MAT_SHELL_NOT_ALLOWED, &scale, (Vec *)MAT_SHELL_NOT_ALLOWED, (Vec *)MAT_SHELL_NOT_ALLOWED, &right, (Mat *)MAT_SHELL_NOT_ALLOWED, (IS *)MAT_SHELL_NOT_ALLOWED, (IS *)MAT_SHELL_NOT_ALLOWED));
329 PetscCall(MatShellGetContext(A, &a));
330 PetscCall(MatGetLocalSize(C, &m, &n));
331 PetscCall(MatGetSize(C, &M, &N));
332 if (m == PETSC_DECIDE || n == PETSC_DECIDE || M == PETSC_DECIDE || N == PETSC_DECIDE) {
333 PetscCall(MatGetLocalSize(B, NULL, &n));
334 PetscCall(MatGetSize(B, NULL, &N));
335 PetscCall(MatGetLocalSize(A, &m, NULL));
336 PetscCall(MatGetSize(A, &M, NULL));
337 PetscCall(MatSetSizes(C, m, n, M, N));
338 }
339 PetscCall(MatSetType(C, ((PetscObject)B)->type_name));
340 PetscCall(MatSetUp(C));
341 PetscCall(PetscNew(&contents));
342 C->product->data = contents;
343 C->product->destroy = MatNormal_DenseDestroy;
344 if (right) PetscCall(MatProductCreate(a->A, C, NULL, contents->work));
345 else PetscCall(MatProductCreate(a->A, B, NULL, contents->work));
346 PetscCall(MatProductSetType(contents->work[0], MATPRODUCT_AB));
347 PetscCall(MatProductSetFromOptions(contents->work[0]));
348 PetscCall(MatProductSymbolic(contents->work[0]));
349 PetscCall(MatProductCreate(a->A, contents->work[0], NULL, contents->work + 1));
350 PetscCall(MatProductSetType(contents->work[1], MATPRODUCT_AtB));
351 PetscCall(MatProductSetFromOptions(contents->work[1]));
352 PetscCall(MatProductSymbolic(contents->work[1]));
353 PetscCall(MatDenseGetArrayWrite(C, &array));
354 PetscCall(MatSeqDenseSetPreallocation(contents->work[1], array));
355 PetscCall(MatMPIDenseSetPreallocation(contents->work[1], array));
356 PetscCall(MatDenseRestoreArrayWrite(C, &array));
357 C->ops->productnumeric = MatProductNumeric_Normal_Dense;
358 PetscFunctionReturn(PETSC_SUCCESS);
359 }
360
MatProductSetFromOptions_Normal_Dense(Mat C)361 static PetscErrorCode MatProductSetFromOptions_Normal_Dense(Mat C)
362 {
363 Mat_Product *product = C->product;
364
365 PetscFunctionBegin;
366 if (product->type == MATPRODUCT_AB) C->ops->productsymbolic = MatProductSymbolic_Normal_Dense;
367 PetscFunctionReturn(PETSC_SUCCESS);
368 }
369
370 /*MC
371 MATNORMAL - a matrix that behaves like A'*A for `MatMult()` while only containing A
372
373 Level: intermediate
374
375 Developer Notes:
376 This is implemented on top of `MATSHELL` to get support for scaling and shifting without requiring duplicate code
377
378 Users can not call `MatShellSetOperation()` operations on this class, there is some error checking for that incorrect usage
379
380 .seealso: [](ch_matrices), `Mat`, `MatCreateNormal()`, `MatMult()`, `MatNormalGetMat()`, `MATNORMALHERMITIAN`, `MatCreateNormalHermitian()`
381 M*/
382
383 /*@
384 MatCreateNormal - Creates a new `MATNORMAL` matrix object that behaves like $A^T A$.
385
386 Collective
387
388 Input Parameter:
389 . A - the (possibly rectangular) matrix
390
391 Output Parameter:
392 . N - the matrix that represents $A^T A $
393
394 Level: intermediate
395
396 Notes:
397 The product $A^T A$ is NOT actually formed! Rather the new matrix
398 object performs the matrix-vector product, `MatMult()`, by first multiplying by
399 $A$ and then $A^T$
400
401 If `MatGetFactor()` is called on this matrix with `MAT_FACTOR_QR` then the inner matrix `A` is used for the factorization
402
403 .seealso: [](ch_matrices), `Mat`, `MATNORMAL`, `MatMult()`, `MatNormalGetMat()`, `MATNORMALHERMITIAN`, `MatCreateNormalHermitian()`
404 @*/
MatCreateNormal(Mat A,Mat * N)405 PetscErrorCode MatCreateNormal(Mat A, Mat *N)
406 {
407 Mat_Normal *Na;
408 VecType vtype;
409
410 PetscFunctionBegin;
411 PetscCall(MatCreate(PetscObjectComm((PetscObject)A), N));
412 PetscCall(PetscLayoutReference(A->cmap, &(*N)->rmap));
413 PetscCall(PetscLayoutReference(A->cmap, &(*N)->cmap));
414 PetscCall(MatSetType(*N, MATSHELL));
415 PetscCall(PetscNew(&Na));
416 PetscCall(MatShellSetContext(*N, Na));
417 PetscCall(PetscObjectReference((PetscObject)A));
418 Na->A = A;
419 PetscCall(MatCreateVecs(A, NULL, &Na->w));
420
421 PetscCall(MatSetBlockSize(*N, A->cmap->bs));
422 PetscCall(MatShellSetOperation(*N, MATOP_DESTROY, (PetscErrorCodeFn *)MatDestroy_Normal));
423 PetscCall(MatShellSetOperation(*N, MATOP_MULT, (PetscErrorCodeFn *)MatMult_Normal));
424 PetscCall(MatShellSetOperation(*N, MATOP_MULT_TRANSPOSE, (PetscErrorCodeFn *)MatMult_Normal));
425 PetscCall(MatShellSetOperation(*N, MATOP_DUPLICATE, (PetscErrorCodeFn *)MatDuplicate_Normal));
426 PetscCall(MatShellSetOperation(*N, MATOP_GET_DIAGONAL, (PetscErrorCodeFn *)MatGetDiagonal_Normal));
427 PetscCall(MatShellSetOperation(*N, MATOP_GET_DIAGONAL_BLOCK, (PetscErrorCodeFn *)MatGetDiagonalBlock_Normal));
428 PetscCall(MatShellSetOperation(*N, MATOP_COPY, (PetscErrorCodeFn *)MatCopy_Normal));
429 (*N)->ops->increaseoverlap = MatIncreaseOverlap_Normal;
430 (*N)->ops->createsubmatrices = MatCreateSubMatrices_Normal;
431 (*N)->ops->permute = MatPermute_Normal;
432
433 PetscCall(PetscObjectComposeFunction((PetscObject)*N, "MatNormalGetMat_C", MatNormalGetMat_Normal));
434 PetscCall(PetscObjectComposeFunction((PetscObject)*N, "MatConvert_normal_seqaij_C", MatConvert_Normal_AIJ));
435 PetscCall(PetscObjectComposeFunction((PetscObject)*N, "MatConvert_normal_mpiaij_C", MatConvert_Normal_AIJ));
436 #if defined(PETSC_HAVE_HYPRE)
437 PetscCall(PetscObjectComposeFunction((PetscObject)*N, "MatConvert_normal_hypre_C", MatConvert_Normal_HYPRE));
438 #endif
439 PetscCall(PetscObjectComposeFunction((PetscObject)*N, "MatProductSetFromOptions_normal_seqdense_C", MatProductSetFromOptions_Normal_Dense));
440 PetscCall(PetscObjectComposeFunction((PetscObject)*N, "MatProductSetFromOptions_normal_mpidense_C", MatProductSetFromOptions_Normal_Dense));
441 PetscCall(PetscObjectComposeFunction((PetscObject)*N, "MatShellSetContext_C", MatShellSetContext_Immutable));
442 PetscCall(PetscObjectComposeFunction((PetscObject)*N, "MatShellSetContextDestroy_C", MatShellSetContextDestroy_Immutable));
443 PetscCall(PetscObjectComposeFunction((PetscObject)*N, "MatShellSetManageScalingShifts_C", MatShellSetManageScalingShifts_Immutable));
444 PetscCall(MatSetOption(*N, MAT_SYMMETRIC, PETSC_TRUE));
445 PetscCall(MatGetVecType(A, &vtype));
446 PetscCall(MatSetVecType(*N, vtype));
447 #if defined(PETSC_HAVE_DEVICE)
448 PetscCall(MatBindToCPU(*N, A->boundtocpu));
449 #endif
450 PetscCall(MatSetUp(*N));
451 PetscCall(PetscObjectChangeTypeName((PetscObject)*N, MATNORMAL));
452 PetscFunctionReturn(PETSC_SUCCESS);
453 }
454