1 #include <petsc/private/matimpl.h> /*I "petscmat.h" I*/ 2 3 static PetscErrorCode MatTransposeAXPY_Private(Mat Y, PetscScalar a, Mat X, MatStructure str, Mat T) 4 { 5 Mat A, F; 6 PetscErrorCode (*f)(Mat, Mat *); 7 8 PetscFunctionBegin; 9 PetscCall(PetscObjectQueryFunction((PetscObject)T, "MatTransposeGetMat_C", &f)); 10 if (f) { 11 PetscCall(MatTransposeGetMat(T, &A)); 12 if (T == X) { 13 PetscCall(PetscInfo(NULL, "Explicitly transposing X of type MATTRANSPOSEVIRTUAL to perform MatAXPY()\n")); 14 PetscCall(MatTranspose(A, MAT_INITIAL_MATRIX, &F)); 15 A = Y; 16 } else { 17 PetscCall(PetscInfo(NULL, "Transposing X because Y of type MATTRANSPOSEVIRTUAL to perform MatAXPY()\n")); 18 PetscCall(MatTranspose(X, MAT_INITIAL_MATRIX, &F)); 19 } 20 } else { 21 PetscCall(MatHermitianTransposeGetMat(T, &A)); 22 if (T == X) { 23 PetscCall(PetscInfo(NULL, "Explicitly Hermitian transposing X of type MATHERMITIANTRANSPOSEVIRTUAL to perform MatAXPY()\n")); 24 PetscCall(MatHermitianTranspose(A, MAT_INITIAL_MATRIX, &F)); 25 A = Y; 26 } else { 27 PetscCall(PetscInfo(NULL, "Hermitian transposing X because Y of type MATHERMITIANTRANSPOSEVIRTUAL to perform MatAXPY()\n")); 28 PetscCall(MatHermitianTranspose(X, MAT_INITIAL_MATRIX, &F)); 29 } 30 } 31 PetscCall(MatAXPY(A, a, F, str)); 32 PetscCall(MatDestroy(&F)); 33 PetscFunctionReturn(PETSC_SUCCESS); 34 } 35 36 /*@ 37 MatAXPY - Computes Y = a*X + Y. 38 39 Logically Collective 40 41 Input Parameters: 42 + a - the scalar multiplier 43 . X - the first matrix 44 . Y - the second matrix 45 - str - either `SAME_NONZERO_PATTERN`, `DIFFERENT_NONZERO_PATTERN`, `UNKNOWN_NONZERO_PATTERN`, or `SUBSET_NONZERO_PATTERN` (nonzeros of `X` is a subset of `Y`'s) 46 47 Level: intermediate 48 49 .seealso: [](ch_matrices), `Mat`, `MatAYPX()` 50 @*/ 51 PetscErrorCode MatAXPY(Mat Y, PetscScalar a, Mat X, MatStructure str) 52 { 53 PetscInt M1, M2, N1, N2; 54 PetscInt m1, m2, n1, n2; 55 PetscBool sametype, transpose; 56 57 PetscFunctionBegin; 58 PetscValidHeaderSpecific(Y, MAT_CLASSID, 1); 59 PetscValidLogicalCollectiveScalar(Y, a, 2); 60 PetscValidHeaderSpecific(X, MAT_CLASSID, 3); 61 PetscCheckSameComm(Y, 1, X, 3); 62 PetscCall(MatGetSize(X, &M1, &N1)); 63 PetscCall(MatGetSize(Y, &M2, &N2)); 64 PetscCall(MatGetLocalSize(X, &m1, &n1)); 65 PetscCall(MatGetLocalSize(Y, &m2, &n2)); 66 PetscCheck(M1 == M2 && N1 == N2, PetscObjectComm((PetscObject)Y), PETSC_ERR_ARG_SIZ, "Non conforming matrix add: global sizes X %" PetscInt_FMT " x %" PetscInt_FMT ", Y %" PetscInt_FMT " x %" PetscInt_FMT, M1, N1, M2, N2); 67 PetscCheck(m1 == m2 && n1 == n2, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Non conforming matrix add: local sizes X %" PetscInt_FMT " x %" PetscInt_FMT ", Y %" PetscInt_FMT " x %" PetscInt_FMT, m1, n1, m2, n2); 68 PetscCheck(Y->assembled, PetscObjectComm((PetscObject)Y), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix (Y)"); 69 PetscCheck(X->assembled, PetscObjectComm((PetscObject)X), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix (X)"); 70 if (a == (PetscScalar)0.0) PetscFunctionReturn(PETSC_SUCCESS); 71 if (Y == X) { 72 PetscCall(MatScale(Y, 1.0 + a)); 73 PetscFunctionReturn(PETSC_SUCCESS); 74 } 75 PetscCall(PetscObjectObjectTypeCompare((PetscObject)X, (PetscObject)Y, &sametype)); 76 PetscCall(PetscLogEventBegin(MAT_AXPY, Y, 0, 0, 0)); 77 if (Y->ops->axpy && (sametype || X->ops->axpy == Y->ops->axpy)) { 78 PetscUseTypeMethod(Y, axpy, a, X, str); 79 } else { 80 PetscCall(PetscObjectTypeCompareAny((PetscObject)X, &transpose, MATTRANSPOSEVIRTUAL, MATHERMITIANTRANSPOSEVIRTUAL, "")); 81 if (transpose) { 82 PetscCall(MatTransposeAXPY_Private(Y, a, X, str, X)); 83 } else { 84 PetscCall(PetscObjectTypeCompareAny((PetscObject)Y, &transpose, MATTRANSPOSEVIRTUAL, MATHERMITIANTRANSPOSEVIRTUAL, "")); 85 if (transpose) { 86 PetscCall(MatTransposeAXPY_Private(Y, a, X, str, Y)); 87 } else { 88 PetscCall(MatAXPY_Basic(Y, a, X, str)); 89 } 90 } 91 } 92 PetscCall(PetscLogEventEnd(MAT_AXPY, Y, 0, 0, 0)); 93 PetscFunctionReturn(PETSC_SUCCESS); 94 } 95 96 PetscErrorCode MatAXPY_Basic_Preallocate(Mat Y, Mat X, Mat *B) 97 { 98 PetscErrorCode (*preall)(Mat, Mat, Mat *) = NULL; 99 100 PetscFunctionBegin; 101 /* look for any available faster alternative to the general preallocator */ 102 PetscCall(PetscObjectQueryFunction((PetscObject)Y, "MatAXPYGetPreallocation_C", &preall)); 103 if (preall) { 104 PetscCall((*preall)(Y, X, B)); 105 } else { /* Use MatPrellocator, assumes same row-col distribution */ 106 Mat preallocator; 107 PetscInt r, rstart, rend; 108 PetscInt m, n, M, N; 109 110 PetscCall(MatGetRowUpperTriangular(Y)); 111 PetscCall(MatGetRowUpperTriangular(X)); 112 PetscCall(MatGetSize(Y, &M, &N)); 113 PetscCall(MatGetLocalSize(Y, &m, &n)); 114 PetscCall(MatCreate(PetscObjectComm((PetscObject)Y), &preallocator)); 115 PetscCall(MatSetType(preallocator, MATPREALLOCATOR)); 116 PetscCall(MatSetLayouts(preallocator, Y->rmap, Y->cmap)); 117 PetscCall(MatSetUp(preallocator)); 118 PetscCall(MatGetOwnershipRange(preallocator, &rstart, &rend)); 119 for (r = rstart; r < rend; ++r) { 120 PetscInt ncols; 121 const PetscInt *row; 122 const PetscScalar *vals; 123 124 PetscCall(MatGetRow(Y, r, &ncols, &row, &vals)); 125 PetscCall(MatSetValues(preallocator, 1, &r, ncols, row, vals, INSERT_VALUES)); 126 PetscCall(MatRestoreRow(Y, r, &ncols, &row, &vals)); 127 PetscCall(MatGetRow(X, r, &ncols, &row, &vals)); 128 PetscCall(MatSetValues(preallocator, 1, &r, ncols, row, vals, INSERT_VALUES)); 129 PetscCall(MatRestoreRow(X, r, &ncols, &row, &vals)); 130 } 131 PetscCall(MatSetOption(preallocator, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE)); 132 PetscCall(MatAssemblyBegin(preallocator, MAT_FINAL_ASSEMBLY)); 133 PetscCall(MatAssemblyEnd(preallocator, MAT_FINAL_ASSEMBLY)); 134 PetscCall(MatRestoreRowUpperTriangular(Y)); 135 PetscCall(MatRestoreRowUpperTriangular(X)); 136 137 PetscCall(MatCreate(PetscObjectComm((PetscObject)Y), B)); 138 PetscCall(MatSetType(*B, ((PetscObject)Y)->type_name)); 139 PetscCall(MatSetLayouts(*B, Y->rmap, Y->cmap)); 140 PetscCall(MatPreallocatorPreallocate(preallocator, PETSC_FALSE, *B)); 141 PetscCall(MatDestroy(&preallocator)); 142 } 143 PetscFunctionReturn(PETSC_SUCCESS); 144 } 145 146 PetscErrorCode MatAXPY_Basic(Mat Y, PetscScalar a, Mat X, MatStructure str) 147 { 148 PetscBool isshell, isdense, isnest; 149 150 PetscFunctionBegin; 151 PetscCall(MatIsShell(Y, &isshell)); 152 if (isshell) { /* MatShell has special support for AXPY */ 153 PetscErrorCode (*f)(Mat, PetscScalar, Mat, MatStructure); 154 155 PetscCall(MatGetOperation(Y, MATOP_AXPY, (void (**)(void)) & f)); 156 if (f) { 157 PetscCall((*f)(Y, a, X, str)); 158 PetscFunctionReturn(PETSC_SUCCESS); 159 } 160 } 161 /* no need to preallocate if Y is dense */ 162 PetscCall(PetscObjectBaseTypeCompareAny((PetscObject)Y, &isdense, MATSEQDENSE, MATMPIDENSE, "")); 163 if (isdense) { 164 PetscCall(PetscObjectTypeCompare((PetscObject)X, MATNEST, &isnest)); 165 if (isnest) { 166 PetscCall(MatAXPY_Dense_Nest(Y, a, X)); 167 PetscFunctionReturn(PETSC_SUCCESS); 168 } 169 if (str == DIFFERENT_NONZERO_PATTERN || str == UNKNOWN_NONZERO_PATTERN) str = SUBSET_NONZERO_PATTERN; 170 } 171 if (str != DIFFERENT_NONZERO_PATTERN && str != UNKNOWN_NONZERO_PATTERN) { 172 PetscInt i, start, end, j, ncols, m, n; 173 const PetscInt *row; 174 PetscScalar *val; 175 const PetscScalar *vals; 176 177 PetscCall(MatGetSize(X, &m, &n)); 178 PetscCall(MatGetOwnershipRange(X, &start, &end)); 179 PetscCall(MatGetRowUpperTriangular(X)); 180 if (a == 1.0) { 181 for (i = start; i < end; i++) { 182 PetscCall(MatGetRow(X, i, &ncols, &row, &vals)); 183 PetscCall(MatSetValues(Y, 1, &i, ncols, row, vals, ADD_VALUES)); 184 PetscCall(MatRestoreRow(X, i, &ncols, &row, &vals)); 185 } 186 } else { 187 PetscInt vs = 100; 188 /* realloc if needed, as this function may be used in parallel */ 189 PetscCall(PetscMalloc1(vs, &val)); 190 for (i = start; i < end; i++) { 191 PetscCall(MatGetRow(X, i, &ncols, &row, &vals)); 192 if (vs < ncols) { 193 vs = PetscMin(2 * ncols, n); 194 PetscCall(PetscRealloc(vs * sizeof(*val), &val)); 195 } 196 for (j = 0; j < ncols; j++) val[j] = a * vals[j]; 197 PetscCall(MatSetValues(Y, 1, &i, ncols, row, val, ADD_VALUES)); 198 PetscCall(MatRestoreRow(X, i, &ncols, &row, &vals)); 199 } 200 PetscCall(PetscFree(val)); 201 } 202 PetscCall(MatRestoreRowUpperTriangular(X)); 203 PetscCall(MatAssemblyBegin(Y, MAT_FINAL_ASSEMBLY)); 204 PetscCall(MatAssemblyEnd(Y, MAT_FINAL_ASSEMBLY)); 205 } else { 206 Mat B; 207 208 PetscCall(MatAXPY_Basic_Preallocate(Y, X, &B)); 209 PetscCall(MatAXPY_BasicWithPreallocation(B, Y, a, X, str)); 210 PetscCall(MatHeaderMerge(Y, &B)); 211 } 212 PetscFunctionReturn(PETSC_SUCCESS); 213 } 214 215 PetscErrorCode MatAXPY_BasicWithPreallocation(Mat B, Mat Y, PetscScalar a, Mat X, MatStructure str) 216 { 217 PetscInt i, start, end, j, ncols, m, n; 218 const PetscInt *row; 219 PetscScalar *val; 220 const PetscScalar *vals; 221 222 PetscFunctionBegin; 223 PetscCall(MatGetSize(X, &m, &n)); 224 PetscCall(MatGetOwnershipRange(X, &start, &end)); 225 PetscCall(MatGetRowUpperTriangular(Y)); 226 PetscCall(MatGetRowUpperTriangular(X)); 227 if (a == 1.0) { 228 for (i = start; i < end; i++) { 229 PetscCall(MatGetRow(Y, i, &ncols, &row, &vals)); 230 PetscCall(MatSetValues(B, 1, &i, ncols, row, vals, ADD_VALUES)); 231 PetscCall(MatRestoreRow(Y, i, &ncols, &row, &vals)); 232 233 PetscCall(MatGetRow(X, i, &ncols, &row, &vals)); 234 PetscCall(MatSetValues(B, 1, &i, ncols, row, vals, ADD_VALUES)); 235 PetscCall(MatRestoreRow(X, i, &ncols, &row, &vals)); 236 } 237 } else { 238 PetscInt vs = 100; 239 /* realloc if needed, as this function may be used in parallel */ 240 PetscCall(PetscMalloc1(vs, &val)); 241 for (i = start; i < end; i++) { 242 PetscCall(MatGetRow(Y, i, &ncols, &row, &vals)); 243 PetscCall(MatSetValues(B, 1, &i, ncols, row, vals, ADD_VALUES)); 244 PetscCall(MatRestoreRow(Y, i, &ncols, &row, &vals)); 245 246 PetscCall(MatGetRow(X, i, &ncols, &row, &vals)); 247 if (vs < ncols) { 248 vs = PetscMin(2 * ncols, n); 249 PetscCall(PetscRealloc(vs * sizeof(*val), &val)); 250 } 251 for (j = 0; j < ncols; j++) val[j] = a * vals[j]; 252 PetscCall(MatSetValues(B, 1, &i, ncols, row, val, ADD_VALUES)); 253 PetscCall(MatRestoreRow(X, i, &ncols, &row, &vals)); 254 } 255 PetscCall(PetscFree(val)); 256 } 257 PetscCall(MatRestoreRowUpperTriangular(Y)); 258 PetscCall(MatRestoreRowUpperTriangular(X)); 259 PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY)); 260 PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY)); 261 PetscFunctionReturn(PETSC_SUCCESS); 262 } 263 264 /*@ 265 MatShift - Computes `Y = Y + a I`, where `a` is a `PetscScalar` 266 267 Neighbor-wise Collective 268 269 Input Parameters: 270 + Y - the matrix 271 - a - the `PetscScalar` 272 273 Level: intermediate 274 275 Notes: 276 If `Y` is a rectangular matrix, the shift is done on the main diagonal of the matrix (https://en.wikipedia.org/wiki/Main_diagonal) 277 278 If the matrix `Y` is missing some diagonal entries this routine can be very slow. To make it fast one should initially 279 fill the matrix so that all diagonal entries have a value (with a value of zero for those locations that would not have an 280 entry). No operation is performed when a is zero. 281 282 To form Y = Y + diag(V) use `MatDiagonalSet()` 283 284 .seealso: [](ch_matrices), `Mat`, `MatDiagonalSet()`, `MatScale()`, `MatDiagonalScale()` 285 @*/ 286 PetscErrorCode MatShift(Mat Y, PetscScalar a) 287 { 288 PetscFunctionBegin; 289 PetscValidHeaderSpecific(Y, MAT_CLASSID, 1); 290 PetscCheck(Y->assembled, PetscObjectComm((PetscObject)Y), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix"); 291 PetscCheck(!Y->factortype, PetscObjectComm((PetscObject)Y), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 292 MatCheckPreallocated(Y, 1); 293 if (a == 0.0) PetscFunctionReturn(PETSC_SUCCESS); 294 295 if (Y->ops->shift) PetscUseTypeMethod(Y, shift, a); 296 else PetscCall(MatShift_Basic(Y, a)); 297 298 PetscCall(PetscObjectStateIncrease((PetscObject)Y)); 299 PetscFunctionReturn(PETSC_SUCCESS); 300 } 301 302 PetscErrorCode MatDiagonalSet_Default(Mat Y, Vec D, InsertMode is) 303 { 304 PetscInt i, start, end; 305 const PetscScalar *v; 306 307 PetscFunctionBegin; 308 PetscCall(MatGetOwnershipRange(Y, &start, &end)); 309 PetscCall(VecGetArrayRead(D, &v)); 310 for (i = start; i < end; i++) PetscCall(MatSetValues(Y, 1, &i, 1, &i, v + i - start, is)); 311 PetscCall(VecRestoreArrayRead(D, &v)); 312 PetscCall(MatAssemblyBegin(Y, MAT_FINAL_ASSEMBLY)); 313 PetscCall(MatAssemblyEnd(Y, MAT_FINAL_ASSEMBLY)); 314 PetscFunctionReturn(PETSC_SUCCESS); 315 } 316 317 /*@ 318 MatDiagonalSet - Computes `Y` = `Y` + `D`, where `D` is a diagonal matrix 319 that is represented as a vector. Or Y[i,i] = D[i] if `InsertMode` is 320 `INSERT_VALUES`. 321 322 Neighbor-wise Collective 323 324 Input Parameters: 325 + Y - the input matrix 326 . D - the diagonal matrix, represented as a vector 327 - is - `INSERT_VALUES` or `ADD_VALUES` 328 329 Level: intermediate 330 331 Note: 332 If the matrix `Y` is missing some diagonal entries this routine can be very slow. To make it fast one should initially 333 fill the matrix so that all diagonal entries have a value (with a value of zero for those locations that would not have an 334 entry). 335 336 .seealso: [](ch_matrices), `Mat`, `MatShift()`, `MatScale()`, `MatDiagonalScale()` 337 @*/ 338 PetscErrorCode MatDiagonalSet(Mat Y, Vec D, InsertMode is) 339 { 340 PetscInt matlocal, veclocal; 341 342 PetscFunctionBegin; 343 PetscValidHeaderSpecific(Y, MAT_CLASSID, 1); 344 PetscValidHeaderSpecific(D, VEC_CLASSID, 2); 345 PetscCall(MatGetLocalSize(Y, &matlocal, NULL)); 346 PetscCall(VecGetLocalSize(D, &veclocal)); 347 PetscCheck(matlocal == veclocal, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number local rows of matrix %" PetscInt_FMT " does not match that of vector for diagonal %" PetscInt_FMT, matlocal, veclocal); 348 if (Y->ops->diagonalset) PetscUseTypeMethod(Y, diagonalset, D, is); 349 else PetscCall(MatDiagonalSet_Default(Y, D, is)); 350 PetscCall(PetscObjectStateIncrease((PetscObject)Y)); 351 PetscFunctionReturn(PETSC_SUCCESS); 352 } 353 354 /*@ 355 MatAYPX - Computes Y = a*Y + X. 356 357 Logically Collective 358 359 Input Parameters: 360 + a - the `PetscScalar` multiplier 361 . Y - the first matrix 362 . X - the second matrix 363 - str - either `SAME_NONZERO_PATTERN`, `DIFFERENT_NONZERO_PATTERN`, `UNKNOWN_NONZERO_PATTERN`, or `SUBSET_NONZERO_PATTERN` (nonzeros of `X` is a subset of `Y`'s) 364 365 Level: intermediate 366 367 .seealso: [](ch_matrices), `Mat`, `MatAXPY()` 368 @*/ 369 PetscErrorCode MatAYPX(Mat Y, PetscScalar a, Mat X, MatStructure str) 370 { 371 PetscFunctionBegin; 372 PetscCall(MatScale(Y, a)); 373 PetscCall(MatAXPY(Y, 1.0, X, str)); 374 PetscFunctionReturn(PETSC_SUCCESS); 375 } 376 377 /*@C 378 MatComputeOperator - Computes the explicit matrix 379 380 Collective 381 382 Input Parameters: 383 + inmat - the matrix 384 - mattype - the matrix type for the explicit operator 385 386 Output Parameter: 387 . mat - the explicit operator 388 389 Level: advanced 390 391 Note: 392 This computation is done by applying the operators to columns of the identity matrix. 393 This routine is costly in general, and is recommended for use only with relatively small systems. 394 Currently, this routine uses a dense matrix format if `mattype` == `NULL`. 395 396 .seealso: [](ch_matrices), `Mat`, `MatConvert()`, `MatMult()`, `MatComputeOperatorTranspose()` 397 @*/ 398 PetscErrorCode MatComputeOperator(Mat inmat, MatType mattype, Mat *mat) 399 { 400 PetscFunctionBegin; 401 PetscValidHeaderSpecific(inmat, MAT_CLASSID, 1); 402 PetscAssertPointer(mat, 3); 403 PetscCall(MatConvert_Shell(inmat, mattype ? mattype : MATDENSE, MAT_INITIAL_MATRIX, mat)); 404 PetscFunctionReturn(PETSC_SUCCESS); 405 } 406 407 /*@C 408 MatComputeOperatorTranspose - Computes the explicit matrix representation of 409 a give matrix that can apply `MatMultTranspose()` 410 411 Collective 412 413 Input Parameters: 414 + inmat - the matrix 415 - mattype - the matrix type for the explicit operator 416 417 Output Parameter: 418 . mat - the explicit operator transposed 419 420 Level: advanced 421 422 Note: 423 This computation is done by applying the transpose of the operator to columns of the identity matrix. 424 This routine is costly in general, and is recommended for use only with relatively small systems. 425 Currently, this routine uses a dense matrix format if `mattype` == `NULL`. 426 427 .seealso: [](ch_matrices), `Mat`, `MatConvert()`, `MatMult()`, `MatComputeOperator()` 428 @*/ 429 PetscErrorCode MatComputeOperatorTranspose(Mat inmat, MatType mattype, Mat *mat) 430 { 431 Mat A; 432 433 PetscFunctionBegin; 434 PetscValidHeaderSpecific(inmat, MAT_CLASSID, 1); 435 PetscAssertPointer(mat, 3); 436 PetscCall(MatCreateTranspose(inmat, &A)); 437 PetscCall(MatConvert_Shell(A, mattype ? mattype : MATDENSE, MAT_INITIAL_MATRIX, mat)); 438 PetscCall(MatDestroy(&A)); 439 PetscFunctionReturn(PETSC_SUCCESS); 440 } 441 442 /*@ 443 MatFilter - Set all values in the matrix with an absolute value less than or equal to the tolerance to zero, and optionally compress the underlying storage 444 445 Input Parameters: 446 + A - The matrix 447 . tol - The zero tolerance 448 . compress - Whether the storage from the input matrix `A` should be compressed once values less than or equal to `tol` are set to zero 449 - keep - If `compress` is true and for a given row of `A`, the diagonal coefficient is less than or equal to `tol`, indicates whether it should be left in the structure or eliminated as well 450 451 Level: intermediate 452 453 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatZeroEntries()`, `MatEliminateZeros()`, `VecFilter()` 454 @*/ 455 PetscErrorCode MatFilter(Mat A, PetscReal tol, PetscBool compress, PetscBool keep) 456 { 457 Mat a; 458 PetscScalar *newVals; 459 PetscInt *newCols, rStart, rEnd, maxRows, r, colMax = 0, nnz0 = 0, nnz1 = 0; 460 PetscBool flg; 461 462 PetscFunctionBegin; 463 PetscCall(PetscObjectBaseTypeCompareAny((PetscObject)A, &flg, MATSEQDENSE, MATMPIDENSE, "")); 464 if (flg) { 465 PetscCall(MatDenseGetLocalMatrix(A, &a)); 466 PetscCall(MatDenseGetLDA(a, &r)); 467 PetscCall(MatGetSize(a, &rStart, &rEnd)); 468 PetscCall(MatDenseGetArray(a, &newVals)); 469 for (; colMax < rEnd; ++colMax) { 470 for (maxRows = 0; maxRows < rStart; ++maxRows) newVals[maxRows + colMax * r] = PetscAbsScalar(newVals[maxRows + colMax * r]) <= tol ? 0.0 : newVals[maxRows + colMax * r]; 471 } 472 PetscCall(MatDenseRestoreArray(a, &newVals)); 473 } else { 474 const PetscInt *ranges; 475 PetscMPIInt rank, size; 476 477 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 478 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size)); 479 PetscCall(MatGetOwnershipRanges(A, &ranges)); 480 rStart = ranges[rank]; 481 rEnd = ranges[rank + 1]; 482 PetscCall(MatGetRowUpperTriangular(A)); 483 for (r = rStart; r < rEnd; ++r) { 484 PetscInt ncols; 485 486 PetscCall(MatGetRow(A, r, &ncols, NULL, NULL)); 487 colMax = PetscMax(colMax, ncols); 488 PetscCall(MatRestoreRow(A, r, &ncols, NULL, NULL)); 489 } 490 maxRows = 0; 491 for (r = 0; r < size; ++r) maxRows = PetscMax(maxRows, ranges[r + 1] - ranges[r]); 492 PetscCall(PetscCalloc2(colMax, &newCols, colMax, &newVals)); 493 PetscCall(MatGetOption(A, MAT_NO_OFF_PROC_ENTRIES, &flg)); /* cache user-defined value */ 494 PetscCall(MatSetOption(A, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE)); 495 /* short-circuit code in MatAssemblyBegin() and MatAssemblyEnd() */ 496 /* that are potentially called many times depending on the distribution of A */ 497 for (r = rStart; r < rStart + maxRows; ++r) { 498 if (r < rEnd) { 499 const PetscScalar *vals; 500 const PetscInt *cols; 501 PetscInt ncols, newcols = 0, c; 502 503 PetscCall(MatGetRow(A, r, &ncols, &cols, &vals)); 504 nnz0 += ncols - 1; 505 for (c = 0; c < ncols; ++c) { 506 if (PetscUnlikely(PetscAbsScalar(vals[c]) <= tol)) newCols[newcols++] = cols[c]; 507 } 508 nnz1 += ncols - newcols - 1; 509 PetscCall(MatRestoreRow(A, r, &ncols, &cols, &vals)); 510 PetscCall(MatSetValues(A, 1, &r, newcols, newCols, newVals, INSERT_VALUES)); 511 } 512 PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY)); 513 PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY)); 514 } 515 PetscCall(MatRestoreRowUpperTriangular(A)); 516 PetscCall(PetscFree2(newCols, newVals)); 517 PetscCall(MatSetOption(A, MAT_NO_OFF_PROC_ENTRIES, flg)); /* reset option to its user-defined value */ 518 if (nnz0 > 0) PetscCall(PetscInfo(NULL, "Filtering left %g%% edges in graph\n", 100 * (double)nnz1 / (double)nnz0)); 519 else PetscCall(PetscInfo(NULL, "Warning: %" PetscInt_FMT " edges to filter with %" PetscInt_FMT " rows\n", nnz0, maxRows)); 520 } 521 if (compress && A->ops->eliminatezeros) { 522 Mat B; 523 PetscBool flg; 524 525 PetscCall(PetscObjectTypeCompareAny((PetscObject)A, &flg, MATSEQAIJHIPSPARSE, MATMPIAIJHIPSPARSE, "")); 526 if (!flg) { 527 PetscCall(MatEliminateZeros(A, keep)); 528 PetscCall(MatDuplicate(A, MAT_COPY_VALUES, &B)); 529 PetscCall(MatHeaderReplace(A, &B)); 530 } 531 } 532 PetscFunctionReturn(PETSC_SUCCESS); 533 } 534