xref: /petsc/src/mat/tests/ex94.c (revision ffa8c5705e8ab2cf85ee1d14dbe507a6e2eb5283)
1 
2 static char help[] = "Tests sequential and parallel MatMatMult() and MatPtAP(), MatTransposeMatMult(), sequential MatMatTransposeMult(), MatRARt()\n\
3 Input arguments are:\n\
4   -f0 <input_file> -f1 <input_file> -f2 <input_file> -f3 <input_file> : file to load\n\n";
5 /* Example of usage:
6    ./ex94 -f0 <A_binary> -f1 <B_binary> -matmatmult_mat_view ascii::ascii_info -matmatmulttr_mat_view
7    mpiexec -n 3 ./ex94 -f0 medium -f1 medium -f2 arco1 -f3 arco1 -matmatmult_mat_view
8 */
9 
10 #include <petscmat.h>
11 
12 /*
13      B = A - B
14      norm = norm(B)
15 */
16 PetscErrorCode MatNormDifference(Mat A,Mat B,PetscReal *norm)
17 {
18   PetscFunctionBegin;
19   PetscCall(MatAXPY(B,-1.0,A,DIFFERENT_NONZERO_PATTERN));
20   PetscCall(MatNorm(B,NORM_FROBENIUS,norm));
21   PetscFunctionReturn(0);
22 }
23 
24 int main(int argc,char **args)
25 {
26   Mat            A,A_save,B,AT,ATT,BT,BTT,P,R,C,C1;
27   Vec            x,v1,v2,v3,v4;
28   PetscViewer    viewer;
29   PetscMPIInt    size,rank;
30   PetscInt       i,m,n,j,*idxn,M,N,nzp,rstart,rend;
31   PetscReal      norm,norm_abs,norm_tmp,fill=4.0;
32   PetscRandom    rdm;
33   char           file[4][128];
34   PetscBool      flg,preload = PETSC_TRUE;
35   PetscScalar    *a,rval,alpha,none = -1.0;
36   PetscBool      Test_MatMatMult=PETSC_TRUE,Test_MatMatTr=PETSC_TRUE,Test_MatPtAP=PETSC_TRUE,Test_MatRARt=PETSC_TRUE,Test_MatMatMatMult=PETSC_TRUE;
37   PetscBool      Test_MatAXPY=PETSC_FALSE,view=PETSC_FALSE;
38   PetscInt       pm,pn,pM,pN;
39   MatInfo        info;
40   PetscBool      seqaij;
41   MatType        mattype;
42   Mat            Cdensetest,Pdense,Cdense,Adense;
43 
44   PetscCall(PetscInitialize(&argc,&args,(char*)0,help));
45   PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD,&size));
46   PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD,&rank));
47 
48   PetscCall(PetscOptionsGetReal(NULL,NULL,"-fill",&fill,NULL));
49   PetscCall(PetscOptionsGetBool(NULL,NULL,"-matops_view",&view,NULL));
50   if (view) PetscCall(PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD,PETSC_VIEWER_ASCII_INFO));
51 
52   /*  Load the matrices A_save and B */
53   PetscCall(PetscOptionsGetString(NULL,NULL,"-f0",file[0],sizeof(file[0]),&flg));
54   PetscCheck(flg,PETSC_COMM_WORLD,PETSC_ERR_USER,"Must indicate a file name for small matrix A with the -f0 option.");
55   PetscCall(PetscOptionsGetString(NULL,NULL,"-f1",file[1],sizeof(file[1]),&flg));
56   PetscCheck(flg,PETSC_COMM_WORLD,PETSC_ERR_USER,"Must indicate a file name for small matrix B with the -f1 option.");
57   PetscCall(PetscOptionsGetString(NULL,NULL,"-f2",file[2],sizeof(file[2]),&flg));
58   if (!flg) {
59     preload = PETSC_FALSE;
60   } else {
61     PetscCall(PetscOptionsGetString(NULL,NULL,"-f3",file[3],sizeof(file[3]),&flg));
62     PetscCheck(flg,PETSC_COMM_WORLD,PETSC_ERR_USER,"Must indicate a file name for test matrix B with the -f3 option.");
63   }
64 
65   PetscPreLoadBegin(preload,"Load system");
66   PetscCall(PetscViewerBinaryOpen(PETSC_COMM_WORLD,file[2*PetscPreLoadIt],FILE_MODE_READ,&viewer));
67   PetscCall(MatCreate(PETSC_COMM_WORLD,&A_save));
68   PetscCall(MatSetFromOptions(A_save));
69   PetscCall(MatLoad(A_save,viewer));
70   PetscCall(PetscViewerDestroy(&viewer));
71 
72   PetscCall(PetscViewerBinaryOpen(PETSC_COMM_WORLD,file[2*PetscPreLoadIt+1],FILE_MODE_READ,&viewer));
73   PetscCall(MatCreate(PETSC_COMM_WORLD,&B));
74   PetscCall(MatSetFromOptions(B));
75   PetscCall(MatLoad(B,viewer));
76   PetscCall(PetscViewerDestroy(&viewer));
77 
78   PetscCall(MatGetType(B,&mattype));
79 
80   PetscCall(MatGetSize(B,&M,&N));
81   nzp  = PetscMax((PetscInt)(0.1*M),5);
82   PetscCall(PetscMalloc((nzp+1)*(sizeof(PetscInt)+sizeof(PetscScalar)),&idxn));
83   a    = (PetscScalar*)(idxn + nzp);
84 
85   /* Create vectors v1 and v2 that are compatible with A_save */
86   PetscCall(VecCreate(PETSC_COMM_WORLD,&v1));
87   PetscCall(MatGetLocalSize(A_save,&m,NULL));
88   PetscCall(VecSetSizes(v1,m,PETSC_DECIDE));
89   PetscCall(VecSetFromOptions(v1));
90   PetscCall(VecDuplicate(v1,&v2));
91 
92   PetscCall(PetscRandomCreate(PETSC_COMM_WORLD,&rdm));
93   PetscCall(PetscRandomSetFromOptions(rdm));
94   PetscCall(PetscOptionsGetReal(NULL,NULL,"-fill",&fill,NULL));
95 
96   /* Test MatAXPY()    */
97   /*-------------------*/
98   PetscCall(PetscOptionsHasName(NULL,NULL,"-test_MatAXPY",&Test_MatAXPY));
99   if (Test_MatAXPY) {
100     Mat Btmp;
101     PetscCall(MatDuplicate(A_save,MAT_COPY_VALUES,&A));
102     PetscCall(MatDuplicate(B,MAT_COPY_VALUES,&Btmp));
103     PetscCall(MatAXPY(A,-1.0,B,DIFFERENT_NONZERO_PATTERN)); /* A = -B + A_save */
104 
105     PetscCall(MatScale(A,-1.0)); /* A = -A = B - A_save */
106     PetscCall(MatAXPY(Btmp,-1.0,A,DIFFERENT_NONZERO_PATTERN)); /* Btmp = -A + B = A_save */
107     PetscCall(MatMultEqual(A_save,Btmp,10,&flg));
108     PetscCheck(flg,PETSC_COMM_SELF,PETSC_ERR_PLIB,"MatAXPY() is incorrect");
109     PetscCall(MatDestroy(&A));
110     PetscCall(MatDestroy(&Btmp));
111 
112     Test_MatMatMult    = PETSC_FALSE;
113     Test_MatMatTr      = PETSC_FALSE;
114     Test_MatPtAP       = PETSC_FALSE;
115     Test_MatRARt       = PETSC_FALSE;
116     Test_MatMatMatMult = PETSC_FALSE;
117   }
118 
119   /* 1) Test MatMatMult() */
120   /* ---------------------*/
121   if (Test_MatMatMult) {
122     PetscCall(MatDuplicate(A_save,MAT_COPY_VALUES,&A));
123     PetscCall(MatCreateTranspose(A,&AT));
124     PetscCall(MatCreateTranspose(AT,&ATT));
125     PetscCall(MatCreateTranspose(B,&BT));
126     PetscCall(MatCreateTranspose(BT,&BTT));
127 
128     PetscCall(MatMatMult(AT,B,MAT_INITIAL_MATRIX,fill,&C));
129     PetscCall(MatMatMultEqual(AT,B,C,10,&flg));
130     PetscCheck(flg,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Error: MatMatMult() for C=AT*B");
131     PetscCall(MatDestroy(&C));
132 
133     PetscCall(MatMatMult(ATT,B,MAT_INITIAL_MATRIX,fill,&C));
134     PetscCall(MatMatMultEqual(ATT,B,C,10,&flg));
135     PetscCheck(flg,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Error: MatMatMult() for C=ATT*B");
136     PetscCall(MatDestroy(&C));
137 
138     PetscCall(MatMatMult(A,B,MAT_INITIAL_MATRIX,fill,&C));
139     PetscCall(MatMatMultEqual(A,B,C,10,&flg));
140     PetscCheck(flg,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Error: MatMatMult() for reuse C=A*B");
141     /* ATT has different matrix type as A (although they have same internal data structure),
142        we cannot call MatProductReplaceMats(ATT,NULL,NULL,C) and MatMatMult(ATT,B,MAT_REUSE_MATRIX,fill,&C) */
143     PetscCall(MatDestroy(&C));
144 
145     PetscCall(MatMatMult(A,BTT,MAT_INITIAL_MATRIX,fill,&C));
146     PetscCall(MatMatMultEqual(A,BTT,C,10,&flg));
147     PetscCheck(flg,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Error: MatMatMult() for C=A*BTT");
148     PetscCall(MatDestroy(&C));
149 
150     PetscCall(MatMatMult(ATT,BTT,MAT_INITIAL_MATRIX,fill,&C));
151     PetscCall(MatMatMultEqual(A,B,C,10,&flg));
152     PetscCheck(flg,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Error: MatMatMult()");
153     PetscCall(MatDestroy(&C));
154 
155     PetscCall(MatDestroy(&BTT));
156     PetscCall(MatDestroy(&BT));
157     PetscCall(MatDestroy(&ATT));
158     PetscCall(MatDestroy(&AT));
159 
160     PetscCall(MatMatMult(A,B,MAT_INITIAL_MATRIX,fill,&C));
161     PetscCall(MatSetOptionsPrefix(C,"matmatmult_")); /* enable option '-matmatmult_' for matrix C */
162     PetscCall(MatGetInfo(C,MAT_GLOBAL_SUM,&info));
163 
164     /* Test MAT_REUSE_MATRIX - reuse symbolic C */
165     alpha=1.0;
166     for (i=0; i<2; i++) {
167       alpha -=0.1;
168       PetscCall(MatScale(A,alpha));
169       PetscCall(MatMatMult(A,B,MAT_REUSE_MATRIX,fill,&C));
170     }
171     PetscCall(MatMatMultEqual(A,B,C,10,&flg));
172     PetscCheck(flg,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Error: MatMatMult()");
173     PetscCall(MatDestroy(&A));
174 
175     /* Test MatDuplicate() of C=A*B */
176     PetscCall(MatDuplicate(C,MAT_COPY_VALUES,&C1));
177     PetscCall(MatDestroy(&C1));
178     PetscCall(MatDestroy(&C));
179   } /* if (Test_MatMatMult) */
180 
181   /* 2) Test MatTransposeMatMult() and MatMatTransposeMult() */
182   /* ------------------------------------------------------- */
183   if (Test_MatMatTr) {
184     /* Create P */
185     PetscInt PN,rstart,rend;
186     PN   = M/2;
187     nzp  = 5; /* num of nonzeros in each row of P */
188     PetscCall(MatCreate(PETSC_COMM_WORLD,&P));
189     PetscCall(MatSetSizes(P,PETSC_DECIDE,PETSC_DECIDE,M,PN));
190     PetscCall(MatSetType(P,mattype));
191     PetscCall(MatSeqAIJSetPreallocation(P,nzp,NULL));
192     PetscCall(MatMPIAIJSetPreallocation(P,nzp,NULL,nzp,NULL));
193     PetscCall(MatGetOwnershipRange(P,&rstart,&rend));
194     for (i=0; i<nzp; i++) {
195       PetscCall(PetscRandomGetValue(rdm,&a[i]));
196     }
197     for (i=rstart; i<rend; i++) {
198       for (j=0; j<nzp; j++) {
199         PetscCall(PetscRandomGetValue(rdm,&rval));
200         idxn[j] = (PetscInt)(PetscRealPart(rval)*PN);
201       }
202       PetscCall(MatSetValues(P,1,&i,nzp,idxn,a,ADD_VALUES));
203     }
204     PetscCall(MatAssemblyBegin(P,MAT_FINAL_ASSEMBLY));
205     PetscCall(MatAssemblyEnd(P,MAT_FINAL_ASSEMBLY));
206 
207     /* Create R = P^T */
208     PetscCall(MatTranspose(P,MAT_INITIAL_MATRIX,&R));
209 
210     { /* Test R = P^T, C1 = R*B */
211       PetscCall(MatMatMult(R,B,MAT_INITIAL_MATRIX,fill,&C1));
212       PetscCall(MatTranspose(P,MAT_REUSE_MATRIX,&R));
213       PetscCall(MatMatMult(R,B,MAT_REUSE_MATRIX,fill,&C1));
214       PetscCall(MatDestroy(&C1));
215     }
216 
217     /* C = P^T*B */
218     PetscCall(MatTransposeMatMult(P,B,MAT_INITIAL_MATRIX,fill,&C));
219     PetscCall(MatGetInfo(C,MAT_GLOBAL_SUM,&info));
220 
221     /* Test MAT_REUSE_MATRIX - reuse symbolic C */
222     PetscCall(MatTransposeMatMult(P,B,MAT_REUSE_MATRIX,fill,&C));
223     if (view) {
224       PetscCall(PetscPrintf(PETSC_COMM_WORLD,"C = P^T * B:\n"));
225       PetscCall(MatView(C,PETSC_VIEWER_STDOUT_WORLD));
226     }
227     PetscCall(MatProductClear(C));
228     if (view) {
229       PetscCall(PetscPrintf(PETSC_COMM_WORLD,"\nC = P^T * B after MatProductClear():\n"));
230       PetscCall(MatView(C,PETSC_VIEWER_STDOUT_WORLD));
231     }
232 
233     /* Compare P^T*B and R*B */
234     PetscCall(MatMatMult(R,B,MAT_INITIAL_MATRIX,fill,&C1));
235     PetscCall(MatNormDifference(C,C1,&norm));
236     PetscCheckFalse(norm > PETSC_SMALL,PETSC_COMM_WORLD,PETSC_ERR_PLIB,"Error in MatTransposeMatMult(): %g",(double)norm);
237     PetscCall(MatDestroy(&C1));
238 
239     /* Test MatDuplicate() of C=P^T*B */
240     PetscCall(MatDuplicate(C,MAT_COPY_VALUES,&C1));
241     PetscCall(MatDestroy(&C1));
242     PetscCall(MatDestroy(&C));
243 
244     /* C = B*R^T */
245     PetscCall(PetscObjectTypeCompare((PetscObject)B,MATSEQAIJ,&seqaij));
246     if (size == 1 && seqaij) {
247       PetscCall(MatMatTransposeMult(B,R,MAT_INITIAL_MATRIX,fill,&C));
248       PetscCall(MatSetOptionsPrefix(C,"matmatmulttr_")); /* enable '-matmatmulttr_' for matrix C */
249       PetscCall(MatGetInfo(C,MAT_GLOBAL_SUM,&info));
250 
251       /* Test MAT_REUSE_MATRIX - reuse symbolic C */
252       PetscCall(MatMatTransposeMult(B,R,MAT_REUSE_MATRIX,fill,&C));
253 
254       /* Check */
255       PetscCall(MatMatMult(B,P,MAT_INITIAL_MATRIX,fill,&C1));
256       PetscCall(MatNormDifference(C,C1,&norm));
257       PetscCheckFalse(norm > PETSC_SMALL,PETSC_COMM_WORLD,PETSC_ERR_PLIB,"Error in MatMatTransposeMult() %g",(double)norm);
258       PetscCall(MatDestroy(&C1));
259       PetscCall(MatDestroy(&C));
260     }
261     PetscCall(MatDestroy(&P));
262     PetscCall(MatDestroy(&R));
263   }
264 
265   /* 3) Test MatPtAP() */
266   /*-------------------*/
267   if (Test_MatPtAP) {
268     PetscInt  PN;
269     Mat       Cdup;
270 
271     PetscCall(MatDuplicate(A_save,MAT_COPY_VALUES,&A));
272     PetscCall(MatGetSize(A,&M,&N));
273     PetscCall(MatGetLocalSize(A,&m,&n));
274 
275     PN   = M/2;
276     nzp  = (PetscInt)(0.1*PN+1); /* num of nozeros in each row of P */
277     PetscCall(MatCreate(PETSC_COMM_WORLD,&P));
278     PetscCall(MatSetSizes(P,PETSC_DECIDE,PETSC_DECIDE,N,PN));
279     PetscCall(MatSetType(P,mattype));
280     PetscCall(MatSeqAIJSetPreallocation(P,nzp,NULL));
281     PetscCall(MatMPIAIJSetPreallocation(P,nzp,NULL,nzp,NULL));
282     for (i=0; i<nzp; i++) {
283       PetscCall(PetscRandomGetValue(rdm,&a[i]));
284     }
285     PetscCall(MatGetOwnershipRange(P,&rstart,&rend));
286     for (i=rstart; i<rend; i++) {
287       for (j=0; j<nzp; j++) {
288         PetscCall(PetscRandomGetValue(rdm,&rval));
289         idxn[j] = (PetscInt)(PetscRealPart(rval)*PN);
290       }
291       PetscCall(MatSetValues(P,1,&i,nzp,idxn,a,ADD_VALUES));
292     }
293     PetscCall(MatAssemblyBegin(P,MAT_FINAL_ASSEMBLY));
294     PetscCall(MatAssemblyEnd(P,MAT_FINAL_ASSEMBLY));
295 
296     /* PetscCall(MatView(P,PETSC_VIEWER_STDOUT_WORLD)); */
297     PetscCall(MatGetSize(P,&pM,&pN));
298     PetscCall(MatGetLocalSize(P,&pm,&pn));
299     PetscCall(MatPtAP(A,P,MAT_INITIAL_MATRIX,fill,&C));
300 
301     /* Test MAT_REUSE_MATRIX - reuse symbolic C */
302     alpha=1.0;
303     for (i=0; i<2; i++) {
304       alpha -=0.1;
305       PetscCall(MatScale(A,alpha));
306       PetscCall(MatPtAP(A,P,MAT_REUSE_MATRIX,fill,&C));
307     }
308 
309     /* Test PtAP ops with P Dense and A either AIJ or SeqDense (it assumes MatPtAP_XAIJ_XAIJ is fine) */
310     PetscCall(PetscObjectTypeCompare((PetscObject)A,MATSEQAIJ,&seqaij));
311     if (seqaij) {
312       PetscCall(MatConvert(C,MATSEQDENSE,MAT_INITIAL_MATRIX,&Cdensetest));
313       PetscCall(MatConvert(P,MATSEQDENSE,MAT_INITIAL_MATRIX,&Pdense));
314     } else {
315       PetscCall(MatConvert(C,MATMPIDENSE,MAT_INITIAL_MATRIX,&Cdensetest));
316       PetscCall(MatConvert(P,MATMPIDENSE,MAT_INITIAL_MATRIX,&Pdense));
317     }
318 
319     /* test with A(AIJ), Pdense -- call MatPtAP_Basic() when np>1 */
320     PetscCall(MatPtAP(A,Pdense,MAT_INITIAL_MATRIX,fill,&Cdense));
321     PetscCall(MatPtAP(A,Pdense,MAT_REUSE_MATRIX,fill,&Cdense));
322     PetscCall(MatPtAPMultEqual(A,Pdense,Cdense,10,&flg));
323     PetscCheck(flg,PETSC_COMM_WORLD,PETSC_ERR_PLIB,"Error in MatPtAP with A AIJ and P Dense");
324     PetscCall(MatDestroy(&Cdense));
325 
326     /* test with A SeqDense */
327     if (seqaij) {
328       PetscCall(MatConvert(A,MATSEQDENSE,MAT_INITIAL_MATRIX,&Adense));
329       PetscCall(MatPtAP(Adense,Pdense,MAT_INITIAL_MATRIX,fill,&Cdense));
330       PetscCall(MatPtAP(Adense,Pdense,MAT_REUSE_MATRIX,fill,&Cdense));
331       PetscCall(MatPtAPMultEqual(Adense,Pdense,Cdense,10,&flg));
332       PetscCheck(flg,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Error in MatPtAP with A SeqDense and P SeqDense");
333       PetscCall(MatDestroy(&Cdense));
334       PetscCall(MatDestroy(&Adense));
335     }
336     PetscCall(MatDestroy(&Cdensetest));
337     PetscCall(MatDestroy(&Pdense));
338 
339     /* Test MatDuplicate() of C=PtAP and MatView(Cdup,...) */
340     PetscCall(MatDuplicate(C,MAT_COPY_VALUES,&Cdup));
341     if (view) {
342       PetscCall(PetscPrintf(PETSC_COMM_WORLD,"\nC = P^T * A * P:\n"));
343       PetscCall(MatView(C,PETSC_VIEWER_STDOUT_WORLD));
344 
345       PetscCall(MatProductClear(C));
346       PetscCall(PetscPrintf(PETSC_COMM_WORLD,"\nC = P^T * A * P after MatProductClear():\n"));
347       PetscCall(MatView(C,PETSC_VIEWER_STDOUT_WORLD));
348 
349       PetscCall(PetscPrintf(PETSC_COMM_WORLD,"\nCdup:\n"));
350       PetscCall(MatView(Cdup,PETSC_VIEWER_STDOUT_WORLD));
351     }
352     PetscCall(MatDestroy(&Cdup));
353 
354     if (size>1 || !seqaij) Test_MatRARt = PETSC_FALSE;
355     /* 4) Test MatRARt() */
356     /* ----------------- */
357     if (Test_MatRARt) {
358       Mat R, RARt, Rdense, RARtdense;
359       PetscCall(MatTranspose(P,MAT_INITIAL_MATRIX,&R));
360 
361       /* Test MatRARt_Basic(), MatMatMatMult_Basic() */
362       PetscCall(MatConvert(R,MATDENSE,MAT_INITIAL_MATRIX,&Rdense));
363       PetscCall(MatRARt(A,Rdense,MAT_INITIAL_MATRIX,2.0,&RARtdense));
364       PetscCall(MatRARt(A,Rdense,MAT_REUSE_MATRIX,2.0,&RARtdense));
365 
366       PetscCall(MatConvert(RARtdense,MATAIJ,MAT_INITIAL_MATRIX,&RARt));
367       PetscCall(MatNormDifference(C,RARt,&norm));
368       PetscCheckFalse(norm > PETSC_SMALL,PETSC_COMM_SELF,PETSC_ERR_PLIB,"|PtAP - RARtdense| = %g",(double)norm);
369       PetscCall(MatDestroy(&Rdense));
370       PetscCall(MatDestroy(&RARtdense));
371       PetscCall(MatDestroy(&RARt));
372 
373       /* Test MatRARt() for aij matrices */
374       PetscCall(MatRARt(A,R,MAT_INITIAL_MATRIX,2.0,&RARt));
375       PetscCall(MatRARt(A,R,MAT_REUSE_MATRIX,2.0,&RARt));
376       PetscCall(MatNormDifference(C,RARt,&norm));
377       PetscCheckFalse(norm > PETSC_SMALL,PETSC_COMM_SELF,PETSC_ERR_PLIB,"|PtAP - RARt| = %g",(double)norm);
378       PetscCall(MatDestroy(&R));
379       PetscCall(MatDestroy(&RARt));
380     }
381 
382     if (Test_MatMatMatMult && size == 1) {
383       Mat       R, RAP;
384       PetscCall(MatTranspose(P,MAT_INITIAL_MATRIX,&R));
385       PetscCall(MatMatMatMult(R,A,P,MAT_INITIAL_MATRIX,2.0,&RAP));
386       PetscCall(MatMatMatMult(R,A,P,MAT_REUSE_MATRIX,2.0,&RAP));
387       PetscCall(MatNormDifference(C,RAP,&norm));
388       PetscCheckFalse(norm > PETSC_SMALL,PETSC_COMM_SELF,PETSC_ERR_PLIB,"PtAP != RAP %g",(double)norm);
389       PetscCall(MatDestroy(&R));
390       PetscCall(MatDestroy(&RAP));
391     }
392 
393     /* Create vector x that is compatible with P */
394     PetscCall(VecCreate(PETSC_COMM_WORLD,&x));
395     PetscCall(MatGetLocalSize(P,&m,&n));
396     PetscCall(VecSetSizes(x,n,PETSC_DECIDE));
397     PetscCall(VecSetFromOptions(x));
398 
399     PetscCall(VecCreate(PETSC_COMM_WORLD,&v3));
400     PetscCall(VecSetSizes(v3,n,PETSC_DECIDE));
401     PetscCall(VecSetFromOptions(v3));
402     PetscCall(VecDuplicate(v3,&v4));
403 
404     norm = 0.0;
405     for (i=0; i<10; i++) {
406       PetscCall(VecSetRandom(x,rdm));
407       PetscCall(MatMult(P,x,v1));
408       PetscCall(MatMult(A,v1,v2));  /* v2 = A*P*x */
409 
410       PetscCall(MatMultTranspose(P,v2,v3)); /* v3 = Pt*A*P*x */
411       PetscCall(MatMult(C,x,v4));           /* v3 = C*x   */
412       PetscCall(VecNorm(v4,NORM_2,&norm_abs));
413       PetscCall(VecAXPY(v4,none,v3));
414       PetscCall(VecNorm(v4,NORM_2,&norm_tmp));
415 
416       norm_tmp /= norm_abs;
417       if (norm_tmp > norm) norm = norm_tmp;
418     }
419     PetscCheckFalse(norm >= PETSC_SMALL,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Error: MatPtAP(), |v1 - v2|: %g",(double)norm);
420 
421     PetscCall(MatDestroy(&A));
422     PetscCall(MatDestroy(&P));
423     PetscCall(MatDestroy(&C));
424     PetscCall(VecDestroy(&v3));
425     PetscCall(VecDestroy(&v4));
426     PetscCall(VecDestroy(&x));
427   }
428 
429   /* Destroy objects */
430   PetscCall(VecDestroy(&v1));
431   PetscCall(VecDestroy(&v2));
432   PetscCall(PetscRandomDestroy(&rdm));
433   PetscCall(PetscFree(idxn));
434 
435   PetscCall(MatDestroy(&A_save));
436   PetscCall(MatDestroy(&B));
437 
438   PetscPreLoadEnd();
439   PetscCall(PetscFinalize());
440   return 0;
441 }
442 
443 /*TEST
444 
445    test:
446       suffix: 2_mattransposematmult_matmatmult
447       nsize: 3
448       requires: datafilespath !complex double !defined(PETSC_USE_64BIT_INDICES)
449       args: -f0 ${DATAFILESPATH}/matrices/medium -f1 ${DATAFILESPATH}/matrices/medium -mattransposematmult_via at*b> ex94_2.tmp 2>&1
450 
451    test:
452       suffix: 2_mattransposematmult_scalable
453       nsize: 3
454       requires: datafilespath !complex double !defined(PETSC_USE_64BIT_INDICES)
455       args: -f0 ${DATAFILESPATH}/matrices/medium -f1 ${DATAFILESPATH}/matrices/medium -mattransposematmult_via scalable> ex94_2.tmp 2>&1
456       output_file: output/ex94_1.out
457 
458    test:
459       suffix: axpy_mpiaij
460       requires: datafilespath !complex double !defined(PETSC_USE_64BIT_INDICES)
461       nsize: 8
462       args: -f0 ${DATAFILESPATH}/matrices/poisson_2d5p -f1 ${DATAFILESPATH}/matrices/poisson_2d13p -test_MatAXPY
463       output_file: output/ex94_1.out
464 
465    test:
466       suffix: axpy_mpibaij
467       requires: datafilespath !complex double !defined(PETSC_USE_64BIT_INDICES)
468       nsize: 8
469       args: -f0 ${DATAFILESPATH}/matrices/poisson_2d5p -f1 ${DATAFILESPATH}/matrices/poisson_2d13p -test_MatAXPY -mat_type baij
470       output_file: output/ex94_1.out
471 
472    test:
473       suffix: axpy_mpisbaij
474       requires: datafilespath !complex double !defined(PETSC_USE_64BIT_INDICES)
475       nsize: 8
476       args: -f0 ${DATAFILESPATH}/matrices/poisson_2d5p -f1 ${DATAFILESPATH}/matrices/poisson_2d13p -test_MatAXPY -mat_type sbaij
477       output_file: output/ex94_1.out
478 
479    test:
480       suffix: matmatmult
481       requires: datafilespath !complex double !defined(PETSC_USE_64BIT_INDICES)
482       args: -f0 ${DATAFILESPATH}/matrices/arco1 -f1 ${DATAFILESPATH}/matrices/arco1 -viewer_binary_skip_info
483       output_file: output/ex94_1.out
484 
485    test:
486       suffix: matmatmult_2
487       requires: datafilespath !complex double !defined(PETSC_USE_64BIT_INDICES)
488       args: -f0 ${DATAFILESPATH}/matrices/arco1 -f1 ${DATAFILESPATH}/matrices/arco1 -mat_type mpiaij -viewer_binary_skip_info
489       output_file: output/ex94_1.out
490 
491    test:
492       suffix: matmatmult_scalable
493       nsize: 4
494       requires: datafilespath !complex double !defined(PETSC_USE_64BIT_INDICES)
495       args: -f0 ${DATAFILESPATH}/matrices/arco1 -f1 ${DATAFILESPATH}/matrices/arco1 -matmatmult_via scalable
496       output_file: output/ex94_1.out
497 
498    test:
499       suffix: ptap
500       nsize: 3
501       requires: datafilespath !complex double !defined(PETSC_USE_64BIT_INDICES)
502       args: -f0 ${DATAFILESPATH}/matrices/medium -f1 ${DATAFILESPATH}/matrices/medium -matptap_via scalable
503       output_file: output/ex94_1.out
504 
505    test:
506       suffix: rap
507       nsize: 3
508       requires: datafilespath !complex double !defined(PETSC_USE_64BIT_INDICES)
509       args: -f0 ${DATAFILESPATH}/matrices/medium -f1 ${DATAFILESPATH}/matrices/medium
510       output_file: output/ex94_1.out
511 
512    test:
513       suffix: scalable0
514       requires: datafilespath !complex double !defined(PETSC_USE_64BIT_INDICES)
515       args: -f0 ${DATAFILESPATH}/matrices/arco1 -f1 ${DATAFILESPATH}/matrices/arco1 -viewer_binary_skip_info
516       output_file: output/ex94_1.out
517 
518    test:
519       suffix: scalable1
520       requires: datafilespath !complex double !defined(PETSC_USE_64BIT_INDICES)
521       args: -f0 ${DATAFILESPATH}/matrices/arco1 -f1 ${DATAFILESPATH}/matrices/arco1 -viewer_binary_skip_info -matptap_via scalable
522       output_file: output/ex94_1.out
523 
524    test:
525       suffix: view
526       nsize: 2
527       requires: datafilespath !complex double !defined(PETSC_USE_64BIT_INDICES)
528       args: -f0 ${DATAFILESPATH}/matrices/tiny -f1 ${DATAFILESPATH}/matrices/tiny -viewer_binary_skip_info -matops_view
529       output_file: output/ex94_2.out
530 
531 TEST*/
532