1 /* 2 Defines matrix-matrix product routines for pairs of SeqAIJ 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 9 static int logkey_matmatmult = 0; 10 static int logkey_matmatmult_symbolic = 0; 11 static int logkey_matmatmult_numeric = 0; 12 13 #undef __FUNCT__ 14 #define __FUNCT__ "MatMatMult" 15 /*@ 16 MatMatMult - Performs Matrix-Matrix Multiplication C=A*B. 17 18 Collective on Mat 19 20 Input Parameters: 21 + A - the left matrix 22 - B - the right matrix 23 24 Output Parameters: 25 . C - the product matrix 26 27 Notes: 28 C will be created and must be destroyed by the user with MatDestroy(). 29 30 This routine is currently only implemented for pairs of SeqAIJ matrices. 31 32 Level: intermediate 33 34 .seealso: MatMatMultSymbolic(),MatMatMultNumeric() 35 @*/ 36 int MatMatMult(Mat A,Mat B, Mat *C) { 37 /* Perhaps this "interface" routine should be moved into the interface directory.*/ 38 /* To facilitate implementations with varying types, QueryFunction is used.*/ 39 /* It is assumed that implementations will be composed as "MatMatMult_<type of A><type of B>". */ 40 int ierr; 41 char funct[80]; 42 int (*mult)(Mat,Mat,Mat*); 43 44 PetscFunctionBegin; 45 PetscValidHeaderSpecific(A,MAT_COOKIE,1); 46 PetscValidType(A,1); 47 MatPreallocated(A); 48 if (!A->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix"); 49 if (A->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix"); 50 51 PetscValidHeaderSpecific(B,MAT_COOKIE,2); 52 PetscValidType(B,2); 53 MatPreallocated(B); 54 if (!B->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix"); 55 if (B->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix"); 56 57 PetscValidPointer(C,3); 58 59 if (B->M!=A->N) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %d != %d",B->M,A->N); 60 61 ierr = PetscStrcpy(funct,"MatMatMult_");CHKERRQ(ierr); 62 ierr = PetscStrcat(funct,A->type_name);CHKERRQ(ierr); 63 ierr = PetscStrcat(funct,B->type_name);CHKERRQ(ierr); 64 ierr = PetscObjectQueryFunction((PetscObject)A,funct,(PetscVoidFunction)&mult);CHKERRQ(ierr); 65 if (!mult) SETERRQ2(PETSC_ERR_SUP,"C=A*B not implemented for A of type %s and B of type %s", 66 A->type_name,B->type_name); 67 ierr = (*mult)(A,B,C);CHKERRQ(ierr); 68 PetscFunctionReturn(0); 69 } 70 71 #undef __FUNCT__ 72 #define __FUNCT__ "MatMatMult_SeqAIJ_SeqAIJ" 73 int MatMatMult_SeqAIJ_SeqAIJ(Mat A,Mat B, Mat *C) { 74 int ierr; 75 char symfunct[80],numfunct[80],types[80]; 76 int (*symbolic)(Mat,Mat,Mat*),(*numeric)(Mat,Mat,Mat); 77 78 PetscFunctionBegin; 79 ierr = PetscStrcpy(types,A->type_name);CHKERRQ(ierr); 80 ierr = PetscStrcat(types,B->type_name);CHKERRQ(ierr); 81 ierr = PetscStrcpy(symfunct,"MatMatMultSymbolic_");CHKERRQ(ierr); 82 ierr = PetscStrcat(symfunct,types);CHKERRQ(ierr); 83 ierr = PetscObjectQueryFunction((PetscObject)A,symfunct,(PetscVoidFunction)&symbolic);CHKERRQ(ierr); 84 if (!symbolic) SETERRQ2(PETSC_ERR_SUP, 85 "C=A*B not implemented for A of type %s and B of type %s", 86 A->type_name,B->type_name); 87 ierr = PetscStrcpy(numfunct,"MatMatMultNumeric_");CHKERRQ(ierr); 88 ierr = PetscStrcat(numfunct,types);CHKERRQ(ierr); 89 ierr = PetscObjectQueryFunction((PetscObject)A,numfunct,(PetscVoidFunction)&numeric);CHKERRQ(ierr); 90 if (!numeric) SETERRQ2(PETSC_ERR_SUP, 91 "C=A*B not implemented for A of type %s and B of type %s", 92 A->type_name,B->type_name); 93 ierr = PetscLogEventBegin(logkey_matmatmult,A,B,0,0);CHKERRQ(ierr); 94 ierr = (*symbolic)(A,B,C);CHKERRQ(ierr); 95 ierr = (*numeric)(A,B,*C);CHKERRQ(ierr); 96 ierr = PetscLogEventEnd(logkey_matmatmult,A,B,0,0);CHKERRQ(ierr); 97 PetscFunctionReturn(0); 98 } 99 100 #undef __FUNCT__ 101 #define __FUNCT__ "MatMatMultSymbolic" 102 /*@ 103 MatMatMultSymbolic - Performs construction, preallocation, and computes the ij structure 104 of the matrix-matrix product C=A*B. Call this routine before calling MatMatMultNumeric(). 105 106 Collective on Mat 107 108 Input Parameters: 109 + A - the left matrix 110 - B - the right matrix 111 112 Output Parameters: 113 . C - the matrix containing the ij structure of product matrix 114 115 Notes: 116 C will be created and must be destroyed by the user with MatDestroy(). 117 118 This routine is currently only implemented for SeqAIJ type matrices. 119 120 Level: intermediate 121 122 .seealso: MatMatMult(),MatMatMultNumeric() 123 @*/ 124 int MatMatMultSymbolic(Mat A,Mat B,Mat *C) { 125 /* Perhaps this "interface" routine should be moved into the interface directory.*/ 126 /* To facilitate implementations with varying types, QueryFunction is used.*/ 127 /* It is assumed that implementations will be composed as "MatMatMultSymbolic_<type of A><type of B>". */ 128 int ierr; 129 char funct[80]; 130 int (*symbolic)(Mat,Mat,Mat *); 131 132 PetscFunctionBegin; 133 PetscValidHeaderSpecific(A,MAT_COOKIE,1); 134 PetscValidType(A,1); 135 MatPreallocated(A); 136 if (!A->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix"); 137 if (A->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix"); 138 139 PetscValidHeaderSpecific(B,MAT_COOKIE,2); 140 PetscValidType(B,2); 141 MatPreallocated(B); 142 if (!B->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix"); 143 if (B->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix"); 144 PetscValidPointer(C,3); 145 146 147 if (B->M!=A->N) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %d != %d",B->M,A->N); 148 149 ierr = PetscStrcpy(funct,"MatMatMultSymbolic_");CHKERRQ(ierr); 150 ierr = PetscStrcat(funct,A->type_name);CHKERRQ(ierr); 151 ierr = PetscStrcat(funct,B->type_name);CHKERRQ(ierr); 152 ierr = PetscObjectQueryFunction((PetscObject)A,funct,(PetscVoidFunction)&symbolic);CHKERRQ(ierr); 153 if (!symbolic) SETERRQ2(PETSC_ERR_SUP, 154 "C=A*B not implemented for A of type %s and B of type %s", 155 A->type_name,B->type_name); 156 ierr = (*symbolic)(A,B,C);CHKERRQ(ierr); 157 158 PetscFunctionReturn(0); 159 } 160 161 #undef __FUNCT__ 162 #define __FUNCT__ "MatMatMult_Symbolic_SeqAIJ_SeqAIJ" 163 int MatMatMult_Symbolic_SeqAIJ_SeqAIJ(Mat A,Mat B,Mat *C) 164 { 165 int ierr; 166 FreeSpaceList free_space=PETSC_NULL,current_space=PETSC_NULL; 167 Mat_SeqAIJ *a=(Mat_SeqAIJ*)A->data,*b=(Mat_SeqAIJ*)B->data,*c; 168 int *ai=a->i,*aj=a->j,*bi=b->i,*bj=b->j,*bjj; 169 int *ci,*cj,*lnk,idx0,idx,bcol; 170 int am=A->M,bn=B->N,bm=B->M; 171 int i,j,k,anzi,brow,bnzj,cnzi; 172 MatScalar *ca; 173 174 PetscFunctionBegin; 175 /* Start timers */ 176 ierr = PetscLogEventBegin(logkey_matmatmult_symbolic,A,B,0,0);CHKERRQ(ierr); 177 178 /* Set up */ 179 /* Allocate ci array, arrays for fill computation and */ 180 /* free space for accumulating nonzero column info */ 181 ierr = PetscMalloc(((am+1)+1)*sizeof(int),&ci);CHKERRQ(ierr); 182 ci[0] = 0; 183 184 ierr = PetscMalloc((bn+1)*sizeof(int),&lnk);CHKERRQ(ierr); 185 for (i=0; i<bn; i++) lnk[i] = -1; 186 187 /* Initial FreeSpace size is nnz(B)=4*bi[bm] */ 188 ierr = GetMoreSpace(4*bi[bm],&free_space);CHKERRQ(ierr); 189 current_space = free_space; 190 191 /* Determine symbolic info for each row of the product: */ 192 for (i=0;i<am;i++) { 193 anzi = ai[i+1] - ai[i]; 194 cnzi = 0; 195 lnk[bn] = bn; 196 for (j=0;j<anzi;j++) { 197 brow = *aj++; 198 bnzj = bi[brow+1] - bi[brow]; 199 bjj = bj + bi[brow]; 200 idx = bn; 201 for (k=0;k<bnzj;k++) { 202 bcol = bjj[k]; 203 if (lnk[bcol] == -1) { /* new col */ 204 if (k>0) idx = bjj[k-1]; 205 do { 206 idx0 = idx; 207 idx = lnk[idx0]; 208 } while (bcol > idx); 209 lnk[idx0] = bcol; 210 lnk[bcol] = idx; 211 cnzi++; 212 } 213 } 214 } 215 216 /* If free space is not available, make more free space */ 217 /* Double the amount of total space in the list */ 218 if (current_space->local_remaining<cnzi) { 219 printf("...%d -th row, double space ...\n",i); 220 ierr = GetMoreSpace(current_space->total_array_size,¤t_space);CHKERRQ(ierr); 221 } 222 223 /* Copy data into free space, and zero out denserow and lnk */ 224 idx = bn; 225 for (j=0; j<cnzi; j++){ 226 idx0 = idx; 227 idx = lnk[idx0]; 228 *current_space->array++ = idx; 229 lnk[idx0] = -1; 230 } 231 lnk[idx] = -1; 232 233 current_space->local_used += cnzi; 234 current_space->local_remaining -= cnzi; 235 236 ci[i+1] = ci[i] + cnzi; 237 } 238 239 /* Column indices are in the list of free space */ 240 /* Allocate space for cj, initialize cj, and */ 241 /* destroy list of free space and other temporary array(s) */ 242 ierr = PetscMalloc((ci[am]+1)*sizeof(int),&cj);CHKERRQ(ierr); 243 ierr = MakeSpaceContiguous(&free_space,cj);CHKERRQ(ierr); 244 ierr = PetscFree(lnk);CHKERRQ(ierr); 245 246 /* Allocate space for ca */ 247 ierr = PetscMalloc((ci[am]+1)*sizeof(MatScalar),&ca);CHKERRQ(ierr); 248 ierr = PetscMemzero(ca,(ci[am]+1)*sizeof(MatScalar));CHKERRQ(ierr); 249 250 /* put together the new matrix */ 251 ierr = MatCreateSeqAIJWithArrays(A->comm,am,bn,ci,cj,ca,C);CHKERRQ(ierr); 252 253 /* MatCreateSeqAIJWithArrays flags matrix so PETSc doesn't free the user's arrays. */ 254 /* These are PETSc arrays, so change flags so arrays can be deleted by PETSc */ 255 c = (Mat_SeqAIJ *)((*C)->data); 256 c->freedata = PETSC_TRUE; 257 c->nonew = 0; 258 259 ierr = PetscLogEventEnd(logkey_matmatmult_symbolic,A,B,0,0);CHKERRQ(ierr); 260 PetscFunctionReturn(0); 261 } 262 263 #undef __FUNCT__ 264 #define __FUNCT__ "MatMatMultNumeric" 265 /*@ 266 MatMatMultNumeric - Performs the numeric matrix-matrix product. 267 Call this routine after first calling MatMatMultSymbolic(). 268 269 Collective on Mat 270 271 Input Parameters: 272 + A - the left matrix 273 - B - the right matrix 274 275 Output Parameters: 276 . C - the product matrix, whose ij structure was defined from MatMatMultSymbolic(). 277 278 Notes: 279 C must have been created with MatMatMultSymbolic. 280 281 This routine is currently only implemented for SeqAIJ type matrices. 282 283 Level: intermediate 284 285 .seealso: MatMatMult(),MatMatMultSymbolic() 286 @*/ 287 int MatMatMultNumeric(Mat A,Mat B,Mat C){ 288 /* Perhaps this "interface" routine should be moved into the interface directory.*/ 289 /* To facilitate implementations with varying types, QueryFunction is used.*/ 290 /* It is assumed that implementations will be composed as "MatMatMultNumeric_<type of A><type of B>". */ 291 int ierr; 292 char funct[80]; 293 int (*numeric)(Mat,Mat,Mat); 294 295 PetscFunctionBegin; 296 297 PetscValidHeaderSpecific(A,MAT_COOKIE,1); 298 PetscValidType(A,1); 299 MatPreallocated(A); 300 if (!A->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix"); 301 if (A->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix"); 302 303 PetscValidHeaderSpecific(B,MAT_COOKIE,2); 304 PetscValidType(B,2); 305 MatPreallocated(B); 306 if (!B->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix"); 307 if (B->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix"); 308 309 PetscValidHeaderSpecific(C,MAT_COOKIE,3); 310 PetscValidType(C,3); 311 MatPreallocated(C); 312 if (!C->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix"); 313 if (C->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix"); 314 315 if (B->N!=C->N) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %d != %d",B->N,C->N); 316 if (B->M!=A->N) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %d != %d",B->M,A->N); 317 if (A->M!=C->M) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %d != %d",A->M,C->M); 318 319 /* Query A for ApplyPtAP implementation based on types of P */ 320 ierr = PetscStrcpy(funct,"MatMatMultNumeric_");CHKERRQ(ierr); 321 ierr = PetscStrcat(funct,A->type_name);CHKERRQ(ierr); 322 ierr = PetscStrcat(funct,B->type_name);CHKERRQ(ierr); 323 ierr = PetscObjectQueryFunction((PetscObject)A,funct,(PetscVoidFunction)&numeric);CHKERRQ(ierr); 324 if (!numeric) SETERRQ2(PETSC_ERR_SUP, 325 "C=A*B not implemented for A of type %s and B of type %s", 326 A->type_name,B->type_name); 327 ierr = (*numeric)(A,B,C);CHKERRQ(ierr); 328 329 PetscFunctionReturn(0); 330 } 331 332 #undef __FUNCT__ 333 #define __FUNCT__ "MatMatMult_Numeric_SeqAIJ_SeqAIJ" 334 int MatMatMult_Numeric_SeqAIJ_SeqAIJ(Mat A,Mat B,Mat C) 335 { 336 int ierr,flops=0; 337 Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data; 338 Mat_SeqAIJ *b = (Mat_SeqAIJ *)B->data; 339 Mat_SeqAIJ *c = (Mat_SeqAIJ *)C->data; 340 int *ai=a->i,*aj=a->j,*bi=b->i,*bj=b->j,*bjj,*ci=c->i,*cj=c->j; 341 int am=A->M,cn=C->N; 342 int i,j,k,anzi,bnzi,cnzi,brow; 343 MatScalar *aa=a->a,*ba=b->a,*baj,*ca=c->a,*temp; 344 345 PetscFunctionBegin; 346 347 /* Start timers */ 348 ierr = PetscLogEventBegin(logkey_matmatmult_numeric,A,B,C,0);CHKERRQ(ierr); 349 350 /* Allocate temp accumulation space to avoid searching for nonzero columns in C */ 351 ierr = PetscMalloc((cn+1)*sizeof(MatScalar),&temp);CHKERRQ(ierr); 352 ierr = PetscMemzero(temp,cn*sizeof(MatScalar));CHKERRQ(ierr); 353 /* Traverse A row-wise. */ 354 /* Build the ith row in C by summing over nonzero columns in A, */ 355 /* the rows of B corresponding to nonzeros of A. */ 356 for (i=0;i<am;i++) { 357 anzi = ai[i+1] - ai[i]; 358 for (j=0;j<anzi;j++) { 359 brow = *aj++; 360 bnzi = bi[brow+1] - bi[brow]; 361 bjj = bj + bi[brow]; 362 baj = ba + bi[brow]; 363 for (k=0;k<bnzi;k++) { 364 temp[bjj[k]] += (*aa)*baj[k]; 365 } 366 flops += 2*bnzi; 367 aa++; 368 } 369 /* Store row back into C, and re-zero temp */ 370 cnzi = ci[i+1] - ci[i]; 371 for (j=0;j<cnzi;j++) { 372 ca[j] = temp[cj[j]]; 373 temp[cj[j]] = 0.0; 374 } 375 ca += cnzi; 376 cj += cnzi; 377 } 378 ierr = MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 379 ierr = MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 380 381 /* Free temp */ 382 ierr = PetscFree(temp);CHKERRQ(ierr); 383 ierr = PetscLogFlops(flops);CHKERRQ(ierr); 384 ierr = PetscLogEventEnd(logkey_matmatmult_numeric,A,B,C,0);CHKERRQ(ierr); 385 PetscFunctionReturn(0); 386 } 387 388 #undef __FUNCT__ 389 #define __FUNCT__ "RegisterMatMatMultRoutines_Private" 390 int RegisterMatMatMultRoutines_Private(Mat A) { 391 int ierr; 392 393 PetscFunctionBegin; 394 if (!logkey_matmatmult) { 395 ierr = PetscLogEventRegister(&logkey_matmatmult,"MatMatMult",MAT_COOKIE);CHKERRQ(ierr); 396 } 397 ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatMatMult_seqaijseqaij", 398 "MatMatMult_SeqAIJ_SeqAIJ", 399 MatMatMult_SeqAIJ_SeqAIJ);CHKERRQ(ierr); 400 if (!logkey_matmatmult_symbolic) { 401 ierr = PetscLogEventRegister(&logkey_matmatmult_symbolic,"MatMatMult_Symbolic",MAT_COOKIE);CHKERRQ(ierr); 402 } 403 ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatMatMultSymbolic_seqaijseqaij", 404 "MatMatMult_Symbolic_SeqAIJ_SeqAIJ", 405 MatMatMult_Symbolic_SeqAIJ_SeqAIJ);CHKERRQ(ierr); 406 if (!logkey_matmatmult_numeric) { 407 ierr = PetscLogEventRegister(&logkey_matmatmult_numeric,"MatMatMult_Numeric",MAT_COOKIE);CHKERRQ(ierr); 408 } 409 ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatMatMultNumeric_seqaijseqaij", 410 "MatMatMult_Numeric_SeqAIJ_SeqAIJ", 411 MatMatMult_Numeric_SeqAIJ_SeqAIJ);CHKERRQ(ierr); 412 PetscFunctionReturn(0); 413 } 414