Actual source code: multequal.c


  2: #include <petsc/private/matimpl.h>

  4: static PetscErrorCode MatMultEqual_Private(Mat A, Mat B, PetscInt n, PetscBool *flg, PetscInt t, PetscBool add)
  5: {
  6:   Vec         Ax = NULL, Bx = NULL, s1 = NULL, s2 = NULL, Ay = NULL, By = NULL;
  7:   PetscRandom rctx;
  8:   PetscReal   r1, r2, tol = PETSC_SQRT_MACHINE_EPSILON;
  9:   PetscInt    am, an, bm, bn, k;
 10:   PetscScalar none   = -1.0;
 11:   const char *sops[] = {"MatMult", "MatMultAdd", "MatMultTranspose", "MatMultTransposeAdd", "MatMultHermitianTranspose", "MatMultHermitianTransposeAdd"};
 12:   const char *sop;

 14:   PetscFunctionBegin;
 17:   PetscCheckSameComm(A, 1, B, 2);
 22:   PetscCall(MatGetLocalSize(A, &am, &an));
 23:   PetscCall(MatGetLocalSize(B, &bm, &bn));
 24:   PetscCheck(am == bm && an == bn, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Mat A,Mat B: local dim %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT, am, bm, an, bn);
 25:   sop = sops[(add ? 1 : 0) + 2 * t]; /* t = 0 => no transpose, t = 1 => transpose, t = 2 => Hermitian transpose */
 26:   PetscCall(PetscRandomCreate(PetscObjectComm((PetscObject)A), &rctx));
 27:   PetscCall(PetscRandomSetFromOptions(rctx));
 28:   if (t) {
 29:     PetscCall(MatCreateVecs(A, &s1, &Ax));
 30:     PetscCall(MatCreateVecs(B, &s2, &Bx));
 31:   } else {
 32:     PetscCall(MatCreateVecs(A, &Ax, &s1));
 33:     PetscCall(MatCreateVecs(B, &Bx, &s2));
 34:   }
 35:   if (add) {
 36:     PetscCall(VecDuplicate(s1, &Ay));
 37:     PetscCall(VecDuplicate(s2, &By));
 38:   }

 40:   *flg = PETSC_TRUE;
 41:   for (k = 0; k < n; k++) {
 42:     PetscCall(VecSetRandom(Ax, rctx));
 43:     PetscCall(VecCopy(Ax, Bx));
 44:     if (add) {
 45:       PetscCall(VecSetRandom(Ay, rctx));
 46:       PetscCall(VecCopy(Ay, By));
 47:     }
 48:     if (t == 1) {
 49:       if (add) {
 50:         PetscCall(MatMultTransposeAdd(A, Ax, Ay, s1));
 51:         PetscCall(MatMultTransposeAdd(B, Bx, By, s2));
 52:       } else {
 53:         PetscCall(MatMultTranspose(A, Ax, s1));
 54:         PetscCall(MatMultTranspose(B, Bx, s2));
 55:       }
 56:     } else if (t == 2) {
 57:       if (add) {
 58:         PetscCall(MatMultHermitianTransposeAdd(A, Ax, Ay, s1));
 59:         PetscCall(MatMultHermitianTransposeAdd(B, Bx, By, s2));
 60:       } else {
 61:         PetscCall(MatMultHermitianTranspose(A, Ax, s1));
 62:         PetscCall(MatMultHermitianTranspose(B, Bx, s2));
 63:       }
 64:     } else {
 65:       if (add) {
 66:         PetscCall(MatMultAdd(A, Ax, Ay, s1));
 67:         PetscCall(MatMultAdd(B, Bx, By, s2));
 68:       } else {
 69:         PetscCall(MatMult(A, Ax, s1));
 70:         PetscCall(MatMult(B, Bx, s2));
 71:       }
 72:     }
 73:     PetscCall(VecNorm(s2, NORM_INFINITY, &r2));
 74:     if (r2 < tol) {
 75:       PetscCall(VecNorm(s1, NORM_INFINITY, &r1));
 76:     } else {
 77:       PetscCall(VecAXPY(s2, none, s1));
 78:       PetscCall(VecNorm(s2, NORM_INFINITY, &r1));
 79:       r1 /= r2;
 80:     }
 81:     if (r1 > tol) {
 82:       *flg = PETSC_FALSE;
 83:       PetscCall(PetscInfo(A, "Error: %" PetscInt_FMT "-th %s() %g\n", k, sop, (double)r1));
 84:       break;
 85:     }
 86:   }
 87:   PetscCall(PetscRandomDestroy(&rctx));
 88:   PetscCall(VecDestroy(&Ax));
 89:   PetscCall(VecDestroy(&Bx));
 90:   PetscCall(VecDestroy(&Ay));
 91:   PetscCall(VecDestroy(&By));
 92:   PetscCall(VecDestroy(&s1));
 93:   PetscCall(VecDestroy(&s2));
 94:   PetscFunctionReturn(PETSC_SUCCESS);
 95: }

 97: static PetscErrorCode MatMatMultEqual_Private(Mat A, Mat B, Mat C, PetscInt n, PetscBool *flg, PetscBool At, PetscBool Bt)
 98: {
 99:   Vec         Ax, Bx, Cx, s1, s2, s3;
100:   PetscRandom rctx;
101:   PetscReal   r1, r2, tol = PETSC_SQRT_MACHINE_EPSILON;
102:   PetscInt    am, an, bm, bn, cm, cn, k;
103:   PetscScalar none   = -1.0;
104:   const char *sops[] = {"MatMatMult", "MatTransposeMatMult", "MatMatTransposeMult", "MatTransposeMatTransposeMult"};
105:   const char *sop;

107:   PetscFunctionBegin;
110:   PetscCheckSameComm(A, 1, B, 2);
112:   PetscCheckSameComm(A, 1, C, 3);
117:   PetscCall(MatGetLocalSize(A, &am, &an));
118:   PetscCall(MatGetLocalSize(B, &bm, &bn));
119:   PetscCall(MatGetLocalSize(C, &cm, &cn));
120:   if (At) {
121:     PetscInt tt = an;
122:     an          = am;
123:     am          = tt;
124:   };
125:   if (Bt) {
126:     PetscInt tt = bn;
127:     bn          = bm;
128:     bm          = tt;
129:   };
130:   PetscCheck(an == bm && am == cm && bn == cn, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Mat A, B, C local dim %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT, am, an, bm, bn, cm, cn);

132:   sop = sops[(At ? 1 : 0) + 2 * (Bt ? 1 : 0)];
133:   PetscCall(PetscRandomCreate(PetscObjectComm((PetscObject)C), &rctx));
134:   PetscCall(PetscRandomSetFromOptions(rctx));
135:   if (Bt) {
136:     PetscCall(MatCreateVecs(B, &s1, &Bx));
137:   } else {
138:     PetscCall(MatCreateVecs(B, &Bx, &s1));
139:   }
140:   if (At) {
141:     PetscCall(MatCreateVecs(A, &s2, &Ax));
142:   } else {
143:     PetscCall(MatCreateVecs(A, &Ax, &s2));
144:   }
145:   PetscCall(MatCreateVecs(C, &Cx, &s3));

147:   *flg = PETSC_TRUE;
148:   for (k = 0; k < n; k++) {
149:     PetscCall(VecSetRandom(Bx, rctx));
150:     if (Bt) {
151:       PetscCall(MatMultTranspose(B, Bx, s1));
152:     } else {
153:       PetscCall(MatMult(B, Bx, s1));
154:     }
155:     PetscCall(VecCopy(s1, Ax));
156:     if (At) {
157:       PetscCall(MatMultTranspose(A, Ax, s2));
158:     } else {
159:       PetscCall(MatMult(A, Ax, s2));
160:     }
161:     PetscCall(VecCopy(Bx, Cx));
162:     PetscCall(MatMult(C, Cx, s3));

164:     PetscCall(VecNorm(s2, NORM_INFINITY, &r2));
165:     if (r2 < tol) {
166:       PetscCall(VecNorm(s3, NORM_INFINITY, &r1));
167:     } else {
168:       PetscCall(VecAXPY(s2, none, s3));
169:       PetscCall(VecNorm(s2, NORM_INFINITY, &r1));
170:       r1 /= r2;
171:     }
172:     if (r1 > tol) {
173:       *flg = PETSC_FALSE;
174:       PetscCall(PetscInfo(A, "Error: %" PetscInt_FMT "-th %s %g\n", k, sop, (double)r1));
175:       break;
176:     }
177:   }
178:   PetscCall(PetscRandomDestroy(&rctx));
179:   PetscCall(VecDestroy(&Ax));
180:   PetscCall(VecDestroy(&Bx));
181:   PetscCall(VecDestroy(&Cx));
182:   PetscCall(VecDestroy(&s1));
183:   PetscCall(VecDestroy(&s2));
184:   PetscCall(VecDestroy(&s3));
185:   PetscFunctionReturn(PETSC_SUCCESS);
186: }

188: /*@
189:    MatMultEqual - Compares matrix-vector products of two matrices.

191:    Collective

193:    Input Parameters:
194: +  A - the first matrix
195: .  B - the second matrix
196: -  n - number of random vectors to be tested

198:    Output Parameter:
199: .  flg - PETSC_TRUE if the products are equal; PETSC_FALSE otherwise.

201:    Level: intermediate

203: @*/
204: PetscErrorCode MatMultEqual(Mat A, Mat B, PetscInt n, PetscBool *flg)
205: {
206:   PetscFunctionBegin;
207:   PetscCall(MatMultEqual_Private(A, B, n, flg, 0, PETSC_FALSE));
208:   PetscFunctionReturn(PETSC_SUCCESS);
209: }

211: /*@
212:    MatMultAddEqual - Compares matrix-vector products of two matrices.

214:    Collective

216:    Input Parameters:
217: +  A - the first matrix
218: .  B - the second matrix
219: -  n - number of random vectors to be tested

221:    Output Parameter:
222: .  flg - PETSC_TRUE if the products are equal; PETSC_FALSE otherwise.

224:    Level: intermediate

226: @*/
227: PetscErrorCode MatMultAddEqual(Mat A, Mat B, PetscInt n, PetscBool *flg)
228: {
229:   PetscFunctionBegin;
230:   PetscCall(MatMultEqual_Private(A, B, n, flg, 0, PETSC_TRUE));
231:   PetscFunctionReturn(PETSC_SUCCESS);
232: }

234: /*@
235:    MatMultTransposeEqual - Compares matrix-vector products of two matrices.

237:    Collective

239:    Input Parameters:
240: +  A - the first matrix
241: .  B - the second matrix
242: -  n - number of random vectors to be tested

244:    Output Parameter:
245: .  flg - PETSC_TRUE if the products are equal; PETSC_FALSE otherwise.

247:    Level: intermediate

249: @*/
250: PetscErrorCode MatMultTransposeEqual(Mat A, Mat B, PetscInt n, PetscBool *flg)
251: {
252:   PetscFunctionBegin;
253:   PetscCall(MatMultEqual_Private(A, B, n, flg, 1, PETSC_FALSE));
254:   PetscFunctionReturn(PETSC_SUCCESS);
255: }

257: /*@
258:    MatMultTransposeAddEqual - Compares matrix-vector products of two matrices.

260:    Collective

262:    Input Parameters:
263: +  A - the first matrix
264: .  B - the second matrix
265: -  n - number of random vectors to be tested

267:    Output Parameter:
268: .  flg - PETSC_TRUE if the products are equal; PETSC_FALSE otherwise.

270:    Level: intermediate

272: @*/
273: PetscErrorCode MatMultTransposeAddEqual(Mat A, Mat B, PetscInt n, PetscBool *flg)
274: {
275:   PetscFunctionBegin;
276:   PetscCall(MatMultEqual_Private(A, B, n, flg, 1, PETSC_TRUE));
277:   PetscFunctionReturn(PETSC_SUCCESS);
278: }

280: /*@
281:    MatMultHermitianTransposeEqual - Compares matrix-vector products of two matrices.

283:    Collective

285:    Input Parameters:
286: +  A - the first matrix
287: .  B - the second matrix
288: -  n - number of random vectors to be tested

290:    Output Parameter:
291: .  flg - PETSC_TRUE if the products are equal; PETSC_FALSE otherwise.

293:    Level: intermediate

295: @*/
296: PetscErrorCode MatMultHermitianTransposeEqual(Mat A, Mat B, PetscInt n, PetscBool *flg)
297: {
298:   PetscFunctionBegin;
299:   PetscCall(MatMultEqual_Private(A, B, n, flg, 2, PETSC_FALSE));
300:   PetscFunctionReturn(PETSC_SUCCESS);
301: }

303: /*@
304:    MatMultHermitianTransposeAddEqual - Compares matrix-vector products of two matrices.

306:    Collective

308:    Input Parameters:
309: +  A - the first matrix
310: .  B - the second matrix
311: -  n - number of random vectors to be tested

313:    Output Parameter:
314: .  flg - PETSC_TRUE if the products are equal; PETSC_FALSE otherwise.

316:    Level: intermediate

318: @*/
319: PetscErrorCode MatMultHermitianTransposeAddEqual(Mat A, Mat B, PetscInt n, PetscBool *flg)
320: {
321:   PetscFunctionBegin;
322:   PetscCall(MatMultEqual_Private(A, B, n, flg, 2, PETSC_TRUE));
323:   PetscFunctionReturn(PETSC_SUCCESS);
324: }

326: /*@
327:    MatMatMultEqual - Test A*B*x = C*x for n random vector x

329:    Collective

331:    Input Parameters:
332: +  A - the first matrix
333: .  B - the second matrix
334: .  C - the third matrix
335: -  n - number of random vectors to be tested

337:    Output Parameter:
338: .  flg - PETSC_TRUE if the products are equal; PETSC_FALSE otherwise.

340:    Level: intermediate

342: @*/
343: PetscErrorCode MatMatMultEqual(Mat A, Mat B, Mat C, PetscInt n, PetscBool *flg)
344: {
345:   PetscFunctionBegin;
346:   PetscCall(MatMatMultEqual_Private(A, B, C, n, flg, PETSC_FALSE, PETSC_FALSE));
347:   PetscFunctionReturn(PETSC_SUCCESS);
348: }

350: /*@
351:    MatTransposeMatMultEqual - Test A^T*B*x = C*x for n random vector x

353:    Collective

355:    Input Parameters:
356: +  A - the first matrix
357: .  B - the second matrix
358: .  C - the third matrix
359: -  n - number of random vectors to be tested

361:    Output Parameter:
362: .  flg - PETSC_TRUE if the products are equal; PETSC_FALSE otherwise.

364:    Level: intermediate

366: @*/
367: PetscErrorCode MatTransposeMatMultEqual(Mat A, Mat B, Mat C, PetscInt n, PetscBool *flg)
368: {
369:   PetscFunctionBegin;
370:   PetscCall(MatMatMultEqual_Private(A, B, C, n, flg, PETSC_TRUE, PETSC_FALSE));
371:   PetscFunctionReturn(PETSC_SUCCESS);
372: }

374: /*@
375:    MatMatTransposeMultEqual - Test A*B^T*x = C*x for n random vector x

377:    Collective

379:    Input Parameters:
380: +  A - the first matrix
381: .  B - the second matrix
382: .  C - the third matrix
383: -  n - number of random vectors to be tested

385:    Output Parameter:
386: .  flg - PETSC_TRUE if the products are equal; PETSC_FALSE otherwise.

388:    Level: intermediate

390: @*/
391: PetscErrorCode MatMatTransposeMultEqual(Mat A, Mat B, Mat C, PetscInt n, PetscBool *flg)
392: {
393:   PetscFunctionBegin;
394:   PetscCall(MatMatMultEqual_Private(A, B, C, n, flg, PETSC_FALSE, PETSC_TRUE));
395:   PetscFunctionReturn(PETSC_SUCCESS);
396: }

398: static PetscErrorCode MatProjMultEqual_Private(Mat A, Mat B, Mat C, PetscInt n, PetscBool rart, PetscBool *flg)
399: {
400:   Vec         x, v1, v2, v3, v4, Cx, Bx;
401:   PetscReal   norm_abs, norm_rel, tol = PETSC_SQRT_MACHINE_EPSILON;
402:   PetscInt    i, am, an, bm, bn, cm, cn;
403:   PetscRandom rdm;
404:   PetscScalar none = -1.0;

406:   PetscFunctionBegin;
407:   PetscCall(MatGetLocalSize(A, &am, &an));
408:   PetscCall(MatGetLocalSize(B, &bm, &bn));
409:   if (rart) {
410:     PetscInt t = bm;
411:     bm         = bn;
412:     bn         = t;
413:   }
414:   PetscCall(MatGetLocalSize(C, &cm, &cn));
415:   PetscCheck(an == bm && bn == cm && bn == cn, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Mat A, B, C local dim %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT, am, an, bm, bn, cm, cn);

417:   /* Create left vector of A: v2 */
418:   PetscCall(MatCreateVecs(A, &Bx, &v2));

420:   /* Create right vectors of B: x, v3, v4 */
421:   if (rart) {
422:     PetscCall(MatCreateVecs(B, &v1, &x));
423:   } else {
424:     PetscCall(MatCreateVecs(B, &x, &v1));
425:   }
426:   PetscCall(VecDuplicate(x, &v3));

428:   PetscCall(MatCreateVecs(C, &Cx, &v4));
429:   PetscCall(PetscRandomCreate(PETSC_COMM_WORLD, &rdm));
430:   PetscCall(PetscRandomSetFromOptions(rdm));

432:   *flg = PETSC_TRUE;
433:   for (i = 0; i < n; i++) {
434:     PetscCall(VecSetRandom(x, rdm));
435:     PetscCall(VecCopy(x, Cx));
436:     PetscCall(MatMult(C, Cx, v4)); /* v4 = C*x   */
437:     if (rart) {
438:       PetscCall(MatMultTranspose(B, x, v1));
439:     } else {
440:       PetscCall(MatMult(B, x, v1));
441:     }
442:     PetscCall(VecCopy(v1, Bx));
443:     PetscCall(MatMult(A, Bx, v2)); /* v2 = A*B*x */
444:     PetscCall(VecCopy(v2, v1));
445:     if (rart) {
446:       PetscCall(MatMult(B, v1, v3)); /* v3 = R*A*R^t*x */
447:     } else {
448:       PetscCall(MatMultTranspose(B, v1, v3)); /* v3 = Bt*A*B*x */
449:     }
450:     PetscCall(VecNorm(v4, NORM_2, &norm_abs));
451:     PetscCall(VecAXPY(v4, none, v3));
452:     PetscCall(VecNorm(v4, NORM_2, &norm_rel));

454:     if (norm_abs > tol) norm_rel /= norm_abs;
455:     if (norm_rel > tol) {
456:       *flg = PETSC_FALSE;
457:       PetscCall(PetscInfo(A, "Error: %" PetscInt_FMT "-th Mat%sMult() %g\n", i, rart ? "RARt" : "PtAP", (double)norm_rel));
458:       break;
459:     }
460:   }

462:   PetscCall(PetscRandomDestroy(&rdm));
463:   PetscCall(VecDestroy(&x));
464:   PetscCall(VecDestroy(&Bx));
465:   PetscCall(VecDestroy(&Cx));
466:   PetscCall(VecDestroy(&v1));
467:   PetscCall(VecDestroy(&v2));
468:   PetscCall(VecDestroy(&v3));
469:   PetscCall(VecDestroy(&v4));
470:   PetscFunctionReturn(PETSC_SUCCESS);
471: }

473: /*@
474:    MatPtAPMultEqual - Compares matrix-vector products of C = Bt*A*B

476:    Collective

478:    Input Parameters:
479: +  A - the first matrix
480: .  B - the second matrix
481: .  C - the third matrix
482: -  n - number of random vectors to be tested

484:    Output Parameter:
485: .  flg - PETSC_TRUE if the products are equal; PETSC_FALSE otherwise.

487:    Level: intermediate

489: @*/
490: PetscErrorCode MatPtAPMultEqual(Mat A, Mat B, Mat C, PetscInt n, PetscBool *flg)
491: {
492:   PetscFunctionBegin;
493:   PetscCall(MatProjMultEqual_Private(A, B, C, n, PETSC_FALSE, flg));
494:   PetscFunctionReturn(PETSC_SUCCESS);
495: }

497: /*@
498:    MatRARtMultEqual - Compares matrix-vector products of C = B*A*B^t

500:    Collective

502:    Input Parameters:
503: +  A - the first matrix
504: .  B - the second matrix
505: .  C - the third matrix
506: -  n - number of random vectors to be tested

508:    Output Parameter:
509: .  flg - PETSC_TRUE if the products are equal; PETSC_FALSE otherwise.

511:    Level: intermediate

513: @*/
514: PetscErrorCode MatRARtMultEqual(Mat A, Mat B, Mat C, PetscInt n, PetscBool *flg)
515: {
516:   PetscFunctionBegin;
517:   PetscCall(MatProjMultEqual_Private(A, B, C, n, PETSC_TRUE, flg));
518:   PetscFunctionReturn(PETSC_SUCCESS);
519: }

521: /*@
522:    MatIsLinear - Check if a shell matrix A is a linear operator.

524:    Collective

526:    Input Parameters:
527: +  A - the shell matrix
528: -  n - number of random vectors to be tested

530:    Output Parameter:
531: .  flg - PETSC_TRUE if the shell matrix is linear; PETSC_FALSE otherwise.

533:    Level: intermediate
534: @*/
535: PetscErrorCode MatIsLinear(Mat A, PetscInt n, PetscBool *flg)
536: {
537:   Vec         x, y, s1, s2;
538:   PetscRandom rctx;
539:   PetscScalar a;
540:   PetscInt    k;
541:   PetscReal   norm, normA;
542:   MPI_Comm    comm;
543:   PetscMPIInt rank;

545:   PetscFunctionBegin;
547:   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
548:   PetscCallMPI(MPI_Comm_rank(comm, &rank));

550:   PetscCall(PetscRandomCreate(comm, &rctx));
551:   PetscCall(PetscRandomSetFromOptions(rctx));
552:   PetscCall(MatCreateVecs(A, &x, &s1));
553:   PetscCall(VecDuplicate(x, &y));
554:   PetscCall(VecDuplicate(s1, &s2));

556:   *flg = PETSC_TRUE;
557:   for (k = 0; k < n; k++) {
558:     PetscCall(VecSetRandom(x, rctx));
559:     PetscCall(VecSetRandom(y, rctx));
560:     if (rank == 0) PetscCall(PetscRandomGetValue(rctx, &a));
561:     PetscCallMPI(MPI_Bcast(&a, 1, MPIU_SCALAR, 0, comm));

563:     /* s2 = a*A*x + A*y */
564:     PetscCall(MatMult(A, y, s2));  /* s2 = A*y */
565:     PetscCall(MatMult(A, x, s1));  /* s1 = A*x */
566:     PetscCall(VecAXPY(s2, a, s1)); /* s2 = a s1 + s2 */

568:     /* s1 = A * (a x + y) */
569:     PetscCall(VecAXPY(y, a, x)); /* y = a x + y */
570:     PetscCall(MatMult(A, y, s1));
571:     PetscCall(VecNorm(s1, NORM_INFINITY, &normA));

573:     PetscCall(VecAXPY(s2, -1.0, s1)); /* s2 = - s1 + s2 */
574:     PetscCall(VecNorm(s2, NORM_INFINITY, &norm));
575:     if (norm / normA > 100. * PETSC_MACHINE_EPSILON) {
576:       *flg = PETSC_FALSE;
577:       PetscCall(PetscInfo(A, "Error: %" PetscInt_FMT "-th |A*(ax+y) - (a*A*x+A*y)|/|A(ax+y)| %g > tol %g\n", k, (double)(norm / normA), (double)(100. * PETSC_MACHINE_EPSILON)));
578:       break;
579:     }
580:   }
581:   PetscCall(PetscRandomDestroy(&rctx));
582:   PetscCall(VecDestroy(&x));
583:   PetscCall(VecDestroy(&y));
584:   PetscCall(VecDestroy(&s1));
585:   PetscCall(VecDestroy(&s2));
586:   PetscFunctionReturn(PETSC_SUCCESS);
587: }