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: }