1 #define PETSCMAT_DLL 2 3 /* 4 Defines the basic matrix operations for the ADJ adjacency list matrix data-structure. 5 */ 6 #include "src/mat/impls/adj/mpi/mpiadj.h" 7 #include "petscsys.h" 8 9 #undef __FUNCT__ 10 #define __FUNCT__ "MatView_MPIAdj_ASCII" 11 PetscErrorCode MatView_MPIAdj_ASCII(Mat A,PetscViewer viewer) 12 { 13 Mat_MPIAdj *a = (Mat_MPIAdj*)A->data; 14 PetscErrorCode ierr; 15 PetscInt i,j,m = A->m; 16 const char *name; 17 PetscViewerFormat format; 18 19 PetscFunctionBegin; 20 ierr = PetscObjectGetName((PetscObject)A,&name);CHKERRQ(ierr); 21 ierr = PetscViewerGetFormat(viewer,&format);CHKERRQ(ierr); 22 if (format == PETSC_VIEWER_ASCII_INFO) { 23 PetscFunctionReturn(0); 24 } else if (format == PETSC_VIEWER_ASCII_MATLAB) { 25 SETERRQ(PETSC_ERR_SUP,"Matlab format not supported"); 26 } else { 27 ierr = PetscViewerASCIIUseTabs(viewer,PETSC_NO);CHKERRQ(ierr); 28 for (i=0; i<m; i++) { 29 ierr = PetscViewerASCIISynchronizedPrintf(viewer,"row %D:",i+a->rstart);CHKERRQ(ierr); 30 for (j=a->i[i]; j<a->i[i+1]; j++) { 31 ierr = PetscViewerASCIISynchronizedPrintf(viewer," %D ",a->j[j]);CHKERRQ(ierr); 32 } 33 ierr = PetscViewerASCIISynchronizedPrintf(viewer,"\n");CHKERRQ(ierr); 34 } 35 ierr = PetscViewerASCIIUseTabs(viewer,PETSC_YES);CHKERRQ(ierr); 36 } 37 ierr = PetscViewerFlush(viewer);CHKERRQ(ierr); 38 PetscFunctionReturn(0); 39 } 40 41 #undef __FUNCT__ 42 #define __FUNCT__ "MatView_MPIAdj" 43 PetscErrorCode MatView_MPIAdj(Mat A,PetscViewer viewer) 44 { 45 PetscErrorCode ierr; 46 PetscTruth iascii; 47 48 PetscFunctionBegin; 49 ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);CHKERRQ(ierr); 50 if (iascii) { 51 ierr = MatView_MPIAdj_ASCII(A,viewer);CHKERRQ(ierr); 52 } else { 53 SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported by MPIAdj",((PetscObject)viewer)->type_name); 54 } 55 PetscFunctionReturn(0); 56 } 57 58 #undef __FUNCT__ 59 #define __FUNCT__ "MatDestroy_MPIAdj" 60 PetscErrorCode MatDestroy_MPIAdj(Mat mat) 61 { 62 Mat_MPIAdj *a = (Mat_MPIAdj*)mat->data; 63 PetscErrorCode ierr; 64 65 PetscFunctionBegin; 66 #if defined(PETSC_USE_LOG) 67 PetscLogObjectState((PetscObject)mat,"Rows=%D, Cols=%D, NZ=%D",mat->m,mat->n,a->nz); 68 #endif 69 if (a->diag) {ierr = PetscFree(a->diag);CHKERRQ(ierr);} 70 if (a->freeaij) { 71 ierr = PetscFree(a->i);CHKERRQ(ierr); 72 ierr = PetscFree(a->j);CHKERRQ(ierr); 73 if (a->values) {ierr = PetscFree(a->values);CHKERRQ(ierr);} 74 } 75 ierr = PetscFree(a->rowners);CHKERRQ(ierr); 76 ierr = PetscFree(a);CHKERRQ(ierr); 77 78 ierr = PetscObjectComposeFunction((PetscObject)mat,"MatMPIAdjSetPreallocation_C","",PETSC_NULL);CHKERRQ(ierr); 79 PetscFunctionReturn(0); 80 } 81 82 #undef __FUNCT__ 83 #define __FUNCT__ "MatSetOption_MPIAdj" 84 PetscErrorCode MatSetOption_MPIAdj(Mat A,MatOption op) 85 { 86 Mat_MPIAdj *a = (Mat_MPIAdj*)A->data; 87 PetscErrorCode ierr; 88 89 PetscFunctionBegin; 90 switch (op) { 91 case MAT_SYMMETRIC: 92 case MAT_STRUCTURALLY_SYMMETRIC: 93 case MAT_HERMITIAN: 94 a->symmetric = PETSC_TRUE; 95 break; 96 case MAT_NOT_SYMMETRIC: 97 case MAT_NOT_STRUCTURALLY_SYMMETRIC: 98 case MAT_NOT_HERMITIAN: 99 a->symmetric = PETSC_FALSE; 100 break; 101 case MAT_SYMMETRY_ETERNAL: 102 case MAT_NOT_SYMMETRY_ETERNAL: 103 break; 104 default: 105 ierr = PetscVerboseInfo((A,"MatSetOption_MPIAdj:Option ignored\n"));CHKERRQ(ierr); 106 break; 107 } 108 PetscFunctionReturn(0); 109 } 110 111 112 /* 113 Adds diagonal pointers to sparse matrix structure. 114 */ 115 116 #undef __FUNCT__ 117 #define __FUNCT__ "MatMarkDiagonal_MPIAdj" 118 PetscErrorCode MatMarkDiagonal_MPIAdj(Mat A) 119 { 120 Mat_MPIAdj *a = (Mat_MPIAdj*)A->data; 121 PetscErrorCode ierr; 122 PetscInt i,j,*diag,m = A->m; 123 124 PetscFunctionBegin; 125 ierr = PetscMalloc((m+1)*sizeof(PetscInt),&diag);CHKERRQ(ierr); 126 ierr = PetscLogObjectMemory(A,(m+1)*sizeof(PetscInt));CHKERRQ(ierr); 127 for (i=0; i<A->m; i++) { 128 for (j=a->i[i]; j<a->i[i+1]; j++) { 129 if (a->j[j] == i) { 130 diag[i] = j; 131 break; 132 } 133 } 134 } 135 a->diag = diag; 136 PetscFunctionReturn(0); 137 } 138 139 #undef __FUNCT__ 140 #define __FUNCT__ "MatGetRow_MPIAdj" 141 PetscErrorCode MatGetRow_MPIAdj(Mat A,PetscInt row,PetscInt *nz,PetscInt **idx,PetscScalar **v) 142 { 143 Mat_MPIAdj *a = (Mat_MPIAdj*)A->data; 144 PetscInt *itmp; 145 146 PetscFunctionBegin; 147 row -= a->rstart; 148 149 if (row < 0 || row >= A->m) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Row out of range"); 150 151 *nz = a->i[row+1] - a->i[row]; 152 if (v) *v = PETSC_NULL; 153 if (idx) { 154 itmp = a->j + a->i[row]; 155 if (*nz) { 156 *idx = itmp; 157 } 158 else *idx = 0; 159 } 160 PetscFunctionReturn(0); 161 } 162 163 #undef __FUNCT__ 164 #define __FUNCT__ "MatRestoreRow_MPIAdj" 165 PetscErrorCode MatRestoreRow_MPIAdj(Mat A,PetscInt row,PetscInt *nz,PetscInt **idx,PetscScalar **v) 166 { 167 PetscFunctionBegin; 168 PetscFunctionReturn(0); 169 } 170 171 #undef __FUNCT__ 172 #define __FUNCT__ "MatEqual_MPIAdj" 173 PetscErrorCode MatEqual_MPIAdj(Mat A,Mat B,PetscTruth* flg) 174 { 175 Mat_MPIAdj *a = (Mat_MPIAdj *)A->data,*b = (Mat_MPIAdj *)B->data; 176 PetscErrorCode ierr; 177 PetscTruth flag; 178 179 PetscFunctionBegin; 180 /* If the matrix dimensions are not equal,or no of nonzeros */ 181 if ((A->m != B->m) ||(a->nz != b->nz)) { 182 flag = PETSC_FALSE; 183 } 184 185 /* if the a->i are the same */ 186 ierr = PetscMemcmp(a->i,b->i,(A->m+1)*sizeof(PetscInt),&flag);CHKERRQ(ierr); 187 188 /* if a->j are the same */ 189 ierr = PetscMemcmp(a->j,b->j,(a->nz)*sizeof(PetscInt),&flag);CHKERRQ(ierr); 190 191 ierr = MPI_Allreduce(&flag,flg,1,MPI_INT,MPI_LAND,A->comm);CHKERRQ(ierr); 192 PetscFunctionReturn(0); 193 } 194 195 #undef __FUNCT__ 196 #define __FUNCT__ "MatGetRowIJ_MPIAdj" 197 PetscErrorCode MatGetRowIJ_MPIAdj(Mat A,PetscInt oshift,PetscTruth symmetric,PetscInt *m,PetscInt *ia[],PetscInt *ja[],PetscTruth *done) 198 { 199 PetscErrorCode ierr; 200 PetscMPIInt size; 201 PetscInt i; 202 Mat_MPIAdj *a = (Mat_MPIAdj *)A->data; 203 204 PetscFunctionBegin; 205 ierr = MPI_Comm_size(A->comm,&size);CHKERRQ(ierr); 206 if (size > 1) {*done = PETSC_FALSE; PetscFunctionReturn(0);} 207 *m = A->m; 208 *ia = a->i; 209 *ja = a->j; 210 *done = PETSC_TRUE; 211 if (oshift) { 212 for (i=0; i<(*ia)[*m]; i++) { 213 (*ja)[i]++; 214 } 215 for (i=0; i<=(*m); i++) (*ia)[i]++; 216 } 217 PetscFunctionReturn(0); 218 } 219 220 #undef __FUNCT__ 221 #define __FUNCT__ "MatRestoreRowIJ_MPIAdj" 222 PetscErrorCode MatRestoreRowIJ_MPIAdj(Mat A,PetscInt oshift,PetscTruth symmetric,PetscInt *m,PetscInt *ia[],PetscInt *ja[],PetscTruth *done) 223 { 224 PetscInt i; 225 Mat_MPIAdj *a = (Mat_MPIAdj *)A->data; 226 227 PetscFunctionBegin; 228 if (ia && a->i != *ia) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"ia passed back is not one obtained with MatGetRowIJ()"); 229 if (ja && a->j != *ja) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"ja passed back is not one obtained with MatGetRowIJ()"); 230 if (oshift) { 231 for (i=0; i<=(*m); i++) (*ia)[i]--; 232 for (i=0; i<(*ia)[*m]; i++) { 233 (*ja)[i]--; 234 } 235 } 236 PetscFunctionReturn(0); 237 } 238 239 /* -------------------------------------------------------------------*/ 240 static struct _MatOps MatOps_Values = {0, 241 MatGetRow_MPIAdj, 242 MatRestoreRow_MPIAdj, 243 0, 244 /* 4*/ 0, 245 0, 246 0, 247 0, 248 0, 249 0, 250 /*10*/ 0, 251 0, 252 0, 253 0, 254 0, 255 /*15*/ 0, 256 MatEqual_MPIAdj, 257 0, 258 0, 259 0, 260 /*20*/ 0, 261 0, 262 0, 263 MatSetOption_MPIAdj, 264 0, 265 /*25*/ 0, 266 0, 267 0, 268 0, 269 0, 270 /*30*/ 0, 271 0, 272 0, 273 0, 274 0, 275 /*35*/ 0, 276 0, 277 0, 278 0, 279 0, 280 /*40*/ 0, 281 0, 282 0, 283 0, 284 0, 285 /*45*/ 0, 286 0, 287 0, 288 0, 289 0, 290 /*50*/ 0, 291 MatGetRowIJ_MPIAdj, 292 MatRestoreRowIJ_MPIAdj, 293 0, 294 0, 295 /*55*/ 0, 296 0, 297 0, 298 0, 299 0, 300 /*60*/ 0, 301 MatDestroy_MPIAdj, 302 MatView_MPIAdj, 303 MatGetPetscMaps_Petsc, 304 0, 305 /*65*/ 0, 306 0, 307 0, 308 0, 309 0, 310 /*70*/ 0, 311 0, 312 0, 313 0, 314 0, 315 /*75*/ 0, 316 0, 317 0, 318 0, 319 0, 320 /*80*/ 0, 321 0, 322 0, 323 0, 324 0, 325 /*85*/ 0, 326 0, 327 0, 328 0, 329 0, 330 /*90*/ 0, 331 0, 332 0, 333 0, 334 0, 335 /*95*/ 0, 336 0, 337 0, 338 0}; 339 340 EXTERN_C_BEGIN 341 #undef __FUNCT__ 342 #define __FUNCT__ "MatMPIAdjSetPreallocation_MPIAdj" 343 PetscErrorCode PETSCMAT_DLLEXPORT MatMPIAdjSetPreallocation_MPIAdj(Mat B,PetscInt *i,PetscInt *j,PetscInt *values) 344 { 345 Mat_MPIAdj *b = (Mat_MPIAdj *)B->data; 346 PetscErrorCode ierr; 347 #if defined(PETSC_USE_DEBUG) 348 PetscInt ii; 349 #endif 350 351 PetscFunctionBegin; 352 B->preallocated = PETSC_TRUE; 353 #if defined(PETSC_USE_DEBUG) 354 if (i[0] != 0) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"First i[] index must be zero, instead it is %D\n",i[0]); 355 for (ii=1; ii<B->m; ii++) { 356 if (i[ii] < 0 || i[ii] < i[ii-1]) { 357 SETERRQ4(PETSC_ERR_ARG_OUTOFRANGE,"i[%D]=%D index is out of range: i[%D]=%D",ii,i[ii],ii-1,i[ii-1]); 358 } 359 } 360 for (ii=0; ii<i[B->m]; ii++) { 361 if (j[ii] < 0 || j[ii] >= B->N) { 362 SETERRQ2(PETSC_ERR_ARG_OUTOFRANGE,"Column index %D out of range %D\n",ii,j[ii]); 363 } 364 } 365 #endif 366 367 b->j = j; 368 b->i = i; 369 b->values = values; 370 371 b->nz = i[B->m]; 372 b->diag = 0; 373 b->symmetric = PETSC_FALSE; 374 b->freeaij = PETSC_TRUE; 375 376 ierr = MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 377 ierr = MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 378 PetscFunctionReturn(0); 379 } 380 EXTERN_C_END 381 382 /*MC 383 MATMPIADJ - MATMPIADJ = "mpiadj" - A matrix type to be used for distributed adjacency matrices, 384 intended for use constructing orderings and partitionings. 385 386 Level: beginner 387 388 .seealso: MatCreateMPIAdj 389 M*/ 390 391 EXTERN_C_BEGIN 392 #undef __FUNCT__ 393 #define __FUNCT__ "MatCreate_MPIAdj" 394 PetscErrorCode PETSCMAT_DLLEXPORT MatCreate_MPIAdj(Mat B) 395 { 396 Mat_MPIAdj *b; 397 PetscErrorCode ierr; 398 PetscInt ii; 399 PetscMPIInt size,rank; 400 401 PetscFunctionBegin; 402 ierr = MPI_Comm_size(B->comm,&size);CHKERRQ(ierr); 403 ierr = MPI_Comm_rank(B->comm,&rank);CHKERRQ(ierr); 404 405 ierr = PetscNew(Mat_MPIAdj,&b);CHKERRQ(ierr); 406 B->data = (void*)b; 407 ierr = PetscMemcpy(B->ops,&MatOps_Values,sizeof(struct _MatOps));CHKERRQ(ierr); 408 B->factor = 0; 409 B->mapping = 0; 410 B->assembled = PETSC_FALSE; 411 412 ierr = PetscSplitOwnership(B->comm,&B->m,&B->M);CHKERRQ(ierr); 413 B->n = B->N = PetscMax(B->N,B->n);CHKERRQ(ierr); 414 415 /* the information in the maps duplicates the information computed below, eventually 416 we should remove the duplicate information that is not contained in the maps */ 417 ierr = PetscMapCreateMPI(B->comm,B->m,B->M,&B->rmap);CHKERRQ(ierr); 418 /* we don't know the "local columns" so just use the row information :-(*/ 419 ierr = PetscMapCreateMPI(B->comm,B->m,B->M,&B->cmap);CHKERRQ(ierr); 420 421 ierr = PetscMalloc((size+1)*sizeof(PetscInt),&b->rowners);CHKERRQ(ierr); 422 ierr = PetscLogObjectMemory(B,(size+2)*sizeof(PetscInt)+sizeof(struct _p_Mat)+sizeof(Mat_MPIAdj));CHKERRQ(ierr); 423 ierr = MPI_Allgather(&B->m,1,MPI_INT,b->rowners+1,1,MPI_INT,B->comm);CHKERRQ(ierr); 424 b->rowners[0] = 0; 425 for (ii=2; ii<=size; ii++) { 426 b->rowners[ii] += b->rowners[ii-1]; 427 } 428 b->rstart = b->rowners[rank]; 429 b->rend = b->rowners[rank+1]; 430 ierr = PetscObjectComposeFunctionDynamic((PetscObject)B,"MatMPIAdjSetPreallocation_C", 431 "MatMPIAdjSetPreallocation_MPIAdj", 432 MatMPIAdjSetPreallocation_MPIAdj);CHKERRQ(ierr); 433 PetscFunctionReturn(0); 434 } 435 EXTERN_C_END 436 437 #undef __FUNCT__ 438 #define __FUNCT__ "MatMPIAdjSetPreallocation" 439 /*@C 440 MatMPIAdjSetPreallocation - Sets the array used for storing the matrix elements 441 442 Collective on MPI_Comm 443 444 Input Parameters: 445 + A - the matrix 446 . i - the indices into j for the start of each row 447 . j - the column indices for each row (sorted for each row). 448 The indices in i and j start with zero (NOT with one). 449 - values - [optional] edge weights 450 451 Level: intermediate 452 453 .seealso: MatCreate(), MatCreateMPIAdj(), MatSetValues() 454 @*/ 455 PetscErrorCode PETSCMAT_DLLEXPORT MatMPIAdjSetPreallocation(Mat B,PetscInt *i,PetscInt *j,PetscInt *values) 456 { 457 PetscErrorCode ierr,(*f)(Mat,PetscInt*,PetscInt*,PetscInt*); 458 459 PetscFunctionBegin; 460 ierr = PetscObjectQueryFunction((PetscObject)B,"MatMPIAdjSetPreallocation_C",(void (**)(void))&f);CHKERRQ(ierr); 461 if (f) { 462 ierr = (*f)(B,i,j,values);CHKERRQ(ierr); 463 } 464 PetscFunctionReturn(0); 465 } 466 467 #undef __FUNCT__ 468 #define __FUNCT__ "MatCreateMPIAdj" 469 /*@C 470 MatCreateMPIAdj - Creates a sparse matrix representing an adjacency list. 471 The matrix does not have numerical values associated with it, but is 472 intended for ordering (to reduce bandwidth etc) and partitioning. 473 474 Collective on MPI_Comm 475 476 Input Parameters: 477 + comm - MPI communicator 478 . m - number of local rows 479 . n - number of columns 480 . i - the indices into j for the start of each row 481 . j - the column indices for each row (sorted for each row). 482 The indices in i and j start with zero (NOT with one). 483 - values -[optional] edge weights 484 485 Output Parameter: 486 . A - the matrix 487 488 Level: intermediate 489 490 Notes: This matrix object does not support most matrix operations, include 491 MatSetValues(). 492 You must NOT free the ii, values and jj arrays yourself. PETSc will free them 493 when the matrix is destroyed; you must allocate them with PetscMalloc(). If you 494 call from Fortran you need not create the arrays with PetscMalloc(). 495 Should not include the matrix diagonals. 496 497 If you already have a matrix, you can create its adjacency matrix by a call 498 to MatConvert, specifying a type of MATMPIADJ. 499 500 Possible values for MatSetOption() - MAT_STRUCTURALLY_SYMMETRIC 501 502 .seealso: MatCreate(), MatConvert(), MatGetOrdering() 503 @*/ 504 PetscErrorCode PETSCMAT_DLLEXPORT MatCreateMPIAdj(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt *i,PetscInt *j,PetscInt *values,Mat *A) 505 { 506 PetscErrorCode ierr; 507 508 PetscFunctionBegin; 509 ierr = MatCreate(comm,A);CHKERRQ(ierr); 510 ierr = MatSetSizes(*A,m,n,PETSC_DETERMINE,n);CHKERRQ(ierr); 511 ierr = MatSetType(*A,MATMPIADJ);CHKERRQ(ierr); 512 ierr = MatMPIAdjSetPreallocation(*A,i,j,values);CHKERRQ(ierr); 513 PetscFunctionReturn(0); 514 } 515 516 EXTERN_C_BEGIN 517 #undef __FUNCT__ 518 #define __FUNCT__ "MatConvertTo_MPIAdj" 519 PetscErrorCode PETSCMAT_DLLEXPORT MatConvertTo_MPIAdj(Mat A,MatType type,MatReuse reuse,Mat *newmat) 520 { 521 Mat B; 522 PetscErrorCode ierr; 523 PetscInt i,m,N,nzeros = 0,*ia,*ja,len,rstart,cnt,j,*a; 524 const PetscInt *rj; 525 const PetscScalar *ra; 526 MPI_Comm comm; 527 528 PetscFunctionBegin; 529 ierr = MatGetSize(A,PETSC_NULL,&N);CHKERRQ(ierr); 530 ierr = MatGetLocalSize(A,&m,PETSC_NULL);CHKERRQ(ierr); 531 ierr = MatGetOwnershipRange(A,&rstart,PETSC_NULL);CHKERRQ(ierr); 532 533 /* count the number of nonzeros per row */ 534 for (i=0; i<m; i++) { 535 ierr = MatGetRow(A,i+rstart,&len,&rj,PETSC_NULL);CHKERRQ(ierr); 536 for (j=0; j<len; j++) { 537 if (rj[j] == i+rstart) {len--; break;} /* don't count diagonal */ 538 } 539 ierr = MatRestoreRow(A,i+rstart,&len,&rj,PETSC_NULL);CHKERRQ(ierr); 540 nzeros += len; 541 } 542 543 /* malloc space for nonzeros */ 544 ierr = PetscMalloc((nzeros+1)*sizeof(PetscInt),&a);CHKERRQ(ierr); 545 ierr = PetscMalloc((N+1)*sizeof(PetscInt),&ia);CHKERRQ(ierr); 546 ierr = PetscMalloc((nzeros+1)*sizeof(PetscInt),&ja);CHKERRQ(ierr); 547 548 nzeros = 0; 549 ia[0] = 0; 550 for (i=0; i<m; i++) { 551 ierr = MatGetRow(A,i+rstart,&len,&rj,&ra);CHKERRQ(ierr); 552 cnt = 0; 553 for (j=0; j<len; j++) { 554 if (rj[j] != i+rstart) { /* if not diagonal */ 555 a[nzeros+cnt] = (PetscInt) PetscAbsScalar(ra[j]); 556 ja[nzeros+cnt++] = rj[j]; 557 } 558 } 559 ierr = MatRestoreRow(A,i+rstart,&len,&rj,&ra);CHKERRQ(ierr); 560 nzeros += cnt; 561 ia[i+1] = nzeros; 562 } 563 564 ierr = PetscObjectGetComm((PetscObject)A,&comm);CHKERRQ(ierr); 565 ierr = MatCreate(comm,&B);CHKERRQ(ierr); 566 ierr = MatSetSizes(B,m,N,PETSC_DETERMINE,N);CHKERRQ(ierr); 567 ierr = MatSetType(B,type);CHKERRQ(ierr); 568 ierr = MatMPIAdjSetPreallocation(B,ia,ja,a);CHKERRQ(ierr); 569 570 if (reuse == MAT_REUSE_MATRIX) { 571 ierr = MatHeaderReplace(A,B);CHKERRQ(ierr); 572 } else { 573 *newmat = B; 574 } 575 PetscFunctionReturn(0); 576 } 577 EXTERN_C_END 578 579 580 581 582 583