1 /* 2 Defines matrix-matrix product routines for pairs of AIJ matrices 3 C = A * B 4 */ 5 6 #include "src/mat/impls/aij/seq/aij.h" /*I "petscmat.h" I*/ 7 #include "src/mat/utils/freespace.h" 8 #include "src/mat/impls/aij/mpi/mpiaij.h" 9 10 typedef struct { /* used by MatMatMult_MPIAIJ_MPIAIJ for reusing symbolic mat product */ 11 IS isrowa,isrowb,iscolb; 12 Mat *aseq,*bseq,C_seq; 13 } Mat_MatMatMultMPI; 14 15 #undef __FUNCT__ 16 #define __FUNCT__ "MatMatMult" 17 /*@ 18 MatMatMult - Performs Matrix-Matrix Multiplication C=A*B. 19 20 Collective on Mat 21 22 Input Parameters: 23 + A - the left matrix 24 . B - the right matrix 25 . scall - either MAT_INITIAL_MATRIX or MAT_REUSE_MATRIX 26 - fill - expected fill as ratio of nnz(C)/(nnz(A) + nnz(B)) 27 28 Output Parameters: 29 . C - the product matrix 30 31 Notes: 32 C will be created and must be destroyed by the user with MatDestroy(). 33 34 This routine is currently only implemented for pairs of SeqAIJ matrices and classes 35 which inherit from SeqAIJ. C will be of type MATSEQAIJ. 36 37 Level: intermediate 38 39 .seealso: MatMatMultSymbolic(),MatMatMultNumeric() 40 @*/ 41 PetscErrorCode MatMatMult(Mat A,Mat B,MatReuse scall,PetscReal fill,Mat *C) 42 { 43 PetscErrorCode ierr; 44 PetscErrorCode (*fA)(Mat,Mat,MatReuse,PetscReal,Mat*); 45 PetscErrorCode (*fB)(Mat,Mat,MatReuse,PetscReal,Mat*); 46 47 PetscFunctionBegin; 48 PetscValidHeaderSpecific(A,MAT_COOKIE,1); 49 PetscValidType(A,1); 50 MatPreallocated(A); 51 if (!A->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix"); 52 if (A->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix"); 53 PetscValidHeaderSpecific(B,MAT_COOKIE,2); 54 PetscValidType(B,2); 55 MatPreallocated(B); 56 if (!B->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix"); 57 if (B->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix"); 58 PetscValidPointer(C,3); 59 if (B->M!=A->N) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %d != %d",B->M,A->N); 60 61 if (fill <=0.0) SETERRQ1(PETSC_ERR_ARG_SIZ,"fill=%g must be > 0.0",fill); 62 63 /* For now, we do not dispatch based on the type of A and B */ 64 /* When implementations like _SeqAIJ_MAIJ exist, attack the multiple dispatch problem. */ 65 fA = A->ops->matmult; 66 if (!fA) SETERRQ1(PETSC_ERR_SUP,"MatMatMult not supported for A of type %s",A->type_name); 67 fB = B->ops->matmult; 68 if (!fB) SETERRQ1(PETSC_ERR_SUP,"MatMatMult not supported for B of type %s",B->type_name); 69 if (fB!=fA) SETERRQ2(PETSC_ERR_ARG_INCOMP,"MatMatMult requires A, %s, to be compatible with B, %s",A->type_name,B->type_name); 70 71 ierr = PetscLogEventBegin(MAT_MatMult,A,B,0,0);CHKERRQ(ierr); 72 ierr = (*A->ops->matmult)(A,B,scall,fill,C);CHKERRQ(ierr); 73 ierr = PetscLogEventEnd(MAT_MatMult,A,B,0,0);CHKERRQ(ierr); 74 75 PetscFunctionReturn(0); 76 } 77 78 #undef __FUNCT__ 79 #define __FUNCT__ "MatMatMult_MPIAIJ_MPIAIJ" 80 PetscErrorCode MatMatMult_MPIAIJ_MPIAIJ(Mat A,Mat B,MatReuse scall,PetscReal fill, Mat *C) 81 { 82 PetscErrorCode ierr; 83 84 PetscFunctionBegin; 85 if (scall == MAT_INITIAL_MATRIX){ 86 ierr = MatMatMultSymbolic_MPIAIJ_MPIAIJ(A,B,fill,C);CHKERRQ(ierr);/* numeric product is computed as well */ 87 } else if (scall == MAT_REUSE_MATRIX){ 88 ierr = MatMatMultNumeric_MPIAIJ_MPIAIJ(A,B,*C);CHKERRQ(ierr); 89 } else { 90 SETERRQ1(PETSC_ERR_ARG_WRONG,"Invalid MatReuse %d",scall); 91 } 92 PetscFunctionReturn(0); 93 } 94 95 #undef __FUNCT__ 96 #define __FUNCT__ "MatMatMult_SeqAIJ_SeqAIJ" 97 PetscErrorCode MatMatMult_SeqAIJ_SeqAIJ(Mat A,Mat B,MatReuse scall,PetscReal fill,Mat *C) { 98 PetscErrorCode ierr; 99 100 PetscFunctionBegin; 101 if (scall == MAT_INITIAL_MATRIX){ 102 ierr = MatMatMultSymbolic_SeqAIJ_SeqAIJ(A,B,fill,C);CHKERRQ(ierr); 103 } 104 ierr = MatMatMultNumeric_SeqAIJ_SeqAIJ(A,B,*C);CHKERRQ(ierr); 105 PetscFunctionReturn(0); 106 } 107 108 #undef __FUNCT__ 109 #define __FUNCT__ "MatMatMultSymbolic" 110 /*@ 111 MatMatMultSymbolic - Performs construction, preallocation, and computes the ij structure 112 of the matrix-matrix product C=A*B. Call this routine before calling MatMatMultNumeric(). 113 114 Collective on Mat 115 116 Input Parameters: 117 + A - the left matrix 118 . B - the right matrix 119 - fill - expected fill as ratio of nnz(C)/(nnz(A) + nnz(B)) 120 121 Output Parameters: 122 . C - the matrix containing the ij structure of product matrix 123 124 Notes: 125 C will be created as a MATSEQAIJ matrix and must be destroyed by the user with MatDestroy(). 126 127 This routine is currently only implemented for SeqAIJ matrices and classes which inherit from SeqAIJ. 128 129 Level: intermediate 130 131 .seealso: MatMatMult(),MatMatMultNumeric() 132 @*/ 133 PetscErrorCode MatMatMultSymbolic(Mat A,Mat B,PetscReal fill,Mat *C) { 134 PetscErrorCode ierr; 135 PetscErrorCode (*Asymbolic)(Mat,Mat,PetscReal,Mat *); 136 PetscErrorCode (*Bsymbolic)(Mat,Mat,PetscReal,Mat *); 137 138 PetscFunctionBegin; 139 PetscValidHeaderSpecific(A,MAT_COOKIE,1); 140 PetscValidType(A,1); 141 MatPreallocated(A); 142 if (!A->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix"); 143 if (A->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix"); 144 145 PetscValidHeaderSpecific(B,MAT_COOKIE,2); 146 PetscValidType(B,2); 147 MatPreallocated(B); 148 if (!B->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix"); 149 if (B->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix"); 150 PetscValidPointer(C,3); 151 152 if (B->M!=A->N) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %d != %d",B->M,A->N); 153 if (fill <=0.0) SETERRQ1(PETSC_ERR_ARG_SIZ,"fill=%g must be > 0.0",fill); 154 155 /* For now, we do not dispatch based on the type of A and P */ 156 /* When implementations like _SeqAIJ_MAIJ exist, attack the multiple dispatch problem. */ 157 Asymbolic = A->ops->matmultsymbolic; 158 if (!Asymbolic) SETERRQ1(PETSC_ERR_SUP,"C=A*B not implemented for A of type %s",A->type_name); 159 Bsymbolic = B->ops->matmultsymbolic; 160 if (!Bsymbolic) SETERRQ1(PETSC_ERR_SUP,"C=A*B not implemented for B of type %s",B->type_name); 161 if (Bsymbolic!=Asymbolic) SETERRQ2(PETSC_ERR_ARG_INCOMP,"MatMatMultSymbolic requires A, %s, to be compatible with B, %s",A->type_name,B->type_name); 162 163 ierr = PetscLogEventBegin(MAT_MatMultSymbolic,A,B,0,0);CHKERRQ(ierr); 164 ierr = (*Asymbolic)(A,B,fill,C);CHKERRQ(ierr); 165 ierr = PetscLogEventEnd(MAT_MatMultSymbolic,A,B,0,0);CHKERRQ(ierr); 166 167 PetscFunctionReturn(0); 168 } 169 170 EXTERN PetscErrorCode MatDestroy_MPIAIJ(Mat); 171 #undef __FUNCT__ 172 #define __FUNCT__ "MatDestroy_MPIAIJ_MatMatMult" 173 PetscErrorCode MatDestroy_MPIAIJ_MatMatMult(Mat A) 174 { 175 PetscErrorCode ierr; 176 Mat_MatMatMultMPI *mult=(Mat_MatMatMultMPI*)A->spptr; 177 178 PetscFunctionBegin; 179 ierr = ISDestroy(mult->isrowb);CHKERRQ(ierr); 180 ierr = ISDestroy(mult->iscolb);CHKERRQ(ierr); 181 ierr = ISDestroy(mult->isrowa);CHKERRQ(ierr); 182 ierr = MatDestroyMatrices(1,&mult->aseq);CHKERRQ(ierr); 183 ierr = MatDestroyMatrices(1,&mult->bseq);CHKERRQ(ierr); 184 ierr = MatDestroy(mult->C_seq);CHKERRQ(ierr); 185 ierr = PetscFree(mult);CHKERRQ(ierr); 186 187 ierr = MatDestroy_MPIAIJ(A);CHKERRQ(ierr); 188 189 PetscFunctionReturn(0); 190 } 191 192 #undef __FUNCT__ 193 #define __FUNCT__ "MatMatMultSymbolic_MPIAIJ_MPIAIJ" 194 PetscErrorCode MatMatMultSymbolic_MPIAIJ_MPIAIJ(Mat A,Mat B,PetscReal fill,Mat *C) 195 { 196 Mat_MPIAIJ *a = (Mat_MPIAIJ*)A->data; 197 PetscErrorCode ierr; 198 int *idx,i,start,end,ncols,imark,nzA,nzB,*cmap; 199 Mat_MatMatMultMPI *mult; 200 201 PetscFunctionBegin; 202 ierr = PetscNew(Mat_MatMatMultMPI,&mult);CHKERRQ(ierr); 203 204 /* create a seq matrix B_seq = submatrix of B by taking rows of B that equal to nonzero col of A */ 205 start = a->cstart; 206 cmap = a->garray; 207 nzA = a->A->n; 208 nzB = a->B->n; 209 ierr = PetscMalloc((nzA+nzB)*sizeof(int), &idx);CHKERRQ(ierr); 210 ncols = 0; 211 for (i=0; i<nzB; i++) { 212 if (cmap[i] < start) idx[ncols++] = cmap[i]; 213 else break; 214 } 215 imark = i; 216 for (i=0; i<nzA; i++) idx[ncols++] = start + i; 217 for (i=imark; i<nzB; i++) idx[ncols++] = cmap[i]; 218 ierr = ISCreateGeneral(PETSC_COMM_SELF,ncols,idx,&mult->isrowb);CHKERRQ(ierr); 219 ierr = PetscFree(idx);CHKERRQ(ierr); 220 ierr = ISCreateStride(PETSC_COMM_SELF,B->N,0,1,&mult->iscolb);CHKERRQ(ierr); 221 ierr = MatGetSubMatrices(B,1,&mult->isrowb,&mult->iscolb,MAT_INITIAL_MATRIX,&mult->bseq);CHKERRQ(ierr) 222 223 /* create a seq matrix A_seq = submatrix of A by taking all local rows of A */ 224 start = a->rstart; end = a->rend; 225 ierr = ISCreateStride(PETSC_COMM_SELF,end-start,start,1,&mult->isrowa);CHKERRQ(ierr); 226 ierr = MatGetSubMatrices(A,1,&mult->isrowa,&mult->isrowb,MAT_INITIAL_MATRIX,&mult->aseq);CHKERRQ(ierr); 227 228 /* compute C_seq = A_seq * B_seq */ 229 ierr = MatMatMult_SeqAIJ_SeqAIJ(mult->aseq[0],mult->bseq[0],MAT_INITIAL_MATRIX,fill,&mult->C_seq);CHKERRQ(ierr); 230 231 /* create mpi matrix C by concatinating C_seq */ 232 ierr = PetscObjectReference((PetscObject)mult->C_seq);CHKERRQ(ierr); /* prevent C_seq being destroyed by MatMerge() */ 233 ierr = MatMerge(A->comm,mult->C_seq,MAT_INITIAL_MATRIX,C);CHKERRQ(ierr); 234 235 /* attach the supporting struct to C for reuse of symbolic C */ 236 (*C)->spptr = (void*)mult; 237 (*C)->ops->destroy = MatDestroy_MPIAIJ_MatMatMult; 238 239 PetscFunctionReturn(0); 240 } 241 242 #undef __FUNCT__ 243 #define __FUNCT__ "MatMatMultSymbolic_SeqAIJ_SeqAIJ" 244 PetscErrorCode MatMatMultSymbolic_SeqAIJ_SeqAIJ(Mat A,Mat B,PetscReal fill,Mat *C) 245 { 246 PetscErrorCode ierr; 247 FreeSpaceList free_space=PETSC_NULL,current_space=PETSC_NULL; 248 Mat_SeqAIJ *a=(Mat_SeqAIJ*)A->data,*b=(Mat_SeqAIJ*)B->data,*c; 249 int *ai=a->i,*aj=a->j,*bi=b->i,*bj=b->j,*bjj; 250 int *ci,*cj,*lnk; 251 int am=A->M,bn=B->N,bm=B->M; 252 int i,j,anzi,brow,bnzj,cnzi,nlnk,lnk_init=-1,nspacedouble=0; 253 MatScalar *ca; 254 255 PetscFunctionBegin; 256 /* Set up */ 257 /* Allocate ci array, arrays for fill computation and */ 258 /* free space for accumulating nonzero column info */ 259 ierr = PetscMalloc(((am+1)+1)*sizeof(int),&ci);CHKERRQ(ierr); 260 ci[0] = 0; 261 262 ierr = PetscMalloc((bn+1)*sizeof(int),&lnk);CHKERRQ(ierr); 263 nlnk = bn+1; 264 ierr = PetscLLInitialize(lnk_init,nlnk,lnk);CHKERRQ(ierr); 265 266 /* Initial FreeSpace size is fill*(nnz(A)+nnz(B)) */ 267 ierr = GetMoreSpace((int)(fill*(ai[am]+bi[bm])),&free_space);CHKERRQ(ierr); 268 current_space = free_space; 269 270 /* Determine symbolic info for each row of the product: */ 271 for (i=0;i<am;i++) { 272 anzi = ai[i+1] - ai[i]; 273 cnzi = 0; 274 lnk[bn] = bn; 275 j = anzi; 276 aj = a->j + ai[i]; 277 while (j){/* assume cols are almost in increasing order, starting from its end saves computation */ 278 j--; 279 brow = *(aj + j); 280 bnzj = bi[brow+1] - bi[brow]; 281 bjj = bj + bi[brow]; 282 /* add non-zero cols of B into the sorted linked list lnk */ 283 ierr = PetscLLAdd(bnzj,bjj,bn,lnk_init,nlnk,lnk);CHKERRQ(ierr); 284 cnzi += nlnk; 285 } 286 287 /* If free space is not available, make more free space */ 288 /* Double the amount of total space in the list */ 289 if (current_space->local_remaining<cnzi) { 290 /* printf("MatMatMultSymbolic_SeqAIJ_SeqAIJ()...%d -th row, double space ...\n",i);*/ 291 ierr = GetMoreSpace(current_space->total_array_size,¤t_space);CHKERRQ(ierr); 292 nspacedouble++; 293 } 294 295 /* Copy data into free space, then initialize lnk */ 296 ierr = PetscLLClear(bn,lnk_init,cnzi,lnk,current_space->array);CHKERRQ(ierr); 297 current_space->array += cnzi; 298 299 current_space->local_used += cnzi; 300 current_space->local_remaining -= cnzi; 301 302 ci[i+1] = ci[i] + cnzi; 303 } 304 305 /* Column indices are in the list of free space */ 306 /* Allocate space for cj, initialize cj, and */ 307 /* destroy list of free space and other temporary array(s) */ 308 ierr = PetscMalloc((ci[am]+1)*sizeof(int),&cj);CHKERRQ(ierr); 309 ierr = MakeSpaceContiguous(&free_space,cj);CHKERRQ(ierr); 310 ierr = PetscFree(lnk);CHKERRQ(ierr); 311 312 /* Allocate space for ca */ 313 ierr = PetscMalloc((ci[am]+1)*sizeof(MatScalar),&ca);CHKERRQ(ierr); 314 ierr = PetscMemzero(ca,(ci[am]+1)*sizeof(MatScalar));CHKERRQ(ierr); 315 316 /* put together the new symbolic matrix */ 317 ierr = MatCreateSeqAIJWithArrays(A->comm,am,bn,ci,cj,ca,C);CHKERRQ(ierr); 318 319 /* MatCreateSeqAIJWithArrays flags matrix so PETSc doesn't free the user's arrays. */ 320 /* These are PETSc arrays, so change flags so arrays can be deleted by PETSc */ 321 c = (Mat_SeqAIJ *)((*C)->data); 322 c->freedata = PETSC_TRUE; 323 c->nonew = 0; 324 325 PetscLogInfo((PetscObject)(*C),"Number of calls to GetMoreSpace(): %d\n",nspacedouble); 326 PetscFunctionReturn(0); 327 } 328 329 #undef __FUNCT__ 330 #define __FUNCT__ "MatMatMultNumeric" 331 /*@ 332 MatMatMultNumeric - Performs the numeric matrix-matrix product. 333 Call this routine after first calling MatMatMultSymbolic(). 334 335 Collective on Mat 336 337 Input Parameters: 338 + A - the left matrix 339 - B - the right matrix 340 341 Output Parameters: 342 . C - the product matrix, whose ij structure was defined from MatMatMultSymbolic(). 343 344 Notes: 345 C must have been created with MatMatMultSymbolic. 346 347 This routine is currently only implemented for SeqAIJ type matrices. 348 349 Level: intermediate 350 351 .seealso: MatMatMult(),MatMatMultSymbolic() 352 @*/ 353 PetscErrorCode MatMatMultNumeric(Mat A,Mat B,Mat C){ 354 PetscErrorCode ierr; 355 PetscErrorCode (*Anumeric)(Mat,Mat,Mat); 356 PetscErrorCode (*Bnumeric)(Mat,Mat,Mat); 357 358 PetscFunctionBegin; 359 360 PetscValidHeaderSpecific(A,MAT_COOKIE,1); 361 PetscValidType(A,1); 362 MatPreallocated(A); 363 if (!A->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix"); 364 if (A->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix"); 365 366 PetscValidHeaderSpecific(B,MAT_COOKIE,2); 367 PetscValidType(B,2); 368 MatPreallocated(B); 369 if (!B->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix"); 370 if (B->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix"); 371 372 PetscValidHeaderSpecific(C,MAT_COOKIE,3); 373 PetscValidType(C,3); 374 MatPreallocated(C); 375 if (!C->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix"); 376 if (C->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix"); 377 378 if (B->N!=C->N) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %d != %d",B->N,C->N); 379 if (B->M!=A->N) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %d != %d",B->M,A->N); 380 if (A->M!=C->M) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %d != %d",A->M,C->M); 381 382 /* For now, we do not dispatch based on the type of A and B */ 383 /* When implementations like _SeqAIJ_MAIJ exist, attack the multiple dispatch problem. */ 384 Anumeric = A->ops->matmultnumeric; 385 if (!Anumeric) SETERRQ1(PETSC_ERR_SUP,"MatMatMultNumeric not supported for A of type %s",A->type_name); 386 Bnumeric = B->ops->matmultnumeric; 387 if (!Bnumeric) SETERRQ1(PETSC_ERR_SUP,"MatMatMultNumeric not supported for B of type %s",B->type_name); 388 if (Bnumeric!=Anumeric) SETERRQ2(PETSC_ERR_ARG_INCOMP,"MatMatMultNumeric requires A, %s, to be compatible with B, %s",A->type_name,B->type_name); 389 390 ierr = PetscLogEventBegin(MAT_MatMultNumeric,A,B,0,0);CHKERRQ(ierr); 391 ierr = (*Anumeric)(A,B,C);CHKERRQ(ierr); 392 ierr = PetscLogEventEnd(MAT_MatMultNumeric,A,B,0,0);CHKERRQ(ierr); 393 394 PetscFunctionReturn(0); 395 } 396 397 /* This routine is called ONLY in the case of reusing previously computed symbolic C */ 398 #undef __FUNCT__ 399 #define __FUNCT__ "MatMatMultNumeric_MPIAIJ_MPIAIJ" 400 PetscErrorCode MatMatMultNumeric_MPIAIJ_MPIAIJ(Mat A,Mat B,Mat C) 401 { 402 PetscErrorCode ierr; 403 Mat_MatMatMultMPI *mult=(Mat_MatMatMultMPI*)C->spptr; 404 405 PetscFunctionBegin; 406 ierr = MatGetSubMatrices(B,1,&mult->isrowb,&mult->iscolb,MAT_REUSE_MATRIX,&mult->bseq);CHKERRQ(ierr) 407 ierr = MatGetSubMatrices(A,1,&mult->isrowa,&mult->isrowb,MAT_REUSE_MATRIX,&mult->aseq);CHKERRQ(ierr); 408 ierr = MatMatMult_SeqAIJ_SeqAIJ(mult->aseq[0],mult->bseq[0],MAT_REUSE_MATRIX,0.0,&mult->C_seq);CHKERRQ(ierr); 409 410 ierr = PetscObjectReference((PetscObject)mult->C_seq);CHKERRQ(ierr); 411 ierr = MatMerge(A->comm,mult->C_seq,MAT_REUSE_MATRIX,&C);CHKERRQ(ierr); 412 413 PetscFunctionReturn(0); 414 } 415 416 #undef __FUNCT__ 417 #define __FUNCT__ "MatMatMultNumeric_SeqAIJ_SeqAIJ" 418 PetscErrorCode MatMatMultNumeric_SeqAIJ_SeqAIJ(Mat A,Mat B,Mat C) 419 { 420 PetscErrorCode ierr; 421 int flops=0; 422 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 423 Mat_SeqAIJ *b = (Mat_SeqAIJ *)B->data; 424 Mat_SeqAIJ *c = (Mat_SeqAIJ *)C->data; 425 int *ai=a->i,*aj=a->j,*bi=b->i,*bj=b->j,*bjj,*ci=c->i,*cj=c->j; 426 int am=A->M,cn=C->N; 427 int i,j,k,anzi,bnzi,cnzi,brow; 428 MatScalar *aa=a->a,*ba=b->a,*baj,*ca=c->a,*temp; 429 430 PetscFunctionBegin; 431 432 /* Allocate temp accumulation space to avoid searching for nonzero columns in C */ 433 ierr = PetscMalloc((cn+1)*sizeof(MatScalar),&temp);CHKERRQ(ierr); 434 ierr = PetscMemzero(temp,cn*sizeof(MatScalar));CHKERRQ(ierr); 435 /* Traverse A row-wise. */ 436 /* Build the ith row in C by summing over nonzero columns in A, */ 437 /* the rows of B corresponding to nonzeros of A. */ 438 for (i=0;i<am;i++) { 439 anzi = ai[i+1] - ai[i]; 440 for (j=0;j<anzi;j++) { 441 brow = *aj++; 442 bnzi = bi[brow+1] - bi[brow]; 443 bjj = bj + bi[brow]; 444 baj = ba + bi[brow]; 445 for (k=0;k<bnzi;k++) { 446 temp[bjj[k]] += (*aa)*baj[k]; 447 } 448 flops += 2*bnzi; 449 aa++; 450 } 451 /* Store row back into C, and re-zero temp */ 452 cnzi = ci[i+1] - ci[i]; 453 for (j=0;j<cnzi;j++) { 454 ca[j] = temp[cj[j]]; 455 temp[cj[j]] = 0.0; 456 } 457 ca += cnzi; 458 cj += cnzi; 459 } 460 ierr = MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 461 ierr = MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 462 463 /* Free temp */ 464 ierr = PetscFree(temp);CHKERRQ(ierr); 465 ierr = PetscLogFlops(flops);CHKERRQ(ierr); 466 PetscFunctionReturn(0); 467 } 468